作者 yangfu

gocomm

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