Browse Source

first commit

master
dengbiao 1 month ago
commit
d24a299251
100 changed files with 19181 additions and 0 deletions
  1. +46
    -0
      .gitignore
  2. +34
    -0
      Dockerfile
  3. +34
    -0
      Dockerfile-task
  4. +32
    -0
      Makefile
  5. +38
    -0
      README.md
  6. +51
    -0
      app/cfg/cfg_app.go
  7. +3
    -0
      app/cfg/cfg_cache_key.go
  8. +9
    -0
      app/cfg/init_cache.go
  9. +50
    -0
      app/cfg/init_cfg.go
  10. +20
    -0
      app/cfg/init_log.go
  11. +28
    -0
      app/cfg/init_rabbitmq.go
  12. +236
    -0
      app/e/code.go
  13. +72
    -0
      app/e/error.go
  14. +110
    -0
      app/e/msg.go
  15. +8
    -0
      app/e/set_cache.go
  16. +16
    -0
      app/lib/qiniu/bucket_create.go
  17. +18
    -0
      app/lib/qiniu/bucket_delete.go
  18. +18
    -0
      app/lib/qiniu/bucket_get_domain.go
  19. +22
    -0
      app/lib/qiniu/init.go
  20. +54
    -0
      app/lib/qiniu/req_img_upload.go
  21. +54
    -0
      app/md/file.go
  22. +11
    -0
      app/md/mq.go
  23. +68
    -0
      app/svc/svc_file_img_upload.go
  24. +33
    -0
      app/svc/svc_validate_comm.go
  25. +38
    -0
      app/svc/svc_wx_pay.go
  26. +123
    -0
      app/utils/aes.go
  27. +95
    -0
      app/utils/base64.go
  28. +26
    -0
      app/utils/boolean.go
  29. +421
    -0
      app/utils/cache/base.go
  30. +107
    -0
      app/utils/cache/cache/cache.go
  31. +86
    -0
      app/utils/cache/cache/conv.go
  32. +241
    -0
      app/utils/cache/cache/file.go
  33. +239
    -0
      app/utils/cache/cache/memory.go
  34. +409
    -0
      app/utils/cache/redis.go
  35. +622
    -0
      app/utils/cache/redis_cluster.go
  36. +324
    -0
      app/utils/cache/redis_pool.go
  37. +617
    -0
      app/utils/cache/redis_pool_cluster.go
  38. +322
    -0
      app/utils/convert.go
  39. +19
    -0
      app/utils/crypto.go
  40. +209
    -0
      app/utils/curl.go
  41. +25
    -0
      app/utils/debug.go
  42. +37
    -0
      app/utils/duplicate.go
  43. +22
    -0
      app/utils/file.go
  44. +29
    -0
      app/utils/file_and_dir.go
  45. +59
    -0
      app/utils/format.go
  46. +146
    -0
      app/utils/ip.go
  47. +17
    -0
      app/utils/json.go
  48. +245
    -0
      app/utils/logx/log.go
  49. +105
    -0
      app/utils/logx/output.go
  50. +192
    -0
      app/utils/logx/sugar.go
  51. +9
    -0
      app/utils/map.go
  52. +341
    -0
      app/utils/map_and_struct.go
  53. +12
    -0
      app/utils/md5.go
  54. +33
    -0
      app/utils/qrcode/decodeFile.go
  55. +43
    -0
      app/utils/qrcode/getBase64.go
  56. +85
    -0
      app/utils/qrcode/saveFile.go
  57. +39
    -0
      app/utils/qrcode/writeWeb.go
  58. +31
    -0
      app/utils/rand.go
  59. +170
    -0
      app/utils/rsa.go
  60. +23
    -0
      app/utils/serialize.go
  61. +48
    -0
      app/utils/shuffle.go
  62. +125
    -0
      app/utils/sign_check.go
  63. +26
    -0
      app/utils/slice.go
  64. +47
    -0
      app/utils/slice_and_string.go
  65. +155
    -0
      app/utils/string.go
  66. +241
    -0
      app/utils/time.go
  67. +16
    -0
      app/utils/url.go
  68. +76
    -0
      app/utils/uuid.go
  69. +55
    -0
      app/utils/validator_err_trans.go
  70. +31
    -0
      app/utils/wx.go
  71. +2
    -0
      bin/.gitignore
  72. +18
    -0
      build.sh
  73. +12
    -0
      cmd_run.bat
  74. +8
    -0
      cmd_run.sh
  75. +13
    -0
      cmd_task.bat
  76. +9
    -0
      cmd_task.sh
  77. +45
    -0
      consume/init.go
  78. +27
    -0
      consume/md/consume_key.go
  79. +11
    -0
      consume/md/md_order.go
  80. +38
    -0
      consume/md/mq.go
  81. +68
    -0
      consume/one_circles_sign_in_consume.go
  82. BIN
     
  83. +103
    -0
      es/md/es_mapping.go
  84. +35
    -0
      es/md/es_struct.go
  85. +7
    -0
      etc/db_tpl/config
  86. +17
    -0
      etc/db_tpl/struct.go.tpl
  87. +37
    -0
      etc/task.yml
  88. +113
    -0
      go.mod
  89. +55
    -0
      k8s/zyos-go-mq-consume-prd.yaml
  90. +45
    -0
      main.go
  91. +1607
    -0
      pkg/pb/im.business.ext.pb.go
  92. +595
    -0
      pkg/pb/im.business.int.pb.go
  93. +131
    -0
      pkg/pb/im.common.ext.pb.go
  94. +2450
    -0
      pkg/pb/im.connect.ext.pb.go
  95. +395
    -0
      pkg/pb/im.connect.int.pb.go
  96. +3587
    -0
      pkg/pb/im.logic.ext.pb.go
  97. +1547
    -0
      pkg/pb/im.logic.int.pb.go
  98. +623
    -0
      pkg/pb/im.push.ext.pb.go
  99. +103
    -0
      pkg/proto/im.business.ext.proto
  100. +34
    -0
      pkg/proto/im.business.int.proto

+ 46
- 0
.gitignore View File

@@ -0,0 +1,46 @@
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib
# Test binary, built with `go test -c`
*.test
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
.idea
.vscode
*.log
.DS_Store
Thumbs.db
*.swp
*.swn
*.swo
*.swm
*.7z
*.zip
*.rar
*.tar
*.tar.gz
go.sum
/etc/cfg.yaml
images
test/test.json
etc/cfg.yml
t.json
t1.json
t2.json
t3.json
t.go
wait-for-it.sh
test.go
xorm
test.csv
nginx.conf
.devcontainer
.devcontainer/Dockerfile
.devcontainer/sources.list
/t1.go
/tmp/*
.idea/*
/.idea/modules.xml

+ 34
- 0
Dockerfile View File

@@ -0,0 +1,34 @@
# 多重构建,减少镜像大小
# 构建:使用golang:1.15版本
FROM registry.cn-shenzhen.aliyuncs.com/fnuoos-prd/golang:1.18.4 as build

# 容器环境变量添加,会覆盖默认的变量值
ENV GO111MODULE=on
ENV GOPROXY=https://goproxy.cn,direct
ENV TZ="Asia/Shanghai"
# 设置工作区
WORKDIR /go/release

# 把全部文件添加到/go/release目录
ADD . .

# 编译:把main.go编译成可执行的二进制文件,命名为zyos
RUN GOOS=linux CGO_ENABLED=0 GOARCH=amd64 go build -tags netgo -ldflags="-s -w" -installsuffix cgo -o zyos main.go

FROM ubuntu:xenial as prod
LABEL maintainer="dengbiao"
ENV TZ="Asia/Shanghai"

COPY static/html static/html
# 时区纠正
RUN rm -f /etc/localtime \
&& ln -sv /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
&& echo "Asia/Shanghai" > /etc/timezone
# 在build阶段复制可执行的go二进制文件app
COPY --from=build /go/release/zyos ./zyos

COPY --from=build /go/release/etc/cfg.yml /var/zyos/cfg.yml

# 启动服务
CMD ["./zyos","-c","/var/zyos/cfg.yml"]


+ 34
- 0
Dockerfile-task View File

@@ -0,0 +1,34 @@
# 多重构建,减少镜像大小
# 构建:使用golang:1.18版本
FROM registry.cn-shenzhen.aliyuncs.com/fnuoos-prd/golang:1.18.4 as build

# 容器环境变量添加,会覆盖默认的变量值
ENV GO111MODULE=on
ENV GOPROXY=https://goproxy.cn,direct
ENV TZ="Asia/Shanghai"
# 设置工作区
WORKDIR /go/release

# 把全部文件添加到/go/release目录
ADD . .

# 编译:把main.go编译成可执行的二进制文件,命名为zyos
RUN GOOS=linux CGO_ENABLED=0 GOARCH=amd64 go build -tags netgo -ldflags="-s -w" -installsuffix cgo -o zyos_mall_task cmd/task/main.go

FROM ubuntu:xenial as prod
LABEL maintainer="dengbiao"
ENV TZ="Asia/Shanghai"

COPY static/html static/html
# 时区纠正
RUN rm -f /etc/localtime \
&& ln -sv /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
&& echo "Asia/Shanghai" > /etc/timezone
# 在build阶段复制可执行的go二进制文件app
COPY --from=build /go/release/zyos ./zyos

COPY --from=build /go/release/etc/cfg.yml /var/zyos/cfg.yml

# 启动服务
CMD ["./zyos","-c","/var/zyos/cfg.yml"]


+ 32
- 0
Makefile View File

@@ -0,0 +1,32 @@
.PHONY: build clean tool lint help

APP=applet

all: build

build:
go build -o ./bin/$(APP) ./cmd/main.go

lite:
go build -ldflags "-s -w" -o ./bin/$(APP) ./cmd/main.go

install:
#@go build -v .
go install ./cmd/...

tool:
go vet ./...; true
gofmt -w .

lint:
golint ./...

clean:
rm -rf go-gin-example
go clean -i .

help:
@echo "make: compile packages and dependencies"
@echo "make tool: run specified go tool"
@echo "make lint: golint ./..."
@echo "make clean: remove object files and cached files"

+ 38
- 0
README.md View File

@@ -0,0 +1,38 @@
# applet

## 要看 nginx.conf 和 wap conf

## 层级介绍

- hdl 做接收数据的报错, 数据校验
- svc 做数据处理的报错, 数据转换
- lib 只抛出错误给hdl或者svc进行处理, 不做数据校验
- db 可以处理db错误,其它错误返回给svc进行处理
- mw 中间件
- md 结构体

#### 介绍
蛋蛋星球RabbitMq消费项目

#### 软件架构

软件架构说明

#### 安装教程

1. xxxx
2. xxxx
3. xxxx

#### 使用说明

1. xxxx
2. xxxx
3. xxxx

#### 参与贡献

1. Fork 本仓库
2. 新建 Feat_xxx 分支
3. 提交代码
4. 新建 Pull Request

+ 51
- 0
app/cfg/cfg_app.go View File

@@ -0,0 +1,51 @@
package cfg

import (
"time"
)

type Config struct {
CurlDebug bool `yaml:"curldebug"`
Debug bool `yaml:"debug"`
Prd bool `yaml:"prd"`
RedisAddr string `yaml:"redis_addr"`
RedisPassword string `yaml:"redis_password"`
DB DBCfg `yaml:"db"`
MQ MQCfg `yaml:"mq"`
Log LogCfg `yaml:"log"`
}

// 数据库配置结构体
type DBCfg struct {
Host string `yaml:"host"` //ip及端口
Name string `yaml:"name"` //库名
User string `yaml:"user"` //用户
Psw string `yaml:"psw"` //密码
ShowLog bool `yaml:"show_log"` //是否显示SQL语句
MaxLifetime time.Duration `yaml:"max_lifetime"`
MaxOpenConns int `yaml:"max_open_conns"`
MaxIdleConns int `yaml:"max_idle_conns"`
Path string `yaml:"path"` //日志文件存放路径
}

// 日志配置结构体
type LogCfg struct {
AppName string `yaml:"app_name" `
Level string `yaml:"level"`
IsStdOut bool `yaml:"is_stdout"`
TimeFormat string `yaml:"time_format"` // second, milli, nano, standard, iso,
Encoding string `yaml:"encoding"` // console, json

IsFileOut bool `yaml:"is_file_out"`
FileDir string `yaml:"file_dir"`
FileName string `yaml:"file_name"`
FileMaxSize int `yaml:"file_max_size"`
FileMaxAge int `yaml:"file_max_age"`
}

type MQCfg struct {
Host string `yaml:"host"`
Port string `yaml:"port"`
User string `yaml:"user"`
Pwd string `yaml:"pwd"`
}

+ 3
- 0
app/cfg/cfg_cache_key.go View File

@@ -0,0 +1,3 @@
package cfg

// 统一管理缓存

+ 9
- 0
app/cfg/init_cache.go View File

@@ -0,0 +1,9 @@
package cfg

import (
"applet/app/utils/cache"
)

func InitCache() {
cache.NewRedis(RedisAddr, RedisPassword)
}

+ 50
- 0
app/cfg/init_cfg.go View File

@@ -0,0 +1,50 @@
package cfg

import (
"flag"
"io/ioutil"

"gopkg.in/yaml.v2"
)

// 配置文件数据,全局变量
var (
Debug bool
Prd bool
CurlDebug bool
RedisAddr string
RedisPassword string
DB *DBCfg
MQ *MQCfg
Log *LogCfg
)

// 初始化配置文件,将cfg.yml读入到内存
func InitCfg() {
//用指定的名称、默认值、使用信息注册一个string类型flag。
path := flag.String("c", "etc/cfg.yml", "config file")
//解析命令行参数写入注册的flag里。
//解析之后,flag的值可以直接使用。
flag.Parse()
var (
c []byte
err error
conf *Config
)
if c, err = ioutil.ReadFile(*path); err != nil {
panic(err)
}
//yaml.Unmarshal反序列化映射到Config
if err = yaml.Unmarshal(c, &conf); err != nil {
panic(err)
}
//数据读入内存
Prd = conf.Prd
Debug = conf.Debug
CurlDebug = conf.CurlDebug
DB = &conf.DB
Log = &conf.Log
RedisAddr = conf.RedisAddr
MQ = &conf.MQ
RedisPassword = conf.RedisPassword
}

+ 20
- 0
app/cfg/init_log.go View File

@@ -0,0 +1,20 @@
package cfg

import "applet/app/utils/logx"

func InitLog() {
logx.InitDefaultLogger(&logx.LogConfig{
AppName: Log.AppName,
Level: Log.Level,
StacktraceLevel: "error",
IsStdOut: Log.IsStdOut,
TimeFormat: Log.TimeFormat,
Encoding: Log.Encoding,
IsFileOut: Log.IsFileOut,
FileDir: Log.FileDir,
FileName: Log.FileName,
FileMaxSize: Log.FileMaxSize,
FileMaxAge: Log.FileMaxAge,
Skip: 2,
})
}

+ 28
- 0
app/cfg/init_rabbitmq.go View File

@@ -0,0 +1,28 @@
package cfg

import (
"code.fnuoos.com/go_rely_warehouse/zyos_go_mq.git/rabbit"
"encoding/json"
"os"
"strings"
"time"
)

func InitMq() {
data, _ := json.Marshal(MQ)
filePutContents("init_rabbit_mq", string(data))
err := rabbit.Init(MQ.Host, MQ.Port, MQ.User, MQ.Pwd)
if err != nil {
filePutContents("init_rabbit_mq", err.Error())
return
}
}

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

+ 236
- 0
app/e/code.go View File

@@ -0,0 +1,236 @@
package e

const (
// 200 因为部分第三方接口不能返回错误头,因此在此定义部分错误
ERR_FILE_SAVE = 200001
// 400 系列
ERR_BAD_REQUEST = 400000
ERR_INVALID_ARGS = 400001
ERR_API_RESPONSE = 400002
ERR_NO_DATA = 400003
ERR_MOBILE_NIL = 400004
ERR_MOBILE_MATH = 400005
ERR_FILE_EXT = 400006
ERR_FILE_MAX_SIZE = 400007
ERR_SIGN = 400008
ERR_PASSWORD_MATH = 400009
ERR_PROVIDER_RESPONSE = 400010
ERR_AES_ENCODE = 400011
ERR_ADMIN_API = 400012
ERR_QINIUAPI_RESPONSE = 400013
ERR_URL_TURNCHAIN = 400014

// 401 未授权
ERR_UNAUTHORIZED = 401000
ERR_NOT_AUTH = 401001
ERR_SMS_AUTH = 401002
ERR_TOKEN_AUTH = 401003
ERR_TOKEN_FORMAT = 401004
ERR_TOKEN_GEN = 401005
ERR_CACHE_SET = 401006
// 403 禁止
ERR_FORBIDEN = 403000
ERR_PLATFORM = 403001
ERR_MOBILE_EXIST = 403002
ERR_USER_NO_EXIST = 403003
ERR_MOBILE_NO_EXIST = 403004
ERR_FORBIDEN_VALID = 403005
ERR_RELATE_ERR = 403006
ERR_REPEAT_RELATE = 403007
ERR_MOB_FORBIDEN = 403008
ERR_MOB_SMS_NO_AVA = 403009
ERR_USER_IS_REG = 403010
ERR_MASTER_ID = 403011
ERR_CASH_OUT_TIME = 403012
ERR_CASH_OUT_FEE = 403013
ERR_CASH_OUT_USER_NOT_FOUND = 403014
ERR_CASH_OUT_FAIL = 403015
ERR_CASH_OUT_TIMES = 403016
ERR_CASH_OUT_MINI = 403017
ERR_CASH_OUT_MUT = 403018
ERR_CASH_OUT_NOT_DECIMAL = 403019
ERR_CASH_OUT_NOT_DAY_AVA = 403020
ERR_USER_LEVEL_PAY_CHECK_TASK_NO_DONE = 403021
ERR_USER_LEVEL_PAY_CHECK_NO_CROSS = 403022
ERR_USER_LEVEL_ORD_EXP = 403023
ERR_IS_BIND_THIRDPARTY = 403024
ERR_USER_LEVEL_UPDATE_CHECK_TASK_NO_DONE = 403025
ERR_USER_LEVEL_UPDATE_CHECK_NOT_FOUND_ORDER = 403026
ERR_USER_LEVEL_UPDATE_REPEAT = 403027
ERR_USER_NO_ACTIVE = 403028
ERR_USER_IS_BAN = 403029
ERR_ALIPAY_SETTING = 403030
ERR_ALIPAY_ORDERTYPE = 403031
ERR_CLIPBOARD_UNSUP = 403032
ERR_SYSUNION_CONFIG = 403033
ERR_WECAHT_MINI = 403034
ERR_WECAHT_MINI_CACHE = 403035
ERR_WECAHT_MINI_DECODE = 403036
ERR_WECHAT_MINI_ACCESSTOKEN = 403037
ERR_CURRENT_VIP_LEVEL_AUDITING = 403038
ERR_LEVEL_RENEW_SHOULD_KEEP_CURRENT = 403039
ERR_LEVEL_UPGRADE_APPLY_AUDITTING = 403040
ERR_LEVEL_TASK_PAY_TYPE = 403041
ERR_BALANCE_NOT_ENOUGH = 403042
ERR_ADMIN_PUSH = 403043
ERR_PLAN = 403044
ERR_MOB_CONFIG = 403045
ERR_BAlANCE_PAY_ORDERTYPE = 403046
ERR_PHONE_EXISTED = 403047
ERR_NOT_RESULT = 403048
ERR_REVIEW = 403049
ERR_USER_LEVEL_HAS_PAID = 403050
ERR_USER_BIND_OWN = 403051
ERR_PARENTUID_ERR = 403052
ERR_USER_DEL = 403053
ERR_SEARCH_ERR = 403054
ERR_LEVEL_REACH_TOP = 403055
ERR_USER_CHECK_ERR = 403056
ERR_PASSWORD_ERR = 403057
// 404
ERR_USER_NOTFOUND = 404001
ERR_SUP_NOTFOUND = 404002
ERR_LEVEL_MAP = 404003
ERR_MOD_NOTFOUND = 404004
ERR_CLIPBOARD_PARSE = 404005
ERR_NOT_FAN = 404006
ERR_USER_LEVEL = 404007
ERR_LACK_PAY_CFG = 404008
ERR_NOT_LEVEL_TASK = 404009
ERR_ITEM_NOT_FOUND = 404010
ERR_WX_CHECKFILE_NOTFOUND = 404011

// 429 请求频繁
ERR_TOO_MANY_REQUESTS = 429000
// 500 系列
ERR = 500000
ERR_UNMARSHAL = 500001
ERR_UNKNOWN = 500002
ERR_SMS = 500003
ERR_ARKID_REGISTER = 500004
ERR_ARKID_WHITELIST = 500005
ERR_ARKID_LOGIN = 500006
ERR_CFG = 500007
ERR_DB_ORM = 500008
ERR_CFG_CACHE = 500009
ERR_ZHIMENG_CONVERT_ERR = 500010
ERR_ALIPAY_ERR = 500011
ERR_ALIPAY_ORDER_ERR = 500012
ERR_PAY_ERR = 500013
ERR_IS_BIND_THIRDOTHER = 500014
)

var MsgFlags = map[int]string{
// 200
ERR_FILE_SAVE: "文件保存失败",
// 400
ERR_BAD_REQUEST: "请求失败",
ERR_INVALID_ARGS: "请求参数错误",
ERR_API_RESPONSE: "API错误",
ERR_QINIUAPI_RESPONSE: "七牛请求API错误",
ERR_URL_TURNCHAIN: "转链失败",
ERR_NO_DATA: "暂无数据",
ERR_MOBILE_NIL: "电话号码不能为空",
ERR_MOBILE_MATH: "电话号码输入有误",
ERR_FILE_MAX_SIZE: "文件上传大小超限",
ERR_FILE_EXT: "文件类型不支持",
ERR_SIGN: "签名校验失败",
ERR_PROVIDER_RESPONSE: "提供商接口错误",
ERR_AES_ENCODE: "加解密错误",
ERR_ADMIN_API: "后台接口请求失败",
// 401
ERR_NOT_AUTH: "请登录后操作",
ERR_SMS_AUTH: "验证码过期或无效",
ERR_UNAUTHORIZED: "验证用户失败",
ERR_TOKEN_FORMAT: "Token格式不对",
ERR_TOKEN_GEN: "生成Token失败",
ERR_CACHE_SET: "生成缓存失败",
// 403
ERR_FORBIDEN: "禁止访问",
ERR_PLATFORM: "平台不支持",
ERR_MOBILE_EXIST: "该号码已注册过",
ERR_USER_NO_EXIST: "用户没有注册或账号密码不正确",
ERR_PASSWORD_ERR: "输入两次密码不一致",
ERR_RELATE_ERR: "推荐人不能是自己的粉丝",
ERR_PARENTUID_ERR: "推荐人不存在",
ERR_TOKEN_AUTH: "登录信息失效,请重新登录",
ERR_MOB_SMS_NO_AVA: "短信余额不足或智盟短信配置失败",
ERR_USER_IS_REG: "用户已注册",
ERR_MASTER_ID: "找不到对应站长的数据库",
ERR_CASH_OUT_TIME: "非可提现时间段",
ERR_CASH_OUT_USER_NOT_FOUND: "收款账号不存在",
ERR_CASH_OUT_FAIL: "提现失败",
ERR_CASH_OUT_FEE: "提现金额必须大于手续费",
ERR_CASH_OUT_TIMES: "当日提现次数已达上线",
ERR_CASH_OUT_MINI: "申请提现金额未达到最低金额要求",
ERR_CASH_OUT_MUT: "申请提现金额未达到整数倍要求",
ERR_CASH_OUT_NOT_DECIMAL: "提现申请金额只能是整数",
ERR_CASH_OUT_NOT_DAY_AVA: "不在可提现日期范围内",
ERR_USER_LEVEL_PAY_CHECK_TASK_NO_DONE: "请先完成其他任务",
ERR_USER_LEVEL_PAY_CHECK_NO_CROSS: "无法跨越升级",
ERR_USER_LEVEL_ORD_EXP: "付费订单已失效",
ERR_IS_BIND_THIRDPARTY: "该用户已经绑定了",
ERR_IS_BIND_THIRDOTHER: "该账号已经被绑定了",
ERR_USER_LEVEL_UPDATE_CHECK_TASK_NO_DONE: "请完成指定任务",
ERR_USER_LEVEL_UPDATE_CHECK_NOT_FOUND_ORDER: "没有找到对应的订单",
ERR_USER_LEVEL_UPDATE_REPEAT: "不允许重复升级",
ERR_USER_NO_ACTIVE: "账户没激活",
ERR_USER_IS_BAN: "账户已被冻结",
ERR_SYSUNION_CONFIG: "联盟设置错误,请检查配置",
ERR_WECAHT_MINI: "小程序响应错误,请检查小程序配置",
ERR_WECAHT_MINI_CACHE: "获取小程序缓存失败",
ERR_WECAHT_MINI_DECODE: "小程序解密失败",
ERR_WECHAT_MINI_ACCESSTOKEN: "无法获取accesstoekn",
ERR_CURRENT_VIP_LEVEL_AUDITING: "当前等级正在审核中",
ERR_LEVEL_RENEW_SHOULD_KEEP_CURRENT: "续费只能在当前等级续费",
ERR_LEVEL_UPGRADE_APPLY_AUDITTING: "已有申请正在审核中,暂时不能申请",
ERR_LEVEL_TASK_PAY_TYPE: "任务付费类型错误",
ERR_BALANCE_NOT_ENOUGH: "余额不足",
ERR_ADMIN_PUSH: "后台MOB推送错误",
ERR_PLAN: "分拥方案出错",
ERR_MOB_CONFIG: "Mob 配置错误",
ERR_BAlANCE_PAY_ORDERTYPE: "无效余额支付订单类型",
ERR_PHONE_EXISTED: "手机号码已存在",
ERR_NOT_RESULT: "已加载完毕",
ERR_REVIEW: "审核模板错误",
ERR_USER_LEVEL_HAS_PAID: "该等级已经付过款",
// 404
ERR_USER_NOTFOUND: "用户不存在",
ERR_USER_DEL: "账号被删除,如有疑问请联系客服",
ERR_SUP_NOTFOUND: "上级用户不存在",
ERR_LEVEL_MAP: "无等级映射关系",
ERR_MOD_NOTFOUND: "没有找到对应模块",
ERR_CLIPBOARD_PARSE: "无法解析剪切板内容",
ERR_NOT_FAN: "没有粉丝",
ERR_CLIPBOARD_UNSUP: "不支持该平台",
ERR_USER_LEVEL: "该等级已不存在",
ERR_LACK_PAY_CFG: "支付配置不完整",
ERR_NOT_LEVEL_TASK: "等级任务查找错误",
ERR_ITEM_NOT_FOUND: "找不到对应商品",
ERR_WX_CHECKFILE_NOTFOUND: "找不到微信校验文件",
ERR_USER_BIND_OWN: "不能填写自己的邀请码",
// 429
ERR_TOO_MANY_REQUESTS: "请求频繁,请稍后重试",
// 500 内部错误
ERR: "接口错误",
ERR_SMS: "短信发送出错",
ERR_CFG: "服务器配置错误",
ERR_UNMARSHAL: "JSON解码错误",
ERR_UNKNOWN: "未知错误",
ERR_ARKID_LOGIN: "登录失败",
ERR_MOBILE_NO_EXIST: "该用户未设定手机号",
ERR_FORBIDEN_VALID: "验证码错误",
ERR_CFG_CACHE: "获取配置缓存失败",
ERR_DB_ORM: "数据操作失败",
ERR_REPEAT_RELATE: "重复关联",
ERR_ZHIMENG_CONVERT_ERR: "智盟转链失败",
ERR_MOB_FORBIDEN: "Mob调用失败",
ERR_ALIPAY_ERR: "支付宝参数错误",
ERR_ALIPAY_SETTING: "请在后台正确配置支付宝",
ERR_ALIPAY_ORDERTYPE: "无效支付宝订单类型",
ERR_ALIPAY_ORDER_ERR: "订单创建错误",
ERR_PAY_ERR: "未找到支付方式",
ERR_SEARCH_ERR: "暂无该分类商品",
ERR_LEVEL_REACH_TOP: "已经是最高等级",
ERR_USER_CHECK_ERR: "校验失败",
}

+ 72
- 0
app/e/error.go View File

@@ -0,0 +1,72 @@
package e

import (
"fmt"
"path"
"runtime"
)

type E struct {
Code int // 错误码
msg string // 报错代码
st string // 堆栈信息
}

func NewErrCode(code int) error {
if msg, ok := MsgFlags[code]; ok {
return E{code, msg, stack(3)}
}
return E{ERR_UNKNOWN, "unknown", stack(3)}
}

func NewErr(code int, msg string) error {
return E{code, msg, stack(3)}
}

func NewErrf(code int, msg string, args ...interface{}) error {
return E{code, fmt.Sprintf(msg, args), stack(3)}
}

func (e E) Error() string {
return e.msg
}

func stack(skip int) string {
stk := make([]uintptr, 32)
str := ""
l := runtime.Callers(skip, stk[:])
for i := 0; i < l; i++ {
f := runtime.FuncForPC(stk[i])
name := f.Name()
file, line := f.FileLine(stk[i])
str += fmt.Sprintf("\n%-30s[%s:%d]", name, path.Base(file), line)
}
return str
}

// ErrorIsAccountBan is 检查这个账号是否被禁用的错误
func ErrorIsAccountBan(e error) bool {
err, ok := e.(E)
if ok && err.Code == 403029 {
return true
}
return false
}

// ErrorIsAccountNoActive is 检查这个账号是否被禁用的错误
func ErrorIsAccountNoActive(e error) bool {
err, ok := e.(E)
if ok && err.Code == 403028 {
return true
}
return false
}

// ErrorIsUserDel is 检查这个账号是否被删除
func ErrorIsUserDel(e error) bool {
err, ok := e.(E)
if ok && err.Code == 403053 {
return true
}
return false
}

+ 110
- 0
app/e/msg.go View File

@@ -0,0 +1,110 @@
package e

import (
"applet/app/utils"
"encoding/json"
"net/http"

"github.com/gin-gonic/gin"

"applet/app/utils/logx"
)

// GetMsg get error information based on Code
// 因为这里code是自己控制的, 因此没考虑报错信息
func GetMsg(code int) (int, string) {
if msg, ok := MsgFlags[code]; ok {
return code / 1000, msg
}
if http.StatusText(code) == "" {
code = 200
}
return code, MsgFlags[ERR_BAD_REQUEST]
}

// 成功输出, fields 是额外字段, 与code, msg同级
func OutSuc(c *gin.Context, data interface{}, fields map[string]interface{}) {
res := gin.H{
"code": 1,
"msg": "ok",
"data": data,
}
if fields != nil {
for k, v := range fields {
res[k] = v
}
}
if utils.GetApiVersion(c) > 0 { //加了签名校验只返回加密的字符串
jsonData, _ := json.Marshal(res)
str := utils.ResultAes(c, jsonData)
c.Writer.WriteString(str)
} else {
c.AbortWithStatusJSON(200, res)
}
}

func OutSucPure(c *gin.Context, data interface{}, fields map[string]interface{}) {
res := gin.H{
"code": 1,
"msg": "ok",
"data": data,
}
if fields != nil {
for k, v := range fields {
res[k] = v
}
}
c.Abort()
c.PureJSON(200, res)
}

// 错误输出
func OutErr(c *gin.Context, code int, err ...interface{}) {
statusCode, msg := GetMsg(code)
if len(err) > 0 && err[0] != nil {
e := err[0]
switch v := e.(type) {
case E:
statusCode = v.Code / 1000
msg = v.Error()
logx.Error(v.msg + ": " + v.st) // 记录堆栈信息
case error:
logx.Error(v)
break
case string:
msg = v
case int:
if _, ok := MsgFlags[v]; ok {
msg = MsgFlags[v]
}
}
}
if utils.GetApiVersion(c) > 0 { //加了签名校验只返回加密的字符串
jsonData, _ := json.Marshal(gin.H{
"code": code,
"msg": msg,
"data": []struct{}{},
})
str := utils.ResultAes(c, jsonData)
if code > 100000 {
code = int(utils.FloatFormat(float64(code/1000), 0))
}
c.Status(500)
c.Writer.WriteString(str)
} else {
c.AbortWithStatusJSON(statusCode, gin.H{
"code": code,
"msg": msg,
"data": []struct{}{},
})
}
}

// 重定向
func OutRedirect(c *gin.Context, code int, loc string) {
if code < 301 || code > 308 {
code = 303
}
c.Redirect(code, loc)
c.Abort()
}

+ 8
- 0
app/e/set_cache.go View File

@@ -0,0 +1,8 @@
package e

func SetCache(cacheTime int64) map[string]interface{} {
if cacheTime == 0 {
return map[string]interface{}{"cache_time": cacheTime}
}
return map[string]interface{}{"cache_time": cacheTime}
}

+ 16
- 0
app/lib/qiniu/bucket_create.go View File

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

+ 18
- 0
app/lib/qiniu/bucket_delete.go View File

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

+ 18
- 0
app/lib/qiniu/bucket_get_domain.go View File

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

+ 22
- 0
app/lib/qiniu/init.go View File

@@ -0,0 +1,22 @@
package qiniu

import (
"applet/app/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)
}

+ 54
- 0
app/lib/qiniu/req_img_upload.go View File

@@ -0,0 +1,54 @@
package qiniu

import (
"applet/app/md"
"applet/app/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))}
}

/*
form表单上传
地址 : http://upload-z2.qiniup.com
header
- Content-Type : multipart/form-data

body :
- key : 文件名
- token : 生成token
- file : 待上传文件
*/

