mirror of
https://github.com/pyihe/go-pkg.git
synced 2025-10-07 08:50:51 +08:00
init
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -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
|
63
README.md
63
README.md
@@ -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
57
bytes/bytes.go
Normal 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
27
certs/cert.go
Normal 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
73
clone/clone.go
Normal 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
99
encoding/encoding.go
Normal 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
38
encrypts/encrypt.go
Normal 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
73
errors/errors.go
Normal 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
16
files/file.go
Normal 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
15
go.mod
Normal 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
67
go.sum
Normal 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
71
https/http.go
Normal 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
126
https/https.go
Normal 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
217
logs/log.go
Normal 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
83
logs/log_log.go
Normal 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
92
logs/log_option.go
Normal 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
226
logs/log_zap.go
Normal 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
99
maps/map.go
Normal 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
64
maths/math.go
Normal 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
157
maths/sort.go
Normal 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
45
monitor/file.go
Normal 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
64
monitor/monitor.go
Normal 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
125
nets/net.go
Normal 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
199
queue/queue.go
Normal 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
45
rands/rand.go
Normal 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
426
redis/conn.go
Normal 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
31
redis/hash.go
Normal 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
31
redis/list.go
Normal 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
151
redis/pool.go
Normal 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
21
redis/set.go
Normal 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
48
redis/string.go
Normal 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
86
snowflakes/snowflake.go
Normal 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
101
sorts/sort.go
Normal 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
169
strings/strings.go
Normal 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
68
times/timer.go
Normal 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
91
typo/typo.go
Normal 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
121
utils/utils.go
Normal 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
49
zips/zip.go
Normal 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)
|
||||||
|
}
|
Reference in New Issue
Block a user