作者 yangfu

gocomm

  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 +}
  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 +}
  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 +//}
  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 +//}
  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 +
  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 +
  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
  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=
  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 +
  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 +}
  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 +}
  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 +}
  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 +}
  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 +}
  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 +}
  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 + }
  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 +}
  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 +}
  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 +}
  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 +}
  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 + }
  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 +}
  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 +}
  1 +package orm
  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 +}
  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 +}
  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 +}
  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 +}
  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 +}
  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 +}
  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 +}
  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 +}
  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 +}
  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 +
  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 +}
  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 +}
  1 +package counter
  2 +
  3 +import (
  4 + "fmt"
  5 + "testing"
  6 +)
  7 +type cc int64
  8 +func TestCounter(t *testing.T){
  9 + var c cc
  10 + c = 1
  11 + fmt.Println(c)
  12 + d :=2
  13 + fmt.Println(d)
  14 + d = int(c)
  15 + fmt.Println(d)
  16 +}
  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 +
  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 +}
  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 +}
  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 +}
  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 +}
  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 +}
  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 +}
  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 +}
  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 +}
  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 +
  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 +}