first commit
This commit is contained in:
53
.gitignore
vendored
Normal file
53
.gitignore
vendored
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
*.exe
|
||||||
|
/logs/*.log
|
||||||
|
/logs
|
||||||
|
/web/fy-trade/unpackage
|
||||||
|
.DS_Store
|
||||||
|
/data
|
||||||
|
__debug_bin*
|
||||||
|
|
||||||
|
HELP.md
|
||||||
|
.gradle
|
||||||
|
/build/
|
||||||
|
!gradle/wrapper/gradle-wrapper.jar
|
||||||
|
|
||||||
|
### STS ###
|
||||||
|
.apt_generated
|
||||||
|
.classpath
|
||||||
|
.factorypath
|
||||||
|
.project
|
||||||
|
.settings
|
||||||
|
.springBeans
|
||||||
|
.sts4-cache
|
||||||
|
|
||||||
|
### IntelliJ IDEA ###
|
||||||
|
.idea
|
||||||
|
*.iws
|
||||||
|
*.ipr
|
||||||
|
/out/
|
||||||
|
/bin/
|
||||||
|
|
||||||
|
### NetBeans ###
|
||||||
|
/nbproject/private/
|
||||||
|
/nbbuild/
|
||||||
|
/dist/
|
||||||
|
/nbdist/
|
||||||
|
/.nb-gradle/
|
||||||
|
|
||||||
|
### VS Code ###
|
||||||
|
#.vscode/
|
||||||
|
|
||||||
|
|
||||||
|
/node_modules
|
||||||
|
/web/node_modules
|
||||||
|
*.iml
|
||||||
|
/logs
|
||||||
|
*.tmp
|
||||||
|
projectFilesBackup
|
||||||
|
/*.exe
|
||||||
|
/NNOperation
|
||||||
|
lastupdate.tmp
|
||||||
|
/temp
|
||||||
|
/views/static
|
||||||
|
/serviceoperation
|
||||||
|
/app
|
||||||
80
.vscode/launch.json
vendored
Normal file
80
.vscode/launch.json
vendored
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
{
|
||||||
|
// Use IntelliSense to learn about possible attributes.
|
||||||
|
// Hover to view descriptions of existing attributes.
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "app",
|
||||||
|
"type": "go",
|
||||||
|
"request": "launch",
|
||||||
|
"mode": "auto",
|
||||||
|
"program": "${workspaceFolder}/cmd/server/main.go",
|
||||||
|
"cwd": "${workspaceFolder}",
|
||||||
|
"args": ["app", "-e", "dev"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "app-local",
|
||||||
|
"type": "go",
|
||||||
|
"request": "launch",
|
||||||
|
"mode": "auto",
|
||||||
|
"program": "${workspaceFolder}/cmd/server/main.go",
|
||||||
|
"cwd": "${workspaceFolder}",
|
||||||
|
"args": ["app", "-e", "local"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "admin",
|
||||||
|
"type": "go",
|
||||||
|
"request": "launch",
|
||||||
|
"mode": "auto",
|
||||||
|
"program": "${workspaceFolder}/cmd/server/main.go",
|
||||||
|
"cwd": "${workspaceFolder}",
|
||||||
|
"args": ["admin", "-e", "dev"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "admin-local",
|
||||||
|
"type": "go",
|
||||||
|
"request": "launch",
|
||||||
|
"mode": "auto",
|
||||||
|
"program": "${workspaceFolder}/cmd/server/main.go",
|
||||||
|
"cwd": "${workspaceFolder}",
|
||||||
|
"args": ["admin", "-e", "local"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cms",
|
||||||
|
"type": "go",
|
||||||
|
"request": "launch",
|
||||||
|
"mode": "auto",
|
||||||
|
"program": "${workspaceFolder}/cmd/server/main.go",
|
||||||
|
"cwd": "${workspaceFolder}",
|
||||||
|
"args": ["cms", "-e", "dev"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "data",
|
||||||
|
"type": "go",
|
||||||
|
"request": "launch",
|
||||||
|
"mode": "auto",
|
||||||
|
"program": "${workspaceFolder}/cmd/server/main.go",
|
||||||
|
"cwd": "${workspaceFolder}",
|
||||||
|
"args": ["data", "-e", "dev"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "trade",
|
||||||
|
"type": "go",
|
||||||
|
"request": "launch",
|
||||||
|
"mode": "auto",
|
||||||
|
"program": "${workspaceFolder}/cmd/server/main.go",
|
||||||
|
"cwd": "${workspaceFolder}",
|
||||||
|
"args": ["all", "-e", "dev"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "activity",
|
||||||
|
"type": "go",
|
||||||
|
"request": "launch",
|
||||||
|
"mode": "auto",
|
||||||
|
"program": "${workspaceFolder}/cmd/server/main.go",
|
||||||
|
"cwd": "${workspaceFolder}",
|
||||||
|
"args": ["activity", "-e", "dev"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
33
.zed/debug.json
Normal file
33
.zed/debug.json
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
// Project-local debug tasks
|
||||||
|
//
|
||||||
|
// For more documentation on how to configure debug tasks,
|
||||||
|
// see: https://zed.dev/docs/debugger
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"adapter": "Delve",
|
||||||
|
"label": "app_dev",
|
||||||
|
"request": "launch",
|
||||||
|
"mode": "debug",
|
||||||
|
"program": "${ZED_WORKTREE_ROOT}/cmd/server/main.go",
|
||||||
|
"cwd": "${ZED_WORKTREE_ROOT}",
|
||||||
|
"args": ["app", "-e", "dev"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"adapter": "Delve",
|
||||||
|
"label": "admin_dev",
|
||||||
|
"request": "launch",
|
||||||
|
"mode": "debug",
|
||||||
|
"program": "${ZED_WORKTREE_ROOT}/cmd/server/main.go",
|
||||||
|
"cwd": "${ZED_WORKTREE_ROOT}",
|
||||||
|
"args": ["admin", "-e", "dev"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"adapter": "Delve",
|
||||||
|
"label": "cms_dev",
|
||||||
|
"request": "launch",
|
||||||
|
"mode": "debug",
|
||||||
|
"program": "${ZED_WORKTREE_ROOT}/cmd/server/main.go",
|
||||||
|
"cwd": "${ZED_WORKTREE_ROOT}",
|
||||||
|
"args": ["cms", "-e", "dev"]
|
||||||
|
}
|
||||||
|
]
|
||||||
16
README.md
Normal file
16
README.md
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
## 代码说明
|
||||||
|
|
||||||
|
### 目录说明
|
||||||
|
|
||||||
|
- pkg:通用模块
|
||||||
|
- errors:错误定义
|
||||||
|
- client:三方api客户端封装
|
||||||
|
- lock:内存中的单体服务全局锁
|
||||||
|
- constant:常量定义
|
||||||
|
- datasource:数据库连接,其中的fields可以用户res结构体的scan映射
|
||||||
|
- log:日志
|
||||||
|
- model:模型实体定义,自动生成
|
||||||
|
- repo:数据库访问方法定义,自动生成
|
||||||
|
- req:请求体定义,前缀为模块名
|
||||||
|
- res:响应体定义,前缀为模块名
|
||||||
|
- tools:通用工具封装
|
||||||
163
go.mod
Normal file
163
go.mod
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
module servicebase
|
||||||
|
|
||||||
|
go 1.24.0
|
||||||
|
|
||||||
|
toolchain go1.24.10
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.5 // indirect
|
||||||
|
github.com/alibabacloud-go/debug v1.0.1 // indirect
|
||||||
|
github.com/alibabacloud-go/endpoint-util v1.1.0 // indirect
|
||||||
|
github.com/alibabacloud-go/openapi-util v0.1.1 // indirect
|
||||||
|
github.com/aliyun/alibaba-cloud-sdk-go v1.63.49
|
||||||
|
github.com/anxpp/beego v1.12.2-no-color-info
|
||||||
|
github.com/apache/rocketmq-client-go/v2 v2.1.2
|
||||||
|
github.com/dgrijalva/jwt-go v3.2.0+incompatible
|
||||||
|
github.com/disintegration/imaging v1.6.2
|
||||||
|
github.com/gin-gonic/gin v1.10.0
|
||||||
|
github.com/go-resty/resty/v2 v2.15.3
|
||||||
|
github.com/golang-jwt/jwt/v5 v5.2.1
|
||||||
|
github.com/google/uuid v1.6.0
|
||||||
|
github.com/natefinch/lumberjack v2.0.0+incompatible
|
||||||
|
github.com/olivere/elastic/v7 v7.0.32
|
||||||
|
github.com/pkg/errors v0.9.1
|
||||||
|
github.com/prometheus/client_golang v1.20.5 // indirect
|
||||||
|
github.com/qiniu/go-sdk/v7 v7.25.0
|
||||||
|
github.com/redis/go-redis/v9 v9.7.0
|
||||||
|
github.com/shopspring/decimal v1.4.0
|
||||||
|
github.com/spf13/viper v1.19.0
|
||||||
|
github.com/tealeg/xlsx v1.0.5
|
||||||
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/clb v1.0.1038
|
||||||
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1038
|
||||||
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/sms v1.0.1031
|
||||||
|
go.mongodb.org/mongo-driver v1.17.1
|
||||||
|
go.opentelemetry.io/otel/trace v1.31.0
|
||||||
|
go.uber.org/zap v1.27.0
|
||||||
|
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
|
||||||
|
gorm.io/driver/mysql v1.5.7
|
||||||
|
gorm.io/gen v0.3.26
|
||||||
|
gorm.io/gorm v1.25.12
|
||||||
|
gorm.io/plugin/dbresolver v1.5.3
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/AgoraIO/Tools/DynamicKey/AgoraDynamicKey/go/src v0.0.0-20250603060255-42a9cad9cffc
|
||||||
|
github.com/alibabacloud-go/darabonba-openapi/v2 v2.1.7
|
||||||
|
github.com/alibabacloud-go/dysmsapi-20170525/v3 v3.0.6
|
||||||
|
github.com/alibabacloud-go/tea v1.3.8
|
||||||
|
github.com/alibabacloud-go/tea-utils/v2 v2.0.7
|
||||||
|
github.com/yidun/yidun-golang-sdk v1.0.29
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/anxpp/common-utils v0.0.0-20250612015512-2dc997d0693c
|
||||||
|
github.com/wechatpay-apiv3/wechatpay-go v0.2.21
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/alibabacloud-go/openplatform-20191219/v2 v2.0.1 // indirect
|
||||||
|
github.com/alibabacloud-go/tea-fileform v1.1.1 // indirect
|
||||||
|
github.com/alibabacloud-go/tea-oss-sdk v1.1.5 // indirect
|
||||||
|
github.com/alibabacloud-go/tea-oss-utils v1.1.0 // indirect
|
||||||
|
github.com/go-sql-driver/mysql v1.7.0 // indirect
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/BurntSushi/toml v1.4.0 // indirect
|
||||||
|
github.com/alex-ant/gomath v0.0.0-20160516115720-89013a210a82 // indirect
|
||||||
|
github.com/alibabacloud-go/cloudauth-20190307/v3 v3.9.2
|
||||||
|
github.com/alibabacloud-go/tea-utils v1.4.5 // indirect
|
||||||
|
github.com/alibabacloud-go/tea-xml v1.1.3 // indirect
|
||||||
|
github.com/aliyun/credentials-go v1.4.6 // indirect
|
||||||
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
|
github.com/bytedance/sonic v1.12.1 // indirect
|
||||||
|
github.com/bytedance/sonic/loader v0.2.0 // indirect
|
||||||
|
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||||
|
github.com/clbanning/mxj/v2 v2.7.0 // indirect
|
||||||
|
github.com/cloudwego/base64x v0.1.4 // indirect
|
||||||
|
github.com/cloudwego/iasm v0.2.0 // indirect
|
||||||
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||||
|
github.com/elastic/go-sysinfo v1.15.0 // indirect
|
||||||
|
github.com/elastic/go-windows v1.0.0 // indirect
|
||||||
|
github.com/emirpasic/gods v1.12.0 // indirect
|
||||||
|
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
||||||
|
github.com/gabriel-vasile/mimetype v1.4.5 // indirect
|
||||||
|
github.com/gammazero/toposort v0.1.1 // indirect
|
||||||
|
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||||
|
github.com/go-playground/locales v0.14.1 // indirect
|
||||||
|
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||||
|
github.com/go-playground/validator/v10 v10.22.0 // indirect
|
||||||
|
github.com/goccy/go-json v0.10.3 // indirect
|
||||||
|
github.com/gofrs/flock v0.8.1 // indirect
|
||||||
|
github.com/golang/mock v1.4.4 // indirect
|
||||||
|
github.com/golang/snappy v0.0.4 // indirect
|
||||||
|
github.com/hashicorp/golang-lru v0.5.4 // indirect
|
||||||
|
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||||
|
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||||
|
github.com/jinzhu/now v1.1.5 // indirect
|
||||||
|
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||||
|
github.com/josharian/intern v1.0.0 // indirect
|
||||||
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
|
github.com/klauspost/compress v1.17.9 // indirect
|
||||||
|
github.com/klauspost/cpuid/v2 v2.2.8 // indirect
|
||||||
|
github.com/konsorten/go-windows-terminal-sequences v1.0.3 // indirect
|
||||||
|
github.com/leodido/go-urn v1.4.0 // indirect
|
||||||
|
github.com/magiconair/properties v1.8.7 // indirect
|
||||||
|
github.com/mailru/easyjson v0.7.7 // indirect
|
||||||
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
|
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
|
github.com/montanaflynn/stats v0.7.1 // indirect
|
||||||
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||||
|
github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b // indirect
|
||||||
|
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
|
||||||
|
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
|
||||||
|
github.com/prometheus/client_model v0.6.1 // indirect
|
||||||
|
github.com/prometheus/common v0.55.0 // indirect
|
||||||
|
github.com/prometheus/procfs v0.15.1 // indirect
|
||||||
|
github.com/sagikazarmark/locafero v0.4.0 // indirect
|
||||||
|
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
|
||||||
|
github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 // indirect
|
||||||
|
github.com/sirupsen/logrus v1.6.0 // indirect
|
||||||
|
github.com/sourcegraph/conc v0.3.0 // indirect
|
||||||
|
github.com/spf13/afero v1.11.0 // indirect
|
||||||
|
github.com/spf13/cast v1.6.0
|
||||||
|
github.com/spf13/pflag v1.0.5 // indirect
|
||||||
|
github.com/subosito/gotenv v1.6.0 // indirect
|
||||||
|
github.com/tidwall/gjson v1.13.0 // indirect
|
||||||
|
github.com/tidwall/match v1.1.1 // indirect
|
||||||
|
github.com/tidwall/pretty v1.2.0 // indirect
|
||||||
|
github.com/tjfoc/gmsm v1.4.1
|
||||||
|
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||||
|
github.com/ugorji/go/codec v1.2.12 // indirect
|
||||||
|
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
|
||||||
|
github.com/xdg-go/scram v1.1.2 // indirect
|
||||||
|
github.com/xdg-go/stringprep v1.0.4 // indirect
|
||||||
|
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
|
||||||
|
go.opentelemetry.io/otel v1.31.0 // indirect
|
||||||
|
go.uber.org/atomic v1.9.0 // indirect
|
||||||
|
go.uber.org/multierr v1.11.0 // indirect
|
||||||
|
golang.org/x/arch v0.9.0 // indirect
|
||||||
|
golang.org/x/crypto v0.28.0 // indirect
|
||||||
|
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
|
||||||
|
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8 // indirect
|
||||||
|
golang.org/x/mod v0.20.0 // indirect
|
||||||
|
golang.org/x/net v0.30.0 // indirect
|
||||||
|
golang.org/x/sync v0.8.0 // indirect
|
||||||
|
golang.org/x/sys v0.26.0 // indirect
|
||||||
|
golang.org/x/text v0.19.0 // indirect
|
||||||
|
golang.org/x/time v0.13.0
|
||||||
|
golang.org/x/tools v0.24.0 // indirect
|
||||||
|
google.golang.org/protobuf v1.35.1 // indirect
|
||||||
|
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
|
||||||
|
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||||
|
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
|
||||||
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
|
gorm.io/datatypes v1.1.1-0.20230130040222-c43177d3cf8c // indirect
|
||||||
|
gorm.io/hints v1.1.0 // indirect
|
||||||
|
howett.net/plist v0.0.0-20181124034731-591f970eefbb // indirect
|
||||||
|
modernc.org/fileutil v1.0.0 // indirect
|
||||||
|
stathat.com/c/consistent v1.0.0 // indirect
|
||||||
|
)
|
||||||
821
go.sum
Normal file
821
go.sum
Normal file
@ -0,0 +1,821 @@
|
|||||||
|
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
|
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||||
|
github.com/AgoraIO/Tools/DynamicKey/AgoraDynamicKey/go/src v0.0.0-20250603060255-42a9cad9cffc h1:VMQwCNGT82ipigEooHtijUvbSp5g1JG6WTXQ9wyhYMM=
|
||||||
|
github.com/AgoraIO/Tools/DynamicKey/AgoraDynamicKey/go/src v0.0.0-20250603060255-42a9cad9cffc/go.mod h1:4bXIK0ntDk9CqAXobmomWd7dedbfNv/aaIpmpqqzt+A=
|
||||||
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
|
github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
||||||
|
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
||||||
|
github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0=
|
||||||
|
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
||||||
|
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||||
|
github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo=
|
||||||
|
github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
|
||||||
|
github.com/agiledragon/gomonkey v2.0.2+incompatible h1:eXKi9/piiC3cjJD1658mEE2o3NjkJ5vDLgYjCQu0Xlw=
|
||||||
|
github.com/agiledragon/gomonkey v2.0.2+incompatible/go.mod h1:2NGfXu1a80LLr2cmWXGBDaHEjb1idR6+FVlX5T3D9hw=
|
||||||
|
github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw=
|
||||||
|
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||||
|
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||||
|
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||||
|
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||||
|
github.com/alex-ant/gomath v0.0.0-20160516115720-89013a210a82 h1:7dONQ3WNZ1zy960TmkxJPuwoolZwL7xKtpcM04MBnt4=
|
||||||
|
github.com/alex-ant/gomath v0.0.0-20160516115720-89013a210a82/go.mod h1:nLnM0KdK1CmygvjpDUO6m1TjSsiQtL61juhNsvV/JVI=
|
||||||
|
github.com/alibabacloud-go/alibabacloud-gateway-pop v0.0.6 h1:eIf+iGJxdU4U9ypaUfbtOWCsZSbTb8AUHvyPrxu6mAA=
|
||||||
|
github.com/alibabacloud-go/alibabacloud-gateway-pop v0.0.6/go.mod h1:4EUIoxs/do24zMOGGqYVWgw0s9NtiylnJglOeEB5UJo=
|
||||||
|
github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4/go.mod h1:sCavSAvdzOjul4cEqeVtvlSaSScfNsTQ+46HwlTL1hc=
|
||||||
|
github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.5 h1:zE8vH9C7JiZLNJJQ5OwjU9mSi4T9ef9u3BURT6LCLC8=
|
||||||
|
github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.5/go.mod h1:tWnyE9AjF8J8qqLk645oUmVUnFybApTQWklQmi5tY6g=
|
||||||
|
github.com/alibabacloud-go/cloudauth-20190307/v3 v3.9.2 h1:y4s0WQ1jrBtOJfXGgsv/83brJvkkHbFdORp0WDyVAuw=
|
||||||
|
github.com/alibabacloud-go/cloudauth-20190307/v3 v3.9.2/go.mod h1:kD75qqMQyjCiz6lssjRzYGTumcli8STLXQstVe6ytxk=
|
||||||
|
github.com/alibabacloud-go/darabonba-array v0.1.0 h1:vR8s7b1fWAQIjEjWnuF0JiKsCvclSRTfDzZHTYqfufY=
|
||||||
|
github.com/alibabacloud-go/darabonba-array v0.1.0/go.mod h1:BLKxr0brnggqOJPqT09DFJ8g3fsDshapUD3C3aOEFaI=
|
||||||
|
github.com/alibabacloud-go/darabonba-encode-util v0.0.2 h1:1uJGrbsGEVqWcWxrS9MyC2NG0Ax+GpOM5gtupki31XE=
|
||||||
|
github.com/alibabacloud-go/darabonba-encode-util v0.0.2/go.mod h1:JiW9higWHYXm7F4PKuMgEUETNZasrDM6vqVr/Can7H8=
|
||||||
|
github.com/alibabacloud-go/darabonba-map v0.0.2 h1:qvPnGB4+dJbJIxOOfawxzF3hzMnIpjmafa0qOTp6udc=
|
||||||
|
github.com/alibabacloud-go/darabonba-map v0.0.2/go.mod h1:28AJaX8FOE/ym8OUFWga+MtEzBunJwQGceGQlvaPGPc=
|
||||||
|
github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.0/go.mod h1:5JHVmnHvGzR2wNdgaW1zDLQG8kOC4Uec8ubkMogW7OQ=
|
||||||
|
github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.2/go.mod h1:5JHVmnHvGzR2wNdgaW1zDLQG8kOC4Uec8ubkMogW7OQ=
|
||||||
|
github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.10/go.mod h1:26a14FGhZVELuz2cc2AolvW4RHmIO3/HRwsdHhaIPDE=
|
||||||
|
github.com/alibabacloud-go/darabonba-openapi/v2 v2.1.7 h1:ASXSBga98QrGMxbIThCD6jAti09gedLfvry6yJtsoBE=
|
||||||
|
github.com/alibabacloud-go/darabonba-openapi/v2 v2.1.7/go.mod h1:TBpgqm3XofZz2LCYjZhektGPU7ArEgascyzbm4SjFo4=
|
||||||
|
github.com/alibabacloud-go/darabonba-signature-util v0.0.7 h1:UzCnKvsjPFzApvODDNEYqBHMFt1w98wC7FOo0InLyxg=
|
||||||
|
github.com/alibabacloud-go/darabonba-signature-util v0.0.7/go.mod h1:oUzCYV2fcCH797xKdL6BDH8ADIHlzrtKVjeRtunBNTQ=
|
||||||
|
github.com/alibabacloud-go/darabonba-string v1.0.2 h1:E714wms5ibdzCqGeYJ9JCFywE5nDyvIXIIQbZVFkkqo=
|
||||||
|
github.com/alibabacloud-go/darabonba-string v1.0.2/go.mod h1:93cTfV3vuPhhEwGGpKKqhVW4jLe7tDpo3LUM0i0g6mA=
|
||||||
|
github.com/alibabacloud-go/debug v0.0.0-20190504072949-9472017b5c68/go.mod h1:6pb/Qy8c+lqua8cFpEy7g39NRRqOWc3rOwAy8m5Y2BY=
|
||||||
|
github.com/alibabacloud-go/debug v1.0.0/go.mod h1:8gfgZCCAC3+SCzjWtY053FrOcd4/qlH6IHTI4QyICOc=
|
||||||
|
github.com/alibabacloud-go/debug v1.0.1 h1:MsW9SmUtbb1Fnt3ieC6NNZi6aEwrXfDksD4QA6GSbPg=
|
||||||
|
github.com/alibabacloud-go/debug v1.0.1/go.mod h1:8gfgZCCAC3+SCzjWtY053FrOcd4/qlH6IHTI4QyICOc=
|
||||||
|
github.com/alibabacloud-go/dysmsapi-20170525/v3 v3.0.6 h1:UTl97mt2qfavxveqCkaVg4tKaZUPzA9RKbFIRaIdtdg=
|
||||||
|
github.com/alibabacloud-go/dysmsapi-20170525/v3 v3.0.6/go.mod h1:UWpcGrWwTbES9QW7OQ7xDffukMJ/l7lzioixIz8+lgY=
|
||||||
|
github.com/alibabacloud-go/endpoint-util v1.1.0 h1:r/4D3VSw888XGaeNpP994zDUaxdgTSHBbVfZlzf6b5Q=
|
||||||
|
github.com/alibabacloud-go/endpoint-util v1.1.0/go.mod h1:O5FuCALmCKs2Ff7JFJMudHs0I5EBgecXXxZRyswlEjE=
|
||||||
|
github.com/alibabacloud-go/openapi-util v0.0.11/go.mod h1:sQuElr4ywwFRlCCberQwKRFhRzIyG4QTP/P4y1CJ6Ws=
|
||||||
|
github.com/alibabacloud-go/openapi-util v0.1.0/go.mod h1:sQuElr4ywwFRlCCberQwKRFhRzIyG4QTP/P4y1CJ6Ws=
|
||||||
|
github.com/alibabacloud-go/openapi-util v0.1.1 h1:ujGErJjG8ncRW6XtBBMphzHTvCxn4DjrVw4m04HsS28=
|
||||||
|
github.com/alibabacloud-go/openapi-util v0.1.1/go.mod h1:/UehBSE2cf1gYT43GV4E+RxTdLRzURImCYY0aRmlXpw=
|
||||||
|
github.com/alibabacloud-go/openplatform-20191219/v2 v2.0.1 h1:L0TIjr9Qh/SLVc1yPhFkcB9+9SbCNK/jPq4ZKB5zmnc=
|
||||||
|
github.com/alibabacloud-go/openplatform-20191219/v2 v2.0.1/go.mod h1:EKxBRDLcMzwl4VLF/1WJwlByZZECJawPXUvinKMsTTs=
|
||||||
|
github.com/alibabacloud-go/tea v1.1.0/go.mod h1:IkGyUSX4Ba1V+k4pCtJUc6jDpZLFph9QMy2VUPTwukg=
|
||||||
|
github.com/alibabacloud-go/tea v1.1.7/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4=
|
||||||
|
github.com/alibabacloud-go/tea v1.1.8/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4=
|
||||||
|
github.com/alibabacloud-go/tea v1.1.10/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4=
|
||||||
|
github.com/alibabacloud-go/tea v1.1.11/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4=
|
||||||
|
github.com/alibabacloud-go/tea v1.1.12/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4=
|
||||||
|
github.com/alibabacloud-go/tea v1.1.17/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A=
|
||||||
|
github.com/alibabacloud-go/tea v1.1.19/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A=
|
||||||
|
github.com/alibabacloud-go/tea v1.1.20/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A=
|
||||||
|
github.com/alibabacloud-go/tea v1.2.2/go.mod h1:CF3vOzEMAG+bR4WOql8gc2G9H3EkH3ZLAQdpmpXMgwk=
|
||||||
|
github.com/alibabacloud-go/tea v1.3.8 h1:Sk2+BDJC//xJ1/Eljf+Dlg2u2tgWpA9P7mlb87AEcEs=
|
||||||
|
github.com/alibabacloud-go/tea v1.3.8/go.mod h1:A560v/JTQ1n5zklt2BEpurJzZTI8TUT+Psg2drWlxRg=
|
||||||
|
github.com/alibabacloud-go/tea-fileform v1.1.1 h1:1YG6erAP3joQ0XdCXYIotuD7zyOM6qCR49xkp5FZDeU=
|
||||||
|
github.com/alibabacloud-go/tea-fileform v1.1.1/go.mod h1:ZeCV91o4ISmxidd686f0ebdS5EDHWU+vW+TkjLhrsFE=
|
||||||
|
github.com/alibabacloud-go/tea-oss-sdk v1.1.3/go.mod h1:yUnodpR3Bf2rudLE7V/Gft5txjJF30Pk+hH77K/Eab0=
|
||||||
|
github.com/alibabacloud-go/tea-oss-sdk v1.1.5 h1:CFUFcqanvBaoGN/CyTHUZrVNtFZd1WTjem46m0HTTV0=
|
||||||
|
github.com/alibabacloud-go/tea-oss-sdk v1.1.5/go.mod h1:5fhlKMa/kWRJNgPYRt+5qSg3UidRvNbf9Z2bI8Dp5/s=
|
||||||
|
github.com/alibabacloud-go/tea-oss-utils v1.1.0 h1:y65crjjcZ2Pbb6UZtC2deuIZHDVTS3IaDWE7M9nVLRc=
|
||||||
|
github.com/alibabacloud-go/tea-oss-utils v1.1.0/go.mod h1:PFCF12e9yEKyBUIn7X1IrF/pNjvxgkHy0CgxX4+xRuY=
|
||||||
|
github.com/alibabacloud-go/tea-utils v1.3.1/go.mod h1:EI/o33aBfj3hETm4RLiAxF/ThQdSngxrpF8rKUDJjPE=
|
||||||
|
github.com/alibabacloud-go/tea-utils v1.3.6/go.mod h1:EI/o33aBfj3hETm4RLiAxF/ThQdSngxrpF8rKUDJjPE=
|
||||||
|
github.com/alibabacloud-go/tea-utils v1.4.5 h1:h0/6Xd2f3bPE4XHTvkpjwxowIwRCJAJOqY6Eq8f3zfA=
|
||||||
|
github.com/alibabacloud-go/tea-utils v1.4.5/go.mod h1:KNcT0oXlZZxOXINnZBs6YvgOd5aYp9U67G+E3R8fcQw=
|
||||||
|
github.com/alibabacloud-go/tea-utils/v2 v2.0.0/go.mod h1:U5MTY10WwlquGPS34DOeomUGBB0gXbLueiq5Trwu0C4=
|
||||||
|
github.com/alibabacloud-go/tea-utils/v2 v2.0.3/go.mod h1:sj1PbjPodAVTqGTA3olprfeeqqmwD0A5OQz94o9EuXQ=
|
||||||
|
github.com/alibabacloud-go/tea-utils/v2 v2.0.5/go.mod h1:dL6vbUT35E4F4bFTHL845eUloqaerYBYPsdWR2/jhe4=
|
||||||
|
github.com/alibabacloud-go/tea-utils/v2 v2.0.6/go.mod h1:qxn986l+q33J5VkialKMqT/TTs3E+U9MJpd001iWQ9I=
|
||||||
|
github.com/alibabacloud-go/tea-utils/v2 v2.0.7 h1:WDx5qW3Xa5ZgJ1c8NfqJkF6w+AU5wB8835UdhPr6Ax0=
|
||||||
|
github.com/alibabacloud-go/tea-utils/v2 v2.0.7/go.mod h1:qxn986l+q33J5VkialKMqT/TTs3E+U9MJpd001iWQ9I=
|
||||||
|
github.com/alibabacloud-go/tea-xml v1.1.1/go.mod h1:Rq08vgCcCAjHyRi/M7xlHKUykZCEtyBy9+DPF6GgEu8=
|
||||||
|
github.com/alibabacloud-go/tea-xml v1.1.2/go.mod h1:Rq08vgCcCAjHyRi/M7xlHKUykZCEtyBy9+DPF6GgEu8=
|
||||||
|
github.com/alibabacloud-go/tea-xml v1.1.3 h1:7LYnm+JbOq2B+T/B0fHC4Ies4/FofC4zHzYtqw7dgt0=
|
||||||
|
github.com/alibabacloud-go/tea-xml v1.1.3/go.mod h1:Rq08vgCcCAjHyRi/M7xlHKUykZCEtyBy9+DPF6GgEu8=
|
||||||
|
github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc=
|
||||||
|
github.com/alicebob/miniredis v2.5.0+incompatible/go.mod h1:8HZjEj4yU0dwhYHky+DxYx+6BMjkBbe5ONFIF1MXffk=
|
||||||
|
github.com/aliyun/alibaba-cloud-sdk-go v1.63.49 h1:79qdt3Rzg3fQV/KwNwpBjOUW108Ram/fSda6IC/vF0k=
|
||||||
|
github.com/aliyun/alibaba-cloud-sdk-go v1.63.49/go.mod h1:SOSDHfe1kX91v3W5QiBsWSLqeLxImobbMX1mxrFHsVQ=
|
||||||
|
github.com/aliyun/credentials-go v1.1.2/go.mod h1:ozcZaMR5kLM7pwtCMEpVmQ242suV6qTJya2bDq4X1Tw=
|
||||||
|
github.com/aliyun/credentials-go v1.3.1/go.mod h1:8jKYhQuDawt8x2+fusqa1Y6mPxemTsBEN04dgcAcYz0=
|
||||||
|
github.com/aliyun/credentials-go v1.3.6/go.mod h1:1LxUuX7L5YrZUWzBrRyk0SwSdH4OmPrib8NVePL3fxM=
|
||||||
|
github.com/aliyun/credentials-go v1.3.10/go.mod h1:Jm6d+xIgwJVLVWT561vy67ZRP4lPTQxMbEYRuT2Ti1U=
|
||||||
|
github.com/aliyun/credentials-go v1.4.5/go.mod h1:Jm6d+xIgwJVLVWT561vy67ZRP4lPTQxMbEYRuT2Ti1U=
|
||||||
|
github.com/aliyun/credentials-go v1.4.6 h1:CG8rc/nxCNKfXbZWpWDzI9GjF4Tuu3Es14qT8Y0ClOk=
|
||||||
|
github.com/aliyun/credentials-go v1.4.6/go.mod h1:Jm6d+xIgwJVLVWT561vy67ZRP4lPTQxMbEYRuT2Ti1U=
|
||||||
|
github.com/anxpp/beego v1.12.2-no-color-info h1:wuWLtMoUcjiCKOVZxps7Ur5yzm9Xq7OMsW7RHNJ//qQ=
|
||||||
|
github.com/anxpp/beego v1.12.2-no-color-info/go.mod h1:fH8i0zzzdz83XlTnHhwkinhyWY4C66ZEA7C5tqkeIio=
|
||||||
|
github.com/anxpp/common-utils v0.0.0-20250612015512-2dc997d0693c h1:85zxsmewhZ2/EaeKeegi8yWN4DL0SK4Q/1k8xXpsdYg=
|
||||||
|
github.com/anxpp/common-utils v0.0.0-20250612015512-2dc997d0693c/go.mod h1:aIMWzeXuzYK3m3M/bKfG+B71mKgy4Uy0GP61+yYr7Hc=
|
||||||
|
github.com/apache/rocketmq-client-go/v2 v2.1.2 h1:yt73olKe5N6894Dbm+ojRf/JPiP0cxfDNNffKwhpJVg=
|
||||||
|
github.com/apache/rocketmq-client-go/v2 v2.1.2/go.mod h1:6I6vgxHR3hzrvn+6n/4mrhS+UTulzK/X9LB2Vk1U5gE=
|
||||||
|
github.com/beego/goyaml2 v0.0.0-20130207012346-5545475820dd/go.mod h1:1b+Y/CofkYwXMUU0OhQqGvsY2Bvgr4j6jfT699wyZKQ=
|
||||||
|
github.com/beego/x2j v0.0.0-20131220205130-a0352aadc542/go.mod h1:kSeGC/p1AbBiEp5kat81+DSQrZenVBZXklMLaELspWU=
|
||||||
|
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||||
|
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||||
|
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||||
|
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||||
|
github.com/bradfitz/gomemcache v0.0.0-20180710155616-bc664df96737/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60=
|
||||||
|
github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
|
||||||
|
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
|
||||||
|
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
|
||||||
|
github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
|
||||||
|
github.com/bytedance/sonic v1.12.1 h1:jWl5Qz1fy7X1ioY74WqO0KjAMtAGQs4sYnjiEBiyX24=
|
||||||
|
github.com/bytedance/sonic v1.12.1/go.mod h1:B8Gt/XvtZ3Fqj+iSKMypzymZxw/FVwgIGKzMzT9r/rk=
|
||||||
|
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
|
||||||
|
github.com/bytedance/sonic/loader v0.2.0 h1:zNprn+lsIP06C/IqCHs3gPQIvnvpKbbxyXQP1iU4kWM=
|
||||||
|
github.com/bytedance/sonic/loader v0.2.0/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
|
||||||
|
github.com/casbin/casbin v1.7.0/go.mod h1:c67qKN6Oum3UF5Q1+BByfFxkwKvhwW57ITjqwtzR1KE=
|
||||||
|
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||||
|
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
|
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
|
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||||
|
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
|
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||||
|
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||||
|
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||||
|
github.com/clbanning/mxj/v2 v2.5.5/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=
|
||||||
|
github.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME=
|
||||||
|
github.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=
|
||||||
|
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||||
|
github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58/go.mod h1:EOBUe0h4xcZ5GoxqC5SDxFQ8gwyZPKQoEzownBlhI80=
|
||||||
|
github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
|
||||||
|
github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
|
||||||
|
github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
|
||||||
|
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
|
||||||
|
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||||
|
github.com/couchbase/go-couchbase v0.0.0-20200519150804-63f3cdb75e0d/go.mod h1:TWI8EKQMs5u5jLKW/tsb9VwauIrMIxQG1r5fMsswK5U=
|
||||||
|
github.com/couchbase/gomemcached v0.0.0-20200526233749-ec430f949808/go.mod h1:srVSlQLB8iXBVXHgnqemxUXqN6FCvClgCMPCsjBDR7c=
|
||||||
|
github.com/couchbase/goutils v0.0.0-20180530154633-e865a1461c8a/go.mod h1:BQwMFlJzDjFDG3DJUdU0KORxn88UlsOULuxLExMh3Hs=
|
||||||
|
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||||
|
github.com/cupcake/rdb v0.0.0-20161107195141-43ba34106c76/go.mod h1:vYwsqCOLxGiisLwp9rITslkFNpZD5rz43tf41QFkTWY=
|
||||||
|
github.com/dave/jennifer v1.6.1/go.mod h1:nXbxhEmQfOZhWml3D1cDK5M1FLnMSozpbFN/m3RmGZc=
|
||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||||
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
|
||||||
|
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||||
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
|
||||||
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
||||||
|
github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c=
|
||||||
|
github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4=
|
||||||
|
github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
|
||||||
|
github.com/elastic/go-elasticsearch/v6 v6.8.5/go.mod h1:UwaDJsD3rWLM5rKNFzv9hgox93HoX8utj1kxD9aFUcI=
|
||||||
|
github.com/elastic/go-sysinfo v1.0.2/go.mod h1:O/D5m1VpYLwGjCYzEt63g3Z1uO3jXfwyzzjiW90t8cY=
|
||||||
|
github.com/elastic/go-sysinfo v1.15.0 h1:54pRFlAYUlVNQ2HbXzLVZlV+fxS7Eax49stzg95M4Xw=
|
||||||
|
github.com/elastic/go-sysinfo v1.15.0/go.mod h1:jPSuTgXG+dhhh0GKIyI2Cso+w5lPJ5PvVqKlL8LV/Hk=
|
||||||
|
github.com/elastic/go-windows v1.0.0 h1:qLURgZFkkrYyTTkvYpsZIgf83AUsdIHfvlJaqaZ7aSY=
|
||||||
|
github.com/elastic/go-windows v1.0.0/go.mod h1:TsU0Nrp7/y3+VwE82FoZF8gC/XFg/Elz6CcloAxnPgU=
|
||||||
|
github.com/elazarl/go-bindata-assetfs v1.0.0 h1:G/bYguwHIzWq9ZoyUQqrjTmJbbYn3j3CKKpKinvZLFk=
|
||||||
|
github.com/elazarl/go-bindata-assetfs v1.0.0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4=
|
||||||
|
github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg=
|
||||||
|
github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
|
||||||
|
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||||
|
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||||
|
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||||
|
github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
|
||||||
|
github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw=
|
||||||
|
github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
|
||||||
|
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
||||||
|
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||||
|
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||||
|
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||||
|
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
||||||
|
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
|
||||||
|
github.com/gabriel-vasile/mimetype v1.4.5 h1:J7wGKdGu33ocBOhGy0z653k/lFKLFDPJMG8Gql0kxn4=
|
||||||
|
github.com/gabriel-vasile/mimetype v1.4.5/go.mod h1:ibHel+/kbxn9x2407k1izTA1S81ku1z/DlgOW2QE0M4=
|
||||||
|
github.com/gammazero/toposort v0.1.1 h1:OivGxsWxF3U3+U80VoLJ+f50HcPU1MIqE1JlKzoJ2Eg=
|
||||||
|
github.com/gammazero/toposort v0.1.1/go.mod h1:H2cozTnNpMw0hg2VHAYsAxmkHXBYroNangj2NTBQDvw=
|
||||||
|
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||||
|
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||||
|
github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU=
|
||||||
|
github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
|
||||||
|
github.com/glendc/gopher-json v0.0.0-20170414221815-dc4743023d0c/go.mod h1:Gja1A+xZ9BoviGJNA2E9vFkPjjsl+CoJxSXiQM1UXtw=
|
||||||
|
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||||
|
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||||
|
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||||
|
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||||
|
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||||
|
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||||
|
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
||||||
|
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||||
|
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
|
||||||
|
github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs=
|
||||||
|
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
|
||||||
|
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
||||||
|
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
|
||||||
|
github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA=
|
||||||
|
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
||||||
|
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||||
|
github.com/go-playground/validator/v10 v10.7.0/go.mod h1:xm76BBt941f7yWdGnI2DVPFFg1UK3YY04qifoXU3lOk=
|
||||||
|
github.com/go-playground/validator/v10 v10.22.0 h1:k6HsTZ0sTnROkhS//R0O+55JgM8C4Bx7ia+JlgcnOao=
|
||||||
|
github.com/go-playground/validator/v10 v10.22.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
|
||||||
|
github.com/go-redis/redis v6.14.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
|
||||||
|
github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo=
|
||||||
|
github.com/go-resty/resty/v2 v2.15.3 h1:bqff+hcqAflpiF591hhJzNdkRsFhlB96CYfBwSFvql8=
|
||||||
|
github.com/go-resty/resty/v2 v2.15.3/go.mod h1:0fHAoK7JoBy/Ch36N8VFeMsK7xQOHhvWaC3iOktwmIU=
|
||||||
|
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||||
|
github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc=
|
||||||
|
github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
|
||||||
|
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||||
|
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||||
|
github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA=
|
||||||
|
github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
|
||||||
|
github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw=
|
||||||
|
github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
|
||||||
|
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||||
|
github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A=
|
||||||
|
github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk=
|
||||||
|
github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
||||||
|
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA=
|
||||||
|
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
|
||||||
|
github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A=
|
||||||
|
github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI=
|
||||||
|
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
|
||||||
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||||
|
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||||
|
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
||||||
|
github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc=
|
||||||
|
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
|
||||||
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||||
|
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||||
|
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||||
|
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||||
|
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||||
|
github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
|
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
|
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
||||||
|
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
|
github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
|
||||||
|
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||||
|
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
|
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
|
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||||
|
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
|
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||||
|
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
|
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||||
|
github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00 h1:l5lAOZEym3oK3SQ2HBHWsJUfbNBiTXJDeW2QDxw9AQ0=
|
||||||
|
github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||||
|
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
|
||||||
|
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
|
||||||
|
github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
|
||||||
|
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
||||||
|
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||||
|
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||||
|
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||||
|
github.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=
|
||||||
|
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||||
|
github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8=
|
||||||
|
github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
|
||||||
|
github.com/jackc/pgconn v1.13.0 h1:3L1XMNV2Zvca/8BYhzcRFS70Lr0WlDg16Di6SFGAbys=
|
||||||
|
github.com/jackc/pgconn v1.13.0/go.mod h1:AnowpAqO4CMIIJNZl2VJp+KrkAZciAkhEl0W0JIobpI=
|
||||||
|
github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE=
|
||||||
|
github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8=
|
||||||
|
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
||||||
|
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||||
|
github.com/jackc/pgproto3/v2 v2.3.1 h1:nwj7qwf0S+Q7ISFfBndqeLwSwxs+4DPsbRFjECT1Y4Y=
|
||||||
|
github.com/jackc/pgproto3/v2 v2.3.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
|
||||||
|
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg=
|
||||||
|
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E=
|
||||||
|
github.com/jackc/pgtype v1.12.0 h1:Dlq8Qvcch7kiehm8wPGIW0W3KsCCHJnRacKW0UM8n5w=
|
||||||
|
github.com/jackc/pgtype v1.12.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4=
|
||||||
|
github.com/jackc/pgx/v4 v4.17.2 h1:0Ut0rpeKwvIVbMQ1KbMBU4h6wxehBI535LK6Flheh8E=
|
||||||
|
github.com/jackc/pgx/v4 v4.17.2/go.mod h1:lcxIZN44yMIrWI78a5CpucdD14hX0SBDbNRvjDBItsw=
|
||||||
|
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||||
|
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||||
|
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||||
|
github.com/jinzhu/now v1.1.2/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||||
|
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
|
||||||
|
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||||
|
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
|
||||||
|
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
|
||||||
|
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
|
||||||
|
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
|
||||||
|
github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901/go.mod h1:Z86h9688Y0wesXCyonoVr47MasHilkuLMqGhRZ4Hpak=
|
||||||
|
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||||
|
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||||
|
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||||
|
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||||
|
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||||
|
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||||
|
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
||||||
|
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||||
|
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||||
|
github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
|
||||||
|
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
|
||||||
|
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
|
||||||
|
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||||
|
github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM=
|
||||||
|
github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
||||||
|
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
|
||||||
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
|
github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8=
|
||||||
|
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
|
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||||
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
|
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||||
|
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
|
||||||
|
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||||
|
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||||
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
|
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
||||||
|
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||||
|
github.com/ledisdb/ledisdb v0.0.0-20200510135210-d35789ec47e6/go.mod h1:n931TsDuKuq+uX4v1fulaMbA/7ZLLhjc85h7chZGBCQ=
|
||||||
|
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
|
||||||
|
github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
|
||||||
|
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
|
||||||
|
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
|
||||||
|
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||||
|
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
|
||||||
|
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
||||||
|
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
||||||
|
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||||
|
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||||
|
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
|
github.com/mattn/go-sqlite3 v1.14.8/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
||||||
|
github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U=
|
||||||
|
github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||||
|
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||||
|
github.com/microsoft/go-mssqldb v0.17.0 h1:Fto83dMZPnYv1Zwx5vHHxpNraeEaUlQ/hhHLgZiaenE=
|
||||||
|
github.com/microsoft/go-mssqldb v0.17.0/go.mod h1:OkoNGhGEs8EZqchVTtochlXruEhEOaO4S0d2sB5aeGQ=
|
||||||
|
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
||||||
|
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
|
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
|
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
|
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||||
|
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||||
|
github.com/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8eaE=
|
||||||
|
github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
|
||||||
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||||
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||||
|
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||||
|
github.com/natefinch/lumberjack v2.0.0+incompatible h1:4QJd3OLAMgj7ph+yZTuX13Ld4UpgHp07nNdFX7mqFfM=
|
||||||
|
github.com/natefinch/lumberjack v2.0.0+incompatible/go.mod h1:Wi9p2TTF5DG5oU+6YfsmYQpsTIOm0B1VNzQg9Mw6nPk=
|
||||||
|
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||||
|
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||||
|
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
||||||
|
github.com/olivere/elastic/v7 v7.0.32 h1:R7CXvbu8Eq+WlsLgxmKVKPox0oOwAE/2T9Si5BnvK6E=
|
||||||
|
github.com/olivere/elastic/v7 v7.0.32/go.mod h1:c7PVmLe3Fxq77PIfY/bZmxY/TAamBhCzZ8xDOE09a9k=
|
||||||
|
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
|
github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg=
|
||||||
|
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
||||||
|
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
|
||||||
|
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
|
||||||
|
github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
|
||||||
|
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||||
|
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||||
|
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
|
||||||
|
github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs=
|
||||||
|
github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b h1:FfH+VrHHk6Lxt9HdVS0PXzSXFyS2NbZKXv33FYPol0A=
|
||||||
|
github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b/go.mod h1:AC62GU6hc0BrNm+9RK9VSiwa/EUe1bkIeFORAMcHvJU=
|
||||||
|
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
|
||||||
|
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
|
||||||
|
github.com/pelletier/go-toml v1.0.1/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||||
|
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||||
|
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
|
||||||
|
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
|
||||||
|
github.com/peterh/liner v1.0.1-0.20171122030339-3681c2a91233/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc=
|
||||||
|
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||||
|
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||||
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||||
|
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||||
|
github.com/prometheus/client_golang v1.7.0/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
|
||||||
|
github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y=
|
||||||
|
github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
|
||||||
|
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||||
|
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
|
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
|
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
|
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
|
||||||
|
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
|
||||||
|
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||||
|
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
|
||||||
|
github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc=
|
||||||
|
github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8=
|
||||||
|
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||||
|
github.com/prometheus/procfs v0.0.0-20190425082905-87a4384529e0/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||||
|
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||||
|
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
|
||||||
|
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
|
||||||
|
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
|
||||||
|
github.com/qiniu/dyn v1.3.0/go.mod h1:E8oERcm8TtwJiZvkQPbcAh0RL8jO1G0VXJMW3FAWdkk=
|
||||||
|
github.com/qiniu/go-sdk/v7 v7.25.0 h1:Roi4XMxRly9K4wb87DhQOKaQylyiphEXC7/l8uqJZaQ=
|
||||||
|
github.com/qiniu/go-sdk/v7 v7.25.0/go.mod h1:uZE85Pi0ftIHT/UNLShosdzwsovqpdas0LwAGO7cPao=
|
||||||
|
github.com/qiniu/x v1.10.5/go.mod h1:03Ni9tj+N2h2aKnAz+6N0Xfl8FwMEDRC2PAlxekASDs=
|
||||||
|
github.com/redis/go-redis/v9 v9.7.0 h1:HhLSs+B6O021gwzl+locl0zEDnyNkxMtf/Z3NNBMa9E=
|
||||||
|
github.com/redis/go-redis/v9 v9.7.0/go.mod h1:f6zhXITC7JUJIlPEiBOTXxJgPLdZcA93GewI7inzyWw=
|
||||||
|
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||||
|
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
|
||||||
|
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
|
||||||
|
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
|
||||||
|
github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ=
|
||||||
|
github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4=
|
||||||
|
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
|
||||||
|
github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
|
||||||
|
github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 h1:X+yvsM2yrEktyI+b2qND5gpH8YhURn0k8OCaeRnkINo=
|
||||||
|
github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644/go.mod h1:nkxAfR/5quYxwPZhyDxgasBMnRtBZd0FCEpawpjMUFg=
|
||||||
|
github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k=
|
||||||
|
github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME=
|
||||||
|
github.com/siddontang/go v0.0.0-20170517070808-cb568a3e5cc0/go.mod h1:3yhqj7WBBfRhbBlzyOC3gUxftwsU0u8gqevxwIHQpMw=
|
||||||
|
github.com/siddontang/goredis v0.0.0-20150324035039-760763f78400/go.mod h1:DDcKzU3qCuvj/tPnimWSsZZzvk9qvkvrIL5naVBPh5s=
|
||||||
|
github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d/go.mod h1:AMEsy7v5z92TR1JKMkLLoaOQk++LVnOKL3ScbJ8GNGA=
|
||||||
|
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||||
|
github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||||
|
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||||
|
github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I=
|
||||||
|
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||||
|
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||||
|
github.com/smartystreets/assertions v1.1.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo=
|
||||||
|
github.com/smartystreets/assertions v1.1.1 h1:T/YLemO5Yp7KPzS+lVtu+WsHn8yoSwTfItdAd1r3cck=
|
||||||
|
github.com/smartystreets/assertions v1.1.1/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo=
|
||||||
|
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
|
||||||
|
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||||
|
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
|
||||||
|
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
|
||||||
|
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
|
||||||
|
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
|
||||||
|
github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
|
||||||
|
github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
|
||||||
|
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||||
|
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
|
github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI=
|
||||||
|
github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg=
|
||||||
|
github.com/ssdb/gossdb v0.0.0-20180723034631-88f6b59b84ec/go.mod h1:QBvMkMya+gXctz3kmljlUCu/yB3GZ6oee+dUozsezQE=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||||
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
|
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||||
|
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||||
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
|
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||||
|
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
|
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
|
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||||
|
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||||
|
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
|
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
|
||||||
|
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
|
||||||
|
github.com/syndtr/goleveldb v0.0.0-20160425020131-cfa635847112/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0=
|
||||||
|
github.com/syndtr/goleveldb v0.0.0-20181127023241-353a9fca669c/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0=
|
||||||
|
github.com/tealeg/xlsx v1.0.5 h1:+f8oFmvY8Gw1iUXzPk+kz+4GpbDZPK1FhPiQRd+ypgE=
|
||||||
|
github.com/tealeg/xlsx v1.0.5/go.mod h1:btRS8dz54TDnvKNosuAqxrM1QgN1udgk9O34bDCnORM=
|
||||||
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/clb v1.0.1038 h1:o959ZjutJ3JNTRPUhlxtcHusxTNXhyZhw4kzsyUlcSI=
|
||||||
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/clb v1.0.1038/go.mod h1:ycOzZvXJAduBYfdglvjE6MEqw78thHkQlpOJedJSt7A=
|
||||||
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1031/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
|
||||||
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1038 h1:tB3DLzyQXavvGTI+JUvEcuYh0EtTn1rvh9W6xxFHL38=
|
||||||
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1038/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
|
||||||
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/sms v1.0.1031 h1:H6dg0sRgD4Cv5gLh6Dyb9YZgSKZRPuxePuSq/S6YwjQ=
|
||||||
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/sms v1.0.1031/go.mod h1:g8gKXKzfVl//PXhLeyRk2Nzlct7hMwHszgWcD2pdVFk=
|
||||||
|
github.com/tidwall/gjson v1.13.0 h1:3TFY9yxOQShrvmjdM76K+jc66zJeT6D3/VFFYCGQf7M=
|
||||||
|
github.com/tidwall/gjson v1.13.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||||
|
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
|
||||||
|
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
|
||||||
|
github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
|
||||||
|
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||||
|
github.com/tjfoc/gmsm v1.3.2/go.mod h1:HaUcFuY0auTiaHB9MHFGCPx5IaLhTUd2atbCFBQXn9w=
|
||||||
|
github.com/tjfoc/gmsm v1.4.1 h1:aMe1GlZb+0bLjn+cKTPEvvn9oUEBlJitaZiiBwsbgho=
|
||||||
|
github.com/tjfoc/gmsm v1.4.1/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE=
|
||||||
|
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
|
||||||
|
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
|
||||||
|
github.com/uber/jaeger-client-go v2.30.0+incompatible h1:D6wyKGCecFaSRUpo8lCVbaOOb6ThwMmTEbhRwtKR97o=
|
||||||
|
github.com/uber/jaeger-client-go v2.30.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk=
|
||||||
|
github.com/uber/jaeger-lib v2.4.1+incompatible h1:td4jdvLcExb4cBISKIpHuGoVXh+dVKhn2Um6rjCsSsg=
|
||||||
|
github.com/uber/jaeger-lib v2.4.1+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U=
|
||||||
|
github.com/ugorji/go v0.0.0-20171122102828-84cb69a8af83/go.mod h1:hnLbHMwcvSihnDhEfx2/BzKp2xb0Y+ErdfYcrs9tkJQ=
|
||||||
|
github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
|
||||||
|
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
||||||
|
github.com/wechatpay-apiv3/wechatpay-go v0.2.21 h1:uIyMpzvcaHA33W/QPtHstccw+X52HO1gFdvVL9O6Lfs=
|
||||||
|
github.com/wechatpay-apiv3/wechatpay-go v0.2.21/go.mod h1:A254AUBVB6R+EqQFo3yTgeh7HtyqRRtN2w9hQSOrd4Q=
|
||||||
|
github.com/wendal/errors v0.0.0-20130201093226-f66c77a7882b/go.mod h1:Q12BUT7DqIlHRmgv3RskH+UCM/4eqVMgI0EMmlSpAXc=
|
||||||
|
github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
|
||||||
|
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
|
||||||
|
github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY=
|
||||||
|
github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4=
|
||||||
|
github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8=
|
||||||
|
github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM=
|
||||||
|
github.com/yidun/yidun-golang-sdk v1.0.29 h1:/KGl1g4LCMGoY8EwpfQ/G+eAsW57CvAi29drrKMECYA=
|
||||||
|
github.com/yidun/yidun-golang-sdk v1.0.29/go.mod h1:+JGdWbkUvLi9uKTtHI+nrxajulfZKA7BXDPlzt1RCsU=
|
||||||
|
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 h1:ilQV1hzziu+LLM3zUTJ0trRztfwgjqKnBWNtSRkbmwM=
|
||||||
|
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfSfmXjznFBSZNN13rSJjlIOI1fUNAtF7rmI=
|
||||||
|
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
|
github.com/yuin/goldmark v1.1.30/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
|
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
|
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||||
|
github.com/yuin/gopher-lua v0.0.0-20171031051903-609c9cd26973/go.mod h1:aEV29XrmTYFr3CiRxZeGHpkvbwq+prZduBqMaascyCU=
|
||||||
|
go.mongodb.org/mongo-driver v1.17.1 h1:Wic5cJIwJgSpBhe3lx3+/RybR5PiYRMpVFgO7cOHyIM=
|
||||||
|
go.mongodb.org/mongo-driver v1.17.1/go.mod h1:wwWm/+BuOddhcq3n68LKRmgk2wXzmF6s0SFOa0GINL4=
|
||||||
|
go.opentelemetry.io/otel v1.31.0 h1:NsJcKPIW0D0H3NgzPDHmo0WW6SptzPdqg/L1zsIm2hY=
|
||||||
|
go.opentelemetry.io/otel v1.31.0/go.mod h1:O0C14Yl9FgkjqcCZAsE053C13OaddMYr/hz6clDkEJE=
|
||||||
|
go.opentelemetry.io/otel/trace v1.31.0 h1:ffjsj1aRouKewfr85U2aGagJ46+MvodynlQ1HYdmJys=
|
||||||
|
go.opentelemetry.io/otel/trace v1.31.0/go.mod h1:TXZkRk7SM2ZQLtR6eoAWQFIHPvzQ06FJAsO1tJg480A=
|
||||||
|
go.uber.org/atomic v1.5.1/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||||
|
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
|
||||||
|
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||||
|
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||||
|
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||||
|
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||||
|
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||||
|
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
|
||||||
|
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
||||||
|
golang.org/x/arch v0.9.0 h1:ub9TgUInamJ8mrZIGlBG6/4TqWeMszd4N8lNorbrr6k=
|
||||||
|
golang.org/x/arch v0.9.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
|
||||||
|
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/crypto v0.0.0-20191219195013-becbf705a915/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
|
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
|
golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
|
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
|
||||||
|
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
||||||
|
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
|
||||||
|
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||||
|
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
|
||||||
|
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||||
|
golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
|
||||||
|
golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw=
|
||||||
|
golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U=
|
||||||
|
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
|
golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
|
golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
|
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
|
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
|
||||||
|
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g=
|
||||||
|
golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k=
|
||||||
|
golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
|
||||||
|
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||||
|
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||||
|
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8 h1:hVwzHzIUGRjiF7EcUjqNxk3NCfkPxbDKRdnNE1Rpg0U=
|
||||||
|
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||||
|
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
|
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||||
|
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
|
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
|
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||||
|
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
||||||
|
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||||
|
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
|
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||||
|
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
|
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
|
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||||
|
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||||
|
golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0=
|
||||||
|
golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||||
|
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||||
|
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||||
|
golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
|
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
|
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
|
||||||
|
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||||
|
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||||
|
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||||
|
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||||
|
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
||||||
|
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
||||||
|
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
|
||||||
|
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||||
|
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
||||||
|
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||||
|
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
|
||||||
|
golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4=
|
||||||
|
golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||||
|
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
|
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
|
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
|
||||||
|
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190425145619-16072639606e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200509044756-6aff5f38e54f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
|
||||||
|
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
|
||||||
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
|
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||||
|
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||||
|
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
|
||||||
|
golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
|
||||||
|
golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY=
|
||||||
|
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||||
|
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
|
||||||
|
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
||||||
|
golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0=
|
||||||
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
|
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
||||||
|
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
|
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||||
|
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||||
|
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
|
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
|
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
|
||||||
|
golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
|
||||||
|
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||||
|
golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
|
golang.org/x/time v0.13.0 h1:eUlYslOIt32DgYD6utsuUeHs4d7AsEYLuIAdg7FlYgI=
|
||||||
|
golang.org/x/time v0.13.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=
|
||||||
|
golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||||
|
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
|
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
|
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20200117065230-39095c1d176c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
|
golang.org/x/tools v0.0.0-20200509030707-2212a7e161a5/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||||
|
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
|
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||||
|
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||||
|
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
||||||
|
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||||
|
golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=
|
||||||
|
golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ=
|
||||||
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo=
|
||||||
|
gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0=
|
||||||
|
gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw=
|
||||||
|
gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc=
|
||||||
|
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||||
|
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
|
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||||
|
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||||
|
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
|
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||||
|
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||||
|
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||||
|
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||||
|
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||||
|
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||||
|
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||||
|
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||||
|
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||||
|
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||||
|
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||||
|
google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA=
|
||||||
|
google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||||
|
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||||
|
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk=
|
||||||
|
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||||
|
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||||
|
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||||
|
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AWRXxgwEyPp2z+p0+hgMuE=
|
||||||
|
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw=
|
||||||
|
gopkg.in/ini.v1 v1.56.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
|
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
|
||||||
|
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
|
gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
|
||||||
|
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
|
||||||
|
gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
|
||||||
|
gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
|
||||||
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||||
|
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||||
|
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gorm.io/datatypes v1.1.1-0.20230130040222-c43177d3cf8c h1:jWdr7cHgl8c/ua5vYbR2WhSp+NQmzhsj0xoY3foTzW8=
|
||||||
|
gorm.io/datatypes v1.1.1-0.20230130040222-c43177d3cf8c/go.mod h1:SH2K9R+2RMjuX1CkCONrPwoe9JzVv2hkQvEu4bXGojE=
|
||||||
|
gorm.io/driver/mysql v1.5.7 h1:MndhOPYOfEp2rHKgkZIhJ16eVUIRf2HmzgoPmh7FCWo=
|
||||||
|
gorm.io/driver/mysql v1.5.7/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM=
|
||||||
|
gorm.io/driver/postgres v1.4.5 h1:mTeXTTtHAgnS9PgmhN2YeUbazYpLhUI1doLnw42XUZc=
|
||||||
|
gorm.io/driver/postgres v1.4.5/go.mod h1:GKNQYSJ14qvWkvPwXljMGehpKrhlDNsqYRr5HnYGncg=
|
||||||
|
gorm.io/driver/sqlite v1.1.6/go.mod h1:W8LmC/6UvVbHKah0+QOC7Ja66EaZXHwUTjgXY8YNWX8=
|
||||||
|
gorm.io/driver/sqlite v1.4.3 h1:HBBcZSDnWi5BW3B3rwvVTc510KGkBkexlOg0QrmLUuU=
|
||||||
|
gorm.io/driver/sqlite v1.4.3/go.mod h1:0Aq3iPO+v9ZKbcdiz8gLWRw5VOPcBOPUQJFLq5e2ecI=
|
||||||
|
gorm.io/driver/sqlserver v1.4.1 h1:t4r4r6Jam5E6ejqP7N82qAJIJAht27EGT41HyPfXRw0=
|
||||||
|
gorm.io/driver/sqlserver v1.4.1/go.mod h1:DJ4P+MeZbc5rvY58PnmN1Lnyvb5gw5NPzGshHDnJLig=
|
||||||
|
gorm.io/gen v0.3.26 h1:sFf1j7vNStimPRRAtH4zz5NiHM+1dr6eA9aaRdplyhY=
|
||||||
|
gorm.io/gen v0.3.26/go.mod h1:a5lq5y3w4g5LMxBcw0wnO6tYUCdNutWODq5LrIt75LE=
|
||||||
|
gorm.io/gorm v1.21.15/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0=
|
||||||
|
gorm.io/gorm v1.22.2/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0=
|
||||||
|
gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
|
||||||
|
gorm.io/gorm v1.25.12 h1:I0u8i2hWQItBq1WfE0o2+WuL9+8L21K9e2HHSTE/0f8=
|
||||||
|
gorm.io/gorm v1.25.12/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ=
|
||||||
|
gorm.io/hints v1.1.0 h1:Lp4z3rxREufSdxn4qmkK3TLDltrM10FLTHiuqwDPvXw=
|
||||||
|
gorm.io/hints v1.1.0/go.mod h1:lKQ0JjySsPBj3uslFzY3JhYDtqEwzm+G1hv8rWujB6Y=
|
||||||
|
gorm.io/plugin/dbresolver v1.5.3 h1:wFwINGZZmttuu9h7XpvbDHd8Lf9bb8GNzp/NpAMV2wU=
|
||||||
|
gorm.io/plugin/dbresolver v1.5.3/go.mod h1:TSrVhaUg2DZAWP3PrHlDlITEJmNOkL0tFTjvTEsQ4XE=
|
||||||
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
howett.net/plist v0.0.0-20181124034731-591f970eefbb h1:jhnBjNi9UFpfpl8YZhA9CrOqpnJdvzuiHsl/dnxl11M=
|
||||||
|
howett.net/plist v0.0.0-20181124034731-591f970eefbb/go.mod h1:vMygbs4qMhSZSc4lCUl2OEE+rDiIIJAIdR4m7MiMcm0=
|
||||||
|
modernc.org/fileutil v1.0.0 h1:Z1AFLZwl6BO8A5NldQg/xTSjGLetp+1Ubvl4alfGx8w=
|
||||||
|
modernc.org/fileutil v1.0.0/go.mod h1:JHsWpkrk/CnVV1H/eGlFf85BEpfkrp56ro8nojIq9Q8=
|
||||||
|
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
|
||||||
|
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
||||||
|
stathat.com/c/consistent v1.0.0 h1:ezyc51EGcRPJUxfHGSgJjWzJdj3NiMU9pNfLNGiXV0c=
|
||||||
|
stathat.com/c/consistent v1.0.0/go.mod h1:QkzMWzcbB+yQBL2AttO6sgsQS/JSTapcDISJalmCDS0=
|
||||||
46
pkg/authmeta/rbac.go
Normal file
46
pkg/authmeta/rbac.go
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
package authmeta
|
||||||
|
|
||||||
|
// 定义通用
|
||||||
|
|
||||||
|
type TenantItem struct {
|
||||||
|
Name string
|
||||||
|
Type string
|
||||||
|
Code string
|
||||||
|
}
|
||||||
|
|
||||||
|
type ScopeItem struct {
|
||||||
|
Name string
|
||||||
|
Type string
|
||||||
|
Code string
|
||||||
|
}
|
||||||
|
|
||||||
|
type PrivilegeItem struct {
|
||||||
|
Name string
|
||||||
|
Type string
|
||||||
|
Code string
|
||||||
|
Children []PrivilegeItem
|
||||||
|
}
|
||||||
|
|
||||||
|
// (comment:(?<name>.+)){0}" json.*`$
|
||||||
|
type RoleItem struct {
|
||||||
|
Name string
|
||||||
|
Code string
|
||||||
|
UserType string
|
||||||
|
Desc string
|
||||||
|
PrivilegeResource []string
|
||||||
|
PrivilegeInterface []string
|
||||||
|
}
|
||||||
|
|
||||||
|
type AdminUser struct {
|
||||||
|
Username string
|
||||||
|
Channel string
|
||||||
|
ChannelCode string
|
||||||
|
Nickname string
|
||||||
|
Desc string
|
||||||
|
State int32
|
||||||
|
Password string
|
||||||
|
PassCipher string
|
||||||
|
PassSalt string
|
||||||
|
ExtID string
|
||||||
|
Roles []string
|
||||||
|
}
|
||||||
174
pkg/cache/RedisSingleton.go
vendored
Normal file
174
pkg/cache/RedisSingleton.go
vendored
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
package cache
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
redis "github.com/redis/go-redis/v9"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 公共redis单例
|
||||||
|
var commonInstance *singleton
|
||||||
|
var commonOnce sync.Once
|
||||||
|
|
||||||
|
func CommonClient() *redis.Client {
|
||||||
|
return GetCommonRedisInstance().RedisClient
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取公用redis连接
|
||||||
|
func GetCommonRedisInstance() *singleton {
|
||||||
|
commonOnce.Do(func() {
|
||||||
|
commonInstance = &singleton{}
|
||||||
|
commonInstance.RedisClient = createCommonmRedisClient()
|
||||||
|
})
|
||||||
|
return commonInstance
|
||||||
|
}
|
||||||
|
|
||||||
|
// 用户redis单例
|
||||||
|
var userInstance *singleton
|
||||||
|
var userOnce sync.Once
|
||||||
|
|
||||||
|
func UserClient() *redis.Client {
|
||||||
|
return GetUserRedisInstance().RedisClient
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取公用redis连接
|
||||||
|
func GetUserRedisInstance() *singleton {
|
||||||
|
userOnce.Do(func() {
|
||||||
|
userInstance = &singleton{}
|
||||||
|
userInstance.RedisClient = createUserRedisClient()
|
||||||
|
})
|
||||||
|
return userInstance
|
||||||
|
}
|
||||||
|
|
||||||
|
// 用户关系redis单例
|
||||||
|
var relationInstance *singleton
|
||||||
|
var relationOnce sync.Once
|
||||||
|
|
||||||
|
// 获取relation redis连接
|
||||||
|
func GetUserRelationRedisInstance() *singleton {
|
||||||
|
relationOnce.Do(func() {
|
||||||
|
relationInstance = &singleton{}
|
||||||
|
relationInstance.RedisClient = createUserRelationRedisClient()
|
||||||
|
})
|
||||||
|
return relationInstance
|
||||||
|
}
|
||||||
|
|
||||||
|
// 动态redis单例
|
||||||
|
var timelineInstance *singleton
|
||||||
|
var timelineOnce sync.Once
|
||||||
|
|
||||||
|
// 获取动态redis连接
|
||||||
|
func GetTimelineRedisInstance() *singleton {
|
||||||
|
timelineOnce.Do(func() {
|
||||||
|
timelineInstance = &singleton{}
|
||||||
|
timelineInstance.RedisClient = createTimelineRedisClient()
|
||||||
|
})
|
||||||
|
return timelineInstance
|
||||||
|
}
|
||||||
|
|
||||||
|
// 活动redis单例
|
||||||
|
var activityInstance *singleton
|
||||||
|
var activityOnce sync.Once
|
||||||
|
|
||||||
|
func ActivityClient() *redis.Client {
|
||||||
|
return GetActivityRedisInstance().RedisClient
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取活动redis连接
|
||||||
|
func GetActivityRedisInstance() *singleton {
|
||||||
|
activityOnce.Do(func() {
|
||||||
|
activityInstance = &singleton{}
|
||||||
|
activityInstance.RedisClient = createActivityRedisClient()
|
||||||
|
})
|
||||||
|
return activityInstance
|
||||||
|
}
|
||||||
|
|
||||||
|
// 公会redis单例
|
||||||
|
var guildInstance *singleton
|
||||||
|
var guildOnce sync.Once
|
||||||
|
|
||||||
|
func GuildClient() *redis.Client {
|
||||||
|
return GetGuildRedisInstance().RedisClient
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取公会redis连接
|
||||||
|
func GetGuildRedisInstance() *singleton {
|
||||||
|
guildOnce.Do(func() {
|
||||||
|
guildInstance = &singleton{}
|
||||||
|
guildInstance.RedisClient = createGuildRedisClient()
|
||||||
|
})
|
||||||
|
return guildInstance
|
||||||
|
}
|
||||||
|
|
||||||
|
// 聊天室redis单例
|
||||||
|
var chatroomInstance *singleton
|
||||||
|
var chatroomOnce sync.Once
|
||||||
|
|
||||||
|
func RoomClient() *redis.Client {
|
||||||
|
return GetChatroomRedisInstance().RedisClient
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取chatroom redis连接
|
||||||
|
func GetChatroomRedisInstance() *singleton {
|
||||||
|
chatroomOnce.Do(func() {
|
||||||
|
chatroomInstance = &singleton{}
|
||||||
|
chatroomInstance.RedisClient = createChatroomRedisClient()
|
||||||
|
})
|
||||||
|
return chatroomInstance
|
||||||
|
}
|
||||||
|
|
||||||
|
// SESSION redis单例
|
||||||
|
var sessionInstance *singleton
|
||||||
|
var sessionOnce sync.Once
|
||||||
|
|
||||||
|
// 获取Session redis连接
|
||||||
|
func GetSessionRedisInstance() *singleton {
|
||||||
|
sessionOnce.Do(func() {
|
||||||
|
sessionInstance = &singleton{}
|
||||||
|
sessionInstance.RedisClient = createSessionRedisClient()
|
||||||
|
})
|
||||||
|
return sessionInstance
|
||||||
|
}
|
||||||
|
|
||||||
|
// 技能订单redis单例
|
||||||
|
var skillInstance *singleton
|
||||||
|
var skillOnce sync.Once
|
||||||
|
|
||||||
|
// 获取用户关系redis连接
|
||||||
|
func GetSkillRedisInstance() *singleton {
|
||||||
|
skillOnce.Do(func() {
|
||||||
|
skillInstance = &singleton{}
|
||||||
|
skillInstance.RedisClient = createSkillRedisClient()
|
||||||
|
})
|
||||||
|
return skillInstance
|
||||||
|
}
|
||||||
|
|
||||||
|
// 活动redis单例
|
||||||
|
var imInstance *singleton
|
||||||
|
var imOnce sync.Once
|
||||||
|
|
||||||
|
// 获取用户关系redis连接
|
||||||
|
func GetIMRedisInstance() *singleton {
|
||||||
|
imOnce.Do(func() {
|
||||||
|
imInstance = &singleton{}
|
||||||
|
imInstance.RedisClient = createIMRedisClient()
|
||||||
|
})
|
||||||
|
return imInstance
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cms系统 redis单例
|
||||||
|
var cmsInstance *singleton
|
||||||
|
var cmsOnce sync.Once
|
||||||
|
|
||||||
|
func CmsClient() *redis.Client {
|
||||||
|
return GetCmsRedisInstance().RedisClient
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取公用redis连接
|
||||||
|
func GetCmsRedisInstance() *singleton {
|
||||||
|
cmsOnce.Do(func() {
|
||||||
|
cmsInstance = &singleton{}
|
||||||
|
cmsInstance.RedisClient = createCmsRedisClient()
|
||||||
|
})
|
||||||
|
return cmsInstance
|
||||||
|
}
|
||||||
163
pkg/cache/redis_client.go
vendored
Normal file
163
pkg/cache/redis_client.go
vendored
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
package cache
|
||||||
|
|
||||||
|
import (
|
||||||
|
logs "servicebase/pkg/log"
|
||||||
|
"context"
|
||||||
|
|
||||||
|
redis "github.com/redis/go-redis/v9"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
)
|
||||||
|
|
||||||
|
type singleton struct {
|
||||||
|
RedisClient *redis.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
func Ctx() context.Context {
|
||||||
|
return context.Background()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建公共的redis
|
||||||
|
func createCommonmRedisClient() *redis.Client {
|
||||||
|
client := redis.NewClient(&redis.Options{
|
||||||
|
Addr: viper.GetString("redis.default.addr"),
|
||||||
|
Password: viper.GetString("redis.default.pass"),
|
||||||
|
DB: 0,
|
||||||
|
PoolSize: 32,
|
||||||
|
MinIdleConns: 4,
|
||||||
|
})
|
||||||
|
logs.Info("#REDIS#" + "创建一个 common redis连接池,返回一个连接" + "#REDIS#")
|
||||||
|
return client
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建user的redis
|
||||||
|
func createUserRedisClient() *redis.Client {
|
||||||
|
client := redis.NewClient(&redis.Options{
|
||||||
|
Addr: viper.GetString("redis.default.addr"),
|
||||||
|
Password: viper.GetString("redis.default.pass"), // no password set
|
||||||
|
DB: 1,
|
||||||
|
PoolSize: 32,
|
||||||
|
MinIdleConns: 4,
|
||||||
|
})
|
||||||
|
|
||||||
|
logs.Info("#REDIS#" + "创建一个 user redis连接池,返回一个连接" + "#REDIS#")
|
||||||
|
return client
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建relation的redis
|
||||||
|
func createUserRelationRedisClient() *redis.Client {
|
||||||
|
client := redis.NewClient(&redis.Options{
|
||||||
|
Addr: viper.GetString("redis.default.addr"),
|
||||||
|
Password: viper.GetString("redis.default.pass"), // no password set
|
||||||
|
DB: 2,
|
||||||
|
PoolSize: 32,
|
||||||
|
MinIdleConns: 4,
|
||||||
|
})
|
||||||
|
logs.Info("#REDIS#" + "创建一个 relation redis连接池,返回一个连接" + "#REDIS#")
|
||||||
|
return client
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建timeline的redis
|
||||||
|
func createTimelineRedisClient() *redis.Client {
|
||||||
|
client := redis.NewClient(&redis.Options{
|
||||||
|
Addr: viper.GetString("redis.default.addr"),
|
||||||
|
Password: viper.GetString("redis.default.pass"), // no password set
|
||||||
|
DB: 3,
|
||||||
|
PoolSize: 32,
|
||||||
|
MinIdleConns: 4,
|
||||||
|
})
|
||||||
|
logs.Info("#REDIS#" + "创建一个 timeline redis连接池,返回一个连接" + "#REDIS#")
|
||||||
|
return client
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建活动的redis
|
||||||
|
func createActivityRedisClient() *redis.Client {
|
||||||
|
client := redis.NewClient(&redis.Options{
|
||||||
|
Addr: viper.GetString("redis.activity.addr"),
|
||||||
|
Password: viper.GetString("redis.activity.pass"), // no password set
|
||||||
|
DB: viper.GetInt("redis.activity.db"),
|
||||||
|
PoolSize: 32,
|
||||||
|
MinIdleConns: 4,
|
||||||
|
})
|
||||||
|
logs.Info("#REDIS#" + "创建一个 activity redis连接池,返回一个连接" + "#REDIS#")
|
||||||
|
return client
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建俱乐部的redis
|
||||||
|
func createGuildRedisClient() *redis.Client {
|
||||||
|
client := redis.NewClient(&redis.Options{
|
||||||
|
Addr: viper.GetString("redis.guild.addr"),
|
||||||
|
Password: viper.GetString("redis.guild.pass"), // no password set
|
||||||
|
DB: viper.GetInt("redis.guild.db"),
|
||||||
|
PoolSize: 32,
|
||||||
|
MinIdleConns: 4,
|
||||||
|
})
|
||||||
|
logs.Info("#REDIS#" + "创建一个 guild redis连接池,返回一个连接" + "#REDIS#")
|
||||||
|
return client
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建chatroom的redis
|
||||||
|
func createChatroomRedisClient() *redis.Client {
|
||||||
|
client := redis.NewClient(&redis.Options{
|
||||||
|
Addr: viper.GetString("redis.default.addr"),
|
||||||
|
Password: viper.GetString("redis.default.pass"), // no password set
|
||||||
|
DB: 6,
|
||||||
|
PoolSize: 32,
|
||||||
|
MinIdleConns: 4,
|
||||||
|
})
|
||||||
|
logs.Info("#REDIS#" + "创建一个 chatroom redis连接池,返回一个连接" + "#REDIS#")
|
||||||
|
return client
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建session的redis
|
||||||
|
func createSessionRedisClient() *redis.Client {
|
||||||
|
client := redis.NewClient(&redis.Options{
|
||||||
|
Addr: viper.GetString("redis.default.addr"),
|
||||||
|
Password: viper.GetString("redis.default.pass"), // no password set
|
||||||
|
DB: 7,
|
||||||
|
PoolSize: 32,
|
||||||
|
MinIdleConns: 4,
|
||||||
|
})
|
||||||
|
logs.Info("#REDIS#" + "创建一个 session redis连接池,返回一个连接" + "#REDIS#")
|
||||||
|
return client
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建用户关系的redis
|
||||||
|
func createSkillRedisClient() *redis.Client {
|
||||||
|
client := redis.NewClient(&redis.Options{
|
||||||
|
Addr: viper.GetString("redis.default.addr"),
|
||||||
|
Password: viper.GetString("redis.default.pass"), // no password set
|
||||||
|
DB: 8,
|
||||||
|
PoolSize: 32,
|
||||||
|
MinIdleConns: 4,
|
||||||
|
})
|
||||||
|
logs.Info("#REDIS#" + "创建一个 skill redis连接池,返回一个连接" + "#REDIS#")
|
||||||
|
return client
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建IM的redis
|
||||||
|
func createIMRedisClient() *redis.Client {
|
||||||
|
client := redis.NewClient(&redis.Options{
|
||||||
|
Addr: viper.GetString("redis.default.addr"),
|
||||||
|
Password: viper.GetString("redis.default.pass"), // no password set
|
||||||
|
DB: 10,
|
||||||
|
PoolSize: 32,
|
||||||
|
MinIdleConns: 4,
|
||||||
|
})
|
||||||
|
logs.Info("#REDIS#" + "创建一个 im redis连接池,返回一个连接" + "#REDIS#")
|
||||||
|
return client
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建CMS的redis
|
||||||
|
func createCmsRedisClient() *redis.Client {
|
||||||
|
redisHost := viper.GetString("redis.default.addr")
|
||||||
|
redisPwd := viper.GetString("redis.default.pass")
|
||||||
|
client := redis.NewClient(&redis.Options{
|
||||||
|
Addr: redisHost,
|
||||||
|
Password: redisPwd,
|
||||||
|
DB: 11,
|
||||||
|
PoolSize: 32,
|
||||||
|
MinIdleConns: 4,
|
||||||
|
})
|
||||||
|
logs.Info("#REDIS#" + "创建一个 cms redis连接池,返回一个连接" + "#REDIS#")
|
||||||
|
return client
|
||||||
|
}
|
||||||
511
pkg/cache/redis_key.go
vendored
Normal file
511
pkg/cache/redis_key.go
vendored
Normal file
@ -0,0 +1,511 @@
|
|||||||
|
package cache
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
const (
|
||||||
|
// 验证码的RedisKEY + biz_type + mobile = verification code
|
||||||
|
AUTH_CODE_KEY_PREV = "AUTH_CODE_KEY_"
|
||||||
|
SMS_CODE_EXPIRATION_KEY = "SMS_CODE_EXPIRATION_"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
//微信登录用户的KEY + WX_SESSION_ID = WxUser json
|
||||||
|
WX_SESSION_USER_KEY_PREV = "WX_SESSION_USER_KEY_"
|
||||||
|
//微信unionID绑定的嗯嗯ID + WX_UNION_ID = USER_ID
|
||||||
|
WX_UNIONID_BINDED_ID_PREV = "WX_UNIONID_BINDED_ID_"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
//管理员Session + staff_id = staffmodel
|
||||||
|
SESSION_STAFF_PREV = "SESSION_STAFF_"
|
||||||
|
|
||||||
|
BANNER_KEY_PREV = "BANNER_LIST_KEY_PREV_"
|
||||||
|
LuckBoxPrize = "LUCK_BOX_PRIZE"
|
||||||
|
HotBoxPrize = "HOT_BOX_PRIZE"
|
||||||
|
HotBoxAngerPrize = "HOT_BOX_ANGER_PRIZE"
|
||||||
|
PetPrize = "PET_PRIZE"
|
||||||
|
// 下载页
|
||||||
|
COMMON_DOWNLOAD_DATA = "COMMON_DOWNLOAD_DATA"
|
||||||
|
WITHDRAW_WHITE_LIST = "WITHDRAW_SPEC_ACCOUNT_LIST_KEY"
|
||||||
|
JACKPOT_WHITE_LIST = "HIT_EGG_SINGLE_POOL_USER"
|
||||||
|
|
||||||
|
HomeDataConfig = "HOME_DATA_CONFIG"
|
||||||
|
|
||||||
|
AppSettingKey = "APP_SETTING_KEY"
|
||||||
|
|
||||||
|
PRODUCT_KEY_PREV = "PRODUCT_LIST_KEY"
|
||||||
|
ProductNCoin_KEY_PREV = "PRODUCT_N_COIN_LIST_KEY"
|
||||||
|
|
||||||
|
//礼物列表 = string
|
||||||
|
GIFT_WALL_VIEW_LIST_KEY = "TOTALLY_GIFT_LIST_KEY"
|
||||||
|
|
||||||
|
// 审核帐号列表
|
||||||
|
APPLE_APPROVE_ID_LIST_KEY = "APPLE_APPROVE_ID_LIST"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
|
||||||
|
// 验证码的RedisKEY +biz_type+mobile = verification code
|
||||||
|
VERICODE_KEY_PREV = "VERICODE_KEY_"
|
||||||
|
|
||||||
|
// 验证码的默认过期时间 5分钟
|
||||||
|
VERICODE_DEFAULT_EXPIRE_DURATION = time.Minute * 5
|
||||||
|
|
||||||
|
// 登录验证码的过期时间 5分钟
|
||||||
|
SIGN_IN_VERICODE_DURATION = time.Minute * 5
|
||||||
|
|
||||||
|
// 验证码发送时间 + biz_type + mobile = 时间
|
||||||
|
VERICODE_SEND_TIME_PREV = "VERICODE_SEND_TIME_"
|
||||||
|
|
||||||
|
// 授权令牌的redisKEY +access_token = user_id
|
||||||
|
// ACCESSTOKEN_KEY_PREV = "ACCESSTOKEN_"
|
||||||
|
|
||||||
|
//accesstoken 过期时间为30天
|
||||||
|
// ACCESSTOKEN_EXPIRE_DURATION = time.Hour * 24 * 180
|
||||||
|
|
||||||
|
// 用户信息的RedisKEY +user_id = user_model_json
|
||||||
|
USER_DETAIL_KEY_PREV = "USER_DETAIL_"
|
||||||
|
|
||||||
|
// 用户VIP信息的RedisKEY + user_id = user_vip_model_json
|
||||||
|
USER_VIP_MODEL_KEY_PREV = "USER_VIP_MODEL_"
|
||||||
|
|
||||||
|
// 用户粉丝列表 + user_id = zset 按关注时间
|
||||||
|
USER_FAN_LIST_KEY_PREV = "USER_FAN_LIST_KEY_"
|
||||||
|
|
||||||
|
// 用户关注列表 + user_id = zset 按关注时间
|
||||||
|
USER_FOLLOW_LIST_KEY_PREV = "USER_FOLLOW_LIST_KEY_"
|
||||||
|
|
||||||
|
// 用户黑名单列表 + user_id = set
|
||||||
|
USER_BLACK_LIST_KEY_PREV = "USER_BLACK_LIST_KEY_"
|
||||||
|
|
||||||
|
// 数据版本号缓存
|
||||||
|
DATA_VERSION_KEY = "DATA_VERSION_KEY"
|
||||||
|
|
||||||
|
// 兴趣列表的KEY
|
||||||
|
DATA_HOBBIES_KEY = "DATA_HOBBIES_KEY"
|
||||||
|
|
||||||
|
// 黑名单关键词的KEY
|
||||||
|
DATA_BLACK_KEYWORD_KEY = "DATA_BLACK_KEYWORD_KEY"
|
||||||
|
|
||||||
|
//AppSetting的KEY
|
||||||
|
APP_SETTING_KEY = "APP_SETTING_KEY"
|
||||||
|
|
||||||
|
// 首页内容配置
|
||||||
|
HOME_DATA_CONFIG = "HOME_DATA_CONFIG"
|
||||||
|
|
||||||
|
// 七牛图片上传的TOKEN EKY
|
||||||
|
QINIU_PHOTO_UPLOAD_KEY = "QINIU_PHOTO_UPLOAD_KEY"
|
||||||
|
|
||||||
|
// 运营后台七牛图片上传的TOKEN EKY
|
||||||
|
QINIU_PHOTO_UPLOAD_KEY_FOR_OPERATION = "QINIU_PHOTO_UPLOAD_KEY_FOR_OPERATION"
|
||||||
|
|
||||||
|
// 七牛audio上传的TOKEN EKY
|
||||||
|
QINIU_AUDIO_UPLOAD_KEY = "QINIU_AUDIO_UPLOAD_KEY"
|
||||||
|
|
||||||
|
// 七牛VIDEO上传的TOKEN EKY
|
||||||
|
QINIU_VIDEO_UPLOAD_KEY = "QINIU_VIDEO_UPLOAD_KEY"
|
||||||
|
|
||||||
|
// 用户照片墙 + user_id = string
|
||||||
|
USER_PHOTO_LIST_KEY_PREV = "USER_PHOTO_LIST_KEY_"
|
||||||
|
|
||||||
|
// 用户兴趣 + user_id = string
|
||||||
|
USER_HOBBIES_LIST_KEY_PREV = "USER_HOBBIES_LIST_KEY_"
|
||||||
|
|
||||||
|
// 用户Tag + user_id = string
|
||||||
|
USER_TAG_LIST_KEY_PREV = "USER_TAG_LIST_KEY_"
|
||||||
|
|
||||||
|
// 用户Tag + user_id = string
|
||||||
|
USER_CS_SET = "USER_CS_SET"
|
||||||
|
|
||||||
|
// 用户属性 + user_id = string
|
||||||
|
USER_PROP_LIST_KEY_PREV = "USER_PROP_LIST_KEY_"
|
||||||
|
|
||||||
|
// 用户别名 + user_id = hash
|
||||||
|
USER_ALIAS_NAME_KEY_PREV = "USER_ALIAS_NAME_KEY_"
|
||||||
|
|
||||||
|
// 用户最后活跃时间
|
||||||
|
USER_LAST_HEART_TIME = "USER_LAST_HEART_TIME"
|
||||||
|
|
||||||
|
// 商品列表 = string
|
||||||
|
PRODUCT_LIST_KEY = "PRODUCT_LIST_KEY"
|
||||||
|
PRODUCT_N_COIN_LIST_KEY = "PRODUCT_N_COIN_LIST_KEY"
|
||||||
|
|
||||||
|
// 正常的礼物列表 = string
|
||||||
|
GIFT_LIST_KEY = "GIFT_LIST_KEY"
|
||||||
|
|
||||||
|
GENERAL_RANK_REWARD_KEY = "GENERAL_RANK_CHARM_REWARD_KEY"
|
||||||
|
|
||||||
|
GENERAL_RANK_BALLER_KEY = "GENERAL_RANK_BALLER_REWARD_KEY"
|
||||||
|
|
||||||
|
// 全部礼物列表 包括过期的
|
||||||
|
TOTALLY_GIFT_LIST_KEY = "TOTALLY_GIFT_LIST_KEY"
|
||||||
|
|
||||||
|
// 礼物详情 + giftId = DBModel
|
||||||
|
GIFT_DETAIL_KEY_PREV = "GIFT_DETAIL_"
|
||||||
|
|
||||||
|
// 首页tab列表 = string
|
||||||
|
HOME_TAB_LIST_KEY = "HOME_TAB_LIST_KEY"
|
||||||
|
|
||||||
|
//banner列表 + position_code = string
|
||||||
|
BANNER_LIST_KEY_PREV = "app:data:banner"
|
||||||
|
|
||||||
|
// 银行列表
|
||||||
|
BANK_LIST_KEY = "BANK_LIST_KEY"
|
||||||
|
|
||||||
|
// 聊天室模板列表
|
||||||
|
CHATROOM_TEMPLATE_LIST_KEY = "CHATROOM_TEMPLATE_LIST_KEY"
|
||||||
|
|
||||||
|
// 用户收藏的聊天室KEY + user_id
|
||||||
|
USER_COLLECT_CHATROOM_LIST_KEY_PREV = "USER_COLLECT_CHATROOM_LIST_"
|
||||||
|
|
||||||
|
// 用户访问的聊天室KEY + user_id
|
||||||
|
USER_VISITED_CHATROOM_LIST_KEY_PREV = "USER_VISITED_CHATROOM_LIST_"
|
||||||
|
|
||||||
|
// 聊天室周榜key + chatroomid + 年 + 周 = 总魅力 某个聊天室当前周总魅力值
|
||||||
|
CHATROOM_WEEKLY_TOTAL_INCOME_KEY = "CHATROOM_WEEKLY_TOTAL_INCOME_"
|
||||||
|
|
||||||
|
// 聊天室周榜key + chatroomid + 年 + 周 = 总消费 某个聊天室当前周总贡献(流水)
|
||||||
|
CHATROOM_WEEKLY_TOTAL_CONSUME_KEY = "CHATROOM_WEEKLY_TOTAL_CONSUME_"
|
||||||
|
|
||||||
|
// 聊天室周榜key + 年 + 周 = ZSCORE 周聊天室收益排行榜
|
||||||
|
CHATROOM_WEEKLY_ROOM_REVENUE_TOP_LIST = "CHATROOM_WEEKLY_ROOM_REVENUE_TOP_LIST"
|
||||||
|
|
||||||
|
// 房间周贡献榜KEY + chatroomid + 年 + 周 = zset集合 某个聊天室的周贡献榜单
|
||||||
|
CHATROOM_WEEKLY_CONSUME_USER_LIST_KEY_PREV = "CHATROOM_WEEKLY_CONSUME_USER_LIST_KEY_"
|
||||||
|
|
||||||
|
// 房间月贡献榜KEY + chatroomid + 年月 = zset集合 某个聊天室的月贡献榜单
|
||||||
|
CHATROOM_MONTH_CONSUME_USER_LIST_KEY_PREV = "CHATROOM_MONTH_CONSUME_USER_LIST_KEY_"
|
||||||
|
|
||||||
|
// 房间总贡献榜KEY + chatroomid = zset集合 某个聊天室的贡献榜单
|
||||||
|
CHATROOM_ALL_CONSUME_USER_LIST_KEY_PREV = "CHATROOM_ALL_CONSUME_USER_LIST_KEY_"
|
||||||
|
|
||||||
|
// 房间日贡献榜KEY + chatroomid = zset集合 某个聊天室的贡献榜单
|
||||||
|
CHATROOM_DAY_CONSUME_USER_LIST_KEY_PREV = "CHATROOM_DAY_CONSUME_USER_LIST_KEY_"
|
||||||
|
|
||||||
|
// 房间周魅力KEY + chatroomid + 年 + 周 = zset集合 某个聊天室的周魅力榜单
|
||||||
|
CHATROOM_WEEKLY_CHARM_USER_LIST_KEY_PREV = "CHATROOM_WEEKLY_CHARM_USER_LIST_KEY_"
|
||||||
|
|
||||||
|
// 房间月魅力KEY + chatroomid + 年月 = zset集合 某个聊天室的月魅力榜单
|
||||||
|
CHATROOM_MONTH_CHARM_USER_LIST_KEY_PREV = "CHATROOM_MONTH_CHARM_USER_LIST_KEY_"
|
||||||
|
|
||||||
|
// 房间总魅力KEY + chatroomid + 年月 = zset集合 某个聊天室的总魅力榜单
|
||||||
|
CHATROOM_ALL_CHARM_USER_LIST_KEY_PREV = "CHATROOM_ALL_CHARM_USER_LIST_KEY_"
|
||||||
|
|
||||||
|
// 房间日魅力KEY + chatroomid + 日 = zset集合 某个聊天室的日魅力榜单
|
||||||
|
CHATROOM_DAY_CHARM_USER_LIST_KEY_PREV = "CHATROOM_DAY_CHARM_USER_LIST_KEY_"
|
||||||
|
|
||||||
|
// 聊天室超级管理员列表 SET
|
||||||
|
CHATROOM_SUPER_ADMIN_USER_LIST_KEY = "CHATROOM_SUPER_ADMIN_USER_LIST"
|
||||||
|
|
||||||
|
// 聊天室房管列表key+chatroomId SET 某个聊天室的管理员列表
|
||||||
|
CHATROOM_ADMIN_USER_LIST_PREV = "CHATROOM_ADMIN_USER_LIST_"
|
||||||
|
|
||||||
|
// 聊天室主持人列表key+chatroomId SET 某个聊天室的主持人列表
|
||||||
|
CHATROOM_HOST_USER_LIST_PREV = "CHATROOM_HOST_USER_LIST_"
|
||||||
|
|
||||||
|
// 聊天室黑名单列表key+chatroomId SET 某个聊天室的黑名单列表
|
||||||
|
CHATROOM_BLACK_USER_LIST_PREV = "CHATROOM_BLACK_USER_LIST_"
|
||||||
|
|
||||||
|
// 聊天室在线人数 + chatroomId 某个聊天室的在线人数
|
||||||
|
CHATROOM_ONLINE_USER_COUNT_PREV = "CHATROOM_ONLINE_USER_COUNT_"
|
||||||
|
|
||||||
|
// 聊天室在线人数 + chatroomId 某个跟聊天室的在线人数(包含子房间)
|
||||||
|
CHATROOM_ROOT_ONLINE_USER_SET__PREV = "CHATROOM_ROOT_ONLINE_USER_SET_"
|
||||||
|
|
||||||
|
// 开启的聊天室列表key 全服正在开厅的聊天室列表
|
||||||
|
CHATROOM_OPENING_LIST_KEY = "CHATROOM_OPENING_LIST_KEY"
|
||||||
|
|
||||||
|
// 推荐到首页的房间
|
||||||
|
SET_RECOMMEND_ROOM_IDS_KEY = "SET_RECOMMEND_ROOM"
|
||||||
|
|
||||||
|
CHATROOM_EMOJI_RESULT_PREV = "CHATROOM_EMOJI_RESULT_"
|
||||||
|
|
||||||
|
// 聊天室当前主持人 + chatroomId = user_id 某个聊天室当前的主持人ID
|
||||||
|
CHATROOM_CURRENT_HOST_USER_PREV = "CHATROOM_CURRENT_HOST_USER_"
|
||||||
|
|
||||||
|
// 聊天室DBModel缓存 某个聊天室的DB MODEL缓存
|
||||||
|
// CHATROOM_DB_MODEL_KEY_PREV = "CHATROOM_DB_MODEL_KEY_"
|
||||||
|
|
||||||
|
// 聊天室DBModel缓存 某个聊天室的DB MODEL缓存
|
||||||
|
CHATROOM_HOT_SET = "CHATROOM_HOT_SET_"
|
||||||
|
|
||||||
|
// 聊天室EXT DBModel缓存 某个聊天室的EXT DB MODEL缓存
|
||||||
|
CHATROOM_EXT_DB_MODEL_KEY_PREV = "CHATROOM_EXT_DB_MODEL_KEY_PREV"
|
||||||
|
|
||||||
|
// 聊天室全服周贡献榜KEY + 年 + 周 = zset 全服周贡献榜
|
||||||
|
CHATROOM_TOTAL_CONSUME_USER_LIST_PREV = "CHATROOM_TOTAL_CONSUME_USER_LIST_"
|
||||||
|
|
||||||
|
// 聊天室全服周魅力榜KEY + 年 + 周 = zset 全服周魅力榜
|
||||||
|
CHATROOM_TOTAL_CHARM_USER_LIST_PREV = "CHATROOM_TOTAL_CHARM_USER_LIST_"
|
||||||
|
|
||||||
|
// 牵手榜
|
||||||
|
CHATROOM_HAND_PREV = "CHATROOM_HAND_PREV_"
|
||||||
|
|
||||||
|
// 聊天室打赏连击次数key + chatroomId + userId + giftId + touserId = 连击次数
|
||||||
|
CHATROOM_USER_COMBO_HIT_COUNT_PREV = "CHATROOM_USER_COMBO_HIT_COUNT_"
|
||||||
|
|
||||||
|
// 连击已发送的全服消息数 + chatroomId + userId + giftId + touserId = 已发送的飞机数
|
||||||
|
CHATROOM_COMBOHIT_SENDED_FULL_MSG_COUNT_PREV = "CHATROOM_COMBOHIT_SENDED_FULL_MSG_COUNT_"
|
||||||
|
|
||||||
|
// 聊天室表情列表
|
||||||
|
CHATROOM_EMOJI_LIST_KEY = "CHATROOM_EMOJI_LIST_KEY"
|
||||||
|
|
||||||
|
// 聊天室座位缓存 key+chatroomId HASH 某个聊天室的座位列表
|
||||||
|
CHATROOM_SEAT_LIST_HASH_KEY_PREV = "CHATROOM_SEAT_LIST_HASH_KEY_"
|
||||||
|
// 管理员麦序
|
||||||
|
CHATROOM_SEAT_LIST_ADMIN_KEY_PREV = "CHATROOM_SEAT_LIST_ADMIN_"
|
||||||
|
CHATROOM_SEAT_HASH_ADMIN_KEY_PREV = "CHATROOM_SEAT_HASG_ADMIN_"
|
||||||
|
// 自由麦序
|
||||||
|
CHATROOM_SEAT_LIST_FREE_KEY_PREV = "CHATROOM_SEAT_LIST_FREE_"
|
||||||
|
CHATROOM_SEAT_HASH_FREE_KEY_PREV = "CHATROOM_SEAT_HASH_FREE_"
|
||||||
|
// 聊天室排队列表对象缓存 key+chatroomId Hset 某个聊天室的申请上麦列表
|
||||||
|
CHATROOM_WAITING_QUEUE_LIST_REVE = "CHATROOM_WAITING_QUEUE_LIST_"
|
||||||
|
// 聊天室排队列表 有序userId列表
|
||||||
|
CHATROOM_WAITING_QUEUE_SORTED_USERID_PREV = "CHATROOM_WAITING_QUEUE_SORTED_USERID_"
|
||||||
|
CHATROOM_COMMON_SEAT_COUNTDOWN_LOCK = "CHATROOM_COMMON_SEAT_COUNTDOWN_LOCK"
|
||||||
|
CHATROOM_COMMON_SEAT_COUNTDOWN_ZSET = "CHATROOM_COMMON_SEAT_COUNTDOWN"
|
||||||
|
|
||||||
|
// 聊天室的命令编号
|
||||||
|
CHATROOM_CMD_SEQUENCE_NUMBER_PREV = "CHATROOM_CMD_SEQUENCE_NUMBER_"
|
||||||
|
|
||||||
|
// VIP配置列表
|
||||||
|
VIP_CONFIG_MODEL_LIST_KEY = "VIP_CONFIG_MODEL_LIST"
|
||||||
|
|
||||||
|
// VIP配置列表
|
||||||
|
VIP_RIGHT_MODEL_LIST_KEY = "VIP_RIGHT_MODEL_LIST"
|
||||||
|
|
||||||
|
// 用户当前所在的房间ID + userid = chatroomid
|
||||||
|
// USER_CURRENT_IN_CHATROOM_ID_PREV = "USER_CURRENT_IN_CHATROOM_ID_"
|
||||||
|
|
||||||
|
// 用户在聊天室的心跳时间 + userid = datetime
|
||||||
|
USER_IN_CHATROOM_HEARTBEAT_TIME_PREV = "USER_IN_CHATROOM_HEARTBEAT_TIME_"
|
||||||
|
|
||||||
|
// 交友房间的阶段 开始时间 等数据 HASH + chatroomId = hash
|
||||||
|
FRIEND_CHATROOM_GAME_DATA_PREV = "FRIEND_CHATROOM_GAME_DATA_"
|
||||||
|
|
||||||
|
// 被踢出房间的用户KEY +chatroom_id + user_id = 1
|
||||||
|
KICKED_USER_FROM_CHATROOM_PREV = "KICKED_USER_FROM_CHATROOM_"
|
||||||
|
|
||||||
|
// 交友模板 房间当轮魅力值 + chatroomId = zset
|
||||||
|
CHATROOM_CURRENT_ROUND_CHARM_ZSET = "CHATROOM_CURRENT_ROUND_CHARM_ZSET"
|
||||||
|
|
||||||
|
// 聊天室关闭时间 10秒过期,如果存在不能创建 +chatroomId = close_time
|
||||||
|
CHATROOM_CLOSE_TIME_PREV = "CHATROOM_CLOSE_TIME_PREV"
|
||||||
|
|
||||||
|
// 聊天室在线成员列表 + chatroomId = set
|
||||||
|
CHATROOM_ONLINE_MEMBER_LIST_PREV = "CHATROOM_ONLINE_MEMBER_LIST_PREV"
|
||||||
|
|
||||||
|
// 聊天室机器人列表 + chatroomId = set
|
||||||
|
CHATROOM_ROBOT_LIST_PREV = "CHATROOM_ROBOT_LIST_PREV"
|
||||||
|
|
||||||
|
// 聊天室守护配置 string
|
||||||
|
CHATROOM_GUARD_CONFIG_KEY = "CHATROOM_GUARD_CONFIG_KEY"
|
||||||
|
|
||||||
|
// 聊天室活动列表KEY
|
||||||
|
CHATROOM_ACTIVITY_LIST_KEY = "CHATROOM_ACTIVITY_LIST_KEY"
|
||||||
|
|
||||||
|
// 用户隐私设置的KEY +userId = string
|
||||||
|
USER_PRIVACY_SETTING_KEY = "USER_PRIVACY_SETTING_KEY_"
|
||||||
|
|
||||||
|
// 用户头像框的KEY +userId = string
|
||||||
|
USER_AVATAR_DECORATION_KEY = "USER_AVATAR_DECORATION_KEY_"
|
||||||
|
|
||||||
|
// 聊天室背景图 + chatroomID = string
|
||||||
|
CHATROOM_BACKGROUDN_IMG_URL_PREV = "CHATROOM_BACKGROUDN_IMG_URL_"
|
||||||
|
|
||||||
|
// 聊天室每分钟的流水 + chatroomID + 分钟 = int64
|
||||||
|
CHATROOM_MINUTE_REVENUE_PREV = "CHATROOM_MINUTE_REVENUE_"
|
||||||
|
|
||||||
|
// 个人房间在线人数排序SET + CHATROOMID = ZSET SCORE = 人数
|
||||||
|
PERSONAL_ROOM_SORTED_SET = "PERSONAL_ROOM_SORTED_SET"
|
||||||
|
|
||||||
|
// 用户在聊天室里的签结果 + chatroomId + useId = string
|
||||||
|
ROCK_SKEWER_RESULT_PREV = "ROCK_SKEWER_RESULT_"
|
||||||
|
|
||||||
|
// 礼物对应的头饰 + GIFTID = string
|
||||||
|
GIFT_INCLUDED_AVATAR_DECORATION_LIST_PREV = "GIFT_INCLUDED_AVATAR_DECORATION_LIST_"
|
||||||
|
|
||||||
|
// 商品详情 + goodsId = string
|
||||||
|
GOODS_DETAIL_DB_MODEL_PREV = "GOODS_DETAIL_DB_MODEL_"
|
||||||
|
|
||||||
|
// 用户当前使用的头饰或座驾 + GOODS_TYPE + "_" + USER_ID = USER_STORE MODEL STR
|
||||||
|
USER_CURRENT_USED_STORE_MODEL_PREV = "USER_CURRENT_USED_STORE_MODEL_"
|
||||||
|
|
||||||
|
// 订单是否正在支付 + order_id = 1
|
||||||
|
PAY_ORDER_IS_PAYING_PREV = "PAY_ORDER_IS_PAYING_"
|
||||||
|
|
||||||
|
//============= 技能订单相关 ==================
|
||||||
|
|
||||||
|
// 技能对象缓存的KEY + skill_id = string
|
||||||
|
SKILL_MODEL_KEY_PREV = "SKILL_MODEL_"
|
||||||
|
|
||||||
|
// 技能配置
|
||||||
|
SKILL_CONFIG_TREE_HASH_KEY = "SKILL_CONFIG_TREE_HASH"
|
||||||
|
|
||||||
|
// 技能配置
|
||||||
|
SKILL_CONFIG_KEY = "SKILL_CONFIG_"
|
||||||
|
|
||||||
|
// 用户审核中的技能 +user_id = SET
|
||||||
|
USER_APPLYING_SKILL_ID_LIST_PREV = "USER_APPLYING_SKILL_ID_LIST_"
|
||||||
|
|
||||||
|
// /////////////////////////
|
||||||
|
// 派单 1、添加到房间的派单列表 CHATROOM_CURRENT_DISPATCH_ORDER_LIST
|
||||||
|
// 2、追加接单的用户 DISPATCH_ORDER_TO_USER_LIST DISPATCH_ORDER_TO_USER_MAP
|
||||||
|
// 3、用户可接单 DISPATCH_ORDER_USER_GET_LIST
|
||||||
|
// 陪玩接单
|
||||||
|
// 1、移除用户可接单 DISPATCH_ORDER_USER_GET_LIST
|
||||||
|
// 2、添加用户已接单 DISPATCH_ORDER_USER_GET_TAKED_LIST
|
||||||
|
// 3、添加派单已接单用户 DISPATCH_ORDER_TO_USER_TAKED_LIST
|
||||||
|
// 派单结束
|
||||||
|
// 1、删除房间派单列表中的数据 CHATROOM_CURRENT_DISPATCH_ORDER_LIST
|
||||||
|
// 2、用户可解的单中删除该派单 DISPATCH_ORDER_USER_GET_LIST DISPATCH_ORDER_USER_GET_TAKED_LIST
|
||||||
|
// 3、删除派给的用户列表 DISPATCH_ORDER_TO_USER_LIST DISPATCH_ORDER_TO_USER_MAP
|
||||||
|
// /////////////////////////
|
||||||
|
|
||||||
|
// 聊天室当前派单ID + chatroomid = order_id
|
||||||
|
CHATROOM_CURRENT_DISPATCH_ORDER_ID = "CHATROOM_CURRENT_DISPATCH_ORDER_ID_"
|
||||||
|
// 聊天室当前派单列表 + chatroomid = order_id
|
||||||
|
CHATROOM_CURRENT_DISPATCH_ORDER_LIST = "CHATROOM_CURRENT_DISPATCH_ORDER_LIST_"
|
||||||
|
// 当前派单已派的用户LIST + order_id = userIds
|
||||||
|
DISPATCH_ORDER_TO_USER_LIST = "DISPATCH_ORDER_TO_USER_LIST_"
|
||||||
|
// 当前派单已派的用户SET + order_id = userIds (实际是Set)
|
||||||
|
DISPATCH_ORDER_TO_USER_MAP = "DISPATCH_ORDER_TO_USER_MAP_"
|
||||||
|
// 当前用户可接的派单 + user_id = orderIds
|
||||||
|
DISPATCH_ORDER_USER_GET_LIST = "DISPATCH_ORDER_USER_GET_LIST_"
|
||||||
|
// 当前派单接单的用户 + order_id = userIds
|
||||||
|
DISPATCH_ORDER_TO_USER_TAKED_LIST = "DISPATCH_ORDER_TO_USER_TAKED_LIST_"
|
||||||
|
// 当前用户已接的派单 + order_id = userIds
|
||||||
|
DISPATCH_ORDER_USER_GET_TAKED_LIST = "DISPATCH_ORDER_USER_GET_TAKED_LIST_"
|
||||||
|
|
||||||
|
// ============= 定时任务ID ==============
|
||||||
|
|
||||||
|
// 定时清理异常掉线的聊天室用户
|
||||||
|
TASK_ID_CLEAR_CHATROOM_DEADED_USER = "TASK_ID_CLEAR_CHATROOM_DEADED_USER"
|
||||||
|
TASK_ID_CLEAR_DISPATCH_CHATROOM_DEADED_USER = "TASK_ID_CLEAR_DISPATCH_CHATROOM_DEADED_USER"
|
||||||
|
|
||||||
|
// 自动解冻帐号
|
||||||
|
TASK_ID_AUTO_UNFROZEN_USER = "TASK_ID_AUTO_UNFROZEN_USER"
|
||||||
|
|
||||||
|
// 定时清理房间麦序
|
||||||
|
TASK_ID_CLEAR_CHATROOM_SEAT_USER = "TASK_ID_CLEAR_CHATROOM_SEAT_USER"
|
||||||
|
|
||||||
|
// 定时清理个人厅异常掉线的聊天室用户
|
||||||
|
TASK_ID_CLEAR_PERSONAL_CHATROOM_DEADED_USER = "TASK_ID_CLEAR_PERSONAL_CHATROOM_DEADED_USER"
|
||||||
|
|
||||||
|
// ============ 打赏特殊帐号 刷空单 ==================
|
||||||
|
// 老板号
|
||||||
|
DASHANG_SPEC_ACCOUNT_BOSS_LIST_KEY = "DASHANG_SPEC_ACCOUNT_BOSS_LIST"
|
||||||
|
|
||||||
|
// 服务员号
|
||||||
|
DASHANG_SPEC_ACCOUNT_WAITTER_LIST_KEY = "DASHANG_SPEC_ACCOUNT_WAITTER_LIST"
|
||||||
|
|
||||||
|
// 指定厅
|
||||||
|
DASHANG_SPEC_BOSS_WAITTER_ROOM_LIST_KEY = "DASHANG_SPEC_BOSS_WAITTER_ROOM_LIST_KEY"
|
||||||
|
|
||||||
|
// 置顶厅
|
||||||
|
SET_TOP_CHATROOM_ID_LIST_KEY = "SET_TOP_CHATROOM_ID_LIST_KEY"
|
||||||
|
|
||||||
|
// 提现特殊帐号 可日提的
|
||||||
|
WITHDRAW_SPEC_ACCOUNT_LIST_KEY = "WITHDRAW_SPEC_ACCOUNT_LIST_KEY"
|
||||||
|
|
||||||
|
// SVIP用户每次钻石打赏限额 + user_id = 已用
|
||||||
|
HIT_EGG_SVIP_USER_DAY_USED_MONEY = "HIT_EGG_SVIP_USER_DAY_USED_MONEY_"
|
||||||
|
|
||||||
|
// 用户动态数 + user_id = value
|
||||||
|
USER_TIMELINE_COUNT = "USER_TIMELINE_COUNT_"
|
||||||
|
|
||||||
|
// 用户位置的集合
|
||||||
|
LOCATION_USER = "LOCATION_USER"
|
||||||
|
|
||||||
|
// 用户最后获取广播的时间 + user_id = string
|
||||||
|
USER_LAST_GET_BROADCAST_TIME = "USER_LAST_GET_BROADCAST_TIME_"
|
||||||
|
|
||||||
|
// 动态详情model + timelineId = model json
|
||||||
|
TIMELINE_MODEL_PREV = "TIMELINE_MODEL_"
|
||||||
|
|
||||||
|
// 日注册用户数 + YYYY-MM-DD = string
|
||||||
|
DAY_SIGNUP_USER_COUNT_PREV = "DAY_SIGNUP_USER_COUNT_"
|
||||||
|
|
||||||
|
// 技能等级配置
|
||||||
|
SKILL_LEVEL_CONFIG = "SKILL_LEVEL_CONFIG"
|
||||||
|
|
||||||
|
// 动态Location的集合
|
||||||
|
TIMELINE_LOCATION_COLLECTION_KEY = "TIMELINE_LOCATION_COLLECTION"
|
||||||
|
|
||||||
|
// 动态的点赞用户列表 + TIMELINEID = LIST
|
||||||
|
TIMELINE_PRAISED_USER_LIST_PREV = "TIMELINE_PRAISED_USER_LIST_"
|
||||||
|
|
||||||
|
// 动态的点赞数 = string
|
||||||
|
TIMELINE_PRAISED_USER_COUNT_PREV = "TIMELINE_PRAISED_USER_COUNT_"
|
||||||
|
|
||||||
|
// 关注的动态 +userid = list
|
||||||
|
TIMELINE_FOLLOWED_KEY_PREV = "TIMELINE_FOLLOWED_KEY_"
|
||||||
|
|
||||||
|
// 关注的动态 +userid = list
|
||||||
|
TIMELINE_FOLLOWED_NEW_CNT_KEY_PREV = "TIMELINE_FOLLOWED_NEW_CNT_KEY_"
|
||||||
|
|
||||||
|
// 用户勋章缓存 + USER_ID = STR
|
||||||
|
USER_MEDAL_LIST = "USER_MEDAL_LIST_"
|
||||||
|
|
||||||
|
// SKU勋章缓存 + SKU_ID = STR
|
||||||
|
SKU_MEDAL_LIST = "SKU_MEDAL_LIST_"
|
||||||
|
|
||||||
|
// 勋章缓存 = STR
|
||||||
|
MEDAL_LIST_KEY = "MEDAL_LIST_KEY"
|
||||||
|
|
||||||
|
// 进入场景对象缓存 + sceneId = str
|
||||||
|
ENTER_ROOM_SCENE_MODEL_PREV = "ENTER_ROOM_SCENE_MODEL_"
|
||||||
|
|
||||||
|
// VIP SCENE 列表
|
||||||
|
VIP_SCENE_LIST = "VIP_SCENE_LIST"
|
||||||
|
|
||||||
|
// MainTabBar 列表 = string
|
||||||
|
MAIN_TAB_BAR_LIST_KEY = "MAIN_TAB_BAR_LIST"
|
||||||
|
|
||||||
|
// 青少年模式集合
|
||||||
|
CHILD_MODE_SET_KEY = "CHILD_MODE_SET"
|
||||||
|
|
||||||
|
// 爵位配置Hash
|
||||||
|
ALL_NOBILITY_CONFIG_LIST_KEY = "ALL_NOBILITY_CONFIG_LIST"
|
||||||
|
|
||||||
|
// 用户贵族信息的RedisKEY + user_id = user_nobility_model_json
|
||||||
|
USER_NOBILITY_MODEL_KEY_PREV = "USER_NOBILITY_MODEL_"
|
||||||
|
|
||||||
|
// 开箱排行榜KEY
|
||||||
|
USER_OPEN_BOX_RANK_PREV = "USER_OPEN_BOX_RANK_"
|
||||||
|
|
||||||
|
// 易盾TOKEN对应手机号
|
||||||
|
YIDUN_TOKEN_PREV = "YIDUN_TOKEN_"
|
||||||
|
|
||||||
|
//APPLE登录AUTH CODE的key
|
||||||
|
APPLE_AUTH_CODE_PREV = "APPLE_AUTH_CODE_"
|
||||||
|
|
||||||
|
// 用户支付宝充值的支付宝帐号hash + USERID = HASH
|
||||||
|
USER_ALIPAY_RECHARGE_PAY_ACCOUNT_HASH_PREV = "USER_ALIPAY_RECHARGE_PAY_ACCOUNT_HASH_"
|
||||||
|
USER_ALIPAY_RECHARGE_N_COIN_PAY_ACCOUNT_HASH_PREV = "USER_ALI_RECHARGE_N_COIN_ACCOUNT_HASH_"
|
||||||
|
|
||||||
|
// 谁给用户发了多少信息 + USER_ID = HASH
|
||||||
|
USER_MSG_MAP_FROM_PREV = "USER_MSG_MAP_FROM_"
|
||||||
|
|
||||||
|
// 用户特殊颜色缓存
|
||||||
|
USER_SPEC_COLOR_MODEL_PREV = "USER_SPEC_COLOR_MODEL_"
|
||||||
|
|
||||||
|
// 用户IAP充值 预检查通过的key
|
||||||
|
USER_IAP_RECHARGE_PASS_KEY = "USER_IAP_RECHARGE_PASS_"
|
||||||
|
|
||||||
|
// 用户最后获取访客记录的时间
|
||||||
|
USER_LAST_GET_VISITED_LIST_TIME_PREV = "USER_LAST_GET_VISITED_LIST_TIME_"
|
||||||
|
|
||||||
|
// 用户新访客set
|
||||||
|
USER_NEW_VISITOR_SET_PREV = "USER_NEW_VISITOR_SET_"
|
||||||
|
|
||||||
|
// 用户修改昵称缓存记录
|
||||||
|
USER_EDIT_NICKNAME_COUNT_PREV = "USER_EDIT_NICKNAME_COUNT_"
|
||||||
|
|
||||||
|
// 公会相关的
|
||||||
|
// 公会信息
|
||||||
|
GUILD_MODEL_KEY_PREV = "guild:model:"
|
||||||
|
|
||||||
|
// 周星礼物发放定时任务的礼物列表
|
||||||
|
WEEK_STAR_GRANT_GIFT_KEY = "WEEK_STAR_GRANT_GIFT_KEY"
|
||||||
|
)
|
||||||
68
pkg/cache/redis_lock.go
vendored
Normal file
68
pkg/cache/redis_lock.go
vendored
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
package cache
|
||||||
|
|
||||||
|
import (
|
||||||
|
"servicebase/pkg/log"
|
||||||
|
"errors"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Lock(key string) (e error) {
|
||||||
|
var success bool
|
||||||
|
TryMax := 6
|
||||||
|
redisClient := GetCommonRedisInstance().RedisClient
|
||||||
|
for i := 0; i < TryMax; i++ {
|
||||||
|
success, e = redisClient.SetNX(Ctx(), key, time.Now(), time.Millisecond*1000*3).Result()
|
||||||
|
if e != nil {
|
||||||
|
log.Info("Lock GetCommonRedisInstance error: " + e.Error())
|
||||||
|
}
|
||||||
|
if success {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
time.Sleep(time.Millisecond * 50)
|
||||||
|
}
|
||||||
|
return errors.New("操作太频繁了~")
|
||||||
|
}
|
||||||
|
|
||||||
|
func Free(key string) {
|
||||||
|
client := GetCommonRedisInstance().RedisClient
|
||||||
|
_ = client.Del(Ctx(), key).Err()
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
TryMax = int(30)
|
||||||
|
TryDuration = time.Millisecond * 13
|
||||||
|
LockTimeout = time.Millisecond * 700
|
||||||
|
)
|
||||||
|
|
||||||
|
func RedisLockGetTime(key string, duration time.Duration) (e error) {
|
||||||
|
redisClient := GetCommonRedisInstance().RedisClient
|
||||||
|
success, e := redisClient.SetNX(Ctx(), key, "1", duration).Result()
|
||||||
|
if !success {
|
||||||
|
e = errors.New("(LOCK_FAILED)系统繁忙,请稍后再试!")
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func RedisLockGet(key string) (e error) {
|
||||||
|
redisClient := GetCommonRedisInstance().RedisClient
|
||||||
|
success := false
|
||||||
|
for i := 0; i < TryMax; i++ {
|
||||||
|
success, e = redisClient.SetNX(Ctx(), key, time.Now(), LockTimeout).Result()
|
||||||
|
if nil != e {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if success {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
time.Sleep(TryDuration)
|
||||||
|
}
|
||||||
|
if !success {
|
||||||
|
e = errors.New("(LOCK_FAILED)系统繁忙,请稍后再试!")
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func RedisLockDel(key string) {
|
||||||
|
redisClient := GetCommonRedisInstance().RedisClient
|
||||||
|
_ = redisClient.Del(Ctx(), key).Err()
|
||||||
|
}
|
||||||
68
pkg/cache/user/user.go
vendored
Normal file
68
pkg/cache/user/user.go
vendored
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
package cache_user
|
||||||
|
|
||||||
|
import (
|
||||||
|
"servicebase/pkg/cache"
|
||||||
|
"servicebase/pkg/tools"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/anxpp/beego/logs"
|
||||||
|
"github.com/anxpp/common-utils/str"
|
||||||
|
)
|
||||||
|
|
||||||
|
const key = "user:models"
|
||||||
|
const keyToken = "user:token"
|
||||||
|
|
||||||
|
// 用户当前所在的房间ID + userid = chatroomid
|
||||||
|
const ACCESSTOKEN_KEY_PREV = "ACCESSTOKEN_"
|
||||||
|
const ACCESSTOKEN_EXPIRE_DURATION = time.Hour * 24 * 180
|
||||||
|
|
||||||
|
// 通过token获取userId
|
||||||
|
func IdByToken(token string) (userId string) {
|
||||||
|
if len(token) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var e error
|
||||||
|
if userId, e = cache.CommonClient().HGet(cache.Ctx(), keyToken, token).Result(); e != nil || len(userId) == 0 {
|
||||||
|
userId, e = cache.CommonClient().Get(cache.Ctx(), ACCESSTOKEN_KEY_PREV+token).Result()
|
||||||
|
if e != nil {
|
||||||
|
logs.Error("GetUserIdByAccessToken redisError=%v token=%v", e.Error(), token)
|
||||||
|
return
|
||||||
|
} else if len(userId) > 0 {
|
||||||
|
// 迁移token
|
||||||
|
ttl, err := cache.CommonClient().TTL(cache.Ctx(), ACCESSTOKEN_KEY_PREV+token).Result()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
value := fmt.Sprintf("%s#%s", userId, str.TimeToString(time.Now().Add(ttl)))
|
||||||
|
if err := cache.CommonClient().HSet(cache.Ctx(), keyToken, token, value).Err(); err == nil {
|
||||||
|
cache.CommonClient().Del(cache.Ctx(), ACCESSTOKEN_KEY_PREV+token)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
arr := strings.Split(userId, "#")
|
||||||
|
if len(arr) != 2 {
|
||||||
|
_ = IdTokenDel(token)
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
over := tools.StrToDateTime(arr[1])
|
||||||
|
if over.Before(time.Now()) {
|
||||||
|
_ = IdTokenDel(token)
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
userId = arr[0]
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func IdTokenSet(token, userId string) (e error) {
|
||||||
|
value := fmt.Sprintf("%s#%s", userId, str.TimeToString(time.Now().Add(ACCESSTOKEN_EXPIRE_DURATION)))
|
||||||
|
return cache.CommonClient().HSet(cache.Ctx(), keyToken, token, value).Err()
|
||||||
|
}
|
||||||
|
|
||||||
|
func IdTokenDel(token string) (e error) {
|
||||||
|
_, e = cache.CommonClient().HDel(cache.Ctx(), keyToken, token).Result()
|
||||||
|
cache.CommonClient().Del(cache.Ctx(), ACCESSTOKEN_KEY_PREV+token)
|
||||||
|
return
|
||||||
|
}
|
||||||
63
pkg/cerrors/const.go
Normal file
63
pkg/cerrors/const.go
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
package cerrors
|
||||||
|
|
||||||
|
import "errors"
|
||||||
|
|
||||||
|
const (
|
||||||
|
Success = 200
|
||||||
|
|
||||||
|
BadRequest = 400
|
||||||
|
Unauthorized = 401
|
||||||
|
Forbidden = 403
|
||||||
|
NotFound = 404
|
||||||
|
NotAcceptable = 406
|
||||||
|
Gone = 410
|
||||||
|
RangeNotSatisfiable = 416
|
||||||
|
|
||||||
|
ParamError = 501
|
||||||
|
|
||||||
|
InternalServerError = 500
|
||||||
|
ServiceUnavailable = 503
|
||||||
|
|
||||||
|
DataCreateError = 511
|
||||||
|
DataUpdateError = 512
|
||||||
|
DataUpdateNoneError = 515
|
||||||
|
DataReadError = 513
|
||||||
|
DataDeleteError = 514
|
||||||
|
|
||||||
|
// ContentSmsTemplateExistErr 81xx 内容维护错误码
|
||||||
|
ContentSmsTemplateExistErr = 8100
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
CodeMsg = map[int]string{
|
||||||
|
Success: "成功",
|
||||||
|
|
||||||
|
BadRequest: "请求出错",
|
||||||
|
Unauthorized: "登录信息过期",
|
||||||
|
Forbidden: "无权限访问",
|
||||||
|
NotFound: "数据不存在",
|
||||||
|
NotAcceptable: "服务器忙",
|
||||||
|
Gone: "数据已失效",
|
||||||
|
RangeNotSatisfiable: "请求参数范围不支持",
|
||||||
|
|
||||||
|
ParamError: "参数错误",
|
||||||
|
InternalServerError: "服务器错误",
|
||||||
|
ServiceUnavailable: "服务暂不可用",
|
||||||
|
|
||||||
|
DataCreateError: "数据创建失败",
|
||||||
|
DataUpdateError: "数据更新失败",
|
||||||
|
DataUpdateNoneError: "数据更新无效",
|
||||||
|
DataReadError: "数据查询失败",
|
||||||
|
DataDeleteError: "数据删除失败",
|
||||||
|
|
||||||
|
ContentSmsTemplateExistErr: "短信模板已存在",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func Msg(code int) string {
|
||||||
|
return CodeMsg[code]
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetError(code int) error {
|
||||||
|
return errors.New(Msg(code))
|
||||||
|
}
|
||||||
15
pkg/client/configs/mail-template-reset.html
Normal file
15
pkg/client/configs/mail-template-reset.html
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||||
|
<title>{{.Title}}</title>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<p>Hello!</p>
|
||||||
|
<p>This is a password reset email.</p>
|
||||||
|
<a href="{{.Url}}">{{.Url}}</a>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
225
pkg/client/game/wz/wz_client.go
Normal file
225
pkg/client/game/wz/wz_client.go
Normal file
@ -0,0 +1,225 @@
|
|||||||
|
package client_game_wz
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"servicebase/pkg/utils"
|
||||||
|
|
||||||
|
"github.com/anxpp/common-utils/logg"
|
||||||
|
"github.com/anxpp/common-utils/str"
|
||||||
|
)
|
||||||
|
|
||||||
|
const WZYD_TOKEN = "SZN62jr4"
|
||||||
|
const WZYD_UID = "1702857155"
|
||||||
|
|
||||||
|
func RoleInfo(targetUid string) (targetRole map[string]interface{}, e error) {
|
||||||
|
if len(targetUid) == 0 {
|
||||||
|
e = errors.New("参数不足")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
apiUrl := "https://kohcamp.qq.com/game/koh/profile"
|
||||||
|
token := WZYD_TOKEN // 登录王者营地的token
|
||||||
|
uid := WZYD_UID // 营地ID
|
||||||
|
headerMap := make(map[string]string, 0)
|
||||||
|
headerMap["Content-Type"] = "application/json"
|
||||||
|
headerMap["userId"] = uid
|
||||||
|
headerMap["cCurrentGameId"] = "20001"
|
||||||
|
headerMap["Accept-Language"] = "zh-Hans-CN;q=1, en-CN;q=0.9"
|
||||||
|
headerMap["token"] = token
|
||||||
|
|
||||||
|
paraMap := make(map[string]string, 4)
|
||||||
|
paraMap["CampPreloadHTTPHandledIdentifier"] = "2"
|
||||||
|
paraMap["targetUserId"] = targetUid
|
||||||
|
|
||||||
|
resStr, err2 := utils.HttpDo(http.MethodPost, apiUrl, headerMap, str.ToJsonString(paraMap))
|
||||||
|
|
||||||
|
if err2 != nil {
|
||||||
|
logg.Info("调用王者营地数据查询失败", err2.Error())
|
||||||
|
e = fmt.Errorf("调用王者营地数据查询失败: %v", err2.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
logg.Info(resStr)
|
||||||
|
|
||||||
|
resMap := make(map[string]interface{}, 0)
|
||||||
|
json.Unmarshal([]byte(resStr), &resMap)
|
||||||
|
|
||||||
|
if resMap["returnCode"].(float64) != 0 {
|
||||||
|
e = fmt.Errorf("调用王者营地数据查询失败2: %v", resMap["returnMsg"])
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取成功
|
||||||
|
data := resMap["data"].(map[string]interface{})
|
||||||
|
// 默认角色ID
|
||||||
|
targetRoleId := data["targetRoleId"].(string)
|
||||||
|
|
||||||
|
//角色列表
|
||||||
|
roleList := data["roleList"].([]interface{})
|
||||||
|
|
||||||
|
// 匹配默认角色
|
||||||
|
for _, item := range roleList {
|
||||||
|
m := item.(map[string]interface{})
|
||||||
|
if m["roleId"].(string) == targetRoleId {
|
||||||
|
targetRole = m
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if targetRole == nil {
|
||||||
|
e = errors.New("未找到角色信息")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 其他数据
|
||||||
|
head := data["head"].(map[string]interface{})
|
||||||
|
mods := head["mods"].([]interface{})
|
||||||
|
//targetRole["mods"] = mods
|
||||||
|
|
||||||
|
for _, item := range mods {
|
||||||
|
mod := item.(map[string]interface{})
|
||||||
|
modId := mod["modId"].(float64)
|
||||||
|
if modId == 401 {
|
||||||
|
// 总场次
|
||||||
|
targetRole["totalPlayCount"] = mod["content"].(string)
|
||||||
|
} else if modId == 408 {
|
||||||
|
// MVP
|
||||||
|
targetRole["mvpCount"] = mod["content"].(string)
|
||||||
|
} else if modId == 409 {
|
||||||
|
// 胜率
|
||||||
|
targetRole["winRate"] = mod["content"].(string)
|
||||||
|
} else if modId == 201 {
|
||||||
|
// 英雄数
|
||||||
|
targetRole["heroCount"] = mod["content"].(string)
|
||||||
|
} else if modId == 202 {
|
||||||
|
// 皮肤数
|
||||||
|
targetRole["skinCount"] = mod["content"].(string)
|
||||||
|
} else if modId == 702 {
|
||||||
|
// 巅峰赛
|
||||||
|
targetRole["topScore"] = mod["content"].(string)
|
||||||
|
} else if modId == 304 {
|
||||||
|
// 战力
|
||||||
|
targetRole["battleScore"] = mod["content"].(string)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func RoleSkinList(roleId string) (result map[string][]interface{}, e error) {
|
||||||
|
apiUrl := "https://kohcamp.qq.com/game/itempage/skinlist"
|
||||||
|
token := WZYD_TOKEN // 登录王者营地的token
|
||||||
|
uid := WZYD_UID // 营地ID
|
||||||
|
|
||||||
|
if len(roleId) == 0 {
|
||||||
|
e = errors.New("参数不足")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
headerMap := make(map[string]string, 0)
|
||||||
|
headerMap["Content-Type"] = "application/json"
|
||||||
|
headerMap["userId"] = uid
|
||||||
|
headerMap["cCurrentGameId"] = "20001"
|
||||||
|
headerMap["Accept-Language"] = "zh-Hans-CN;q=1, en-CN;q=0.9"
|
||||||
|
headerMap["token"] = token
|
||||||
|
|
||||||
|
paraMap := make(map[string]string, 4)
|
||||||
|
paraMap["roleId"] = roleId
|
||||||
|
|
||||||
|
resStr, err2 := utils.HttpDo(http.MethodPost, apiUrl, headerMap, str.ToJsonString(paraMap))
|
||||||
|
|
||||||
|
if err2 != nil {
|
||||||
|
logg.Info("调用王者营地数据查询失败", err2.Error())
|
||||||
|
e = fmt.Errorf("调用王者营地数据查询失败:%v", err2)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
resMap := make(map[string]interface{}, 0)
|
||||||
|
json.Unmarshal([]byte(resStr), &resMap)
|
||||||
|
|
||||||
|
if _, ok := resMap["returnCode"]; ok {
|
||||||
|
e = fmt.Errorf("调用王者营地数据查询失败2: %v", resMap["returnMsg"])
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//全部皮肤
|
||||||
|
allSkin := resMap["allSkinConf"].([]interface{})
|
||||||
|
// 用户的皮肤
|
||||||
|
userSkinList := resMap["skinData"].([]interface{})
|
||||||
|
|
||||||
|
resultList := []interface{}{}
|
||||||
|
|
||||||
|
rongyaoList := []interface{}{} // 荣耀典藏
|
||||||
|
xiandingList := []interface{}{} // 限定
|
||||||
|
shishiList := []interface{}{} // 史诗级
|
||||||
|
chuanshuoList := []interface{}{} // 传说
|
||||||
|
wushuangList := []interface{}{} //无双
|
||||||
|
|
||||||
|
for _, item := range userSkinList {
|
||||||
|
skinMap := item.(map[string]interface{})
|
||||||
|
userSkinId := skinMap["skinId"].(float64)
|
||||||
|
|
||||||
|
mySkin := getSkinModel(allSkin, userSkinId)
|
||||||
|
mySkin["acquireTime"] = skinMap["acquireTime"].(string)
|
||||||
|
|
||||||
|
// 去掉隐藏的皮肤
|
||||||
|
if mySkin["isHidden"].(float64) == 1 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// 去掉原皮
|
||||||
|
if int64(userSkinId)%100 == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// 等级处理
|
||||||
|
classTypeName := mySkin["classTypeName"].([]interface{})
|
||||||
|
|
||||||
|
nameList := []string{}
|
||||||
|
for _, name := range classTypeName {
|
||||||
|
nameList = append(nameList, name.(string))
|
||||||
|
}
|
||||||
|
|
||||||
|
str := fmt.Sprintf("%s(%s)", mySkin["skinName"].(string), mySkin["heroName"].(string))
|
||||||
|
|
||||||
|
if utils.IsInStringList("荣耀典藏", nameList) {
|
||||||
|
rongyaoList = append(rongyaoList, str)
|
||||||
|
}
|
||||||
|
if utils.IsInStringList("限定", nameList) {
|
||||||
|
xiandingList = append(xiandingList, str)
|
||||||
|
}
|
||||||
|
if utils.IsInStringList("史诗品质", nameList) {
|
||||||
|
shishiList = append(shishiList, str)
|
||||||
|
}
|
||||||
|
if utils.IsInStringList("传说品质", nameList) {
|
||||||
|
chuanshuoList = append(chuanshuoList, str)
|
||||||
|
}
|
||||||
|
if utils.IsInStringList("无双", nameList) {
|
||||||
|
wushuangList = append(wushuangList, str)
|
||||||
|
}
|
||||||
|
|
||||||
|
resultList = append(resultList, mySkin)
|
||||||
|
}
|
||||||
|
|
||||||
|
logg.Info("皮肤数量", len(resultList))
|
||||||
|
|
||||||
|
result = make(map[string][]interface{}, 0)
|
||||||
|
// result["totalCount"] = len(resultList)
|
||||||
|
result["allSkin"] = resultList
|
||||||
|
result["荣耀典藏"] = rongyaoList
|
||||||
|
result["限定"] = xiandingList
|
||||||
|
result["史诗品质"] = shishiList
|
||||||
|
result["传说品质"] = chuanshuoList
|
||||||
|
result["无双"] = wushuangList
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func getSkinModel(allSkin []interface{}, userSkinId float64) (result map[string]interface{}) {
|
||||||
|
for _, item := range allSkin {
|
||||||
|
skin := item.(map[string]interface{})
|
||||||
|
skinId := skin["skinId"].(float64)
|
||||||
|
if skinId == userSkinId {
|
||||||
|
result = skin
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
89
pkg/client/http.go
Normal file
89
pkg/client/http.go
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewClient() *http.Client {
|
||||||
|
tr := &http.Transport{
|
||||||
|
MaxIdleConns: 10,
|
||||||
|
IdleConnTimeout: 30 * time.Second,
|
||||||
|
DisableCompression: true,
|
||||||
|
}
|
||||||
|
return &http.Client{
|
||||||
|
Transport: tr,
|
||||||
|
Timeout: 5 * time.Second,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Get(url string, headers map[string]string, params map[string]string) (res []byte, e error) {
|
||||||
|
var (
|
||||||
|
client = NewClient()
|
||||||
|
resp *http.Response
|
||||||
|
)
|
||||||
|
req, _ := http.NewRequest(http.MethodGet, url, nil)
|
||||||
|
for k, v := range headers {
|
||||||
|
req.Header.Add(k, v)
|
||||||
|
}
|
||||||
|
q := req.URL.Query()
|
||||||
|
for k, v := range params {
|
||||||
|
q.Add(k, v)
|
||||||
|
}
|
||||||
|
req.URL.RawQuery = q.Encode()
|
||||||
|
if resp, e = client.Do(req); e != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer func(body io.ReadCloser) {
|
||||||
|
_ = body.Close()
|
||||||
|
}(resp.Body)
|
||||||
|
if res, e = io.ReadAll(resp.Body); e != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !success(resp.StatusCode) {
|
||||||
|
e = errors.New(fmt.Sprintf("status code error: %s", resp.Status))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func Post(url string, headers map[string]string, body map[string]interface{}) (res []byte, e error) {
|
||||||
|
var (
|
||||||
|
client = NewClient()
|
||||||
|
resp *http.Response
|
||||||
|
)
|
||||||
|
j, e := json.Marshal(body)
|
||||||
|
if e != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
req, _ := http.NewRequest(http.MethodPost, url, bytes.NewBuffer(j))
|
||||||
|
for k, v := range headers {
|
||||||
|
req.Header.Add(k, v)
|
||||||
|
}
|
||||||
|
//q := req.URL.Query()
|
||||||
|
//for k, v := range params {
|
||||||
|
// q.Add(k, v)
|
||||||
|
//}
|
||||||
|
//req.URL.RawQuery = q.Encode()
|
||||||
|
if resp, e = client.Do(req); e != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer func(body io.ReadCloser) {
|
||||||
|
_ = body.Close()
|
||||||
|
}(resp.Body)
|
||||||
|
if res, e = io.ReadAll(resp.Body); e != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !success(resp.StatusCode) {
|
||||||
|
e = errors.New(fmt.Sprintf("status code error: %s", resp.Status))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// func success(code int) bool {
|
||||||
|
// return code >= 200 && code < 400
|
||||||
|
// }
|
||||||
45
pkg/client/http_api/user.go
Normal file
45
pkg/client/http_api/user.go
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
package http_api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"servicebase/pkg/log"
|
||||||
|
"servicebase/pkg/res"
|
||||||
|
"servicebase/pkg/utils"
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/go-resty/resty/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
type InnerLoginReq struct {
|
||||||
|
Mobile string `json:"mobile"`
|
||||||
|
Signature string `json:"signature"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type InnerLoginRes struct {
|
||||||
|
Code string
|
||||||
|
Result res.AccessTokenDTO
|
||||||
|
Msg string
|
||||||
|
}
|
||||||
|
|
||||||
|
func InnerLogin(url, secret, mobile string) (token string, e error) {
|
||||||
|
var req = map[string]string{
|
||||||
|
"mobile": mobile,
|
||||||
|
}
|
||||||
|
sign := utils.CreateApiSign(req, secret)
|
||||||
|
req["Signature"] = sign
|
||||||
|
client := resty.New()
|
||||||
|
_ = client
|
||||||
|
var res InnerLoginRes
|
||||||
|
resp, err := client.R().
|
||||||
|
SetHeader("Content-Type", "application/json").
|
||||||
|
SetBody(req).
|
||||||
|
SetResult(&res). // or SetResult(AuthSuccess{}).
|
||||||
|
Post(url)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
log.InfoF("%++v %v", res, string(resp.Body()))
|
||||||
|
if res.Code == "8000" {
|
||||||
|
return res.Result.AccessToken, nil
|
||||||
|
}
|
||||||
|
return "", errors.New("登录失败:" + res.Msg)
|
||||||
|
}
|
||||||
112
pkg/client/mongo.go
Normal file
112
pkg/client/mongo.go
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"servicebase/pkg/common/req"
|
||||||
|
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
"go.mongodb.org/mongo-driver/bson"
|
||||||
|
"go.mongodb.org/mongo-driver/mongo"
|
||||||
|
"go.mongodb.org/mongo-driver/mongo/options"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MongoInitStarter struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
var Client *mongo.Client
|
||||||
|
var DB *mongo.Database
|
||||||
|
|
||||||
|
func (s *MongoInitStarter) Init() error {
|
||||||
|
var (
|
||||||
|
ctx = context.TODO()
|
||||||
|
host = viper.GetString("db.mongo.host")
|
||||||
|
port = viper.GetString("db.mongo.port")
|
||||||
|
username = viper.GetString("db.mongo.username")
|
||||||
|
password = viper.GetString("db.mongo.password")
|
||||||
|
dbname = viper.GetString("db.mongo.dbname")
|
||||||
|
e error
|
||||||
|
)
|
||||||
|
// log.InfoF(ctx, "host=%s port=%s db=%s", host, port, dbname)
|
||||||
|
if Client, e = mongo.Connect(ctx, options.Client().
|
||||||
|
SetAuth(options.Credential{Username: username, Password: password}).
|
||||||
|
ApplyURI(fmt.Sprintf("mongodb://%s:%s", host, port))); e != nil {
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
DB = Client.Database(dbname)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func CheckTable(c context.Context, table string) error {
|
||||||
|
if r, e := DB.ListCollectionNames(c, bson.M{"name": "table"}); e != nil {
|
||||||
|
return e
|
||||||
|
} else if len(r) == 0 {
|
||||||
|
return DB.CreateCollection(c, table)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func InsertOne(c context.Context, table string, record interface{}) (*mongo.InsertOneResult, error) {
|
||||||
|
if e := CheckTable(c, table); e != nil {
|
||||||
|
return nil, e
|
||||||
|
}
|
||||||
|
return DB.Collection(table).InsertOne(c, record)
|
||||||
|
}
|
||||||
|
|
||||||
|
func SaveOne(c context.Context, table string, filter, record interface{}) (*mongo.UpdateResult, error) {
|
||||||
|
if e := CheckTable(c, table); e != nil {
|
||||||
|
return nil, e
|
||||||
|
}
|
||||||
|
return DB.Collection(table).ReplaceOne(c, filter, record, options.Replace().SetUpsert(true))
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeleteOne(c context.Context, table string, record interface{}) (*mongo.DeleteResult, error) {
|
||||||
|
if e := CheckTable(c, table); e != nil {
|
||||||
|
return nil, e
|
||||||
|
}
|
||||||
|
return DB.Collection(table).DeleteOne(c, record)
|
||||||
|
}
|
||||||
|
|
||||||
|
func UpdateByID(c context.Context, table string, id interface{}, record interface{}) (*mongo.UpdateResult, error) {
|
||||||
|
if e := CheckTable(c, table); e != nil {
|
||||||
|
return nil, e
|
||||||
|
}
|
||||||
|
return DB.Collection(table).UpdateByID(c, id, bson.D{{Key: "$set", Value: record}})
|
||||||
|
}
|
||||||
|
|
||||||
|
func Page(c context.Context, table string, page req.Page, filter bson.D, results interface{}) (int64, error) {
|
||||||
|
if e := CheckTable(c, table); e != nil {
|
||||||
|
return 0, e
|
||||||
|
}
|
||||||
|
cursor, e := DB.Collection(table).Find(
|
||||||
|
c,
|
||||||
|
filter,
|
||||||
|
options.Find().SetSkip(int64(page.Offset())),
|
||||||
|
options.Find().SetLimit(int64(page.Limit())),
|
||||||
|
)
|
||||||
|
if e != nil {
|
||||||
|
// log.ErrorF(c, "db Page error: %v", e)
|
||||||
|
return 0, e
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
if e := cursor.Close(c); e != nil {
|
||||||
|
// log.Error(c, e.Error())
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
if e != nil {
|
||||||
|
return 0, e
|
||||||
|
}
|
||||||
|
cnt, e := DB.Collection(table).CountDocuments(c, filter)
|
||||||
|
if e != nil {
|
||||||
|
return 0, e
|
||||||
|
}
|
||||||
|
return cnt, cursor.All(c, results)
|
||||||
|
}
|
||||||
|
|
||||||
|
func MToD(m bson.M) (d bson.D) {
|
||||||
|
for key, value := range m {
|
||||||
|
d = append(d, bson.E{Key: key, Value: value})
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
132
pkg/client/netease/IMService.go
Normal file
132
pkg/client/netease/IMService.go
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
package Netease
|
||||||
|
|
||||||
|
import (
|
||||||
|
"servicebase/pkg/common/HyTools"
|
||||||
|
"encoding/json"
|
||||||
|
"net/url"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
Netease "servicebase/pkg/common/netease"
|
||||||
|
|
||||||
|
"github.com/anxpp/beego"
|
||||||
|
"github.com/anxpp/beego/logs"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// ChatRoomManagerUserId 聊天室消息管理员ID
|
||||||
|
ChatRoomManagerUserId = "34cc7185d0b60eacf38f616b8aad8c51"
|
||||||
|
SystemNoticeUserId = "x94b992dbb4e4dfca9c971200d797a02"
|
||||||
|
P2pMessagesTypeSystemNotice = "104"
|
||||||
|
TimeDefaultFormat = "Y-m-d H:i:s"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ImService struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// ImMsgBodyAttach IM消息 body对象
|
||||||
|
type ImMsgBodyAttach struct {
|
||||||
|
TypeCode string `json:"TypeCode"`
|
||||||
|
BizData interface{} `json:"BizData"`
|
||||||
|
Msg string `json:"msg,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ChatRoomMsgAttach 聊天室自定义消息
|
||||||
|
type ChatRoomMsgAttach struct {
|
||||||
|
TypeCode string `json:"TypeCode"`
|
||||||
|
BizData interface{} `json:"BizData"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SendCustomMsgToChatroomByChatroomManager 向聊天室发消息
|
||||||
|
func (s *ImService) SendCustomMsgToChatroomByChatroomManager(messageRoomId string, attachData ChatRoomMsgAttach) error {
|
||||||
|
msgParameter := make(map[string]string)
|
||||||
|
msgParameter["roomid"] = messageRoomId
|
||||||
|
msgParameter["msgId"] = HyTools.GetUUID()
|
||||||
|
msgParameter["fromAccid"] = ChatRoomManagerUserId
|
||||||
|
msgParameter["msgType"] = "100" //自定义消息
|
||||||
|
msgParameter["resendFlag"] = "0"
|
||||||
|
bodyBytes, _ := json.Marshal(attachData)
|
||||||
|
msgParameter["ext"] = ""
|
||||||
|
msgParameter["attach"] = string(bodyBytes)
|
||||||
|
imClient := Netease.NewImClient()
|
||||||
|
return imClient.SendChatroomMsg(msgParameter)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SendCustomerMsgFromAToB 发IM点对点自定义消息 系统通知 用户关系变化
|
||||||
|
func (s *ImService) SendCustomerMsgFromAToB(fromAccid, toAccid, pushContent, payloadJson string, bodyModel ImMsgBodyAttach, optionMap map[string]string) error {
|
||||||
|
msgParameter := make(map[string]string)
|
||||||
|
msgParameter["from"] = fromAccid
|
||||||
|
msgParameter["ope"] = "0" //0=p2p 1=群消息
|
||||||
|
msgParameter["to"] = toAccid
|
||||||
|
msgParameter["type"] = "100" //0 表示文本消息, 1 表示图片, 2 表示语音, 3 表示视频, 4 表示地理位置信息, 6 表示文件, 100 自定义消息类型
|
||||||
|
|
||||||
|
bodyBytes, _ := json.Marshal(bodyModel)
|
||||||
|
|
||||||
|
msgParameter["body"] = string(bodyBytes) //最大长度5000字符,为一个JSON串
|
||||||
|
msgParameter["antispam"] = "false" //对于对接了易盾反垃圾功能的应用,本消息是否需要指定经由易盾检测的内容 只对消息类型为:100 自定义消息类型 的消息生效。
|
||||||
|
|
||||||
|
optionBytes, _ := json.Marshal(optionMap)
|
||||||
|
msgParameter["option"] = string(optionBytes) //发消息时特殊指定的行为选项,JSON格式,可用于指定消息的漫游,存云端历史,发送方多端同步,推送,消息抄送等特殊行为
|
||||||
|
|
||||||
|
//需要推送
|
||||||
|
if optionMap["push"] == "true" {
|
||||||
|
if len(pushContent) > 0 {
|
||||||
|
msgParameter["pushcontent"] = pushContent // ios推送内容,不超过150字符,option选项中允许推送(push=true),此字段可以指定推送内容
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(payloadJson) > 0 {
|
||||||
|
msgParameter["payload"] = payloadJson // ios 推送对应的payload,必须是JSON,不能超过2k字符
|
||||||
|
}
|
||||||
|
}
|
||||||
|
imClient := Netease.NewImClient()
|
||||||
|
return imClient.SendMsg(msgParameter)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SendSystemNoticeToUser 给用户发系统消息
|
||||||
|
// _ = messageService.SendSystemNoticeToUser(userId, "厅补贴到账通知", msgContent, "", "")
|
||||||
|
func (s *ImService) SendSystemNoticeToUser(toAccid, msgTitle, msgText, schemeUrl, imageUrl string) {
|
||||||
|
option := GetDefaultMsgOption()
|
||||||
|
fromUserId := SystemNoticeUserId
|
||||||
|
logs.Info("SendSystemNoticeToUser from " + fromUserId + "to " + toAccid)
|
||||||
|
pushContent := ""
|
||||||
|
payloadJson := ""
|
||||||
|
bizData := make(map[string]string, 0)
|
||||||
|
bizData["Title"] = url.QueryEscape(msgTitle)
|
||||||
|
bizData["Content"] = url.QueryEscape(msgText)
|
||||||
|
bizData["Scheme"] = schemeUrl
|
||||||
|
bizData["ImageUrl"] = imageUrl
|
||||||
|
bizData["CreateTime"] = beego.Date(time.Now(), TimeDefaultFormat)
|
||||||
|
//body的业务数据
|
||||||
|
var bodyAttach ImMsgBodyAttach
|
||||||
|
bodyAttach.TypeCode = P2pMessagesTypeSystemNotice
|
||||||
|
bodyAttach.BizData = bizData
|
||||||
|
bodyAttach.Msg = msgTitle
|
||||||
|
err := s.SendCustomerMsgFromAToB(fromUserId, toAccid, pushContent, payloadJson, bodyAttach, option)
|
||||||
|
if nil != err {
|
||||||
|
logs.Error("通知发送失败!!!!")
|
||||||
|
logs.Info(err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetDefaultMsgOption 发送消息默认的配置
|
||||||
|
func GetDefaultMsgOption() map[string]string {
|
||||||
|
/*
|
||||||
|
1. roam: 该消息是否需要漫游,默认true(需要app开通漫游消息功能);
|
||||||
|
2. history: 该消息是否存云端历史,默认true;
|
||||||
|
3. sendersync: 该消息是否需要发送方多端同步,默认true;
|
||||||
|
4. push: 该消息是否需要APNS推送或安卓系统通知栏推送,默认true;
|
||||||
|
5. route: 该消息是否需要抄送第三方;默认true (需要app开通消息抄送功能);
|
||||||
|
6. badge:该消息是否需要计入到未读计数中,默认true;
|
||||||
|
7. needPushNick: 推送文案是否需要带上昵称,不设置该参数时默认true;
|
||||||
|
8. persistent: 是否需要存离线消息,不设置该参数时默认true。
|
||||||
|
*/
|
||||||
|
result := make(map[string]string)
|
||||||
|
result["roam"] = "true"
|
||||||
|
result["history"] = "true"
|
||||||
|
result["sendersync"] = "false"
|
||||||
|
result["push"] = "true"
|
||||||
|
result["route"] = "true"
|
||||||
|
result["badge"] = "true"
|
||||||
|
result["needPushNick"] = "false"
|
||||||
|
result["persistent"] = "true"
|
||||||
|
return result
|
||||||
|
}
|
||||||
104
pkg/client/netease/MessageService.go
Normal file
104
pkg/client/netease/MessageService.go
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
package Netease
|
||||||
|
|
||||||
|
const (
|
||||||
|
// ChatroomCustomMessageTypePresentActivityMsg 聊天室打赏活动物品消息
|
||||||
|
ChatroomCustomMessageTypePresentActivityMsg = "380"
|
||||||
|
// ChatroomCustomMessageTypeFullScreenNoticeMsg 聊天室 全服通知动效
|
||||||
|
ChatroomCustomMessageTypeFullScreenNoticeMsg = "381"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
//聊天室字体颜色 - 黄色
|
||||||
|
CHATROOM_SYSTEM_MSG_COLOR_YELLOW = "#FFD700"
|
||||||
|
//聊天室字体颜色 - 绿色
|
||||||
|
CHATROOM_SYSTEM_MSG_COLOR_GREEN = "#8ADE4D"
|
||||||
|
//聊天室字体颜色 - 系统栏
|
||||||
|
CHATROOM_SYSTEM_MSG_COLOR_SYSTEM_BLUE = "#43EAE1"
|
||||||
|
//聊天室字体颜色 - 紫色
|
||||||
|
CHATROOM_SYSTEM_MSG_COLOR_PURPLE = "#E031FE"
|
||||||
|
// 默认等级的背景颜色
|
||||||
|
SKILL_LEVEL_DEFAULT_BG_COLOR = "#FFD700"
|
||||||
|
//聊天室字体颜色 - 蓝色
|
||||||
|
CHATROOM_SYSTEM_MSG_COLOR_BLUE = "#25C6FD"
|
||||||
|
//聊天室字体颜色 - 青色
|
||||||
|
CHATROOM_SYSTEM_MSG_COLOR_QING = "#00FFCC"
|
||||||
|
//聊天室字体颜色 - 白色
|
||||||
|
CHATROOM_SYSTEM_MSG_COLOR_WHITE = "#FFFFFF"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MessageService struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
type TextAndColor struct {
|
||||||
|
Text string
|
||||||
|
Color string
|
||||||
|
}
|
||||||
|
|
||||||
|
// ChatroomFullScreenNoticeMsgBizData 聊天室活动全服飘屏通知
|
||||||
|
type ChatroomFullScreenNoticeMsgBizData struct {
|
||||||
|
ChatroomId string
|
||||||
|
ContentIcon string
|
||||||
|
ContentText string
|
||||||
|
ContentTextColor string //内容字体颜色
|
||||||
|
ContentBgColor string //背景颜色
|
||||||
|
AnimationApngUrl string //加入播放礼物动效队列
|
||||||
|
BgImgUrl string //背景图
|
||||||
|
TextList []TextAndColor //文字颜色列表
|
||||||
|
StayTime string //停留时长(秒)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ChatroomPresentActivityMsgBizData 聊天室打赏活动消息data数据结构
|
||||||
|
type ChatroomPresentActivityMsgBizData struct {
|
||||||
|
ChatroomId string
|
||||||
|
FromUserId string
|
||||||
|
FromNickName string
|
||||||
|
FromAvatar string
|
||||||
|
FromNickNameColor string //打赏人昵称颜色
|
||||||
|
ActionText string //动作文本 :赠送一个盲盒给
|
||||||
|
ActionTextColor string //动作文本颜色
|
||||||
|
|
||||||
|
ToNickName string
|
||||||
|
ToNickNameColor string //被打赏人昵称颜色
|
||||||
|
|
||||||
|
PresentCount string //物品个数
|
||||||
|
PresentGoodsName string
|
||||||
|
PresentGoodsIcon string
|
||||||
|
PresentGoodsNameColor string
|
||||||
|
|
||||||
|
ResultGoodsIcon string
|
||||||
|
ComboHitCount string //连击次数
|
||||||
|
AnimationApngUrl string //加入播放礼物动效队列 有的话显示播放动画
|
||||||
|
AnimationFormat string //动画格式 SVGA APNG
|
||||||
|
FillMode string //填充模式 1=左右 2=上下
|
||||||
|
|
||||||
|
IsViewFlyView string //是否显示飘屏view 有的话显示连击信息
|
||||||
|
//显示到信息流
|
||||||
|
TextList []TextAndColor //信息流文字颜色列表
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// SendChatroomSystemMsgV2 发送聊天室系统消息 V2
|
||||||
|
func (s *MessageService) SendChatroomSystemMsgV2(messageRoomId string, msgData ChatroomPresentActivityMsgBizData) (err error) {
|
||||||
|
// 发打赏消息
|
||||||
|
var service ImService
|
||||||
|
attachModel := ChatRoomMsgAttach{}
|
||||||
|
//消息类型
|
||||||
|
typeCode := ChatroomCustomMessageTypePresentActivityMsg
|
||||||
|
attachModel.TypeCode = typeCode
|
||||||
|
attachModel.BizData = msgData
|
||||||
|
err = service.SendCustomMsgToChatroomByChatroomManager(messageRoomId, attachModel)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// SendChatroomPresentActivityFullServiceMsg 发送聊天室活动全服
|
||||||
|
func (s *MessageService) SendChatroomPresentActivityFullServiceMsg(messageRoomId string, msgData ChatroomFullScreenNoticeMsgBizData) (err error) {
|
||||||
|
// 发打赏消息
|
||||||
|
var service ImService
|
||||||
|
attachModel := ChatRoomMsgAttach{}
|
||||||
|
//消息类型
|
||||||
|
typeCode := ChatroomCustomMessageTypeFullScreenNoticeMsg
|
||||||
|
attachModel.TypeCode = typeCode
|
||||||
|
attachModel.BizData = msgData
|
||||||
|
err = service.SendCustomMsgToChatroomByChatroomManager(messageRoomId, attachModel)
|
||||||
|
return
|
||||||
|
}
|
||||||
43
pkg/client/netease/captcha.go
Normal file
43
pkg/client/netease/captcha.go
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
package Netease
|
||||||
|
|
||||||
|
import (
|
||||||
|
"servicebase/pkg/log"
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
captcha "github.com/yidun/yidun-golang-sdk/yidun/service/captcha"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
CaptchaId = "28a052c000324d2e992e9e184291c92d"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CaptchaSecondVerify 验证码二次校验请求
|
||||||
|
func CaptchaSecondVerify(captchaId, validate string) (bool, error) {
|
||||||
|
request := captcha.NewCaptchaVerifyRequest()
|
||||||
|
var user string = ""
|
||||||
|
request.SetCaptchaId(captchaId).SetValidate(validate).SetUser(user)
|
||||||
|
secretId := viper.GetString("netease.captcha.secretId")
|
||||||
|
secretKey := viper.GetString("netease.captcha.secretKey")
|
||||||
|
captchaClient := captcha.NewCaptchaVerifyClientWithAccessKey(secretId, secretKey)
|
||||||
|
response, err := captchaClient.Verify(request)
|
||||||
|
if err != nil {
|
||||||
|
log.ErrorF("CaptchaSecondVerify err: %+v", err)
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
if response == nil {
|
||||||
|
log.ErrorF("CaptchaSecondVerify response is nil")
|
||||||
|
return false, errors.Errorf("CaptchaSecondVerify response is nil")
|
||||||
|
}
|
||||||
|
respBody, err := json.Marshal(response)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
log.InfoF("CaptchaSecondVerify response is : %s", string(respBody))
|
||||||
|
if response.Result == nil {
|
||||||
|
log.ErrorF("CaptchaSecondVerify response.Result is nil")
|
||||||
|
return false, errors.Errorf("CaptchaSecondVerify response.Result is nil")
|
||||||
|
}
|
||||||
|
return *response.Result, nil
|
||||||
|
}
|
||||||
196
pkg/client/netease/live_person.go
Normal file
196
pkg/client/netease/live_person.go
Normal file
@ -0,0 +1,196 @@
|
|||||||
|
package Netease
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"crypto/md5"
|
||||||
|
"encoding/hex"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"math/rand"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"servicebase/pkg/log"
|
||||||
|
"sort"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
"github.com/tjfoc/gmsm/sm3"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
apiURL = "https://verify.dun.163.com/v1/face/liveness/h5/auth"
|
||||||
|
recheckTokenUrl = "https://verify.dun.163.com/v1/face/liveness/h5/recheck"
|
||||||
|
version = "v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ApplyInfoReq struct {
|
||||||
|
Name string
|
||||||
|
CardNo string
|
||||||
|
RedirectUrl string
|
||||||
|
CallBackUrl string
|
||||||
|
DataId string
|
||||||
|
CallbackValidate string
|
||||||
|
EncryptType string
|
||||||
|
}
|
||||||
|
|
||||||
|
type BaseRsp[T any] struct {
|
||||||
|
Code int `json:"code"`
|
||||||
|
Msg string `json:"msg"`
|
||||||
|
Result T `json:"result"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type H5ApplyLivePersonRsp struct {
|
||||||
|
AuthUrl string `json:"authUrl"`
|
||||||
|
AuthToken string `json:"authToken"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type H5ReCheckLivePersonTokenRsp struct {
|
||||||
|
TaskId string `json:"taskId"`
|
||||||
|
PicType int64 `json:"picType"`
|
||||||
|
Avatar string `json:"avatar"`
|
||||||
|
Status int64 `json:"status"`
|
||||||
|
ReasonType int `json:"reasonType"`
|
||||||
|
IsPayed int64 `json:"isPayed"`
|
||||||
|
SimilarityScore float64 `json:"similarityScore"`
|
||||||
|
FaceMatched int64 `json:"faceMatched"`
|
||||||
|
FaceAttributeInfo interface{} `json:"faceAttributeInfo"`
|
||||||
|
ExtInfo ExtInfoEntity `json:"extInfo"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ExtInfoEntity struct {
|
||||||
|
SuspectedNonageFlag bool `json:"suspectedNonageFlag"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// H5ApplyLivePerson 请求易盾生成h5人身验证h5 url 和 authToken
|
||||||
|
func H5ApplyLivePerson(ctx context.Context, req *ApplyInfoReq) (*H5ApplyLivePersonRsp, error) {
|
||||||
|
params := url.Values{
|
||||||
|
"name": []string{req.Name},
|
||||||
|
"cardNo": []string{req.CardNo},
|
||||||
|
"redirectUrl": []string{req.RedirectUrl},
|
||||||
|
}
|
||||||
|
rsp, err := apply(params)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return rsp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// H5ReCheckLivePersonToken 根据authToken二次验证,并获取相关信息,如正面拍照的活体图片
|
||||||
|
func H5ReCheckLivePersonToken(ctx context.Context, token string) (*H5ReCheckLivePersonTokenRsp, error) {
|
||||||
|
params := url.Values{
|
||||||
|
"authToken": []string{token},
|
||||||
|
}
|
||||||
|
rsp, err := checkToken(params)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return rsp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成签名信息
|
||||||
|
func genSignature(params url.Values) string {
|
||||||
|
var paramStr string
|
||||||
|
keys := make([]string, 0, len(params))
|
||||||
|
for k := range params {
|
||||||
|
keys = append(keys, k)
|
||||||
|
}
|
||||||
|
sort.Strings(keys)
|
||||||
|
for _, key := range keys {
|
||||||
|
paramStr += key + params[key][0]
|
||||||
|
}
|
||||||
|
paramStr += viper.GetString("netease.captcha.secretKey")
|
||||||
|
if params["signatureMethod"] != nil && params["signatureMethod"][0] == "SM3" {
|
||||||
|
sm3Reader := sm3.New()
|
||||||
|
sm3Reader.Write([]byte(paramStr))
|
||||||
|
return hex.EncodeToString(sm3Reader.Sum(nil))
|
||||||
|
}
|
||||||
|
md5Reader := md5.New()
|
||||||
|
md5Reader.Write([]byte(paramStr))
|
||||||
|
return hex.EncodeToString(md5Reader.Sum(nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 请求易盾接口
|
||||||
|
func apply(params url.Values) (*H5ApplyLivePersonRsp, error) {
|
||||||
|
params["secretId"] = []string{viper.GetString("netease.captcha.secretId")}
|
||||||
|
params["businessId"] = []string{viper.GetString("netease.captcha.businessId")}
|
||||||
|
params["version"] = []string{version}
|
||||||
|
params["timestamp"] = []string{strconv.FormatInt(time.Now().UnixNano()/1000000, 10)}
|
||||||
|
params["nonce"] = []string{strconv.FormatInt(rand.New(rand.NewSource(time.Now().UnixNano())).Int63n(10000000000), 10)}
|
||||||
|
params["signature"] = []string{genSignature(params)}
|
||||||
|
|
||||||
|
resp, err := http.Post(apiURL, "application/x-www-form-urlencoded", strings.NewReader(params.Encode()))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.WithStack(err)
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
return nil, errors.Errorf("请求网易易盾获取h5人身验证失败,状态码为%d", resp.StatusCode)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
contents, _ := io.ReadAll(resp.Body)
|
||||||
|
log.InfoF("请求网易易盾获取h5人身验证响应: %s", string(contents))
|
||||||
|
var rsp BaseRsp[*H5ApplyLivePersonRsp]
|
||||||
|
err = json.Unmarshal(contents, &rsp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.WithStack(err)
|
||||||
|
}
|
||||||
|
if rsp.Code != 200 {
|
||||||
|
return nil, errors.Errorf("响应体状态码不是200(%d),信息: %s", rsp.Code, rsp.Msg)
|
||||||
|
}
|
||||||
|
return rsp.Result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkToken(params url.Values) (*H5ReCheckLivePersonTokenRsp, error) {
|
||||||
|
params["secretId"] = []string{viper.GetString("netease.captcha.secretId")}
|
||||||
|
params["businessId"] = []string{viper.GetString("netease.captcha.businessId")}
|
||||||
|
params["version"] = []string{version}
|
||||||
|
params["timestamp"] = []string{strconv.FormatInt(time.Now().UnixNano()/1000000, 10)}
|
||||||
|
params["nonce"] = []string{strconv.FormatInt(rand.New(rand.NewSource(time.Now().UnixNano())).Int63n(10000000000), 10)}
|
||||||
|
params["signature"] = []string{genSignature(params)}
|
||||||
|
|
||||||
|
resp, err := http.Post(recheckTokenUrl, "application/x-www-form-urlencoded", strings.NewReader(params.Encode()))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.WithStack(err)
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
return nil, errors.Errorf("请求网易易盾获取h5人身验证失败,状态码为%d", resp.StatusCode)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
contents, _ := io.ReadAll(resp.Body)
|
||||||
|
log.InfoF("请求网易云盾获取人身核验二次验证token响应: %s", string(contents))
|
||||||
|
var rsp BaseRsp[*H5ReCheckLivePersonTokenRsp]
|
||||||
|
err = json.Unmarshal(contents, &rsp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.WithStack(err)
|
||||||
|
}
|
||||||
|
if rsp.Code != 200 {
|
||||||
|
return nil, errors.Errorf("响应体状态码不是200(%d),信息: %s", rsp.Code, rsp.Msg)
|
||||||
|
}
|
||||||
|
return rsp.Result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var livePersonAndIdCheckFailReason = map[int]string{
|
||||||
|
2: "活体通过,姓名身份证号一致,人脸比对非同一人",
|
||||||
|
3: "活体通过,姓名身份证号不一致",
|
||||||
|
4: "活体不通过",
|
||||||
|
5: "活体检测超时或出现异常",
|
||||||
|
6: "活体通过,查无此身份证",
|
||||||
|
7: "活体通过,库中无此身份证照片",
|
||||||
|
8: "活体通过,人脸照过大",
|
||||||
|
9: "活体通过,权威数据源出现异常",
|
||||||
|
10: "疑似攻击,建议拦截",
|
||||||
|
11: "检测对象为未成年人",
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetLivePersonAndIdCheckFailReason(code int) string {
|
||||||
|
r, ok := livePersonAndIdCheckFailReason[code]
|
||||||
|
if !ok {
|
||||||
|
return fmt.Sprintf("其他原因:ReasonType==%d", code)
|
||||||
|
}
|
||||||
|
return r
|
||||||
|
}
|
||||||
78
pkg/client/netease/live_person_test.go
Normal file
78
pkg/client/netease/live_person_test.go
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
package Netease
|
||||||
|
|
||||||
|
import (
|
||||||
|
"servicebase/pkg/common/HyTools"
|
||||||
|
"servicebase/pkg/log"
|
||||||
|
"servicebase/pkg/partner/qiniu"
|
||||||
|
"context"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestApplyH5LivePerson(t *testing.T) {
|
||||||
|
log.Init()
|
||||||
|
rst, err := H5ApplyLivePerson(context.Background(), &ApplyInfoReq{
|
||||||
|
Name: "xxx", // 姓名
|
||||||
|
CardNo: "xxxxxxx", // 身份证号码,x需要变成大写X
|
||||||
|
RedirectUrl: "https://www.baidu.com",
|
||||||
|
CallBackUrl: "",
|
||||||
|
DataId: "",
|
||||||
|
CallbackValidate: "",
|
||||||
|
EncryptType: "",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
println(rst.AuthToken)
|
||||||
|
println(rst.AuthUrl)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestH5ReCheckLivePersonToken(t *testing.T) {
|
||||||
|
log.Init()
|
||||||
|
_, err := H5ReCheckLivePersonToken(context.Background(), "6ZgHU-x9XsRVF8aS7PIFppBho28QEUAR")
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestB(t *testing.T) {
|
||||||
|
log.Init()
|
||||||
|
|
||||||
|
// key: CwGN8XGmbEZr7qqJl-y-QodcUYREz8ph_glVKCqp
|
||||||
|
// secret: KbZKt8WwQcZ6II0tygMLsO3KWpm50aMz737VaMV0
|
||||||
|
viper.Set("qiniu.key", "CwGN8XGmbEZr7qqJl-y-QodcUYREz8ph_glVKCqp")
|
||||||
|
|
||||||
|
viper.Set("qiniu.secret", "KbZKt8WwQcZ6II0tygMLsO3KWpm50aMz737VaMV0")
|
||||||
|
|
||||||
|
viper.Set("qiniu.bucket.photo", "ddphoto")
|
||||||
|
|
||||||
|
key := func() string {
|
||||||
|
resp, err := http.Get("xxx")
|
||||||
|
if err != nil {
|
||||||
|
log.ErrorF("获取人脸核身正面照图片错误:%+v", err)
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
log.ErrorF("获取人脸核身正面照图片错误 http code为%d", resp.StatusCode)
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
imageData, err := io.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
log.ErrorF("")
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
key := "upload/" + HyTools.GetUUID() + ".jpg"
|
||||||
|
//上传文件
|
||||||
|
newKey := qiniu.UploadFile(context.Background(), viper.GetString("qiniu.bucket.photo"), imageData, key)
|
||||||
|
if len(newKey) == 0 {
|
||||||
|
log.ErrorF("获取人脸核身正面照图片上传到七牛oss失败")
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return key
|
||||||
|
}()
|
||||||
|
println(key)
|
||||||
|
}
|
||||||
84
pkg/client/shengwang_client.go
Normal file
84
pkg/client/shengwang_client.go
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"servicebase/pkg/tools"
|
||||||
|
|
||||||
|
rtctokenbuilder "github.com/AgoraIO/Tools/DynamicKey/AgoraDynamicKey/go/src/rtctokenbuilder2"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GenerateShenWangToken(userNo, RoomId string) (token string, e error) {
|
||||||
|
// Need to set environment variable AGORA_APP_ID
|
||||||
|
appId := viper.GetString("agora.tokenGen.appId")
|
||||||
|
// Need to set environment variable AGORA_APP_CERTIFICATE
|
||||||
|
appCertificate := viper.GetString("agora.tokenGen.appCertificate")
|
||||||
|
channelName := RoomId
|
||||||
|
uidStr := userNo
|
||||||
|
uid := uint32(tools.StrToInt32(userNo))
|
||||||
|
expire := 3600 * 24
|
||||||
|
tokenExpirationInSeconds := uint32(expire)
|
||||||
|
privilegeExpirationInSeconds := uint32(expire)
|
||||||
|
joinChannelPrivilegeExpireInSeconds := uint32(expire)
|
||||||
|
pubAudioPrivilegeExpireInSeconds := uint32(expire)
|
||||||
|
pubVideoPrivilegeExpireInSeconds := uint32(expire)
|
||||||
|
pubDataStreamPrivilegeExpireInSeconds := uint32(expire)
|
||||||
|
|
||||||
|
fmt.Println("App Id:", appId)
|
||||||
|
fmt.Println("App Certificate:", appCertificate)
|
||||||
|
if appId == "" || appCertificate == "" {
|
||||||
|
fmt.Println("Need to set environment variable AGORA_APP_ID and AGORA_APP_CERTIFICATE")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := rtctokenbuilder.BuildTokenWithUid(appId, appCertificate, channelName, uid, rtctokenbuilder.RolePublisher, tokenExpirationInSeconds, privilegeExpirationInSeconds)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
return "", err
|
||||||
|
} else {
|
||||||
|
fmt.Printf("Token with int uid: %s\n", result)
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err = rtctokenbuilder.BuildTokenWithUserAccount(appId, appCertificate, channelName, uidStr, rtctokenbuilder.RolePublisher, tokenExpirationInSeconds, privilegeExpirationInSeconds)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
return "", err
|
||||||
|
} else {
|
||||||
|
fmt.Printf("Token with user account: %s\n", result)
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err = rtctokenbuilder.BuildTokenWithUidAndPrivilege(appId, appCertificate, channelName, uid,
|
||||||
|
tokenExpirationInSeconds, joinChannelPrivilegeExpireInSeconds, pubAudioPrivilegeExpireInSeconds, pubVideoPrivilegeExpireInSeconds, pubDataStreamPrivilegeExpireInSeconds)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
return "", err
|
||||||
|
} else {
|
||||||
|
fmt.Printf("Token with int uid and privilege: %s\n", result)
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err = rtctokenbuilder.BuildTokenWithUserAccountAndPrivilege(appId, appCertificate, channelName, uidStr,
|
||||||
|
tokenExpirationInSeconds, joinChannelPrivilegeExpireInSeconds, pubAudioPrivilegeExpireInSeconds, pubVideoPrivilegeExpireInSeconds, pubDataStreamPrivilegeExpireInSeconds)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
return "", err
|
||||||
|
} else {
|
||||||
|
fmt.Printf("Token with user account and privilege: %s\n", result)
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err = rtctokenbuilder.BuildTokenWithRtm(appId, appCertificate, channelName, uidStr, rtctokenbuilder.RolePublisher, tokenExpirationInSeconds, privilegeExpirationInSeconds)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
return "", err
|
||||||
|
} else {
|
||||||
|
fmt.Printf("Token with RTM: %s\n", result)
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err = rtctokenbuilder.BuildTokenWithRtm2(appId, appCertificate, channelName, uidStr, rtctokenbuilder.RolePublisher, tokenExpirationInSeconds, privilegeExpirationInSeconds, pubAudioPrivilegeExpireInSeconds, pubVideoPrivilegeExpireInSeconds, pubDataStreamPrivilegeExpireInSeconds, uidStr, tokenExpirationInSeconds)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
return "", err
|
||||||
|
} else {
|
||||||
|
fmt.Printf("Token with RTM: %s\n", result)
|
||||||
|
}
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
11
pkg/client/shengwang_client_test.go
Normal file
11
pkg/client/shengwang_client_test.go
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGenerateShenWangToken(t *testing.T) {
|
||||||
|
gotToken, err := GenerateShenWangToken("65945666", "9956050")
|
||||||
|
fmt.Printf("%+v %+v\n", gotToken, err)
|
||||||
|
}
|
||||||
311
pkg/client/sms_client.go
Normal file
311
pkg/client/sms_client.go
Normal file
@ -0,0 +1,311 @@
|
|||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"servicebase/pkg/helper"
|
||||||
|
"servicebase/pkg/log"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
openapi "github.com/alibabacloud-go/darabonba-openapi/v2/client"
|
||||||
|
dysmsapi20170525 "github.com/alibabacloud-go/dysmsapi-20170525/v3/client"
|
||||||
|
util "github.com/alibabacloud-go/tea-utils/v2/service"
|
||||||
|
"github.com/alibabacloud-go/tea/tea"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CreateAliSmsClient
|
||||||
|
/**
|
||||||
|
* 使用AK&SK初始化账号Client
|
||||||
|
* @param accessKeyId
|
||||||
|
* @param accessKeySecret
|
||||||
|
* @return Client
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
func CreateAliSmsClient(accessKeyId *string, accessKeySecret *string) (_result *dysmsapi20170525.Client, _err error) {
|
||||||
|
config := &openapi.Config{
|
||||||
|
// 必填,您的 AccessKey ID
|
||||||
|
AccessKeyId: accessKeyId,
|
||||||
|
// 必填,您的 AccessKey Secret
|
||||||
|
AccessKeySecret: accessKeySecret,
|
||||||
|
}
|
||||||
|
// Endpoint 请参考 https://api.aliyun.com/product/Dysmsapi
|
||||||
|
config.Endpoint = tea.String("dysmsapi.aliyuncs.com")
|
||||||
|
_result = &dysmsapi20170525.Client{}
|
||||||
|
_result, _err = dysmsapi20170525.NewClient(config)
|
||||||
|
return _result, _err
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
smsSignList = []string{"淮南东东网络科技"}
|
||||||
|
tempCodeList = []string{"SMS_320216048"}
|
||||||
|
smsSignCodeLock sync.Mutex
|
||||||
|
smsSignCodeIndex int64
|
||||||
|
)
|
||||||
|
|
||||||
|
func getSignAndCode() (sign, code string) {
|
||||||
|
smsSignCodeLock.Lock()
|
||||||
|
defer smsSignCodeLock.Unlock()
|
||||||
|
i := smsSignCodeIndex % int64(len(smsSignList))
|
||||||
|
sign = smsSignList[int(i)]
|
||||||
|
code = tempCodeList[int(i)]
|
||||||
|
smsSignCodeIndex++
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func SendVerifyCode01(mobile, content string, fn func(_result *dysmsapi20170525.SendSmsResponse, success bool)) (_result *dysmsapi20170525.SendSmsResponse, e error) {
|
||||||
|
if !helper.IsMobile(mobile) {
|
||||||
|
return nil, errors.New("手机号有误!")
|
||||||
|
}
|
||||||
|
sign, code := getSignAndCode()
|
||||||
|
log.InfoF("get sms sign and code: %s %s", sign, code)
|
||||||
|
_result, e = SendMobileMsg01(mobile, sign, code, content)
|
||||||
|
if fn != nil {
|
||||||
|
fn(_result, e == nil)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func SendMobileMsg01(mobile, signName, tempCode, content string) (_result *dysmsapi20170525.SendSmsResponse, _err error) {
|
||||||
|
var (
|
||||||
|
ID = viper.GetString("aliyun.sms.accessKeyId")
|
||||||
|
Secret = viper.GetString("aliyun.sms.accessKeySecret")
|
||||||
|
)
|
||||||
|
// 请确保代码运行环境设置了环境变量 ALIBABA_CLOUD_ACCESS_KEY_ID 和 ALIBABA_CLOUD_ACCESS_KEY_SECRET。
|
||||||
|
// 工程代码泄露可能会导致 AccessKey 泄露,并威胁账号下所有资源的安全性。以下代码示例使用环境变量获取 AccessKey 的方式进行调用,仅供参考,建议使用更安全的 STS 方式,更多鉴权访问方式请参见:https://help.aliyun.com/document_detail/378661.html
|
||||||
|
client, _err := CreateAliSmsClient(tea.String(ID), tea.String(Secret))
|
||||||
|
if _err != nil {
|
||||||
|
return nil, _err
|
||||||
|
}
|
||||||
|
|
||||||
|
sendSmsRequest := &dysmsapi20170525.SendSmsRequest{
|
||||||
|
PhoneNumbers: tea.String(mobile),
|
||||||
|
SignName: tea.String(signName),
|
||||||
|
TemplateCode: tea.String(tempCode),
|
||||||
|
TemplateParam: tea.String(fmt.Sprintf("{\"code\":\"%s\"}", content)),
|
||||||
|
}
|
||||||
|
res, tryErr := func() (_result *dysmsapi20170525.SendSmsResponse, _e error) {
|
||||||
|
defer func() {
|
||||||
|
if r := tea.Recover(recover()); r != nil {
|
||||||
|
_e = r
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
// 复制代码运行请自行打印 API 的返回值
|
||||||
|
_result, _err = client.SendSmsWithOptions(sendSmsRequest, &util.RuntimeOptions{})
|
||||||
|
if _err != nil {
|
||||||
|
return nil, _err
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}()
|
||||||
|
|
||||||
|
if tryErr != nil {
|
||||||
|
var e = &tea.SDKError{}
|
||||||
|
if _t, ok := tryErr.(*tea.SDKError); ok {
|
||||||
|
e = _t
|
||||||
|
} else {
|
||||||
|
e.Message = tea.String(tryErr.Error())
|
||||||
|
}
|
||||||
|
// 如有需要,请打印 error
|
||||||
|
_, _err = util.AssertAsString(e.Message)
|
||||||
|
if _err != nil {
|
||||||
|
return nil, _err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res, _err
|
||||||
|
}
|
||||||
|
|
||||||
|
func SendVerifyCodeUsaAndCanada(mobile, content string, fn func(_result *dysmsapi20170525.SendSmsResponse, success bool)) (_result *dysmsapi20170525.SendSmsResponse, e error) {
|
||||||
|
// if !helper.IsMobile(mobile) {
|
||||||
|
// return nil, errors.New("手机号有误!")
|
||||||
|
// }
|
||||||
|
sign, code := getSignAndCode()
|
||||||
|
log.InfoF("SendVerifyCodeUsaAndCanada get sms sign and code: %s %s", sign, code)
|
||||||
|
_result, e = SendMobileMsgUsaAndCanada(mobile, sign, code, content)
|
||||||
|
if fn != nil {
|
||||||
|
fn(_result, e == nil)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func SendVerifyCodeGlobalOther(mobile, content string, fn func(_result *dysmsapi20170525.SendSmsResponse, success bool)) (_result *dysmsapi20170525.SendSmsResponse, e error) {
|
||||||
|
// if !helper.IsMobile(mobile) {
|
||||||
|
// return nil, errors.New("手机号有误!")
|
||||||
|
// }
|
||||||
|
sign, code := getSignAndCode()
|
||||||
|
log.InfoF("SendVerifyCodeUsaAndCanada get sms sign and code: %s %s", sign, code)
|
||||||
|
_result, e = SendMobileMsgGlobalOther(mobile, sign, code, content)
|
||||||
|
if fn != nil {
|
||||||
|
fn(_result, e == nil)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// SendMobileMsgUsaAndCanada 美国/加拿大地区短信发送
|
||||||
|
func SendMobileMsgUsaAndCanada(mobile, signName, tempCode, content string) (_result *dysmsapi20170525.SendSmsResponse, _err error) {
|
||||||
|
var (
|
||||||
|
ID = viper.GetString("aliyun.sms.accessKeyId")
|
||||||
|
Secret = viper.GetString("aliyun.sms.accessKeySecret")
|
||||||
|
)
|
||||||
|
// 请确保代码运行环境设置了环境变量 ALIBABA_CLOUD_ACCESS_KEY_ID 和 ALIBABA_CLOUD_ACCESS_KEY_SECRET。
|
||||||
|
// 工程代码泄露可能会导致 AccessKey 泄露,并威胁账号下所有资源的安全性。以下代码示例使用环境变量获取 AccessKey 的方式进行调用,仅供参考,建议使用更安全的 STS 方式,更多鉴权访问方式请参见:https://help.aliyun.com/document_detail/378661.html
|
||||||
|
client, _err := CreateAliSmsClient(tea.String(ID), tea.String(Secret))
|
||||||
|
if _err != nil {
|
||||||
|
return nil, _err
|
||||||
|
}
|
||||||
|
|
||||||
|
sendSmsRequest := &dysmsapi20170525.SendSmsRequest{
|
||||||
|
PhoneNumbers: tea.String(mobile),
|
||||||
|
SignName: tea.String(signName),
|
||||||
|
TemplateCode: tea.String(tempCode),
|
||||||
|
TemplateParam: tea.String(fmt.Sprintf("{\"code\":\"%s\"}", content)),
|
||||||
|
}
|
||||||
|
res, tryErr := func() (_result *dysmsapi20170525.SendSmsResponse, _e error) {
|
||||||
|
defer func() {
|
||||||
|
if r := tea.Recover(recover()); r != nil {
|
||||||
|
_e = r
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
// 复制代码运行请自行打印 API 的返回值
|
||||||
|
_result, _err = client.SendSmsWithOptions(sendSmsRequest, &util.RuntimeOptions{})
|
||||||
|
if _err != nil {
|
||||||
|
return nil, _err
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}()
|
||||||
|
|
||||||
|
if tryErr != nil {
|
||||||
|
var e = &tea.SDKError{}
|
||||||
|
if _t, ok := tryErr.(*tea.SDKError); ok {
|
||||||
|
e = _t
|
||||||
|
} else {
|
||||||
|
e.Message = tea.String(tryErr.Error())
|
||||||
|
}
|
||||||
|
// 如有需要,请打印 error
|
||||||
|
_, _err = util.AssertAsString(e.Message)
|
||||||
|
if _err != nil {
|
||||||
|
return nil, _err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res, _err
|
||||||
|
}
|
||||||
|
|
||||||
|
// SendMobileMsgGlobalOther 全球其他国家
|
||||||
|
func SendMobileMsgGlobalOther(mobile, signName, tempCode, content string) (_result *dysmsapi20170525.SendSmsResponse, _err error) {
|
||||||
|
var (
|
||||||
|
// ID AccessKey ID
|
||||||
|
// LTAI5tRfkJnr6Y6NU2T6jWoB
|
||||||
|
//
|
||||||
|
// AccessKey Secret
|
||||||
|
// BcaMWgXkwdxdJXFnCwRQbEl3Q3Xtxl
|
||||||
|
// TODO: 替换为您的AccessKey ID和AccessKey Secret
|
||||||
|
ID = viper.GetString("aliyun.sms.accessKeyId")
|
||||||
|
Secret = viper.GetString("aliyun.sms.accessKeySecret")
|
||||||
|
)
|
||||||
|
// 请确保代码运行环境设置了环境变量 ALIBABA_CLOUD_ACCESS_KEY_ID 和 ALIBABA_CLOUD_ACCESS_KEY_SECRET。
|
||||||
|
// 工程代码泄露可能会导致 AccessKey 泄露,并威胁账号下所有资源的安全性。以下代码示例使用环境变量获取 AccessKey 的方式进行调用,仅供参考,建议使用更安全的 STS 方式,更多鉴权访问方式请参见:https://help.aliyun.com/document_detail/378661.html
|
||||||
|
client, _err := CreateAliSmsClient(tea.String(ID), tea.String(Secret))
|
||||||
|
if _err != nil {
|
||||||
|
return nil, _err
|
||||||
|
}
|
||||||
|
|
||||||
|
sendSmsRequest := &dysmsapi20170525.SendSmsRequest{
|
||||||
|
PhoneNumbers: tea.String(mobile),
|
||||||
|
SignName: tea.String(signName),
|
||||||
|
TemplateCode: tea.String(tempCode),
|
||||||
|
TemplateParam: tea.String(fmt.Sprintf("{\"code\":\"%s\"}", content)),
|
||||||
|
}
|
||||||
|
res, tryErr := func() (_result *dysmsapi20170525.SendSmsResponse, _e error) {
|
||||||
|
defer func() {
|
||||||
|
if r := tea.Recover(recover()); r != nil {
|
||||||
|
_e = r
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
// 复制代码运行请自行打印 API 的返回值
|
||||||
|
_result, _err = client.SendSmsWithOptions(sendSmsRequest, &util.RuntimeOptions{})
|
||||||
|
if _err != nil {
|
||||||
|
return nil, _err
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}()
|
||||||
|
|
||||||
|
if tryErr != nil {
|
||||||
|
var e = &tea.SDKError{}
|
||||||
|
if _t, ok := tryErr.(*tea.SDKError); ok {
|
||||||
|
e = _t
|
||||||
|
} else {
|
||||||
|
e.Message = tea.String(tryErr.Error())
|
||||||
|
}
|
||||||
|
// 如有需要,请打印 error
|
||||||
|
_, _err = util.AssertAsString(e.Message)
|
||||||
|
if _err != nil {
|
||||||
|
return nil, _err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res, _err
|
||||||
|
}
|
||||||
|
|
||||||
|
func SendVerifyHKMacauAndTW(mobile, content string, fn func(_result *dysmsapi20170525.SendSmsResponse, success bool)) (_result *dysmsapi20170525.SendSmsResponse, e error) {
|
||||||
|
if !helper.IsMobile(mobile) {
|
||||||
|
return nil, errors.New("手机号有误!")
|
||||||
|
}
|
||||||
|
sign, code := getSignAndCode()
|
||||||
|
log.InfoF("get sms sign and code: %s %s", sign, code)
|
||||||
|
_result, e = SendMobileMsgHKMacauAndTW(mobile, sign, code, content)
|
||||||
|
if fn != nil {
|
||||||
|
fn(_result, e == nil)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// SendMobileMsgHKMacauAndTW 港澳台
|
||||||
|
func SendMobileMsgHKMacauAndTW(mobile, signName, tempCode, content string) (_result *dysmsapi20170525.SendSmsResponse, _err error) {
|
||||||
|
var (
|
||||||
|
ID = viper.GetString("aliyun.sms.accessKeyId")
|
||||||
|
Secret = viper.GetString("aliyun.sms.accessKeySecret")
|
||||||
|
)
|
||||||
|
// 请确保代码运行环境设置了环境变量 ALIBABA_CLOUD_ACCESS_KEY_ID 和 ALIBABA_CLOUD_ACCESS_KEY_SECRET。
|
||||||
|
// 工程代码泄露可能会导致 AccessKey 泄露,并威胁账号下所有资源的安全性。以下代码示例使用环境变量获取 AccessKey 的方式进行调用,仅供参考,建议使用更安全的 STS 方式,更多鉴权访问方式请参见:https://help.aliyun.com/document_detail/378661.html
|
||||||
|
client, _err := CreateAliSmsClient(tea.String(ID), tea.String(Secret))
|
||||||
|
if _err != nil {
|
||||||
|
return nil, _err
|
||||||
|
}
|
||||||
|
|
||||||
|
sendSmsRequest := &dysmsapi20170525.SendSmsRequest{
|
||||||
|
PhoneNumbers: tea.String(mobile),
|
||||||
|
SignName: tea.String(signName),
|
||||||
|
TemplateCode: tea.String(tempCode),
|
||||||
|
TemplateParam: tea.String(fmt.Sprintf("{\"code\":\"%s\"}", content)),
|
||||||
|
}
|
||||||
|
res, tryErr := func() (_result *dysmsapi20170525.SendSmsResponse, _e error) {
|
||||||
|
defer func() {
|
||||||
|
if r := tea.Recover(recover()); r != nil {
|
||||||
|
_e = r
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
// 复制代码运行请自行打印 API 的返回值
|
||||||
|
_result, _err = client.SendSmsWithOptions(sendSmsRequest, &util.RuntimeOptions{})
|
||||||
|
if _err != nil {
|
||||||
|
return nil, _err
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}()
|
||||||
|
|
||||||
|
if tryErr != nil {
|
||||||
|
var e = &tea.SDKError{}
|
||||||
|
if _t, ok := tryErr.(*tea.SDKError); ok {
|
||||||
|
e = _t
|
||||||
|
} else {
|
||||||
|
e.Message = tea.String(tryErr.Error())
|
||||||
|
}
|
||||||
|
// 如有需要,请打印 error
|
||||||
|
_, _err = util.AssertAsString(e.Message)
|
||||||
|
if _err != nil {
|
||||||
|
return nil, _err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res, _err
|
||||||
|
}
|
||||||
260
pkg/client/tencent.go
Normal file
260
pkg/client/tencent.go
Normal file
@ -0,0 +1,260 @@
|
|||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common"
|
||||||
|
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors"
|
||||||
|
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile"
|
||||||
|
sms "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/sms/v20210111" // 引入sms
|
||||||
|
)
|
||||||
|
|
||||||
|
func _SmsFullContent(template string, param []interface{}) string {
|
||||||
|
var smsTemplateContentMap = map[string]string{
|
||||||
|
viper.GetString("tencent.smsTemplateCode"): "验证码为:{1},您正在登录,若非本人操作,请勿泄露。",
|
||||||
|
}
|
||||||
|
return fmt.Sprintf(smsTemplateContentMap[template], param...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _SmsSendVerifyCode(mobile, code string) (*sms.SendSmsResponseParams, error) {
|
||||||
|
return _SmsSendByTemplate(viper.GetString("tencent.smsTemplateCode"), mobile, []string{code})
|
||||||
|
}
|
||||||
|
|
||||||
|
func _SmsSendByTemplate(templateID, mobile string, param []string) (*sms.SendSmsResponseParams, error) {
|
||||||
|
if !strings.HasPrefix(mobile, "+86") && !strings.HasPrefix(mobile, "86") {
|
||||||
|
mobile = "+86" + mobile
|
||||||
|
}
|
||||||
|
credential := common.NewCredential(viper.GetString("tencent.secretId"), viper.GetString("tencent.secretKey"))
|
||||||
|
cpf := profile.NewClientProfile()
|
||||||
|
cpf.HttpProfile.ReqMethod = "POST"
|
||||||
|
cpf.HttpProfile.Endpoint = "sms.tencentcloudapi.com"
|
||||||
|
cpf.SignMethod = "HmacSHA1"
|
||||||
|
client, _ := sms.NewClient(credential, "ap-guangzhou", cpf)
|
||||||
|
request := sms.NewSendSmsRequest()
|
||||||
|
request.SmsSdkAppId = common.StringPtr(viper.GetString("tencent.sdkAppId"))
|
||||||
|
request.SignName = common.StringPtr(viper.GetString("tencent.signName"))
|
||||||
|
request.TemplateId = common.StringPtr(templateID)
|
||||||
|
request.TemplateParamSet = common.StringPtrs(param)
|
||||||
|
request.PhoneNumberSet = common.StringPtrs([]string{mobile})
|
||||||
|
request.SessionContext = common.StringPtr("")
|
||||||
|
request.ExtendCode = common.StringPtr("")
|
||||||
|
request.SenderId = common.StringPtr("")
|
||||||
|
response, err := client.SendSms(request)
|
||||||
|
if _, ok := err.(*errors.TencentCloudSDKError); ok {
|
||||||
|
fmt.Printf("An API error has returned: %s", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return response.Response, nil
|
||||||
|
// {"SendStatusSet":[{"SerialNo":"4012:319315169316952992330592922","PhoneNumber":"+8615215229221","Fee":1,"SessionContext":"","Code":"Ok","Message":"send success","IsoCode":"CN"}],"RequestId":"82798726-4312-4ea8-926b-b23894a39cf1"}
|
||||||
|
}
|
||||||
|
|
||||||
|
func _SmsQueryStatus(mobile string) (*sms.PullSmsSendStatusByPhoneNumberResponseParams, error) {
|
||||||
|
credential := common.NewCredential(viper.GetString("tencent.secretId"), viper.GetString("tencent.secretKey"))
|
||||||
|
cpf := profile.NewClientProfile()
|
||||||
|
cpf.HttpProfile.ReqMethod = "POST"
|
||||||
|
cpf.HttpProfile.Endpoint = "sms.tencentcloudapi.com"
|
||||||
|
cpf.SignMethod = "HmacSHA1"
|
||||||
|
client, _ := sms.NewClient(credential, "ap-guangzhou", cpf)
|
||||||
|
request := sms.NewPullSmsSendStatusByPhoneNumberRequest()
|
||||||
|
request.SmsSdkAppId = common.StringPtr(viper.GetString("tencent.sdkAppId"))
|
||||||
|
request.Limit = common.Uint64Ptr(10)
|
||||||
|
request.PhoneNumber = common.StringPtr(mobile)
|
||||||
|
request.BeginTime = common.Uint64Ptr(uint64(time.Now().Unix()) - (60 * 60))
|
||||||
|
request.Offset = common.Uint64Ptr(0)
|
||||||
|
response, err := client.PullSmsSendStatusByPhoneNumber(request)
|
||||||
|
if _, ok := err.(*errors.TencentCloudSDKError); ok {
|
||||||
|
fmt.Printf("An API error has returned: %s", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return response.Response, nil
|
||||||
|
// {"PullSmsSendStatusSet":[{"UserReceiveTime":1695299239,"CountryCode":"86","SubscriberNumber":"15215229221","PhoneNumber":"+8615215229221","SerialNo":"4012:319315169316952992330592922","ReportStatus":"SUCCESS","Description":"DELIVRD","SessionContext":""}],"RequestId":"40476317-2cf4-4c48-bf30-2b33ac14a8b7"}
|
||||||
|
}
|
||||||
|
|
||||||
|
func _SendSms() {
|
||||||
|
/* 必要步骤:
|
||||||
|
* 实例化一个认证对象,入参需要传入腾讯云账户密钥对secretId,secretKey。
|
||||||
|
* 这里采用的是从环境变量读取的方式,需要在环境变量中先设置这两个值。
|
||||||
|
* 您也可以直接在代码中写死密钥对,但是小心不要将代码复制、上传或者分享给他人,
|
||||||
|
* 以免泄露密钥对危及您的财产安全。
|
||||||
|
* SecretId、SecretKey 查询: https://console.cloud.tencent.com/cam/capi */
|
||||||
|
credential := common.NewCredential(
|
||||||
|
// os.Getenv("TENCENTCLOUD_SECRET_ID"),
|
||||||
|
// os.Getenv("TENCENTCLOUD_SECRET_KEY"),
|
||||||
|
viper.GetString("tencent.secretId"),
|
||||||
|
viper.GetString("tencent.secretKey"),
|
||||||
|
)
|
||||||
|
/* 非必要步骤:
|
||||||
|
* 实例化一个客户端配置对象,可以指定超时时间等配置 */
|
||||||
|
cpf := profile.NewClientProfile()
|
||||||
|
|
||||||
|
/* SDK默认使用POST方法。
|
||||||
|
* 如果您一定要使用GET方法,可以在这里设置。GET方法无法处理一些较大的请求 */
|
||||||
|
cpf.HttpProfile.ReqMethod = "POST"
|
||||||
|
|
||||||
|
/* SDK有默认的超时时间,非必要请不要进行调整
|
||||||
|
* 如有需要请在代码中查阅以获取最新的默认值 */
|
||||||
|
// cpf.HttpProfile.ReqTimeout = 5
|
||||||
|
|
||||||
|
/* 指定接入地域域名,默认就近地域接入域名为 sms.tencentcloudapi.com ,也支持指定地域域名访问,例如广州地域的域名为 sms.ap-guangzhou.tencentcloudapi.com */
|
||||||
|
cpf.HttpProfile.Endpoint = "sms.tencentcloudapi.com"
|
||||||
|
|
||||||
|
/* SDK默认用TC3-HMAC-SHA256进行签名,非必要请不要修改这个字段 */
|
||||||
|
cpf.SignMethod = "HmacSHA1"
|
||||||
|
|
||||||
|
/* 实例化要请求产品(以sms为例)的client对象
|
||||||
|
* 第二个参数是地域信息,可以直接填写字符串ap-guangzhou,支持的地域列表参考 https://cloud.tencent.com/document/api/382/52071#.E5.9C.B0.E5.9F.9F.E5.88.97.E8.A1.A8 */
|
||||||
|
client, _ := sms.NewClient(credential, "ap-guangzhou", cpf)
|
||||||
|
|
||||||
|
/* 实例化一个请求对象,根据调用的接口和实际情况,可以进一步设置请求参数
|
||||||
|
* 您可以直接查询SDK源码确定接口有哪些属性可以设置
|
||||||
|
* 属性可能是基本类型,也可能引用了另一个数据结构
|
||||||
|
* 推荐使用IDE进行开发,可以方便的跳转查阅各个接口和数据结构的文档说明 */
|
||||||
|
request := sms.NewSendSmsRequest()
|
||||||
|
|
||||||
|
/* 基本类型的设置:
|
||||||
|
* SDK采用的是指针风格指定参数,即使对于基本类型您也需要用指针来对参数赋值。
|
||||||
|
* SDK提供对基本类型的指针引用封装函数
|
||||||
|
* 帮助链接:
|
||||||
|
* 短信控制台: https://console.cloud.tencent.com/smsv2
|
||||||
|
* 腾讯云短信小助手: https://cloud.tencent.com/document/product/382/3773#.E6.8A.80.E6.9C.AF.E4.BA.A4.E6.B5.81 */
|
||||||
|
|
||||||
|
/* 短信应用ID: 短信SdkAppId在 [短信控制台] 添加应用后生成的实际SdkAppId,示例如1400006666 */
|
||||||
|
// 应用 ID 可前往 [短信控制台](https://console.cloud.tencent.com/smsv2/app-manage) 查看
|
||||||
|
request.SmsSdkAppId = common.StringPtr(viper.GetString("tencent.sdkAppId"))
|
||||||
|
|
||||||
|
/* 短信签名内容: 使用 UTF-8 编码,必须填写已审核通过的签名 */
|
||||||
|
// 签名信息可前往 [国内短信](https://console.cloud.tencent.com/smsv2/csms-sign) 或 [国际/港澳台短信](https://console.cloud.tencent.com/smsv2/isms-sign) 的签名管理查看
|
||||||
|
request.SignName = common.StringPtr("好出行Trip小程序")
|
||||||
|
|
||||||
|
/* 模板 ID: 必须填写已审核通过的模板 ID */
|
||||||
|
// 模板 ID 可前往 [国内短信](https://console.cloud.tencent.com/smsv2/csms-template) 或 [国际/港澳台短信](https://console.cloud.tencent.com/smsv2/isms-template) 的正文模板管理查看
|
||||||
|
request.TemplateId = common.StringPtr("1916515")
|
||||||
|
|
||||||
|
/* 模板参数: 模板参数的个数需要与 TemplateId 对应模板的变量个数保持一致,若无模板参数,则设置为空*/
|
||||||
|
request.TemplateParamSet = common.StringPtrs([]string{"6666"})
|
||||||
|
|
||||||
|
/* 下发手机号码,采用 E.164 标准,+[国家或地区码][手机号]
|
||||||
|
* 示例如:+8613711112222, 其中前面有一个+号 ,86为国家码,13711112222为手机号,最多不要超过200个手机号*/
|
||||||
|
request.PhoneNumberSet = common.StringPtrs([]string{"+8615215229221"})
|
||||||
|
|
||||||
|
/* 用户的 session 内容(无需要可忽略): 可以携带用户侧 ID 等上下文信息,server 会原样返回 */
|
||||||
|
request.SessionContext = common.StringPtr("")
|
||||||
|
|
||||||
|
/* 短信码号扩展号(无需要可忽略): 默认未开通,如需开通请联系 [腾讯云短信小助手] */
|
||||||
|
request.ExtendCode = common.StringPtr("")
|
||||||
|
|
||||||
|
/* 国内短信无需填写该项;国际/港澳台短信已申请独立 SenderId 需要填写该字段,默认使用公共 SenderId,无需填写该字段。注:月度使用量达到指定量级可申请独立 SenderId 使用,详情请联系 [腾讯云短信小助手](https://cloud.tencent.com/document/product/382/3773#.E6.8A.80.E6.9C.AF.E4.BA.A4.E6.B5.81)。 */
|
||||||
|
request.SenderId = common.StringPtr("")
|
||||||
|
|
||||||
|
// 通过client对象调用想要访问的接口,需要传入请求对象
|
||||||
|
response, err := client.SendSms(request)
|
||||||
|
// 处理异常
|
||||||
|
if _, ok := err.(*errors.TencentCloudSDKError); ok {
|
||||||
|
fmt.Printf("An API error has returned: %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 非SDK异常,直接失败。实际代码中可以加入其他的处理。
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
b, _ := json.Marshal(response.Response)
|
||||||
|
// 打印返回的json字符串
|
||||||
|
fmt.Printf("%s", b)
|
||||||
|
|
||||||
|
// {"SendStatusSet":[{"SerialNo":"4012:319315169316952992330592922","PhoneNumber":"+8615215229221","Fee":1,"SessionContext":"","Code":"Ok","Message":"send success","IsoCode":"CN"}],"RequestId":"82798726-4312-4ea8-926b-b23894a39cf1"}
|
||||||
|
|
||||||
|
/* 当出现以下错误码时,快速解决方案参考
|
||||||
|
* [FailedOperation.SignatureIncorrectOrUnapproved](https://cloud.tencent.com/document/product/382/9558#.E7.9F.AD.E4.BF.A1.E5.8F.91.E9.80.81.E6.8F.90.E7.A4.BA.EF.BC.9Afailedoperation.signatureincorrectorunapproved-.E5.A6.82.E4.BD.95.E5.A4.84.E7.90.86.EF.BC.9F)
|
||||||
|
* [FailedOperation.TemplateIncorrectOrUnapproved](https://cloud.tencent.com/document/product/382/9558#.E7.9F.AD.E4.BF.A1.E5.8F.91.E9.80.81.E6.8F.90.E7.A4.BA.EF.BC.9Afailedoperation.templateincorrectorunapproved-.E5.A6.82.E4.BD.95.E5.A4.84.E7.90.86.EF.BC.9F)
|
||||||
|
* [UnauthorizedOperation.SmsSdkAppIdVerifyFail](https://cloud.tencent.com/document/product/382/9558#.E7.9F.AD.E4.BF.A1.E5.8F.91.E9.80.81.E6.8F.90.E7.A4.BA.EF.BC.9Aunauthorizedoperation.smssdkappidverifyfail-.E5.A6.82.E4.BD.95.E5.A4.84.E7.90.86.EF.BC.9F)
|
||||||
|
* [UnsupportedOperation.ContainDomesticAndInternationalPhoneNumber](https://cloud.tencent.com/document/product/382/9558#.E7.9F.AD.E4.BF.A1.E5.8F.91.E9.80.81.E6.8F.90.E7.A4.BA.EF.BC.9Aunsupportedoperation.containdomesticandinternationalphonenumber-.E5.A6.82.E4.BD.95.E5.A4.84.E7.90.86.EF.BC.9F)
|
||||||
|
* 更多错误,可咨询[腾讯云助手](https://tccc.qcloud.com/web/im/index.html#/chat?webAppId=8fa15978f85cb41f7e2ea36920cb3ae1&title=Sms)
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
func _PullStatus() {
|
||||||
|
/* 必要步骤:
|
||||||
|
* 实例化一个认证对象,入参需要传入腾讯云账户密钥对secretId,secretKey。
|
||||||
|
* 这里采用的是从环境变量读取的方式,需要在环境变量中先设置这两个值。
|
||||||
|
* 您也可以直接在代码中写死密钥对,但是小心不要将代码复制、上传或者分享给他人,
|
||||||
|
* 以免泄露密钥对危及您的财产安全。
|
||||||
|
* SecretId、SecretKey 查询: https://console.cloud.tencent.com/cam/capi */
|
||||||
|
credential := common.NewCredential(
|
||||||
|
// os.Getenv("TENCENTCLOUD_SECRET_ID"),
|
||||||
|
// os.Getenv("TENCENTCLOUD_SECRET_KEY"),
|
||||||
|
viper.GetString("tencent.secretId"),
|
||||||
|
viper.GetString("tencent.secretKey"),
|
||||||
|
)
|
||||||
|
/* 非必要步骤:
|
||||||
|
* 实例化一个客户端配置对象,可以指定超时时间等配置 */
|
||||||
|
cpf := profile.NewClientProfile()
|
||||||
|
|
||||||
|
/* SDK默认使用POST方法。
|
||||||
|
* 如果您一定要使用GET方法,可以在这里设置。GET方法无法处理一些较大的请求 */
|
||||||
|
cpf.HttpProfile.ReqMethod = "POST"
|
||||||
|
|
||||||
|
/* SDK有默认的超时时间,非必要请不要进行调整
|
||||||
|
* 如有需要请在代码中查阅以获取最新的默认值 */
|
||||||
|
// cpf.HttpProfile.ReqTimeout = 5
|
||||||
|
|
||||||
|
/* 指定接入地域域名,默认就近地域接入域名为 sms.tencentcloudapi.com ,也支持指定地域域名访问,例如广州地域的域名为 sms.ap-guangzhou.tencentcloudapi.com */
|
||||||
|
cpf.HttpProfile.Endpoint = "sms.tencentcloudapi.com"
|
||||||
|
|
||||||
|
/* SDK默认用TC3-HMAC-SHA256进行签名
|
||||||
|
* 非必要请不要修改这个字段 */
|
||||||
|
cpf.SignMethod = "HmacSHA1"
|
||||||
|
|
||||||
|
/* 实例化要请求产品(以sms为例)的client对象
|
||||||
|
* 第二个参数是地域信息,可以直接填写字符串ap-guangzhou,支持的地域列表参考 https://cloud.tencent.com/document/api/382/52071#.E5.9C.B0.E5.9F.9F.E5.88.97.E8.A1.A8 */
|
||||||
|
client, _ := sms.NewClient(credential, "ap-guangzhou", cpf)
|
||||||
|
|
||||||
|
/* 实例化一个请求对象,根据调用的接口和实际情况,可以进一步设置请求参数
|
||||||
|
* 您可以直接查询SDK源码确定接口有哪些属性可以设置
|
||||||
|
* 属性可能是基本类型,也可能引用了另一个数据结构
|
||||||
|
* 推荐使用IDE进行开发,可以方便的跳转查阅各个接口和数据结构的文档说明 */
|
||||||
|
request := sms.NewPullSmsSendStatusByPhoneNumberRequest()
|
||||||
|
|
||||||
|
/* 基本类型的设置:
|
||||||
|
* SDK采用的是指针风格指定参数,即使对于基本类型您也需要用指针来对参数赋值。
|
||||||
|
* SDK提供对基本类型的指针引用封装函数
|
||||||
|
* 帮助链接:
|
||||||
|
* 短信控制台: https://console.cloud.tencent.com/smsv2
|
||||||
|
* 腾讯云短信小助手: https://cloud.tencent.com/document/product/382/3773#.E6.8A.80.E6.9C.AF.E4.BA.A4.E6.B5.81 */
|
||||||
|
|
||||||
|
/* 短信应用ID: 短信SdkAppId在 [短信控制台] 添加应用后生成的实际SdkAppId,示例如1400006666 */
|
||||||
|
request.SmsSdkAppId = common.StringPtr(viper.GetString("tencent.sdkAppId"))
|
||||||
|
/* 拉取最大条数,最多100条 */
|
||||||
|
request.Limit = common.Uint64Ptr(10)
|
||||||
|
PhoneNumber := "+8615215229221"
|
||||||
|
request.PhoneNumber = &PhoneNumber
|
||||||
|
beginTime := uint64(time.Now().Unix()) - (60 * 60)
|
||||||
|
request.BeginTime = &beginTime
|
||||||
|
Offset := uint64(0)
|
||||||
|
request.Offset = &Offset
|
||||||
|
|
||||||
|
// 通过client对象调用想要访问的接口,需要传入请求对象
|
||||||
|
response, err := client.PullSmsSendStatusByPhoneNumber(request)
|
||||||
|
// 处理异常
|
||||||
|
if _, ok := err.(*errors.TencentCloudSDKError); ok {
|
||||||
|
fmt.Printf("An API error has returned: %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 非SDK异常,直接失败。实际代码中可以加入其他的处理。
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
b, _ := json.Marshal(response.Response)
|
||||||
|
// 打印返回的json字符串
|
||||||
|
fmt.Printf("%s", b)
|
||||||
|
// {"PullSmsSendStatusSet":[{"UserReceiveTime":1695299239,"CountryCode":"86","SubscriberNumber":"15215229221","PhoneNumber":"+8615215229221","SerialNo":"4012:319315169316952992330592922","ReportStatus":"SUCCESS","Description":"DELIVRD","SessionContext":""}],"RequestId":"40476317-2cf4-4c48-bf30-2b33ac14a8b7"}
|
||||||
|
}
|
||||||
74
pkg/client/tencent_test.go
Normal file
74
pkg/client/tencent_test.go
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
sms "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/sms/v20210111"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSendSms(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "test01",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
_SendSms()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPullStatus(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "test01",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
_PullStatus()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSmsSendByTemplate(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
templateID string
|
||||||
|
mobile string
|
||||||
|
param []string
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
want *sms.SendSmsResponseParams
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "01",
|
||||||
|
args: args{
|
||||||
|
templateID: "2319145",
|
||||||
|
mobile: "",
|
||||||
|
param: []string{"6666"},
|
||||||
|
},
|
||||||
|
want: &sms.SendSmsResponseParams{},
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
_, err := _SmsSendByTemplate(tt.args.templateID, tt.args.mobile, tt.args.param)
|
||||||
|
if (err != nil) != tt.wantErr {
|
||||||
|
t.Errorf("SmsSendByTemplate() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// if !reflect.DeepEqual(got, tt.want) {
|
||||||
|
// t.Errorf("SmsSendByTemplate() = %v, want %v", got, tt.want)
|
||||||
|
// }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
215
pkg/client/wechat_client.go
Normal file
215
pkg/client/wechat_client.go
Normal file
@ -0,0 +1,215 @@
|
|||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
UserAppID = ""
|
||||||
|
UserSecret = ""
|
||||||
|
DriverAppID = ""
|
||||||
|
DriverSecret = ""
|
||||||
|
Code2SessionAppURL = "https://api.weixin.qq.com/sns/oauth2/access_token"
|
||||||
|
UserInfoAppURL = "https://api.weixin.qq.com/sns/userinfo"
|
||||||
|
|
||||||
|
Code2SessionJsURL = "https://api.weixin.qq.com/sns/jscode2session"
|
||||||
|
|
||||||
|
SendMessageURL = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=ACCESS_TOKEN"
|
||||||
|
GetAccessTokenURL = "https://api.weixin.qq.com/cgi-bin/token"
|
||||||
|
)
|
||||||
|
|
||||||
|
func WeChatNewAuthJsReqMap(code string) map[string]string {
|
||||||
|
return map[string]string{
|
||||||
|
"appid": UserAppID,
|
||||||
|
"secret": UserSecret,
|
||||||
|
"js_code": code,
|
||||||
|
"grant_type": "authorization_code"}
|
||||||
|
}
|
||||||
|
|
||||||
|
func WeChatNewAuthAppReqMap(code string) map[string]string {
|
||||||
|
return map[string]string{
|
||||||
|
"appid": UserAppID,
|
||||||
|
"secret": UserSecret,
|
||||||
|
"code": code,
|
||||||
|
"grant_type": "authorization_code"}
|
||||||
|
}
|
||||||
|
|
||||||
|
func WeChatGetAccessTokenReq(_type int) map[string]string {
|
||||||
|
switch _type {
|
||||||
|
case 1: // 用户
|
||||||
|
return map[string]string{
|
||||||
|
"grant_type": "client_credential",
|
||||||
|
"appid": UserAppID,
|
||||||
|
"secret": UserSecret,
|
||||||
|
}
|
||||||
|
case 2: // 其他
|
||||||
|
return map[string]string{
|
||||||
|
"grant_type": "client_credential",
|
||||||
|
"appid": DriverAppID,
|
||||||
|
"secret": DriverSecret,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 小程序换取token的返回
|
||||||
|
type WeChatLoginJsRes struct {
|
||||||
|
SessionKey string `json:"session_key"`
|
||||||
|
UnionID string `json:"unionid"`
|
||||||
|
OpenID string `json:"openid"`
|
||||||
|
ErrCode int32 `json:"errcode"`
|
||||||
|
ErrMsg string `json:"errmsg"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// APP换取token的返回
|
||||||
|
type WeChatLoginAppRes struct {
|
||||||
|
AccessToken string `json:"access_token"` // 接口调用凭证
|
||||||
|
ExpiresIn int32 `json:"expires_in"` // access_token 接口调用凭证超时时间,单位(秒)
|
||||||
|
RefreshToken string `json:"refresh_token"` // 用户刷新 access_token
|
||||||
|
UnionID string `json:"unionid"` // 用户统一标识。针对一个微信开放平台账号下的应用,同一用户的 unionid 是唯一的
|
||||||
|
OpenID string `json:"openid"` // 授权用户唯一标识
|
||||||
|
Scope string `json:"scope"` // 用户授权的作用域,使用逗号(,)分隔
|
||||||
|
ErrCode int32 `json:"errcode"`
|
||||||
|
ErrMsg string `json:"errmsg"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// APP获取用户信息
|
||||||
|
type WeChatUserInfoAppRes struct {
|
||||||
|
UnionID string `json:"unionid"` // 用户统一标识。针对一个微信开放平台账号下的应用,同一用户的 unionid 是唯一的
|
||||||
|
OpenID string `json:"openid"` // 授权用户唯一标识
|
||||||
|
Nickname string `json:"nickname"` // 普通用户昵称
|
||||||
|
Sex int32 `json:"sex"` // 普通用户性别,1 为男性,2 为女性
|
||||||
|
Province string `json:"province"` // 普通用户个人资料填写的省份
|
||||||
|
City string `json:"city"` // 普通用户个人资料填写的城市
|
||||||
|
Country string `json:"country"` // 国家,如中国为 CN
|
||||||
|
Avatar string `json:"headimgurl"` // 用户头像,最后一个数值代表正方形头像大小(有 0、46、64、96、132 数值可选,0 代表 640*640 正方形头像),用户没有头像时该项为空
|
||||||
|
ErrCode int32 `json:"errcode"`
|
||||||
|
ErrMsg string `json:"errmsg"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 换取token所用的请求
|
||||||
|
func WeChatNewAuthReqMapUser(code string) map[string]string {
|
||||||
|
return map[string]string{
|
||||||
|
"appid": UserAppID,
|
||||||
|
"secret": UserSecret,
|
||||||
|
"js_code": code,
|
||||||
|
"grant_type": "authorization_code"}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 小程序换取token的请求
|
||||||
|
func WeChatCode2JsSession(headers map[string]string, params map[string]string) (wxLoginBody WeChatLoginJsRes, e error) {
|
||||||
|
var (
|
||||||
|
client = NewClient()
|
||||||
|
resp *http.Response
|
||||||
|
res []byte
|
||||||
|
)
|
||||||
|
req, _ := http.NewRequest(http.MethodGet, Code2SessionJsURL, nil)
|
||||||
|
for k, v := range headers {
|
||||||
|
req.Header.Add(k, v)
|
||||||
|
}
|
||||||
|
q := req.URL.Query()
|
||||||
|
for k, v := range params {
|
||||||
|
q.Add(k, v)
|
||||||
|
}
|
||||||
|
req.URL.RawQuery = q.Encode()
|
||||||
|
if resp, e = client.Do(req); e != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer func(body io.ReadCloser) {
|
||||||
|
_ = body.Close()
|
||||||
|
}(resp.Body)
|
||||||
|
if res, e = io.ReadAll(resp.Body); e != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !success(resp.StatusCode) {
|
||||||
|
e = fmt.Errorf("status code error: %s", resp.Status)
|
||||||
|
}
|
||||||
|
if e = json.Unmarshal(res, &wxLoginBody); e != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if wxLoginBody.ErrCode != 0 {
|
||||||
|
e = fmt.Errorf("获取微信登录凭证错误,错误码: %d 错误信息:%s", wxLoginBody.ErrCode, wxLoginBody.ErrMsg)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// APP换取token的请求
|
||||||
|
func WeChatCode2AppToken(headers map[string]string, params map[string]string) (wxLoginBody WeChatLoginAppRes, e error) {
|
||||||
|
var (
|
||||||
|
client = NewClient()
|
||||||
|
resp *http.Response
|
||||||
|
res []byte
|
||||||
|
)
|
||||||
|
req, _ := http.NewRequest(http.MethodGet, Code2SessionAppURL, nil)
|
||||||
|
for k, v := range headers {
|
||||||
|
req.Header.Add(k, v)
|
||||||
|
}
|
||||||
|
q := req.URL.Query()
|
||||||
|
for k, v := range params {
|
||||||
|
q.Add(k, v)
|
||||||
|
}
|
||||||
|
req.URL.RawQuery = q.Encode()
|
||||||
|
if resp, e = client.Do(req); e != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer func(body io.ReadCloser) {
|
||||||
|
_ = body.Close()
|
||||||
|
}(resp.Body)
|
||||||
|
if res, e = io.ReadAll(resp.Body); e != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !success(resp.StatusCode) {
|
||||||
|
e = fmt.Errorf("status code error: %s", resp.Status)
|
||||||
|
}
|
||||||
|
if e = json.Unmarshal(res, &wxLoginBody); e != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if wxLoginBody.ErrCode != 0 {
|
||||||
|
e = fmt.Errorf("获取微信登录凭证错误,错误码: %d 错误信息:%s", wxLoginBody.ErrCode, wxLoginBody.ErrMsg)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// APP获取用户信息
|
||||||
|
func WeChatUserInfoApp(token, openId string) (wxUserInfoBody WeChatUserInfoAppRes, e error) {
|
||||||
|
var (
|
||||||
|
client = NewClient()
|
||||||
|
resp *http.Response
|
||||||
|
res []byte
|
||||||
|
)
|
||||||
|
req, _ := http.NewRequest(http.MethodGet, UserInfoAppURL, nil)
|
||||||
|
|
||||||
|
q := req.URL.Query()
|
||||||
|
q.Add("access_token", token)
|
||||||
|
q.Add("openid", openId)
|
||||||
|
req.URL.RawQuery = q.Encode()
|
||||||
|
if resp, e = client.Do(req); e != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer func(body io.ReadCloser) {
|
||||||
|
_ = body.Close()
|
||||||
|
}(resp.Body)
|
||||||
|
if res, e = io.ReadAll(resp.Body); e != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !success(resp.StatusCode) {
|
||||||
|
e = fmt.Errorf("status code error: %s", resp.Status)
|
||||||
|
}
|
||||||
|
if e = json.Unmarshal(res, &wxUserInfoBody); e != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if wxUserInfoBody.ErrCode != 0 {
|
||||||
|
e = fmt.Errorf("获取微信登录凭证错误,错误码: %d 错误信息:%s", wxUserInfoBody.ErrCode, wxUserInfoBody.ErrMsg)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func success(code int) bool {
|
||||||
|
return code >= 200 && code < 400
|
||||||
|
}
|
||||||
76
pkg/client/weichat_notice.go
Normal file
76
pkg/client/weichat_notice.go
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type WeGetTokenRes struct {
|
||||||
|
AccessToken string `json:"access_token"`
|
||||||
|
ExpiresIn int `json:"expires_in"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func WeGetToken() (token string, e error) {
|
||||||
|
gotRes, err := Get(GetAccessTokenURL, nil, WeChatGetAccessTokenReq(1))
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
var body WeGetTokenRes
|
||||||
|
if e = json.Unmarshal(gotRes, &body); e != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
token = body.AccessToken
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
type WeSendMessageReq map[string]WeSendMessageItemReq
|
||||||
|
|
||||||
|
type WeSendMessageItemReq struct {
|
||||||
|
Value string `json:"value"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func WeSendMessage(openID, templateID string, message WeSendMessageReq, token string) (e error) {
|
||||||
|
if len(token) == 0 {
|
||||||
|
if token, e = WeGetToken(); e != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gotRes, err := Post(strings.ReplaceAll(SendMessageURL, "ACCESS_TOKEN", token), nil, map[string]interface{}{
|
||||||
|
"template_id": templateID,
|
||||||
|
"touser": openID,
|
||||||
|
"data": message,
|
||||||
|
"miniprogram_state": "formal", // developer为开发版;trial为体验版;formal为正式版;默认为正式版
|
||||||
|
"lang": "zh_CN", // 进入小程序查看”的语言类型,支持zh_CN(简体中文)、en_US(英文)、zh_HK(繁体中文)、zh_TW(繁体中文),默认为 zh_CN
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fmt.Printf("%s\n", string(gotRes))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func WeSendNoticeTakeOrder(openID, company, driver, vehicel string, date time.Time) error {
|
||||||
|
const tid = "Ff5tDsIlBy-t51Usxh_oBvge9WbMbBFVKI020hIpWcA"
|
||||||
|
return WeSendMessage(openID, tid, messageNoticeTakeOrder(company, driver, vehicel, date), "")
|
||||||
|
}
|
||||||
|
|
||||||
|
// messageBookReminder 预约提醒消息
|
||||||
|
func messageNoticeTakeOrder(company, driver, vehicel string, date time.Time) WeSendMessageReq {
|
||||||
|
return WeSendMessageReq{
|
||||||
|
"thing1": WeSendMessageItemReq{Value: company}, // 公司名称
|
||||||
|
"thing2": WeSendMessageItemReq{Value: driver}, // 接单司机
|
||||||
|
"car_number3": WeSendMessageItemReq{Value: vehicel}, // 车牌号
|
||||||
|
"time4": WeSendMessageItemReq{Value: StrFromTime(date)}, // 接单时间
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
TimeFormat = "2006-01-02 15:04:05"
|
||||||
|
DateFormat = "2006-01-02"
|
||||||
|
)
|
||||||
|
|
||||||
|
func StrFromTime(t time.Time) string {
|
||||||
|
return t.Format(TimeFormat)
|
||||||
|
}
|
||||||
5
pkg/comm/p_vars.go
Normal file
5
pkg/comm/p_vars.go
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
package comm
|
||||||
|
|
||||||
|
const (
|
||||||
|
ApiDomain = "https://www.jx3api.com"
|
||||||
|
)
|
||||||
118
pkg/common/CmdTools/AliyunCloudClient.go
Normal file
118
pkg/common/CmdTools/AliyunCloudClient.go
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/aliyun/alibaba-cloud-sdk-go/services/slb"
|
||||||
|
)
|
||||||
|
|
||||||
|
// LTAI5tCB8SmJcwfO
|
||||||
|
// dX4kgF4VcblsbCVdKvtCGCmvNbLkZK
|
||||||
|
// ./AliyunCloudClient -t b -o update -key LTAI5tCB8SmJcwfO -sec dX4kgF4VcblsbCVdKvtCGCmvNbLkZK -reg cn-hangzhou -lb "[{"ServerId":"ServerId","Weight":"0"}]
|
||||||
|
func main() {
|
||||||
|
var target string
|
||||||
|
flag.StringVar(&target, "t", "b", "target: b=backendServer")
|
||||||
|
var operation string
|
||||||
|
flag.StringVar(&operation, "o", "update", "operation: add、update、remove")
|
||||||
|
var accessKeyId string
|
||||||
|
flag.StringVar(&accessKeyId, "key", "accessKeyId", "accessKeyId")
|
||||||
|
var accessSecret string
|
||||||
|
flag.StringVar(&accessSecret, "sec", "accessSecret", "accessSecret")
|
||||||
|
var regionId string
|
||||||
|
flag.StringVar(®ionId, "reg", "regionId", "regionId: cn-hangzhou")
|
||||||
|
var loadBalancerId string
|
||||||
|
flag.StringVar(&loadBalancerId, "lb", "loadBalancerId", "loadBalancerId")
|
||||||
|
var params string
|
||||||
|
flag.StringVar(¶ms, "params", "", `SetBackendServers: [{"ServerId":"ServerId","Weight":"0"}]
|
||||||
|
AddBackendServers: [{"ServerId":"ServerId","Weight":"100","Type":"eni","ServerIp":"192.168.11.1"}]
|
||||||
|
RemoveBackendServers: [{"ServerId":"ServerId","Weight":"100"}]
|
||||||
|
`)
|
||||||
|
flag.Parse()
|
||||||
|
flag.Usage()
|
||||||
|
fmt.Printf("target=%s,operation=%s,accessKeyId=%s,accessSecret=%s,regionId=%s,loadBalancerId=%s,params=%s", target, operation, accessKeyId, accessSecret, regionId, loadBalancerId, params)
|
||||||
|
if target == "b" {
|
||||||
|
switch operation {
|
||||||
|
case "update":
|
||||||
|
SetBackendServers(regionId, accessKeyId, accessSecret, loadBalancerId, params)
|
||||||
|
break
|
||||||
|
case "add":
|
||||||
|
AddBackendServers(regionId, accessKeyId, accessSecret, loadBalancerId, params)
|
||||||
|
break
|
||||||
|
case "remove":
|
||||||
|
RemoveBackendServers(regionId, accessKeyId, accessSecret, loadBalancerId, params)
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
fmt.Println("operation: " + operation + " not support")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fmt.Println("target: " + target + " not support")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetBackendServers(regionId, accessKeyId, accessSecret, loadBalancerId, params string) {
|
||||||
|
// client, err := slb.NewClientWithAccessKey(regionId, accessKeyId, accessSecret)
|
||||||
|
// if nil != err {
|
||||||
|
// fmt.Println("get client error:")
|
||||||
|
// fmt.Println(err.Error())
|
||||||
|
// }
|
||||||
|
|
||||||
|
// request := slb.CreateSetBackendServersRequest()
|
||||||
|
// request.Scheme = "https"
|
||||||
|
|
||||||
|
// request.LoadBalancerId = loadBalancerId
|
||||||
|
// request.BackendServers = params
|
||||||
|
|
||||||
|
// if nil == client {
|
||||||
|
// fmt.Println("error: client is nil")
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
// response, err := client.SetBackendServers(request)
|
||||||
|
// if err != nil {
|
||||||
|
// fmt.Print(err.Error())
|
||||||
|
// }
|
||||||
|
// fmt.Printf("response is %#v\n", response)
|
||||||
|
}
|
||||||
|
|
||||||
|
func AddBackendServers(regionId, accessKeyId, accessSecret, loadBalancerId, params string) {
|
||||||
|
client, err := slb.NewClientWithAccessKey(regionId, accessKeyId, accessSecret)
|
||||||
|
|
||||||
|
request := slb.CreateAddBackendServersRequest()
|
||||||
|
request.Scheme = "https"
|
||||||
|
|
||||||
|
request.LoadBalancerId = loadBalancerId
|
||||||
|
request.BackendServers = params
|
||||||
|
|
||||||
|
if nil == client {
|
||||||
|
fmt.Println("error: client is nil")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
response, err := client.AddBackendServers(request)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Print(err.Error())
|
||||||
|
}
|
||||||
|
fmt.Printf("response is %#v\n", response)
|
||||||
|
}
|
||||||
|
|
||||||
|
func RemoveBackendServers(regionId, accessKeyId, accessSecret, loadBalancerId, params string) {
|
||||||
|
|
||||||
|
client, err := slb.NewClientWithAccessKey(regionId, accessKeyId, accessSecret)
|
||||||
|
|
||||||
|
request := slb.CreateRemoveBackendServersRequest()
|
||||||
|
request.Scheme = "https"
|
||||||
|
|
||||||
|
request.LoadBalancerId = loadBalancerId
|
||||||
|
request.BackendServers = params
|
||||||
|
|
||||||
|
if nil == client {
|
||||||
|
fmt.Println("error: client is nil")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
response, err := client.RemoveBackendServers(request)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Print(err.Error())
|
||||||
|
}
|
||||||
|
fmt.Printf("response is %#v\n", response)
|
||||||
|
}
|
||||||
70
pkg/common/CmdTools/ExcelTool.go
Normal file
70
pkg/common/CmdTools/ExcelTool.go
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/tealeg/xlsx"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main02() {
|
||||||
|
data := ReadSheet("./CmdTools/星钻VIP体系.xlsx", 0)
|
||||||
|
fmt.Println(json.Marshal(data))
|
||||||
|
for index, item := range data {
|
||||||
|
if index > 0 {
|
||||||
|
level, _ := strconv.Atoi(item[0])
|
||||||
|
exp, _ := strconv.Atoi(item[1])
|
||||||
|
fmt.Printf("insert into t_vip_config (id,vip_level,min_exp,vip_name,vip_icon,create_time) values (%d,%d,%d,'v%d','https://xz-static.10909.com/XingZuanCommon/Img/Vip/%d@2x.png',now());\n", level, level, exp, level, level)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ReadSheet(file string, sheet int) [][]string {
|
||||||
|
var result [][]string
|
||||||
|
xlFile, err := xlsx.OpenFile(file)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err.Error())
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
for index, row := range xlFile.Sheets[sheet].Rows {
|
||||||
|
if index > 60 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
var data []string
|
||||||
|
for index, cell := range row.Cells {
|
||||||
|
if index > 1 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
text := cell.String()
|
||||||
|
println(text)
|
||||||
|
data = append(data, text)
|
||||||
|
}
|
||||||
|
result = append(result, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func ReadAll(file string) {
|
||||||
|
// 打开文件
|
||||||
|
xlFile, err := xlsx.OpenFile(file)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 遍历sheet页读取
|
||||||
|
for _, sheet := range xlFile.Sheets {
|
||||||
|
fmt.Println("sheet name: ", sheet.Name)
|
||||||
|
//遍历行读取
|
||||||
|
for _, row := range sheet.Rows {
|
||||||
|
// 遍历每行的列读取
|
||||||
|
for _, cell := range row.Cells {
|
||||||
|
text := cell.String()
|
||||||
|
fmt.Printf("%20s", text)
|
||||||
|
}
|
||||||
|
fmt.Print("\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.Println("\n\nimport success")
|
||||||
|
}
|
||||||
94
pkg/common/CmdTools/TencentCloudClient.go
Normal file
94
pkg/common/CmdTools/TencentCloudClient.go
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
clb "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/clb/v20180317"
|
||||||
|
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common"
|
||||||
|
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors"
|
||||||
|
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ./TencentCloudClient -t b -o add -key AKIDSoxxjI5tukPr9ECsQmwthKhroaCZlldI -sec b1FG2b3JMrESVLxjJdhYDgx12qPiplXB -reg ap-shanghai -params "{\"LoadBalancerId\":\"lb-jip7505r\",\"Targets\":[{\"InstanceId\":\"ins-n2i7x483\",\"Weight\":20}]}"
|
||||||
|
// ./TencentCloudClient -t b -o remove -key AKIDSoxxjI5tukPr9ECsQmwthKhroaCZlldI -sec b1FG2b3JMrESVLxjJdhYDgx12qPiplXB -reg ap-shanghai -params "{\"LoadBalancerId\":\"lb-jip7505r\",\"InstanceIds\":[\"ins-n2i7x483\"]}"
|
||||||
|
func main03() {
|
||||||
|
|
||||||
|
var target string
|
||||||
|
flag.StringVar(&target, "t", "b", "target: b=backendServer")
|
||||||
|
var operation string
|
||||||
|
flag.StringVar(&operation, "o", "add", "operation: add、remove")
|
||||||
|
var accessKeyId string
|
||||||
|
flag.StringVar(&accessKeyId, "key", "secretId", "accessKeyId")
|
||||||
|
var accessSecret string
|
||||||
|
flag.StringVar(&accessSecret, "sec", "secretKey", "accessSecret")
|
||||||
|
var regionId string
|
||||||
|
flag.StringVar(®ionId, "reg", "regionId", "regionId: cn-hangzhou")
|
||||||
|
var params string
|
||||||
|
flag.StringVar(¶ms, "params", "params", `
|
||||||
|
AddBackendServers: [{"ServerId":"ServerId","Weight":"100","Type":"eni","ServerIp":"192.168.11.1"}]
|
||||||
|
RemoveBackendServers: [{"ServerId":"ServerId","Weight":"100"}]
|
||||||
|
`)
|
||||||
|
flag.Parse()
|
||||||
|
flag.Usage()
|
||||||
|
fmt.Printf("target=%s,operation=%s,accessKeyId=%s,accessSecret=%s,regionId=%s,params=%s\n", target, operation, accessKeyId, accessSecret, regionId, params)
|
||||||
|
if target == "b" {
|
||||||
|
switch operation {
|
||||||
|
case "add":
|
||||||
|
ClassicBind(regionId, accessKeyId, accessSecret, params)
|
||||||
|
break
|
||||||
|
case "remove":
|
||||||
|
ClassicRemove(regionId, accessKeyId, accessSecret, params)
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
fmt.Println("operation: " + operation + " not support")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fmt.Println("target: " + target + " not support")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ClassicBind(regionId, accessKeyId, accessSecret, params string) {
|
||||||
|
credential := common.NewCredential(accessKeyId, accessSecret)
|
||||||
|
cpf := profile.NewClientProfile()
|
||||||
|
cpf.HttpProfile.Endpoint = "clb.tencentcloudapi.com"
|
||||||
|
client, _ := clb.NewClient(credential, regionId, cpf)
|
||||||
|
|
||||||
|
request := clb.NewRegisterTargetsWithClassicalLBRequest()
|
||||||
|
|
||||||
|
err := request.FromJsonString(params)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
response, err := client.RegisterTargetsWithClassicalLB(request)
|
||||||
|
if _, ok := err.(*errors.TencentCloudSDKError); ok {
|
||||||
|
fmt.Printf("An API error has returned: %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
fmt.Printf("%s", response.ToJsonString())
|
||||||
|
}
|
||||||
|
|
||||||
|
func ClassicRemove(regionId, accessKeyId, accessSecret, params string) {
|
||||||
|
credential := common.NewCredential(accessKeyId, accessSecret)
|
||||||
|
cpf := profile.NewClientProfile()
|
||||||
|
cpf.HttpProfile.Endpoint = "clb.tencentcloudapi.com"
|
||||||
|
client, _ := clb.NewClient(credential, regionId, cpf)
|
||||||
|
|
||||||
|
request := clb.NewDeregisterTargetsFromClassicalLBRequest()
|
||||||
|
err := request.FromJsonString(params)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
response, err := client.DeregisterTargetsFromClassicalLB(request)
|
||||||
|
if _, ok := err.(*errors.TencentCloudSDKError); ok {
|
||||||
|
fmt.Printf("An API error has returned: %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
fmt.Printf("%s", response.ToJsonString())
|
||||||
|
}
|
||||||
57
pkg/common/CmdTools/readme.md
Normal file
57
pkg/common/CmdTools/readme.md
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
# CMD 工具
|
||||||
|
|
||||||
|
## 阿里云SLB后端服务器client工具
|
||||||
|
|
||||||
|
### Usage
|
||||||
|
|
||||||
|
Example: SlbClient.exe -t lb -o update -reg cn-hangzhou -key LTAI5tCB8SmJcwfO -sec dX4kgF4VcblsbCVdKvtCGCmvNbLkZK -lb lb-bp1nz8xl5q8kiqfv0iumf -params "[{\"ServerId\":\"i-bp1hcv8qx0677hv9pr0s\",\"Weight\":\"100\"}]"
|
||||||
|
|
||||||
|
```
|
||||||
|
Usage of SlbClient.exe:
|
||||||
|
-key string
|
||||||
|
accessKeyId (default "accessKeyId")
|
||||||
|
-lb string
|
||||||
|
loadBalancerId (default "loadBalancerId")
|
||||||
|
-o string
|
||||||
|
operation: add、update、remove (default "update")
|
||||||
|
-params string
|
||||||
|
SetBackendServers: [{"ServerId":"ServerId","Weight":"0"}]
|
||||||
|
AddBackendServers: [{"ServerId":"ServerId","Weight":"100","Type":"eni","ServerIp":"192.168.11.1"}]
|
||||||
|
RemoveBackendServers: [{"ServerId":"ServerId","Weight":"100"}]
|
||||||
|
(default "params")
|
||||||
|
-reg string
|
||||||
|
regionId: cn-hangzhou (default "regionId")
|
||||||
|
-sec string
|
||||||
|
accessSecret (default "accessSecret")
|
||||||
|
-t string
|
||||||
|
target: lb (default "lb")
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## 腾讯云CLB后端服务器client工具
|
||||||
|
|
||||||
|
### Usage
|
||||||
|
|
||||||
|
Example1: ./TencentCloudClient -t b -o add -key AKIDSoxxjI5tukPr9ECsQmwthKhroaCZlldI -sec b1FG2b3JMrESVLxjJdhYDgx12qPiplXB -reg ap-shanghai -params "{\"LoadBalancerId\":\"lb-jip7505r\",\"Targets\":[{\"InstanceId\":\"ins-n2i7x483\",\"Weight\":20}]}"
|
||||||
|
Example2: ./TencentCloudClient -t b -o remove -key AKIDSoxxjI5tukPr9ECsQmwthKhroaCZlldI -sec b1FG2b3JMrESVLxjJdhYDgx12qPiplXB -reg ap-shanghai -params "{\"LoadBalancerId\":\"lb-jip7505r\",\"InstanceIds\":[\"ins-n2i7x483\"]}"
|
||||||
|
|
||||||
|
```
|
||||||
|
Usage of ./TencentCloudClient:
|
||||||
|
-key string
|
||||||
|
accessKeyId (default "secretId")
|
||||||
|
-o string
|
||||||
|
operation: add、remove (default "add")
|
||||||
|
-params string
|
||||||
|
|
||||||
|
AddBackendServers: [{"ServerId":"ServerId","Weight":"100","Type":"eni","ServerIp":"192.168.11.1"}]
|
||||||
|
RemoveBackendServers: [{"ServerId":"ServerId","Weight":"100"}]
|
||||||
|
(default "params")
|
||||||
|
-reg string
|
||||||
|
regionId: cn-hangzhou (default "regionId")
|
||||||
|
-sec string
|
||||||
|
accessSecret (default "secretKey")
|
||||||
|
-t string
|
||||||
|
target: b=backendServer (default "b")
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
146
pkg/common/ConstVar.go
Normal file
146
pkg/common/ConstVar.go
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
package common
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/anxpp/beego/logs"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
|
||||||
|
//公用
|
||||||
|
|
||||||
|
//API版本号
|
||||||
|
// API_V_NUM = "1"
|
||||||
|
|
||||||
|
//API密钥
|
||||||
|
// API_SECRECT = "x63363eacf804b4394a120aea240fd9a"
|
||||||
|
|
||||||
|
//图片域名
|
||||||
|
|
||||||
|
PHOTO_URL_PREV = "https://photo-app.ddegame.cn/"
|
||||||
|
|
||||||
|
MEDIA_URL_PREV = "https://media-qiniu-app.ddegame.cn/"
|
||||||
|
|
||||||
|
//====== 三方key =======
|
||||||
|
//NETEASE_IM_APPKEY = "a0671ecde01ef03928ccfd460c62d203"
|
||||||
|
//NETEASE_IM_SECRET = "eb88916031ca"
|
||||||
|
|
||||||
|
//用户认证申请状态
|
||||||
|
USER_CERTIFY_STATUS_INIT = "1" //已提交
|
||||||
|
USER_CERTIFY_STATUS_SUCCESS = "2" //成功
|
||||||
|
USER_CERTIFY_STATUS_INIT_FAIL = "3" //初始化失败
|
||||||
|
USER_CERTIFY_STATUS_AUTH_FAIL = "4" //认证失败
|
||||||
|
USER_CERTIFY_STATUS_REFUSE = "5" //拒绝
|
||||||
|
|
||||||
|
// 模块和页面ID
|
||||||
|
|
||||||
|
//用户管理
|
||||||
|
MODULE_ID_USER_MANAGE = "1"
|
||||||
|
//基础数据
|
||||||
|
MODULE_ID_BASE_DATA = "4"
|
||||||
|
//财务管理
|
||||||
|
MODULE_ID_FIN_MANAGE = "7"
|
||||||
|
//数据报表
|
||||||
|
MODULE_ID_DATA_REPORT = "14"
|
||||||
|
//聊天室管理
|
||||||
|
MODULE_ID_ROOM_MANAGE = "20"
|
||||||
|
//付款管理
|
||||||
|
MODULE_ID_PAY_MANAGE = "100"
|
||||||
|
//抽奖管理
|
||||||
|
MODULE_ID_LUCK_MANAGE = "200"
|
||||||
|
//技能管理
|
||||||
|
MODULE_ID_SKILL_MANAGE = "300"
|
||||||
|
//技能订单管理
|
||||||
|
MODULE_ID_SKILL_ORDER_MANAGE = "400"
|
||||||
|
//技能订单列表
|
||||||
|
PAGE_ID_FIN_SKILL_ORDER_LIST = "401"
|
||||||
|
|
||||||
|
//用户列表
|
||||||
|
PAGE_ID_USER_LIST = "2"
|
||||||
|
//用户认证列表
|
||||||
|
PAGE_ID_USER_AUTH_LIST = "3"
|
||||||
|
//礼物列表
|
||||||
|
PAGE_ID_GIFT_LIST = "5"
|
||||||
|
//首页分类列表
|
||||||
|
PAGE_ID_HOME_TAB_LIST = "6"
|
||||||
|
//充值列表
|
||||||
|
PAGE_ID_FIN_RECHARGE_LIST = "8"
|
||||||
|
//提现列表
|
||||||
|
PAGE_ID_FIN_WITHDRAW_LIST = "9"
|
||||||
|
//兑换列表
|
||||||
|
PAGE_ID_FIN_EXCHANGE_LIST = "10"
|
||||||
|
//表情列表
|
||||||
|
PAGE_ID_FIN_EMOJI_ORDER_LIST = "11"
|
||||||
|
//守护订单列表
|
||||||
|
PAGE_ID_FIN_GUARD_ORDER_LIST = "12"
|
||||||
|
//打赏列表
|
||||||
|
PAGE_ID_FIN_PRESENT_GIFT_LIST = "13"
|
||||||
|
|
||||||
|
//日报表
|
||||||
|
PAGE_ID_DAY_REPORT = "15"
|
||||||
|
//厅日流水报表
|
||||||
|
PAGE_ID_DAY_ROOM_SALE_REPORT = "142"
|
||||||
|
//实时厅流水报表
|
||||||
|
PAGE_ID_TODAY_ROOM_SALE_RANK = "143"
|
||||||
|
//厅费用排行
|
||||||
|
PAGE_ID_TODAY_ROOM_MARKET_FEE_RANK = "144"
|
||||||
|
|
||||||
|
//聊天室列表
|
||||||
|
PAGE_ID_CHATROOM_LIST = "21"
|
||||||
|
//房主列表
|
||||||
|
PAGE_ID_CHATROOM_OWNER_LIST = "22"
|
||||||
|
//打赏列表
|
||||||
|
PAGE_ID_FIN_OPERATION_DIAMOND_LIST = "24"
|
||||||
|
//
|
||||||
|
PAGE_ID_FILTER_USER_NO = "25"
|
||||||
|
//付款单列表
|
||||||
|
PAGE_ID_PAY_ORDER_LIST = "101"
|
||||||
|
//客户列表
|
||||||
|
PAGE_ID_PAY_CUSTOMER_LIST = "102"
|
||||||
|
|
||||||
|
//砸蛋列表
|
||||||
|
PAGE_ID_HIT_EGG_LIST = "201"
|
||||||
|
//方案列表
|
||||||
|
PAGE_ID_SOLUTION_LIST_LIST = "202"
|
||||||
|
//权益列表
|
||||||
|
PAGE_ID_QUANYI_LIST_LIST = "203"
|
||||||
|
//用户砸蛋汇总
|
||||||
|
PAGE_ID_USER_HITEGG_SUMMARY = "204"
|
||||||
|
|
||||||
|
//技能申请列表
|
||||||
|
PAGE_ID_SKILL_APPLY_LIST_LIST = "301"
|
||||||
|
|
||||||
|
//技能列表
|
||||||
|
PAGE_ID_SKILL_LIST = "302"
|
||||||
|
|
||||||
|
//卖家列表
|
||||||
|
PAGE_ID_SELLER_LIST = "303"
|
||||||
|
|
||||||
|
//SKU列表
|
||||||
|
PAGE_ID_SKILL_SKU_LIST = "304"
|
||||||
|
|
||||||
|
//技能修改申请列表
|
||||||
|
PAGE_ID_SKILL_EDIT_LIST = "305"
|
||||||
|
|
||||||
|
//技能价格列表
|
||||||
|
PAGE_ID_SKILL_PRICE_LIST = "306"
|
||||||
|
//技能订单列表
|
||||||
|
PAGE_ID_SKILL_ORDER_LIST = "401"
|
||||||
|
|
||||||
|
// 代理订单类型 后台充值
|
||||||
|
AGENT_DIAMOND_ORDER_TYPE_ADMIN_RECHARGE = "1"
|
||||||
|
// 代理订单类型 上级转账
|
||||||
|
AGENT_DIAMOND_ORDER_TYPE_UPER_TRANSFER = "2"
|
||||||
|
|
||||||
|
// 文本反垃圾类型 - 昵称检测
|
||||||
|
RISK_TYPE_TEXT_NICKNAME = "nickname_detection"
|
||||||
|
RISK_TYPE_TEXT_COMMENT = "comment_detection" //评论检测
|
||||||
|
)
|
||||||
|
|
||||||
|
func LogJson(v interface{}) {
|
||||||
|
b, _ := json.Marshal(v)
|
||||||
|
logs.Info(string(b))
|
||||||
|
}
|
||||||
|
|
||||||
|
const photoDomainUrl = "https://ddphoto.youkeya.cn"
|
||||||
96
pkg/common/HyTools/HttpClient.go
Normal file
96
pkg/common/HyTools/HttpClient.go
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
package HyTools
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 调用POST请求
|
||||||
|
func HttpPost(url string, body string) (remoteResponse string, err error) {
|
||||||
|
|
||||||
|
bodyReader := strings.NewReader(body)
|
||||||
|
//application/x-www-form-urlencoded
|
||||||
|
//application/json
|
||||||
|
response, err1 := http.Post(url, "application/x-www-form-urlencoded", bodyReader)
|
||||||
|
|
||||||
|
if err1 != nil {
|
||||||
|
err = err1
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer response.Body.Close()
|
||||||
|
|
||||||
|
resBody, err2 := ioutil.ReadAll(response.Body)
|
||||||
|
|
||||||
|
if err2 != nil {
|
||||||
|
err = err2
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
remoteResponse = string(resBody)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 复杂http请求
|
||||||
|
func HttpDo(httpMethod string, url string, headerMap map[string]string, rawBody string) (remoteResponse string, err error) {
|
||||||
|
|
||||||
|
client := &http.Client{}
|
||||||
|
|
||||||
|
req, err0 := http.NewRequest(httpMethod, url, strings.NewReader(rawBody))
|
||||||
|
|
||||||
|
if err0 != nil {
|
||||||
|
err = err0
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(headerMap) > 0 {
|
||||||
|
for k, v := range headerMap {
|
||||||
|
req.Header.Set(k, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err1 := client.Do(req)
|
||||||
|
|
||||||
|
if err1 != nil {
|
||||||
|
err = err1
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
body, err2 := ioutil.ReadAll(resp.Body)
|
||||||
|
if err2 != nil {
|
||||||
|
err = err2
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
remoteResponse = string(body)
|
||||||
|
return
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func HttpPostJson(url string, body string) (remoteResponse string, err error) {
|
||||||
|
|
||||||
|
bodyReader := strings.NewReader(body)
|
||||||
|
//application/x-www-form-urlencoded
|
||||||
|
//application/json
|
||||||
|
response, err1 := http.Post(url, "application/json", bodyReader)
|
||||||
|
|
||||||
|
if err1 != nil {
|
||||||
|
err = err1
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer response.Body.Close()
|
||||||
|
|
||||||
|
resBody, err2 := ioutil.ReadAll(response.Body)
|
||||||
|
|
||||||
|
if err2 != nil {
|
||||||
|
err = err2
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
remoteResponse = string(resBody)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
40
pkg/common/HyTools/RandTools.go
Normal file
40
pkg/common/HyTools/RandTools.go
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
package HyTools
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/rand"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func RandInt64(min, max int64) int64 {
|
||||||
|
if min >= max || min == 0 || max == 0 {
|
||||||
|
return max
|
||||||
|
}
|
||||||
|
return rand.Int63n(max-min) + min
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取随机数字字符串
|
||||||
|
func GetRandNumber(l int) string {
|
||||||
|
|
||||||
|
str := "0123456789"
|
||||||
|
bytes := []byte(str)
|
||||||
|
result := []byte{}
|
||||||
|
r := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||||
|
for i := 0; i < l; i++ {
|
||||||
|
result = append(result, bytes[r.Intn(len(bytes))])
|
||||||
|
}
|
||||||
|
return string(result)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成随机字符串
|
||||||
|
func GetRandomString(l int) string {
|
||||||
|
|
||||||
|
str := "0123456789abcdefghijklmnopqrstuvwxyz"
|
||||||
|
bytes := []byte(str)
|
||||||
|
result := []byte{}
|
||||||
|
r := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||||
|
for i := 0; i < l; i++ {
|
||||||
|
result = append(result, bytes[r.Intn(len(bytes))])
|
||||||
|
}
|
||||||
|
return string(result)
|
||||||
|
}
|
||||||
146
pkg/common/HyTools/RsaUtil.go
Normal file
146
pkg/common/HyTools/RsaUtil.go
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
package HyTools
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto"
|
||||||
|
"crypto/rand"
|
||||||
|
"crypto/rsa"
|
||||||
|
"crypto/sha1"
|
||||||
|
"crypto/x509"
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/pem"
|
||||||
|
"errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RSA加密
|
||||||
|
func RsaEncrypt(origData string, publicKey string) (string, error) {
|
||||||
|
|
||||||
|
block, _ := pem.Decode([]byte(publicKey)) //将密钥解析成公钥实例
|
||||||
|
if block == nil {
|
||||||
|
return "", errors.New("public key error")
|
||||||
|
}
|
||||||
|
|
||||||
|
pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes) //解析pem.Decode()返回的Block指针实例
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
pub := pubInterface.(*rsa.PublicKey)
|
||||||
|
|
||||||
|
partLen := pub.N.BitLen()/8 - 11
|
||||||
|
|
||||||
|
chunks := ByteSplit([]byte(origData), partLen)
|
||||||
|
|
||||||
|
buffer := bytes.NewBufferString("")
|
||||||
|
|
||||||
|
for _, chunk := range chunks {
|
||||||
|
|
||||||
|
bytes, err := rsa.EncryptPKCS1v15(rand.Reader, pub, chunk)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer.Write(bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
return base64.StdEncoding.EncodeToString(buffer.Bytes()), nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// RSA解密
|
||||||
|
func RsaDecrypt(ciphertext string, privateKey string) (string, error) {
|
||||||
|
|
||||||
|
block, _ := pem.Decode([]byte(privateKey))
|
||||||
|
|
||||||
|
if block == nil {
|
||||||
|
|
||||||
|
return "", errors.New("private key error!")
|
||||||
|
}
|
||||||
|
priv, err := x509.ParsePKCS1PrivateKey(block.Bytes)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
partLen := priv.N.BitLen() / 8
|
||||||
|
|
||||||
|
raw, err := base64.StdEncoding.DecodeString(ciphertext)
|
||||||
|
|
||||||
|
chunks := ByteSplit([]byte(raw), partLen)
|
||||||
|
|
||||||
|
buffer := bytes.NewBufferString("")
|
||||||
|
|
||||||
|
for _, chunk := range chunks {
|
||||||
|
|
||||||
|
decrypted, err := rsa.DecryptPKCS1v15(rand.Reader, priv, chunk)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
|
||||||
|
return "", err
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer.Write(decrypted)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return buffer.String(), err
|
||||||
|
}
|
||||||
|
|
||||||
|
// RSA SHA1加签
|
||||||
|
func RsaSHA1Sign(data string, privateKey string) (string, error) {
|
||||||
|
|
||||||
|
block, _ := pem.Decode([]byte(privateKey))
|
||||||
|
if block == nil {
|
||||||
|
return "", errors.New("Sign private key decode error")
|
||||||
|
}
|
||||||
|
|
||||||
|
prk8, err := x509.ParsePKCS1PrivateKey(block.Bytes)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
h := sha1.New()
|
||||||
|
h.Write([]byte(data))
|
||||||
|
hashed := h.Sum(nil)
|
||||||
|
|
||||||
|
sign, err := rsa.SignPKCS1v15(rand.Reader, prk8, crypto.SHA1, hashed)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return base64.StdEncoding.EncodeToString(sign), err
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// RSA SHA1验签
|
||||||
|
func RsaSHA1Verify(data string, sign string, publicKey string) error {
|
||||||
|
|
||||||
|
h := sha1.New()
|
||||||
|
h.Write([]byte(data))
|
||||||
|
hashed := h.Sum(nil)
|
||||||
|
|
||||||
|
decodedSign, err := base64.StdEncoding.DecodeString(sign)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
|
||||||
|
return err
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
block, _ := pem.Decode([]byte(publicKey))
|
||||||
|
if block == nil {
|
||||||
|
return errors.New("Sign public key decode error")
|
||||||
|
}
|
||||||
|
|
||||||
|
pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes) //解析pem.Decode()返回的Block指针实例
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
pub := pubInterface.(*rsa.PublicKey)
|
||||||
|
|
||||||
|
return rsa.VerifyPKCS1v15(pub, crypto.SHA1, hashed, decodedSign)
|
||||||
|
|
||||||
|
}
|
||||||
30
pkg/common/HyTools/StringBuilder.go
Normal file
30
pkg/common/HyTools/StringBuilder.go
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
package HyTools
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
type StringBuilder struct {
|
||||||
|
buf bytes.Buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewStringBuilder() *StringBuilder {
|
||||||
|
return &StringBuilder{buf: bytes.Buffer{}}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *StringBuilder) Append(obj interface{}) *StringBuilder {
|
||||||
|
this.buf.WriteString(fmt.Sprintf("%v", obj))
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *StringBuilder) ToString() string {
|
||||||
|
return this.buf.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 字符串转int32
|
||||||
|
func JsonStr(v interface{}) string {
|
||||||
|
bys, _ := json.Marshal(v)
|
||||||
|
return string(bys)
|
||||||
|
}
|
||||||
243
pkg/common/HyTools/TypeTools.go
Normal file
243
pkg/common/HyTools/TypeTools.go
Normal file
@ -0,0 +1,243 @@
|
|||||||
|
package HyTools
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/md5"
|
||||||
|
"crypto/sha1"
|
||||||
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MD5加密
|
||||||
|
func StringToMD5(waitMD5string string) string {
|
||||||
|
|
||||||
|
h := md5.New()
|
||||||
|
h.Write([]byte(waitMD5string))
|
||||||
|
cipherStr := h.Sum(nil)
|
||||||
|
|
||||||
|
result := hex.EncodeToString(cipherStr)
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// SHA1加密
|
||||||
|
func StringToSHA1(waitMD5string string) string {
|
||||||
|
|
||||||
|
h := sha1.New()
|
||||||
|
h.Write([]byte(waitMD5string))
|
||||||
|
cipherStr := h.Sum(nil)
|
||||||
|
|
||||||
|
result := hex.EncodeToString(cipherStr)
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// 字符串转int64
|
||||||
|
func StringToInt64(waitString string) int64 {
|
||||||
|
|
||||||
|
stringInt64, err := strconv.ParseInt(waitString, 10, 64)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return stringInt64
|
||||||
|
}
|
||||||
|
|
||||||
|
// 字符串转int32
|
||||||
|
func StringToInt(waitString string) int {
|
||||||
|
|
||||||
|
stringInt, err := strconv.Atoi(waitString)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return stringInt
|
||||||
|
}
|
||||||
|
|
||||||
|
// 字符串转float64
|
||||||
|
func StringToFloat64(waitString string) float64 {
|
||||||
|
|
||||||
|
stringInt64, err := strconv.ParseFloat(waitString, 64)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return stringInt64
|
||||||
|
}
|
||||||
|
|
||||||
|
// strconv.FormatFloat(float64, 'E', -1, 64)
|
||||||
|
// float64转字符串
|
||||||
|
func Float64ToString(waitFloat64 float64) string {
|
||||||
|
|
||||||
|
stringInt64 := strconv.FormatFloat(waitFloat64, 'f', -1, 64)
|
||||||
|
|
||||||
|
return stringInt64
|
||||||
|
}
|
||||||
|
|
||||||
|
// 截取字符串
|
||||||
|
func Substr(str string, start int, length int) string {
|
||||||
|
rs := []rune(str)
|
||||||
|
rl := len(rs)
|
||||||
|
end := 0
|
||||||
|
|
||||||
|
if start < 0 {
|
||||||
|
start = rl - 1 + start
|
||||||
|
}
|
||||||
|
end = start + length
|
||||||
|
|
||||||
|
if start > end {
|
||||||
|
start, end = end, start
|
||||||
|
}
|
||||||
|
|
||||||
|
if start < 0 {
|
||||||
|
start = 0
|
||||||
|
}
|
||||||
|
if start > rl {
|
||||||
|
start = rl
|
||||||
|
}
|
||||||
|
if end < 0 {
|
||||||
|
end = 0
|
||||||
|
}
|
||||||
|
if end > rl {
|
||||||
|
end = rl
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(rs[start:end])
|
||||||
|
}
|
||||||
|
|
||||||
|
// map转html
|
||||||
|
func MapToXML(mapData map[string]string) string {
|
||||||
|
|
||||||
|
if len(mapData) == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
sb := NewStringBuilder()
|
||||||
|
sb.Append("<xml>")
|
||||||
|
for key, val := range mapData {
|
||||||
|
sb.Append("<" + key + ">")
|
||||||
|
sb.Append(val)
|
||||||
|
sb.Append("</" + key + ">")
|
||||||
|
|
||||||
|
}
|
||||||
|
sb.Append("</xml>")
|
||||||
|
|
||||||
|
return sb.ToString()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取当前年周
|
||||||
|
func GetCurrentYearWeek() string {
|
||||||
|
|
||||||
|
year, week := time.Now().ISOWeek()
|
||||||
|
|
||||||
|
return strconv.Itoa(year) + strconv.Itoa(week)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 字符串转time类型
|
||||||
|
func StringToTime(dateString string) time.Time {
|
||||||
|
|
||||||
|
//获取本地location
|
||||||
|
toBeCharge := dateString //待转化为时间戳的字符串 注意 这里的小时和分钟还要秒必须写 因为是跟着模板走的 修改模板的话也可以不写
|
||||||
|
timeLayout := "2006-01-02 15:04:05" //转化所需模板
|
||||||
|
loc, _ := time.LoadLocation("Local") //重要:获取时区
|
||||||
|
theTime, _ := time.ParseInLocation(timeLayout, toBeCharge, loc) //使用模板在对应时区转化为time.time类型
|
||||||
|
//sr := theTime.Unix() //转化为时间戳 类型是int64
|
||||||
|
|
||||||
|
//时间戳转日期
|
||||||
|
//dataTimeStr := time.Unix(sr, 0).Format(timeLayout) //设置时间戳 使用模板格式化为日期字符串
|
||||||
|
|
||||||
|
return theTime
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断数组是否包含某个元素
|
||||||
|
func CheckStringIsInArray(arrayList []string, element string) bool {
|
||||||
|
|
||||||
|
if len(arrayList) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
isInArray := false
|
||||||
|
for _, data := range arrayList {
|
||||||
|
|
||||||
|
if data == element {
|
||||||
|
isInArray = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return isInArray
|
||||||
|
}
|
||||||
|
|
||||||
|
// slice to 字符串
|
||||||
|
func StringListToString(stringList []string, split string) string {
|
||||||
|
if len(split) == 0 {
|
||||||
|
split = ","
|
||||||
|
}
|
||||||
|
return strings.Replace(strings.Trim(fmt.Sprint(stringList), "[]"), " ", split, -1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// map 转 url参数
|
||||||
|
func MapToUrlParams(mapData map[string]string) string {
|
||||||
|
|
||||||
|
mapLen := len(mapData)
|
||||||
|
if mapLen == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
sb := NewStringBuilder()
|
||||||
|
|
||||||
|
i := 0
|
||||||
|
for k, v := range mapData {
|
||||||
|
|
||||||
|
sb.Append(k + "=" + v)
|
||||||
|
if i < mapLen-1 {
|
||||||
|
sb.Append("&")
|
||||||
|
}
|
||||||
|
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
return sb.ToString()
|
||||||
|
}
|
||||||
|
|
||||||
|
// []byte 合并
|
||||||
|
func BytesCombine(pBytes ...[]byte) []byte {
|
||||||
|
return bytes.Join(pBytes, []byte(""))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取当前UTC时间 秒数
|
||||||
|
func GetCurrentUtcTimeSecond() int64 {
|
||||||
|
return time.Now().UTC().Unix()
|
||||||
|
}
|
||||||
|
|
||||||
|
// byte数组分组
|
||||||
|
func ByteSplit(buf []byte, lim int) [][]byte {
|
||||||
|
|
||||||
|
var chunk []byte
|
||||||
|
|
||||||
|
chunks := make([][]byte, 0, len(buf)/lim+1)
|
||||||
|
|
||||||
|
for len(buf) >= lim {
|
||||||
|
|
||||||
|
chunk, buf = buf[:lim], buf[lim:]
|
||||||
|
|
||||||
|
chunks = append(chunks, chunk)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bufLen := len(buf)
|
||||||
|
if bufLen > 0 {
|
||||||
|
|
||||||
|
chunks = append(chunks, buf[:bufLen])
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return chunks
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func Float64ToIntRound(f float64) int {
|
||||||
|
return int(math.Round(f))
|
||||||
|
}
|
||||||
111
pkg/common/HyTools/Uuid.go
Normal file
111
pkg/common/HyTools/Uuid.go
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
package HyTools
|
||||||
|
|
||||||
|
import (
|
||||||
|
crand "crypto/rand"
|
||||||
|
"encoding/hex"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
mrand "math/rand"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
// seeded indicates if math/rand has been seeded
|
||||||
|
var seeded bool = false
|
||||||
|
|
||||||
|
// uuidRegex matches the UUID string
|
||||||
|
var uuidRegex *regexp.Regexp = regexp.MustCompile(`^\{?([a-fA-F0-9]{8})-?([a-fA-F0-9]{4})-?([a-fA-F0-9]{4})-?([a-fA-F0-9]{4})-?([a-fA-F0-9]{12})\}?$`)
|
||||||
|
|
||||||
|
// UUID type.
|
||||||
|
type UUID [16]byte
|
||||||
|
|
||||||
|
// Hex returns a hex string representation of the UUID in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format.
|
||||||
|
func (this UUID) Hex() string {
|
||||||
|
|
||||||
|
x := [16]byte(this)
|
||||||
|
|
||||||
|
return fmt.Sprintf("%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
|
||||||
|
x[0], x[1], x[2], x[3], x[4],
|
||||||
|
x[5], x[6],
|
||||||
|
x[7], x[8],
|
||||||
|
x[9], x[10], x[11], x[12], x[13], x[14], x[15])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rand generates a new version 4 UUID.
|
||||||
|
func Rand() UUID {
|
||||||
|
var x [16]byte
|
||||||
|
randBytes(x[:])
|
||||||
|
x[6] = (x[6] & 0x0F) | 0x40
|
||||||
|
x[8] = (x[8] & 0x3F) | 0x80
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromStr returns a UUID based on a string.
|
||||||
|
// The string could be in the following format:
|
||||||
|
//
|
||||||
|
// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||||
|
//
|
||||||
|
// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||||
|
//
|
||||||
|
// {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
|
||||||
|
//
|
||||||
|
// If the string is not in one of these formats, it'll return an error.
|
||||||
|
func FromStr(s string) (id UUID, err error) {
|
||||||
|
if s == "" {
|
||||||
|
err = errors.New("Empty string")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
parts := uuidRegex.FindStringSubmatch(s)
|
||||||
|
if parts == nil {
|
||||||
|
err = errors.New("Invalid string format")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var array [16]byte
|
||||||
|
slice, _ := hex.DecodeString(strings.Join(parts[1:], ""))
|
||||||
|
copy(array[:], slice)
|
||||||
|
id = array
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// MustFromStr behaves similarly to FromStr except that it'll panic instead of
|
||||||
|
// returning an error.
|
||||||
|
func MustFromStr(s string) UUID {
|
||||||
|
id, err := FromStr(s)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return id
|
||||||
|
}
|
||||||
|
|
||||||
|
// randBytes uses crypto random to get random numbers. If fails then it uses math random.
|
||||||
|
func randBytes(x []byte) {
|
||||||
|
|
||||||
|
length := len(x)
|
||||||
|
n, err := crand.Read(x)
|
||||||
|
|
||||||
|
if n != length || err != nil {
|
||||||
|
if !seeded {
|
||||||
|
mrand.Seed(time.Now().UnixNano())
|
||||||
|
}
|
||||||
|
|
||||||
|
for length > 0 {
|
||||||
|
length--
|
||||||
|
x[length] = byte(mrand.Int31n(256))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetUUID() string {
|
||||||
|
|
||||||
|
u7, _ := uuid.NewV7()
|
||||||
|
return strings.ReplaceAll(u7.String(), "-", "")
|
||||||
|
// var uuid UUID = Rand()
|
||||||
|
|
||||||
|
// return uuid.Hex()
|
||||||
|
|
||||||
|
}
|
||||||
1352
pkg/common/app_const.go
Normal file
1352
pkg/common/app_const.go
Normal file
File diff suppressed because it is too large
Load Diff
94
pkg/common/es/document/user.go
Normal file
94
pkg/common/es/document/user.go
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
package document
|
||||||
|
|
||||||
|
type User struct {
|
||||||
|
Id string
|
||||||
|
Mobile string
|
||||||
|
RegionCode string
|
||||||
|
NickName string
|
||||||
|
Salt string
|
||||||
|
Password string
|
||||||
|
Status string
|
||||||
|
Avatar string
|
||||||
|
Gender string
|
||||||
|
Birthday string
|
||||||
|
WxUnionId string
|
||||||
|
QqOpenId string
|
||||||
|
MarketChannel string
|
||||||
|
CreateTime string
|
||||||
|
IsActive string
|
||||||
|
ActiveTime string
|
||||||
|
SignupSource string
|
||||||
|
SignupDevicePlatform string
|
||||||
|
SignupDeviceUdid string
|
||||||
|
IdNo string
|
||||||
|
IsAuth string
|
||||||
|
TrueName string
|
||||||
|
Sign string
|
||||||
|
ViewFlag string
|
||||||
|
VideoUrl string
|
||||||
|
School string
|
||||||
|
UserNo string
|
||||||
|
BankName string
|
||||||
|
BankUserName string
|
||||||
|
BankBranchName string
|
||||||
|
BankCardNo string
|
||||||
|
AuthFailReason string
|
||||||
|
AlipayAccount string
|
||||||
|
WellNoIcon string
|
||||||
|
}
|
||||||
|
|
||||||
|
//字符串: text keyword
|
||||||
|
//整数 : byte, short, integer, long
|
||||||
|
//浮点数: float, double
|
||||||
|
//布尔型: boolean
|
||||||
|
//日期: date
|
||||||
|
var UserIndex = map[string]interface{}{
|
||||||
|
"settings": map[string]interface{}{"number_of_shards": 5, "number_of_replicas": 1},
|
||||||
|
"mappings": map[string]interface{}{
|
||||||
|
"properties": map[string]interface{}{
|
||||||
|
"ActiveTime": map[string]string{"type": "date", "format": "yyyy-MM-dd HH:mm:ssZ||yyyy-MM-dd HH:mm:ss.SSSZ||yyyy-MM-ddZ||epoch_millis||epoch_second"},
|
||||||
|
"AlipayAccount": map[string]string{"type": "keyword"},
|
||||||
|
"AuthFailReason": map[string]string{"type": "text", "analyzer": "ik_max_word"},
|
||||||
|
"Avatar": map[string]string{"type": "text", "analyzer": "ik_max_word"},
|
||||||
|
"BankBranchName": map[string]string{"type": "keyword"},
|
||||||
|
"BankCardNo": map[string]string{"type": "keyword"},
|
||||||
|
"BankName": map[string]string{"type": "text"},
|
||||||
|
"BankUserName": map[string]string{"type": "text"},
|
||||||
|
"Birthday": map[string]string{"type": "date", "format": "yyyy-MM-dd HH:mm:ssZ||yyyy-MM-dd HH:mm:ss.SSSZ||yyyy-MM-ddZ||epoch_millis||epoch_second"},
|
||||||
|
"CreateTime": map[string]string{"type": "date", "format": "yyyy-MM-dd HH:mm:ssZ||yyyy-MM-dd HH:mm:ss.SSSZ||yyyy-MM-ddZ||epoch_millis||epoch_second"},
|
||||||
|
"Gender": map[string]string{"type": "keyword"},
|
||||||
|
"Id": map[string]string{"type": "keyword"},
|
||||||
|
"IdNo": map[string]string{"type": "keyword"},
|
||||||
|
"IsActive": map[string]string{"type": "keyword"},
|
||||||
|
"IsAuth": map[string]string{"type": "keyword"},
|
||||||
|
"MarketChannel": map[string]string{"type": "keyword"},
|
||||||
|
"Mobile": map[string]string{"type": "keyword"},
|
||||||
|
"NickName": map[string]string{"type": "text", "analyzer": "ik_max_word"},
|
||||||
|
"QqOpenId": map[string]string{"type": "keyword"},
|
||||||
|
"RegionCode": map[string]string{"type": "keyword"},
|
||||||
|
"Salt": map[string]string{"type": "keyword"},
|
||||||
|
"School": map[string]string{"type": "text", "analyzer": "ik_max_word"},
|
||||||
|
"Sign": map[string]string{"type": "text", "analyzer": "ik_max_word"},
|
||||||
|
"SignupDevicePlatform": map[string]string{"type": "text", "analyzer": "ik_max_word"},
|
||||||
|
"SignupDeviceUdid": map[string]string{"type": "keyword"},
|
||||||
|
"SignupSource": map[string]string{"type": "text", "analyzer": "ik_max_word"},
|
||||||
|
"Status": map[string]string{"type": "keyword"},
|
||||||
|
"TrueName": map[string]string{"type": "text", "analyzer": "ik_max_word"},
|
||||||
|
"UserNo": map[string]string{"type": "keyword"},
|
||||||
|
"VideoUrl": map[string]string{"type": "text", "analyzer": "ik_max_word"},
|
||||||
|
"ViewFlag": map[string]string{"type": "keyword"},
|
||||||
|
"WellNoIcon": map[string]string{"type": "keyword"},
|
||||||
|
"WxUnionId": map[string]string{"type": "keyword"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var MessageIndex = map[string]interface{}{
|
||||||
|
"settings": map[string]interface{}{"number_of_shards": 5, "number_of_replicas": 1},
|
||||||
|
"mappings": map[string]interface{}{
|
||||||
|
"properties": map[string]interface{}{
|
||||||
|
"id": map[string]string{"type": "keyword"},
|
||||||
|
"curTime": map[string]string{"type": "date", "format": "yyyy-MM-dd HH:mm:ssZ||yyyy-MM-dd HH:mm:ss.SSSZ||yyyy-MM-ddZ||epoch_millis||epoch_second"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
261
pkg/common/es/es_client.go
Normal file
261
pkg/common/es/es_client.go
Normal file
@ -0,0 +1,261 @@
|
|||||||
|
package ess
|
||||||
|
|
||||||
|
import (
|
||||||
|
"servicebase/pkg/common/es/document"
|
||||||
|
"servicebase/pkg/common/messages"
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"reflect"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/anxpp/beego/logs"
|
||||||
|
"github.com/olivere/elastic/v7"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
)
|
||||||
|
|
||||||
|
var client *elastic.Client
|
||||||
|
|
||||||
|
type EsClient struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func Init() {
|
||||||
|
index := messages.TagIndex(string(messages.EventTagUser))
|
||||||
|
client = _connect()
|
||||||
|
exists, e := client.IndexExists(index).Do(context.Background())
|
||||||
|
if e != nil {
|
||||||
|
logs.Error("IndexExists ", index, " error: ", e.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !exists {
|
||||||
|
logs.Info("es user not exist")
|
||||||
|
createIndex, e := client.CreateIndex(index).BodyJson(document.UserIndex).Do(context.Background())
|
||||||
|
if e != nil {
|
||||||
|
logs.Error("IndexCreate ", index, " error: ", e.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !createIndex.Acknowledged {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
indexMessage := messages.TagIndex(string(messages.EventTagMessage))
|
||||||
|
existsMessage, e := client.IndexExists(indexMessage).Do(context.Background())
|
||||||
|
if e != nil {
|
||||||
|
logs.Error("IndexExists indexMessage", index, " error: ", e.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !existsMessage {
|
||||||
|
logs.Info("es indexMessage not exist")
|
||||||
|
createIndex, e := client.CreateIndex(indexMessage).BodyJson(document.MessageIndex).Do(context.Background())
|
||||||
|
if e != nil {
|
||||||
|
logs.Error("IndexCreate ", indexMessage, " error: ", e.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !createIndex.Acknowledged {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logs.Info("init elasticsearch finish")
|
||||||
|
}
|
||||||
|
|
||||||
|
func _connect() (c *elastic.Client) {
|
||||||
|
c, e := elastic.NewSimpleClient(
|
||||||
|
elastic.SetHealthcheck(true),
|
||||||
|
elastic.SetHealthcheckInterval(10*time.Second),
|
||||||
|
elastic.SetURL(viper.GetString("es.default.addr")),
|
||||||
|
// elastic.SetBasicAuth(beego.AppConfig.String("es_username"), beego.AppConfig.String("es_password")),
|
||||||
|
)
|
||||||
|
if e != nil {
|
||||||
|
logs.Error("NewClient_error: ", e.Error())
|
||||||
|
}
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建记录
|
||||||
|
func (*EsClient) Create(index, id string, model interface{}) (body string, success bool, msg string) {
|
||||||
|
client := _connect()
|
||||||
|
_, e := client.Index().Index(index).Id(id).BodyJson(model).Do(context.Background())
|
||||||
|
if e != nil {
|
||||||
|
success = false
|
||||||
|
msg = e.Error()
|
||||||
|
b, _ := json.Marshal(model)
|
||||||
|
logs.Error("Document Create Error: ", e.Error(), " document: ", string(b), index, id)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
success = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断存在
|
||||||
|
func (*EsClient) Exists(index, id string) (exists, success bool, msg string, e error) {
|
||||||
|
client := _connect()
|
||||||
|
exists, e = client.Exists().Index(index).Type("_doc").Id(id).Do(context.Background())
|
||||||
|
if e != nil {
|
||||||
|
success = false
|
||||||
|
msg = e.Error()
|
||||||
|
logs.Error("Id Exists Error: ", e.Error(), " id: ", id)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
success = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新记录
|
||||||
|
func (*EsClient) Update(index, id string, model interface{}) (body string, success bool, msg string) {
|
||||||
|
client := _connect()
|
||||||
|
_, e := client.Update().Index(index).Id(id).Doc(model).Do(context.Background())
|
||||||
|
if e != nil {
|
||||||
|
success = false
|
||||||
|
msg = e.Error()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
success = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 搜索
|
||||||
|
func (*EsClient) Search(index string, key string, fields ...string) (body []interface{}, success bool, msg string) {
|
||||||
|
client := _connect()
|
||||||
|
logs.Info("ES Search index =", index, " key =", key, " fields =", fields)
|
||||||
|
var list []*elastic.WildcardQuery
|
||||||
|
for _, field := range fields {
|
||||||
|
list = append(list, elastic.NewWildcardQuery(field, key))
|
||||||
|
}
|
||||||
|
s := client.Search().Index(index)
|
||||||
|
for _, query := range list {
|
||||||
|
s = s.Query(query)
|
||||||
|
}
|
||||||
|
res, e := s.From(0).Size(20).Pretty(true).Do(context.Background())
|
||||||
|
if e != nil {
|
||||||
|
success = false
|
||||||
|
msg = e.Error()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
logs.Info(res.Status)
|
||||||
|
logs.Info(res.Hits.TotalHits)
|
||||||
|
var item document.User
|
||||||
|
for _, item := range res.Each(reflect.TypeOf(item)) {
|
||||||
|
if t, ok := item.(document.User); ok {
|
||||||
|
body = append(body, t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//if res.Hits.TotalHits.Value > 0 {
|
||||||
|
// for _, hit := range res.Hits.Hits {
|
||||||
|
// var t document.User
|
||||||
|
// _ := json.Unmarshal(hit.Source, &t)
|
||||||
|
// body = append(body, t)
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
type ESFilter struct {
|
||||||
|
Queries []ESQuery
|
||||||
|
BoolMustInShouldQueries [][]ESQuery
|
||||||
|
Sort ESSort
|
||||||
|
}
|
||||||
|
|
||||||
|
type ESQuery struct {
|
||||||
|
Key string
|
||||||
|
Value string
|
||||||
|
Type string
|
||||||
|
}
|
||||||
|
|
||||||
|
type ESSort struct {
|
||||||
|
Field string
|
||||||
|
Ascending bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// 搜索消息
|
||||||
|
func (*EsClient) SearchMulti(index string, filter ESFilter, page, size int) (result interface{}, success bool, msg string) {
|
||||||
|
client := _connect()
|
||||||
|
var list []elastic.Query
|
||||||
|
for _, item := range filter.Queries {
|
||||||
|
switch item.Type {
|
||||||
|
case "match":
|
||||||
|
list = append(list, elastic.NewMatchQuery(item.Key, item.Value))
|
||||||
|
case "multi_match":
|
||||||
|
list = append(list, elastic.NewMultiMatchQuery(item.Value).Type("best_fields").Lenient(true))
|
||||||
|
case "range_gte":
|
||||||
|
list = append(list, elastic.NewRangeQuery(item.Key).Gte(item.Value))
|
||||||
|
case "range_lte":
|
||||||
|
list = append(list, elastic.NewRangeQuery(item.Key).Lte(item.Value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(filter.BoolMustInShouldQueries) > 0 {
|
||||||
|
BQ := elastic.NewBoolQuery()
|
||||||
|
var bqList []elastic.Query
|
||||||
|
for _, bq := range filter.BoolMustInShouldQueries {
|
||||||
|
var listBq []elastic.Query
|
||||||
|
boolQuery := elastic.NewBoolQuery()
|
||||||
|
for _, item := range bq {
|
||||||
|
switch item.Type {
|
||||||
|
case "match":
|
||||||
|
listBq = append(listBq, elastic.NewMatchQuery(item.Key, item.Value))
|
||||||
|
case "multi_match":
|
||||||
|
listBq = append(listBq, elastic.NewMultiMatchQuery(item.Value).Type("best_fields").Lenient(true))
|
||||||
|
case "range_gte":
|
||||||
|
listBq = append(listBq, elastic.NewRangeQuery(item.Key).Gte(item.Value))
|
||||||
|
case "range_lte":
|
||||||
|
listBq = append(listBq, elastic.NewRangeQuery(item.Key).Lte(item.Value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
boolQuery.Must(listBq...)
|
||||||
|
bqList = append(bqList, boolQuery)
|
||||||
|
}
|
||||||
|
BQ.Should(bqList...)
|
||||||
|
list = append(list, BQ)
|
||||||
|
}
|
||||||
|
query := elastic.NewBoolQuery().Filter(list...)
|
||||||
|
//logs.Info(len(list))
|
||||||
|
//a1, _ := query.Source()
|
||||||
|
//a2, _ := json.MarshalIndent(a1, "", " ")
|
||||||
|
//logs.Info(string(a2))
|
||||||
|
s := client.Search().Index(index).Query(query)
|
||||||
|
if len(filter.Sort.Field) > 0 {
|
||||||
|
s = s.Sort(filter.Sort.Field, filter.Sort.Ascending)
|
||||||
|
}
|
||||||
|
res, e := s.From(page * size).Size(size).Pretty(false).Do(context.Background())
|
||||||
|
if e != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var body []interface{}
|
||||||
|
for _, item := range res.Hits.Hits {
|
||||||
|
b, _ := item.Source.MarshalJSON()
|
||||||
|
m := make(map[string]interface{})
|
||||||
|
_ = json.Unmarshal(b, &m)
|
||||||
|
body = append(body, m)
|
||||||
|
}
|
||||||
|
result = map[string]interface{}{
|
||||||
|
"Status": res.Status,
|
||||||
|
"Total": res.Hits.TotalHits,
|
||||||
|
"List": body,
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 搜索
|
||||||
|
func (*EsClient) QueryString(page, size int, index string, key string, fields ...string) (list []document.User, count int64, success bool, msg string) {
|
||||||
|
client := _connect()
|
||||||
|
logs.Info("ES QueryString index =", index, " key =", key, " fields =", fields)
|
||||||
|
query := elastic.NewQueryStringQuery(key)
|
||||||
|
for _, field := range fields {
|
||||||
|
query.Field(field)
|
||||||
|
}
|
||||||
|
query.AnalyzeWildcard(false)
|
||||||
|
s := client.Search().Index(index)
|
||||||
|
s = s.Query(query)
|
||||||
|
s = s.Sort("_score", false)
|
||||||
|
res, e := s.From(page * size).Size(size).Pretty(true).Do(context.Background())
|
||||||
|
if e != nil {
|
||||||
|
success = false
|
||||||
|
msg = e.Error()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
count = res.TotalHits()
|
||||||
|
var user document.User
|
||||||
|
for _, item := range res.Each(reflect.TypeOf(user)) {
|
||||||
|
if t, ok := item.(document.User); ok {
|
||||||
|
list = append(list, t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
success = true
|
||||||
|
return
|
||||||
|
}
|
||||||
81
pkg/common/es/es_client_test.go
Normal file
81
pkg/common/es/es_client_test.go
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
package ess
|
||||||
|
|
||||||
|
import (
|
||||||
|
"servicebase/pkg/common/messages"
|
||||||
|
"context"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/anxpp/beego/logs"
|
||||||
|
"github.com/olivere/elastic/v7"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestClient(t *testing.T) {
|
||||||
|
Init()
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestClientCreateUser(t *testing.T) {
|
||||||
|
//for _, item := range models.LogUserRegisterAll() {
|
||||||
|
// cli := EsClient{}
|
||||||
|
// _, success, msg := cli.Create("test_user_register", item.Id, item)
|
||||||
|
// if !success {
|
||||||
|
// logs.Error(msg)
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestClientSearch(t *testing.T) {
|
||||||
|
}
|
||||||
|
|
||||||
|
func _testConnect() (c *elastic.Client) {
|
||||||
|
c, e := elastic.NewSimpleClient(
|
||||||
|
elastic.SetHealthcheck(true),
|
||||||
|
elastic.SetHealthcheckInterval(10*time.Second),
|
||||||
|
// elastic.SetURL("http://47.97.157.234:9200"),
|
||||||
|
elastic.SetURL(viper.GetString("es.default.addr")),
|
||||||
|
// elastic.SetBasicAuth(beego.AppConfig.String("es_username"), beego.AppConfig.String("es_password")),
|
||||||
|
)
|
||||||
|
if e != nil {
|
||||||
|
logs.Error("NewClient_error: ", e.Error())
|
||||||
|
}
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestClientNew(t *testing.T) {
|
||||||
|
var client EsClient
|
||||||
|
client.Create("es_index_message", "003", map[string]interface{}{
|
||||||
|
"id": "003",
|
||||||
|
"curTime": 1440570500855,
|
||||||
|
"f1": 1234,
|
||||||
|
"f2": "22222",
|
||||||
|
"f3": "22222",
|
||||||
|
"f4": "22222",
|
||||||
|
"f5": "22222",
|
||||||
|
"f6": "2020-08-09 23:37:00",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSearchMessage(t *testing.T) {
|
||||||
|
index := messages.TagIndex(string(messages.EventTagMessage))
|
||||||
|
client := _testConnect()
|
||||||
|
var list []elastic.Query
|
||||||
|
list = append(list, elastic.NewWildcardQuery("eventType", "1"))
|
||||||
|
list = append(list, elastic.NewMatchQuery("msgType", "TEXT"))
|
||||||
|
s := client.Search().Index(index)
|
||||||
|
for _, query := range list {
|
||||||
|
s = s.Query(query)
|
||||||
|
}
|
||||||
|
res, e := s.From(0).Size(20).Pretty(true).Do(context.Background())
|
||||||
|
if e != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
logs.Info(res.Status)
|
||||||
|
logs.Info(res.Hits.TotalHits)
|
||||||
|
logs.Info(len(res.Hits.Hits))
|
||||||
|
for i, item := range res.Hits.Hits {
|
||||||
|
b, _ := item.Source.MarshalJSON()
|
||||||
|
logs.Info(i, string(b))
|
||||||
|
}
|
||||||
|
time.Sleep(time.Second * 3)
|
||||||
|
}
|
||||||
25
pkg/common/http/dto/ChatRoomDTO.go
Normal file
25
pkg/common/http/dto/ChatRoomDTO.go
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
package dto
|
||||||
|
|
||||||
|
type ChatRoomModelDTO struct {
|
||||||
|
Id string
|
||||||
|
OwnerUserId string
|
||||||
|
RoomNo string
|
||||||
|
RoomName string
|
||||||
|
MessageRoomId string
|
||||||
|
TabId string //分类ID
|
||||||
|
TemplateId string
|
||||||
|
CreateTime string
|
||||||
|
Status string
|
||||||
|
OpenTime string
|
||||||
|
RoomPwd string
|
||||||
|
MaxMemberCount string
|
||||||
|
IsHot string
|
||||||
|
RobotCount string
|
||||||
|
RoomTagIcon string
|
||||||
|
GuestCanUseEmoji string
|
||||||
|
SendMessageTimeGap string //发送消息间隔
|
||||||
|
UpSeatType string //1=排麦 2=自由麦
|
||||||
|
AudioQualityLevel string //音质等级 1=正常 2=高音质 3=超高音质
|
||||||
|
ViewSkewer string //是否显示福签 1=显示 0=不显示
|
||||||
|
IsViewHitegg string // 是否显示砸蛋
|
||||||
|
}
|
||||||
5
pkg/common/http/dto/RequestDTO.go
Normal file
5
pkg/common/http/dto/RequestDTO.go
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
package dto
|
||||||
|
|
||||||
|
type RequestDTO struct {
|
||||||
|
Token string
|
||||||
|
}
|
||||||
17
pkg/common/http/dto/UserDTO.go
Normal file
17
pkg/common/http/dto/UserDTO.go
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package dto
|
||||||
|
|
||||||
|
type UserDTO struct {
|
||||||
|
UserId string
|
||||||
|
UserNo string
|
||||||
|
NickName string
|
||||||
|
Avatar string
|
||||||
|
Gender string
|
||||||
|
BirthDay string
|
||||||
|
VipLevel string
|
||||||
|
VipExp string
|
||||||
|
IsAuth string
|
||||||
|
Status string
|
||||||
|
TrueName string
|
||||||
|
Mobile string
|
||||||
|
AvatarDecoration string //头饰
|
||||||
|
}
|
||||||
7
pkg/common/http/dto/UserInviteSummaryDTO.go
Normal file
7
pkg/common/http/dto/UserInviteSummaryDTO.go
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package dto
|
||||||
|
|
||||||
|
type UserInviteSummaryDTO struct {
|
||||||
|
UserId string
|
||||||
|
InviteDiamond string
|
||||||
|
InviteUserCount string
|
||||||
|
}
|
||||||
51
pkg/common/http/response/Activity.go
Normal file
51
pkg/common/http/response/Activity.go
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
package response
|
||||||
|
|
||||||
|
import "servicebase/pkg/common/http/dto"
|
||||||
|
|
||||||
|
type CommonResponse struct {
|
||||||
|
Code string
|
||||||
|
Result interface{}
|
||||||
|
Msg string
|
||||||
|
}
|
||||||
|
|
||||||
|
// 用户信息
|
||||||
|
type UserInfoResponse struct {
|
||||||
|
Code string
|
||||||
|
Result dto.UserDTO
|
||||||
|
Msg string
|
||||||
|
}
|
||||||
|
|
||||||
|
//获取用户邀请汇总数据返回
|
||||||
|
type UserInviteSummaryResponse struct {
|
||||||
|
Code string
|
||||||
|
Result dto.UserInviteSummaryDTO
|
||||||
|
Msg string
|
||||||
|
}
|
||||||
|
|
||||||
|
func Success(data interface{}) (res CommonResponse) {
|
||||||
|
res.Code = "6000"
|
||||||
|
res.Result = data
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func Page(data interface{}, count int64) (res CommonResponse) {
|
||||||
|
res.Code = "6000"
|
||||||
|
res.Result = map[string]interface{}{
|
||||||
|
"list": data,
|
||||||
|
"count": count,
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func Failed(msg string) (res CommonResponse) {
|
||||||
|
res.Code = "8020"
|
||||||
|
res.Msg = msg
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func Gen(code, msg string, result interface{}) (res CommonResponse) {
|
||||||
|
res.Code = code
|
||||||
|
res.Msg = msg
|
||||||
|
res.Result = result
|
||||||
|
return
|
||||||
|
}
|
||||||
12
pkg/common/messages/active_message.go
Normal file
12
pkg/common/messages/active_message.go
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
package messages
|
||||||
|
|
||||||
|
// 活跃消息
|
||||||
|
type Active struct {
|
||||||
|
MessageId string
|
||||||
|
UserId string //用户ID
|
||||||
|
DeviceId string //设备ID
|
||||||
|
ActiveTime string //活跃的平台
|
||||||
|
ActivePlatform string //活跃的平台
|
||||||
|
ActiveDeviceModel string //活跃的设备型号
|
||||||
|
ActiveIp string //活跃的IP
|
||||||
|
}
|
||||||
26
pkg/common/messages/error_message.go
Normal file
26
pkg/common/messages/error_message.go
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
package messages
|
||||||
|
|
||||||
|
// 错误消息(补偿)
|
||||||
|
type Error struct {
|
||||||
|
MessageId string
|
||||||
|
Code string // 错误代码
|
||||||
|
Content string // 错误内容(json)
|
||||||
|
Tag ErrorTag // 消息标签:auto=自动处理 manual=手动处理 auto_to_manual=自动转手动
|
||||||
|
}
|
||||||
|
|
||||||
|
type ErrorTag string
|
||||||
|
|
||||||
|
const (
|
||||||
|
Auto ErrorTag = "AUTO"
|
||||||
|
Manual ErrorTag = "MANUAL"
|
||||||
|
AutoToManual ErrorTag = "AUTO_TO_MANUAL"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ErrorState string
|
||||||
|
|
||||||
|
const (
|
||||||
|
ErrorCreate ErrorState = "CREATED"
|
||||||
|
ErrorSuccess ErrorState = "SUCCESS"
|
||||||
|
ErrorFailed ErrorState = "FAILED"
|
||||||
|
ErrorReSuccess ErrorState = "RE_SUCCESS"
|
||||||
|
)
|
||||||
49
pkg/common/messages/event_message.go
Normal file
49
pkg/common/messages/event_message.go
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
package messages
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 事件
|
||||||
|
type Event struct {
|
||||||
|
MessageId string
|
||||||
|
Tag EventTag // 消息标签:EventTagUser=用户
|
||||||
|
Flag EventFlag // 消息标签:EventFlagCreate=创建 EventFlagUpdate=更新
|
||||||
|
EventId string // 事件ID
|
||||||
|
EventContent interface{} // 事件内容
|
||||||
|
}
|
||||||
|
|
||||||
|
type EventTag string
|
||||||
|
|
||||||
|
const (
|
||||||
|
EventTagUser EventTag = "user"
|
||||||
|
EventTagRoomInto EventTag = "into_room"
|
||||||
|
EventTagMessage EventTag = "message"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TagIndex(key string) string {
|
||||||
|
switch key {
|
||||||
|
case string(EventTagUser):
|
||||||
|
return viper.GetString("es.default.indexUser")
|
||||||
|
case string(EventTagMessage):
|
||||||
|
return viper.GetString("es.default.indexMessage")
|
||||||
|
default:
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type EventFlag string
|
||||||
|
|
||||||
|
const (
|
||||||
|
EventFlagSave EventFlag = "save"
|
||||||
|
EventFlagCreate EventFlag = "create"
|
||||||
|
EventFlagUpdate EventFlag = "update"
|
||||||
|
EventFlagDelete EventFlag = "delete"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (message *Event) ToJson() string {
|
||||||
|
b, _ := json.Marshal(message)
|
||||||
|
return string(b)
|
||||||
|
}
|
||||||
12
pkg/common/messages/register_message.go
Normal file
12
pkg/common/messages/register_message.go
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
package messages
|
||||||
|
|
||||||
|
// 注册消息
|
||||||
|
type Register struct {
|
||||||
|
MessageId string
|
||||||
|
UserId string //用户ID
|
||||||
|
DeviceId string //设备ID
|
||||||
|
RegisterTime string //注册时间
|
||||||
|
ChannelCode string //渠道代码
|
||||||
|
Ip string //ip
|
||||||
|
Platform string //平台
|
||||||
|
}
|
||||||
98
pkg/common/messages/transaction_message.go
Normal file
98
pkg/common/messages/transaction_message.go
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
package messages
|
||||||
|
|
||||||
|
// 交易消息
|
||||||
|
type Transaction struct {
|
||||||
|
MessageId string
|
||||||
|
FromUserId string //发起用户ID
|
||||||
|
FromCurrency TransactionCurrencyEnum //扣款类型
|
||||||
|
FromAmount string //扣款数量
|
||||||
|
FromPlatform string //扣款所在平台
|
||||||
|
ToUserId string //接收用户
|
||||||
|
ToCurrency TransactionCurrencyEnum //接收类型
|
||||||
|
ToAmount string //接收数量
|
||||||
|
TransactionRate string //交易抽成
|
||||||
|
TransactionState TransactionStateEnum //交易状态
|
||||||
|
TransactionType TransactionTypeEnum //充值、打赏、购买表情、购买守护、兑换、砸蛋、提现、订单等
|
||||||
|
TransactionId string //充值ID、打赏ID、购买表情ID、购买守护ID、兑换ID、砸蛋ID、提现ID、订单ID等
|
||||||
|
TransactionCreateTime string //交易创建时间
|
||||||
|
TransactionCompleteTime string //交易完成时间
|
||||||
|
TransactionSubjectId string //充值为产品ID、打赏为房间ID、购买表情为表情ID、购买守护为房间ID、兑换为配置ID、砸蛋为配置ID、提现为配置ID、订单为品类ID
|
||||||
|
TransactionCode TransactionCodeEnum //充值为充值渠道(支付宝H5、支付宝App、微信、运营赠送等)、打赏为打赏类型(单个、批量)、购买表情为空、购买守护为守护类型、兑换为空、砸蛋为中奖等级、提现为银行名称、订单为空
|
||||||
|
TransactionAmount string //交易金额(单位为扣款类型)
|
||||||
|
TransactionAmountCoupon string //交易优惠金额(单位为扣款类型)
|
||||||
|
TransactionAmountCouponId string //交易优惠凭证ID
|
||||||
|
TransactionAmountPay string //交易实际支付金额(单位为扣款类型)
|
||||||
|
GuildId string //俱乐部ID
|
||||||
|
}
|
||||||
|
|
||||||
|
// 交易更新消息
|
||||||
|
type TransactionUpdate struct {
|
||||||
|
MessageId string
|
||||||
|
TransactionState TransactionStateEnum //交易状态
|
||||||
|
TransactionId string //充值ID、打赏ID、购买表情ID、购买守护ID、兑换ID、砸蛋ID、提现ID、订单ID等
|
||||||
|
TransactionCompleteTime string //交易完成时间
|
||||||
|
}
|
||||||
|
|
||||||
|
type TransactionCodeEnum string
|
||||||
|
|
||||||
|
const (
|
||||||
|
RewardSimple TransactionCodeEnum = "SIMPLE" //单个打赏
|
||||||
|
RewardMulti TransactionCodeEnum = "MULTI" //批量打赏
|
||||||
|
RewardBagSimple TransactionCodeEnum = "BAG_SIMPLE" //背包礼物单个打赏
|
||||||
|
RewardBagMulti TransactionCodeEnum = "BAG_MULTI" //背包礼物批量打赏
|
||||||
|
|
||||||
|
GuardLevel01 TransactionCodeEnum = "1" //青铜守护
|
||||||
|
GuardLevel02 TransactionCodeEnum = "2" //白银守护
|
||||||
|
GuardLevel03 TransactionCodeEnum = "3" //黄金守护
|
||||||
|
|
||||||
|
Hunting1 TransactionCodeEnum = "1" //单砸
|
||||||
|
Hunting10 TransactionCodeEnum = "10" //十砸
|
||||||
|
Hunting100 TransactionCodeEnum = "100" //百砸
|
||||||
|
|
||||||
|
RechargeAppAlipay TransactionCodeEnum = "AppAlipay" //app支付宝
|
||||||
|
RechargeAppWeChat TransactionCodeEnum = "AppWeChat" //app微信
|
||||||
|
RechargeAppIap TransactionCodeEnum = "AppIap" //appIap
|
||||||
|
RechargeH5Alipay TransactionCodeEnum = "H5Alipay" //H5支付宝
|
||||||
|
RechargeH5WeChatClub TransactionCodeEnum = "H5WeChatClub" //H5微信公众号
|
||||||
|
RechargeOperation TransactionCodeEnum = "Operation" //Operation
|
||||||
|
)
|
||||||
|
|
||||||
|
type TransactionStateEnum string
|
||||||
|
|
||||||
|
const (
|
||||||
|
CREATED TransactionStateEnum = "CREATED" //已创建
|
||||||
|
SUCCESS TransactionStateEnum = "SUCCESS" //成功
|
||||||
|
FAILED TransactionStateEnum = "FAILED" //失败
|
||||||
|
)
|
||||||
|
|
||||||
|
type TransactionCurrencyEnum string
|
||||||
|
|
||||||
|
const (
|
||||||
|
DIAMOND TransactionCurrencyEnum = "DIAMOND" //钻石
|
||||||
|
CRYSTAL TransactionCurrencyEnum = "CRYSTAL" //晶石
|
||||||
|
MONEY TransactionCurrencyEnum = "MONEY" //钱
|
||||||
|
FRAGMENT TransactionCurrencyEnum = "FRAGMENT" //碎片
|
||||||
|
)
|
||||||
|
|
||||||
|
type TransactionTypeEnum string
|
||||||
|
|
||||||
|
const (
|
||||||
|
RECHARGE TransactionTypeEnum = "RECHARGE" //充值
|
||||||
|
RechargeNCoin TransactionTypeEnum = "RECHARGE_N_COIN" //充值N币
|
||||||
|
REWARD TransactionTypeEnum = "REWARD" //打赏
|
||||||
|
REWARDNCoin TransactionTypeEnum = "REWARD_N_COIN" //打赏
|
||||||
|
GUARD TransactionTypeEnum = "GUARD" //购买守护
|
||||||
|
EMOJI TransactionTypeEnum = "EMOJI" //购买表情
|
||||||
|
OperationDiamond TransactionTypeEnum = "OPERATION_DIAMOND" //手工加钻石
|
||||||
|
OperationCrystal TransactionTypeEnum = "OPERATION_CRYSTAL" //手工加晶石
|
||||||
|
OperationCrystalReduce TransactionTypeEnum = "OPERATION_CRYSTAL_REDUCE" //手工扣除晶石
|
||||||
|
EXCHANGE TransactionTypeEnum = "EXCHANGE" //兑换
|
||||||
|
HUNTING TransactionTypeEnum = "HUNTING" //星空寻宝
|
||||||
|
WithdrawNCoin TransactionTypeEnum = "WITHDRAW_N_COIN" //提现 N币
|
||||||
|
ORDER TransactionTypeEnum = "ORDER" //订单
|
||||||
|
ORDERNCoin TransactionTypeEnum = "ORDER_N_COIN" //订单
|
||||||
|
ORDER_H5 TransactionTypeEnum = "ORDER_H5" //订单
|
||||||
|
ORDER_H5_NCoin TransactionTypeEnum = "ORDER_H5_N_COIN" //订单
|
||||||
|
LUCK_GIFT TransactionTypeEnum = "LUCK_GIFT" //幸运礼物
|
||||||
|
LuckGiftNCoin TransactionTypeEnum = "LUCK_GIFT_N_COIN" //幸运礼物
|
||||||
|
)
|
||||||
767
pkg/common/netease/ImClient.go
Normal file
767
pkg/common/netease/ImClient.go
Normal file
@ -0,0 +1,767 @@
|
|||||||
|
package Netease
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"servicebase/pkg/common"
|
||||||
|
"servicebase/pkg/common/HyTools"
|
||||||
|
yunxin "servicebase/pkg/common/netease/dto"
|
||||||
|
"servicebase/pkg/htools"
|
||||||
|
"servicebase/pkg/log"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"github.com/spf13/cast"
|
||||||
|
|
||||||
|
"math/rand"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/anxpp/beego/logs"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ImClient struct {
|
||||||
|
AppKey string
|
||||||
|
AppSecret string
|
||||||
|
}
|
||||||
|
|
||||||
|
type CreateImRes struct {
|
||||||
|
Code int
|
||||||
|
Desc string
|
||||||
|
}
|
||||||
|
|
||||||
|
type BroadcastNotificationReq struct {
|
||||||
|
FromAccountId string `json:"from_account_id"`
|
||||||
|
Content string `json:"content"`
|
||||||
|
TargetOs []string `json:"target_os"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewImClient() *ImClient {
|
||||||
|
fmt.Printf("NewImClient: %s\n", viper.GetString("netease.im.key"))
|
||||||
|
key := viper.GetString("netease.im.key")
|
||||||
|
secret := viper.GetString("netease.im.secret")
|
||||||
|
return &ImClient{AppKey: key, AppSecret: secret}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成云信header
|
||||||
|
func (client *ImClient) generateHeader() map[string]string {
|
||||||
|
nonce := randNumber()
|
||||||
|
t := time.Now()
|
||||||
|
currentTime := strconv.FormatInt(t.UTC().Unix(), 10)
|
||||||
|
result := make(map[string]string)
|
||||||
|
result["AppKey"] = client.AppKey
|
||||||
|
result["Nonce"] = nonce
|
||||||
|
result["CurTime"] = currentTime
|
||||||
|
result["CheckSum"] = client.generateCheckSum(nonce, currentTime)
|
||||||
|
result["Content-Type"] = "application/x-www-form-urlencoded;charset=utf-8"
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *ImClient) generateJsonHeader() map[string]string {
|
||||||
|
nonce := randNumber()
|
||||||
|
t := time.Now()
|
||||||
|
currentTime := strconv.FormatInt(t.UTC().Unix(), 10)
|
||||||
|
result := make(map[string]string)
|
||||||
|
result["AppKey"] = client.AppKey
|
||||||
|
result["Nonce"] = nonce
|
||||||
|
result["CurTime"] = currentTime
|
||||||
|
result["CheckSum"] = client.generateCheckSum(nonce, currentTime)
|
||||||
|
result["Content-Type"] = "application/json"
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成云信签名
|
||||||
|
func (client *ImClient) generateCheckSum(nonce, currentTime string) string {
|
||||||
|
waitSignStr := client.AppSecret + nonce + currentTime
|
||||||
|
result := HyTools.StringToSHA1(waitSignStr)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建云信账户
|
||||||
|
// imService.CreateImUser(common.SYNC_DATA_USER_ID,"数据同步",common.PHOTO_DOMAIN_URL+"assets/sys/guanfanggonggao.png")
|
||||||
|
func (client *ImClient) CreateImUser(userId, nickName, avatar string) error {
|
||||||
|
url := "https://api.netease.im/nimserver/user/create.action"
|
||||||
|
httpMethod := common.HTTP_METHOD_POST
|
||||||
|
header := client.generateHeader()
|
||||||
|
sb := HyTools.NewStringBuilder()
|
||||||
|
sb.Append("accid=" + userId)
|
||||||
|
sb.Append("&")
|
||||||
|
sb.Append("token=123456")
|
||||||
|
sb.Append("&")
|
||||||
|
sb.Append("name=" + nickName)
|
||||||
|
sb.Append("&")
|
||||||
|
sb.Append("icon=" + avatar)
|
||||||
|
res, err := HyTools.HttpDo(httpMethod, url, header, sb.ToString())
|
||||||
|
if err != nil {
|
||||||
|
// {"desc":"already register","code":414}
|
||||||
|
logs.Info("YunXin_SignUp_Fail_AccID_%s:"+err.Error(), userId)
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
// {"code":200,"info":{"token":"123456","accid":"b8af4bebe2064435974ba2340d852055","name":"b8af4bebe2064435974ba2340d852055"}}
|
||||||
|
var resDTO CreateImRes
|
||||||
|
json.Unmarshal([]byte(res), &resDTO)
|
||||||
|
if resDTO.Code != 200 {
|
||||||
|
logs.Info("YunXin_SignUp_Fail_AccID_%s:"+resDTO.Desc, userId)
|
||||||
|
} else {
|
||||||
|
logs.Info("YunXin_SignUp_Success_AccID_%s:"+res, userId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var body map[string]interface{}
|
||||||
|
if errJson := json.Unmarshal([]byte(res), &body); errJson != nil {
|
||||||
|
return errJson
|
||||||
|
}
|
||||||
|
if int(body["code"].(float64)) != 200 {
|
||||||
|
return errors.New(body["desc"].(string))
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询用户信息
|
||||||
|
func (client *ImClient) GetImUserInfo(userId string) error {
|
||||||
|
url := "https://api.netease.im/nimserver/user/getUinfos.action"
|
||||||
|
httpMethod := common.HTTP_METHOD_POST
|
||||||
|
header := client.generateHeader()
|
||||||
|
sb := HyTools.NewStringBuilder()
|
||||||
|
accids := []string{userId}
|
||||||
|
byteData, _ := json.Marshal(accids)
|
||||||
|
sb.Append("accids=" + string(byteData))
|
||||||
|
res, err := HyTools.HttpDo(httpMethod, url, header, sb.ToString())
|
||||||
|
// #查询云信用户信息结果:{"desc":"b8af4bebe2064435974ba2340d852055not register","code":414}#
|
||||||
|
// {"code":200,"uinfos":[{"icon":"https://xzphoto.meetalk.tech/upload/6bba4098-6ea8-4758-8193-19abed540c0b.0","accid":"2251bae8a0514e6892f0374f5dd260d4","name":"弦乐","gender":0}]}
|
||||||
|
logs.Info("#" + "查询云信用户信息结果:" + res + "#")
|
||||||
|
var body map[string]interface{}
|
||||||
|
if errJson := json.Unmarshal([]byte(res), &body); errJson != nil {
|
||||||
|
return errJson
|
||||||
|
}
|
||||||
|
if int(body["code"].(float64)) != 200 {
|
||||||
|
return errors.New(body["desc"].(string))
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新云信信息
|
||||||
|
func (client *ImClient) UpdateImUserInfo(accid, nickName, avatar string) error {
|
||||||
|
url := "https://api.netease.im/nimserver/user/updateUinfo.action"
|
||||||
|
httpMethod := common.HTTP_METHOD_POST
|
||||||
|
header := client.generateHeader()
|
||||||
|
sb := htools.NewStringBuilder()
|
||||||
|
sb.Append("accid=" + accid)
|
||||||
|
sb.Append("&")
|
||||||
|
sb.Append("name=" + nickName)
|
||||||
|
sb.Append("&")
|
||||||
|
sb.Append("icon=" + avatar)
|
||||||
|
res, err := htools.HttpDo(httpMethod, url, header, sb.ToString())
|
||||||
|
logs.Info(common.LOG_QUOTE_STRING + "云信更新用户信息结果:" + res + common.LOG_QUOTE_STRING)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新云信用户扩展信息
|
||||||
|
func (client *ImClient) UpdateImUserExt(accid, ext string) error {
|
||||||
|
url := "https://api.netease.im/nimserver/user/updateUinfo.action"
|
||||||
|
httpMethod := common.HTTP_METHOD_POST
|
||||||
|
header := client.generateHeader()
|
||||||
|
sb := htools.NewStringBuilder()
|
||||||
|
sb.Append("accid=" + accid)
|
||||||
|
sb.Append("&")
|
||||||
|
sb.Append("ex=" + ext)
|
||||||
|
logs.Info("update_im_user userID[%s] ext:%s", accid, ext)
|
||||||
|
res, err := htools.HttpDo(httpMethod, url, header, sb.ToString())
|
||||||
|
logs.Info(common.LOG_QUOTE_STRING+"云信更新用户ext%s信息结果:"+res+common.LOG_QUOTE_STRING, ext)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 封禁云信帐号
|
||||||
|
func (client *ImClient) BlockImUser(accid string) error {
|
||||||
|
|
||||||
|
url := "https://api.netease.im/nimserver/user/block.action"
|
||||||
|
httpMethod := common.HTTP_METHOD_POST
|
||||||
|
header := client.generateHeader()
|
||||||
|
|
||||||
|
sb := htools.NewStringBuilder()
|
||||||
|
sb.Append("accid=" + accid)
|
||||||
|
sb.Append("&")
|
||||||
|
sb.Append("needkick=true")
|
||||||
|
|
||||||
|
res, err := htools.HttpDo(httpMethod, url, header, sb.ToString())
|
||||||
|
logs.Info(common.LOG_QUOTE_STRING + "封禁云信帐号结果:" + res + common.LOG_QUOTE_STRING)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解禁云信帐号
|
||||||
|
func (client *ImClient) UnBlockImUser(accid string) error {
|
||||||
|
|
||||||
|
url := "https://api.netease.im/nimserver/user/unblock.action"
|
||||||
|
httpMethod := common.HTTP_METHOD_POST
|
||||||
|
header := client.generateHeader()
|
||||||
|
|
||||||
|
sb := htools.NewStringBuilder()
|
||||||
|
sb.Append("accid=" + accid)
|
||||||
|
|
||||||
|
res, err := htools.HttpDo(httpMethod, url, header, sb.ToString())
|
||||||
|
logs.Info(common.LOG_QUOTE_STRING + "解禁云信帐号结果:" + res + common.LOG_QUOTE_STRING)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建云信聊天室
|
||||||
|
func (client *ImClient) CreateChatroom(ownerUserId string, roomName string) (chatroomModel NeteaseChatroomDTO) {
|
||||||
|
logs.Info("CreateChatroom ownerUserId=%s roomName=%s", ownerUserId, roomName)
|
||||||
|
url := "https://api.netease.im/nimserver/chatroom/create.action"
|
||||||
|
httpMethod := common.HTTP_METHOD_POST
|
||||||
|
header := client.generateHeader()
|
||||||
|
sb := htools.NewStringBuilder()
|
||||||
|
sb.Append("creator=" + ownerUserId)
|
||||||
|
sb.Append("&")
|
||||||
|
sb.Append("name=" + roomName)
|
||||||
|
res, err := htools.HttpDo(httpMethod, url, header, sb.ToString())
|
||||||
|
if err != nil {
|
||||||
|
logs.Info(common.LOG_QUOTE_STRING + "云信创建聊天室请求失败:" + err.Error() + common.LOG_QUOTE_STRING)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// {"valid":true,"ext":"","creator":"1b94b5e7af8a45ed9fda27d28165d4c9","name":"32452345","muted":false,"roomid":11142139973,"queuelevel":0}
|
||||||
|
logs.Info(common.LOG_QUOTE_STRING + "云信创建聊天室结果:" + res + common.LOG_QUOTE_STRING)
|
||||||
|
var createRes CreateChatroomResponse
|
||||||
|
err1 := json.Unmarshal([]byte(res), &createRes)
|
||||||
|
if err1 != nil {
|
||||||
|
logs.Info(common.LOG_QUOTE_STRING + "创建聊天室失败,解析结果错误:" + res + common.LOG_QUOTE_STRING)
|
||||||
|
panic(err1)
|
||||||
|
}
|
||||||
|
if createRes.Code != 200 {
|
||||||
|
|
||||||
|
logs.Info(common.LOG_QUOTE_STRING + "创建Im聊天室失败:code= " + strconv.Itoa(createRes.Code) + common.LOG_QUOTE_STRING)
|
||||||
|
panic(errors.New("创建云信Im聊天室失败"))
|
||||||
|
}
|
||||||
|
chatroomModel = createRes.Chatroom
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// IM发送消息
|
||||||
|
func (client *ImClient) SendMsg(parameters map[string]string) error {
|
||||||
|
url := "https://api.netease.im/nimserver/msg/sendMsg.action"
|
||||||
|
httpMethod := common.HTTP_METHOD_POST
|
||||||
|
header := client.generateHeader()
|
||||||
|
sb := htools.NewStringBuilder()
|
||||||
|
parametersCount := len(parameters)
|
||||||
|
i := 0
|
||||||
|
for k, v := range parameters {
|
||||||
|
sb.Append(k + "=" + v)
|
||||||
|
if i < parametersCount-1 {
|
||||||
|
sb.Append("&")
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
logs.Info(common.LOG_QUOTE_STRING + "云信IM发消息请求:" + sb.ToString() + common.LOG_QUOTE_STRING)
|
||||||
|
res, err := htools.HttpDo(httpMethod, url, header, sb.ToString())
|
||||||
|
logs.Info(common.LOG_QUOTE_STRING + "云信IM发消息结果:" + res + common.LOG_QUOTE_STRING)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加机器人
|
||||||
|
func (client *ImClient) AddRobot(parameters map[string]string) error {
|
||||||
|
url := "https://api.netease.im/nimserver/chatroom/addRobot.action"
|
||||||
|
httpMethod := common.HTTP_METHOD_POST
|
||||||
|
header := client.generateHeader()
|
||||||
|
sb := htools.NewStringBuilder()
|
||||||
|
parametersCount := len(parameters)
|
||||||
|
i := 0
|
||||||
|
for k, v := range parameters {
|
||||||
|
sb.Append(k + "=" + v)
|
||||||
|
if i < parametersCount-1 {
|
||||||
|
sb.Append("&")
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
logs.Info(common.LOG_QUOTE_STRING + "添加机器人:" + sb.ToString() + common.LOG_QUOTE_STRING)
|
||||||
|
res, err := htools.HttpDo(httpMethod, url, header, sb.ToString())
|
||||||
|
logs.Info(common.LOG_QUOTE_STRING + "添加机器人:" + res + common.LOG_QUOTE_STRING)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 移除机器人
|
||||||
|
func (client *ImClient) RemoveRobot(parameters map[string]string) error {
|
||||||
|
|
||||||
|
url := "https://api.netease.im/nimserver/chatroom/removeRobot.action"
|
||||||
|
httpMethod := common.HTTP_METHOD_POST
|
||||||
|
header := client.generateHeader()
|
||||||
|
sb := htools.NewStringBuilder()
|
||||||
|
parametersCount := len(parameters)
|
||||||
|
i := 0
|
||||||
|
for k, v := range parameters {
|
||||||
|
sb.Append(k + "=" + v)
|
||||||
|
if i < parametersCount-1 {
|
||||||
|
sb.Append("&")
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
logs.Info(common.LOG_QUOTE_STRING + "移除机器人:" + sb.ToString() + common.LOG_QUOTE_STRING)
|
||||||
|
res, err := htools.HttpDo(httpMethod, url, header, sb.ToString())
|
||||||
|
logs.Info(common.LOG_QUOTE_STRING + "移除机器人:" + res + common.LOG_QUOTE_STRING)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发送聊天室消息
|
||||||
|
func (client *ImClient) SendChatroomMsg(parameters map[string]string) error {
|
||||||
|
|
||||||
|
url := "https://api.netease.im/nimserver/chatroom/sendMsg.action"
|
||||||
|
|
||||||
|
httpMethod := common.HTTP_METHOD_POST
|
||||||
|
header := client.generateHeader()
|
||||||
|
|
||||||
|
sb := htools.NewStringBuilder()
|
||||||
|
parametersCount := len(parameters)
|
||||||
|
i := 0
|
||||||
|
for k, v := range parameters {
|
||||||
|
sb.Append(k + "=" + v)
|
||||||
|
if i < parametersCount-1 {
|
||||||
|
sb.Append("&")
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
|
||||||
|
logs.Info(common.LOG_QUOTE_STRING + "聊天室发消息请求:" + sb.ToString() + common.LOG_QUOTE_STRING)
|
||||||
|
res, err := htools.HttpDo(httpMethod, url, header, sb.ToString())
|
||||||
|
logs.Info(common.LOG_QUOTE_STRING + "聊天室发消息结果:" + res + common.LOG_QUOTE_STRING)
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取在线成员信息
|
||||||
|
func (client *ImClient) GetChatroomMembers(parameters map[string]string) (imResponse ImResponse, err error) {
|
||||||
|
|
||||||
|
url := "https://api.netease.im/nimserver/chatroom/queryMembers.action"
|
||||||
|
|
||||||
|
httpMethod := common.HTTP_METHOD_POST
|
||||||
|
|
||||||
|
header := client.generateHeader()
|
||||||
|
|
||||||
|
body := generateBodyData(parameters)
|
||||||
|
|
||||||
|
logs.Info(common.LOG_QUOTE_STRING + "获取在线成员请求:" + body + common.LOG_QUOTE_STRING)
|
||||||
|
|
||||||
|
res, err1 := htools.HttpDo(httpMethod, url, header, body)
|
||||||
|
|
||||||
|
if err1 != nil {
|
||||||
|
logs.Error(common.LOG_QUOTE_STRING + "获取在线成员失败:" + err1.Error() + common.LOG_QUOTE_STRING)
|
||||||
|
err = err1
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
logs.Info(common.LOG_QUOTE_STRING + "获取在线成员结果:" + res + common.LOG_QUOTE_STRING)
|
||||||
|
var response ImResponse
|
||||||
|
if err2 := json.Unmarshal([]byte(res), &response); err2 != nil {
|
||||||
|
|
||||||
|
logs.Error(common.LOG_QUOTE_STRING + "获取在线成员解析失败:" + err2.Error() + common.LOG_QUOTE_STRING)
|
||||||
|
err = err2
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
imResponse = response
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 分页获取聊天室在线用户列表
|
||||||
|
func (client *ImClient) GetChatroomOnlineUserListByPage(parameters map[string]string) (imResponse ImResponse, err error) {
|
||||||
|
|
||||||
|
url := "https://api.netease.im/nimserver/chatroom/membersByPage.action"
|
||||||
|
|
||||||
|
httpMethod := common.HTTP_METHOD_POST
|
||||||
|
|
||||||
|
header := client.generateHeader()
|
||||||
|
|
||||||
|
body := generateBodyData(parameters)
|
||||||
|
|
||||||
|
logs.Info(common.LOG_QUOTE_STRING + "分页获取聊天室在线列表:" + body + common.LOG_QUOTE_STRING)
|
||||||
|
|
||||||
|
res, err1 := htools.HttpDo(httpMethod, url, header, body)
|
||||||
|
|
||||||
|
if err1 != nil {
|
||||||
|
logs.Error(common.LOG_QUOTE_STRING + "分页获取聊天室在线列表失败:" + err1.Error() + common.LOG_QUOTE_STRING)
|
||||||
|
err = err1
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
logs.Info(common.LOG_QUOTE_STRING + "分页获取聊天室在线列表结果:" + res + common.LOG_QUOTE_STRING)
|
||||||
|
var response ImResponse
|
||||||
|
if err2 := json.Unmarshal([]byte(res), &response); err2 != nil {
|
||||||
|
|
||||||
|
logs.Error(common.LOG_QUOTE_STRING + "分页获取聊天室在线列表失败:" + err2.Error() + common.LOG_QUOTE_STRING)
|
||||||
|
err = err2
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
imResponse = response
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新聊天室房间信息
|
||||||
|
func (client *ImClient) UpdateRoomInfo(request yunxin.UpdateRoomInfoRequest) (err error) {
|
||||||
|
|
||||||
|
url := "https://api.netease.im/nimserver/chatroom/update.action"
|
||||||
|
|
||||||
|
httpMethod := common.HTTP_METHOD_POST
|
||||||
|
header := client.generateHeader()
|
||||||
|
|
||||||
|
sb := htools.NewStringBuilder()
|
||||||
|
sb.Append("roomid=" + request.Roomid)
|
||||||
|
sb.Append("&")
|
||||||
|
sb.Append("name=")
|
||||||
|
sb.Append("&")
|
||||||
|
sb.Append("announcement=")
|
||||||
|
sb.Append("&")
|
||||||
|
sb.Append("ext=")
|
||||||
|
sb.Append("&")
|
||||||
|
sb.Append("notifyExt=" + request.NotifyExt)
|
||||||
|
|
||||||
|
logs.Info(common.LOG_QUOTE_STRING + "更新聊天室信息请求:" + sb.ToString() + common.LOG_QUOTE_STRING)
|
||||||
|
res, httpErr := htools.HttpDo(httpMethod, url, header, sb.ToString())
|
||||||
|
logs.Info(common.LOG_QUOTE_STRING + "更新聊天室信息结果:" + res + common.LOG_QUOTE_STRING)
|
||||||
|
|
||||||
|
if httpErr != nil {
|
||||||
|
logs.Info(common.LOG_QUOTE_STRING + "更新聊天室信息失败:" + httpErr.Error() + common.LOG_QUOTE_STRING)
|
||||||
|
err = httpErr
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
resMap := make(map[string]interface{})
|
||||||
|
jsonErr := json.Unmarshal([]byte(res), &resMap)
|
||||||
|
|
||||||
|
if jsonErr != nil {
|
||||||
|
logs.Info(common.LOG_QUOTE_STRING + "解析更新房间信息结果失败:" + jsonErr.Error() + common.LOG_QUOTE_STRING)
|
||||||
|
err = jsonErr
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
code := resMap["code"].(float64)
|
||||||
|
codeStr := htools.Float64ToString(code)
|
||||||
|
if codeStr != "200" {
|
||||||
|
logs.Info(common.LOG_QUOTE_STRING + "更新房间信息结果失败: code=" + codeStr + common.LOG_QUOTE_STRING)
|
||||||
|
err = errors.New("更新失败 code=" + codeStr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 聊天室临时禁言
|
||||||
|
func (client *ImClient) ChatroomMuteUser(parameters map[string]string) error {
|
||||||
|
|
||||||
|
url := "https://api.netease.im/nimserver/chatroom/temporaryMute.action"
|
||||||
|
|
||||||
|
httpMethod := common.HTTP_METHOD_POST
|
||||||
|
header := client.generateHeader()
|
||||||
|
|
||||||
|
sb := htools.NewStringBuilder()
|
||||||
|
parametersCount := len(parameters)
|
||||||
|
i := 0
|
||||||
|
for k, v := range parameters {
|
||||||
|
sb.Append(k + "=" + v)
|
||||||
|
if i < parametersCount-1 {
|
||||||
|
sb.Append("&")
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
|
||||||
|
logs.Info(common.LOG_QUOTE_STRING + "聊天室临时禁言请求:" + sb.ToString() + common.LOG_QUOTE_STRING)
|
||||||
|
res, err := htools.HttpDo(httpMethod, url, header, sb.ToString())
|
||||||
|
logs.Info(common.LOG_QUOTE_STRING + "聊天室临时禁言结果:" + res + common.LOG_QUOTE_STRING)
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 切换聊天室状态
|
||||||
|
func (client *ImClient) ChangeChatroomStat(parameters map[string]string) error {
|
||||||
|
|
||||||
|
url := "https://api.netease.im/nimserver/chatroom/toggleCloseStat.action"
|
||||||
|
|
||||||
|
httpMethod := common.HTTP_METHOD_POST
|
||||||
|
header := client.generateHeader()
|
||||||
|
|
||||||
|
sb := htools.NewStringBuilder()
|
||||||
|
parametersCount := len(parameters)
|
||||||
|
i := 0
|
||||||
|
for k, v := range parameters {
|
||||||
|
sb.Append(k + "=" + v)
|
||||||
|
if i < parametersCount-1 {
|
||||||
|
sb.Append("&")
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
|
||||||
|
requestId := HyTools.GetUUID()
|
||||||
|
logs.Info(common.LOG_QUOTE_STRING + "聊天室切换聊天室开关状态请求:requestId " + requestId + " body " + sb.ToString() + common.LOG_QUOTE_STRING)
|
||||||
|
res, err := htools.HttpDo(httpMethod, url, header, sb.ToString())
|
||||||
|
if len(res) == 0 {
|
||||||
|
logs.Info(common.LOG_QUOTE_STRING + "聊天室切换聊天室开关状态结果:失败 res为空 requestId " + requestId + common.LOG_QUOTE_STRING)
|
||||||
|
return errors.New("操作失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logs.Info(common.LOG_QUOTE_STRING + "聊天室切换聊天室开关状态结果:失败 返回error requestId " + requestId + "error " + err.Error() + common.LOG_QUOTE_STRING)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
//{"desc":"parameter roomid should be long","code":414}
|
||||||
|
var resData struct {
|
||||||
|
Code int `json:"code"`
|
||||||
|
Desc string `json:"desc"`
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = json.Unmarshal([]byte(res), &resData)
|
||||||
|
|
||||||
|
if resData.Code != 200 {
|
||||||
|
if resData.Code != 417 { // 重复操作 直接忽略
|
||||||
|
logs.Info(fmt.Sprintf(common.LOG_QUOTE_STRING+"聊天室切换聊天室开关状态结果:失败 code[%d] requestId "+requestId+" desc[%s] "+common.LOG_QUOTE_STRING, resData.Code, resData.Desc))
|
||||||
|
return errors.New("操作失败")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
logs.Info(common.LOG_QUOTE_STRING + "聊天室切换聊天室开关状态结果: requestId " + requestId + " response " + res + common.LOG_QUOTE_STRING)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置聊天室成员角色
|
||||||
|
func (client *ImClient) SetChatroomMemberRole(parameters map[string]string) error {
|
||||||
|
|
||||||
|
url := "https://api.netease.im/nimserver/chatroom/setMemberRole.action"
|
||||||
|
|
||||||
|
httpMethod := common.HTTP_METHOD_POST
|
||||||
|
header := client.generateHeader()
|
||||||
|
|
||||||
|
sb := htools.NewStringBuilder()
|
||||||
|
parametersCount := len(parameters)
|
||||||
|
i := 0
|
||||||
|
for k, v := range parameters {
|
||||||
|
sb.Append(k + "=" + v)
|
||||||
|
if i < parametersCount-1 {
|
||||||
|
sb.Append("&")
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
|
||||||
|
logs.Info(common.LOG_QUOTE_STRING + "设置聊天室成员角色请求:" + sb.ToString() + common.LOG_QUOTE_STRING)
|
||||||
|
res, err := htools.HttpDo(httpMethod, url, header, sb.ToString())
|
||||||
|
logs.Info(common.LOG_QUOTE_STRING + "设置聊天室成员角色结果:" + res + common.LOG_QUOTE_STRING)
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发送广播消息
|
||||||
|
func (client *ImClient) SendBroadCastMsg(parameters map[string]string) error {
|
||||||
|
|
||||||
|
url := "https://api.netease.im/nimserver/msg/broadcastMsg.action"
|
||||||
|
|
||||||
|
httpMethod := common.HTTP_METHOD_POST
|
||||||
|
header := client.generateHeader()
|
||||||
|
|
||||||
|
sb := htools.NewStringBuilder()
|
||||||
|
parametersCount := len(parameters)
|
||||||
|
i := 0
|
||||||
|
for k, v := range parameters {
|
||||||
|
sb.Append(k + "=" + v)
|
||||||
|
if i < parametersCount-1 {
|
||||||
|
sb.Append("&")
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
|
||||||
|
logs.Info(common.LOG_QUOTE_STRING + "发送广播请求:" + sb.ToString() + common.LOG_QUOTE_STRING)
|
||||||
|
res, err := htools.HttpDo(httpMethod, url, header, sb.ToString())
|
||||||
|
logs.Info(common.LOG_QUOTE_STRING + "发送广播结果:" + res + common.LOG_QUOTE_STRING)
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发送全员广播 V2
|
||||||
|
func (client *ImClient) SendBroadCastMsgV2(req BroadcastNotificationReq) error {
|
||||||
|
|
||||||
|
url := "https://open.yunxinapi.com/im/v2/broadcast_notification"
|
||||||
|
|
||||||
|
httpMethod := common.HTTP_METHOD_POST
|
||||||
|
header := client.generateJsonHeader()
|
||||||
|
|
||||||
|
bodyStr := HyTools.JsonStr(req)
|
||||||
|
|
||||||
|
logs.Info(common.LOG_QUOTE_STRING + "发送广播请求V2:" + bodyStr + common.LOG_QUOTE_STRING)
|
||||||
|
res, err := htools.HttpDo(httpMethod, url, header, bodyStr)
|
||||||
|
logs.Info(common.LOG_QUOTE_STRING + "发送广播结果V2:" + res + common.LOG_QUOTE_STRING)
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 踢出用户登录 V2 https://{endpoint}/im/v2/accounts/{account_id}/actions/kick
|
||||||
|
|
||||||
|
func (client *ImClient) KickOutUserV2(userId string) error {
|
||||||
|
|
||||||
|
url := "https://open.yunxinapi.com/im/v2/accounts/" + userId + "/actions/kick"
|
||||||
|
|
||||||
|
httpMethod := common.HTTP_METHOD_POST
|
||||||
|
header := client.generateJsonHeader()
|
||||||
|
|
||||||
|
req := make(map[string]any, 3)
|
||||||
|
req["type"] = 1
|
||||||
|
req["device_id_list"] = []string{}
|
||||||
|
req["kick_notify_extension"] = ""
|
||||||
|
|
||||||
|
bodyStr := HyTools.JsonStr(req)
|
||||||
|
|
||||||
|
logs.Info(common.LOG_QUOTE_STRING + "发送踢下线请求V2:" + bodyStr + common.LOG_QUOTE_STRING)
|
||||||
|
res, err := htools.HttpDo(httpMethod, url, header, bodyStr)
|
||||||
|
logs.Info(common.LOG_QUOTE_STRING + "发送踢下线结果V2:" + res + common.LOG_QUOTE_STRING)
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置/取消 拉黑 静音
|
||||||
|
func (client *ImClient) SetSpecialRelation(parameters map[string]string) error {
|
||||||
|
|
||||||
|
url := "https://api.netease.im/nimserver/user/setSpecialRelation.action"
|
||||||
|
|
||||||
|
httpMethod := common.HTTP_METHOD_POST
|
||||||
|
header := client.generateHeader()
|
||||||
|
|
||||||
|
sb := htools.NewStringBuilder()
|
||||||
|
parametersCount := len(parameters)
|
||||||
|
i := 0
|
||||||
|
for k, v := range parameters {
|
||||||
|
sb.Append(k + "=" + v)
|
||||||
|
if i < parametersCount-1 {
|
||||||
|
sb.Append("&")
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
|
||||||
|
logs.Info(common.LOG_QUOTE_STRING + "设置/取消 拉黑请求:" + sb.ToString() + common.LOG_QUOTE_STRING)
|
||||||
|
res, err := htools.HttpDo(httpMethod, url, header, sb.ToString())
|
||||||
|
logs.Info(common.LOG_QUOTE_STRING + "设置/取消 拉黑结果:" + res + common.LOG_QUOTE_STRING)
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发送自定义系统通知
|
||||||
|
func (client *ImClient) BatchSendMsg(parameters map[string]string) error {
|
||||||
|
|
||||||
|
url := "https://api.netease.im/nimserver/msg/sendBatchMsg.action"
|
||||||
|
httpMethod := common.HTTP_METHOD_POST
|
||||||
|
header := client.generateHeader()
|
||||||
|
|
||||||
|
sb := htools.NewStringBuilder()
|
||||||
|
parametersCount := len(parameters)
|
||||||
|
i := 0
|
||||||
|
for k, v := range parameters {
|
||||||
|
sb.Append(k + "=" + v)
|
||||||
|
if i < parametersCount-1 {
|
||||||
|
sb.Append("&")
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
logs.Info(common.LOG_QUOTE_STRING + "云信IM批量发消息请求:" + sb.ToString() + common.LOG_QUOTE_STRING)
|
||||||
|
res, err := htools.HttpDo(httpMethod, url, header, sb.ToString())
|
||||||
|
logs.Info(common.LOG_QUOTE_STRING + "云信IM批量发消息结果:" + res + common.LOG_QUOTE_STRING)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 批量发送消息
|
||||||
|
func (client *ImClient) SendAttachMsg(parameters map[string]string) error {
|
||||||
|
|
||||||
|
url := "https://api.netease.im/nimserver/msg/sendAttachMsg.action"
|
||||||
|
httpMethod := common.HTTP_METHOD_POST
|
||||||
|
header := client.generateHeader()
|
||||||
|
|
||||||
|
sb := htools.NewStringBuilder()
|
||||||
|
parametersCount := len(parameters)
|
||||||
|
i := 0
|
||||||
|
for k, v := range parameters {
|
||||||
|
sb.Append(k + "=" + v)
|
||||||
|
if i < parametersCount-1 {
|
||||||
|
sb.Append("&")
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
logs.Info(common.LOG_QUOTE_STRING + "云信IM发系统通知请求:" + sb.ToString() + common.LOG_QUOTE_STRING)
|
||||||
|
res, err := htools.HttpDo(httpMethod, url, header, sb.ToString())
|
||||||
|
logs.Info(common.LOG_QUOTE_STRING + "云信IM发系统通知结果:" + res + common.LOG_QUOTE_STRING)
|
||||||
|
if parameters["to"] == "b260b07ff3d1411f926e2d767cb9d6f3" {
|
||||||
|
log.Info("完成给老板发接单消息")
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateChatGroup 创建群组
|
||||||
|
func (client *ImClient) CreateChatGroup(ctx context.Context, ownerUserId string, groupName string, inviteMem []string) (string, error) {
|
||||||
|
|
||||||
|
url := "https://open.yunxinapi.com/im/v2.1/teams"
|
||||||
|
httpMethod := common.HTTP_METHOD_POST
|
||||||
|
header := client.generateJsonHeader()
|
||||||
|
reqBody := &CreateChatGroupReq{
|
||||||
|
OwnerAccountID: ownerUserId,
|
||||||
|
TeamType: 1,
|
||||||
|
Name: groupName,
|
||||||
|
MembersLimit: 3000,
|
||||||
|
InviteAccountIDs: inviteMem,
|
||||||
|
InviteMsg: "管理",
|
||||||
|
Configuration: &TeamConfiguration{
|
||||||
|
JoinMode: 1,
|
||||||
|
},
|
||||||
|
AntispamConfiguration: nil,
|
||||||
|
}
|
||||||
|
bodyBytes, err := json.Marshal(reqBody)
|
||||||
|
if err != nil {
|
||||||
|
return "", errors.WithStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := HyTools.HttpDo(httpMethod, url, header, string(bodyBytes))
|
||||||
|
if err != nil {
|
||||||
|
// {"desc":"already register","code":414}
|
||||||
|
logs.Info("YunXin_CreateChatGroup_Fail_AccID_%s:"+err.Error(), ownerUserId)
|
||||||
|
return "", errors.WithStack(err)
|
||||||
|
}
|
||||||
|
log.InfoF("create group chat resp: %s", res)
|
||||||
|
var body BaseRes[CreateChatGroupRsp]
|
||||||
|
err = json.Unmarshal([]byte(res), &body)
|
||||||
|
if err != nil {
|
||||||
|
return "", errors.WithStack(err)
|
||||||
|
}
|
||||||
|
if body.Code != 200 {
|
||||||
|
return "", errors.Errorf("YunXin_CreateChatGroup code(%d) not 200,msg: %s", body.Code, body.Msg)
|
||||||
|
}
|
||||||
|
if len(body.Data.FailedList) > 0 {
|
||||||
|
var errInfo []string
|
||||||
|
for _, member := range body.Data.FailedList {
|
||||||
|
errInfo = append(errInfo, fmt.Sprintf("account: %s ,code: %d ,msg: %s", member.AccountID, member.ErrorCode, member.ErrorMsg))
|
||||||
|
}
|
||||||
|
return "", errors.Errorf("YunXin_CreateChatGroup err: %s", strings.Join(errInfo, ";"))
|
||||||
|
}
|
||||||
|
|
||||||
|
return cast.ToString(body.Data.TeamInfo.TeamID), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ================ 私有方法 ========================
|
||||||
|
func generateBodyData(parameters map[string]string) string {
|
||||||
|
sb := htools.NewStringBuilder()
|
||||||
|
parametersCount := len(parameters)
|
||||||
|
i := 0
|
||||||
|
for k, v := range parameters {
|
||||||
|
sb.Append(k + "=" + v)
|
||||||
|
if i < parametersCount-1 {
|
||||||
|
sb.Append("&")
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
return sb.ToString()
|
||||||
|
}
|
||||||
|
|
||||||
|
func randNumber() string {
|
||||||
|
str := "0123456789"
|
||||||
|
bytes := []byte(str)
|
||||||
|
var result []byte
|
||||||
|
r := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||||
|
for i := 0; i < 4; i++ {
|
||||||
|
result = append(result, bytes[r.Intn(len(bytes))])
|
||||||
|
}
|
||||||
|
return string(result)
|
||||||
|
}
|
||||||
124
pkg/common/netease/ImClient_test.go
Normal file
124
pkg/common/netease/ImClient_test.go
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
package Netease
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 测试获取IM用户信息
|
||||||
|
func TestImClient_GetImUserInfo(t *testing.T) {
|
||||||
|
type fields struct {
|
||||||
|
AppKey string
|
||||||
|
AppSecret string
|
||||||
|
}
|
||||||
|
type args struct {
|
||||||
|
userId string
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
fields fields
|
||||||
|
args args
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "test",
|
||||||
|
fields: fields{
|
||||||
|
AppKey: "543b1a440b940b170fccdf494839efc01",
|
||||||
|
AppSecret: "41134093938f1",
|
||||||
|
},
|
||||||
|
args: args{
|
||||||
|
// 2251bae8a0514e6892f0374f5dd260d4
|
||||||
|
// b8af4bebe2064435974ba2340d852055
|
||||||
|
userId: "fcda23bc00e641f5ae17492503b566ed",
|
||||||
|
},
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
client := &ImClient{
|
||||||
|
AppKey: tt.fields.AppKey,
|
||||||
|
AppSecret: tt.fields.AppSecret,
|
||||||
|
}
|
||||||
|
if err := client.GetImUserInfo(tt.args.userId); (err != nil) != tt.wantErr {
|
||||||
|
t.Errorf("GetImUserInfo() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 测试注册IM用户
|
||||||
|
func TestImClient_CreateImUser(t *testing.T) {
|
||||||
|
type fields struct {
|
||||||
|
AppKey string
|
||||||
|
AppSecret string
|
||||||
|
}
|
||||||
|
type args struct {
|
||||||
|
userId string
|
||||||
|
nickname string
|
||||||
|
avatar string
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
fields fields
|
||||||
|
args args
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "test",
|
||||||
|
fields: fields{
|
||||||
|
AppKey: "543b1a440b940b170fccdf494839efc01",
|
||||||
|
AppSecret: "41134093938f1",
|
||||||
|
},
|
||||||
|
args: args{
|
||||||
|
// 2251bae8a0514e6892f0374f5dd260d4
|
||||||
|
// b8af4bebe2064435974ba2340d852055
|
||||||
|
userId: "fcda23bc00e641f5ae17492503b566ed",
|
||||||
|
nickname: "杏",
|
||||||
|
avatar: "https://photo-app.ddegame.cn/upload/19986a27-3bae-49f7-9643-cd18cda87557.jpg",
|
||||||
|
},
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
client := &ImClient{
|
||||||
|
AppKey: tt.fields.AppKey,
|
||||||
|
AppSecret: tt.fields.AppSecret,
|
||||||
|
}
|
||||||
|
if err := client.CreateImUser(tt.args.userId, tt.args.nickname, tt.args.avatar); (err != nil) != tt.wantErr {
|
||||||
|
t.Errorf("GetImUserInfo() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 测试注册IM用户
|
||||||
|
func TestImClient_CreateImUserOne(t *testing.T) {
|
||||||
|
client := &ImClient{
|
||||||
|
AppKey: "543b1a440b940b170fccdf494839efc01",
|
||||||
|
AppSecret: "41134093938f1",
|
||||||
|
}
|
||||||
|
client.CreateImUser("fcda23bc00e641f5ae17492503b566ed", "杏", "https://photo-app.ddegame.cn/upload/19986a27-3bae-49f7-9643-cd18cda87557.jpg")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestImClient_CreateChatGroup(t *testing.T) {
|
||||||
|
client := &ImClient{
|
||||||
|
AppKey: "543b1a440b940b170fccdf494839efc01",
|
||||||
|
AppSecret: "41134093938f1",
|
||||||
|
}
|
||||||
|
groupId, err := client.CreateChatGroup(context.Background(), "e1fbefbbd77a402e8c2101a0ebe15f5d", "测试群", []string{"e1fbefbbd77a402e8c2101a0ebe15f5d"})
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
println(groupId)
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
// viper.SetConfigName("dev.yaml")
|
||||||
|
// viper.AddConfigPath("../../../configs/admin/")
|
||||||
|
// viper.SetConfigType("yaml")
|
||||||
|
// _ = viper.ReadInConfig()
|
||||||
|
// log.Init()
|
||||||
|
// datasource.InitMySQlMaster()
|
||||||
|
}
|
||||||
33
pkg/common/netease/ImResponse.go
Normal file
33
pkg/common/netease/ImResponse.go
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
package Netease
|
||||||
|
|
||||||
|
type ImResponse struct {
|
||||||
|
Code int `json:"code"`
|
||||||
|
Desc interface{} `json:"desc"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取聊天室在线列表返回对象
|
||||||
|
type GetChatroomMemberResponse struct {
|
||||||
|
Data []ChatroomMemberDTO `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 聊天室会员
|
||||||
|
type ChatroomMemberDTO struct {
|
||||||
|
RoomId int `json:"roomid"`
|
||||||
|
AccId string `json:"accid"`
|
||||||
|
OnlineStat bool `json:"onlineStat"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建聊天室返回结果
|
||||||
|
type CreateChatroomResponse struct {
|
||||||
|
Code int `json:"code"`
|
||||||
|
Chatroom NeteaseChatroomDTO `json:"chatroom"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 聊天室会员
|
||||||
|
type NeteaseChatroomDTO struct {
|
||||||
|
RoomId int `json:"roomid"`
|
||||||
|
Valid bool `json:"valid"`
|
||||||
|
RoomName string `json:"name"`
|
||||||
|
Ext string `json:"ext"`
|
||||||
|
Creator string `json:"creator"`
|
||||||
|
}
|
||||||
10
pkg/common/netease/dto/ImChatroomOnlineMember.go
Normal file
10
pkg/common/netease/dto/ImChatroomOnlineMember.go
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
package yunxin
|
||||||
|
|
||||||
|
// 聊天室在线成员对象
|
||||||
|
type ImChatroomOnlineMember struct {
|
||||||
|
MessageRoomId int `json:"roomid"`
|
||||||
|
UserId string `json:"accid"`
|
||||||
|
EnterTime int64 `json:"enterTime"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
OnlineStat bool `json:"onlineStat"`
|
||||||
|
}
|
||||||
9
pkg/common/netease/dto/ImUserExtData.go
Normal file
9
pkg/common/netease/dto/ImUserExtData.go
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
package yunxin
|
||||||
|
|
||||||
|
// IM用户扩展信息 会话列表用户数据从IM信息获取
|
||||||
|
type ImUserExtData struct {
|
||||||
|
VipLevel string // Vip等级
|
||||||
|
AvatarDecoration string // 头饰
|
||||||
|
GroupType string
|
||||||
|
VipConfig string // json字符串dto.UserVipConfigDTO
|
||||||
|
}
|
||||||
7
pkg/common/netease/dto/UpdateRoomInfoRequest.go
Normal file
7
pkg/common/netease/dto/UpdateRoomInfoRequest.go
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package yunxin
|
||||||
|
|
||||||
|
// 更新聊天室信息请求对象
|
||||||
|
type UpdateRoomInfoRequest struct {
|
||||||
|
Roomid string `json:"roomid"` // 房间ID
|
||||||
|
NotifyExt string `json:"notifyExt" // 扩展信息`
|
||||||
|
}
|
||||||
38
pkg/common/netease/req.go
Normal file
38
pkg/common/netease/req.go
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
package Netease
|
||||||
|
|
||||||
|
// CreateChatGroupReq 创建群组请求
|
||||||
|
// https://doc.yunxin.163.com/messaging2/server-apis/DIwODUwMTE?platform=server
|
||||||
|
type CreateChatGroupReq struct {
|
||||||
|
OwnerAccountID string `json:"owner_account_id"` // M 群主(创建者)的 IM 账号 ID。
|
||||||
|
TeamType int `json:"team_type"` // M 1:高级群。2:超大群。
|
||||||
|
Name string `json:"name"` // M 长度上限 64 位字符。
|
||||||
|
Icon string `json:"icon,omitempty"` // O 群组头像的 URL 地址,例如 "https://netease/xxx.png",长度上限 1024 位字符。
|
||||||
|
Announcement string `json:"announcement,omitempty"` // O 群组公告,长度上限 1024 位字符。
|
||||||
|
Intro string `json:"intro,omitempty"` // O群组简介,长度上限 512 位字符。
|
||||||
|
MembersLimit int `json:"members_limit"` // O 群组成员数上限(包含群主),默认为 200。可设置范围的为:[2 ~ 200]。
|
||||||
|
ServerExtension string `json:"server_extension,omitempty"` // O 自定义群组扩展字段,第三方可以跟据此属性自定义扩展自己的群属性,建议封装成 JSONObject 格式,{key:value}。长度上限 1024 位字符。 对应 SDK 的 serverExtension 字段。
|
||||||
|
CustomerExtension string `json:"customer_extension,omitempty"` // O 客户端自定义扩展字段,仅服务器 API 可以设置,SDK 仅负责透传,不解析内容。 对应 SDK 的 customerExtension 字段。
|
||||||
|
Extension string `json:"extension,omitempty"` // M 创建群组时邀请入群的成员列表。
|
||||||
|
InviteAccountIDs []string `json:"invite_account_ids,omitempty"` // M 邀请入群的附言,长度上限 150 位字符。
|
||||||
|
InviteMsg string `json:"invite_msg,omitempty"`
|
||||||
|
Configuration *TeamConfiguration `json:"configuration,omitempty"`
|
||||||
|
AntispamConfiguration *AntispamConfig `json:"antispam_configuration,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type TeamConfiguration struct {
|
||||||
|
JoinMode int `json:"join_mode"` // 通过 SDK 侧操作申请入群的验证方式。 0(默认):无需验证,直接入群。 1:需要群主或管理员验证通过才能入群。 2:不允许任何人申请入群。
|
||||||
|
AgreeMode int `json:"agree_mode"` // 邀请入群时是否需要被邀请人的同意。 0(默认):需要被邀请人同意才能入群。 1:不需要被邀请人同意,直接入群。
|
||||||
|
InviteMode int `json:"invite_mode"` // 邀请权限,即谁可以邀请他人入群。 0(默认):群主和管理员。 1:所有人。
|
||||||
|
UpdateTeamInfoMode int `json:"update_team_info_mode"`
|
||||||
|
UpdateExtensionMode int `json:"update_extension_mode"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AntispamConfig struct {
|
||||||
|
Enabled bool `json:"enabled"`
|
||||||
|
BusinessIDMap *BusinessIDMap `json:"business_id_map,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type BusinessIDMap struct {
|
||||||
|
Type int `json:"type"`
|
||||||
|
AntispamBusinessID string `json:"antispam_business_id"`
|
||||||
|
}
|
||||||
35
pkg/common/netease/rsp.go
Normal file
35
pkg/common/netease/rsp.go
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
package Netease
|
||||||
|
|
||||||
|
type CreateChatGroupRsp struct {
|
||||||
|
FailedList []*FailedMember `json:"failed_list,omitempty"`
|
||||||
|
TeamInfo *TeamInfo `json:"team_info"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type FailedMember struct {
|
||||||
|
AccountID string `json:"account_id"`
|
||||||
|
ErrorCode int `json:"error_code"`
|
||||||
|
ErrorMsg string `json:"error_msg"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type TeamInfo struct {
|
||||||
|
TeamID int64 `json:"team_id"`
|
||||||
|
OwnerAccountID string `json:"owner_account_id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Icon string `json:"icon,omitempty"`
|
||||||
|
Announcement string `json:"announcement,omitempty"`
|
||||||
|
Intro string `json:"intro,omitempty"`
|
||||||
|
MembersLimit int `json:"members_limit"`
|
||||||
|
MemberCount int `json:"member_count"`
|
||||||
|
ServerExtension string `json:"server_extension,omitempty"`
|
||||||
|
CustomerExtension string `json:"customer_extension,omitempty"`
|
||||||
|
CreateTime int64 `json:"create_time"`
|
||||||
|
UpdateTime int64 `json:"update_time"`
|
||||||
|
TeamType int `json:"team_type"`
|
||||||
|
Configuration *TeamConfiguration `json:"configuration,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type BaseRes[T any] struct {
|
||||||
|
Code int
|
||||||
|
Msg string
|
||||||
|
Data T
|
||||||
|
}
|
||||||
45
pkg/common/network/response.go
Normal file
45
pkg/common/network/response.go
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
package network
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
SuccessCode = "6000" // 成功
|
||||||
|
NeedLogin = "6018" // 登陆过期
|
||||||
|
ErrorCode = "6020" // 错误
|
||||||
|
|
||||||
|
)
|
||||||
|
|
||||||
|
type Response struct {
|
||||||
|
Code string
|
||||||
|
Result interface{}
|
||||||
|
Msg string
|
||||||
|
}
|
||||||
|
|
||||||
|
type EmptyResponse struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func Fail(msg string) Response {
|
||||||
|
response := Response{Code: ErrorCode, Msg: msg}
|
||||||
|
return response
|
||||||
|
}
|
||||||
|
|
||||||
|
func Invalid() string {
|
||||||
|
response := Response{Code: NeedLogin, Msg: "用户身份已过期"}
|
||||||
|
str, _ := json.Marshal(response)
|
||||||
|
return string(str)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Success(data interface{}) Response {
|
||||||
|
response := Response{Code: SuccessCode, Result: data}
|
||||||
|
return response
|
||||||
|
}
|
||||||
|
|
||||||
|
func Page(data interface{}, count int64) Response {
|
||||||
|
response := Response{Code: SuccessCode, Result: map[string]interface{}{
|
||||||
|
"List": data,
|
||||||
|
"Count": count,
|
||||||
|
}}
|
||||||
|
return response
|
||||||
|
}
|
||||||
148
pkg/common/pinyin/pinyin.go
Normal file
148
pkg/common/pinyin/pinyin.go
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
package pinyin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"unicode/utf8"
|
||||||
|
)
|
||||||
|
|
||||||
|
type vowel int32
|
||||||
|
|
||||||
|
var (
|
||||||
|
ys = []vowel{'ā', 'ē', 'ī', 'ō', 'ū', 'ǖ', 'Ā', 'Ē', 'Ī', 'Ō', 'Ū', 'Ǖ'} // 单韵母 一声
|
||||||
|
es = []vowel{'á', 'é', 'í', 'ó', 'ú', 'ǘ', 'Á', 'É', 'Í', 'Ó', 'Ú', 'Ǘ'} // 单韵母 二声
|
||||||
|
ss = []vowel{'ǎ', 'ě', 'ǐ', 'ǒ', 'ǔ', 'ǚ', 'Ǎ', 'Ě', 'Ǐ', 'Ǒ', 'Ǔ', 'Ǚ'} // 单韵母 三声
|
||||||
|
fs = []vowel{'à', 'è', 'ì', 'ò', 'ù', 'ǜ', 'À', 'È', 'Ì', 'Ò', 'Ù', 'Ǜ'} // 单韵母 四声
|
||||||
|
ws = []vowel{'a', 'e', 'i', 'o', 'u', 'v', 'A', 'E', 'I', 'O', 'U', 'V'} // 单韵母 无声调
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
pinyinTemp map[vowel]interface{}
|
||||||
|
toneTemp map[vowel]vowel
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
Tone string = "带声调的拼音" // 带声调的拼音 例如:Cào
|
||||||
|
InitialsInCapitals string = "首字母大写不带声调" // 首字母大写不带声调 例如:Cao
|
||||||
|
None string = "" //如果匹配不到汉字,就靠大家维护下 【匹配失败,手动添加代码到pinyin.txt】
|
||||||
|
)
|
||||||
|
|
||||||
|
func LoadingPYFile(filename string) {
|
||||||
|
f, err := os.Open(filename)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
pinyinTemp = make(map[vowel]interface{}, 0)
|
||||||
|
toneTemp = make(map[vowel]vowel)
|
||||||
|
for i, t := range ys {
|
||||||
|
toneTemp[t] = ws[i]
|
||||||
|
}
|
||||||
|
for i, t := range es {
|
||||||
|
toneTemp[t] = ws[i]
|
||||||
|
}
|
||||||
|
for i, t := range ss {
|
||||||
|
toneTemp[t] = ws[i]
|
||||||
|
}
|
||||||
|
for i, t := range fs {
|
||||||
|
toneTemp[t] = ws[i]
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
_ = f.Close()
|
||||||
|
}()
|
||||||
|
scanner := bufio.NewScanner(f)
|
||||||
|
for scanner.Scan() {
|
||||||
|
//单行分割取出拼音
|
||||||
|
str := strings.Split(scanner.Text(), "=>")
|
||||||
|
if len(str) < 2 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
i, err := strconv.ParseInt(str[0], 16, 32)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
pinyinTemp[vowel(i)] = str[1]
|
||||||
|
//fmt.Println(pinyinTemp[vowel(i)])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func PY(source string) (string, error) {
|
||||||
|
return PYSplit(source, "", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func PYSplit(source string, split string, types string) (string, error) {
|
||||||
|
hz := []vowel(source)
|
||||||
|
words := make([]string, 0)
|
||||||
|
for _, s := range hz {
|
||||||
|
word, err := _vowel(s, types)
|
||||||
|
if err != nil {
|
||||||
|
return None, err
|
||||||
|
}
|
||||||
|
if len(word) > 0 {
|
||||||
|
words = append(words, word)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return strings.Join(words, split), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func _vowel(source vowel, types string) (string, error) {
|
||||||
|
switch types {
|
||||||
|
case Tone:
|
||||||
|
return getTone(source), nil
|
||||||
|
case InitialsInCapitals:
|
||||||
|
return getInitialsInCapitals(source), nil
|
||||||
|
default:
|
||||||
|
return getDefault(source), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getTone(source vowel) string {
|
||||||
|
if pinyinTemp[source] != nil {
|
||||||
|
return pinyinTemp[source].(string)
|
||||||
|
}
|
||||||
|
return string(source)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getInitialsInCapitals(source vowel) string {
|
||||||
|
def := getDefault(source)
|
||||||
|
var result string
|
||||||
|
if def == "" {
|
||||||
|
return def
|
||||||
|
}
|
||||||
|
str := []vowel(def)
|
||||||
|
if str[0] > 32 {
|
||||||
|
str[0] = str[0] - 32
|
||||||
|
}
|
||||||
|
for _, v := range str {
|
||||||
|
result += string(v)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func getDefault(source vowel) string {
|
||||||
|
tone := getTone(source)
|
||||||
|
var result string
|
||||||
|
if tone == "" {
|
||||||
|
return None
|
||||||
|
}
|
||||||
|
resultLen := make([]vowel, utf8.RuneCountInString(tone))
|
||||||
|
count := 0
|
||||||
|
for _, t := range tone {
|
||||||
|
changes, ok := toneTemp[vowel(t)]
|
||||||
|
if ok {
|
||||||
|
resultLen[count] = changes
|
||||||
|
} else {
|
||||||
|
resultLen[count] = vowel(t)
|
||||||
|
}
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
for _, v := range resultLen {
|
||||||
|
result += string(v)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
41208
pkg/common/pinyin/pinyin.txt
Normal file
41208
pkg/common/pinyin/pinyin.txt
Normal file
File diff suppressed because it is too large
Load Diff
9
pkg/common/pinyin/pinyin_test.go
Normal file
9
pkg/common/pinyin/pinyin_test.go
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
package pinyin
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestTo_Py(t *testing.T) {
|
||||||
|
LoadingPYFile("./pinyin.txt")
|
||||||
|
s, _ := PY("3425另264325一4个44平444台")
|
||||||
|
println(s)
|
||||||
|
}
|
||||||
30
pkg/common/req/req.go
Normal file
30
pkg/common/req/req.go
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
package req
|
||||||
|
|
||||||
|
const (
|
||||||
|
defaultPage = 1
|
||||||
|
defaultSize = 10
|
||||||
|
)
|
||||||
|
|
||||||
|
type Page struct {
|
||||||
|
Page int64 `json:"page" form:"page" uri:"page"`
|
||||||
|
Size int64 `json:"size" form:"size" uri:"size"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Page) check() {
|
||||||
|
if p.Page < 1 {
|
||||||
|
p.Page = defaultPage
|
||||||
|
}
|
||||||
|
if p.Size <= 0 {
|
||||||
|
p.Size = defaultSize
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Page) Offset() int {
|
||||||
|
p.check()
|
||||||
|
return int(p.Page*p.Size - p.Size)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Page) Limit() int {
|
||||||
|
p.check()
|
||||||
|
return int(p.Size)
|
||||||
|
}
|
||||||
154
pkg/common/util/string_util.go
Normal file
154
pkg/common/util/string_util.go
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
package util
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/md5"
|
||||||
|
"encoding/hex"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
"sort"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
PhotoDomainUrl = "https://photo-app.ddegame.cn/"
|
||||||
|
TimeLayout = "2006-01-02 15:04:05"
|
||||||
|
DateLayout = "2006-01-02"
|
||||||
|
DateLayoutShort = "20060102"
|
||||||
|
)
|
||||||
|
|
||||||
|
func FullPhotoUrl(path string) string {
|
||||||
|
if len(path) == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
if strings.Index(path, "http") == 0 {
|
||||||
|
return path
|
||||||
|
}
|
||||||
|
return PhotoDomainUrl + path
|
||||||
|
}
|
||||||
|
|
||||||
|
func Md5ForList(s ...string) string {
|
||||||
|
sort.Strings(s)
|
||||||
|
h := md5.New()
|
||||||
|
h.Write([]byte(strings.Join(s, "")))
|
||||||
|
return hex.EncodeToString(h.Sum(nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
func StringToInt(source string) int {
|
||||||
|
target, _ := strconv.Atoi(source)
|
||||||
|
return target
|
||||||
|
}
|
||||||
|
|
||||||
|
func StringToFloat(source string) float64 {
|
||||||
|
target, _ := strconv.ParseFloat(source, 64)
|
||||||
|
return target
|
||||||
|
}
|
||||||
|
|
||||||
|
func StringIntPlus(s1, s2 string) string {
|
||||||
|
return strconv.Itoa(StringToInt(s1) + StringToInt(s2))
|
||||||
|
}
|
||||||
|
|
||||||
|
func StringIntMultiply(s1, s2 string) string {
|
||||||
|
return strconv.Itoa(StringToInt(s1) * StringToInt(s2))
|
||||||
|
}
|
||||||
|
|
||||||
|
func StringIntSub(s1, s2 string) string {
|
||||||
|
return strconv.Itoa(StringToInt(s1) - StringToInt(s2))
|
||||||
|
}
|
||||||
|
|
||||||
|
func StringFloatSub(s1, s2 string) string {
|
||||||
|
return strconv.FormatFloat(StringToFloat(s1)-StringToFloat(s2), 'f', -1, 64)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ListToSet(list []string) (set []string) {
|
||||||
|
m := make(map[string]bool, 0)
|
||||||
|
for i := range list {
|
||||||
|
m[list[i]] = true
|
||||||
|
}
|
||||||
|
for k := range m {
|
||||||
|
set = append(set, k)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func ToJson(source interface{}) []byte {
|
||||||
|
b, _ := json.Marshal(source)
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func ToJsonString(source interface{}) string {
|
||||||
|
return string(ToJson(source))
|
||||||
|
}
|
||||||
|
|
||||||
|
func NowTimeToString() string {
|
||||||
|
return time.Now().Format(TimeLayout)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NowTimeIncreaseString(t time.Duration) string {
|
||||||
|
return time.Now().Add(t).Format(TimeLayout)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NowDateToString() string {
|
||||||
|
return time.Now().Format(DateLayout)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NowDateToStringShort() string {
|
||||||
|
return time.Now().Format(DateLayoutShort)
|
||||||
|
}
|
||||||
|
|
||||||
|
func DateToString(source time.Time) string {
|
||||||
|
return source.Format(TimeLayout)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Md5(s string) string {
|
||||||
|
h := md5.New()
|
||||||
|
h.Write([]byte(s))
|
||||||
|
return hex.EncodeToString(h.Sum(nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
func ProcessTimeStr(s string) (string, error) {
|
||||||
|
// 定义两种时间格式
|
||||||
|
layout1 := "2006-01-02 15:04:05" // 无时区的格式
|
||||||
|
layout2 := "2006-01-02 15:04:05 -0700 MST" // 带时区的格式(包含偏移和时区名称)
|
||||||
|
|
||||||
|
// 尝试解析为无时区格式
|
||||||
|
_, err1 := time.Parse(layout1, s)
|
||||||
|
if err1 == nil {
|
||||||
|
return s, nil // 直接返回原字符串
|
||||||
|
}
|
||||||
|
|
||||||
|
// 尝试解析为带时区格式
|
||||||
|
t2, err2 := time.Parse(layout2, s)
|
||||||
|
if err2 == nil {
|
||||||
|
// 格式化为无时区格式
|
||||||
|
return t2.Format(layout1), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 两种格式都不匹配
|
||||||
|
return "", fmt.Errorf("invalid time format: %s", s)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解析url里的参数为map
|
||||||
|
func ParseUrlParameter(fullUrl string) (result map[string]string) {
|
||||||
|
|
||||||
|
result = make(map[string]string)
|
||||||
|
|
||||||
|
// 解析URL
|
||||||
|
parsedURL, err := url.Parse(fullUrl)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("解析URL失败: %v\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解析查询参数
|
||||||
|
queryParams := parsedURL.Query()
|
||||||
|
|
||||||
|
// 输出所有参数
|
||||||
|
for key, values := range queryParams {
|
||||||
|
result[key] = values[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
17
pkg/common/util/string_util_test.go
Normal file
17
pkg/common/util/string_util_test.go
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package util
|
||||||
|
|
||||||
|
import (
|
||||||
|
"servicebase/pkg/common"
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_processTimeStr(t *testing.T) {
|
||||||
|
tmp, e := ProcessTimeStr("2025-05-29 09:08:38 +0800 CST")
|
||||||
|
fmt.Printf("%v %v\n", tmp, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParseUrlParameter(t *testing.T) {
|
||||||
|
// assets/img/op_1754967614.png?c=#000000&s=160
|
||||||
|
ParseUrlParameter(common.FullPhotoUrl("assets/img/op_1754967614.png?c=%23000000&s=160"))
|
||||||
|
}
|
||||||
18
pkg/constant/content.go
Normal file
18
pkg/constant/content.go
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
package constant
|
||||||
|
|
||||||
|
const (
|
||||||
|
JxApiToken = "8056be17be26d7e8f4"
|
||||||
|
|
||||||
|
ContentSmsTemplateTypeLogin = "LOGIN"
|
||||||
|
ContentSmsTemplateTypeRegDriver = "REG-DRIVER"
|
||||||
|
ContentSmsTemplateTypeRegPassenger = "REG-PASSENGER"
|
||||||
|
|
||||||
|
ContentSmsRecordSendSuccess = 2
|
||||||
|
ContentSmsRecordSendFailed = 1
|
||||||
|
)
|
||||||
|
|
||||||
|
var ContentSmsTemplateType map[string]string
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
ContentSmsTemplateType = map[string]string{}
|
||||||
|
}
|
||||||
170
pkg/constant/exam_order/order_status.go
Normal file
170
pkg/constant/exam_order/order_status.go
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
package exam_order
|
||||||
|
|
||||||
|
type OrderStatus string
|
||||||
|
|
||||||
|
const (
|
||||||
|
// 订单原始状态 已下单待支付
|
||||||
|
ORDER_ORIGIN_STATUS_CREATED_WAIT_PAY OrderStatus = "1"
|
||||||
|
|
||||||
|
// 订单原始状态 已支付待接单
|
||||||
|
ORDER_ORIGIN_STATUS_PAID_WAIT_SELLER_AGREE OrderStatus = "2"
|
||||||
|
// 订单原始状态 已接单
|
||||||
|
ORDER_ORIGIN_STATUS_SELLER_AGREED OrderStatus = "3"
|
||||||
|
// 订单原始状态 已完成
|
||||||
|
ORDER_ORIGIN_STATUS_FINISHED OrderStatus = "4"
|
||||||
|
// 订单原始状态 退款中
|
||||||
|
ORDER_ORIGIN_STATUS_REFUNDING OrderStatus = "5"
|
||||||
|
// 订单原始状态 售后中(申诉中)
|
||||||
|
ORDER_ORIGIN_STATUS_IN_APPEAL OrderStatus = "6"
|
||||||
|
// 订单原始状态 申诉失败 订单完成
|
||||||
|
ORDER_ORIGIN_STATUS_APPEAL_FAILED OrderStatus = "8"
|
||||||
|
// 订单原始状态 售后完成(申诉完成)
|
||||||
|
ORDER_ORIGIN_STATUS_APPEAL_DONE OrderStatus = "9"
|
||||||
|
// 订单原始状态 支付前买家取消
|
||||||
|
ORDER_ORIGIN_STATUS_UNPAY_BUYER_CANCELED OrderStatus = "20"
|
||||||
|
|
||||||
|
// 订单原始状态 10分钟未支付自动过期
|
||||||
|
ORDER_ORIGIN_STATUS_UNPAY_AUTO_EXPISED OrderStatus = "21"
|
||||||
|
// 订单原始状态 支付后买家取消
|
||||||
|
ORDER_ORIGIN_STATUS_PAID_BUYER_CANCELED OrderStatus = "22"
|
||||||
|
// 订单原始状态 支付后卖家未接单 自动取消
|
||||||
|
ORDER_ORIGIN_STATUS_PAID_SELLER_NOT_AGREE_AUTO_CANCELED OrderStatus = "23"
|
||||||
|
// 订单原始状态 卖家拒绝接单
|
||||||
|
ORDER_ORIGIN_STATUS_SELLER_REJECTED_ORDER OrderStatus = "24"
|
||||||
|
// 订单原始状态 卖家同意退款
|
||||||
|
ORDER_ORIGIN_STATUS_SELLER_AGREE_REFUND OrderStatus = "25"
|
||||||
|
// 订单原始状态 (售后成功)申诉成功,并免单退款
|
||||||
|
ORDER_ORIGIN_STATUS_APPEAL_SUCCESS_CANCELED OrderStatus = "26"
|
||||||
|
// 订单原始状态 买家申请退款卖家超时未处理自动取消
|
||||||
|
ORDER_ORIGIN_STATUS_REFUNDING_EXPIRED_AUTO_CANCELED OrderStatus = "27"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (o OrderStatus) String() string {
|
||||||
|
return string(o)
|
||||||
|
}
|
||||||
|
|
||||||
|
type PayStatus string
|
||||||
|
|
||||||
|
const (
|
||||||
|
// 订单支付状态 未支付
|
||||||
|
ORDER_PAY_STATUS_UNPAY PayStatus = "0"
|
||||||
|
// 订单支付状态 已支付
|
||||||
|
ORDER_PAY_STATUS_PAID PayStatus = "1"
|
||||||
|
// 订单支付状态 已退款
|
||||||
|
ORDER_PAY_STATUS_REFUND PayStatus = "2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (o PayStatus) String() string {
|
||||||
|
return string(o)
|
||||||
|
}
|
||||||
|
|
||||||
|
type ExaminerOrderStatus string
|
||||||
|
|
||||||
|
const (
|
||||||
|
ExaminerIdle ExaminerOrderStatus = "idle" // 空闲
|
||||||
|
ExaminerAccept ExaminerOrderStatus = "accept" // 空闲
|
||||||
|
)
|
||||||
|
|
||||||
|
func (o ExaminerOrderStatus) String() string {
|
||||||
|
return string(o)
|
||||||
|
}
|
||||||
|
|
||||||
|
type ExamSkillStatus string
|
||||||
|
|
||||||
|
const (
|
||||||
|
ExamSkillNormal ExamSkillStatus = "normal"
|
||||||
|
ExamSkillDown ExamSkillStatus = "down"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (o ExamSkillStatus) String() string {
|
||||||
|
return string(o)
|
||||||
|
}
|
||||||
|
|
||||||
|
type OrderAction string
|
||||||
|
|
||||||
|
const (
|
||||||
|
//PayOrder = 支付订单 CancelOrder = 取消订单 AgreeOrder= 同意接单 RefuseOrder=拒绝接单 FinishOrder = 确认完成 RequestRefund=请求退款 AgreeRefund=同意退款 RefuseRefund=拒绝退款
|
||||||
|
// 订单操作 创建订单
|
||||||
|
ORDER_ACTION_CREATE_ORDER OrderAction = "CreateOrder"
|
||||||
|
// 订单操作 支付订单
|
||||||
|
ORDER_ACTION_PAY_ORDER OrderAction = "PayOrder"
|
||||||
|
// 订单操作 取消订单
|
||||||
|
ORDER_ACTION_CANCEL_ORDER OrderAction = "CancelOrder"
|
||||||
|
// 订单操作 卖家同意接单
|
||||||
|
ORDER_ACTION_AGREE_ORDER OrderAction = "AgreeOrder"
|
||||||
|
// 订单操作 卖家完成一局
|
||||||
|
ORDER_ACTION_SUB_COMPLETE_ORDER OrderAction = "SubCompleteOrder"
|
||||||
|
// 订单操作 买家续单
|
||||||
|
ORDER_ACTION_RENEW_ORDER OrderAction = "RenewOrder"
|
||||||
|
// 订单操作 卖家开始陪玩
|
||||||
|
ORDER_ACTION_START_ORDER OrderAction = "StartOrder"
|
||||||
|
// 订单操作 卖家拒绝接单
|
||||||
|
ORDER_ACTION_REJECT_ORDER OrderAction = "RejectOrder"
|
||||||
|
// 订单操作 买家完成订单
|
||||||
|
ORDER_ACTION_FINISH_ORDER OrderAction = "FinishOrder"
|
||||||
|
// 订单操作 提前结束
|
||||||
|
ORDER_ACTION_EARLY_END_ORDER OrderAction = "EarlyEndOrder"
|
||||||
|
// 订单操作 按局订单 陪玩结束
|
||||||
|
ORDER_ACTION_SELLER_END_ORDER OrderAction = "SellerEndOrderByCount"
|
||||||
|
// 订单操作 买家请求退款
|
||||||
|
ORDER_ACTION_REQUEST_REFUND OrderAction = "RequestRefund"
|
||||||
|
// 订单操作 卖家同意退款
|
||||||
|
ORDER_ACTION_AGREE_REFUND OrderAction = "AgreeRefund"
|
||||||
|
// 订单操作 卖家拒绝退款
|
||||||
|
ORDER_ACTION_REJECT_REFUND OrderAction = "RejectRefund"
|
||||||
|
// 订单操作 评价订单
|
||||||
|
ORDER_ACTION_RATE_ORDER OrderAction = "RateOrder"
|
||||||
|
// 订单操作 再次下单
|
||||||
|
ORDER_ACTION_ORDER_AGAIN OrderAction = "ReCreateOrder"
|
||||||
|
// 订单操作 申请售后
|
||||||
|
ORDER_ACTION_ORDER_SUPPORT OrderAction = "ApplySupportOrder"
|
||||||
|
// 订单操作 删除订单
|
||||||
|
ORDER_ACTION_ORDER_DEL OrderAction = "DeleteOrder"
|
||||||
|
// 订单操作 订单免单
|
||||||
|
ORDER_ACTION_ORDER_FREE OrderAction = "FreeOrder"
|
||||||
|
// 订单操作 联系售后
|
||||||
|
ORDER_ACTION_CONTACT_SUPPORT OrderAction = "ContactSupport"
|
||||||
|
// 订单操作 删除评价订单
|
||||||
|
ORDER_ACTION_DELETE_ORDER_RATE OrderAction = "DeleteOrderRate"
|
||||||
|
// 订单操作 删除订单
|
||||||
|
ORDER_ACTION_DELETE_ORDER OrderAction = "DeleteOrder"
|
||||||
|
// 订单操作 申诉
|
||||||
|
ORDER_ACTION_APPEAL_SUCCESS OrderAction = "AppealSuccess"
|
||||||
|
// 订单操作 申诉失败
|
||||||
|
ORDER_ACTION_APPEAL_FAIL OrderAction = "AppealFail"
|
||||||
|
//订单操作 增加单量
|
||||||
|
ORDER_ACTION_ADD_ORDER_COUNT OrderAction = "AddOrderCount"
|
||||||
|
//订单操作 减少单量
|
||||||
|
ORDER_ACTION_REDUCE_ORDER_COUNT OrderAction = "ReduceOrderCount"
|
||||||
|
//订单操作 进入房间
|
||||||
|
ORDER_ACTION_ENTER_ROOM OrderAction = "EnterRoom"
|
||||||
|
// 订单操作 提交审核
|
||||||
|
ORDER_ACTION_SUBMIT_REVIEW OrderAction = "SubmitReview"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (o OrderAction) String() string {
|
||||||
|
return string(o)
|
||||||
|
}
|
||||||
|
|
||||||
|
type OrderReviewStatus string
|
||||||
|
|
||||||
|
const (
|
||||||
|
OrderReviewInit OrderReviewStatus = "init"
|
||||||
|
OrderReviewAccept OrderReviewStatus = "accept"
|
||||||
|
OrderReviewDeny OrderReviewStatus = "deny"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (o OrderReviewStatus) String() string {
|
||||||
|
return string(o)
|
||||||
|
}
|
||||||
|
|
||||||
|
type OrderSupportStatus string
|
||||||
|
|
||||||
|
const (
|
||||||
|
OrderSupportInit OrderSupportStatus = "init"
|
||||||
|
OrderSupportDone OrderSupportStatus = "done"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (o OrderSupportStatus) String() string {
|
||||||
|
return string(o)
|
||||||
|
}
|
||||||
24
pkg/constant/p_vars.go
Normal file
24
pkg/constant/p_vars.go
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
package constant
|
||||||
|
|
||||||
|
const (
|
||||||
|
PhotoDomainUrl = "https://photo-app.ddegame.cn/"
|
||||||
|
API_SECRET = "c9ca017f078a4cd1ba5ccb9d02d4869a"
|
||||||
|
HTTP_METHOD_POST = "POST"
|
||||||
|
LOG_QUOTE_STRING = "#"
|
||||||
|
|
||||||
|
// 验证码类型
|
||||||
|
SMS_CODE_TYPE_SIGN_IN = "signIn" //登录验证码
|
||||||
|
|
||||||
|
// 未登录 需要跳登录页
|
||||||
|
ErrorCodeNeedLogin int = 7031
|
||||||
|
ErrorCodeSignError int = 7032
|
||||||
|
|
||||||
|
// APP登录方式
|
||||||
|
AppLoginTypePwd = "1" //密码登录
|
||||||
|
AppLoginTypeSmsCode = "2" //验证码登录
|
||||||
|
|
||||||
|
CustomerProductId = "CUSTOMER" // 自定义充值的产品ID
|
||||||
|
|
||||||
|
WeekStarGiftGrantToReward = "TO_REWARD" // 给周星名气榜用户发放的礼物列表key
|
||||||
|
WeekStarGiftGrantToReceive = "TO_RECEIVE" // 给周星人气榜用户发放的礼物列表key
|
||||||
|
)
|
||||||
15
pkg/constant/sys_vars.go
Normal file
15
pkg/constant/sys_vars.go
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package constant
|
||||||
|
|
||||||
|
// 资源类型
|
||||||
|
type ResourceTypeEnum int
|
||||||
|
|
||||||
|
const (
|
||||||
|
Image ResourceTypeEnum = iota // = 0
|
||||||
|
Video // = 1
|
||||||
|
Audio
|
||||||
|
)
|
||||||
|
|
||||||
|
func (actionType ResourceTypeEnum) String() string {
|
||||||
|
names := []string{"图片", "视频", "音频"}
|
||||||
|
return names[actionType]
|
||||||
|
}
|
||||||
7
pkg/constant/tenant.go
Normal file
7
pkg/constant/tenant.go
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package constant
|
||||||
|
|
||||||
|
const (
|
||||||
|
HeaderUserId = "USER-ID"
|
||||||
|
TenantId = "TENANT-ID"
|
||||||
|
ScopeId = "SCOPE-ID"
|
||||||
|
)
|
||||||
21
pkg/constant/withdraw_status.go
Normal file
21
pkg/constant/withdraw_status.go
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package constant
|
||||||
|
|
||||||
|
const (
|
||||||
|
WithdrawStatusReview = "1"
|
||||||
|
WithdrawStatusApproved = "2"
|
||||||
|
WithdrawStatusReject = "3"
|
||||||
|
WithdrawStatusPayFailed = "4"
|
||||||
|
WithdrawStatusPaySuccess = "5"
|
||||||
|
)
|
||||||
|
|
||||||
|
var WithdrawStatusCon map[string]string
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
WithdrawStatusCon = map[string]string{
|
||||||
|
WithdrawStatusReview: "审核中",
|
||||||
|
WithdrawStatusApproved: "审核通过",
|
||||||
|
WithdrawStatusReject: "审核失败",
|
||||||
|
WithdrawStatusPayFailed: "打款失败",
|
||||||
|
WithdrawStatusPaySuccess: "打款成功",
|
||||||
|
}
|
||||||
|
}
|
||||||
185
pkg/datasource/fields/field.go
Normal file
185
pkg/datasource/fields/field.go
Normal file
@ -0,0 +1,185 @@
|
|||||||
|
package fields
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"database/sql/driver"
|
||||||
|
"encoding/binary"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"gorm.io/gorm"
|
||||||
|
"gorm.io/gorm/clause"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
timeFormat = "2006-01-02 15:04:05"
|
||||||
|
dateFormat = "2006-01-02"
|
||||||
|
)
|
||||||
|
|
||||||
|
type STPoint struct {
|
||||||
|
Lng float64
|
||||||
|
Lat float64
|
||||||
|
}
|
||||||
|
|
||||||
|
type Time time.Time
|
||||||
|
|
||||||
|
func (t *Time) UnmarshalJSON(data []byte) (err error) {
|
||||||
|
now, err := time.ParseInLocation(`"`+timeFormat+`"`, string(data), time.Local)
|
||||||
|
*t = Time(now)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Time) MarshalJSON() ([]byte, error) {
|
||||||
|
b := make([]byte, 0, len(timeFormat)+2)
|
||||||
|
b = append(b, '"')
|
||||||
|
b = time.Time(*t).AppendFormat(b, timeFormat)
|
||||||
|
b = append(b, '"')
|
||||||
|
return b, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Time) String() string {
|
||||||
|
return time.Time(*t).Format(timeFormat)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Time) Value() (driver.Value, error) {
|
||||||
|
return time.Time(*t).Format(timeFormat), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Time) Time() time.Time {
|
||||||
|
return time.Time(*t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NowTime() Time {
|
||||||
|
return Time(time.Now())
|
||||||
|
}
|
||||||
|
|
||||||
|
type Date time.Time
|
||||||
|
|
||||||
|
func (t *Date) UnmarshalJSON(data []byte) (err error) {
|
||||||
|
now, err := time.ParseInLocation(`"`+dateFormat+`"`, string(data), time.Local)
|
||||||
|
*t = Date(now)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Date) MarshalJSON() ([]byte, error) {
|
||||||
|
b := make([]byte, 0, len(dateFormat)+2)
|
||||||
|
b = append(b, '"')
|
||||||
|
b = time.Time(*t).AppendFormat(b, dateFormat)
|
||||||
|
b = append(b, '"')
|
||||||
|
return b, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Date) String() string {
|
||||||
|
return time.Time(*t).Format(dateFormat)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Date) FromStr(s string) error {
|
||||||
|
now, err := time.ParseInLocation(dateFormat, string(s), time.Local)
|
||||||
|
*t = Date(now)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Date) Time() time.Time {
|
||||||
|
return time.Time(*t)
|
||||||
|
}
|
||||||
|
|
||||||
|
type Month time.Time
|
||||||
|
|
||||||
|
const (
|
||||||
|
monthFormat = "2006-01"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (t *Month) UnmarshalJSON(data []byte) (err error) {
|
||||||
|
if len(data) <= 2 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
now, err := time.ParseInLocation(`"`+monthFormat+`"`, string(data), time.Local)
|
||||||
|
*t = Month(now)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Month) MarshalJSON() ([]byte, error) {
|
||||||
|
b := make([]byte, 0, len(monthFormat)+2)
|
||||||
|
b = append(b, '"')
|
||||||
|
b = time.Time(*t).AppendFormat(b, monthFormat)
|
||||||
|
b = append(b, '"')
|
||||||
|
return b, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Month) String() string {
|
||||||
|
return time.Time(*t).Format(monthFormat)
|
||||||
|
}
|
||||||
|
|
||||||
|
type Point struct {
|
||||||
|
Lat float64 `json:"lat"`
|
||||||
|
Lng float64 `json:"lng"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p Point) Value() (driver.Value, error) {
|
||||||
|
return fmt.Sprintf("POINT(%f %f)", p.Lng, p.Lat), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Point) Scan(src interface{}) error {
|
||||||
|
switch src.(type) {
|
||||||
|
case []byte:
|
||||||
|
var b = src.([]byte)
|
||||||
|
if len(b) != 25 {
|
||||||
|
return errors.New(fmt.Sprintf("Expected []bytes with length 25, got %d", len(b)))
|
||||||
|
}
|
||||||
|
var longitude float64
|
||||||
|
var latitude float64
|
||||||
|
buf := bytes.NewReader(b[9:17])
|
||||||
|
err := binary.Read(buf, binary.LittleEndian, &longitude)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
buf = bytes.NewReader(b[17:25])
|
||||||
|
err = binary.Read(buf, binary.LittleEndian, &latitude)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
p.Lng = longitude
|
||||||
|
p.Lat = latitude
|
||||||
|
default:
|
||||||
|
return errors.New(fmt.Sprintf("Expected []byte for Location type, got %T", src))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (loc Point) GormDataType() string {
|
||||||
|
return "point"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (loc Point) GormValue(ctx context.Context, db *gorm.DB) clause.Expr {
|
||||||
|
return clause.Expr{
|
||||||
|
SQL: "ST_PointFromText(?)",
|
||||||
|
Vars: []interface{}{fmt.Sprintf("POINT(%f %f)", loc.Lng, loc.Lat)},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p Point) DistanceTo(other Point) float64 {
|
||||||
|
const earthRadius = 6371000 // 地球半径,单位为米
|
||||||
|
|
||||||
|
lat1 := p.Lat * math.Pi / 180
|
||||||
|
lng1 := p.Lng * math.Pi / 180
|
||||||
|
lat2 := other.Lat * math.Pi / 180
|
||||||
|
lng2 := other.Lng * math.Pi / 180
|
||||||
|
|
||||||
|
dlat := lat2 - lat1
|
||||||
|
dlng := lng2 - lng1
|
||||||
|
|
||||||
|
a := math.Sin(dlat/2)*math.Sin(dlat/2) +
|
||||||
|
math.Cos(lat1)*math.Cos(lat2)*math.Sin(dlng/2)*math.Sin(dlng/2)
|
||||||
|
c := 2 * math.Atan2(math.Sqrt(a), math.Sqrt(1-a))
|
||||||
|
|
||||||
|
distance := earthRadius * c
|
||||||
|
// point1 := Point{Lat: 40.7128, Lng: -74.0060}
|
||||||
|
// point2 := Point{Lat: 34.0522, Lng: -118.2437}
|
||||||
|
// distance := point1.DistanceTo(point2)
|
||||||
|
// fmt.Printf("Distance between points: %.2f km\n", distance)
|
||||||
|
// fmt.Printf("Distance between points: %d meters\n", distance)
|
||||||
|
return distance
|
||||||
|
}
|
||||||
128
pkg/datasource/mysql.go
Normal file
128
pkg/datasource/mysql.go
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
package datasource
|
||||||
|
|
||||||
|
import (
|
||||||
|
"servicebase/pkg/log"
|
||||||
|
"servicebase/pkg/repo"
|
||||||
|
"servicebase/pkg/utils"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
"gorm.io/driver/mysql"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
"gorm.io/gorm/schema"
|
||||||
|
"gorm.io/plugin/dbresolver"
|
||||||
|
)
|
||||||
|
|
||||||
|
type BaseModel struct {
|
||||||
|
ID int `gorm:"primaryKey" json:"id"`
|
||||||
|
CreateTime utils.Time `gorm:"type:datetime;index;not null" json:"createTime"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (model *BaseModel) BeforeCreate(tx *gorm.DB) (err error) {
|
||||||
|
model.CreateTime.Time = time.Now()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var DB *gorm.DB
|
||||||
|
|
||||||
|
type MySQLStarter struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *MySQLStarter) Init() error {
|
||||||
|
InitMySQl()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func InitMySQl() {
|
||||||
|
dsn := viper.GetString("db.connectString")
|
||||||
|
log.InfoF("init db config with: %s", dsn)
|
||||||
|
var e error
|
||||||
|
if DB, e = gorm.Open(mysql.New(mysql.Config{
|
||||||
|
DriverName: "",
|
||||||
|
ServerVersion: "",
|
||||||
|
DSN: dsn,
|
||||||
|
Conn: nil,
|
||||||
|
SkipInitializeWithVersion: false,
|
||||||
|
DefaultStringSize: 255,
|
||||||
|
DefaultDatetimePrecision: nil,
|
||||||
|
DisableDatetimePrecision: true,
|
||||||
|
DontSupportRenameIndex: false,
|
||||||
|
DontSupportRenameColumn: true,
|
||||||
|
DontSupportForShareClause: false,
|
||||||
|
// DontSupportNullAsDefaultValue: false,
|
||||||
|
}), &gorm.Config{
|
||||||
|
SkipDefaultTransaction: false,
|
||||||
|
NamingStrategy: schema.NamingStrategy{
|
||||||
|
TablePrefix: "", // table name prefix, table for `User` would be `t_users`
|
||||||
|
SingularTable: true, // use singular table name, table for `User` would be `user` with this option enabled
|
||||||
|
NoLowerCase: false, // skip the snake_casing of names
|
||||||
|
NameReplacer: strings.NewReplacer("PID", "pid"), // use name replacer to change struct/field name before convert it to db name
|
||||||
|
},
|
||||||
|
FullSaveAssociations: false,
|
||||||
|
Logger: &log.GLog{}, //
|
||||||
|
NowFunc: func() time.Time {
|
||||||
|
return time.Now().Local()
|
||||||
|
},
|
||||||
|
DryRun: false,
|
||||||
|
PrepareStmt: false, // 执行任何 SQL 时都会创建一个 prepared statement 并将其缓存,以提高后续的效率
|
||||||
|
DisableAutomaticPing: false, // 在完成初始化后,GORM 会自动 ping 数据库以检查数据库的可用性
|
||||||
|
DisableForeignKeyConstraintWhenMigrating: true, // 在 AutoMigrate 或 CreateTable 时,GORM 会自动创建外键约束,若要禁用该特性,可将其设置为 true
|
||||||
|
DisableNestedTransaction: false, // 嵌套事务
|
||||||
|
AllowGlobalUpdate: false, // true = 启用全局 update/delete
|
||||||
|
QueryFields: false,
|
||||||
|
CreateBatchSize: 0,
|
||||||
|
ClauseBuilders: nil,
|
||||||
|
ConnPool: nil,
|
||||||
|
Dialector: nil,
|
||||||
|
Plugins: nil,
|
||||||
|
}); e != nil {
|
||||||
|
panic("failed to connect database")
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = DB.Use(dbresolver.Register(dbresolver.Config{
|
||||||
|
Replicas: []gorm.Dialector{mysql.Open(dsn)},
|
||||||
|
Policy: dbresolver.RandomPolicy{},
|
||||||
|
}).Register(dbresolver.Config{
|
||||||
|
Replicas: []gorm.Dialector{mysql.Open(dsn)},
|
||||||
|
} /* &model.User{} */))
|
||||||
|
|
||||||
|
sqlDB, _ := DB.DB()
|
||||||
|
// SetMaxIdleConns 用于设置连接池中空闲连接的最大数量。
|
||||||
|
sqlDB.SetMaxIdleConns(20)
|
||||||
|
// SetMaxOpenConns 设置打开数据库连接的最大数量。
|
||||||
|
sqlDB.SetMaxOpenConns(100)
|
||||||
|
// SetConnMaxLifetime 设置了连接可复用的最大时间。
|
||||||
|
sqlDB.SetConnMaxLifetime(time.Hour * 24)
|
||||||
|
|
||||||
|
// log.InfoF("gorm metrics at: %d", viper.GetUint32("db.metrics.port"))
|
||||||
|
// _ = DB.Use(prometheus.New(prometheus.Config{
|
||||||
|
// DBName: "db_data-front", // 使用 `DBName` 作为指标 label
|
||||||
|
// RefreshInterval: 10, // 指标刷新频率(默认为 15 秒)
|
||||||
|
// PushAddr: "", // 如果配置了 `PushAddr`,则推送指标
|
||||||
|
// StartServer: false, // 启用一个 http 服务来暴露指标
|
||||||
|
// //HTTPServerPort: viper.GetUint32("db.metrics.port"), // 配置 http 服务监听端口,默认端口为 8080 (如果您配置了多个,只有第一个 `HTTPServerPort` 会被使用)
|
||||||
|
// MetricsCollector: []prometheus.MetricsCollector{
|
||||||
|
// &prometheus.MySQL{
|
||||||
|
// // 指标名前缀,默认为 `gorm_status_`
|
||||||
|
// // 例如: Threads_running 的指标名就是 `gorm_status_Threads_running`
|
||||||
|
// Prefix: "gorm_status_",
|
||||||
|
// // 拉取频率,默认使用 Prometheus 的 RefreshInterval
|
||||||
|
// Interval: 30,
|
||||||
|
// // 从 SHOW STATUS 选择变量变量,如果不设置,则使用全部的状态变量
|
||||||
|
// VariableNames: []string{"Threads_running"},
|
||||||
|
// },
|
||||||
|
// }, // 用户自定义指标
|
||||||
|
// }))
|
||||||
|
|
||||||
|
//_ = DB.Use(tracing.NewPlugin(tracing.WithoutMetrics()))
|
||||||
|
|
||||||
|
autoMigrate()
|
||||||
|
|
||||||
|
repo.SetDefault(DB)
|
||||||
|
}
|
||||||
|
|
||||||
|
func autoMigrate() {
|
||||||
|
//_ = DB.AutoMigrate(&model.User{})
|
||||||
|
//_ = DB.AutoMigrate(&model.LeaseType{})
|
||||||
|
}
|
||||||
144
pkg/helper/AliAudio.go
Normal file
144
pkg/helper/AliAudio.go
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
package helper
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/aliyun/alibaba-cloud-sdk-go/sdk"
|
||||||
|
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth/credentials"
|
||||||
|
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TransAudioToText(fileUrl string) (result string, err error) {
|
||||||
|
|
||||||
|
// 地域ID,固定值。
|
||||||
|
const REGION_ID string = "cn-shanghai"
|
||||||
|
const ENDPOINT_NAME string = "cn-shanghai"
|
||||||
|
const PRODUCT string = "nls-filetrans"
|
||||||
|
const DOMAIN string = "filetrans.cn-shanghai.aliyuncs.com"
|
||||||
|
const API_VERSION string = "2018-08-17"
|
||||||
|
const POST_REQUEST_ACTION string = "SubmitTask"
|
||||||
|
const GET_REQUEST_ACTION string = "GetTaskResult"
|
||||||
|
// 请求参数
|
||||||
|
const KEY_APP_KEY string = "appkey" //此处appkey无需替换。
|
||||||
|
const KEY_FILE_LINK string = "file_link"
|
||||||
|
const KEY_VERSION string = "version"
|
||||||
|
const KEY_ENABLE_WORDS string = "enable_words"
|
||||||
|
// 响应参数
|
||||||
|
const KEY_TASK string = "Task"
|
||||||
|
const KEY_TASK_ID string = "TaskId"
|
||||||
|
const KEY_STATUS_TEXT string = "StatusText"
|
||||||
|
const KEY_RESULT string = "Result"
|
||||||
|
// 状态值
|
||||||
|
const STATUS_SUCCESS string = "SUCCESS"
|
||||||
|
const STATUS_RUNNING string = "RUNNING"
|
||||||
|
const STATUS_QUEUEING string = "QUEUEING"
|
||||||
|
var accessKeyId string = viper.GetString("aliyun.audio.accessKeyId")
|
||||||
|
var accessKeySecret string = viper.GetString("aliyun.audio.accessKeySecret")
|
||||||
|
var appKey string = viper.GetString("aliyun.audio.appKey")
|
||||||
|
var fileLink string = fileUrl
|
||||||
|
c := sdk.NewConfig()
|
||||||
|
credential := credentials.NewAccessKeyCredential(accessKeyId, accessKeySecret)
|
||||||
|
client, err := sdk.NewClientWithOptions(REGION_ID, c, credential)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
postRequest := requests.NewCommonRequest()
|
||||||
|
postRequest.Domain = DOMAIN
|
||||||
|
postRequest.Version = API_VERSION
|
||||||
|
postRequest.Product = PRODUCT
|
||||||
|
postRequest.ApiName = POST_REQUEST_ACTION
|
||||||
|
postRequest.Method = "POST"
|
||||||
|
mapTask := make(map[string]string)
|
||||||
|
mapTask[KEY_APP_KEY] = appKey
|
||||||
|
mapTask[KEY_FILE_LINK] = fileLink
|
||||||
|
// 新接入请使用4.0版本,已接入(默认2.0)如需维持现状,请注释掉该参数设置。
|
||||||
|
mapTask[KEY_VERSION] = "4.0"
|
||||||
|
// 设置是否输出词信息,默认为false。开启时需要设置version为4.0。
|
||||||
|
mapTask[KEY_ENABLE_WORDS] = "false"
|
||||||
|
mapTask["enable_sample_rate_adaptive"] = "true" //大于
|
||||||
|
task, err := json.Marshal(mapTask)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
postRequest.FormParams[KEY_TASK] = string(task)
|
||||||
|
postResponse, err := client.ProcessCommonRequest(postRequest)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
postResponseContent := postResponse.GetHttpContentString()
|
||||||
|
fmt.Println(postResponseContent)
|
||||||
|
if postResponse.GetHttpStatus() != 200 {
|
||||||
|
fmt.Println("录音文件识别请求失败,Http错误码: ", postResponse.GetHttpStatus())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var postMapResult map[string]interface{}
|
||||||
|
err = json.Unmarshal([]byte(postResponseContent), &postMapResult)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
var taskId string = ""
|
||||||
|
var statusText string = ""
|
||||||
|
statusText = postMapResult[KEY_STATUS_TEXT].(string)
|
||||||
|
if statusText == STATUS_SUCCESS {
|
||||||
|
fmt.Println("录音文件识别请求成功响应!")
|
||||||
|
taskId = postMapResult[KEY_TASK_ID].(string)
|
||||||
|
} else {
|
||||||
|
fmt.Println("录音文件识别请求失败!")
|
||||||
|
err = errors.New("录音文件识别请求失败")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
getRequest := requests.NewCommonRequest()
|
||||||
|
getRequest.Domain = DOMAIN
|
||||||
|
getRequest.Version = API_VERSION
|
||||||
|
getRequest.Product = PRODUCT
|
||||||
|
getRequest.ApiName = GET_REQUEST_ACTION
|
||||||
|
getRequest.Method = "GET"
|
||||||
|
getRequest.QueryParams[KEY_TASK_ID] = taskId
|
||||||
|
statusText = ""
|
||||||
|
|
||||||
|
for {
|
||||||
|
getResponse, err := client.ProcessCommonRequest(getRequest)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
getResponseContent := getResponse.GetHttpContentString()
|
||||||
|
fmt.Println("识别查询结果:", getResponseContent)
|
||||||
|
if getResponse.GetHttpStatus() != 200 {
|
||||||
|
fmt.Println("识别结果查询请求失败,Http错误码:", getResponse.GetHttpStatus())
|
||||||
|
break
|
||||||
|
}
|
||||||
|
var getMapResult map[string]interface{}
|
||||||
|
err = json.Unmarshal([]byte(getResponseContent), &getMapResult)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
statusText = getMapResult[KEY_STATUS_TEXT].(string)
|
||||||
|
if statusText == STATUS_RUNNING || statusText == STATUS_QUEUEING {
|
||||||
|
time.Sleep(10 * time.Second)
|
||||||
|
} else if statusText == STATUS_SUCCESS {
|
||||||
|
var resResult = getMapResult[KEY_RESULT].(map[string]interface{})
|
||||||
|
fmt.Println("result:", resResult["Sentences"].([]interface{}))
|
||||||
|
ss := resResult["Sentences"].([]interface{})
|
||||||
|
for _, seg := range ss {
|
||||||
|
item := seg.(map[string]interface{})
|
||||||
|
result += item["Text"].(string)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if statusText == STATUS_SUCCESS {
|
||||||
|
|
||||||
|
fmt.Println("录音文件识别成功!", result)
|
||||||
|
} else {
|
||||||
|
fmt.Println("录音文件识别失败!")
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
}
|
||||||
11
pkg/helper/AliAudio_test.go
Normal file
11
pkg/helper/AliAudio_test.go
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
package helper
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestTransAudioToText(t *testing.T) {
|
||||||
|
gotResult, err := TransAudioToText("https://check.dongdongdianjing.com/videos/20250606/d69960523fe2756076f1f8d7c37fa742.mp4")
|
||||||
|
fmt.Sprintf("%+v %+v", gotResult, err)
|
||||||
|
}
|
||||||
156
pkg/helper/Helper.go
Normal file
156
pkg/helper/Helper.go
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
package helper
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/md5"
|
||||||
|
"crypto/sha1"
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/hex"
|
||||||
|
"encoding/json"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"sort"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 生成header
|
||||||
|
func GenerateApiHeader(jsonBody string) map[string]string {
|
||||||
|
|
||||||
|
sign := GenerateSign(jsonBody)
|
||||||
|
|
||||||
|
headerMap := getCommonHeaderMap()
|
||||||
|
|
||||||
|
headerMap["Signature"] = sign
|
||||||
|
|
||||||
|
return headerMap
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据body生成签名
|
||||||
|
func GenerateSign(jsonBody string) string {
|
||||||
|
|
||||||
|
var mapRequest map[string]string
|
||||||
|
|
||||||
|
err := json.Unmarshal([]byte(jsonBody), &mapRequest)
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
commonHeaderMap := getCommonHeaderMap()
|
||||||
|
|
||||||
|
for k, v := range commonHeaderMap {
|
||||||
|
mapRequest[k] = v
|
||||||
|
}
|
||||||
|
sign := createSign(mapRequest)
|
||||||
|
return sign
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取公共的header字段
|
||||||
|
func getCommonHeaderMap() map[string]string {
|
||||||
|
|
||||||
|
headerMap := make(map[string]string, 0)
|
||||||
|
headerMap["ClientVersion"] = "1.0.1"
|
||||||
|
headerMap["DeviceId"] = "MWEB"
|
||||||
|
headerMap["Platform"] = "H5"
|
||||||
|
headerMap["MarketChannel"] = ""
|
||||||
|
headerMap["DeviceModel"] = "MWEB"
|
||||||
|
headerMap["ApiVersionNum"] = viper.GetString("api-num")
|
||||||
|
headerMap["TimeStamp"] = strconv.Itoa(time.Now().Second())
|
||||||
|
headerMap["BundleId"] = "meetalkH5"
|
||||||
|
headerMap["OsVersion"] = "10.01"
|
||||||
|
headerMap["INNER-TOKEN"] = "b028c52286c95de48a1c773d7ed02d04"
|
||||||
|
|
||||||
|
return headerMap
|
||||||
|
}
|
||||||
|
|
||||||
|
func createSign(params map[string]string) string {
|
||||||
|
|
||||||
|
keys := make([]string, 20)
|
||||||
|
|
||||||
|
for key, _ := range params {
|
||||||
|
if key == "Signature" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
keys = append(keys, key)
|
||||||
|
}
|
||||||
|
//按key升序
|
||||||
|
sort.Strings(keys)
|
||||||
|
|
||||||
|
//把KEY值合并为字符串
|
||||||
|
waitSignString := ""
|
||||||
|
for _, value := range keys {
|
||||||
|
|
||||||
|
waitSignString += base64.StdEncoding.EncodeToString([]byte(params[value]))
|
||||||
|
}
|
||||||
|
|
||||||
|
//加上密钥
|
||||||
|
appSecret := "x63363eacf804b4394a120aea240fd9a"
|
||||||
|
waitSignString += appSecret
|
||||||
|
|
||||||
|
//sha1加密
|
||||||
|
t := sha1.New()
|
||||||
|
io.WriteString(t, waitSignString)
|
||||||
|
sign := t.Sum(nil)
|
||||||
|
|
||||||
|
return hex.EncodeToString(sign)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 复杂http请求
|
||||||
|
func HttpDo(httpMethod string, url string, headerMap map[string]string, rawBody string) (remoteResponse string, err error) {
|
||||||
|
|
||||||
|
client := &http.Client{}
|
||||||
|
|
||||||
|
req, err0 := http.NewRequest(httpMethod, url, strings.NewReader(rawBody))
|
||||||
|
|
||||||
|
if err0 != nil {
|
||||||
|
|
||||||
|
err = err0
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(headerMap) > 0 {
|
||||||
|
for k, v := range headerMap {
|
||||||
|
req.Header.Set(k, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err1 := client.Do(req)
|
||||||
|
|
||||||
|
if err1 != nil {
|
||||||
|
err = err1
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
body, err2 := ioutil.ReadAll(resp.Body)
|
||||||
|
if err2 != nil {
|
||||||
|
err = err2
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
remoteResponse = string(body)
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func StringToMD5(waitMD5string string) string {
|
||||||
|
h := md5.New()
|
||||||
|
h.Write([]byte(waitMD5string))
|
||||||
|
cipherStr := h.Sum(nil)
|
||||||
|
result := hex.EncodeToString(cipherStr)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// SHA1加密
|
||||||
|
func StringToSHA1(waitMD5string string) string {
|
||||||
|
h := sha1.New()
|
||||||
|
h.Write([]byte(waitMD5string))
|
||||||
|
cipherStr := h.Sum(nil)
|
||||||
|
result := hex.EncodeToString(cipherStr)
|
||||||
|
return result
|
||||||
|
}
|
||||||
68
pkg/helper/NetHelper.go
Normal file
68
pkg/helper/NetHelper.go
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
package helper
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Url(url string) string {
|
||||||
|
return viper.GetString("service.host.api") + url
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发送GET请求
|
||||||
|
// url:请求地址
|
||||||
|
// response:请求返回的内容
|
||||||
|
func Get(url string) (response string) {
|
||||||
|
client := http.Client{Timeout: 30 * time.Second}
|
||||||
|
resp, e := client.Get(url)
|
||||||
|
if e != nil {
|
||||||
|
panic(e)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
var buffer [512]byte
|
||||||
|
result := bytes.NewBuffer(nil)
|
||||||
|
for {
|
||||||
|
n, err := resp.Body.Read(buffer[0:])
|
||||||
|
result.Write(buffer[0:n])
|
||||||
|
if err != nil && err == io.EOF {
|
||||||
|
break
|
||||||
|
} else if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
response = result.String()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发送POST请求
|
||||||
|
// url:请求地址,data:POST请求提交的数据,contentType:请求体格式,如:application/json
|
||||||
|
// response:请求返回的内容
|
||||||
|
func Post(url string, data interface{}, header map[string]string) (response string) {
|
||||||
|
jsonStr, _ := json.Marshal(data)
|
||||||
|
req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonStr))
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
req.Header.Add("content-type", "application/json")
|
||||||
|
for key := range header {
|
||||||
|
req.Header.Add(key, header[key])
|
||||||
|
}
|
||||||
|
defer req.Body.Close()
|
||||||
|
|
||||||
|
client := &http.Client{Timeout: 30 * time.Second}
|
||||||
|
resp, err := client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
result, _ := ioutil.ReadAll(resp.Body)
|
||||||
|
response = string(result)
|
||||||
|
return
|
||||||
|
}
|
||||||
371
pkg/helper/NumberHelper.go
Normal file
371
pkg/helper/NumberHelper.go
Normal file
@ -0,0 +1,371 @@
|
|||||||
|
package helper
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"github.com/anxpp/beego/logs"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type NumberInfo struct {
|
||||||
|
Level int
|
||||||
|
Rule map[string]bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算号码的登记
|
||||||
|
func Calc(src int64) NumberInfo {
|
||||||
|
level := 0
|
||||||
|
rule := make(map[string]bool)
|
||||||
|
number := strconv.FormatInt(src, 10)
|
||||||
|
length := len(number)
|
||||||
|
// 尾号AAA
|
||||||
|
checkEndAAA := length >= 3 && number[length-1] == number[length-2] && number[length-2] == number[length-3]
|
||||||
|
if checkEndAAA {
|
||||||
|
level++
|
||||||
|
}
|
||||||
|
rule["EndAAA"] = checkEndAAA
|
||||||
|
// 尾号ABAB
|
||||||
|
checkABAB := length >= 4 && number[length-4] == number[length-2] && number[length-3] == number[length-1]
|
||||||
|
if checkABAB {
|
||||||
|
level++
|
||||||
|
}
|
||||||
|
rule["EndABAB"] = checkABAB
|
||||||
|
// 尾号AABB
|
||||||
|
checkAABB := length >= 4 && number[length-4] == number[length-3] && number[length-2] == number[length-1]
|
||||||
|
if checkAABB {
|
||||||
|
level++
|
||||||
|
}
|
||||||
|
rule["EndAABB"] = checkAABB
|
||||||
|
// 520
|
||||||
|
check520 := strings.HasSuffix(number, "520")
|
||||||
|
if check520 {
|
||||||
|
level++
|
||||||
|
}
|
||||||
|
rule["520"] = check520
|
||||||
|
// 1314
|
||||||
|
check1314 := strings.HasSuffix(number, "1314")
|
||||||
|
if check1314 {
|
||||||
|
level++
|
||||||
|
}
|
||||||
|
rule["1314"] = check1314
|
||||||
|
// 5201314
|
||||||
|
check5201314 := strings.HasSuffix(number, "5201314")
|
||||||
|
if check5201314 {
|
||||||
|
level++
|
||||||
|
}
|
||||||
|
rule["5201314"] = check5201314
|
||||||
|
// AAA
|
||||||
|
checkAAA := _checkRepeat(number, 3)
|
||||||
|
if checkAAA {
|
||||||
|
level++
|
||||||
|
}
|
||||||
|
rule["AAA"] = checkAAA
|
||||||
|
// AAAA
|
||||||
|
checkAAAA := _checkRepeat(number, 4)
|
||||||
|
if checkAAAA {
|
||||||
|
level++
|
||||||
|
}
|
||||||
|
rule["AAAA"] = checkAAAA
|
||||||
|
// AAAAA
|
||||||
|
checkAAAAA := _checkRepeat(number, 5)
|
||||||
|
if checkAAAAA {
|
||||||
|
level++
|
||||||
|
level++
|
||||||
|
}
|
||||||
|
rule["AAAAA"] = checkAAAAA
|
||||||
|
// AAAAAA
|
||||||
|
checkAAAAAA := _checkRepeat(number, 6)
|
||||||
|
if checkAAAAAA {
|
||||||
|
level++
|
||||||
|
}
|
||||||
|
rule["AAAAAA"] = checkAAAAAA
|
||||||
|
// AAAAAAA
|
||||||
|
checkAAAAAAA := _checkRepeat(number, 7)
|
||||||
|
if checkAAAAAAA {
|
||||||
|
level++
|
||||||
|
}
|
||||||
|
rule["AAAAAAA"] = checkAAAAAAA
|
||||||
|
// AAAAAAA
|
||||||
|
checkAAAAAAAA := _checkRepeat(number, 8)
|
||||||
|
if checkAAAAAAAA {
|
||||||
|
level++
|
||||||
|
}
|
||||||
|
rule["AAAAAAAA"] = checkAAAAAAAA
|
||||||
|
// ABCABC
|
||||||
|
checkABCABC := _checkABCABC(number)
|
||||||
|
if checkABCABC {
|
||||||
|
level++
|
||||||
|
}
|
||||||
|
rule["ABCABC"] = checkABCABC
|
||||||
|
// AABBCC
|
||||||
|
checkAABBCC := _checkAABBCC(number)
|
||||||
|
if checkAABBCC {
|
||||||
|
level++
|
||||||
|
}
|
||||||
|
rule["AABBCC"] = checkAABBCC
|
||||||
|
// ABABAB
|
||||||
|
checkABABAB := _checkABABAB(number)
|
||||||
|
if checkABABAB {
|
||||||
|
level++
|
||||||
|
}
|
||||||
|
rule["ABABAB"] = checkABABAB
|
||||||
|
// AAABBB
|
||||||
|
checkAAABBB := _checkAAABBB(number)
|
||||||
|
if checkAAABBB {
|
||||||
|
level++
|
||||||
|
}
|
||||||
|
rule["AAABBB"] = checkAAABBB
|
||||||
|
// ABBABB
|
||||||
|
checkABBABB := _checkABBABB(number)
|
||||||
|
if checkABBABB {
|
||||||
|
level++
|
||||||
|
}
|
||||||
|
rule["ABBABB"] = checkABBABB
|
||||||
|
// ABBCBB
|
||||||
|
checkABBCBB := _checkABBCBB(number)
|
||||||
|
if checkABBCBB {
|
||||||
|
level++
|
||||||
|
}
|
||||||
|
rule["ABBCBB"] = checkABBCBB
|
||||||
|
// BBCBBA
|
||||||
|
checkBBCBBA := _checkBBCBBA(number)
|
||||||
|
if checkBBCBBA {
|
||||||
|
level++
|
||||||
|
}
|
||||||
|
rule["BBCBBA"] = checkBBCBBA
|
||||||
|
// AABAAB
|
||||||
|
checkAABAAB := _checkAABAAB(number)
|
||||||
|
if checkAABAAB {
|
||||||
|
level++
|
||||||
|
}
|
||||||
|
rule["AABAAB"] = checkAABAAB
|
||||||
|
// 102030
|
||||||
|
check102030 := _check102030(number)
|
||||||
|
if check102030 {
|
||||||
|
level++
|
||||||
|
}
|
||||||
|
rule["102030"] = check102030
|
||||||
|
// 010203
|
||||||
|
check010203 := _check010203(number)
|
||||||
|
if check010203 {
|
||||||
|
level++
|
||||||
|
}
|
||||||
|
rule["010203"] = check010203
|
||||||
|
// AABBB
|
||||||
|
checkAABBB := _checkAABBB(number)
|
||||||
|
if checkAABBB {
|
||||||
|
level++
|
||||||
|
}
|
||||||
|
rule["AABBB"] = checkAABBB
|
||||||
|
// 123
|
||||||
|
check123 := _checkIncrease(number, 3)
|
||||||
|
if check123 {
|
||||||
|
level++
|
||||||
|
}
|
||||||
|
rule["123"] = check123
|
||||||
|
// 123
|
||||||
|
check1234 := _checkIncrease(number, 4)
|
||||||
|
if check1234 {
|
||||||
|
level++
|
||||||
|
}
|
||||||
|
rule["1234"] = check1234
|
||||||
|
// 123
|
||||||
|
check12345 := _checkIncrease(number, 5)
|
||||||
|
if check12345 {
|
||||||
|
level++
|
||||||
|
}
|
||||||
|
rule["12345"] = check12345
|
||||||
|
// 123
|
||||||
|
check123456 := _checkIncrease(number, 6)
|
||||||
|
if check123456 {
|
||||||
|
level++
|
||||||
|
}
|
||||||
|
rule["123456"] = check123456
|
||||||
|
// 123
|
||||||
|
check1234567 := _checkIncrease(number, 7)
|
||||||
|
if check1234567 {
|
||||||
|
level++
|
||||||
|
}
|
||||||
|
rule["1234567"] = check1234567
|
||||||
|
info := NumberInfo{level, rule}
|
||||||
|
bytes, _ := json.Marshal(info)
|
||||||
|
if src%100000 == 0 {
|
||||||
|
logs.Info(number + ": " + string(bytes))
|
||||||
|
}
|
||||||
|
return info
|
||||||
|
}
|
||||||
|
|
||||||
|
func _checkRepeat(number string, length int) bool {
|
||||||
|
count := 1
|
||||||
|
old := ' '
|
||||||
|
for _, ch := range number {
|
||||||
|
if ch == old {
|
||||||
|
count++
|
||||||
|
if count == length {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
old = ch
|
||||||
|
count = 1
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func _checkIncrease(number string, length int) bool {
|
||||||
|
count := 0
|
||||||
|
old := ' '
|
||||||
|
for _, ch := range number {
|
||||||
|
if count <= 0 {
|
||||||
|
count++
|
||||||
|
if count == length {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
old = ch
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if ch == old+1 {
|
||||||
|
count++
|
||||||
|
if count == length {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
old = ch
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
old = ch
|
||||||
|
count = 0
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func _checkABCABC(number string) bool {
|
||||||
|
length := len(number)
|
||||||
|
if length >= 6 {
|
||||||
|
for i := 3; i < length-2; i++ {
|
||||||
|
if number[i-3] == number[i] && number[i-2] == number[i+1] && number[i-1] == number[i+2] {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func _checkABBABB(number string) bool {
|
||||||
|
length := len(number)
|
||||||
|
if length >= 6 {
|
||||||
|
for i := 3; i < length-2; i++ {
|
||||||
|
if number[i-3] == number[i] && number[i-2] == number[i+1] && number[i-1] == number[i+2] && number[i-2] == number[i-1] {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func _checkABBCBB(number string) bool {
|
||||||
|
length := len(number)
|
||||||
|
if length >= 6 {
|
||||||
|
for i := 3; i < length-2; i++ {
|
||||||
|
if number[i-2] == number[i-1] && number[i-1] == number[i+1] && number[i+1] == number[i+2] {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func _checkBBCBBA(number string) bool {
|
||||||
|
length := len(number)
|
||||||
|
if length >= 6 {
|
||||||
|
for i := 3; i < length-2; i++ {
|
||||||
|
if number[i-3] == number[i-2] && number[i-2] == number[i] && number[i] == number[i+1] {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func _checkAABAAB(number string) bool {
|
||||||
|
length := len(number)
|
||||||
|
if length >= 6 {
|
||||||
|
for i := 3; i < length-2; i++ {
|
||||||
|
if number[i-3] == number[i] && number[i-3] == number[i-2] && number[i-2] == number[i+1] && number[i-1] == number[i+2] {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func _check102030(number string) bool {
|
||||||
|
length := len(number)
|
||||||
|
if length >= 6 {
|
||||||
|
for i := 3; i < length-2; i++ {
|
||||||
|
if number[i-2] == number[i] && number[i] == number[i+2] && number[i-3]-number[i-1] == number[i-1]-number[i+1] {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func _check010203(number string) bool {
|
||||||
|
length := len(number)
|
||||||
|
if length >= 6 {
|
||||||
|
for i := 3; i < length-2; i++ {
|
||||||
|
if number[i-2]-number[i] == number[i]-number[i+2] && number[i-3] == number[i-1] && number[i-1] == number[i+1] {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func _checkAABBCC(number string) bool {
|
||||||
|
length := len(number)
|
||||||
|
if length >= 6 {
|
||||||
|
for i := 3; i < length-2; i++ {
|
||||||
|
if number[i-3] == number[i-2] && number[i-1] == number[i] && number[i+1] == number[i+2] {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func _checkABABAB(number string) bool {
|
||||||
|
length := len(number)
|
||||||
|
if length >= 6 {
|
||||||
|
for i := 3; i < length-2; i++ {
|
||||||
|
if number[i-3] == number[i-1] && number[i-1] == number[i+1] && number[i-2] == number[i] && number[i] == number[i+2] {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func _checkAAABBB(number string) bool {
|
||||||
|
length := len(number)
|
||||||
|
if length >= 6 {
|
||||||
|
for i := 3; i < length-2; i++ {
|
||||||
|
if number[i-3] == number[i-2] && number[i-2] == number[i-1] && number[i] == number[i+1] && number[i+1] == number[i+2] {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func _checkAABBB(number string) bool {
|
||||||
|
length := len(number)
|
||||||
|
if length >= 5 {
|
||||||
|
for i := 3; i < length-2; i++ {
|
||||||
|
if number[i-3] == number[i-2] && number[i-1] == number[i] && number[i] == number[i+1] {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
85
pkg/helper/QiNiuHelper.go
Normal file
85
pkg/helper/QiNiuHelper.go
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
package helper
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/base64"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/anxpp/beego/logs"
|
||||||
|
"github.com/qiniu/go-sdk/v7/auth"
|
||||||
|
"github.com/qiniu/go-sdk/v7/storage"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
)
|
||||||
|
|
||||||
|
//{"id":"z0.0A2234420A3600F3365DD1FA282B440D","pipeline":"1381904061.XZVideoToImagesQueue","code":0,
|
||||||
|
// "desc":"The fop was completed successfully","reqid":"Ry0AAMB45er_HtgV","inputBucket":"media","inputKey":"shot/xingzuan_appstore_video.mp4_000001.jpg",
|
||||||
|
// "items":[{"cmd":"animate/duration/5/merge/key/c2hvdC94aW5nenVhbl9hcHBzdG9yZV92aWRlby5tcDRfMDAwMDAyLmpwZw==/key/c2hvdC94aW5nenVhbl9hcHBzdG9yZV92aWRlby5tcDRfMDAwMDAzLmpwZw==/key/c2hvdC94aW5nenVhbl9hcHBzdG9yZV92aWRlby5tcDRfMDAwMDA0LmpwZw==/key/c2hvdC94aW5nenVhbl9hcHBzdG9yZV92aWRlby5tcDRfMDAwMDA1LmpwZw==/key/c2hvdC94aW5nenVhbl9hcHBzdG9yZV92aWRlby5tcDRfMDAwMDA2LmpwZw==/key/c2hvdC94aW5nenVhbl9hcHBzdG9yZV92aWRlby5tcDRfMDAwMDA3LmpwZw==/key/c2hvdC94aW5nenVhbl9hcHBzdG9yZV92aWRlby5tcDRfMDAwMDA4LmpwZw==/key/c2hvdC94aW5nenVhbl9hcHBzdG9yZV92aWRlby5tcDRfMDAwMDA5LmpwZw==/key/c2hvdC94aW5nenVhbl9hcHBzdG9yZV92aWRlby5tcDRfMDAwMDEwLmpwZw==/key/c2hvdC94aW5nenVhbl9hcHBzdG9yZV92aWRlby5tcDRfMDAwMDExLmpwZw==/key/c2hvdC94aW5nenVhbl9hcHBzdG9yZV92aWRlby5tcDRfMDAwMDEyLmpwZw==/key/c2hvdC94aW5nenVhbl9hcHBzdG9yZV92aWRlby5tcDRfMDAwMDEzLmpwZw==/key/c2hvdC94aW5nenVhbl9hcHBzdG9yZV92aWRlby5tcDRfMDAwMDE0LmpwZw==/key/c2hvdC94aW5nenVhbl9hcHBzdG9yZV92aWRlby5tcDRfMDAwMDE1LmpwZw==/key/c2hvdC94aW5nenVhbl9hcHBzdG9yZV92aWRlby5tcDRfMDAwMDE2LmpwZw==/key/c2hvdC94aW5nenVhbl9hcHBzdG9yZV92aWRlby5tcDRfMDAwMDE3LmpwZw==/key/c2hvdC94aW5nenVhbl9hcHBzdG9yZV92aWRlby5tcDRfMDAwMDE4LmpwZw==/key/c2hvdC94aW5nenVhbl9hcHBzdG9yZV92aWRlby5tcDRfMDAwMDE5LmpwZw==/key/c2hvdC94aW5nenVhbl9hcHBzdG9yZV92aWRlby5tcDRfMDAwMDIwLmpwZw==/effect/0",
|
||||||
|
// "code":0,"desc":"The fop was completed successfully","hash":"lmW7N4-x40al165ufZj2SJGbut6L","key":"-KqubldLD_opMcwnpcOJ2FOml7M=/Ftq7oAVtIsQ-hOdz1amflU4f0mxO","returnOld":0}]}
|
||||||
|
|
||||||
|
type QiNiuVideoToImagesParam struct {
|
||||||
|
Id string `json:"id"`
|
||||||
|
Pipeline string `json:"pipeline"`
|
||||||
|
Code int `json:"code"`
|
||||||
|
Desc string `json:"desc"`
|
||||||
|
Reqid string `json:"reqid"`
|
||||||
|
InputBucket string `json:"inputBucket"`
|
||||||
|
InputKey string `json:"inputKey"`
|
||||||
|
Items []QiNiuVideoToImagesParamItem `json:"items"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type QiNiuVideoToImagesParamItem struct {
|
||||||
|
Cmd string `json:"cmd"`
|
||||||
|
Code int `json:"code"`
|
||||||
|
Desc string `json:"desc"`
|
||||||
|
Keys []string `json:"keys"`
|
||||||
|
Key string `json:"key"`
|
||||||
|
Hash string `json:"hash"`
|
||||||
|
ReturnOld int `json:"returnOld"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取视频抽帧的token
|
||||||
|
// 第2秒开始,每秒10张,抽20张
|
||||||
|
func QiNiuVideoToImages(key string) (persistentId string) {
|
||||||
|
|
||||||
|
mac := auth.New(viper.GetString("qiniu.key"), viper.GetString("qiniu.secret"))
|
||||||
|
cfg := storage.Config{UseHTTPS: true}
|
||||||
|
operationManager := storage.NewOperationManager(mac, &cfg)
|
||||||
|
saveBucket := "dddjmedia"
|
||||||
|
// 处理指令集合
|
||||||
|
// vsample/<Format>/ss/<StartTime>/t/<Duration>/s/<Resolution>/rotate/<Degree>/interval/<Interval>/pattern/<Pattern>
|
||||||
|
// /ss/<StartTime> 是 指定截取视频的开始时刻,单位:秒,精度为 100ms。例如 /ss/1.1
|
||||||
|
// /t/<Duration> 是 采样总时长,单位:秒,精度为 100ms。例如 t/1.1
|
||||||
|
// /s/<Resolution> 缩略图分辨率,单位:像素(px),格式:<Width>x<Height>,宽度取值范围为1-1920,高度取值范围为1-1080。 默认为原始视频分辨率。
|
||||||
|
// /rotate/<Degree> 指定顺时针旋转的度数,可取值为90、180、270、auto。 默认为不旋转。
|
||||||
|
// /interval/<Interval> 指定采样间隔,单元:秒。 默认为5秒,精度为 100ms,例如/interval/0.1
|
||||||
|
// /pattern/<Pattern> 是 指定各张截图的资源名格式,支持如下魔法变量: $(count) :六个占位符的数字串,不足位的填充前导零即%06d,如 000001
|
||||||
|
fopVSample := fmt.Sprintf("vsample/png/ss/2/t/2/interval/0.1/pattern/%s", base64.URLEncoding.EncodeToString([]byte("shot/"+key+"_$(count).jpg")))
|
||||||
|
fopBatch := []string{fopVSample}
|
||||||
|
fops := strings.Join(fopBatch, ";")
|
||||||
|
persistentId, err := operationManager.Pfop(saveBucket, key, fops, "FYVideoToImagesQueue", viper.GetString("open.notify.qiniuVideoShot"), true)
|
||||||
|
if err != nil {
|
||||||
|
logs.Error(err.Error(), " ", persistentId, "", key)
|
||||||
|
}
|
||||||
|
return persistentId
|
||||||
|
}
|
||||||
|
|
||||||
|
func QiNiuImagesToGif(keys []string) (persistentId string) {
|
||||||
|
mac := auth.New(viper.GetString("qiniu.key"), viper.GetString("qiniu.secret"))
|
||||||
|
cfg := storage.Config{UseHTTPS: true}
|
||||||
|
operationManager := storage.NewOperationManager(mac, &cfg)
|
||||||
|
saveBucket := "dddjmedia"
|
||||||
|
an := "animate/duration/5/merge"
|
||||||
|
for i := 1; i < len(keys); i++ {
|
||||||
|
an += "/key/" + base64.URLEncoding.EncodeToString([]byte(keys[i]))
|
||||||
|
}
|
||||||
|
an += "/effect/0"
|
||||||
|
logs.Info("result of img merge", an)
|
||||||
|
fopBatch := []string{an}
|
||||||
|
fops := strings.Join(fopBatch, ";")
|
||||||
|
persistentId, err := operationManager.Pfop(saveBucket, keys[0], fops, "FYVideoToImagesQueue", viper.GetString("open.notify.qiniuImgMergeShot"), true)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
logs.Error(err.Error())
|
||||||
|
}
|
||||||
|
return persistentId
|
||||||
|
}
|
||||||
13
pkg/helper/WxHelper.go
Normal file
13
pkg/helper/WxHelper.go
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
package helper
|
||||||
|
|
||||||
|
import "strings"
|
||||||
|
|
||||||
|
//是否使用微信打开
|
||||||
|
func IsWeiXinBrowser(httpUserAgent string) bool {
|
||||||
|
wxAgentKey := "MicroMessenger"
|
||||||
|
|
||||||
|
if strings.Contains(httpUserAgent, wxAgentKey) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
23
pkg/helper/passwordHelper.go
Normal file
23
pkg/helper/passwordHelper.go
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
package helper
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/md5"
|
||||||
|
"encoding/hex"
|
||||||
|
"math/rand"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 获取随机盐值
|
||||||
|
func PasswordSalt() string {
|
||||||
|
randInt := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||||
|
return strconv.Itoa(randInt.Int() % 10000)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算加密后的密码
|
||||||
|
func PasswordWithMd5(password, salt string) string {
|
||||||
|
h := md5.New()
|
||||||
|
h.Write([]byte(password + salt))
|
||||||
|
cipherStr := h.Sum(nil)
|
||||||
|
return hex.EncodeToString(cipherStr)
|
||||||
|
}
|
||||||
144
pkg/helper/string_util.go
Normal file
144
pkg/helper/string_util.go
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
package helper
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/md5"
|
||||||
|
"encoding/hex"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"regexp"
|
||||||
|
"sort"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
PhotoDomainUrl = "https://photo-app.ddegame.cn/"
|
||||||
|
TimeLayout = "2006-01-02 15:04:05"
|
||||||
|
DateLayout = "2006-01-02"
|
||||||
|
DateLayoutShort = "20060102"
|
||||||
|
)
|
||||||
|
|
||||||
|
func FullPhotoUrl(path string) string {
|
||||||
|
if len(path) == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
if strings.Index(path, "http") == 0 {
|
||||||
|
return path
|
||||||
|
}
|
||||||
|
return PhotoDomainUrl + path
|
||||||
|
}
|
||||||
|
|
||||||
|
func Md5ForList(s ...string) string {
|
||||||
|
sort.Strings(s)
|
||||||
|
h := md5.New()
|
||||||
|
h.Write([]byte(strings.Join(s, "")))
|
||||||
|
return hex.EncodeToString(h.Sum(nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
func StringToInt(source string) int {
|
||||||
|
target, _ := strconv.Atoi(source)
|
||||||
|
return target
|
||||||
|
}
|
||||||
|
|
||||||
|
func StringToInt64(source string) int64 {
|
||||||
|
target, _ := strconv.Atoi(source)
|
||||||
|
return int64(target)
|
||||||
|
}
|
||||||
|
|
||||||
|
func StringToFloat(source string) float64 {
|
||||||
|
target, _ := strconv.ParseFloat(source, 64)
|
||||||
|
return target
|
||||||
|
}
|
||||||
|
|
||||||
|
func StringIntPlus(s1, s2 string) string {
|
||||||
|
return strconv.Itoa(StringToInt(s1) + StringToInt(s2))
|
||||||
|
}
|
||||||
|
|
||||||
|
func StringIntMultiply(s1, s2 string) string {
|
||||||
|
return strconv.Itoa(StringToInt(s1) * StringToInt(s2))
|
||||||
|
}
|
||||||
|
|
||||||
|
func StringIntSub(s1, s2 string) string {
|
||||||
|
return strconv.Itoa(StringToInt(s1) - StringToInt(s2))
|
||||||
|
}
|
||||||
|
|
||||||
|
func StringFloatSub(s1, s2 string) string {
|
||||||
|
return strconv.FormatFloat(StringToFloat(s1)-StringToFloat(s2), 'f', -1, 64)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ListToSet(list []string) (set []string) {
|
||||||
|
m := make(map[string]bool, 0)
|
||||||
|
for i := range list {
|
||||||
|
m[list[i]] = true
|
||||||
|
}
|
||||||
|
for k := range m {
|
||||||
|
set = append(set, k)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func ToJson(source interface{}) []byte {
|
||||||
|
b, _ := json.Marshal(source)
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func NowTimeToString() string {
|
||||||
|
return time.Now().Format(TimeLayout)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NowTimeIncreaseString(t time.Duration) string {
|
||||||
|
now := time.Now()
|
||||||
|
now.Add(t)
|
||||||
|
return now.Format(TimeLayout)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NowDateToString() string {
|
||||||
|
return time.Now().Format(DateLayout)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NowDateToStringShort() string {
|
||||||
|
return time.Now().Format(DateLayoutShort)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Md5(s string) string {
|
||||||
|
h := md5.New()
|
||||||
|
h.Write([]byte(s))
|
||||||
|
return hex.EncodeToString(h.Sum(nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
func ZeroFillByStr(str string, resultLen int, reverse bool) string {
|
||||||
|
if len(str) > resultLen || resultLen <= 0 {
|
||||||
|
return str
|
||||||
|
}
|
||||||
|
if reverse {
|
||||||
|
return fmt.Sprintf("%0*s", resultLen, str) //不足前置补零
|
||||||
|
}
|
||||||
|
result := str
|
||||||
|
for i := 0; i < resultLen-len(str); i++ {
|
||||||
|
result += "0"
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsMobile(no string) bool {
|
||||||
|
return regexp.MustCompile("^1[3456789]\\d{9}$").MatchString(no)
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsEmail(email string) bool {
|
||||||
|
pattern := `^[0-9a-z][_.0-9a-z-]{0,31}@([0-9a-z][0-9a-z-]{0,30}[0-9a-z]\.){1,4}[a-z]{2,4}$`
|
||||||
|
return regexp.MustCompile(pattern).MatchString(email)
|
||||||
|
}
|
||||||
|
|
||||||
|
func LegalUsername(source string) bool {
|
||||||
|
return regexp.MustCompile("^\\D[\\w-]{5,17}$").MatchString(source)
|
||||||
|
}
|
||||||
|
|
||||||
|
func LegalShortUsername(source string) bool {
|
||||||
|
return regexp.MustCompile("^[a-zA-Z][\\w-]{2,17}$").MatchString(source)
|
||||||
|
}
|
||||||
|
|
||||||
|
func LegalPassword(source string) bool {
|
||||||
|
return regexp.MustCompile("^[a-zA-Z0-9,.!@#$%^&*()_-]{6,18}$").MatchString(source)
|
||||||
|
}
|
||||||
71
pkg/htools/HttpClient.go
Normal file
71
pkg/htools/HttpClient.go
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
package htools
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 调用POST请求
|
||||||
|
func HttpPost(url string, body string) (remoteResponse string, err error) {
|
||||||
|
|
||||||
|
bodyReader := strings.NewReader(body)
|
||||||
|
//application/x-www-form-urlencoded
|
||||||
|
//application/json
|
||||||
|
response, err1 := http.Post(url, "application/x-www-form-urlencoded", bodyReader)
|
||||||
|
|
||||||
|
if err1 != nil {
|
||||||
|
err = err1
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer response.Body.Close()
|
||||||
|
|
||||||
|
resBody, err2 := ioutil.ReadAll(response.Body)
|
||||||
|
|
||||||
|
if err2 != nil {
|
||||||
|
err = err2
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
remoteResponse = string(resBody)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 复杂http请求
|
||||||
|
func HttpDo(httpMethod string, url string, headerMap map[string]string, rawBody string) (remoteResponse string, err error) {
|
||||||
|
|
||||||
|
client := &http.Client{}
|
||||||
|
|
||||||
|
req, err0 := http.NewRequest(httpMethod, url, strings.NewReader(rawBody))
|
||||||
|
|
||||||
|
if err0 != nil {
|
||||||
|
err = err0
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(headerMap) > 0 {
|
||||||
|
for k, v := range headerMap {
|
||||||
|
req.Header.Set(k, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err1 := client.Do(req)
|
||||||
|
|
||||||
|
if err1 != nil {
|
||||||
|
err = err1
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
body, err2 := ioutil.ReadAll(resp.Body)
|
||||||
|
if err2 != nil {
|
||||||
|
err = err2
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
remoteResponse = string(body)
|
||||||
|
return
|
||||||
|
|
||||||
|
}
|
||||||
47
pkg/htools/Random.go
Normal file
47
pkg/htools/Random.go
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
package htools
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/rand"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetVericode() string {
|
||||||
|
|
||||||
|
result := RandNumber()
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func RandInt64(min, max int64) int64 {
|
||||||
|
if min >= max || min == 0 || max == 0 {
|
||||||
|
return max
|
||||||
|
}
|
||||||
|
return rand.Int63n(max-min) + min
|
||||||
|
}
|
||||||
|
|
||||||
|
func RandNumber() string {
|
||||||
|
|
||||||
|
str := "0123456789"
|
||||||
|
bytes := []byte(str)
|
||||||
|
result := []byte{}
|
||||||
|
r := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||||
|
for i := 0; i < 4; i++ {
|
||||||
|
result = append(result, bytes[r.Intn(len(bytes))])
|
||||||
|
}
|
||||||
|
return string(result)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成随机字符串
|
||||||
|
func GetRandomString(l int) string {
|
||||||
|
|
||||||
|
str := "0123456789abcdefghijklmnopqrstuvwxyz"
|
||||||
|
bytes := []byte(str)
|
||||||
|
result := []byte{}
|
||||||
|
r := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||||
|
for i := 0; i < l; i++ {
|
||||||
|
result = append(result, bytes[r.Intn(len(bytes))])
|
||||||
|
}
|
||||||
|
return string(result)
|
||||||
|
}
|
||||||
146
pkg/htools/RsaUtils.go
Normal file
146
pkg/htools/RsaUtils.go
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
package htools
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto"
|
||||||
|
"crypto/rand"
|
||||||
|
"crypto/rsa"
|
||||||
|
"crypto/sha1"
|
||||||
|
"crypto/x509"
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/pem"
|
||||||
|
"errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RSA加密
|
||||||
|
func RsaEncrypt(origData string, publicKey string) (string, error) {
|
||||||
|
|
||||||
|
block, _ := pem.Decode([]byte(publicKey)) // 将密钥解析成公钥实例
|
||||||
|
if block == nil {
|
||||||
|
return "", errors.New("public key error")
|
||||||
|
}
|
||||||
|
|
||||||
|
pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes) // 解析pem.Decode()返回的Block指针实例
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
pub := pubInterface.(*rsa.PublicKey)
|
||||||
|
|
||||||
|
partLen := pub.N.BitLen()/8 - 11
|
||||||
|
|
||||||
|
chunks := ByteSplit([]byte(origData), partLen)
|
||||||
|
|
||||||
|
buffer := bytes.NewBufferString("")
|
||||||
|
|
||||||
|
for _, chunk := range chunks {
|
||||||
|
|
||||||
|
bytes, err := rsa.EncryptPKCS1v15(rand.Reader, pub, chunk)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer.Write(bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
return base64.StdEncoding.EncodeToString(buffer.Bytes()), nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// RSA解密
|
||||||
|
func RsaDecrypt(ciphertext string, privateKey string) (string, error) {
|
||||||
|
|
||||||
|
block, _ := pem.Decode([]byte(privateKey))
|
||||||
|
|
||||||
|
if block == nil {
|
||||||
|
|
||||||
|
return "", errors.New("private key error!")
|
||||||
|
}
|
||||||
|
priv, err := x509.ParsePKCS1PrivateKey(block.Bytes)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
partLen := priv.N.BitLen() / 8
|
||||||
|
|
||||||
|
raw, err := base64.StdEncoding.DecodeString(ciphertext)
|
||||||
|
|
||||||
|
chunks := ByteSplit([]byte(raw), partLen)
|
||||||
|
|
||||||
|
buffer := bytes.NewBufferString("")
|
||||||
|
|
||||||
|
for _, chunk := range chunks {
|
||||||
|
|
||||||
|
decrypted, err := rsa.DecryptPKCS1v15(rand.Reader, priv, chunk)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
|
||||||
|
return "", err
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer.Write(decrypted)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return buffer.String(), err
|
||||||
|
}
|
||||||
|
|
||||||
|
// RSA SHA1加签
|
||||||
|
func RsaSHA1Sign(data string, privateKey string) (string, error) {
|
||||||
|
|
||||||
|
block, _ := pem.Decode([]byte(privateKey))
|
||||||
|
if block == nil {
|
||||||
|
return "", errors.New("Sign private key decode error")
|
||||||
|
}
|
||||||
|
|
||||||
|
prk8, err := x509.ParsePKCS1PrivateKey(block.Bytes)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
h := sha1.New()
|
||||||
|
h.Write([]byte(data))
|
||||||
|
hashed := h.Sum(nil)
|
||||||
|
|
||||||
|
sign, err := rsa.SignPKCS1v15(rand.Reader, prk8, crypto.SHA1, hashed)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return base64.StdEncoding.EncodeToString(sign), err
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// RSA SHA1验签
|
||||||
|
func RsaSHA1Verify(data string, sign string, publicKey string) error {
|
||||||
|
|
||||||
|
h := sha1.New()
|
||||||
|
h.Write([]byte(data))
|
||||||
|
hashed := h.Sum(nil)
|
||||||
|
|
||||||
|
decodedSign, err := base64.StdEncoding.DecodeString(sign)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
|
||||||
|
return err
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
block, _ := pem.Decode([]byte(publicKey))
|
||||||
|
if block == nil {
|
||||||
|
return errors.New("Sign public key decode error")
|
||||||
|
}
|
||||||
|
|
||||||
|
pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes) // 解析pem.Decode()返回的Block指针实例
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
pub := pubInterface.(*rsa.PublicKey)
|
||||||
|
|
||||||
|
return rsa.VerifyPKCS1v15(pub, crypto.SHA1, hashed, decodedSign)
|
||||||
|
|
||||||
|
}
|
||||||
23
pkg/htools/StringBuilder.go
Normal file
23
pkg/htools/StringBuilder.go
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
package htools
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
type StringBuilder struct {
|
||||||
|
buf bytes.Buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewStringBuilder() *StringBuilder {
|
||||||
|
return &StringBuilder{buf: bytes.Buffer{}}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *StringBuilder) Append(obj interface{}) *StringBuilder {
|
||||||
|
this.buf.WriteString(fmt.Sprintf("%v", obj))
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *StringBuilder) ToString() string {
|
||||||
|
return this.buf.String()
|
||||||
|
}
|
||||||
335
pkg/htools/Tools.go
Normal file
335
pkg/htools/Tools.go
Normal file
@ -0,0 +1,335 @@
|
|||||||
|
package htools
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/hmac"
|
||||||
|
"crypto/md5"
|
||||||
|
"crypto/sha1"
|
||||||
|
"encoding/hex"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"math/rand"
|
||||||
|
"reflect"
|
||||||
|
"sort"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MD5加密
|
||||||
|
func StringToMD5(waitMD5string string) string {
|
||||||
|
|
||||||
|
h := md5.New()
|
||||||
|
h.Write([]byte(waitMD5string))
|
||||||
|
cipherStr := h.Sum(nil)
|
||||||
|
|
||||||
|
result := hex.EncodeToString(cipherStr)
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// SHA1加密
|
||||||
|
func StringToSHA1(waitMD5string string) string {
|
||||||
|
|
||||||
|
h := sha1.New()
|
||||||
|
h.Write([]byte(waitMD5string))
|
||||||
|
cipherStr := h.Sum(nil)
|
||||||
|
|
||||||
|
result := hex.EncodeToString(cipherStr)
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// HMAC SHA1
|
||||||
|
func StringToHmacSha1(waitShaString, keyStr string) string {
|
||||||
|
|
||||||
|
key := []byte(keyStr)
|
||||||
|
mac := hmac.New(sha1.New, key)
|
||||||
|
mac.Write([]byte(waitShaString))
|
||||||
|
|
||||||
|
result := hex.EncodeToString(mac.Sum(nil))
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// 字符串转int64
|
||||||
|
func StringToInt64(waitString string) int64 {
|
||||||
|
|
||||||
|
stringInt64, err := strconv.ParseInt(waitString, 10, 64)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return stringInt64
|
||||||
|
}
|
||||||
|
|
||||||
|
// 字符串转int32
|
||||||
|
func StringToInt(waitString string) int {
|
||||||
|
if waitString == "" {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
stringInt, err := strconv.Atoi(waitString)
|
||||||
|
if err != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return stringInt
|
||||||
|
}
|
||||||
|
|
||||||
|
func StringNumPlus(v1, v2 string) string {
|
||||||
|
return strconv.Itoa(StringToInt(v1) + StringToInt(v2))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 字符串转float64
|
||||||
|
func StringToFloat64(waitString string) float64 {
|
||||||
|
|
||||||
|
stringInt64, err := strconv.ParseFloat(waitString, 64)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return stringInt64
|
||||||
|
}
|
||||||
|
|
||||||
|
// float64保留2位
|
||||||
|
func Float64Decimal(waitFloatValue float64) float64 {
|
||||||
|
|
||||||
|
value, err := strconv.ParseFloat(fmt.Sprintf("%.2f", waitFloatValue), 64)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
// strconv.FormatFloat(float64, 'E', -1, 64)
|
||||||
|
// float64转字符串
|
||||||
|
func Float64ToString(waitFloat64 float64) string {
|
||||||
|
|
||||||
|
stringInt64 := strconv.FormatFloat(waitFloat64, 'f', -1, 64)
|
||||||
|
|
||||||
|
return stringInt64
|
||||||
|
}
|
||||||
|
|
||||||
|
// 截取字符串
|
||||||
|
func Substr(str string, start int, length int) string {
|
||||||
|
rs := []rune(str)
|
||||||
|
rl := len(rs)
|
||||||
|
end := 0
|
||||||
|
|
||||||
|
if start < 0 {
|
||||||
|
start = rl - 1 + start
|
||||||
|
}
|
||||||
|
end = start + length
|
||||||
|
|
||||||
|
if start > end {
|
||||||
|
start, end = end, start
|
||||||
|
}
|
||||||
|
|
||||||
|
if start < 0 {
|
||||||
|
start = 0
|
||||||
|
}
|
||||||
|
if start > rl {
|
||||||
|
start = rl
|
||||||
|
}
|
||||||
|
if end < 0 {
|
||||||
|
end = 0
|
||||||
|
}
|
||||||
|
if end > rl {
|
||||||
|
end = rl
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(rs[start:end])
|
||||||
|
}
|
||||||
|
|
||||||
|
// map转html
|
||||||
|
func MapToXML(mapData map[string]string) string {
|
||||||
|
|
||||||
|
if len(mapData) == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
sb := NewStringBuilder()
|
||||||
|
sb.Append("<xml>")
|
||||||
|
for key, val := range mapData {
|
||||||
|
sb.Append("<" + key + ">")
|
||||||
|
sb.Append(val)
|
||||||
|
sb.Append("</" + key + ">")
|
||||||
|
|
||||||
|
}
|
||||||
|
sb.Append("</xml>")
|
||||||
|
|
||||||
|
return sb.ToString()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取当前年周
|
||||||
|
func GetCurrentYearWeek() string {
|
||||||
|
|
||||||
|
year, week := time.Now().ISOWeek()
|
||||||
|
|
||||||
|
return strconv.Itoa(year) + strconv.Itoa(week)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 字符串转time类型
|
||||||
|
func StringToTime(dateString string) time.Time {
|
||||||
|
|
||||||
|
// 获取本地location
|
||||||
|
toBeCharge := dateString // 待转化为时间戳的字符串 注意 这里的小时和分钟还要秒必须写 因为是跟着模板走的 修改模板的话也可以不写
|
||||||
|
timeLayout := "2006-01-02 15:04:05" // 转化所需模板
|
||||||
|
loc, _ := time.LoadLocation("Local") // 重要:获取时区
|
||||||
|
theTime, _ := time.ParseInLocation(timeLayout, toBeCharge, loc) // 使用模板在对应时区转化为time.time类型
|
||||||
|
//sr := theTime.Unix() // 转化为时间戳 类型是int64
|
||||||
|
|
||||||
|
// 时间戳转日期
|
||||||
|
//dataTimeStr := time.Unix(sr, 0).Format(timeLayout) // 设置时间戳 使用模板格式化为日期字符串
|
||||||
|
|
||||||
|
return theTime
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断数组是否包含某个元素
|
||||||
|
func CheckStringIsInArray(arrayList []string, element string) bool {
|
||||||
|
|
||||||
|
if len(arrayList) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
isInArray := false
|
||||||
|
for _, data := range arrayList {
|
||||||
|
|
||||||
|
if data == element {
|
||||||
|
isInArray = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return isInArray
|
||||||
|
}
|
||||||
|
|
||||||
|
// slice to 字符串
|
||||||
|
func StringListToString(stringList []string, split string) string {
|
||||||
|
if len(split) == 0 {
|
||||||
|
split = ","
|
||||||
|
}
|
||||||
|
return strings.Replace(strings.Trim(fmt.Sprint(stringList), "[]"), " ", split, -1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// map 转 url参数
|
||||||
|
func MapToUrlParams(mapData map[string]string) string {
|
||||||
|
|
||||||
|
mapLen := len(mapData)
|
||||||
|
if mapLen == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
sb := NewStringBuilder()
|
||||||
|
|
||||||
|
i := 0
|
||||||
|
for k, v := range mapData {
|
||||||
|
|
||||||
|
sb.Append(k + "=" + v)
|
||||||
|
if i < mapLen-1 {
|
||||||
|
sb.Append("&")
|
||||||
|
}
|
||||||
|
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
return sb.ToString()
|
||||||
|
}
|
||||||
|
|
||||||
|
// []byte 合并
|
||||||
|
func BytesCombine(pBytes ...[]byte) []byte {
|
||||||
|
return bytes.Join(pBytes, []byte(""))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取当前UTC时间 秒数
|
||||||
|
func GetCurrentUtcTimeSecond() int64 {
|
||||||
|
return time.Now().UTC().Unix()
|
||||||
|
}
|
||||||
|
|
||||||
|
// byte数组分组
|
||||||
|
func ByteSplit(buf []byte, lim int) [][]byte {
|
||||||
|
|
||||||
|
var chunk []byte
|
||||||
|
|
||||||
|
chunks := make([][]byte, 0, len(buf)/lim+1)
|
||||||
|
|
||||||
|
for len(buf) >= lim {
|
||||||
|
|
||||||
|
chunk, buf = buf[:lim], buf[lim:]
|
||||||
|
|
||||||
|
chunks = append(chunks, chunk)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bufLen := len(buf)
|
||||||
|
if bufLen > 0 {
|
||||||
|
|
||||||
|
chunks = append(chunks, buf[:bufLen])
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return chunks
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 强类型数组转为interface类型的数组
|
||||||
|
func ToSlice(arr interface{}) []interface{} {
|
||||||
|
v := reflect.ValueOf(arr)
|
||||||
|
if v.Kind() != reflect.Slice {
|
||||||
|
panic("toslice arr not slice")
|
||||||
|
}
|
||||||
|
l := v.Len()
|
||||||
|
ret := make([]interface{}, l)
|
||||||
|
for i := 0; i < l; i++ {
|
||||||
|
ret[i] = v.Index(i).Interface()
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从字符串数组随机获取一个数组
|
||||||
|
func GetRandArrayFromArray(sourceArr []interface{}, resultCount int) (resultArr []interface{}) {
|
||||||
|
|
||||||
|
// 结果
|
||||||
|
resultArr = make([]interface{}, 0)
|
||||||
|
|
||||||
|
if len(sourceArr) < resultCount {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
r1 := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||||
|
for _, k := range r1.Perm(len(sourceArr)) {
|
||||||
|
|
||||||
|
if len(resultArr) >= resultCount {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
val := sourceArr[k]
|
||||||
|
resultArr = append(resultArr, val)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func RelationKey(userIds ...string) (key string) {
|
||||||
|
sort.Strings(userIds)
|
||||||
|
return strings.Join(userIds, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func ApplyKey(userIds ...string) (key string) {
|
||||||
|
return strings.Join(userIds, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func IPToUint32(ip string) (uint32, error) {
|
||||||
|
ips := strings.Split(ip, ".")
|
||||||
|
if len(ips) != 4 {
|
||||||
|
return 0, errors.New("ip error")
|
||||||
|
}
|
||||||
|
num := uint64(0)
|
||||||
|
for i, item := range ips {
|
||||||
|
n, _ := strconv.ParseUint(item, 10, 32)
|
||||||
|
num += n << (8 * uint(3-i))
|
||||||
|
}
|
||||||
|
return uint32(num), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func JsonStr(v interface{}) string {
|
||||||
|
b, _ := json.Marshal(v)
|
||||||
|
return string(b)
|
||||||
|
}
|
||||||
102
pkg/htools/UUID.go
Normal file
102
pkg/htools/UUID.go
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
package htools
|
||||||
|
|
||||||
|
import (
|
||||||
|
crand "crypto/rand"
|
||||||
|
"encoding/hex"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
mrand "math/rand"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// seeded indicates if math/rand has been seeded
|
||||||
|
var seeded bool = false
|
||||||
|
|
||||||
|
// uuidRegex matches the UUID string
|
||||||
|
var uuidRegex *regexp.Regexp = regexp.MustCompile(`^\{?([a-fA-F0-9]{8})-?([a-fA-F0-9]{4})-?([a-fA-F0-9]{4})-?([a-fA-F0-9]{4})-?([a-fA-F0-9]{12})\}?$`)
|
||||||
|
|
||||||
|
// UUID type.
|
||||||
|
type UUID [16]byte
|
||||||
|
|
||||||
|
// Hex returns a hex string representation of the UUID in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format.
|
||||||
|
func (this UUID) Hex() string {
|
||||||
|
|
||||||
|
x := [16]byte(this)
|
||||||
|
|
||||||
|
return fmt.Sprintf("%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
|
||||||
|
x[0], x[1], x[2], x[3], x[4],
|
||||||
|
x[5], x[6],
|
||||||
|
x[7], x[8],
|
||||||
|
x[9], x[10], x[11], x[12], x[13], x[14], x[15])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rand generates a new version 4 UUID.
|
||||||
|
func Rand() UUID {
|
||||||
|
var x [16]byte
|
||||||
|
randBytes(x[:])
|
||||||
|
x[6] = (x[6] & 0x0F) | 0x40
|
||||||
|
x[8] = (x[8] & 0x3F) | 0x80
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromStr returns a UUID based on a string.
|
||||||
|
// The string could be in the following format:
|
||||||
|
//
|
||||||
|
// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||||
|
//
|
||||||
|
// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||||
|
//
|
||||||
|
// {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
|
||||||
|
//
|
||||||
|
// If the string is not in one of these formats, it'll return an error.
|
||||||
|
func FromStr(s string) (id UUID, err error) {
|
||||||
|
if s == "" {
|
||||||
|
err = errors.New("Empty string")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
parts := uuidRegex.FindStringSubmatch(s)
|
||||||
|
if parts == nil {
|
||||||
|
err = errors.New("Invalid string format")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var array [16]byte
|
||||||
|
slice, _ := hex.DecodeString(strings.Join(parts[1:], ""))
|
||||||
|
copy(array[:], slice)
|
||||||
|
id = array
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// MustFromStr behaves similarly to FromStr except that it'll panic instead of
|
||||||
|
// returning an error.
|
||||||
|
func MustFromStr(s string) UUID {
|
||||||
|
id, err := FromStr(s)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return id
|
||||||
|
}
|
||||||
|
|
||||||
|
// randBytes uses crypto random to get random numbers. If fails then it uses math random.
|
||||||
|
func randBytes(x []byte) {
|
||||||
|
|
||||||
|
length := len(x)
|
||||||
|
n, err := crand.Read(x)
|
||||||
|
|
||||||
|
if n != length || err != nil {
|
||||||
|
for length > 0 {
|
||||||
|
length--
|
||||||
|
x[length] = byte(mrand.Int31n(256))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetUUID() string {
|
||||||
|
|
||||||
|
var uuid UUID = Rand()
|
||||||
|
|
||||||
|
return uuid.Hex()
|
||||||
|
|
||||||
|
}
|
||||||
195
pkg/log/zap.go
Normal file
195
pkg/log/zap.go
Normal file
@ -0,0 +1,195 @@
|
|||||||
|
package log
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/natefinch/lumberjack"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
"go.opentelemetry.io/otel/trace"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
"go.uber.org/zap/zapcore"
|
||||||
|
"gorm.io/gorm/logger"
|
||||||
|
)
|
||||||
|
|
||||||
|
var Log *zap.Logger
|
||||||
|
|
||||||
|
type ZapStarter struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ZapStarter) Init() error {
|
||||||
|
Init()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func Init() {
|
||||||
|
// 编码器
|
||||||
|
encoderConfig := zap.NewProductionEncoderConfig() // NewJSONEncoder()输出json格式,NewConsoleEncoder()输出普通文本格式
|
||||||
|
encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder // 指定时间格式
|
||||||
|
encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder // 按级别显示不同颜色,不需要的话取值 CapitalLevelEncoder 就可以了
|
||||||
|
encoderConfig.EncodeCaller = zapcore.ShortCallerEncoder // 是否显示完整文件路径
|
||||||
|
encoderConfig.EncodeTime = zapcore.TimeEncoderOfLayout("2006-01-02 15:04:05.000")
|
||||||
|
env := viper.GetString("env")
|
||||||
|
//encoder := zapcore.NewJSONEncoder(encoderConfig)
|
||||||
|
encoder := zapcore.NewConsoleEncoder(encoderConfig) // todo
|
||||||
|
if env != "dev" {
|
||||||
|
fmt.Printf("zap log with %s env\n", env)
|
||||||
|
encoder = zapcore.NewConsoleEncoder(encoderConfig)
|
||||||
|
}
|
||||||
|
normalPriority := zap.LevelEnablerFunc(func(lev zapcore.Level) bool { // info 级别
|
||||||
|
return lev < zap.ErrorLevel && lev >= zap.InfoLevel
|
||||||
|
})
|
||||||
|
|
||||||
|
errorPriority := zap.LevelEnablerFunc(func(lev zapcore.Level) bool { // info 级别
|
||||||
|
return lev > zap.InfoLevel
|
||||||
|
})
|
||||||
|
|
||||||
|
normalWriteSyncer := zapcore.AddSync(&lumberjack.Logger{
|
||||||
|
Filename: viper.GetString("log.normal.file"), // 日志文件存放目录
|
||||||
|
MaxSize: viper.GetInt("log.normal.size"), // 文件大小限制,单位MB
|
||||||
|
MaxBackups: viper.GetInt("log.normal.backups"), // 最大保留日志文件数量
|
||||||
|
MaxAge: viper.GetInt("log.normal.age"), // 日志文件保留天数
|
||||||
|
Compress: viper.GetBool("log.normal.compress"), // 是否压缩处理
|
||||||
|
LocalTime: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
errorWriteSyncer := zapcore.AddSync(&lumberjack.Logger{
|
||||||
|
Filename: viper.GetString("log.error.file"),
|
||||||
|
MaxSize: viper.GetInt("log.error.size"),
|
||||||
|
MaxBackups: viper.GetInt("log.error.backups"),
|
||||||
|
MaxAge: viper.GetInt("log.error.age"),
|
||||||
|
Compress: viper.GetBool("log.error.compress"),
|
||||||
|
LocalTime: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
Log = zap.New(zapcore.NewTee(
|
||||||
|
[]zapcore.Core{
|
||||||
|
zapcore.NewCore(
|
||||||
|
encoder,
|
||||||
|
zapcore.NewMultiWriteSyncer(normalWriteSyncer, zapcore.AddSync(os.Stdout)),
|
||||||
|
normalPriority,
|
||||||
|
),
|
||||||
|
zapcore.NewCore(
|
||||||
|
encoder,
|
||||||
|
zapcore.NewMultiWriteSyncer(errorWriteSyncer, zapcore.AddSync(os.Stdout)),
|
||||||
|
errorPriority,
|
||||||
|
),
|
||||||
|
}...,
|
||||||
|
), zap.AddCaller(), zap.AddCallerSkip(1))
|
||||||
|
}
|
||||||
|
|
||||||
|
func traceID(ctx context.Context, fields ...zap.Field) []zap.Field {
|
||||||
|
sp := trace.SpanContextFromContext(ctx)
|
||||||
|
traceID := zap.String("trace_id", sp.TraceID().String())
|
||||||
|
fields = append(fields, traceID)
|
||||||
|
return fields
|
||||||
|
}
|
||||||
|
|
||||||
|
func InfoWithCtx(ctx context.Context, msg string, fields ...zap.Field) {
|
||||||
|
Info(msg, traceID(ctx, fields...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Info(msg string, fields ...zap.Field) {
|
||||||
|
if strings.Contains(msg, "SHOW STATUS") {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if strings.Contains(msg, "GET _health") {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if strings.Contains(msg, "GET url: /health") {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
Log.Info(msg, fields...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func WarnWithCtx(ctx context.Context, msg string, fields ...zap.Field) {
|
||||||
|
Warn(msg, traceID(ctx, fields...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Warn(msg string, fields ...zap.Field) {
|
||||||
|
Log.Warn(msg, fields...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ErrorWithCtx(ctx context.Context, msg string, fields ...zap.Field) {
|
||||||
|
Log.Error(msg, traceID(ctx, fields...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Error(msg string, fields ...zap.Field) {
|
||||||
|
Log.Error(msg, fields...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func InfoFWithCtx(ctx context.Context, msg string, args ...interface{}) {
|
||||||
|
Log.Info(fmt.Sprintf(msg, args...), traceID(ctx)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func InfoF(msg string, args ...interface{}) {
|
||||||
|
msg = fmt.Sprintf(msg, args...)
|
||||||
|
Info(msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func WarnFWithCtx(ctx context.Context, msg string, args ...interface{}) {
|
||||||
|
Log.Warn(fmt.Sprintf(msg, args...), traceID(ctx)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func WarnF(msg string, args ...interface{}) {
|
||||||
|
Log.Warn(fmt.Sprintf(msg, args...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func ErrorFWithCtx(ctx context.Context, msg string, args ...interface{}) {
|
||||||
|
Log.Warn(fmt.Sprintf(msg, args...), traceID(ctx)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ErrorF(msg string, args ...interface{}) {
|
||||||
|
Log.Error(fmt.Sprintf(msg, args...))
|
||||||
|
}
|
||||||
|
|
||||||
|
type GLog struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g GLog) LogMode(_ logger.LogLevel) logger.Interface {
|
||||||
|
return &g
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g GLog) Info(_ context.Context, msg string, args ...interface{}) {
|
||||||
|
Info(fmt.Sprintf(msg, args...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g GLog) Warn(_ context.Context, msg string, args ...interface{}) {
|
||||||
|
Warn(fmt.Sprintf(msg, args...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g GLog) Error(_ context.Context, msg string, args ...interface{}) {
|
||||||
|
Error(fmt.Sprintf(msg, args...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g GLog) Trace(_ context.Context, begin time.Time, fc func() (sql string, rowsAffected int64), err error) {
|
||||||
|
sql, ra := fc()
|
||||||
|
if sql == "SHOW STATUS" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
Info("gorm callback trace", zap.String("sql", sql), zap.Int64("rows", ra), zap.Error(err))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g GLog) Printf(msg string, args ...interface{}) {
|
||||||
|
Info(fmt.Sprintf(msg, args...))
|
||||||
|
}
|
||||||
|
|
||||||
|
// CLog cron logger
|
||||||
|
type CLog struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c CLog) Info(msg string, keysAndValues ...interface{}) {
|
||||||
|
InfoF(msg, keysAndValues...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error logs an error condition.
|
||||||
|
func (c CLog) Error(err error, msg string, keysAndValues ...interface{}) {
|
||||||
|
ErrorF(msg, keysAndValues...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c CLog) Printf(msg string, args ...interface{}) {
|
||||||
|
InfoF(msg, args...)
|
||||||
|
}
|
||||||
30
pkg/middleware/authorize.go
Normal file
30
pkg/middleware/authorize.go
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
package middleware
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/anxpp/common-utils/logg"
|
||||||
|
"github.com/anxpp/common-utils/net"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Authorize() gin.HandlerFunc {
|
||||||
|
return func(c *gin.Context) {
|
||||||
|
inputToken := c.Request.Header.Get("X-Token")
|
||||||
|
if len(inputToken) == 0 {
|
||||||
|
c.JSON(http.StatusOK, net.Custom(500, "缺少授权token"))
|
||||||
|
c.Abort()
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Next()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func LogRequest() gin.HandlerFunc {
|
||||||
|
return func(c *gin.Context) {
|
||||||
|
decodedStr, _ := url.QueryUnescape(c.Request.RequestURI)
|
||||||
|
logg.Info("request:", c.Request.RemoteAddr, decodedStr)
|
||||||
|
|
||||||
|
c.Next()
|
||||||
|
}
|
||||||
|
}
|
||||||
25
pkg/middleware/cors.go
Normal file
25
pkg/middleware/cors.go
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
package middleware
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 处理跨域请求,支持options访问
|
||||||
|
func Cors() gin.HandlerFunc {
|
||||||
|
return func(c *gin.Context) {
|
||||||
|
method := c.Request.Method
|
||||||
|
c.Header("Access-Control-Allow-Origin", "*") // 可将将 * 替换为指定的域名
|
||||||
|
c.Header("Access-Control-Allow-Headers", "Content-Type,X-TOKEN") //你想放行的header也可以在后面自行添加
|
||||||
|
c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS") //我自己只使用 get post 所以只放行它
|
||||||
|
c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Content-Type")
|
||||||
|
c.Header("Access-Control-Allow-Credentials", "true")
|
||||||
|
|
||||||
|
// 放行所有OPTIONS方法
|
||||||
|
if method == "OPTIONS" {
|
||||||
|
c.AbortWithStatus(http.StatusNoContent)
|
||||||
|
}
|
||||||
|
// 处理请求
|
||||||
|
c.Next()
|
||||||
|
}
|
||||||
|
}
|
||||||
35
pkg/middleware/global_panic.go
Normal file
35
pkg/middleware/global_panic.go
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
package middleware
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"net/http"
|
||||||
|
"runtime/debug"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Recover(c *gin.Context) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
debug.PrintStack()
|
||||||
|
|
||||||
|
c.JSON(http.StatusOK, gin.H{
|
||||||
|
"code": 500,
|
||||||
|
"message": "系统异常",
|
||||||
|
"detailError": errorToString(r),
|
||||||
|
"data": nil,
|
||||||
|
})
|
||||||
|
|
||||||
|
c.Abort()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
c.Next()
|
||||||
|
}
|
||||||
|
|
||||||
|
func errorToString(r interface{}) string {
|
||||||
|
switch v := r.(type) {
|
||||||
|
case error:
|
||||||
|
return v.Error()
|
||||||
|
default:
|
||||||
|
return r.(string)
|
||||||
|
}
|
||||||
|
}
|
||||||
38
pkg/model/admin_privilege.gen.go
Normal file
38
pkg/model/admin_privilege.gen.go
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
// Code generated by gorm.io/gen. DO NOT EDIT.
|
||||||
|
// Code generated by gorm.io/gen. DO NOT EDIT.
|
||||||
|
// Code generated by gorm.io/gen. DO NOT EDIT.
|
||||||
|
|
||||||
|
package model
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
const TableNameAdminPrivilege = "admin_privilege"
|
||||||
|
|
||||||
|
// AdminPrivilege 租户-权限表
|
||||||
|
type AdminPrivilege struct {
|
||||||
|
ID string `gorm:"column:id;type:char(32);not null;uniqueIndex:id,priority:1;comment:业务ID" json:"id"` // 业务ID
|
||||||
|
TenantID string `gorm:"column:tenant_id;type:char(32);not null;default:system;comment:企业ID" json:"tenant_id"` // 企业ID
|
||||||
|
ScopeID string `gorm:"column:scope_id;type:char(32);not null;comment:范围" json:"scope_id"` // 范围
|
||||||
|
ParentID string `gorm:"column:parent_id;type:char(32);not null;comment:父ID" json:"parent_id"` // 父ID
|
||||||
|
Code string `gorm:"column:code;type:varchar(64);not null;comment:代码" json:"code"` // 代码
|
||||||
|
Name string `gorm:"column:name;type:varchar(64);not null;index:idx_name,priority:1;comment:权限名称" json:"name"` // 权限名称
|
||||||
|
Level int32 `gorm:"column:level;type:int;not null;comment:权限级别" json:"level"` // 权限级别
|
||||||
|
SourceType string `gorm:"column:source_type;type:varchar(64);not null;comment:类型:resource、interface等" json:"source_type"` // 类型:resource、interface等
|
||||||
|
TargetType string `gorm:"column:target_type;type:varchar(255);not null" json:"target_type"`
|
||||||
|
Target string `gorm:"column:target;type:varchar(255);not null;comment:权限值 resource:菜单路径; api=url-pre" json:"target"` // 权限值 resource:菜单路径; api=url-pre
|
||||||
|
Desc string `gorm:"column:desc;type:varchar(64);not null;comment:描述" json:"desc"` // 描述
|
||||||
|
DeleteAt *gorm.DeletedAt `gorm:"column:delete_at;type:datetime;index:idx_delete_at,priority:1;comment:del标志" json:"delete_at"` // del标志
|
||||||
|
CreateAt time.Time `gorm:"column:create_at;type:datetime;not null;default:CURRENT_TIMESTAMP;comment:创建时间" json:"create_at"` // 创建时间
|
||||||
|
CreateBy string `gorm:"column:create_by;type:varchar(255);not null;comment:创建人" json:"create_by"` // 创建人
|
||||||
|
UpdateAt time.Time `gorm:"column:update_at;type:datetime;not null;index:idx_delete_at,priority:2;default:CURRENT_TIMESTAMP;comment:更新时间" json:"update_at"` // 更新时间
|
||||||
|
UpdateBy string `gorm:"column:update_by;type:varchar(255);not null;comment:更新人" json:"update_by"` // 更新人
|
||||||
|
}
|
||||||
|
|
||||||
|
// TableName AdminPrivilege's table name
|
||||||
|
func (*AdminPrivilege) TableName() string {
|
||||||
|
return TableNameAdminPrivilege
|
||||||
|
}
|
||||||
33
pkg/model/admin_role.gen.go
Normal file
33
pkg/model/admin_role.gen.go
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
// Code generated by gorm.io/gen. DO NOT EDIT.
|
||||||
|
// Code generated by gorm.io/gen. DO NOT EDIT.
|
||||||
|
// Code generated by gorm.io/gen. DO NOT EDIT.
|
||||||
|
|
||||||
|
package model
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
const TableNameAdminRole = "admin_role"
|
||||||
|
|
||||||
|
// AdminRole 租户-角色表
|
||||||
|
type AdminRole struct {
|
||||||
|
ID string `gorm:"column:id;type:char(32);not null;uniqueIndex:id,priority:1;comment:业务ID" json:"id"` // 业务ID
|
||||||
|
TenantID string `gorm:"column:tenant_id;type:char(32);not null;default:system;comment:企业ID" json:"tenant_id"` // 企业ID
|
||||||
|
ScopeID string `gorm:"column:scope_id;type:char(32);not null;comment:角色范围" json:"scope_id"` // 角色范围
|
||||||
|
Code string `gorm:"column:code;type:varchar(64);not null;comment:代码" json:"code"` // 代码
|
||||||
|
Name string `gorm:"column:name;type:varchar(64);not null;index:idx_name,priority:1" json:"name"`
|
||||||
|
Desc string `gorm:"column:desc;type:varchar(64);not null;comment:描述" json:"desc"` // 描述
|
||||||
|
DeleteAt *gorm.DeletedAt `gorm:"column:delete_at;type:datetime;index:idx_delete_at,priority:1;comment:del标志" json:"delete_at"` // del标志
|
||||||
|
CreateAt time.Time `gorm:"column:create_at;type:datetime;not null;default:CURRENT_TIMESTAMP;comment:创建时间" json:"create_at"` // 创建时间
|
||||||
|
CreateBy string `gorm:"column:create_by;type:varchar(255);not null;comment:创建人" json:"create_by"` // 创建人
|
||||||
|
UpdateAt time.Time `gorm:"column:update_at;type:datetime;not null;index:idx_delete_at,priority:2;default:CURRENT_TIMESTAMP;comment:更新时间" json:"update_at"` // 更新时间
|
||||||
|
UpdateBy string `gorm:"column:update_by;type:varchar(255);not null;comment:更新人" json:"update_by"` // 更新人
|
||||||
|
}
|
||||||
|
|
||||||
|
// TableName AdminRole's table name
|
||||||
|
func (*AdminRole) TableName() string {
|
||||||
|
return TableNameAdminRole
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user