+ 54
- 0
app/md/file.go View File

@@ -0,0 +1,54 @@
package md

// 用户拥有上传权限的目录, 目录ID

const (
FILE_DIR_FEEDBACK = "feedback"
FILE_DIR_AVATAR = "avatar"
FILE_DIR_QRCODE = "qrcode"
FILE_DIR_STYLE = "style"
)

var (
FileUserDir = map[string]string{
FILE_DIR_FEEDBACK: "4", // 用户反馈
FILE_DIR_AVATAR: "5", // 用户头像
FILE_DIR_QRCODE: "6", // 用户微信二维码
FILE_DIR_STYLE: "7", // 用户样式
}
)

// 文件回调信息
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"` // 签名
}

type FileList struct {
Path string `json:"path"`
DirId int `json:"dir_id"`
FileName string `json:"f_name"` // 显示名称
StgName string `json:"stg_name"` // 存储名字
Ext string `json:"ext"` // 后缀名, png,jpg等
FileSize string `json:"f_size"`
Provider string `json:"provider"` // 存储供应商
Hash string `json:"hash"`
Bucket string `json:"bucket"`
Width int `json:"w"`
Height int `json:"h"`
Mime string `json:"mime"`
IsAdm bool `json:"is_adm"` //是否管理后台上传
IsDir bool `json:"is_dir"` //是否文件夹
CreateAt int `json:"create_at"`
Url string `json:"url"`
}

+ 11
- 0
app/md/mq.go View File

@@ -0,0 +1,11 @@
package md

const OrdExchange = "order"

const (
OrdRoutKeyForJudgePackageOrdOrdState = "judge_package_ord_state" //订单状态
)

type JudgePackageOrdOrdState struct {
OrdNo string `json:"ord_no"`
}

+ 68
- 0
app/svc/svc_file_img_upload.go View File

@@ -0,0 +1,68 @@
package svc

import (
"applet/app/db"
"applet/app/e"
"applet/app/enum"
"applet/app/lib/qiniu"
"applet/app/md"
"applet/app/utils"
"errors"
"fmt"
"strings"
"time"
)

// 请求文件上传
func ImgReqUpload(uid, dirName, fname, callbackUrl string, fsize int64) (interface{}, error) {
ext := utils.FileExt(fname)
if err := initStg(fsize, ext); err != nil {
return nil, err
}
pureFileName := strings.Replace(fname, "."+ext, "", 1)
pureFileName += "-" + utils.RandString(6, utils.AnyToString(time.Now().UnixNano()))
newName := dirName + "/" + pureFileName + "." + ext

f := &md.FileCallback{
Uid: uid,
DirId: dirName,
FileName: newName,
}
return qiniu.ReqImgUpload(f, callbackUrl), nil
}

func initStg(fsize int64, ext string) error {
// 获取上传配置
fileCfg := make(map[string]string)
sysCfgDb := db.SysCfgDb{}
sysCfgDb.Set()
fileCfg[enum.FileBucket] = sysCfgDb.SysCfgGetWithDb(enum.FileBucket)
fileCfg[enum.FileBucketHost] = sysCfgDb.SysCfgGetWithDb(enum.FileBucketHost)
fileCfg[enum.FileAccessKey] = sysCfgDb.SysCfgGetWithDb(enum.FileAccessKey)
fileCfg[enum.FileSecretKey] = sysCfgDb.SysCfgGetWithDb(enum.FileSecretKey)
fileCfg[enum.FileBucketRegion] = sysCfgDb.SysCfgGetWithDb(enum.FileBucketRegion)
fileCfg[enum.FileUserUploadMaxSize] = sysCfgDb.SysCfgGetWithDb(enum.FileUserUploadMaxSize)
fileCfg[enum.FileExt] = sysCfgDb.SysCfgGetWithDb(enum.FileExt)
fileCfg[enum.FileBucketScheme] = sysCfgDb.SysCfgGetWithDb(enum.FileBucketScheme)
utils.FilePutContents("initStg", fmt.Sprintf("[KEY_CFG_FILE_BUCKET]:%s ; [KEY_CFG_FILE_HOST]:%s ; [KEY_CFG_FILE_AK]::%s;"+
" [KEY_CFG_FILE_SK]::%s, ;[KEY_CFG_FILE_REGION]::%s, ;[KEY_CFG_FILE_MAX_SIZE]::%s, ;[KEY_CFG_FILE_EXT]::%s, ;[KEY_CFG_FILE_SCHEME]::%s, "+
">>>>>>>>>>>>>>>>>>>>", fileCfg[enum.FileBucket], fileCfg[enum.FileBucketHost], fileCfg[enum.FileAccessKey], fileCfg[enum.FileSecretKey],
fileCfg[enum.FileBucketRegion], fileCfg[enum.FileUserUploadMaxSize], fileCfg[enum.FileExt], fileCfg[enum.FileBucketScheme]))
for _, v := range fileCfg {
if v == "" {
return errors.New("上传配置不完整")
}
}

qiniu.Init(fileCfg[enum.FileAccessKey], fileCfg[enum.FileSecretKey], fileCfg[enum.FileBucket], fileCfg[enum.FileBucketRegion], fileCfg[enum.FileBucketScheme])

// 检查文件大小限制
if utils.StrToInt64(fileCfg[enum.FileUserUploadMaxSize]) < fsize {
return e.NewErrCode(e.ERR_FILE_MAX_SIZE)
}
// 检查文件后缀
if !strings.Contains(fileCfg[enum.FileExt], ext) {
return e.NewErrCode(e.ERR_FILE_EXT)
}
return nil
}

+ 33
- 0
app/svc/svc_validate_comm.go View File

@@ -0,0 +1,33 @@
package svc

import (
"applet/app/e"
"applet/app/utils"
"applet/app/utils/logx"
"encoding/json"
"fmt"
"github.com/go-playground/validator/v10"
)

func HandleValidateErr(err error) error {
switch err.(type) {
case *json.UnmarshalTypeError:
return e.NewErr(e.ERR_UNMARSHAL, "参数格式错误")
case validator.ValidationErrors:
errs := err.(validator.ValidationErrors)
transMsgMap := errs.Translate(utils.ValidatorTrans) // utils.ValidatorTrans \app\utils\validator_err_trans.go::ValidatorTransInit初始化获得
transMsgOne := transMsgMap[GetOneKeyOfMapString(transMsgMap)]
return e.NewErr(e.ERR_INVALID_ARGS, transMsgOne)
default:
_ = logx.Error(err)
return e.NewErr(e.ERR, fmt.Sprintf("validate request params, err:%v\n", err))
}
}

// GetOneKeyOfMapString 取出Map的一个key
func GetOneKeyOfMapString(collection map[string]string) string {
for k := range collection {
return k
}
return ""
}

+ 38
- 0
app/svc/svc_wx_pay.go View File

@@ -0,0 +1,38 @@
package svc

import (
"applet/app/db"
"applet/app/enum"
"github.com/gin-gonic/gin"
"github.com/wechatpay-apiv3/wechatpay-go/core"
"github.com/wechatpay-apiv3/wechatpay-go/core/option"
"github.com/wechatpay-apiv3/wechatpay-go/utils"
)

func NewWxPayClient(ctx *gin.Context) (client *core.Client, err error) {
sysCfgDb := db.SysCfgDb{}
sysCfgDb.Set()
sysCfg := sysCfgDb.SysCfgFindWithDb(enum.WxSpMchId, enum.WxSpMchApiV3Key, enum.WxSpMchCertificateSerialNumber)

var (
mchID string = sysCfg[enum.WxSpMchId] // 商户号
mchCertificateSerialNumber string = sysCfg[enum.WxSpMchCertificateSerialNumber] // 商户证书序列号
mchAPIv3Key string = sysCfg[enum.WxSpMchApiV3Key] // 商户APIv3密钥
)

// 使用 utils 提供的函数从本地文件中加载商户私钥,商户私钥会用来生成请求的签名
mchPrivateKey, err := utils.LoadPrivateKeyWithPath("./static/wx/merchant/apiclient_key.pem")
if err != nil {
return
}

// 使用商户私钥等初始化 client,并使它具有自动定时获取微信支付平台证书的能力
opts := []core.ClientOption{
option.WithWechatPayAutoAuthCipher(mchID, mchCertificateSerialNumber, mchPrivateKey, mchAPIv3Key),
}
client, err = core.NewClient(ctx, opts...)
if err != nil {
return
}
return
}

+ 123
- 0
app/utils/aes.go View File

@@ -0,0 +1,123 @@
package utils

import (
"bytes"
"crypto/aes"
"crypto/cipher"
"fmt"
)

func AesEncrypt(rawData, key []byte) ([]byte, error) {
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
blockSize := block.BlockSize()
rawData = PKCS5Padding(rawData, blockSize)
// rawData = ZeroPadding(rawData, block.BlockSize())
blockMode := cipher.NewCBCEncrypter(block, key[:blockSize])
encrypted := make([]byte, len(rawData))
// 根据CryptBlocks方法的说明,如下方式初始化encrypted也可以
// encrypted := rawData
blockMode.CryptBlocks(encrypted, rawData)
return encrypted, nil
}

func AesDecrypt(encrypted, key []byte) ([]byte, error) {
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
blockSize := block.BlockSize()
blockMode := cipher.NewCBCDecrypter(block, key[:blockSize])
rawData := make([]byte, len(encrypted))
// rawData := encrypted
blockMode.CryptBlocks(rawData, encrypted)
rawData = PKCS5UnPadding(rawData)
// rawData = ZeroUnPadding(rawData)
return rawData, nil
}

func ZeroPadding(cipherText []byte, blockSize int) []byte {
padding := blockSize - len(cipherText)%blockSize
padText := bytes.Repeat([]byte{0}, padding)
return append(cipherText, padText...)
}

func ZeroUnPadding(rawData []byte) []byte {
length := len(rawData)
unPadding := int(rawData[length-1])
return rawData[:(length - unPadding)]
}

func PKCS5Padding(cipherText []byte, blockSize int) []byte {
padding := blockSize - len(cipherText)%blockSize
padText := bytes.Repeat([]byte{byte(padding)}, padding)
return append(cipherText, padText...)
}

func PKCS5UnPadding(rawData []byte) []byte {
length := len(rawData)
// 去掉最后一个字节 unPadding 次
unPadding := int(rawData[length-1])
return rawData[:(length - unPadding)]
}

// 填充0
func zeroFill(key *string) {
l := len(*key)
if l != 16 && l != 24 && l != 32 {
if l < 16 {
*key = *key + fmt.Sprintf("%0*d", 16-l, 0)
} else if l < 24 {
*key = *key + fmt.Sprintf("%0*d", 24-l, 0)
} else if l < 32 {
*key = *key + fmt.Sprintf("%0*d", 32-l, 0)
} else {
*key = string([]byte(*key)[:32])
}
}
}

type AesCrypt struct {
Key []byte
Iv []byte
}

func (a *AesCrypt) Encrypt(data []byte) ([]byte, error) {
aesBlockEncrypt, err := aes.NewCipher(a.Key)
if err != nil {
println(err.Error())
return nil, err
}

content := pKCS5Padding(data, aesBlockEncrypt.BlockSize())
cipherBytes := make([]byte, len(content))
aesEncrypt := cipher.NewCBCEncrypter(aesBlockEncrypt, a.Iv)
aesEncrypt.CryptBlocks(cipherBytes, content)
return cipherBytes, nil
}

func (a *AesCrypt) Decrypt(src []byte) (data []byte, err error) {
decrypted := make([]byte, len(src))
var aesBlockDecrypt cipher.Block
aesBlockDecrypt, err = aes.NewCipher(a.Key)
if err != nil {
println(err.Error())
return nil, err
}
aesDecrypt := cipher.NewCBCDecrypter(aesBlockDecrypt, a.Iv)
aesDecrypt.CryptBlocks(decrypted, src)
return pKCS5Trimming(decrypted), nil
}

func pKCS5Padding(cipherText []byte, blockSize int) []byte {
padding := blockSize - len(cipherText)%blockSize
padText := bytes.Repeat([]byte{byte(padding)}, padding)
return append(cipherText, padText...)
}

func pKCS5Trimming(encrypt []byte) []byte {
padding := encrypt[len(encrypt)-1]
return encrypt[:len(encrypt)-int(padding)]
}

+ 95
- 0
app/utils/base64.go View File

@@ -0,0 +1,95 @@
package utils

import (
"encoding/base64"
"fmt"
)

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

+ 26
- 0
app/utils/boolean.go View File

@@ -0,0 +1,26 @@
package utils

import "reflect"

// 检验一个值是否为空
func Empty(val interface{}) bool {
v := reflect.ValueOf(val)
switch v.Kind() {
case reflect.String, reflect.Array:
return v.Len() == 0
case reflect.Map, reflect.Slice:
return v.Len() == 0 || v.IsNil()
case reflect.Bool:
return !v.Bool()
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return v.Int() == 0
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return v.Uint() == 0
case reflect.Float32, reflect.Float64:
return v.Float() == 0
case reflect.Interface, reflect.Ptr:
return v.IsNil()
}

return reflect.DeepEqual(val, reflect.Zero(v.Type()).Interface())
}

+ 421
- 0
app/utils/cache/base.go View File

@@ -0,0 +1,421 @@
package cache

import (
"errors"
"fmt"
"strconv"
"time"
)

const (
redisDialTTL = 10 * time.Second
redisReadTTL = 3 * time.Second
redisWriteTTL = 3 * time.Second
redisIdleTTL = 10 * time.Second
redisPoolTTL = 10 * time.Second
redisPoolSize int = 512
redisMaxIdleConn int = 64
redisMaxActive int = 512
)

var (
ErrNil = errors.New("nil return")
ErrWrongArgsNum = errors.New("args num error")
ErrNegativeInt = errors.New("redis cluster: unexpected value for Uint64")
)

// 以下为提供类型转换

func Int(reply interface{}, err error) (int, error) {
if err != nil {
return 0, err
}
switch reply := reply.(type) {
case int:
return reply, nil
case int8:
return int(reply), nil
case int16:
return int(reply), nil
case int32:
return int(reply), nil
case int64:
x := int(reply)
if int64(x) != reply {
return 0, strconv.ErrRange
}
return x, nil
case uint:
n := int(reply)
if n < 0 {
return 0, strconv.ErrRange
}
return n, nil
case uint8:
return int(reply), nil
case uint16:
return int(reply), nil
case uint32:
n := int(reply)
if n < 0 {
return 0, strconv.ErrRange
}
return n, nil
case uint64:
n := int(reply)
if n < 0 {
return 0, strconv.ErrRange
}
return n, nil
case []byte:
data := string(reply)
if len(data) == 0 {
return 0, ErrNil
}

n, err := strconv.ParseInt(data, 10, 0)
return int(n), err
case string:
if len(reply) == 0 {
return 0, ErrNil
}

n, err := strconv.ParseInt(reply, 10, 0)
return int(n), err
case nil:
return 0, ErrNil
case error:
return 0, reply
}
return 0, fmt.Errorf("redis cluster: unexpected type for Int, got type %T", reply)
}

func Int64(reply interface{}, err error) (int64, error) {
if err != nil {
return 0, err
}
switch reply := reply.(type) {
case int:
return int64(reply), nil
case int8:
return int64(reply), nil
case int16:
return int64(reply), nil
case int32:
return int64(reply), nil
case int64:
return reply, nil
case uint:
n := int64(reply)
if n < 0 {
return 0, strconv.ErrRange
}
return n, nil
case uint8:
return int64(reply), nil
case uint16:
return int64(reply), nil
case uint32:
return int64(reply), nil
case uint64:
n := int64(reply)
if n < 0 {
return 0, strconv.ErrRange
}
return n, nil
case []byte:
data := string(reply)
if len(data) == 0 {
return 0, ErrNil
}

n, err := strconv.ParseInt(data, 10, 64)
return n, err
case string:
if len(reply) == 0 {
return 0, ErrNil
}

n, err := strconv.ParseInt(reply, 10, 64)
return n, err
case nil:
return 0, ErrNil
case error:
return 0, reply
}
return 0, fmt.Errorf("redis cluster: unexpected type for Int64, got type %T", reply)
}

func Uint64(reply interface{}, err error) (uint64, error) {
if err != nil {
return 0, err
}
switch reply := reply.(type) {
case uint:
return uint64(reply), nil
case uint8:
return uint64(reply), nil
case uint16:
return uint64(reply), nil
case uint32:
return uint64(reply), nil
case uint64:
return reply, nil
case int:
if reply < 0 {
return 0, ErrNegativeInt
}
return uint64(reply), nil
case int8:
if reply < 0 {
return 0, ErrNegativeInt
}
return uint64(reply), nil
case int16:
if reply < 0 {
return 0, ErrNegativeInt
}
return uint64(reply), nil
case int32:
if reply < 0 {
return 0, ErrNegativeInt
}
return uint64(reply), nil
case int64:
if reply < 0 {
return 0, ErrNegativeInt
}
return uint64(reply), nil
case []byte:
data := string(reply)
if len(data) == 0 {
return 0, ErrNil
}

n, err := strconv.ParseUint(data, 10, 64)
return n, err
case string:
if len(reply) == 0 {
return 0, ErrNil
}

n, err := strconv.ParseUint(reply, 10, 64)
return n, err
case nil:
return 0, ErrNil
case error:
return 0, reply
}
return 0, fmt.Errorf("redis cluster: unexpected type for Uint64, got type %T", reply)
}

func Float64(reply interface{}, err error) (float64, error) {
if err != nil {
return 0, err
}

var value float64
err = nil
switch v := reply.(type) {
case float32:
value = float64(v)
case float64:
value = v
case int:
value = float64(v)
case int8:
value = float64(v)
case int16:
value = float64(v)
case int32:
value = float64(v)
case int64:
value = float64(v)
case uint:
value = float64(v)
case uint8:
value = float64(v)
case uint16:
value = float64(v)
case uint32:
value = float64(v)
case uint64:
value = float64(v)
case []byte:
data := string(v)
if len(data) == 0 {
return 0, ErrNil
}
value, err = strconv.ParseFloat(string(v), 64)
case string:
if len(v) == 0 {
return 0, ErrNil
}
value, err = strconv.ParseFloat(v, 64)
case nil:
err = ErrNil
case error:
err = v
default:
err = fmt.Errorf("redis cluster: unexpected type for Float64, got type %T", v)
}

return value, err
}

func Bool(reply interface{}, err error) (bool, error) {
if err != nil {
return false, err
}
switch reply := reply.(type) {
case bool:
return reply, nil
case int64:
return reply != 0, nil
case []byte:
data := string(reply)
if len(data) == 0 {
return false, ErrNil
}

return strconv.ParseBool(data)
case string:
if len(reply) == 0 {
return false, ErrNil
}

return strconv.ParseBool(reply)
case nil:
return false, ErrNil
case error:
return false, reply
}
return false, fmt.Errorf("redis cluster: unexpected type for Bool, got type %T", reply)
}

func Bytes(reply interface{}, err error) ([]byte, error) {
if err != nil {
return nil, err
}
switch reply := reply.(type) {
case []byte:
if len(reply) == 0 {
return nil, ErrNil
}
return reply, nil
case string:
data := []byte(reply)
if len(data) == 0 {
return nil, ErrNil
}
return data, nil
case nil:
return nil, ErrNil
case error:
return nil, reply
}
return nil, fmt.Errorf("redis cluster: unexpected type for Bytes, got type %T", reply)
}

func String(reply interface{}, err error) (string, error) {
if err != nil {
return "", err
}

value := ""
err = nil
switch v := reply.(type) {
case string:
if len(v) == 0 {
return "", ErrNil
}

value = v
case []byte:
if len(v) == 0 {
return "", ErrNil
}

value = string(v)
case int:
value = strconv.FormatInt(int64(v), 10)
case int8:
value = strconv.FormatInt(int64(v), 10)
case int16:
value = strconv.FormatInt(int64(v), 10)
case int32:
value = strconv.FormatInt(int64(v), 10)
case int64:
value = strconv.FormatInt(v, 10)
case uint:
value = strconv.FormatUint(uint64(v), 10)
case uint8:
value = strconv.FormatUint(uint64(v), 10)
case uint16:
value = strconv.FormatUint(uint64(v), 10)
case uint32:
value = strconv.FormatUint(uint64(v), 10)
case uint64:
value = strconv.FormatUint(v, 10)
case float32:
value = strconv.FormatFloat(float64(v), 'f', -1, 32)
case float64:
value = strconv.FormatFloat(v, 'f', -1, 64)
case bool:
value = strconv.FormatBool(v)
case nil:
err = ErrNil
case error:
err = v
default:
err = fmt.Errorf("redis cluster: unexpected type for String, got type %T", v)
}

return value, err
}

func Strings(reply interface{}, err error) ([]string, error) {
if err != nil {
return nil, err
}
switch reply := reply.(type) {
case []interface{}:
result := make([]string, len(reply))
for i := range reply {
if reply[i] == nil {
continue
}
switch subReply := reply[i].(type) {
case string:
result[i] = subReply
case []byte:
result[i] = string(subReply)
default:
return nil, fmt.Errorf("redis cluster: unexpected element type for String, got type %T", reply[i])
}
}
return result, nil
case []string:
return reply, nil
case nil:
return nil, ErrNil
case error:
return nil, reply
}
return nil, fmt.Errorf("redis cluster: unexpected type for Strings, got type %T", reply)
}

func Values(reply interface{}, err error) ([]interface{}, error) {
if err != nil {
return nil, err
}
switch reply := reply.(type) {
case []interface{}:
return reply, nil
case nil:
return nil, ErrNil
case error:
return nil, reply
}
return nil, fmt.Errorf("redis cluster: unexpected type for Values, got type %T", reply)
}

+ 107
- 0
app/utils/cache/cache/cache.go View File

@@ -0,0 +1,107 @@
package cache

import (
"fmt"
"time"
)

var c Cache

type Cache interface {
// get cached value by key.
Get(key string) interface{}
// GetMulti is a batch version of Get.
GetMulti(keys []string) []interface{}
// set cached value with key and expire time.
Put(key string, val interface{}, timeout time.Duration) error
// delete cached value by key.
Delete(key string) error
// increase cached int value by key, as a counter.
Incr(key string) error
// decrease cached int value by key, as a counter.
Decr(key string) error
// check if cached value exists or not.
IsExist(key string) bool
// clear all cache.
ClearAll() error
// start gc routine based on config string settings.
StartAndGC(config string) error
}

// Instance is a function create a new Cache Instance
type Instance func() Cache

var adapters = make(map[string]Instance)

// Register makes a cache adapter available by the adapter name.
// If Register is called twice with the same name or if driver is nil,
// it panics.
func Register(name string, adapter Instance) {
if adapter == nil {
panic("cache: Register adapter is nil")
}
if _, ok := adapters[name]; ok {
panic("cache: Register called twice for adapter " + name)
}
adapters[name] = adapter
}

// NewCache Create a new cache driver by adapter name and config string.
// config need to be correct JSON as string: {"interval":360}.
// it will start gc automatically.
func NewCache(adapterName, config string) (adapter Cache, err error) {
instanceFunc, ok := adapters[adapterName]
if !ok {
err = fmt.Errorf("cache: unknown adapter name %q (forgot to import?)", adapterName)
return
}
adapter = instanceFunc()
err = adapter.StartAndGC(config)
if err != nil {
adapter = nil
}
return
}

func InitCache(adapterName, config string) (err error) {
instanceFunc, ok := adapters[adapterName]
if !ok {
err = fmt.Errorf("cache: unknown adapter name %q (forgot to import?)", adapterName)
return
}
c = instanceFunc()
err = c.StartAndGC(config)
if err != nil {
c = nil
}
return
}

func Get(key string) interface{} {
return c.Get(key)
}

func GetMulti(keys []string) []interface{} {
return c.GetMulti(keys)
}
func Put(key string, val interface{}, ttl time.Duration) error {
return c.Put(key, val, ttl)
}
func Delete(key string) error {
return c.Delete(key)
}
func Incr(key string) error {
return c.Incr(key)
}
func Decr(key string) error {
return c.Decr(key)
}
func IsExist(key string) bool {
return c.IsExist(key)
}
func ClearAll() error {
return c.ClearAll()
}
func StartAndGC(cfg string) error {
return c.StartAndGC(cfg)
}

+ 86
- 0
app/utils/cache/cache/conv.go View File

@@ -0,0 +1,86 @@
package cache

import (
"fmt"
"strconv"
)

// GetString convert interface to string.
func GetString(v interface{}) string {
switch result := v.(type) {
case string:
return result
case []byte:
return string(result)
default:
if v != nil {
return fmt.Sprint(result)
}
}
return ""
}

// GetInt convert interface to int.
func GetInt(v interface{}) int {
switch result := v.(type) {
case int:
return result
case int32:
return int(result)
case int64:
return int(result)
default:
if d := GetString(v); d != "" {
value, _ := strconv.Atoi(d)
return value
}
}
return 0
}

// GetInt64 convert interface to int64.
func GetInt64(v interface{}) int64 {
switch result := v.(type) {
case int:
return int64(result)
case int32:
return int64(result)
case int64:
return result
default:

if d := GetString(v); d != "" {
value, _ := strconv.ParseInt(d, 10, 64)
return value
}
}
return 0
}

// GetFloat64 convert interface to float64.
func GetFloat64(v interface{}) float64 {
switch result := v.(type) {
case float64:
return result
default:
if d := GetString(v); d != "" {
value, _ := strconv.ParseFloat(d, 64)
return value
}
}
return 0
}

// GetBool convert interface to bool.
func GetBool(v interface{}) bool {
switch result := v.(type) {
case bool:
return result
default:
if d := GetString(v); d != "" {
value, _ := strconv.ParseBool(d)
return value
}
}
return false
}

+ 241
- 0
app/utils/cache/cache/file.go View File

@@ -0,0 +1,241 @@
package cache

import (
"bytes"
"crypto/md5"
"encoding/gob"
"encoding/hex"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"
"reflect"
"strconv"
"time"
)

// FileCacheItem is basic unit of file cache adapter.
// it contains data and expire time.
type FileCacheItem struct {
Data interface{}
LastAccess time.Time
Expired time.Time
}

// FileCache Config
var (
FileCachePath = "cache" // cache directory
FileCacheFileSuffix = ".bin" // cache file suffix
FileCacheDirectoryLevel = 2 // cache file deep level if auto generated cache files.
FileCacheEmbedExpiry time.Duration // cache expire time, default is no expire forever.
)

// FileCache is cache adapter for file storage.
type FileCache struct {
CachePath string
FileSuffix string
DirectoryLevel int
EmbedExpiry int
}

// NewFileCache Create new file cache with no config.
// the level and expiry need set in method StartAndGC as config string.
func NewFileCache() Cache {
// return &FileCache{CachePath:FileCachePath, FileSuffix:FileCacheFileSuffix}
return &FileCache{}
}

// StartAndGC will start and begin gc for file cache.
// the config need to be like {CachePath:"/cache","FileSuffix":".bin","DirectoryLevel":2,"EmbedExpiry":0}
func (fc *FileCache) StartAndGC(config string) error {

var cfg map[string]string
json.Unmarshal([]byte(config), &cfg)
if _, ok := cfg["CachePath"]; !ok {
cfg["CachePath"] = FileCachePath
}
if _, ok := cfg["FileSuffix"]; !ok {
cfg["FileSuffix"] = FileCacheFileSuffix
}
if _, ok := cfg["DirectoryLevel"]; !ok {
cfg["DirectoryLevel"] = strconv.Itoa(FileCacheDirectoryLevel)
}
if _, ok := cfg["EmbedExpiry"]; !ok {
cfg["EmbedExpiry"] = strconv.FormatInt(int64(FileCacheEmbedExpiry.Seconds()), 10)
}
fc.CachePath = cfg["CachePath"]
fc.FileSuffix = cfg["FileSuffix"]
fc.DirectoryLevel, _ = strconv.Atoi(cfg["DirectoryLevel"])
fc.EmbedExpiry, _ = strconv.Atoi(cfg["EmbedExpiry"])

fc.Init()
return nil
}

