正在显示
49 个修改的文件
包含
3769 行增加
和
0 行删除
common/common.go
0 → 100644
1 | +package common | ||
2 | + | ||
3 | +import "fmt" | ||
4 | + | ||
5 | +// Must panics if err is not nil. | ||
6 | +func Must(err error) { | ||
7 | + if err != nil { | ||
8 | + panic(err) | ||
9 | + } | ||
10 | +} | ||
11 | + | ||
12 | +// Must2 panics if the second parameter is not nil, otherwise returns the first parameter. | ||
13 | +func Must2(v interface{}, err error) interface{} { | ||
14 | + Must(err) | ||
15 | + return v | ||
16 | +} | ||
17 | + | ||
18 | +// Error2 returns the err from the 2nd parameter. | ||
19 | +func Error2(v interface{}, err error) error { | ||
20 | + return err | ||
21 | +} | ||
22 | + | ||
23 | +func LogF(format string,args interface{})string{ | ||
24 | + return fmt.Sprintf(format,args) | ||
25 | +} |
common/jwt.go
0 → 100644
1 | +package common | ||
2 | + | ||
3 | +import ( | ||
4 | + "time" | ||
5 | + "gitlab.fjmaimaimai.com/mmm-go/gocomm/pkg/log" | ||
6 | + | ||
7 | + "github.com/dgrijalva/jwt-go" | ||
8 | +) | ||
9 | + | ||
10 | + | ||
11 | +type UserTokenClaims struct { | ||
12 | + Username string `json:"username"` | ||
13 | + Password string `json:"password"` | ||
14 | + jwt.StandardClaims | ||
15 | +} | ||
16 | + | ||
17 | +var jwtSecret = []byte("123456") | ||
18 | + | ||
19 | +//解析 UserTokenClaims | ||
20 | +func ParseJWTToken(token string) (*UserTokenClaims, error) { | ||
21 | + tokenClaims, err := jwt.ParseWithClaims(token, &UserTokenClaims{}, func(token *jwt.Token) (interface{}, error) { | ||
22 | + return jwtSecret, nil | ||
23 | + }) | ||
24 | + | ||
25 | + if tokenClaims != nil { | ||
26 | + if claim, ok := tokenClaims.Claims.(*UserTokenClaims); ok && tokenClaims.Valid { | ||
27 | + log.Info("ParseJWTToken:%s -> %v", token, claim) | ||
28 | + return claim, nil | ||
29 | + } | ||
30 | + } | ||
31 | + | ||
32 | + return nil, err | ||
33 | +} | ||
34 | + | ||
35 | +func GenerateToken(username, password string) (string, error) { | ||
36 | + now := time.Now() | ||
37 | + expireTime := now.Add(3 * time.Hour) | ||
38 | + | ||
39 | + claims := UserTokenClaims{ | ||
40 | + Username: username, | ||
41 | + Password: password, | ||
42 | + StandardClaims: jwt.StandardClaims{ | ||
43 | + ExpiresAt: expireTime.Unix(), | ||
44 | + Issuer: "jwt", | ||
45 | + }, | ||
46 | + } | ||
47 | + | ||
48 | + tokenClaims := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) | ||
49 | + token, err := tokenClaims.SignedString(jwtSecret) | ||
50 | + return token, err | ||
51 | +} |
config/config.go
0 → 100644
1 | +package config | ||
2 | + | ||
3 | +//import ( | ||
4 | +// "fmt" | ||
5 | +// "github.com/micro/go-config" | ||
6 | +// "github.com/micro/go-config/source/grpc" | ||
7 | +// "log" | ||
8 | +// "sync" | ||
9 | +//) | ||
10 | +// | ||
11 | +//var ( | ||
12 | +// once sync.Once | ||
13 | +//) | ||
14 | +// | ||
15 | +//func Init(addr, name string) { | ||
16 | +// once.Do(func() { | ||
17 | +// source := grpc.NewSource( | ||
18 | +// grpc.WithAddress(addr), | ||
19 | +// grpc.WithPath(name), | ||
20 | +// ) | ||
21 | +// | ||
22 | +// if err := config.Load(source); err != nil { | ||
23 | +// log.Fatal(err) | ||
24 | +// return | ||
25 | +// } | ||
26 | +// | ||
27 | +// go func() { | ||
28 | +// watcher, err := config.Watch() | ||
29 | +// if err != nil { | ||
30 | +// log.Fatal(err) | ||
31 | +// } | ||
32 | +// | ||
33 | +// for { | ||
34 | +// v, err := watcher.Next() | ||
35 | +// if err != nil { | ||
36 | +// log.Println(err) | ||
37 | +// continue | ||
38 | +// } | ||
39 | +// | ||
40 | +// log.Printf("[Init] file change: %v", string(v.Bytes())) | ||
41 | +// } | ||
42 | +// }() | ||
43 | +// }) | ||
44 | +//} | ||
45 | +// | ||
46 | +//func Get(conf interface{}, path ...string) (err error) { | ||
47 | +// if v := config.Get(path...); v != nil { | ||
48 | +// err = v.Scan(conf) | ||
49 | +// } else { | ||
50 | +// err = fmt.Errorf("[Get] 配置不存在, err: %v", path) | ||
51 | +// } | ||
52 | +// return | ||
53 | +//} |
config/config_test.go
0 → 100644
1 | +package config | ||
2 | + | ||
3 | +//import ( | ||
4 | +// "fmt" | ||
5 | +// "log" | ||
6 | +// "testing" | ||
7 | +//) | ||
8 | +// | ||
9 | +//func TestInit(t *testing.T){ | ||
10 | +// var ( | ||
11 | +// App App | ||
12 | +// Mysql Mysql | ||
13 | +// Redis Redis | ||
14 | +// Consul Consul | ||
15 | +// ) | ||
16 | +// Init("127.0.0.1:9600", "srv-passport") | ||
17 | +// Get(&App, "app") | ||
18 | +// Get(&Consul, "consul") | ||
19 | +// Get(&Mysql, "mysql") | ||
20 | +// Get(&Redis, "redis") | ||
21 | +// | ||
22 | +// log.Println(fmt.Sprintf("%v",App)) | ||
23 | +//} |
config/model.go
0 → 100644
1 | +package config | ||
2 | + | ||
3 | +type App struct { | ||
4 | + Name string `json:"name,omitempty"` | ||
5 | + Version string `json:"version,omitempty"` | ||
6 | + RegisterTTL int `json:"register_ttl,omitempty"` | ||
7 | + RegisterInterval int `json:"register_interval,omitempty"` | ||
8 | + MaxConcurrent int `json:"max_concurrent,omitempty"` | ||
9 | + RpsLimit int `json:"rps_limit,omitempty"` | ||
10 | + TraceAddr string `json:"trace_addr,omitempty"` | ||
11 | + BrokerAddr string `json:"broker_addr,omitempty"` | ||
12 | +} | ||
13 | + | ||
14 | +type Mysql struct { | ||
15 | + DataSource string `json:"data_source,omitempty"` | ||
16 | + MaxIdle int `json:"max_idle,omitempty"` | ||
17 | + MaxOpen int `json:"max_open,omitempty"` | ||
18 | +} | ||
19 | + | ||
20 | +type Redis struct { | ||
21 | + Addr string `json:"addr,omitempty"` | ||
22 | + Password string `json:"password,omitempty"` | ||
23 | + MaxIdle int `json:"max_idle,omitempty"` | ||
24 | +} | ||
25 | + | ||
26 | +type Hystrix struct { | ||
27 | + Timeout int `json:"timout,omitempty"` | ||
28 | + MaxConcurrentRequests int `json:"max_concurrent_requests,omitempty"` | ||
29 | + RequestVolumeThreshold int `json:"request_volume_threshold,omitempty"` | ||
30 | + SleepWindow int `json:"sleep_window,omitempty"` | ||
31 | + ErrorPercentThreshold int `json:"error_percent_threshold,omitempty"` | ||
32 | +} | ||
33 | + | ||
34 | +type Consul struct { | ||
35 | + Addrs []string `json:"addrs,omitempty"` | ||
36 | +} | ||
37 | + | ||
38 | +type Logger struct { | ||
39 | + Level string `json:"level,omitempty"` | ||
40 | + Filename string `json:"filename,omitempty"` | ||
41 | + MaxSize int `json:"max_size,omitempty"` | ||
42 | + MaxBackups int `json:"max_backups,omitempty"` | ||
43 | + MaxAge int `json:"max_age,omitempty"` | ||
44 | + Compress bool `json:"compress,omitempty"` | ||
45 | +} | ||
46 | + | ||
47 | +type Broker struct { | ||
48 | + Addrs []string `json:"addrs,omitempty"` | ||
49 | + ClusterID string `json:"cluster_id,omitempty"` | ||
50 | + DurableName string `json:"durable_name,omitempty"` | ||
51 | + Queue string `json:"queue,omitempty"` | ||
52 | +} | ||
53 | + |
config/viper.go
0 → 100644
1 | +package config | ||
2 | + | ||
3 | +import ( | ||
4 | + "fmt" | ||
5 | + "github.com/spf13/viper" | ||
6 | +) | ||
7 | + | ||
8 | +type IConfig interface { | ||
9 | + Int(k string)(int,error) | ||
10 | + Int64(k string)(int64,error) | ||
11 | + | ||
12 | + String(k string)string | ||
13 | + Strings(k string)[]string | ||
14 | + | ||
15 | + Bool(k string)(bool,error) | ||
16 | + Float(k string)(float64,error) | ||
17 | +} | ||
18 | + | ||
19 | +func assertViperImplementIconfig(){ | ||
20 | + var _ IConfig= (*ViperConfig)(nil) | ||
21 | +} | ||
22 | + | ||
23 | +type ViperConfig struct { | ||
24 | + viper *viper.Viper | ||
25 | +} | ||
26 | + | ||
27 | +func(v *ViperConfig)Int(k string)(value int,err error){ | ||
28 | + defer func(){ | ||
29 | + if p:=recover();p!=nil{ | ||
30 | + err = fmt.Errorf("%v",p) | ||
31 | + return | ||
32 | + } | ||
33 | + }() | ||
34 | + value = v.viper.GetInt(k) | ||
35 | + return | ||
36 | +} | ||
37 | +func(v *ViperConfig)Int64(k string)(value int64,err error){ | ||
38 | + defer func(){ | ||
39 | + if p:=recover();p!=nil{ | ||
40 | + err = fmt.Errorf("%v",p) | ||
41 | + return | ||
42 | + } | ||
43 | + }() | ||
44 | + value = v.viper.GetInt64(k) | ||
45 | + return 0,nil | ||
46 | +} | ||
47 | +func(v *ViperConfig)String(k string)string{ | ||
48 | + return v.viper.GetString(k) | ||
49 | +} | ||
50 | +func(v *ViperConfig)Strings(k string)[]string{ | ||
51 | + return v.viper.GetStringSlice(k) | ||
52 | +} | ||
53 | +func(v *ViperConfig)Bool(k string)(b bool,err error){ | ||
54 | + defer func(){ | ||
55 | + if p:=recover();p!=nil{ | ||
56 | + err = fmt.Errorf("%v",p) | ||
57 | + return | ||
58 | + } | ||
59 | + }() | ||
60 | + b = v.viper.GetBool(k) | ||
61 | + return | ||
62 | +} | ||
63 | +func(v *ViperConfig)Float(k string)(f float64,err error){ | ||
64 | + defer func(){ | ||
65 | + if p:=recover();p!=nil{ | ||
66 | + err = fmt.Errorf("%v",p) | ||
67 | + return | ||
68 | + } | ||
69 | + }() | ||
70 | + f = v.viper.GetFloat64(k) | ||
71 | + return | ||
72 | +} | ||
73 | + | ||
74 | + | ||
75 | +var Default IConfig | ||
76 | + | ||
77 | +func NewViperConfig(configType,configFile string)IConfig{ | ||
78 | + v := viper.New() | ||
79 | + v.SetConfigType(configType) | ||
80 | + v.SetConfigFile(configFile) | ||
81 | + v.ReadInConfig() | ||
82 | + Default = &ViperConfig{v} | ||
83 | + return Default | ||
84 | +} | ||
85 | + | ||
86 | + |
config/viper_test.go
0 → 100644
1 | +package config | ||
2 | + | ||
3 | +import ( | ||
4 | + "testing" | ||
5 | +) | ||
6 | + | ||
7 | +func Test_NewViperConfig(t *testing.T){ | ||
8 | + NewViperConfig("yaml","F:\\examples_gincomm\\conf\\app-dev.yaml") | ||
9 | + dataSource :=Default.String("redis_url") | ||
10 | + if len(dataSource)==0{ | ||
11 | + t.Fatal("error get") | ||
12 | + } | ||
13 | +} | ||
14 | + | ||
15 | +func Benchmark_NewViperConfig(b *testing.B){ | ||
16 | + NewViperConfig("yaml","F:\\examples_gincomm\\conf\\app-dev.yaml") | ||
17 | + dataSource :="" | ||
18 | + for i:=0;i<b.N;i++{ | ||
19 | + dataSource =Default.String("redis_url") | ||
20 | + if len(dataSource)==0{ | ||
21 | + b.Fatal("error get") | ||
22 | + } | ||
23 | + } | ||
24 | +} |
1 | module gitlab.fjmaimaimai.com/mmm-go/gocomm | 1 | module gitlab.fjmaimaimai.com/mmm-go/gocomm |
2 | 2 | ||
3 | go 1.13 | 3 | go 1.13 |
4 | + | ||
5 | +require ( | ||
6 | + github.com/astaxie/beego v1.10.0 | ||
7 | + | ||
8 | + github.com/dgrijalva/jwt-go v3.2.0+incompatible | ||
9 | + github.com/garyburd/redigo v1.6.0 | ||
10 | + github.com/gin-gonic/gin v1.4.0 | ||
11 | + github.com/google/go-cmp v0.2.0 | ||
12 | + github.com/gorilla/websocket v1.4.1 | ||
13 | + github.com/mattn/go-sqlite3 v1.11.0 // indirect | ||
14 | + | ||
15 | + github.com/opentracing-contrib/go-stdlib v0.0.0-20190519235532-cf7a6c988dc9 | ||
16 | + github.com/opentracing/opentracing-go v1.1.0 | ||
17 | + github.com/spf13/viper v1.4.0 | ||
18 | + github.com/uber/jaeger-client-go v2.16.0+incompatible | ||
19 | + github.com/uber/jaeger-lib v2.0.0+incompatible | ||
20 | +) | ||
21 | + | ||
22 | +replace github.com/ugorji/go v1.1.4 => github.com/ugorji/go/codec v0.0.0-20190204201341-e444a5086c43 |
go.sum
0 → 100644
1 | +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= | ||
2 | +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= | ||
3 | +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= | ||
4 | +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= | ||
5 | +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= | ||
6 | +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= | ||
7 | +github.com/astaxie/beego v1.10.0/go.mod h1:0R4++1tUqERR0WYFWdfkcrsyoVBCG4DgpDGokT3yb+U= | ||
8 | +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= | ||
9 | +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= | ||
10 | +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= | ||
11 | +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= | ||
12 | +github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= | ||
13 | +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= | ||
14 | +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= | ||
15 | +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= | ||
16 | +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= | ||
17 | +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||
18 | +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||
19 | +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= | ||
20 | +github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= | ||
21 | +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= | ||
22 | +github.com/garyburd/redigo v1.6.0/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= | ||
23 | +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= | ||
24 | +github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s= | ||
25 | +github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM= | ||
26 | +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= | ||
27 | +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= | ||
28 | +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= | ||
29 | +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= | ||
30 | +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= | ||
31 | +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= | ||
32 | +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= | ||
33 | +github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= | ||
34 | +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= | ||
35 | +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= | ||
36 | +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= | ||
37 | +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= | ||
38 | +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= | ||
39 | +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= | ||
40 | +github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= | ||
41 | +github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= | ||
42 | +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= | ||
43 | +github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= | ||
44 | +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= | ||
45 | +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= | ||
46 | +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= | ||
47 | +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= | ||
48 | +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= | ||
49 | +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= | ||
50 | +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= | ||
51 | +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= | ||
52 | +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= | ||
53 | +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= | ||
54 | +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= | ||
55 | +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= | ||
56 | +github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= | ||
57 | +github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= | ||
58 | +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= | ||
59 | +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= | ||
60 | +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= | ||
61 | +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= | ||
62 | +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= | ||
63 | +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= | ||
64 | +github.com/opentracing-contrib/go-stdlib v0.0.0-20190519235532-cf7a6c988dc9/go.mod h1:PLldrQSroqzH70Xl+1DQcGnefIbqsKR7UDaiux3zV+w= | ||
65 | +github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= | ||
66 | +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= | ||
67 | +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= | ||
68 | +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | ||
69 | +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= | ||
70 | +github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= | ||
71 | +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= | ||
72 | +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= | ||
73 | +github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= | ||
74 | +github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= | ||
75 | +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= | ||
76 | +github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= | ||
77 | +github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= | ||
78 | +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= | ||
79 | +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= | ||
80 | +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= | ||
81 | +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= | ||
82 | +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= | ||
83 | +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= | ||
84 | +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= | ||
85 | +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= | ||
86 | +github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= | ||
87 | +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | ||
88 | +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | ||
89 | +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= | ||
90 | +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= | ||
91 | +github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= | ||
92 | +github.com/uber/jaeger-client-go v2.16.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= | ||
93 | +github.com/uber/jaeger-lib v2.0.0+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U= | ||
94 | +github.com/ugorji/go v1.1.2/go.mod h1:hnLbHMwcvSihnDhEfx2/BzKp2xb0Y+ErdfYcrs9tkJQ= | ||
95 | +github.com/ugorji/go/codec v0.0.0-20190204201341-e444a5086c43/go.mod h1:iT03XoTwV7xq/+UGwKO3UbC1nNNlopQiY61beSdrtOA= | ||
96 | +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= | ||
97 | +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= | ||
98 | +go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= | ||
99 | +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= | ||
100 | +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= | ||
101 | +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= | ||
102 | +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= | ||
103 | +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= | ||
104 | +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= | ||
105 | +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= | ||
106 | +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | ||
107 | +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | ||
108 | +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | ||
109 | +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= | ||
110 | +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= | ||
111 | +golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= | ||
112 | +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= | ||
113 | +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||
114 | +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||
115 | +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||
116 | +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||
117 | +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||
118 | +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||
119 | +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||
120 | +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||
121 | +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||
122 | +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | ||
123 | +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= | ||
124 | +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= | ||
125 | +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= | ||
126 | +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= | ||
127 | +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= | ||
128 | +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= | ||
129 | +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= | ||
130 | +google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= | ||
131 | +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= | ||
132 | +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||
133 | +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||
134 | +gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= | ||
135 | +gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y= | ||
136 | +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= | ||
137 | +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= | ||
138 | +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= | ||
139 | +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= | ||
140 | +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= |
identity/idgen/idgen.go
0 → 100644
1 | +package idgen | ||
2 | + | ||
3 | +//import ( | ||
4 | +// "fmt" | ||
5 | +// "github.com/sony/sonyflake" | ||
6 | +//) | ||
7 | + | ||
8 | +// import ( | ||
9 | +// "github.com/bwmarrin/snowflake" | ||
10 | +// ) | ||
11 | + | ||
12 | +//var sf *sonyflake.Sonyflake | ||
13 | +// | ||
14 | +//func init() { | ||
15 | +// st := sonyflake.Settings{ | ||
16 | +// MachineID: getMachineId, | ||
17 | +// } | ||
18 | +// sf = sonyflake.NewSonyflake(st) | ||
19 | +//} | ||
20 | +// | ||
21 | +//func getMachineId() (uint16, error) { | ||
22 | +// // TODO | ||
23 | +// return 1, nil | ||
24 | +//} | ||
25 | +// | ||
26 | +//// Next generates next id as an uint64 | ||
27 | +//func Next() (id int64) { | ||
28 | +// var i uint64 | ||
29 | +// if sf != nil { | ||
30 | +// i, _ = sf.NextID() | ||
31 | +// id = int64(i) | ||
32 | +// } | ||
33 | +// return | ||
34 | +//} | ||
35 | +// | ||
36 | +//// NextString generates next id as a string | ||
37 | +//func NextString() (id string) { | ||
38 | +// id = fmt.Sprintf("%d", Next()) | ||
39 | +// | ||
40 | +// return | ||
41 | +//} | ||
42 | +// | ||
43 | +//func GetOne() int64 { | ||
44 | +// return Next() | ||
45 | +//} | ||
46 | +// | ||
47 | +//func GetMulti(n int) (ids []int64) { | ||
48 | +// for i := 0; i < n; i++ { | ||
49 | +// ids = append(ids, Next()) | ||
50 | +// } | ||
51 | +// return | ||
52 | +//} | ||
53 | + |
identity/uid/uuid.go
0 → 100644
1 | +// Package uuid provides implementation of Universally Unique Identifier (UUID). | ||
2 | +// Supported versions are 1, 3, 4 and 5 (as specified in RFC 4122) and | ||
3 | +// version 2 (as specified in DCE 1.1). | ||
4 | +package uid | ||
5 | + | ||
6 | +import ( | ||
7 | + "bytes" | ||
8 | + "crypto/md5" | ||
9 | + "crypto/rand" | ||
10 | + "crypto/sha1" | ||
11 | + "database/sql/driver" | ||
12 | + "encoding/binary" | ||
13 | + "encoding/hex" | ||
14 | + "fmt" | ||
15 | + "hash" | ||
16 | + "net" | ||
17 | + "os" | ||
18 | + "sync" | ||
19 | + "time" | ||
20 | +) | ||
21 | + | ||
22 | +// UUID layout variants. | ||
23 | +const ( | ||
24 | + VariantNCS = iota | ||
25 | + VariantRFC4122 | ||
26 | + VariantMicrosoft | ||
27 | + VariantFuture | ||
28 | +) | ||
29 | + | ||
30 | +// UUID DCE domains. | ||
31 | +const ( | ||
32 | + DomainPerson = iota | ||
33 | + DomainGroup | ||
34 | + DomainOrg | ||
35 | +) | ||
36 | + | ||
37 | +// Difference in 100-nanosecond intervals between | ||
38 | +// UUID epoch (October 15, 1582) and Unix epoch (January 1, 1970). | ||
39 | +const epochStart = 122192928000000000 | ||
40 | + | ||
41 | +// Used in string method conversion | ||
42 | +const dash byte = '-' | ||
43 | + | ||
44 | +// UUID v1/v2 storage. | ||
45 | +var ( | ||
46 | + storageMutex sync.Mutex | ||
47 | + storageOnce sync.Once | ||
48 | + epochFunc = unixTimeFunc | ||
49 | + clockSequence uint16 | ||
50 | + lastTime uint64 | ||
51 | + hardwareAddr [6]byte | ||
52 | + posixUID = uint32(os.Getuid()) | ||
53 | + posixGID = uint32(os.Getgid()) | ||
54 | +) | ||
55 | + | ||
56 | +// String parse helpers. | ||
57 | +var ( | ||
58 | + urnPrefix = []byte("urn:uuid:") | ||
59 | + byteGroups = []int{8, 4, 4, 4, 12} | ||
60 | +) | ||
61 | + | ||
62 | +func initClockSequence() { | ||
63 | + buf := make([]byte, 2) | ||
64 | + safeRandom(buf) | ||
65 | + clockSequence = binary.BigEndian.Uint16(buf) | ||
66 | +} | ||
67 | + | ||
68 | +func initHardwareAddr() { | ||
69 | + interfaces, err := net.Interfaces() | ||
70 | + if err == nil { | ||
71 | + for _, iface := range interfaces { | ||
72 | + if len(iface.HardwareAddr) >= 6 { | ||
73 | + copy(hardwareAddr[:], iface.HardwareAddr) | ||
74 | + return | ||
75 | + } | ||
76 | + } | ||
77 | + } | ||
78 | + | ||
79 | + // Initialize hardwareAddr randomly in case | ||
80 | + // of real network interfaces absence | ||
81 | + safeRandom(hardwareAddr[:]) | ||
82 | + | ||
83 | + // Set multicast bit as recommended in RFC 4122 | ||
84 | + hardwareAddr[0] |= 0x01 | ||
85 | +} | ||
86 | + | ||
87 | +func initStorage() { | ||
88 | + initClockSequence() | ||
89 | + initHardwareAddr() | ||
90 | +} | ||
91 | + | ||
92 | +func safeRandom(dest []byte) { | ||
93 | + if _, err := rand.Read(dest); err != nil { | ||
94 | + panic(err) | ||
95 | + } | ||
96 | +} | ||
97 | + | ||
98 | +// Returns difference in 100-nanosecond intervals between | ||
99 | +// UUID epoch (October 15, 1582) and current time. | ||
100 | +// This is default epoch calculation function. | ||
101 | +func unixTimeFunc() uint64 { | ||
102 | + return epochStart + uint64(time.Now().UnixNano()/100) | ||
103 | +} | ||
104 | + | ||
105 | +// UUID representation compliant with specification | ||
106 | +// described in RFC 4122. | ||
107 | +type UUID [16]byte | ||
108 | + | ||
109 | +// NullUUID can be used with the standard sql package to represent a | ||
110 | +// UUID value that can be NULL in the database | ||
111 | +type NullUUID struct { | ||
112 | + UUID UUID | ||
113 | + Valid bool | ||
114 | +} | ||
115 | + | ||
116 | +// The nil UUID is special form of UUID that is specified to have all | ||
117 | +// 128 bits set to zero. | ||
118 | +var Nil = UUID{} | ||
119 | + | ||
120 | +// Predefined namespace UUIDs. | ||
121 | +var ( | ||
122 | + NamespaceDNS, _ = FromString("6ba7b810-9dad-11d1-80b4-00c04fd430c8") | ||
123 | + NamespaceURL, _ = FromString("6ba7b811-9dad-11d1-80b4-00c04fd430c8") | ||
124 | + NamespaceOID, _ = FromString("6ba7b812-9dad-11d1-80b4-00c04fd430c8") | ||
125 | + NamespaceX500, _ = FromString("6ba7b814-9dad-11d1-80b4-00c04fd430c8") | ||
126 | +) | ||
127 | + | ||
128 | +// And returns result of binary AND of two UUIDs. | ||
129 | +func And(u1 UUID, u2 UUID) UUID { | ||
130 | + u := UUID{} | ||
131 | + for i := 0; i < 16; i++ { | ||
132 | + u[i] = u1[i] & u2[i] | ||
133 | + } | ||
134 | + return u | ||
135 | +} | ||
136 | + | ||
137 | +// Or returns result of binary OR of two UUIDs. | ||
138 | +func Or(u1 UUID, u2 UUID) UUID { | ||
139 | + u := UUID{} | ||
140 | + for i := 0; i < 16; i++ { | ||
141 | + u[i] = u1[i] | u2[i] | ||
142 | + } | ||
143 | + return u | ||
144 | +} | ||
145 | + | ||
146 | +// Equal returns true if u1 and u2 equals, otherwise returns false. | ||
147 | +func Equal(u1 UUID, u2 UUID) bool { | ||
148 | + return bytes.Equal(u1[:], u2[:]) | ||
149 | +} | ||
150 | + | ||
151 | +// Version returns algorithm version used to generate UUID. | ||
152 | +func (u UUID) Version() uint { | ||
153 | + return uint(u[6] >> 4) | ||
154 | +} | ||
155 | + | ||
156 | +// Variant returns UUID layout variant. | ||
157 | +func (u UUID) Variant() uint { | ||
158 | + switch { | ||
159 | + case (u[8] & 0x80) == 0x00: | ||
160 | + return VariantNCS | ||
161 | + case (u[8]&0xc0)|0x80 == 0x80: | ||
162 | + return VariantRFC4122 | ||
163 | + case (u[8]&0xe0)|0xc0 == 0xc0: | ||
164 | + return VariantMicrosoft | ||
165 | + } | ||
166 | + return VariantFuture | ||
167 | +} | ||
168 | + | ||
169 | +// Bytes returns bytes slice representation of UUID. | ||
170 | +func (u UUID) Bytes() []byte { | ||
171 | + return u[:] | ||
172 | +} | ||
173 | + | ||
174 | +// Returns canonical string representation of UUID: | ||
175 | +// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx. | ||
176 | +func (u UUID) String() string { | ||
177 | + buf := make([]byte, 36) | ||
178 | + | ||
179 | + hex.Encode(buf[0:8], u[0:4]) | ||
180 | + buf[8] = dash | ||
181 | + hex.Encode(buf[9:13], u[4:6]) | ||
182 | + buf[13] = dash | ||
183 | + hex.Encode(buf[14:18], u[6:8]) | ||
184 | + buf[18] = dash | ||
185 | + hex.Encode(buf[19:23], u[8:10]) | ||
186 | + buf[23] = dash | ||
187 | + hex.Encode(buf[24:], u[10:]) | ||
188 | + | ||
189 | + return string(buf) | ||
190 | +} | ||
191 | + | ||
192 | +//0001 时间的版本 | ||
193 | +//0010 DCE Security | ||
194 | +//0011 MD5哈希 | ||
195 | +//0100 (伪)随机数 | ||
196 | +//0101 SHA-1哈希 | ||
197 | + | ||
198 | +// SetVersion sets version bits. | ||
199 | +func (u *UUID) SetVersion(v byte) { | ||
200 | + u[6] = (u[6] & 0x0f) | (v << 4) | ||
201 | +} | ||
202 | + | ||
203 | +// SetVariant sets variant bits as described in RFC 4122. | ||
204 | +func (u *UUID) SetVariant() { | ||
205 | + u[8] = (u[8] & 0xbf) | 0x80 | ||
206 | +} | ||
207 | + | ||
208 | +// MarshalText implements the encoding.TextMarshaler interface. | ||
209 | +// The encoding is the same as returned by String. | ||
210 | +func (u UUID) MarshalText() (text []byte, err error) { | ||
211 | + text = []byte(u.String()) | ||
212 | + return | ||
213 | +} | ||
214 | + | ||
215 | +// UnmarshalText implements the encoding.TextUnmarshaler interface. | ||
216 | +// Following formats are supported: | ||
217 | +// "6ba7b810-9dad-11d1-80b4-00c04fd430c8", | ||
218 | +// "{6ba7b810-9dad-11d1-80b4-00c04fd430c8}", | ||
219 | +// "urn:uuid:6ba7b810-9dad-11d1-80b4-00c04fd430c8" | ||
220 | +func (u *UUID) UnmarshalText(text []byte) (err error) { | ||
221 | + if len(text) < 32 { | ||
222 | + err = fmt.Errorf("uuid: UUID string too short: %s", text) | ||
223 | + return | ||
224 | + } | ||
225 | + | ||
226 | + t := text[:] | ||
227 | + braced := false | ||
228 | + | ||
229 | + if bytes.Equal(t[:9], urnPrefix) { | ||
230 | + t = t[9:] | ||
231 | + } else if t[0] == '{' { | ||
232 | + braced = true | ||
233 | + t = t[1:] | ||
234 | + } | ||
235 | + | ||
236 | + b := u[:] | ||
237 | + | ||
238 | + for i, byteGroup := range byteGroups { | ||
239 | + if i > 0 && t[0] == '-' { | ||
240 | + t = t[1:] | ||
241 | + } else if i > 0 && t[0] != '-' { | ||
242 | + err = fmt.Errorf("uuid: invalid string format") | ||
243 | + return | ||
244 | + } | ||
245 | + | ||
246 | + if i == 2 { | ||
247 | + if !bytes.Contains([]byte("012345"), []byte{t[0]}) { | ||
248 | + err = fmt.Errorf("uuid: invalid version number: %v", t[0]) | ||
249 | + return | ||
250 | + } | ||
251 | + } | ||
252 | + | ||
253 | + if len(t) < byteGroup { | ||
254 | + err = fmt.Errorf("uuid: UUID string too short: %s", text) | ||
255 | + return | ||
256 | + } | ||
257 | + | ||
258 | + if i == 4 && len(t) > byteGroup && | ||
259 | + ((braced && t[byteGroup] != '}') || len(t[byteGroup:]) > 1 || !braced) { | ||
260 | + err = fmt.Errorf("uuid: UUID string too long: %s", t) | ||
261 | + return | ||
262 | + } | ||
263 | + | ||
264 | + _, err = hex.Decode(b[:byteGroup/2], t[:byteGroup]) | ||
265 | + | ||
266 | + if err != nil { | ||
267 | + return | ||
268 | + } | ||
269 | + | ||
270 | + t = t[byteGroup:] | ||
271 | + b = b[byteGroup/2:] | ||
272 | + } | ||
273 | + | ||
274 | + return | ||
275 | +} | ||
276 | + | ||
277 | +// MarshalBinary implements the encoding.BinaryMarshaler interface. | ||
278 | +func (u UUID) MarshalBinary() (data []byte, err error) { | ||
279 | + data = u.Bytes() | ||
280 | + return | ||
281 | +} | ||
282 | + | ||
283 | +// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface. | ||
284 | +// It will return error if the slice isn't 16 bytes long. | ||
285 | +func (u *UUID) UnmarshalBinary(data []byte) (err error) { | ||
286 | + if len(data) != 16 { | ||
287 | + err = fmt.Errorf("uuid: UUID must be exactly 16 bytes long, got %d bytes", len(data)) | ||
288 | + return | ||
289 | + } | ||
290 | + copy(u[:], data) | ||
291 | + | ||
292 | + return | ||
293 | +} | ||
294 | + | ||
295 | +// Value implements the driver.Valuer interface. | ||
296 | +func (u UUID) Value() (driver.Value, error) { | ||
297 | + return u.String(), nil | ||
298 | +} | ||
299 | + | ||
300 | +// Scan implements the sql.Scanner interface. | ||
301 | +// A 16-byte slice is handled by UnmarshalBinary, while | ||
302 | +// a longer byte slice or a string is handled by UnmarshalText. | ||
303 | +func (u *UUID) Scan(src interface{}) error { | ||
304 | + switch src := src.(type) { | ||
305 | + case []byte: | ||
306 | + if len(src) == 16 { | ||
307 | + return u.UnmarshalBinary(src) | ||
308 | + } | ||
309 | + return u.UnmarshalText(src) | ||
310 | + | ||
311 | + case string: | ||
312 | + return u.UnmarshalText([]byte(src)) | ||
313 | + } | ||
314 | + | ||
315 | + return fmt.Errorf("uuid: cannot convert %T to UUID", src) | ||
316 | +} | ||
317 | + | ||
318 | +// Value implements the driver.Valuer interface. | ||
319 | +func (u NullUUID) Value() (driver.Value, error) { | ||
320 | + if !u.Valid { | ||
321 | + return nil, nil | ||
322 | + } | ||
323 | + // Delegate to UUID Value function | ||
324 | + return u.UUID.Value() | ||
325 | +} | ||
326 | + | ||
327 | +// Scan implements the sql.Scanner interface. | ||
328 | +func (u *NullUUID) Scan(src interface{}) error { | ||
329 | + if src == nil { | ||
330 | + u.UUID, u.Valid = Nil, false | ||
331 | + return nil | ||
332 | + } | ||
333 | + | ||
334 | + // Delegate to UUID Scan function | ||
335 | + u.Valid = true | ||
336 | + return u.UUID.Scan(src) | ||
337 | +} | ||
338 | + | ||
339 | +// FromBytes returns UUID converted from raw byte slice input. | ||
340 | +// It will return error if the slice isn't 16 bytes long. | ||
341 | +func FromBytes(input []byte) (u UUID, err error) { | ||
342 | + err = u.UnmarshalBinary(input) | ||
343 | + return | ||
344 | +} | ||
345 | + | ||
346 | +// FromBytesOrNil returns UUID converted from raw byte slice input. | ||
347 | +// Same behavior as FromBytes, but returns a Nil UUID on error. | ||
348 | +func FromBytesOrNil(input []byte) UUID { | ||
349 | + uuid, err := FromBytes(input) | ||
350 | + if err != nil { | ||
351 | + return Nil | ||
352 | + } | ||
353 | + return uuid | ||
354 | +} | ||
355 | + | ||
356 | +// FromString returns UUID parsed from string input. | ||
357 | +// Input is expected in a form accepted by UnmarshalText. | ||
358 | +func FromString(input string) (u UUID, err error) { | ||
359 | + err = u.UnmarshalText([]byte(input)) | ||
360 | + return | ||
361 | +} | ||
362 | + | ||
363 | +// FromStringOrNil returns UUID parsed from string input. | ||
364 | +// Same behavior as FromString, but returns a Nil UUID on error. | ||
365 | +func FromStringOrNil(input string) UUID { | ||
366 | + uuid, err := FromString(input) | ||
367 | + if err != nil { | ||
368 | + return Nil | ||
369 | + } | ||
370 | + return uuid | ||
371 | +} | ||
372 | + | ||
373 | +// Returns UUID v1/v2 storage state. | ||
374 | +// Returns epoch timestamp, clock sequence, and hardware address. | ||
375 | +func getStorage() (uint64, uint16, []byte) { | ||
376 | + storageOnce.Do(initStorage) | ||
377 | + | ||
378 | + storageMutex.Lock() | ||
379 | + defer storageMutex.Unlock() | ||
380 | + | ||
381 | + timeNow := epochFunc() | ||
382 | + // Clock changed backwards since last UUID generation. | ||
383 | + // Should increase clock sequence. | ||
384 | + if timeNow <= lastTime { | ||
385 | + clockSequence++ | ||
386 | + } | ||
387 | + lastTime = timeNow | ||
388 | + | ||
389 | + return timeNow, clockSequence, hardwareAddr[:] | ||
390 | +} | ||
391 | + | ||
392 | +// NewV1 returns UUID based on current timestamp and MAC address. | ||
393 | +func NewV1() UUID { | ||
394 | + u := UUID{} | ||
395 | + | ||
396 | + timeNow, clockSeq, hardwareAddr := getStorage() | ||
397 | + | ||
398 | + binary.BigEndian.PutUint32(u[0:], uint32(timeNow)) | ||
399 | + binary.BigEndian.PutUint16(u[4:], uint16(timeNow>>32)) | ||
400 | + binary.BigEndian.PutUint16(u[6:], uint16(timeNow>>48)) | ||
401 | + binary.BigEndian.PutUint16(u[8:], clockSeq) | ||
402 | + | ||
403 | + copy(u[10:], hardwareAddr) | ||
404 | + | ||
405 | + u.SetVersion(1) | ||
406 | + u.SetVariant() | ||
407 | + | ||
408 | + return u | ||
409 | +} | ||
410 | + | ||
411 | +// NewV2 returns DCE Security UUID based on POSIX UID/GID. | ||
412 | +func NewV2(domain byte) UUID { | ||
413 | + u := UUID{} | ||
414 | + | ||
415 | + timeNow, clockSeq, hardwareAddr := getStorage() | ||
416 | + | ||
417 | + switch domain { | ||
418 | + case DomainPerson: | ||
419 | + binary.BigEndian.PutUint32(u[0:], posixUID) | ||
420 | + case DomainGroup: | ||
421 | + binary.BigEndian.PutUint32(u[0:], posixGID) | ||
422 | + } | ||
423 | + | ||
424 | + binary.BigEndian.PutUint16(u[4:], uint16(timeNow>>32)) | ||
425 | + binary.BigEndian.PutUint16(u[6:], uint16(timeNow>>48)) | ||
426 | + binary.BigEndian.PutUint16(u[8:], clockSeq) | ||
427 | + u[9] = domain | ||
428 | + | ||
429 | + copy(u[10:], hardwareAddr) | ||
430 | + | ||
431 | + u.SetVersion(2) | ||
432 | + u.SetVariant() | ||
433 | + | ||
434 | + return u | ||
435 | +} | ||
436 | + | ||
437 | +// NewV3 returns UUID based on MD5 hash of namespace UUID and name. | ||
438 | +func NewV3(ns UUID, name string) UUID { | ||
439 | + u := newFromHash(md5.New(), ns, name) | ||
440 | + u.SetVersion(3) | ||
441 | + u.SetVariant() | ||
442 | + | ||
443 | + return u | ||
444 | +} | ||
445 | + | ||
446 | +// NewV4 returns random generated UUID. | ||
447 | +func NewV4() UUID { | ||
448 | + u := UUID{} | ||
449 | + safeRandom(u[:]) | ||
450 | + u.SetVersion(4) | ||
451 | + u.SetVariant() | ||
452 | + | ||
453 | + return u | ||
454 | +} | ||
455 | + | ||
456 | +// NewV5 returns UUID based on SHA-1 hash of namespace UUID and name. | ||
457 | +func NewV5(ns UUID, name string) UUID { | ||
458 | + u := newFromHash(sha1.New(), ns, name) | ||
459 | + u.SetVersion(5) | ||
460 | + u.SetVariant() | ||
461 | + | ||
462 | + return u | ||
463 | +} | ||
464 | + | ||
465 | +// Returns UUID based on hashing of namespace UUID and name. | ||
466 | +func newFromHash(h hash.Hash, ns UUID, name string) UUID { | ||
467 | + u := UUID{} | ||
468 | + h.Write(ns[:]) | ||
469 | + h.Write([]byte(name)) | ||
470 | + copy(u[:], h.Sum(nil)) | ||
471 | + | ||
472 | + return u | ||
473 | +} |
identity/uid/uuid_test.go
0 → 100644
1 | +package uid | ||
2 | + | ||
3 | +import ( | ||
4 | + "fmt" | ||
5 | + "testing" | ||
6 | +) | ||
7 | + | ||
8 | +func TestUID(t *testing.T){ | ||
9 | + uid :=NewV1() | ||
10 | + //t.Fatal(uid) | ||
11 | + fmt.Println(uid) | ||
12 | + udata,err := uid.MarshalBinary() | ||
13 | + if err!=nil{ | ||
14 | + t.Fatal(err) | ||
15 | + } | ||
16 | + fmt.Println("MarshalBinary:",udata) | ||
17 | + fmt.Println("uuid version:",uid.Version()) | ||
18 | +} |
pkg/log/beelog.go
0 → 100644
1 | +package log | ||
2 | + | ||
3 | +import ( | ||
4 | + "github.com/astaxie/beego" | ||
5 | + "github.com/astaxie/beego/logs" | ||
6 | + "gitlab.fjmaimaimai.com/mmm-go/gocomm/config" | ||
7 | + "path/filepath" | ||
8 | + "strconv" | ||
9 | +) | ||
10 | + | ||
11 | +type beegoLog struct { | ||
12 | + log *logs.BeeLogger | ||
13 | +} | ||
14 | + | ||
15 | +func newbeelog(conf config.Logger)Log{ | ||
16 | + filename := `{"filename":"` + filepath.ToSlash(conf.Filename) + `"}` | ||
17 | + | ||
18 | + l :=&beegoLog{ | ||
19 | + log:logs.GetBeeLogger(), | ||
20 | + } | ||
21 | + l.log.SetLogger(logs.AdapterFile,filename) | ||
22 | + ilv,err :=strconv.Atoi(conf.Level) | ||
23 | + if err!=nil{ | ||
24 | + ilv = logs.LevelDebug | ||
25 | + } | ||
26 | + l.log.SetLevel(ilv) | ||
27 | + l.log.EnableFuncCallDepth(true) | ||
28 | + l.log.SetLogFuncCallDepth(6) | ||
29 | + return l | ||
30 | +} | ||
31 | + | ||
32 | +func(this *beegoLog)Debug(args ...interface{}){ | ||
33 | + //this.log.Debug(args...) | ||
34 | + beego.Debug(args...) | ||
35 | +} | ||
36 | + | ||
37 | +func(this *beegoLog)Info(args ...interface{}){ | ||
38 | + beego.Info(args...) | ||
39 | +} | ||
40 | + | ||
41 | +func(this *beegoLog)Warn(args ...interface{}){ | ||
42 | + beego.Warn(args...) | ||
43 | +} | ||
44 | + | ||
45 | +func(this *beegoLog)Error(args ...interface{}){ | ||
46 | + beego.Error(args...) | ||
47 | +} | ||
48 | + | ||
49 | +func(this *beegoLog)Panic(args ...interface{}){ | ||
50 | + beego.Error(args...) | ||
51 | +} | ||
52 | + | ||
53 | +func(this *beegoLog)Fatal(args ...interface{}){ | ||
54 | + beego.Error(args...) | ||
55 | +} |
pkg/log/ginlog.go
0 → 100644
1 | +package log | ||
2 | + | ||
3 | +import ( | ||
4 | + "fmt" | ||
5 | + "github.com/gin-gonic/gin" | ||
6 | + "gitlab.fjmaimaimai.com/mmm-go/gocomm/config" | ||
7 | + "io" | ||
8 | + "os" | ||
9 | + "strings" | ||
10 | +) | ||
11 | + | ||
12 | +func InitGinLog(conf config.Logger){ | ||
13 | + DefaultLog= newginlog(conf) | ||
14 | + | ||
15 | + formatMap = make(map[int]string,5) | ||
16 | + formatMap[1]=v1 | ||
17 | + formatMap[2]=v2 | ||
18 | + formatMap[3]=v3 | ||
19 | + formatMap[4]=v4 | ||
20 | + formatMap[5]=v5 | ||
21 | +} | ||
22 | + | ||
23 | +type ginLog struct { | ||
24 | + io.Writer | ||
25 | +} | ||
26 | + | ||
27 | +func newginlog(conf config.Logger)Log{ | ||
28 | + f, _ := os.Create(conf.Filename) | ||
29 | + gin.DefaultWriter = io.MultiWriter(f) | ||
30 | + l :=&ginLog{} | ||
31 | + return l | ||
32 | +} | ||
33 | + | ||
34 | +func(this *ginLog)Debug(args ...interface{}){ | ||
35 | + //this.log.Debug(args...) | ||
36 | + //beego.Debug(args...) | ||
37 | + fmt.Fprintf(gin.DefaultWriter,generateFmtStr(len(args)),args...) | ||
38 | +} | ||
39 | + | ||
40 | +func(this *ginLog)Info(args ...interface{}){ | ||
41 | + fmt.Fprintf(gin.DefaultWriter,generateFmtStr(len(args)),args...) | ||
42 | +} | ||
43 | + | ||
44 | +func(this *ginLog)Warn(args ...interface{}){ | ||
45 | + fmt.Fprintf(gin.DefaultWriter,generateFmtStr(len(args)),args...) | ||
46 | +} | ||
47 | + | ||
48 | +func(this *ginLog)Error(args ...interface{}){ | ||
49 | + fmt.Fprintf(gin.DefaultWriter,generateFmtStr(len(args)),args...) | ||
50 | +} | ||
51 | + | ||
52 | +func(this *ginLog)Panic(args ...interface{}){ | ||
53 | + fmt.Fprintf(gin.DefaultWriter,generateFmtStr(len(args)),args...) | ||
54 | +} | ||
55 | + | ||
56 | +func(this *ginLog)Fatal(args ...interface{}){ | ||
57 | + fmt.Fprintf(gin.DefaultWriter,generateFmtStr(len(args)),args...) | ||
58 | +} | ||
59 | + | ||
60 | +const ( | ||
61 | + v1="%v \n" | ||
62 | + v2="%v %v \n" | ||
63 | + v3="%v %v %v \n" | ||
64 | + v4="%v %v %v %v \n" | ||
65 | + v5="%v %v %v %v %v \n" | ||
66 | +) | ||
67 | +var formatMap map[int]string | ||
68 | + | ||
69 | +func generateFmtStr(n int) string { | ||
70 | + if v,ok:=formatMap[n];ok{ | ||
71 | + return v | ||
72 | + } | ||
73 | + s := strings.Repeat("%v ", n)+"\n" | ||
74 | + return s | ||
75 | +} |
pkg/log/log.go
0 → 100644
1 | +package log | ||
2 | + | ||
3 | +import "gitlab.fjmaimaimai.com/mmm-go/gocomm/config" | ||
4 | + | ||
5 | +type Log interface{ | ||
6 | + Debug(args ...interface{}) | ||
7 | + Info(args ...interface{}) | ||
8 | + Warn(args ...interface{}) | ||
9 | + Error(args ...interface{}) | ||
10 | + Panic(args ...interface{}) | ||
11 | + Fatal(args ...interface{}) | ||
12 | +} | ||
13 | + | ||
14 | +var( | ||
15 | + DefaultLog Log | ||
16 | +) | ||
17 | + | ||
18 | +func InitLog(conf config.Logger){ | ||
19 | + DefaultLog= newbeelog(conf) | ||
20 | +} | ||
21 | +func Debug(args ...interface{}){ | ||
22 | + DefaultLog.Debug(args...) | ||
23 | +} | ||
24 | +func Info(args ...interface{}){ | ||
25 | + DefaultLog.Info(args...) | ||
26 | +} | ||
27 | +func Warn(args ...interface{}){ | ||
28 | + DefaultLog.Warn(args...) | ||
29 | +} | ||
30 | +func Error(args ...interface{}){ | ||
31 | + DefaultLog.Error(args...) | ||
32 | +} | ||
33 | +func Panic(args ...interface{}){ | ||
34 | + DefaultLog.Panic(args...) | ||
35 | +} | ||
36 | +func Fatal(args ...interface{}){ | ||
37 | + DefaultLog.Fatal(args...) | ||
38 | +} |
pkg/mybeego/base.go
0 → 100644
1 | +package mybeego | ||
2 | + | ||
3 | +import ( | ||
4 | + "encoding/json" | ||
5 | + "fmt" | ||
6 | + "gitlab.fjmaimaimai.com/mmm-go/gocomm/pkg/log" | ||
7 | + "strconv" | ||
8 | + | ||
9 | + "github.com/astaxie/beego" | ||
10 | + "gitlab.fjmaimaimai.com/mmm-go/gocomm/pkg/redis" | ||
11 | + "gitlab.fjmaimaimai.com/mmm-go/gocomm/time" | ||
12 | +) | ||
13 | + | ||
14 | +// BaseController | ||
15 | +type BaseController struct { | ||
16 | + beego.Controller | ||
17 | + Query map[string]string | ||
18 | + JSONBody map[string]interface{} | ||
19 | + ByteBody []byte | ||
20 | + RequestHead *RequestHead | ||
21 | +} | ||
22 | + | ||
23 | +func assertCompleteImplement (){ | ||
24 | + var _ beego.ControllerInterface = (*BaseController)(nil) | ||
25 | +} | ||
26 | + | ||
27 | +func (this *BaseController) Options() { | ||
28 | + this.AllowCross() //允许跨域 | ||
29 | + this.Data["json"] = map[string]interface{}{"status": 200, "message": "ok", "moreinfo": ""} | ||
30 | + this.ServeJSON() | ||
31 | +} | ||
32 | + | ||
33 | +func (this *BaseController) AllowCross() { | ||
34 | + this.Ctx.ResponseWriter.Header().Set("Access-Control-Allow-Origin", "*") | ||
35 | + this.Ctx.ResponseWriter.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE") | ||
36 | + //this.Ctx.ResponseWriter.Header().Set("Access-Control-Allow-Headers", "uid, token,jwt, deviceid, appid,Content-Type,Authorization,from") | ||
37 | + this.Ctx.WriteString("") | ||
38 | + | ||
39 | +} | ||
40 | + | ||
41 | +func (this *BaseController) Prepare() { | ||
42 | + | ||
43 | + this.Ctx.ResponseWriter.Header().Set("Access-Control-Allow-Origin", "*") | ||
44 | + if this.Ctx.Input.Method() == "OPTIONS" { | ||
45 | + this.Ctx.ResponseWriter.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE") | ||
46 | + //this.Ctx.ResponseWriter.Header().Set("Access-Control-Allow-Headers", "uid, token,jwt, deviceid, appid,Content-Type,Authorization,from") | ||
47 | + this.Ctx.WriteString("") | ||
48 | + return | ||
49 | + } | ||
50 | + | ||
51 | + this.Query = map[string]string{} | ||
52 | + input := this.Input() | ||
53 | + for k := range input { | ||
54 | + this.Query[k] = input.Get(k) | ||
55 | + } | ||
56 | + if this.Ctx.Input.RequestBody != nil { | ||
57 | + // contentType := this.Ctx.Input.Header("Content-type") | ||
58 | + // if strings.HasPrefix(contentType, "application/json") { | ||
59 | + this.ByteBody = this.Ctx.Input.RequestBody[:] | ||
60 | + if len(this.ByteBody) < 1 { | ||
61 | + this.ByteBody = []byte("{}") | ||
62 | + } | ||
63 | + this.RequestHead = &RequestHead{} | ||
64 | + this.RequestHead.Token = this.Ctx.Input.Header("token") | ||
65 | + this.RequestHead.Version = this.Ctx.Input.Header("version") | ||
66 | + this.RequestHead.Os = this.Ctx.Input.Header("os") | ||
67 | + this.RequestHead.From = this.Ctx.Input.Header("from") | ||
68 | + this.RequestHead.Screen = this.Ctx.Input.Header("screen") | ||
69 | + this.RequestHead.Model = this.Ctx.Input.Header("model") | ||
70 | + this.RequestHead.Channel = this.Ctx.Input.Header("channel") | ||
71 | + this.RequestHead.Net = this.Ctx.Input.Header("net") | ||
72 | + this.RequestHead.DeviceId = this.Ctx.Input.Header("deviceid") | ||
73 | + this.RequestHead.Uid, _ = strconv.ParseInt(this.Ctx.Input.Header("uid"), 10, 64) | ||
74 | + this.RequestHead.AppId, _ = strconv.Atoi(this.Ctx.Input.Header("appid")) | ||
75 | + this.RequestHead.LoginIp = this.Ctx.Input.IP() | ||
76 | + this.RequestHead.Jwt = this.Ctx.Input.Header("jwt") | ||
77 | + this.RequestHead.SetRequestId(fmt.Sprintf("%v.%v.%s",this.RequestHead.Uid,time.GetTimeByYyyymmddhhmmss(),this.Ctx.Request.URL)) | ||
78 | + log.Info(fmt.Sprintf("====>Recv data from uid(%d) client:\nHeadData: %s\nRequestId:%s BodyData: %s", this.RequestHead.Uid, this.Ctx.Request.Header,this.RequestHead.GetRequestId(), string(this.ByteBody))) | ||
79 | + } | ||
80 | + key := SWITCH_INFO_KEY | ||
81 | + str := "" | ||
82 | + switchInfo := &TotalSwitchStr{} | ||
83 | + if str,_ = redis.Get(key); str == "" { | ||
84 | + switchInfo.TotalSwitch = TOTAL_SWITCH_ON | ||
85 | + switchInfo.MessageBody = "正常运行" | ||
86 | + redis.Set(key, switchInfo, redis.INFINITE) | ||
87 | + } else { | ||
88 | + json.Unmarshal([]byte(str), switchInfo) | ||
89 | + } | ||
90 | + if switchInfo.TotalSwitch == TOTAL_SWITCH_OFF { | ||
91 | + var msg *Message | ||
92 | + msg = NewMessage(3) | ||
93 | + msg.Errmsg = switchInfo.MessageBody | ||
94 | + log.Info(msg.Errmsg) | ||
95 | + this.Data["json"] = msg | ||
96 | + this.ServeJSON() | ||
97 | + return | ||
98 | + } | ||
99 | +} | ||
100 | + | ||
101 | +func (this *BaseController) Resp(msg *Message) { | ||
102 | + | ||
103 | + this.Data["json"] = msg | ||
104 | + this.ServeJSON() | ||
105 | +} | ||
106 | + | ||
107 | +func (this *BaseController) Finish() { | ||
108 | + | ||
109 | + if this.Ctx.Input.Method() == "OPTIONS" { | ||
110 | + return | ||
111 | + } | ||
112 | + | ||
113 | + strByte, _ := json.Marshal(this.Data["json"]) | ||
114 | + length := len(strByte) | ||
115 | + if length > 5000 { | ||
116 | + log.Info(fmt.Sprintf("<====Send to uid(%d) client: %d byte\nRequestId:%s RspBodyData: %s......", this.RequestHead.Uid, length,this.RequestHead.GetRequestId(), string(strByte[:5000]))) | ||
117 | + } else { | ||
118 | + log.Info(fmt.Sprintf("<====Send to uid(%d) client: %d byte\nRequestId:%s RspBodyData: %s", this.RequestHead.Uid, length,this.RequestHead.GetRequestId(), string(strByte))) | ||
119 | + } | ||
120 | +} | ||
121 | + | ||
122 | +// BaseControllerCallBack | ||
123 | +type BaseControllerCallBack struct { | ||
124 | + beego.Controller | ||
125 | + Query map[string]string | ||
126 | + JSONBody map[string]interface{} | ||
127 | + ByteBody []byte | ||
128 | +} | ||
129 | + | ||
130 | +func (this *BaseControllerCallBack) Prepare() { | ||
131 | + this.Query = map[string]string{} | ||
132 | + input := this.Input() | ||
133 | + for k := range input { | ||
134 | + this.Query[k] = input.Get(k) | ||
135 | + } | ||
136 | + | ||
137 | + if this.Ctx.Input.RequestBody != nil { | ||
138 | + log.Info("RecvHead:", string(this.Ctx.Input.Header("Authorization"))) | ||
139 | + this.ByteBody = this.Ctx.Input.RequestBody | ||
140 | + } | ||
141 | +} | ||
142 | + | ||
143 | +func (this *BaseControllerCallBack) Resp(msg *Message) { | ||
144 | + this.Data["json"] = msg | ||
145 | + this.ServeJSON() | ||
146 | +} | ||
147 | + | ||
148 | +func (this *BaseControllerCallBack) Finish() { | ||
149 | + strByte, _ := json.Marshal(this.Data["json"]) | ||
150 | + log.Debug("<====Send to client:\n", string(strByte)) | ||
151 | +} |
pkg/mybeego/protocol.go
0 → 100644
1 | +package mybeego | ||
2 | + | ||
3 | +import ( | ||
4 | + "fmt" | ||
5 | + "github.com/astaxie/beego" | ||
6 | + "time" | ||
7 | +) | ||
8 | + | ||
9 | +const ( | ||
10 | + TOTAL_SWITCH_ON int = 0 // 通行 | ||
11 | + TOTAL_SWITCH_OFF int = 1 // 关闭,系统停止受理 | ||
12 | + SWITCH_INFO_KEY string ="switch_info" | ||
13 | +) | ||
14 | + | ||
15 | +type Message struct { | ||
16 | + Errno int `json:"errno"` | ||
17 | + Errmsg string `json:"errmsg"` | ||
18 | + SysTime int64 `json:"sys_time"` | ||
19 | + Data interface{} `json:"data"` | ||
20 | +} | ||
21 | + | ||
22 | +var ErrnoMsg map[int]string | ||
23 | +//var MessageMap map[int]*Message | ||
24 | + | ||
25 | +func NewMessage(code int) *Message { | ||
26 | + return &Message{ | ||
27 | + Errno: code, | ||
28 | + Errmsg: ErrnoMsg[code], | ||
29 | + SysTime: time.Now().Unix(), | ||
30 | + } | ||
31 | +} | ||
32 | + | ||
33 | +func NewErrMessage(code int, errMsg ...interface{}) *Message { | ||
34 | + defer func() { | ||
35 | + if p := recover(); p != nil { | ||
36 | + beego.Error(p) | ||
37 | + } | ||
38 | + }() | ||
39 | + msg := NewMessage(code) | ||
40 | + if len(errMsg) > 1 { | ||
41 | + msg.Data = fmt.Sprintf(errMsg[0].(string), errMsg[1:]...) | ||
42 | + } else if len(errMsg) == 1 { | ||
43 | + msg.Data = errMsg[0].(string) | ||
44 | + } else { | ||
45 | + msg.Data = nil | ||
46 | + } | ||
47 | + return msg | ||
48 | +} | ||
49 | + | ||
50 | +func init() { | ||
51 | + // 注:错误码9999消息文本可自定义 | ||
52 | + ErrnoMsg = make(map[int]string) | ||
53 | + ErrnoMsg[0] = "成功" | ||
54 | + | ||
55 | + ErrnoMsg[1] = "系统错误" | ||
56 | + ErrnoMsg[2] = "参数错误" | ||
57 | + ErrnoMsg[3] = "系统升级中" | ||
58 | + ErrnoMsg[4] = "您目前使用的版本过低,无法显示最新的相关内容,请使用响单单APP最新版本。" | ||
59 | + ErrnoMsg[5] = "描述包含敏感词,请重新编辑" | ||
60 | + ErrnoMsg[6] ="重复提交,请稍后再试" | ||
61 | + } |
pkg/mybeego/request.go
0 → 100644
1 | +package mybeego | ||
2 | + | ||
3 | +import ( | ||
4 | + "fmt" | ||
5 | + "sync/atomic" | ||
6 | +) | ||
7 | + | ||
8 | +type RequestHead struct { | ||
9 | + Token string // 登录令牌 | ||
10 | + Uid int64 // 用户id | ||
11 | + AppId int // APP唯一标志 | ||
12 | + Version string // 客户端版本 | ||
13 | + Os string // 手机系统版本 | ||
14 | + From string // 请求来源 | ||
15 | + Screen string // 屏幕尺寸 | ||
16 | + Model string // 机型信息 | ||
17 | + Channel string // 渠道信息 | ||
18 | + Net string // 当前网络状态 | ||
19 | + DeviceId string // 设备Id | ||
20 | + LoginIp string // 登录IP | ||
21 | + Jwt string // jwt | ||
22 | + | ||
23 | + requestId string //请求编号 md5 | ||
24 | + reqIndex int64 //请求链序号 | ||
25 | + //lastOpTime int64 //保存上一次操作请求时间戳,暂时未使用(计算链路耗时) | ||
26 | +} | ||
27 | +func (reqHead *RequestHead)SetRequestId(addString ...string){ | ||
28 | + if (len(addString)==0){ | ||
29 | + return | ||
30 | + } | ||
31 | + reqHead.requestId = addString[0] | ||
32 | +} | ||
33 | +func(reqHead *RequestHead)GetRequestId()string{ | ||
34 | + atomic.AddInt64(&reqHead.reqIndex,1) | ||
35 | + return fmt.Sprintf("%s.%d",reqHead.requestId,reqHead.reqIndex) | ||
36 | +} | ||
37 | + | ||
38 | + | ||
39 | +type TotalSwitchStr struct { | ||
40 | + TotalSwitch int `json:"total_switch"` // 总开关:0-on; 1-off | ||
41 | + MessageBody string `json:"message_body"` // 消息提示信息 | ||
42 | +} |
pkg/mybeego/sql.go
0 → 100644
1 | +package mybeego | ||
2 | + | ||
3 | +import ( | ||
4 | + "bytes" | ||
5 | + "fmt" | ||
6 | + "github.com/astaxie/beego/orm" | ||
7 | + "strings" | ||
8 | +) | ||
9 | + | ||
10 | +type SqlExcutor struct { | ||
11 | + table string | ||
12 | + wherestr []string | ||
13 | + orderstr []string | ||
14 | + islimit bool | ||
15 | + offset int | ||
16 | + pagenum int | ||
17 | +} | ||
18 | + | ||
19 | +func NewSqlExutor()*SqlExcutor{ | ||
20 | + return &SqlExcutor{} | ||
21 | +} | ||
22 | + | ||
23 | +func(s *SqlExcutor)Table(str string)*SqlExcutor{ | ||
24 | + s.table = str | ||
25 | + return s | ||
26 | +} | ||
27 | + | ||
28 | +func(s *SqlExcutor)Where(condition ...string)*SqlExcutor{ | ||
29 | + if len(condition)<=0{ | ||
30 | + return s | ||
31 | + } | ||
32 | + s.wherestr = append(s.wherestr,condition...) | ||
33 | + return s | ||
34 | +} | ||
35 | + | ||
36 | +func(s *SqlExcutor)Order(condition ...string)*SqlExcutor{ | ||
37 | + if len(condition)<=0{ | ||
38 | + return s | ||
39 | + } | ||
40 | + s.orderstr = append(s.orderstr,condition...) | ||
41 | + return s | ||
42 | +} | ||
43 | + | ||
44 | +func(s *SqlExcutor)Limit(page,pagenum int)*SqlExcutor{ | ||
45 | + offset :=0 | ||
46 | + if page>0{ | ||
47 | + offset = (page-1)*pagenum | ||
48 | + } | ||
49 | + s.islimit =true | ||
50 | + s.offset = offset | ||
51 | + s.pagenum = pagenum | ||
52 | + return s | ||
53 | +} | ||
54 | + | ||
55 | +func(s *SqlExcutor)Strings()( string, string, error){ | ||
56 | + sqlRow :=bytes.NewBufferString(" select * ") | ||
57 | + sqlCount :=bytes.NewBufferString("select count(0) ") | ||
58 | + sql :=bytes.NewBufferString("") | ||
59 | + if len(s.table)<0{ | ||
60 | + err := fmt.Errorf("table name is empty") | ||
61 | + return "","",err | ||
62 | + } | ||
63 | + sql.WriteString(fmt.Sprintf(" from %v",s.table)) | ||
64 | + if len(s.wherestr)>0{ | ||
65 | + sql.WriteString(" where ") | ||
66 | + for i:=range s.wherestr{ | ||
67 | + if i!=0{ | ||
68 | + sql.WriteString( " AND ") | ||
69 | + } | ||
70 | + sql.WriteString(s.wherestr[i]) | ||
71 | + } | ||
72 | + } | ||
73 | + if len(s.orderstr)>0{ | ||
74 | + sql.WriteString("\n order by ") | ||
75 | + sql.WriteString(strings.Join(s.orderstr,",")) | ||
76 | + } | ||
77 | + sqlCount.WriteString(sql.String()) | ||
78 | + if s.islimit{ | ||
79 | + sql.WriteString(fmt.Sprintf("\n limit %v,%v",s.offset,s.pagenum)) | ||
80 | + } | ||
81 | + sqlRow.WriteString(sql.String()) | ||
82 | + return sqlRow.String(),sqlCount.String(),nil | ||
83 | +} | ||
84 | + | ||
85 | +func(s *SqlExcutor)Querys(v interface{})(total int,err error){ | ||
86 | + o :=orm.NewOrm() | ||
87 | + var sqlRow,sqlCount string | ||
88 | + if sr,sc,e :=s.Strings();e!=nil{ | ||
89 | + err =e | ||
90 | + return | ||
91 | + }else{ | ||
92 | + sqlRow = sr | ||
93 | + sqlCount = sc | ||
94 | + } | ||
95 | + if err=o.Raw(sqlCount).QueryRow(&total);err!=nil{ | ||
96 | + return | ||
97 | + } | ||
98 | + if _,err=o.Raw(sqlRow).QueryRows(v);err!=nil{ | ||
99 | + return | ||
100 | + } | ||
101 | + return | ||
102 | +} |
pkg/mygin/base.go
0 → 100644
1 | +package mygin | ||
2 | + | ||
3 | +import ( | ||
4 | + "github.com/gin-gonic/gin" | ||
5 | + "net/http" | ||
6 | + "strconv" | ||
7 | + "time" | ||
8 | + | ||
9 | + "gitlab.fjmaimaimai.com/mmm-go/gocomm/common" | ||
10 | +) | ||
11 | + | ||
12 | +type BaseController struct { | ||
13 | + | ||
14 | +} | ||
15 | + | ||
16 | +func(this *BaseController)JWTMiddleware()gin.HandlerFunc{ | ||
17 | + return func(c *gin.Context){ | ||
18 | + token := c.GetHeader("token") | ||
19 | + code := http.StatusOK | ||
20 | + if token == "" { | ||
21 | + code = http.StatusUnauthorized | ||
22 | + } else { | ||
23 | + claims, err := common.ParseJWTToken(token) | ||
24 | + if err != nil { | ||
25 | + code = http.StatusUnauthorized | ||
26 | + } else if time.Now().Unix() > claims.ExpiresAt { | ||
27 | + code = http.StatusUnauthorized | ||
28 | + } | ||
29 | + } | ||
30 | + if code != http.StatusOK { | ||
31 | + this.Resp(c,NewMessage(1).SetHttpCode(code)) | ||
32 | + return | ||
33 | + } | ||
34 | + c.Next() | ||
35 | + } | ||
36 | +} | ||
37 | + | ||
38 | +//group.Use(Prepare) | ||
39 | +func(this *BaseController)Prepare(c *gin.Context){ | ||
40 | + this.Secure(c) | ||
41 | + this.NoCache(c) | ||
42 | +} | ||
43 | + | ||
44 | +// NoCache is a middleware function that appends headers | ||
45 | +// to prevent the client from caching the HTTP response. | ||
46 | +func (this *BaseController)NoCache(c *gin.Context) { | ||
47 | + c.Header("Cache-Control", "no-cache, no-store, max-age=0, must-revalidate, value") | ||
48 | + c.Header("Expires", "Thu, 01 Jan 1970 00:00:00 GMT") | ||
49 | + c.Header("Last-Modified", time.Now().UTC().Format(http.TimeFormat)) | ||
50 | + c.Next() | ||
51 | +} | ||
52 | + | ||
53 | +// Secure is a middleware function that appends security | ||
54 | +// and resource access headers. | ||
55 | +func (this *BaseController)Secure(c *gin.Context) { | ||
56 | + c.Header("Access-Control-Allow-Origin", "*") | ||
57 | + c.Header("X-Frame-Options", "DENY") | ||
58 | + c.Header("X-Content-Type-Options", "nosniff") | ||
59 | + c.Header("X-XSS-Protection", "1; mode=block") | ||
60 | + c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE") | ||
61 | + c.Header("Access-Control-Allow-Headers", "uid, token,jwt, deviceid, appid,Content-Type,Authorization,from") | ||
62 | + if c.Request.TLS != nil { | ||
63 | + c.Header("Strict-Transport-Security", "max-age=31536000") | ||
64 | + } | ||
65 | + | ||
66 | + // Also consider adding Content-Security-Policy headers | ||
67 | + // c.Header("Content-Security-Policy", "script-src 'self' https://cdnjs.cloudflare.com") | ||
68 | +} | ||
69 | + | ||
70 | +func(this *BaseController)GetRequestHead(c *gin.Context)*RequestHead{ | ||
71 | + requestHead := &RequestHead{} | ||
72 | + requestHead.Token = c.Query("token") | ||
73 | + requestHead.Version = c.Query("version") | ||
74 | + requestHead.Os = c.Query("os") | ||
75 | + requestHead.From = c.Query("from") | ||
76 | + requestHead.Screen = c.Query("screen") | ||
77 | + requestHead.Model = c.Query("model") | ||
78 | + requestHead.Channel = c.Query("channel") | ||
79 | + requestHead.Net = c.Query("net") | ||
80 | + requestHead.DeviceId = c.Query("deviceid") | ||
81 | + requestHead.Uid, _ = strconv.ParseInt(c.Query("uid"), 10, 64) | ||
82 | + requestHead.AppId, _ = strconv.Atoi(c.Query("appid")) | ||
83 | + requestHead.LoginIp = c.ClientIP() | ||
84 | + requestHead.Jwt = c.Query("jwt") | ||
85 | + return requestHead | ||
86 | +} | ||
87 | + | ||
88 | + | ||
89 | +func(this *BaseController)Resp(c *gin.Context,rsp *Message){ | ||
90 | + c.JSON(rsp.HttpCode,rsp) | ||
91 | + c.Abort() | ||
92 | +} |
pkg/mygin/base_test.go
0 → 100644
1 | +package mygin | ||
2 | + | ||
3 | +import ( | ||
4 | + "github.com/gin-gonic/gin" | ||
5 | + "testing" | ||
6 | +) | ||
7 | + | ||
8 | +func Test_Server(t *testing.T){ | ||
9 | + r := gin.Default() | ||
10 | + r.GET("/ping", (&PingController{}).Ping) | ||
11 | + r.Run(":8081") | ||
12 | +} | ||
13 | + | ||
14 | +type PingController struct { | ||
15 | + *BaseGinController | ||
16 | +} | ||
17 | + | ||
18 | +func(this *PingController)Ping(c *gin.Context) { | ||
19 | + c.String(200, "pong") | ||
20 | +} |
pkg/mygin/protocol.go
0 → 100644
1 | +package mygin | ||
2 | + | ||
3 | +import ( | ||
4 | + "fmt" | ||
5 | + "github.com/astaxie/beego" | ||
6 | + "net/http" | ||
7 | + "time" | ||
8 | +) | ||
9 | + | ||
10 | +const ( | ||
11 | + TOTAL_SWITCH_ON int = 0 // 通行 | ||
12 | + TOTAL_SWITCH_OFF int = 1 // 关闭,系统停止受理 | ||
13 | + SWITCH_INFO_KEY string ="switch_info" | ||
14 | +) | ||
15 | + | ||
16 | +type Message struct { | ||
17 | + HttpCode int `json:"-"` | ||
18 | + Errno int `json:"errno"` | ||
19 | + Errmsg string `json:"errmsg"` | ||
20 | + SysTime int64 `json:"sys_time"` | ||
21 | + Data interface{} `json:"data"` | ||
22 | +} | ||
23 | + | ||
24 | +var ErrnoMsg map[int]string | ||
25 | +//var MessageMap map[int]*Message | ||
26 | + | ||
27 | +func NewMessage(code int) *Message { | ||
28 | + return &Message{ | ||
29 | + HttpCode:http.StatusOK, | ||
30 | + Errno: code, | ||
31 | + Errmsg: ErrnoMsg[code], | ||
32 | + SysTime: time.Now().Unix(), | ||
33 | + } | ||
34 | +} | ||
35 | + | ||
36 | +func NewErrMessage(code int, errMsg ...interface{}) *Message { | ||
37 | + defer func() { | ||
38 | + if p := recover(); p != nil { | ||
39 | + beego.Error(p) | ||
40 | + } | ||
41 | + }() | ||
42 | + msg := NewMessage(code) | ||
43 | + if len(errMsg) > 1 { | ||
44 | + msg.Data = fmt.Sprintf(errMsg[0].(string), errMsg[1:]...) | ||
45 | + } else if len(errMsg) == 1 { | ||
46 | + msg.Data = errMsg[0].(string) | ||
47 | + } else { | ||
48 | + msg.Data = nil | ||
49 | + } | ||
50 | + return msg | ||
51 | +} | ||
52 | + | ||
53 | +func(m *Message)SetHttpCode(code int)*Message{ | ||
54 | + m.HttpCode = code | ||
55 | + return m | ||
56 | +} | ||
57 | + | ||
58 | +func init() { | ||
59 | + // 注:错误码9999消息文本可自定义 | ||
60 | + ErrnoMsg = make(map[int]string) | ||
61 | + ErrnoMsg[0] = "成功" | ||
62 | + | ||
63 | + ErrnoMsg[1] = "系统错误" | ||
64 | + ErrnoMsg[2] = "参数错误" | ||
65 | + ErrnoMsg[3] = "系统升级中" | ||
66 | + ErrnoMsg[4] = "您目前使用的版本过低,无法显示最新的相关内容,请使用响单单APP最新版本。" | ||
67 | + ErrnoMsg[5] = "描述包含敏感词,请重新编辑" | ||
68 | + ErrnoMsg[6] ="重复提交,请稍后再试" | ||
69 | + } |
pkg/mygin/request.go
0 → 100644
1 | +package mygin | ||
2 | + | ||
3 | +import ( | ||
4 | + "fmt" | ||
5 | + "sync/atomic" | ||
6 | +) | ||
7 | + | ||
8 | +type RequestHead struct { | ||
9 | + Token string // 登录令牌 | ||
10 | + Uid int64 // 用户id | ||
11 | + AppId int // APP唯一标志 | ||
12 | + Version string // 客户端版本 | ||
13 | + Os string // 手机系统版本 | ||
14 | + From string // 请求来源 | ||
15 | + Screen string // 屏幕尺寸 | ||
16 | + Model string // 机型信息 | ||
17 | + Channel string // 渠道信息 | ||
18 | + Net string // 当前网络状态 | ||
19 | + DeviceId string // 设备Id | ||
20 | + LoginIp string // 登录IP | ||
21 | + Jwt string // jwt | ||
22 | + | ||
23 | + requestId string //请求编号 md5 | ||
24 | + reqIndex int64 //请求链序号 | ||
25 | + //lastOpTime int64 //保存上一次操作请求时间戳,暂时未使用(计算链路耗时) | ||
26 | +} | ||
27 | +func (reqHead *RequestHead)SetRequestId(addString ...string){ | ||
28 | + if (len(addString)==0){ | ||
29 | + return | ||
30 | + } | ||
31 | + reqHead.requestId = addString[0] | ||
32 | +} | ||
33 | +func(reqHead *RequestHead)GetRequestId()string{ | ||
34 | + atomic.AddInt64(&reqHead.reqIndex,1) | ||
35 | + return fmt.Sprintf("%s.%d",reqHead.requestId,reqHead.reqIndex) | ||
36 | +} | ||
37 | + | ||
38 | + | ||
39 | +type TotalSwitchStr struct { | ||
40 | + TotalSwitch int `json:"total_switch"` // 总开关:0-on; 1-off | ||
41 | + MessageBody string `json:"message_body"` // 消息提示信息 | ||
42 | +} |
pkg/orm/beeorm.go
0 → 100644
1 | +package orm | ||
2 | + | ||
3 | +import ( | ||
4 | + "github.com/astaxie/beego/orm" | ||
5 | + "gitlab.fjmaimaimai.com/mmm-go/gocomm/config" | ||
6 | + "gitlab.fjmaimaimai.com/mmm-go/gocomm/pkg/log" | ||
7 | +) | ||
8 | + | ||
9 | +func NewBeeormEngine(conf config.Mysql){ | ||
10 | + err:=orm.RegisterDataBase("default","mysql",conf.DataSource) | ||
11 | + if err!=nil{ | ||
12 | + log.Error(err) | ||
13 | + }else{ | ||
14 | + log.Debug("open db address:",conf.DataSource) | ||
15 | + } | ||
16 | + orm.SetMaxIdleConns("default", conf.MaxIdle) | ||
17 | + orm.SetMaxOpenConns("default", conf.MaxOpen) | ||
18 | +} |
pkg/orm/orm.go
0 → 100644
1 | +package orm |
pkg/redis/hash.go
0 → 100644
1 | +package redis | ||
2 | + | ||
3 | +import ( | ||
4 | + "errors" | ||
5 | + "github.com/garyburd/redigo/redis" | ||
6 | +) | ||
7 | + | ||
8 | +//设置指定hash指定key的值 | ||
9 | +func Hset(key string, field string, value interface{}, timeout int64) error { | ||
10 | + if len(key) < 1 || len(field) < 1 { | ||
11 | + return errors.New("Invalid argument") | ||
12 | + } | ||
13 | + c := redisPool.Get() | ||
14 | + defer c.Close() | ||
15 | + var err error | ||
16 | + _, err = c.Do("HSET", key, field, value) | ||
17 | + if err != nil { | ||
18 | + return err | ||
19 | + } | ||
20 | + //设置有效时间 | ||
21 | + if timeout > 0 { | ||
22 | + length := Hlen(key) | ||
23 | + if 1 == length { | ||
24 | + _, err := c.Do("EXPIRE", key, timeout) | ||
25 | + if err != nil { | ||
26 | + Del(key) | ||
27 | + return err | ||
28 | + } | ||
29 | + } | ||
30 | + } | ||
31 | + return nil | ||
32 | +} | ||
33 | + | ||
34 | +//获取指定hash的所有key | ||
35 | +func Hkeys(key string) ([][]byte, error) { | ||
36 | + if len(key) < 1 { | ||
37 | + return nil, errors.New("Invalid argument") | ||
38 | + } | ||
39 | + c := redisPool.Get() | ||
40 | + defer c.Close() | ||
41 | + v, err := redis.ByteSlices(c.Do("HKEYS", key)) | ||
42 | + if err != nil { | ||
43 | + return nil, err | ||
44 | + } | ||
45 | + return v, nil | ||
46 | +} | ||
47 | + | ||
48 | +//获取指定hash指定key的value | ||
49 | +func Hget(key string, field string) (string, error) { | ||
50 | + if len(key) < 1 { | ||
51 | + return "", errors.New("invalid argument") | ||
52 | + } | ||
53 | + c := redisPool.Get() | ||
54 | + defer c.Close() | ||
55 | + v, err := redis.String(c.Do("HGET", key, field)) | ||
56 | + if err != nil { | ||
57 | + return "", err | ||
58 | + } | ||
59 | + return v, nil | ||
60 | +} | ||
61 | + | ||
62 | +//获取指定hash的key和value | ||
63 | +func Hgetall(key string) (map[string]string, error) { | ||
64 | + if len(key) < 1 { | ||
65 | + return nil, errors.New("Invalid argument") | ||
66 | + } | ||
67 | + c := redisPool.Get() | ||
68 | + defer c.Close() | ||
69 | + v, err := redis.StringMap(c.Do("HGETALL", key)) | ||
70 | + if err != nil { | ||
71 | + return nil, err | ||
72 | + } | ||
73 | + return v, nil | ||
74 | +} | ||
75 | + | ||
76 | +//获取hash字段数量 | ||
77 | +func Hlen(key string) int { | ||
78 | + if len(key) < 1 { | ||
79 | + return 0 | ||
80 | + } | ||
81 | + c := redisPool.Get() | ||
82 | + defer c.Close() | ||
83 | + v, err := redis.Int(c.Do("HLEN", key)) | ||
84 | + if err != nil || v <= 0 { | ||
85 | + return 0 | ||
86 | + } | ||
87 | + return v | ||
88 | +} | ||
89 | + | ||
90 | +// 删除哈希指定字段 | ||
91 | +func Hdel(key string, field string) error { | ||
92 | + if len(key) < 1 { | ||
93 | + return errors.New("Invalid argument") | ||
94 | + } | ||
95 | + c := redisPool.Get() | ||
96 | + defer c.Close() | ||
97 | + var err error | ||
98 | + _, err = c.Do("HDEL", key, field) | ||
99 | + if err != nil { | ||
100 | + return err | ||
101 | + } | ||
102 | + return nil | ||
103 | +} | ||
104 | + | ||
105 | +// 查看哈希表 key 中,指定的字段是否存在 | ||
106 | +func Hexists(key string, field string) bool { | ||
107 | + if len(key) < 1 || len(field) < 1 { | ||
108 | + return false | ||
109 | + } | ||
110 | + cli := redisPool.Get() | ||
111 | + defer cli.Close() | ||
112 | + v, err := redis.Int(cli.Do("HEXISTS", key, field)) | ||
113 | + if err != nil || v == 0 { | ||
114 | + return false | ||
115 | + } | ||
116 | + return true | ||
117 | +} |
pkg/redis/locker.go
0 → 100644
1 | +package redis | ||
2 | + | ||
3 | +import ( | ||
4 | + "fmt" | ||
5 | + "github.com/astaxie/beego" | ||
6 | + "github.com/garyburd/redigo/redis" | ||
7 | + "sync" | ||
8 | +) | ||
9 | + | ||
10 | +type Mutex struct { | ||
11 | + conn redis.Conn | ||
12 | + timeOut int64 | ||
13 | + resource string | ||
14 | + lock bool | ||
15 | + closeOnce sync.Once | ||
16 | +} | ||
17 | +//NewMutex create new mutex | ||
18 | +func NewMutex(source string)*Mutex{ | ||
19 | + return &Mutex{ | ||
20 | + resource:source, | ||
21 | + lock:false, | ||
22 | + timeOut:SECOND*5,//未执行完,已经超时 超时时间设大 | ||
23 | + } | ||
24 | +} | ||
25 | +func (l *Mutex)Key()string{ | ||
26 | + return fmt.Sprintf("reidslock:%s",l.resource) | ||
27 | +} | ||
28 | +func(l *Mutex)Conn()redis.Conn{ | ||
29 | + return l.conn | ||
30 | +} | ||
31 | +//设置超时 | ||
32 | +func (l *Mutex)TimeOut(t int64)*Mutex{ | ||
33 | + l.timeOut = t | ||
34 | + return l | ||
35 | +} | ||
36 | +//加锁 | ||
37 | +//true:加锁成功 false:加锁失败 | ||
38 | +func (l *Mutex)Lock()( bool){ | ||
39 | + defer func(){ | ||
40 | + if !l.lock{ | ||
41 | + beego.Warn("on locked:",l.Key()) | ||
42 | + l.Close() | ||
43 | + } | ||
44 | + }() | ||
45 | + if l.lock{ | ||
46 | + return l.lock | ||
47 | + } | ||
48 | + l.conn =redisPool.Get() | ||
49 | + resourceKey :=l.Key() | ||
50 | + if result, err := l.conn.Do("SET", resourceKey,l.resource,"NX","EX", l.timeOut); err != nil || result==nil{ | ||
51 | + return l.lock | ||
52 | + }else{ | ||
53 | + ok :=result.(string) | ||
54 | + if ok !="OK"{ | ||
55 | + return l.lock | ||
56 | + } | ||
57 | + } | ||
58 | + l.lock = true | ||
59 | + return l.lock | ||
60 | +} | ||
61 | +//解锁 | ||
62 | +func(l *Mutex)UnLock()error{ | ||
63 | + defer l.Close() | ||
64 | + if !l.lock{ | ||
65 | + return nil | ||
66 | + } | ||
67 | + if _,err :=l.conn.Do("DEL",l.Key());err!=nil{ | ||
68 | + return err | ||
69 | + } | ||
70 | + l.lock = false | ||
71 | + return nil | ||
72 | +} | ||
73 | +//关闭 | ||
74 | +func(l *Mutex)Close(){ | ||
75 | + l.closeOnce.Do(func(){ | ||
76 | + if l.conn!=nil{ | ||
77 | + l.conn.Close() | ||
78 | + } | ||
79 | + }) | ||
80 | +} |
pkg/redis/redis.go
0 → 100644
1 | +package redis | ||
2 | + | ||
3 | +import ( | ||
4 | + "errors" | ||
5 | + "fmt" | ||
6 | + "github.com/garyburd/redigo/redis" | ||
7 | + "gitlab.fjmaimaimai.com/mmm-go/gocomm/config" | ||
8 | + "time" | ||
9 | +) | ||
10 | + | ||
11 | +const ( | ||
12 | + INFINITE int64 = 0 | ||
13 | + SECOND int64 = 1 | ||
14 | + MINUTE int64 = 60 | ||
15 | + HOUR int64 = 3600 | ||
16 | + DAY int64 = 24 * HOUR | ||
17 | + WEEK int64 = 7 * DAY | ||
18 | + MONTH int64 = 30 * DAY | ||
19 | + YEAR int64 = 365 * DAY | ||
20 | +) | ||
21 | + | ||
22 | +var ( | ||
23 | + // 连接池 | ||
24 | + redisPool *redis.Pool | ||
25 | +) | ||
26 | + | ||
27 | +func InitWithDb(size int, addr, password, db string) error { | ||
28 | + redisPool = &redis.Pool{ | ||
29 | + MaxIdle: size, | ||
30 | + IdleTimeout: 180 * time.Second, | ||
31 | + TestOnBorrow: func(c redis.Conn, t time.Time) error { | ||
32 | + _, err := c.Do("PING") | ||
33 | + return err | ||
34 | + }, | ||
35 | + Dial: func() (redis.Conn, error) { | ||
36 | + return dialWithDB(addr, password, db) | ||
37 | + }, | ||
38 | + } | ||
39 | + | ||
40 | + _, err := ping() | ||
41 | + return err | ||
42 | +} | ||
43 | + | ||
44 | +func Init(conf config.Redis) error { | ||
45 | + redisPool = &redis.Pool{ | ||
46 | + MaxIdle: conf.MaxIdle, | ||
47 | + IdleTimeout: 180 * time.Second, | ||
48 | + TestOnBorrow: func(c redis.Conn, t time.Time) error { | ||
49 | + _, err := c.Do("PING") | ||
50 | + return err | ||
51 | + }, | ||
52 | + Dial: func() (redis.Conn, error) { | ||
53 | + return dial(conf.Addr, conf.Password) | ||
54 | + }, | ||
55 | + } | ||
56 | + _, err := ping() | ||
57 | + return err | ||
58 | +} | ||
59 | + | ||
60 | +func ping() (bool, error) { | ||
61 | + c := redisPool.Get() | ||
62 | + defer c.Close() | ||
63 | + data, err := c.Do("PING") | ||
64 | + if err != nil || data == nil { | ||
65 | + return false, err | ||
66 | + } | ||
67 | + return (data == "PONG"), nil | ||
68 | +} | ||
69 | + | ||
70 | +func dial(addr, password string) (redis.Conn, error) { | ||
71 | + c, err := redis.Dial("tcp", addr) | ||
72 | + if err != nil { | ||
73 | + return nil, err | ||
74 | + } | ||
75 | + if password != "" { | ||
76 | + if _, err := c.Do("AUTH", password); err != nil { | ||
77 | + c.Close() | ||
78 | + return nil, err | ||
79 | + } | ||
80 | + } | ||
81 | + return c, err | ||
82 | +} | ||
83 | + | ||
84 | +func dialWithDB(addr, password, db string) (redis.Conn, error) { | ||
85 | + c, err := dial(addr, password) | ||
86 | + if err != nil { | ||
87 | + return nil, err | ||
88 | + } | ||
89 | + if _, err := c.Do("SELECT", db); err != nil { | ||
90 | + c.Close() | ||
91 | + return nil, err | ||
92 | + } | ||
93 | + return c, err | ||
94 | +} | ||
95 | + | ||
96 | +//判断键是否存在 | ||
97 | +func Exists(key string) (bool, error) { | ||
98 | + if len(key) <= 0 { | ||
99 | + return false, errors.New("Empty key") | ||
100 | + } | ||
101 | + c := redisPool.Get() | ||
102 | + defer c.Close() | ||
103 | + exists, err := redis.Bool(c.Do("EXISTS", key)) | ||
104 | + return exists, err | ||
105 | +} | ||
106 | + | ||
107 | +//删除指定键 | ||
108 | +func Del(key string) (bool, error) { | ||
109 | + if len(key) <= 0 { | ||
110 | + return false, errors.New("Empty key") | ||
111 | + } | ||
112 | + c := redisPool.Get() | ||
113 | + defer c.Close() | ||
114 | + return redis.Bool(c.Do("DEL", key)) | ||
115 | +} | ||
116 | + | ||
117 | +//批量删除指定键 | ||
118 | +func DelMulti(key ...interface{}) (bool, error) { | ||
119 | + if len(key) <= 0 { | ||
120 | + return false, errors.New("Invalid argument") | ||
121 | + } | ||
122 | + c := redisPool.Get() | ||
123 | + defer c.Close() | ||
124 | + return redis.Bool(c.Do("DEL", key...)) | ||
125 | +} | ||
126 | + | ||
127 | +// func LikeDeletes(key string) error { | ||
128 | +// conn := RedisConn.Get() | ||
129 | +// defer conn.Close() | ||
130 | + | ||
131 | +// keys, err := redis.Strings(conn.Do("KEYS", "*"+key+"*")) | ||
132 | +// if err != nil { | ||
133 | +// return err | ||
134 | +// } | ||
135 | + | ||
136 | +// for _, key := range keys { | ||
137 | +// _, err = Delete(key) | ||
138 | +// if err != nil { | ||
139 | +// return err | ||
140 | +// } | ||
141 | +// } | ||
142 | + | ||
143 | +// return nil | ||
144 | +// } | ||
145 | + | ||
146 | +//设置制定键的生存周期 | ||
147 | +func Expire(key string, timeout int64) error { | ||
148 | + if len(key) <= 0 || timeout < 0 { | ||
149 | + return fmt.Errorf("Invalid argument: key=[%s] timeout=[%d]", key, timeout) | ||
150 | + } | ||
151 | + c := redisPool.Get() | ||
152 | + defer c.Close() | ||
153 | + if timeout == 0 { | ||
154 | + return nil | ||
155 | + } | ||
156 | + _, err := c.Do("EXPIRE", key, timeout) | ||
157 | + return err | ||
158 | +} | ||
159 | + | ||
160 | +func setExpire(c redis.Conn, key string, timeout int64) error { | ||
161 | + if len(key) <= 0 || timeout < 0 { | ||
162 | + return fmt.Errorf("Invalid argument: key=[%s] timeout=[%d]", key, timeout) | ||
163 | + } | ||
164 | + _, err := c.Do("EXPIRE", key, timeout) | ||
165 | + return err | ||
166 | +} | ||
167 | + | ||
168 | +func DelPattern(pattern string) bool { | ||
169 | + if len(pattern) <= 0 { | ||
170 | + return false | ||
171 | + } | ||
172 | + c := redisPool.Get() | ||
173 | + defer c.Close() | ||
174 | + result, err := redis.Strings(c.Do("Keys", pattern)) | ||
175 | + if err != nil { | ||
176 | + return false | ||
177 | + } | ||
178 | + // TODO:pipeline | ||
179 | + for i := range result { | ||
180 | + Del(result[i]) | ||
181 | + } | ||
182 | + return true | ||
183 | +} | ||
184 | + | ||
185 | +func GetKeyPattern(pattern string) ([]string, error) { | ||
186 | + if len(pattern) < 1 { | ||
187 | + return nil, errors.New("Invalid argument") | ||
188 | + } | ||
189 | + c := redisPool.Get() | ||
190 | + defer c.Close() | ||
191 | + result, err := redis.Strings(c.Do("Keys", pattern)) | ||
192 | + if err != nil { | ||
193 | + return nil, err | ||
194 | + } | ||
195 | + return result, nil | ||
196 | +} |
pkg/redis/set.go
0 → 100644
1 | +package redis | ||
2 | + | ||
3 | +import ( | ||
4 | + "errors" | ||
5 | + | ||
6 | + "github.com/garyburd/redigo/redis" | ||
7 | +) | ||
8 | + | ||
9 | +//设置集合 | ||
10 | +func Sadd(key string, value string, timeout int64) error { | ||
11 | + if len(key) < 1 || len(value) < 1 { | ||
12 | + return errors.New("Invalid argument") | ||
13 | + } | ||
14 | + c := redisPool.Get() | ||
15 | + defer c.Close() | ||
16 | + var err error | ||
17 | + _, err = c.Do("SADD", key, value) | ||
18 | + if err != nil { | ||
19 | + return err | ||
20 | + } | ||
21 | + //设置有效时间 | ||
22 | + if 1 == Scard(key) && timeout > 0 { | ||
23 | + _, err := c.Do("EXPIRE", key, timeout) | ||
24 | + if err != nil { | ||
25 | + Del(key) | ||
26 | + return err | ||
27 | + } | ||
28 | + } | ||
29 | + return nil | ||
30 | +} | ||
31 | + | ||
32 | +//删除集合中一个元素 | ||
33 | +func Srem(key string, value string) error { | ||
34 | + if len(key) < 1 || len(value) < 1 { | ||
35 | + return errors.New("Invalid argument") | ||
36 | + } | ||
37 | + c := redisPool.Get() | ||
38 | + defer c.Close() | ||
39 | + var err error | ||
40 | + _, err = c.Do("SREM", key, value) | ||
41 | + if err != nil { | ||
42 | + return err | ||
43 | + } | ||
44 | + return nil | ||
45 | +} | ||
46 | + | ||
47 | +//随机获取集合中的1个 | ||
48 | +func Srandmember(key string) (string, error) { | ||
49 | + if len(key) < 1 { | ||
50 | + return "", errors.New("Invalid argument") | ||
51 | + } | ||
52 | + c := redisPool.Get() | ||
53 | + defer c.Close() | ||
54 | + v, err := redis.String(c.Do("SRANDMEMBER", key)) | ||
55 | + if err != nil { | ||
56 | + return "", err | ||
57 | + } | ||
58 | + return v, nil | ||
59 | +} | ||
60 | + | ||
61 | +//获取set集合成员数量 | ||
62 | +func Scard(key string) int { | ||
63 | + if len(key) < 1 { | ||
64 | + return 0 | ||
65 | + } | ||
66 | + c := redisPool.Get() | ||
67 | + defer c.Close() | ||
68 | + v, err := redis.Int(c.Do("SCARD", key)) | ||
69 | + if err != nil || v <= 0 { | ||
70 | + return 0 | ||
71 | + } | ||
72 | + return v | ||
73 | +} | ||
74 | + | ||
75 | +//获取集合中所有元素 | ||
76 | +func Smembers(key string) ([]string, error) { | ||
77 | + if len(key) < 1 { | ||
78 | + return nil, errors.New("Invalid argument") | ||
79 | + } | ||
80 | + c := redisPool.Get() | ||
81 | + defer c.Close() | ||
82 | + v, err := redis.Strings(c.Do("SMEMBERS", key)) | ||
83 | + if err != nil { | ||
84 | + return nil, err | ||
85 | + } | ||
86 | + return v, nil | ||
87 | +} | ||
88 | + | ||
89 | +//获取集合中所有元素 | ||
90 | +func SmembersInt(key string) ([]int, error) { | ||
91 | + if len(key) < 1 { | ||
92 | + return nil, errors.New("Invalid argument") | ||
93 | + } | ||
94 | + c := redisPool.Get() | ||
95 | + defer c.Close() | ||
96 | + v, err := redis.Ints(c.Do("SMEMBERS", key)) | ||
97 | + if err != nil { | ||
98 | + return nil, err | ||
99 | + } | ||
100 | + return v, nil | ||
101 | +} |
pkg/redis/string.go
0 → 100644
1 | +package redis | ||
2 | + | ||
3 | +import ( | ||
4 | + "encoding/json" | ||
5 | + "errors" | ||
6 | + | ||
7 | + "github.com/garyburd/redigo/redis" | ||
8 | +) | ||
9 | + | ||
10 | +func Set(key string, v interface{}, timeout int64) error { | ||
11 | + if len(key) <= 0 || timeout < 0 || v == nil { | ||
12 | + err := errors.New("Invalid argument") | ||
13 | + return err | ||
14 | + } | ||
15 | + c := redisPool.Get() | ||
16 | + defer c.Close() | ||
17 | + switch v := v.(type) { | ||
18 | + case int8, int16, int32, int, int64, uint8, uint16, uint, uint32, uint64, string: | ||
19 | + if timeout == 0 { | ||
20 | + if _, err := c.Do("SET", key, v); err != nil { | ||
21 | + return err | ||
22 | + } | ||
23 | + } else { | ||
24 | + if _, err := c.Do("SETEX", key, timeout, v); err != nil { | ||
25 | + return err | ||
26 | + } | ||
27 | + } | ||
28 | + default: | ||
29 | + b, err := json.Marshal(v) | ||
30 | + if err != nil { | ||
31 | + return err | ||
32 | + } | ||
33 | + if timeout == 0 { | ||
34 | + if _, err = c.Do("SET", key, string(b)); err != nil { | ||
35 | + return err | ||
36 | + } | ||
37 | + } else { | ||
38 | + if _, err = c.Do("SETEX", key, timeout, string(b)); err != nil { | ||
39 | + return err | ||
40 | + } | ||
41 | + } | ||
42 | + | ||
43 | + } | ||
44 | + return nil | ||
45 | +} | ||
46 | + | ||
47 | +func Get(key string) (string, error) { | ||
48 | + if len(key) < 1 { | ||
49 | + return "", errors.New("Invalid argument") | ||
50 | + } | ||
51 | + c := redisPool.Get() | ||
52 | + defer c.Close() | ||
53 | + v, err := redis.String(c.Do("GET", key)) | ||
54 | + if err != nil { | ||
55 | + return "", err | ||
56 | + } | ||
57 | + | ||
58 | + return v, nil | ||
59 | +} | ||
60 | + | ||
61 | +//获取指定键的INCR | ||
62 | +func Incr(key string, timeout int64) (int64, bool) { | ||
63 | + if len(key) < 1 { | ||
64 | + return 0, false | ||
65 | + } | ||
66 | + c := redisPool.Get() | ||
67 | + defer c.Close() | ||
68 | + var isExpire bool = false | ||
69 | + // timeout大于0并且不存在改key,则需要设置ttl | ||
70 | + exists, err := Exists(key) | ||
71 | + if err != nil { | ||
72 | + return 0, false | ||
73 | + } | ||
74 | + if timeout > INFINITE && !exists { | ||
75 | + isExpire = true | ||
76 | + } | ||
77 | + v, err := redis.Int64(c.Do("INCR", key)) | ||
78 | + if err != nil || v == 0 { | ||
79 | + return 0, false | ||
80 | + } | ||
81 | + if isExpire { | ||
82 | + Expire(key, timeout) | ||
83 | + } | ||
84 | + return v, true | ||
85 | +} |
pkg/redis/zset.go
0 → 100644
1 | +package redis | ||
2 | + | ||
3 | +import ( | ||
4 | + "errors" | ||
5 | + "github.com/garyburd/redigo/redis" | ||
6 | +) | ||
7 | + | ||
8 | +//设置集合 | ||
9 | +func Zadd(key string, score float64, member interface{}) error { | ||
10 | + if len(key) < 1 { | ||
11 | + return errors.New("Invalid argument") | ||
12 | + } | ||
13 | + c := redisPool.Get() | ||
14 | + defer c.Close() | ||
15 | + var err error | ||
16 | + _, err = c.Do("ZADD", key, score, member) | ||
17 | + if err != nil { | ||
18 | + return err | ||
19 | + } | ||
20 | + return nil | ||
21 | +} | ||
22 | + | ||
23 | +//有序集合中对指定成员的分数加上增量 increment | ||
24 | +func Zincrby(key string, increment int64, member interface{}) error { | ||
25 | + if len(key) < 1 { | ||
26 | + return errors.New("Invalid argument") | ||
27 | + } | ||
28 | + c := redisPool.Get() | ||
29 | + defer c.Close() | ||
30 | + var err error | ||
31 | + _, err = c.Do("ZINCRBY", key, increment, member) | ||
32 | + if err != nil { | ||
33 | + return err | ||
34 | + } | ||
35 | + return nil | ||
36 | +} | ||
37 | + | ||
38 | +// 有序集合中对指定成员的分数加上增量 increment | ||
39 | +// 注意:次函数只能获取member是整形的情况,如遇到member不少整形的情况需要另外函数 | ||
40 | +func Zrevrange(key string, start, stop int64) ([]string, error) { | ||
41 | + if len(key) < 1 { | ||
42 | + return nil, errors.New("Invalid argument") | ||
43 | + } | ||
44 | + c := redisPool.Get() | ||
45 | + defer c.Close() | ||
46 | + datas, err := redis.Strings(c.Do("ZREVRANGE", key, start, stop, "WITHSCORES")) | ||
47 | + if err != nil { | ||
48 | + return nil, err | ||
49 | + } | ||
50 | + return datas, nil | ||
51 | +} |
pkg/tracer/http.go
0 → 100644
1 | +package tracer | ||
2 | + | ||
3 | +import ( | ||
4 | + "github.com/opentracing/opentracing-go" | ||
5 | + "github.com/opentracing/opentracing-go/ext" | ||
6 | + "net/http" | ||
7 | +) | ||
8 | + | ||
9 | +func TracingHTTPRequest(tracer opentracing.Tracer,tracerName string,tagValue interface{}) (func(next http.Handler) http.Handler) { | ||
10 | + return func(next http.Handler) (http.Handler) { | ||
11 | + return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { | ||
12 | + // Try to join to a trace propagated in `req`. | ||
13 | + //步骤1 解客户端span | ||
14 | + wireContext, err := tracer.Extract( | ||
15 | + opentracing.TextMap, | ||
16 | + opentracing.HTTPHeadersCarrier(req.Header), | ||
17 | + ) | ||
18 | + if err!=nil{ | ||
19 | + panic(err) | ||
20 | + } | ||
21 | + //步骤2 启动服务端span | ||
22 | + span := tracer.StartSpan(tracerName, ext.RPCServerOption(wireContext)) | ||
23 | + span.SetTag("server", tagValue) | ||
24 | + //部署4 关闭span | ||
25 | + defer span.Finish() | ||
26 | + // 部署3 store span in context | ||
27 | + ctx := opentracing.ContextWithSpan(req.Context(), span) | ||
28 | + // update request context to include our new span | ||
29 | + req = req.WithContext(ctx) | ||
30 | + // next middleware or actual request handler | ||
31 | + next.ServeHTTP(w, req) | ||
32 | + }) | ||
33 | + } | ||
34 | +} |
pkg/tracer/jaeger.go
0 → 100644
1 | +package tracer | ||
2 | + | ||
3 | +import ( | ||
4 | + "fmt" | ||
5 | + "gitlab.fjmaimaimai.com/mmm-go/gocomm/common" | ||
6 | + "net/http" | ||
7 | + | ||
8 | + "github.com/opentracing-contrib/go-stdlib/nethttp" | ||
9 | + "github.com/opentracing/opentracing-go" | ||
10 | + "github.com/uber/jaeger-client-go" | ||
11 | + jaegercfg "github.com/uber/jaeger-client-go/config" | ||
12 | + "github.com/uber/jaeger-lib/metrics" | ||
13 | + "github.com/uber/jaeger-lib/metrics/metricstest" | ||
14 | + | ||
15 | + "gitlab.fjmaimaimai.com/mmm-go/gocomm/pkg/log" | ||
16 | +) | ||
17 | + | ||
18 | +func Init(serviceName, addr string) (opentracing.Tracer, error) { | ||
19 | + // Sample configuration for testing. Use constant sampling to sample every trace | ||
20 | + // and enable LogSpan to log every span via configured Logger. | ||
21 | + cfg := jaegercfg.Configuration{ | ||
22 | + Sampler: &jaegercfg.SamplerConfig{ | ||
23 | + Type: jaeger.SamplerTypeConst, | ||
24 | + Param: 1, | ||
25 | + }, | ||
26 | + Reporter: &jaegercfg.ReporterConfig{ | ||
27 | + LogSpans: true, | ||
28 | + }, | ||
29 | + } | ||
30 | + | ||
31 | + cfg.ServiceName = serviceName | ||
32 | + | ||
33 | + // Example logger and metrics factory. Use github.com/uber/jaeger-client-go/log | ||
34 | + // and github.com/uber/jaeger-lib/metrics respectively to bind to real logging and metrics | ||
35 | + // frameworks. | ||
36 | + jLogger := &jaegerLogger{} | ||
37 | + jMetricsFactory := metrics.NullFactory | ||
38 | + | ||
39 | + metricsFactory := metricstest.NewFactory(0) | ||
40 | + metrics := jaeger.NewMetrics(metricsFactory, nil) | ||
41 | + | ||
42 | + sender, err := jaeger.NewUDPTransport(addr, 0) | ||
43 | + if err != nil { | ||
44 | + log.Error("could not initialize jaeger sender:", err.Error()) | ||
45 | + return nil, err | ||
46 | + } | ||
47 | + | ||
48 | + repoter := jaeger.NewRemoteReporter(sender, jaeger.ReporterOptions.Metrics(metrics)) | ||
49 | + | ||
50 | + tracer, _, err := cfg.NewTracer( | ||
51 | + jaegercfg.Logger(jLogger), | ||
52 | + jaegercfg.Metrics(jMetricsFactory), | ||
53 | + jaegercfg.Reporter(repoter), | ||
54 | + ) | ||
55 | + if err != nil { | ||
56 | + return nil, fmt.Errorf("new trace error: %v", err) | ||
57 | + } | ||
58 | + | ||
59 | + return tracer, nil | ||
60 | + | ||
61 | +} | ||
62 | + | ||
63 | +type jaegerLogger struct{} | ||
64 | + | ||
65 | +func (l *jaegerLogger) Error(msg string) { | ||
66 | + log.Error(common.LogF("ERROR: %s", msg)) | ||
67 | +} | ||
68 | + | ||
69 | +// Infof logs a message at info priority | ||
70 | +func (l *jaegerLogger) Infof(msg string, args ...interface{}) { | ||
71 | + log.Info(common.LogF(msg,args)) | ||
72 | +} | ||
73 | + | ||
74 | +func TracingMiddleware(handler http.Handler) http.Handler { | ||
75 | + return nethttp.Middleware( | ||
76 | + opentracing.GlobalTracer(), | ||
77 | + handler, | ||
78 | + nethttp.MWSpanObserver(func(span opentracing.Span, r *http.Request) { | ||
79 | + | ||
80 | + }), | ||
81 | + nethttp.OperationNameFunc(func(r *http.Request) string { | ||
82 | + return "HTTP " + r.Method + " " + r.RequestURI | ||
83 | + }), | ||
84 | + ) | ||
85 | +} |
pkg/websocket/websocket.go
0 → 100644
1 | +package websocket | ||
2 | + | ||
3 | +import ( | ||
4 | + "encoding/json" | ||
5 | + "fmt" | ||
6 | + "github.com/astaxie/beego" | ||
7 | + "github.com/gorilla/websocket" | ||
8 | + "gitlab.fjmaimaimai.com/mmm-go/gocomm/pkg/mybeego" | ||
9 | + "reflect" | ||
10 | + "sync" | ||
11 | +) | ||
12 | + | ||
13 | +type ConnState int | ||
14 | + | ||
15 | +const ( | ||
16 | + Disconnected ConnState = iota | ||
17 | + Connected | ||
18 | +) | ||
19 | + | ||
20 | +func init() { | ||
21 | + keyType := reflect.TypeOf(&websocket.Conn{}) | ||
22 | + valueType := reflect.TypeOf(&WebsocketConnection{}) | ||
23 | + Connections = NewJMap(keyType, valueType) | ||
24 | + Clients = NewJMap(reflect.TypeOf("1:1"), valueType) | ||
25 | +} | ||
26 | + | ||
27 | +type ReceiveHandler (func([]byte) *mybeego.Message) | ||
28 | + | ||
29 | +type WebsocketConnection struct { | ||
30 | + Uid int64 | ||
31 | + AppId int | ||
32 | + Conn *websocket.Conn | ||
33 | + Echan chan interface{} | ||
34 | + Wchan chan string | ||
35 | + State ConnState | ||
36 | + OnReceive ReceiveHandler | ||
37 | + OnceClose sync.Once | ||
38 | +} | ||
39 | + | ||
40 | +func NewWebsocketConnection(conn *websocket.Conn,head *mybeego.RequestHead,recv ReceiveHandler)*WebsocketConnection{ | ||
41 | + return &WebsocketConnection{ | ||
42 | + Uid: head.Uid, | ||
43 | + AppId: head.AppId, | ||
44 | + Conn: conn, | ||
45 | + Echan: make(chan interface{}), | ||
46 | + Wchan: make(chan string, 10), | ||
47 | + State: Connected, | ||
48 | + OnReceive: recv, | ||
49 | + } | ||
50 | +} | ||
51 | + | ||
52 | +//声明了两个cliets 管理 一个通过uid 一个通过conn管理 | ||
53 | +// key(*websocket.Conn) value(*WebsocketConnection) | ||
54 | +var Connections *JMap | ||
55 | +// key=uid(int64) value(*WebsocketConnection) | ||
56 | +var Clients *JMap | ||
57 | + | ||
58 | +type JMap struct { | ||
59 | + sync.RWMutex | ||
60 | + m map[interface{}]interface{} | ||
61 | + keyType reflect.Type | ||
62 | + valueType reflect.Type | ||
63 | +} | ||
64 | + | ||
65 | +func NewJMap(keyType, valueType reflect.Type) *JMap { | ||
66 | + return &JMap{ | ||
67 | + keyType: keyType, | ||
68 | + valueType: valueType, | ||
69 | + m: make(map[interface{}]interface{}), | ||
70 | + } | ||
71 | +} | ||
72 | + | ||
73 | +func (this *JMap) PrintConnectStatus() interface{} { | ||
74 | + beego.Debug("PrintConnectStatus...") | ||
75 | + beego.Info("============查看websocket连接状态begin============") | ||
76 | + for i, v := range this.m { | ||
77 | + beego.Info("key:", i, " conn:", v) | ||
78 | + } | ||
79 | + beego.Info("============查看websocket连接状态end============") | ||
80 | + return this.m | ||
81 | +} | ||
82 | + | ||
83 | +func (this *JMap) GetOnlineClient() map[interface{}]interface{} { | ||
84 | + return this.m | ||
85 | +} | ||
86 | + | ||
87 | +func (this *JMap) acceptable(k, v interface{}) bool { | ||
88 | + if k == nil || reflect.TypeOf(k) != this.keyType { | ||
89 | + return false | ||
90 | + } | ||
91 | + | ||
92 | + if k == nil || reflect.TypeOf(v) != this.valueType { | ||
93 | + return false | ||
94 | + } | ||
95 | + | ||
96 | + return true | ||
97 | +} | ||
98 | + | ||
99 | +func (this *JMap) Get(k interface{}) (interface{}, bool) { | ||
100 | + this.RLock() | ||
101 | + conn, ok := this.m[k] | ||
102 | + this.RUnlock() | ||
103 | + return conn, ok | ||
104 | +} | ||
105 | + | ||
106 | +func (this *JMap) Put(k interface{}, v interface{}) bool { | ||
107 | + if !this.acceptable(k, v) { | ||
108 | + return false | ||
109 | + } | ||
110 | + if connI, ok := Clients.Get(k); ok { | ||
111 | + beego.Debug("key:", k, "已经连接,先剔除下线") | ||
112 | + if conn, ok := connI.(*WebsocketConnection); ok { | ||
113 | + //conn.Conn.WriteMessage(websocket.TextMessage, []byte("您的帐号在其它地方登录,您被剔除下线")) | ||
114 | + conn.Close() | ||
115 | + } | ||
116 | + | ||
117 | + } | ||
118 | + this.Lock() | ||
119 | + this.m[k] = v | ||
120 | + this.Unlock() | ||
121 | + return true | ||
122 | +} | ||
123 | + | ||
124 | +func (this *JMap) Remove(k interface{}) { | ||
125 | + this.Lock() | ||
126 | + delete(this.m, k) | ||
127 | + this.Unlock() | ||
128 | +} | ||
129 | + | ||
130 | +func (this *JMap) Clear() { | ||
131 | + this.Lock() | ||
132 | + this.m = make(map[interface{}]interface{}) | ||
133 | + this.Unlock() | ||
134 | +} | ||
135 | + | ||
136 | +func (this *JMap) Size() int { | ||
137 | + this.RLock() | ||
138 | + defer this.RUnlock() | ||
139 | + return len(this.m) | ||
140 | +} | ||
141 | + | ||
142 | +func (this *JMap) IsEmpty() bool { | ||
143 | + return this.Size() == 0 | ||
144 | +} | ||
145 | + | ||
146 | +func (this *JMap) Contains(k interface{}) bool { | ||
147 | + this.RLock() | ||
148 | + _, ok := this.m[k] | ||
149 | + this.RUnlock() | ||
150 | + return ok | ||
151 | +} | ||
152 | + | ||
153 | +func (c *WebsocketConnection) Serve() { | ||
154 | + c.State = Connected | ||
155 | + Connections.Put(c.Conn, c) | ||
156 | + key := fmt.Sprintf("%d:%d", c.Uid, c.AppId) | ||
157 | + Clients.Put(key, c) | ||
158 | + | ||
159 | + go doWrite(c) | ||
160 | + doRead(c) | ||
161 | +} | ||
162 | + | ||
163 | +func (c *WebsocketConnection) Send(msg string) { | ||
164 | + //panic("panic in websocket.send...") | ||
165 | + c.Wchan <- msg | ||
166 | +} | ||
167 | + | ||
168 | +func (c *WebsocketConnection) Close() { | ||
169 | + c.OnceClose.Do(func(){ | ||
170 | + beego.Info("ws:close----uid:", c.Uid, "appid:", c.AppId, "state:", c.State) | ||
171 | + if c.State == Disconnected { | ||
172 | + return | ||
173 | + } | ||
174 | + | ||
175 | + Connections.Remove(c.Conn) | ||
176 | + key := fmt.Sprintf("%d:%d", c.Uid, c.AppId) | ||
177 | + Clients.Remove(key) | ||
178 | + | ||
179 | + c.State = Disconnected | ||
180 | + close(c.Echan) | ||
181 | + close(c.Wchan) | ||
182 | + c.Conn.Close() | ||
183 | + }) | ||
184 | +} | ||
185 | + | ||
186 | +func doRead(c *WebsocketConnection) { | ||
187 | + defer func() { | ||
188 | + //beego.Debug("doRead exit...uid:", c.Uid, "appid:", c.AppId) | ||
189 | + c.Close() | ||
190 | + }() | ||
191 | + | ||
192 | + for { | ||
193 | + select { | ||
194 | + case <-c.Echan: | ||
195 | + return | ||
196 | + default: | ||
197 | + } | ||
198 | + _, msg, err := c.Conn.ReadMessage() | ||
199 | + if err != nil { | ||
200 | + beego.Info(err) | ||
201 | + return | ||
202 | + } | ||
203 | + beego.Info(fmt.Sprintf("===>ws:recv msg from uid(%d) : %s", c.Uid, string(msg))) | ||
204 | + retMsg := c.OnReceive(msg) | ||
205 | + retMsgByte, err := json.Marshal(retMsg) | ||
206 | + beego.Info(fmt.Sprintf("<===ws:send to client uid(%d) : %s", c.Uid, string(retMsgByte))) | ||
207 | + c.Send(string(retMsgByte)) | ||
208 | + } | ||
209 | +} | ||
210 | + | ||
211 | +func doWrite(c *WebsocketConnection) { | ||
212 | + defer func() { | ||
213 | + if err := recover(); err != nil { | ||
214 | + beego.Error("Recover in doWrite...uid:", c.Uid, "apid:", c.AppId, "err:", err) | ||
215 | + } | ||
216 | + }() | ||
217 | + defer func() { | ||
218 | + //beego.Debug("doWrite exit...uid:", c.Uid, "appid:", c.AppId) | ||
219 | + c.Close() | ||
220 | + }() | ||
221 | + | ||
222 | + for { | ||
223 | + select { | ||
224 | + case <-c.Echan: | ||
225 | + return | ||
226 | + default: | ||
227 | + } | ||
228 | + msg, ok := <-c.Wchan | ||
229 | + if !ok { | ||
230 | + break | ||
231 | + } | ||
232 | + err := c.Conn.WriteMessage(websocket.TextMessage, []byte(msg)) | ||
233 | + if err != nil { | ||
234 | + break | ||
235 | + } | ||
236 | + } | ||
237 | +} | ||
238 | + | ||
239 | +func SendDataByWs(uid int64, appId int, sendMsg interface{}) bool { | ||
240 | + if sendMsg == nil || uid < 1 || appId < 1 { | ||
241 | + return false | ||
242 | + } | ||
243 | + msg := &mybeego.Message{ | ||
244 | + Errno: 0, | ||
245 | + Errmsg: mybeego.NewMessage(0).Errmsg, | ||
246 | + Data: sendMsg, | ||
247 | + } | ||
248 | + msgByte, err := json.Marshal(msg) | ||
249 | + if err != nil { | ||
250 | + beego.Error(err) | ||
251 | + return false | ||
252 | + } | ||
253 | + key := fmt.Sprintf("%d:%d", uid, appId) | ||
254 | + if connI, ok := Clients.Get(key); ok { | ||
255 | + beego.Debug(ok) | ||
256 | + if conn, ok := connI.(*WebsocketConnection); ok { | ||
257 | + conn.Send(string(msgByte)) | ||
258 | + return true | ||
259 | + } | ||
260 | + } | ||
261 | + return false | ||
262 | +} |
pkg/websocket/websocket_test.go
0 → 100644
1 | +package websocket | ||
2 | + | ||
3 | +import ( | ||
4 | + "github.com/gorilla/websocket" | ||
5 | + "log" | ||
6 | + "gitlab.fjmaimaimai.com/mmm-go/gocomm/pkg/mybeego" | ||
7 | + "net/http" | ||
8 | + "strconv" | ||
9 | + "testing" | ||
10 | + "html/template" | ||
11 | +) | ||
12 | + | ||
13 | +func Test_RunWebSocket(t *testing.T){ | ||
14 | + http.HandleFunc("/join",join) | ||
15 | + http.HandleFunc("/",home) | ||
16 | + log.Fatal(http.ListenAndServe(":8080",nil)) | ||
17 | +} | ||
18 | +var upgrader = websocket.Upgrader{} | ||
19 | +func join(w http.ResponseWriter,r *http.Request){ | ||
20 | + requestHead := &mybeego.RequestHead{} | ||
21 | + requestHead.Uid, _ = strconv.ParseInt(r.Header.Get("uid"), 10, 64) | ||
22 | + requestHead.AppId, _ = strconv.Atoi(r.Header.Get("appid")) | ||
23 | + requestHead.Token = r.Header.Get("token") | ||
24 | + if !validToken(requestHead.Token){ | ||
25 | + return | ||
26 | + } | ||
27 | + conn,err :=upgrader.Upgrade(w,r,nil) | ||
28 | + if err!=nil{ | ||
29 | + log.Fatal(err) | ||
30 | + } | ||
31 | + wsConn :=NewWebsocketConnection(conn,requestHead,onReceive) | ||
32 | + wsConn.Serve() | ||
33 | +} | ||
34 | + | ||
35 | +func onReceive(data []byte)*mybeego.Message{ | ||
36 | + return mybeego.NewMessage(0) | ||
37 | +} | ||
38 | + | ||
39 | +func home(w http.ResponseWriter,r *http.Request){ | ||
40 | + homeTemplate.Execute(w, "ws://"+r.Host+"/join") | ||
41 | +} | ||
42 | + | ||
43 | +func validToken(token string)bool{ | ||
44 | + return true | ||
45 | +} | ||
46 | + | ||
47 | + | ||
48 | +var homeTemplate = template.Must(template.New("").Parse(` | ||
49 | +<!DOCTYPE html> | ||
50 | +<html> | ||
51 | +<head> | ||
52 | +<meta charset="utf-8"> | ||
53 | +<script> | ||
54 | +window.addEventListener("load", function(evt) { | ||
55 | + var output = document.getElementById("output"); | ||
56 | + var input = document.getElementById("input"); | ||
57 | + var ws; | ||
58 | + var print = function(message) { | ||
59 | + var d = document.createElement("div"); | ||
60 | + d.innerHTML = message; | ||
61 | + output.appendChild(d); | ||
62 | + }; | ||
63 | + document.getElementById("open").onclick = function(evt) { | ||
64 | + if (ws) { | ||
65 | + return false; | ||
66 | + } | ||
67 | + ws = new WebSocket("{{.}}"); | ||
68 | + ws.onopen = function(evt) { | ||
69 | + print("OPEN"); | ||
70 | + } | ||
71 | + ws.onclose = function(evt) { | ||
72 | + print("CLOSE"); | ||
73 | + ws = null; | ||
74 | + } | ||
75 | + ws.onmessage = function(evt) { | ||
76 | + print("RESPONSE: " + evt.data); | ||
77 | + } | ||
78 | + ws.onerror = function(evt) { | ||
79 | + print("ERROR: " + evt.data); | ||
80 | + } | ||
81 | + return false; | ||
82 | + }; | ||
83 | + document.getElementById("send").onclick = function(evt) { | ||
84 | + if (!ws) { | ||
85 | + return false; | ||
86 | + } | ||
87 | + print("SEND: " + input.value); | ||
88 | + ws.send(input.value); | ||
89 | + return false; | ||
90 | + }; | ||
91 | + document.getElementById("close").onclick = function(evt) { | ||
92 | + if (!ws) { | ||
93 | + return false; | ||
94 | + } | ||
95 | + ws.close(); | ||
96 | + return false; | ||
97 | + }; | ||
98 | +}); | ||
99 | +</script> | ||
100 | +</head> | ||
101 | +<body> | ||
102 | +<table> | ||
103 | +<tr><td valign="top" width="50%"> | ||
104 | +<p>Click "Open" to create a connection to the server, | ||
105 | +"Send" to send a message to the server and "Close" to close the connection. | ||
106 | +You can change the message and send multiple times. | ||
107 | +<p> | ||
108 | +<form> | ||
109 | +<button id="open">Open</button> | ||
110 | +<button id="close">Close</button> | ||
111 | +<p><input id="input" type="text" value="Hello world!"> | ||
112 | +<button id="send">Send</button> | ||
113 | +</form> | ||
114 | +</td><td valign="top" width="50%"> | ||
115 | +<div id="output"></div> | ||
116 | +</td></tr></table> | ||
117 | +</body> | ||
118 | +</html> | ||
119 | +`)) | ||
120 | + |
stat/counter/counter.go
0 → 100644
1 | +package counter | ||
2 | + | ||
3 | +import ( | ||
4 | + "sync" | ||
5 | +) | ||
6 | + | ||
7 | +// Counter is a counter interface. | ||
8 | +type Counter interface { | ||
9 | + Add(int64) | ||
10 | + Reset() | ||
11 | + Value() int64 | ||
12 | +} | ||
13 | + | ||
14 | +// Group is a counter group. | ||
15 | +type Group struct { | ||
16 | + mu sync.RWMutex | ||
17 | + vecs map[string]Counter | ||
18 | + | ||
19 | + // New optionally specifies a function to generate a counter. | ||
20 | + // It may not be changed concurrently with calls to other functions. | ||
21 | + New func() Counter | ||
22 | +} | ||
23 | + | ||
24 | +// Add add a counter by a specified key, if counter not exists then make a new one and return new value. | ||
25 | +func (g *Group) Add(key string, value int64) { | ||
26 | + g.mu.RLock() | ||
27 | + vec, ok := g.vecs[key] | ||
28 | + g.mu.RUnlock() | ||
29 | + if !ok { | ||
30 | + vec = g.New() | ||
31 | + g.mu.Lock() | ||
32 | + if g.vecs == nil { | ||
33 | + g.vecs = make(map[string]Counter) | ||
34 | + } | ||
35 | + if _, ok = g.vecs[key]; !ok { | ||
36 | + g.vecs[key] = vec | ||
37 | + } | ||
38 | + g.mu.Unlock() | ||
39 | + } | ||
40 | + vec.Add(value) | ||
41 | +} | ||
42 | + | ||
43 | +// Value get a counter value by key. | ||
44 | +func (g *Group) Value(key string) int64 { | ||
45 | + g.mu.RLock() | ||
46 | + vec, ok := g.vecs[key] | ||
47 | + g.mu.RUnlock() | ||
48 | + if ok { | ||
49 | + return vec.Value() | ||
50 | + } | ||
51 | + return 0 | ||
52 | +} | ||
53 | + | ||
54 | +// Reset reset a counter by key. | ||
55 | +func (g *Group) Reset(key string) { | ||
56 | + g.mu.RLock() | ||
57 | + vec, ok := g.vecs[key] | ||
58 | + g.mu.RUnlock() | ||
59 | + if ok { | ||
60 | + vec.Reset() | ||
61 | + } | ||
62 | +} |
stat/counter/gauge.go
0 → 100644
1 | +package counter | ||
2 | + | ||
3 | +import "sync/atomic" | ||
4 | + | ||
5 | +var _ Counter = new(gaugeCounter) | ||
6 | + | ||
7 | +// A value is a thread-safe counter implementation. | ||
8 | +type gaugeCounter int64 | ||
9 | + | ||
10 | +// NewGauge return a guage counter. | ||
11 | +func NewGauge() Counter { | ||
12 | + return new(gaugeCounter) | ||
13 | +} | ||
14 | + | ||
15 | +// Add method increments the counter by some value and return new value | ||
16 | +func (v *gaugeCounter) Add(val int64) { | ||
17 | + atomic.AddInt64((*int64)(v), val) | ||
18 | +} | ||
19 | + | ||
20 | +// Value method returns the counter's current value. | ||
21 | +func (v *gaugeCounter) Value() int64 { | ||
22 | + return atomic.LoadInt64((*int64)(v)) | ||
23 | +} | ||
24 | + | ||
25 | +// Reset reset the counter. | ||
26 | +func (v *gaugeCounter) Reset() { | ||
27 | + atomic.StoreInt64((*int64)(v), 0) | ||
28 | +} |
stat/counter/gauge_test.go
0 → 100644
sync/errgroup/errgroup.go
0 → 100644
1 | +// Copyright 2016 The Go Authors. All rights reserved. | ||
2 | +// Use of this source code is governed by a BSD-style | ||
3 | +// license that can be found in the LICENSE file. | ||
4 | + | ||
5 | +// Package errgroup provides synchronization, error propagation, and Context | ||
6 | +// cancelation for groups of goroutines working on subtasks of a common task. | ||
7 | +package errgroup | ||
8 | + | ||
9 | +import ( | ||
10 | + "context" | ||
11 | + "fmt" | ||
12 | + "runtime" | ||
13 | + "sync" | ||
14 | +) | ||
15 | + | ||
16 | +// A Group is a collection of goroutines working on subtasks that are part of | ||
17 | +// the same overall task. | ||
18 | +// | ||
19 | +// A zero Group is valid and does not cancel on error. | ||
20 | +type Group struct { | ||
21 | + err error | ||
22 | + wg sync.WaitGroup | ||
23 | + errOnce sync.Once | ||
24 | + | ||
25 | + workerOnce sync.Once | ||
26 | + ch chan func() error | ||
27 | + chs []func() error | ||
28 | + | ||
29 | + cancel func() | ||
30 | +} | ||
31 | + | ||
32 | +// WithContext returns a new Group and an associated Context derived from ctx. | ||
33 | +// | ||
34 | +// The derived Context is canceled the first time a function passed to Go | ||
35 | +// returns a non-nil error or the first time Wait returns, whichever occurs | ||
36 | +// first. | ||
37 | +func WithContext(ctx context.Context) (*Group, context.Context) { | ||
38 | + ctx, cancel := context.WithCancel(ctx) | ||
39 | + return &Group{cancel: cancel}, ctx | ||
40 | +} | ||
41 | + | ||
42 | +func (g *Group) do(f func() error) { | ||
43 | + var err error | ||
44 | + defer func() { | ||
45 | + if r := recover(); r != nil { | ||
46 | + buf := make([]byte, 64<<10) | ||
47 | + buf = buf[:runtime.Stack(buf, false)] | ||
48 | + err = fmt.Errorf("errgroup: panic recovered: %s\n%s", r, buf) | ||
49 | + } | ||
50 | + if err != nil { | ||
51 | + g.errOnce.Do(func() { | ||
52 | + g.err = err | ||
53 | + if g.cancel != nil { | ||
54 | + g.cancel() | ||
55 | + } | ||
56 | + }) | ||
57 | + } | ||
58 | + g.wg.Done() | ||
59 | + }() | ||
60 | + err = f() | ||
61 | +} | ||
62 | + | ||
63 | +// GOMAXPROCS set max goroutine to work. | ||
64 | +func (g *Group) GOMAXPROCS(n int) { | ||
65 | + if n <= 0 { | ||
66 | + panic("errgroup: GOMAXPROCS must great than 0") | ||
67 | + } | ||
68 | + g.workerOnce.Do(func() { | ||
69 | + g.ch = make(chan func() error, n) | ||
70 | + for i := 0; i < n; i++ { | ||
71 | + go func() { | ||
72 | + for f := range g.ch { | ||
73 | + g.do(f) | ||
74 | + } | ||
75 | + }() | ||
76 | + } | ||
77 | + }) | ||
78 | +} | ||
79 | + | ||
80 | +// Go calls the given function in a new goroutine. | ||
81 | +// | ||
82 | +// The first call to return a non-nil error cancels the group; its error will be | ||
83 | +// returned by Wait. | ||
84 | +func (g *Group) Go(f func() error) { | ||
85 | + g.wg.Add(1) | ||
86 | + if g.ch != nil { | ||
87 | + select { | ||
88 | + case g.ch <- f: | ||
89 | + default: | ||
90 | + g.chs = append(g.chs, f) | ||
91 | + } | ||
92 | + return | ||
93 | + } | ||
94 | + go g.do(f) | ||
95 | +} | ||
96 | + | ||
97 | +// Wait blocks until all function calls from the Go method have returned, then | ||
98 | +// returns the first non-nil error (if any) from them. | ||
99 | +func (g *Group) Wait() error { | ||
100 | + if g.ch != nil { | ||
101 | + for _, f := range g.chs { | ||
102 | + g.ch <- f | ||
103 | + } | ||
104 | + } | ||
105 | + | ||
106 | + g.wg.Wait() | ||
107 | + if g.ch != nil { | ||
108 | + close(g.ch) // let all receiver exit | ||
109 | + } | ||
110 | + if g.cancel != nil { | ||
111 | + g.cancel() | ||
112 | + } | ||
113 | + return g.err | ||
114 | +} | ||
115 | + |
sync/fanout/fanout.go
0 → 100644
1 | +package fanout | ||
2 | + | ||
3 | +import "sync" | ||
4 | + | ||
5 | +func Merge(size int,cs ...<-chan interface{})<-chan interface{}{ | ||
6 | + var wg sync.WaitGroup | ||
7 | + outChan :=make(chan interface{},size) | ||
8 | + | ||
9 | + outputFunc :=func(c <-chan interface{}){ | ||
10 | + for n:=range c{ | ||
11 | + outChan <-n | ||
12 | + } | ||
13 | + wg.Done() | ||
14 | + } | ||
15 | + wg.Add(len(cs)) | ||
16 | + for _,c :=range cs{ | ||
17 | + go outputFunc(c) | ||
18 | + } | ||
19 | + go func(){ | ||
20 | + wg.Wait() | ||
21 | + close(outChan) | ||
22 | + }() | ||
23 | + return outChan | ||
24 | +} |
sync/fanout/fanout_test.go
0 → 100644
1 | +package fanout | ||
2 | + | ||
3 | +import ( | ||
4 | + "fmt" | ||
5 | + "testing" | ||
6 | +) | ||
7 | + | ||
8 | +func Test_Merge(t *testing.T){ | ||
9 | + c := gen(2, 3, 4, 5, 6, 7, 8) | ||
10 | + out2 := sq(c) | ||
11 | + out1 := sq(c) | ||
12 | + for v := range Merge(len(c),out1, out2) { | ||
13 | + fmt.Println(v) | ||
14 | + } | ||
15 | +} | ||
16 | +func gen(nums ...int) <-chan interface{} { | ||
17 | + out := make(chan interface{}) | ||
18 | + go func() { | ||
19 | + for _, n := range nums { | ||
20 | + out <- n | ||
21 | + } | ||
22 | + close(out) | ||
23 | + }() | ||
24 | + return out | ||
25 | +} | ||
26 | +func sq(in <-chan interface{}) <-chan interface{} { | ||
27 | + out := make(chan interface{}) | ||
28 | + go func() { | ||
29 | + for n := range in { | ||
30 | + out <- (n.(int))*(n.(int)) | ||
31 | + } | ||
32 | + close(out) | ||
33 | + }() | ||
34 | + return out | ||
35 | +} |
sync/signal/semaphore/semaphore.go
0 → 100644
1 | +package semaphore | ||
2 | + | ||
3 | +// Instance is an implementation of semaphore. | ||
4 | +type Instance struct { | ||
5 | + token chan struct{} | ||
6 | +} | ||
7 | + | ||
8 | +// New create a new Semaphore with n permits. | ||
9 | +func New(n int) *Instance { | ||
10 | + s := &Instance{ | ||
11 | + token: make(chan struct{}, n), | ||
12 | + } | ||
13 | + for i := 0; i < n; i++ { | ||
14 | + s.token <- struct{}{} | ||
15 | + } | ||
16 | + return s | ||
17 | +} | ||
18 | + | ||
19 | +// Wait returns a channel for acquiring a permit. | ||
20 | +func (s *Instance) Wait() <-chan struct{} { | ||
21 | + return s.token | ||
22 | +} | ||
23 | + | ||
24 | +// Signal releases a permit into the semaphore. | ||
25 | +func (s *Instance) Signal() { | ||
26 | + s.token <- struct{}{} | ||
27 | +} |
sync/task/periodic.go
0 → 100644
1 | +package task | ||
2 | + | ||
3 | +import ( | ||
4 | + "sync" | ||
5 | + "time" | ||
6 | +) | ||
7 | + | ||
8 | +// Periodic is a task that runs periodically. | ||
9 | +type Periodic struct { | ||
10 | + // Interval of the task being run | ||
11 | + Interval time.Duration | ||
12 | + // Execute is the task function | ||
13 | + Execute func() error | ||
14 | + | ||
15 | + access sync.Mutex | ||
16 | + timer *time.Timer | ||
17 | + running bool | ||
18 | +} | ||
19 | + | ||
20 | +func NewPeriodic(interval time.Duration,exec func()error)*Periodic{ | ||
21 | + return &Periodic{ | ||
22 | + Interval:interval, | ||
23 | + Execute:exec, | ||
24 | + } | ||
25 | +} | ||
26 | + | ||
27 | +func (t *Periodic) hasClosed() bool { | ||
28 | + t.access.Lock() | ||
29 | + defer t.access.Unlock() | ||
30 | + | ||
31 | + return !t.running | ||
32 | +} | ||
33 | + | ||
34 | +func (t *Periodic) checkedExecute() error { | ||
35 | + if t.hasClosed() { | ||
36 | + return nil | ||
37 | + } | ||
38 | + | ||
39 | + if err := t.Execute(); err != nil { | ||
40 | + t.access.Lock() | ||
41 | + t.running = false | ||
42 | + t.access.Unlock() | ||
43 | + return err | ||
44 | + } | ||
45 | + | ||
46 | + t.access.Lock() | ||
47 | + defer t.access.Unlock() | ||
48 | + | ||
49 | + if !t.running { | ||
50 | + return nil | ||
51 | + } | ||
52 | + | ||
53 | + t.timer = time.AfterFunc(t.Interval, func() { | ||
54 | + t.checkedExecute() // nolint: errcheck | ||
55 | + }) | ||
56 | + | ||
57 | + return nil | ||
58 | +} | ||
59 | + | ||
60 | +// Start implements common.Runnable. | ||
61 | +func (t *Periodic) Start() error { | ||
62 | + t.access.Lock() | ||
63 | + if t.running { | ||
64 | + t.access.Unlock() | ||
65 | + return nil | ||
66 | + } | ||
67 | + t.running = true | ||
68 | + t.access.Unlock() | ||
69 | + | ||
70 | + if err := t.checkedExecute(); err != nil { | ||
71 | + t.access.Lock() | ||
72 | + t.running = false | ||
73 | + t.access.Unlock() | ||
74 | + return err | ||
75 | + } | ||
76 | + | ||
77 | + return nil | ||
78 | +} | ||
79 | + | ||
80 | +// Close implements common.Closable. | ||
81 | +func (t *Periodic) Close() error { | ||
82 | + t.access.Lock() | ||
83 | + defer t.access.Unlock() | ||
84 | + | ||
85 | + t.running = false | ||
86 | + if t.timer != nil { | ||
87 | + t.timer.Stop() | ||
88 | + t.timer = nil | ||
89 | + } | ||
90 | + | ||
91 | + return nil | ||
92 | +} |
sync/task/periodic_test.go
0 → 100644
1 | +package task | ||
2 | + | ||
3 | +import ( | ||
4 | + "gitlab.fjmaimaimai.com/mmm-go/gocomm/common" | ||
5 | + "log" | ||
6 | + "testing" | ||
7 | + "time" | ||
8 | +) | ||
9 | + | ||
10 | +func TestPeriodic(t *testing.T){ | ||
11 | + count:=0 | ||
12 | + task :=NewPeriodic(time.Second*2,func()error{ | ||
13 | + count++ | ||
14 | + log.Println("current count:",count) | ||
15 | + return nil | ||
16 | + }) | ||
17 | + common.Must(task.Start()) | ||
18 | + time.Sleep(time.Second * 5) | ||
19 | + common.Must(task.Close()) | ||
20 | + log.Println("Count:",count) | ||
21 | + common.Must(task.Start()) | ||
22 | + time.Sleep(time.Second*5) | ||
23 | + log.Println("Count:",count) | ||
24 | + common.Must(task.Close()) | ||
25 | +} |
sync/task/task.go
0 → 100644
1 | +package task | ||
2 | + | ||
3 | +import ( | ||
4 | + "context" | ||
5 | + | ||
6 | + "gitlab.fjmaimaimai.com/mmm-go/gocomm/sync/signal/semaphore" | ||
7 | +) | ||
8 | + | ||
9 | +// OnSuccess executes g() after f() returns nil. | ||
10 | +func OnSuccess(f func() error, g func() error) func() error { | ||
11 | + return func() error { | ||
12 | + if err := f(); err != nil { | ||
13 | + return err | ||
14 | + } | ||
15 | + return g() | ||
16 | + } | ||
17 | +} | ||
18 | + | ||
19 | +// Run executes a list of tasks in parallel, returns the first error encountered or nil if all tasks pass. | ||
20 | +func Run(ctx context.Context, tasks ...func() error) error { | ||
21 | + n := len(tasks) | ||
22 | + s := semaphore.New(n) | ||
23 | + done := make(chan error, 1) | ||
24 | + | ||
25 | + for i := range tasks { | ||
26 | + <-s.Wait() | ||
27 | + go func(f func() error) { | ||
28 | + err := f() | ||
29 | + if err == nil { | ||
30 | + s.Signal() | ||
31 | + return | ||
32 | + } | ||
33 | + | ||
34 | + select { | ||
35 | + case done <- err: | ||
36 | + default: | ||
37 | + } | ||
38 | + }(tasks[i]) | ||
39 | + } | ||
40 | + | ||
41 | + for i := 0; i < n; i++ { | ||
42 | + select { | ||
43 | + case err := <-done: | ||
44 | + return err | ||
45 | + case <-ctx.Done(): | ||
46 | + return ctx.Err() | ||
47 | + case <-s.Wait(): | ||
48 | + } | ||
49 | + } | ||
50 | + | ||
51 | + return nil | ||
52 | +} |
sync/task/task_test.go
0 → 100644
1 | +package task | ||
2 | + | ||
3 | +import ( | ||
4 | + "context" | ||
5 | + "errors" | ||
6 | + "github.com/google/go-cmp/cmp" | ||
7 | + "log" | ||
8 | + "strings" | ||
9 | + "testing" | ||
10 | + "time" | ||
11 | +) | ||
12 | + | ||
13 | +func Test_OnSuccess(t *testing.T){ | ||
14 | + work :=func()error{ | ||
15 | + log.Println("do work in") | ||
16 | + return errors.New("do work error") | ||
17 | + } | ||
18 | + afterwork:= func()error{ | ||
19 | + log.Println("after work") | ||
20 | + return nil | ||
21 | + } | ||
22 | + f :=OnSuccess(work,afterwork) | ||
23 | + err := f() | ||
24 | + if err!=nil{ | ||
25 | + log.Println(err) | ||
26 | + } | ||
27 | +} | ||
28 | + | ||
29 | +func Test_ExecuteParallel(t *testing.T){ | ||
30 | + err :=Run(context.Background(), | ||
31 | + func() error { | ||
32 | + time.Sleep(time.Microsecond*300) | ||
33 | + return errors.New("T1") | ||
34 | + }, | ||
35 | + func()error{ | ||
36 | + time.Sleep(time.Microsecond*500) | ||
37 | + return errors.New("T2") | ||
38 | + }) | ||
39 | + if r:=cmp.Diff(err.Error(),"T1");r!=""{ | ||
40 | + t.Error(r) | ||
41 | + } | ||
42 | +} | ||
43 | + | ||
44 | +func Test_ExecuteParallelContextCancel(t *testing.T){ | ||
45 | + ctx,cancel :=context.WithCancel(context.Background()) | ||
46 | + err :=Run(ctx, | ||
47 | + func() error { | ||
48 | + time.Sleep(time.Microsecond*3000) | ||
49 | + return errors.New("T1") | ||
50 | + }, | ||
51 | + func()error{ | ||
52 | + time.Sleep(time.Microsecond*5000) | ||
53 | + return errors.New("T2") | ||
54 | + }, | ||
55 | + func()error{ | ||
56 | + time.Sleep(time.Microsecond*1000) | ||
57 | + cancel() | ||
58 | + return nil | ||
59 | + }) | ||
60 | + errStr := err.Error() | ||
61 | + if strings.Contains(errStr, "canceled") { | ||
62 | + t.Error("expected error string to contain 'canceled', but actually not: ", errStr) | ||
63 | + } | ||
64 | +} | ||
65 | + | ||
66 | +func BenchmarkExecuteOne(b *testing.B){ | ||
67 | + noop:=func()error{ | ||
68 | + return nil | ||
69 | + } | ||
70 | + for i:=0;i<b.N;i++{ | ||
71 | + Run(context.Background(),noop) | ||
72 | + } | ||
73 | +} | ||
74 | + | ||
75 | +func BenchmarkExecuteTwo(b *testing.B){ | ||
76 | + noop:=func()error{ | ||
77 | + return nil | ||
78 | + } | ||
79 | + for i:=0;i<b.N;i++{ | ||
80 | + Run(context.Background(),noop,noop) | ||
81 | + } | ||
82 | +} |
time/time.go
0 → 100644
1 | +package time | ||
2 | + | ||
3 | +import ( | ||
4 | + "fmt" | ||
5 | + "strconv" | ||
6 | + "time" | ||
7 | + "gitlab.fjmaimaimai.com/mmm-go/gocomm/pkg/log" | ||
8 | +) | ||
9 | + | ||
10 | +//获取当前时间字符串,格式:"20170420133114" (2017-04-20 13:3114) | ||
11 | +func GetTimeByYyyymmddhhmmss() string { | ||
12 | + timestamp := time.Now().Unix() | ||
13 | + tm := time.Unix(timestamp, 0) | ||
14 | + return tm.Format("20060102150405") | ||
15 | +} | ||
16 | + | ||
17 | +//获取当前时间字符串,格式:"0420133114" (2017-04-20 13:3114) | ||
18 | +func GetTimeByhhmmss() string { | ||
19 | + timestamp := time.Now().Unix() | ||
20 | + tm := time.Unix(timestamp, 0) | ||
21 | + return tm.Format("150405") | ||
22 | +} | ||
23 | + | ||
24 | +func GetTimeByYyyymmddhhmm() string { | ||
25 | + timestamp := time.Now().Unix() | ||
26 | + tm := time.Unix(timestamp, 0) | ||
27 | + return tm.Format("2006-01-02 15:04") | ||
28 | +} | ||
29 | + | ||
30 | +// 获取当前日期前一天日期 | ||
31 | +func GetDateBeforeDay() string { | ||
32 | + nTime := time.Now() | ||
33 | + yesTime := nTime.AddDate(0, 0, -1) | ||
34 | + logDay := yesTime.Format("20060102") | ||
35 | + return logDay | ||
36 | +} | ||
37 | + | ||
38 | +// 根据指定时间戳获取加减相应时间后的时间戳 | ||
39 | +func GetUnixTimeByUnix(timeUnix int64, years int, months int, days int) int64 { | ||
40 | + if timeUnix < 1 { | ||
41 | + return 0 | ||
42 | + } | ||
43 | + tm := time.Unix(timeUnix, 0) | ||
44 | + return tm.AddDate(years, months, days).Unix() | ||
45 | +} | ||
46 | + | ||
47 | +//获取当前时间字符串,格式:"20170420" (2017-04-20) | ||
48 | +func GetTimeByYyyymmdd() string { | ||
49 | + timestamp := time.Now().Unix() | ||
50 | + tm := time.Unix(timestamp, 0) | ||
51 | + return tm.Format("20060102") | ||
52 | +} | ||
53 | + | ||
54 | +func GetTimeByYyyymmdd2() string { | ||
55 | + timestamp := time.Now().Unix() | ||
56 | + tm := time.Unix(timestamp, 0) | ||
57 | + return tm.Format("2006-01-02") | ||
58 | +} | ||
59 | + | ||
60 | +//获取当前时间字符串,格式:"20170420" (2017-04-20) | ||
61 | +func GetTimeByYyyymmddInt64() (int64, error) { | ||
62 | + timestamp := time.Now().Unix() | ||
63 | + tm := time.Unix(timestamp, 0) | ||
64 | + nowDay, err := strconv.ParseInt(tm.Format("20060102"), 10, 64) | ||
65 | + if err != nil { | ||
66 | + return 0, err | ||
67 | + } | ||
68 | + return nowDay, nil | ||
69 | +} | ||
70 | + | ||
71 | +// 根据时间戳获取对应日期整数 | ||
72 | +func GetTDayByUnixTime(nowUnix int64) int64 { | ||
73 | + if nowUnix < 1 { | ||
74 | + return 0 | ||
75 | + } | ||
76 | + tm := time.Unix(nowUnix, 0) | ||
77 | + nowDay, err := strconv.ParseInt(tm.Format("20060102"), 10, 64) | ||
78 | + if err != nil { | ||
79 | + log.Error(err) | ||
80 | + return 0 | ||
81 | + } | ||
82 | + return nowDay | ||
83 | +} | ||
84 | + | ||
85 | +// 根据时间戳获取对应日期格式 | ||
86 | +func GetDiyTimeByUnixTime(nowUnix int64) string { | ||
87 | + if nowUnix < 1 { | ||
88 | + return "" | ||
89 | + } | ||
90 | + tm := time.Unix(nowUnix, 0) | ||
91 | + return tm.Format("2006/01/02") | ||
92 | +} | ||
93 | + | ||
94 | +// 根据时间戳获取对应月份整数 | ||
95 | +func GetMonthByUnixTime(nowUnix int64) int64 { | ||
96 | + if nowUnix < 1 { | ||
97 | + return 0 | ||
98 | + } | ||
99 | + tm := time.Unix(nowUnix, 0) | ||
100 | + nowDay, err := strconv.ParseInt(tm.Format("200601"), 10, 64) | ||
101 | + if err != nil { | ||
102 | + log.Error(err) | ||
103 | + return 0 | ||
104 | + } | ||
105 | + return nowDay | ||
106 | +} | ||
107 | + | ||
108 | +//获取当前日期(20170802)零点对应的Unix时间戳 | ||
109 | +func GetUnixTimeByYyyymmdd() int64 { | ||
110 | + timeStr := time.Now().Format("2006-01-02") | ||
111 | + | ||
112 | + //使用Parse 默认获取为UTC时区 需要获取本地时区 所以使用ParseInLocation | ||
113 | + t, err := time.ParseInLocation("2006-01-02", timeStr, time.Local) | ||
114 | + if err != nil { | ||
115 | + log.Error(err) | ||
116 | + return 0 | ||
117 | + } | ||
118 | + return t.Unix() | ||
119 | +} | ||
120 | + | ||
121 | +//获取指定时间戳下n天0点时间戳 | ||
122 | +func GetUnixTimeByNDayUnix(timeUnix int64, n int) int64 { | ||
123 | + timeUnix = GetUnixTimeByUnix(timeUnix, 0, 0, n) | ||
124 | + timeStr := time.Unix(timeUnix, 0).Format("2006-01-02") | ||
125 | + | ||
126 | + //使用Parse 默认获取为UTC时区 需要获取本地时区 所以使用ParseInLocation | ||
127 | + t, err := time.ParseInLocation("2006-01-02", timeStr, time.Local) | ||
128 | + if err != nil { | ||
129 | + log.Error(err) | ||
130 | + return 0 | ||
131 | + } | ||
132 | + return t.Unix() | ||
133 | +} | ||
134 | + | ||
135 | +//获取指定时间戳下n月0点时间戳 | ||
136 | +func GetUnixTimeByNMonthUnix(timeUnix int64, n int) int64 { | ||
137 | + timeUnix = GetUnixTimeByUnix(timeUnix, 0, n, 0) | ||
138 | + timeStr := time.Unix(timeUnix, 0).Format("2006-01-02") | ||
139 | + | ||
140 | + //使用Parse 默认获取为UTC时区 需要获取本地时区 所以使用ParseInLocation | ||
141 | + t, err := time.ParseInLocation("2006-01-02", timeStr, time.Local) | ||
142 | + if err != nil { | ||
143 | + log.Error(err) | ||
144 | + return 0 | ||
145 | + } | ||
146 | + return t.Unix() | ||
147 | +} | ||
148 | + | ||
149 | +//获取指定时间下月份0点时间戳 | ||
150 | +func GetUnixTimeByMonthUnix(t time.Time)int64{ | ||
151 | + year, month, _ := t.Date() | ||
152 | + thisMonth := time.Date(year, month, 1, 0, 0, 0, 0, time.Local) | ||
153 | + return thisMonth.Unix() | ||
154 | +} | ||
155 | + | ||
156 | +// 获取制定时间戳是1970年1月1日开始的第几天 | ||
157 | +func GetDaythByTime(timeUnix int64) int64 { | ||
158 | + return (timeUnix+28800)/86400 + 1 | ||
159 | +} | ||
160 | + | ||
161 | +// 获取上个月月初和月末的时间戳 | ||
162 | +func GetLastMonthStartAndEnd() (int64, int64) { | ||
163 | + year, month, _ := time.Now().Date() | ||
164 | + thisMonth := time.Date(year, month, 1, 0, 0, 0, 0, time.Local) | ||
165 | + start := thisMonth.AddDate(0, -1, 0).Unix() | ||
166 | + end := thisMonth.Unix() - 1 | ||
167 | + return start, end | ||
168 | +} | ||
169 | + | ||
170 | +// 根据毫秒时间戳转换成20:18:23:3(20点28分23秒3毫秒)对应的整数(201823003) | ||
171 | +func GetTimeNanoByNano(timeNano int64) int64 { | ||
172 | + tm := time.Unix(timeNano/1000, 0) | ||
173 | + str := fmt.Sprintf("%s%03d", tm.Format("150405"), timeNano%1000) | ||
174 | + n, _ := strconv.ParseInt(str, 10, 64) | ||
175 | + return n | ||
176 | +} |
xstr/xstr.go
0 → 100644
1 | +package xstr | ||
2 | + | ||
3 | +import ( | ||
4 | + "bytes" | ||
5 | + "strconv" | ||
6 | + "strings" | ||
7 | + "sync" | ||
8 | +) | ||
9 | + | ||
10 | +var ( | ||
11 | + bfPool = sync.Pool{ | ||
12 | + New: func() interface{} { | ||
13 | + return bytes.NewBuffer([]byte{}) | ||
14 | + }, | ||
15 | + } | ||
16 | +) | ||
17 | + | ||
18 | +// JoinInts format int64 slice like:n1,n2,n3. | ||
19 | +func JoinInts(is []int64) string { | ||
20 | + if len(is) == 0 { | ||
21 | + return "" | ||
22 | + } | ||
23 | + if len(is) == 1 { | ||
24 | + return strconv.FormatInt(is[0], 10) | ||
25 | + } | ||
26 | + buf := bfPool.Get().(*bytes.Buffer) | ||
27 | + joinWithDelim(buf,is,byte(',')) | ||
28 | + s := buf.String() | ||
29 | + buf.Reset() | ||
30 | + bfPool.Put(buf) | ||
31 | + return s | ||
32 | +} | ||
33 | + | ||
34 | +func joinWithDelim(buf *bytes.Buffer,is []int64,delim byte){ | ||
35 | + for _, i := range is { | ||
36 | + buf.WriteString(strconv.FormatInt(i, 10)) | ||
37 | + buf.WriteByte(',') | ||
38 | + } | ||
39 | + if buf.Len() > 0 { | ||
40 | + buf.Truncate(buf.Len() - 1) | ||
41 | + } | ||
42 | +} | ||
43 | + | ||
44 | +// SplitInts split string into int64 slice. | ||
45 | +func SplitInts(s string) ([]int64, error) { | ||
46 | + if s == "" { | ||
47 | + return nil, nil | ||
48 | + } | ||
49 | + sArr := strings.Split(s, ",") | ||
50 | + res := make([]int64, 0, len(sArr)) | ||
51 | + for _, sc := range sArr { | ||
52 | + i, err := strconv.ParseInt(sc, 10, 64) | ||
53 | + if err != nil { | ||
54 | + return nil, err | ||
55 | + } | ||
56 | + res = append(res, i) | ||
57 | + } | ||
58 | + return res, nil | ||
59 | +} | ||
60 | + |
xstr/xstr_test.go
0 → 100644
1 | +package xstr | ||
2 | + | ||
3 | +import ( | ||
4 | + "testing" | ||
5 | +) | ||
6 | + | ||
7 | +func TestJoinInts(t *testing.T) { | ||
8 | + // test empty slice | ||
9 | + is := []int64{} | ||
10 | + s := JoinInts(is) | ||
11 | + if s != "" { | ||
12 | + t.Errorf("input:%v,output:%s,result is incorrect", is, s) | ||
13 | + } else { | ||
14 | + t.Logf("input:%v,output:%s", is, s) | ||
15 | + } | ||
16 | + // test len(slice)==1 | ||
17 | + is = []int64{1} | ||
18 | + s = JoinInts(is) | ||
19 | + if s != "1" { | ||
20 | + t.Errorf("input:%v,output:%s,result is incorrect", is, s) | ||
21 | + } else { | ||
22 | + t.Logf("input:%v,output:%s", is, s) | ||
23 | + } | ||
24 | + // test len(slice)>1 | ||
25 | + is = []int64{1, 2, 3} | ||
26 | + s = JoinInts(is) | ||
27 | + if s != "1,2,3" { | ||
28 | + t.Errorf("input:%v,output:%s,result is incorrect", is, s) | ||
29 | + } else { | ||
30 | + t.Logf("input:%v,output:%s", is, s) | ||
31 | + } | ||
32 | +} | ||
33 | + | ||
34 | +func TestSplitInts(t *testing.T) { | ||
35 | + // test empty slice | ||
36 | + s := "" | ||
37 | + is, err := SplitInts(s) | ||
38 | + if err != nil || len(is) != 0 { | ||
39 | + t.Error(err) | ||
40 | + } | ||
41 | + // test split int64 | ||
42 | + s = "1,2,3" | ||
43 | + is, err = SplitInts(s) | ||
44 | + if err != nil || len(is) != 3 { | ||
45 | + t.Error(err) | ||
46 | + } | ||
47 | +} | ||
48 | + | ||
49 | +func BenchmarkJoinInts(b *testing.B) { | ||
50 | + is := make([]int64, 10000, 10000) | ||
51 | + for i := int64(0); i < 10000; i++ { | ||
52 | + is[i] = i | ||
53 | + } | ||
54 | + b.ResetTimer() | ||
55 | + b.RunParallel(func(pb *testing.PB) { | ||
56 | + for pb.Next() { | ||
57 | + JoinInts(is) | ||
58 | + } | ||
59 | + }) | ||
60 | +} |
-
请 注册 或 登录 后发表评论