From db7a580b28835c79665b90e67c2870d1e17977a1 Mon Sep 17 00:00:00 2001 From: DengBiao <2319963317@qq.com> Date: Thu, 17 Nov 2022 11:51:35 +0800 Subject: [PATCH] update --- go.mod | 3 + go.sum | 5 + internal/business/api/business_ext.go | 21 + internal/business/comm/cloud_upload.go | 20 + internal/business/comm/db/db_sys_cfg.go | 119 +++++ internal/business/comm/db/model/sys_cfg.go | 8 + internal/business/comm/md/app_redis_key.go | 7 + internal/business/comm/md/cfg_key.go | 17 + internal/business/comm/md/file.go | 33 ++ .../comm/service/qiniu/bucket_create.go | 16 + .../comm/service/qiniu/bucket_delete.go | 18 + .../comm/service/qiniu/bucket_get_domain.go | 18 + internal/business/comm/service/qiniu/init.go | 22 + .../comm/service/qiniu/req_img_upload.go | 42 ++ .../business/comm/service/svc_file_upload.go | 92 ++++ .../business/comm/service/svc_sys_cfg_get.go | 106 ++++ internal/business/comm/utils/base64.go | 117 +++++ internal/business/comm/utils/convert.go | 369 ++++++++++++++ internal/business/comm/utils/curl.go | 209 ++++++++ internal/business/comm/utils/file.go | 22 + internal/business/comm/utils/logx/log.go | 245 ++++++++++ internal/business/comm/utils/logx/output.go | 105 ++++ internal/business/comm/utils/logx/sugar.go | 192 ++++++++ internal/business/comm/utils/md5.go | 12 + internal/business/comm/utils/rand.go | 46 ++ internal/business/comm/utils/reply.go | 29 ++ internal/business/comm/utils/serialize.go | 23 + internal/business/comm/utils/time.go | 208 ++++++++ .../business/domain/user/model/im_package.go | 24 + internal/business/domain/user/model/master.go | 17 + .../domain/user/repo/im_package_dao.go | 25 + .../domain/user/repo/im_package_repo.go | 18 + .../business/domain/user/repo/master_cache.go | 51 ++ .../business/domain/user/repo/master_dao.go | 38 ++ .../business/domain/user/repo/master_repo.go | 37 ++ internal/logic/api/logic_ext_test.go | 20 +- pkg/grpclib/ctx.go | 16 + pkg/pb/business.ext.pb.go | 451 +++++++++++++----- pkg/pb/business.int.pb.go | 2 +- pkg/pb/connect.int.pb.go | 2 +- pkg/pb/logic.ext.pb.go | 2 +- pkg/pb/logic.int.pb.go | 2 +- pkg/proto/business.ext.proto | 15 +- pkg/rpc/rpc.go | 2 + pkg/util/json.go | 11 +- pkg/util/redis.go | 61 +++ test/tcp_conn/main.go | 6 +- 47 files changed, 2797 insertions(+), 127 deletions(-) create mode 100644 internal/business/comm/cloud_upload.go create mode 100644 internal/business/comm/db/db_sys_cfg.go create mode 100644 internal/business/comm/db/model/sys_cfg.go create mode 100644 internal/business/comm/md/app_redis_key.go create mode 100644 internal/business/comm/md/cfg_key.go create mode 100644 internal/business/comm/md/file.go create mode 100644 internal/business/comm/service/qiniu/bucket_create.go create mode 100644 internal/business/comm/service/qiniu/bucket_delete.go create mode 100644 internal/business/comm/service/qiniu/bucket_get_domain.go create mode 100644 internal/business/comm/service/qiniu/init.go create mode 100644 internal/business/comm/service/qiniu/req_img_upload.go create mode 100644 internal/business/comm/service/svc_file_upload.go create mode 100644 internal/business/comm/service/svc_sys_cfg_get.go create mode 100644 internal/business/comm/utils/base64.go create mode 100644 internal/business/comm/utils/convert.go create mode 100644 internal/business/comm/utils/curl.go create mode 100644 internal/business/comm/utils/file.go create mode 100644 internal/business/comm/utils/logx/log.go create mode 100644 internal/business/comm/utils/logx/output.go create mode 100644 internal/business/comm/utils/logx/sugar.go create mode 100644 internal/business/comm/utils/md5.go create mode 100644 internal/business/comm/utils/rand.go create mode 100644 internal/business/comm/utils/reply.go create mode 100644 internal/business/comm/utils/serialize.go create mode 100644 internal/business/comm/utils/time.go create mode 100644 internal/business/domain/user/model/im_package.go create mode 100644 internal/business/domain/user/model/master.go create mode 100644 internal/business/domain/user/repo/im_package_dao.go create mode 100644 internal/business/domain/user/repo/im_package_repo.go create mode 100644 internal/business/domain/user/repo/master_cache.go create mode 100644 internal/business/domain/user/repo/master_dao.go create mode 100644 internal/business/domain/user/repo/master_repo.go diff --git a/go.mod b/go.mod index 970062a..631efcb 100644 --- a/go.mod +++ b/go.mod @@ -38,6 +38,7 @@ require ( github.com/golang/glog v1.0.0 // indirect github.com/google/gnostic v0.5.7-v3refs // indirect github.com/google/gofuzz v1.1.0 // indirect + github.com/gookit/color v1.3.6 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.12.0 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/josharian/intern v1.0.0 // indirect @@ -48,12 +49,14 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/onsi/ginkgo v1.16.5 // indirect + github.com/qiniu/api.v7/v7 v7.8.2 // indirect github.com/ugorji/go/codec v1.1.7 // indirect go.uber.org/atomic v1.7.0 // indirect go.uber.org/multierr v1.6.0 // indirect golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd // indirect golang.org/x/net v0.1.0 // indirect golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783 // indirect + golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect golang.org/x/sys v0.1.0 // indirect golang.org/x/term v0.1.0 // indirect golang.org/x/text v0.4.0 // indirect diff --git a/go.sum b/go.sum index 64d13d5..55dc9a8 100644 --- a/go.sum +++ b/go.sum @@ -235,6 +235,8 @@ github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= +github.com/gookit/color v1.3.6 h1:Rgbazd4JO5AgSTVGS3o0nvaSdwdrS8bzvIXwtK6OiMk= +github.com/gookit/color v1.3.6/go.mod h1:R3ogXq2B9rTbXoSHJ1HyUVAZ3poOJHpd9nQmyGZsfvQ= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= @@ -320,6 +322,8 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE 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/qiniu/api.v7/v7 v7.8.2 h1:f08kI0MmsJNzK4sUS8bG3HDH67ktwd/ji23Gkiy2ra4= +github.com/qiniu/api.v7/v7 v7.8.2/go.mod h1:FPsIqxh1Ym3X01sANE5ZwXfLZSWoCUp5+jNI8cLo3l0= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= @@ -486,6 +490,7 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= diff --git a/internal/business/api/business_ext.go b/internal/business/api/business_ext.go index 2b4067a..27a949e 100644 --- a/internal/business/api/business_ext.go +++ b/internal/business/api/business_ext.go @@ -3,8 +3,11 @@ package api import ( "context" "gim/internal/business/app" + comm "gim/internal/business/comm" + "gim/internal/business/comm/utils" "gim/pkg/grpclib" "gim/pkg/pb" + "strconv" ) type BusinessExtServer struct{} @@ -45,3 +48,21 @@ func (s *BusinessExtServer) SearchUser(ctx context.Context, req *pb.SearchUserRe users, err := app.UserApp.Search(ctx, req.Key, req.MasterId) return &pb.SearchUserResp{Users: users}, err } + +func (s *BusinessExtServer) CloudUploadFile(ctx context.Context, req *pb.CloudUploadFileReq) (*pb.CloudUploadFileResp, error) { + userId, _, err := grpclib.GetCtxData(ctx) + if err != nil { + return nil, err + } + upload, err := comm.CloudUpload.FileReqUpload(ctx, strconv.FormatInt(userId, 10), req.Dir, req.FileName, utils.StrToInt64(req.FileSize)) + data := utils.SerializeStr(upload) + var result map[string]string + utils.Unserialize([]byte(data), &result) + + return &pb.CloudUploadFileResp{ + Method: result["method"], + Host: result["host"], + Key: result["key"], + Token: result["token"], + }, err +} diff --git a/internal/business/comm/cloud_upload.go b/internal/business/comm/cloud_upload.go new file mode 100644 index 0000000..d25a2a5 --- /dev/null +++ b/internal/business/comm/cloud_upload.go @@ -0,0 +1,20 @@ +package app + +import ( + "context" + svc "gim/internal/business/comm/service" + "gim/pkg/grpclib" +) + +type cloudUpload struct{} + +var CloudUpload = new(cloudUpload) + +// FileReqUpload 请求文件上传 +func (*cloudUpload) FileReqUpload(ctx context.Context, uid, dirName, fName string, fSize int64) (interface{}, error) { + masterId, _ := grpclib.GetCtxMasterId(ctx) + + callbackUrl := svc.SysCfgGet("-1", "cloud_file_upload_call_back_url") + callbackUrl = callbackUrl + masterId + return svc.FileReqUpload(ctx, uid, dirName, fName, callbackUrl, fSize) +} diff --git a/internal/business/comm/db/db_sys_cfg.go b/internal/business/comm/db/db_sys_cfg.go new file mode 100644 index 0000000..15cf866 --- /dev/null +++ b/internal/business/comm/db/db_sys_cfg.go @@ -0,0 +1,119 @@ +package db + +import ( + "fmt" + "gim/internal/business/comm/db/model" + "gim/internal/business/comm/md" + "gim/internal/business/comm/utils" + "gim/internal/business/comm/utils/logx" + "gim/pkg/db" + "gim/pkg/gerrors" +) + +type dbSysCfg struct{} + +var DbSysCfg = new(dbSysCfg) + +// SysCfgGetAll 获取系统配置 +func (*dbSysCfg) SysCfgGetAll(masterId int64) (*[]model.SysCfg, error) { + var cfgList []model.SysCfg + if err := db.DB.Where("`master_id`=?", masterId).Find(&cfgList).Error; err != nil { + return nil, gerrors.WrapError(err) + } + return &cfgList, nil +} + +// SysCfgGetOne 获取一条记录 +func (*dbSysCfg) SysCfgGetOne(key string, masterId int64) (*model.SysCfg, error) { + var cfgList model.SysCfg + if err := db.DB.Where("`key` = ? and `master_id` = ?", key, masterId).First(&cfgList).Error; err != nil { + return nil, gerrors.WrapError(err) + } + return &cfgList, nil +} + +// SysCfgInsert 插入一条配置信息 +func (*dbSysCfg) SysCfgInsert(key, val, memo string, masterId int64) bool { + cfg := model.SysCfg{Key: key, Val: val, Memo: memo, MasterId: masterId} + err := db.DB.Create(&cfg).Error + if err != nil { + logx.Error(err) + return false + } + return true +} + +// SysCfgUpdate 修改某条配置信息 +func (*dbSysCfg) SysCfgUpdate(key, val, memo string, masterId int64) bool { + cfg := model.SysCfg{Key: key, Val: val, Memo: memo} + err := db.DB.Where("`key` = ? and `master_id` = ?", key, masterId).Update(&cfg).Error + if err != nil { + logx.Error(err) + return false + } + return true +} + +// SysCfgGetWithDb 单条记录获取 +func (*dbSysCfg) SysCfgGetWithDb(masterId string, HKey string) string { + cacheKey := fmt.Sprintf(md.AppCfgCacheKey, masterId, HKey[0:1]) + get, err := db.RedisUtil.HGetString(cacheKey, HKey) + if err != nil || get == "" { + cfg, err := DbSysCfg.SysCfgGetOne(HKey, utils.StrToInt64(masterId)) + if err != nil || cfg == nil { + _ = logx.Error(err) + return "" + } + + // key是否存在 + cacheKeyExist := false + if db.RedisUtil.Exists(cacheKey) { + cacheKeyExist = true + } + + // 设置缓存 + _, err = db.RedisUtil.HSet(cacheKey, HKey, cfg.Val) + if err != nil { + _ = logx.Error(err) + return "" + } + if !cacheKeyExist { // 如果是首次设置 设置过期时间 + _, err := db.RedisUtil.Expire(cacheKey, md.CfgCacheTime) + if err != nil { + _ = logx.Error(err) + return "" + } + } + return cfg.Val + } + return get +} + +// SysCfgFindWithDb 多条记录获取 +func (*dbSysCfg) SysCfgFindWithDb(masterId string, keys ...string) map[string]string { + res := map[string]string{} + cacheKey := fmt.Sprintf(md.AppCfgCacheKey, masterId) + err := db.RedisUtil.GetJson(cacheKey, &res) + if err != nil || len(res) == 0 { + cfgList, _ := DbSysCfg.SysCfgGetAll(utils.StrToInt64(masterId)) + if cfgList == nil { + return nil + } + for _, v := range *cfgList { + res[v.Key] = v.Val + } + db.RedisUtil.SetJson(cacheKey, res, md.CfgCacheTime) + } + if len(keys) == 0 { + return res + } + tmp := map[string]string{} + for _, v := range keys { + if val, ok := res[v]; ok { + tmp[v] = val + } else { + tmp[v] = "" + } + } + return tmp +} diff --git a/internal/business/comm/db/model/sys_cfg.go b/internal/business/comm/db/model/sys_cfg.go new file mode 100644 index 0000000..2edd928 --- /dev/null +++ b/internal/business/comm/db/model/sys_cfg.go @@ -0,0 +1,8 @@ +package model + +type SysCfg struct { + Key string // 键 + Val string // 值 + Memo string // 备注 + MasterId int64 // 站长id +} diff --git a/internal/business/comm/md/app_redis_key.go b/internal/business/comm/md/app_redis_key.go new file mode 100644 index 0000000..0df0da1 --- /dev/null +++ b/internal/business/comm/md/app_redis_key.go @@ -0,0 +1,7 @@ +package md + +// 缓存key统一管理, %s格式化为masterId +const ( + AppCfgCacheKey = "%s:gim_cfg_cache:%s" // 占位符: masterId, key的第一个字母 + CfgCacheTime = 86400 +) diff --git a/internal/business/comm/md/cfg_key.go b/internal/business/comm/md/cfg_key.go new file mode 100644 index 0000000..e4a0dad --- /dev/null +++ b/internal/business/comm/md/cfg_key.go @@ -0,0 +1,17 @@ +package md + +// 获取用户的缓存key +const ( + KEY_SYS_CFG_CACHE = "gim_sys_cfg_cache" + + // 文件缓存的key + KEY_CFG_FILE_PVD = "file_provider" // 文件供应商 + KEY_CFG_FILE_BUCKET = "file_bucket" + KEY_CFG_FILE_REGION = "file_bucket_region" + KEY_CFG_FILE_HOST = "file_bucket_host" + KEY_CFG_FILE_SCHEME = "file_bucket_scheme" + KEY_CFG_FILE_AK = "file_access_key" + KEY_CFG_FILE_SK = "file_secret_key" + KEY_CFG_FILE_MAX_SIZE = "file_user_upload_max_size" + KEY_CFG_FILE_EXT = "file_ext" +) diff --git a/internal/business/comm/md/file.go b/internal/business/comm/md/file.go new file mode 100644 index 0000000..356ca3c --- /dev/null +++ b/internal/business/comm/md/file.go @@ -0,0 +1,33 @@ +package md + +// 用户拥有上传权限的目录, 目录ID + +const ( + FILE_DIR_IMAGE = "image" + FILE_DIR_VIDEO = "video" + FILE_DIR_FILE = "file" +) + +var ( + FileUserDir = map[string]string{ + FILE_DIR_IMAGE: "1", // 图片上传 + FILE_DIR_VIDEO: "2", // 视频上传 + FILE_DIR_FILE: "3", // 文件上传 + } +) + +// 文件回调信息 +type FileCallback struct { + Uid string `json:"uid"` + DirId string `json:"dir_id"` + Provider string `json:"provider"` // 供应商 + FileName string `json:"fname"` // 原文件名 + FileSize string `json:"fsize"` + Hash string `json:"hash"` + Bucket string `json:"bucket"` + Mime string `json:"mime"` + Width string `json:"w,omitempty"` + Height string `json:"h,omitempty"` + Time string `json:"time"` // 默认一个小时内要上传完毕,否则超时 + Sign string `json:"sign"` // 签名 +} diff --git a/internal/business/comm/service/qiniu/bucket_create.go b/internal/business/comm/service/qiniu/bucket_create.go new file mode 100644 index 0000000..28d8106 --- /dev/null +++ b/internal/business/comm/service/qiniu/bucket_create.go @@ -0,0 +1,16 @@ +package qiniu + +import ( + "github.com/qiniu/api.v7/v7/auth" + "github.com/qiniu/api.v7/v7/storage" +) + +func BucketCreate() error { + mac := auth.New(AK, SK) + cfg := storage.Config{ + // 是否使用https域名进行资源管理 + UseHTTPS: false, + } + bucketManager := storage.NewBucketManager(mac, &cfg) + return bucketManager.CreateBucket("", storage.RIDHuanan) +} diff --git a/internal/business/comm/service/qiniu/bucket_delete.go b/internal/business/comm/service/qiniu/bucket_delete.go new file mode 100644 index 0000000..6d41521 --- /dev/null +++ b/internal/business/comm/service/qiniu/bucket_delete.go @@ -0,0 +1,18 @@ +package qiniu + +import ( + "github.com/qiniu/api.v7/v7/auth" + "github.com/qiniu/api.v7/v7/storage" +) + +func BucketDelete(bucketName string) error { + mac := auth.New(AK, SK) + + cfg := storage.Config{ + // 是否使用https域名进行资源管理 + UseHTTPS: false, + } + + bucketManager := storage.NewBucketManager(mac, &cfg) + return bucketManager.DropBucket(bucketName) +} diff --git a/internal/business/comm/service/qiniu/bucket_get_domain.go b/internal/business/comm/service/qiniu/bucket_get_domain.go new file mode 100644 index 0000000..f4cee3a --- /dev/null +++ b/internal/business/comm/service/qiniu/bucket_get_domain.go @@ -0,0 +1,18 @@ +package qiniu + +import ( + "github.com/qiniu/api.v7/v7/auth" + "github.com/qiniu/api.v7/v7/storage" +) + +func BucketGetDomain(bucketName string) (string, error) { + mac := auth.New(AK, SK) + + cfg := storage.Config{UseHTTPS: false} + bucketManager := storage.NewBucketManager(mac, &cfg) + b, err := bucketManager.ListBucketDomains(bucketName) + if err != nil { + return "", err + } + return b[0].Domain, nil +} diff --git a/internal/business/comm/service/qiniu/init.go b/internal/business/comm/service/qiniu/init.go new file mode 100644 index 0000000..9064c00 --- /dev/null +++ b/internal/business/comm/service/qiniu/init.go @@ -0,0 +1,22 @@ +package qiniu + +import ( + "gim/internal/business/comm/utils" +) + +var ( + AK = "MmxNdai23egjNUHjdzEVaTPdPCIbWzENz9BQuak3" + SK = "mElaFlM9O16rXp-ihoQdJ9KOH56naKm3MoyQBA59" + BUCKET = "dev-fnuoos" // 桶子名称 + BUCKET_SCHEME = "http" + BUCKET_REGION = "up-z2.qiniup.com" + Expires uint64 = 3600 +) + +func Init(ak, sk, bucket, region, scheme string) { + AK, SK, BUCKET, BUCKET_REGION, BUCKET_SCHEME = ak, sk, bucket, region, scheme +} + +func Sign(t string) string { + return utils.Md5(AK + SK + t) +} diff --git a/internal/business/comm/service/qiniu/req_img_upload.go b/internal/business/comm/service/qiniu/req_img_upload.go new file mode 100644 index 0000000..a7946a3 --- /dev/null +++ b/internal/business/comm/service/qiniu/req_img_upload.go @@ -0,0 +1,42 @@ +package qiniu + +import ( + "gim/internal/business/comm/md" + "gim/internal/business/comm/utils" + "time" + + "github.com/qiniu/api.v7/v7/auth/qbox" + _ "github.com/qiniu/api.v7/v7/conf" + "github.com/qiniu/api.v7/v7/storage" +) + +// 请求图片上传地址信息 +func ReqImgUpload(f *md.FileCallback, callbackUrl string) interface{} { + if ext := utils.FileExt(f.FileName); ext == "png" || ext == "jpg" || ext == "jpeg" || ext == "gif" || ext == "bmp" || ext == "webp" { + f.Width = "$(imageInfo.width)" + f.Height = "$(imageInfo.height)" + } + f.Provider = "qiniu" + f.FileSize = "$(fsize)" + f.Hash = "$(etag)" + f.Bucket = "$(bucket)" + f.Mime = "$(mimeType)" + f.Time = utils.Int64ToStr(time.Now().Unix()) + f.Sign = Sign(f.Time) + putPolicy := storage.PutPolicy{ + Scope: BUCKET + ":" + f.FileName, // 使用覆盖方式时候必须请求里面有key,否则报错 + Expires: Expires, + ForceSaveKey: true, + SaveKey: f.FileName, + //MimeLimit: "image/*", // 只允许上传图片 + CallbackURL: callbackUrl, + CallbackBody: utils.SerializeStr(f), + CallbackBodyType: "application/json", + } + return &struct { + Method string `json:"method"` + Key string `json:"key"` + Host string `json:"host"` + Token string `json:"token"` + }{Key: f.FileName, Method: "POST", Host: BUCKET_SCHEME + "://" + BUCKET_REGION, Token: putPolicy.UploadToken(qbox.NewMac(AK, SK))} +} diff --git a/internal/business/comm/service/svc_file_upload.go b/internal/business/comm/service/svc_file_upload.go new file mode 100644 index 0000000..ec1fc10 --- /dev/null +++ b/internal/business/comm/service/svc_file_upload.go @@ -0,0 +1,92 @@ +package svc + +import ( + "context" + "errors" + "fmt" + "gim/internal/business/comm/md" + "gim/internal/business/comm/service/qiniu" + "gim/internal/business/comm/utils" + "gim/internal/business/comm/utils/logx" + "strings" +) + +// 请求文件上传 +func FileReqUpload(ctx context.Context, uid, dirName, fName, callbackUrl string, fSize int64) (interface{}, error) { + ext := utils.FileExt(fName) + if err := initStg(ctx, fSize, ext); err != nil { + return nil, err + } + newName := dirName + "_" + fmt.Sprintf("%010s", uid) + + // 默认都加时间戳 + newName += "_" + utils.FormatNanoUnix() + utils.RandString(4, "0123456789") + newName += "." + ext + + f := &md.FileCallback{ + Uid: uid, + DirId: md.FileUserDir[dirName], + FileName: newName, + } + return qiniu.ReqImgUpload(f, callbackUrl), nil +} + +func initStg(ctx context.Context, fSize int64, ext string) error { + // 获取上传配置 + stgInfo := SysCfgFind( + ctx, + md.KEY_CFG_FILE_BUCKET, + md.KEY_CFG_FILE_HOST, + md.KEY_CFG_FILE_AK, + md.KEY_CFG_FILE_SK, + md.KEY_CFG_FILE_PVD, + md.KEY_CFG_FILE_REGION, + md.KEY_CFG_FILE_MAX_SIZE, + md.KEY_CFG_FILE_EXT, + md.KEY_CFG_FILE_SCHEME, + ) + + if stgInfo == nil { + return errors.New("获取配置信息出错") + } + // todo 目前仅支持七牛 + if v, ok := stgInfo[md.KEY_CFG_FILE_PVD]; !ok || v != "qiniu" { + return errors.New("file_provider error") + } + if v, ok := stgInfo[md.KEY_CFG_FILE_REGION]; !ok || v == "" { + return errors.New("file_bucket_region error") + } + if v, ok := stgInfo[md.KEY_CFG_FILE_AK]; !ok || v == "" { + return errors.New("file_access_key error") + } + if v, ok := stgInfo[md.KEY_CFG_FILE_SK]; !ok || v == "" { + return errors.New("file_secret_key error") + } + if v, ok := stgInfo[md.KEY_CFG_FILE_BUCKET]; !ok || v == "" { + return errors.New("file_bucket error") + } + if v, ok := stgInfo[md.KEY_CFG_FILE_SCHEME]; !ok || v == "" { + stgInfo[md.KEY_CFG_FILE_SCHEME] = "http" + SysCfgSet(ctx, md.KEY_CFG_FILE_SCHEME, stgInfo[md.KEY_CFG_FILE_SCHEME], "文件域名HTTP协议") + } + qiniu.Init(stgInfo[md.KEY_CFG_FILE_AK], stgInfo[md.KEY_CFG_FILE_SK], stgInfo[md.KEY_CFG_FILE_BUCKET], stgInfo[md.KEY_CFG_FILE_REGION], stgInfo[md.KEY_CFG_FILE_SCHEME]) + if v, ok := stgInfo[md.KEY_CFG_FILE_HOST]; !ok || v == "" { + var err error + stgInfo[md.KEY_CFG_FILE_HOST], err = qiniu.BucketGetDomain(stgInfo[md.KEY_CFG_FILE_BUCKET]) + if err != nil { + logx.Error(err) + return errors.New("服务器配置错误") + } + SysCfgSet(ctx, md.KEY_CFG_FILE_HOST, stgInfo[md.KEY_CFG_FILE_HOST], "文件域名地址") + } + + // 检查文件大小限制 + if v, ok := stgInfo[md.KEY_CFG_FILE_MAX_SIZE]; ok && v != "" && utils.StrToInt64(v) < fSize { + return errors.New("file_user_upload_max_size error") + } + // 检查文件后缀 + if v, ok := stgInfo[md.KEY_CFG_FILE_EXT]; ok && v != "" && !strings.Contains(v, ext) { + return errors.New("file_ext error") + } + return nil +} diff --git a/internal/business/comm/service/svc_sys_cfg_get.go b/internal/business/comm/service/svc_sys_cfg_get.go new file mode 100644 index 0000000..953ab47 --- /dev/null +++ b/internal/business/comm/service/svc_sys_cfg_get.go @@ -0,0 +1,106 @@ +package svc + +import ( + "context" + "fmt" + "gim/internal/business/comm/db" + "gim/internal/business/comm/md" + "gim/internal/business/comm/utils" + db2 "gim/pkg/db" + "gim/pkg/grpclib" +) + +// 单挑记录获取 +func SysCfgGet(masterId, key string) string { + return db.DbSysCfg.SysCfgGetWithDb(masterId, key) +} + +// 多条记录获取 +func SysCfgFind(ctx context.Context, keys ...string) map[string]string { + masterId, _ := grpclib.GetCtxMasterId(ctx) + tmp := SysCfgFindComm(masterId, keys...) + return tmp +} + +// SysCfgGetByMasterId get one config by master id +func SysCfgGetByMasterId(masterId, key string) string { + res := SysCfgFindComm(masterId, key) + if _, ok := res[key]; !ok { + return "" + } + return res[key] +} + +// SysCfgFindComm get cfg by master id +func SysCfgFindComm(masterId string, keys ...string) map[string]string { + res := map[string]string{} + cfgKey := fmt.Sprintf("%s:gim_cfg_cache", masterId) + err := db2.RedisUtil.GetJson(cfgKey, &res) + if err != nil || len(res) == 0 { + cfgList, _ := db.DbSysCfg.SysCfgGetAll(utils.StrToInt64(masterId)) + if cfgList == nil { + return nil + } + for _, v := range *cfgList { + res[v.Key] = v.Val + } + db2.RedisUtil.SetJson(cfgKey, res, 1800) + } + if len(keys) == 0 { + return res + } + tmp := map[string]string{} + for _, v := range keys { + if val, ok := res[v]; ok { + tmp[v] = val + } else { + tmp[v] = "" + } + } + return tmp +} + +// EgSysCfgFind 多条记录获取 +func EgSysCfgFind(masterId string, keys ...string) map[string]string { + res := map[string]string{} + if len(res) == 0 { + cfgList, _ := db.DbSysCfg.SysCfgGetAll(utils.StrToInt64(masterId)) + if cfgList == nil { + return nil + } + for _, v := range *cfgList { + res[v.Key] = v.Val + } + } + if len(keys) == 0 { + return res + } + tmp := map[string]string{} + for _, v := range keys { + if val, ok := res[v]; ok { + tmp[v] = val + } else { + tmp[v] = "" + } + } + return tmp +} + +// SysCfgCleanCache 清理系统配置信息 +func SysCfgCleanCache() { + db2.RedisUtil.Del(md.KEY_SYS_CFG_CACHE) +} + +// SysCfgSet 写入系统设置 +func SysCfgSet(ctx context.Context, key, val, memo string) bool { + masterId, _ := grpclib.GetCtxMasterId(ctx) + cfg, err := db.DbSysCfg.SysCfgGetOne(key, utils.StrToInt64(masterId)) + if err != nil || cfg == nil { + return db.DbSysCfg.SysCfgInsert(key, val, memo, utils.StrToInt64(masterId)) + } + if memo != "" && cfg.Memo != memo { + cfg.Memo = memo + } + SysCfgCleanCache() + return db.DbSysCfg.SysCfgUpdate(key, val, cfg.Memo, utils.StrToInt64(masterId)) +} diff --git a/internal/business/comm/utils/base64.go b/internal/business/comm/utils/base64.go new file mode 100644 index 0000000..661b552 --- /dev/null +++ b/internal/business/comm/utils/base64.go @@ -0,0 +1,117 @@ +package utils + +import ( + "encoding/base64" + "fmt" + "regexp" +) + +const ( + Base64Std = iota + Base64Url + Base64RawStd + Base64RawUrl +) + +func Base64StdEncode(str interface{}) string { + return Base64Encode(str, Base64Std) +} + +func Base64StdDecode(str interface{}) string { + return Base64Decode(str, Base64Std) +} + +func Base64UrlEncode(str interface{}) string { + return Base64Encode(str, Base64Url) +} + +func Base64UrlDecode(str interface{}) string { + return Base64Decode(str, Base64Url) +} + +func Base64RawStdEncode(str interface{}) string { + return Base64Encode(str, Base64RawStd) +} + +func Base64RawStdDecode(str interface{}) string { + return Base64Decode(str, Base64RawStd) +} + +func Base64RawUrlEncode(str interface{}) string { + return Base64Encode(str, Base64RawUrl) +} + +func Base64RawUrlDecode(str interface{}) string { + return Base64Decode(str, Base64RawUrl) +} + +func Base64Encode(str interface{}, encode int) string { + newEncode := base64Encode(encode) + if newEncode == nil { + return "" + } + switch v := str.(type) { + case string: + return newEncode.EncodeToString([]byte(v)) + case []byte: + return newEncode.EncodeToString(v) + } + return newEncode.EncodeToString([]byte(fmt.Sprint(str))) +} + +func Base64Decode(str interface{}, encode int) string { + var err error + var b []byte + newEncode := base64Encode(encode) + if newEncode == nil { + return "" + } + switch v := str.(type) { + case string: + b, err = newEncode.DecodeString(v) + case []byte: + b, err = newEncode.DecodeString(string(v)) + default: + return "" + } + if err != nil { + return "" + } + return string(b) +} + +func base64Encode(encode int) *base64.Encoding { + switch encode { + case Base64Std: + return base64.StdEncoding + case Base64Url: + return base64.URLEncoding + case Base64RawStd: + return base64.RawStdEncoding + case Base64RawUrl: + return base64.RawURLEncoding + default: + return nil + } +} + +func JudgeBase64(str string) bool { + pattern := "^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{4}|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)$" + matched, err := regexp.MatchString(pattern, str) + if err != nil { + return false + } + if !(len(str)%4 == 0 && matched) { + return false + } + unCodeStr, err := base64.StdEncoding.DecodeString(str) + if err != nil { + return false + } + tranStr := base64.StdEncoding.EncodeToString(unCodeStr) + //return str==base64.StdEncoding.EncodeToString(unCodeStr) + if str == tranStr { + return true + } + return false +} diff --git a/internal/business/comm/utils/convert.go b/internal/business/comm/utils/convert.go new file mode 100644 index 0000000..33715d4 --- /dev/null +++ b/internal/business/comm/utils/convert.go @@ -0,0 +1,369 @@ +package utils + +import ( + "encoding/binary" + "encoding/json" + "fmt" + "math" + "strconv" + "strings" +) + +func ToString(raw interface{}, e error) (res string) { + if e != nil { + return "" + } + return AnyToString(raw) +} + +func ToInt64(raw interface{}, e error) int64 { + if e != nil { + return 0 + } + return AnyToInt64(raw) +} + +func Float64ToStrPrec4(f float64) string { + return strconv.FormatFloat(f, 'f', 4, 64) +} +func AnyToBool(raw interface{}) bool { + switch i := raw.(type) { + case float32, float64, int, int64, uint, uint8, uint16, uint32, uint64, int8, int16, int32: + return i != 0 + case []byte: + return i != nil + case string: + if i == "false" { + return false + } + return i != "" + case error: + return false + case nil: + return true + } + val := fmt.Sprint(raw) + val = strings.TrimLeft(val, "&") + if strings.TrimLeft(val, "{}") == "" { + return false + } + if strings.TrimLeft(val, "[]") == "" { + return false + } + // ptr type + b, err := json.Marshal(raw) + if err != nil { + return false + } + if strings.TrimLeft(string(b), "\"\"") == "" { + return false + } + if strings.TrimLeft(string(b), "{}") == "" { + return false + } + return true +} + +func AnyToInt64(raw interface{}) int64 { + switch i := raw.(type) { + case string: + res, _ := strconv.ParseInt(i, 10, 64) + return res + case []byte: + return BytesToInt64(i) + case int: + return int64(i) + case int64: + return i + case uint: + return int64(i) + case uint8: + return int64(i) + case uint16: + return int64(i) + case uint32: + return int64(i) + case uint64: + return int64(i) + case int8: + return int64(i) + case int16: + return int64(i) + case int32: + return int64(i) + case float32: + return int64(i) + case float64: + return int64(i) + case error: + return 0 + case bool: + if i { + return 1 + } + return 0 + } + return 0 +} + +func AnyToString(raw interface{}) string { + switch i := raw.(type) { + case []byte: + return string(i) + case int: + return strconv.FormatInt(int64(i), 10) + case int64: + return strconv.FormatInt(i, 10) + case float32: + return Float64ToStr(float64(i)) + case float64: + return Float64ToStr(i) + case uint: + return strconv.FormatInt(int64(i), 10) + case uint8: + return strconv.FormatInt(int64(i), 10) + case uint16: + return strconv.FormatInt(int64(i), 10) + case uint32: + return strconv.FormatInt(int64(i), 10) + case uint64: + return strconv.FormatInt(int64(i), 10) + case int8: + return strconv.FormatInt(int64(i), 10) + case int16: + return strconv.FormatInt(int64(i), 10) + case int32: + return strconv.FormatInt(int64(i), 10) + case string: + return i + case error: + return i.Error() + case bool: + return strconv.FormatBool(i) + } + return fmt.Sprintf("%#v", raw) +} + +func AnyToFloat64(raw interface{}) float64 { + switch i := raw.(type) { + case []byte: + f, _ := strconv.ParseFloat(string(i), 64) + return f + case int: + return float64(i) + case int64: + return float64(i) + case float32: + return float64(i) + case float64: + return i + case uint: + return float64(i) + case uint8: + return float64(i) + case uint16: + return float64(i) + case uint32: + return float64(i) + case uint64: + return float64(i) + case int8: + return float64(i) + case int16: + return float64(i) + case int32: + return float64(i) + case string: + f, _ := strconv.ParseFloat(i, 64) + return f + case bool: + if i { + return 1 + } + } + return 0 +} + +func ToByte(raw interface{}, e error) []byte { + if e != nil { + return []byte{} + } + switch i := raw.(type) { + case string: + return []byte(i) + case int: + return Int64ToBytes(int64(i)) + case int64: + return Int64ToBytes(i) + case float32: + return Float32ToByte(i) + case float64: + return Float64ToByte(i) + case uint: + return Int64ToBytes(int64(i)) + case uint8: + return Int64ToBytes(int64(i)) + case uint16: + return Int64ToBytes(int64(i)) + case uint32: + return Int64ToBytes(int64(i)) + case uint64: + return Int64ToBytes(int64(i)) + case int8: + return Int64ToBytes(int64(i)) + case int16: + return Int64ToBytes(int64(i)) + case int32: + return Int64ToBytes(int64(i)) + case []byte: + return i + case error: + return []byte(i.Error()) + case bool: + if i { + return []byte("true") + } + return []byte("false") + } + return []byte(fmt.Sprintf("%#v", raw)) +} + +func Int64ToBytes(i int64) []byte { + var buf = make([]byte, 8) + binary.BigEndian.PutUint64(buf, uint64(i)) + return buf +} + +func BytesToInt64(buf []byte) int64 { + return int64(binary.BigEndian.Uint64(buf)) +} + +func StrToInt(s string) int { + res, _ := strconv.Atoi(s) + return res +} + +func StrToInt64(s string) int64 { + res, _ := strconv.ParseInt(s, 10, 64) + return res +} + +func Float32ToByte(float float32) []byte { + bits := math.Float32bits(float) + bytes := make([]byte, 4) + binary.LittleEndian.PutUint32(bytes, bits) + + return bytes +} + +func ByteToFloat32(bytes []byte) float32 { + bits := binary.LittleEndian.Uint32(bytes) + return math.Float32frombits(bits) +} + +func Float64ToByte(float float64) []byte { + bits := math.Float64bits(float) + bytes := make([]byte, 8) + binary.LittleEndian.PutUint64(bytes, bits) + return bytes +} + +func ByteToFloat64(bytes []byte) float64 { + bits := binary.LittleEndian.Uint64(bytes) + return math.Float64frombits(bits) +} + +func Float64ToStr(f float64) string { + return strconv.FormatFloat(f, 'f', 2, 64) +} +func Float64ToStrPrec1(f float64) string { + return strconv.FormatFloat(f, 'f', 1, 64) +} +func Float64ToStrByPrec(f float64, prec int) string { + return strconv.FormatFloat(f, 'f', prec, 64) +} + +func Float32ToStr(f float32) string { + return Float64ToStr(float64(f)) +} + +func StrToFloat64(s string) float64 { + res, err := strconv.ParseFloat(s, 64) + if err != nil { + return 0 + } + return res +} +func StrToFormat(s string, prec int) string { + ex := strings.Split(s, ".") + if len(ex) == 2 { + if StrToFloat64(ex[1]) == 0 { //小数点后面为空就是不要小数点了 + return ex[0] + } + //看取多少位 + str := ex[1] + str1 := str + if prec < len(str) { + str1 = str[0:prec] + } else { + for i := 0; i < prec-len(str); i++ { + str1 += "0" + } + } + if prec > 0 { + return ex[0] + "." + str1 + } else { + return ex[0] + } + } + return s +} + +func StrToFloat32(s string) float32 { + res, err := strconv.ParseFloat(s, 32) + if err != nil { + return 0 + } + return float32(res) +} + +func StrToBool(s string) bool { + b, _ := strconv.ParseBool(s) + return b +} + +func BoolToStr(b bool) string { + if b { + return "true" + } + return "false" +} + +func FloatToInt64(f float64) int64 { + return int64(f) +} + +func IntToStr(i int) string { + return strconv.Itoa(i) +} + +func Int64ToStr(i int64) string { + return strconv.FormatInt(i, 10) +} + +func IntToFloat64(i int) float64 { + s := strconv.Itoa(i) + res, err := strconv.ParseFloat(s, 64) + if err != nil { + return 0 + } + return res +} +func Int64ToFloat64(i int64) float64 { + s := strconv.FormatInt(i, 10) + res, err := strconv.ParseFloat(s, 64) + if err != nil { + return 0 + } + return res +} diff --git a/internal/business/comm/utils/curl.go b/internal/business/comm/utils/curl.go new file mode 100644 index 0000000..0a45607 --- /dev/null +++ b/internal/business/comm/utils/curl.go @@ -0,0 +1,209 @@ +package utils + +import ( + "bytes" + "crypto/tls" + "fmt" + "io" + "io/ioutil" + "net/http" + "net/url" + "sort" + "strings" + "time" +) + +var CurlDebug bool + +func CurlGet(router string, header map[string]string) ([]byte, error) { + return curl(http.MethodGet, router, nil, header) +} +func CurlGetJson(router string, body interface{}, header map[string]string) ([]byte, error) { + return curl_new(http.MethodGet, router, body, header) +} + +// 只支持form 与json 提交, 请留意body的类型, 支持string, []byte, map[string]string +func CurlPost(router string, body interface{}, header map[string]string) ([]byte, error) { + return curl(http.MethodPost, router, body, header) +} + +func CurlPut(router string, body interface{}, header map[string]string) ([]byte, error) { + return curl(http.MethodPut, router, body, header) +} + +// 只支持form 与json 提交, 请留意body的类型, 支持string, []byte, map[string]string +func CurlPatch(router string, body interface{}, header map[string]string) ([]byte, error) { + return curl(http.MethodPatch, router, body, header) +} + +// CurlDelete is curl delete +func CurlDelete(router string, body interface{}, header map[string]string) ([]byte, error) { + return curl(http.MethodDelete, router, body, header) +} + +func curl(method, router string, body interface{}, header map[string]string) ([]byte, error) { + var reqBody io.Reader + contentType := "application/json" + switch v := body.(type) { + case string: + reqBody = strings.NewReader(v) + case []byte: + reqBody = bytes.NewReader(v) + case map[string]string: + val := url.Values{} + for k, v := range v { + val.Set(k, v) + } + reqBody = strings.NewReader(val.Encode()) + contentType = "application/x-www-form-urlencoded" + case map[string]interface{}: + val := url.Values{} + for k, v := range v { + val.Set(k, v.(string)) + } + reqBody = strings.NewReader(val.Encode()) + contentType = "application/x-www-form-urlencoded" + } + if header == nil { + header = map[string]string{"Content-Type": contentType} + } + if _, ok := header["Content-Type"]; !ok { + header["Content-Type"] = contentType + } + resp, er := CurlReq(method, router, reqBody, header) + if er != nil { + return nil, er + } + res, err := ioutil.ReadAll(resp.Body) + if CurlDebug { + blob := SerializeStr(body) + if contentType != "application/json" { + blob = HttpBuild(body) + } + fmt.Printf("\n\n=====================\n[url]: %s\n[time]: %s\n[method]: %s\n[content-type]: %v\n[req_header]: %s\n[req_body]: %#v\n[resp_err]: %v\n[resp_header]: %v\n[resp_body]: %v\n=====================\n\n", + router, + time.Now().Format("2006-01-02 15:04:05.000"), + method, + contentType, + HttpBuildQuery(header), + blob, + err, + SerializeStr(resp.Header), + string(res), + ) + } + resp.Body.Close() + return res, err +} + +func curl_new(method, router string, body interface{}, header map[string]string) ([]byte, error) { + var reqBody io.Reader + contentType := "application/json" + + if header == nil { + header = map[string]string{"Content-Type": contentType} + } + if _, ok := header["Content-Type"]; !ok { + header["Content-Type"] = contentType + } + resp, er := CurlReq(method, router, reqBody, header) + if er != nil { + return nil, er + } + res, err := ioutil.ReadAll(resp.Body) + if CurlDebug { + blob := SerializeStr(body) + if contentType != "application/json" { + blob = HttpBuild(body) + } + fmt.Printf("\n\n=====================\n[url]: %s\n[time]: %s\n[method]: %s\n[content-type]: %v\n[req_header]: %s\n[req_body]: %#v\n[resp_err]: %v\n[resp_header]: %v\n[resp_body]: %v\n=====================\n\n", + router, + time.Now().Format("2006-01-02 15:04:05.000"), + method, + contentType, + HttpBuildQuery(header), + blob, + err, + SerializeStr(resp.Header), + string(res), + ) + } + resp.Body.Close() + return res, err +} + +func CurlReq(method, router string, reqBody io.Reader, header map[string]string) (*http.Response, error) { + req, _ := http.NewRequest(method, router, reqBody) + if header != nil { + for k, v := range header { + req.Header.Set(k, v) + } + } + // 绕过github等可能因为特征码返回503问题 + // https://www.imwzk.com/posts/2021-03-14-why-i-always-get-503-with-golang/ + defaultCipherSuites := []uint16{0xc02f, 0xc030, 0xc02b, 0xc02c, 0xcca8, 0xcca9, 0xc013, 0xc009, + 0xc014, 0xc00a, 0x009c, 0x009d, 0x002f, 0x0035, 0xc012, 0x000a} + client := &http.Client{ + Transport: &http.Transport{ + TLSClientConfig: &tls.Config{ + InsecureSkipVerify: true, + CipherSuites: append(defaultCipherSuites[8:], defaultCipherSuites[:8]...), + }, + }, + // 获取301重定向 + CheckRedirect: func(req *http.Request, via []*http.Request) error { + return http.ErrUseLastResponse + }, + } + return client.Do(req) +} + +// 组建get请求参数,sortAsc true为小到大,false为大到小,nil不排序 a=123&b=321 +func HttpBuildQuery(args map[string]string, sortAsc ...bool) string { + str := "" + if len(args) == 0 { + return str + } + if len(sortAsc) > 0 { + keys := make([]string, 0, len(args)) + for k := range args { + keys = append(keys, k) + } + if sortAsc[0] { + sort.Strings(keys) + } else { + sort.Sort(sort.Reverse(sort.StringSlice(keys))) + } + for _, k := range keys { + str += "&" + k + "=" + args[k] + } + } else { + for k, v := range args { + str += "&" + k + "=" + v + } + } + return str[1:] +} + +func HttpBuild(body interface{}, sortAsc ...bool) string { + params := map[string]string{} + if args, ok := body.(map[string]interface{}); ok { + for k, v := range args { + params[k] = AnyToString(v) + } + return HttpBuildQuery(params, sortAsc...) + } + if args, ok := body.(map[string]string); ok { + for k, v := range args { + params[k] = AnyToString(v) + } + return HttpBuildQuery(params, sortAsc...) + } + if args, ok := body.(map[string]int); ok { + for k, v := range args { + params[k] = AnyToString(v) + } + return HttpBuildQuery(params, sortAsc...) + } + return AnyToString(body) +} diff --git a/internal/business/comm/utils/file.go b/internal/business/comm/utils/file.go new file mode 100644 index 0000000..93ed08f --- /dev/null +++ b/internal/business/comm/utils/file.go @@ -0,0 +1,22 @@ +package utils + +import ( + "os" + "path" + "strings" + "time" +) + +// 获取文件后缀 +func FileExt(fname string) string { + return strings.ToLower(strings.TrimLeft(path.Ext(fname), ".")) +} + +func FilePutContents(fileName string, content string) { + fd, _ := os.OpenFile("./tmp/"+fileName+".log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0644) + fd_time := time.Now().Format("2006-01-02 15:04:05") + fd_content := strings.Join([]string{"[", fd_time, "] ", content, "\n"}, "") + buf := []byte(fd_content) + fd.Write(buf) + fd.Close() +} diff --git a/internal/business/comm/utils/logx/log.go b/internal/business/comm/utils/logx/log.go new file mode 100644 index 0000000..ca11223 --- /dev/null +++ b/internal/business/comm/utils/logx/log.go @@ -0,0 +1,245 @@ +package logx + +import ( + "os" + "strings" + "time" + + "go.uber.org/zap" + "go.uber.org/zap/zapcore" +) + +type LogConfig struct { + AppName string `yaml:"app_name" json:"app_name" toml:"app_name"` + Level string `yaml:"level" json:"level" toml:"level"` + StacktraceLevel string `yaml:"stacktrace_level" json:"stacktrace_level" toml:"stacktrace_level"` + IsStdOut bool `yaml:"is_stdout" json:"is_stdout" toml:"is_stdout"` + TimeFormat string `yaml:"time_format" json:"time_format" toml:"time_format"` // second, milli, nano, standard, iso, + Encoding string `yaml:"encoding" json:"encoding" toml:"encoding"` // console, json + Skip int `yaml:"skip" json:"skip" toml:"skip"` + + IsFileOut bool `yaml:"is_file_out" json:"is_file_out" toml:"is_file_out"` + FileDir string `yaml:"file_dir" json:"file_dir" toml:"file_dir"` + FileName string `yaml:"file_name" json:"file_name" toml:"file_name"` + FileMaxSize int `yaml:"file_max_size" json:"file_max_size" toml:"file_max_size"` + FileMaxAge int `yaml:"file_max_age" json:"file_max_age" toml:"file_max_age"` +} + +var ( + l *LogX = defaultLogger() + conf *LogConfig +) + +// default logger setting +func defaultLogger() *LogX { + conf = &LogConfig{ + Level: "debug", + StacktraceLevel: "error", + IsStdOut: true, + TimeFormat: "standard", + Encoding: "console", + Skip: 2, + } + writers := []zapcore.WriteSyncer{os.Stdout} + lg, lv := newZapLogger(setLogLevel(conf.Level), setLogLevel(conf.StacktraceLevel), conf.Encoding, conf.TimeFormat, conf.Skip, zapcore.NewMultiWriteSyncer(writers...)) + zap.RedirectStdLog(lg) + return &LogX{logger: lg, atomLevel: lv} +} + +// initial standard log, if you don't init, it will use default logger setting +func InitDefaultLogger(cfg *LogConfig) { + var writers []zapcore.WriteSyncer + if cfg.IsStdOut || (!cfg.IsStdOut && !cfg.IsFileOut) { + writers = append(writers, os.Stdout) + } + if cfg.IsFileOut { + writers = append(writers, NewRollingFile(cfg.FileDir, cfg.FileName, cfg.FileMaxSize, cfg.FileMaxAge)) + } + + lg, lv := newZapLogger(setLogLevel(cfg.Level), setLogLevel(cfg.StacktraceLevel), cfg.Encoding, cfg.TimeFormat, cfg.Skip, zapcore.NewMultiWriteSyncer(writers...)) + zap.RedirectStdLog(lg) + if cfg.AppName != "" { + lg = lg.With(zap.String("app", cfg.AppName)) // 加上应用名称 + } + l = &LogX{logger: lg, atomLevel: lv} +} + +// create a new logger +func NewLogger(cfg *LogConfig) *LogX { + var writers []zapcore.WriteSyncer + if cfg.IsStdOut || (!cfg.IsStdOut && !cfg.IsFileOut) { + writers = append(writers, os.Stdout) + } + if cfg.IsFileOut { + writers = append(writers, NewRollingFile(cfg.FileDir, cfg.FileName, cfg.FileMaxSize, cfg.FileMaxAge)) + } + + lg, lv := newZapLogger(setLogLevel(cfg.Level), setLogLevel(cfg.StacktraceLevel), cfg.Encoding, cfg.TimeFormat, cfg.Skip, zapcore.NewMultiWriteSyncer(writers...)) + zap.RedirectStdLog(lg) + if cfg.AppName != "" { + lg = lg.With(zap.String("app", cfg.AppName)) // 加上应用名称 + } + return &LogX{logger: lg, atomLevel: lv} +} + +// create a new zaplog logger +func newZapLogger(level, stacktrace zapcore.Level, encoding, timeType string, skip int, output zapcore.WriteSyncer) (*zap.Logger, *zap.AtomicLevel) { + encCfg := zapcore.EncoderConfig{ + TimeKey: "T", + LevelKey: "L", + NameKey: "N", + CallerKey: "C", + MessageKey: "M", + StacktraceKey: "S", + LineEnding: zapcore.DefaultLineEnding, + EncodeCaller: zapcore.ShortCallerEncoder, + EncodeDuration: zapcore.NanosDurationEncoder, + EncodeLevel: zapcore.LowercaseLevelEncoder, + } + setTimeFormat(timeType, &encCfg) // set time type + atmLvl := zap.NewAtomicLevel() // set level + atmLvl.SetLevel(level) + encoder := zapcore.NewJSONEncoder(encCfg) // 确定encoder格式 + if encoding == "console" { + encoder = zapcore.NewConsoleEncoder(encCfg) + } + return zap.New(zapcore.NewCore(encoder, output, atmLvl), zap.AddCaller(), zap.AddStacktrace(stacktrace), zap.AddCallerSkip(skip)), &atmLvl +} + +// set log level +func setLogLevel(lvl string) zapcore.Level { + switch strings.ToLower(lvl) { + case "panic": + return zapcore.PanicLevel + case "fatal": + return zapcore.FatalLevel + case "error": + return zapcore.ErrorLevel + case "warn", "warning": + return zapcore.WarnLevel + case "info": + return zapcore.InfoLevel + default: + return zapcore.DebugLevel + } +} + +// set time format +func setTimeFormat(timeType string, z *zapcore.EncoderConfig) { + switch strings.ToLower(timeType) { + case "iso": // iso8601 standard + z.EncodeTime = zapcore.ISO8601TimeEncoder + case "sec": // only for unix second, without millisecond + z.EncodeTime = func(t time.Time, enc zapcore.PrimitiveArrayEncoder) { + enc.AppendInt64(t.Unix()) + } + case "second": // unix second, with millisecond + z.EncodeTime = zapcore.EpochTimeEncoder + case "milli", "millisecond": // millisecond + z.EncodeTime = zapcore.EpochMillisTimeEncoder + case "nano", "nanosecond": // nanosecond + z.EncodeTime = zapcore.EpochNanosTimeEncoder + default: // standard format + z.EncodeTime = func(t time.Time, enc zapcore.PrimitiveArrayEncoder) { + enc.AppendString(t.Format("2006-01-02 15:04:05.000")) + } + } +} + +func GetLevel() string { + switch l.atomLevel.Level() { + case zapcore.PanicLevel: + return "panic" + case zapcore.FatalLevel: + return "fatal" + case zapcore.ErrorLevel: + return "error" + case zapcore.WarnLevel: + return "warn" + case zapcore.InfoLevel: + return "info" + default: + return "debug" + } +} + +func SetLevel(lvl string) { + l.atomLevel.SetLevel(setLogLevel(lvl)) +} + +// temporary add call skip +func AddCallerSkip(skip int) *LogX { + l.logger.WithOptions(zap.AddCallerSkip(skip)) + return l +} + +// permanent add call skip +func AddDepth(skip int) *LogX { + l.logger = l.logger.WithOptions(zap.AddCallerSkip(skip)) + return l +} + +// permanent add options +func AddOptions(opts ...zap.Option) *LogX { + l.logger = l.logger.WithOptions(opts...) + return l +} + +func AddField(k string, v interface{}) { + l.logger.With(zap.Any(k, v)) +} + +func AddFields(fields map[string]interface{}) *LogX { + for k, v := range fields { + l.logger.With(zap.Any(k, v)) + } + return l +} + +// Normal log +func Debug(e interface{}, args ...interface{}) error { + return l.Debug(e, args...) +} +func Info(e interface{}, args ...interface{}) error { + return l.Info(e, args...) +} +func Warn(e interface{}, args ...interface{}) error { + return l.Warn(e, args...) +} +func Error(e interface{}, args ...interface{}) error { + return l.Error(e, args...) +} +func Panic(e interface{}, args ...interface{}) error { + return l.Panic(e, args...) +} +func Fatal(e interface{}, args ...interface{}) error { + return l.Fatal(e, args...) +} + +// Format logs +func Debugf(format string, args ...interface{}) error { + return l.Debugf(format, args...) +} +func Infof(format string, args ...interface{}) error { + return l.Infof(format, args...) +} +func Warnf(format string, args ...interface{}) error { + return l.Warnf(format, args...) +} +func Errorf(format string, args ...interface{}) error { + return l.Errorf(format, args...) +} +func Panicf(format string, args ...interface{}) error { + return l.Panicf(format, args...) +} +func Fatalf(format string, args ...interface{}) error { + return l.Fatalf(format, args...) +} + +func formatFieldMap(m FieldMap) []Field { + var res []Field + for k, v := range m { + res = append(res, zap.Any(k, v)) + } + return res +} diff --git a/internal/business/comm/utils/logx/output.go b/internal/business/comm/utils/logx/output.go new file mode 100644 index 0000000..ef33f0b --- /dev/null +++ b/internal/business/comm/utils/logx/output.go @@ -0,0 +1,105 @@ +package logx + +import ( + "bytes" + "io" + "os" + "path/filepath" + "time" + + "gopkg.in/natefinch/lumberjack.v2" +) + +// output interface +type WriteSyncer interface { + io.Writer + Sync() error +} + +// split writer +func NewRollingFile(dir, filename string, maxSize, MaxAge int) WriteSyncer { + s, err := os.Stat(dir) + if err != nil || !s.IsDir() { + os.RemoveAll(dir) + if err := os.MkdirAll(dir, 0766); err != nil { + panic(err) + } + } + return newLumberjackWriteSyncer(&lumberjack.Logger{ + Filename: filepath.Join(dir, filename), + MaxSize: maxSize, // megabytes, MB + MaxAge: MaxAge, // days + LocalTime: true, + Compress: false, + }) +} + +type lumberjackWriteSyncer struct { + *lumberjack.Logger + buf *bytes.Buffer + logChan chan []byte + closeChan chan interface{} + maxSize int +} + +func newLumberjackWriteSyncer(l *lumberjack.Logger) *lumberjackWriteSyncer { + ws := &lumberjackWriteSyncer{ + Logger: l, + buf: bytes.NewBuffer([]byte{}), + logChan: make(chan []byte, 5000), + closeChan: make(chan interface{}), + maxSize: 1024, + } + go ws.run() + return ws +} + +func (l *lumberjackWriteSyncer) run() { + ticker := time.NewTicker(1 * time.Second) + + for { + select { + case <-ticker.C: + if l.buf.Len() > 0 { + l.sync() + } + case bs := <-l.logChan: + _, err := l.buf.Write(bs) + if err != nil { + continue + } + if l.buf.Len() > l.maxSize { + l.sync() + } + case <-l.closeChan: + l.sync() + return + } + } +} + +func (l *lumberjackWriteSyncer) Stop() { + close(l.closeChan) +} + +func (l *lumberjackWriteSyncer) Write(bs []byte) (int, error) { + b := make([]byte, len(bs)) + for i, c := range bs { + b[i] = c + } + l.logChan <- b + return 0, nil +} + +func (l *lumberjackWriteSyncer) Sync() error { + return nil +} + +func (l *lumberjackWriteSyncer) sync() error { + defer l.buf.Reset() + _, err := l.Logger.Write(l.buf.Bytes()) + if err != nil { + return err + } + return nil +} diff --git a/internal/business/comm/utils/logx/sugar.go b/internal/business/comm/utils/logx/sugar.go new file mode 100644 index 0000000..ab380fc --- /dev/null +++ b/internal/business/comm/utils/logx/sugar.go @@ -0,0 +1,192 @@ +package logx + +import ( + "errors" + "fmt" + "strconv" + + "go.uber.org/zap" +) + +type LogX struct { + logger *zap.Logger + atomLevel *zap.AtomicLevel +} + +type Field = zap.Field +type FieldMap map[string]interface{} + +// 判断其他类型--start +func getFields(msg string, format bool, args ...interface{}) (string, []Field) { + var str []interface{} + var fields []zap.Field + if len(args) > 0 { + for _, v := range args { + if f, ok := v.(Field); ok { + fields = append(fields, f) + } else if f, ok := v.(FieldMap); ok { + fields = append(fields, formatFieldMap(f)...) + } else { + str = append(str, AnyToString(v)) + } + } + if format { + return fmt.Sprintf(msg, str...), fields + } + str = append([]interface{}{msg}, str...) + return fmt.Sprintln(str...), fields + } + return msg, []Field{} +} + +func (l *LogX) Debug(s interface{}, args ...interface{}) error { + es, e := checkErr(s) + if es != "" { + msg, field := getFields(es, false, args...) + l.logger.Debug(msg, field...) + } + return e +} +func (l *LogX) Info(s interface{}, args ...interface{}) error { + es, e := checkErr(s) + if es != "" { + msg, field := getFields(es, false, args...) + l.logger.Info(msg, field...) + } + return e +} +func (l *LogX) Warn(s interface{}, args ...interface{}) error { + es, e := checkErr(s) + if es != "" { + msg, field := getFields(es, false, args...) + l.logger.Warn(msg, field...) + } + return e +} +func (l *LogX) Error(s interface{}, args ...interface{}) error { + es, e := checkErr(s) + if es != "" { + msg, field := getFields(es, false, args...) + l.logger.Error(msg, field...) + } + return e +} +func (l *LogX) DPanic(s interface{}, args ...interface{}) error { + es, e := checkErr(s) + if es != "" { + msg, field := getFields(es, false, args...) + l.logger.DPanic(msg, field...) + } + return e +} +func (l *LogX) Panic(s interface{}, args ...interface{}) error { + es, e := checkErr(s) + if es != "" { + msg, field := getFields(es, false, args...) + l.logger.Panic(msg, field...) + } + return e +} +func (l *LogX) Fatal(s interface{}, args ...interface{}) error { + es, e := checkErr(s) + if es != "" { + msg, field := getFields(es, false, args...) + l.logger.Fatal(msg, field...) + } + return e +} + +func checkErr(s interface{}) (string, error) { + switch e := s.(type) { + case error: + return e.Error(), e + case string: + return e, errors.New(e) + case []byte: + return string(e), nil + default: + return "", nil + } +} + +func (l *LogX) LogError(err error) error { + return l.Error(err.Error()) +} + +func (l *LogX) Debugf(msg string, args ...interface{}) error { + s, f := getFields(msg, true, args...) + l.logger.Debug(s, f...) + return errors.New(s) +} + +func (l *LogX) Infof(msg string, args ...interface{}) error { + s, f := getFields(msg, true, args...) + l.logger.Info(s, f...) + return errors.New(s) +} + +func (l *LogX) Warnf(msg string, args ...interface{}) error { + s, f := getFields(msg, true, args...) + l.logger.Warn(s, f...) + return errors.New(s) +} + +func (l *LogX) Errorf(msg string, args ...interface{}) error { + s, f := getFields(msg, true, args...) + l.logger.Error(s, f...) + return errors.New(s) +} + +func (l *LogX) DPanicf(msg string, args ...interface{}) error { + s, f := getFields(msg, true, args...) + l.logger.DPanic(s, f...) + return errors.New(s) +} + +func (l *LogX) Panicf(msg string, args ...interface{}) error { + s, f := getFields(msg, true, args...) + l.logger.Panic(s, f...) + return errors.New(s) +} + +func (l *LogX) Fatalf(msg string, args ...interface{}) error { + s, f := getFields(msg, true, args...) + l.logger.Fatal(s, f...) + return errors.New(s) +} + +func AnyToString(raw interface{}) string { + switch i := raw.(type) { + case []byte: + return string(i) + case int: + return strconv.FormatInt(int64(i), 10) + case int64: + return strconv.FormatInt(i, 10) + case float32: + return strconv.FormatFloat(float64(i), 'f', 2, 64) + case float64: + return strconv.FormatFloat(i, 'f', 2, 64) + case uint: + return strconv.FormatInt(int64(i), 10) + case uint8: + return strconv.FormatInt(int64(i), 10) + case uint16: + return strconv.FormatInt(int64(i), 10) + case uint32: + return strconv.FormatInt(int64(i), 10) + case uint64: + return strconv.FormatInt(int64(i), 10) + case int8: + return strconv.FormatInt(int64(i), 10) + case int16: + return strconv.FormatInt(int64(i), 10) + case int32: + return strconv.FormatInt(int64(i), 10) + case string: + return i + case error: + return i.Error() + } + return fmt.Sprintf("%#v", raw) +} diff --git a/internal/business/comm/utils/md5.go b/internal/business/comm/utils/md5.go new file mode 100644 index 0000000..52c108d --- /dev/null +++ b/internal/business/comm/utils/md5.go @@ -0,0 +1,12 @@ +package utils + +import ( + "crypto/md5" + "encoding/hex" +) + +func Md5(str string) string { + h := md5.New() + h.Write([]byte(str)) + return hex.EncodeToString(h.Sum(nil)) +} diff --git a/internal/business/comm/utils/rand.go b/internal/business/comm/utils/rand.go new file mode 100644 index 0000000..5c52ae3 --- /dev/null +++ b/internal/business/comm/utils/rand.go @@ -0,0 +1,46 @@ +package utils + +import ( + crand "crypto/rand" + "fmt" + "math/big" + "math/rand" + "time" +) + +func RandString(l int, c ...string) string { + var ( + chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" + str string + num *big.Int + ) + if len(c) > 0 { + chars = c[0] + } + chrLen := int64(len(chars)) + for len(str) < l { + num, _ = crand.Int(crand.Reader, big.NewInt(chrLen)) + str += string(chars[num.Int64()]) + } + return str +} + +func RandNum() string { + seed := time.Now().UnixNano() + rand.Int63() + return fmt.Sprintf("%05v", rand.New(rand.NewSource(seed)).Int31n(1000000)) +} + +//x的y次方 +func RandPow(l int) string { + var i = "1" + for j := 0; j < l; j++ { + i += "0" + } + k := StrToInt64(i) + n := rand.New(rand.NewSource(time.Now().UnixNano())).Int63n(k) + ls := "%0" + IntToStr(l) + "v" + str := fmt.Sprintf(ls, n) + //min := int(math.Pow10(l - 1)) + //max := int(math.Pow10(l) - 1) + return str +} diff --git a/internal/business/comm/utils/reply.go b/internal/business/comm/utils/reply.go new file mode 100644 index 0000000..dd65e73 --- /dev/null +++ b/internal/business/comm/utils/reply.go @@ -0,0 +1,29 @@ +package utils + +import ( + "errors" + "fmt" +) + +type Error string + +func (err Error) Error() string { return string(err) } + +var ErrNil = errors.New("redigo: nil returned") + +func Bytes(reply interface{}, err error) ([]byte, error) { + if err != nil { + return nil, err + } + switch reply := reply.(type) { + case []byte: + return reply, nil + case string: + return []byte(reply), nil + case nil: + return nil, ErrNil + case Error: + return nil, reply + } + return nil, fmt.Errorf("redigo: unexpected type for Bytes, got type %T", reply) +} diff --git a/internal/business/comm/utils/serialize.go b/internal/business/comm/utils/serialize.go new file mode 100644 index 0000000..1ac4d80 --- /dev/null +++ b/internal/business/comm/utils/serialize.go @@ -0,0 +1,23 @@ +package utils + +import ( + "encoding/json" +) + +func Serialize(data interface{}) []byte { + res, err := json.Marshal(data) + if err != nil { + return []byte{} + } + return res +} + +func Unserialize(b []byte, dst interface{}) { + if err := json.Unmarshal(b, dst); err != nil { + dst = nil + } +} + +func SerializeStr(data interface{}, arg ...interface{}) string { + return string(Serialize(data)) +} diff --git a/internal/business/comm/utils/time.go b/internal/business/comm/utils/time.go new file mode 100644 index 0000000..16fb214 --- /dev/null +++ b/internal/business/comm/utils/time.go @@ -0,0 +1,208 @@ +package utils + +import ( + "errors" + "fmt" + "strconv" + "strings" + "time" +) + +func StrToTime(s string) (int64, error) { + // delete all not int characters + if s == "" { + return time.Now().Unix(), nil + } + r := make([]rune, 14) + l := 0 + // 过滤除数字以外的字符 + for _, v := range s { + if '0' <= v && v <= '9' { + r[l] = v + l++ + if l == 14 { + break + } + } + } + for l < 14 { + r[l] = '0' // 补0 + l++ + } + t, err := time.Parse("20060102150405", string(r)) + if err != nil { + return 0, err + } + return t.Unix(), nil +} + +func TimeToStr(unixSecTime interface{}, layout ...string) string { + i := AnyToInt64(unixSecTime) + if i == 0 { + return "" + } + f := "2006-01-02 15:04:05" + if len(layout) > 0 { + f = layout[0] + } + return time.Unix(i, 0).Format(f) +} + +func FormatNanoUnix() string { + return strings.Replace(time.Now().Format("20060102150405.0000000"), ".", "", 1) +} + +func TimeParse(format, src string) (time.Time, error) { + return time.ParseInLocation(format, src, time.Local) +} + +func TimeParseStd(src string) time.Time { + t, _ := TimeParse("2006-01-02 15:04:05", src) + return t +} + +func TimeStdParseUnix(src string) int64 { + t, err := TimeParse("2006-01-02 15:04:05", src) + if err != nil { + return 0 + } + return t.Unix() +} + +// 获取一个当前时间 时间间隔 时间戳 +func GetTimeInterval(unit string, amount int) (startTime, endTime int64) { + t := time.Now() + nowTime := t.Unix() + tmpTime := int64(0) + switch unit { + case "years": + tmpTime = time.Date(t.Year()+amount, t.Month(), t.Day(), t.Hour(), 0, 0, 0, t.Location()).Unix() + case "months": + tmpTime = time.Date(t.Year(), t.Month()+time.Month(amount), t.Day(), t.Hour(), 0, 0, 0, t.Location()).Unix() + case "days": + tmpTime = time.Date(t.Year(), t.Month(), t.Day()+amount, t.Hour(), 0, 0, 0, t.Location()).Unix() + case "hours": + tmpTime = time.Date(t.Year(), t.Month(), t.Day(), t.Hour()+amount, 0, 0, 0, t.Location()).Unix() + } + if amount > 0 { + startTime = nowTime + endTime = tmpTime + } else { + startTime = tmpTime + endTime = nowTime + } + return +} + +// 几天前 +func TimeInterval(newTime int) string { + now := time.Now().Unix() + newTime64 := AnyToInt64(newTime) + if newTime64 >= now { + return "刚刚" + } + interval := now - newTime64 + switch { + case interval < 60: + return AnyToString(interval) + "秒前" + case interval < 60*60: + return AnyToString(interval/60) + "分前" + case interval < 60*60*24: + return AnyToString(interval/60/60) + "小时前" + case interval < 60*60*24*30: + return AnyToString(interval/60/60/24) + "天前" + case interval < 60*60*24*30*12: + return AnyToString(interval/60/60/24/30) + "月前" + default: + return AnyToString(interval/60/60/24/30/12) + "年前" + } +} + +// 时分秒字符串转时间戳,传入示例:8:40 or 8:40:10 +func HmsToUnix(str string) (int64, error) { + t := time.Now() + arr := strings.Split(str, ":") + if len(arr) < 2 { + return 0, errors.New("Time format error") + } + h, _ := strconv.Atoi(arr[0]) + m, _ := strconv.Atoi(arr[1]) + s := 0 + if len(arr) == 3 { + s, _ = strconv.Atoi(arr[3]) + } + formatted1 := fmt.Sprintf("%d%02d%02d%02d%02d%02d", t.Year(), t.Month(), t.Day(), h, m, s) + res, err := time.ParseInLocation("20060102150405", formatted1, time.Local) + if err != nil { + return 0, err + } else { + return res.Unix(), nil + } +} + +// 获取特定时间范围 +func GetTimeRange(s string) map[string]int64 { + t := time.Now() + var stime, etime time.Time + switch s { + case "today": + stime = time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, t.Location()) + etime = time.Date(t.Year(), t.Month(), t.Day()+1, 0, 0, 0, 0, t.Location()) + case "yesterday": + stime = time.Date(t.Year(), t.Month(), t.Day()-1, 0, 0, 0, 0, t.Location()) + etime = time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, t.Location()) + case "within_seven_days": + // 前6天0点 + stime = time.Date(t.Year(), t.Month(), t.Day()-6, 0, 0, 0, 0, t.Location()) + // 明天 0点 + etime = time.Date(t.Year(), t.Month(), t.Day()+1, 0, 0, 0, 0, t.Location()) + case "current_month": + stime = GetFirstDateOfMonth(t) + etime = time.Now() + case "last_month": + etime = GetFirstDateOfMonth(t) + monthTimes := TimeStdParseUnix(etime.Format("2006-01-02 15:04:05")) - 86400 + times, _ := UnixToTime(Int64ToStr(monthTimes)) + stime = GetFirstDateOfMonth(times) + + } + + return map[string]int64{ + "start": stime.Unix(), + "end": etime.Unix(), + } +} + +//时间戳转时间格式 +func UnixToTime(e string) (datatime time.Time, err error) { + data, err := strconv.ParseInt(e, 10, 64) + datatime = time.Unix(data, 0) + return +} + +//获取传入的时间所在月份的第一天,即某月第一天的0点。如传入time.Now(), 返回当前月份的第一天0点时间。 +func GetFirstDateOfMonth(d time.Time) time.Time { + d = d.AddDate(0, 0, -d.Day()+1) + return GetZeroTime(d) +} + +//获取传入的时间所在月份的最后一天,即某月最后一天的0点。如传入time.Now(), 返回当前月份的最后一天0点时间。 +func GetLastDateOfMonth(d time.Time) time.Time { + return GetFirstDateOfMonth(d).AddDate(0, 1, -1) +} + +//获取某一天的0点时间 +func GetZeroTime(d time.Time) time.Time { + return time.Date(d.Year(), d.Month(), d.Day(), 0, 0, 0, 0, d.Location()) +} + +//获取当月某天的某个时间的时间 +func GetDayToTime(day, timeStr string) string { + if timeStr == "" { + timeStr = "00:00:00" + } + year := time.Now().Year() + month := time.Now().Format("01") + times := fmt.Sprintf("%s-%s-%s %s", IntToStr(year), month, day, timeStr) + return times +} diff --git a/internal/business/domain/user/model/im_package.go b/internal/business/domain/user/model/im_package.go new file mode 100644 index 0000000..265529d --- /dev/null +++ b/internal/business/domain/user/model/im_package.go @@ -0,0 +1,24 @@ +package model + +import "time" + +type ImPackage struct { + Id int64 // 自增主键 + Name string // 套餐名 + Price string // 价格 + ValidityDay int64 // 有效期(天/月/年) + ValidityDayType int32 // 有效期类型(1:天 2:月 3:年) + FriendsTotalNum int64 // 好友总数 + FriendsSingleNum int64 // 单用户可添加好友数 + GroupTotalNum int64 // 群组总数 + GroupSingleNum int64 // 单用户可创建群组总数 + GroupNum int64 // 群人员数量 + SingleChatNumsEveryDay int64 // 每日单聊消息数 + GroupChatNumsEveryDay int64 // 每日群聊消息数 + LivingNumsEveryDay int64 // 日活数 + MessageCloudStorageDay int64 // 消息云端存储(天) + Sort int64 // 排序(天) + isUse int32 // 是否启用(1:启用 2:禁用) + CreateTime time.Time // 创建时间 + UpdateTime time.Time // 更新时间 +} diff --git a/internal/business/domain/user/model/master.go b/internal/business/domain/user/model/master.go new file mode 100644 index 0000000..2320018 --- /dev/null +++ b/internal/business/domain/user/model/master.go @@ -0,0 +1,17 @@ +package model + +import "time" + +type Master struct { + Id int64 // 自增主键 + Phone string // 手机号 + MasterId int64 // 站长id + MasterName string // 站长名称 + AvatarUrl string // 站长头像链接 + Extra string // 附加属性 + PackageId int64 // 套餐id(0:未购买套餐) + PackageExpireTime string // 套餐到期时间 + IsUse int32 // 是否可用(1:可用 2:禁用) + CreateTime time.Time // 创建时间 + UpdateTime time.Time // 更新时间 +} diff --git a/internal/business/domain/user/repo/im_package_dao.go b/internal/business/domain/user/repo/im_package_dao.go new file mode 100644 index 0000000..16e4b93 --- /dev/null +++ b/internal/business/domain/user/repo/im_package_dao.go @@ -0,0 +1,25 @@ +package repo + +import ( + "gim/internal/business/domain/user/model" + "gim/pkg/db" + "gim/pkg/gerrors" + "github.com/jinzhu/gorm" +) + +type imPackageDao struct{} + +var ImPackageDao = new(imPackageDao) + +// Get 获取套餐包详情 +func (*imPackageDao) Get(id int64) (*model.ImPackage, error) { + var imPackage = model.ImPackage{Id: id} + err := db.DB.First(&imPackage).Error + if err != nil && err != gorm.ErrRecordNotFound { + return nil, gerrors.WrapError(err) + } + if err == gorm.ErrRecordNotFound { + return nil, nil + } + return &imPackage, err +} diff --git a/internal/business/domain/user/repo/im_package_repo.go b/internal/business/domain/user/repo/im_package_repo.go new file mode 100644 index 0000000..1c2744a --- /dev/null +++ b/internal/business/domain/user/repo/im_package_repo.go @@ -0,0 +1,18 @@ +package repo + +import ( + "gim/internal/business/domain/user/model" +) + +type imPackageRepo struct{} + +var ImPackageRepo = new(imPackageRepo) + +// Get 获取单个套餐包 +func (*imPackageRepo) Get(masterId int64) (*model.ImPackage, error) { + imPackage, err := ImPackageDao.Get(masterId) + if err != nil { + return nil, err + } + return imPackage, err +} diff --git a/internal/business/domain/user/repo/master_cache.go b/internal/business/domain/user/repo/master_cache.go new file mode 100644 index 0000000..206e453 --- /dev/null +++ b/internal/business/domain/user/repo/master_cache.go @@ -0,0 +1,51 @@ +package repo + +import ( + "gim/internal/business/domain/user/model" + "gim/pkg/db" + "gim/pkg/gerrors" + "strconv" + "time" + + "github.com/go-redis/redis" +) + +const ( + MasterKey = "master:" + MasterExpire = 24 * time.Hour +) + +type masterCache struct{} + +var MasterCache = new(masterCache) + +// Get 获取用户缓存 +func (c *masterCache) Get(masterId int64) (*model.Master, error) { + var master model.Master + err := db.RedisUtil.Get(MasterKey+strconv.FormatInt(masterId, 10), &master) + if err != nil && err != redis.Nil { + return nil, gerrors.WrapError(err) + } + if err == redis.Nil { + return nil, nil + } + return &master, nil +} + +// Set 设置用户缓存 +func (c *masterCache) Set(master model.Master) error { + err := db.RedisUtil.Set(MasterKey+strconv.FormatInt(master.MasterId, 10), master, MasterExpire) + if err != nil { + return gerrors.WrapError(err) + } + return nil +} + +// Del 删除用户缓存 +func (c *masterCache) Del(masterId int64) error { + _, err := db.RedisCli.Del(MasterKey + strconv.FormatInt(masterId, 10)).Result() + if err != nil { + return gerrors.WrapError(err) + } + return nil +} diff --git a/internal/business/domain/user/repo/master_dao.go b/internal/business/domain/user/repo/master_dao.go new file mode 100644 index 0000000..d734a07 --- /dev/null +++ b/internal/business/domain/user/repo/master_dao.go @@ -0,0 +1,38 @@ +package repo + +import ( + "gim/internal/business/domain/user/model" + "gim/pkg/db" + "gim/pkg/gerrors" + "github.com/jinzhu/gorm" +) + +type masterDao struct{} + +var MasterDao = new(masterDao) + +// Get 获取站长信息 +func (*masterDao) Get(masterId int64) (*model.Master, error) { + var master = model.Master{MasterId: masterId} + err := db.DB.First(&master).Error + if err != nil && err != gorm.ErrRecordNotFound { + return nil, gerrors.WrapError(err) + } + if err == gorm.ErrRecordNotFound { + return nil, nil + } + return &master, err +} + +// GetByPhone 根据手机号获取用户信息 +func (*masterDao) GetByPhone(phone string) (*model.Master, error) { + var master model.Master + err := db.DB.First(&master, "phone_number = ?", phone).Error + if err != nil && err != gorm.ErrRecordNotFound { + return nil, gerrors.WrapError(err) + } + if err == gorm.ErrRecordNotFound { + return nil, nil + } + return &master, err +} diff --git a/internal/business/domain/user/repo/master_repo.go b/internal/business/domain/user/repo/master_repo.go new file mode 100644 index 0000000..1259aa8 --- /dev/null +++ b/internal/business/domain/user/repo/master_repo.go @@ -0,0 +1,37 @@ +package repo + +import ( + "gim/internal/business/domain/user/model" +) + +type masterRepo struct{} + +var MasterRepo = new(masterRepo) + +// Get 获取单个站长 +func (*masterRepo) Get(masterId int64) (*model.Master, error) { + master, err := MasterCache.Get(masterId) + if err != nil { + return nil, err + } + if master != nil { + return master, nil + } + + master, err = MasterDao.Get(masterId) + if err != nil { + return nil, err + } + + if master != nil { + err = MasterCache.Set(*master) + if err != nil { + return nil, err + } + } + return master, err +} + +func (*masterRepo) GetByPhone(phone string, masterId int64) (*model.Master, error) { + return MasterDao.GetByPhone(phone) +} diff --git a/internal/logic/api/logic_ext_test.go b/internal/logic/api/logic_ext_test.go index 48e7105..3d4d1ce 100644 --- a/internal/logic/api/logic_ext_test.go +++ b/internal/logic/api/logic_ext_test.go @@ -26,10 +26,10 @@ func getLogicExtClient() pb.LogicExtClient { // deprecated: func getCtx() context.Context { - token := "VRZWQVPFXHPUCCKFOANEYOLCDSFMKEAVYVMAZQWQ" + token := "AYBVKGSIFENYDKKOPBYVONZWTCZAQEDGHLAKZLXT" return metadata.NewOutgoingContext(context.TODO(), metadata.Pairs( - "user_id", "2", - "device_id", "2", + "user_id", "13", + "device_id", "10", "token", token, "request_id", strconv.FormatInt(time.Now().UnixNano(), 10))) } @@ -208,3 +208,17 @@ func TestLogicExtServer_GetGroupMembers(t *testing.T) { } fmt.Printf("%+v\n", resp) } + +func TestLogicExtServer_AddFriend(t *testing.T) { + resp, err := getLogicExtClient().AddFriend(getCtx(), + &pb.AddFriendReq{ + FriendId: 2, + Remarks: "weihan", + Description: "hello", + }) + if err != nil { + fmt.Println(err) + return + } + fmt.Printf("%+v\n", resp) +} diff --git a/pkg/grpclib/ctx.go b/pkg/grpclib/ctx.go index ae9f5e4..4389564 100644 --- a/pkg/grpclib/ctx.go +++ b/pkg/grpclib/ctx.go @@ -13,6 +13,7 @@ const ( CtxUserId = "user_id" CtxDeviceId = "device_id" CtxToken = "token" + CtxMasterId = "master_id" CtxRequestId = "request_id" ) @@ -107,6 +108,21 @@ func GetCtxToken(ctx context.Context) (string, error) { return tokens[0], nil } +// GetCtxMasterId 获取ctx的masterId +func GetCtxMasterId(ctx context.Context) (string, error) { + md, ok := metadata.FromIncomingContext(ctx) + if !ok { + return "", gerrors.ErrUnauthorized + } + + masterId, ok := md[CtxMasterId] + if !ok && len(masterId) == 0 { + return "", gerrors.ErrUnauthorized + } + + return masterId[0], nil +} + // NewAndCopyRequestId 创建一个context,并且复制RequestId func NewAndCopyRequestId(ctx context.Context) context.Context { newCtx := context.TODO() diff --git a/pkg/pb/business.ext.pb.go b/pkg/pb/business.ext.pb.go index 70cfb2b..548d8e3 100644 --- a/pkg/pb/business.ext.pb.go +++ b/pkg/pb/business.ext.pb.go @@ -1,8 +1,8 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.26.0 -// protoc v3.14.0 -// source: business.ext.proto_back +// protoc-gen-go v1.28.1 +// protoc v3.20.0--rc1 +// source: business.ext.proto package pb @@ -166,6 +166,140 @@ func (x *SignInResp) GetMasterId() int64 { return 0 } +type CloudUploadFileReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Dir string `protobuf:"bytes,1,opt,name=dir,proto3" json:"dir,omitempty"` // 目录名 + FileName string `protobuf:"bytes,2,opt,name=file_name,json=fileName,proto3" json:"file_name,omitempty"` // 上传原文件名称 + FileSize string `protobuf:"bytes,3,opt,name=file_size,json=fileSize,proto3" json:"file_size,omitempty"` // 文件大小 +} + +func (x *CloudUploadFileReq) Reset() { + *x = CloudUploadFileReq{} + if protoimpl.UnsafeEnabled { + mi := &file_business_ext_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CloudUploadFileReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CloudUploadFileReq) ProtoMessage() {} + +func (x *CloudUploadFileReq) ProtoReflect() protoreflect.Message { + mi := &file_business_ext_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CloudUploadFileReq.ProtoReflect.Descriptor instead. +func (*CloudUploadFileReq) Descriptor() ([]byte, []int) { + return file_business_ext_proto_rawDescGZIP(), []int{2} +} + +func (x *CloudUploadFileReq) GetDir() string { + if x != nil { + return x.Dir + } + return "" +} + +func (x *CloudUploadFileReq) GetFileName() string { + if x != nil { + return x.FileName + } + return "" +} + +func (x *CloudUploadFileReq) GetFileSize() string { + if x != nil { + return x.FileSize + } + return "" +} + +type CloudUploadFileResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Method string `protobuf:"bytes,1,opt,name=method,proto3" json:"method,omitempty"` // 请求方式 + Host string `protobuf:"bytes,2,opt,name=host,proto3" json:"host,omitempty"` // 域名 + Key string `protobuf:"bytes,3,opt,name=key,proto3" json:"key,omitempty"` // key + Token string `protobuf:"bytes,4,opt,name=token,proto3" json:"token,omitempty"` // token +} + +func (x *CloudUploadFileResp) Reset() { + *x = CloudUploadFileResp{} + if protoimpl.UnsafeEnabled { + mi := &file_business_ext_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CloudUploadFileResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CloudUploadFileResp) ProtoMessage() {} + +func (x *CloudUploadFileResp) ProtoReflect() protoreflect.Message { + mi := &file_business_ext_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CloudUploadFileResp.ProtoReflect.Descriptor instead. +func (*CloudUploadFileResp) Descriptor() ([]byte, []int) { + return file_business_ext_proto_rawDescGZIP(), []int{3} +} + +func (x *CloudUploadFileResp) GetMethod() string { + if x != nil { + return x.Method + } + return "" +} + +func (x *CloudUploadFileResp) GetHost() string { + if x != nil { + return x.Host + } + return "" +} + +func (x *CloudUploadFileResp) GetKey() string { + if x != nil { + return x.Key + } + return "" +} + +func (x *CloudUploadFileResp) GetToken() string { + if x != nil { + return x.Token + } + return "" +} + type User struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -184,7 +318,7 @@ type User struct { func (x *User) Reset() { *x = User{} if protoimpl.UnsafeEnabled { - mi := &file_business_ext_proto_msgTypes[2] + mi := &file_business_ext_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -197,7 +331,7 @@ func (x *User) String() string { func (*User) ProtoMessage() {} func (x *User) ProtoReflect() protoreflect.Message { - mi := &file_business_ext_proto_msgTypes[2] + mi := &file_business_ext_proto_msgTypes[4] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -210,7 +344,7 @@ func (x *User) ProtoReflect() protoreflect.Message { // Deprecated: Use User.ProtoReflect.Descriptor instead. func (*User) Descriptor() ([]byte, []int) { - return file_business_ext_proto_rawDescGZIP(), []int{2} + return file_business_ext_proto_rawDescGZIP(), []int{4} } func (x *User) GetUserId() int64 { @@ -280,7 +414,7 @@ type GetUserReq struct { func (x *GetUserReq) Reset() { *x = GetUserReq{} if protoimpl.UnsafeEnabled { - mi := &file_business_ext_proto_msgTypes[3] + mi := &file_business_ext_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -293,7 +427,7 @@ func (x *GetUserReq) String() string { func (*GetUserReq) ProtoMessage() {} func (x *GetUserReq) ProtoReflect() protoreflect.Message { - mi := &file_business_ext_proto_msgTypes[3] + mi := &file_business_ext_proto_msgTypes[5] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -306,7 +440,7 @@ func (x *GetUserReq) ProtoReflect() protoreflect.Message { // Deprecated: Use GetUserReq.ProtoReflect.Descriptor instead. func (*GetUserReq) Descriptor() ([]byte, []int) { - return file_business_ext_proto_rawDescGZIP(), []int{3} + return file_business_ext_proto_rawDescGZIP(), []int{5} } func (x *GetUserReq) GetUserId() int64 { @@ -327,7 +461,7 @@ type GetUserResp struct { func (x *GetUserResp) Reset() { *x = GetUserResp{} if protoimpl.UnsafeEnabled { - mi := &file_business_ext_proto_msgTypes[4] + mi := &file_business_ext_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -340,7 +474,7 @@ func (x *GetUserResp) String() string { func (*GetUserResp) ProtoMessage() {} func (x *GetUserResp) ProtoReflect() protoreflect.Message { - mi := &file_business_ext_proto_msgTypes[4] + mi := &file_business_ext_proto_msgTypes[6] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -353,7 +487,7 @@ func (x *GetUserResp) ProtoReflect() protoreflect.Message { // Deprecated: Use GetUserResp.ProtoReflect.Descriptor instead. func (*GetUserResp) Descriptor() ([]byte, []int) { - return file_business_ext_proto_rawDescGZIP(), []int{4} + return file_business_ext_proto_rawDescGZIP(), []int{6} } func (x *GetUserResp) GetUser() *User { @@ -377,7 +511,7 @@ type UpdateUserReq struct { func (x *UpdateUserReq) Reset() { *x = UpdateUserReq{} if protoimpl.UnsafeEnabled { - mi := &file_business_ext_proto_msgTypes[5] + mi := &file_business_ext_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -390,7 +524,7 @@ func (x *UpdateUserReq) String() string { func (*UpdateUserReq) ProtoMessage() {} func (x *UpdateUserReq) ProtoReflect() protoreflect.Message { - mi := &file_business_ext_proto_msgTypes[5] + mi := &file_business_ext_proto_msgTypes[7] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -403,7 +537,7 @@ func (x *UpdateUserReq) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateUserReq.ProtoReflect.Descriptor instead. func (*UpdateUserReq) Descriptor() ([]byte, []int) { - return file_business_ext_proto_rawDescGZIP(), []int{5} + return file_business_ext_proto_rawDescGZIP(), []int{7} } func (x *UpdateUserReq) GetNickname() string { @@ -446,7 +580,7 @@ type SearchUserReq struct { func (x *SearchUserReq) Reset() { *x = SearchUserReq{} if protoimpl.UnsafeEnabled { - mi := &file_business_ext_proto_msgTypes[6] + mi := &file_business_ext_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -459,7 +593,7 @@ func (x *SearchUserReq) String() string { func (*SearchUserReq) ProtoMessage() {} func (x *SearchUserReq) ProtoReflect() protoreflect.Message { - mi := &file_business_ext_proto_msgTypes[6] + mi := &file_business_ext_proto_msgTypes[8] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -472,7 +606,7 @@ func (x *SearchUserReq) ProtoReflect() protoreflect.Message { // Deprecated: Use SearchUserReq.ProtoReflect.Descriptor instead. func (*SearchUserReq) Descriptor() ([]byte, []int) { - return file_business_ext_proto_rawDescGZIP(), []int{6} + return file_business_ext_proto_rawDescGZIP(), []int{8} } func (x *SearchUserReq) GetKey() string { @@ -500,7 +634,7 @@ type SearchUserResp struct { func (x *SearchUserResp) Reset() { *x = SearchUserResp{} if protoimpl.UnsafeEnabled { - mi := &file_business_ext_proto_msgTypes[7] + mi := &file_business_ext_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -513,7 +647,7 @@ func (x *SearchUserResp) String() string { func (*SearchUserResp) ProtoMessage() {} func (x *SearchUserResp) ProtoReflect() protoreflect.Message { - mi := &file_business_ext_proto_msgTypes[7] + mi := &file_business_ext_proto_msgTypes[9] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -526,7 +660,7 @@ func (x *SearchUserResp) ProtoReflect() protoreflect.Message { // Deprecated: Use SearchUserResp.ProtoReflect.Descriptor instead. func (*SearchUserResp) Descriptor() ([]byte, []int) { - return file_business_ext_proto_rawDescGZIP(), []int{7} + return file_business_ext_proto_rawDescGZIP(), []int{9} } func (x *SearchUserResp) GetUsers() []*User { @@ -556,55 +690,72 @@ var file_business_ext_proto_rawDesc = []byte{ 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, - 0x08, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x49, 0x64, 0x22, 0xe1, 0x01, 0x0a, 0x04, 0x55, 0x73, - 0x65, 0x72, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x03, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x6e, - 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6e, - 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x73, 0x65, 0x78, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x73, 0x65, 0x78, 0x12, 0x1d, 0x0a, 0x0a, 0x61, 0x76, 0x61, - 0x74, 0x61, 0x72, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, - 0x76, 0x61, 0x74, 0x61, 0x72, 0x55, 0x72, 0x6c, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x78, 0x74, 0x72, - 0x61, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x78, 0x74, 0x72, 0x61, 0x12, 0x1f, - 0x0a, 0x0b, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x06, 0x20, - 0x01, 0x28, 0x03, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, - 0x1f, 0x0a, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x07, - 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, - 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x08, 0x20, - 0x01, 0x28, 0x03, 0x52, 0x08, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x49, 0x64, 0x22, 0x25, 0x0a, - 0x0a, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x12, 0x17, 0x0a, 0x07, 0x75, - 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x75, 0x73, - 0x65, 0x72, 0x49, 0x64, 0x22, 0x2b, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x52, - 0x65, 0x73, 0x70, 0x12, 0x1c, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x08, 0x2e, 0x70, 0x62, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x04, 0x75, 0x73, 0x65, - 0x72, 0x22, 0x72, 0x0a, 0x0d, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, - 0x65, 0x71, 0x12, 0x1a, 0x0a, 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x10, - 0x0a, 0x03, 0x73, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x73, 0x65, 0x78, - 0x12, 0x1d, 0x0a, 0x0a, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x55, 0x72, 0x6c, 0x12, - 0x14, 0x0a, 0x05, 0x65, 0x78, 0x74, 0x72, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, - 0x65, 0x78, 0x74, 0x72, 0x61, 0x22, 0x3e, 0x0a, 0x0d, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x55, - 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x61, 0x73, 0x74, - 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x6d, 0x61, 0x73, - 0x74, 0x65, 0x72, 0x49, 0x64, 0x22, 0x30, 0x0a, 0x0e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x55, - 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x12, 0x1e, 0x0a, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, - 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x08, 0x2e, 0x70, 0x62, 0x2e, 0x55, 0x73, 0x65, 0x72, - 0x52, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x32, 0xc3, 0x01, 0x0a, 0x0b, 0x42, 0x75, 0x73, 0x69, - 0x6e, 0x65, 0x73, 0x73, 0x45, 0x78, 0x74, 0x12, 0x27, 0x0a, 0x06, 0x53, 0x69, 0x67, 0x6e, 0x49, - 0x6e, 0x12, 0x0d, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x49, 0x6e, 0x52, 0x65, 0x71, - 0x1a, 0x0e, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x49, 0x6e, 0x52, 0x65, 0x73, 0x70, - 0x12, 0x2a, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x12, 0x0e, 0x2e, 0x70, 0x62, - 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x1a, 0x0f, 0x2e, 0x70, 0x62, - 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x12, 0x2a, 0x0a, 0x0a, - 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x12, 0x11, 0x2e, 0x70, 0x62, 0x2e, - 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x1a, 0x09, 0x2e, - 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x33, 0x0a, 0x0a, 0x53, 0x65, 0x61, 0x72, - 0x63, 0x68, 0x55, 0x73, 0x65, 0x72, 0x12, 0x11, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x65, 0x61, 0x72, - 0x63, 0x68, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x1a, 0x12, 0x2e, 0x70, 0x62, 0x2e, 0x53, - 0x65, 0x61, 0x72, 0x63, 0x68, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x42, 0x0d, 0x5a, - 0x0b, 0x67, 0x69, 0x6d, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x70, 0x62, 0x2f, 0x62, 0x06, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x33, + 0x08, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x49, 0x64, 0x22, 0x60, 0x0a, 0x12, 0x43, 0x6c, 0x6f, + 0x75, 0x64, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x12, + 0x10, 0x0a, 0x03, 0x64, 0x69, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x64, 0x69, + 0x72, 0x12, 0x1b, 0x0a, 0x09, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1b, + 0x0a, 0x09, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x22, 0x69, 0x0a, 0x13, 0x43, + 0x6c, 0x6f, 0x75, 0x64, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, + 0x73, 0x70, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x6f, + 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x12, 0x10, + 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, + 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0xe1, 0x01, 0x0a, 0x04, 0x55, 0x73, 0x65, 0x72, 0x12, + 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x6e, 0x69, 0x63, 0x6b, + 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6e, 0x69, 0x63, 0x6b, + 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x73, 0x65, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x05, 0x52, 0x03, 0x73, 0x65, 0x78, 0x12, 0x1d, 0x0a, 0x0a, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, + 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, 0x76, 0x61, 0x74, + 0x61, 0x72, 0x55, 0x72, 0x6c, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x78, 0x74, 0x72, 0x61, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x78, 0x74, 0x72, 0x61, 0x12, 0x1f, 0x0a, 0x0b, 0x63, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x1f, 0x0a, 0x0b, + 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x1b, 0x0a, + 0x09, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x08, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x49, 0x64, 0x22, 0x25, 0x0a, 0x0a, 0x47, 0x65, + 0x74, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, + 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, + 0x64, 0x22, 0x2b, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, + 0x12, 0x1c, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x08, + 0x2e, 0x70, 0x62, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x22, 0x72, + 0x0a, 0x0d, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x12, + 0x1a, 0x0a, 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x73, + 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x73, 0x65, 0x78, 0x12, 0x1d, 0x0a, + 0x0a, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x09, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x55, 0x72, 0x6c, 0x12, 0x14, 0x0a, 0x05, + 0x65, 0x78, 0x74, 0x72, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x78, 0x74, + 0x72, 0x61, 0x22, 0x3e, 0x0a, 0x0d, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x55, 0x73, 0x65, 0x72, + 0x52, 0x65, 0x71, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x5f, + 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, + 0x49, 0x64, 0x22, 0x30, 0x0a, 0x0e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x55, 0x73, 0x65, 0x72, + 0x52, 0x65, 0x73, 0x70, 0x12, 0x1e, 0x0a, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x08, 0x2e, 0x70, 0x62, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x05, 0x75, + 0x73, 0x65, 0x72, 0x73, 0x32, 0x87, 0x02, 0x0a, 0x0b, 0x42, 0x75, 0x73, 0x69, 0x6e, 0x65, 0x73, + 0x73, 0x45, 0x78, 0x74, 0x12, 0x27, 0x0a, 0x06, 0x53, 0x69, 0x67, 0x6e, 0x49, 0x6e, 0x12, 0x0d, + 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x49, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x0e, 0x2e, + 0x70, 0x62, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x49, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x2a, 0x0a, + 0x07, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x12, 0x0e, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, + 0x74, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x1a, 0x0f, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, + 0x74, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x12, 0x2a, 0x0a, 0x0a, 0x55, 0x70, 0x64, + 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x12, 0x11, 0x2e, 0x70, 0x62, 0x2e, 0x55, 0x70, 0x64, + 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x1a, 0x09, 0x2e, 0x70, 0x62, 0x2e, + 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x33, 0x0a, 0x0a, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x55, + 0x73, 0x65, 0x72, 0x12, 0x11, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x55, + 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x1a, 0x12, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x65, 0x61, 0x72, + 0x63, 0x68, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x12, 0x42, 0x0a, 0x0f, 0x43, 0x6c, + 0x6f, 0x75, 0x64, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x16, 0x2e, + 0x70, 0x62, 0x2e, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x46, 0x69, + 0x6c, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x17, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6c, 0x6f, 0x75, 0x64, + 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x42, 0x0d, + 0x5a, 0x0b, 0x67, 0x69, 0x6d, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x70, 0x62, 0x2f, 0x62, 0x06, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -619,34 +770,38 @@ func file_business_ext_proto_rawDescGZIP() []byte { return file_business_ext_proto_rawDescData } -var file_business_ext_proto_msgTypes = make([]protoimpl.MessageInfo, 8) +var file_business_ext_proto_msgTypes = make([]protoimpl.MessageInfo, 10) var file_business_ext_proto_goTypes = []interface{}{ - (*SignInReq)(nil), // 0: pb.SignInReq - (*SignInResp)(nil), // 1: pb.SignInResp - (*User)(nil), // 2: pb.User - (*GetUserReq)(nil), // 3: pb.GetUserReq - (*GetUserResp)(nil), // 4: pb.GetUserResp - (*UpdateUserReq)(nil), // 5: pb.UpdateUserReq - (*SearchUserReq)(nil), // 6: pb.SearchUserReq - (*SearchUserResp)(nil), // 7: pb.SearchUserResp - (*Empty)(nil), // 8: pb.Empty + (*SignInReq)(nil), // 0: pb.SignInReq + (*SignInResp)(nil), // 1: pb.SignInResp + (*CloudUploadFileReq)(nil), // 2: pb.CloudUploadFileReq + (*CloudUploadFileResp)(nil), // 3: pb.CloudUploadFileResp + (*User)(nil), // 4: pb.User + (*GetUserReq)(nil), // 5: pb.GetUserReq + (*GetUserResp)(nil), // 6: pb.GetUserResp + (*UpdateUserReq)(nil), // 7: pb.UpdateUserReq + (*SearchUserReq)(nil), // 8: pb.SearchUserReq + (*SearchUserResp)(nil), // 9: pb.SearchUserResp + (*Empty)(nil), // 10: pb.Empty } var file_business_ext_proto_depIdxs = []int32{ - 2, // 0: pb.GetUserResp.user:type_name -> pb.User - 2, // 1: pb.SearchUserResp.users:type_name -> pb.User - 0, // 2: pb.BusinessExt.SignIn:input_type -> pb.SignInReq - 3, // 3: pb.BusinessExt.GetUser:input_type -> pb.GetUserReq - 5, // 4: pb.BusinessExt.UpdateUser:input_type -> pb.UpdateUserReq - 6, // 5: pb.BusinessExt.SearchUser:input_type -> pb.SearchUserReq - 1, // 6: pb.BusinessExt.SignIn:output_type -> pb.SignInResp - 4, // 7: pb.BusinessExt.GetUser:output_type -> pb.GetUserResp - 8, // 8: pb.BusinessExt.UpdateUser:output_type -> pb.Empty - 7, // 9: pb.BusinessExt.SearchUser:output_type -> pb.SearchUserResp - 6, // [6:10] is the sub-list for method output_type - 2, // [2:6] is the sub-list for method input_type - 2, // [2:2] is the sub-list for extension type_name - 2, // [2:2] is the sub-list for extension extendee - 0, // [0:2] is the sub-list for field type_name + 4, // 0: pb.GetUserResp.user:type_name -> pb.User + 4, // 1: pb.SearchUserResp.users:type_name -> pb.User + 0, // 2: pb.BusinessExt.SignIn:input_type -> pb.SignInReq + 5, // 3: pb.BusinessExt.GetUser:input_type -> pb.GetUserReq + 7, // 4: pb.BusinessExt.UpdateUser:input_type -> pb.UpdateUserReq + 8, // 5: pb.BusinessExt.SearchUser:input_type -> pb.SearchUserReq + 2, // 6: pb.BusinessExt.CloudUploadFile:input_type -> pb.CloudUploadFileReq + 1, // 7: pb.BusinessExt.SignIn:output_type -> pb.SignInResp + 6, // 8: pb.BusinessExt.GetUser:output_type -> pb.GetUserResp + 10, // 9: pb.BusinessExt.UpdateUser:output_type -> pb.Empty + 9, // 10: pb.BusinessExt.SearchUser:output_type -> pb.SearchUserResp + 3, // 11: pb.BusinessExt.CloudUploadFile:output_type -> pb.CloudUploadFileResp + 7, // [7:12] is the sub-list for method output_type + 2, // [2:7] is the sub-list for method input_type + 2, // [2:2] is the sub-list for extension type_name + 2, // [2:2] is the sub-list for extension extendee + 0, // [0:2] is the sub-list for field type_name } func init() { file_business_ext_proto_init() } @@ -681,7 +836,7 @@ func file_business_ext_proto_init() { } } file_business_ext_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*User); i { + switch v := v.(*CloudUploadFileReq); i { case 0: return &v.state case 1: @@ -693,7 +848,7 @@ func file_business_ext_proto_init() { } } file_business_ext_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetUserReq); i { + switch v := v.(*CloudUploadFileResp); i { case 0: return &v.state case 1: @@ -705,7 +860,7 @@ func file_business_ext_proto_init() { } } file_business_ext_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetUserResp); i { + switch v := v.(*User); i { case 0: return &v.state case 1: @@ -717,7 +872,7 @@ func file_business_ext_proto_init() { } } file_business_ext_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*UpdateUserReq); i { + switch v := v.(*GetUserReq); i { case 0: return &v.state case 1: @@ -729,7 +884,7 @@ func file_business_ext_proto_init() { } } file_business_ext_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SearchUserReq); i { + switch v := v.(*GetUserResp); i { case 0: return &v.state case 1: @@ -741,6 +896,30 @@ func file_business_ext_proto_init() { } } file_business_ext_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdateUserReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_business_ext_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SearchUserReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_business_ext_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*SearchUserResp); i { case 0: return &v.state @@ -759,7 +938,7 @@ func file_business_ext_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_business_ext_proto_rawDesc, NumEnums: 0, - NumMessages: 8, + NumMessages: 10, NumExtensions: 0, NumServices: 1, }, @@ -773,17 +952,14 @@ func file_business_ext_proto_init() { file_business_ext_proto_depIdxs = nil } -// Reference imports to suppress errors if they are not otherwise used. -var _ context.Context -var _ grpc.ClientConnInterface - // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. -const _ = grpc.SupportPackageIsVersion6 +// Requires gRPC-Go v1.32.0 or later. +const _ = grpc.SupportPackageIsVersion7 // BusinessExtClient is the client API for BusinessExt service. // -// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. type BusinessExtClient interface { // 登录 SignIn(ctx context.Context, in *SignInReq, opts ...grpc.CallOption) (*SignInResp, error) @@ -793,6 +969,8 @@ type BusinessExtClient interface { UpdateUser(ctx context.Context, in *UpdateUserReq, opts ...grpc.CallOption) (*Empty, error) // 搜索用户(这里简单数据库实现,生产环境建议使用ES) SearchUser(ctx context.Context, in *SearchUserReq, opts ...grpc.CallOption) (*SearchUserResp, error) + // 上传文件至云端 + CloudUploadFile(ctx context.Context, in *CloudUploadFileReq, opts ...grpc.CallOption) (*CloudUploadFileResp, error) } type businessExtClient struct { @@ -839,7 +1017,18 @@ func (c *businessExtClient) SearchUser(ctx context.Context, in *SearchUserReq, o return out, nil } +func (c *businessExtClient) CloudUploadFile(ctx context.Context, in *CloudUploadFileReq, opts ...grpc.CallOption) (*CloudUploadFileResp, error) { + out := new(CloudUploadFileResp) + err := c.cc.Invoke(ctx, "/pb.BusinessExt/CloudUploadFile", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // BusinessExtServer is the server API for BusinessExt service. +// All implementations must embed UnimplementedBusinessExtServer +// for forward compatibility type BusinessExtServer interface { // 登录 SignIn(context.Context, *SignInReq) (*SignInResp, error) @@ -849,27 +1038,32 @@ type BusinessExtServer interface { UpdateUser(context.Context, *UpdateUserReq) (*Empty, error) // 搜索用户(这里简单数据库实现,生产环境建议使用ES) SearchUser(context.Context, *SearchUserReq) (*SearchUserResp, error) + // 上传文件至云端 + CloudUploadFile(context.Context, *CloudUploadFileReq) (*CloudUploadFileResp, error) } -// UnimplementedBusinessExtServer can be embedded to have forward compatible implementations. +// UnimplementedBusinessExtServer must be embedded to have forward compatible implementations. type UnimplementedBusinessExtServer struct { } -func (*UnimplementedBusinessExtServer) SignIn(context.Context, *SignInReq) (*SignInResp, error) { +func (UnimplementedBusinessExtServer) SignIn(context.Context, *SignInReq) (*SignInResp, error) { return nil, status.Errorf(codes.Unimplemented, "method SignIn not implemented") } -func (*UnimplementedBusinessExtServer) GetUser(context.Context, *GetUserReq) (*GetUserResp, error) { +func (UnimplementedBusinessExtServer) GetUser(context.Context, *GetUserReq) (*GetUserResp, error) { return nil, status.Errorf(codes.Unimplemented, "method GetUser not implemented") } -func (*UnimplementedBusinessExtServer) UpdateUser(context.Context, *UpdateUserReq) (*Empty, error) { +func (UnimplementedBusinessExtServer) UpdateUser(context.Context, *UpdateUserReq) (*Empty, error) { return nil, status.Errorf(codes.Unimplemented, "method UpdateUser not implemented") } -func (*UnimplementedBusinessExtServer) SearchUser(context.Context, *SearchUserReq) (*SearchUserResp, error) { +func (UnimplementedBusinessExtServer) SearchUser(context.Context, *SearchUserReq) (*SearchUserResp, error) { return nil, status.Errorf(codes.Unimplemented, "method SearchUser not implemented") } +func (UnimplementedBusinessExtServer) CloudUploadFile(context.Context, *CloudUploadFileReq) (*CloudUploadFileResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method CloudUploadFile not implemented") +} -func RegisterBusinessExtServer(s *grpc.Server, srv BusinessExtServer) { - s.RegisterService(&_BusinessExt_serviceDesc, srv) +func RegisterBusinessExtServer(s grpc.ServiceRegistrar, srv BusinessExtServer) { + s.RegisterService(&BusinessExt_ServiceDesc, srv) } func _BusinessExt_SignIn_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { @@ -944,7 +1138,28 @@ func _BusinessExt_SearchUser_Handler(srv interface{}, ctx context.Context, dec f return interceptor(ctx, in, info, handler) } -var _BusinessExt_serviceDesc = grpc.ServiceDesc{ +func _BusinessExt_CloudUploadFile_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CloudUploadFileReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(BusinessExtServer).CloudUploadFile(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/pb.BusinessExt/CloudUploadFile", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(BusinessExtServer).CloudUploadFile(ctx, req.(*CloudUploadFileReq)) + } + return interceptor(ctx, in, info, handler) +} + +// BusinessExt_ServiceDesc is the grpc.ServiceDesc for BusinessExt service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var BusinessExt_ServiceDesc = grpc.ServiceDesc{ ServiceName: "pb.BusinessExt", HandlerType: (*BusinessExtServer)(nil), Methods: []grpc.MethodDesc{ @@ -964,7 +1179,11 @@ var _BusinessExt_serviceDesc = grpc.ServiceDesc{ MethodName: "SearchUser", Handler: _BusinessExt_SearchUser_Handler, }, + { + MethodName: "CloudUploadFile", + Handler: _BusinessExt_CloudUploadFile_Handler, + }, }, Streams: []grpc.StreamDesc{}, - Metadata: "business.ext.proto_back", + Metadata: "business.ext.proto", } diff --git a/pkg/pb/business.int.pb.go b/pkg/pb/business.int.pb.go index f6fce63..d67d35f 100644 --- a/pkg/pb/business.int.pb.go +++ b/pkg/pb/business.int.pb.go @@ -333,7 +333,7 @@ func file_business_int_proto_init() { var _ context.Context var _ grpc.ClientConnInterface -// This is a compile-time assertion to ensure that this generated file +// This is a compile-time assertion to ensure that this generated comm // is compatible with the grpc package it is being compiled against. const _ = grpc.SupportPackageIsVersion6 diff --git a/pkg/pb/connect.int.pb.go b/pkg/pb/connect.int.pb.go index e4f9029..eb72b6d 100644 --- a/pkg/pb/connect.int.pb.go +++ b/pkg/pb/connect.int.pb.go @@ -316,7 +316,7 @@ func file_connect_int_proto_init() { var _ context.Context var _ grpc.ClientConnInterface -// This is a compile-time assertion to ensure that this generated file +// This is a compile-time assertion to ensure that this generated comm // is compatible with the grpc package it is being compiled against. const _ = grpc.SupportPackageIsVersion6 diff --git a/pkg/pb/logic.ext.pb.go b/pkg/pb/logic.ext.pb.go index a1a748d..1681fdf 100644 --- a/pkg/pb/logic.ext.pb.go +++ b/pkg/pb/logic.ext.pb.go @@ -2387,7 +2387,7 @@ func file_logic_ext_proto_init() { var _ context.Context var _ grpc.ClientConnInterface -// This is a compile-time assertion to ensure that this generated file +// This is a compile-time assertion to ensure that this generated comm // is compatible with the grpc package it is being compiled against. const _ = grpc.SupportPackageIsVersion6 diff --git a/pkg/pb/logic.int.pb.go b/pkg/pb/logic.int.pb.go index 8892af3..c7e89ed 100644 --- a/pkg/pb/logic.int.pb.go +++ b/pkg/pb/logic.int.pb.go @@ -1126,7 +1126,7 @@ func file_logic_int_proto_init() { var _ context.Context var _ grpc.ClientConnInterface -// This is a compile-time assertion to ensure that this generated file +// This is a compile-time assertion to ensure that this generated comm // is compatible with the grpc package it is being compiled against. const _ = grpc.SupportPackageIsVersion6 diff --git a/pkg/proto/business.ext.proto b/pkg/proto/business.ext.proto index 5c8700a..b2c672c 100644 --- a/pkg/proto/business.ext.proto +++ b/pkg/proto/business.ext.proto @@ -2,7 +2,7 @@ syntax = "proto3"; package pb; option go_package = "gim/pkg/pb/"; -import "common.ext.proto"; +message Empty{} service BusinessExt { // 登录 @@ -13,6 +13,8 @@ service BusinessExt { rpc UpdateUser (UpdateUserReq) returns (Empty); // 搜索用户(这里简单数据库实现,生产环境建议使用ES) rpc SearchUser (SearchUserReq) returns (SearchUserResp); + // 上传文件至云端 + rpc CloudUploadFile (CloudUploadFileReq) returns (CloudUploadFileResp); } message SignInReq { @@ -27,6 +29,17 @@ message SignInResp { string token = 3; // token int64 master_id = 4; // 站长id } +message CloudUploadFileReq { + string dir = 1; // 目录名 + string file_name = 2; // 上传原文件名称 + string file_size = 3; // 文件大小 +} +message CloudUploadFileResp { + string method = 1; // 请求方式 + string host = 2; // 域名 + string key = 3; // key + string token = 4; // token +} message User { int64 user_id = 1; // 用户id diff --git a/pkg/rpc/rpc.go b/pkg/rpc/rpc.go index f5f095b..121113d 100644 --- a/pkg/rpc/rpc.go +++ b/pkg/rpc/rpc.go @@ -58,6 +58,8 @@ func initConnectIntClient() { } func initBusinessIntClient() { + //conn, err := grpc.DialContext(context.TODO(), "127.0.0.1:8000", grpc.WithInsecure(), + // grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"LoadBalancingPolicy": "%s"}`, roundrobin.Name))) conn, err := grpc.DialContext(context.TODO(), k8s.GetK8STarget("gim", "business", "8000"), grpc.WithInsecure(), grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"LoadBalancingPolicy": "%s"}`, roundrobin.Name))) if err != nil { diff --git a/pkg/util/json.go b/pkg/util/json.go index d973395..4bc23e0 100644 --- a/pkg/util/json.go +++ b/pkg/util/json.go @@ -48,8 +48,15 @@ func FormatMessage(messageType pb.MessageType, messageContent []byte) string { msg = &pb.Text{} err = proto.Unmarshal(messageContent, msg) case pb.MessageType_MT_COMMAND: - msg = &pb.Text{} - err = proto.Unmarshal(messageContent, msg) + msgCmd := &pb.Command{ + Code: 0, + Data: nil, + } + err = proto.Unmarshal(messageContent, msgCmd) + if msgCmd.Code == int32(pb.PushCode_PC_ADD_FRIEND) { + msg = &pb.AddFriendPush{} + err = proto.Unmarshal(messageContent, msg) + } case pb.MessageType_MT_CUSTOM: msg = &pb.Text{} err = proto.Unmarshal(messageContent, msg) diff --git a/pkg/util/redis.go b/pkg/util/redis.go index 4b6f668..33989f7 100644 --- a/pkg/util/redis.go +++ b/pkg/util/redis.go @@ -1,6 +1,8 @@ package util import ( + "encoding/json" + "gim/internal/business/comm/utils" "gim/pkg/logger" "time" @@ -45,3 +47,62 @@ func (u *RedisUtil) Get(key string, value interface{}) error { } return nil } + +func (u *RedisUtil) HGetString(key string, HKey string) (string, error) { + return u.client.Do("HGET", key, HKey).String() +} + +func (u *RedisUtil) Exists(key string) bool { + count, err := u.client.Do("EXISTS", key).Int() + if count == 0 || err != nil { + return false + } + return true +} + +func (u *RedisUtil) HSet(key string, HKey string, data interface{}) (interface{}, error) { + return u.client.HSet(key, HKey, data).Result() +} + +func (u *RedisUtil) Expire(key string, ttl int) (interface{}, error) { + return u.client.Do("EXPIRE", key, ttl).Result() +} + +func (u *RedisUtil) Del(key string) (interface{}, error) { + return u.client.Do("DEL", key).Result() +} + +func (u *RedisUtil) Do(args ...interface{}) (reply interface{}, err error) { + return u.client.Do(args...).String() +} + +func (u *RedisUtil) SetEx(key string, data interface{}, ttl int) (reply interface{}, err error) { + return u.client.Do("SETEX", key, ttl, data).Result() +} + +func (u *RedisUtil) GetJson(key string, dst interface{}) error { + b, err := utils.Bytes(u.client.Do("GET", key).Result()) + if err != nil { + return err + } + if err = json.Unmarshal(b, dst); err != nil { + return err + } + return nil +} + +func (u *RedisUtil) SetJson(key string, data interface{}, ttl int) bool { + c, err := json.Marshal(data) + if err != nil { + return false + } + if ttl < 1 { + err = u.Set(key, c, time.Duration(ttl)) + } else { + _, err = u.SetEx(key, c, ttl) + } + if err != nil { + return false + } + return true +} diff --git a/test/tcp_conn/main.go b/test/tcp_conn/main.go index 8ef12bc..36f0a0a 100644 --- a/test/tcp_conn/main.go +++ b/test/tcp_conn/main.go @@ -87,7 +87,7 @@ func (c *TcpClient) SignIn() { signIn := pb.SignInInput{ UserId: c.UserId, DeviceId: c.DeviceId, - Token: "ABPIKUKGTCZZGLUSZQAGFXKCSQFEVXEMAYHNNOUZ", + Token: "GPFMVIWQKIKLLPHMDYECZJONPCAAKUWKMNGXRTSP", } c.Output(pb.PackageType_PT_SIGN_IN, time.Now().UnixNano(), &signIn) } @@ -165,6 +165,10 @@ func (c *TcpClient) HandlePackage(bytes []byte) { } msg := messageSend.Message + //if msg.Sender.SenderType == 1 { + // //系统发送的消息 + // + //} log.Printf("消息:发送者类型:%d 发送者id:%d 接收者类型:%d 接收者id:%d 消息内容:%+v seq:%d \n", msg.Sender.SenderType, msg.Sender.SenderId, msg.ReceiverType, msg.ReceiverId, util.FormatMessage(msg.MessageType, msg.MessageContent), msg.Seq)