// Init will make new dir for file cache if not exist.
func (fc *FileCache) Init() {
if ok, _ := exists(fc.CachePath); !ok { // todo : error handle
_ = os.MkdirAll(fc.CachePath, os.ModePerm) // todo : error handle
}
}

// get cached file name. it's md5 encoded.
func (fc *FileCache) getCacheFileName(key string) string {
m := md5.New()
io.WriteString(m, key)
keyMd5 := hex.EncodeToString(m.Sum(nil))
cachePath := fc.CachePath
switch fc.DirectoryLevel {
case 2:
cachePath = filepath.Join(cachePath, keyMd5[0:2], keyMd5[2:4])
case 1:
cachePath = filepath.Join(cachePath, keyMd5[0:2])
}

if ok, _ := exists(cachePath); !ok { // todo : error handle
_ = os.MkdirAll(cachePath, os.ModePerm) // todo : error handle
}

return filepath.Join(cachePath, fmt.Sprintf("%s%s", keyMd5, fc.FileSuffix))
}

// Get value from file cache.
// if non-exist or expired, return empty string.
func (fc *FileCache) Get(key string) interface{} {
fileData, err := FileGetContents(fc.getCacheFileName(key))
if err != nil {
return ""
}
var to FileCacheItem
GobDecode(fileData, &to)
if to.Expired.Before(time.Now()) {
return ""
}
return to.Data
}

// GetMulti gets values from file cache.
// if non-exist or expired, return empty string.
func (fc *FileCache) GetMulti(keys []string) []interface{} {
var rc []interface{}
for _, key := range keys {
rc = append(rc, fc.Get(key))
}
return rc
}

// Put value into file cache.
// timeout means how long to keep this file, unit of ms.
// if timeout equals FileCacheEmbedExpiry(default is 0), cache this item forever.
func (fc *FileCache) Put(key string, val interface{}, timeout time.Duration) error {
gob.Register(val)

item := FileCacheItem{Data: val}
if timeout == FileCacheEmbedExpiry {
item.Expired = time.Now().Add((86400 * 365 * 10) * time.Second) // ten years
} else {
item.Expired = time.Now().Add(timeout)
}
item.LastAccess = time.Now()
data, err := GobEncode(item)
if err != nil {
return err
}
return FilePutContents(fc.getCacheFileName(key), data)
}

// Delete file cache value.
func (fc *FileCache) Delete(key string) error {
filename := fc.getCacheFileName(key)
if ok, _ := exists(filename); ok {
return os.Remove(filename)
}
return nil
}

// Incr will increase cached int value.
// fc value is saving forever unless Delete.
func (fc *FileCache) Incr(key string) error {
data := fc.Get(key)
var incr int
if reflect.TypeOf(data).Name() != "int" {
incr = 0
} else {
incr = data.(int) + 1
}
fc.Put(key, incr, FileCacheEmbedExpiry)
return nil
}

// Decr will decrease cached int value.
func (fc *FileCache) Decr(key string) error {
data := fc.Get(key)
var decr int
if reflect.TypeOf(data).Name() != "int" || data.(int)-1 <= 0 {
decr = 0
} else {
decr = data.(int) - 1
}
fc.Put(key, decr, FileCacheEmbedExpiry)
return nil
}

// IsExist check value is exist.
func (fc *FileCache) IsExist(key string) bool {
ret, _ := exists(fc.getCacheFileName(key))
return ret
}

// ClearAll will clean cached files.
// not implemented.
func (fc *FileCache) ClearAll() error {
return nil
}

// check file exist.
func exists(path string) (bool, error) {
_, err := os.Stat(path)
if err == nil {
return true, nil
}
if os.IsNotExist(err) {
return false, nil
}
return false, err
}

// FileGetContents Get bytes to file.
// if non-exist, create this file.
func FileGetContents(filename string) (data []byte, e error) {
return ioutil.ReadFile(filename)
}

// FilePutContents Put bytes to file.
// if non-exist, create this file.
func FilePutContents(filename string, content []byte) error {
return ioutil.WriteFile(filename, content, os.ModePerm)
}

// GobEncode Gob encodes file cache item.
func GobEncode(data interface{}) ([]byte, error) {
buf := bytes.NewBuffer(nil)
enc := gob.NewEncoder(buf)
err := enc.Encode(data)
if err != nil {
return nil, err
}
return buf.Bytes(), err
}

// GobDecode Gob decodes file cache item.
func GobDecode(data []byte, to *FileCacheItem) error {
buf := bytes.NewBuffer(data)
dec := gob.NewDecoder(buf)
return dec.Decode(&to)
}

func init() {
Register("file", NewFileCache)
}

+ 239
- 0
app/utils/cache/cache/memory.go View File

@@ -0,0 +1,239 @@
package cache

import (
"encoding/json"
"errors"
"sync"
"time"
)

var (
// DefaultEvery means the clock time of recycling the expired cache items in memory.
DefaultEvery = 60 // 1 minute
)

// MemoryItem store memory cache item.
type MemoryItem struct {
val interface{}
createdTime time.Time
lifespan time.Duration
}

func (mi *MemoryItem) isExpire() bool {
// 0 means forever
if mi.lifespan == 0 {
return false
}
return time.Now().Sub(mi.createdTime) > mi.lifespan
}

// MemoryCache is Memory cache adapter.
// it contains a RW locker for safe map storage.
type MemoryCache struct {
sync.RWMutex
dur time.Duration
items map[string]*MemoryItem
Every int // run an expiration check Every clock time
}

// NewMemoryCache returns a new MemoryCache.
func NewMemoryCache() Cache {
cache := MemoryCache{items: make(map[string]*MemoryItem)}
return &cache
}

// Get cache from memory.
// if non-existed or expired, return nil.
func (bc *MemoryCache) Get(name string) interface{} {
bc.RLock()
defer bc.RUnlock()
if itm, ok := bc.items[name]; ok {
if itm.isExpire() {
return nil
}
return itm.val
}
return nil
}

// GetMulti gets caches from memory.
// if non-existed or expired, return nil.
func (bc *MemoryCache) GetMulti(names []string) []interface{} {
var rc []interface{}
for _, name := range names {
rc = append(rc, bc.Get(name))
}
return rc
}

// Put cache to memory.
// if lifespan is 0, it will be forever till restart.
func (bc *MemoryCache) Put(name string, value interface{}, lifespan time.Duration) error {
bc.Lock()
defer bc.Unlock()
bc.items[name] = &MemoryItem{
val: value,
createdTime: time.Now(),
lifespan: lifespan,
}
return nil
}

// Delete cache in memory.
func (bc *MemoryCache) Delete(name string) error {
bc.Lock()
defer bc.Unlock()
if _, ok := bc.items[name]; !ok {
return errors.New("key not exist")
}
delete(bc.items, name)
if _, ok := bc.items[name]; ok {
return errors.New("delete key error")
}
return nil
}

// Incr increase cache counter in memory.
// it supports int,int32,int64,uint,uint32,uint64.
func (bc *MemoryCache) Incr(key string) error {
bc.RLock()
defer bc.RUnlock()
itm, ok := bc.items[key]
if !ok {
return errors.New("key not exist")
}
switch itm.val.(type) {
case int:
itm.val = itm.val.(int) + 1
case int32:
itm.val = itm.val.(int32) + 1
case int64:
itm.val = itm.val.(int64) + 1
case uint:
itm.val = itm.val.(uint) + 1
case uint32:
itm.val = itm.val.(uint32) + 1
case uint64:
itm.val = itm.val.(uint64) + 1
default:
return errors.New("item val is not (u)int (u)int32 (u)int64")
}
return nil
}

// Decr decrease counter in memory.
func (bc *MemoryCache) Decr(key string) error {
bc.RLock()
defer bc.RUnlock()
itm, ok := bc.items[key]
if !ok {
return errors.New("key not exist")
}
switch itm.val.(type) {
case int:
itm.val = itm.val.(int) - 1
case int64:
itm.val = itm.val.(int64) - 1
case int32:
itm.val = itm.val.(int32) - 1
case uint:
if itm.val.(uint) > 0 {
itm.val = itm.val.(uint) - 1
} else {
return errors.New("item val is less than 0")
}
case uint32:
if itm.val.(uint32) > 0 {
itm.val = itm.val.(uint32) - 1
} else {
return errors.New("item val is less than 0")
}
case uint64:
if itm.val.(uint64) > 0 {
itm.val = itm.val.(uint64) - 1
} else {
return errors.New("item val is less than 0")
}
default:
return errors.New("item val is not int int64 int32")
}
return nil
}

// IsExist check cache exist in memory.
func (bc *MemoryCache) IsExist(name string) bool {
bc.RLock()
defer bc.RUnlock()
if v, ok := bc.items[name]; ok {
return !v.isExpire()
}
return false
}

// ClearAll will delete all cache in memory.
func (bc *MemoryCache) ClearAll() error {
bc.Lock()
defer bc.Unlock()
bc.items = make(map[string]*MemoryItem)
return nil
}

// StartAndGC start memory cache. it will check expiration in every clock time.
func (bc *MemoryCache) StartAndGC(config string) error {
var cf map[string]int
json.Unmarshal([]byte(config), &cf)
if _, ok := cf["interval"]; !ok {
cf = make(map[string]int)
cf["interval"] = DefaultEvery
}
dur := time.Duration(cf["interval"]) * time.Second
bc.Every = cf["interval"]
bc.dur = dur
go bc.vacuum()
return nil
}

// check expiration.
func (bc *MemoryCache) vacuum() {
bc.RLock()
every := bc.Every
bc.RUnlock()

if every < 1 {
return
}
for {
<-time.After(bc.dur)
if bc.items == nil {
return
}
if keys := bc.expiredKeys(); len(keys) != 0 {
bc.clearItems(keys)
}
}
}

// expiredKeys returns key list which are expired.
func (bc *MemoryCache) expiredKeys() (keys []string) {
bc.RLock()
defer bc.RUnlock()
for key, itm := range bc.items {
if itm.isExpire() {
keys = append(keys, key)
}
}
return
}

// clearItems removes all the items which key in keys.
func (bc *MemoryCache) clearItems(keys []string) {
bc.Lock()
defer bc.Unlock()
for _, key := range keys {
delete(bc.items, key)
}
}

func init() {
Register("memory", NewMemoryCache)
}

+ 409
- 0
app/utils/cache/redis.go View File

@@ -0,0 +1,409 @@
package cache

import (
"encoding/json"
"errors"
"log"
"strings"
"time"

redigo "github.com/gomodule/redigo/redis"
)

// configuration
type Config struct {
Server string
Password string
MaxIdle int // Maximum number of idle connections in the pool.

// Maximum number of connections allocated by the pool at a given time.
// When zero, there is no limit on the number of connections in the pool.
MaxActive int

// Close connections after remaining idle for this duration. If the value
// is zero, then idle connections are not closed. Applications should set
// the timeout to a value less than the server's timeout.
IdleTimeout time.Duration

// If Wait is true and the pool is at the MaxActive limit, then Get() waits
// for a connection to be returned to the pool before returning.
Wait bool
KeyPrefix string // prefix to all keys; example is "dev environment name"
KeyDelimiter string // delimiter to be used while appending keys; example is ":"
KeyPlaceholder string // placeholder to be parsed using given arguments to obtain a final key; example is "?"
}

var pool *redigo.Pool
var conf *Config

func NewRedis(addr, pwd string) {
if addr == "" {
panic("\nredis connect string cannot be empty\n")
}
pool = &redigo.Pool{
MaxIdle: redisMaxIdleConn,
IdleTimeout: redisIdleTTL,
MaxActive: redisMaxActive,
// MaxConnLifetime: redisDialTTL,
Wait: true,
Dial: func() (redigo.Conn, error) {
c, err := redigo.Dial("tcp", addr,
redigo.DialPassword(pwd),
redigo.DialConnectTimeout(redisDialTTL),
redigo.DialReadTimeout(redisReadTTL),
redigo.DialWriteTimeout(redisWriteTTL),
)
if err != nil {
log.Println("Redis Dial failed: ", err)
return nil, err
}
return c, err
},
TestOnBorrow: func(c redigo.Conn, t time.Time) error {
_, err := c.Do("PING")
if err != nil {
log.Println("Unable to ping to redis server:", err)
}
return err
},
}
conn := pool.Get()
defer conn.Close()
if conn.Err() != nil {
println("\nredis connect " + addr + " error: " + conn.Err().Error())
} else {
println("\nredis connect " + addr + " success!\n")
}
}

func Do(cmd string, args ...interface{}) (reply interface{}, err error) {
conn := pool.Get()
defer conn.Close()
return conn.Do(cmd, args...)
}

func GetPool() *redigo.Pool {
return pool
}

func ParseKey(key string, vars []string) (string, error) {
arr := strings.Split(key, conf.KeyPlaceholder)
actualKey := ""
if len(arr) != len(vars)+1 {
return "", errors.New("redis/connection.go: Insufficient arguments to parse key")
} else {
for index, val := range arr {
if index == 0 {
actualKey = arr[index]
} else {
actualKey += vars[index-1] + val
}
}
}
return getPrefixedKey(actualKey), nil
}

func getPrefixedKey(key string) string {
return conf.KeyPrefix + conf.KeyDelimiter + key
}
func StripEnvKey(key string) string {
return strings.TrimLeft(key, conf.KeyPrefix+conf.KeyDelimiter)
}
func SplitKey(key string) []string {
return strings.Split(key, conf.KeyDelimiter)
}
func Expire(key string, ttl int) (interface{}, error) {
return Do("EXPIRE", key, ttl)
}
func Persist(key string) (interface{}, error) {
return Do("PERSIST", key)
}

func Del(key string) (interface{}, error) {
return Do("DEL", key)
}
func Set(key string, data interface{}) (interface{}, error) {
// set
return Do("SET", key, data)
}
func SetNX(key string, data interface{}) (interface{}, error) {
return Do("SETNX", key, data)
}
func SetEx(key string, data interface{}, ttl int) (interface{}, error) {
return Do("SETEX", key, ttl, data)
}

func SetJson(key string, data interface{}, ttl int) bool {
c, err := json.Marshal(data)
if err != nil {
return false
}
if ttl < 1 {
_, err = Set(key, c)
} else {
_, err = SetEx(key, c, ttl)
}
if err != nil {
return false
}
return true
}

func GetJson(key string, dst interface{}) error {
b, err := GetBytes(key)
if err != nil {
return err
}
if err = json.Unmarshal(b, dst); err != nil {
return err
}
return nil
}

func Get(key string) (interface{}, error) {
// get
return Do("GET", key)
}
func GetTTL(key string) (time.Duration, error) {
ttl, err := redigo.Int64(Do("TTL", key))
return time.Duration(ttl) * time.Second, err
}
func GetBytes(key string) ([]byte, error) {
return redigo.Bytes(Do("GET", key))
}
func GetString(key string) (string, error) {
return redigo.String(Do("GET", key))
}
func GetStringMap(key string) (map[string]string, error) {
return redigo.StringMap(Do("GET", key))
}
func GetInt(key string) (int, error) {
return redigo.Int(Do("GET", key))
}
func GetInt64(key string) (int64, error) {
return redigo.Int64(Do("GET", key))
}
func GetStringLength(key string) (int, error) {
return redigo.Int(Do("STRLEN", key))
}
func ZAdd(key string, score float64, data interface{}) (interface{}, error) {
return Do("ZADD", key, score, data)
}
func ZAddNX(key string, score float64, data interface{}) (interface{}, error) {
return Do("ZADD", key, "NX", score, data)
}
func ZRem(key string, data interface{}) (interface{}, error) {
return Do("ZREM", key, data)
}
func ZRange(key string, start int, end int, withScores bool) ([]interface{}, error) {
if withScores {
return redigo.Values(Do("ZRANGE", key, start, end, "WITHSCORES"))
}
return redigo.Values(Do("ZRANGE", key, start, end))
}
func ZRemRangeByScore(key string, start int64, end int64) ([]interface{}, error) {
return redigo.Values(Do("ZREMRANGEBYSCORE", key, start, end))
}
func ZCard(setName string) (int64, error) {
return redigo.Int64(Do("ZCARD", setName))
}
func ZScan(setName string) (int64, error) {
return redigo.Int64(Do("ZCARD", setName))
}
func SAdd(setName string, data interface{}) (interface{}, error) {
return Do("SADD", setName, data)
}
func SCard(setName string) (int64, error) {
return redigo.Int64(Do("SCARD", setName))
}
func SIsMember(setName string, data interface{}) (bool, error) {
return redigo.Bool(Do("SISMEMBER", setName, data))
}
func SMembers(setName string) ([]string, error) {
return redigo.Strings(Do("SMEMBERS", setName))
}
func SRem(setName string, data interface{}) (interface{}, error) {
return Do("SREM", setName, data)
}
func HSet(key string, HKey string, data interface{}) (interface{}, error) {
return Do("HSET", key, HKey, data)
}

func HGet(key string, HKey string) (interface{}, error) {
return Do("HGET", key, HKey)
}

func HMGet(key string, hashKeys ...string) ([]interface{}, error) {
ret, err := Do("HMGET", key, hashKeys)
if err != nil {
return nil, err
}
reta, ok := ret.([]interface{})
if !ok {
return nil, errors.New("result not an array")
}
return reta, nil
}

func HMSet(key string, hashKeys []string, vals []interface{}) (interface{}, error) {
if len(hashKeys) == 0 || len(hashKeys) != len(vals) {
var ret interface{}
return ret, errors.New("bad length")
}
input := []interface{}{key}
for i, v := range hashKeys {
input = append(input, v, vals[i])
}
return Do("HMSET", input...)
}

func HGetString(key string, HKey string) (string, error) {
return redigo.String(Do("HGET", key, HKey))
}
func HGetFloat(key string, HKey string) (float64, error) {
f, err := redigo.Float64(Do("HGET", key, HKey))
return f, err
}
func HGetInt(key string, HKey string) (int, error) {
return redigo.Int(Do("HGET", key, HKey))
}
func HGetInt64(key string, HKey string) (int64, error) {
return redigo.Int64(Do("HGET", key, HKey))
}
func HGetBool(key string, HKey string) (bool, error) {
return redigo.Bool(Do("HGET", key, HKey))
}
func HDel(key string, HKey string) (interface{}, error) {
return Do("HDEL", key, HKey)
}

func HGetAll(key string) (map[string]interface{}, error) {
vals, err := redigo.Values(Do("HGETALL", key))
if err != nil {
return nil, err
}
num := len(vals) / 2
result := make(map[string]interface{}, num)
for i := 0; i < num; i++ {
key, _ := redigo.String(vals[2*i], nil)
result[key] = vals[2*i+1]
}
return result, nil
}

func FlushAll() bool {
res, _ := redigo.String(Do("FLUSHALL"))
if res == "" {
return false
}
return true
}

// NOTE: Use this in production environment with extreme care.
// Read more here:https://redigo.io/commands/keys
func Keys(pattern string) ([]string, error) {
return redigo.Strings(Do("KEYS", pattern))
}

func HKeys(key string) ([]string, error) {
return redigo.Strings(Do("HKEYS", key))
}

func Exists(key string) bool {
count, err := redigo.Int(Do("EXISTS", key))
if count == 0 || err != nil {
return false
}
return true
}

func Incr(key string) (int64, error) {
return redigo.Int64(Do("INCR", key))
}

func Decr(key string) (int64, error) {
return redigo.Int64(Do("DECR", key))
}

func IncrBy(key string, incBy int64) (int64, error) {
return redigo.Int64(Do("INCRBY", key, incBy))
}

func DecrBy(key string, decrBy int64) (int64, error) {
return redigo.Int64(Do("DECRBY", key))
}

func IncrByFloat(key string, incBy float64) (float64, error) {
return redigo.Float64(Do("INCRBYFLOAT", key, incBy))
}

func DecrByFloat(key string, decrBy float64) (float64, error) {
return redigo.Float64(Do("DECRBYFLOAT", key, decrBy))
}

// use for message queue
func LPush(key string, data interface{}) (interface{}, error) {
// set
return Do("LPUSH", key, data)
}

func LPop(key string) (interface{}, error) {
return Do("LPOP", key)
}

func LPopString(key string) (string, error) {
return redigo.String(Do("LPOP", key))
}
func LPopFloat(key string) (float64, error) {
f, err := redigo.Float64(Do("LPOP", key))
return f, err
}
func LPopInt(key string) (int, error) {
return redigo.Int(Do("LPOP", key))
}
func LPopInt64(key string) (int64, error) {
return redigo.Int64(Do("LPOP", key))
}

func RPush(key string, data interface{}) (interface{}, error) {
// set
return Do("RPUSH", key, data)
}

func RPop(key string) (interface{}, error) {
return Do("RPOP", key)
}

func RPopString(key string) (string, error) {
return redigo.String(Do("RPOP", key))
}
func RPopFloat(key string) (float64, error) {
f, err := redigo.Float64(Do("RPOP", key))
return f, err
}
func RPopInt(key string) (int, error) {
return redigo.Int(Do("RPOP", key))
}
func RPopInt64(key string) (int64, error) {
return redigo.Int64(Do("RPOP", key))
}

func Scan(cursor int64, pattern string, count int64) (int64, []string, error) {
var items []string
var newCursor int64

values, err := redigo.Values(Do("SCAN", cursor, "MATCH", pattern, "COUNT", count))
if err != nil {
return 0, nil, err
}
values, err = redigo.Scan(values, &newCursor, &items)
if err != nil {
return 0, nil, err
}
return newCursor, items, nil
}

func LPushMax(key string, data ...interface{}) (interface{}, error) {
// set
return Do("LPUSH", key, data)
}

+ 622
- 0
app/utils/cache/redis_cluster.go View File

@@ -0,0 +1,622 @@
package cache

import (
"strconv"
"time"

"github.com/go-redis/redis"
)

var pools *redis.ClusterClient

func NewRedisCluster(addrs []string) error {
opt := &redis.ClusterOptions{
Addrs: addrs,
PoolSize: redisPoolSize,
PoolTimeout: redisPoolTTL,
IdleTimeout: redisIdleTTL,
DialTimeout: redisDialTTL,
ReadTimeout: redisReadTTL,
WriteTimeout: redisWriteTTL,
}
pools = redis.NewClusterClient(opt)
if err := pools.Ping().Err(); err != nil {
return err
}
return nil
}

func RCGet(key string) (interface{}, error) {
res, err := pools.Get(key).Result()
if err != nil {
return nil, convertError(err)
}
return []byte(res), nil
}
func RCSet(key string, value interface{}) error {
err := pools.Set(key, value, 0).Err()
return convertError(err)
}
func RCGetSet(key string, value interface{}) (interface{}, error) {
res, err := pools.GetSet(key, value).Result()
if err != nil {
return nil, convertError(err)
}
return []byte(res), nil
}
func RCSetNx(key string, value interface{}) (int64, error) {
res, err := pools.SetNX(key, value, 0).Result()
if err != nil {
return 0, convertError(err)
}
if res {
return 1, nil
}
return 0, nil
}
func RCSetEx(key string, value interface{}, timeout int64) error {
_, err := pools.Set(key, value, time.Duration(timeout)*time.Second).Result()
if err != nil {
return convertError(err)
}
return nil
}

// nil表示成功,ErrNil表示数据库内已经存在这个key,其他表示数据库发生错误
func RCSetNxEx(key string, value interface{}, timeout int64) error {
res, err := pools.SetNX(key, value, time.Duration(timeout)*time.Second).Result()
if err != nil {
return convertError(err)
}
if res {
return nil
}
return ErrNil
}
func RCMGet(keys ...string) ([]interface{}, error) {
res, err := pools.MGet(keys...).Result()
return res, convertError(err)
}

// 为确保多个key映射到同一个slot,每个key最好加上hash tag,如:{test}
func RCMSet(kvs map[string]interface{}) error {
pairs := make([]string, 0, len(kvs)*2)
for k, v := range kvs {
val, err := String(v, nil)
if err != nil {
return err
}
pairs = append(pairs, k, val)
}
return convertError(pools.MSet(pairs).Err())
}

// 为确保多个key映射到同一个slot,每个key最好加上hash tag,如:{test}
func RCMSetNX(kvs map[string]interface{}) (bool, error) {
pairs := make([]string, 0, len(kvs)*2)
for k, v := range kvs {
val, err := String(v, nil)
if err != nil {
return false, err
}
pairs = append(pairs, k, val)
}
res, err := pools.MSetNX(pairs).Result()
return res, convertError(err)
}
func RCExpireAt(key string, timestamp int64) (int64, error) {
res, err := pools.ExpireAt(key, time.Unix(timestamp, 0)).Result()
if err != nil {
return 0, convertError(err)
}
if res {
return 1, nil
}
return 0, nil
}
func RCDel(keys ...string) (int64, error) {
args := make([]interface{}, 0, len(keys))
for _, key := range keys {
args = append(args, key)
}
res, err := pools.Del(keys...).Result()
if err != nil {
return res, convertError(err)
}
return res, nil
}
func RCIncr(key string) (int64, error) {
res, err := pools.Incr(key).Result()
if err != nil {
return res, convertError(err)
}
return res, nil
}
func RCIncrBy(key string, delta int64) (int64, error) {
res, err := pools.IncrBy(key, delta).Result()
if err != nil {
return res, convertError(err)
}
return res, nil
}
func RCExpire(key string, duration int64) (int64, error) {
res, err := pools.Expire(key, time.Duration(duration)*time.Second).Result()
if err != nil {
return 0, convertError(err)
}
if res {
return 1, nil
}
return 0, nil
}
func RCExists(key string) (bool, error) {
res, err := pools.Exists(key).Result()
if err != nil {
return false, convertError(err)
}
if res > 0 {
return true, nil
}
return false, nil
}
func RCHGet(key string, field string) (interface{}, error) {
res, err := pools.HGet(key, field).Result()
if err != nil {
return nil, convertError(err)
}
return []byte(res), nil
}
func RCHLen(key string) (int64, error) {
res, err := pools.HLen(key).Result()
if err != nil {
return res, convertError(err)
}
return res, nil
}
func RCHSet(key string, field string, val interface{}) error {
value, err := String(val, nil)
if err != nil && err != ErrNil {
return err
}
_, err = pools.HSet(key, field, value).Result()
if err != nil {
return convertError(err)
}
return nil
}
func RCHDel(key string, fields ...string) (int64, error) {
args := make([]interface{}, 0, len(fields)+1)
args = append(args, key)
for _, field := range fields {
args = append(args, field)
}
res, err := pools.HDel(key, fields...).Result()
if err != nil {
return 0, convertError(err)
}
return res, nil
}

func RCHMGet(key string, fields ...string) (interface{}, error) {
args := make([]interface{}, 0, len(fields)+1)
args = append(args, key)
for _, field := range fields {
args = append(args, field)
}
if len(fields) == 0 {
return nil, ErrNil
}
res, err := pools.HMGet(key, fields...).Result()
if err != nil {
return nil, convertError(err)
}
return res, nil
}
func RCHMSet(key string, kvs ...interface{}) error {
if len(kvs) == 0 {
return nil
}
if len(kvs)%2 != 0 {
return ErrWrongArgsNum
}
var err error
v := map[string]interface{}{} // todo change
v["field"], err = String(kvs[0], nil)
if err != nil && err != ErrNil {
return err
}
v["value"], err = String(kvs[1], nil)
if err != nil && err != ErrNil {
return err
}
pairs := make([]string, 0, len(kvs)-2)
if len(kvs) > 2 {
for _, kv := range kvs[2:] {
kvString, err := String(kv, nil)
if err != nil && err != ErrNil {
return err
}
pairs = append(pairs, kvString)
}
}
v["paris"] = pairs
_, err = pools.HMSet(key, v).Result()
if err != nil {
return convertError(err)
}
return nil
}

func RCHKeys(key string) ([]string, error) {
res, err := pools.HKeys(key).Result()
if err != nil {
return res, convertError(err)
}
return res, nil
}
func RCHVals(key string) ([]interface{}, error) {
res, err := pools.HVals(key).Result()
if err != nil {
return nil, convertError(err)
}
rs := make([]interface{}, 0, len(res))
for _, res := range res {
rs = append(rs, res)
}
return rs, nil
}
func RCHGetAll(key string) (map[string]string, error) {
vals, err := pools.HGetAll(key).Result()
if err != nil {
return nil, convertError(err)
}
return vals, nil
}
func RCHIncrBy(key, field string, delta int64) (int64, error) {
res, err := pools.HIncrBy(key, field, delta).Result()
if err != nil {
return res, convertError(err)
}
return res, nil
}
func RCZAdd(key string, kvs ...interface{}) (int64, error) {
args := make([]interface{}, 0, len(kvs)+1)
args = append(args, key)
args = append(args, kvs...)
if len(kvs) == 0 {
return 0, nil
}
if len(kvs)%2 != 0 {
return 0, ErrWrongArgsNum
}
zs := make([]redis.Z, len(kvs)/2)
for i := 0; i < len(kvs); i += 2 {
idx := i / 2
score, err := Float64(kvs[i], nil)
if err != nil && err != ErrNil {
return 0, err
}
zs[idx].Score = score
zs[idx].Member = kvs[i+1]
}
res, err := pools.ZAdd(key, zs...).Result()
if err != nil {
return res, convertError(err)
}
return res, nil
}
func RCZRem(key string, members ...string) (int64, error) {
args := make([]interface{}, 0, len(members))
args = append(args, key)
for _, member := range members {
args = append(args, member)
}
res, err := pools.ZRem(key, members).Result()
if err != nil {
return res, convertError(err)
}
return res, err
}

