This commit is contained in:
hong
2021-06-29 21:48:49 +08:00
parent ae43646373
commit 95b6f3f0cd
38 changed files with 3534 additions and 2 deletions

2
.gitignore vendored
View File

@@ -13,3 +13,5 @@
# Dependency directories (remove the comment below to include it) # Dependency directories (remove the comment below to include it)
# vendor/ # vendor/
*_test.go

View File

@@ -1,2 +1,61 @@
# go-pkg | package | comment |
some notes | :---- | :----|
|[bytes](https://github.com/pyihe/util/tree/master/bytes)|byte相关|
|[certs](https://github.com/pyihe/util/tree/master/certs)|证书相关|
|[clone](https://github.com/pyihe/util/tree/master/clone)|拷贝相关|
|[encoding](https://github.com/pyihe/util/tree/master/encoding)|编解码相关|
|[encrypts](https://github.com/pyihe/util/tree/master/encrypts)|加解密相关|
|[errors](https://github.com/pyihe/util/tree/master/errors)|错误相关|
|[files](https://github.com/pyihe/util/tree/master/files)|文件相关|
|[https](https://github.com/pyihe/util/tree/master/https)|http相关|
|[logs](https://github.com/pyihe/util/tree/master/logs)|日志相关|
|[maps](https://github.com/pyihe/util/tree/master/maps)|map相关|
|[maths](https://github.com/pyihe/util/tree/master/maths)|数学相关|
|[monitor](https://github.com/pyihe/util/tree/master/monitor)|监控相关|
|[nets](https://github.com/pyihe/util/tree/master/nets)|网络相关|
|[queue](https://github.com/pyihe/util/tree/master/queue)|队列相关|
|[rands](https://github.com/pyihe/util/tree/master/rands)|随机函数相关|
|[redis](https://github.com/pyihe/util/tree/master/redis)|redis相关|
|[snowflakes](https://github.com/pyihe/util/tree/master/snowflakes)|snowflake相关|
|[sorts](https://github.com/pyihe/util/tree/master/sorts)|排序相关|
|[strings](https://github.com/pyihe/util/tree/master/strings)|字符串相关|
|[typo](https://github.com/pyihe/util/tree/master/typo)|类型相关|
|[utils](https://github.com/pyihe/util/tree/master/utils)| 一些辅助函数|
|[zips](https://github.com/pyihe/util/tree/master/zips)|压缩相关|
- golang编译命令
1. GOOS="target OS" GOARCH="target arch" go build -o "output file name"
| OS | GOOS | GOARCH |
|:------|:------ | :--------------- |
|Mac|darwin|386, amd64, arm, arm64|
|DragonflyBSD|dragonfly|amd64|
|FreeBSD|freebsd|386, amd64, arm|
|Debian,RedHat,CentOs,Ubuntu|linux|386, amd64, arm, arm64, ppc64, ppc641e|
|NetBSD|netbsd|386, amd64, arm|
|OpenBSD|openbsd|386, amd64, arm|
|Plan 9|plan9|386, amd64|
|Solaris|solaris|amd64|
|Win series|windows|386, amd64|
2. [gox](https://github.com/mitchellh/gox) -osarch="target os/target arch"<br>
|target os|target arch|
|:--------|:----------|
|darwin|386|
|darwin|amd64|
|linux|386|
|linux|amd64|
|linux|arm|
|freebsd|386|
|freebsd|amd64|
|freebsd|arm|
|openbsd|386|
|openbsd|amd64|
|netbsd|386|
|netbsd|amd64|
|netbsd|arm|
|plan9|386|
|windows|386|
|windows|amd64|

57
bytes/bytes.go Normal file
View File

@@ -0,0 +1,57 @@
package bytes
import "unsafe"
// String []byte转换为string
func String(b []byte) string {
return *(*string)(unsafe.Pointer(&b))
}
// SliceEqual
func SliceEqual(a, b []byte) bool {
aLen, bLen := len(a), len(b)
if aLen != bLen {
return false
}
if (a == nil) != (b == nil) {
return false
}
b = b[:aLen]
for i, v := range a {
if b[i] != v {
return false
}
}
return true
}
// Contain
func Contain(ele byte, b []byte) bool {
for _, v := range b {
if v == ele {
return true
}
}
return false
}
// Reverse
func Reverse(b []byte) {
l := len(b)
for i := l/2 - 1; i >= 0; i-- {
opp := l - i - 1
b[i], b[opp] = b[opp], b[i]
}
}
// Remove
func Remove(ele byte, b []byte) {
for i := range b {
if ele == b[i] {
b = append(b[:i], b[i+1:]...)
break
}
}
}

27
certs/cert.go Normal file
View File

@@ -0,0 +1,27 @@
package certs
import (
"crypto/tls"
"encoding/pem"
"io/ioutil"
"golang.org/x/crypto/pkcs12"
)
func P12ToPem(p12Path string, password string) (*tls.Certificate, error) {
p12, err := ioutil.ReadFile(p12Path)
if err != nil {
return nil, err
}
blocks, err := pkcs12.ToPEM(p12, password)
if err != nil {
return nil, err
}
var pemData []byte
for _, b := range blocks {
pemData = append(pemData, pem.EncodeToMemory(b)...)
}
pemCert, err := tls.X509KeyPair(pemData, pemData)
return &pemCert, err
}

73
clone/clone.go Normal file
View File

@@ -0,0 +1,73 @@
package clone
import "reflect"
func deepCopy(dst, src reflect.Value) {
switch src.Kind() {
case reflect.Interface:
value := src.Elem()
if !value.IsValid() {
return
}
newValue := reflect.New(value.Type()).Elem()
deepCopy(newValue, value)
dst.Set(newValue)
case reflect.Ptr:
value := src.Elem()
if !value.IsValid() {
return
}
dst.Set(reflect.New(value.Type()))
deepCopy(dst.Elem(), value)
case reflect.Map:
dst.Set(reflect.MakeMap(src.Type()))
keys := src.MapKeys()
for _, key := range keys {
value := src.MapIndex(key)
newValue := reflect.New(value.Type()).Elem()
deepCopy(newValue, value)
dst.SetMapIndex(key, newValue)
}
case reflect.Slice:
dst.Set(reflect.MakeSlice(src.Type(), src.Len(), src.Cap()))
for i := 0; i < src.Len(); i++ {
deepCopy(dst.Index(i), src.Index(i))
}
case reflect.Struct:
typeSrc := src.Type()
for i := 0; i < src.NumField(); i++ {
value := src.Field(i)
tag := typeSrc.Field(i).Tag
if value.CanSet() && tag.Get("deepcopy") != "-" {
deepCopy(dst.Field(i), value)
}
}
default:
dst.Set(src)
}
}
func DeepCopy(dst, src interface{}) {
typeDst := reflect.TypeOf(dst)
typeSrc := reflect.TypeOf(src)
if typeDst != typeSrc {
panic("DeepCopy: " + typeDst.String() + " != " + typeSrc.String())
}
if typeSrc.Kind() != reflect.Ptr {
panic("DeepCopy: pass arguments by address")
}
valueDst := reflect.ValueOf(dst).Elem()
valueSrc := reflect.ValueOf(src).Elem()
if !valueDst.IsValid() || !valueSrc.IsValid() {
panic("DeepCopy: invalid arguments")
}
deepCopy(valueDst, valueSrc)
}
func DeepClone(v interface{}) interface{} {
dst := reflect.New(reflect.TypeOf(v)).Elem()
deepCopy(dst, reflect.ValueOf(v))
return dst.Interface()
}

99
encoding/encoding.go Normal file
View File

@@ -0,0 +1,99 @@
package encoding
import (
"bytes"
"encoding/gob"
"encoding/json"
"errors"
"github.com/golang/protobuf/proto"
"github.com/vmihailenco/msgpack/v5"
)
type Encoding interface {
Marshal(v interface{}) ([]byte, error)
Unmarshal(data []byte, v interface{}) error
}
// JSONEncoding json格式
func JSONEncoding() Encoding {
return &jsonEncoding{}
}
// GobEncoding
func GobEncoding() Encoding {
return &gobEncoding{}
}
// MsgpackEncoding
func MsgpackEncoding() Encoding {
return &msgpackEncoding{}
}
// ProtoEncoding
func ProtoEncoding() Encoding {
return &protoEncoding{}
}
/***JSON Marshaler***/
type jsonEncoding struct{}
// Marshal
func (j *jsonEncoding) Marshal(v interface{}) ([]byte, error) {
return json.Marshal(v)
}
// Unmarshal
func (j *jsonEncoding) Unmarshal(data []byte, v interface{}) error {
return json.Unmarshal(data, v)
}
/***gob Marshaler***/
type gobEncoding struct{}
// Marshal
func (g *gobEncoding) Marshal(v interface{}) ([]byte, error) {
var b = bytes.NewBuffer(nil)
err := gob.NewEncoder(b).Encode(v)
return b.Bytes(), err
}
// Unmarshal
func (g *gobEncoding) Unmarshal(data []byte, v interface{}) error {
return gob.NewDecoder(bytes.NewReader(data)).Decode(v)
}
/***msgpack Marshaler***/
type msgpackEncoding struct{}
// Marshal
func (m *msgpackEncoding) Marshal(v interface{}) ([]byte, error) {
return msgpack.Marshal(v)
}
// Unmarshal
func (m *msgpackEncoding) Unmarshal(data []byte, v interface{}) error {
return msgpack.Unmarshal(data, v)
}
/***proto Encoding***/
type protoEncoding struct{}
// Marshal
func (p *protoEncoding) Marshal(v interface{}) ([]byte, error) {
m, ok := v.(proto.Message)
if !ok {
return nil, errors.New("not proto.Message")
}
return proto.Marshal(m)
}
// Unmarshal
func (p *protoEncoding) Unmarshal(data []byte, v interface{}) error {
m, ok := v.(proto.Message)
if !ok {
return errors.New("not proto.Message")
}
return proto.Unmarshal(data, m)
}

38
encrypts/encrypt.go Normal file
View File

@@ -0,0 +1,38 @@
package encrypts
import (
"encoding/base64"
"golang.org/x/crypto/bcrypt"
"golang.org/x/crypto/scrypt"
)
//用于加密web的密码
func BcEncryptPass(plainPass string) (string, error) {
var encryptPass string
data, err := bcrypt.GenerateFromPassword([]byte(plainPass), bcrypt.DefaultCost)
if err != nil {
return encryptPass, err
}
encryptPass = base64.StdEncoding.EncodeToString(data)
return encryptPass, nil
}
//比较密码是否匹配
func BcComparePass(hashPass, plainPass string) error {
hashBytes, err := base64.StdEncoding.DecodeString(hashPass)
if err != nil {
return err
}
return bcrypt.CompareHashAndPassword(hashBytes, []byte(plainPass))
}
//scrypt加密
func ScryptPass(plainPass, salt string) (string, error) {
data, err := scrypt.Key([]byte(plainPass), []byte(salt), 1<<15, 8, 1, 32)
if err != nil {
return "", err
}
encryptPass := base64.StdEncoding.EncodeToString(data)
return encryptPass, nil
}

73
errors/errors.go Normal file
View File

@@ -0,0 +1,73 @@
package errors
import (
"fmt"
)
const (
ErrorCodeFail = 100000 //默认错误代码
)
type Error interface {
Error() string
Code() int
Message() string
WithCode(code int) Error
WithMessage(msg string) Error
}
type myError struct {
code int
message string
}
func NewError(code int, message string) Error {
return &myError{
code: code,
message: message,
}
}
func Errorf(m string, args ...interface{}) Error {
e := &myError{}
e.message = fmt.Sprintf(m, args...)
return e
}
func (m *myError) WithCode(code int) Error {
if m == nil {
return nil
}
m.code = code
return m
}
func (m *myError) WithMessage(msg string) Error {
if m == nil {
return nil
}
m.message = msg
return m
}
func (m *myError) Error() string {
if m == nil {
return ""
}
return fmt.Sprintf("Code: %d, Message: %s", m.code, m.message)
}
func (m *myError) Message() string {
if m == nil {
return ""
}
return m.message
}
func (m *myError) Code() int {
if m != nil {
return m.code
}
return 0
}

16
files/file.go Normal file
View File

@@ -0,0 +1,16 @@
package files
import "os"
// MakeNewPath 判断目录是否存在,如果不存在,则新建一个目录
func MakeNewPath(targetPath string) error {
if _, err := os.Stat(targetPath); err != nil {
if !os.IsExist(err) {
//创建目录
if mErr := os.MkdirAll(targetPath, os.ModePerm); mErr != nil {
return mErr
}
}
}
return nil
}

15
go.mod Normal file
View File

@@ -0,0 +1,15 @@
module github.com/pyihe/go-pkg
go 1.16
require (
github.com/garyburd/redigo v1.6.2 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible // indirect
github.com/lestrrat-go/strftime v1.0.4 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/robfig/cron/v3 v3.0.1 // indirect
github.com/vmihailenco/msgpack/v5 v5.3.4 // indirect
go.uber.org/zap v1.18.1 // indirect
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e // indirect
)

67
go.sum Normal file
View File

@@ -0,0 +1,67 @@
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/garyburd/redigo v1.6.2 h1:yE/pwKCrbLpLpQICzYTeZ7JsTA/C53wFTJHaEtRqniM=
github.com/garyburd/redigo v1.6.2/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc/go.mod h1:kopuH9ugFRkIXf3YoqHKyrJ9YfUFsckUU9S7B+XP+is=
github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible h1:Y6sqxHMyB1D2YSzWkLibYKgg+SwmyFU9dF2hn6MdTj4=
github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible/go.mod h1:ZQnN8lSECaebrkQytbHj4xNgtg8CR7RYXnPok8e0EHA=
github.com/lestrrat-go/strftime v1.0.4 h1:T1Rb9EPkAhgxKqbcMIPguPq8glqXTA1koF8n9BHElA8=
github.com/lestrrat-go/strftime v1.0.4/go.mod h1:E1nN3pCbtMSu1yjSVeyuRFVm/U0xoR76fd03sz+Qz4g=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/vmihailenco/msgpack/v5 v5.3.4 h1:qMKAwOV+meBw2Y8k9cVwAy7qErtYCwBzZ2ellBfvnqc=
github.com/vmihailenco/msgpack/v5 v5.3.4/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc=
github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g=
github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds=
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
go.uber.org/zap v1.18.1 h1:CSUJ2mjFszzEWt4CdKISEuChVIXGBn3lAPwkRGyVrc4=
go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e h1:gsTQYXdTw2Gq7RBsWvlQ91b+aEQ6bXFUngBGuR8sPpI=
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

71
https/http.go Normal file
View File

@@ -0,0 +1,71 @@
package https
import (
"io"
"io/ioutil"
"net/http"
"strings"
"github.com/pyihe/go-pkg/encoding"
"github.com/pyihe/go-pkg/errors"
)
var (
ErrInvalidUrl = errors.NewError(errors.ErrorCodeFail, "url must start with 'http'")
ErrInvalidEncoder = errors.NewError(errors.ErrorCodeFail, "invalid encoder")
)
// Get
func Get(client *http.Client, url string) ([]byte, error) {
if url == "" || !strings.HasPrefix(url, "http") {
return nil, ErrInvalidUrl
}
if client == nil {
client = http.DefaultClient
}
response, err := client.Get(url)
if err != nil {
return nil, err
}
defer response.Body.Close()
return ioutil.ReadAll(response.Body)
}
// GetWithObj
func GetWithObj(client *http.Client, url string, encoder encoding.Encoding, obj interface{}) error {
data, err := Get(client, url)
if err != nil {
return err
}
err = encoder.Unmarshal(data, obj)
return err
}
// Post
func Post(client *http.Client, url string, contentType string, body io.Reader) ([]byte, error) {
if url == "" || !strings.HasPrefix(url, "http") {
return nil, ErrInvalidUrl
}
if client == nil {
client = http.DefaultClient
}
response, err := client.Post(url, contentType, body)
if err != nil {
return nil, err
}
defer response.Body.Close()
return ioutil.ReadAll(response.Body)
}
// PostWithObj
func PostWithObj(client *http.Client, url string, contentType string, body io.Reader, encoder encoding.Encoding, v interface{}) error {
data, err := Post(client, url, contentType, body)
if err != nil {
return err
}
return encoder.Unmarshal(data, v)
}

126
https/https.go Normal file
View File

@@ -0,0 +1,126 @@
package https
import (
"crypto/tls"
"crypto/x509"
"io"
"io/ioutil"
"net/http"
"github.com/pyihe/go-pkg/encoding"
)
type TLSClient interface {
Get(url string) ([]byte, error)
GetWithObj(url string, obj interface{}) error
Post(url, contentType string, body io.Reader) ([]byte, error)
PostWithObj(url, contentType string, body io.Reader, obj interface{}) error
ListenAndServeTLS(serverCrt, serverKey string) error
}
// httpClient
type httpClient struct {
client *http.Client
ca *x509.CertPool
certificate tls.Certificate
encoder encoding.Encoding
}
// NewTLSClient
func NewTLSClient(caCrt, clientCrt, clientKey string, encoder encoding.Encoding) {
var err error
c := &httpClient{
encoder: encoder,
}
c.ca, err = loadCA(caCrt)
if err != nil {
panic(err)
}
c.certificate, err = tls.LoadX509KeyPair(clientCrt, clientKey)
if err != nil {
panic(err)
}
c.client = &http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{
RootCAs: c.ca,
Certificates: []tls.Certificate{c.certificate},
},
},
}
}
// ListenAndServeTLS
func (h *httpClient) ListenAndServeTLS(serverCrt, serverKey string) error {
server := &http.Server{
Addr: ":443",
TLSConfig: &tls.Config{
ClientCAs: h.ca,
ClientAuth: tls.RequireAndVerifyClientCert,
},
}
return server.ListenAndServeTLS(serverCrt, serverKey)
}
// Get
func (h *httpClient) Get(url string) ([]byte, error) {
response, err := h.client.Get(url)
if err != nil {
return nil, err
}
defer response.Body.Close()
return ioutil.ReadAll(response.Body)
}
// GetWithObj
func (h *httpClient) GetWithObj(url string, obj interface{}) error {
data, err := h.Get(url)
if err != nil {
return err
}
if h.encoder == nil {
return ErrInvalidEncoder
}
return h.encoder.Unmarshal(data, obj)
}
// Post
func (h *httpClient) Post(url, contentType string, body io.Reader) ([]byte, error) {
response, err := h.client.Post(url, contentType, body)
if err != nil {
return nil, err
}
defer response.Body.Close()
return ioutil.ReadAll(response.Body)
}
// PostWithObj
func (h *httpClient) PostWithObj(url, contentType string, body io.Reader, obj interface{}) error {
data, err := h.Post(url, contentType, body)
if err != nil {
return err
}
if h.encoder == nil {
return ErrInvalidEncoder
}
return h.encoder.Unmarshal(data, obj)
}
// loadCA 加载身份证书
func loadCA(caFile string) (*x509.CertPool, error) {
p := x509.NewCertPool()
ca, err := ioutil.ReadFile(caFile)
if err != nil {
return nil, err
}
p.AppendCertsFromPEM(ca)
return p, nil
}

217
logs/log.go Normal file
View File

@@ -0,0 +1,217 @@
package logs
import (
"fmt"
"io"
"os"
"path"
"runtime"
"sync"
"time"
)
const (
colorRed = 31
colorYellow = 33
colorBlue = 34
levelT = "[T] "
levelE = "[E] "
levelW = "[W] "
levelF = "[F] "
defaultFileSize = 60 * 1024 * 1024
minFileSize = 1 * 1024 * 1024
defaultLogDir = "logs"
defaultLogName = "default.logs"
)
const (
logTypeStd logType = iota + 1
logTypeFile
)
type (
logType int
logOption func(log *myLog)
myLog struct {
sync.Once
sync.Mutex
outs map[logType]io.Writer //writer集合
file *os.File //文件句柄
fileName string //日志名
dir string //日志存放路径
size int64 //单个日志文件的大小限制
}
)
var (
defaultLogger = &myLog{}
)
func (m *myLog) init() {
if m.dir == "" {
m.dir = defaultLogDir
}
if m.fileName == "" {
m.fileName = defaultLogName
}
if m.size == 0 {
m.size = defaultFileSize
} else {
if m.size < minFileSize {
panic(fmt.Sprintf("invalid size: %d", m.size))
}
}
if m.outs == nil {
m.outs = make(map[logType]io.Writer)
}
if !isExist(m.dir) {
if err := os.Mkdir(m.dir, 0777); err != nil {
panic(err)
}
}
name := path.Join(m.dir, m.fileName)
file, err := os.OpenFile(name, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0755)
if err != nil {
panic(err)
}
m.file = file
m.outs[logTypeStd] = os.Stdout
m.outs[logTypeFile] = file
}
func (m *myLog) checkLogSize() {
if m.file == nil {
return
}
m.Lock()
defer m.Unlock()
fileInfo, err := m.file.Stat()
if err != nil {
panic(err)
}
if m.size > fileInfo.Size() {
return
}
//需要分割
newName := path.Join(m.dir, time.Now().Format("2006_01_02_15:04:03")+".logs")
name := path.Join(m.dir, m.fileName)
err = os.Rename(name, newName)
if err != nil {
panic(err)
}
file, err := os.OpenFile(name, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0755)
if err != nil {
panic(err)
}
m.file.Close()
m.file = file
m.outs[logTypeFile] = file
return
}
func (m *myLog) writeLog() {
}
func (m *myLog) write(msg, timeStr, fileName, prefix string, line, color int) {
m.checkLogSize()
for k, wr := range m.outs {
if k == logTypeStd {
fmt.Fprintf(wr, "%c[%dm%s[%s %s:%d] %s%c[0m\n", 0x1B, color, prefix, timeStr, fileName, line, msg, 0x1B)
} else {
fmt.Fprintf(wr, "%s[%s %s:%d] %s\n", prefix, timeStr, fileName, line, msg)
}
}
}
func WithSize(size int64) logOption {
return func(log *myLog) {
log.size = size
}
}
func WithLogDir(dir string) logOption {
return func(log *myLog) {
log.dir = dir
}
}
func WithFileName(name string) logOption {
return func(log *myLog) {
log.fileName = name
}
}
func InitLogger(args ...logOption) {
defaultLogger.Do(func() {
for _, af := range args {
af(defaultLogger)
}
defaultLogger.init()
})
}
////Info
func T(format string, v ...interface{}) {
timeStr, fileName, line := getPrefixInfo()
defaultLogger.write(fmt.Sprintf(format, v...), timeStr, fileName, levelT, line, colorBlue)
}
//
////Error
func E(format string, v ...interface{}) {
timeStr, fileName, line := getPrefixInfo()
defaultLogger.write(fmt.Sprintf(format, v...), timeStr, fileName, levelE, line, colorYellow)
}
//Warn
func W(format string, v ...interface{}) {
timeStr, fileName, line := getPrefixInfo()
defaultLogger.write(fmt.Sprintf(format, v...), timeStr, fileName, levelW, line, colorRed)
}
//Fatal
func F(format string, v ...interface{}) {
timeStr, fileName, line := getPrefixInfo()
defaultLogger.write(fmt.Sprintf(format, v...), timeStr, fileName, levelF, line, colorRed)
os.Exit(-1)
}
func getPrefixInfo() (timeStr, fileName string, line int) {
_, file, line, _ := runtime.Caller(1)
fileName = shortFileName(file)
timeStr = time.Now().Format("2006-01-02 15:04:05.0000")
return timeStr, fileName, line
}
func isExist(path string) bool {
_, err := os.Stat(path)
if err != nil {
if os.IsExist(err) {
return true
}
return false
}
return true
}
func shortFileName(file string) string {
short := file
for i := len(file) - 1; i > 0; i-- {
if file[i] == '/' {
short = file[i+1:]
break
}
}
return short
}

83
logs/log_log.go Normal file
View File

@@ -0,0 +1,83 @@
package logs
var (
logger Logger
)
type Fields map[string]interface{}
type Logger interface {
Debug(args ...interface{})
Info(args ...interface{})
Warn(args ...interface{})
Error(args ...interface{})
Fatal(args ...interface{})
Debugf(format string, args ...interface{})
Infof(format string, args ...interface{})
Warnf(format string, args ...interface{})
Errorf(format string, args ...interface{})
Fatalf(format string, args ...interface{})
Panicf(format string, args ...interface{})
WithFields(fields Fields) Logger
}
// Debug
func Debug(args ...interface{}) {
logger.Debug(args...)
}
// Debugf
func Debugf(format string, args ...interface{}) {
logger.Debugf(format, args...)
}
// Info
func Info(args ...interface{}) {
logger.Info(args...)
}
// Infof
func Infof(format string, args ...interface{}) {
logger.Infof(format, args...)
}
// Warn
func Warn(args ...interface{}) {
logger.Warn(args...)
}
// Warnf
func Warnf(format string, args ...interface{}) {
logger.Warnf(format, args...)
}
// Error
func Error(args ...interface{}) {
logger.Error(args...)
}
// Errorf
func Errorf(format string, args ...interface{}) {
logger.Errorf(format, args...)
}
// Fatal
func Fatal(args ...interface{}) {
logger.Fatal(args...)
}
// Fatalf
func Fatalf(format string, args ...interface{}) {
logger.Fatalf(format, args...)
}
// Panicf
func Panicf(format string, args ...interface{}) {
logger.Panicf(format, args...)
}
// WithFields
func WithFields(fields Fields) Logger {
return logger.WithFields(fields)
}

92
logs/log_option.go Normal file
View File

@@ -0,0 +1,92 @@
package logs
// LogOption 日志配置项
type LogOption func(zl *zapLogger)
// NewLogger 初始化日志记录器
func NewLogger(options ...LogOption) error {
var err error
logger, err = newZapLogger(options...)
if err != nil {
return err
}
return nil
}
// WithName 日志输出时的应用名
func WithName(n string) LogOption {
return func(zl *zapLogger) {
zl.name = n
}
}
// WithWriters 日志输出流, file: 只输出到文件; stdout: 只输出到标准输出流; file,stdout: 同时输出到文件和标准输出流
func WithWriters(w string) LogOption {
return func(zl *zapLogger) {
zl.writers = w
}
}
// WithLevel 日志级别: DEBUG, INFO, WARN, ERROR, FATAL
func WithLevel(l string) LogOption {
return func(zl *zapLogger) {
zl.loggerLevel = l
}
}
// WithFile 日志文件名: name.logger
func WithFile(f string) LogOption {
return func(zl *zapLogger) {
zl.loggerFile = f
}
}
// WithWarnFile 警告日志文件名: name_warn.logger
func WithWarnFile(f string) LogOption {
return func(zl *zapLogger) {
zl.loggerWarnFile = f
}
}
// WithErrorFile 错误日志名: name_error.logger
func WithErrorFile(f string) LogOption {
return func(zl *zapLogger) {
zl.loggerErrorFile = f
}
}
// WithFormatText 日志输出格式, json, plaintext
func WithFormatText(b bool) LogOption {
return func(zl *zapLogger) {
zl.logFormatText = b
}
}
// WithRollingPolicy 日志切割方式, daily: 每24小时切割; hourly: 每小时切割
func WithRollingPolicy(r string) LogOption {
return func(zl *zapLogger) {
zl.logRollingPolicy = r
}
}
// WithRotateDate 日志转存时间
func WithRotateDate(d int) LogOption {
return func(zl *zapLogger) {
zl.logRotateDate = d
}
}
// WithRotateSize 日志转存大小
func WithRotateSize(s int) LogOption {
return func(zl *zapLogger) {
zl.logRotateSize = s
}
}
// WithBackUpCount 日志数量达到一定量后进行压缩备份
func WithBackUpCount(n uint) LogOption {
return func(zl *zapLogger) {
zl.logBackupCount = n
}
}

226
logs/log_zap.go Normal file
View File

@@ -0,0 +1,226 @@
package logs
import (
"io"
"os"
"strings"
"time"
"github.com/pyihe/go-pkg/nets"
rotatelogs "github.com/lestrrat-go/file-rotatelogs"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)
const (
// writerStdOut 标准输出流
writerStdOut = "stdout"
// writerFile 文件输出流
writerFile = "file"
)
const (
// RotateTimeDaily 默认按天切割
RotateTimeDaily = "daily"
// RotateTimeHourly 按小时切割
RotateTimeHourly = "hourly"
)
type zapLogger struct {
name string // 日志对应的应用名
writers string // 日志输出流
loggerLevel string // 日志级别
loggerFile string // 日志文件
loggerWarnFile string // 警告日志文件
loggerErrorFile string // 错误日志文件
logFormatText bool // 日志输出格式
logRollingPolicy string // 日志文件切割策略
logRotateDate int // 日志文件转存时间
logRotateSize int // 日志转存大小
logBackupCount uint // 日志文件达到多少个时进行压缩备份
sugaredLogger *zap.SugaredLogger
}
func newZapLogger(opts ...LogOption) (Logger, error) {
var (
zlogger = &zapLogger{}
cores []zapcore.Core
options []zap.Option
)
for _, opt := range opts {
opt(zlogger)
}
encoder := getJSONEncoder()
op := zap.Fields(zap.String("ip", nets.GetLocalIP()), zap.String("app", zlogger.name))
options = append(options, op)
allLevel := zap.LevelEnablerFunc(func(lv zapcore.Level) bool {
return lv <= zapcore.FatalLevel
})
writers := strings.Split(zlogger.writers, ",")
for _, w := range writers {
if w == writerStdOut {
c := zapcore.NewCore(encoder, zapcore.AddSync(os.Stdout), zapcore.DebugLevel)
cores = append(cores, c)
}
if w == writerFile {
infoWriter := zlogger.getLogWriterWithTime(zapcore.InfoLevel)
warnWriter := zlogger.getLogWriterWithTime(zapcore.WarnLevel)
errorWriter := zlogger.getLogWriterWithTime(zapcore.ErrorLevel)
infoLevel := zap.LevelEnablerFunc(func(lv zapcore.Level) bool {
return lv <= zapcore.InfoLevel
})
warnLevel := zap.LevelEnablerFunc(func(lv zapcore.Level) bool {
stackTrace := zap.AddStacktrace(zapcore.WarnLevel)
options = append(options, stackTrace)
return lv == zapcore.WarnLevel
})
errorLevel := zap.LevelEnablerFunc(func(lv zapcore.Level) bool {
stackTrace := zap.AddStacktrace(zapcore.ErrorLevel)
options = append(options, stackTrace)
return lv >= zapcore.ErrorLevel
})
core := zapcore.NewCore(encoder, zapcore.AddSync(infoWriter), infoLevel)
cores = append(cores, core)
core = zapcore.NewCore(encoder, zapcore.AddSync(warnWriter), warnLevel)
cores = append(cores, core)
core = zapcore.NewCore(encoder, zapcore.AddSync(errorWriter), errorLevel)
cores = append(cores, core)
}
if w != writerFile && w != writerStdOut {
core := zapcore.NewCore(encoder, zapcore.AddSync(os.Stdout), zapcore.DebugLevel)
cores = append(cores, core)
allWriter := zlogger.getLogWriterWithTime(zapcore.InfoLevel)
core = zapcore.NewCore(encoder, zapcore.AddSync(allWriter), allLevel)
cores = append(cores, core)
}
}
combinedCore := zapcore.NewTee(cores...)
// 开启开发模式, 堆栈跟踪
caller := zap.AddCaller()
options = append(options, caller)
//开启文件及行号
development := zap.Development()
options = append(options, development)
//跳过文件调用层数
addCallerSkip := zap.AddCallerSkip(2)
options = append(options, addCallerSkip)
zlogger.sugaredLogger = zap.New(combinedCore, options...).Sugar()
return zlogger, nil
}
// getJSONEncoder
func getJSONEncoder() zapcore.Encoder {
encoderConfig := zapcore.EncoderConfig{
MessageKey: "msg",
LevelKey: "level",
TimeKey: "time",
NameKey: "app",
CallerKey: "file",
StacktraceKey: "trace",
LineEnding: "",
EncodeLevel: zapcore.LowercaseLevelEncoder,
EncodeTime: zapcore.ISO8601TimeEncoder,
EncodeDuration: zapcore.MillisDurationEncoder,
EncodeCaller: zapcore.ShortCallerEncoder,
EncodeName: nil,
}
return zapcore.NewJSONEncoder(encoderConfig)
}
// getLogWriterWithTime 按时间对日志进行切割(默认24小时切割一次)
func (z *zapLogger) getLogWriterWithTime(level zapcore.Level) io.Writer {
var filename string
switch level {
case zapcore.WarnLevel:
filename = z.loggerWarnFile
case zapcore.ErrorLevel:
filename = z.loggerErrorFile
default:
filename = z.loggerFile
}
//默认24小时切割一次
rotateDuration := time.Hour * 24
if z.logRollingPolicy == RotateTimeHourly {
rotateDuration = time.Hour
}
hook, err := rotatelogs.New(
filename+".%Y%m%d%H", //保存的文件名,后缀为时间
rotatelogs.WithLinkName(filename), //生成软联,指向最新的日志文件
rotatelogs.WithRotationCount(z.logBackupCount), //日志文件最多保存多少份
rotatelogs.WithRotationTime(rotateDuration), //切割的时间间隔
)
if err != nil {
panic(err)
}
return hook
}
func (z *zapLogger) Debug(args ...interface{}) {
z.sugaredLogger.Debug(args...)
}
func (z *zapLogger) Debugf(format string, args ...interface{}) {
z.sugaredLogger.Debugf(format, args...)
}
func (z *zapLogger) Info(args ...interface{}) {
z.sugaredLogger.Info(args...)
}
func (z *zapLogger) Infof(format string, args ...interface{}) {
z.sugaredLogger.Infof(format, args...)
}
func (z *zapLogger) Warn(args ...interface{}) {
z.sugaredLogger.Warn(args...)
}
func (z *zapLogger) Warnf(format string, args ...interface{}) {
z.sugaredLogger.Warnf(format, args...)
}
func (z *zapLogger) Error(args ...interface{}) {
z.sugaredLogger.Error(args...)
}
func (z *zapLogger) Errorf(format string, args ...interface{}) {
z.sugaredLogger.Errorf(format, args...)
}
func (z *zapLogger) Fatal(args ...interface{}) {
z.sugaredLogger.Fatal(args...)
}
func (z *zapLogger) Fatalf(format string, args ...interface{}) {
z.sugaredLogger.Fatalf(format, args...)
}
func (z *zapLogger) Panicf(format string, args ...interface{}) {
z.sugaredLogger.Panicf(format, args...)
}
func (z *zapLogger) WithFields(fields Fields) Logger {
var f = make([]interface{}, 0)
for k, v := range fields {
f = append(f, k, v)
}
newLogger := z.sugaredLogger.With(f...)
return &zapLogger{sugaredLogger: newLogger}
}

99
maps/map.go Normal file
View File

@@ -0,0 +1,99 @@
package maps
import "sync"
type Map struct {
sync.RWMutex
m map[interface{}]interface{}
}
func (m *Map) init() {
if m.m == nil {
m.m = make(map[interface{}]interface{})
}
}
func (m *Map) UnsafeGet(key interface{}) interface{} {
if m.m == nil {
return nil
} else {
return m.m[key]
}
}
func (m *Map) Get(key interface{}) interface{} {
m.RLock()
defer m.RUnlock()
return m.UnsafeGet(key)
}
func (m *Map) UnsafeSet(key interface{}, value interface{}) {
m.init()
m.m[key] = value
}
func (m *Map) Set(key interface{}, value interface{}) {
m.Lock()
defer m.Unlock()
m.UnsafeSet(key, value)
}
func (m *Map) TestAndSet(key interface{}, value interface{}) interface{} {
m.Lock()
defer m.Unlock()
m.init()
if v, ok := m.m[key]; ok {
return v
} else {
m.m[key] = value
return nil
}
}
func (m *Map) UnsafeDel(key interface{}) {
m.init()
delete(m.m, key)
}
func (m *Map) Del(key interface{}) {
m.Lock()
defer m.Unlock()
m.UnsafeDel(key)
}
func (m *Map) UnsafeLen() int {
if m.m == nil {
return 0
} else {
return len(m.m)
}
}
func (m *Map) Len() int {
m.RLock()
defer m.RUnlock()
return m.UnsafeLen()
}
func (m *Map) UnsafeRange(f func(interface{}, interface{})) {
if m.m == nil {
return
}
for k, v := range m.m {
f(k, v)
}
}
func (m *Map) RLockRange(f func(interface{}, interface{})) {
m.RLock()
defer m.RUnlock()
m.UnsafeRange(f)
}
func (m *Map) LockRange(f func(interface{}, interface{})) {
m.Lock()
defer m.Unlock()
m.UnsafeRange(f)
}

64
maths/math.go Normal file
View File

@@ -0,0 +1,64 @@
package maths
func MaxInt(a, b int) int {
if a > b {
return a
}
return b
}
func MinInt(a, b int) int {
if a < b {
return a
}
return b
}
func MaxInt32(a, b int32) int32 {
if a > b {
return a
}
return b
}
func MinInt32(a, b int32) int32 {
if a < b {
return a
}
return b
}
func MaxInt64(a, b int64) int64 {
if a > b {
return a
}
return b
}
func MinInt64(a, b int64) int64 {
if a < b {
return a
}
return b
}
func AbsInt32(a int32) int32 {
if a < 0 {
return -a
}
return a
}
func AbsInt64(a int64) int64 {
if a < 0 {
return -a
}
return a
}
func Abs(n int) int {
if n < 0 {
return -n
}
return n
}

157
maths/sort.go Normal file
View File

@@ -0,0 +1,157 @@
package maths
import "sort"
type Uint8Slice []uint8
type Int8Slice []int8
type Uint16Slice []uint16
type Int16Slice []int16
type Int32Slice []int32
type Uint32Slice []uint32
type Int64Slice []int64
type Uint64Slice []uint64
type Float32Slice []float32
func SortUint8(s []uint8) {
sort.Sort(Uint8Slice(s))
}
func SortInt8(s []int8) {
sort.Sort(Int8Slice(s))
}
func SortUint16(s []uint16) {
sort.Sort(Uint16Slice(s))
}
func SortInt16(s []int16) {
sort.Sort(Int16Slice(s))
}
func SortInt32s(s []int32) {
sort.Sort(Int32Slice(s))
}
func SortUint32(s []uint32) {
sort.Sort(Uint32Slice(s))
}
func SortInt64s(s []int64) {
sort.Sort(Int64Slice(s))
}
func SortUint64(s []uint64) {
sort.Sort(Uint64Slice(s))
}
func SortFloat32s(s []float32) {
sort.Sort(Float32Slice(s))
}
func (u Uint8Slice) Len() int {
return len(u)
}
func (u Uint8Slice) Less(i, j int) bool {
return u[i] < u[j]
}
func (u Uint8Slice) Swap(i, j int) {
u[i], u[j] = u[j], u[i]
}
func (i8s Int8Slice) Len() int {
return len(i8s)
}
func (i8s Int8Slice) Less(i, j int) bool {
return i8s[i] < i8s[j]
}
func (i8s Int8Slice) Swap(i, j int) {
i8s[i], i8s[j] = i8s[j], i8s[i]
}
func (u16s Uint16Slice) Len() int {
return len(u16s)
}
func (u16s Uint16Slice) Less(i, j int) bool {
return u16s[i] < u16s[j]
}
func (u16s Uint16Slice) Swap(i, j int) {
u16s[i], u16s[j] = u16s[j], u16s[i]
}
func (i16s Int16Slice) Len() int {
return len(i16s)
}
func (i16s Int16Slice) Less(i, j int) bool {
return i16s[i] < i16s[j]
}
func (i16s Int16Slice) Swap(i, j int) {
i16s[i], i16s[j] = i16s[j], i16s[i]
}
func (i32s Int32Slice) Len() int {
return len(i32s)
}
func (i32s Int32Slice) Less(i, j int) bool {
return i32s[i] < i32s[j]
}
func (i32s Int32Slice) Swap(i, j int) {
i32s[i], i32s[j] = i32s[j], i32s[i]
}
func (u32s Uint32Slice) Len() int {
return len(u32s)
}
func (u32s Uint32Slice) Less(i, j int) bool {
return u32s[i] < u32s[j]
}
func (u32s Uint32Slice) Swap(i, j int) {
u32s[i], u32s[j] = u32s[j], u32s[i]
}
func (u64s Uint64Slice) Len() int {
return len(u64s)
}
func (u64s Uint64Slice) Less(i, j int) bool {
return u64s[i] < u64s[j]
}
func (u64s Uint64Slice) Swap(i, j int) {
u64s[i], u64s[j] = u64s[j], u64s[i]
}
func (i64s Int64Slice) Len() int {
return len(i64s)
}
func (i64s Int64Slice) Less(i, j int) bool {
return i64s[i] < i64s[j]
}
func (i64s Int64Slice) Swap(i, j int) {
i64s[i], i64s[j] = i64s[j], i64s[i]
}
func (f32s Float32Slice) Len() int {
return len(f32s)
}
func (f32s Float32Slice) Less(i, j int) bool {
return f32s[i] < f32s[j]
}
func (f32s Float32Slice) Swap(i, j int) {
f32s[i], f32s[j] = f32s[j], f32s[i]
}

45
monitor/file.go Normal file
View File

@@ -0,0 +1,45 @@
package monitor
import (
"os"
"github.com/robfig/cron/v3"
)
type myFile struct {
c *cron.Cron
id cron.EntryID
spec string //时间描述
filePath string //单个配置文件的目录
updateOn int64 //最后一次更新时间
handle func() //文件更新时需要直行的handler
}
func (m *myFile) init() {
timer := cron.New(cron.WithSeconds())
id, err := timer.AddJob(m.spec, m)
if err != nil {
panic(err)
}
m.id = id
m.c = timer
timer.Start()
}
func (m *myFile) Run() {
file, err := os.Open(m.filePath)
if err != nil {
panic(err)
}
defer file.Close()
fileInfo, err := file.Stat()
if err != nil {
panic(err)
}
modifyTime := fileInfo.ModTime().Unix()
if modifyTime > m.updateOn {
//更新
m.handle()
m.updateOn = modifyTime
}
}

64
monitor/monitor.go Normal file
View File

@@ -0,0 +1,64 @@
package monitor
import (
"errors"
"sync"
"time"
)
type (
Monitor interface {
AddFile(path string, spec string, handler func()) error
DelFile(path string) error
}
myMonitor struct {
sync.RWMutex
fs Files
}
Files map[string]*myFile
)
func (m *myMonitor) init() {
m.fs = make(map[string]*myFile)
}
func NewMonitor() Monitor {
mon := new(myMonitor)
mon.init()
return mon
}
func (m *myMonitor) AddFile(path string, spec string, handler func()) error {
m.Lock()
defer m.Unlock()
if handler == nil {
return errors.New("handler cannot be nil")
}
if _, ok := m.fs[path]; ok {
return errors.New("already exist")
}
f := &myFile{
spec: spec,
filePath: path,
updateOn: time.Now().Unix(),
handle: handler,
}
m.fs[path] = f
f.init()
return nil
}
func (m *myMonitor) DelFile(path string) error {
m.Lock()
defer m.Unlock()
f, ok := m.fs[path]
if !ok {
return nil
}
f.c.Stop()
f.c.Remove(f.id)
delete(m.fs, path)
return nil
}

125
nets/net.go Normal file
View File

@@ -0,0 +1,125 @@
package nets
import (
"net"
"strconv"
"strings"
"sync"
)
var (
once sync.Once
localIP string
)
// GetLocalIP 获取本地内网IP
func GetLocalIP() string {
once.Do(func() {
ips, _ := internetIP()
if len(ips) > 0 {
localIP = ips[0]
} else {
localIP = "127.0.0.1"
}
})
return localIP
}
// GetInternalIP 获取Internal IP
func GetInternalIP() string {
inters, err := net.Interfaces()
if err != nil {
return ""
}
for _, inter := range inters {
if inter.Flags&net.FlagUp != 0 && !strings.HasPrefix(inter.Name, "lo") {
addrs, err := inter.Addrs()
if err != nil {
continue
}
for _, addr := range addrs {
if ipnet, ok := addr.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
return ipnet.IP.String()
}
}
}
}
return ""
}
func internetIP() ([]string, error) {
var (
ips []string
err error
)
ifaces, err := net.Interfaces()
if err != nil {
return ips, err
}
for _, iface := range ifaces {
if iface.Flags&net.FlagUp == 0 {
continue
}
if iface.Flags&net.FlagLoopback != 0 {
continue
}
if strings.HasPrefix(iface.Name, "docker") || strings.HasPrefix(iface.Name, "w-") {
continue
}
addrs, err := iface.Addrs()
if err != nil {
return ips, err
}
for _, ad := range addrs {
var ip net.IP
switch t := ad.(type) {
case *net.IPNet:
ip = t.IP
case *net.IPAddr:
ip = t.IP
}
if ip == nil || ip.IsLoopback() {
continue
}
ip = ip.To4()
if ip == nil {
continue
}
ipStr := ip.String()
if isIntranet(ipStr) {
ips = append(ips, ipStr)
}
}
}
return ips, nil
}
func isIntranet(s string) bool {
if strings.HasPrefix(s, "10.") || strings.HasPrefix(s, "192.168.") {
return true
}
if strings.HasPrefix(s, "172.") {
// 172.16.0.0-172.31.255.255
arr := strings.Split(s, ".")
if len(arr) != 4 {
return false
}
second, err := strconv.ParseInt(arr[1], 10, 64)
if err != nil {
return false
}
if second >= 16 && second <= 31 {
return true
}
}
return false
}

199
queue/queue.go Normal file
View File

@@ -0,0 +1,199 @@
package queue
import (
"sync"
)
type (
Queue interface {
Len() int
UnsafeLen() int
Push(ele interface{})
Pop() interface{}
Del(i int)
UnsafeDel(i int)
Get(i int) interface{}
UnsafeGet(i int) interface{}
Set(index int, v interface{})
UnsafeSet(index int, v interface{})
Range(func(i int, v interface{}))
UnsafeRange(func(i int, v interface{}))
Index(data interface{}) (ok bool, i int)
UnsafeIndex(data interface{}) (ok bool, i int)
}
queue struct {
mu *sync.RWMutex
t ListType
count int
data []interface{}
}
ListType int
)
const (
ListTypeQueue ListType = iota + 1
ListTypeStack
)
var _ Queue = &queue{}
func NewQueue(t ListType, defaultCap int) Queue {
switch t {
case ListTypeStack:
case ListTypeQueue:
default:
panic("unknown list type")
}
q := &queue{
mu: &sync.RWMutex{},
count: 0,
t: t,
data: make([]interface{}, 0, defaultCap),
}
return q
}
func (q *queue) init() {
q.count = 0
q.data = make([]interface{}, 0)
}
func (q *queue) checkLen(i int) {
if q.count-1 < i {
panic("out of range")
}
}
func (q *queue) Len() int {
q.mu.RLock()
defer q.mu.RUnlock()
return q.count
}
func (q *queue) UnsafeLen() int {
return q.count
}
//add
func (q *queue) Push(ele interface{}) {
q.mu.Lock()
defer q.mu.Unlock()
q.count++
q.data = append(q.data, ele)
}
//get&remove
func (q *queue) Pop() interface{} {
var data interface{}
q.mu.Lock()
defer q.mu.Unlock()
if q.count == 0 {
return nil
}
switch q.t {
case ListTypeQueue:
data = q.data[0]
q.data = q.data[1:]
case ListTypeStack:
data = q.data[q.count-1]
q.data = q.data[:q.count-1]
}
q.count--
return data
}
//update
func (q *queue) Set(i int, v interface{}) {
q.mu.Lock()
defer q.mu.Unlock()
q.checkLen(i)
q.data[i] = v
}
func (q *queue) UnsafeSet(i int, v interface{}) {
q.checkLen(i)
q.data[i] = v
}
//del
func (q *queue) Del(i int) {
q.mu.Lock()
defer q.mu.Unlock()
q.checkLen(i)
q.data = append(q.data[:i], q.data[i+1:]...)
q.count--
}
func (q *queue) UnsafeDel(i int) {
q.checkLen(i)
q.data = append(q.data[:i], q.data[i+1:]...)
q.count--
}
//Get
func (q *queue) Get(i int) interface{} {
q.mu.RLock()
defer q.mu.RUnlock()
q.checkLen(i)
d := q.data[i]
return d
}
func (q *queue) UnsafeGet(i int) interface{} {
q.checkLen(i)
d := q.data[i]
return d
}
//safe range
func (q *queue) Range(f func(i int, v interface{})) {
q.mu.Lock()
defer q.mu.Unlock()
switch q.t {
case ListTypeQueue:
for i, v := range q.data {
f(i, v)
}
case ListTypeStack:
for i := q.count - 1; i >= 0; i-- {
f(i, q.data[i])
}
}
}
//unsafe range
func (q *queue) UnsafeRange(f func(i int, v interface{})) {
switch q.t {
case ListTypeQueue:
for i, v := range q.data {
f(i, v)
}
case ListTypeStack:
for i := q.count - 1; i >= 0; i-- {
f(i, q.data[i])
}
}
}
func (q *queue) Index(data interface{}) (bool, int) {
q.mu.RLock()
defer q.mu.RUnlock()
for i, v := range q.data {
if v == data {
return true, i
}
}
return false, 0
}
func (q *queue) UnsafeIndex(data interface{}) (bool, int) {
for i, v := range q.data {
if v == data {
return true, i
}
}
return false, 0
}

45
rands/rand.go Normal file
View File

@@ -0,0 +1,45 @@
package rands
import (
"math/rand"
"strings"
"time"
)
const (
letterBytes = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
letterIdxBits = 6
letterIdxMask = 1<<letterIdxBits - 1
letterIdxMax = 63 / letterIdxBits
)
func init() {
rand.Seed(time.Now().UnixNano())
}
//生成min-max之间的一个随机数
func Int(min, max int) int {
if min >= max {
panic("min bigger than max")
}
return rand.Intn(max-min+1) + min
}
//随机指定长度的字符串
func String(n uint) string {
sb := strings.Builder{}
sb.Grow(int(n))
for i, cache, remain := n-1, rand.Int63(), letterIdxMax; i >= 0; {
if remain == 0 {
cache, remain = rand.Int63(), letterIdxMax
}
if idx := int(cache & letterIdxMask); idx < len(letterBytes) {
sb.WriteByte(letterBytes[idx])
i--
}
cache >>= letterIdxBits
remain--
}
return sb.String()
}

426
redis/conn.go Normal file
View File

@@ -0,0 +1,426 @@
package redis
import (
"github.com/garyburd/redigo/redis"
"github.com/pyihe/go-pkg/encoding"
"github.com/pyihe/go-pkg/errors"
)
var (
ErrInvalidKey = errors.NewError(errors.ErrorCodeFail, "invalid key")
ErrInvalidEncoder = errors.NewError(errors.ErrorCodeFail, "not figure encoder")
ErrInvalidConn = errors.NewError(errors.ErrorCodeFail, "invalid redis conn")
ErrInvalidParamNum = errors.NewError(errors.ErrorCodeFail, "invalid param num")
)
type myRedisConn struct {
conn redis.Conn //redis连接池
encoder encoding.Encoding
prefix string
}
func (conn *myRedisConn) checkKey(key string) (string, error) {
if len(key) == 0 {
return "", ErrInvalidKey
}
key = conn.prefix + key
return key, nil
}
func (conn *myRedisConn) Close() error {
if conn.conn != nil {
return conn.conn.Close()
}
return ErrInvalidConn
}
/*****************************string操作**********************************/
//获取指定模式的key
func (conn *myRedisConn) getKeys(pattern string) (keys []string, err error) {
if pattern == "" {
pattern = conn.prefix + "*"
}
keys, err = redis.Strings(conn.conn.Do("KEYS", pattern))
return keys, err
}
//string
func (conn *myRedisConn) getString(key string) (value string, err error) {
if key, err = conn.checkKey(key); err != nil {
return "", err
}
value, err = redis.String(conn.conn.Do("GET", key))
if err != nil {
if err == redis.ErrNil {
err = nil
}
return value, err
}
return value, err
}
func (conn *myRedisConn) setString(key, value string) error {
var err error
if key, err = conn.checkKey(key); err != nil {
return err
}
_, err = redis.String(conn.conn.Do("SET", key, value))
return err
}
//[]byte
func (conn *myRedisConn) getBytes(key string) (value []byte, err error) {
if key, err = conn.checkKey(key); err != nil {
return nil, err
}
value, err = redis.Bytes(conn.conn.Do("GET", key))
if err != nil {
if err == redis.ErrNil {
err = nil
}
}
return value, err
}
//
func (conn *myRedisConn) setBytes(key string, value []byte) error {
var err error
if key, err = conn.checkKey(key); err != nil {
return err
}
_, err = redis.String(conn.conn.Do("SET", key, value))
if err != nil {
return err
}
return nil
}
//int
func (conn *myRedisConn) getInt(key string) (value int, err error) {
if key, err = conn.checkKey(key); err != nil {
return 0, err
}
value, err = redis.Int(conn.conn.Do("GET", key))
if err == redis.ErrNil {
err = nil
}
return value, err
}
func (conn *myRedisConn) getInt64(key string) (value int64, err error) {
if key, err = conn.checkKey(key); err != nil {
return 0, err
}
value, err = redis.Int64(conn.conn.Do("GET", key))
if err == redis.ErrNil {
err = nil
}
return value, err
}
func (conn *myRedisConn) setInt(key string, value int64) error {
var err error
if key, err = conn.checkKey(key); err != nil {
return err
}
_, err = redis.String(conn.conn.Do("SET", key, value))
return err
}
//struct
func (conn *myRedisConn) getStruct(key string, data interface{}) (err error) {
if key, err = conn.checkKey(key); err != nil {
return err
}
bytes, err := redis.Bytes(conn.conn.Do("GET", key))
if err == redis.ErrNil {
err = nil
return err
}
if err != nil {
return err
}
err = conn.encoder.Unmarshal(bytes, data)
if err != nil {
return err
}
return nil
}
func (conn *myRedisConn) setStruct(key string, data interface{}) error {
var err error
if key, err = conn.checkKey(key); err != nil {
return err
}
if conn.encoder == nil {
return ErrInvalidEncoder
}
bytes, err := conn.encoder.Marshal(data)
if err != nil {
return err
}
_, err = redis.String(conn.conn.Do("SET", key, bytes))
return err
}
func (conn *myRedisConn) del(key string) error {
var err error
if key, err = conn.checkKey(key); err != nil {
return err
}
_, err = redis.String(conn.conn.Do("DEL", key))
return err
}
/******************************set操作*********************************/
//往key对应的set添加元素
func (conn *myRedisConn) sAdd(key string, members ...interface{}) error {
var err error
if key, err = conn.checkKey(key); err != nil {
return err
}
_, err = conn.conn.Do("MULTI")
if err != nil {
return err
}
for _, m := range members {
_, err = conn.conn.Do("SADD", key, m)
if err != nil {
return err
}
}
_, err = conn.conn.Do("EXEC")
if err != nil {
return err
}
return nil
}
//判断元素是否为set的元素
func (conn *myRedisConn) sIsMember(key string, member interface{}) (bool, error) {
var err error
if key, err = conn.checkKey(key); err != nil {
return false, err
}
result, err := redis.Int(conn.conn.Do("SISMEMBER", key, member))
if err != nil {
if err == redis.ErrNil {
err = nil
}
return false, err
}
return result == 1, err
}
//随机从集合中获取元素
func (conn *myRedisConn) sRandMember(key string, count uint) (value []interface{}, err error) {
if key, err = conn.checkKey(key); err != nil {
return nil, err
}
value, err = redis.Values(conn.conn.Do("SRANDMEMBER", key, count))
return
}
//返回集合中的元素数量
func (conn *myRedisConn) sCARD(key string) (int, error) {
var err error
if key, err = conn.checkKey(key); err != nil {
return 0, err
}
result, err := redis.Int(conn.conn.Do("SCARD", key))
if err != nil {
if err == redis.ErrNil {
err = nil
}
}
return result, err
}
//返回集合中的所有元素
func (conn *myRedisConn) sMembers(key string) ([]interface{}, error) {
var err error
if key, err = conn.checkKey(key); err != nil {
return nil, err
}
result, err := redis.Values(conn.conn.Do("SMEMBERS", key))
if err != nil {
if err == redis.ErrNil {
err = nil
}
}
return result, err
}
/*****************************hash操作**********************************/
func (conn *myRedisConn) hSet(key, field string, value interface{}) error {
var err error
if key, err = conn.checkKey(key); err != nil {
return err
}
_, err = conn.conn.Do("HSET", key, field, value)
return err
}
//获取指定域的值
func (conn *myRedisConn) hGet(key, field string) ([]byte, error) {
var err error
if key, err = conn.checkKey(key); err != nil {
return nil, err
}
result, err := redis.Bytes(conn.conn.Do("HGET", key, field))
if err == redis.ErrNil {
err = nil
}
return result, err
}
//返回hash中所有的域
func (conn *myRedisConn) hKeys(key string) (keys []string, err error) {
if key, err = conn.checkKey(key); err != nil {
return nil, err
}
keys, err = redis.Strings(conn.conn.Do("HKEYS", key))
return keys, err
}
//返回key对应的所有域和值
func (conn *myRedisConn) hGetAll(key string) (value []interface{}, err error) {
if key, err = conn.checkKey(key); err != nil {
return nil, err
}
value, err = redis.Values(conn.conn.Do("HGETALL", key))
return value, err
}
//设置多对field-value
func (conn *myRedisConn) hMset(key string, fields ...interface{}) error {
var err error
if key, err = conn.checkKey(key); err != nil {
return err
}
if len(fields)%2 != 0 {
return ErrInvalidParamNum
}
_, err = conn.conn.Do("MULTI")
if err != nil {
return err
}
var field, value interface{}
for i, v := range fields {
if i%2 != 0 {
value = v
} else {
field = v
}
_, err = redis.String(conn.conn.Do("HMSET", key, field, value))
if err != nil {
break
}
}
_, execErr := conn.conn.Do("EXEC")
return execErr
}
//删除
func (conn *myRedisConn) hDel(key string, field string) (num int, err error) {
if key, err = conn.checkKey(key); err != nil {
return 0, err
}
num, err = redis.Int(conn.conn.Do("HDEL", key, field))
return num, err
}
/*****************************list操作**********************************/
//将value插入到list头部
func (conn *myRedisConn) lpush(key string, values ...interface{}) error {
var err error
if key, err = conn.checkKey(key); err != nil {
return err
}
if len(values) > 0 {
for _, v := range values {
_, err := redis.String(conn.conn.Do("LPUSH", key, v))
if err != nil {
return err
}
}
}
return nil
}
func (conn *myRedisConn) lpushx(key string, values ...interface{}) error {
var err error
if key, err = conn.checkKey(key); err != nil {
return err
}
if len(values) > 0 {
for _, v := range values {
_, err := redis.String(conn.conn.Do("LPUSHX", key, v))
if err != nil {
return err
}
}
}
return nil
}
func (conn *myRedisConn) rpush(key string, values ...interface{}) error {
var err error
if key, err = conn.checkKey(key); err != nil {
return err
}
if len(values) > 0 {
for _, v := range values {
_, err := redis.String(conn.conn.Do("RPUSH", key, v))
if err != nil {
return err
}
}
}
return nil
}
func (conn *myRedisConn) rpushx(key string, values ...interface{}) error {
var err error
if key, err = conn.checkKey(key); err != nil {
return err
}
if len(values) > 0 {
for _, v := range values {
_, err := redis.String(conn.conn.Do("RPUSHX", key, v))
if err != nil {
return err
}
}
}
return nil
}
//移除列表的头元素,及左边的那个元素
func (conn *myRedisConn) lpop(key string) ([]byte, error) {
var err error
if key, err = conn.checkKey(key); err != nil {
return nil, err
}
result, err := redis.Bytes(conn.conn.Do("LPOP", key))
if err == redis.ErrNil {
err = nil
}
return result, err
}
func (conn *myRedisConn) rpop(key string) ([]byte, error) {
var err error
if key, err = conn.checkKey(key); err != nil {
return nil, err
}
result, err := redis.Bytes(conn.conn.Do("RPOP", key))
if err == redis.ErrNil {
err = nil
}
return result, err
}

31
redis/hash.go Normal file
View File

@@ -0,0 +1,31 @@
package redis
func (conn *myRedisConn) HGet(key string, field string) ([]byte, error) {
value, err := conn.hGet(key, field)
return value, err
}
func (conn *myRedisConn) HSet(key string, field string, value interface{}) error {
err := conn.hSet(key, field, value)
return err
}
func (conn *myRedisConn) HGetAll(key string) ([]interface{}, error) {
result, err := conn.hGetAll(key)
return result, err
}
func (conn *myRedisConn) HKeys(key string) ([]string, error) {
keys, err := conn.hKeys(key)
return keys, err
}
func (conn *myRedisConn) HMset(key string, fieldValues ...interface{}) error {
err := conn.hMset(key, fieldValues...)
return err
}
func (conn *myRedisConn) HDel(key, field string) (int, error) {
num, err := conn.hDel(key, field)
return num, err
}

31
redis/list.go Normal file
View File

@@ -0,0 +1,31 @@
package redis
func (conn *myRedisConn) RPush(key string, values ...interface{}) error {
err := conn.rpush(key, values...)
return err
}
func (conn *myRedisConn) RPushX(key string, values ...interface{}) error {
err := conn.rpushx(key, values...)
return err
}
func (conn *myRedisConn) LPush(key string, values ...interface{}) error {
err := conn.lpush(key, values...)
return err
}
func (conn *myRedisConn) LPushX(key string, values ...interface{}) error {
err := conn.lpushx(key, values...)
return err
}
func (conn *myRedisConn) LPop(key string) (result []byte, err error) {
result, err = conn.lpop(key)
return result, err
}
func (conn *myRedisConn) RPop(key string) (result []byte, err error) {
result, err = conn.rpop(key)
return result, err
}

151
redis/pool.go Normal file
View File

@@ -0,0 +1,151 @@
package redis
import (
"fmt"
"time"
"github.com/pyihe/util/encoding"
"github.com/garyburd/redigo/redis"
)
type RedisConn interface {
Close() error
//string
GetKeys(pattern string) (keys []string, err error)
GetString(key string) (value string, err error)
SetString(key, value string) error
GetBytes(key string) (value []byte, err error)
SetBytes(key string, value []byte) error
GetInt(key string) (value int, err error)
GetInt64(key string) (value int64, err error)
SetInt(key string, value int64) error
GetStruct(key string, data interface{}) (err error)
SetStruct(key string, data interface{}) error
//hash
HGet(key string, field string) ([]byte, error)
HSet(key string, field string, value interface{}) error
HGetAll(key string) ([]interface{}, error)
HKeys(key string) ([]string, error)
HMset(key string, fieldValues ...interface{}) error
HDel(key, field string) (int, error)
//list
RPush(key string, values ...interface{}) error
RPushX(key string, values ...interface{}) error
LPush(key string, values ...interface{}) error
LPushX(key string, values ...interface{}) error
LPop(key string) (result []byte, err error)
RPop(key string) (result []byte, err error)
//set
SADD(key string, members ...interface{}) error
SIsMember(key string, member interface{}) (bool, error)
SCard(key string) (int, error)
Smembers(key string) ([]interface{}, error)
}
type RedisPool interface {
Get() (RedisConn, error)
Close() error
}
type myPool struct {
prefix string
net string
addr string
pass string
db int
p *redis.Pool
encoder encoding.Encoding
}
type InitOptions func(m *myPool)
func WithEncoding(encoder encoding.Encoding) InitOptions {
return func(m *myPool) {
m.encoder = encoder
}
}
func WithPrefix(prefix string) InitOptions {
return func(m *myPool) {
m.prefix = prefix
}
}
func WithNetWork(net string) InitOptions {
return func(m *myPool) {
m.net = net
}
}
func WithAddr(addr string) InitOptions {
return func(m *myPool) {
m.addr = addr
}
}
func WithPass(pass string) InitOptions {
return func(m *myPool) {
m.pass = pass
}
}
func WithDBIndex(db int) InitOptions {
return func(m *myPool) {
m.db = db
}
}
func NewPool(opts ...InitOptions) (RedisPool, error) {
defaultPool := &myPool{}
for _, op := range opts {
op(defaultPool)
}
if defaultPool.addr == "" {
return nil, fmt.Errorf("no redis address")
}
if defaultPool.db == 0 {
defaultPool.db = 1
}
if defaultPool.net == "" {
defaultPool.net = "tcp"
}
defaultPool.p = &redis.Pool{
Dial: func() (conn redis.Conn, e error) {
return redis.Dial(defaultPool.net, defaultPool.addr, redis.DialDatabase(defaultPool.db), redis.DialPassword(defaultPool.pass))
},
MaxIdle: 10,
MaxActive: 0,
IdleTimeout: 120 * time.Second,
Wait: true,
TestOnBorrow: func(c redis.Conn, t time.Time) error {
_, err := c.Do("PING")
return err
},
}
return defaultPool, nil
}
func (m *myPool) Get() (RedisConn, error) {
conn := m.p.Get()
if conn == nil {
return nil, fmt.Errorf("unavailable conn")
}
_, err := conn.Do("PING")
if err != nil {
return nil, err
}
c := &myRedisConn{
prefix: m.prefix,
conn: conn,
encoder: m.encoder,
}
return c, nil
}
func (m *myPool) Close() error {
return m.p.Close()
}

21
redis/set.go Normal file
View File

@@ -0,0 +1,21 @@
package redis
func (conn *myRedisConn) SADD(key string, members ...interface{}) error {
err := conn.sAdd(key, members...)
return err
}
func (conn *myRedisConn) SIsMember(key string, member interface{}) (bool, error) {
result, err := conn.sIsMember(key, member)
return result, err
}
func (conn *myRedisConn) SCard(key string) (int, error) {
count, err := conn.sCARD(key)
return count, err
}
func (conn *myRedisConn) Smembers(key string) ([]interface{}, error) {
result, err := conn.sMembers(key)
return result, err
}

48
redis/string.go Normal file
View File

@@ -0,0 +1,48 @@
package redis
func (conn *myRedisConn) GetKeys(pattern string) (keys []string, err error) {
keys, err = conn.getKeys(pattern)
return
}
func (conn *myRedisConn) GetString(key string) (value string, err error) {
return conn.getString(key)
}
func (conn *myRedisConn) SetString(key, value string) error {
return conn.setString(key, value)
}
func (conn *myRedisConn) GetBytes(key string) (value []byte, err error) {
value, err = conn.getBytes(key)
return value, err
}
func (conn *myRedisConn) SetBytes(key string, value []byte) error {
return conn.setBytes(key, value)
}
func (conn *myRedisConn) GetInt(key string) (value int, err error) {
value, err = conn.getInt(key)
return value, err
}
func (conn *myRedisConn) GetInt64(key string) (value int64, err error) {
value, err = conn.getInt64(key)
return value, err
}
func (conn *myRedisConn) SetInt(key string, value int64) error {
err := conn.setInt(key, value)
return err
}
func (conn *myRedisConn) GetStruct(key string, data interface{}) (err error) {
err = conn.getStruct(key, data)
return err
}
func (conn *myRedisConn) SetStruct(key string, data interface{}) error {
err := conn.setStruct(key, data)
return err
}

86
snowflakes/snowflake.go Normal file
View File

@@ -0,0 +1,86 @@
package snowflakes
import (
"errors"
"strconv"
"sync"
"time"
)
type Worker interface {
GetInt64() int64
GetString() string
}
//生成的64位ID的组成(从左到右编号由1至64):
//1: 1位符号位
//2-42: 41位时间戳
//43-64: 剩下22位由两部分组成: 分布式节点ID所占的位数和每个节点每毫秒内可以生成的ID数构成, 这两部分所占位数不固定, 但是总和必须等于22
const (
nodeBits uint8 = 10 // 每台机器(节点)的ID位数 10位最大可以有2^10=1024个节点
numberBits uint8 = 12 // 表示每个集群下的每个节点1毫秒内可生成的id序号的二进制位数 即每毫秒可生成 2^12-1=4096个唯一ID
nodeMax int64 = -1 ^ (-1 << nodeBits) // 节点ID的最大值用于防止溢出
numberMax int64 = -1 ^ (-1 << numberBits) // 同上用来表示生成id序号的最大值
timeShift = nodeBits + numberBits // 时间戳向左的偏移量
workerShift = numberBits // 节点ID向左的偏移量
)
type Option func(*builder) error
type builder struct {
mu sync.Mutex // 添加互斥锁 确保并发安全
epoch int64
timestamp int64 // 记录时间戳
workerId int64 // 该节点的ID
number int64 // 当前毫秒已经生成的id序列号(从0开始累加) 1毫秒内最多生成4096个ID
}
// 实例化一个工作节点
func NewWorker(opts ...Option) Worker {
b := &builder{
epoch: time.Now().Unix() * 1000,
}
for _, opt := range opts {
if err := opt(b); err != nil {
panic(err)
}
}
return b
}
func WithWorkerId(workerId int64) Option {
return func(b *builder) error {
if workerId < 0 || workerId > nodeMax {
return errors.New("work id cannot more than 1024")
}
b.workerId = workerId
return nil
}
}
func (w *builder) GetInt64() int64 {
w.mu.Lock()
defer w.mu.Unlock()
now := time.Now().UnixNano() / 1e6
if w.timestamp == now {
w.number++
if w.number > numberMax {
for now <= w.timestamp {
now = time.Now().UnixNano() / 1e6
}
}
} else {
w.number = 0
w.timestamp = now
}
return (now-w.epoch)<<timeShift | (w.workerId << workerShift) | (w.number)
}
func (w *builder) GetString() string {
return strconv.FormatInt(w.GetInt64(), 10)
}

101
sorts/sort.go Normal file
View File

@@ -0,0 +1,101 @@
package sorts
//从小到大排序
//冒泡排序,每次找出最小的值放在最前面
func BubbleSort(data []int) {
count := len(data)
if count <= 1 {
return
}
for i := 0; i < count; i++ {
for j := 0; j < count-i-1; j++ {
if data[j] > data[j+1] {
data[j], data[j+1] = data[j+1], data[j]
}
}
}
}
//快速排序
func QuickSort(data []int) []int {
count := len(data)
if count <= 0 {
return nil
}
//选择中间的数作为参考
keyIndex := count / 2
key := data[keyIndex]
//分成左右两部分左边放比key小的值右边放比key大的值
left := make([]int, 0)
right := make([]int, 0)
for i := 0; i < count; i++ {
if i == keyIndex {
continue
}
if data[i] < key {
left = append(left, data[i])
} else {
right = append(right, data[i])
}
}
left = QuickSort(left)
right = QuickSort(right)
//最后将得到的两组数组合起来
var result []int
result = append(result, left...)
result = append(result, key)
result = append(result, right...)
return result
}
//选择排序:每次选择出未排序切片里最大或者最小的数放入已排好序的数组里
func SelectSort(data []int) []int {
count := len(data)
if count <= 0 {
return nil
}
var min, minIndex int
for i := 0; i < count-1; i++ {
min = data[i]
minIndex = i
for j := i + 1; j < count; j++ {
if data[j] < min {
min = data[j]
minIndex = j
}
}
data[i], data[minIndex] = data[minIndex], data[i]
}
return data
}
/*插入排序:从第一个元素开始,该元素可以认为已经被排序,取出下一个元素,
在已经排序的元素序列中从后向前扫描如果该元素(已排序)大于新元素,
将该元素移到下一位置重复步骤3直到找到已排序的元素小于或者等于新
元素的位置将新元素插入到下一位置中重复步骤2*/
func InsertSort(data []int) {
count := len(data)
if count <= 1 {
return
}
var key, pos int
for i := 1; i < count; i++ {
key = data[i]
pos = i
//此处循环为了将比key大的数往后移动
for pos > 0 && data[pos-1] > key {
data[pos] = data[pos-1]
pos--
}
data[pos] = key
}
}

169
strings/strings.go Normal file
View File

@@ -0,0 +1,169 @@
package strings
import (
"strconv"
"strings"
"unsafe"
)
// Bytes string转换为[]byte
func Bytes(s string) []byte {
sp := *(*[2]uintptr)(unsafe.Pointer(&s))
bp := [3]uintptr{sp[0], sp[1], sp[1]}
return *(*[]byte)(unsafe.Pointer(&bp))
}
// Uint64 string转换为uint64
func Uint64(s string) (uint64, error) {
val, err := strconv.Atoi(s)
if err != nil {
return 0, err
}
return uint64(val), nil
}
// Int64 string转换为int64
func Int64(s string) (int64, error) {
val, err := strconv.Atoi(s)
if err != nil {
return 0, err
}
return int64(val), nil
}
// Int string转换为int
func Int(s string) (int, error) {
val, err := strconv.Atoi(s)
if err != nil {
return 0, err
}
return val, err
}
// Bool string转换为bool
func Bool(s string) (bool, error) {
return strconv.ParseBool(s)
}
// Float32 string转换为float32
func Float32(s string) (float32, error) {
fv, err := strconv.ParseFloat(s, 32)
if err != nil {
return 0, err
}
return float32(fv), nil
}
// Float64 string转换为float64
func Float64(s string) (float64, error) {
return strconv.ParseFloat(s, 64)
}
// IsEmpty 判断字符串本身或者去除空格后是否为空字符串
func IsEmpty(s string) bool {
if s == "" {
return true
}
s = strings.TrimSpace(s)
return s == ""
}
// SliceEqual 判断两个字符串切片值是否相等
func SliceEqual(a, b []string) bool {
aLen, bLen := len(a), len(b)
if aLen != bLen {
return false
}
if (a == nil) != (b == nil) {
return false
}
b = b[:aLen]
for i, v := range a {
if b[i] != v {
return false
}
}
return true
}
// Contain 判断字符串切片是否包含ele
func Contain(ele string, s []string) bool {
for _, v := range s {
if v == ele {
return true
}
}
return false
}
// Reverse 字符切片反转
func Reverse(s []string) {
l := len(s)
for i := l/2 - 1; i >= 0; i-- {
opp := l - i - 1
s[i], s[opp] = s[opp], s[i]
}
}
// Remove
func Remove(ele string, s []string) {
for i := range s {
if s[i] == ele {
s = append(s[:i], s[i+1:]...)
break
}
}
}
// MaxSubStrLen 寻找最长不重复子串长度
func MaxSubStrLen(str string) int {
var maxLen int
var start int
m := make(map[rune]int)
for i, ch := range []rune(str) {
if lastIndex, ok := m[ch]; ok && lastIndex >= start {
start = lastIndex + 1
}
if i-start+1 > maxLen {
maxLen = i - start + 1
}
m[ch] = i
}
return maxLen
}
// FilterRepeatBySlice 元素去重
func FilterRepeatBySlice(slc []string) []string {
var result []string
for i := range slc {
flag := true
for j := range result {
if slc[i] == result[j] {
flag = false
break
}
}
if flag {
result = append(result, slc[i])
}
}
return result
}
//通过map转换
func FilterRepeatByMap(slc []string) []string {
//result := make([]string, 0)
var result []string
tempMap := make(map[string]byte, 0)
for _, e := range slc {
l := len(tempMap)
tempMap[e] = 0
if len(tempMap) != l {
result = append(result, e)
}
}
return result
}

68
times/timer.go Normal file
View File

@@ -0,0 +1,68 @@
package times
import "time"
type Timer interface {
Remain(unit string) int32
Stop()
StopTicker()
After(t time.Duration, handler func())
Every(t time.Duration, handle func())
}
type myTimer struct {
timer *time.Timer
ticker *time.Ticker
endTime time.Time
handler func()
}
func NewTimer() Timer {
return new(myTimer)
}
func (m *myTimer) Remain(unit string) int32 {
if m.timer == nil {
return 0
}
r := m.endTime.Sub(time.Now())
switch unit {
case "H":
return int32(r.Hours())
case "M":
return int32(r.Minutes())
default:
return int32(r.Seconds())
}
}
func (m *myTimer) Stop() {
if m.timer == nil {
return
}
m.timer.Stop()
m.timer = nil
}
func (m *myTimer) StopTicker() {
if m.ticker == nil {
return
}
m.ticker.Stop()
m.ticker = nil
}
func (m *myTimer) After(t time.Duration, handler func()) {
m.endTime = time.Now().Add(t)
m.handler = handler
m.timer = time.AfterFunc(t, handler)
}
func (m *myTimer) Every(t time.Duration, handle func()) {
m.ticker = time.NewTicker(t)
go func() {
for range m.ticker.C {
handle()
}
}()
}

91
typo/typo.go Normal file
View File

@@ -0,0 +1,91 @@
package typo
func Bool(b bool) *bool {
var ptr = new(bool)
*ptr = b
return ptr
}
func String(s string) *string {
var ptr = new(string)
*ptr = s
return ptr
}
func Byte(b byte) *byte {
var ptr = new(byte)
*ptr = b
return ptr
}
func Uint8(u uint8) *uint8 {
var ptr = new(uint8)
*ptr = u
return ptr
}
func Int8(i int8) *int8 {
var ptr = new(int8)
*ptr = i
return ptr
}
func Int16(i int16) *int16 {
var ptr = new(int16)
*ptr = i
return ptr
}
func Uint16(u uint16) *uint16 {
var ptr = new(uint16)
*ptr = u
return ptr
}
func Int(i int) *int {
var ptr = new(int)
*ptr = i
return ptr
}
func Uint(u uint) *uint {
var ptr = new(uint)
*ptr = u
return ptr
}
func Int32(i int32) *int32 {
var ptr = new(int32)
*ptr = i
return ptr
}
func Uint32(u uint32) *uint32 {
var ptr = new(uint32)
*ptr = u
return ptr
}
func Int64(i int64) *int64 {
var ptr = new(int64)
*ptr = i
return ptr
}
func Uint64(u uint64) *uint64 {
var ptr = new(uint64)
*ptr = u
return ptr
}
func Float32(f float32) *float32 {
var ptr = new(float32)
*ptr = f
return ptr
}
func Float64(f float64) *float64 {
var ptr = new(float64)
*ptr = f
return ptr
}

121
utils/utils.go Normal file
View File

@@ -0,0 +1,121 @@
package utils
import (
"bytes"
"compress/gzip"
"encoding/binary"
"io/ioutil"
"os"
"os/signal"
"reflect"
"regexp"
"strconv"
"syscall"
"github.com/pyihe/go-pkg/rands"
)
var (
mailChecker = regexp.MustCompile(`^[A-Za-z0-9]+([_\.][A-Za-z0-9]+)*@([A-Za-z0-9\-]+\.)+[A-Za-z]{2,6}$`)
phoneChecker = regexp.MustCompile(`^[1](([3][0-9])|([4][5-9])|([5][0-3,5-9])|([6][5,6])|([7][0-8])|([8][0-9])|([9][1,8,9]))[0-9]{8}$`)
)
//校验邮箱格式
func CheckMailFormat(mail string) bool {
return mailChecker.MatchString(mail)
}
//校验电话号码格式
func CheckPhoneFormat(phone string) bool {
return phoneChecker.MatchString(phone)
}
//生成一个1-100的随机数, 用于简单的判断概率
func LessThanIn100(per int) bool {
if per < 1 || per > 100 {
panic("input must between 1 and 100")
}
return per >= rands.Int(1, 100)
}
//如果监听到系统中断信号则执行onNotify()
func Notify(onNotify func()) {
//SIGHUP 终端控制进程结束(终端连接断开)
//SIGQUIT 用户发送QUIT字符(Ctrl+/)触发
//SIGTERM 结束程序(可以被捕获、阻塞或忽略)
//SIGINT 用户发送INTR字符(Ctrl+C)触发
//SIGSTOP 停止进程(不能被捕获、阻塞或忽略)
ch := make(chan os.Signal, 1)
signal.Notify(ch, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGSTOP, syscall.SIGINT)
for {
s := <-ch
switch s {
case syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGSTOP, syscall.SIGINT, syscall.SIGHUP:
if onNotify == nil {
return
}
onNotify()
default:
return
}
}
}
//判断src中是否有元素ele
func Contain(src interface{}, ele interface{}) bool {
switch reflect.TypeOf(src).Kind() {
case reflect.Slice:
s := reflect.ValueOf(src)
for i := 0; i < s.Len(); i++ {
if reflect.DeepEqual(ele, s.Index(i).Interface()) {
return true
}
}
}
return false
}
//将嵌套的map[string]interface全部转换成一层
func Interface2Map(data interface{}) map[string]interface{} {
result := make(map[string]interface{})
for k, v := range data.(map[string]interface{}) {
switch v := v.(type) {
case map[string]interface{}:
for i, u := range v {
result[i] = u
}
default:
result[k] = v
}
}
return result
}
//gzip解压
func UnGZIP(content []byte) ([]byte, error) {
buffer := new(bytes.Buffer)
err := binary.Write(buffer, binary.BigEndian, content)
if err != nil {
return nil, err
}
zipReader, err := gzip.NewReader(buffer)
if err != nil {
return nil, err
}
defer zipReader.Close()
result, err := ioutil.ReadAll(zipReader)
if err != nil {
return nil, err
}
return result, nil
}
// ConvertToBinary 十进制转换为二进制字符串
func ConvertToBinary(data int) string {
result := ""
for ; data > 0; data = data / 2 {
n := data % 2
result = strconv.Itoa(n) + result
}
return result
}

49
zips/zip.go Normal file
View File

@@ -0,0 +1,49 @@
package zips
import (
"bytes"
"compress/gzip"
"io/ioutil"
)
// GzipEncode 编码
func GzipEncode(in []byte) ([]byte, error) {
var (
buffer bytes.Buffer
out []byte
err error
)
writer, err := gzip.NewWriterLevel(&buffer, gzip.BestCompression)
if err != nil {
return nil, err
}
_, err = writer.Write(in)
if err != nil {
err = writer.Close()
if err != nil {
return out, err
}
return out, err
}
err = writer.Close()
if err != nil {
return out, err
}
return buffer.Bytes(), nil
}
// GzipDecode 解码
func GzipDecode(in []byte) ([]byte, error) {
reader, err := gzip.NewReader(bytes.NewReader(in))
if err != nil {
var out []byte
return out, err
}
defer func() {
reader.Close()
}()
return ioutil.ReadAll(reader)
}