diff --git a/.fly.yml b/.fly.yml new file mode 100644 index 0000000..ad61d2e --- /dev/null +++ b/.fly.yml @@ -0,0 +1,218 @@ +kind: pipeline +type: docker +name: product + +workspace: + path: /service + +platform: + os: linux + arch: amd64 + +trigger: + branch: + - master + event: + - push + +steps: + - name: version + image: registry.eu-central-1.aliyuncs.com/bibiservice/version:v1.0.0 + pull: always + volumes: + - name: timezone + path: /etc/timezone + - name: localtime + path: /etc/localtime + settings: + image_repository: registry.eu-central-1.aliyuncs.com/bibiservice/user + - name: autotag + image: registry.eu-central-1.aliyuncs.com/bibiservice/autotag:v1.0.0 + pull: always + volumes: + - name: timezone + path: /etc/timezone + - name: localtime + path: /etc/localtime + - name: chart + image: registry.eu-central-1.aliyuncs.com/bibiservice/chart:v1.0.0 + pull: always + volumes: + - name: timezone + path: /etc/timezone + - name: localtime + path: /etc/localtime + settings: + git_repository: + name_space: bibi-service + replicas: 3 + image_repository: registry.eu-central-1.aliyuncs.com/bibiservice/user + service_name: user + service_port: 80 + service_type: ClusterIP + service_account_name: bibi + stage: product + - name: build + image: registry.eu-central-1.aliyuncs.com/bibiservice/golang:1.15.3-alpine3.12-ur + pull: always + privileged: true + volumes: + - name: go + path: /go + - name: timezone + path: /etc/timezone + - name: localtime + path: /etc/localtime + commands: + - go mod tidy + - go build -o ./pack/service main.go + - name: docker + image: registry.eu-central-1.aliyuncs.com/bibiservice/docker:v1.0.0 + pull: always + volumes: + - name: docker_sock + path: /var/run/docker.sock + - name: timezone + path: /etc/timezone + - name: localtime + path: /etc/localtime + settings: + service_name: user + image_repository: registry.eu-central-1.aliyuncs.com/bibiservice/user + - name: k8s + image: registry.eu-central-1.aliyuncs.com/bibiservice/helm:1.0.0-product + pull: always + volumes: + - name: timezone + path: /etc/timezone + - name: localtime + path: /etc/localtime + commands: + - helm template chart | kubectl apply -f - + +image_pull_secrets: + - docker_config_json + +volumes: + - name: go + host: + path: /go + - name: docker_sock + host: + path: /var/run/docker.sock + - name: timezone + host: + path: /etc/timezone + - name: localtime + host: + path: /etc/localtime + +--- +kind: pipeline +type: docker +name: test + +workspace: + path: /service + +platform: + os: linux + arch: amd64 + +trigger: + branch: + - develop + event: + - push + +steps: + - name: version + image: registry.eu-central-1.aliyuncs.com/bibiservice/version:v1.0.0 + pull: always + volumes: + - name: timezone + path: /etc/timezone + - name: localtime + path: /etc/localtime + settings: + image_repository: registry.eu-central-1.aliyuncs.com/bibiservice/user + - name: autotag + image: registry.eu-central-1.aliyuncs.com/bibiservice/autotag:v1.0.0 + pull: always + volumes: + - name: timezone + path: /etc/timezone + - name: localtime + path: /etc/localtime + - name: chart + image: registry.eu-central-1.aliyuncs.com/bibiservice/chart:v1.0.0 + pull: always + volumes: + - name: timezone + path: /etc/timezone + - name: localtime + path: /etc/localtime + settings: + git_repository: + name_space: bibi-service + replicas: 3 + image_repository: registry.eu-central-1.aliyuncs.com/bibiservice/user + service_name: user + service_port: 80 + service_type: ClusterIP + service_account_name: bibi + stage: test + - name: build + image: registry.eu-central-1.aliyuncs.com/bibiservice/golang:1.15.3-alpine3.12-ur + pull: always + privileged: true + volumes: + - name: go + path: /go + - name: timezone + path: /etc/timezone + - name: localtime + path: /etc/localtime + commands: + - go mod tidy + - go build -o ./pack/service main.go + - name: docker + image: registry.eu-central-1.aliyuncs.com/bibiservice/docker:v1.0.0 + pull: always + volumes: + - name: docker_sock + path: /var/run/docker.sock + - name: timezone + path: /etc/timezone + - name: localtime + path: /etc/localtime + settings: + service_name: user + image_repository: registry.eu-central-1.aliyuncs.com/bibiservice/user + - name: k8s + image: registry.eu-central-1.aliyuncs.com/bibiservice/helm:1.0.0-test + pull: always + volumes: + - name: timezone + path: /etc/timezone + - name: localtime + path: /etc/localtime + commands: + - helm template chart | kubectl apply -f - + +image_pull_secrets: + - docker_config_json + +volumes: + - name: go + host: + path: /go + - name: docker_sock + host: + path: /var/run/docker.sock + - name: timezone + host: + path: /etc/timezone + - name: localtime + host: + path: /etc/localtime \ No newline at end of file diff --git a/.version.yml b/.version.yml new file mode 100644 index 0000000..30750c3 --- /dev/null +++ b/.version.yml @@ -0,0 +1,8 @@ +git: + tag: v1.0.11 +image: + tag: v1.0.11 +version: + feature: 1 + hotfix: 11 + main: 3 \ No newline at end of file diff --git a/api_test/bench_test.go b/api_test/bench_test.go new file mode 100644 index 0000000..182116d --- /dev/null +++ b/api_test/bench_test.go @@ -0,0 +1,86 @@ +package apitest + +//import ( +// "github.com/rs/zerolog/log" +// "gitlab.chongshengteng.cn/bibi_service/protobuf/pb" +// "google.golang.org/protobuf/proto" +// "sync" +// "testing" +// "time" +//) +// +//func TestUserPropertyGetBench(t *testing.T) { +// //SignInTest(t) +// +// start := time.Now().UnixNano() +// t.Log("start time:", time.Now().UnixNano()) +// +// for k := 0; k < 30; k++ { +// var wg sync.WaitGroup +// for i := 0; i < 8000; i++ { +// wg.Add(1) +// go UserPropertyGet(t, &wg) +// } +// +// wg.Wait() +// +// end := time.Now().UnixNano() +// duration := end - start +// t.Log("--------------------duration:", duration) +// +// time.Sleep(time.Second * 2) +// } +// +// t.Log("--------------------ok") +// +// time.Sleep(time.Second * 60) +//} +// +//func UserPropertyGet(t *testing.T, wg *sync.WaitGroup) { +// defer wg.Done() +// +// //t.Log("用户uid:", UserBase.GetUid()) +// uid := UserBase.GetUid() +// userPropertyGet := &pb.ReqUserPropertyGet{ +// Uid: UserBase.GetUid(), +// } +// +// reqBytes, err := proto.Marshal(userPropertyGet) +// if err != nil { +// log.Error().Msgf("err=%v", err) +// return +// } +// +// req := GetReq(pb.MsgType_UserPropertyGet, reqBytes, uid) +// +// resp, err := DoRequest(req, Token) +// if err != nil { +// t.Error(err) +// return +// } +// +// statusCode := resp.GetCode() +// if statusCode != pb.StatusCode_StatusOK { +// t.Log("状态码出错") +// t.Fail() +// return +// } +// +// respBytes := resp.GetRspBytes() +// +// var rspUserPropertyGet pb.RspUserPropertyGet +// err = proto.Unmarshal(respBytes, &rspUserPropertyGet) +// if err != nil { +// t.Error(err) +// return +// } +// +// t.Logf("UserPropertyGet=%#v", rspUserPropertyGet.String()) +// +// //getUserProperty := rspUserPropertyGet.GetUserProperty() +// //getUserPropertyJson, _ := json.Marshal(getUserProperty) +// //t.Logf("getUserPropertyJson= %s", string(getUserPropertyJson)) +// //t.Logf("getUserProperty.GetPoint= %#v", getUserProperty.GetPoint()) +// //t.Logf("getUserProperty.GetRm= %#v", getUserProperty.GetRm()) +// //t.Logf("getUserProperty.GetVm= %#v", getUserProperty.GetVm()) +//} diff --git a/api_test/data_test.go b/api_test/data_test.go new file mode 100644 index 0000000..a7bfbf0 --- /dev/null +++ b/api_test/data_test.go @@ -0,0 +1,24 @@ +package apitest + +import ( + "fmt" + "testing" +) + +func TestRedisData(t *testing.T) { + //InitRedis() + //uids := []string{"21000505", "21000501", "21000503", "21000507"} + //results, err := libredis.GetRedisClient().HMGet(context.TODO(), model.RedisHashKeyUserInRoomRole(21000505), uids...).Result() + //if err != nil && err.Error() != redis.Nil.Error() { + // t.Log("err=", err) + //} + //t.Logf("results:%v", results) + //if len(results) != len(uids) { + // t.Log("userBases role error") + //} + +} + +func RedisKeyRoomOnlineUserList(roomId uint32) string { + return fmt.Sprintf("room:user:%d", roomId) +} diff --git a/cmd/start.go b/cmd/start.go new file mode 100644 index 0000000..a18000a --- /dev/null +++ b/cmd/start.go @@ -0,0 +1,72 @@ +package cmd + +import ( + "fmt" + "gitee.com/codinl/erp_server/config" + "gitee.com/codinl/erp_server/lib/auth" + "gitee.com/codinl/erp_server/lib/log" + "gitee.com/codinl/erp_server/model" + "gitee.com/codinl/erp_server/router" + "github.com/codinl/go-logger" + "github.com/gin-gonic/gin" + "github.com/urfave/cli/v2" + "os" +) + +func Start() { + app := &cli.App{ + Commands: []*cli.Command{ + { + Name: "start", + Usage: "启动服务", + Action: startService, + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: config.ServiceName, + Aliases: []string{"n"}, + Usage: "服务名", + Value: "erp", + }, + &cli.StringFlag{ + Name: config.STAGE, + Aliases: []string{"s"}, + Usage: "stage", + Value: config.DefaultStage, + EnvVars: []string{config.STAGE}, + }, + }, + }, + }, + } + if err := app.Run(os.Args); err != nil { + logger.Fatal("err:", err) + } +} + +func startService(c *cli.Context) error { + err := config.Init(c) + if err != nil { + fmt.Println("config init err:", err) + return err + } + log.Init(config.ConfigValue.LoggerPath, config.ConfigValue.LoggerFile, config.ConfigValue.LoggerLevel) + model.InitDB() + auth.Init(config.ConfigValue.JwtKey, int64(config.ConfigValue.JwtExpire)) + + runServer() + + return nil +} + +func runServer() { + server := gin.Default() + gin.SetMode(gin.DebugMode) + + router.ConfigAppRouter(server) + + err := server.Run(fmt.Sprintf(":%d", 8030)) + if err != nil { + logger.Error(err) + return + } +} diff --git a/config/config.go b/config/config.go new file mode 100644 index 0000000..fe6ac82 --- /dev/null +++ b/config/config.go @@ -0,0 +1,121 @@ +package config + +import ( + "fmt" + "gitee.com/codinl/erp_server/config/file" + "gitee.com/codinl/erp_server/config/internal" + "github.com/codinl/go-logger" + + "github.com/urfave/cli/v2" +) + +var ConfigValue *configValue + +// Config 当前service的config +var Config internal.Config + +type configValue struct { + ConfigHost string `json:"config_host"` + ConfigPort int `json:"config_port"` + + ServiceHttpPort int `json:"service_http_port"` + ServiceRpcPort int `json:"service_rpc_port"` + ServiceHttpsPort int `json:"service_https_port"` + + MysqlDriver string `json:"mysql_driver"` + MysqlHost string `json:"mysql_host"` + MysqlPort string `json:"mysql_port"` + MysqlUser string `json:"mysql_user"` + MysqlDBName string `json:"mysql_db_name"` + MysqlPassword string `json:"mysql_user_password"` + + RedisHost string `json:"redis_host"` + RedisPort string `json:"redis_port"` + RedisUser string `json:"redis_user"` + RedisPassword string `json:"redis_password"` + + MongoHost string `json:"mongo_host"` + MongoPort string `json:"mongo_port"` + MongoUser string `json:"mongo_user"` + MongoPassword string `json:"mongo_password"` + MongoDBName string `json:"mongo_db_name"` + + AliyunAccessKeyID string `json:"aliyun_access_key_id"` + AliyunAccessKeySecret string `json:"aliyun_access_key_secret"` + AliyunRoleArn string `json:"aliyun_role_arn"` + AliyunOssBaseUrl string `json:"aliyun_oss_base_url"` + AliyunOssBucketName string `json:"aliyun_oss_bucket_name"` + AliyunKafkaEndpoint string `json:"aliyun_kafka_endpoint"` + + JwtKey string `json:"jwt_key"` + JwtExpire int `json:"jwt_expire"` + + PaypalClientId string `json:"paypal_client_id"` + PaypalSecret string `json:"paypal_secret"` + PaypalAPIBase string `json:"paypal_api_base"` + + LoggerPath string `json:"logger_path"` + LoggerFile string `json:"logger_file"` + LoggerLevel int `json:"logger_level"` +} + +func Init(c *cli.Context) error { + //servicePath := fmt.Sprintf("%s/.app.config.yaml", DefaultConfigPath) + servicePath := fmt.Sprintf("%s/.app.config.yaml", ".") + cfg := internal.New(internal.WithSource( + file.NewSource(servicePath), + )) + if err := cfg.Load(); err != nil { + logger.Error("cfg load err:", err) + return err + } + + Config = cfg + + ConfigValue = &configValue{ + ConfigHost: Config.Value("config.host").String(), + ConfigPort: int(Config.Value("config.port").Int()), + + ServiceHttpPort: int(Config.Value("service.http.port").Int()), + ServiceRpcPort: int(Config.Value("service.rpc.port").Int()), + ServiceHttpsPort: int(Config.Value("service.https.port").Int()), + + MysqlDriver: Config.Value("mysql.driver").String(), + MysqlHost: Config.Value("mysql.host").String(), + MysqlPort: Config.Value("mysql.port").String(), + MysqlUser: Config.Value("mysql.user").String(), + MysqlDBName: Config.Value("mysql.db_name").String(), + MysqlPassword: Config.Value("mysql.password").String(), + + RedisHost: Config.Value("redis.host").String(), + RedisPort: Config.Value("redis.port").String(), + RedisUser: Config.Value("redis.user").String(), + RedisPassword: Config.Value("redis.password").String(), + + MongoHost: Config.Value("mongo.host").String(), + MongoPort: Config.Value("mongo.port").String(), + MongoUser: Config.Value("mongo.user").String(), + MongoPassword: Config.Value("mongo.password").String(), + MongoDBName: Config.Value("mongo.db_name").String(), + + AliyunAccessKeyID: "", + AliyunAccessKeySecret: "", + AliyunRoleArn: "", + AliyunOssBaseUrl: "", + AliyunOssBucketName: "", + AliyunKafkaEndpoint: "", + + JwtKey: Config.Value("jwt.key").String(), + JwtExpire: int(Config.Value("jwt.expire").Int()), + + PaypalClientId: Config.Value("paypal.client_id").String(), + PaypalSecret: Config.Value("paypal.secret").String(), + PaypalAPIBase: Config.Value("paypal.api_base").String(), + + LoggerPath: Config.Value("logger.path").String(), + LoggerFile: Config.Value("logger.file").String(), + LoggerLevel: int(Config.Value("logger.level").Int()), + } + + return nil +} diff --git a/config/const.go b/config/const.go new file mode 100644 index 0000000..87b10c5 --- /dev/null +++ b/config/const.go @@ -0,0 +1,25 @@ +package config + +const ServiceName = "service_name" + +const Local = "Local" + +const ( + Yes = "yes" + No = "no" +) + +const DefaultConfigPath = "./pack" +const DefaultConfigSuffix = ".yaml" + +const ( + STAGE = "STAGE" + + StageLocal = "local" + StageDevelop = "develop" + StageTest = "test" + StageRelease = "release" + StageProduct = "product" + + DefaultStage = StageLocal +) diff --git a/config/file/file.go b/config/file/file.go new file mode 100644 index 0000000..aab17b4 --- /dev/null +++ b/config/file/file.go @@ -0,0 +1,75 @@ +package file + +import ( + "gitee.com/codinl/erp_server/config/internal" + "io/ioutil" + "os" + "path/filepath" + "strings" +) + +var _ internal.Source = (*file)(nil) + +type file struct { + path string +} + +// NewSource new a file source. +func NewSource(path string) internal.Source { + return &file{path: path} +} + +func (f *file) loadFile(path string) (*internal.KeyValue, error) { + file, err := os.Open(path) + if err != nil { + return nil, err + } + defer file.Close() + data, err := ioutil.ReadAll(file) + if err != nil { + return nil, err + } + info, err := file.Stat() + if err != nil { + return nil, err + } + return &internal.KeyValue{ + Key: info.Name(), + Format: format(info.Name()), + Value: data, + }, nil +} + +func (f *file) loadDir(path string) (kvs []*internal.KeyValue, err error) { + files, err := ioutil.ReadDir(f.path) + if err != nil { + return nil, err + } + for _, file := range files { + // ignore hidden files + if file.IsDir() || strings.HasPrefix(file.Name(), ".") { + continue + } + kv, err := f.loadFile(filepath.Join(f.path, file.Name())) + if err != nil { + return nil, err + } + kvs = append(kvs, kv) + } + return +} + +func (f *file) Load() (kvs []*internal.KeyValue, err error) { + fi, err := os.Stat(f.path) + if err != nil { + return nil, err + } + if fi.IsDir() { + return f.loadDir(f.path) + } + kv, err := f.loadFile(f.path) + if err != nil { + return nil, err + } + return []*internal.KeyValue{kv}, nil +} diff --git a/config/file/format.go b/config/file/format.go new file mode 100644 index 0000000..9e20e60 --- /dev/null +++ b/config/file/format.go @@ -0,0 +1,10 @@ +package file + +import "strings" + +func format(name string) string { + if p := strings.Split(name, "."); len(p) > 1 { + return p[len(p)-1] + } + return "" +} diff --git a/config/internal/config.go b/config/internal/config.go new file mode 100644 index 0000000..5f2851f --- /dev/null +++ b/config/internal/config.go @@ -0,0 +1,90 @@ +package internal + +import ( + "errors" + "github.com/go-kratos/kratos/v2/log" + "sync" + + // init encoding + _ "github.com/go-kratos/kratos/v2/encoding/json" + _ "github.com/go-kratos/kratos/v2/encoding/proto" + _ "github.com/go-kratos/kratos/v2/encoding/xml" + _ "github.com/go-kratos/kratos/v2/encoding/yaml" +) + +var ( + // ErrNotFound is key not found. + ErrNotFound = errors.New("key not found") + // ErrTypeAssert is type assert error. + ErrTypeAssert = errors.New("type assert error") + + _ Config = (*config)(nil) +) + +// Observer is config observer. +type Observer func(string, Value) + +// Config is a config interface. +type Config interface { + Load() error + Bytes() ([]byte, error) + Value(key string) Value +} + +type config struct { + opts options + reader Reader + cached sync.Map + observers sync.Map + log *log.Helper +} + +// New new a config with options. +func New(opts ...Option) Config { + o := options{ + logger: log.DefaultLogger, + decoder: defaultDecoder, + resolver: defaultResolver, + } + for _, opt := range opts { + opt(&o) + } + return &config{ + opts: o, + reader: newReader(o), + log: log.NewHelper(o.logger), + } +} + +func (c *config) Load() error { + for _, src := range c.opts.sources { + kvs, err := src.Load() + if err != nil { + return err + } + if err = c.reader.Merge(kvs...); err != nil { + c.log.Errorf("failed to merge config source: %v", err) + return err + } + } + if err := c.reader.Resolve(); err != nil { + c.log.Errorf("failed to resolve config source: %v", err) + return err + } + return nil +} + +func (c *config) Bytes() ([]byte, error) { + return c.reader.Bytes() +} + +func (c *config) Value(key string) Value { + if v, ok := c.cached.Load(key); ok { + return v.(Value) + } + if v, ok := c.reader.Value(key); ok { + c.cached.Store(key, v) + return v + } + return &errValue{err: ErrNotFound} +} diff --git a/config/internal/options.go b/config/internal/options.go new file mode 100644 index 0000000..8295246 --- /dev/null +++ b/config/internal/options.go @@ -0,0 +1,134 @@ +package internal + +import ( + "fmt" + "regexp" + "strings" + + "github.com/go-kratos/kratos/v2/encoding" + "github.com/go-kratos/kratos/v2/log" +) + +// Decoder is config decoder. +type Decoder func(*KeyValue, map[string]interface{}) error + +// Resolver resolve placeholder in config. +type Resolver func(map[string]interface{}) error + +// Option is config option. +type Option func(*options) + +type options struct { + sources []Source + decoder Decoder + resolver Resolver + logger log.Logger +} + +// WithSource with config source. +func WithSource(s ...Source) Option { + return func(o *options) { + o.sources = s + } +} + +// WithDecoder with config decoder. +// DefaultDecoder behavior: +// If KeyValue.Format is non-empty, then KeyValue.Value will be deserialized into map[string]interface{} +// and stored in the config cache(map[string]interface{}) +// if KeyValue.Format is empty,{KeyValue.Key : KeyValue.Value} will be stored in config cache(map[string]interface{}) +func WithDecoder(d Decoder) Option { + return func(o *options) { + o.decoder = d + } +} + +// WithResolver with config resolver. +func WithResolver(r Resolver) Option { + return func(o *options) { + o.resolver = r + } +} + +// WithLogger with config logger. +func WithLogger(l log.Logger) Option { + return func(o *options) { + o.logger = l + } +} + +// defaultDecoder decode config from source KeyValue +// to target map[string]interface{} using src.Format codec. +func defaultDecoder(src *KeyValue, target map[string]interface{}) error { + if src.Format == "" { + // expand key "aaa.bbb" into map[aaa]map[bbb]interface{} + keys := strings.Split(src.Key, ".") + for i, k := range keys { + if i == len(keys)-1 { + target[k] = src.Value + } else { + sub := make(map[string]interface{}) + target[k] = sub + target = sub + } + } + return nil + } + if codec := encoding.GetCodec(src.Format); codec != nil { + return codec.Unmarshal(src.Value, &target) + } + return fmt.Errorf("unsupported key: %s format: %s", src.Key, src.Format) +} + +// defaultResolver resolve placeholder in map value, +// placeholder format in ${key:default}. +func defaultResolver(input map[string]interface{}) error { + mapper := func(name string) string { + args := strings.SplitN(strings.TrimSpace(name), ":", 2) //nolint:gomnd + if v, has := readValue(input, args[0]); has { + return v.String() + } else if len(args) > 1 { // default value + return args[1] + } + return "" + } + + var resolve func(map[string]interface{}) error + resolve = func(sub map[string]interface{}) error { + for k, v := range sub { + switch vt := v.(type) { + case string: + sub[k] = expand(vt, mapper) + case map[string]interface{}: + if err := resolve(vt); err != nil { + return err + } + case []interface{}: + for i, iface := range vt { + switch it := iface.(type) { + case string: + vt[i] = expand(it, mapper) + case map[string]interface{}: + if err := resolve(it); err != nil { + return err + } + } + } + sub[k] = vt + } + } + return nil + } + return resolve(input) +} + +func expand(s string, mapping func(string) string) string { + r := regexp.MustCompile(`\${(.*?)}`) + re := r.FindAllStringSubmatch(s, -1) + for _, i := range re { + if len(i) == 2 { //nolint:gomnd + s = strings.ReplaceAll(s, i[0], mapping(i[1])) + } + } + return s +} diff --git a/config/internal/reader.go b/config/internal/reader.go new file mode 100644 index 0000000..2c18b6f --- /dev/null +++ b/config/internal/reader.go @@ -0,0 +1,175 @@ +package internal + +import ( + "bytes" + "encoding/gob" + "encoding/json" + "errors" + "fmt" + "github.com/go-kratos/kratos/v2/encoding" + "strings" + "sync" + + "github.com/imdario/mergo" + "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" +) + +// Reader is config reader. +type Reader interface { + Merge(...*KeyValue) error + Value(string) (Value, bool) + Source() ([]byte, error) + Bytes() ([]byte, error) + Resolve() error +} + +type reader struct { + opts options + values map[string]interface{} + lock sync.Mutex +} + +func newReader(opts options) Reader { + return &reader{ + opts: opts, + values: make(map[string]interface{}), + lock: sync.Mutex{}, + } +} + +func (r *reader) Bytes() ([]byte, error) { + if codec := encoding.GetCodec("yaml"); codec != nil { + return codec.Marshal(r.values) + } + return nil, errors.New("fail") +} + +func (r *reader) Merge(kvs ...*KeyValue) error { + r.lock.Lock() + merged, err := cloneMap(r.values) + r.lock.Unlock() + if err != nil { + return err + } + for _, kv := range kvs { + next := make(map[string]interface{}) + if err := r.opts.decoder(kv, next); err != nil { + return err + } + if err := mergo.Map(&merged, convertMap(next), mergo.WithOverride); err != nil { + return err + } + } + r.lock.Lock() + r.values = merged + r.lock.Unlock() + return nil +} + +func (r *reader) Value(path string) (Value, bool) { + r.lock.Lock() + defer r.lock.Unlock() + return readValue(r.values, path) +} + +func (r *reader) Source() ([]byte, error) { + r.lock.Lock() + defer r.lock.Unlock() + return marshalJSON(convertMap(r.values)) +} + +func (r *reader) Resolve() error { + r.lock.Lock() + defer r.lock.Unlock() + return r.opts.resolver(r.values) +} + +func cloneMap(src map[string]interface{}) (map[string]interface{}, error) { + // https://gist.github.com/soroushjp/0ec92102641ddfc3ad5515ca76405f4d + var buf bytes.Buffer + gob.Register(map[string]interface{}{}) + gob.Register([]interface{}{}) + enc := gob.NewEncoder(&buf) + dec := gob.NewDecoder(&buf) + err := enc.Encode(src) + if err != nil { + return nil, err + } + var copy map[string]interface{} + err = dec.Decode(©) + if err != nil { + return nil, err + } + return copy, nil +} + +func convertMap(src interface{}) interface{} { + switch m := src.(type) { + case map[string]interface{}: + dst := make(map[string]interface{}, len(m)) + for k, v := range m { + dst[k] = convertMap(v) + } + return dst + case map[interface{}]interface{}: + dst := make(map[string]interface{}, len(m)) + for k, v := range m { + dst[fmt.Sprint(k)] = convertMap(v) + } + return dst + case []interface{}: + dst := make([]interface{}, len(m)) + for k, v := range m { + dst[k] = convertMap(v) + } + return dst + case []byte: + // there will be no binary data in the config data + return string(m) + default: + return src + } +} + +// readValue read Value in given map[string]interface{} +// by the given path, will return false if not found. +func readValue(values map[string]interface{}, path string) (Value, bool) { + var ( + next = values + keys = strings.Split(path, ".") + last = len(keys) - 1 + ) + for idx, key := range keys { + value, ok := next[key] + if !ok { + return nil, false + } + if idx == last { + av := &atomicValue{} + av.Store(value) + return av, true + } + switch vm := value.(type) { + case map[string]interface{}: + next = vm + default: + return nil, false + } + } + return nil, false +} + +func marshalJSON(v interface{}) ([]byte, error) { + if m, ok := v.(proto.Message); ok { + return protojson.MarshalOptions{EmitUnpopulated: true}.Marshal(m) + } + return json.Marshal(v) +} + +func unmarshalJSON(data []byte, v interface{}) error { + if m, ok := v.(proto.Message); ok { + return protojson.UnmarshalOptions{DiscardUnknown: true}.Unmarshal(data, m) + } + return json.Unmarshal(data, v) +} diff --git a/config/internal/source.go b/config/internal/source.go new file mode 100644 index 0000000..c6c1a83 --- /dev/null +++ b/config/internal/source.go @@ -0,0 +1,13 @@ +package internal + +// KeyValue is config key value. +type KeyValue struct { + Key string + Value []byte + Format string +} + +// Source is config source. +type Source interface { + Load() ([]*KeyValue, error) +} \ No newline at end of file diff --git a/config/internal/value.go b/config/internal/value.go new file mode 100644 index 0000000..eca80f8 --- /dev/null +++ b/config/internal/value.go @@ -0,0 +1,119 @@ +package internal + +import ( + "encoding/json" + "fmt" + "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" + "strconv" + "sync/atomic" +) + +var ( + _ Value = (*atomicValue)(nil) + _ Value = (*errValue)(nil) +) + +// Value is config value interface. +type Value interface { + Bool() bool + Int() int64 + Float() float64 + String() string + Scan(interface{}) error + Load() interface{} + Store(interface{}) +} + +type atomicValue struct { + atomic.Value +} + +func (v *atomicValue) Bool() bool { + switch val := v.Load().(type) { + case bool: + return val + case int, int32, int64, float64, string: + v, err := strconv.ParseBool(fmt.Sprint(val)) + if err == nil { + return v + } + } + return false +} + +func (v *atomicValue) Int() int64 { + switch val := v.Load().(type) { + case int: + return int64(val) + case int32: + return int64(val) + case int64: + return val + case float64: + return int64(val) + case string: + v, err := strconv.ParseInt(val, 10, 64) + if err == nil { + return v + } + } + return 0 +} + +func (v *atomicValue) Float() float64 { + switch val := v.Load().(type) { + case float64: + return val + case int: + return float64(val) + case int32: + return float64(val) + case int64: + return float64(val) + case string: + v, err := strconv.ParseFloat(val, 64) + if err == nil { + return v + } + } + return 0.0 +} + +func (v *atomicValue) String() string { + switch val := v.Load().(type) { + case string: + return val + case bool, int, int32, int64, float64: + return fmt.Sprint(val) + case []byte: + return string(val) + default: + if s, ok := val.(fmt.Stringer); ok { + return s.String() + } + } + return "" +} + +func (v *atomicValue) Scan(obj interface{}) error { + data, err := json.Marshal(v.Load()) + if err != nil { + return err + } + if pb, ok := obj.(proto.Message); ok { + return protojson.Unmarshal(data, pb) + } + return json.Unmarshal(data, obj) +} + +type errValue struct { + err error +} +func (v errValue) Bool() bool { return false } +func (v errValue) Int() int64 { return 0 } +func (v errValue) Float() float64 { return 0.0 } +func (v errValue) String() string { return "" } +func (v errValue) Scan(interface{}) error { return v.err } +func (v errValue) Load() interface{} { return nil } +func (v errValue) Store(interface{}) {} diff --git a/controller/auth.go b/controller/auth.go new file mode 100644 index 0000000..cdb1ffb --- /dev/null +++ b/controller/auth.go @@ -0,0 +1,7 @@ +package controller + +import "github.com/gin-gonic/gin" + +func AuthLogin(c *gin.Context) { + +} diff --git a/controller/base.go b/controller/base.go new file mode 100644 index 0000000..deacf90 --- /dev/null +++ b/controller/base.go @@ -0,0 +1,130 @@ +package controller + +import ( + "encoding/json" + "encoding/xml" + "fmt" + "gitee.com/codinl/erp_server/lib/status" + + "github.com/codinl/go-logger" + "github.com/gin-gonic/gin" +) + +type RespRet struct { + Code int `json:"code"` + Msg string `json:"msg"` + Data interface{} `json:"data"` +} + +func RespJson(c *gin.Context, code int, data interface{}) { + result := RespRet{ + Code: code, + Msg: status.StatusMsg(code), + Data: data, + } + body, err := json.Marshal(result) + if err != nil { + logger.Error(err) + body = []byte{} + } + c.Data(status.OK, "application/json; charset=utf-8", body) + c.Abort() +} + +func RespOK(c *gin.Context, data interface{}) { + result := RespRet{ + Code: 200, + Msg: "成功", + Data: data, + } + body, err := json.Marshal(result) + if err != nil { + logger.Error(err) + body = []byte{} + } + c.Data(status.OK, "application/json; charset=utf-8", body) + c.Abort() +} + +func RespError(c *gin.Context, data ...string) { + var respMsg string + if len(data) > 0 { + respMsg = data[0] + } else { + respMsg = "服务器开小差了" + } + result := RespRet{ + Code: 500, + Msg: respMsg, + Data: "", + } + body, err := json.Marshal(result) + if err != nil { + logger.Error(err) + body = []byte{} + } + c.Data(status.OK, "application/json; charset=utf-8", body) + c.Abort() +} + +func Resp(c *gin.Context, code int, msg string, data interface{}) { + result := RespRet{ + Code: code, + Msg: msg, + Data: data, + } + body, err := json.Marshal(result) + if err != nil { + logger.Error(err) + body = []byte{} + } + c.Data(status.OK, "application/json; charset=utf-8", body) + c.Abort() +} + +func RespNotice(c *gin.Context, code string, msg string) { + result := struct { + Code string `json:"code"` + Message string `json:"message"` + }{ + Code: code, + Message: msg, + } + body, err := json.Marshal(result) + if err != nil { + logger.Error(err) + body = []byte{} + } + c.Data(status.OK, "application/json; charset=utf-8", body) + c.Abort() +} + +func RespBodyXML(c *gin.Context, data interface{}) { + body, err := xml.Marshal(data) + if err != nil { + logger.Error(err) + body = []byte{} + } + fmt.Println("回复消息:", string(body)) + c.Data(status.OK, "application/xml; charset=utf-8", body) + c.Abort() +} + +func Toast(c *gin.Context, data interface{}) { + result := struct { + Code int `json:"code"` + Msg interface{} `json:"msg"` + Data interface{} `json:"data"` + }{ + Code: status.ToastErr, + Msg: data, + Data: data, + } + body, err := json.Marshal(result) + if err != nil { + logger.Error(err) + body = []byte{} + } + c.Data(status.OK, "application/json; charset=utf-8", body) + c.Abort() +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..b5944f0 --- /dev/null +++ b/go.mod @@ -0,0 +1,26 @@ +module gitee.com/codinl/erp_server + +go 1.16 + +require ( + github.com/codinl/go-logger v1.0.0 + github.com/dgrijalva/jwt-go v3.2.0+incompatible + //code.chongshengteng.cn/bibi/i18n v1.0.57 + //code.chongshengteng.cn/bibi/lib v1.0.334 + //github.com/NSObjects/TencentIM v1.0.3 + //github.com/eclipse/paho.mqtt.golang v1.3.1 + github.com/gin-gonic/gin v1.6.3 + github.com/go-kratos/kratos/v2 v2.5.0 + github.com/go-sql-driver/mysql v1.6.0 // indirect + github.com/imdario/mergo v0.3.13 + github.com/jinzhu/gorm v1.9.16 + github.com/jinzhu/now v1.1.5 // indirect + github.com/rs/zerolog v1.28.0 + //github.com/go-redis/redis/v8 v8.4.8 + //github.com/jinzhu/gorm v1.9.16 + //github.com/rs/zerolog v1.20.0 + //github.com/sensorsdata/sa-sdk-go v2.0.1+incompatible + github.com/urfave/cli/v2 v2.3.0 + google.golang.org/protobuf v1.28.1 +//google.golang.org/protobuf v1.25.0 +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..eacafbc --- /dev/null +++ b/go.sum @@ -0,0 +1,254 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc= +github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8= +github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/codinl/go-logger v1.0.0 h1:qjPNKi4v1hx7hraY3qlFvVf2tPuBy284zWJiYrPKMdQ= +github.com/codinl/go-logger v1.0.0/go.mod h1:tDJ+0Vgd7/hp/0V355poSk+rcdwmtbXYor/aG8O3+4A= +github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd h1:83Wprp6ROGeiHFAP8WJdI2RoxALQYgdllERc3N5N2DM= +github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= +github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 h1:Yzb9+7DPaBjB8zlTR87/ElzFsnQfuHnVUVqpZZIcV5Y= +github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0= +github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= +github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14= +github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= +github.com/go-kratos/aegis v0.1.2/go.mod h1:jYeSQ3Gesba478zEnujOiG5QdsyF3Xk/8owFUeKcHxw= +github.com/go-kratos/kratos/v2 v2.5.0 h1:lHpfp/AodxpRM9j8b894EsGTwsL40X8WMjNeJ6ChOqQ= +github.com/go-kratos/kratos/v2 v2.5.0/go.mod h1:5acyLj4EgY428AJnZl2EwCrMV1OVlttQFBum+SghMiA= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= +github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/form/v4 v4.2.0/go.mod h1:q1a2BY+AQUUzhl6xA/6hBetay6dEIhMHjgvJiGo6K7U= +github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= +github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= +github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= +github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= +github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY= +github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= +github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= +github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/golang-jwt/jwt/v4 v4.4.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY= +github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +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.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o= +github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= +github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= +github.com/jinzhu/gorm v1.9.16 h1:+IyIjPEABKRpsu/F8OvDPy9fyQlgsg2luMV2ZIH5i5o= +github.com/jinzhu/gorm v1.9.16/go.mod h1:G3LB3wezTOWM2ITLzPxEXgSkOXAntiLHS7UdBefADcs= +github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= +github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= +github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= +github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= +github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= +github.com/lib/pq v1.1.1 h1:sJZmqHoEaY7f+NPP8pgLB/WxulyR3fewgCM2qaSlBb4= +github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-sqlite3 v1.14.0 h1:mLyGNKR8+Vv9CAU7PphKa2hkEqxxhn8i32J6FPj1/QA= +github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= +github.com/rs/zerolog v1.28.0 h1:MirSo27VyNi7RJYP3078AA1+Cyzd2GB66qy3aUHvsWY= +github.com/rs/zerolog v1.28.0/go.mod h1:NILgTygv/Uej1ra5XxGf82ZFSLk58MFGAUS2o6usyD0= +github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/shirou/gopsutil/v3 v3.21.8/go.mod h1:YWp/H8Qs5fVmf17v7JNZzA0mPJ+mS2e9JdiUF9LlKzQ= +github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/tklauser/go-sysconf v0.3.9/go.mod h1:11DU/5sG7UexIrp/O6g35hrWzu0JxlwQ3LSFUzyeuhs= +github.com/tklauser/numcpus v0.3.0/go.mod h1:yFGUr7TUHQRAhyqBcEg0Ge34zDBAsIvJJcyE6boqnA8= +github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= +github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= +github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= +github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= +github.com/urfave/cli/v2 v2.3.0 h1:qph92Y649prgesehzOrQjdWyxFOp/QVM+6imKHad91M= +github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= +go.opentelemetry.io/otel v1.7.0/go.mod h1:5BdUoMIz5WEs0vt0CUEMtSSaTSHBBVwrhnz7+nrD5xk= +go.opentelemetry.io/otel/sdk v1.7.0/go.mod h1:uTEOTwaqIVuTGiJN7ii13Ibp75wJmYUDe374q6cZwUU= +go.opentelemetry.io/otel/trace v1.7.0/go.mod h1:fzLSB9nqR2eXzxPXb2JW9IKE+ScyXA48yyE4TNvoHqU= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/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-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +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/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220513210516-0976fa681c29/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-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210816074244-15123e1e1f71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad h1:ntjMns5wyP/fN65tdBD4g8J5w8n015+iIIs9rtjXkY0= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0 h1:hjy8E9ON/egN1tAYqKb61G10WtihqetD4sz2H+8nIeA= +gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/lib/auth/auth.go b/lib/auth/auth.go new file mode 100644 index 0000000..8832b06 --- /dev/null +++ b/lib/auth/auth.go @@ -0,0 +1 @@ +package auth diff --git a/lib/auth/auth_user.go b/lib/auth/auth_user.go new file mode 100755 index 0000000..8a90050 --- /dev/null +++ b/lib/auth/auth_user.go @@ -0,0 +1,178 @@ +package auth + +import ( + "errors" + + "gitee.com/codinl/erp_server/lib/status" + "strings" + + "github.com/codinl/go-logger" + "github.com/dgrijalva/jwt-go" + "github.com/gin-gonic/gin" +) + +var ( + TokenExpired error = errors.New("token is expired") + TokenInvalid error = errors.New("couldn't handle this token") + //TokenNotValidYet error = errors.New("Token not active yet") + //TokenMalformed error = errors.New("That's not even a token") +) + +var jwtUserAccessKey string +var jwtUserRefreshKey string +var jwtUserAccessExpire int64 +var jwtUserRefreshExpire int64 + +var jwtAdminAccessKey string + +//var jwtAdminRefreshKey string +//var jwtAdminAccessExpire int64 +//var jwtAdminRefreshExpire int64 + +func Init(userAccessKey string, userAccessExpire int64) { + jwtUserAccessKey = userAccessKey + jwtUserAccessExpire = userAccessExpire +} + +func UserAccessAuth(c *gin.Context) { + token := c.Request.Header.Get("Authorization") + if s := strings.Split(token, " "); len(s) == 2 { + token = s[1] + } + if token == "" || len(token) < 10 { + // TODO + //RespJson(c, status.Unauthorized, nil) + return + } + + j := NewJWT(jwtUserAccessKey) + claims, err := j.ParseToken(token) + if err != nil { + logger.Error(err) + if err == TokenExpired { + RespJson(c, status.AccessTokenExpired, nil) + } + //else { // TODO + // RespJson(c, status.Unauthorized, nil) + //} + return + } + + c.Set("claims", claims) +} + +func AdminAccessAuth(c *gin.Context) { + token := c.Request.Header.Get("Authorization") + if s := strings.Split(token, " "); len(s) == 2 { + token = s[1] + } + if token == "" || len(token) < 10 { + RespJson(c, status.Unauthorized, nil) + return + } + + j := NewJWT(jwtAdminAccessKey) + claims, err := j.ParseToken(token) + if err != nil { + RespJson(c, status.Unauthorized, nil) + return + } + + c.Set("claims", claims) +} + +func RespJson(c *gin.Context, code int, data interface{}) { + result := struct { + Code int `json:"code"` + Msg string `json:"msg"` + Desc string `json:"desc"` + Data interface{} `json:"data"` + }{ + Code: code, + Desc: status.StatusDesc(code), + Data: data, + } + c.JSON(status.OK, result) + c.Abort() +} + +type JWT struct { + SigningKey []byte +} + +type UserClaims struct { + Uid uint32 `json:"uid"` + jwt.StandardClaims +} + +func NewJWT(key string) *JWT { + return &JWT{ + []byte(key), + } +} + +//func (j *JWT) CreateToken(user *UserClaims) (string, error) { +// user.ExpiresAt = jwt.TimeFunc().Unix() + int64(jwtUserAccessExpire) +// token := jwt.NewWithClaims(jwt.SigningMethodHS256, user) +// return token.SignedString(j.SigningKey) +//} + +func (j *JWT) CreateToken(uid uint32, key string, expire int64) (string, error) { + user := UserClaims{ + Uid: uid, + } + user.ExpiresAt = jwt.TimeFunc().Unix() + expire + token := jwt.NewWithClaims(jwt.SigningMethodHS256, user) + return token.SignedString(key) +} + +func (j *JWT) ParseToken(tokenString string) (*UserClaims, error) { + token, err := jwt.ParseWithClaims(tokenString, &UserClaims{}, func(token *jwt.Token) (interface{}, error) { + return j.SigningKey, nil + }) + + if err != nil { + e := err.(*jwt.ValidationError) + if e.Errors&jwt.ValidationErrorExpired != 0 { + return nil, TokenExpired + } + return nil, err + } + + if claims, ok := token.Claims.(*UserClaims); ok && token.Valid { + return claims, nil + } else { + logger.Error(err) + } + + return nil, TokenInvalid +} + +func GetCurrentUser(c *gin.Context) *UserClaims { + claims, ok := c.Get("claims") + if !ok { + return nil + } + user, ok := claims.(*UserClaims) + if ok { + return user + } + return nil +} + +func CreateToken(uid uint32, key string, expire int64) (string, error) { + user := UserClaims{ + Uid: uid, + } + user.ExpiresAt = jwt.TimeFunc().Unix() + expire + token := jwt.NewWithClaims(jwt.SigningMethodHS256, user) + return token.SignedString([]byte(key)) +} + +func CreateAccessToken(uid uint32) (string, error) { + return CreateToken(uid, jwtUserAccessKey, jwtUserAccessExpire) +} + +func CreateRefreshToken(uid uint32) (string, error) { + return CreateToken(uid, jwtUserRefreshKey, jwtUserRefreshExpire) +} diff --git a/lib/log/init.go b/lib/log/init.go new file mode 100644 index 0000000..c64c5ac --- /dev/null +++ b/lib/log/init.go @@ -0,0 +1,16 @@ +package log + +import ( + "fmt" + + "github.com/codinl/go-logger" +) + +func Init(path, file string, level int) { + err := logger.Init(path, file, level, true, true, true) + if err != nil { + fmt.Println("logger init error:", err) + panic(err) + } + fmt.Println("logger init success") +} diff --git a/lib/status/status.go b/lib/status/status.go new file mode 100644 index 0000000..7f9ef27 --- /dev/null +++ b/lib/status/status.go @@ -0,0 +1,268 @@ +package status + +//20x 一定是正确。所有异常都不使用200返回码 +//10x 用于指定客户端应相应的某些动作。 +//20x 用于表示请求成功。 +//30x 表示要完成请求,需要进一步操作(重定向)。 +//40x 客户端请求问题 +//50x 服务器错误。 + +//错误码的前3位是http status code +const ( + //10x 消息 + + //20x 成功----------------------------------------------------------------------------------/ + OK = 200 //成功 + + // 400xx StatusBadRequest:请求参数有误,当前请求无法被服务器理解 + BadRequest = 400001 // 通用型,错误的请求 + PwdIllegal = 400002 // 密码不合法 + CaptchaErr = 400003 // 验证码错误 + CheckSignFail = 400004 // 验证签名失败 + TelOrCaptchaErr = 400005 // 手机号或验证码错误 + + //402xx StatusUnauthorized 当前请求需要用户验证 + Unauthorized = 402001 //用户没有登录 + AccessTokenExpired = 402002 //access token过期 + RefreshTokenExpired = 402003 //refresh token过期 + RefreshTokenInvalid = 402004 //refresh token无效 + + //403xx StatusForbidden 服务器已经理解请求,但是拒绝执行它 + Forbidden = 403001 // 通用型, 服务器拒绝执行 + LoginFail = 403002 // 登录失败,账号或密码错误 + UserNameUsed = 403003 // 用户名已使用 + EmailUsed = 403004 // 邮箱已使用 + TelUsed = 403005 // 手机号已使用 + LogoutFail = 403006 // 登出失败 + RegisterFail = 403007 // 注册失败 + UpdateTokenFail = 403008 // 更新token失败 + UpdateFail = 403009 // 更新失败 + LockUserAuthed = 403012 // 用户已授权 + ServerBusy = 403022 // 服务器繁忙,请稍后再试 + MoneySufficient = 403024 // 余额不足 + UserHasBeenInvited = 403029 // 用户已被邀请过 + UserSelfInviteSelf = 403030 // 不允自己邀请自己 + OutOffWithdrawCountLimit = 403041 // 超出当月提现次数 + OutOffWithdrawAccountLimit = 403042 // 超出提现金额范围 + CaptchaDelivered = 403044 // 验证码已发出 + NeedBindTel = 403045 // 需要绑定手机号 + ShoppingTimesNotEnough = 403046 // 购物次数不足 + UserVmNotEnough = 403049 // 用户积分余额不足 + + HbKeySendFail = 403055 // 口令发送失败,60秒后重试 + IsNoviceFail = 403056 // 不是新用户 + + CheckInAlready = 403060 // 今日已经签到 + OpenChestTimeNot = 403061 // 宝箱时间未到 + + ExchangeStepLimit = 403070 // 今日兑换步数超出上限 + + HaveUnreturnedOrders = 403080 // 请归还未完成订单 + GoodsSoldOut = 403090 // 商品已下架 + //404xx StatusNotFound 请求失败,请求所希望得到的资源未被在服务器上发现 + NotExists = 404001 // 通用型,请求的资源不存在 + + UserNotExists = 404002 // 用户不存在 + LockNotExists = 404003 // 锁不存在 + IsExists = 405001 + + //500xx StatusInternalServerError 服务器遇到了一个未曾预料的状况,导致了它无法完成对请求的处理。 + InternalServerError = 500001 // 通用型,服务器内部错误 + SmsFail = 500002 // 短信发送失败 + JsonParseError = 500005 // json解析错误 + JsonCreateError = 500006 // json生成错误 + DBOperateError = 500007 // 数据库操作错误 + RpcError = 500008 // RPC调用错误 + RequestTimeout = 500009 // 请求超时 + InviteUserFail = 500015 // 邀请码邀请失败 + RewardUsedByTaskFail = 500016 // 奖励关联其它任务,无法删除 + + PayStateIng = 500300 // 等待支付结果 + PayStateFail = 500301 // 等待支付结果 + + AwardOffShelves = 500407 //奖品下架 + AwardExchangeOut = 500408 //奖品已兑完 + + NotMember = 500501 //非会员 + HadReceiveReward = 500502 // 已经领取过奖励 + OrderDelivered = 500503 // 订单已发货 + OrderCompleted = 500504 // 订单已完成 + OrderStockOut = 500505 // 没有库存 + OrderUnpaidDeposit = 500506 // 未交押金 + RefundDepositSubmitted = 500507 // 已提交押金退款 + OrderMemberLevelLow = 500508 // 会员等级低 + OrderOutRentCount = 500509 // 会员超过可借卡数 + OrderStatusNotReturning = 500510 // 订单已完成 + ShareCardBillStateCancelError = 500511 // 共享单状态不能取消 + ShareCardRetrieveExistAppliedCard = 500513 // 存在重复申请收回的卡 + IssueFeedbackReceiptTimeOver48Hour = 500514 // 问题反馈 超过 48小时 + CardRetrieveBefore6Month = 500515 // 用户收回卡需要半年后 + IssueFeedbackRepetition = 500516 // 问题反馈已存在,不能重复反馈 + TodayAttendance = 500517 // 已签到 + NoAuth = 500519 // 没有权限 + GoodsNotSale = 500508 // 商品已下架 + StateNotCancel = 500521 // 状态不能取消 + UserFocusHasCoupon = 500522 // 用户已经领取了兑换券 + + ToastErr = 600 // 报错 +) + +var statusDesc = map[int]string{ + OK: "成功", + + BadRequest: "参数不合法,请检查参数", + PwdIllegal: "密码不合法", + CaptchaErr: "验证码错误", + CheckSignFail: "验证签名失败", + TelOrCaptchaErr: "手机号或验证码错误", + NeedBindTel: "需要绑定手机号", + ShoppingTimesNotEnough: "购物次数不足", + + Unauthorized: "用户没有登录", + AccessTokenExpired: "access token过期", + RefreshTokenExpired: "refresh token过期", + RefreshTokenInvalid: "refresh token invalid", + LoginFail: "登录失败,账号或密码错误", + UserNameUsed: "用户名已使用", + EmailUsed: "邮箱已使用", + TelUsed: "手机号已使用", + LogoutFail: "登出失败", + RegisterFail: "注册失败", + UpdateTokenFail: "更新token失败", + UpdateFail: "更新失败", + LockUserAuthed: "用户已授权", + ServerBusy: "服务器繁忙,请稍后再试", + + HaveUnreturnedOrders: "请归还未完成订单", + GoodsSoldOut: "商品已下架", + UserNotExists: "用户不存在", + + CheckInAlready: "今日已签到", + OpenChestTimeNot: "宝箱时间未到", + + ExchangeStepLimit: "今日兑换步数超出上限", + + NotExists: "请求的资源不存在", + IsExists: "资源已经存在", + OrderStatusNotReturning: "该卡状态不能取消", + + InternalServerError: "服务器开小差了,请稍后再试", + SmsFail: "短信发送失败", + JsonParseError: "服务器开小差了,请稍后再试", + JsonCreateError: "服务器开小差了,请稍后再试", + DBOperateError: "服务器开小差了,请稍后再试", + RpcError: "服务器开小差了,请稍后再试", + RequestTimeout: "服务器开小差了,请稍后再试", + + InviteUserFail: "邀请失败", + + UserHasBeenInvited: "用户已被邀请过", + UserSelfInviteSelf: "不允许自己邀请自己", + OutOffWithdrawCountLimit: "超出当月提现次数", + OutOffWithdrawAccountLimit: "超出提现金额范围", + CaptchaDelivered: "验证码5分钟内有效", + + PayStateIng: "支付中", + PayStateFail: "支付失败", + MoneySufficient: "余额不足", + + AwardOffShelves: "奖品已下架", + AwardExchangeOut: "奖品已兑完", + + GoodsNotSale: "商品已下架", + StateNotCancel: "状态不能取消", + UserFocusHasCoupon: "你已经兑换了优惠券", + + NotMember: "非会员", + HadReceiveReward: "已经领取过了", +} + +var statusMsg = map[int]string{ + OK: "成功", + + BadRequest: "参数不合法,请检查参数", + PwdIllegal: "密码不合法", + CaptchaErr: "验证码错误", + CheckSignFail: "验证签名失败", + TelOrCaptchaErr: "手机号或验证码错误", + + Unauthorized: "用户没有登录", + AccessTokenExpired: "token过期", + LoginFail: "登录失败,账号或密码错误", + UserNameUsed: "用户名已使用", + EmailUsed: "邮箱已使用", + TelUsed: "手机号已使用", + LogoutFail: "登出失败", + RegisterFail: "注册失败", + UpdateTokenFail: "更新token失败", + UpdateFail: "更新失败", + LockUserAuthed: "用户已授权", + ServerBusy: "服务器繁忙,请稍后再试", + + HaveUnreturnedOrders: "请归还未完成订单", + GoodsSoldOut: "商品已下架", + + UserNotExists: "用户不存在", + + HbKeySendFail: "口令发送失败,60秒后重试", + IsNoviceFail: "该用户不是新用户", + + CheckInAlready: "今日已签到", + NoAuth: "没有权限", + + OpenChestTimeNot: "宝箱时间未到", + + NotExists: "请求的资源不存在", + IsExists: "资源已经存在", + OrderOutRentCount: "借卡数量超了", + + InternalServerError: "服务器开小差了,请稍后再试", + SmsFail: "短信发送失败", + JsonParseError: "服务器开小差了,请稍后再试", + JsonCreateError: "服务器开小差了,请稍后再试", + DBOperateError: "服务器开小差了,请稍后再试", + RpcError: "服务器开小差了,请稍后再试", + RequestTimeout: "服务器开小差了,请稍后再试", + InviteUserFail: "邀请失败", + + UserHasBeenInvited: "用户已被邀请过", + UserSelfInviteSelf: "不允许自己邀请自己", + OutOffWithdrawCountLimit: "超出每天提现次数", + OutOffWithdrawAccountLimit: "超出提现金额范围", + CaptchaDelivered: "验证码5分钟内有效", + ShareCardBillStateCancelError: "当前状态不能取消", + ShareCardRetrieveExistAppliedCard: "存在重复申请收回的卡", + IssueFeedbackReceiptTimeOver48Hour: "签收后已超过48小时", + CardRetrieveBefore6Month: "收回的卡需共享满半年", + IssueFeedbackRepetition: "改卡反馈已存在,不能重复反馈", + TodayAttendance: "今天已签到", + PayStateIng: "支付中", + PayStateFail: "支付失败", + MoneySufficient: "余额不足", + UserVmNotEnough: "积分余额不足", + + UserFocusHasCoupon: "你已经兑换了优惠券", + + AwardOffShelves: "奖品已下架", + AwardExchangeOut: "奖品已兑完", + + GoodsNotSale: "商品已下架", + + NotMember: "非会员", + HadReceiveReward: "已经领取过了", +} + +func StatusDesc(code int) string { + return statusDesc[code] +} + +func StatusMsg(code int) string { + return statusMsg[code] +} + +func HttpStatusCode(code int) int { + for code > 999 { + code = code / 10 + } + return code +} diff --git a/main.go b/main.go new file mode 100644 index 0000000..5930d7c --- /dev/null +++ b/main.go @@ -0,0 +1,7 @@ +package main + +import "gitee.com/codinl/erp_server/cmd" + +func main() { + cmd.Start() +} diff --git a/model/base_init_db.go b/model/base_init_db.go new file mode 100644 index 0000000..5fc4aea --- /dev/null +++ b/model/base_init_db.go @@ -0,0 +1,79 @@ +package model + +import ( + "fmt" + "gitee.com/codinl/erp_server/config" + "time" + + "github.com/codinl/go-logger" + "github.com/jinzhu/gorm" + _ "github.com/jinzhu/gorm/dialects/mysql" +) + +var DB *gorm.DB + +func InitDB() { + var err error + dialect := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=True&loc=Local", + config.ConfigValue.MysqlUser, config.ConfigValue.MysqlPassword, config.ConfigValue.MysqlHost, config.ConfigValue.MysqlPort, + config.ConfigValue.MysqlDBName) + DB, err = gorm.Open(config.ConfigValue.MysqlDriver, dialect) + if err != nil { + logger.Info("Connect Database Error:", err) + panic(err) + } + DB.DB().SetMaxOpenConns(1000) + DB.DB().SetMaxIdleConns(500) + DB.DB().SetConnMaxLifetime(time.Second * 10) + DB.LogMode(true) + + DB.SingularTable(true) + if err := DB.DB().Ping(); err != nil { + logger.Info("Ping Database Fail:", err) + panic(err) + } + fmt.Println("DB init success") + logger.Info("DB init success") +} + +func CloseDB() { + if DB != nil { + if err := DB.Close(); err != nil { + fmt.Println("DB Close err", err) + logger.Error("DB Close err", err) + } + } +} + +type DBLoggerWriter struct { + gorm.LogWriter +} + +func (DBLoggerWriter) Print(values ...interface{}) { +} + +func TransactionBegin() *gorm.DB { + return DB.Begin() +} + +// Transaction 事务自动处理,如果有错误将回滚,否则将提交事务 +func Transaction(tx *gorm.DB, err error) error { + if err == nil { + ret := tx.Commit() + if ret.Error != nil { + return ret.Error + } + return err + } + ret := tx.Rollback() + if ret.Error != nil { + return ret.Error + } + return nil +} + +func initCreateTable() { + if err := DB.Set("gorm:table_options", "ENGINE=InnoDB DEFAULT CHARSET=utf8").AutoMigrate().Error; err != nil { + logger.Info("AutoMigrate createTable Error:", err) + } +} diff --git a/model/model.go b/model/model.go new file mode 100644 index 0000000..5d03be0 --- /dev/null +++ b/model/model.go @@ -0,0 +1,90 @@ +package model + +import ( + "github.com/jinzhu/gorm" + "time" +) + +var RecordNotFound = gorm.ErrRecordNotFound + +type BaseModel struct { + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` + DeletedAt *time.Time `json:"deletedAt"` +} + +type Model struct { + ID uint32 `json:"id" gorm:"primary_key;AUTO_INCREMENT"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"-"` + DeletedAt *time.Time `json:"-" sql:"index"` +} + +type Unix struct { + ID uint32 `gorm:"primary_key"` + Created time.Time `gorm:"-"` // 忽略储存在数据库 + CreatedUnix int64 + Updated time.Time `gorm:"-"` // 忽略储存在数据库 + UpdatedUnix int64 +} + +// 查询前把时间格式化 +func (m *Unix) AfterFind() (err error) { + m.Created = time.Unix(m.CreatedUnix, 0).Local() + m.Updated = time.Unix(m.UpdatedUnix, 0).Local() + return +} + +// 更新前对时间戳创建 +func (m *Unix) BeforeCreate() (err error) { + m.UpdatedUnix = time.Now().Local().Unix() + m.CreatedUnix = time.Now().Local().Unix() + return +} + +// 更新前对时间戳更改 +func (m *Unix) BeforeUpdate(scope *gorm.Scope) (err error) { + return scope.SetColumn("UpdatedUnix", time.Now().Local().Unix()) +} + +type Unix64 struct { + ID uint64 `gorm:"primary_key"` + Created time.Time `gorm:"-"` // 忽略储存在数据库 + CreatedUnix int64 + Updated time.Time `gorm:"-"` // 忽略储存在数据库 + UpdatedUnix int64 +} + +// 查询前把时间格式化 +func (m *Unix64) AfterFind() (err error) { + m.Created = time.Unix(m.CreatedUnix, 0).Local() + m.Updated = time.Unix(m.UpdatedUnix, 0).Local() + return +} + +// 更新前对时间戳创建 +func (m *Unix64) BeforeCreate() { + m.UpdatedUnix = time.Now().Local().Unix() + m.CreatedUnix = time.Now().Local().Unix() +} + +// 更新前对时间戳更改 +func (m *Unix64) BeforeUpdate(scope *gorm.Scope) (err error) { + return scope.SetColumn("UpdatedUnix", time.Now().Local().Unix()) +} + +type Deleted struct { + Unix64 + DeletedUnix int64 `sql:"index"` +} + +// 删除回调 +func (d *Deleted) BeforeCreate() { + d.Unix64.BeforeCreate() + d.DeletedUnix = -1 +} + +// 执行删除操作 +func (d *Deleted) BeforeDelete(scope *gorm.Scope) (err error) { + return scope.SetColumn("DeletedUnix", time.Now().Local().Unix()) +} diff --git a/model/system.go b/model/system.go new file mode 100644 index 0000000..f201282 --- /dev/null +++ b/model/system.go @@ -0,0 +1,13 @@ +package model + +type Logging struct { + Model + + Machine string `json:"machine"` + StoreId uint32 `json:"store_id" gorm:"index"` // 门店id + StoreName string `json:"store_name"` + Operator string `json:"operator"` + Function string `json:"function"` + Event string `json:"event"` + Ip string `json:"ip"` +} diff --git a/pack/.app.config.yaml b/pack/.app.config.yaml new file mode 100644 index 0000000..3987e3a --- /dev/null +++ b/pack/.app.config.yaml @@ -0,0 +1,69 @@ +service: + http: + port: 80 + rpc: + port: 81 + +mysql: + driver: mysql + host: 39.108.188.218 + port: 3306 + db_name: mh_dev + user: mh_dev + password: m5h4parZsXjbeiFh + charset: utf8mb4 + parseTime: true + maxIdle: 500 + maxOpen: 1000 + debug: true + + +redis: + host: r-uf6lqwtvuvsrkyejuqpd.redis.rds.aliyuncs.com + port: 6379 + db: 0 + password: QW9PumiHTuAGBX2 + max_idle: 200 + max_active: 100 + idle_timeout: 5 + connect_timeout: 300 + read_timeout: 3000 + write_timeout: 1800 + default_expiration: 3600 + +elasticsearch: + host: http://es.duoduohuoke.com + port: 80 + username: elastic + password: DkSCbIedPP + +jwt: +# key: eyJwIjoiNGtzNXJLRVRoam9aM0cwSlR6eWpLdDNLQnU5aGR0SFJLT1RYdkxBV0Qwbjg3TTFOSDQzQUJBMFRwQmNsdS1JRmVaNWZpaFlLbjhlcmk5YjI4cFFmeEpYTjEycHlpYVYwbHdsclNvaFY4WWRNeGFFb044OUxEdjlWQndNeTdlN0tFbl90YkFoaWV6d0Z1N19helFGZFpEb0R3cjRIUmo5Nk80YmV1VDB0TWFVIiwia3R5IjoiUlNBIiwicSI6InZzRGJzR1JKUXlHME9PenRPTXZNRjk2RVBOOUxock9ucTJnLTFWNVExZERBN0dlYjc2Q1puUXpFaDZhUjlhMVpCcFFMUlVqZnNCVnBsUklPTFV3aHhMZ3gtVXZ2amREYy1mczNneVZlY2Iyck1wT2NhX2hISHljTk5WNll6SUJwdVBSenI4LTR6TVlFSFFISm1ndnRfNk95MC03ODZXU1pkOU5FazJkMDI1RSIsImQiOiJuVEhoSnFMWnpPMWhscklueHZWMHY4b0NySl9zXy1scWZhME5lX1YyU1BpUU1aM2NreW82dDRPamMzUndDM3ROQnFYRzNscmh2V18zSlIxSHlUaTZFZUxkWEEtRHloN042c3VBcS1pWXVzenJZeWMxNXZDUC1FanVvRUQ1QmlNWDJrNnk3SDRTUWtRYUZkS2l3a1g0bUVTeGVLR04xRkRMU09pWHpGMmdQUWlIZ3p4MkdEY1ZId2lpRVBNOUF4QURwa214NElTaTh2dFRjaEtadXhUaDd2TUVEQXp2ZlhlYWJ1cUlLNVN2S2NhR2Q3Zk9STm5NcmNzRS1iVUh1MTdXbjRxV3VyV0RfZ29oZXdtVnFiYUlHc0lrY29jRmk2QXVGRzBsS1haLW5TRXAzOWstMlZYT0w0RWFtSDdhbHIwb2NpVms5cldNUHAxNEVDU0hNdHFpUVEiLCJlIjoiQVFBQiIsInVzZSI6InNpZyIsImtpZCI6InpRUlBrVjVXRW5uQTFUdEJ2aDM3TlJxWkhZaUxOOU9DTDltellGQzl4WkkiLCJxaSI6IkhRVV82ZXZHM0EwV0tyV01rbjc5emZ5RmVkeHpGa2ZFQjNDb1B5VzFFLU5zLWhMUGxtd09FbHdGUWdtaGRCdkg0LWRaOWxlYkdSSXlsS3ZpU0FzN1RIeHRkQzBpX19LaTREU2Jwa29LOGdHcTJFZFI1RXhhcHFDN1Z3alpINHpXQU5RMkd0THlVdllsUGtMOHJNYW00RHpqdHNQbFpPMS1lR0lxRzYxdzFDZyIsImRwIjoiWGQ0WWFXeFRmZjFCMXZaX3d4ZURFM2Yyb3BQUG1Rc0Z1UEhjTDRfWFJyWkpMUzBvRGF1dDk4QTQ0bnNia3VqNW5tNDhjVG9kWkJQZUs5NmFoeHM4Wmo1QnFWYWxka1ZrckhZaXhFTHphNEhWTGJGZ3ptMjFVOTVFTmVsMHljLWdrTFh5RlRzUkpzOUtEWXhTeFhFSWZWZTNVYU9qdnRiNzdBOVEtZ1BQYUdVIiwiYWxnIjoiUlM1MTIiLCJkcSI6ImVhTkR0QnlQTnpiRDFOVUloSUk0bURQMXdWZG1zdlBYQkktS0djZDE1cEtpbzEyQ2EzRE80XzNqU05rb0ZEREJKMWU2UkNrdk12ckVoQ0dxVnFwSWtrZ2UzZWpWVG1xVXJ2ZktNMV9kOU12TTRvaU1ZN0ZEc1JMVzhtUnJMV1RwaGQ2ajhzV1VBMGgyRVFVMXlIeTRfSjRuaDh2TERRMXdhNS1XQ0NVZHVIRSIsIm4iOiJxSjVQYTZlNXhoQ1lSRjBwNnZaekd5cldQNnkxWEo5NzB6S3ZBWmVOSG1rcXZsaWhBTXVZTFhyNllyNFJQTkRpaWh1UmpQVHE3ZlhuaHJVOWxWa3cySml1dk5sX05ueGVsYTduUTN4MzVuS1M0T3pDYlg4ZUctOUpGWEo5aGFSMG42S1pza01HX3A5N3hSTDBQZ2hkODFPSEdPT1k5MFpVRmJpREhvd2NGYVdra055eXlrTXRwdi12akVxRVNjM0hZSmhjMElKS21JenNJOW1NeFhGcGZBV2Z5RDdPa25GUG85Z0dTbkxNc1UyWlhoM1NaUUR6X0lwTVlwZzIwNTN5c19nc2V1czhOaGtkc2lKTUdpdFh2M3FGSXluWXdfekVCLWJwajBjSGlMa1k1MWktZ0I5TlBoM2lUTGh5dVVZOXhYWGo3YXE2YUhCTG05dDBNZFZGZFEifQ== + key: oOqYrhCNQRvVNAaEo4h4osoW + expire: 7200 + +wx: + mini_app: + app_id: wxff888972e97ff2ef + app_secret: 3d7335cf0b9fa1d70aa7eb079526ebf0 + token: xiaoquanhuoke + encoding_aesKey: FzTNdIqDR4LHEWZYCQxH1GfzNEdT1HXLA6NBmE7nkBa + pay: + mch_id: 1497386122 + mch_secret: 7c81a2a7cd19514b9ea1dac7ad352431 + callback_url: https://box.duoduohuoke.com/wxpay/ + cert_file: /pack/1497386122_20220722_cert/apiclient_cert.p12 + key_file: /pack/1497386122_20220722_cert/apiclient_key.pem + root_ca_file: /pack/1497386122_20220722_cert/apiclient_cert.pem + +paypal: + client_id: AecAXJnfUqNBOT68RczPoY3AAHDPfTfCjtC6Q5xtt72FfX34gwMy7Qm4X_HyctUA1xVPgKnBFrdQvNsL + secret: EHT7Kh0nfloIA5MEdYEUslIEuE0Vu_umUi8NFxfYeX909En02N26lwOAtvyrlDbgNSZP12Ip9c0lpx6X + api_base: https://api.sandbox.paypal.com + +logger: + path: ./log_server + file: server + level: 0 + +firebase: \ No newline at end of file diff --git a/pack/.service.config.tpl.yaml b/pack/.service.config.tpl.yaml new file mode 100644 index 0000000..835c2ce --- /dev/null +++ b/pack/.service.config.tpl.yaml @@ -0,0 +1,47 @@ +{{- $develop := "develop" }} +{{- $local := "local" -}} +config: + server: + host: {{ if or (eq .Stage $local) (eq .Stage $develop) }}192.168.20.45{{end}} + port: {{ if or (eq .Stage $local) (eq .Stage $develop) }}1001{{end}} + +service: + name: {{.Service}} + stage: {{.Stage}} + http: + port: {{ if or (eq .Stage $local) (eq .Stage $develop) }}10100{{else}}80{{- end}} + rpc: + port: {{ if or (eq .Stage $local) (eq .Stage $develop) }}10101{{else}}1000{{- end}} + +mysql: + driver: mysql + host: {{ if or (eq .Stage $local) (eq .Stage $develop) }}rm-wz9qf3m85605602z33o.mysql.rds.aliyuncs.com{{- end}} + port: {{ if or (eq .Stage $local) (eq .Stage $develop) }}3306{{- end}} + db_name: {{ if or (eq .Stage $local) (eq .Stage $develop) }}bibi_test{{- end}} + user: {{ if or (eq .Stage $local) (eq .Stage $develop) }}bibi_test{{- end}} + password: {{ if or (eq .Stage $local) (eq .Stage $develop) }}c8b1521533f766c01d8ebf5b8217c3e2{{- end}} + charset: utf8mb4 + parseTime: true + maxIdle: 500 + maxOpen: 1000 + debug: true + +redis: + host: {{ if or (eq .Stage $local) (eq .Stage $develop) }}r-wz944zuf47go86xx61pd.redis.rds.aliyuncs.com{{- end}} + port: {{ if or (eq .Stage $local) (eq .Stage $develop) }}6379{{- end}} + db: 0 + password: {{ if or (eq .Stage $local) (eq .Stage $develop) }}Af63ee0752e9fc03717601fac67693fe{{- end}} + maxIdle: 200 + maxActive: 100 + idleTimeout: 5 + connectTimeout: 300 + readTimeout: 3000 + writeTimeout: 1800 + defaultExpiration: 3600 + +mongo: + host: {{ if or (eq .Stage $local) (eq .Stage $develop) }}dds-wz956563ee8204442759-pub.mongodb.rds.aliyuncs.com{{- end}} + port: {{ if or (eq .Stage $local) (eq .Stage $develop) }}3717{{- end}} + db_name: {{ if or (eq .Stage $local) (eq .Stage $develop) }}admin{{- end}} + user: {{ if or (eq .Stage $local) (eq .Stage $develop) }}root{{- end}} + password: {{ if or (eq .Stage $local) (eq .Stage $develop) }}dasdRRFs*wadf{{- end}} \ No newline at end of file diff --git a/pack/.service.config.yaml b/pack/.service.config.yaml new file mode 100644 index 0000000..6c43aec --- /dev/null +++ b/pack/.service.config.yaml @@ -0,0 +1,45 @@ +config: + server: + host: 192.168.20.45 + port: 1001 + +service: + name: user + stage: local + http: + port: 10100 + rpc: + port: 10101 + +mysql: + driver: mysql + host: rm-wz9qf3m85605602z33o.mysql.rds.aliyuncs.com + port: 3306 + db_name: bibi_test + user: bibi_test + password: c8b1521533f766c01d8ebf5b8217c3e2 + charset: utf8mb4 + parseTime: true + maxIdle: 500 + maxOpen: 1000 + debug: true + +redis: + host: r-wz944zuf47go86xx61pd.redis.rds.aliyuncs.com + port: 6379 + db: 0 + password: Af63ee0752e9fc03717601fac67693fe + maxIdle: 200 + maxActive: 100 + idleTimeout: 5 + connectTimeout: 300 + readTimeout: 3000 + writeTimeout: 1800 + defaultExpiration: 3600 + +mongo: + host: dds-wz956563ee8204442759-pub.mongodb.rds.aliyuncs.com + port: 3717 + db_name: admin + user: root + password: dasdRRFs*wadf \ No newline at end of file diff --git a/pack/Dockerfile b/pack/Dockerfile new file mode 100644 index 0000000..5ac28af --- /dev/null +++ b/pack/Dockerfile @@ -0,0 +1,11 @@ +FROM registry.eu-central-1.aliyuncs.com/bibiservice/golang:1.15.3-alpine3.12-ur + +COPY ./service ./service +#COPY .service.config.tpl.yaml ./pack/.service.config.tpl.yaml +COPY .app.config.yaml ./pack/.app.config.yaml + +EXPOSE 80 +EXPOSE 1000 + +ENTRYPOINT ["./service"] +CMD ["start"] \ No newline at end of file diff --git a/pack/build_server.sh b/pack/build_server.sh new file mode 100755 index 0000000..40ad559 --- /dev/null +++ b/pack/build_server.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -tags=jsoniter -o ./erp_server_`date '+%Y%m%d_%H%M%S'` ../main.go \ No newline at end of file diff --git a/pack/restart_server_dev.sh b/pack/restart_server_dev.sh new file mode 100755 index 0000000..e37a6b1 --- /dev/null +++ b/pack/restart_server_dev.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +export CONFIG_PATH=configs +export CONFIG_FILE_NAME=server + +export ENV=dev +export APP_NAME=server + +export LOG_FILE_NAME=server +export LOG_PATH=log_server + +#go run ../main.go server +go run ../main.go start \ No newline at end of file diff --git a/pack/update_uid.sql b/pack/update_uid.sql new file mode 100644 index 0000000..b228477 --- /dev/null +++ b/pack/update_uid.sql @@ -0,0 +1,138 @@ +-- 更新用户UID + +SET @OLD_UID := 449854; +SET @NEW_UID := 10003; + +UPDATE user_base SET uid=@NEW_UID WHERE uid=@OLD_UID; +UPDATE user_auth SET uid=@NEW_UID WHERE uid=@OLD_UID; +UPDATE user_count SET uid=@NEW_UID WHERE uid=@OLD_UID; +UPDATE user_decoration_base_info SET uid=@NEW_UID WHERE uid=@OLD_UID; +UPDATE user_detail SET uid=@NEW_UID WHERE uid=@OLD_UID; +UPDATE user_device SET uid=@NEW_UID WHERE uid=@OLD_UID; +UPDATE user_feedback SET uid=@NEW_UID WHERE uid=@OLD_UID; +UPDATE user_gift_count SET uid=@NEW_UID WHERE uid=@OLD_UID; +UPDATE user_honor SET uid=@NEW_UID WHERE uid=@OLD_UID; +UPDATE user_pack_gift SET uid=@NEW_UID WHERE uid=@OLD_UID; +UPDATE user_pack_gift_count SET uid=@NEW_UID WHERE uid=@OLD_UID; +UPDATE user_photo SET uid=@NEW_UID WHERE uid=@OLD_UID; +UPDATE user_property SET uid=@NEW_UID WHERE uid=@OLD_UID; +UPDATE user_property_record SET uid=@NEW_UID WHERE uid=@OLD_UID; +UPDATE user_setting SET uid=@NEW_UID WHERE uid=@OLD_UID; +UPDATE user_tag SET uid=@NEW_UID WHERE uid=@OLD_UID; +UPDATE user_task_progress SET uid=@NEW_UID WHERE uid=@OLD_UID; +UPDATE user_xp_record SET uid=@NEW_UID WHERE uid=@OLD_UID; +UPDATE room SET owner_uid=@NEW_UID WHERE owner_uid=@OLD_UID; +UPDATE room_attention SET uid=@NEW_UID WHERE uid=@OLD_UID; +UPDATE room_fans SET uid=@NEW_UID WHERE uid=@OLD_UID; +UPDATE recharge SET uid=@NEW_UID WHERE uid=@OLD_UID; + +-- 更新用户数值 + +UPDATE user_base SET xp={经验值} WHERE uid={新ID}; +UPDATE user_property SET rm={钻石},vm={水晶},point={金币} WHERE uid={新ID}; + +-- 举例: +UPDATE user_base SET xp=678704 WHERE uid=301543; +UPDATE user_property SET rm=1082,vm=62100,point=36 WHERE uid=301543; + + + +UPDATE user_base SET xp=678704 WHERE uid=301543; +UPDATE user_property SET rm=1082,vm=62100,point=36 WHERE uid=301543; + +UPDATE user_base SET xp=3092 WHERE uid=300679; +UPDATE user_property SET rm=49,vm=600,point=871 WHERE uid=300679; + +UPDATE user_base SET xp=28740 WHERE uid=647536; +UPDATE user_property SET rm=11,vm=5100,point=371 WHERE uid=647536; + +UPDATE user_base SET xp=34048 WHERE uid=688890; +UPDATE user_property SET rm=1485,vm=600,point=1530 WHERE uid=688890; + +UPDATE user_base SET xp=1312665 WHERE uid=472924; +UPDATE user_property SET rm=65,vm=650,point=469 WHERE uid=472924; + +UPDATE user_base SET xp=105188 WHERE uid=469125; +UPDATE user_property SET rm=0,vm=7550,point=624 WHERE uid=469125; + +UPDATE user_base SET xp=16900 WHERE uid=972610; +UPDATE user_property SET rm=47,vm=14500,point=45 WHERE uid=972610; + +UPDATE user_base SET xp=25529 WHERE uid=622274; +UPDATE user_property SET rm=2,vm=0,point=37 WHERE uid=622274; + +UPDATE user_base SET xp=16900 WHERE uid=972610; +UPDATE user_property SET rm=47,vm=14500,point=45 WHERE uid=972610; + +UPDATE user_base SET xp=487 WHERE uid=488264; +UPDATE user_property SET rm=3,vm=300,point=63 WHERE uid=488264; + +UPDATE user_base SET xp=87641 WHERE uid=335763; +UPDATE user_property SET rm=20595,vm=22500,point=1583 WHERE uid=335763; + +UPDATE user_base SET xp=248203 WHERE uid=866762; +UPDATE user_property SET rm=1321,vm=2550,point=53109 WHERE uid=866762; + +UPDATE user_base SET xp=736378 WHERE uid=994105; +UPDATE user_property SET rm=3820,vm=30150,point=29767 WHERE uid=994105; + +UPDATE user_base SET xp=54243 WHERE uid=238928; +UPDATE user_property SET rm=2059,vm=500,point=46 WHERE uid=238928; + +UPDATE user_base SET xp=14567 WHERE uid=428717; +UPDATE user_property SET rm=592,vm=100,point=215 WHERE uid=428717; + +UPDATE user_base SET xp=28740 WHERE uid=647536; +UPDATE user_property SET rm=11,vm=5100,point=371 WHERE uid=647536; + +UPDATE user_base SET xp=17402 WHERE uid=526699; +UPDATE user_property SET rm=0,vm=0,point=722 WHERE uid=526699; + +UPDATE user_base SET xp=0 WHERE uid=553948; +UPDATE user_property SET rm=0,vm=0,point=0 WHERE uid=553948; + +UPDATE user_base SET xp=111637 WHERE uid=962979; +UPDATE user_property SET rm=158,vm=4000,point=24 WHERE uid=962979; + +UPDATE user_base SET xp=10 WHERE uid=127203; +UPDATE user_property SET rm=157,vm=3100,point=5 WHERE uid=127203; + +UPDATE user_base SET xp=111637 WHERE uid=962979; +UPDATE user_property SET rm=158,vm=4000,point=24 WHERE uid=962979; + +UPDATE user_base SET xp=201877 WHERE uid=811161; +UPDATE user_property SET rm=78,vm=2375,point=16009 WHERE uid=811161; + +UPDATE user_base SET xp=8486 WHERE uid=689175; +UPDATE user_property SET rm=160,vm=500,point=86 WHERE uid=689175; + +UPDATE user_base SET xp=70207 WHERE uid=134862; +UPDATE user_property SET rm=51,vm=200,point=6 WHERE uid=134862; + +UPDATE user_base SET xp=361563 WHERE uid=401275; +UPDATE user_property SET rm=1223,vm=600,point=94 WHERE uid=401275; + +UPDATE user_base SET xp=17104 WHERE uid=194545; +UPDATE user_property SET rm=36,vm=6200,point=4877 WHERE uid=194545; + +UPDATE user_base SET xp=111262 WHERE uid=143297; +UPDATE user_property SET rm=54,vm=1500,point=49 WHERE uid=143297; + +UPDATE user_base SET xp=15021 WHERE uid=642501; +UPDATE user_property SET rm=13,vm=4600,point=23 WHERE uid=642501; + +UPDATE user_base SET xp=6849 WHERE uid=105076; +UPDATE user_property SET rm=3,vm=0,point=772 WHERE uid=105076; + +UPDATE user_base SET xp=60000 WHERE uid=513372; +UPDATE user_property SET rm=635,vm=0,point=9 WHERE uid=513372; + +UPDATE user_base SET xp=278699 WHERE uid=21077101; +UPDATE user_property SET rm=960,vm=1350,point=52 WHERE uid=21077101; + +UPDATE user_base SET xp=16666 WHERE uid=894170; +UPDATE user_property SET rm=55,vm=1100,point=5677 WHERE uid=894170; + +UPDATE user_base SET xp=112774 WHERE uid=848064; +UPDATE user_property SET rm=40049,vm=94370,point=28205 WHERE uid=848064; + diff --git a/router/init.go b/router/init.go new file mode 100755 index 0000000..91e4604 --- /dev/null +++ b/router/init.go @@ -0,0 +1,44 @@ +package router + +import ( + "gitee.com/codinl/erp_server/controller" + "gitee.com/codinl/erp_server/lib/status" + "strings" + + "github.com/codinl/go-logger" + "github.com/gin-gonic/gin" +) + +const ApiVersionV1 = "v1" +const ApiVersionV2 = "v2" +const ApiVersionV3 = "v3" + +func CORSMiddleware(c *gin.Context) { + origin := c.Request.Header.Get("origin") + c.Writer.Header().Set("Access-Control-Allow-Origin", origin) + c.Writer.Header().Set("Access-Control-Allow-Credentials", "true") + c.Writer.Header().Set("Access-Control-Allow-Headers", strings.Join([]string{ + "Content-Type", "Content-Length", "XMLHttpRequest", "Accept-Encoding", + "X-CSRF-Token", "token", "Cache-Control", + }, ",")) + c.Writer.Header().Set("Access-Control-Max-Age", "31536000") + c.Writer.Header().Set("Access-Control-Allow-Methods", "POST,GET,PUT,OPTIONS") + if c.Request.Method == "OPTIONS" { + c.String(200, "ok") + return + } + logger.Info(c.Request.RequestURI) + c.Next() +} + +// WrapHandle 通过钩子处理错误,防止主程序宕机 +func WrapHandle(c *gin.Context) { + defer func() { + if err := recover(); err != nil { + logger.Error("gin recover: ", err) + controller.RespJson(c, status.InternalServerError, nil) + return + } + }() + c.Next() +} diff --git a/router/router_app.go b/router/router_app.go new file mode 100644 index 0000000..7e2ff8d --- /dev/null +++ b/router/router_app.go @@ -0,0 +1,25 @@ +package router + +import ( + "gitee.com/codinl/erp_server/controller" + "github.com/gin-gonic/gin" +) + +func ConfigAppRouter(r gin.IRouter) { + r.Use(CORSMiddleware) + r.Use(WrapHandle) + r.Use(gin.Recovery()) + + api := r.Group("/api/" + ApiVersionV1) + { + + } + + // 用户鉴权 + authGroup := api.Group("auth") + { + authGroup.POST("login", controller.AuthLogin) // 登录 + //authGroup.POST("token/refresh", controller.TokenRefresh) // 刷新AccessToken + } + +}