func RCZRange(key string, min, max int64, withScores bool) (interface{}, error) {
res := make([]interface{}, 0)
if withScores {
zs, err := pools.ZRangeWithScores(key, min, max).Result()
if err != nil {
return nil, convertError(err)
}
for _, z := range zs {
res = append(res, z.Member, strconv.FormatFloat(z.Score, 'f', -1, 64))
}
} else {
ms, err := pools.ZRange(key, min, max).Result()
if err != nil {
return nil, convertError(err)
}
for _, m := range ms {
res = append(res, m)
}
}
return res, nil
}
func RCZRangeByScoreWithScore(key string, min, max int64) (map[string]int64, error) {
opt := new(redis.ZRangeBy)
opt.Min = strconv.FormatInt(int64(min), 10)
opt.Max = strconv.FormatInt(int64(max), 10)
opt.Count = -1
opt.Offset = 0
vals, err := pools.ZRangeByScoreWithScores(key, *opt).Result()
if err != nil {
return nil, convertError(err)
}
res := make(map[string]int64, len(vals))
for _, val := range vals {
key, err := String(val.Member, nil)
if err != nil && err != ErrNil {
return nil, err
}
res[key] = int64(val.Score)
}
return res, nil
}
func RCLRange(key string, start, stop int64) (interface{}, error) {
res, err := pools.LRange(key, start, stop).Result()
if err != nil {
return nil, convertError(err)
}
return res, nil
}
func RCLSet(key string, index int, value interface{}) error {
err := pools.LSet(key, int64(index), value).Err()
return convertError(err)
}
func RCLLen(key string) (int64, error) {
res, err := pools.LLen(key).Result()
if err != nil {
return res, convertError(err)
}
return res, nil
}
func RCLRem(key string, count int, value interface{}) (int, error) {
val, _ := value.(string)
res, err := pools.LRem(key, int64(count), val).Result()
if err != nil {
return int(res), convertError(err)
}
return int(res), nil
}
func RCTTl(key string) (int64, error) {
duration, err := pools.TTL(key).Result()
if err != nil {
return int64(duration.Seconds()), convertError(err)
}
return int64(duration.Seconds()), nil
}
func RCLPop(key string) (interface{}, error) {
res, err := pools.LPop(key).Result()
if err != nil {
return nil, convertError(err)
}
return res, nil
}
func RCRPop(key string) (interface{}, error) {
res, err := pools.RPop(key).Result()
if err != nil {
return nil, convertError(err)
}
return res, nil
}
func RCBLPop(key string, timeout int) (interface{}, error) {
res, err := pools.BLPop(time.Duration(timeout)*time.Second, key).Result()
if err != nil {
// 兼容redis 2.x
if err == redis.Nil {
return nil, ErrNil
}
return nil, err
}
return res[1], nil
}
func RCBRPop(key string, timeout int) (interface{}, error) {
res, err := pools.BRPop(time.Duration(timeout)*time.Second, key).Result()
if err != nil {
// 兼容redis 2.x
if err == redis.Nil {
return nil, ErrNil
}
return nil, convertError(err)
}
return res[1], nil
}
func RCLPush(key string, value ...interface{}) error {
args := make([]interface{}, 0, len(value)+1)
args = append(args, key)
args = append(args, value...)
vals := make([]string, 0, len(value))
for _, v := range value {
val, err := String(v, nil)
if err != nil && err != ErrNil {
return err
}
vals = append(vals, val)
}
_, err := pools.LPush(key, vals).Result() // todo ...
if err != nil {
return convertError(err)
}
return nil
}
func RCRPush(key string, value ...interface{}) error {
args := make([]interface{}, 0, len(value)+1)
args = append(args, key)
args = append(args, value...)
vals := make([]string, 0, len(value))
for _, v := range value {
val, err := String(v, nil)
if err != nil && err != ErrNil {
if err == ErrNil {
continue
}
return err
}
if val == "" {
continue
}
vals = append(vals, val)
}
_, err := pools.RPush(key, vals).Result() // todo ...
if err != nil {
return convertError(err)
}
return nil
}

// 为确保srcKey跟destKey映射到同一个slot,srcKey和destKey需要加上hash tag,如:{test}
func RCBRPopLPush(srcKey string, destKey string, timeout int) (interface{}, error) {
res, err := pools.BRPopLPush(srcKey, destKey, time.Duration(timeout)*time.Second).Result()
if err != nil {
return nil, convertError(err)
}
return res, nil
}

// 为确保srcKey跟destKey映射到同一个slot,srcKey和destKey需要加上hash tag,如:{test}
func RCRPopLPush(srcKey string, destKey string) (interface{}, error) {
res, err := pools.RPopLPush(srcKey, destKey).Result()
if err != nil {
return nil, convertError(err)
}
return res, nil
}
func RCSAdd(key string, members ...interface{}) (int64, error) {
args := make([]interface{}, 0, len(members)+1)
args = append(args, key)
args = append(args, members...)
ms := make([]string, 0, len(members))
for _, member := range members {
m, err := String(member, nil)
if err != nil && err != ErrNil {
return 0, err
}
ms = append(ms, m)
}
res, err := pools.SAdd(key, ms).Result() // todo ...
if err != nil {
return res, convertError(err)
}
return res, nil
}
func RCSPop(key string) ([]byte, error) {
res, err := pools.SPop(key).Result()
if err != nil {
return nil, convertError(err)
}
return []byte(res), nil
}
func RCSIsMember(key string, member interface{}) (bool, error) {
m, _ := member.(string)
res, err := pools.SIsMember(key, m).Result()
if err != nil {
return res, convertError(err)
}
return res, nil
}
func RCSRem(key string, members ...interface{}) (int64, error) {
args := make([]interface{}, 0, len(members)+1)
args = append(args, key)
args = append(args, members...)
ms := make([]string, 0, len(members))
for _, member := range members {
m, err := String(member, nil)
if err != nil && err != ErrNil {
return 0, err
}
ms = append(ms, m)
}
res, err := pools.SRem(key, ms).Result() // todo ...
if err != nil {
return res, convertError(err)
}
return res, nil
}
func RCSMembers(key string) ([]string, error) {
res, err := pools.SMembers(key).Result()
if err != nil {
return nil, convertError(err)
}
return res, nil
}
func RCScriptLoad(luaScript string) (interface{}, error) {
res, err := pools.ScriptLoad(luaScript).Result()
if err != nil {
return nil, convertError(err)
}
return res, nil
}
func RCEvalSha(sha1 string, numberKeys int, keysArgs ...interface{}) (interface{}, error) {
vals := make([]interface{}, 0, len(keysArgs)+2)
vals = append(vals, sha1, numberKeys)
vals = append(vals, keysArgs...)
keys := make([]string, 0, numberKeys)
args := make([]string, 0, len(keysArgs)-numberKeys)
for i, value := range keysArgs {
val, err := String(value, nil)
if err != nil && err != ErrNil {
return nil, err
}
if i < numberKeys {
keys = append(keys, val)
} else {
args = append(args, val)
}
}
res, err := pools.EvalSha(sha1, keys, args).Result()
if err != nil {
return nil, convertError(err)
}
return res, nil
}
func RCEval(luaScript string, numberKeys int, keysArgs ...interface{}) (interface{}, error) {
vals := make([]interface{}, 0, len(keysArgs)+2)
vals = append(vals, luaScript, numberKeys)
vals = append(vals, keysArgs...)
keys := make([]string, 0, numberKeys)
args := make([]string, 0, len(keysArgs)-numberKeys)
for i, value := range keysArgs {
val, err := String(value, nil)
if err != nil && err != ErrNil {
return nil, err
}
if i < numberKeys {
keys = append(keys, val)
} else {
args = append(args, val)
}
}
res, err := pools.Eval(luaScript, keys, args).Result()
if err != nil {
return nil, convertError(err)
}
return res, nil
}
func RCGetBit(key string, offset int64) (int64, error) {
res, err := pools.GetBit(key, offset).Result()
if err != nil {
return res, convertError(err)
}
return res, nil
}
func RCSetBit(key string, offset uint32, value int) (int, error) {
res, err := pools.SetBit(key, int64(offset), value).Result()
return int(res), convertError(err)
}
func RCGetClient() *redis.ClusterClient {
return pools
}
func convertError(err error) error {
if err == redis.Nil {
// 为了兼容redis 2.x,这里不返回 ErrNil,ErrNil在调用redis_cluster_reply函数时才返回
return nil
}
return err
}

+ 324
- 0
app/utils/cache/redis_pool.go View File

@@ -0,0 +1,324 @@
package cache

import (
"errors"
"log"
"strings"
"time"

redigo "github.com/gomodule/redigo/redis"
)

type RedisPool struct {
*redigo.Pool
}

func NewRedisPool(cfg *Config) *RedisPool {
return &RedisPool{&redigo.Pool{
MaxIdle: cfg.MaxIdle,
IdleTimeout: cfg.IdleTimeout,
MaxActive: cfg.MaxActive,
Wait: cfg.Wait,
Dial: func() (redigo.Conn, error) {
c, err := redigo.Dial("tcp", cfg.Server)
if err != nil {
log.Println("Redis Dial failed: ", err)
return nil, err
}
if cfg.Password != "" {
if _, err := c.Do("AUTH", cfg.Password); err != nil {
c.Close()
log.Println("Redis AUTH failed: ", err)
return nil, err
}
}
return c, err
},
TestOnBorrow: func(c redigo.Conn, t time.Time) error {
_, err := c.Do("PING")
if err != nil {
log.Println("Unable to ping to redis server:", err)
}
return err
},
}}
}

func (p *RedisPool) Do(cmd string, args ...interface{}) (reply interface{}, err error) {
conn := pool.Get()
defer conn.Close()
return conn.Do(cmd, args...)
}

func (p *RedisPool) GetPool() *redigo.Pool {
return pool
}

func (p *RedisPool) ParseKey(key string, vars []string) (string, error) {
arr := strings.Split(key, conf.KeyPlaceholder)
actualKey := ""
if len(arr) != len(vars)+1 {
return "", errors.New("redis/connection.go: Insufficient arguments to parse key")
} else {
for index, val := range arr {
if index == 0 {
actualKey = arr[index]
} else {
actualKey += vars[index-1] + val
}
}
}
return getPrefixedKey(actualKey), nil
}

func (p *RedisPool) getPrefixedKey(key string) string {
return conf.KeyPrefix + conf.KeyDelimiter + key
}
func (p *RedisPool) StripEnvKey(key string) string {
return strings.TrimLeft(key, conf.KeyPrefix+conf.KeyDelimiter)
}
func (p *RedisPool) SplitKey(key string) []string {
return strings.Split(key, conf.KeyDelimiter)
}
func (p *RedisPool) Expire(key string, ttl int) (interface{}, error) {
return Do("EXPIRE", key, ttl)
}
func (p *RedisPool) Persist(key string) (interface{}, error) {
return Do("PERSIST", key)
}

func (p *RedisPool) Del(key string) (interface{}, error) {
return Do("DEL", key)
}
func (p *RedisPool) Set(key string, data interface{}) (interface{}, error) {
// set
return Do("SET", key, data)
}
func (p *RedisPool) SetNX(key string, data interface{}) (interface{}, error) {
return Do("SETNX", key, data)
}
func (p *RedisPool) SetEx(key string, data interface{}, ttl int) (interface{}, error) {
return Do("SETEX", key, ttl, data)
}
func (p *RedisPool) Get(key string) (interface{}, error) {
// get
return Do("GET", key)
}
func (p *RedisPool) GetStringMap(key string) (map[string]string, error) {
// get
return redigo.StringMap(Do("GET", key))
}

func (p *RedisPool) GetTTL(key string) (time.Duration, error) {
ttl, err := redigo.Int64(Do("TTL", key))
return time.Duration(ttl) * time.Second, err
}
func (p *RedisPool) GetBytes(key string) ([]byte, error) {
return redigo.Bytes(Do("GET", key))
}
func (p *RedisPool) GetString(key string) (string, error) {
return redigo.String(Do("GET", key))
}
func (p *RedisPool) GetInt(key string) (int, error) {
return redigo.Int(Do("GET", key))
}
func (p *RedisPool) GetStringLength(key string) (int, error) {
return redigo.Int(Do("STRLEN", key))
}
func (p *RedisPool) ZAdd(key string, score float64, data interface{}) (interface{}, error) {
return Do("ZADD", key, score, data)
}
func (p *RedisPool) ZRem(key string, data interface{}) (interface{}, error) {
return Do("ZREM", key, data)
}
func (p *RedisPool) ZRange(key string, start int, end int, withScores bool) ([]interface{}, error) {
if withScores {
return redigo.Values(Do("ZRANGE", key, start, end, "WITHSCORES"))
}
return redigo.Values(Do("ZRANGE", key, start, end))
}
func (p *RedisPool) SAdd(setName string, data interface{}) (interface{}, error) {
return Do("SADD", setName, data)
}
func (p *RedisPool) SCard(setName string) (int64, error) {
return redigo.Int64(Do("SCARD", setName))
}
func (p *RedisPool) SIsMember(setName string, data interface{}) (bool, error) {
return redigo.Bool(Do("SISMEMBER", setName, data))
}
func (p *RedisPool) SMembers(setName string) ([]string, error) {
return redigo.Strings(Do("SMEMBERS", setName))
}
func (p *RedisPool) SRem(setName string, data interface{}) (interface{}, error) {
return Do("SREM", setName, data)
}
func (p *RedisPool) HSet(key string, HKey string, data interface{}) (interface{}, error) {
return Do("HSET", key, HKey, data)
}

func (p *RedisPool) HGet(key string, HKey string) (interface{}, error) {
return Do("HGET", key, HKey)
}

func (p *RedisPool) HMGet(key string, hashKeys ...string) ([]interface{}, error) {
ret, err := Do("HMGET", key, hashKeys)
if err != nil {
return nil, err
}
reta, ok := ret.([]interface{})
if !ok {
return nil, errors.New("result not an array")
}
return reta, nil
}

func (p *RedisPool) HMSet(key string, hashKeys []string, vals []interface{}) (interface{}, error) {
if len(hashKeys) == 0 || len(hashKeys) != len(vals) {
var ret interface{}
return ret, errors.New("bad length")
}
input := []interface{}{key}
for i, v := range hashKeys {
input = append(input, v, vals[i])
}
return Do("HMSET", input...)
}

func (p *RedisPool) HGetString(key string, HKey string) (string, error) {
return redigo.String(Do("HGET", key, HKey))
}
func (p *RedisPool) HGetFloat(key string, HKey string) (float64, error) {
f, err := redigo.Float64(Do("HGET", key, HKey))
return float64(f), err
}
func (p *RedisPool) HGetInt(key string, HKey string) (int, error) {
return redigo.Int(Do("HGET", key, HKey))
}
func (p *RedisPool) HGetInt64(key string, HKey string) (int64, error) {
return redigo.Int64(Do("HGET", key, HKey))
}
func (p *RedisPool) HGetBool(key string, HKey string) (bool, error) {
return redigo.Bool(Do("HGET", key, HKey))
}
func (p *RedisPool) HDel(key string, HKey string) (interface{}, error) {
return Do("HDEL", key, HKey)
}
func (p *RedisPool) HGetAll(key string) (map[string]interface{}, error) {
vals, err := redigo.Values(Do("HGETALL", key))
if err != nil {
return nil, err
}
num := len(vals) / 2
result := make(map[string]interface{}, num)
for i := 0; i < num; i++ {
key, _ := redigo.String(vals[2*i], nil)
result[key] = vals[2*i+1]
}
return result, nil
}

// NOTE: Use this in production environment with extreme care.
// Read more here:https://redigo.io/commands/keys
func (p *RedisPool) Keys(pattern string) ([]string, error) {
return redigo.Strings(Do("KEYS", pattern))
}

func (p *RedisPool) HKeys(key string) ([]string, error) {
return redigo.Strings(Do("HKEYS", key))
}

func (p *RedisPool) Exists(key string) (bool, error) {
count, err := redigo.Int(Do("EXISTS", key))
if count == 0 {
return false, err
} else {
return true, err
}
}

func (p *RedisPool) Incr(key string) (int64, error) {
return redigo.Int64(Do("INCR", key))
}

func (p *RedisPool) Decr(key string) (int64, error) {
return redigo.Int64(Do("DECR", key))
}

func (p *RedisPool) IncrBy(key string, incBy int64) (int64, error) {
return redigo.Int64(Do("INCRBY", key, incBy))
}

func (p *RedisPool) DecrBy(key string, decrBy int64) (int64, error) {
return redigo.Int64(Do("DECRBY", key))
}

func (p *RedisPool) IncrByFloat(key string, incBy float64) (float64, error) {
return redigo.Float64(Do("INCRBYFLOAT", key, incBy))
}

func (p *RedisPool) DecrByFloat(key string, decrBy float64) (float64, error) {
return redigo.Float64(Do("DECRBYFLOAT", key, decrBy))
}

// use for message queue
func (p *RedisPool) LPush(key string, data interface{}) (interface{}, error) {
// set
return Do("LPUSH", key, data)
}

func (p *RedisPool) LPop(key string) (interface{}, error) {
return Do("LPOP", key)
}

func (p *RedisPool) LPopString(key string) (string, error) {
return redigo.String(Do("LPOP", key))
}
func (p *RedisPool) LPopFloat(key string) (float64, error) {
f, err := redigo.Float64(Do("LPOP", key))
return float64(f), err
}
func (p *RedisPool) LPopInt(key string) (int, error) {
return redigo.Int(Do("LPOP", key))
}
func (p *RedisPool) LPopInt64(key string) (int64, error) {
return redigo.Int64(Do("LPOP", key))
}

func (p *RedisPool) RPush(key string, data interface{}) (interface{}, error) {
// set
return Do("RPUSH", key, data)
}

func (p *RedisPool) RPop(key string) (interface{}, error) {
return Do("RPOP", key)
}

func (p *RedisPool) RPopString(key string) (string, error) {
return redigo.String(Do("RPOP", key))
}
func (p *RedisPool) RPopFloat(key string) (float64, error) {
f, err := redigo.Float64(Do("RPOP", key))
return float64(f), err
}
func (p *RedisPool) RPopInt(key string) (int, error) {
return redigo.Int(Do("RPOP", key))
}
func (p *RedisPool) RPopInt64(key string) (int64, error) {
return redigo.Int64(Do("RPOP", key))
}

func (p *RedisPool) Scan(cursor int64, pattern string, count int64) (int64, []string, error) {
var items []string
var newCursor int64

values, err := redigo.Values(Do("SCAN", cursor, "MATCH", pattern, "COUNT", count))
if err != nil {
return 0, nil, err
}
values, err = redigo.Scan(values, &newCursor, &items)
if err != nil {
return 0, nil, err
}

return newCursor, items, nil
}

+ 617
- 0
app/utils/cache/redis_pool_cluster.go View File

@@ -0,0 +1,617 @@
package cache

import (
"strconv"
"time"

"github.com/go-redis/redis"
)

type RedisClusterPool struct {
client *redis.ClusterClient
}

func NewRedisClusterPool(addrs []string) (*RedisClusterPool, error) {
opt := &redis.ClusterOptions{
Addrs: addrs,
PoolSize: 512,
PoolTimeout: 10 * time.Second,
IdleTimeout: 10 * time.Second,
DialTimeout: 10 * time.Second,
ReadTimeout: 3 * time.Second,
WriteTimeout: 3 * time.Second,
}
c := redis.NewClusterClient(opt)
if err := c.Ping().Err(); err != nil {
return nil, err
}
return &RedisClusterPool{client: c}, nil
}

func (p *RedisClusterPool) Get(key string) (interface{}, error) {
res, err := p.client.Get(key).Result()
if err != nil {
return nil, convertError(err)
}
return []byte(res), nil
}
func (p *RedisClusterPool) Set(key string, value interface{}) error {
err := p.client.Set(key, value, 0).Err()
return convertError(err)
}
func (p *RedisClusterPool) GetSet(key string, value interface{}) (interface{}, error) {
res, err := p.client.GetSet(key, value).Result()
if err != nil {
return nil, convertError(err)
}
return []byte(res), nil
}
func (p *RedisClusterPool) SetNx(key string, value interface{}) (int64, error) {
res, err := p.client.SetNX(key, value, 0).Result()
if err != nil {
return 0, convertError(err)
}
if res {
return 1, nil
}
return 0, nil
}
func (p *RedisClusterPool) SetEx(key string, value interface{}, timeout int64) error {
_, err := p.client.Set(key, value, time.Duration(timeout)*time.Second).Result()
if err != nil {
return convertError(err)
}
return nil
}

// nil表示成功,ErrNil表示数据库内已经存在这个key,其他表示数据库发生错误
func (p *RedisClusterPool) SetNxEx(key string, value interface{}, timeout int64) error {
res, err := p.client.SetNX(key, value, time.Duration(timeout)*time.Second).Result()
if err != nil {
return convertError(err)
}
if res {
return nil
}
return ErrNil
}
func (p *RedisClusterPool) MGet(keys ...string) ([]interface{}, error) {
res, err := p.client.MGet(keys...).Result()
return res, convertError(err)
}

// 为确保多个key映射到同一个slot,每个key最好加上hash tag,如:{test}
func (p *RedisClusterPool) MSet(kvs map[string]interface{}) error {
pairs := make([]string, 0, len(kvs)*2)
for k, v := range kvs {
val, err := String(v, nil)
if err != nil {
return err
}
pairs = append(pairs, k, val)
}
return convertError(p.client.MSet(pairs).Err())
}

// 为确保多个key映射到同一个slot,每个key最好加上hash tag,如:{test}
func (p *RedisClusterPool) MSetNX(kvs map[string]interface{}) (bool, error) {
pairs := make([]string, 0, len(kvs)*2)
for k, v := range kvs {
val, err := String(v, nil)
if err != nil {
return false, err
}
pairs = append(pairs, k, val)
}
res, err := p.client.MSetNX(pairs).Result()
return res, convertError(err)
}
func (p *RedisClusterPool) ExpireAt(key string, timestamp int64) (int64, error) {
res, err := p.client.ExpireAt(key, time.Unix(timestamp, 0)).Result()
if err != nil {
return 0, convertError(err)
}
if res {
return 1, nil
}
return 0, nil
}
func (p *RedisClusterPool) Del(keys ...string) (int64, error) {
args := make([]interface{}, 0, len(keys))
for _, key := range keys {
args = append(args, key)
}
res, err := p.client.Del(keys...).Result()
if err != nil {
return res, convertError(err)
}
return res, nil
}
func (p *RedisClusterPool) Incr(key string) (int64, error) {
res, err := p.client.Incr(key).Result()
if err != nil {
return res, convertError(err)
}
return res, nil
}
func (p *RedisClusterPool) IncrBy(key string, delta int64) (int64, error) {
res, err := p.client.IncrBy(key, delta).Result()
if err != nil {
return res, convertError(err)
}
return res, nil
}
func (p *RedisClusterPool) Expire(key string, duration int64) (int64, error) {
res, err := p.client.Expire(key, time.Duration(duration)*time.Second).Result()
if err != nil {
return 0, convertError(err)
}
if res {
return 1, nil
}
return 0, nil
}
func (p *RedisClusterPool) Exists(key string) (bool, error) { // todo (bool, error)
res, err := p.client.Exists(key).Result()
if err != nil {
return false, convertError(err)
}
if res > 0 {
return true, nil
}
return false, nil
}
func (p *RedisClusterPool) HGet(key string, field string) (interface{}, error) {
res, err := p.client.HGet(key, field).Result()
if err != nil {
return nil, convertError(err)
}
return []byte(res), nil
}
func (p *RedisClusterPool) HLen(key string) (int64, error) {
res, err := p.client.HLen(key).Result()
if err != nil {
return res, convertError(err)
}
return res, nil
}
func (p *RedisClusterPool) HSet(key string, field string, val interface{}) error {
value, err := String(val, nil)
if err != nil && err != ErrNil {
return err
}
_, err = p.client.HSet(key, field, value).Result()
if err != nil {
return convertError(err)
}
return nil
}
func (p *RedisClusterPool) HDel(key string, fields ...string) (int64, error) {
args := make([]interface{}, 0, len(fields)+1)
args = append(args, key)
for _, field := range fields {
args = append(args, field)
}
res, err := p.client.HDel(key, fields...).Result()
if err != nil {
return 0, convertError(err)
}
return res, nil
}

func (p *RedisClusterPool) HMGet(key string, fields ...string) (interface{}, error) {
args := make([]interface{}, 0, len(fields)+1)
args = append(args, key)
for _, field := range fields {
args = append(args, field)
}
if len(fields) == 0 {
return nil, ErrNil
}
res, err := p.client.HMGet(key, fields...).Result()
if err != nil {
return nil, convertError(err)
}
return res, nil
}
func (p *RedisClusterPool) HMSet(key string, kvs ...interface{}) error {
if len(kvs) == 0 {
return nil
}
if len(kvs)%2 != 0 {
return ErrWrongArgsNum
}
var err error
v := map[string]interface{}{} // todo change
v["field"], err = String(kvs[0], nil)
if err != nil && err != ErrNil {
return err
}
v["value"], err = String(kvs[1], nil)
if err != nil && err != ErrNil {
return err
}
pairs := make([]string, 0, len(kvs)-2)
if len(kvs) > 2 {
for _, kv := range kvs[2:] {
kvString, err := String(kv, nil)
if err != nil && err != ErrNil {
return err
}
pairs = append(pairs, kvString)
}
}
v["paris"] = pairs
_, err = p.client.HMSet(key, v).Result()
if err != nil {
return convertError(err)
}
return nil
}

func (p *RedisClusterPool) HKeys(key string) ([]string, error) {
res, err := p.client.HKeys(key).Result()
if err != nil {
return res, convertError(err)
}
return res, nil
}
func (p *RedisClusterPool) HVals(key string) ([]interface{}, error) {
res, err := p.client.HVals(key).Result()
if err != nil {
return nil, convertError(err)
}
rs := make([]interface{}, 0, len(res))
for _, res := range res {
rs = append(rs, res)
}
return rs, nil
}
func (p *RedisClusterPool) HGetAll(key string) (map[string]string, error) {
vals, err := p.client.HGetAll(key).Result()
if err != nil {
return nil, convertError(err)
}
return vals, nil
}
func (p *RedisClusterPool) HIncrBy(key, field string, delta int64) (int64, error) {
res, err := p.client.HIncrBy(key, field, delta).Result()
if err != nil {
return res, convertError(err)
}
return res, nil
}
func (p *RedisClusterPool) ZAdd(key string, kvs ...interface{}) (int64, error) {
args := make([]interface{}, 0, len(kvs)+1)
args = append(args, key)
args = append(args, kvs...)
if len(kvs) == 0 {
return 0, nil
}
if len(kvs)%2 != 0 {
return 0, ErrWrongArgsNum
}
zs := make([]redis.Z, len(kvs)/2)
for i := 0; i < len(kvs); i += 2 {
idx := i / 2
score, err := Float64(kvs[i], nil)
if err != nil && err != ErrNil {
return 0, err
}
zs[idx].Score = score
zs[idx].Member = kvs[i+1]
}
res, err := p.client.ZAdd(key, zs...).Result()
if err != nil {
return res, convertError(err)
}
return res, nil
}
func (p *RedisClusterPool) ZRem(key string, members ...string) (int64, error) {
args := make([]interface{}, 0, len(members))
args = append(args, key)
for _, member := range members {
args = append(args, member)
}
res, err := p.client.ZRem(key, members).Result()
if err != nil {
return res, convertError(err)
}
return res, err
}

func (p *RedisClusterPool) ZRange(key string, min, max int64, withScores bool) (interface{}, error) {
res := make([]interface{}, 0)
if withScores {
zs, err := p.client.ZRangeWithScores(key, min, max).Result()
if err != nil {
return nil, convertError(err)
}
for _, z := range zs {
res = append(res, z.Member, strconv.FormatFloat(z.Score, 'f', -1, 64))
}
} else {
ms, err := p.client.ZRange(key, min, max).Result()
if err != nil {
return nil, convertError(err)
}
for _, m := range ms {
res = append(res, m)
}
}
return res, nil
}
func (p *RedisClusterPool) ZRangeByScoreWithScore(key string, min, max int64) (map[string]int64, error) {
opt := new(redis.ZRangeBy)
opt.Min = strconv.FormatInt(int64(min), 10)
opt.Max = strconv.FormatInt(int64(max), 10)
opt.Count = -1
opt.Offset = 0
vals, err := p.client.ZRangeByScoreWithScores(key, *opt).Result()
if err != nil {
return nil, convertError(err)
}
res := make(map[string]int64, len(vals))
for _, val := range vals {
key, err := String(val.Member, nil)
if err != nil && err != ErrNil {
return nil, err
}
res[key] = int64(val.Score)
}
return res, nil
}
func (p *RedisClusterPool) LRange(key string, start, stop int64) (interface{}, error) {
res, err := p.client.LRange(key, start, stop).Result()
if err != nil {
return nil, convertError(err)
}
return res, nil
}
func (p *RedisClusterPool) LSet(key string, index int, value interface{}) error {
err := p.client.LSet(key, int64(index), value).Err()
return convertError(err)
}
func (p *RedisClusterPool) LLen(key string) (int64, error) {
res, err := p.client.LLen(key).Result()
if err != nil {
return res, convertError(err)
}
return res, nil
}
func (p *RedisClusterPool) LRem(key string, count int, value interface{}) (int, error) {
val, _ := value.(string)
res, err := p.client.LRem(key, int64(count), val).Result()
if err != nil {
return int(res), convertError(err)
}
return int(res), nil
}
func (p *RedisClusterPool) TTl(key string) (int64, error) {
duration, err := p.client.TTL(key).Result()
if err != nil {
return int64(duration.Seconds()), convertError(err)
}
return int64(duration.Seconds()), nil
}
func (p *RedisClusterPool) LPop(key string) (interface{}, error) {
res, err := p.client.LPop(key).Result()
if err != nil {
return nil, convertError(err)
}
return res, nil
}
func (p *RedisClusterPool) RPop(key string) (interface{}, error) {
res, err := p.client.RPop(key).Result()
if err != nil {
return nil, convertError(err)
}
return res, nil
}
func (p *RedisClusterPool) BLPop(key string, timeout int) (interface{}, error) {
res, err := p.client.BLPop(time.Duration(timeout)*time.Second, key).Result()
if err != nil {
// 兼容redis 2.x
if err == redis.Nil {
return nil, ErrNil
}
return nil, err
}
return res[1], nil
}
func (p *RedisClusterPool) BRPop(key string, timeout int) (interface{}, error) {
res, err := p.client.BRPop(time.Duration(timeout)*time.Second, key).Result()
if err != nil {
// 兼容redis 2.x
if err == redis.Nil {
return nil, ErrNil
}
return nil, convertError(err)
}
return res[1], nil
}
func (p *RedisClusterPool) LPush(key string, value ...interface{}) error {
args := make([]interface{}, 0, len(value)+1)
args = append(args, key)
args = append(args, value...)
vals := make([]string, 0, len(value))
for _, v := range value {
val, err := String(v, nil)
if err != nil && err != ErrNil {
return err
}
vals = append(vals, val)
}
_, err := p.client.LPush(key, vals).Result() // todo ...
if err != nil {
return convertError(err)
}
return nil
}
func (p *RedisClusterPool) RPush(key string, value ...interface{}) error {
args := make([]interface{}, 0, len(value)+1)
args = append(args, key)
args = append(args, value...)
vals := make([]string, 0, len(value))
for _, v := range value {
val, err := String(v, nil)
if err != nil && err != ErrNil {
if err == ErrNil {
continue
}
return err
}
if val == "" {
continue
}
vals = append(vals, val)
}
_, err := p.client.RPush(key, vals).Result() // todo ...
if err != nil {
return convertError(err)
}
return nil
}

// 为确保srcKey跟destKey映射到同一个slot,srcKey和destKey需要加上hash tag,如:{test}
func (p *RedisClusterPool) BRPopLPush(srcKey string, destKey string, timeout int) (interface{}, error) {
res, err := p.client.BRPopLPush(srcKey, destKey, time.Duration(timeout)*time.Second).Result()
if err != nil {
return nil, convertError(err)
}
return res, nil
}

