增加vendor

This commit is contained in:
hoteas
2022-05-24 13:49:25 +08:00
parent c3a24eeb3c
commit 65ece0418e
742 changed files with 509206 additions and 0 deletions
+43
View File
@@ -0,0 +1,43 @@
package aes
import (
"crypto/aes"
"crypto/cipher"
"errors"
)
// AES-CBC 加密数据
func CBCEncrypt(originData, key, iv []byte) ([]byte, error) {
return cbcEncrypt(originData, key, iv)
}
// AES-CBC 解密数据
func CBCDecrypt(secretData, key, iv []byte) ([]byte, error) {
return cbcDecrypt(secretData, key, iv)
}
func cbcEncrypt(originData, key, iv []byte) ([]byte, error) {
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
originData = PKCS7Padding(originData, block.BlockSize())
secretData := make([]byte, len(originData))
blockMode := cipher.NewCBCEncrypter(block, iv[:block.BlockSize()])
blockMode.CryptBlocks(secretData, originData)
return secretData, nil
}
func cbcDecrypt(secretData, key, iv []byte) (originByte []byte, err error) {
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
originByte = make([]byte, len(secretData))
blockMode := cipher.NewCBCDecrypter(block, iv[:block.BlockSize()])
blockMode.CryptBlocks(originByte, secretData)
if len(originByte) == 0 {
return nil, errors.New("blockMode.CryptBlocks error")
}
return PKCS7UnPadding(originByte), nil
}
+105
View File
@@ -0,0 +1,105 @@
package aes
import (
"crypto/aes"
"crypto/cipher"
"errors"
)
// AES-ECB 加密数据
func ECBEncrypt(originData, key []byte) ([]byte, error) {
return ecbEncrypt(originData, key)
}
// AES-ECB 解密数据
func ECBDecrypt(secretData, key []byte) ([]byte, error) {
return ecbDecrypt(secretData, key)
}
func ecbEncrypt(originData, key []byte) ([]byte, error) {
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
originData = PKCS7Padding(originData, block.BlockSize())
secretData := make([]byte, len(originData))
blockMode := newECBEncrypter(block)
blockMode.CryptBlocks(secretData, originData)
return secretData, nil
}
func ecbDecrypt(secretData, key []byte) (originByte []byte, err error) {
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
blockMode := newECBDecrypter(block)
originByte = make([]byte, len(secretData))
blockMode.CryptBlocks(originByte, secretData)
if len(originByte) == 0 {
return nil, errors.New("blockMode.CryptBlocks error")
}
return PKCS7UnPadding(originByte), nil
}
// ===========
type ecb struct {
b cipher.Block
blockSize int
}
func newECB(b cipher.Block) *ecb {
return &ecb{
b: b,
blockSize: b.BlockSize(),
}
}
type ecbEncrypter ecb
// newECBEncrypter returns a BlockMode which encrypts in electronic code book
// mode, using the given Block.
func newECBEncrypter(b cipher.Block) cipher.BlockMode {
return (*ecbEncrypter)(newECB(b))
}
func (x *ecbEncrypter) BlockSize() int { return x.blockSize }
func (x *ecbEncrypter) CryptBlocks(dst, src []byte) {
if len(src)%x.blockSize != 0 {
panic("crypto/cipher: input not full blocks")
}
if len(dst) < len(src) {
panic("crypto/cipher: output smaller than input")
}
for len(src) > 0 {
x.b.Encrypt(dst, src[:x.blockSize])
src = src[x.blockSize:]
dst = dst[x.blockSize:]
}
}
type ecbDecrypter ecb
// newECBDecrypter returns a BlockMode which decrypts in electronic code book
// mode, using the given Block.
func newECBDecrypter(b cipher.Block) cipher.BlockMode {
return (*ecbDecrypter)(newECB(b))
}
func (x *ecbDecrypter) BlockSize() int { return x.blockSize }
func (x *ecbDecrypter) CryptBlocks(dst, src []byte) {
if len(src)%x.blockSize != 0 {
panic("crypto/cipher: input not full blocks")
}
if len(dst) < len(src) {
panic("crypto/cipher: output smaller than input")
}
for len(src) > 0 {
x.b.Decrypt(dst, src[:x.blockSize])
src = src[x.blockSize:]
dst = dst[x.blockSize:]
}
}
+49
View File
@@ -0,0 +1,49 @@
package aes
import (
"crypto/aes"
"crypto/cipher"
"fmt"
"github.com/go-pay/gopay/pkg/util"
)
// AES-GCM 加密数据
func GCMEncrypt(originText, additional, key []byte) (nonce []byte, cipherText []byte, err error) {
return gcmEncrypt(originText, additional, key)
}
// AES-GCM 解密数据
func GCMDecrypt(cipherText, nonce, additional, key []byte) ([]byte, error) {
return gcmDecrypt(cipherText, nonce, additional, key)
}
func gcmDecrypt(secretData, nonce, additional, key []byte) ([]byte, error) {
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
gcm, err := cipher.NewGCM(block)
if err != nil {
return nil, fmt.Errorf("cipher.NewGCM(),error:%w", err)
}
originByte, err := gcm.Open(nil, nonce, secretData, additional)
if err != nil {
return nil, err
}
return originByte, nil
}
func gcmEncrypt(originText, additional, key []byte) ([]byte, []byte, error) {
block, err := aes.NewCipher(key)
if err != nil {
return nil, nil, err
}
nonce := []byte(util.RandomString(12))
gcm, err := cipher.NewGCM(block)
if err != nil {
return nil, nil, fmt.Errorf("cipher.NewGCM(),error:%w", err)
}
cipherBytes := gcm.Seal(nil, nonce, originText, additional)
return nonce, cipherBytes, nil
}
+42
View File
@@ -0,0 +1,42 @@
package aes
import "bytes"
// 加密填充模式(添加补全码) PKCS5Padding
// 加密时,如果加密bytes的length不是blockSize的整数倍,需要在最后面添加填充byte
func PKCS5Padding(ciphertext []byte, blockSize int) []byte {
paddingCount := blockSize - len(ciphertext)%blockSize //需要padding的数目
paddingBytes := []byte{byte(paddingCount)}
padtext := bytes.Repeat(paddingBytes, paddingCount) //生成填充的文本
return append(ciphertext, padtext...)
}
// 解密填充模式(去除补全码) PKCS5UnPadding
// 解密时,需要在最后面去掉加密时添加的填充byte
func PKCS5UnPadding(origData []byte) []byte {
length := len(origData)
unpadding := int(origData[length-1]) //找到Byte数组最后的填充byte
return origData[:(length - unpadding)] //只截取返回有效数字内的byte数组
}
// 加密填充模式(添加补全码) PKCS5Padding
// 加密时,如果加密bytes的length不是blockSize的整数倍,需要在最后面添加填充byte
func PKCS7Padding(ciphertext []byte, blockSize int) []byte {
paddingCount := blockSize - len(ciphertext)%blockSize //需要padding的数目
paddingBytes := []byte{byte(paddingCount)}
padtext := bytes.Repeat(paddingBytes, paddingCount) //生成填充的文本
return append(ciphertext, padtext...)
}
// 解密填充模式(去除补全码) PKCS7UnPadding
// 解密时,需要在最后面去掉加密时添加的填充byte
func PKCS7UnPadding(origData []byte) (bs []byte) {
length := len(origData)
unPaddingNumber := int(origData[length-1]) // 找到Byte数组最后的填充byte 数字
if unPaddingNumber <= 16 {
bs = origData[:(length - unPaddingNumber)] // 只截取返回有效数字内的byte数组
} else {
bs = origData
}
return
}
+126
View File
@@ -0,0 +1,126 @@
package errgroup
import (
"context"
"fmt"
"runtime"
"sync"
)
// A Group is a collection of goroutines working on subtasks that are part of
// the same overall task.
//
// A zero Group is valid and does not cancel on error.
type Group struct {
err error
wg sync.WaitGroup
errOnce sync.Once
workerOnce sync.Once
ch chan func(ctx context.Context) error
chs []func(ctx context.Context) error
workerNum int
ctx context.Context
cancel func()
}
// WithContext create a Group.
// given function from Go will receive this context,
func WithContext(ctx context.Context) *Group {
return &Group{ctx: ctx}
}
// WithCancel create a new Group and an associated Context derived from ctx.
//
// given function from Go will receive context derived from this ctx,
// The derived Context is canceled the first time a function passed to Go
// returns a non-nil error or the first time Wait returns, whichever occurs
// first.
func WithCancel(ctx context.Context) *Group {
ctx, cancel := context.WithCancel(ctx)
return &Group{ctx: ctx, cancel: cancel}
}
func (g *Group) do(f func(ctx context.Context) error) {
ctx := g.ctx
if ctx == nil {
ctx = context.Background()
}
var err error
defer func() {
if r := recover(); r != nil {
buf := make([]byte, 64<<10)
buf = buf[:runtime.Stack(buf, false)]
err = fmt.Errorf("errgroup: panic recovered: %s\n%s", r, buf)
}
if err != nil {
g.errOnce.Do(func() {
g.err = err
if g.cancel != nil {
g.cancel()
}
})
}
g.wg.Done()
}()
err = f(ctx)
}
// GOMAXPROCS set max goroutine to work.
func (g *Group) GOMAXPROCS(n int) {
if n <= 0 {
panic("errgroup: GOMAXPROCS must great than 0")
}
g.workerOnce.Do(func() {
g.ch = make(chan func(context.Context) error, n)
for i := 0; i < n; i++ {
go func() {
for f := range g.ch {
g.do(f)
}
}()
}
})
}
// Go calls the given function in a new goroutine.
//
// The first call to return a non-nil error cancels the group; its error will be
// returned by Wait.
func (g *Group) Go(f func(ctx context.Context) error) {
g.wg.Add(1)
g.workerNum++
if g.ch != nil {
select {
case g.ch <- f:
default:
g.chs = append(g.chs, f)
}
return
}
go g.do(f)
}
// Wait blocks until all function calls from the Go method have returned, then
// returns the first non-nil error (if any) from them.
func (g *Group) Wait() error {
if g.ch != nil {
for _, f := range g.chs {
g.ch <- f
}
}
g.wg.Wait()
if g.ch != nil {
close(g.ch) // let all receiver exit
}
if g.cancel != nil {
g.cancel()
}
g.workerNum = 0
return g.err
}
func (g *Group) WorkNum() int {
return g.workerNum
}
+13
View File
@@ -0,0 +1,13 @@
package util
const (
TimeLayout = "2006-01-02 15:04:05"
TimeLayout_2 = "20060102150405"
DateLayout = "2006-01-02"
NULL = ""
)
type File struct {
Name string `json:"name"`
Content []byte `json:"content"`
}
+100
View File
@@ -0,0 +1,100 @@
package util
import (
"math"
"reflect"
"strconv"
"strings"
"unsafe"
)
// 字符串转Int
// intStr:数字的字符串
func String2Int(intStr string) (intNum int) {
intNum, _ = strconv.Atoi(intStr)
return
}
// 字符串转Int64
// intStr:数字的字符串
func String2Int64(intStr string) (int64Num int64) {
intNum, _ := strconv.Atoi(intStr)
int64Num = int64(intNum)
return
}
// 字符串转Float64
// floatStr:小数点数字的字符串
func String2Float64(floatStr string) (floatNum float64) {
floatNum, _ = strconv.ParseFloat(floatStr, 64)
return
}
// 字符串转Float32
// floatStr:小数点数字的字符串
func String2Float32(floatStr string) (floatNum float32) {
floatNum64, _ := strconv.ParseFloat(floatStr, 32)
floatNum = float32(floatNum64)
return
}
// Int转字符串
// intNum:数字字符串
func Int2String(intNum int) (intStr string) {
intStr = strconv.Itoa(intNum)
return
}
// Int64转字符串
// intNum:数字字符串
func Int642String(intNum int64) (int64Str string) {
//10, 代表10进制
int64Str = strconv.FormatInt(intNum, 10)
return
}
// Float64转字符串
// floatNumfloat64数字
// prec:精度位数(不传则默认float数字精度)
func Float64ToString(floatNum float64, prec ...int) (floatStr string) {
if len(prec) > 0 {
floatStr = strconv.FormatFloat(floatNum, 'f', prec[0], 64)
return
}
floatStr = strconv.FormatFloat(floatNum, 'f', -1, 64)
return
}
// Float32转字符串
// floatNumfloat32数字
// prec:精度位数(不传则默认float数字精度)
func Float32ToString(floatNum float32, prec ...int) (floatStr string) {
if len(prec) > 0 {
floatStr = strconv.FormatFloat(float64(floatNum), 'f', prec[0], 32)
return
}
floatStr = strconv.FormatFloat(float64(floatNum), 'f', -1, 32)
return
}
// 二进制转10进制
func BinaryToDecimal(bit string) (num int) {
fields := strings.Split(bit, "")
lens := len(fields)
var tempF float64 = 0
for i := 0; i < lens; i++ {
floatNum := String2Float64(fields[i])
tempF += floatNum * math.Pow(2, float64(lens-i-1))
}
num = int(tempF)
return
}
// BytesToString 0 拷贝转换 slice byte 为 string
func BytesToString(b []byte) (s string) {
_bptr := (*reflect.SliceHeader)(unsafe.Pointer(&b))
_sptr := (*reflect.StringHeader)(unsafe.Pointer(&s))
_sptr.Data = _bptr.Data
_sptr.Len = _bptr.Len
return s
}
+42
View File
@@ -0,0 +1,42 @@
package util
import (
"math/rand"
"time"
)
//随机生成字符串
func RandomString(l int) string {
str := "0123456789AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz"
bytes := []byte(str)
var result []byte = make([]byte, 0, l)
r := rand.New(rand.NewSource(time.Now().UnixNano()))
for i := 0; i < l; i++ {
result = append(result, bytes[r.Intn(len(bytes))])
}
return BytesToString(result)
}
//随机生成纯字符串
func RandomPureString(l int) string {
str := "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz"
bytes := []byte(str)
var result []byte = make([]byte, 0, l)
r := rand.New(rand.NewSource(time.Now().UnixNano()))
for i := 0; i < l; i++ {
result = append(result, bytes[r.Intn(len(bytes))])
}
return BytesToString(result)
}
//随机生成数字字符串
func RandomNumber(l int) string {
str := "0123456789"
bytes := []byte(str)
var result []byte
r := rand.New(rand.NewSource(time.Now().UnixNano()))
for i := 0; i < l; i++ {
result = append(result, bytes[r.Intn(len(bytes))])
}
return BytesToString(result)
}
+18
View File
@@ -0,0 +1,18 @@
package util
import "encoding/json"
func ConvertToString(v interface{}) (str string) {
if v == nil {
return NULL
}
var (
bs []byte
err error
)
if bs, err = json.Marshal(v); err != nil {
return NULL
}
str = string(bs)
return
}
+361
View File
@@ -0,0 +1,361 @@
package xhttp
import (
"bytes"
"context"
"crypto/tls"
"encoding/json"
"encoding/xml"
"errors"
"fmt"
"io"
"io/ioutil"
"mime/multipart"
"net/http"
"net/url"
"sort"
"strings"
"time"
"github.com/go-pay/gopay"
"github.com/go-pay/gopay/pkg/util"
)
type Client struct {
HttpClient *http.Client
Transport *http.Transport
Header http.Header
Timeout time.Duration
url string
Host string
method string
requestType RequestType
FormString string
ContentType string
unmarshalType string
multipartBodyMap map[string]interface{}
jsonByte []byte
err error
}
// NewClient , default tls.Config{InsecureSkipVerify: true}
func NewClient() (client *Client) {
client = &Client{
HttpClient: &http.Client{
Timeout: 60 * time.Second,
Transport: &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
DisableKeepAlives: true,
Proxy: http.ProxyFromEnvironment,
},
},
Transport: nil,
Header: make(http.Header),
requestType: TypeJSON,
unmarshalType: string(TypeJSON),
}
return client
}
func (c *Client) SetTransport(transport *http.Transport) (client *Client) {
c.Transport = transport
return c
}
func (c *Client) SetTLSConfig(tlsCfg *tls.Config) (client *Client) {
c.Transport = &http.Transport{TLSClientConfig: tlsCfg, DisableKeepAlives: true, Proxy: http.ProxyFromEnvironment}
return c
}
func (c *Client) SetTimeout(timeout time.Duration) (client *Client) {
c.Timeout = timeout
return c
}
func (c *Client) SetHost(host string) (client *Client) {
c.Host = host
return c
}
func (c *Client) Type(typeStr RequestType) (client *Client) {
if _, ok := types[typeStr]; ok {
c.requestType = typeStr
}
return c
}
func (c *Client) Get(url string) (client *Client) {
c.method = GET
c.url = url
return c
}
func (c *Client) Post(url string) (client *Client) {
c.method = POST
c.url = url
return c
}
func (c *Client) Put(url string) (client *Client) {
c.method = PUT
c.url = url
return c
}
func (c *Client) Delete(url string) (client *Client) {
c.method = DELETE
c.url = url
return c
}
func (c *Client) Patch(url string) (client *Client) {
c.method = PATCH
c.url = url
return c
}
func (c *Client) SendStruct(v interface{}) (client *Client) {
if v == nil {
return c
}
bs, err := json.Marshal(v)
if err != nil {
c.err = fmt.Errorf("[%w]: %v, value: %v", gopay.MarshalErr, err, v)
return c
}
switch c.requestType {
case TypeJSON:
c.jsonByte = bs
case TypeXML, TypeUrlencoded, TypeForm, TypeFormData:
body := make(map[string]interface{})
if err = json.Unmarshal(bs, &body); err != nil {
c.err = fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
return c
}
c.FormString = FormatURLParam(body)
}
return c
}
func (c *Client) SendBodyMap(bm map[string]interface{}) (client *Client) {
if bm == nil {
return c
}
switch c.requestType {
case TypeJSON:
bs, err := json.Marshal(bm)
if err != nil {
c.err = fmt.Errorf("[%w]: %v, value: %v", gopay.MarshalErr, err, bm)
return c
}
c.jsonByte = bs
case TypeXML, TypeUrlencoded, TypeForm, TypeFormData:
c.FormString = FormatURLParam(bm)
}
return c
}
func (c *Client) SendMultipartBodyMap(bm map[string]interface{}) (client *Client) {
if bm == nil {
return c
}
switch c.requestType {
case TypeJSON:
bs, err := json.Marshal(bm)
if err != nil {
c.err = fmt.Errorf("[%w]: %v, value: %v", gopay.MarshalErr, err, bm)
return c
}
c.jsonByte = bs
case TypeXML, TypeUrlencoded, TypeForm, TypeFormData:
c.FormString = FormatURLParam(bm)
case TypeMultipartFormData:
c.multipartBodyMap = bm
}
return c
}
// encodeStr: url.Values.Encode() or jsonBody
func (c *Client) SendString(encodeStr string) (client *Client) {
switch c.requestType {
case TypeJSON:
c.jsonByte = []byte(encodeStr)
case TypeXML, TypeUrlencoded, TypeForm, TypeFormData:
c.FormString = encodeStr
}
return c
}
func (c *Client) EndStruct(ctx context.Context, v interface{}) (res *http.Response, err error) {
res, bs, err := c.EndBytes(ctx)
if err != nil {
return nil, err
}
if res.StatusCode != http.StatusOK {
return res, fmt.Errorf("StatusCode(%d) != 200", res.StatusCode)
}
switch c.unmarshalType {
case string(TypeJSON):
err = json.Unmarshal(bs, &v)
if err != nil {
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
}
return res, nil
case string(TypeXML):
err = xml.Unmarshal(bs, &v)
if err != nil {
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
}
return res, nil
default:
return nil, errors.New("unmarshalType Type Wrong")
}
}
func (c *Client) EndBytes(ctx context.Context) (res *http.Response, bs []byte, err error) {
if c.err != nil {
return nil, nil, c.err
}
var (
body io.Reader
bw *multipart.Writer
)
// multipart-form-data
if c.requestType == TypeMultipartFormData {
body = &bytes.Buffer{}
bw = multipart.NewWriter(body.(io.Writer))
}
reqFunc := func() (err error) {
switch c.method {
case GET:
switch c.requestType {
case TypeJSON:
c.ContentType = types[TypeJSON]
case TypeForm, TypeFormData, TypeUrlencoded:
c.ContentType = types[TypeForm]
case TypeMultipartFormData:
c.ContentType = bw.FormDataContentType()
case TypeXML:
c.ContentType = types[TypeXML]
c.unmarshalType = string(TypeXML)
default:
return errors.New("Request type Error ")
}
case POST, PUT, DELETE, PATCH:
switch c.requestType {
case TypeJSON:
if c.jsonByte != nil {
body = strings.NewReader(string(c.jsonByte))
}
c.ContentType = types[TypeJSON]
case TypeForm, TypeFormData, TypeUrlencoded:
body = strings.NewReader(c.FormString)
c.ContentType = types[TypeForm]
case TypeMultipartFormData:
for k, v := range c.multipartBodyMap {
// file 参数
if file, ok := v.(*util.File); ok {
fw, err := bw.CreateFormFile(k, file.Name)
if err != nil {
return err
}
_, _ = fw.Write(file.Content)
continue
}
// text 参数
vs, ok2 := v.(string)
if ok2 {
_ = bw.WriteField(k, vs)
} else if ss := util.ConvertToString(v); ss != "" {
_ = bw.WriteField(k, ss)
}
}
_ = bw.Close()
c.ContentType = bw.FormDataContentType()
case TypeXML:
body = strings.NewReader(c.FormString)
c.ContentType = types[TypeXML]
c.unmarshalType = string(TypeXML)
default:
return errors.New("Request type Error ")
}
default:
return errors.New("Only support GET and POST and PUT and DELETE ")
}
req, err := http.NewRequestWithContext(ctx, c.method, c.url, body)
if err != nil {
return err
}
req.Header = c.Header
req.Header.Set("Content-Type", c.ContentType)
if c.Transport != nil {
c.HttpClient.Transport = c.Transport
}
if c.Host != "" {
req.Host = c.Host
}
if c.Timeout > 0 {
c.HttpClient.Timeout = c.Timeout
}
res, err = c.HttpClient.Do(req)
if err != nil {
return err
}
defer res.Body.Close()
bs, err = ioutil.ReadAll(io.LimitReader(res.Body, int64(5<<20))) // default 5MB change the size you want
if err != nil {
return err
}
return nil
}
if err = reqFunc(); err != nil {
return nil, nil, err
}
return res, bs, nil
}
func FormatURLParam(body map[string]interface{}) (urlParam string) {
var (
buf strings.Builder
keys []string
)
for k := range body {
keys = append(keys, k)
}
sort.Strings(keys)
for _, k := range keys {
v, ok := body[k].(string)
if !ok {
v = convertToString(body[k])
}
if v != "" {
buf.WriteString(url.QueryEscape(k))
buf.WriteByte('=')
buf.WriteString(url.QueryEscape(v))
buf.WriteByte('&')
}
}
if buf.Len() <= 0 {
return ""
}
return buf.String()[:buf.Len()-1]
}
func convertToString(v interface{}) (str string) {
if v == nil {
return ""
}
var (
bs []byte
err error
)
if bs, err = json.Marshal(v); err != nil {
return ""
}
str = string(bs)
return
}
+26
View File
@@ -0,0 +1,26 @@
package xhttp
type RequestType string
const (
GET = "GET"
POST = "POST"
PUT = "PUT"
DELETE = "DELETE"
PATCH = "PATCH"
TypeJSON RequestType = "json"
TypeXML RequestType = "xml"
TypeUrlencoded RequestType = "urlencoded"
TypeForm RequestType = "form"
TypeFormData RequestType = "form-data"
TypeMultipartFormData RequestType = "multipart-form-data"
)
var types = map[RequestType]string{
TypeJSON: "application/json",
TypeXML: "application/xml",
TypeUrlencoded: "application/x-www-form-urlencoded",
TypeForm: "application/x-www-form-urlencoded",
TypeFormData: "application/x-www-form-urlencoded",
TypeMultipartFormData: "multipart/form-data",
}
+112
View File
@@ -0,0 +1,112 @@
package xlog
type ColorType string
var (
Reset = ColorType([]byte{27, 91, 48, 109})
// 标准
White = ColorType([]byte{27, 91, 51, 48, 109}) // 白色
Red = ColorType([]byte{27, 91, 51, 49, 109}) // 红色
Green = ColorType([]byte{27, 91, 51, 50, 109}) // 绿色
Yellow = ColorType([]byte{27, 91, 51, 51, 109}) // 黄色
Blue = ColorType([]byte{27, 91, 51, 52, 109}) // 蓝色
Magenta = ColorType([]byte{27, 91, 51, 53, 109}) // 紫色
Cyan = ColorType([]byte{27, 91, 51, 54, 109}) // 青色
// 高亮
WhiteBright = ColorType([]byte{27, 91, 49, 59, 51, 48, 109})
RedBright = ColorType([]byte{27, 91, 49, 59, 51, 49, 109})
GreenBright = ColorType([]byte{27, 91, 49, 59, 51, 50, 109})
YellowBright = ColorType([]byte{27, 91, 49, 59, 51, 51, 109})
BlueBright = ColorType([]byte{27, 91, 49, 59, 51, 52, 109})
MagentaBright = ColorType([]byte{27, 91, 49, 59, 51, 53, 109})
CyanBright = ColorType([]byte{27, 91, 49, 59, 51, 54, 109})
// 斜体
WhiteBevel = ColorType([]byte{27, 91, 51, 59, 51, 48, 109})
RedBevel = ColorType([]byte{27, 91, 51, 59, 51, 49, 109})
GreenBevel = ColorType([]byte{27, 91, 51, 59, 51, 50, 109})
YellowBevel = ColorType([]byte{27, 91, 51, 59, 51, 51, 109})
BlueBevel = ColorType([]byte{27, 91, 51, 59, 51, 52, 109})
MagentaBevel = ColorType([]byte{27, 91, 51, 59, 51, 53, 109})
CyanBevel = ColorType([]byte{27, 91, 51, 59, 51, 54, 109})
// 下划线
WhiteUnderLine = ColorType([]byte{27, 91, 52, 59, 51, 48, 109})
RedUnderLine = ColorType([]byte{27, 91, 52, 59, 51, 49, 109})
GreenUnderLine = ColorType([]byte{27, 91, 52, 59, 51, 50, 109})
YellowUnderLine = ColorType([]byte{27, 91, 52, 59, 51, 51, 109})
BlueUnderLine = ColorType([]byte{27, 91, 52, 59, 51, 52, 109})
MagentaUnderLine = ColorType([]byte{27, 91, 52, 59, 51, 53, 109})
CyanUnderLine = ColorType([]byte{27, 91, 52, 59, 51, 54, 109})
// 背景色
WhiteBg = ColorType([]byte{27, 91, 55, 59, 51, 48, 109})
RedBg = ColorType([]byte{27, 91, 55, 59, 51, 49, 109})
GreenBg = ColorType([]byte{27, 91, 55, 59, 51, 50, 109})
YellowBg = ColorType([]byte{27, 91, 55, 59, 51, 51, 109})
BlueBg = ColorType([]byte{27, 91, 55, 59, 51, 52, 109})
MagentaBg = ColorType([]byte{27, 91, 55, 59, 51, 53, 109})
CyanBg = ColorType([]byte{27, 91, 55, 59, 51, 54, 109})
// 删除线
WhiteDelLine = ColorType([]byte{27, 91, 57, 59, 51, 48, 109})
RedDelLine = ColorType([]byte{27, 91, 57, 59, 51, 49, 109})
GreenDelLine = ColorType([]byte{27, 91, 57, 59, 51, 50, 109})
YellowDelLine = ColorType([]byte{27, 91, 57, 59, 51, 51, 109})
BlueDelLine = ColorType([]byte{27, 91, 57, 59, 51, 52, 109})
MagentaDelLine = ColorType([]byte{27, 91, 57, 59, 51, 53, 109})
CyanDelLine = ColorType([]byte{27, 91, 57, 59, 51, 54, 109})
)
var cl *ColorLogger
type ColorLogger struct {
Color ColorType
i *InfoLogger
d *DebugLogger
w *WarnLogger
e *ErrorLogger
}
func Color(color ColorType) *ColorLogger {
if cl == nil {
cl = &ColorLogger{
Color: color,
i: &InfoLogger{},
d: &DebugLogger{},
w: &WarnLogger{},
e: &ErrorLogger{},
}
return cl
}
cl.Color = color
return cl
}
func (l *ColorLogger) Info(args ...interface{}) {
l.i.LogOut(&l.Color, nil, args...)
}
func (l *ColorLogger) Infof(format string, args ...interface{}) {
l.i.LogOut(&l.Color, &format, args...)
}
func (l *ColorLogger) Debug(args ...interface{}) {
l.d.LogOut(&l.Color, nil, args...)
}
func (l *ColorLogger) Debugf(format string, args ...interface{}) {
l.d.LogOut(&l.Color, &format, args...)
}
func (l *ColorLogger) Warn(args ...interface{}) {
l.w.LogOut(&l.Color, nil, args...)
}
func (l *ColorLogger) Warnf(format string, args ...interface{}) {
l.w.LogOut(&l.Color, &format, args...)
}
func (l *ColorLogger) Error(args ...interface{}) {
l.e.LogOut(&l.Color, nil, args...)
}
func (l *ColorLogger) Errorf(format string, args ...interface{}) {
l.e.LogOut(&l.Color, &format, args...)
}
+41
View File
@@ -0,0 +1,41 @@
package xlog
import (
"fmt"
"log"
"os"
"sync"
)
type DebugLogger struct {
logger *log.Logger
once sync.Once
}
func (i *DebugLogger) LogOut(col *ColorType, format *string, v ...interface{}) {
i.once.Do(func() {
i.init()
})
if Level >= DebugLevel {
if col != nil {
if format != nil {
i.logger.Output(3, string(*col)+fmt.Sprintf(*format, v...)+string(Reset))
return
}
i.logger.Output(3, string(*col)+fmt.Sprintln(v...)+string(Reset))
return
}
if format != nil {
i.logger.Output(3, fmt.Sprintf(*format, v...))
return
}
i.logger.Output(3, fmt.Sprintln(v...))
}
}
func (i *DebugLogger) init() {
if Level == 0 {
Level = DebugLevel
}
i.logger = log.New(os.Stdout, "[DEBUG] >> ", log.Lmsgprefix|log.Lshortfile|log.Ldate|log.Lmicroseconds)
}
+41
View File
@@ -0,0 +1,41 @@
package xlog
import (
"fmt"
"log"
"os"
"sync"
)
type ErrorLogger struct {
logger *log.Logger
once sync.Once
}
func (e *ErrorLogger) LogOut(col *ColorType, format *string, v ...interface{}) {
e.once.Do(func() {
e.init()
})
if Level >= ErrorLevel {
if col != nil {
if format != nil {
e.logger.Output(3, string(*col)+fmt.Sprintf(*format, v...)+string(Reset))
return
}
e.logger.Output(3, string(*col)+fmt.Sprintln(v...)+string(Reset))
return
}
if format != nil {
e.logger.Output(3, fmt.Sprintf(*format, v...))
return
}
e.logger.Output(3, fmt.Sprintln(v...))
}
}
func (e *ErrorLogger) init() {
if Level == 0 {
Level = DebugLevel
}
e.logger = log.New(os.Stdout, "[ERROR] >> ", log.Lmsgprefix|log.Lshortfile|log.Ldate|log.Lmicroseconds)
}
+41
View File
@@ -0,0 +1,41 @@
package xlog
import (
"fmt"
"log"
"os"
"sync"
)
type InfoLogger struct {
logger *log.Logger
once sync.Once
}
func (i *InfoLogger) LogOut(col *ColorType, format *string, v ...interface{}) {
i.once.Do(func() {
i.init()
})
if Level >= InfoLevel {
if col != nil {
if format != nil {
i.logger.Output(3, string(*col)+fmt.Sprintf(*format, v...)+string(Reset))
return
}
i.logger.Output(3, string(*col)+fmt.Sprintln(v...)+string(Reset))
return
}
if format != nil {
i.logger.Output(3, fmt.Sprintf(*format, v...))
return
}
i.logger.Output(3, fmt.Sprintln(v...))
}
}
func (i *InfoLogger) init() {
if Level == 0 {
Level = DebugLevel
}
i.logger = log.New(os.Stdout, "[INFO] >> ", log.Lmsgprefix|log.Lshortfile|log.Ldate|log.Lmicroseconds)
}
+55
View File
@@ -0,0 +1,55 @@
package xlog
const (
ErrorLevel LogLevel = iota + 1
WarnLevel
InfoLevel
DebugLevel
)
type LogLevel int
var (
debugLog XLogger = &DebugLogger{}
infoLog XLogger = &InfoLogger{}
warnLog XLogger = &WarnLogger{}
errLog XLogger = &ErrorLogger{}
Level LogLevel
)
type XLogger interface {
LogOut(col *ColorType, format *string, args ...interface{})
}
func Info(args ...interface{}) {
infoLog.LogOut(nil, nil, args...)
}
func Infof(format string, args ...interface{}) {
infoLog.LogOut(nil, &format, args...)
}
func Debug(args ...interface{}) {
debugLog.LogOut(nil, nil, args...)
}
func Debugf(format string, args ...interface{}) {
debugLog.LogOut(nil, &format, args...)
}
func Warn(args ...interface{}) {
warnLog.LogOut(nil, nil, args...)
}
func Warnf(format string, args ...interface{}) {
warnLog.LogOut(nil, &format, args...)
}
func Error(args ...interface{}) {
errLog.LogOut(nil, nil, args...)
}
func Errorf(format string, args ...interface{}) {
errLog.LogOut(nil, &format, args...)
}
+41
View File
@@ -0,0 +1,41 @@
package xlog
import (
"fmt"
"log"
"os"
"sync"
)
type WarnLogger struct {
logger *log.Logger
once sync.Once
}
func (i *WarnLogger) LogOut(col *ColorType, format *string, v ...interface{}) {
i.once.Do(func() {
i.init()
})
if Level >= WarnLevel {
if col != nil {
if format != nil {
i.logger.Output(3, string(*col)+fmt.Sprintf(*format, v...)+string(Reset))
return
}
i.logger.Output(3, string(*col)+fmt.Sprintln(v...)+string(Reset))
return
}
if format != nil {
i.logger.Output(3, fmt.Sprintf(*format, v...))
return
}
i.logger.Output(3, fmt.Sprintln(v...))
}
}
func (i *WarnLogger) init() {
if Level == 0 {
Level = DebugLevel
}
i.logger = log.New(os.Stdout, "[WARN] >> ", log.Lmsgprefix|log.Lshortfile|log.Ldate|log.Lmicroseconds)
}
+64
View File
@@ -0,0 +1,64 @@
package xpem
import (
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"fmt"
)
func DecodePublicKey(pemContent []byte) (publicKey *rsa.PublicKey, err error) {
block, _ := pem.Decode(pemContent)
if block == nil {
return nil, fmt.Errorf("pem.Decode(%s)pemContent decode error", pemContent)
}
switch block.Type {
case "CERTIFICATE":
pubKeyCert, err := x509.ParseCertificate(block.Bytes)
if err != nil {
return nil, fmt.Errorf("x509.ParseCertificate(%s)%w", pemContent, err)
}
pubKey, ok := pubKeyCert.PublicKey.(*rsa.PublicKey)
if !ok {
return nil, fmt.Errorf("公钥证书提取公钥出错 [%s]", pemContent)
}
publicKey = pubKey
case "PUBLIC KEY":
pub, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
return nil, fmt.Errorf("x509.ParsePKIXPublicKey(%s),err:%w", pemContent, err)
}
pubKey, ok := pub.(*rsa.PublicKey)
if !ok {
return nil, fmt.Errorf("公钥解析出错 [%s]", pemContent)
}
publicKey = pubKey
case "RSA PUBLIC KEY":
pubKey, err := x509.ParsePKCS1PublicKey(block.Bytes)
if err != nil {
return nil, fmt.Errorf("x509.ParsePKCS1PublicKey(%s)%w", pemContent, err)
}
publicKey = pubKey
}
return publicKey, nil
}
func DecodePrivateKey(pemContent []byte) (privateKey *rsa.PrivateKey, err error) {
block, _ := pem.Decode(pemContent)
if block == nil {
return nil, fmt.Errorf("pem.Decode(%s)pemContent decode error", pemContent)
}
privateKey, err = x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
pk8, err := x509.ParsePKCS8PrivateKey(block.Bytes)
if err != nil {
return nil, fmt.Errorf("私钥解析出错 [%s]", pemContent)
}
var ok bool
privateKey, ok = pk8.(*rsa.PrivateKey)
if !ok {
return nil, fmt.Errorf("私钥解析出错 [%s]", pemContent)
}
}
return privateKey, nil
}
+8
View File
@@ -0,0 +1,8 @@
package xtime
const (
TimeLayout = "2006-01-02 15:04:05"
TimeLayout_1 = "2006-01-02 15:04:05.000"
TimeLayout_2 = "20060102150405"
DateLayout = "2006-01-02"
)
+99
View File
@@ -0,0 +1,99 @@
package xtime
import (
"time"
)
var daysBefore = [...]int32{
0,
31,
31 + 28,
31 + 28 + 31,
31 + 28 + 31 + 30,
31 + 28 + 31 + 30 + 31,
31 + 28 + 31 + 30 + 31 + 30,
31 + 28 + 31 + 30 + 31 + 30 + 31,
31 + 28 + 31 + 30 + 31 + 30 + 31 + 31,
31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30,
31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31,
31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30,
31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31,
}
func MonthDays(m time.Month, year int) int {
if m == time.February && isLeap(year) {
return 29
}
return int(daysBefore[m] - daysBefore[m-1])
}
func isLeap(year int) bool {
return year%4 == 0 && (year%100 != 0 || year%400 == 0)
}
// 获取最近 7天 日期
func GetRecentSevenDay() (sevenDays []string) {
now := time.Now()
nowDay := time.Date(now.Year(), now.Month(), now.Day()-7, 0, 0, 0, 0, time.Local)
for i := 0; i < 7; i++ {
date := nowDay.AddDate(0, 0, i)
sevenDays = append(sevenDays, date.Format(DateLayout))
}
return sevenDays
}
// 获取最近 30天 日期
func GetRecentThirtyDay() (thirtyDays []string) {
now := time.Now()
nowDay := time.Date(now.Year(), now.Month(), now.Day()-30, 0, 0, 0, 0, time.Local)
for i := 0; i < 30; i++ {
date := nowDay.AddDate(0, 0, i)
thirtyDays = append(thirtyDays, date.Format(DateLayout))
}
return thirtyDays
}
// 获取本周 7天 日期
func GetCurWeekDays() (curWeekDays []string) {
now := time.Now()
offset := int(time.Monday - now.Weekday())
if offset > 0 {
offset = -6
}
weekStartDate := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.Local).AddDate(0, 0, offset)
for i := 0; i < 7; i++ {
date := weekStartDate.AddDate(0, 0, i)
curWeekDays = append(curWeekDays, date.Format(DateLayout))
}
return
}
// 获取本月 日期
func GetCurMonthDays() (curMonthDays []string) {
now := time.Now()
year := now.Year()
month := now.Month()
days := MonthDays(month, year)
monthFirstDay := time.Date(year, month, 01, 0, 0, 0, 0, time.Local)
for i := 0; i < days; i++ {
date := monthFirstDay.AddDate(0, 0, i)
curMonthDays = append(curMonthDays, date.Format(DateLayout))
}
return curMonthDays
}
// 获取上一个月 日期
func GetLastMonthDays() (monthDays []string) {
now := time.Now()
year := now.Year()
month := now.Month()
days := MonthDays(month-1, year)
monthFirstDay := time.Date(year, month-1, 01, 0, 0, 0, 0, time.Local)
for i := 0; i < days; i++ {
date := monthFirstDay.AddDate(0, 0, i)
monthDays = append(monthDays, date.Format(DateLayout))
}
return monthDays
}
+107
View File
@@ -0,0 +1,107 @@
package xtime
import (
"strings"
"time"
"github.com/go-pay/gopay/pkg/util"
)
//解析时间
// 时间字符串格式:2006-01-02 15:04:05
func ParseDateTime(timeStr string) (datetime time.Time) {
datetime, _ = time.ParseInLocation(TimeLayout, timeStr, time.Local)
return
}
//解析日期
// 日期字符串格式:2006-01-02
func ParseDate(timeStr string) (date time.Time) {
date, _ = time.ParseInLocation(DateLayout, timeStr, time.Local)
return
}
//格式化Datetime字符串
// 格式化前输入样式:2019-01-04T15:40:00Z 或 2019-01-04T15:40:00+08:00
// 格式化后返回样式:2019-01-04 15:40:00
func FormatDateTime(timeStr string) (formatTime string) {
if timeStr == "" {
return ""
}
replace := strings.Replace(timeStr, "T", " ", 1)
formatTime = replace[:19]
return
}
//格式化Date成字符串
// 格式化前输入样式:2019-01-04T15:40:00Z 或 2019-01-04T15:40:00+08:00
// 格式化后返回样式:2019-01-04
func FormatDate(dateStr string) (formatDate string) {
if dateStr == "" {
return ""
}
split := strings.Split(dateStr, "T")
formatDate = split[0]
return
}
func DurationToUnit(duration time.Duration) string {
var (
t string
intNs = int64(duration)
)
if intNs >= 0 && intNs < int64(time.Second) {
t = util.Int642String(intNs/int64(time.Millisecond)) + "ms"
}
// 大于等于 1秒,小于 1分钟
if intNs >= int64(time.Second) && intNs < int64(time.Minute) {
s := intNs / int64(time.Second)
ms := (intNs - s*int64(time.Second)) / int64(time.Millisecond)
t = util.Int642String(s) + "s"
if ms > 0 {
t += util.Int642String(ms) + "ms"
}
}
// 大于等于 1分钟,小于 1小时
if intNs >= int64(time.Minute) && intNs < int64(time.Hour) {
m := intNs / int64(time.Minute)
s := (intNs - m*int64(time.Minute)) / int64(time.Second)
t = util.Int642String(m) + "m"
if s > 0 {
t += util.Int642String(s) + "s"
}
}
// 大于等于 1小时,小于 1天
if intNs >= int64(time.Hour) && intNs < 24*int64(time.Hour) {
h := intNs / int64(time.Hour)
m := (intNs - h*int64(time.Hour)) / int64(time.Minute)
s := (intNs - h*int64(time.Hour) - m*int64(time.Minute)) / int64(time.Second)
t = util.Int642String(h) + "h"
if m > 0 {
t += util.Int642String(m) + "m"
}
if s > 0 {
t += util.Int642String(s) + "s"
}
}
// 大于等于 1天
if intNs >= 24*int64(time.Hour) {
d := intNs / (24 * int64(time.Hour))
h := (intNs - d*24*int64(time.Hour)) / int64(time.Hour)
m := (intNs - d*24*int64(time.Hour) - h*int64(time.Hour)) / int64(time.Minute)
s := ((intNs - m*int64(time.Minute)) % int64(time.Minute)) / int64(time.Second)
t = util.Int642String(d) + "d"
if h > 0 {
t += util.Int642String(h) + "h"
}
if m > 0 {
t += util.Int642String(m) + "m"
}
if s > 0 {
t += util.Int642String(s) + "s"
}
}
return t
}
+84
View File
@@ -0,0 +1,84 @@
package xtime
import (
"context"
"database/sql/driver"
"strconv"
"time"
)
// Time be used to MySql timestamp converting.
type Time int64
// Scan scan time.
func (t *Time) Scan(src interface{}) (err error) {
switch sc := src.(type) {
case time.Time:
if sc.IsZero() {
return
}
*t = Time(sc.Unix())
case string:
var i int64
i, err = strconv.ParseInt(sc, 10, 64)
*t = Time(i)
}
return
}
// Value get time value.
func (t Time) Value() (driver.Value, error) {
return time.Unix(int64(t), 0), nil
}
// Time get time.
func (t Time) Time() time.Time {
return time.Unix(int64(t), 0)
}
func (t *Time) FromDB(bs []byte) error {
timeStr := string(bs)
ti, err := time.ParseInLocation("2006-01-02T15:04:05", timeStr[:19], time.Local)
if err != nil {
return err
}
if ti.IsZero() {
return nil
}
*t = Time(ti.Unix())
return nil
}
func (t Time) ToDB() ([]byte, error) {
unix := time.Unix(int64(t), 0)
return []byte(unix.String()), nil
}
// Duration be used json unmarshal string time, like 1s, 500ms.
type Duration time.Duration
// UnmarshalText unmarshal text to duration.
func (d *Duration) UnmarshalText(text []byte) error {
tmp, err := time.ParseDuration(string(text))
if err == nil {
*d = Duration(tmp)
}
return err
}
// UnitTime duration parse to unit, such as "300ms", "1h30m" or "2h10s".
func (d *Duration) UnitTime() string {
return DurationToUnit(time.Duration(*d))
}
// Shrink will decrease the duration by comparing with context's timeout duration and return new timeout\context\CancelFunc.
func (d Duration) Shrink(c context.Context) (Duration, context.Context, context.CancelFunc) {
if deadline, ok := c.Deadline(); ok {
if ctimeout := time.Until(deadline); ctimeout < time.Duration(d) {
// deliver small timeout
return Duration(ctimeout), c, func() {}
}
}
ctx, cancel := context.WithTimeout(c, time.Duration(d))
return d, ctx, cancel
}