增加vendor
This commit is contained in:
+43
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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转字符串
|
||||
// floatNum:float64数字
|
||||
// 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转字符串
|
||||
// floatNum:float32数字
|
||||
// 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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
}
|
||||
Reference in New Issue
Block a user