// 为确保srcKey跟destKey映射到同一个slot,srcKey和destKey需要加上hash tag,如:{test}
func (p *RedisClusterPool) RPopLPush(srcKey string, destKey string) (interface{}, error) {
res, err := p.client.RPopLPush(srcKey, destKey).Result()
if err != nil {
return nil, convertError(err)
}
return res, nil
}
func (p *RedisClusterPool) SAdd(key string, members ...interface{}) (int64, error) {
args := make([]interface{}, 0, len(members)+1)
args = append(args, key)
args = append(args, members...)
ms := make([]string, 0, len(members))
for _, member := range members {
m, err := String(member, nil)
if err != nil && err != ErrNil {
return 0, err
}
ms = append(ms, m)
}
res, err := p.client.SAdd(key, ms).Result() // todo ...
if err != nil {
return res, convertError(err)
}
return res, nil
}
func (p *RedisClusterPool) SPop(key string) ([]byte, error) {
res, err := p.client.SPop(key).Result()
if err != nil {
return nil, convertError(err)
}
return []byte(res), nil
}
func (p *RedisClusterPool) SIsMember(key string, member interface{}) (bool, error) {
m, _ := member.(string)
res, err := p.client.SIsMember(key, m).Result()
if err != nil {
return res, convertError(err)
}
return res, nil
}
func (p *RedisClusterPool) SRem(key string, members ...interface{}) (int64, error) {
args := make([]interface{}, 0, len(members)+1)
args = append(args, key)
args = append(args, members...)
ms := make([]string, 0, len(members))
for _, member := range members {
m, err := String(member, nil)
if err != nil && err != ErrNil {
return 0, err
}
ms = append(ms, m)
}
res, err := p.client.SRem(key, ms).Result() // todo ...
if err != nil {
return res, convertError(err)
}
return res, nil
}
func (p *RedisClusterPool) SMembers(key string) ([]string, error) {
res, err := p.client.SMembers(key).Result()
if err != nil {
return nil, convertError(err)
}
return res, nil
}
func (p *RedisClusterPool) ScriptLoad(luaScript string) (interface{}, error) {
res, err := p.client.ScriptLoad(luaScript).Result()
if err != nil {
return nil, convertError(err)
}
return res, nil
}
func (p *RedisClusterPool) EvalSha(sha1 string, numberKeys int, keysArgs ...interface{}) (interface{}, error) {
vals := make([]interface{}, 0, len(keysArgs)+2)
vals = append(vals, sha1, numberKeys)
vals = append(vals, keysArgs...)
keys := make([]string, 0, numberKeys)
args := make([]string, 0, len(keysArgs)-numberKeys)
for i, value := range keysArgs {
val, err := String(value, nil)
if err != nil && err != ErrNil {
return nil, err
}
if i < numberKeys {
keys = append(keys, val)
} else {
args = append(args, val)
}
}
res, err := p.client.EvalSha(sha1, keys, args).Result()
if err != nil {
return nil, convertError(err)
}
return res, nil
}
func (p *RedisClusterPool) Eval(luaScript string, numberKeys int, keysArgs ...interface{}) (interface{}, error) {
vals := make([]interface{}, 0, len(keysArgs)+2)
vals = append(vals, luaScript, numberKeys)
vals = append(vals, keysArgs...)
keys := make([]string, 0, numberKeys)
args := make([]string, 0, len(keysArgs)-numberKeys)
for i, value := range keysArgs {
val, err := String(value, nil)
if err != nil && err != ErrNil {
return nil, err
}
if i < numberKeys {
keys = append(keys, val)
} else {
args = append(args, val)
}
}
res, err := p.client.Eval(luaScript, keys, args).Result()
if err != nil {
return nil, convertError(err)
}
return res, nil
}
func (p *RedisClusterPool) GetBit(key string, offset int64) (int64, error) {
res, err := p.client.GetBit(key, offset).Result()
if err != nil {
return res, convertError(err)
}
return res, nil
}
func (p *RedisClusterPool) SetBit(key string, offset uint32, value int) (int, error) {
res, err := p.client.SetBit(key, int64(offset), value).Result()
return int(res), convertError(err)
}
func (p *RedisClusterPool) GetClient() *redis.ClusterClient {
return pools
}

+ 322
- 0
app/utils/convert.go View File

@@ -0,0 +1,322 @@
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 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 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 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)
}

+ 19
- 0
app/utils/crypto.go View File

@@ -0,0 +1,19 @@
package utils

import (
"crypto/md5"
"encoding/base64"
"fmt"
)

func GetMd5(raw []byte) string {
h := md5.New()
h.Write(raw)
return fmt.Sprintf("%x", h.Sum(nil))
}

func GetBase64Md5(raw []byte) string {
h := md5.New()
h.Write(raw)
return base64.StdEncoding.EncodeToString(h.Sum(nil))
}

+ 209
- 0
app/utils/curl.go View File

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

+ 25
- 0
app/utils/debug.go View File

@@ -0,0 +1,25 @@
package utils

import (
"fmt"
"os"
"strconv"
"time"
)

func Debug(args ...interface{}) {
s := ""
l := len(args)
if l < 1 {
fmt.Println("please input some data")
os.Exit(0)
}
i := 1
for _, v := range args {
s += fmt.Sprintf("【"+strconv.Itoa(i)+"】: %#v\n", v)
i++
}
s = "******************** 【DEBUG - " + time.Now().Format("2006-01-02 15:04:05") + "】 ********************\n" + s + "******************** 【DEBUG - END】 ********************\n"
fmt.Println(s)
os.Exit(0)
}

+ 37
- 0
app/utils/duplicate.go View File

@@ -0,0 +1,37 @@
package utils

func RemoveDuplicateString(elms []string) []string {
res := make([]string, 0, len(elms))
temp := map[string]struct{}{}
for _, item := range elms {
if _, ok := temp[item]; !ok {
temp[item] = struct{}{}
res = append(res, item)
}
}
return res
}

func RemoveDuplicateInt(elms []int) []int {
res := make([]int, 0, len(elms))
temp := map[int]struct{}{}
for _, item := range elms {
if _, ok := temp[item]; !ok {
temp[item] = struct{}{}
res = append(res, item)
}
}
return res
}

func RemoveDuplicateInt64(elms []int64) []int64 {
res := make([]int64, 0, len(elms))
temp := map[int64]struct{}{}
for _, item := range elms {
if _, ok := temp[item]; !ok {
temp[item] = struct{}{}
res = append(res, item)
}
}
return res
}

+ 22
- 0
app/utils/file.go View File

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

+ 29
- 0
app/utils/file_and_dir.go View File

@@ -0,0 +1,29 @@
package utils

import "os"

// 判断所给路径文件、文件夹是否存在
func Exists(path string) bool {
_, err := os.Stat(path) //os.Stat获取文件信息
if err != nil {
if os.IsExist(err) {
return true
}
return false
}
return true
}

// 判断所给路径是否为文件夹
func IsDir(path string) bool {
s, err := os.Stat(path)
if err != nil {
return false
}
return s.IsDir()
}

// 判断所给路径是否为文件
func IsFile(path string) bool {
return !IsDir(path)
}

+ 59
- 0
app/utils/format.go View File

@@ -0,0 +1,59 @@
package utils

import (
"math"
)

func CouponFormat(data string) string {
switch data {
case "0.00", "0", "":
return ""
default:
return Int64ToStr(FloatToInt64(StrToFloat64(data)))
}
}
func CommissionFormat(data string) string {
if StrToFloat64(data) > 0 {
return data
}

return ""
}

func HideString(src string, hLen int) string {
str := []rune(src)
if hLen == 0 {
hLen = 4
}
hideStr := ""
for i := 0; i < hLen; i++ {
hideStr += "*"
}
hideLen := len(str) / 2
showLen := len(str) - hideLen
if hideLen == 0 || showLen == 0 {
return hideStr
}
subLen := showLen / 2
if subLen == 0 {
return string(str[:showLen]) + hideStr
}
s := string(str[:subLen])
s += hideStr
s += string(str[len(str)-subLen:])
return s
}

//SaleCountFormat is 格式化销量
func SaleCountFormat(s string) string {
return s + "已售"
}

// 小数格式化
func FloatFormat(f float64, i int) float64 {
if i > 14 {
return f
}
p := math.Pow10(i)
return float64(int64((f+0.000000000000009)*p)) / p
}

+ 146
- 0
app/utils/ip.go View File

@@ -0,0 +1,146 @@
package utils

import (
"errors"
"math"
"net"
"net/http"
"strings"
)

func GetIP(r *http.Request) string {
ip := ClientPublicIP(r)
if ip == "" {
ip = ClientIP(r)
}
if ip == "" {
ip = "0000"
}
return ip
}

// HasLocalIPddr 检测 IP 地址字符串是否是内网地址
// Deprecated: 此为一个错误名称错误拼写的函数,计划在将来移除,请使用 HasLocalIPAddr 函数
func HasLocalIPddr(ip string) bool {
return HasLocalIPAddr(ip)
}

// HasLocalIPAddr 检测 IP 地址字符串是否是内网地址
func HasLocalIPAddr(ip string) bool {
return HasLocalIP(net.ParseIP(ip))
}

// HasLocalIP 检测 IP 地址是否是内网地址
// 通过直接对比ip段范围效率更高,详见:https://github.com/thinkeridea/go-extend/issues/2
func HasLocalIP(ip net.IP) bool {
if ip.IsLoopback() {
return true
}

ip4 := ip.To4()
if ip4 == nil {
return false
}

return ip4[0] == 10 || // 10.0.0.0/8
(ip4[0] == 172 && ip4[1] >= 16 && ip4[1] <= 31) || // 172.16.0.0/12
(ip4[0] == 169 && ip4[1] == 254) || // 169.254.0.0/16
(ip4[0] == 192 && ip4[1] == 168) // 192.168.0.0/16
}

// ClientIP 尽最大努力实现获取客户端 IP 的算法。
// 解析 X-Real-IP 和 X-Forwarded-For 以便于反向代理(nginx 或 haproxy)可以正常工作。
func ClientIP(r *http.Request) string {
ip := strings.TrimSpace(strings.Split(r.Header.Get("X-Forwarded-For"), ",")[0])
if ip != "" {
return ip
}

ip = strings.TrimSpace(r.Header.Get("X-Real-Ip"))
if ip != "" {
return ip
}

if ip, _, err := net.SplitHostPort(strings.TrimSpace(r.RemoteAddr)); err == nil {
return ip
}

return ""
}

// ClientPublicIP 尽最大努力实现获取客户端公网 IP 的算法。
// 解析 X-Real-IP 和 X-Forwarded-For 以便于反向代理(nginx 或 haproxy)可以正常工作。
func ClientPublicIP(r *http.Request) string {
var ip string
for _, ip = range strings.Split(r.Header.Get("X-Forwarded-For"), ",") {
if ip = strings.TrimSpace(ip); ip != "" && !HasLocalIPAddr(ip) {
return ip
}
}

if ip = strings.TrimSpace(r.Header.Get("X-Real-Ip")); ip != "" && !HasLocalIPAddr(ip) {
return ip
}

if ip = RemoteIP(r); !HasLocalIPAddr(ip) {
return ip
}

return ""
}

// RemoteIP 通过 RemoteAddr 获取 IP 地址, 只是一个快速解析方法。
func RemoteIP(r *http.Request) string {
ip, _, _ := net.SplitHostPort(r.RemoteAddr)
return ip
}

// IPString2Long 把ip字符串转为数值
func IPString2Long(ip string) (uint, error) {
b := net.ParseIP(ip).To4()
if b == nil {
return 0, errors.New("invalid ipv4 format")
}

return uint(b[3]) | uint(b[2])<<8 | uint(b[1])<<16 | uint(b[0])<<24, nil
}

// Long2IPString 把数值转为ip字符串
func Long2IPString(i uint) (string, error) {
if i > math.MaxUint32 {
return "", errors.New("beyond the scope of ipv4")
}

ip := make(net.IP, net.IPv4len)
ip[0] = byte(i >> 24)
ip[1] = byte(i >> 16)
ip[2] = byte(i >> 8)
ip[3] = byte(i)

return ip.String(), nil
}

// IP2Long 把net.IP转为数值
func IP2Long(ip net.IP) (uint, error) {
b := ip.To4()
if b == nil {
return 0, errors.New("invalid ipv4 format")
}

return uint(b[3]) | uint(b[2])<<8 | uint(b[1])<<16 | uint(b[0])<<24, nil
}

// Long2IP 把数值转为net.IP
func Long2IP(i uint) (net.IP, error) {
if i > math.MaxUint32 {
return nil, errors.New("beyond the scope of ipv4")
}

ip := make(net.IP, net.IPv4len)
ip[0] = byte(i >> 24)
ip[1] = byte(i >> 16)
ip[2] = byte(i >> 8)
ip[3] = byte(i)

return ip, nil
}

+ 17
- 0
app/utils/json.go View File

@@ -0,0 +1,17 @@
package utils

import (
"bytes"
"encoding/json"
)

func JsonMarshal(interface{}) {

}

// 不科学计数法
func JsonDecode(data []byte, v interface{}) error {
d := json.NewDecoder(bytes.NewReader(data))
d.UseNumber()
return d.Decode(v)
}

+ 245
- 0
app/utils/logx/log.go View File

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

+ 105
- 0
app/utils/logx/output.go View File

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

+ 192
- 0
app/utils/logx/sugar.go View File

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

+ 9
- 0
app/utils/map.go View File

@@ -0,0 +1,9 @@
package utils

// GetOneKeyOfMapString 取出Map的一个key
func GetOneKeyOfMapString(collection map[string]string) string {
for k := range collection {
return k
}
return ""
}

+ 341
- 0
app/utils/map_and_struct.go View File

@@ -0,0 +1,341 @@
package utils

import (
"encoding/json"
"fmt"
"reflect"
"strconv"
"strings"
)

func Map2Struct(vals map[string]interface{}, dst interface{}) (err error) {
return Map2StructByTag(vals, dst, "json")
}

func Map2StructByTag(vals map[string]interface{}, dst interface{}, structTag string) (err error) {
defer func() {
e := recover()
if e != nil {
if v, ok := e.(error); ok {
err = fmt.Errorf("Panic: %v", v.Error())
} else {
err = fmt.Errorf("Panic: %v", e)
}
}
}()

pt := reflect.TypeOf(dst)
pv := reflect.ValueOf(dst)

if pv.Kind() != reflect.Ptr || pv.Elem().Kind() != reflect.Struct {
return fmt.Errorf("not a pointer of struct")
}

var f reflect.StructField
var ft reflect.Type
var fv reflect.Value

for i := 0; i < pt.Elem().NumField(); i++ {
f = pt.Elem().Field(i)
fv = pv.Elem().Field(i)
ft = f.Type

if f.Anonymous || !fv.CanSet() {
continue
}

tag := f.Tag.Get(structTag)

name, option := parseTag(tag)

if name == "-" {
continue
}

if name == "" {
name = strings.ToLower(f.Name)
}
val, ok := vals[name]

if !ok {
if option == "required" {
return fmt.Errorf("'%v' not found", name)
}
if len(option) != 0 {
val = option // default value
} else {
//fv.Set(reflect.Zero(ft)) // TODO set zero value or just ignore it?
continue
}
}

// convert or set value to field
vv := reflect.ValueOf(val)
vt := reflect.TypeOf(val)

if vt.Kind() != reflect.String {
// try to assign and convert
if vt.AssignableTo(ft) {
fv.Set(vv)
continue
}

if vt.ConvertibleTo(ft) {
fv.Set(vv.Convert(ft))
continue
}

return fmt.Errorf("value type not match: field=%v(%v) value=%v(%v)", f.Name, ft.Kind(), val, vt.Kind())
}
s := strings.TrimSpace(vv.String())
if len(s) == 0 && option == "required" {
return fmt.Errorf("value of required argument can't not be empty")
}
fk := ft.Kind()

// convert string to value
if fk == reflect.Ptr && ft.Elem().Kind() == reflect.String {
fv.Set(reflect.ValueOf(&s))
continue
}
if fk == reflect.Ptr || fk == reflect.Struct {
err = convertJsonValue(s, name, fv)
} else if fk == reflect.Slice {
err = convertSlice(s, f.Name, ft, fv)
} else {
err = convertValue(fk, s, f.Name, fv)
}

if err != nil {
return err
}
continue
}

return nil
}

func Struct2Map(s interface{}) map[string]interface{} {
return Struct2MapByTag(s, "json")
}
func Struct2MapByTag(s interface{}, tagName string) map[string]interface{} {
t := reflect.TypeOf(s)
v := reflect.ValueOf(s)

if v.Kind() == reflect.Ptr && v.Elem().Kind() == reflect.Struct {
t = t.Elem()
v = v.Elem()
}

if v.Kind() != reflect.Struct {
return nil
}

m := make(map[string]interface{})

for i := 0; i < t.NumField(); i++ {
fv := v.Field(i)
ft := t.Field(i)

if !fv.CanInterface() {
continue
}

if ft.PkgPath != "" { // unexported
continue
}

var name string
var option string
tag := ft.Tag.Get(tagName)
if tag != "" {
ts := strings.Split(tag, ",")
if len(ts) == 1 {
name = ts[0]
} else if len(ts) > 1 {
name = ts[0]
option = ts[1]
}
if name == "-" {
continue // skip this field
}
if name == "" {
name = strings.ToLower(ft.Name)
}
if option == "omitempty" {
if isEmpty(&fv) {
continue // skip empty field
}
}
} else {
name = strings.ToLower(ft.Name)
}

if ft.Anonymous && fv.Kind() == reflect.Ptr && fv.IsNil() {
continue
}
if (ft.Anonymous && fv.Kind() == reflect.Struct) ||
(ft.Anonymous && fv.Kind() == reflect.Ptr && fv.Elem().Kind() == reflect.Struct) {

// embedded struct
embedded := Struct2MapByTag(fv.Interface(), tagName)
for embName, embValue := range embedded {
m[embName] = embValue
}
} else if option == "string" {
kind := fv.Kind()
if kind == reflect.Int || kind == reflect.Int8 || kind == reflect.Int16 || kind == reflect.Int32 || kind == reflect.Int64 {
m[name] = strconv.FormatInt(fv.Int(), 10)
} else if kind == reflect.Uint || kind == reflect.Uint8 || kind == reflect.Uint16 || kind == reflect.Uint32 || kind == reflect.Uint64 {
m[name] = strconv.FormatUint(fv.Uint(), 10)
} else if kind == reflect.Float32 || kind == reflect.Float64 {
m[name] = strconv.FormatFloat(fv.Float(), 'f', 2, 64)
} else {
m[name] = fv.Interface()
}
} else {
m[name] = fv.Interface()
}
}

return m
}

func isEmpty(v *reflect.Value) bool {
k := v.Kind()
if k == reflect.Bool {
return v.Bool() == false
} else if reflect.Int < k && k < reflect.Int64 {
return v.Int() == 0
} else if reflect.Uint < k && k < reflect.Uintptr {
return v.Uint() == 0
} else if k == reflect.Float32 || k == reflect.Float64 {
return v.Float() == 0
} else if k == reflect.Array || k == reflect.Map || k == reflect.Slice || k == reflect.String {
return v.Len() == 0
} else if k == reflect.Interface || k == reflect.Ptr {
return v.IsNil()
}
return false
}

func convertSlice(s string, name string, ft reflect.Type, fv reflect.Value) error {
var err error
et := ft.Elem()

if et.Kind() == reflect.Ptr || et.Kind() == reflect.Struct {
return convertJsonValue(s, name, fv)
}

ss := strings.Split(s, ",")

if len(s) == 0 || len(ss) == 0 {
return nil
}

fs := reflect.MakeSlice(ft, 0, len(ss))

for _, si := range ss {
ev := reflect.New(et).Elem()

err = convertValue(et.Kind(), si, name, ev)
if err != nil {
return err
}
fs = reflect.Append(fs, ev)
}

fv.Set(fs)

return nil
}

func convertJsonValue(s string, name string, fv reflect.Value) error {
var err error
d := StringToSlice(s)

if fv.Kind() == reflect.Ptr {
if fv.IsNil() {
fv.Set(reflect.New(fv.Type().Elem()))
}
} else {
fv = fv.Addr()
}

err = json.Unmarshal(d, fv.Interface())

if err != nil {
return fmt.Errorf("invalid json '%v': %v, %v", name, err.Error(), s)
}

return nil
}

func convertValue(kind reflect.Kind, s string, name string, fv reflect.Value) error {
if !fv.CanAddr() {
return fmt.Errorf("can not addr: %v", name)
}

if kind == reflect.String {
fv.SetString(s)
return nil
}

if kind == reflect.Bool {
switch s {
case "true":
fv.SetBool(true)
case "false":
fv.SetBool(false)
case "1":
fv.SetBool(true)
case "0":
fv.SetBool(false)
default:
return fmt.Errorf("invalid bool: %v value=%v", name, s)
}
return nil
}

if reflect.Int <= kind && kind <= reflect.Int64 {
i, err := strconv.ParseInt(s, 10, 64)
if err != nil {
return fmt.Errorf("invalid int: %v value=%v", name, s)
}
fv.SetInt(i)

} else if reflect.Uint <= kind && kind <= reflect.Uint64 {
i, err := strconv.ParseUint(s, 10, 64)
if err != nil {
return fmt.Errorf("invalid int: %v value=%v", name, s)
}
fv.SetUint(i)

} else if reflect.Float32 == kind || kind == reflect.Float64 {
i, err := strconv.ParseFloat(s, 64)

if err != nil {
return fmt.Errorf("invalid float: %v value=%v", name, s)
}

fv.SetFloat(i)
} else {
// not support or just ignore it?
// return fmt.Errorf("type not support: field=%v(%v) value=%v(%v)", name, ft.Kind(), val, vt.Kind())
}
return nil
}

func parseTag(tag string) (string, string) {
tags := strings.Split(tag, ",")

if len(tags) <= 0 {
return "", ""
}

if len(tags) == 1 {
return tags[0], ""
}

return tags[0], tags[1]
}

+ 12
- 0
app/utils/md5.go View File

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

+ 33
- 0
app/utils/qrcode/decodeFile.go View File

@@ -0,0 +1,33 @@
package qrcode

import (
"image"
_ "image/jpeg"
_ "image/png"
"os"

"github.com/makiuchi-d/gozxing"
"github.com/makiuchi-d/gozxing/qrcode"
)

func DecodeFile(fi string) (string, error) {
file, err := os.Open(fi)
if err != nil {
return "", err
}
img, _, err := image.Decode(file)
if err != nil {
return "", err
}
// prepare BinaryBitmap
bmp, err := gozxing.NewBinaryBitmapFromImage(img)
if err != nil {
return "", err
}
// decode image
result, err := qrcode.NewQRCodeReader().Decode(bmp, nil)
if err != nil {
return "", err
}
return result.String(), nil
}

+ 43
- 0
app/utils/qrcode/getBase64.go View File

@@ -0,0 +1,43 @@
package qrcode

// 生成登录二维码图片, 方便在网页上显示

import (
"bytes"
"encoding/base64"
"image/jpeg"
"image/png"

"github.com/boombuler/barcode"
"github.com/boombuler/barcode/qr"
)

func GetJPGBase64(content string, edges ...int) string {
edgeLen := 300
if len(edges) > 0 && edges[0] > 100 && edges[0] < 2000 {
edgeLen = edges[0]
}
img, _ := qr.Encode(content, qr.L, qr.Unicode)
img, _ = barcode.Scale(img, edgeLen, edgeLen)

emptyBuff := bytes.NewBuffer(nil) // 开辟一个新的空buff缓冲区
jpeg.Encode(emptyBuff, img, nil)
dist := make([]byte, 50000) // 开辟存储空间
base64.StdEncoding.Encode(dist, emptyBuff.Bytes()) // buff转成base64
return "data:image/png;base64," + string(dist) // 输出图片base64(type = []byte)
}

func GetPNGBase64(content string, edges ...int) string {
edgeLen := 300
if len(edges) > 0 && edges[0] > 100 && edges[0] < 2000 {
edgeLen = edges[0]
}
img, _ := qr.Encode(content, qr.L, qr.Unicode)
img, _ = barcode.Scale(img, edgeLen, edgeLen)

emptyBuff := bytes.NewBuffer(nil) // 开辟一个新的空buff缓冲区
png.Encode(emptyBuff, img)
dist := make([]byte, 50000) // 开辟存储空间
base64.StdEncoding.Encode(dist, emptyBuff.Bytes()) // buff转成base64
return string(dist) // 输出图片base64(type = []byte)
}

+ 85
- 0
app/utils/qrcode/saveFile.go View File

@@ -0,0 +1,85 @@
package qrcode

// 生成登录二维码图片

import (
"errors"
"image"
"image/jpeg"
"image/png"
"os"
"path/filepath"
"strings"

"github.com/boombuler/barcode"
"github.com/boombuler/barcode/qr"
)

func SaveJpegFile(filePath, content string, edges ...int) error {
edgeLen := 300
if len(edges) > 0 && edges[0] > 100 && edges[0] < 2000 {
edgeLen = edges[0]
}
img, _ := qr.Encode(content, qr.L, qr.Unicode)
img, _ = barcode.Scale(img, edgeLen, edgeLen)

return writeFile(filePath, img, "jpg")
}

func SavePngFile(filePath, content string, edges ...int) error {
edgeLen := 300
if len(edges) > 0 && edges[0] > 100 && edges[0] < 2000 {
edgeLen = edges[0]
}
img, _ := qr.Encode(content, qr.L, qr.Unicode)
img, _ = barcode.Scale(img, edgeLen, edgeLen)

return writeFile(filePath, img, "png")
}

func writeFile(filePath string, img image.Image, format string) error {
if err := createDir(filePath); err != nil {
return err
}
file, err := os.Create(filePath)
defer file.Close()
if err != nil {
return err
}
switch strings.ToLower(format) {
case "png":
err = png.Encode(file, img)
break
case "jpg":
err = jpeg.Encode(file, img, nil)
default:
return errors.New("format not accept")
}
if err != nil {
return err
}
return nil
}

func createDir(filePath string) error {
var err error
// filePath, _ = filepath.Abs(filePath)
dirPath := filepath.Dir(filePath)
dirInfo, err := os.Stat(dirPath)
if err != nil {
if !os.IsExist(err) {
err = os.MkdirAll(dirPath, 0777)
if err != nil {
return err
}
} else {
return err
}
} else {
if dirInfo.IsDir() {
return nil
}
return errors.New("directory is a file")
}
return nil
}

+ 39
- 0
app/utils/qrcode/writeWeb.go View File

@@ -0,0 +1,39 @@
package qrcode

import (
"bytes"
"image/jpeg"
"image/png"
"net/http"

"github.com/boombuler/barcode"
"github.com/boombuler/barcode/qr"
)

func WritePng(w http.ResponseWriter, content string, edges ...int) error {
edgeLen := 300
if len(edges) > 0 && edges[0] > 100 && edges[0] < 2000 {
edgeLen = edges[0]
}
img, _ := qr.Encode(content, qr.L, qr.Unicode)
img, _ = barcode.Scale(img, edgeLen, edgeLen)
buff := bytes.NewBuffer(nil)
png.Encode(buff, img)
w.Header().Set("Content-Type", "image/png")
_, err := w.Write(buff.Bytes())
return err
}

func WriteJpg(w http.ResponseWriter, content string, edges ...int) error {
edgeLen := 300
if len(edges) > 0 && edges[0] > 100 && edges[0] < 2000 {
edgeLen = edges[0]
}
img, _ := qr.Encode(content, qr.L, qr.Unicode)
img, _ = barcode.Scale(img, edgeLen, edgeLen)
buff := bytes.NewBuffer(nil)
jpeg.Encode(buff, img, nil)
w.Header().Set("Content-Type", "image/jpg")
_, err := w.Write(buff.Bytes())
return err
}

+ 31
- 0
app/utils/rand.go View File

@@ -0,0 +1,31 @@
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))
}

+ 170
- 0
app/utils/rsa.go View File

@@ -0,0 +1,170 @@
package utils

import (
"bytes"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"errors"
"fmt"
"io/ioutil"
"log"
"os"
)

// 生成私钥文件 TODO 未指定路径
func RsaKeyGen(bits int) error {
privateKey, err := rsa.GenerateKey(rand.Reader, bits)
if err != nil {
return err
}
derStream := x509.MarshalPKCS1PrivateKey(privateKey)
block := &pem.Block{
Type: "RSA PRIVATE KEY",
Bytes: derStream,
}
priFile, err := os.Create("private.pem")
if err != nil {
return err
}
err = pem.Encode(priFile, block)
priFile.Close()
if err != nil {
return err
}
// 生成公钥文件
publicKey := &privateKey.PublicKey
derPkix, err := x509.MarshalPKIXPublicKey(publicKey)
if err != nil {
return err
}
block = &pem.Block{
Type: "PUBLIC KEY",
Bytes: derPkix,
}
pubFile, err := os.Create("public.pem")
if err != nil {
return err
}
err = pem.Encode(pubFile, block)
pubFile.Close()
if err != nil {
return err
}
return nil
}

// 生成私钥文件, 返回 privateKey , publicKey, error
func RsaKeyGenText(bits int) (string, string, error) { // bits 字节位 1024/2048
privateKey, err := rsa.GenerateKey(rand.Reader, bits)
if err != nil {
return "", "", err
}
derStream := x509.MarshalPKCS1PrivateKey(privateKey)
block := &pem.Block{
Type: "RSA PRIVATE KEY",
Bytes: derStream,
}
priBuff := bytes.NewBuffer(nil)
err = pem.Encode(priBuff, block)
if err != nil {
return "", "", err
}
// 生成公钥文件
publicKey := &privateKey.PublicKey
derPkix, err := x509.MarshalPKIXPublicKey(publicKey)
if err != nil {
return "", "", err
}
block = &pem.Block{
Type: "PUBLIC KEY",
Bytes: derPkix,
}
pubBuff := bytes.NewBuffer(nil)
err = pem.Encode(pubBuff, block)
if err != nil {
return "", "", err
}
return priBuff.String(), pubBuff.String(), nil
}

// 加密
func RsaEncrypt(rawData, publicKey []byte) ([]byte, error) {
block, _ := pem.Decode(publicKey)
if block == nil {
return nil, errors.New("public key error")
}
pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
return nil, err
}
pub := pubInterface.(*rsa.PublicKey)
return rsa.EncryptPKCS1v15(rand.Reader, pub, rawData)
}

// 公钥加密
func RsaEncrypts(data, keyBytes []byte) []byte {
//解密pem格式的公钥
block, _ := pem.Decode(keyBytes)
if block == nil {
panic(errors.New("public key error"))
}
// 解析公钥
pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
panic(err)
}
// 类型断言
pub := pubInterface.(*rsa.PublicKey)
//加密
ciphertext, err := rsa.EncryptPKCS1v15(rand.Reader, pub, data)
if err != nil {
panic(err)
}
return ciphertext
}

// 解密
func RsaDecrypt(cipherText, privateKey []byte) ([]byte, error) {
block, _ := pem.Decode(privateKey)
if block == nil {
return nil, errors.New("private key error")
}
priv, err := x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
return nil, err
}
return rsa.DecryptPKCS1v15(rand.Reader, priv, cipherText)
}

