initialize

This commit is contained in:
li 2022-10-09 11:39:33 +08:00
parent 783e7dd43d
commit d4346241a6
35 changed files with 2634 additions and 0 deletions

218
.fly.yml Normal file
View File

@ -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

8
.version.yml Normal file
View File

@ -0,0 +1,8 @@
git:
tag: v1.0.11
image:
tag: v1.0.11
version:
feature: 1
hotfix: 11
main: 3

86
api_test/bench_test.go Normal file
View File

@ -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())
//}

24
api_test/data_test.go Normal file
View File

@ -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)
}

72
cmd/start.go Normal file
View File

@ -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
}
}

121
config/config.go Normal file
View File

@ -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
}

25
config/const.go Normal file
View File

@ -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
)

75
config/file/file.go Normal file
View File

@ -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
}

10
config/file/format.go Normal file
View File

@ -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 ""
}

90
config/internal/config.go Normal file
View File

@ -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}
}

134
config/internal/options.go Normal file
View File

@ -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
}

175
config/internal/reader.go Normal file
View File

@ -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(&copy)
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)
}

13
config/internal/source.go Normal file
View File

@ -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)
}

119
config/internal/value.go Normal file
View File

@ -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{}) {}

7
controller/auth.go Normal file
View File

@ -0,0 +1,7 @@
package controller
import "github.com/gin-gonic/gin"
func AuthLogin(c *gin.Context) {
}

130
controller/base.go Normal file
View File

@ -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()
}

26
go.mod Normal file
View File

@ -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
)

254
go.sum Normal file
View File

@ -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=

1
lib/auth/auth.go Normal file
View File

@ -0,0 +1 @@
package auth

178
lib/auth/auth_user.go Executable file
View File

@ -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)
}

16
lib/log/init.go Normal file
View File

@ -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")
}

268
lib/status/status.go Normal file
View File

@ -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
}

7
main.go Normal file
View File

@ -0,0 +1,7 @@
package main
import "gitee.com/codinl/erp_server/cmd"
func main() {
cmd.Start()
}

79
model/base_init_db.go Normal file
View File

@ -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)
}
}

90
model/model.go Normal file
View File

@ -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())
}

13
model/system.go Normal file
View File

@ -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"`
}

69
pack/.app.config.yaml Normal file
View File

@ -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:

View File

@ -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}}

45
pack/.service.config.yaml Normal file
View File

@ -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

11
pack/Dockerfile Normal file
View File

@ -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"]

3
pack/build_server.sh Executable file
View File

@ -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

13
pack/restart_server_dev.sh Executable file
View File

@ -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

138
pack/update_uid.sql Normal file
View File

@ -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;

44
router/init.go Executable file
View File

@ -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()
}

25
router/router_app.go Normal file
View File

@ -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
}
}