// 从证书获取公钥
func OpensslPemGetPublic(pathOrString string) (interface{}, error) {
var certPem []byte
var err error
if IsFile(pathOrString) && Exists(pathOrString) {
certPem, err = ioutil.ReadFile(pathOrString)
if err != nil {
return nil, err
}
if string(certPem) == "" {
return nil, errors.New("empty pem file")
}
} else {
if pathOrString == "" {
return nil, errors.New("empty pem string")
}
certPem = StringToSlice(pathOrString)
}
block, rest := pem.Decode(certPem)
if block == nil || block.Type != "PUBLIC KEY" {
//log.Fatal("failed to decode PEM block containing public key")
return nil, errors.New("failed to decode PEM block containing public key")
}
pub, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Got a %T, with remaining data: %q", pub, rest)
return pub, nil
}

+ 23
- 0
app/utils/serialize.go View File

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

+ 48
- 0
app/utils/shuffle.go View File

@@ -0,0 +1,48 @@
package utils

import (
"math/rand"
"time"
)

// 打乱随机字符串
func ShuffleString(s *string) {
if len(*s) > 1 {
b := []byte(*s)
rand.Seed(time.Now().UnixNano())
rand.Shuffle(len(b), func(x, y int) {
b[x], b[y] = b[y], b[x]
})
*s = string(b)
}
}

// 打乱随机slice
func ShuffleSliceBytes(b []byte) {
if len(b) > 1 {
rand.Seed(time.Now().UnixNano())
rand.Shuffle(len(b), func(x, y int) {
b[x], b[y] = b[y], b[x]
})
}
}

// 打乱slice int
func ShuffleSliceInt(i []int) {
if len(i) > 1 {
rand.Seed(time.Now().UnixNano())
rand.Shuffle(len(i), func(x, y int) {
i[x], i[y] = i[y], i[x]
})
}
}

// 打乱slice interface
func ShuffleSliceInterface(i []interface{}) {
if len(i) > 1 {
rand.Seed(time.Now().UnixNano())
rand.Shuffle(len(i), func(x, y int) {
i[x], i[y] = i[y], i[x]
})
}
}

+ 125
- 0
app/utils/sign_check.go View File

@@ -0,0 +1,125 @@
package utils

import (
"applet/app/utils/logx"
"fmt"
"github.com/forgoer/openssl"
"github.com/gin-gonic/gin"
"github.com/syyongx/php2go"
"strings"
)

var publicKey = []byte(`-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCFQD7RL2tDNuwdg0jTfV0zjAzh
WoCWfGrcNiucy2XUHZZU2oGhHv1N10qu3XayTDD4pu4sJ73biKwqR6ZN7IS4Sfon
vrzaXGvrTG4kmdo3XrbrkzmyBHDLTsJvv6pyS2HPl9QPSvKDN0iJ66+KN8QjBpw1
FNIGe7xbDaJPY733/QIDAQAB
-----END PUBLIC KEY-----`)

var privateKey = []byte(`-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQCFQD7RL2tDNuwdg0jTfV0zjAzhWoCWfGrcNiucy2XUHZZU2oGh
Hv1N10qu3XayTDD4pu4sJ73biKwqR6ZN7IS4SfonvrzaXGvrTG4kmdo3Xrbrkzmy
BHDLTsJvv6pyS2HPl9QPSvKDN0iJ66+KN8QjBpw1FNIGe7xbDaJPY733/QIDAQAB
AoGADi14wY8XDY7Bbp5yWDZFfV+QW0Xi2qAgSo/k8gjeK8R+I0cgdcEzWF3oz1Q2
9d+PclVokAAmfj47e0AmXLImqMCSEzi1jDBUFIRoJk9WE1YstE94mrCgV0FW+N/u
+L6OgZcjmF+9dHKprnpaUGQuUV5fF8j0qp8S2Jfs3Sw+dOECQQCQnHALzFjmXXIR
Ez3VSK4ZoYgDIrrpzNst5Hh6AMDNZcG3CrCxlQrgqjgTzBSr3ZSavvkfYRj42STk
TqyX1tQFAkEA6+O6UENoUTk2lG7iO/ta7cdIULnkTGwQqvkgLIUjk6w8E3sBTIfw
rerTEmquw5F42HHE+FMrRat06ZN57lENmQJAYgUHlZevcoZIePZ35Qfcqpbo4Gc8
Fpm6vwKr/tZf2Vlt0qo2VkhWFS6L0C92m4AX6EQmDHT+Pj7BWNdS+aCuGQJBAOkq
NKPZvWdr8jNOV3mKvxqB/U0uMigIOYGGtvLKt5vkh42J7ILFbHW8w95UbWMKjDUG
X/hF3WQEUo//Imsa2yECQHSZIpJxiTRueoDiyRt0LH+jdbYFUu/6D0UIYXhFvP/p
EZX+hfCfUnNYX59UVpRjSZ66g0CbCjuBPOhmOD+hDeQ=
-----END RSA PRIVATE KEY-----`)

func GetApiVersion(c *gin.Context) int {
var apiVersion = c.GetHeader("apiVersion")
if StrToInt(apiVersion) == 0 { //没有版本号先不校验
apiVersion = c.GetHeader("Apiversion")
}
if StrToInt(apiVersion) == 0 { //没有版本号先不校验
apiVersion = c.GetHeader("api_version")
}
return StrToInt(apiVersion)
}

//签名校验
func SignCheck(c *gin.Context) bool {
var apiVersion = GetApiVersion(c)
if apiVersion == 0 { //没有版本号先不校验
return true
}
//1.通过rsa 解析出 aes
var key = c.GetHeader("key")

//拼接对应参数
var uri = c.Request.RequestURI
var query = GetQueryParam(uri)
fmt.Println(query)
query["timestamp"] = c.GetHeader("timestamp")
query["nonce"] = c.GetHeader("nonce")
query["key"] = key
token := c.GetHeader("Authorization")
if token != "" {
// 按空格分割
parts := strings.SplitN(token, " ", 2)
if len(parts) == 2 && parts[0] == "Bearer" {
token = parts[1]
}
}
query["token"] = token
//2.query参数按照 ASCII 码从小到大排序
str := JoinStringsInASCII(query, "&", false, false, "")
//3.拼上密钥
secret := ""
if InArr(c.GetHeader("platform"), []string{"android", "ios"}) {
secret = c.GetString("app_api_secret_key")
} else if c.GetHeader("platform") == "wap" {
secret = c.GetString("h5_api_secret_key")
} else {
secret = c.GetString("applet_api_secret_key")
}
str = fmt.Sprintf("%s&secret=%s", str, secret)
fmt.Println(str)
//4.md5加密 转小写
sign := strings.ToLower(Md5(str))
//5.判断跟前端传来的sign是否一致
if sign != c.GetHeader("sign") {
return false
}
return true
}

func ResultAes(c *gin.Context, raw []byte) string {
var key = c.GetHeader("key")
base, _ := php2go.Base64Decode(key)
aes, err := RsaDecrypt([]byte(base), privateKey)
if err != nil {
logx.Info(err)
return ""
}

str, _ := openssl.AesECBEncrypt(raw, aes, openssl.PKCS7_PADDING)
value := php2go.Base64Encode(string(str))
fmt.Println(value)

return value
}

func ResultAesDecrypt(c *gin.Context, raw string) string {
var key = c.GetHeader("key")
base, _ := php2go.Base64Decode(key)
aes, err := RsaDecrypt([]byte(base), privateKey)
if err != nil {
logx.Info(err)
return ""
}
fmt.Println(raw)
value1, _ := php2go.Base64Decode(raw)
if value1 == "" {
return ""
}
str1, _ := openssl.AesECBDecrypt([]byte(value1), aes, openssl.PKCS7_PADDING)

return string(str1)
}

+ 26
- 0
app/utils/slice.go View File

@@ -0,0 +1,26 @@
package utils

// ContainsString is 字符串是否包含在字符串切片里
func ContainsString(array []string, val string) (index int) {
index = -1
for i := 0; i < len(array); i++ {
if array[i] == val {
index = i
return
}
}
return
}

func PaginateSliceInt64(x []int64, skip int, size int) []int64 {
if skip > len(x) {
skip = len(x)
}

end := skip + size
if end > len(x) {
end = len(x)
}

return x[skip:end]
}

+ 47
- 0
app/utils/slice_and_string.go View File

@@ -0,0 +1,47 @@
package utils

import (
"fmt"
"reflect"
"strings"
"unsafe"
)

// string与slice互转,零copy省内存

// zero copy to change slice to string
func Slice2String(b []byte) (s string) {
pBytes := (*reflect.SliceHeader)(unsafe.Pointer(&b))
pString := (*reflect.StringHeader)(unsafe.Pointer(&s))
pString.Data = pBytes.Data
pString.Len = pBytes.Len
return
}

// no copy to change string to slice
func StringToSlice(s string) (b []byte) {
pBytes := (*reflect.SliceHeader)(unsafe.Pointer(&b))
pString := (*reflect.StringHeader)(unsafe.Pointer(&s))
pBytes.Data = pString.Data
pBytes.Len = pString.Len
pBytes.Cap = pString.Len
return
}

// 任意slice合并
func SliceJoin(sep string, elems ...interface{}) string {
l := len(elems)
if l == 0 {
return ""
}
if l == 1 {
s := fmt.Sprint(elems[0])
sLen := len(s) - 1
if s[0] == '[' && s[sLen] == ']' {
return strings.Replace(s[1:sLen], " ", sep, -1)
}
return s
}
sep = strings.Replace(fmt.Sprint(elems), " ", sep, -1)
return sep[1 : len(sep)-1]
}

+ 155
- 0
app/utils/string.go View File

@@ -0,0 +1,155 @@
package utils

import (
"fmt"
"github.com/syyongx/php2go"
"reflect"
"sort"
"strings"
)

func Implode(glue string, args ...interface{}) string {
data := make([]string, len(args))
for i, s := range args {
data[i] = fmt.Sprint(s)
}
return strings.Join(data, glue)
}

//字符串是否在数组里
func InArr(target string, str_array []string) bool {
for _, element := range str_array {
if target == element {
return true
}
}
return false
}

//把数组的值放到key里
func ArrayColumn(array interface{}, key string) (result map[string]interface{}, err error) {
result = make(map[string]interface{})
t := reflect.TypeOf(array)
v := reflect.ValueOf(array)
if t.Kind() != reflect.Slice {
return nil, nil
}
if v.Len() == 0 {
return nil, nil
}
for i := 0; i < v.Len(); i++ {
indexv := v.Index(i)
if indexv.Type().Kind() != reflect.Struct {
return nil, nil
}
mapKeyInterface := indexv.FieldByName(key)
if mapKeyInterface.Kind() == reflect.Invalid {
return nil, nil
}
mapKeyString, err := InterfaceToString(mapKeyInterface.Interface())
if err != nil {
return nil, err
}
result[mapKeyString] = indexv.Interface()
}
return result, err
}

//转string
func InterfaceToString(v interface{}) (result string, err error) {
switch reflect.TypeOf(v).Kind() {
case reflect.Int64, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32:
result = fmt.Sprintf("%v", v)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
result = fmt.Sprintf("%v", v)
case reflect.String:
result = v.(string)
default:
err = nil
}
return result, err
}

func HideTrueName(name string) string {
res := "**"
if name != "" {
runs := []rune(name)
leng := len(runs)
if leng <= 3 {
res = string(runs[0:1]) + res
} else if leng < 5 {
res = string(runs[0:2]) + res
} else if leng < 10 {
res = string(runs[0:2]) + "***" + string(runs[leng-2:leng])
} else if leng < 16 {
res = string(runs[0:3]) + "****" + string(runs[leng-3:leng])
} else {
res = string(runs[0:4]) + "*****" + string(runs[leng-4:leng])
}
}
return res
}
func GetQueryParam(uri string) map[string]string {
//根据问号分割路由还是query参数
uriList := strings.Split(uri, "?")
var query = make(map[string]string, 0)
//有参数才处理
if len(uriList) == 2 {
//分割query参数
var queryList = strings.Split(uriList[1], "&")
if len(queryList) > 0 {
//key value 分别赋值
for _, v := range queryList {
var valueList = strings.Split(v, "=")
if len(valueList) == 2 {
value, _ := php2go.URLDecode(valueList[1])
if value == "" {
value = valueList[1]
}
query[valueList[0]] = value
}
}
}
}
return query
}

//JoinStringsInASCII 按照规则,参数名ASCII码从小到大排序后拼接
//data 待拼接的数据
//sep 连接符
//onlyValues 是否只包含参数值,true则不包含参数名,否则参数名和参数值均有
//includeEmpty 是否包含空值,true则包含空值,否则不包含,注意此参数不影响参数名的存在
//exceptKeys 被排除的参数名,不参与排序及拼接
func JoinStringsInASCII(data map[string]string, sep string, onlyValues, includeEmpty bool, exceptKeys ...string) string {
var list []string
var keyList []string
m := make(map[string]int)
if len(exceptKeys) > 0 {
for _, except := range exceptKeys {
m[except] = 1
}
}
for k := range data {
if _, ok := m[k]; ok {
continue
}
value := data[k]
if !includeEmpty && value == "" {
continue
}
if onlyValues {
keyList = append(keyList, k)
} else {
list = append(list, fmt.Sprintf("%s=%s", k, value))
}
}
if onlyValues {
sort.Strings(keyList)
for _, v := range keyList {
list = append(list, AnyToString(data[v]))
}
} else {
sort.Strings(list)
}
return strings.Join(list, sep)
}

+ 241
- 0
app/utils/time.go View File

@@ -0,0 +1,241 @@
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 Time2String(date time.Time, format string) string {
if format == "" {
format = "2006-01-02 15:04:05"
}
timeS := date.Format(format)
if timeS == "0001-01-01 00:00:00" {
return ""
}
return timeS
}

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", 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 = time.Date(t.Year(), t.Month(), 0, 0, 0, 0, 0, t.Location())
etime = time.Date(t.Year(), t.Month()+1, 0, 0, 0, 0, 0, t.Location())
case "last_month":
stime = time.Date(t.Year(), t.Month()-1, 0, 0, 0, 0, 0, t.Location())
etime = time.Date(t.Year(), t.Month(), 0, 0, 0, 0, 0, t.Location())
}

return map[string]int64{
"start": stime.Unix(),
"end": etime.Unix(),
}
}

// 获取特定时间范围
func GetDateTimeRangeStr(s string) (string, string) {
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 = time.Date(t.Year(), t.Month(), 0, 0, 0, 0, 0, t.Location())
etime = time.Date(t.Year(), t.Month()+1, 0, 0, 0, 0, 0, t.Location())
case "last_month":
stime = time.Date(t.Year(), t.Month()-1, 0, 0, 0, 0, 0, t.Location())
etime = time.Date(t.Year(), t.Month(), 0, 0, 0, 0, 0, t.Location())
}

return stime.Format("2006-01-02 15:04:05"), etime.Format("2006-01-02 15:04:05")
}

//获取传入的时间所在月份的第一天,即某月第一天的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 ConvertWechatTime(wechatTime string) (string, error) {
const layout = time.RFC3339
parsedTime, err := time.Parse(layout, wechatTime)
if err != nil {
return "", err
}
// 转换到本地时区
localTime := parsedTime.In(time.Local)
// 格式化本地时间为指定的格式,例如:"2006-01-02 15:04:05"

formattedLocalTime := localTime.Format("2006-01-02 15:04:05")

// 返回转换后的时间字符串
return formattedLocalTime, nil
}

+ 16
- 0
app/utils/url.go View File

@@ -0,0 +1,16 @@
package utils

import (
"net/url"
"strings"
)

func UriFilterExcludeQueryString(uri string) string {
URL, _ := url.Parse(uri)

clearUri := strings.ReplaceAll(uri, URL.RawQuery, "")

clearUri = strings.TrimRight(clearUri, "?")

return strings.TrimRight(clearUri, "/")
}

+ 76
- 0
app/utils/uuid.go View File

@@ -0,0 +1,76 @@
package utils

import (
"github.com/sony/sonyflake"

"applet/app/utils/logx"
"fmt"
"math/rand"
"time"
)

const (
KC_RAND_KIND_NUM = 0 // 纯数字
KC_RAND_KIND_LOWER = 1 // 小写字母
KC_RAND_KIND_UPPER = 2 // 大写字母
KC_RAND_KIND_ALL = 3 // 数字、大小写字母
)

func newUUID() *[16]byte {
u := &[16]byte{}
rand.Read(u[:16])
u[8] = (u[8] | 0x80) & 0xBf
u[6] = (u[6] | 0x40) & 0x4f
return u
}

func UUIDString() string {
u := newUUID()
return fmt.Sprintf("%x-%x-%x-%x-%x", u[:4], u[4:6], u[6:8], u[8:10], u[10:])
}

func UUIDHexString() string {
u := newUUID()
return fmt.Sprintf("%x%x%x%x%x", u[:4], u[4:6], u[6:8], u[8:10], u[10:])
}
func UUIDBinString() string {
u := newUUID()
return fmt.Sprintf("%s", [16]byte(*u))
}

func Krand(size int, kind int) []byte {
ikind, kinds, result := kind, [][]int{[]int{10, 48}, []int{26, 97}, []int{26, 65}}, make([]byte, size)
isAll := kind > 2 || kind < 0
rand.Seed(time.Now().UnixNano())
for i := 0; i < size; i++ {
if isAll { // random ikind
ikind = rand.Intn(3)
}
scope, base := kinds[ikind][0], kinds[ikind][1]
result[i] = uint8(base + rand.Intn(scope))
}
return result
}

// OrderUUID is only num for uuid
func OrderUUID(uid int) string {
ustr := IntToStr(uid)
tstr := Int64ToStr(time.Now().Unix())
ulen := len(ustr)
tlen := len(tstr)
rlen := 18 - ulen - tlen
krb := Krand(rlen, KC_RAND_KIND_NUM)
return ustr + tstr + string(krb)
}

var flake *sonyflake.Sonyflake

func GenId() int64 {

id, err := flake.NextID()
if err != nil {
_ = logx.Errorf("flake.NextID() failed with %s\n", err)
panic(err)
}
return int64(id)
}

+ 55
- 0
app/utils/validator_err_trans.go View File

@@ -0,0 +1,55 @@
package utils

import (
"fmt"
"github.com/gin-gonic/gin/binding"
"github.com/go-playground/locales/en"
"github.com/go-playground/locales/zh"
ut "github.com/go-playground/universal-translator"
"github.com/go-playground/validator/v10"
enTranslations "github.com/go-playground/validator/v10/translations/en"
chTranslations "github.com/go-playground/validator/v10/translations/zh"
"reflect"
)

var ValidatorTrans ut.Translator

// ValidatorTransInit 验证器错误信息翻译初始化
// local 通常取决于 http 请求头的 'Accept-Language'
func ValidatorTransInit(local string) (err error) {
if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
zhT := zh.New() //chinese
enT := en.New() //english
uni := ut.New(enT, zhT, enT)

var o bool
ValidatorTrans, o = uni.GetTranslator(local)
if !o {
return fmt.Errorf("uni.GetTranslator(%s) failed", local)
}
// 注册一个方法,从自定义标签label中获取值(用在把字段名映射为中文)
v.RegisterTagNameFunc(func(field reflect.StructField) string {
label := field.Tag.Get("label")
if label == "" {
return field.Name
}
return label
})
// 注册翻译器
switch local {
case "en":
err = enTranslations.RegisterDefaultTranslations(v, ValidatorTrans)
case "zh":
err = chTranslations.RegisterDefaultTranslations(v, ValidatorTrans)
default:
err = enTranslations.RegisterDefaultTranslations(v, ValidatorTrans)
}
return
}
return
}

// ValidatorTransInitZh 验证器错误信息翻译为中文初始化
func ValidatorTransInitZh() (err error) {
return ValidatorTransInit("zh")
}

+ 31
- 0
app/utils/wx.go View File

@@ -0,0 +1,31 @@
package utils

import (
"crypto/sha1"
"encoding/hex"
"sort"
"strings"
)

// CheckSignature 微信公众号签名检查
func CheckSignature(signature, timestamp, nonce, token string) bool {
arr := []string{timestamp, nonce, token}
// 字典序排序
sort.Strings(arr)

n := len(timestamp) + len(nonce) + len(token)
var b strings.Builder
b.Grow(n)
for i := 0; i < len(arr); i++ {
b.WriteString(arr[i])
}

return Sha1(b.String()) == signature
}

// 进行Sha1编码
func Sha1(str string) string {
h := sha1.New()
h.Write([]byte(str))
return hex.EncodeToString(h.Sum(nil))
}

+ 2
- 0
bin/.gitignore View File

@@ -0,0 +1,2 @@
*
!.gitignore

+ 18
- 0
build.sh View File

@@ -0,0 +1,18 @@
echo "update -> repo"
git fetch
git reset --hard origin/master
echo "update repo -> Success"

id="git rev-parse --short HEAD"
export ZYOS_APP_COMMIT_ID=`eval $id`
echo "GET the Commit ID for git -> $ZYOS_APP_COMMIT_ID"

echo "Start build image "

image_name=registry-vpc.cn-shenzhen.aliyuncs.com/fnuoos-prd/zyos-mall:${ZYOS_APP_COMMIT_ID}
#final_image_name=registry.cn-shenzhen.aliyuncs.com/fnuoos-prd/zyos:${ZYOS_APP_COMMIT_ID}
docker build -t ${image_name} .

docker push ${image_name}
echo "Push image -> $image_name Success"
export ZYOS_APP_LATEST_VERSION=${image_name}

+ 12
- 0
cmd_run.bat View File

@@ -0,0 +1,12 @@
@echo off

set BasePath=%~dp0
set APP=applet.exe
set CfgPath=%BasePath%\etc\cfg.yml

del %BasePath%\bin\%APP%

go build -o %BasePath%\bin\%APP% %BasePath%\cmd\main.go && %BasePath%\bin\%APP% -c=%CfgPath%


pause

+ 8
- 0
cmd_run.sh View File

@@ -0,0 +1,8 @@
#!/bin/bash
APP=applet
BasePath=$(dirname $(readlink -f $0))
CfgPath=$BasePath/etc/cfg.yml
cd $BasePath
rm -rf $BasePath/bin/$APP
go build -o $BasePath/bin/$APP $BasePath/main.go \
&& $BasePath/bin/$APP -c=$CfgPath

+ 13
- 0
cmd_task.bat View File

@@ -0,0 +1,13 @@
@echo off

set Name=task
set BasePath=%~dp0
set APP=%Name%.exe
set CfgPath=%BasePath%etc\%Name%.yml

del %BasePath%\bin\%APP%

go build -o %BasePath%\bin\%APP% %BasePath%\cmd\%Name%\main.go && %BasePath%\bin\%APP% -c=%CfgPath%


pause

+ 9
- 0
cmd_task.sh View File

@@ -0,0 +1,9 @@
#!/bin/bash

APP=task
BasePath=$(dirname $(readlink -f $0))
CfgPath=$BasePath/etc/task.yml
cd $BasePath
rm -rf $BasePath/bin/$APP
go build -o $BasePath/bin/$APP $BasePath/cmd/$APP/main.go \
&& $BasePath/bin/$APP -c=$CfgPath

+ 45
- 0
consume/init.go View File

@@ -0,0 +1,45 @@
package consume

import (
"applet/app/utils/logx"
consumeMd "applet/consume/md"
"time"
)

var (
jobs = map[string]func(consumeMd.MqQueue){}
)

func Init() {
// 初始化任务列表
initConsumes()
}

// 增加消费任务队列
func initConsumes() {
//////////////////////////////////////// ORDER /////////////////////////////////////////////////////
jobs[consumeMd.JudgePackageOrdStateQueueConsumeFunName] = JudgePackageOrdStateQueueConsume
}

func Run() {
for _, v := range consumeMd.RabbitMqQueueKeyList {
if _, ok := jobs[v.ConsumeFunName]; ok {
go doConsume(v.ConsumeFunName, *v)()
}
}
}

func doConsume(fnName string, queue consumeMd.MqQueue) func() {
return func() {
begin := time.Now().Local()
jobs[fnName](queue)
end := time.Now().Local()
logx.Infof(
"[%s] AutoConsume started at <%s>, ended at <%s> duration <%s>",
fnName,
begin.Format("2006-01-02 15:04:05.000"),
end.Format("2006-01-02 15:04:05.000"),
time.Duration(end.UnixNano()-begin.UnixNano()).String(),
)
}
}

+ 27
- 0
consume/md/consume_key.go View File

@@ -0,0 +1,27 @@
package md

type MqQueue struct {
ExchangeName string `json:"exchangeName"` //交换机名字
Name string `json:"name"` //队列名字
Type string `json:"type"` //队列类型
IsPersistent bool `json:"is_persistent"` //队列是否持久化
RoutKey string `json:"rout_key"` //路由
BindKey string `json:"bind_key"` //绑定的路由
ConsumeFunName string `json:"consume_fun_name"` //消费方法
}

var RabbitMqQueueKeyList = []*MqQueue{
{
ExchangeName: "order",
Name: "judge_package_ord_state_queue",
Type: TopicQueueType,
IsPersistent: false,
RoutKey: "judge_package_ord_state",
BindKey: "",
ConsumeFunName: "JudgePackageOrdStateQueueConsume",
},
}

const (
JudgePackageOrdStateQueueConsumeFunName = "JudgePackageOrdStateQueueConsume"
)

+ 11
- 0
consume/md/md_order.go View File

@@ -0,0 +1,11 @@
package md

const OrdExchange = "order"

const (
OrdRoutKeyForJudgePackageOrdOrdState = "judge_package_ord_state" //订单状态
)

type JudgePackageOrdOrdState struct {
OrdNo string `json:"ord_no"`
}

+ 38
- 0
consume/md/mq.go View File

@@ -0,0 +1,38 @@
package md

import "github.com/streadway/amqp"

const (
SimpleQueueType = "SimpleQueue"
BroadQueueType = "BroadQueue"
DirectQueueType = "DirectQueue"
TopicQueueType = "TopicQueue"
FanOutQueueType = "FanOutQueue"
)

type MsgClient struct {
Conn *amqp.Connection
Type string `json:"type"` //消息类型
Data string `json:"data"` //队列数据
}

type SimpleQueue struct {
RoutKey string `json:"rout_key"` //路由
Queue string `json:"queue"` //队列的名字
IsPersistent bool `json:"is_persistent"` //队列是否持久化
}

type ComplexQueue struct {
ExchangeName string `json:"exchangeName"`
RoutKey string `json:"rout_key"` //路由
Queue string `json:"queue"` //队列的名字
IsPersistent bool `json:"is_persistent"` //队列是否持久化
}

type TopicQueue struct {
ExchangeName string `json:"exchangeName"`
RoutKey string `json:"rout_key"` //路由
Queue string `json:"queue"` //队列的名字
IsPersistent bool `json:"is_persistent"` //队列是否持久化
BindKey string `json:"bind_key"` //绑定的路由
}

+ 68
- 0
consume/one_circles_sign_in_consume.go View File

@@ -0,0 +1,68 @@
package consume

import (
svc "applet/app/admin/svc/enterprise_manage"
"applet/app/cfg"
"applet/app/utils"
"applet/app/utils/logx"
"applet/consume/md"
"code.fnuoos.com/go_rely_warehouse/zyos_go_mq.git/rabbit"
"code.fnuoos.com/go_rely_warehouse/zyos_go_order_relate_rule.git/rule/one_circles"
"encoding/json"
"errors"
"fmt"
"github.com/streadway/amqp"
)

func JudgePackageOrdStateQueueConsume(queue md.MqQueue) {
fmt.Println(">>>>>>>>>>>>JudgePackageOrdStateQueueConsume>>>>>>>>>>>>")
ch, err := rabbit.Cfg.Pool.GetChannel()
if err != nil {
logx.Error(err)
return
}
defer ch.Release()
//1、将自己绑定到交换机上
ch.Bind(queue.Name, queue.ExchangeName, queue.RoutKey)
//2、取出数据进行消费
ch.Qos(5)
delivery := ch.Consume(queue.Name, false)

one_circles.Init(cfg.RedisAddr)

var res amqp.Delivery
var ok bool
for {
res, ok = <-delivery
if ok == true {
err = handleJudgePackageOrdStateQueueConsume(ch, res.Body)
if err != nil {
fmt.Println("err ::: ", err)
utils.FilePutContents("JudgePackageOrdStateQueueConsume", "[err]:"+err.Error())
//_ = res.Reject(true) //TODO::拒绝 Ack
_ = res.Reject(false)
} else {
_ = res.Ack(true)
}
} else {
panic(errors.New("error getting message"))
}
}
fmt.Println("get msg done")
}

func handleJudgePackageOrdStateQueueConsume(ch *rabbit.Channel, msgData []byte) error {
//1、解析mq中queue的数据结构体
var msg *md.JudgePackageOrdOrdState
err := json.Unmarshal(msgData, &msg)
if err != nil {
return err
}

err = svc.DealJudgePackageOrdOrdState(msg.OrdNo)
fmt.Println("err::::", err)
if err != nil {
return err
}
return nil
}

BIN
View File


+ 103
- 0
es/md/es_mapping.go View File

@@ -0,0 +1,103 @@
package md

const ZhiosOrdersEsIndex = "zhios_orders"
const ZhiosOrdersEsMapping = `
{
"settings" : {
"number_of_shards" : 2,
"number_of_replicas" : 1
},
"mappings":{
"properties":{
"master_id":{
"type": "integer"
},
"ord_id":{
"type": "keyword"
},
"main_ord_id":{
"type": "keyword"
},
"store_ord_id":{
"type": "keyword"
},
"goods_id":{
"type": "keyword"
},
"uid":{
"type": "integer"
},
"buyer_phone":{
"type": "keyword"
},
"cost_price":{
"type": "float"
},
"state":{
"type": "integer"
},
"state_zh":{
"type": "keyword"
},
"pay_time":{
"type": "date",
"format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"
},
"pay_channel":{
"type": "integer"
},
"pay_channel_zh":{
"type": "keyword"
},
"receiver_phone":{
"type": "keyword"
},
"receiver_name":{
"type": "keyword"
},
"receiver_address_detail":{
"type": "text",
"analyzer": "ik_smart"
},
"province_id":{
"type": "keyword"
},
"city_id":{
"type": "keyword"
},
"county_id":{
"type": "keyword"
},
"province":{
"type": "keyword"
},
"city":{
"type": "keyword"
},
"county":{
"type": "keyword"
},
"order_type":{
"type": "integer"
},
"estimate_commission":{
"type": "float"
},
"logistic_company":{
"type": "keyword"
},
"ord_create_time":{
"type": "date",
"format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"
},
"created_at":{
"type": "date",
"format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"
},
"updated_at":{
"type": "date",
"format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"
}
}
}
}`

+ 35
- 0
es/md/es_struct.go View File

@@ -0,0 +1,35 @@
package md

type ZhiosOrdersEs struct {
MasterId int `json:"master_id"`
OrdKind string `json:"ord_kind"`
OrdId string `json:"ord_id"`
MainOrdId string `json:"main_ord_id"`
StoreOrdId string `json:"store_ord_id"`
GoodsId string `json:"goods_id"`
Uid string `json:"uid"`
BuyerPhone string `json:"buyer_phone"`
CostPrice float64 `json:"cost_price"`
Gmv float64 `json:"gmv"`
State int32 `json:"state"`
StateZh string `json:"state_zh"`
PayTime interface{} `json:"pay_time"`
PayChannel int32 `json:"pay_channel"`
GoodsNum int `json:"goods_num"`
PayChannelZh string `json:"pay_channel_zh"`
ReceiverPhone string `json:"receiver_phone"`
ReceiverName string `json:"receiver_name"`
ReceiverAddressDetail string `json:"receiver_address_detail"`
ProvinceId string `json:"province_id"`
CityId string `json:"city_id"`
CountyId string `json:"county_id"`
Province string `json:"province"`
City string `json:"city"`
County string `json:"county"`
OrderType int32 `json:"order_type"`
EstimateCommission float64 `json:"estimate_commission"`
LogisticCompany string `json:"logistic_company"`
OrdCreateTime string `json:"ord_create_time"`
CreatedAt string `json:"created_at"`
UpdatedAt string `json:"updated_at"`
}

+ 7
- 0
etc/db_tpl/config View File

@@ -0,0 +1,7 @@
lang=go
genJson=1
prefix=cos_
ignoreColumnsJSON=
created=
updated=
deleted=

+ 17
- 0
etc/db_tpl/struct.go.tpl View File

@@ -0,0 +1,17 @@
package {{.Models}}

{{$ilen := len .Imports}}
{{if gt $ilen 0}}
import (
{{range .Imports}}"{{.}}"{{end}}
)
{{end}}

{{range .Tables}}
type {{Mapper .Name}} struct {
{{$table := .}}
{{range .ColumnsSeq}}{{$col := $table.GetColumn .}} {{Mapper $col.Name}} {{Type $col}} {{Tag $table $col}}
{{end}}
}
{{end}}


+ 37
- 0
etc/task.yml View File

@@ -0,0 +1,37 @@
# debug release test
debug: true
prd: false
local: true
# 缓存
redis_addr: '120.24.28.6:32572'

app_comm:
url: http://127.0.0.1:5003


admin:
api_aes_key: e{&[^<wpliI$AgKs:>Ft(.~g]1eR-]VO
api_aes_iv: ZV`7<5X]/2brS@sz
# 数据库
db:
host: '119.23.182.117:3306'
name: 'zyos_website'
user: 'root'
psw: 'Fnuo123com@'
show_log: true
max_lifetime: 30
max_open_conns: 100
max_idle_conns: 100
path: 'tmp/task_sql_%v.log'

# 日志
log:
level: 'debug' # 普通日志级别 #debug, info, warn, fatal, panic
is_stdout: true
time_format: 'standard' # sec, second, milli, nano, standard, iso
encoding: 'console'
is_file_out: true
file_dir: './tmp/'
file_max_size: 256
file_max_age: 1
file_name: 'task.log'

+ 113
- 0
go.mod View File

@@ -0,0 +1,113 @@
module applet

go 1.18

// go.mod文件中

require (
code.fnuoos.com/go_rely_warehouse/zyos_go_es.git v1.0.0
code.fnuoos.com/go_rely_warehouse/zyos_go_mq.git v0.0.5
code.fnuoos.com/go_rely_warehouse/zyos_go_order_relate_rule.git v1.9.10-0.20240903060255-62e7a9ea46fe
github.com/360EntSecGroup-Skylar/excelize v1.4.1
github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751
github.com/boombuler/barcode v1.0.1
github.com/chromedp/chromedp v0.10.0
github.com/dchest/uniuri v0.0.0-20200228104902-7aecb25e1fe5
github.com/dgrijalva/jwt-go v3.2.0+incompatible
github.com/forgoer/openssl v1.2.1
github.com/gin-contrib/sessions v1.0.0
github.com/gin-gonic/gin v1.9.1
github.com/go-playground/locales v0.14.1
github.com/go-playground/universal-translator v0.18.1
github.com/go-playground/validator/v10 v10.19.0
github.com/go-redis/redis v6.15.9+incompatible
github.com/go-sql-driver/mysql v1.8.1
github.com/gomodule/redigo v2.0.0+incompatible
github.com/iGoogle-ink/gopay v1.5.36
github.com/jinzhu/copier v0.4.0
github.com/makiuchi-d/gozxing v0.1.1
github.com/mcuadros/go-defaults v1.2.0
github.com/medivhzhan/weapp/v2 v2.5.0
github.com/mingrammer/commonregex v1.0.1
github.com/qiniu/api.v7/v7 v7.8.2
github.com/robfig/cron/v3 v3.0.1
github.com/shopspring/decimal v1.3.1
github.com/sony/sonyflake v1.0.0
github.com/streadway/amqp v1.0.0
github.com/swaggo/swag v1.7.0
github.com/syyongx/php2go v0.9.8
github.com/wechatpay-apiv3/wechatpay-go v0.2.20
go.uber.org/zap v1.16.0
google.golang.org/grpc v1.33.2
google.golang.org/protobuf v1.33.0
gopkg.in/natefinch/lumberjack.v2 v2.2.1
gopkg.in/yaml.v2 v2.4.0
xorm.io/xorm v1.3.2
)

require (
filippo.io/edwards25519 v1.1.0 // indirect
github.com/KyleBanks/depth v1.2.1 // indirect
github.com/PuerkitoBio/purell v1.1.1 // indirect
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
github.com/bytedance/sonic v1.11.3 // indirect
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect
github.com/chenzhuoyu/iasm v0.9.1 // indirect
github.com/chromedp/cdproto v0.0.0-20240801214329-3f85d328b335 // indirect
github.com/chromedp/sysutil v1.0.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-openapi/jsonpointer v0.19.5 // indirect
github.com/go-openapi/jsonreference v0.19.5 // indirect
github.com/go-openapi/spec v0.20.3 // indirect
github.com/go-openapi/swag v0.19.15 // indirect
github.com/gobwas/httphead v0.1.0 // indirect
github.com/gobwas/pool v0.2.1 // indirect
github.com/gobwas/ws v1.4.0 // indirect
github.com/goccy/go-json v0.10.2 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/google/go-cmp v0.5.9 // indirect
github.com/gookit/color v1.3.6 // indirect
github.com/gorilla/context v1.1.2 // indirect
github.com/gorilla/securecookie v1.1.2 // indirect
github.com/gorilla/sessions v1.2.2 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
github.com/kr/pretty v0.3.1 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
github.com/olivere/elastic/v7 v7.0.32 // indirect
github.com/onsi/ginkgo v1.16.5 // indirect
github.com/onsi/gomega v1.19.0 // indirect
github.com/pelletier/go-toml/v2 v2.2.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/syndtr/goleveldb v1.0.0 // indirect
github.com/tidwall/gjson v1.14.1 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.0 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.12 // indirect
go.uber.org/atomic v1.7.0 // indirect
go.uber.org/multierr v1.6.0 // indirect
golang.org/x/arch v0.7.0 // indirect
golang.org/x/crypto v0.21.0 // indirect
golang.org/x/lint v0.0.0-20200302205851-738671d3881b // indirect
golang.org/x/net v0.22.0 // indirect
golang.org/x/sync v0.6.0 // indirect
golang.org/x/sys v0.22.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/tools v0.6.0 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
honnef.co/go/tools v0.0.1-2020.1.4 // indirect
xorm.io/builder v0.3.11-0.20220531020008-1bd24a7dc978 // indirect
)

+ 55
- 0
k8s/zyos-go-mq-consume-prd.yaml View File

@@ -0,0 +1,55 @@
kind: Deployment
apiVersion: apps/v1
# 元数据
metadata:
name: zyos-go-mq-consume-one-circles-v2
namespace: zhios
labels:
app: zyos-go-mq-consume-one-circles-v2
annotations:
kubesphere.io/creator: dengbiao
kubesphere.io/description: 一个圈圈v2
# deployment主要部分
spec:
replicas: 1
selector:
matchLabels:
# 名称与上面的labels对应
app: zyos-go-mq-consume-one-circles-v2
template:
metadata:
labels:
# 名称与上面的matchLabels对应
app: zyos-go-mq-consume-one-circles-v2
spec:
# 声明挂载卷(将外部已存在的pvc、config等挂载进来)
volumes:
# 用于时区校正
- name: host-time
hostPath:
path: /etc/localtime
type: ''
# 将前面创建的configMap也挂载进来
- name: zyos-go-mq-consume-cfg
configMap:
# 这里的名字就是前面创建的configMap的名字
name: zyos-go-mq-consume-cfg
defaultMode: 420
containers:
# 主容器
- name: zyos-go-mq-consume-one-circles-v2-container
# 镜像地址(提前打包好并推送的镜像仓库)
image: 'registry.cn-shenzhen.aliyuncs.com/fnuoos-prd/zyos-go-mq-consume-one-circles-v2:20240727-01'
# 将前面volume声明的需要用到的pvc、config挂载上来
volumeMounts:
- name: host-time
readOnly: true
mountPath: /etc/localtime
- name: zyos-go-mq-consume-cfg # 该名字对应前面volumes声明的名字
readOnly: true
# 挂载到容器的哪个路径
mountPath: /var/zyos
imagePullPolicy: Always
restartPolicy: Always
terminationGracePeriodSeconds: 30
dnsPolicy: ClusterFirst

+ 45
- 0
main.go View File

@@ -0,0 +1,45 @@
package main

import (
"applet/app/cfg"
"applet/app/db"
"applet/app/utils"
"applet/app/utils/logx"
"applet/consume"
"fmt"
"os"
"os/signal"
"syscall"
)

// 系统初始化
func init() {
cfg.InitCfg() //配置初始化
cfg.InitLog() //日志初始化
cfg.InitCache() //缓存初始化
cfg.InitMq() //队列初始化
if cfg.Debug { //判断是否是debug
if err := db.InitDB(cfg.DB); err != nil { //主数据库初始化
panic(err)
}
}
fmt.Println("init success")
}

func main() {
if cfg.CurlDebug {
utils.CurlDebug = true
}

go func() {
// 初始化
consume.Init()
consume.Run()
}()

quit := make(chan os.Signal)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
<-quit
_ = logx.Info("Server exiting...")

}

+ 1607
- 0
pkg/pb/im.business.ext.pb.go
File diff suppressed because it is too large
View File


+ 595
- 0
pkg/pb/im.business.int.pb.go View File

@@ -0,0 +1,595 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.28.1
// protoc v3.20.0--rc1
// source: im.business.int.proto

package pb

import (
context "context"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)

const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)

type MasterAuthReq struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields

MasterId string `protobuf:"bytes,1,opt,name=master_id,json=masterId,proto3" json:"master_id,omitempty"`
}

func (x *MasterAuthReq) Reset() {
*x = MasterAuthReq{}
if protoimpl.UnsafeEnabled {
mi := &file_business_int_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}

func (x *MasterAuthReq) String() string {
return protoimpl.X.MessageStringOf(x)
}

func (*MasterAuthReq) ProtoMessage() {}

func (x *MasterAuthReq) ProtoReflect() protoreflect.Message {
mi := &file_business_int_proto_msgTypes[0]
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 MasterAuthReq.ProtoReflect.Descriptor instead.
func (*MasterAuthReq) Descriptor() ([]byte, []int) {
return file_business_int_proto_rawDescGZIP(), []int{0}
}

func (x *MasterAuthReq) GetMasterId() string {
if x != nil {
return x.MasterId
}
return ""
}

type AuthReq struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields

UserId int64 `protobuf:"varint,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"`
DeviceId int64 `protobuf:"varint,2,opt,name=device_id,json=deviceId,proto3" json:"device_id,omitempty"`
Token string `protobuf:"bytes,3,opt,name=token,proto3" json:"token,omitempty"`
}

func (x *AuthReq) Reset() {
*x = AuthReq{}
if protoimpl.UnsafeEnabled {
mi := &file_business_int_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}

func (x *AuthReq) String() string {
return protoimpl.X.MessageStringOf(x)
}

func (*AuthReq) ProtoMessage() {}

func (x *AuthReq) ProtoReflect() protoreflect.Message {
mi := &file_business_int_proto_msgTypes[1]
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 AuthReq.ProtoReflect.Descriptor instead.
func (*AuthReq) Descriptor() ([]byte, []int) {
return file_business_int_proto_rawDescGZIP(), []int{1}
}

func (x *AuthReq) GetUserId() int64 {
if x != nil {
return x.UserId
}
return 0
}

func (x *AuthReq) GetDeviceId() int64 {
if x != nil {
return x.DeviceId
}
return 0
}

func (x *AuthReq) GetToken() string {
if x != nil {
return x.Token
}
return ""
}

type GetUsersReq struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields

UserIds map[int64]int32 `protobuf:"bytes,1,rep,name=user_ids,json=userIds,proto3" json:"user_ids,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"` // 用户id
}

func (x *GetUsersReq) Reset() {
*x = GetUsersReq{}
if protoimpl.UnsafeEnabled {
mi := &file_business_int_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}

func (x *GetUsersReq) String() string {
return protoimpl.X.MessageStringOf(x)
}

func (*GetUsersReq) ProtoMessage() {}

func (x *GetUsersReq) ProtoReflect() protoreflect.Message {
mi := &file_business_int_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 GetUsersReq.ProtoReflect.Descriptor instead.
func (*GetUsersReq) Descriptor() ([]byte, []int) {
return file_business_int_proto_rawDescGZIP(), []int{2}
}

func (x *GetUsersReq) GetUserIds() map[int64]int32 {
if x != nil {
return x.UserIds
}
return nil
}

type GetUsersResp struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields

Users map[int64]*User `protobuf:"bytes,1,rep,name=users,proto3" json:"users,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` // 用户信息
}

func (x *GetUsersResp) Reset() {
*x = GetUsersResp{}
if protoimpl.UnsafeEnabled {
mi := &file_business_int_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}

func (x *GetUsersResp) String() string {
return protoimpl.X.MessageStringOf(x)
}

func (*GetUsersResp) ProtoMessage() {}

func (x *GetUsersResp) ProtoReflect() protoreflect.Message {
mi := &file_business_int_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 GetUsersResp.ProtoReflect.Descriptor instead.
func (*GetUsersResp) Descriptor() ([]byte, []int) {
return file_business_int_proto_rawDescGZIP(), []int{3}
}

func (x *GetUsersResp) GetUsers() map[int64]*User {
if x != nil {
return x.Users
}
return nil
}

var File_business_int_proto protoreflect.FileDescriptor

var file_business_int_proto_rawDesc = []byte{
0x0a, 0x12, 0x62, 0x75, 0x73, 0x69, 0x6e, 0x65, 0x73, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x12, 0x02, 0x70, 0x62, 0x1a, 0x10, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e,
0x2e, 0x65, 0x78, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x12, 0x62, 0x75, 0x73, 0x69,
0x6e, 0x65, 0x73, 0x73, 0x2e, 0x65, 0x78, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x2c,
0x0a, 0x0d, 0x4d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x41, 0x75, 0x74, 0x68, 0x52, 0x65, 0x71, 0x12,
0x1b, 0x0a, 0x09, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01,
0x28, 0x09, 0x52, 0x08, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x49, 0x64, 0x22, 0x55, 0x0a, 0x07,
0x41, 0x75, 0x74, 0x68, 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,
0x12, 0x1b, 0x0a, 0x09, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20,
0x01, 0x28, 0x03, 0x52, 0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x12, 0x14, 0x0a,
0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f,
0x6b, 0x65, 0x6e, 0x22, 0x82, 0x01, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x73,
0x52, 0x65, 0x71, 0x12, 0x37, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x73, 0x18,
0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73,
0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x73, 0x45, 0x6e,
0x74, 0x72, 0x79, 0x52, 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x73, 0x1a, 0x3a, 0x0a, 0x0c,
0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03,
0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14,
0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x76,
0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x85, 0x01, 0x0a, 0x0c, 0x47, 0x65, 0x74,
0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x12, 0x31, 0x0a, 0x05, 0x75, 0x73, 0x65,
0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65,
0x74, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x73,
0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x1a, 0x42, 0x0a, 0x0a,
0x55, 0x73, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65,
0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x1e, 0x0a, 0x05,
0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x08, 0x2e, 0x70, 0x62,
0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01,
0x32, 0xb4, 0x01, 0x0a, 0x0b, 0x42, 0x75, 0x73, 0x69, 0x6e, 0x65, 0x73, 0x73, 0x49, 0x6e, 0x74,
0x12, 0x2a, 0x0a, 0x0a, 0x4d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x41, 0x75, 0x74, 0x68, 0x12, 0x11,
0x2e, 0x70, 0x62, 0x2e, 0x4d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x41, 0x75, 0x74, 0x68, 0x52, 0x65,
0x71, 0x1a, 0x09, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x1e, 0x0a, 0x04,
0x41, 0x75, 0x74, 0x68, 0x12, 0x0b, 0x2e, 0x70, 0x62, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x52, 0x65,
0x71, 0x1a, 0x09, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 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, 0x2d, 0x0a, 0x08, 0x47, 0x65, 0x74, 0x55,
0x73, 0x65, 0x72, 0x73, 0x12, 0x0f, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65,
0x72, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x10, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73,
0x65, 0x72, 0x73, 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 (
file_business_int_proto_rawDescOnce sync.Once
file_business_int_proto_rawDescData = file_business_int_proto_rawDesc
)

func file_business_int_proto_rawDescGZIP() []byte {
file_business_int_proto_rawDescOnce.Do(func() {
file_business_int_proto_rawDescData = protoimpl.X.CompressGZIP(file_business_int_proto_rawDescData)
})
return file_business_int_proto_rawDescData
}

var file_business_int_proto_msgTypes = make([]protoimpl.MessageInfo, 6)
var file_business_int_proto_goTypes = []interface{}{
(*MasterAuthReq)(nil), // 0: pb.MasterAuthReq
(*AuthReq)(nil), // 1: pb.AuthReq
(*GetUsersReq)(nil), // 2: pb.GetUsersReq
(*GetUsersResp)(nil), // 3: pb.GetUsersResp
nil, // 4: pb.GetUsersReq.UserIdsEntry
nil, // 5: pb.GetUsersResp.UsersEntry
(*User)(nil), // 6: pb.User
(*GetUserReq)(nil), // 7: pb.GetUserReq
(*Empty)(nil), // 8: pb.Empty
(*GetUserResp)(nil), // 9: pb.GetUserResp
}
var file_business_int_proto_depIdxs = []int32{
4, // 0: pb.GetUsersReq.user_ids:type_name -> pb.GetUsersReq.UserIdsEntry
5, // 1: pb.GetUsersResp.users:type_name -> pb.GetUsersResp.UsersEntry
6, // 2: pb.GetUsersResp.UsersEntry.value:type_name -> pb.User
0, // 3: pb.BusinessInt.MasterAuth:input_type -> pb.MasterAuthReq
1, // 4: pb.BusinessInt.Auth:input_type -> pb.AuthReq
7, // 5: pb.BusinessInt.GetUser:input_type -> pb.GetUserReq
2, // 6: pb.BusinessInt.GetUsers:input_type -> pb.GetUsersReq
8, // 7: pb.BusinessInt.MasterAuth:output_type -> pb.Empty
8, // 8: pb.BusinessInt.Auth:output_type -> pb.Empty
9, // 9: pb.BusinessInt.GetUser:output_type -> pb.GetUserResp
3, // 10: pb.BusinessInt.GetUsers:output_type -> pb.GetUsersResp
7, // [7:11] is the sub-list for method output_type
3, // [3:7] is the sub-list for method input_type
3, // [3:3] is the sub-list for extension type_name
3, // [3:3] is the sub-list for extension extendee
0, // [0:3] is the sub-list for field type_name
}

func init() { file_business_int_proto_init() }
func file_business_int_proto_init() {
if File_business_int_proto != nil {
return
}
file_common_ext_proto_init()
file_business_ext_proto_init()
if !protoimpl.UnsafeEnabled {
file_business_int_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*MasterAuthReq); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_business_int_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*AuthReq); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_business_int_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*GetUsersReq); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_business_int_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*GetUsersResp); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_business_int_proto_rawDesc,
NumEnums: 0,
NumMessages: 6,
NumExtensions: 0,
NumServices: 1,
},
GoTypes: file_business_int_proto_goTypes,
DependencyIndexes: file_business_int_proto_depIdxs,
MessageInfos: file_business_int_proto_msgTypes,
}.Build()
File_business_int_proto = out.File
file_business_int_proto_rawDesc = nil
file_business_int_proto_goTypes = nil
file_business_int_proto_depIdxs = nil
}

// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.32.0 or later.
const _ = grpc.SupportPackageIsVersion7

// BusinessIntClient is the client API for BusinessInt service.
//
// 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 BusinessIntClient interface {
// 站长权限校验
MasterAuth(ctx context.Context, in *MasterAuthReq, opts ...grpc.CallOption) (*Empty, error)
// 权限校验
Auth(ctx context.Context, in *AuthReq, opts ...grpc.CallOption) (*Empty, error)
// 批量获取用户信息
GetUser(ctx context.Context, in *GetUserReq, opts ...grpc.CallOption) (*GetUserResp, error)
// 批量获取用户信息
GetUsers(ctx context.Context, in *GetUsersReq, opts ...grpc.CallOption) (*GetUsersResp, error)
}

type businessIntClient struct {
cc grpc.ClientConnInterface
}

func NewBusinessIntClient(cc grpc.ClientConnInterface) BusinessIntClient {
return &businessIntClient{cc}
}

func (c *businessIntClient) MasterAuth(ctx context.Context, in *MasterAuthReq, opts ...grpc.CallOption) (*Empty, error) {
out := new(Empty)
err := c.cc.Invoke(ctx, "/pb.BusinessInt/MasterAuth", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}

func (c *businessIntClient) Auth(ctx context.Context, in *AuthReq, opts ...grpc.CallOption) (*Empty, error) {
out := new(Empty)
err := c.cc.Invoke(ctx, "/pb.BusinessInt/Auth", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}

func (c *businessIntClient) GetUser(ctx context.Context, in *GetUserReq, opts ...grpc.CallOption) (*GetUserResp, error) {
out := new(GetUserResp)
err := c.cc.Invoke(ctx, "/pb.BusinessInt/GetUser", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}

func (c *businessIntClient) GetUsers(ctx context.Context, in *GetUsersReq, opts ...grpc.CallOption) (*GetUsersResp, error) {
out := new(GetUsersResp)
err := c.cc.Invoke(ctx, "/pb.BusinessInt/GetUsers", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}

// BusinessIntServer is the server API for BusinessInt service.
// All implementations must embed UnimplementedBusinessIntServer
// for forward compatibility
type BusinessIntServer interface {
// 站长权限校验
MasterAuth(context.Context, *MasterAuthReq) (*Empty, error)
// 权限校验
Auth(context.Context, *AuthReq) (*Empty, error)
// 批量获取用户信息
GetUser(context.Context, *GetUserReq) (*GetUserResp, error)
// 批量获取用户信息
GetUsers(context.Context, *GetUsersReq) (*GetUsersResp, error)
}

// UnimplementedBusinessIntServer must be embedded to have forward compatible implementations.
type UnimplementedBusinessIntServer struct {
}

func (UnimplementedBusinessIntServer) MasterAuth(context.Context, *MasterAuthReq) (*Empty, error) {
return nil, status.Errorf(codes.Unimplemented, "method MasterAuth not implemented")
}
func (UnimplementedBusinessIntServer) Auth(context.Context, *AuthReq) (*Empty, error) {
return nil, status.Errorf(codes.Unimplemented, "method Auth not implemented")
}
func (UnimplementedBusinessIntServer) GetUser(context.Context, *GetUserReq) (*GetUserResp, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetUser not implemented")
}
func (UnimplementedBusinessIntServer) GetUsers(context.Context, *GetUsersReq) (*GetUsersResp, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetUsers not implemented")
}

func RegisterBusinessIntServer(s grpc.ServiceRegistrar, srv BusinessIntServer) {
s.RegisterService(&BusinessInt_ServiceDesc, srv)
}

func _BusinessInt_MasterAuth_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(MasterAuthReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(BusinessIntServer).MasterAuth(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/pb.BusinessInt/MasterAuth",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(BusinessIntServer).MasterAuth(ctx, req.(*MasterAuthReq))
}
return interceptor(ctx, in, info, handler)
}

func _BusinessInt_Auth_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(AuthReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(BusinessIntServer).Auth(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/pb.BusinessInt/Auth",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(BusinessIntServer).Auth(ctx, req.(*AuthReq))
}
return interceptor(ctx, in, info, handler)
}

func _BusinessInt_GetUser_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetUserReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(BusinessIntServer).GetUser(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/pb.BusinessInt/GetUser",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(BusinessIntServer).GetUser(ctx, req.(*GetUserReq))
}
return interceptor(ctx, in, info, handler)
}

func _BusinessInt_GetUsers_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetUsersReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(BusinessIntServer).GetUsers(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/pb.BusinessInt/GetUsers",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(BusinessIntServer).GetUsers(ctx, req.(*GetUsersReq))
}
return interceptor(ctx, in, info, handler)
}

// BusinessInt_ServiceDesc is the grpc.ServiceDesc for BusinessInt service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var BusinessInt_ServiceDesc = grpc.ServiceDesc{
ServiceName: "pb.BusinessInt",
HandlerType: (*BusinessIntServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "MasterAuth",
Handler: _BusinessInt_MasterAuth_Handler,
},
{
MethodName: "Auth",
Handler: _BusinessInt_Auth_Handler,
},
{
MethodName: "GetUser",
Handler: _BusinessInt_GetUser_Handler,
},
{
MethodName: "GetUsers",
Handler: _BusinessInt_GetUsers_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "im.business.int.proto",
}

+ 131
- 0
pkg/pb/im.common.ext.pb.go View File

@@ -0,0 +1,131 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.26.0
// protoc v3.14.0
// source: common.ext.proto_back

package pb

import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)

const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)

type Empty struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}

func (x *Empty) Reset() {
*x = Empty{}
if protoimpl.UnsafeEnabled {
mi := &file_common_ext_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}

func (x *Empty) String() string {
return protoimpl.X.MessageStringOf(x)
}

func (*Empty) ProtoMessage() {}

func (x *Empty) ProtoReflect() protoreflect.Message {
mi := &file_common_ext_proto_msgTypes[0]
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 Empty.ProtoReflect.Descriptor instead.
func (*Empty) Descriptor() ([]byte, []int) {
return file_common_ext_proto_rawDescGZIP(), []int{0}
}

var File_common_ext_proto protoreflect.FileDescriptor

var file_common_ext_proto_rawDesc = []byte{
0x0a, 0x10, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x78, 0x74, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x12, 0x02, 0x70, 0x62, 0x22, 0x07, 0x0a, 0x05, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x42,
0x0d, 0x5a, 0x0b, 0x67, 0x69, 0x6d, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x70, 0x62, 0x2f, 0x62, 0x06,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}

var (
file_common_ext_proto_rawDescOnce sync.Once
file_common_ext_proto_rawDescData = file_common_ext_proto_rawDesc
)

func file_common_ext_proto_rawDescGZIP() []byte {
file_common_ext_proto_rawDescOnce.Do(func() {
file_common_ext_proto_rawDescData = protoimpl.X.CompressGZIP(file_common_ext_proto_rawDescData)
})
return file_common_ext_proto_rawDescData
}

var file_common_ext_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_common_ext_proto_goTypes = []interface{}{
(*Empty)(nil), // 0: pb.Empty
}
var file_common_ext_proto_depIdxs = []int32{
0, // [0:0] is the sub-list for method output_type
0, // [0:0] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension type_name
0, // [0:0] is the sub-list for extension extendee
0, // [0:0] is the sub-list for field type_name
}

func init() { file_common_ext_proto_init() }
func file_common_ext_proto_init() {
if File_common_ext_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_common_ext_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Empty); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_common_ext_proto_rawDesc,
NumEnums: 0,
NumMessages: 1,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_common_ext_proto_goTypes,
DependencyIndexes: file_common_ext_proto_depIdxs,
MessageInfos: file_common_ext_proto_msgTypes,
}.Build()
File_common_ext_proto = out.File
file_common_ext_proto_rawDesc = nil
file_common_ext_proto_goTypes = nil
file_common_ext_proto_depIdxs = nil
}

+ 2450
- 0
pkg/pb/im.connect.ext.pb.go
File diff suppressed because it is too large
View File


+ 395
- 0
pkg/pb/im.connect.int.pb.go View File

@@ -0,0 +1,395 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.26.0
// protoc v3.14.0
// source: connect.int.proto_back

package pb

import (
context "context"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)

const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)

type DeliverMessageReq struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields

DeviceId int64 `protobuf:"varint,1,opt,name=device_id,json=deviceId,proto3" json:"device_id,omitempty"` // 设备id
MessageSend *MessageSend `protobuf:"bytes,2,opt,name=message_send,json=messageSend,proto3" json:"message_send,omitempty"` // 数据
}

func (x *DeliverMessageReq) Reset() {
*x = DeliverMessageReq{}
if protoimpl.UnsafeEnabled {
mi := &file_connect_int_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}

func (x *DeliverMessageReq) String() string {
return protoimpl.X.MessageStringOf(x)
}

func (*DeliverMessageReq) ProtoMessage() {}

func (x *DeliverMessageReq) ProtoReflect() protoreflect.Message {
mi := &file_connect_int_proto_msgTypes[0]
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 DeliverMessageReq.ProtoReflect.Descriptor instead.
func (*DeliverMessageReq) Descriptor() ([]byte, []int) {
return file_connect_int_proto_rawDescGZIP(), []int{0}
}

func (x *DeliverMessageReq) GetDeviceId() int64 {
if x != nil {
return x.DeviceId
}
return 0
}

func (x *DeliverMessageReq) GetMessageSend() *MessageSend {
if x != nil {
return x.MessageSend
}
return nil
}

// 房间推送
type PushRoomMsg struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields

RoomId int64 `protobuf:"varint,1,opt,name=room_id,json=roomId,proto3" json:"room_id,omitempty"` // 设备id
MessageSend *MessageSend `protobuf:"bytes,2,opt,name=message_send,json=messageSend,proto3" json:"message_send,omitempty"` // 数据
}

func (x *PushRoomMsg) Reset() {
*x = PushRoomMsg{}
if protoimpl.UnsafeEnabled {
mi := &file_connect_int_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}

func (x *PushRoomMsg) String() string {
return protoimpl.X.MessageStringOf(x)
}

func (*PushRoomMsg) ProtoMessage() {}

func (x *PushRoomMsg) ProtoReflect() protoreflect.Message {
mi := &file_connect_int_proto_msgTypes[1]
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 PushRoomMsg.ProtoReflect.Descriptor instead.
func (*PushRoomMsg) Descriptor() ([]byte, []int) {
return file_connect_int_proto_rawDescGZIP(), []int{1}
}

func (x *PushRoomMsg) GetRoomId() int64 {
if x != nil {
return x.RoomId
}
return 0
}

func (x *PushRoomMsg) GetMessageSend() *MessageSend {
if x != nil {
return x.MessageSend
}
return nil
}

// 房间推送
type PushAllMsg struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields

MessageSend *MessageSend `protobuf:"bytes,2,opt,name=message_send,json=messageSend,proto3" json:"message_send,omitempty"` // 数据
}

func (x *PushAllMsg) Reset() {
*x = PushAllMsg{}
if protoimpl.UnsafeEnabled {
mi := &file_connect_int_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}

func (x *PushAllMsg) String() string {
return protoimpl.X.MessageStringOf(x)
}

func (*PushAllMsg) ProtoMessage() {}

func (x *PushAllMsg) ProtoReflect() protoreflect.Message {
mi := &file_connect_int_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 PushAllMsg.ProtoReflect.Descriptor instead.
func (*PushAllMsg) Descriptor() ([]byte, []int) {
return file_connect_int_proto_rawDescGZIP(), []int{2}
}

func (x *PushAllMsg) GetMessageSend() *MessageSend {
if x != nil {
return x.MessageSend
}
return nil
}

var File_connect_int_proto protoreflect.FileDescriptor

var file_connect_int_proto_rawDesc = []byte{
0x0a, 0x11, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x12, 0x02, 0x70, 0x62, 0x1a, 0x10, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e,
0x65, 0x78, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x11, 0x63, 0x6f, 0x6e, 0x6e, 0x65,
0x63, 0x74, 0x2e, 0x65, 0x78, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x64, 0x0a, 0x11,
0x44, 0x65, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65,
0x71, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01,
0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x12, 0x32,
0x0a, 0x0c, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x73, 0x65, 0x6e, 0x64, 0x18, 0x02,
0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x62, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67,
0x65, 0x53, 0x65, 0x6e, 0x64, 0x52, 0x0b, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x53, 0x65,
0x6e, 0x64, 0x22, 0x5a, 0x0a, 0x0b, 0x50, 0x75, 0x73, 0x68, 0x52, 0x6f, 0x6f, 0x6d, 0x4d, 0x73,
0x67, 0x12, 0x17, 0x0a, 0x07, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01,
0x28, 0x03, 0x52, 0x06, 0x72, 0x6f, 0x6f, 0x6d, 0x49, 0x64, 0x12, 0x32, 0x0a, 0x0c, 0x6d, 0x65,
0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x73, 0x65, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b,
0x32, 0x0f, 0x2e, 0x70, 0x62, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x53, 0x65, 0x6e,
0x64, 0x52, 0x0b, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x53, 0x65, 0x6e, 0x64, 0x22, 0x40,
0x0a, 0x0a, 0x50, 0x75, 0x73, 0x68, 0x41, 0x6c, 0x6c, 0x4d, 0x73, 0x67, 0x12, 0x32, 0x0a, 0x0c,
0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x73, 0x65, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01,
0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x62, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x53,
0x65, 0x6e, 0x64, 0x52, 0x0b, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x53, 0x65, 0x6e, 0x64,
0x32, 0x40, 0x0a, 0x0a, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x49, 0x6e, 0x74, 0x12, 0x32,
0x0a, 0x0e, 0x44, 0x65, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
0x12, 0x15, 0x2e, 0x70, 0x62, 0x2e, 0x44, 0x65, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x4d, 0x65, 0x73,
0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x09, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70,
0x74, 0x79, 0x42, 0x0d, 0x5a, 0x0b, 0x67, 0x69, 0x6d, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x70, 0x62,
0x2f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}

var (
file_connect_int_proto_rawDescOnce sync.Once
file_connect_int_proto_rawDescData = file_connect_int_proto_rawDesc
)

func file_connect_int_proto_rawDescGZIP() []byte {
file_connect_int_proto_rawDescOnce.Do(func() {
file_connect_int_proto_rawDescData = protoimpl.X.CompressGZIP(file_connect_int_proto_rawDescData)
})
return file_connect_int_proto_rawDescData
}

var file_connect_int_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
var file_connect_int_proto_goTypes = []interface{}{
(*DeliverMessageReq)(nil), // 0: pb.DeliverMessageReq
(*PushRoomMsg)(nil), // 1: pb.PushRoomMsg
(*PushAllMsg)(nil), // 2: pb.PushAllMsg
(*MessageSend)(nil), // 3: pb.MessageSend
(*Empty)(nil), // 4: pb.Empty
}
var file_connect_int_proto_depIdxs = []int32{
3, // 0: pb.DeliverMessageReq.message_send:type_name -> pb.MessageSend
3, // 1: pb.PushRoomMsg.message_send:type_name -> pb.MessageSend
3, // 2: pb.PushAllMsg.message_send:type_name -> pb.MessageSend
0, // 3: pb.ConnectInt.DeliverMessage:input_type -> pb.DeliverMessageReq
4, // 4: pb.ConnectInt.DeliverMessage:output_type -> pb.Empty
4, // [4:5] is the sub-list for method output_type
3, // [3:4] is the sub-list for method input_type
3, // [3:3] is the sub-list for extension type_name
3, // [3:3] is the sub-list for extension extendee
0, // [0:3] is the sub-list for field type_name
}

func init() { file_connect_int_proto_init() }
func file_connect_int_proto_init() {
if File_connect_int_proto != nil {
return
}
file_common_ext_proto_init()
file_connect_ext_proto_init()
if !protoimpl.UnsafeEnabled {
file_connect_int_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*DeliverMessageReq); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_connect_int_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*PushRoomMsg); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_connect_int_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*PushAllMsg); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_connect_int_proto_rawDesc,
NumEnums: 0,
NumMessages: 3,
NumExtensions: 0,
NumServices: 1,
},
GoTypes: file_connect_int_proto_goTypes,
DependencyIndexes: file_connect_int_proto_depIdxs,
MessageInfos: file_connect_int_proto_msgTypes,
}.Build()
File_connect_int_proto = out.File
file_connect_int_proto_rawDesc = nil
file_connect_int_proto_goTypes = nil
file_connect_int_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 comm
// is compatible with the grpc package it is being compiled against.
const _ = grpc.SupportPackageIsVersion6

// ConnectIntClient is the client API for ConnectInt service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
type ConnectIntClient interface {
// 消息投递
DeliverMessage(ctx context.Context, in *DeliverMessageReq, opts ...grpc.CallOption) (*Empty, error)
}

type connectIntClient struct {
cc grpc.ClientConnInterface
}

func NewConnectIntClient(cc grpc.ClientConnInterface) ConnectIntClient {
return &connectIntClient{cc}
}

func (c *connectIntClient) DeliverMessage(ctx context.Context, in *DeliverMessageReq, opts ...grpc.CallOption) (*Empty, error) {
out := new(Empty)
err := c.cc.Invoke(ctx, "/pb.ConnectInt/DeliverMessage", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}

// ConnectIntServer is the server API for ConnectInt service.
type ConnectIntServer interface {
// 消息投递
DeliverMessage(context.Context, *DeliverMessageReq) (*Empty, error)
}

// UnimplementedConnectIntServer can be embedded to have forward compatible implementations.
type UnimplementedConnectIntServer struct {
}

func (*UnimplementedConnectIntServer) DeliverMessage(context.Context, *DeliverMessageReq) (*Empty, error) {
return nil, status.Errorf(codes.Unimplemented, "method DeliverMessage not implemented")
}

func RegisterConnectIntServer(s *grpc.Server, srv ConnectIntServer) {
s.RegisterService(&_ConnectInt_serviceDesc, srv)
}

func _ConnectInt_DeliverMessage_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(DeliverMessageReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ConnectIntServer).DeliverMessage(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/pb.ConnectInt/DeliverMessage",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ConnectIntServer).DeliverMessage(ctx, req.(*DeliverMessageReq))
}
return interceptor(ctx, in, info, handler)
}

var _ConnectInt_serviceDesc = grpc.ServiceDesc{
ServiceName: "pb.ConnectInt",
HandlerType: (*ConnectIntServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "DeliverMessage",
Handler: _ConnectInt_DeliverMessage_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "connect.int.proto_back",
}

+ 3587
- 0
pkg/pb/im.logic.ext.pb.go
File diff suppressed because it is too large
View File


+ 1547
- 0
pkg/pb/im.logic.int.pb.go
File diff suppressed because it is too large
View File


+ 623
- 0
pkg/pb/im.push.ext.pb.go View File

@@ -0,0 +1,623 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.28.1
// protoc v3.20.0--rc1
// source: im.push.ext.proto

package pb

import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)

const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)

type PushCode int32

const (
PushCode_PC_ADD_DEFAULT PushCode = 0
PushCode_PC_ADD_FRIEND PushCode = 100 // 添加好友请求
PushCode_PC_AGREE_ADD_FRIEND PushCode = 101 // 同意添加好友
PushCode_PC_UPDATE_GROUP PushCode = 110 // 更新群组
PushCode_PC_ADD_GROUP_MEMBERS PushCode = 120 // 添加群组成员
PushCode_PC_REMOVE_GROUP_MEMBER PushCode = 121 // 移除群组成员
)

// Enum value maps for PushCode.
var (
PushCode_name = map[int32]string{
0: "PC_ADD_DEFAULT",
100: "PC_ADD_FRIEND",
101: "PC_AGREE_ADD_FRIEND",
110: "PC_UPDATE_GROUP",
120: "PC_ADD_GROUP_MEMBERS",
121: "PC_REMOVE_GROUP_MEMBER",
}
PushCode_value = map[string]int32{
"PC_ADD_DEFAULT": 0,
"PC_ADD_FRIEND": 100,
"PC_AGREE_ADD_FRIEND": 101,
"PC_UPDATE_GROUP": 110,
"PC_ADD_GROUP_MEMBERS": 120,
"PC_REMOVE_GROUP_MEMBER": 121,
}
)

func (x PushCode) Enum() *PushCode {
p := new(PushCode)
*p = x
return p
}

func (x PushCode) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}

func (PushCode) Descriptor() protoreflect.EnumDescriptor {
return file_push_ext_proto_enumTypes[0].Descriptor()
}

func (PushCode) Type() protoreflect.EnumType {
return &file_push_ext_proto_enumTypes[0]
}

func (x PushCode) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}

// Deprecated: Use PushCode.Descriptor instead.
func (PushCode) EnumDescriptor() ([]byte, []int) {
return file_push_ext_proto_rawDescGZIP(), []int{0}
}

// 推送码 PC_ADD_FRIEND = 100
type AddFriendPush struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields

FriendId int64 `protobuf:"varint,1,opt,name=friend_id,json=friendId,proto3" json:"friend_id,omitempty"` // 好友id
Nickname string `protobuf:"bytes,2,opt,name=nickname,proto3" json:"nickname,omitempty"` // 昵称
AvatarUrl string `protobuf:"bytes,3,opt,name=avatar_url,json=avatarUrl,proto3" json:"avatar_url,omitempty"` // 头像
Description string `protobuf:"bytes,4,opt,name=description,proto3" json:"description,omitempty"` // 描述
}

func (x *AddFriendPush) Reset() {
*x = AddFriendPush{}
if protoimpl.UnsafeEnabled {
mi := &file_push_ext_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}

func (x *AddFriendPush) String() string {
return protoimpl.X.MessageStringOf(x)
}

func (*AddFriendPush) ProtoMessage() {}

func (x *AddFriendPush) ProtoReflect() protoreflect.Message {
mi := &file_push_ext_proto_msgTypes[0]
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 AddFriendPush.ProtoReflect.Descriptor instead.
func (*AddFriendPush) Descriptor() ([]byte, []int) {
return file_push_ext_proto_rawDescGZIP(), []int{0}
}

func (x *AddFriendPush) GetFriendId() int64 {
if x != nil {
return x.FriendId
}
return 0
}

func (x *AddFriendPush) GetNickname() string {
if x != nil {
return x.Nickname
}
return ""
}

func (x *AddFriendPush) GetAvatarUrl() string {
if x != nil {
return x.AvatarUrl
}
return ""
}

func (x *AddFriendPush) GetDescription() string {
if x != nil {
return x.Description
}
return ""
}

// 推送码 PC_AGREE_ADD_FRIEND = 101
type AgreeAddFriendPush struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields

FriendId int64 `protobuf:"varint,1,opt,name=friend_id,json=friendId,proto3" json:"friend_id,omitempty"` // 好友id
Nickname string `protobuf:"bytes,2,opt,name=nickname,proto3" json:"nickname,omitempty"` // 昵称
AvatarUrl string `protobuf:"bytes,3,opt,name=avatar_url,json=avatarUrl,proto3" json:"avatar_url,omitempty"` // 头像
}

func (x *AgreeAddFriendPush) Reset() {
*x = AgreeAddFriendPush{}
if protoimpl.UnsafeEnabled {
mi := &file_push_ext_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}

func (x *AgreeAddFriendPush) String() string {
return protoimpl.X.MessageStringOf(x)
}

func (*AgreeAddFriendPush) ProtoMessage() {}

func (x *AgreeAddFriendPush) ProtoReflect() protoreflect.Message {
mi := &file_push_ext_proto_msgTypes[1]
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 AgreeAddFriendPush.ProtoReflect.Descriptor instead.
func (*AgreeAddFriendPush) Descriptor() ([]byte, []int) {
return file_push_ext_proto_rawDescGZIP(), []int{1}
}

func (x *AgreeAddFriendPush) GetFriendId() int64 {
if x != nil {
return x.FriendId
}
return 0
}

func (x *AgreeAddFriendPush) GetNickname() string {
if x != nil {
return x.Nickname
}
return ""
}

func (x *AgreeAddFriendPush) GetAvatarUrl() string {
if x != nil {
return x.AvatarUrl
}
return ""
}

// 更新群组 PC_UPDATE_GROUP = 110
type UpdateGroupPush struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields

OptId int64 `protobuf:"varint,1,opt,name=opt_id,json=optId,proto3" json:"opt_id,omitempty"` // 操作人用户id
OptName string `protobuf:"bytes,2,opt,name=opt_name,json=optName,proto3" json:"opt_name,omitempty"` // 操作人昵称
Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"` // 群组名称
AvatarUrl string `protobuf:"bytes,4,opt,name=avatar_url,json=avatarUrl,proto3" json:"avatar_url,omitempty"` // 群组头像
Introduction string `protobuf:"bytes,5,opt,name=introduction,proto3" json:"introduction,omitempty"` // 群组简介
Extra string `protobuf:"bytes,6,opt,name=extra,proto3" json:"extra,omitempty"` // 附加字段
}

func (x *UpdateGroupPush) Reset() {
*x = UpdateGroupPush{}
if protoimpl.UnsafeEnabled {
mi := &file_push_ext_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}

func (x *UpdateGroupPush) String() string {
return protoimpl.X.MessageStringOf(x)
}

func (*UpdateGroupPush) ProtoMessage() {}

func (x *UpdateGroupPush) ProtoReflect() protoreflect.Message {
mi := &file_push_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 UpdateGroupPush.ProtoReflect.Descriptor instead.
func (*UpdateGroupPush) Descriptor() ([]byte, []int) {
return file_push_ext_proto_rawDescGZIP(), []int{2}
}

func (x *UpdateGroupPush) GetOptId() int64 {
if x != nil {
return x.OptId
}
return 0
}

func (x *UpdateGroupPush) GetOptName() string {
if x != nil {
return x.OptName
}
return ""
}

func (x *UpdateGroupPush) GetName() string {
if x != nil {
return x.Name
}
return ""
}

func (x *UpdateGroupPush) GetAvatarUrl() string {
if x != nil {
return x.AvatarUrl
}
return ""
}

func (x *UpdateGroupPush) GetIntroduction() string {
if x != nil {
return x.Introduction
}
return ""
}

func (x *UpdateGroupPush) GetExtra() string {
if x != nil {
return x.Extra
}
return ""
}

// 添加群组成员 PC_AGREE_ADD_GROUPS = 120
type AddGroupMembersPush struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields

OptId int64 `protobuf:"varint,1,opt,name=opt_id,json=optId,proto3" json:"opt_id,omitempty"` // 操作人用户id
OptName string `protobuf:"bytes,2,opt,name=opt_name,json=optName,proto3" json:"opt_name,omitempty"` // 操作人昵称
Members []*GroupMember `protobuf:"bytes,3,rep,name=members,proto3" json:"members,omitempty"` // 群组成员
}

func (x *AddGroupMembersPush) Reset() {
*x = AddGroupMembersPush{}
if protoimpl.UnsafeEnabled {
mi := &file_push_ext_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}

func (x *AddGroupMembersPush) String() string {
return protoimpl.X.MessageStringOf(x)
}

func (*AddGroupMembersPush) ProtoMessage() {}

func (x *AddGroupMembersPush) ProtoReflect() protoreflect.Message {
mi := &file_push_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 AddGroupMembersPush.ProtoReflect.Descriptor instead.
func (*AddGroupMembersPush) Descriptor() ([]byte, []int) {
return file_push_ext_proto_rawDescGZIP(), []int{3}
}

func (x *AddGroupMembersPush) GetOptId() int64 {
if x != nil {
return x.OptId
}
return 0
}

func (x *AddGroupMembersPush) GetOptName() string {
if x != nil {
return x.OptName
}
return ""
}

func (x *AddGroupMembersPush) GetMembers() []*GroupMember {
if x != nil {
return x.Members
}
return nil
}

// 删除群组成员 PC_REMOVE_GROUP_MEMBER = 121
type RemoveGroupMemberPush struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields

OptId int64 `protobuf:"varint,1,opt,name=opt_id,json=optId,proto3" json:"opt_id,omitempty"` // 操作人用户id
OptName string `protobuf:"bytes,2,opt,name=opt_name,json=optName,proto3" json:"opt_name,omitempty"` // 操作人昵称
DeletedUserId int64 `protobuf:"varint,3,opt,name=deleted_user_id,json=deletedUserId,proto3" json:"deleted_user_id,omitempty"` // 被删除的成员id
DeletedUserName string `protobuf:"bytes,4,opt,name=deleted_user_name,json=deletedUserName,proto3" json:"deleted_user_name,omitempty"` // 被删除的成员昵称
}

func (x *RemoveGroupMemberPush) Reset() {
*x = RemoveGroupMemberPush{}
if protoimpl.UnsafeEnabled {
mi := &file_push_ext_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}

func (x *RemoveGroupMemberPush) String() string {
return protoimpl.X.MessageStringOf(x)
}

func (*RemoveGroupMemberPush) ProtoMessage() {}

func (x *RemoveGroupMemberPush) ProtoReflect() protoreflect.Message {
mi := &file_push_ext_proto_msgTypes[4]
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 RemoveGroupMemberPush.ProtoReflect.Descriptor instead.
func (*RemoveGroupMemberPush) Descriptor() ([]byte, []int) {
return file_push_ext_proto_rawDescGZIP(), []int{4}
}

func (x *RemoveGroupMemberPush) GetOptId() int64 {
if x != nil {
return x.OptId
}
return 0
}

func (x *RemoveGroupMemberPush) GetOptName() string {
if x != nil {
return x.OptName
}
return ""
}

func (x *RemoveGroupMemberPush) GetDeletedUserId() int64 {
if x != nil {
return x.DeletedUserId
}
return 0
}

func (x *RemoveGroupMemberPush) GetDeletedUserName() string {
if x != nil {
return x.DeletedUserName
}
return ""
}

var File_push_ext_proto protoreflect.FileDescriptor

var file_push_ext_proto_rawDesc = []byte{
0x0a, 0x0e, 0x70, 0x75, 0x73, 0x68, 0x2e, 0x65, 0x78, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x12, 0x02, 0x70, 0x62, 0x1a, 0x0f, 0x6c, 0x6f, 0x67, 0x69, 0x63, 0x2e, 0x65, 0x78, 0x74, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x89, 0x01, 0x0a, 0x0d, 0x41, 0x64, 0x64, 0x46, 0x72, 0x69,
0x65, 0x6e, 0x64, 0x50, 0x75, 0x73, 0x68, 0x12, 0x1b, 0x0a, 0x09, 0x66, 0x72, 0x69, 0x65, 0x6e,
0x64, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x66, 0x72, 0x69, 0x65,
0x6e, 0x64, 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, 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,
0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04,
0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f,
0x6e, 0x22, 0x6c, 0x0a, 0x12, 0x41, 0x67, 0x72, 0x65, 0x65, 0x41, 0x64, 0x64, 0x46, 0x72, 0x69,
0x65, 0x6e, 0x64, 0x50, 0x75, 0x73, 0x68, 0x12, 0x1b, 0x0a, 0x09, 0x66, 0x72, 0x69, 0x65, 0x6e,
0x64, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x66, 0x72, 0x69, 0x65,
0x6e, 0x64, 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, 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, 0x22,
0xb0, 0x01, 0x0a, 0x0f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x50,
0x75, 0x73, 0x68, 0x12, 0x15, 0x0a, 0x06, 0x6f, 0x70, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20,
0x01, 0x28, 0x03, 0x52, 0x05, 0x6f, 0x70, 0x74, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x6f, 0x70,
0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6f, 0x70,
0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20,
0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 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, 0x22, 0x0a, 0x0c, 0x69, 0x6e, 0x74, 0x72,
0x6f, 0x64, 0x75, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c,
0x69, 0x6e, 0x74, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05,
0x65, 0x78, 0x74, 0x72, 0x61, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x78, 0x74,
0x72, 0x61, 0x22, 0x72, 0x0a, 0x13, 0x41, 0x64, 0x64, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x65,
0x6d, 0x62, 0x65, 0x72, 0x73, 0x50, 0x75, 0x73, 0x68, 0x12, 0x15, 0x0a, 0x06, 0x6f, 0x70, 0x74,
0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x6f, 0x70, 0x74, 0x49, 0x64,
0x12, 0x19, 0x0a, 0x08, 0x6f, 0x70, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01,
0x28, 0x09, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x29, 0x0a, 0x07, 0x6d,
0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70,
0x62, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x52, 0x07, 0x6d,
0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x22, 0x9d, 0x01, 0x0a, 0x15, 0x52, 0x65, 0x6d, 0x6f, 0x76,
0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x50, 0x75, 0x73, 0x68,
0x12, 0x15, 0x0a, 0x06, 0x6f, 0x70, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03,
0x52, 0x05, 0x6f, 0x70, 0x74, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x6f, 0x70, 0x74, 0x5f, 0x6e,
0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x4e, 0x61,
0x6d, 0x65, 0x12, 0x26, 0x0a, 0x0f, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x5f, 0x75, 0x73,
0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x64, 0x65, 0x6c,
0x65, 0x74, 0x65, 0x64, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x2a, 0x0a, 0x11, 0x64, 0x65,
0x6c, 0x65, 0x74, 0x65, 0x64, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18,
0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x55, 0x73,
0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x2a, 0x95, 0x01, 0x0a, 0x08, 0x50, 0x75, 0x73, 0x68, 0x43,
0x6f, 0x64, 0x65, 0x12, 0x12, 0x0a, 0x0e, 0x50, 0x43, 0x5f, 0x41, 0x44, 0x44, 0x5f, 0x44, 0x45,
0x46, 0x41, 0x55, 0x4c, 0x54, 0x10, 0x00, 0x12, 0x11, 0x0a, 0x0d, 0x50, 0x43, 0x5f, 0x41, 0x44,
0x44, 0x5f, 0x46, 0x52, 0x49, 0x45, 0x4e, 0x44, 0x10, 0x64, 0x12, 0x17, 0x0a, 0x13, 0x50, 0x43,
0x5f, 0x41, 0x47, 0x52, 0x45, 0x45, 0x5f, 0x41, 0x44, 0x44, 0x5f, 0x46, 0x52, 0x49, 0x45, 0x4e,
0x44, 0x10, 0x65, 0x12, 0x13, 0x0a, 0x0f, 0x50, 0x43, 0x5f, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45,
0x5f, 0x47, 0x52, 0x4f, 0x55, 0x50, 0x10, 0x6e, 0x12, 0x18, 0x0a, 0x14, 0x50, 0x43, 0x5f, 0x41,
0x44, 0x44, 0x5f, 0x47, 0x52, 0x4f, 0x55, 0x50, 0x5f, 0x4d, 0x45, 0x4d, 0x42, 0x45, 0x52, 0x53,
0x10, 0x78, 0x12, 0x1a, 0x0a, 0x16, 0x50, 0x43, 0x5f, 0x52, 0x45, 0x4d, 0x4f, 0x56, 0x45, 0x5f,
0x47, 0x52, 0x4f, 0x55, 0x50, 0x5f, 0x4d, 0x45, 0x4d, 0x42, 0x45, 0x52, 0x10, 0x79, 0x42, 0x0d,
0x5a, 0x0b, 0x67, 0x69, 0x6d, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x70, 0x62, 0x2f, 0x62, 0x06, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x33,
}

var (
file_push_ext_proto_rawDescOnce sync.Once
file_push_ext_proto_rawDescData = file_push_ext_proto_rawDesc
)

func file_push_ext_proto_rawDescGZIP() []byte {
file_push_ext_proto_rawDescOnce.Do(func() {
file_push_ext_proto_rawDescData = protoimpl.X.CompressGZIP(file_push_ext_proto_rawDescData)
})
return file_push_ext_proto_rawDescData
}

var file_push_ext_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
var file_push_ext_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
var file_push_ext_proto_goTypes = []interface{}{
(PushCode)(0), // 0: pb.PushCode
(*AddFriendPush)(nil), // 1: pb.AddFriendPush
(*AgreeAddFriendPush)(nil), // 2: pb.AgreeAddFriendPush
(*UpdateGroupPush)(nil), // 3: pb.UpdateGroupPush
(*AddGroupMembersPush)(nil), // 4: pb.AddGroupMembersPush
(*RemoveGroupMemberPush)(nil), // 5: pb.RemoveGroupMemberPush
(*GroupMember)(nil), // 6: pb.GroupMember
}
var file_push_ext_proto_depIdxs = []int32{
6, // 0: pb.AddGroupMembersPush.members:type_name -> pb.GroupMember
1, // [1:1] is the sub-list for method output_type
1, // [1:1] is the sub-list for method input_type
1, // [1:1] is the sub-list for extension type_name
1, // [1:1] is the sub-list for extension extendee
0, // [0:1] is the sub-list for field type_name
}

func init() { file_push_ext_proto_init() }
func file_push_ext_proto_init() {
if File_push_ext_proto != nil {
return
}
file_logic_ext_proto_init()
if !protoimpl.UnsafeEnabled {
file_push_ext_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*AddFriendPush); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_push_ext_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*AgreeAddFriendPush); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_push_ext_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*UpdateGroupPush); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_push_ext_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*AddGroupMembersPush); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_push_ext_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*RemoveGroupMemberPush); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_push_ext_proto_rawDesc,
NumEnums: 1,
NumMessages: 5,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_push_ext_proto_goTypes,
DependencyIndexes: file_push_ext_proto_depIdxs,
EnumInfos: file_push_ext_proto_enumTypes,
MessageInfos: file_push_ext_proto_msgTypes,
}.Build()
File_push_ext_proto = out.File
file_push_ext_proto_rawDesc = nil
file_push_ext_proto_goTypes = nil
file_push_ext_proto_depIdxs = nil
}

+ 103
- 0
pkg/proto/im.business.ext.proto View File

@@ -0,0 +1,103 @@
syntax = "proto3";
package pb;
option go_package = "gim/pkg/pb/";

import "im.common.ext.proto";

service BusinessExt {
// 登录
rpc SignIn (SignInReq) returns (SignInResp);
// 获取用户信息
rpc GetUser (GetUserReq) returns (GetUserResp);
// 更新用户信息
rpc UpdateUser (UpdateUserReq) returns (Empty);
// 搜索用户(这里简单数据库实现,生产环境建议使用ES)
rpc SearchUser (SearchUserReq) returns (SearchUserResp);
// 上传文件至云端
rpc CloudUploadFile (CloudUploadFileReq) returns (CloudUploadFileResp);
// 获取表情
rpc EmoticonList (Empty) returns (EmoticonListResp);
// 判断是否为好友关系
rpc IsFriends (IsFriendsReq) returns (IsFriendsResp);
}


message IsFriendsReq {
string user_phone = 1;
string friend_phone = 2;
}

message IsFriendsResp {
int64 is_friend = 1;
User user = 2; // 用户信息
}

message Emoticon {
string name = 1; // 名称
string img_url = 2; // 图片地址
string memo = 3; // 备注
int32 sort = 4; // 排序
}
message EmoticonListResp {
repeated Emoticon emoticons = 1;
}
message SignInReq {
string phone_number = 1; // 手机号
string code = 2; // 验证码
int64 device_id = 3; // 设备id
int64 master_id = 4; // 站长id
string push_alia = 5; // 极光推送-别名
}
message SignInResp {
bool is_new = 1; // 是否是新用户
int64 user_id = 2; // 用户id
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
string nickname = 2; // 昵称
int32 sex = 3; // 性别
string avatar_url = 4; // 头像地址
string extra = 5; // 附加字段
int64 create_time = 6; // 创建时间
int64 update_time = 7; // 更新时间
int64 master_id = 8; // 站长id
int64 is_auto_added_friends = 9; // 是否自动被添加好友
}

message GetUserReq {
int64 user_id = 1; // 用户id
string phone = 2; // 用户手机号
}
message GetUserResp {
User user = 1; // 用户信息
}

message UpdateUserReq {
string nickname = 1; // 昵称
int32 sex = 2; // 性别
string avatar_url = 3; // 头像地址
string extra = 4; // 附加字段
}

message SearchUserReq{
string key = 1;
int64 master_id = 2;
}
message SearchUserResp{
repeated User users = 1;
}


+ 34
- 0
pkg/proto/im.business.int.proto View File

@@ -0,0 +1,34 @@
syntax = "proto3";
package pb;
option go_package = "gim/pkg/pb/";

import "im.common.ext.proto";
import "im.business.ext.proto";

service BusinessInt {
// 站长权限校验
rpc MasterAuth (MasterAuthReq) returns (Empty);
// 权限校验
rpc Auth (AuthReq) returns (Empty);
// 批量获取用户信息
rpc GetUser (GetUserReq) returns (GetUserResp);
// 批量获取用户信息
rpc GetUsers (GetUsersReq) returns (GetUsersResp);
}

message MasterAuthReq {
string master_id = 1;
}

message AuthReq {
int64 user_id = 1;
int64 device_id = 2;
string token = 3;
}

message GetUsersReq {
map<int64, int32> user_ids = 1; // 用户id
}
message GetUsersResp {
map<int64, User> users = 1; // 用户信息
}

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save