├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── go.mod ├── go.sum ├── server-common ├── config │ └── config.go ├── const │ ├── const.go │ └── server.go ├── driver │ ├── db.go │ └── es.go ├── nacosRF │ ├── init.go │ ├── serverFind.go │ └── serverRegister.go ├── pkg │ ├── elastic │ │ └── elastic.go │ ├── gorm │ │ └── gorm.go │ ├── httprequest │ │ └── httprequest.go │ ├── jwt │ │ └── jwt.go │ ├── leveldb │ │ └── leveldb.go │ ├── mongo │ │ └── mongo.go │ ├── redis │ │ └── redis.go │ ├── uber │ │ └── zap.go │ ├── viper │ │ └── viper.go │ ├── wetcd │ │ └── etcd.go │ └── wkafka │ │ ├── consumer.go │ │ └── producer.go ├── process │ └── process.go ├── servers │ └── servers.go └── utils │ ├── email │ └── email.go │ ├── encry │ ├── aes.go │ └── encry.go │ ├── enum │ ├── code.go │ └── response.go │ ├── ip │ └── ip.go │ ├── maps │ └── map.go │ ├── orm │ └── orm.go │ ├── regmatch │ └── regmatch.go │ ├── slice │ └── slice.go │ ├── wordsfilter │ ├── words_filter.txt │ └── wordsfilter.go │ └── wtime │ └── time.go ├── server-env ├── RabbitMQ.md ├── mongo.md └── mysql-redis-nacos │ ├── deploy_docker.sh │ ├── init_env.sh │ ├── mysql.yml │ ├── nacos-server.yml │ └── redis.yml ├── server-test ├── global │ └── config.go └── main.go ├── server-user ├── Makefile ├── boot │ ├── db.go │ ├── es.go │ ├── grpc.go │ ├── http.go │ ├── init.go │ ├── log.go │ └── ws.go ├── build.sh ├── cachedb │ └── server.go ├── core │ ├── db.go │ └── es.go ├── daos │ ├── account │ │ └── account.go │ ├── auth │ │ └── login.go │ └── serverDao │ │ └── server.go ├── global │ └── config.go ├── grpcservices │ ├── impl │ │ └── rpcUserService.go │ └── services │ │ └── RpcUserService.go ├── handler │ ├── auth │ │ └── login.go │ ├── user │ │ └── user.go │ └── ws.go ├── input │ ├── login.go │ └── user.go ├── main.go ├── middlewares │ ├── auth.go │ └── userIsEnable.go ├── models │ ├── server.go │ └── user.go ├── out │ ├── login.go │ └── user.go ├── pb │ ├── rpcUserService.pb.go │ └── rpcUserService_grpc.pb.go ├── proto │ └── rpcUserService.proto ├── router │ ├── api.go │ └── ws.go ├── rpc │ ├── demo.go │ └── rpc.go ├── run.sh ├── scripts │ └── generate_pb.sh ├── service │ ├── auth │ │ └── login.go │ └── user │ │ └── user.go ├── ulogger │ └── logger.go ├── up_package.sh └── ws │ └── ws.go └── test ├── aes_test.go ├── email_test.go ├── httprequest_test.go ├── map_test.go ├── regmatch_test.go ├── rpc_test.go ├── wordsfilter_test.go └── ws.html /.gitignore: -------------------------------------------------------------------------------- 1 | # default 2 | .DS_Store 3 | .idea 4 | .vscode 5 | .git 6 | *logs 7 | *level_db 8 | *gcache 9 | cache 10 | log 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 jeffcail 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | help: 2 | @echo "usage: make " 3 | @echo "options and effects:" 4 | @echo " mod : go set env and go install package" 5 | @echo " clean : clean this mod file" 6 | @echo " env : install project env" 7 | 8 | env: 9 | chmod +x server-env/mysql-redis-nacos/deploy_docker.sh 10 | server-env/mysql-redis-nacos/deploy_docker.sh 11 | 12 | chmod +x server-env/mysql-redis-nacos/init_env.sh 13 | server-env/msyql-redis-nacos/init_env.sh 14 | 15 | mod: 16 | @if [ !-f go.mod ]; then go mod init github.com/jeffcail/ginframe;fi 17 | @go env -w GOPROXY=https://goproxy.cn,direct 18 | @go mod tidy 19 | clean: 20 | rm -f go.mod 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ginframe 2 | > 基于Go语言gin框架搭建的可快速开发的微服务脚手架 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | [TOC]- [关于我](#关于我) 13 | - [关于我](#关于我) 14 | - [ginframe](#ginframe) 15 | - [简介](#简介) 16 | - [目录结构](#目录结构) 17 | - [安装](#安装) 18 | - [目的及优势](#目的及优势) 19 | - [职责](#职责) 20 | - [1. 文件配置](#文件配置) 21 | - [2. api路由](#api路由) 22 | - [3. rpc](#rpc) 23 | - [4. websocket路由](#websocket路由) 24 | - [5. api返回统一格式](#api返回统一格式) 25 | - [6. gorm](#gorm) 26 | - [7. redis](#redis) 27 | - [8. Mongo](#Mongo) 28 | - [9. uber.zap.log](#uber.zap.log) 29 | - [10. GOMAXPROCS](#GOMAXPROCS) 30 | - [11. httprequest](#httprequest) 31 | - [12. leveldb](#leveldb) 32 | - [13. ElasticSearch](#ElasticSearch) 33 | - [14. AES](#AES) 34 | - [15. 加密](#加密) 35 | - [16. 动态搜索+分页](#动态搜索+分页) 36 | - [17. map合并和并发安全map](#map合并和并发安全map) 37 | - [18. 时间处理工具类](#时间处理工具类) 38 | - [19. 敏感词识别](#敏感词识别) 39 | - [20. 邮件类工具](#邮件类工具) 40 | - [21. kafka生产者、消费者](#kafka生产者、消费者) 41 | - [22. etcd客户端连接初始化 (写入、读取、修改、删除)](#etcd客户端连接初始化 (写入、读取、修改、删除)) 42 | - [23. jwt](#jwt) 43 | - [24. 登录签发token](#登录签发token) 44 | - [25. token校验中间件](#token校验中间件) 45 | - [26. 账号登录状态是否被禁用校验中间件](#账号登录状态是否被禁用校验中间件) 46 | - [27. 常用正则表达式](#常用正则表达式) 47 | - [28. 数组切片去重](#数组切片去重) 48 | # 关于我 49 | 21实际拾荒人 50 | 51 | # ginframe 52 | 基于Go语言gin框架搭建的可快速开发的微服务脚手架 53 | 54 | 55 | ## 简介 56 | 基于gin框架,搭建一个快速开发的脚手架。 57 | 58 | ## 目录结构 59 | ```markdown 60 | server-common -- 服务公共模块 61 | config -- 解析配置方法 62 | const -- 全局常量 63 | driver -- 全局驱动 64 | nacosRF -- 全局nacos配置 65 | pkg -- 全局公共包 66 | gorm 67 | httprequest 68 | jwt 69 | leveldb 70 | mongo 71 | redis 72 | uber 73 | viper 74 | wetcd 75 | wkafka 76 | process -- cpu核心 77 | servers -- gprc 服务发现 78 | utils -- 全局工具类 79 | email -- 发送邮件 80 | encry -- 加密 81 | enum -- api统一分装返回 82 | ip -- ip工具 83 | maps -- map工具 84 | orm -- gorm动态搜索、分页 85 | regmatch -- 正则匹配 86 | slice -- 切片操作 87 | wordsfilter -- 敏感词过滤 88 | wtime -- 时间处理 89 | server-user -- 用户服务 90 | boot -- 启动目录 91 | db.go 92 | grpc.go 93 | http.go 94 | init.go 95 | log.go 96 | ws.go 97 | cachedb -- 缓存操作 98 | core -- 核心目录 99 | db.go 100 | daos -- daos 101 | global -- user服务全局配置 102 | grpcservices -- grpc services 103 | handler -- 控制器 104 | input -- 入参 105 | middlewares -- 中间件 106 | models -- 模型 107 | out -- 出参映射 108 | pb -- protobuf生成的文件目录 109 | proto -- protobuf文件目录 110 | router -- 路由 111 | api.go 112 | ws.go 113 | rpc -- rpc 114 | scripts -- 脚本 115 | service -- 服务层 116 | ulogger -- 服务日志 117 | ws -- websocket 118 | main.go -- 入口文件 119 | server-test -- 测试服务 120 | ...... -- 其他服务 121 | .gitignore 122 | go.mod -- mod包管理文件 123 | LICENSE 124 | README.md 125 | ``` 126 | 127 | ## 安装 128 | 安装完之后名字ginframe可改,可根据自己的需求精简或者添加架子结构。也可直接使用 129 | ```shell 130 | git clone https://github.com/mazezen/ginframe.git 131 | 132 | cd ginframe 133 | 134 | make env 135 | 136 | make mod 137 | 138 | ``` 139 | 140 | ## 目的及优势 141 | 142 | * 快速上手、快速开发、快速交付 143 | * 高性能、高扩展,避免重复造轮子 144 | 145 | 146 | ## 职责 147 | 快速开发、避免重复造轮子 148 | 149 | ### 文件配置 150 | application.yml为主配置文件.ConfigRemote觉得是否启用远程配置,支持Nacos. 151 | config.yml 为应用配置 152 | 153 | ### api路由 154 | http路由 155 | 156 | ### rpc 157 | 158 | ### websocket路由 159 | websocket路由 160 | 161 | ### api返回统一格式 162 | 成功、失败、分页 163 | 164 | ### gorm 165 | 166 | ### redis 167 | 168 | ### Mongo 169 | 170 | ### uber.zap.log 171 | 172 | ### GOMAXPROCS 173 | 174 | ### httprequest 175 | http请求. GET、POST带header头和参数 176 | 177 | ### leveldb 178 | 179 | ### ElasticSearch 180 | 181 | ### AES 182 | 可用于api接口参数加密 183 | 184 | ### 加密 185 | md5加密 、sha256加密 、sha512加密 、文件md5加密 、 (密码+盐)hash加密(可以用于加密登录密码). 186 | 187 | ### 动态搜索+分页 188 | 189 | ### map合并和并发安全map 190 | 191 | ### 时间处理工具类 192 | 193 | ### 邮件类工具 194 | 195 | ### kafka生产者、消费者 196 | 197 | ### etcd客户端连接初始化 (写入、读取、修改、删除) 198 | 199 | ### jwt 200 | 201 | ### 登录签发token 202 | 203 | ### token校验中间件 204 | 205 | ### 账号登录状态是否被禁用校验中间件 206 | 207 | ### 常用正则表达式 208 | 1. 手机号 209 | 2. 座机号 210 | 3. 18位身份证号 211 | 4. 护照编号 212 | 5. 港澳通行证 213 | 6. IP地址(ipv4) 214 | 7. IPV6 215 | 8. MAC地址 216 | 9. 电子邮箱 217 | 10. 统一社会信用代码 218 | 11. 密码 219 | 12. 网址URL 带端口号 220 | 13. 网址URL 不带端口号 221 | 14. 金额 222 | 223 | ### 数组切片去重 224 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/mazezen/ginframe 2 | 3 | go 1.18 4 | 5 | require ( 6 | github.com/Shopify/sarama v1.38.1 7 | github.com/dgrijalva/jwt-go v3.2.0+incompatible 8 | github.com/gin-gonic/gin v1.9.0 9 | github.com/gorilla/websocket v1.5.0 10 | github.com/jeffcail/gorequest v0.0.0-20230523095137-9809d4f45ca5 11 | github.com/jeffcail/leveldb v1.0.0 12 | github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible 13 | github.com/nacos-group/nacos-sdk-go v1.1.1 14 | github.com/olivere/elastic v6.2.37+incompatible 15 | github.com/robfig/cron v1.2.0 16 | github.com/spf13/cast v1.5.0 17 | github.com/spf13/viper v1.15.0 18 | github.com/syyongx/go-wordsfilter v0.0.0-20190622081656-74232c786041 19 | go.etcd.io/etcd/client/v3 v3.5.9 20 | go.mongodb.org/mongo-driver v1.11.6 21 | go.uber.org/zap v1.24.0 22 | golang.org/x/crypto v0.9.0 23 | google.golang.org/grpc v1.55.0 24 | google.golang.org/protobuf v1.30.0 25 | gopkg.in/natefinch/lumberjack.v2 v2.0.0 26 | gopkg.in/redis.v5 v5.2.9 27 | gorm.io/driver/mysql v1.5.1 28 | gorm.io/gorm v1.25.1 29 | ) 30 | 31 | require ( 32 | github.com/aliyun/alibaba-cloud-sdk-go v1.61.1704 // indirect 33 | github.com/buger/jsonparser v1.1.1 // indirect 34 | github.com/bytedance/sonic v1.8.8 // indirect 35 | github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect 36 | github.com/coreos/go-semver v0.3.0 // indirect 37 | github.com/coreos/go-systemd/v22 v22.3.2 // indirect 38 | github.com/davecgh/go-spew v1.1.1 // indirect 39 | github.com/eapache/go-resiliency v1.3.0 // indirect 40 | github.com/eapache/go-xerial-snappy v0.0.0-20230111030713-bf00bc1b83b6 // indirect 41 | github.com/eapache/queue v1.1.0 // indirect 42 | github.com/fsnotify/fsnotify v1.6.0 // indirect 43 | github.com/gin-contrib/sse v0.1.0 // indirect 44 | github.com/go-errors/errors v1.0.1 // indirect 45 | github.com/go-playground/locales v0.14.1 // indirect 46 | github.com/go-playground/universal-translator v0.18.1 // indirect 47 | github.com/go-playground/validator/v10 v10.13.0 // indirect 48 | github.com/go-sql-driver/mysql v1.7.0 // indirect 49 | github.com/goccy/go-json v0.10.2 // indirect 50 | github.com/gogo/protobuf v1.3.2 // indirect 51 | github.com/golang/mock v1.6.0 // indirect 52 | github.com/golang/protobuf v1.5.3 // indirect 53 | github.com/golang/snappy v0.0.4 // indirect 54 | github.com/hashicorp/errwrap v1.0.0 // indirect 55 | github.com/hashicorp/go-multierror v1.1.1 // indirect 56 | github.com/hashicorp/go-uuid v1.0.3 // indirect 57 | github.com/hashicorp/hcl v1.0.0 // indirect 58 | github.com/jcmturner/aescts/v2 v2.0.0 // indirect 59 | github.com/jcmturner/dnsutils/v2 v2.0.0 // indirect 60 | github.com/jcmturner/gofork v1.7.6 // indirect 61 | github.com/jcmturner/gokrb5/v8 v8.4.3 // indirect 62 | github.com/jcmturner/rpc/v2 v2.0.3 // indirect 63 | github.com/jinzhu/inflection v1.0.0 // indirect 64 | github.com/jinzhu/now v1.1.5 // indirect 65 | github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af // indirect 66 | github.com/josharian/intern v1.0.0 // indirect 67 | github.com/json-iterator/go v1.1.12 // indirect 68 | github.com/klauspost/compress v1.15.14 // indirect 69 | github.com/klauspost/cpuid/v2 v2.2.4 // indirect 70 | github.com/leodido/go-urn v1.2.4 // indirect 71 | github.com/magiconair/properties v1.8.7 // indirect 72 | github.com/mailru/easyjson v0.7.7 // indirect 73 | github.com/mattn/go-isatty v0.0.18 // indirect 74 | github.com/mitchellh/mapstructure v1.5.0 // indirect 75 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 76 | github.com/modern-go/reflect2 v1.0.2 // indirect 77 | github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect 78 | github.com/pelletier/go-toml/v2 v2.0.7 // indirect 79 | github.com/pierrec/lz4/v4 v4.1.17 // indirect 80 | github.com/pkg/errors v0.9.1 // indirect 81 | github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect 82 | github.com/spf13/afero v1.9.3 // indirect 83 | github.com/spf13/jwalterweatherman v1.1.0 // indirect 84 | github.com/spf13/pflag v1.0.5 // indirect 85 | github.com/subosito/gotenv v1.4.2 // indirect 86 | github.com/syndtr/goleveldb v1.0.0 // indirect 87 | github.com/twitchyliquid64/golang-asm v0.15.1 // indirect 88 | github.com/ugorji/go/codec v1.2.11 // indirect 89 | github.com/xdg-go/pbkdf2 v1.0.0 // indirect 90 | github.com/xdg-go/scram v1.1.2 // indirect 91 | github.com/xdg-go/stringprep v1.0.4 // indirect 92 | github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect 93 | go.etcd.io/etcd/api/v3 v3.5.9 // indirect 94 | go.etcd.io/etcd/client/pkg/v3 v3.5.9 // indirect 95 | go.uber.org/atomic v1.9.0 // indirect 96 | go.uber.org/multierr v1.8.0 // indirect 97 | golang.org/x/arch v0.3.0 // indirect 98 | golang.org/x/net v0.10.0 // indirect 99 | golang.org/x/sync v0.1.0 // indirect 100 | golang.org/x/sys v0.8.0 // indirect 101 | golang.org/x/text v0.9.0 // indirect 102 | google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect 103 | gopkg.in/ini.v1 v1.67.0 // indirect 104 | gopkg.in/yaml.v3 v3.0.1 // indirect 105 | ) 106 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 2 | cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 3 | cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= 4 | cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= 5 | cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= 6 | cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= 7 | cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= 8 | cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= 9 | cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= 10 | cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= 11 | cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= 12 | cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= 13 | cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= 14 | cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= 15 | cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= 16 | cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= 17 | cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= 18 | cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= 19 | cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= 20 | cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= 21 | cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= 22 | cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= 23 | cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= 24 | cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= 25 | cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= 26 | cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= 27 | cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= 28 | cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= 29 | cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= 30 | cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= 31 | cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= 32 | cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= 33 | cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= 34 | cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= 35 | cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= 36 | cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= 37 | cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= 38 | dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= 39 | github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= 40 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 41 | github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= 42 | github.com/Shopify/sarama v1.38.1 h1:lqqPUPQZ7zPqYlWpTh+LQ9bhYNu2xJL6k1SJN4WVe2A= 43 | github.com/Shopify/sarama v1.38.1/go.mod h1:iwv9a67Ha8VNa+TifujYoWGxWnu2kNVAQdSdZ4X2o5g= 44 | github.com/Shopify/toxiproxy/v2 v2.5.0 h1:i4LPT+qrSlKNtQf5QliVjdP08GyAH8+BUIc9gT0eahc= 45 | github.com/aliyun/alibaba-cloud-sdk-go v1.61.18/go.mod h1:v8ESoHo4SyHmuB4b1tJqDHxfTGEciD+yhvOU/5s1Rfk= 46 | github.com/aliyun/alibaba-cloud-sdk-go v1.61.1704 h1:PpfENOj/vPfhhy9N2OFRjpue0hjM5XqAp2thFmkXXIk= 47 | github.com/aliyun/alibaba-cloud-sdk-go v1.61.1704/go.mod h1:RcDobYh8k5VP6TNybz9m++gL3ijVI5wueVr0EM10VsU= 48 | github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= 49 | github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs= 50 | github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= 51 | github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= 52 | github.com/bytedance/sonic v1.8.8 h1:Kj4AYbZSeENfyXicsYppYKO0K2YWab+i2UTSY7Ukz9Q= 53 | github.com/bytedance/sonic v1.8.8/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= 54 | github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= 55 | github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= 56 | github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= 57 | github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= 58 | github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= 59 | github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= 60 | github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= 61 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= 62 | github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= 63 | github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= 64 | github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= 65 | github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= 66 | github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= 67 | github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI= 68 | github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= 69 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 70 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 71 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 72 | github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= 73 | github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= 74 | github.com/eapache/go-resiliency v1.3.0 h1:RRL0nge+cWGlxXbUzJ7yMcq6w2XBEr19dCN6HECGaT0= 75 | github.com/eapache/go-resiliency v1.3.0/go.mod h1:5yPzW0MIvSe0JDsv0v+DvcjEv2FyD6iZYSs1ZI+iQho= 76 | github.com/eapache/go-xerial-snappy v0.0.0-20230111030713-bf00bc1b83b6 h1:8yY/I9ndfrgrXUbOGObLHKBR4Fl3nZXwM2c7OYTT8hM= 77 | github.com/eapache/go-xerial-snappy v0.0.0-20230111030713-bf00bc1b83b6/go.mod h1:YvSRo5mw33fLEx1+DlK6L2VV43tJt5Eyel9n9XBcR+0= 78 | github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc= 79 | github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= 80 | github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 81 | github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 82 | github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= 83 | github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= 84 | github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= 85 | github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= 86 | github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= 87 | github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= 88 | github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= 89 | github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= 90 | github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= 91 | github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= 92 | github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= 93 | github.com/gin-gonic/gin v1.9.0 h1:OjyFBKICoexlu99ctXNR2gg+c5pKrKMuyjgARg9qeY8= 94 | github.com/gin-gonic/gin v1.9.0/go.mod h1:W1Me9+hsUSyj3CePGrd1/QrKJMSJ1Tu/0hFEH89961k= 95 | github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w= 96 | github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= 97 | github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= 98 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= 99 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= 100 | github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= 101 | github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= 102 | github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= 103 | github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= 104 | github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= 105 | github.com/go-playground/validator/v10 v10.13.0 h1:cFRQdfaSMCOSfGCCLB20MHvuoHb/s5G8L5pu2ppK5AQ= 106 | github.com/go-playground/validator/v10 v10.13.0/go.mod h1:dwu7+CG8/CtBiJFZDz4e+5Upb6OLw04gtBYw0mcG/z4= 107 | github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc= 108 | github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= 109 | github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= 110 | github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= 111 | github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= 112 | github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= 113 | github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= 114 | github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A= 115 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= 116 | github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 117 | github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 118 | github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 119 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 120 | github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 121 | github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= 122 | github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= 123 | github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= 124 | github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= 125 | github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= 126 | github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= 127 | github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= 128 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 129 | github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 130 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 131 | github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= 132 | github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= 133 | github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= 134 | github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= 135 | github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= 136 | github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= 137 | github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= 138 | github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= 139 | github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= 140 | github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 141 | github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 142 | github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= 143 | github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= 144 | github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= 145 | github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= 146 | github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= 147 | github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= 148 | github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= 149 | github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 150 | github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 151 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 152 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 153 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 154 | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 155 | github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 156 | github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 157 | github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 158 | github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 159 | github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 160 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 161 | github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= 162 | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 163 | github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= 164 | github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= 165 | github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= 166 | github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= 167 | github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= 168 | github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 169 | github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 170 | github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 171 | github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 172 | github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 173 | github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= 174 | github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= 175 | github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= 176 | github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= 177 | github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 178 | github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= 179 | github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= 180 | github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= 181 | github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= 182 | github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= 183 | github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= 184 | github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= 185 | github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= 186 | github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= 187 | github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= 188 | github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= 189 | github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= 190 | github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= 191 | github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= 192 | github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= 193 | github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 194 | github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 195 | github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= 196 | github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= 197 | github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= 198 | github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= 199 | github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= 200 | github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= 201 | github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8= 202 | github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs= 203 | github.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo= 204 | github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM= 205 | github.com/jcmturner/gofork v1.7.6 h1:QH0l3hzAU1tfT3rZCnW5zXl+orbkNMMRGJfdJjHVETg= 206 | github.com/jcmturner/gofork v1.7.6/go.mod h1:1622LH6i/EZqLloHfE7IeZ0uEJwMSUyQ/nDd82IeqRo= 207 | github.com/jcmturner/goidentity/v6 v6.0.1 h1:VKnZd2oEIMorCTsFBnJWbExfNN7yZr3EhJAxwOkZg6o= 208 | github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg= 209 | github.com/jcmturner/gokrb5/v8 v8.4.3 h1:iTonLeSJOn7MVUtyMT+arAn5AKAPrkilzhGw8wE/Tq8= 210 | github.com/jcmturner/gokrb5/v8 v8.4.3/go.mod h1:dqRwJGXznQrzw6cWmyo6kH+E7jksEQG/CyVWsJEsJO0= 211 | github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY= 212 | github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= 213 | github.com/jeffcail/gorequest v0.0.0-20230523095137-9809d4f45ca5 h1:Kl37Oxj9XoNNTL49djSDnyBG7u4lV0i1rH6+F7uFF0c= 214 | github.com/jeffcail/gorequest v0.0.0-20230523095137-9809d4f45ca5/go.mod h1:sDi56Xf9ip5NI/pYhJgv8R39J52trtPYqgChSeYhsp0= 215 | github.com/jeffcail/leveldb v1.0.0 h1:gLgeYs3bGEYj12l41cmgjyCacpINzQEcOYO2f/wwmhs= 216 | github.com/jeffcail/leveldb v1.0.0/go.mod h1:9O6WDK9GYREx/C6PO7D12INivUl7175QlucNIPpHk1c= 217 | github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= 218 | github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= 219 | github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= 220 | github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= 221 | github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM= 222 | github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= 223 | github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible h1:jdpOPRN1zP63Td1hDQbZW73xKmzDvZHzVdNYxhnTMDA= 224 | github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible/go.mod h1:1c7szIrayyPPB/987hsnvNzLushdWf4o/79s3P08L8A= 225 | github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= 226 | github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= 227 | github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= 228 | github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= 229 | github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= 230 | github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 231 | github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= 232 | github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= 233 | github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= 234 | github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= 235 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= 236 | github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= 237 | github.com/klauspost/compress v1.15.14 h1:i7WCKDToww0wA+9qrUZ1xOjp218vfFo3nTU6UHp+gOc= 238 | github.com/klauspost/compress v1.15.14/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM= 239 | github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= 240 | github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk= 241 | github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= 242 | github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= 243 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 244 | github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= 245 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 246 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 247 | github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= 248 | github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= 249 | github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= 250 | github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= 251 | github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= 252 | github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= 253 | github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= 254 | github.com/mattn/go-isatty v0.0.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98= 255 | github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= 256 | github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= 257 | github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= 258 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 259 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= 260 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 261 | github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 262 | github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 263 | github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= 264 | github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= 265 | github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe h1:iruDEfMl2E6fbMZ9s0scYfZQ84/6SPL6zC8ACM2oIL0= 266 | github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= 267 | github.com/nacos-group/nacos-sdk-go v1.1.1 h1:beczWcOoTaVBMgCgikqvZflrN5Xbw7pWAWpxl+VJGIA= 268 | github.com/nacos-group/nacos-sdk-go v1.1.1/go.mod h1:UHOtQNQY/qpk2dhg6gDq8u5+/CEIc3+lWmrmxEzX0/g= 269 | github.com/olivere/elastic v6.2.37+incompatible h1:UfSGJem5czY+x/LqxgeCBgjDn6St+z8OnsCuxwD3L0U= 270 | github.com/olivere/elastic v6.2.37+incompatible/go.mod h1:J+q1zQJTgAz9woqsbVRqGeB5G1iqDKVBWLNSYW8yfJ8= 271 | github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 272 | github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs= 273 | github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 274 | github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU= 275 | github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= 276 | github.com/pelletier/go-toml/v2 v2.0.7 h1:muncTPStnKRos5dpVKULv2FVd4bMOhNePj9CjgDb8Us= 277 | github.com/pelletier/go-toml/v2 v2.0.7/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek= 278 | github.com/pierrec/lz4/v4 v4.1.17 h1:kV4Ip+/hUBC+8T6+2EgburRtkE9ef4nbY3f4dFhGjMc= 279 | github.com/pierrec/lz4/v4 v4.1.17/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= 280 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 281 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 282 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 283 | github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= 284 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 285 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 286 | github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 287 | github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM= 288 | github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= 289 | github.com/robfig/cron v1.2.0 h1:ZjScXvvxeQ63Dbyxy76Fj3AT3Ut0aKsyd2/tl3DTMuQ= 290 | github.com/robfig/cron v1.2.0/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k= 291 | github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= 292 | github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= 293 | github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= 294 | github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= 295 | github.com/spf13/afero v1.9.3 h1:41FoI0fD7OR7mGcKE/aOiLkGreyf8ifIOQmJANWogMk= 296 | github.com/spf13/afero v1.9.3/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= 297 | github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= 298 | github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= 299 | github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= 300 | github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= 301 | github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= 302 | github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= 303 | github.com/spf13/viper v1.15.0 h1:js3yy885G8xwJa6iOISGFwd+qlUo5AvyXb7CiihdtiU= 304 | github.com/spf13/viper v1.15.0/go.mod h1:fFcTBJxvhhzSJiZy8n+PeW6t8l+KeT/uTARa0jHOQLA= 305 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 306 | github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= 307 | github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= 308 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 309 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 310 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 311 | github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= 312 | github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 313 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 314 | github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 315 | github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= 316 | github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= 317 | github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= 318 | github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= 319 | github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= 320 | github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= 321 | github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE= 322 | github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= 323 | github.com/syyongx/go-wordsfilter v0.0.0-20190622081656-74232c786041 h1:5CjnwaE1qLC1x8v06obetAQZxCGyNfLPjNNDXMwQzYg= 324 | github.com/syyongx/go-wordsfilter v0.0.0-20190622081656-74232c786041/go.mod h1:Z3aS1bQVPx2BLLsWOT1lf9yaO1Su1U2JGG5pxpbJjBQ= 325 | github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= 326 | github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= 327 | github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= 328 | github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= 329 | github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= 330 | github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= 331 | github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= 332 | github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= 333 | github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g= 334 | github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY= 335 | github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4= 336 | github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8= 337 | github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8= 338 | github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM= 339 | github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA= 340 | github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= 341 | github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 342 | github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 343 | github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 344 | github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 345 | github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= 346 | github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= 347 | go.etcd.io/etcd/api/v3 v3.5.9 h1:4wSsluwyTbGGmyjJktOf3wFQoTBIURXHnq9n/G/JQHs= 348 | go.etcd.io/etcd/api/v3 v3.5.9/go.mod h1:uyAal843mC8uUVSLWz6eHa/d971iDGnCRpmKd2Z+X8k= 349 | go.etcd.io/etcd/client/pkg/v3 v3.5.9 h1:oidDC4+YEuSIQbsR94rY9gur91UPL6DnxDCIYd2IGsE= 350 | go.etcd.io/etcd/client/pkg/v3 v3.5.9/go.mod h1:y+CzeSmkMpWN2Jyu1npecjB9BBnABxGM4pN8cGuJeL4= 351 | go.etcd.io/etcd/client/v3 v3.5.9 h1:r5xghnU7CwbUxD/fbUtRyJGaYNfDun8sp/gTr1hew6E= 352 | go.etcd.io/etcd/client/v3 v3.5.9/go.mod h1:i/Eo5LrZ5IKqpbtpPDuaUnDOUv471oDg8cjQaUr2MbA= 353 | go.mongodb.org/mongo-driver v1.11.6 h1:XM7G6PjiGAO5betLF13BIa5TlLUUE3uJ/2Ox3Lz1K+o= 354 | go.mongodb.org/mongo-driver v1.11.6/go.mod h1:G9TgswdsWjX4tmDA5zfs2+6AEPpYJwqblyjsfuh8oXY= 355 | go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= 356 | go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= 357 | go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 358 | go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 359 | go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 360 | go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= 361 | go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= 362 | go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= 363 | go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= 364 | go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= 365 | go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= 366 | go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= 367 | go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8= 368 | go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= 369 | go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= 370 | go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= 371 | go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= 372 | go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= 373 | golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= 374 | golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k= 375 | golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= 376 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 377 | golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 378 | golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 379 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 380 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 381 | golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= 382 | golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= 383 | golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= 384 | golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= 385 | golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= 386 | golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g= 387 | golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= 388 | golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 389 | golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 390 | golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= 391 | golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= 392 | golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= 393 | golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 394 | golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 395 | golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 396 | golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= 397 | golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= 398 | golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= 399 | golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= 400 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 401 | golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= 402 | golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 403 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 404 | golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 405 | golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 406 | golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 407 | golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= 408 | golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= 409 | golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= 410 | golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= 411 | golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= 412 | golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= 413 | golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= 414 | golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= 415 | golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 416 | golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 417 | golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 418 | golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 419 | golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 420 | golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 421 | golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 422 | golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= 423 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 424 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 425 | golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 426 | golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 427 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 428 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 429 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 430 | golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 431 | golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 432 | golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= 433 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 434 | golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 435 | golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 436 | golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 437 | golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 438 | golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 439 | golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 440 | golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 441 | golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 442 | golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 443 | golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 444 | golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 445 | golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 446 | golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 447 | golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 448 | golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 449 | golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 450 | golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 451 | golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 452 | golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 453 | golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 454 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 455 | golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= 456 | golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 457 | golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= 458 | golang.org/x/net v0.0.0-20220725212005-46097bf591d3/go.mod h1:AaygXjzTFtRAg2ttMY5RMuhpJ3cNnI0XpyFJD1iQRSM= 459 | golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= 460 | golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= 461 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 462 | golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 463 | golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 464 | golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 465 | golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 466 | golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 467 | golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 468 | golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 469 | golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 470 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 471 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 472 | golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 473 | golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 474 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 475 | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 476 | golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 477 | golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 478 | golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 479 | golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 480 | golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 481 | golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 482 | golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= 483 | golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 484 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 485 | golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 486 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 487 | golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 488 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 489 | golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 490 | golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 491 | golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 492 | golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 493 | golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 494 | golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 495 | golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 496 | golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 497 | golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 498 | golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 499 | golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 500 | golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 501 | golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 502 | golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 503 | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 504 | golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 505 | golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 506 | golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 507 | golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 508 | golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 509 | golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 510 | golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 511 | golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 512 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 513 | golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 514 | golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 515 | golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 516 | golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 517 | golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 518 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 519 | golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 520 | golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 521 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 522 | golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 523 | golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 524 | golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 525 | golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 526 | golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 527 | golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= 528 | golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 529 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 530 | golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= 531 | golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 532 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 533 | golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 534 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 535 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 536 | golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 537 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 538 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= 539 | golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= 540 | golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= 541 | golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= 542 | golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 543 | golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 544 | golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 545 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 546 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 547 | golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= 548 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 549 | golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 550 | golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 551 | golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 552 | golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 553 | golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 554 | golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 555 | golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 556 | golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 557 | golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 558 | golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 559 | golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 560 | golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 561 | golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 562 | golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 563 | golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 564 | golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 565 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 566 | golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 567 | golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 568 | golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 569 | golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 570 | golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 571 | golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 572 | golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 573 | golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 574 | golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 575 | golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 576 | golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 577 | golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 578 | golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= 579 | golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= 580 | golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= 581 | golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 582 | golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 583 | golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 584 | golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 585 | golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 586 | golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= 587 | golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= 588 | golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= 589 | golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= 590 | golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 591 | golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 592 | golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 593 | golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 594 | golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 595 | golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 596 | golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= 597 | golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= 598 | golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= 599 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 600 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 601 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 602 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 603 | google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= 604 | google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= 605 | google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= 606 | google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= 607 | google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 608 | google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 609 | google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 610 | google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 611 | google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 612 | google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 613 | google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 614 | google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 615 | google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= 616 | google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= 617 | google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= 618 | google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= 619 | google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= 620 | google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= 621 | google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= 622 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 623 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 624 | google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 625 | google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= 626 | google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 627 | google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 628 | google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 629 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 630 | google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 631 | google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 632 | google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 633 | google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 634 | google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 635 | google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 636 | google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= 637 | google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 638 | google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 639 | google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 640 | google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 641 | google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 642 | google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 643 | google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= 644 | google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 645 | google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 646 | google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 647 | google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 648 | google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 649 | google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 650 | google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 651 | google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 652 | google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= 653 | google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= 654 | google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= 655 | google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 656 | google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 657 | google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 658 | google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 659 | google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 660 | google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 661 | google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 662 | google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 663 | google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 664 | google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 665 | google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= 666 | google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= 667 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= 668 | google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= 669 | google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= 670 | google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= 671 | google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= 672 | google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 673 | google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 674 | google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 675 | google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= 676 | google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= 677 | google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= 678 | google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= 679 | google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= 680 | google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= 681 | google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= 682 | google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= 683 | google.golang.org/grpc v1.55.0 h1:3Oj82/tFSCeUrRTg/5E/7d/W5A1tj6Ky1ABAuZuv5ag= 684 | google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8= 685 | google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= 686 | google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= 687 | google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= 688 | google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= 689 | google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= 690 | google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 691 | google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 692 | google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 693 | google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= 694 | google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= 695 | google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= 696 | google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= 697 | google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= 698 | google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= 699 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 700 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 701 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= 702 | gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= 703 | gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= 704 | gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= 705 | gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= 706 | gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= 707 | gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= 708 | gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= 709 | gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8= 710 | gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= 711 | gopkg.in/redis.v5 v5.2.9 h1:MNZYOLPomQzZMfpN3ZtD1uyJ2IDonTTlxYiV/pEApiw= 712 | gopkg.in/redis.v5 v5.2.9/go.mod h1:6gtv0/+A4iM08kdRfocWYB3bLX2tebpNtfKlFT6H4mY= 713 | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= 714 | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= 715 | gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 716 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 717 | gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= 718 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 719 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 720 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 721 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 722 | gorm.io/driver/mysql v1.5.1 h1:WUEH5VF9obL/lTtzjmML/5e6VfFR/788coz2uaVCAZw= 723 | gorm.io/driver/mysql v1.5.1/go.mod h1:Jo3Xu7mMhCyj8dlrb3WoCaRd1FhsVh+yMXb1jUInf5o= 724 | gorm.io/gorm v1.25.1 h1:nsSALe5Pr+cM3V1qwwQ7rOkw+6UeLrX5O4v3llhHa64= 725 | gorm.io/gorm v1.25.1/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= 726 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 727 | honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 728 | honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 729 | honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 730 | honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= 731 | honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= 732 | honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= 733 | rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= 734 | rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= 735 | rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= 736 | rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= 737 | -------------------------------------------------------------------------------- /server-common/config/config.go: -------------------------------------------------------------------------------- 1 | // 配置文件加载 2 | 3 | package config 4 | 5 | import ( 6 | _viper "github.com/mazezen/ginframe/server-common/pkg/viper" 7 | ) 8 | 9 | // ParseConfig 配置文件加载 10 | func ParseConfig(path string, config interface{}) { 11 | _viper.ParseViperConfig(path, config) 12 | } 13 | 14 | // LoadCoreConfig 加载配置 15 | func LoadCoreConfig(ip string, port int, cfg string, group string, config interface{}) { 16 | _viper.LoadCoreConfig(ip, port, cfg, group, config) 17 | } 18 | -------------------------------------------------------------------------------- /server-common/const/const.go: -------------------------------------------------------------------------------- 1 | package _const 2 | 3 | const ( 4 | HEALTHCHECK_SERVICE = "grpc.health.v1.Health" 5 | ) 6 | -------------------------------------------------------------------------------- /server-common/const/server.go: -------------------------------------------------------------------------------- 1 | package _const 2 | 3 | const ( 4 | ServerNameU = "user" 5 | UserServerName = "UserServerName:" 6 | ) 7 | -------------------------------------------------------------------------------- /server-common/driver/db.go: -------------------------------------------------------------------------------- 1 | package driver 2 | 3 | import ( 4 | _gorm "github.com/mazezen/ginframe/server-common/pkg/gorm" 5 | _leveldb "github.com/mazezen/ginframe/server-common/pkg/leveldb" 6 | _mongo "github.com/mazezen/ginframe/server-common/pkg/mongo" 7 | _redis "github.com/mazezen/ginframe/server-common/pkg/redis" 8 | leveldb1 "github.com/mazezen/leveldb" 9 | "go.mongodb.org/mongo-driver/mongo" 10 | "gopkg.in/redis.v5" 11 | "gorm.io/gorm" 12 | ) 13 | 14 | // CreateDb create mysql db 15 | func CreateDb(dbDsn string, maxOpenConn, maxIdleConn int) (*gorm.DB, error) { 16 | arg := []int{maxOpenConn, maxIdleConn} 17 | db, err := _gorm.InitGormMysql(dbDsn, arg) 18 | if err != nil { 19 | return nil, err 20 | } 21 | return db, nil 22 | } 23 | 24 | // CreateRedis 初始化redis 连接 25 | func CreateRedis(addr, pass string, rdb int) (*redis.Client, error) { 26 | rd, err := _redis.InitRedis(addr, pass, rdb) 27 | if err != nil { 28 | return nil, err 29 | } 30 | return rd, nil 31 | } 32 | 33 | // InitMongo 初始化mongo 34 | func InitMongo(addr string) (*mongo.Client, error) { 35 | mg, err := _mongo.InitMongoDb(addr) 36 | if err != nil { 37 | return nil, err 38 | } 39 | return mg, nil 40 | } 41 | 42 | // InitLevelDb init level db 43 | func InitLevelDb(path string) *leveldb1.LevelDB { 44 | return _leveldb.InitLevelDb(path) 45 | } 46 | -------------------------------------------------------------------------------- /server-common/driver/es.go: -------------------------------------------------------------------------------- 1 | package driver 2 | 3 | import ( 4 | _elastic "github.com/mazezen/ginframe/server-common/pkg/elastic" 5 | "github.com/olivere/elastic" 6 | ) 7 | 8 | func InitEs(url string) (*elastic.Client, error) { 9 | es, err := _elastic.NewEs(url) 10 | if err != nil { 11 | return nil, err 12 | } 13 | return es, nil 14 | } 15 | -------------------------------------------------------------------------------- /server-common/nacosRF/init.go: -------------------------------------------------------------------------------- 1 | package nacosRF 2 | 3 | import ( 4 | "github.com/nacos-group/nacos-sdk-go/clients" 5 | "github.com/nacos-group/nacos-sdk-go/clients/naming_client" 6 | "github.com/nacos-group/nacos-sdk-go/common/constant" 7 | "github.com/nacos-group/nacos-sdk-go/vo" 8 | "go.uber.org/zap" 9 | "log" 10 | ) 11 | 12 | const ( 13 | clusters = "GIN_FRAME" 14 | groupName = "GIN_FRAME_GROUP" 15 | ) 16 | 17 | type WarningConfig struct { 18 | RoomId int 19 | Url string 20 | } 21 | 22 | type NacosConfig struct { 23 | Addr string 24 | Port int 25 | LogPath string 26 | CachePath string 27 | } 28 | 29 | type nacosRF struct { 30 | client naming_client.INamingClient 31 | } 32 | 33 | var NacosInstance *nacosRF 34 | 35 | // InitNacos init Nacos 36 | func InitNacos(config *NacosConfig) *nacosRF { 37 | //return &nacosRF{} 38 | d := &nacosRF{} 39 | clientConfig := constant.ClientConfig{ 40 | TimeoutMs: 5000, 41 | NotLoadCacheAtStart: true, 42 | LogDir: config.LogPath, 43 | CacheDir: config.CachePath, 44 | LogLevel: "debug", 45 | } 46 | 47 | serverConfigs := []constant.ServerConfig{ 48 | { 49 | IpAddr: config.Addr, 50 | ContextPath: "/nacos", 51 | Port: uint64(config.Port), 52 | Scheme: "http", 53 | }, 54 | } 55 | 56 | var err error 57 | d.client, err = clients.NewNamingClient( 58 | vo.NacosClientParam{ 59 | ClientConfig: &clientConfig, 60 | ServerConfigs: serverConfigs, 61 | }, 62 | ) 63 | if err != nil { 64 | log.Fatal("nacos失败了,err:%v", zap.Error(err)) 65 | } 66 | 67 | NacosInstance = d 68 | return d 69 | } 70 | -------------------------------------------------------------------------------- /server-common/nacosRF/serverFind.go: -------------------------------------------------------------------------------- 1 | package nacosRF 2 | 3 | import ( 4 | "github.com/nacos-group/nacos-sdk-go/model" 5 | "github.com/nacos-group/nacos-sdk-go/vo" 6 | ) 7 | 8 | type ServerInfo struct { 9 | Ip string 10 | Port uint64 11 | ServerName string 12 | } 13 | 14 | // FindOneInstance 获取某个服务连接信息 15 | func (this *nacosRF) FindOneInstance(serverName string) (*ServerInfo, error) { 16 | instance, err := this.client.SelectOneHealthyInstance(vo.SelectOneHealthInstanceParam{ 17 | Clusters: []string{clusters}, 18 | ServiceName: serverName, 19 | GroupName: groupName, 20 | }) 21 | if err != nil { 22 | return nil, err 23 | } 24 | return &ServerInfo{ 25 | Ip: instance.Ip, 26 | Port: instance.Port, 27 | ServerName: instance.ServiceName, 28 | }, nil 29 | } 30 | 31 | // FindAllInstance 获取全部服务连接信息 32 | func (this *nacosRF) FindAllInstance(serverName string) ([]*ServerInfo, error) { 33 | ins, err := this.client.SelectInstances(vo.SelectInstancesParam{ 34 | Clusters: []string{clusters}, 35 | ServiceName: serverName, 36 | GroupName: groupName, 37 | HealthyOnly: true, 38 | }) 39 | if err != nil { 40 | return nil, err 41 | } 42 | infos := make([]*ServerInfo, 0) 43 | for _, info := range ins { 44 | infos = append(infos, &ServerInfo{ 45 | Ip: info.Ip, 46 | Port: info.Port, 47 | ServerName: info.ServiceName, 48 | }) 49 | } 50 | return infos, nil 51 | } 52 | 53 | // ListenInstance 监听某个服务状态信息 54 | func (this *nacosRF) ListenInstance(serverName string, callback func(server *ServerInfo)) { 55 | this.client.Subscribe(&vo.SubscribeParam{ 56 | ServiceName: serverName, 57 | Clusters: []string{clusters}, 58 | GroupName: groupName, 59 | SubscribeCallback: func(services []model.SubscribeService, err error) { 60 | for _, service := range services { 61 | if service.Enable && service.Healthy { 62 | callback(&ServerInfo{ 63 | Ip: service.Ip, 64 | Port: service.Port, 65 | ServerName: service.ServiceName, 66 | }) 67 | } 68 | } 69 | }, 70 | }) 71 | } 72 | -------------------------------------------------------------------------------- /server-common/nacosRF/serverRegister.go: -------------------------------------------------------------------------------- 1 | package nacosRF 2 | 3 | import ( 4 | "fmt" 5 | "github.com/mazezen/ginframe/server-common/utils/ip" 6 | "github.com/nacos-group/nacos-sdk-go/vo" 7 | "log" 8 | ) 9 | 10 | func (this *nacosRF) Register(serverName string, port int) { 11 | ok, err := this.client.RegisterInstance(vo.RegisterInstanceParam{ 12 | Ip: _ip.GetIp(), 13 | Port: uint64(port), 14 | Weight: 10, 15 | Enable: true, 16 | Healthy: true, 17 | Metadata: map[string]string{}, 18 | ClusterName: clusters, 19 | ServiceName: serverName, 20 | GroupName: groupName, 21 | Ephemeral: true, 22 | }) 23 | if err != nil { 24 | log.Fatal(err) 25 | } 26 | if !ok { 27 | log.Fatal(fmt.Sprintf("注册服务【%s】发生错误", serverName)) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /server-common/pkg/elastic/elastic.go: -------------------------------------------------------------------------------- 1 | package _elastic 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "github.com/olivere/elastic" 7 | "log" 8 | "os" 9 | ) 10 | 11 | // NewEs new elastic 12 | func NewEs(url string) (*elastic.Client, error) { 13 | var err error 14 | logger := log.New(os.Stdout, "gin-frame", log.LstdFlags) 15 | esClient, err := elastic.NewClient(elastic.SetErrorLog(logger), 16 | elastic.SetSniff(false), elastic.SetURL(url)) 17 | if err != nil { 18 | panic(err) 19 | } 20 | do, i, err := esClient.Ping(url).Do(context.Background()) 21 | if err != nil { 22 | panic(err) 23 | } 24 | fmt.Println(fmt.Sprintf("Es result with code %d and version %v\n", i, do.Version)) 25 | return esClient, err 26 | } 27 | -------------------------------------------------------------------------------- /server-common/pkg/gorm/gorm.go: -------------------------------------------------------------------------------- 1 | package _gorm 2 | 3 | import ( 4 | "errors" 5 | "gorm.io/driver/mysql" 6 | "gorm.io/gorm" 7 | "gorm.io/gorm/logger" 8 | "gorm.io/gorm/schema" 9 | "time" 10 | ) 11 | 12 | // InitGormMysql gorm 初始化mysql连接 13 | func InitGormMysql(dsn string, args ...[]int) (*gorm.DB, error) { 14 | db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{ 15 | SkipDefaultTransaction: false, 16 | NamingStrategy: schema.NamingStrategy{ 17 | SingularTable: true, // 禁用表名加s 18 | }, 19 | Logger: logger.Default.LogMode(logger.Info), // 打印sql语句 20 | DisableAutomaticPing: false, 21 | DisableForeignKeyConstraintWhenMigrating: true, // 禁用创建外键约束 22 | }) 23 | if err != nil { 24 | return nil, err 25 | } 26 | 27 | sqlDB, _ := db.DB() 28 | if len(args) > 0 { 29 | if len(args[0]) >= 3 { 30 | return nil, errors.New("参数错误") 31 | } 32 | if len(args[0]) == 1 { 33 | // 设置数据库连接池最大连接数 34 | sqlDB.SetMaxOpenConns(args[0][0]) 35 | } 36 | if len(args[0]) == 2 { 37 | // 连接池最大允许的空闲连接数 38 | sqlDB.SetMaxIdleConns(args[0][1]) 39 | } 40 | } else { 41 | // 设置数据库连接池最大连接数 100 42 | sqlDB.SetMaxOpenConns(100) 43 | // 连接池最大允许的空闲连接数 20 44 | sqlDB.SetMaxIdleConns(20) 45 | } 46 | 47 | go func() { 48 | for { 49 | sqlDB.Ping() 50 | time.Sleep(1 * time.Hour) 51 | } 52 | }() 53 | 54 | return db, nil 55 | } 56 | -------------------------------------------------------------------------------- /server-common/pkg/httprequest/httprequest.go: -------------------------------------------------------------------------------- 1 | package httprequest 2 | 3 | import ( 4 | "bytes" 5 | "github.com/mazezen/gorequest" 6 | ) 7 | 8 | type HttpRequest struct{} 9 | 10 | // Get http get 11 | func (hr *HttpRequest) Get(url string, header map[string]string, params map[string]interface{}) ([]byte, error) { 12 | return gorequest.Get(url, header, params) 13 | } 14 | 15 | // Post http post 16 | func (hr *HttpRequest) Post(url string, header map[string]string, params map[string]interface{}) ([]byte, error) { 17 | return gorequest.Post(url, header, params) 18 | } 19 | 20 | // PostMultipart http post multipart 21 | func (hr *HttpRequest) PostMultipart(url string, header map[string]string, payload *bytes.Buffer) ([]byte, error) { 22 | return gorequest.PostMultipart(url, header, payload) 23 | } 24 | -------------------------------------------------------------------------------- /server-common/pkg/jwt/jwt.go: -------------------------------------------------------------------------------- 1 | package _jwt 2 | 3 | import ( 4 | "errors" 5 | "github.com/dgrijalva/jwt-go" 6 | "sync" 7 | "time" 8 | ) 9 | 10 | var ( 11 | EXPIRE time.Duration 12 | SECRET string 13 | lazyClimsInstance *JwtClaims 14 | once sync.Once 15 | ) 16 | 17 | type JwtClaims struct { 18 | ID interface{} `json:"id"` 19 | Username string `json:"username"` 20 | jwt.StandardClaims 21 | } 22 | 23 | func NewJwtInstance(expire time.Duration, secret string) *JwtClaims { 24 | if lazyClimsInstance == nil { 25 | once.Do(func() { 26 | EXPIRE = expire 27 | SECRET = secret 28 | lazyClimsInstance = &JwtClaims{} 29 | }) 30 | } 31 | return lazyClimsInstance 32 | } 33 | 34 | // GenerateToken 签发Token 35 | func (j *JwtClaims) GenerateToken(claims *JwtClaims) (string, error) { 36 | c := JwtClaims{ 37 | ID: claims.ID, 38 | Username: claims.Username, 39 | StandardClaims: jwt.StandardClaims{ 40 | ExpiresAt: time.Now().Add(EXPIRE).Unix(), 41 | }, 42 | } 43 | token := jwt.NewWithClaims(jwt.SigningMethodHS256, c) 44 | return token.SignedString([]byte(SECRET)) 45 | } 46 | 47 | // ParseToken 解析TOKEN 48 | func (j *JwtClaims) ParseToken(token string) (*JwtClaims, error) { 49 | t, err := jwt.ParseWithClaims(token, &JwtClaims{}, 50 | func(token *jwt.Token) (interface{}, error) { 51 | return []byte(SECRET), nil 52 | }) 53 | if err != nil { 54 | return nil, err 55 | } 56 | 57 | if claims, ok := t.Claims.(*JwtClaims); ok && t.Valid { 58 | return claims, nil 59 | } 60 | 61 | return nil, errors.New("invalid token") 62 | } 63 | -------------------------------------------------------------------------------- /server-common/pkg/leveldb/leveldb.go: -------------------------------------------------------------------------------- 1 | package _leveldb 2 | 3 | import ( 4 | leveldb1 "github.com/mazezen/leveldb" 5 | ) 6 | 7 | func InitLevelDb(path string) *leveldb1.LevelDB { 8 | db, err := leveldb1.CreateLevelDB(path) 9 | if err != nil { 10 | panic(err) 11 | } 12 | return db 13 | } 14 | -------------------------------------------------------------------------------- /server-common/pkg/mongo/mongo.go: -------------------------------------------------------------------------------- 1 | package _mongo 2 | 3 | import ( 4 | "context" 5 | "go.mongodb.org/mongo-driver/mongo" 6 | "go.mongodb.org/mongo-driver/mongo/options" 7 | ) 8 | 9 | // InitMongoDb mongodb 连接 10 | func InitMongoDb(addr string) (*mongo.Client, error) { 11 | clientOptions := options.Client().ApplyURI(addr) 12 | 13 | client, err := mongo.Connect(context.TODO(), clientOptions) 14 | if err != nil { 15 | return nil, err 16 | } 17 | 18 | if err = client.Ping(context.TODO(), nil); err != nil { 19 | return nil, err 20 | } 21 | return client, nil 22 | } 23 | -------------------------------------------------------------------------------- /server-common/pkg/redis/redis.go: -------------------------------------------------------------------------------- 1 | package _redis 2 | 3 | import ( 4 | "gopkg.in/redis.v5" 5 | ) 6 | 7 | // InitRedis 初始化redis 8 | func InitRedis(addr, pass string, rdb int) (*redis.Client, error) { 9 | client := redis.NewClient(&redis.Options{ 10 | Addr: addr, 11 | Password: pass, 12 | DB: rdb, 13 | }) 14 | _, err := client.Ping().Result() 15 | if err != nil { 16 | return nil, err 17 | } 18 | return client, nil 19 | } 20 | -------------------------------------------------------------------------------- /server-common/pkg/uber/zap.go: -------------------------------------------------------------------------------- 1 | package _uber 2 | 3 | import ( 4 | "github.com/robfig/cron" 5 | "go.uber.org/zap" 6 | "go.uber.org/zap/zapcore" 7 | "gopkg.in/natefinch/lumberjack.v2" 8 | "os" 9 | ) 10 | 11 | // InitLogger 初始化logger日志 12 | func InitLogger(filepath string) *zap.Logger { 13 | encoder := getEncoder() 14 | writeSyncer := getLogWriter(filepath) 15 | core := zapcore.NewCore(encoder, writeSyncer, zapcore.DebugLevel) 16 | consoleDebug := zapcore.Lock(os.Stdout) 17 | consoleEncoder := zapcore.NewConsoleEncoder(zap.NewDevelopmentEncoderConfig()) 18 | p := zap.LevelEnablerFunc(func(level zapcore.Level) bool { 19 | return level >= zapcore.DebugLevel 20 | }) 21 | var allCode []zapcore.Core 22 | allCode = append(allCode, core) 23 | allCode = append(allCode, zapcore.NewCore(consoleEncoder, consoleDebug, p)) 24 | c := zapcore.NewTee(allCode...) 25 | return zap.New(c, zap.AddCaller()) 26 | } 27 | 28 | func getEncoder() zapcore.Encoder { 29 | encoderConfig := zap.NewProductionEncoderConfig() 30 | encoderConfig.EncodeTime = zapcore.TimeEncoderOfLayout("2006-01-02 15:04:05") 31 | encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder 32 | return zapcore.NewConsoleEncoder(encoderConfig) 33 | } 34 | 35 | func getLogWriter(filepath string) zapcore.WriteSyncer { 36 | lumberJackLogger := &lumberjack.Logger{ 37 | Filename: filepath, 38 | MaxSize: 10240, 39 | MaxAge: 7, 40 | Compress: true, 41 | LocalTime: true, 42 | } 43 | 44 | c := cron.New() 45 | c.AddFunc("0 0 0 1/1 * ?", func() { 46 | lumberJackLogger.Rotate() 47 | }) 48 | c.Start() 49 | return zapcore.AddSync(lumberJackLogger) 50 | } 51 | -------------------------------------------------------------------------------- /server-common/pkg/viper/viper.go: -------------------------------------------------------------------------------- 1 | package _viper 2 | 3 | import ( 4 | "github.com/nacos-group/nacos-sdk-go/clients" 5 | "github.com/nacos-group/nacos-sdk-go/common/constant" 6 | "github.com/nacos-group/nacos-sdk-go/vo" 7 | "github.com/spf13/viper" 8 | "strings" 9 | ) 10 | 11 | // ParseViperConfig 解析配置文件 12 | func ParseViperConfig(path string, config interface{}) { 13 | viper.SetConfigFile(path) 14 | if err := viper.ReadInConfig(); err != nil { 15 | panic(err) 16 | } 17 | if err := viper.Unmarshal(config); err != nil { 18 | panic(err) 19 | } 20 | } 21 | 22 | // LoadCoreConfig 加载nacos配置 23 | func LoadCoreConfig(ip string, port int, cfg string, group string, config interface{}) { 24 | serverConfigs := []constant.ServerConfig{ 25 | {IpAddr: ip, Port: uint64(port)}, 26 | } 27 | nacosClient, err := clients.NewConfigClient(vo.NacosClientParam{ 28 | ClientConfig: &constant.ClientConfig{TimeoutMs: 5000}, 29 | ServerConfigs: serverConfigs, 30 | }) 31 | if err != nil { 32 | panic(err) 33 | } 34 | content, err := nacosClient.GetConfig(vo.ConfigParam{ 35 | DataId: cfg, 36 | Group: group, 37 | }) 38 | if err != nil { 39 | panic(err) 40 | } 41 | viper.SetConfigType("yaml") 42 | err = viper.ReadConfig(strings.NewReader(content)) 43 | if err != nil { 44 | panic(err) 45 | } 46 | err = viper.Unmarshal(config) 47 | if err != nil { 48 | panic(err) 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /server-common/pkg/wetcd/etcd.go: -------------------------------------------------------------------------------- 1 | package wetcd 2 | 3 | import ( 4 | "context" 5 | clientv3 "go.etcd.io/etcd/client/v3" 6 | "time" 7 | ) 8 | 9 | func InitSingleEtcd(addr string) (*clientv3.Client, error) { 10 | client, err := clientv3.New(clientv3.Config{ 11 | Endpoints: []string{addr}, 12 | DialTimeout: 5 * time.Second, 13 | }) 14 | if err != nil { 15 | 16 | } 17 | return client, err 18 | } 19 | 20 | func InitClusterEtcd(addr []string) (*clientv3.Client, error) { 21 | client, err := clientv3.New(clientv3.Config{ 22 | Endpoints: addr, 23 | DialTimeout: 5 * time.Second, 24 | }) 25 | if err != nil { 26 | 27 | } 28 | return client, err 29 | } 30 | 31 | type Wetcd struct{} 32 | 33 | func (w *Wetcd) Put(client *clientv3.Client, key, value string) (err error) { 34 | ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) 35 | defer cancel() 36 | _, err = client.Put(ctx, key, value) 37 | return 38 | } 39 | 40 | func (w *Wetcd) Get(client *clientv3.Client, key string) (string, error) { 41 | ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) 42 | defer cancel() 43 | res, err := client.Get(ctx, key) 44 | if err != nil { 45 | return "", err 46 | } 47 | var result string 48 | for _, v := range res.Kvs { 49 | result = string(v.Value) 50 | } 51 | return result, nil 52 | } 53 | 54 | func (w *Wetcd) Update(client *clientv3.Client, key, value string) (err error) { 55 | ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) 56 | defer cancel() 57 | _, err = client.Put(ctx, key, value) 58 | return 59 | } 60 | 61 | func (w *Wetcd) Delete(client *clientv3.Client, key string) (err error) { 62 | ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) 63 | defer cancel() 64 | _, err = client.Delete(ctx, key) 65 | return 66 | } 67 | -------------------------------------------------------------------------------- /server-common/pkg/wkafka/consumer.go: -------------------------------------------------------------------------------- 1 | package wkafka 2 | 3 | import ( 4 | "github.com/Shopify/sarama" 5 | "log" 6 | "strings" 7 | ) 8 | 9 | var consumer sarama.Consumer 10 | 11 | // InitConsumer 消费者 12 | func InitConsumer(hosts string) { 13 | config := sarama.NewConfig() 14 | client, err := sarama.NewClient(strings.Split(hosts, ","), config) 15 | if err != nil { 16 | log.Printf("init kafka consumer client error: %v\n", err) 17 | } 18 | consumer, err = sarama.NewConsumerFromClient(client) 19 | if err != nil { 20 | log.Printf("init kafka consumer client error: %v\n", err) 21 | } 22 | } 23 | 24 | type ConsumerCallback func(data []byte) 25 | 26 | // ConsumerMsg 消费消息 通过回调函数进行 27 | func ConsumerMsg(callBack ConsumerCallback) { 28 | partitionConsumer, err := consumer.ConsumePartition(topic, 0, sarama.OffsetNewest) 29 | if nil != err { 30 | log.Printf("iConsumePartition error: %v\n", err) 31 | return 32 | } 33 | 34 | defer partitionConsumer.Close() 35 | for { 36 | msg := <-partitionConsumer.Messages() 37 | if nil != callBack { 38 | callBack(msg.Value) 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /server-common/pkg/wkafka/producer.go: -------------------------------------------------------------------------------- 1 | package wkafka 2 | 3 | import ( 4 | "github.com/Shopify/sarama" 5 | "log" 6 | "strings" 7 | ) 8 | 9 | var ( 10 | producer sarama.AsyncProducer 11 | topic = "default_message" 12 | ) 13 | 14 | // InitProducer 生产者 15 | func InitProducer(topicInput, hosts string) { 16 | topic = topicInput 17 | config := sarama.NewConfig() 18 | config.Producer.Compression = sarama.CompressionGZIP 19 | client, err := sarama.NewClient(strings.Split(hosts, ","), config) 20 | if err != nil { 21 | log.Printf("init kafka client err: %v\n", err) 22 | } 23 | producer, err = sarama.NewAsyncProducerFromClient(client) 24 | if err != nil { 25 | log.Printf("init kafka async client err: %v\n", err) 26 | } 27 | } 28 | 29 | func Send(data []byte) { 30 | b := sarama.ByteEncoder(data) 31 | producer.Input() <- &sarama.ProducerMessage{ 32 | Topic: topic, 33 | Key: nil, 34 | Value: b, 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /server-common/process/process.go: -------------------------------------------------------------------------------- 1 | package _process 2 | 3 | import "runtime" 4 | 5 | func GroRuntimeMaxCpu() { 6 | runtime.GOMAXPROCS(runtime.NumCPU()) 7 | } 8 | -------------------------------------------------------------------------------- /server-common/servers/servers.go: -------------------------------------------------------------------------------- 1 | package servers 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | _const "github.com/mazezen/ginframe/server-common/const" 7 | "github.com/mazezen/ginframe/server-common/nacosRF" 8 | "github.com/mazezen/ginframe/server-user/pb" 9 | "google.golang.org/grpc" 10 | "sync" 11 | ) 12 | 13 | type Servers struct { 14 | conn *grpc.ClientConn 15 | } 16 | 17 | var ( 18 | userMap sync.Map 19 | rpcUser sync.Once 20 | ) 21 | 22 | func init() { 23 | userMap = sync.Map{} 24 | } 25 | 26 | // GetUserRpcServer 发现用户服 27 | func GetUserRpcServer(index string) pb.RpcUserServiceClient { 28 | serverName := fmt.Sprintf(_const.UserServerName + index) 29 | v, has := userMap.Load(serverName) 30 | if !has { 31 | info, err := nacosRF.NacosInstance.FindOneInstance(serverName) 32 | if err != nil { 33 | return nil 34 | } 35 | 36 | //conn, err := grpc.Dial(fmt.Sprintf("%s:%d", info.Ip, info.Port), grpc.WithInsecure()) 37 | conn, err := grpc.DialContext(context.Background(), fmt.Sprintf("%s:%d", info.Ip, info.Port), 38 | grpc.WithInsecure(), grpc.WithDisableHealthCheck()) 39 | if err != nil { 40 | return nil 41 | } 42 | p := pb.NewRpcUserServiceClient(conn) 43 | userMap.Store(serverName, p) 44 | go func() { 45 | rpcUser.Do(func() { 46 | nacosRF.NacosInstance.ListenInstance(serverName, func(server *nacosRF.ServerInfo) { 47 | info, err := nacosRF.NacosInstance.FindOneInstance(serverName) 48 | if err != nil { 49 | return 50 | } 51 | conn, err := grpc.DialContext(context.Background(), fmt.Sprintf("%s:%s", info.Ip, info.Port), 52 | grpc.WithInsecure(), grpc.WithDisableHealthCheck()) 53 | if err != nil { 54 | return 55 | } 56 | p = pb.NewRpcUserServiceClient(conn) 57 | userMap.Store(serverName, p) 58 | }) 59 | }) 60 | }() 61 | return p 62 | } 63 | return v.(pb.RpcUserServiceClient) 64 | } 65 | -------------------------------------------------------------------------------- /server-common/utils/email/email.go: -------------------------------------------------------------------------------- 1 | package email 2 | 3 | import ( 4 | "crypto/tls" 5 | "fmt" 6 | "github.com/jordan-wright/email" 7 | "net/smtp" 8 | ) 9 | 10 | // SendMail 发送邮件 11 | // 支持 163邮箱、QQ邮箱、126邮箱 12 | // from 发件人邮箱 `xxxx@163.com`、`xxxx@qq.com`、`xxxx@126.com` 13 | // to 接受人邮箱 14 | // title 邮箱标题 15 | // content 邮箱内容 16 | // mailServer 163邮箱服务地址 163: `smtp.163.com`、 QQ邮箱: `smtp.qq.com`、 126邮箱: `smtp.126.com` 17 | // mailServerPort 163邮箱端口 163: `:465` 、 QQ邮箱端口: `:465`、 126邮箱: `:465` 18 | // mailPassword 163邮箱、QQ邮箱、126邮箱 授权码 `xxxxxxxxxxx` 19 | func SendMail(from, to, title, content, mailServer, mailServerPort, mailPassword string) (err error) { 20 | e := email.NewEmail() 21 | e.From = from 22 | e.To = []string{to} 23 | e.Subject = title 24 | e.HTML = []byte(content) 25 | return e.SendWithTLS(fmt.Sprintf("%s%s", mailServer, mailServerPort), 26 | smtp.PlainAuth("", from, mailPassword, mailServer), 27 | &tls.Config{InsecureSkipVerify: true, ServerName: mailServer}) 28 | } 29 | 30 | // SendGmailEmail 发送谷歌邮件 31 | // 支持 Gmail邮箱 32 | // from 发件人邮箱 `xxxx@gmail.com` 33 | // to 接受人邮箱 34 | // title 邮箱标题 35 | // content 邮箱内容 36 | // mailServer Gmail邮箱服务地址 `smtp.gmail.com` 37 | // mailServerPort Gmail邮箱端口 `:587` 38 | // mailPassword Gmail邮箱登陆密码 39 | func SendGmailEmail(from, to, title, content, mailServer, mailServerPort, mailPassword string) (err error) { 40 | e := email.NewEmail() 41 | e.From = from 42 | e.To = []string{to} 43 | e.Subject = title 44 | e.HTML = []byte(content) 45 | return e.SendWithStartTLS(fmt.Sprintf("%s%s", mailServer, mailServerPort), 46 | smtp.PlainAuth("", from, mailPassword, mailServer), 47 | &tls.Config{InsecureSkipVerify: true, ServerName: mailServer}) 48 | } 49 | 50 | // SendGmail 发送谷歌邮件 支持同时给多人发送 51 | func SendGmail(from string, to []string, content []byte, mailServer, mailServerPort, mailPassword string) (err error) { 52 | auth := smtp.PlainAuth("", from, mailPassword, mailServer) 53 | return smtp.SendMail(mailServer+mailServerPort, auth, from, to, content) 54 | } 55 | -------------------------------------------------------------------------------- /server-common/utils/encry/aes.go: -------------------------------------------------------------------------------- 1 | package encry 2 | 3 | import ( 4 | "bytes" 5 | "crypto/aes" 6 | "crypto/cipher" 7 | "encoding/base64" 8 | ) 9 | 10 | type AesEncrypt struct { 11 | key []byte 12 | iv []byte 13 | block cipher.Block 14 | } 15 | 16 | func NewAesEncryptInstance(key string, secret string) (*AesEncrypt, error) { 17 | b, err := aes.NewCipher([]byte(key)) 18 | if err != nil { 19 | return nil, err 20 | } 21 | a := &AesEncrypt{ 22 | key: []byte(key), 23 | iv: []byte(secret), 24 | block: b, 25 | } 26 | return a, nil 27 | } 28 | 29 | // AesBase64Encrypt aes Base64 加密 30 | func (a *AesEncrypt) AesBase64Encrypt(in string) (string, error) { 31 | origData := []byte(in) 32 | origData = PKCS5Adding(origData, a.block.BlockSize()) 33 | crypted := make([]byte, len(origData)) 34 | bm := cipher.NewCBCEncrypter(a.block, a.iv) 35 | bm.CryptBlocks(crypted, origData) 36 | var b = base64.StdEncoding.EncodeToString(crypted) 37 | return b, nil 38 | } 39 | 40 | // AesBase64Decrypt aes Base64 解密 41 | func (a *AesEncrypt) AesBase64Decrypt(b string) (string, error) { 42 | crypted, err := base64.StdEncoding.DecodeString(b) 43 | if err != nil { 44 | return "", err 45 | } 46 | origData := make([]byte, len(crypted)) 47 | bm := cipher.NewCBCDecrypter(a.block, a.iv) 48 | bm.CryptBlocks(origData, crypted) 49 | origData = PKCS5UnPadding(origData) 50 | var out = string(origData) 51 | return out, nil 52 | } 53 | 54 | func PKCS5Adding(ciphertext []byte, blockSize int) []byte { 55 | padding := blockSize - len(ciphertext)%blockSize 56 | padText := bytes.Repeat([]byte{byte(padding)}, padding) 57 | return append(ciphertext, padText...) 58 | } 59 | 60 | func PKCS5UnPadding(origData []byte) []byte { 61 | length := len(origData) 62 | unPadding := int(origData[length-1]) 63 | return origData[:(length - unPadding)] 64 | } 65 | -------------------------------------------------------------------------------- /server-common/utils/encry/encry.go: -------------------------------------------------------------------------------- 1 | package encry 2 | 3 | import ( 4 | "crypto/md5" 5 | "crypto/sha256" 6 | "crypto/sha512" 7 | "encoding/hex" 8 | "fmt" 9 | "golang.org/x/crypto/bcrypt" 10 | "io" 11 | "log" 12 | "os" 13 | ) 14 | 15 | // Md5 md5加密 16 | func Md5(str string) string { 17 | w := md5.New() 18 | io.WriteString(w, str) 19 | return fmt.Sprintf("%x", w.Sum(nil)) 20 | } 21 | 22 | // Sha256 加密 23 | func Sha256(str string) string { 24 | srcByte := []byte(str) 25 | hash := sha256.New() 26 | hash.Write(srcByte) 27 | hashBytes := hash.Sum(nil) 28 | sha256String := hex.EncodeToString(hashBytes) 29 | return sha256String 30 | } 31 | 32 | // Sha512 加密 33 | func Sha512(str string) string { 34 | srcByte := []byte(str) 35 | hash := sha512.New() 36 | hash.Write(srcByte) 37 | hashBytes := hash.Sum(nil) 38 | sha256String := hex.EncodeToString(hashBytes) 39 | return sha256String 40 | } 41 | 42 | // FileMd5 文件加密 43 | func FileMd5(file string) (string, error) { 44 | f, err := os.Open(file) 45 | if err != nil { 46 | return "", err 47 | } 48 | hash := md5.New() 49 | _, err = io.Copy(hash, f) 50 | if err != nil { 51 | return "", err 52 | } 53 | md5Str := hex.EncodeToString(hash.Sum(nil)) 54 | return md5Str, nil 55 | } 56 | 57 | // ScryptPasswd 密码 + 盐(一串随机数) 再Hash加密 58 | func ScryptPasswd(password string) string { 59 | const cost = 10 60 | hashPwd, err := bcrypt.GenerateFromPassword([]byte(password), cost) 61 | if err != nil { 62 | log.Fatal(err) 63 | } 64 | return string(hashPwd) 65 | } 66 | 67 | // ComparePassword 密码比较 68 | func ComparePassword(hashedPassword, password string) error { 69 | return bcrypt.CompareHashAndPassword([]byte(hashedPassword), []byte(password)) 70 | } 71 | -------------------------------------------------------------------------------- /server-common/utils/enum/code.go: -------------------------------------------------------------------------------- 1 | package enum 2 | 3 | type codes struct { 4 | SUCCESS uint 5 | FAILED uint 6 | PARAMERR uint 7 | TOKENISNOTEXISTS uint 8 | TOKENISVALID uint 9 | USERISDISABLE uint 10 | 11 | MESSAGE map[uint]string 12 | } 13 | 14 | var ApiCode = &codes{ 15 | SUCCESS: 2000, 16 | FAILED: 1000, 17 | PARAMERR: 10001, 18 | TOKENISNOTEXISTS: 401, 19 | TOKENISVALID: 402, 20 | USERISDISABLE: 403, 21 | } 22 | 23 | func InitMapCode() { 24 | ApiCode.MESSAGE = map[uint]string{ 25 | ApiCode.SUCCESS: "成功", 26 | ApiCode.FAILED: "失败", 27 | ApiCode.PARAMERR: "参数错误", 28 | ApiCode.TOKENISNOTEXISTS: "token不存在,非法请求", 29 | ApiCode.TOKENISVALID: "token无效,非法请求", 30 | ApiCode.USERISDISABLE: "账号被禁用,请联系管理员处理", 31 | } 32 | } 33 | 34 | func (c *codes) GetMessage(code uint) string { 35 | message, ok := c.MESSAGE[code] 36 | if !ok { 37 | return "未定义的状态码" 38 | } 39 | return message 40 | } 41 | -------------------------------------------------------------------------------- /server-common/utils/enum/response.go: -------------------------------------------------------------------------------- 1 | package enum 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "net/http" 6 | "sync" 7 | "time" 8 | ) 9 | 10 | var ( 11 | Result *result 12 | once sync.Once 13 | PageL *pageList 14 | ) 15 | 16 | type result struct { 17 | Time time.Time `json:"time"` 18 | Code uint `json:"code"` 19 | Msg string `json:"msg"` 20 | Data interface{} `json:"data"` 21 | } 22 | 23 | // Success 成功返回 24 | func (res *result) Success(c *gin.Context, data ...interface{}) { 25 | var d interface{} 26 | if data != nil { 27 | d = data[0] 28 | } else { 29 | d = data 30 | } 31 | res.Time = time.Now() 32 | res.Code = ApiCode.SUCCESS 33 | res.Msg = ApiCode.GetMessage(ApiCode.SUCCESS) 34 | res.Data = d 35 | c.JSON(http.StatusOK, res) 36 | } 37 | 38 | // Error 失败返回 39 | func (res *result) Error(c *gin.Context, code uint, msg string) { 40 | res.Time = time.Now() 41 | res.Code = code 42 | res.Msg = msg 43 | res.Data = gin.H{} 44 | c.JSON(http.StatusOK, res) 45 | } 46 | 47 | type pageList struct { 48 | Total int64 `json:"total"` 49 | List interface{} `json:"list"` 50 | } 51 | 52 | // Pagination 分页 53 | func (p *pageList) Pagination(count int64, list interface{}) *pageList { 54 | return &pageList{ 55 | Total: count, 56 | List: list, 57 | } 58 | } 59 | 60 | func init() { 61 | InitMapCode() 62 | once.Do(func() { 63 | Result = &result{} 64 | PageL = &pageList{} 65 | }) 66 | } 67 | -------------------------------------------------------------------------------- /server-common/utils/ip/ip.go: -------------------------------------------------------------------------------- 1 | package _ip 2 | 3 | import "net" 4 | 5 | var ip = "" 6 | 7 | func GetIp() string { 8 | if ip != "" { 9 | return ip 10 | } 11 | addrs, err := net.InterfaceAddrs() 12 | if err != nil { 13 | panic("获取本机地址失败:" + err.Error()) 14 | } 15 | for _, address := range addrs { 16 | if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() && ipnet.IP.IsPrivate() { 17 | if ipnet.IP.To4() != nil { 18 | ip = ipnet.IP.String() 19 | return ip 20 | } 21 | } 22 | } 23 | panic("获取本机地址失败") 24 | } 25 | -------------------------------------------------------------------------------- /server-common/utils/maps/map.go: -------------------------------------------------------------------------------- 1 | package maps 2 | 3 | import "sync" 4 | 5 | // MergeMap 6 | // desc: 合并源 map 到目标 map 7 | func MergeMap(dest, src map[interface{}]interface{}) map[interface{}]interface{} { 8 | out := make(map[interface{}]interface{}, len(dest)) 9 | for k, v := range dest { 10 | out[k] = v 11 | } 12 | for k, v := range src { 13 | value := v 14 | if av, ok := out[k]; ok { 15 | if v, ok := v.(map[interface{}]interface{}); ok { 16 | if av, ok := av.(map[interface{}]interface{}); ok { 17 | out[k] = MergeMap(av, v) 18 | } else { 19 | out[k] = v 20 | } 21 | } else { 22 | out[k] = value 23 | } 24 | } else { 25 | out[k] = v 26 | } 27 | } 28 | return out 29 | } 30 | 31 | type ConcurrencyRwMap struct { 32 | Map map[interface{}]interface{} 33 | sync.RWMutex 34 | } 35 | 36 | // Go语言原生的map类型并不支持并发读写。 37 | // concurrent-map提供了一种高性能的解决方案:通过对内部map进行分片,降低锁粒度,从而达到最少的锁等待时间(锁冲突) 38 | // 在Go 1.9之前,go语言标准库中并没有实现并发map。 39 | // 在Go 1.9中,引入了sync.Map。新的sync.Map与此concurrent-map有几个关键区别。 40 | // 标准库中的sync.Map是专为append-only场景设计的。 41 | // 因此,如果您想将Map用于一个类似内存数据库,那么使用我们的版本可能会受益。 42 | // 你可以在golang repo上读到更多,这里 and 这里 译注:sync.Map在读多写少性能比较好,否则并发性能很差 43 | // https://github.com/orcaman/concurrent-map 44 | // 三中方案 sync.Map、 concurrent-map 、以及 NewConcurrencyRwMap 自行选择 45 | 46 | // NewConcurrencyRwMap 加锁实现map并发安全,缺点锁的粒度大 47 | func NewConcurrencyRwMap(capacity int) *ConcurrencyRwMap { 48 | if capacity < 0 { 49 | capacity = 0 50 | } 51 | return &ConcurrencyRwMap{ 52 | Map: make(map[interface{}]interface{}, capacity), 53 | } 54 | } 55 | 56 | // Set 写入 或者 更新 57 | func (m *ConcurrencyRwMap) Set(key interface{}, value interface{}) { 58 | m.Lock() 59 | defer m.Unlock() 60 | m.Map[key] = value 61 | } 62 | 63 | // Get 读 64 | func (m *ConcurrencyRwMap) Get(key interface{}) interface{} { 65 | m.RLock() 66 | defer m.RUnlock() 67 | return m.Map[key] 68 | } 69 | 70 | // Delete 删 71 | func (m *ConcurrencyRwMap) Delete(key interface{}) { 72 | m.Lock() 73 | defer m.Unlock() 74 | delete(m.Map, key) 75 | } 76 | -------------------------------------------------------------------------------- /server-common/utils/orm/orm.go: -------------------------------------------------------------------------------- 1 | package orm 2 | 3 | import ( 4 | "github.com/spf13/cast" 5 | "gorm.io/gorm" 6 | "reflect" 7 | ) 8 | 9 | // Paginate page, pageSize 传入参数 10 | // s 分页默认配置 11 | func Paginate(page interface{}, pageSize interface{}, s map[string]interface{}) func(db *gorm.DB) *gorm.DB { 12 | return func(db *gorm.DB) *gorm.DB { 13 | p := cast.ToInt(page) 14 | size := cast.ToInt(pageSize) 15 | if page == 0 { 16 | if s["page"] != nil { 17 | page = s["page"].(int) 18 | } else { 19 | page = 1 20 | } 21 | } 22 | 23 | if pageSize == 0 { 24 | if s["pageSize"] != nil { 25 | pageSize = s["pageSize"].(int) 26 | } else { 27 | pageSize = 10 28 | } 29 | } 30 | offset := (p - 1) * size 31 | return db.Offset(offset).Limit(size) 32 | } 33 | } 34 | 35 | // FilterString 进行快速条件过滤 36 | func FilterString(key, value, operator string) func(db *gorm.DB) *gorm.DB { 37 | return func(db *gorm.DB) *gorm.DB { 38 | returnDB := db 39 | if value != "" { 40 | switch operator { 41 | case "like": 42 | returnDB = returnDB.Where(key+" Like ? ", "%"+value+"%") 43 | case "=", ">=", "<=", "<": 44 | returnDB = returnDB.Where(key+" "+operator+" "+"?", value) 45 | } 46 | } 47 | return returnDB 48 | } 49 | } 50 | 51 | // InOrNotInFilter where in 或者 where not in 52 | func InOrNotInFilter(key string, value interface{}, operator string) func(db *gorm.DB) *gorm.DB { 53 | return func(db *gorm.DB) *gorm.DB { 54 | returnDB := db 55 | if reflect.ValueOf(value).Len() != 0 { 56 | whereMap := map[string]interface{}{ 57 | key: value, 58 | } 59 | switch operator { 60 | case "in": 61 | returnDB = returnDB.Where(whereMap) 62 | case "not in": 63 | returnDB = returnDB.Not(whereMap) 64 | } 65 | } 66 | return returnDB 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /server-common/utils/regmatch/regmatch.go: -------------------------------------------------------------------------------- 1 | package regmatch 2 | 3 | import ( 4 | "fmt" 5 | "regexp" 6 | ) 7 | 8 | const ( 9 | PHONE = `[1](([3][0-9])|([4][5-9])|([5][0-3,5-9])|([6][5,6])|([7][0-8])|([8][0-9])|([9][1,8,9]))[0-9]{8}` 10 | LINDLINENUMBER = `\b(0\d{2,3}-\d{7,8}|\(?0\d{2,3}[)-]?\d{7,8}|\(?0\d{2,3}[)-]*\d{7,8})\b` 11 | RECORDNO = `[1-9]\d{5}(18|19|20|(3\d))\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]` 12 | PASSPORTNUMBER = `([a-zA-z]|[0-9]){5,17}` 13 | PASSPORT = `[HMhm]{1}([0-9]{10}|[0-9]{8})` 14 | IPV4 = `(((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(.|$)){4})` 15 | IPV6 = `("["([0-9a-fA-F]+:){7}[0-9a-fA-F]+"]")|("["0x[0-9a-fA-F]+([0-9a-fA-F]+|:)*"::"([0-9a-fA-F]+|:)*"]")|("["([0-9a-fA-F]+|:)*"::"([0-9a-fA-F]+|:)*"]")|("["([0-9a-fA-F]+|:)*"::"([0-9a-fA-F]+|:)*([0-9]"."){3}[0-9]"]")` 16 | MAC = `(?:(?:(?:[a-f0-9A-F]{2}:){5})|(?:(?:[a-f0-9A-F]{2}-){5}))[a-f0-9A-F]{2}` 17 | EMAIL = `([\w.\_]{2,10})@(\w{1,}).([a-z]{2,4})` 18 | SOCIALCREDITCODE = `[\dANY]{1}\d{7}[0-9A-HJ-NPQRTUWXY]{10}` 19 | URL = `^(((ht|f)tps?):\/\/)?([^!@#$%^&*?.\s-]([^!@#$%^&*?.\s]{0,63}[^!@#$%^&*?.\s])?\.)+[a-z]{2,6}\/?` 20 | URLPORT = `^((ht|f)tps?:\/\/)?[\w-]+(\.[\w-]+)+:\d{1,5}\/?$` 21 | AMOUNT = `(?:^[1-9]([0-9]+)?(?:\.[0-9]{1,2})?$)|(?:^(?:0)$)|(?:^[0-9]\.[0-9](?:[0-9])?$)` 22 | ) 23 | 24 | // RegMatchPhone reg match phone 25 | func RegMatchPhone(phone string) bool { 26 | matched, err := regexp.MatchString(PHONE, phone) 27 | if err != nil || !matched { 28 | return false 29 | } 30 | return true 31 | } 32 | 33 | // RegLandLineNumber 座机号 判定数据内容是否包含中国固定电话号码 34 | func RegLandLineNumber(lindLineNumber string) bool { 35 | matched, err := regexp.MatchString(LINDLINENUMBER, lindLineNumber) 36 | if err != nil || !matched { 37 | return false 38 | } 39 | return true 40 | } 41 | 42 | // RegIDCard 18位身份证号 43 | func RegIDCard(idCard string) bool { 44 | matched, err := regexp.MatchString(RECORDNO, idCard) 45 | if err != nil || !matched { 46 | return false 47 | } 48 | return true 49 | } 50 | 51 | // PassportNumber 护照编号 52 | func PassportNumber(passportNumber string) bool { 53 | matched, err := regexp.MatchString(RECORDNO, passportNumber) 54 | if err != nil || !matched { 55 | return false 56 | } 57 | return true 58 | } 59 | 60 | // Passport 港澳通行证 61 | func Passport(passport string) bool { 62 | matched, err := regexp.MatchString(PASSPORT, passport) 63 | if err != nil || !matched { 64 | return false 65 | } 66 | return true 67 | } 68 | 69 | // RegIPV4 判定数据内容是否包含IP地址 70 | func RegIPV4(ipv4 string) bool { 71 | matched, err := regexp.MatchString(IPV4, ipv4) 72 | if err != nil || !matched { 73 | return false 74 | } 75 | return true 76 | } 77 | 78 | // RegIPV6 判定数据内容是否包含IPV6地址 79 | func RegIPV6(ipv6 string) bool { 80 | matched, err := regexp.MatchString(IPV6, ipv6) 81 | if err != nil || !matched { 82 | return false 83 | } 84 | return true 85 | } 86 | 87 | // RegMAC 判定数据内容是否包含IP地址 88 | func RegMAC(mac string) bool { 89 | matched, err := regexp.MatchString(MAC, mac) 90 | if err != nil || !matched { 91 | return false 92 | } 93 | return true 94 | } 95 | 96 | // RegEmail 电子邮箱地址 97 | func RegEmail(email string) bool { 98 | matched, err := regexp.MatchString(EMAIL, email) 99 | if err != nil || !matched { 100 | return false 101 | } 102 | return true 103 | } 104 | 105 | // RegSocialCreditCode 统一社会信用代码 106 | func RegSocialCreditCode(socialCreditCode string) bool { 107 | matched, err := regexp.MatchString(SOCIALCREDITCODE, socialCreditCode) 108 | if err != nil || !matched { 109 | return false 110 | } 111 | return true 112 | } 113 | 114 | // CheckPasswordLever 密码常用正则表达式 密码强度必须为字⺟⼤⼩写+数字+符号,9位以上 115 | func CheckPasswordLever(ps string) error { 116 | if len(ps) < 9 { 117 | return fmt.Errorf("password len is < 9") 118 | } 119 | num := `[0-9]{1}` 120 | a_z := `[a-z]{1}` 121 | A_Z := `[A-Z]{1}` 122 | symbol := `[!@#~$%^&*()+|_]{1}` 123 | if b, err := regexp.MatchString(num, ps); !b || err != nil { 124 | return fmt.Errorf("password need num :%v", err) 125 | } 126 | if b, err := regexp.MatchString(a_z, ps); !b || err != nil { 127 | return fmt.Errorf("password need a_z :%v", err) 128 | } 129 | if b, err := regexp.MatchString(A_Z, ps); !b || err != nil { 130 | return fmt.Errorf("password need A_Z :%v", err) 131 | } 132 | if b, err := regexp.MatchString(symbol, ps); !b || err != nil { 133 | return fmt.Errorf("password need symbol :%v", err) 134 | } 135 | return nil 136 | } 137 | 138 | // RegUrlPort 网址URL(带端口号,如:https://www.baidu.com:8080/) 139 | func RegUrlPort(urlPort string) bool { 140 | matched, err := regexp.MatchString(URLPORT, urlPort) 141 | if err != nil || !matched { 142 | return false 143 | } 144 | return true 145 | } 146 | 147 | // RegUrl 网址URL(不带端口号,如:https://www.baidu.com/) 148 | func RegUrl(url string) bool { 149 | matched, err := regexp.MatchString(URL, url) 150 | if err != nil || !matched { 151 | return false 152 | } 153 | return true 154 | } 155 | 156 | // RegAmount 金额(正数,可有最多两位小数,如:8.99) 157 | func RegAmount(amount string) bool { 158 | matched, err := regexp.MatchString(AMOUNT, amount) 159 | if err != nil || !matched { 160 | return false 161 | } 162 | return true 163 | } 164 | -------------------------------------------------------------------------------- /server-common/utils/slice/slice.go: -------------------------------------------------------------------------------- 1 | package _slice 2 | 3 | // RemoveRepeatedElement 数组切片去重 4 | func RemoveRepeatedElement(arr []string) (newArr []string) { 5 | newArr = make([]string, 0) 6 | for i := 0; i < len(arr); i++ { 7 | repeat := false 8 | for j := i + 1; j < len(arr); j++ { 9 | if arr[i] == arr[j] { 10 | repeat = true 11 | break 12 | } 13 | } 14 | if !repeat { 15 | newArr = append(newArr, arr[i]) 16 | } 17 | } 18 | return 19 | } 20 | -------------------------------------------------------------------------------- /server-common/utils/wordsfilter/wordsfilter.go: -------------------------------------------------------------------------------- 1 | package wordsfilter 2 | 3 | import ( 4 | "bufio" 5 | "github.com/syyongx/go-wordsfilter" 6 | "log" 7 | "os" 8 | ) 9 | 10 | var ( 11 | Wf *wordsfilter.WordsFilter 12 | words []string 13 | master map[string]*wordsfilter.Node 14 | ) 15 | 16 | // SetWordsFilter 项目启动的时候,通过此方法将敏感词库加载进去 17 | func SetWordsFilter(filepath string) { 18 | f, err := os.Open(filepath) 19 | if err != nil { 20 | log.Fatal(err) 21 | } 22 | defer f.Close() 23 | scanner := bufio.NewScanner(f) 24 | for scanner.Scan() { 25 | s := scanner.Text() 26 | words = append(words, s) 27 | } 28 | if err := scanner.Err(); err != nil { 29 | log.Fatal(err) 30 | } 31 | 32 | Wf = wordsfilter.New() 33 | master = Wf.Generate(words) 34 | } 35 | 36 | // ContentFilter 需要过滤的地方,调用此方法,将要过滤的内容传递进去即可 37 | func ContentFilter(text string) bool { 38 | return Wf.Contains(text, master) 39 | } 40 | -------------------------------------------------------------------------------- /server-common/utils/wtime/time.go: -------------------------------------------------------------------------------- 1 | package wtime 2 | 3 | import "time" 4 | 5 | var ( 6 | WTtime *wtime 7 | formatTimeDate = "2006-01-02" 8 | formatTime = "2006-01-02 15:04:05" 9 | ) 10 | 11 | type wtime struct{} 12 | 13 | // FormatTime 格式化时间 14 | func (w *wtime) FormatTime(t time.Time) string { 15 | return t.Format(formatTime) 16 | } 17 | 18 | // CurrentDayZero 获取当天零点时间 19 | func (w *wtime) CurrentDayZero() string { 20 | return time.Now().Format(formatTimeDate) + " 00:00:00" 21 | } 22 | 23 | // CurrentDayEnd 获取当天结束时间 24 | func (w *wtime) CurrentDayEnd() string { 25 | return time.Now().Format(formatTimeDate) + " 23:59:59" 26 | } 27 | 28 | // CalculateCurrentTimeAndZeroTime 计算当前时间和零点的时间差 29 | func (w *wtime) CalculateCurrentTimeAndZeroTime() time.Duration { 30 | now := time.Now().Unix() 31 | nd := time.Now().Format(formatTimeDate) + " 23:59:59" 32 | targetTime, _ := time.ParseInLocation(formatTime, nd, time.Local) 33 | ts := targetTime.Unix() 34 | return time.Duration(ts-now) * time.Second 35 | 36 | } 37 | 38 | // PreviousDayStartTime 获取前一天零点时间 39 | func PreviousDayStartTime() string { 40 | now := time.Now() 41 | old := now.AddDate(0, 0, -1).Format(formatTimeDate) 42 | return old + " 00:00:00" 43 | } 44 | 45 | // PreviousDayEndTime 获取前一天结束时间 46 | func PreviousDayEndTime() string { 47 | now := time.Now() 48 | old := now.AddDate(0, 0, -1).Format(formatTimeDate) 49 | return old + " 23:59:59" 50 | } 51 | 52 | // PreviousAfterDate 获取前后指定的时间日期 53 | func PreviousAfterDate(n int) string { 54 | now := time.Now() 55 | t := now.AddDate(0, 0, n).Format(formatTimeDate) 56 | return t 57 | } 58 | 59 | // PreviousAfterTime 获取前后指定的日期的当前时间 60 | func PreviousAfterTime(n int) string { 61 | now := time.Now() 62 | t := now.AddDate(0, 0, n).Format(formatTime) 63 | return t 64 | } 65 | -------------------------------------------------------------------------------- /server-env/RabbitMQ.md: -------------------------------------------------------------------------------- 1 | #### RabbitMQ 2 | 3 | ```shell 4 | 5 | docker pull rabbitmq:3.9.13-management 6 | 7 | docker run -d --name my-rabbitmq -p 5672:5672 -p 15672:15672 -v /Users/cc/rabbitmq:/var/lib/rabbitmq --hostname my-rabbitmq-node1 -e RABBITMQ_DEFAULT_VHOST=my-rabbitmq-vhost -e RABBITMQ_DEFAULT_USER=admin -e RABBITMQ_DEFAULT_PASS=admin rabbitmq:3.9.13-management 8 | 9 | ``` 10 | -------------------------------------------------------------------------------- /server-env/mongo.md: -------------------------------------------------------------------------------- 1 | #### mongo 2 | ``` 3 | 1. shell mkdir dir 4 | 5 | 2. docker pull mongo 6 | 7 | 3. docker run -d --name my-mongo-auth -v /Users/cc/mongo/datadb:/data/db -p 27017:27017 -e MONGO_INITDB_ROOT_USERNAME=root -e MONGO_INITDB_ROOT_PASSWORD=root --privileged=true mongo 8 | 9 | 4. 10 | use ginframe // 选择test数据库 11 | db.createUser( 12 | { 13 | user: "test", 14 | pwd: "123456", 15 | roles: [ 16 | { role: "readWrite", db: "test" } 17 | ] 18 | } 19 | ); 20 | 21 | exit 22 | 23 | mongo -u test -p 123456 --authenticationDatabase ginframe (以刚创建的test用户登录) 24 | ``` 25 | 26 | -------------------------------------------------------------------------------- /server-env/mysql-redis-nacos/deploy_docker.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | yum remove docker docker-client docker-client-latest docker-common docker-latest docker-latest-logrotate docker-logrotate docker-engine 4 | 5 | yum install -y yum-utils device-mapper-persistent-data lvm2 6 | 7 | yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo 8 | 9 | yum install docker-ce docker-ce-cli containerd.io -y 10 | 11 | echo "=====>>>>> 启动 docker..." && sleep 1 12 | systemctl start docker 13 | 14 | echo "=====>>>>> 启动成功..." && sleep 1 15 | 16 | echo "=====>>>>> test docker..." && sleep 1 17 | docker pull hello-world 18 | 19 | docker rmi hello-world 20 | 21 | echo "=====>>>>> install docker-compose..." && sleep 1 22 | curl -L "https://github.com/docker/compose/releases/download/1.24.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose 23 | # curl -L "https://get.daocloud.io/docker/compose/releases/download/1.25.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose 国内镜像源 24 | 25 | chmod +x /usr/local/bin/docker-compose 26 | 27 | ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose 28 | 29 | echo "=====>>>>> test docker-compose..." && sleep 1 30 | docker-compose --version 31 | 32 | echo "=====>>>>> 安装成功" && sleep 1 33 | 34 | exit 35 | -------------------------------------------------------------------------------- /server-env/mysql-redis-nacos/init_env.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | # chmod +x ./deploy_docker.sh 4 | 5 | # echo "=====>>>>> 开始安装 docker..." && sleep 1 && echo "" 6 | # ./deploy_docker.sh 7 | 8 | # echo "=====>>>>> docker安装完毕 " && sleep 1 9 | 10 | # rm -rf ./deploy_docker.sh 11 | # rm -rf ./daemon.json 12 | 13 | echo "=====>>>>> 准备安装并启动 mysql " && sleep 1 && echo "" 14 | docker-compose -f mysql.yml up -d 15 | 16 | sleep 3 && docker ps && echo "" 17 | 18 | echo "=====>>>>> mysql启动成功 " 19 | echo "=====>>>>> 浏览器访问7880端口,数据库密码请查询 mysql.yml " && sleep 2 20 | 21 | echo "=====>>>>> 准备安装并启动 rds " && sleep 1 && echo "" 22 | 23 | docker-compose -f redis.yml up -d 24 | 25 | echo "=====>>>>> redis启动成功" && sleep 1 && echo "" 26 | 27 | 28 | echo "=====>>>>> 准备安装并启动 nacos " && sleep 1 && echo "" 29 | 30 | docker-compose -f nacos-server.yml up -d 31 | 32 | echo "=====>>>>> nacos启动成功" && sleep 1 && echo "" 33 | -------------------------------------------------------------------------------- /server-env/mysql-redis-nacos/mysql.yml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | services: 3 | mysql: 4 | container_name: mysqld-master 5 | image: mysql:8.0.19 6 | environment: 7 | MYSQL_ROOT_PASSWORD: 123456 8 | TZ: Asia/Shanghai 9 | command: 10 | --server_id=1 11 | --binlog_format=MIXED 12 | --slow_query_log='ON' 13 | --long_query_time=20 14 | --character-set_server=utf8mb4 15 | --collation-server=utf8mb4_general_ci 16 | ports: 17 | - 3306:3306 18 | volumes: 19 | - /Users/cc/docker/mysql-redis-nacos/data/mysql:/var/lib/mysql 20 | -------------------------------------------------------------------------------- /server-env/mysql-redis-nacos/nacos-server.yml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | services: 3 | nacos: 4 | image: nacos/nacos-server:v2.0.3 5 | container_name: nacos-server 6 | environment: 7 | - NACOS_AUTH_ENABLE=false 8 | - MODE=standalone 9 | - PREFER_HOST_MODE=hostname 10 | # - SPRING_DATASOURCE_PLATFORM=mysql 11 | # - MYSQL_SERVICE_HOST=192.168.0.40 12 | # - MYSQL_SERVICE_PORT=3306 13 | # - MYSQL_SERVICE_DB_NAME=nacos 14 | # - MYSQL_SERVICE_USER=root 15 | # - MYSQL_SERVICE_PASSWORD=123456 16 | ports: 17 | - "7848:8848" 18 | - "9555:9555" 19 | # restart: always 20 | -------------------------------------------------------------------------------- /server-env/mysql-redis-nacos/redis.yml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | services: 3 | redis: 4 | container_name: redisd 5 | image: redis:5.0.7 6 | command: redis-server --requirepass 123456 7 | ports: 8 | - 7379:6379 9 | -------------------------------------------------------------------------------- /server-test/global/config.go: -------------------------------------------------------------------------------- 1 | package global 2 | 3 | import "github.com/mazezen/ginframe/server-common/nacosRF" 4 | 5 | var TestConfig *GlobalConfig 6 | 7 | type GlobalConfig struct { 8 | GinAppDebug string `json:"gin_app_debug"` 9 | Http Http `json:"http"` 10 | Grpc Grpc `json:"grpc"` 11 | Nacos *nacosRF.NacosConfig `json:"nacos"` 12 | } 13 | 14 | // Http http服务配置 15 | type Http struct { 16 | BindPort string `json:"bind_port"` 17 | LogPath string `json:"log_path"` 18 | } 19 | 20 | // Grpc Grpc配置 21 | type Grpc struct { 22 | Port string `json:"port"` 23 | } 24 | -------------------------------------------------------------------------------- /server-test/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "flag" 6 | "github.com/gin-gonic/gin" 7 | "github.com/mazezen/ginframe/server-common/config" 8 | "github.com/mazezen/ginframe/server-common/nacosRF" 9 | "github.com/mazezen/ginframe/server-common/servers" 10 | "github.com/mazezen/ginframe/server-test/global" 11 | "github.com/mazezen/ginframe/server-user/pb" 12 | "github.com/spf13/cast" 13 | "net/http" 14 | ) 15 | 16 | var ( 17 | ip = flag.String("ip", "127.0.0.1", "The nacos of ip address") 18 | port = flag.Int("p", 7848, "The nacos of port") 19 | cfg = flag.String("c", "server-test.yml", "The nacos of Data ID") 20 | group = flag.String("g", "gin-frame", "The nacos of Group") 21 | ) 22 | 23 | func init() { 24 | flag.Parse() 25 | loadRemoteConfig(*ip, *port, *cfg, *group, &global.TestConfig) 26 | nacosRF.InitNacos(global.TestConfig.Nacos) 27 | } 28 | 29 | func loadRemoteConfig(ip string, port int, cfg string, group string, configs interface{}) { 30 | config.LoadCoreConfig(ip, port, cfg, group, configs) 31 | } 32 | 33 | func main() { 34 | r := gin.Default() 35 | 36 | r.GET("/test", func(c *gin.Context) { 37 | userServiceClient := servers.GetUserRpcServer("1") 38 | if userServiceClient == nil { 39 | c.JSON(http.StatusOK, gin.H{ 40 | "code": 400, 41 | "msg": "没有发现user服务", 42 | }) 43 | return 44 | } 45 | // 用户表id 为 1 46 | info, err := userServiceClient.GetUserInfo(context.Background(), &pb.GetUserInfoRequest{ 47 | Id: "1", 48 | }) 49 | if err != nil { 50 | c.JSON(http.StatusOK, gin.H{ 51 | "code": 400, 52 | "msg": cast.ToString(err), 53 | }) 54 | return 55 | } 56 | c.JSON(http.StatusOK, gin.H{ 57 | "code": 200, 58 | "msg": "success", 59 | "data": info, 60 | }) 61 | }) 62 | 63 | r.Run(":9999") 64 | } 65 | -------------------------------------------------------------------------------- /server-user/Makefile: -------------------------------------------------------------------------------- 1 | APP=server-user 2 | 3 | .PHONY: help all build windows linux darwin 4 | 5 | help: 6 | @echo "usage: make " 7 | @echo "options and effects:" 8 | @echo " help : Show help" 9 | @echo " all : Build multiple binary of this project" 10 | @echo " build : Build the binary of this project for current platform" 11 | @echo " windows: Build the windows binary of this project" 12 | @echo " linux : Build the linux binary of this project" 13 | @echo " darwin : Build the darwin binary of this project" 14 | 15 | all:build windows linux darwin 16 | 17 | build: 18 | @go build -o ${APP} 19 | 20 | windows: 21 | @GOOS=windows go build -o ${APP}-windows 22 | linux: 23 | @GOOS=linux go build -o ${APP}-linux 24 | darwin: 25 | @GOOS=darwin go build -o ${APP}-darwin -------------------------------------------------------------------------------- /server-user/boot/db.go: -------------------------------------------------------------------------------- 1 | package boot 2 | 3 | import ( 4 | "github.com/mazezen/ginframe/server-common/driver" 5 | "github.com/mazezen/ginframe/server-user/core" 6 | "github.com/mazezen/ginframe/server-user/ulogger" 7 | "log" 8 | ) 9 | 10 | // InitDb init gorm 11 | func InitDb(dbDsn string, maxOpenConn, maxIdleConn int) { 12 | gdb, err := driver.CreateDb(dbDsn, maxOpenConn, maxIdleConn) 13 | if err != nil { 14 | log.Fatalf("Create mysql connection err: %v\n", err) 15 | } 16 | core.SetMysql(gdb) 17 | 18 | ulogger.UserLogger.Info("🚀🚀🚀🚀🚀🚀mysql success...🚀🚀🚀🚀🚀🚀") 19 | } 20 | 21 | // InitRedis init redis 22 | func InitRedis(addr, pass string, rdb int) { 23 | rd, err := driver.CreateRedis(addr, pass, rdb) 24 | if err != nil { 25 | log.Fatalf("Create redis client err: %v\n", err) 26 | } 27 | core.SetRedis(rd) 28 | 29 | ulogger.UserLogger.Info("🚀🚀🚀🚀🚀🚀redis success...🚀🚀🚀🚀🚀🚀") 30 | } 31 | 32 | // InitMongo init mongodb 33 | func InitMongo(addr string) { 34 | mongo, err := driver.InitMongo(addr) 35 | if err != nil { 36 | log.Fatalf("Create mongodb client err: %v\n", err) 37 | } 38 | core.SetMongo(mongo) 39 | ulogger.UserLogger.Info("🚀🚀🚀🚀🚀🚀 mongodb success...🚀🚀🚀🚀🚀🚀") 40 | } 41 | 42 | // InitLevelDb init leveldb 43 | func InitLevelDb(path string) { 44 | ldb := driver.InitLevelDb(path) 45 | core.SetLevelDB(ldb) 46 | 47 | ulogger.UserLogger.Info("🚀🚀🚀🚀🚀🚀levedb success...🚀🚀🚀🚀🚀🚀") 48 | } 49 | -------------------------------------------------------------------------------- /server-user/boot/es.go: -------------------------------------------------------------------------------- 1 | package boot 2 | 3 | import ( 4 | "github.com/mazezen/ginframe/server-common/driver" 5 | "github.com/mazezen/ginframe/server-user/core" 6 | "github.com/mazezen/ginframe/server-user/ulogger" 7 | "log" 8 | ) 9 | 10 | // InitEs init elastic 11 | func InitEs(url string) { 12 | es, err := driver.InitEs(url) 13 | if err != nil { 14 | log.Fatalln(err) 15 | } 16 | core.SetEsClient(es) 17 | 18 | ulogger.UserLogger.Info("🚀🚀🚀🚀🚀🚀ES success...🚀🚀🚀🚀🚀🚀") 19 | } 20 | -------------------------------------------------------------------------------- /server-user/boot/grpc.go: -------------------------------------------------------------------------------- 1 | package boot 2 | 3 | import ( 4 | "fmt" 5 | "github.com/mazezen/ginframe/server-common/const" 6 | "github.com/mazezen/ginframe/server-user/global" 7 | "github.com/mazezen/ginframe/server-user/grpcservices/services" 8 | "github.com/mazezen/ginframe/server-user/pb" 9 | "go.uber.org/zap" 10 | "google.golang.org/grpc" 11 | "google.golang.org/grpc/health" 12 | healthpb "google.golang.org/grpc/health/grpc_health_v1" 13 | "google.golang.org/grpc/reflection" 14 | "log" 15 | "net" 16 | ) 17 | 18 | // RunGrpcServer 运行grpc 服务 19 | func RunGrpcServer() error { 20 | s := grpc.NewServer() 21 | // 注册心跳 22 | healthServer := health.NewServer() 23 | healthServer.SetServingStatus(_const.HEALTHCHECK_SERVICE, healthpb.HealthCheckResponse_SERVING) 24 | healthpb.RegisterHealthServer(s, healthServer) 25 | 26 | // 注册服务 27 | pb.RegisterRpcUserServiceServer(s, new(services.RpcUserService)) 28 | 29 | reflection.Register(s) 30 | fmt.Println(global.Config.Grpc.Port) 31 | listen, err := net.Listen("tcp", ":"+global.Config.Grpc.Port) 32 | if err != nil { 33 | log.Fatalf("Router: Start grpc failed, err: %v", zap.Error(err)) 34 | } 35 | return s.Serve(listen) 36 | } 37 | -------------------------------------------------------------------------------- /server-user/boot/http.go: -------------------------------------------------------------------------------- 1 | package boot 2 | 3 | import ( 4 | "fmt" 5 | "github.com/gin-gonic/gin" 6 | "github.com/mazezen/ginframe/server-user/global" 7 | "github.com/mazezen/ginframe/server-user/router" 8 | ) 9 | 10 | // HttpServe init 11 | func HttpServe() error { 12 | r := gin.Default() 13 | router.ApiRouter(r) 14 | return r.Run(fmt.Sprintf("%s%s", ":", global.Config.Http.BindPort)) 15 | } 16 | -------------------------------------------------------------------------------- /server-user/boot/init.go: -------------------------------------------------------------------------------- 1 | // init 项目初始化 2 | 3 | package boot 4 | 5 | import ( 6 | "flag" 7 | "fmt" 8 | "github.com/gin-gonic/gin" 9 | "github.com/mazezen/ginframe/server-common/config" 10 | _const "github.com/mazezen/ginframe/server-common/const" 11 | "github.com/mazezen/ginframe/server-common/nacosRF" 12 | _process "github.com/mazezen/ginframe/server-common/process" 13 | _ip "github.com/mazezen/ginframe/server-common/utils/ip" 14 | "github.com/mazezen/ginframe/server-user/cachedb" 15 | "github.com/mazezen/ginframe/server-user/daos/serverDao" 16 | "github.com/mazezen/ginframe/server-user/global" 17 | _rpc "github.com/mazezen/ginframe/server-user/rpc" 18 | "github.com/mazezen/ginframe/server-user/ulogger" 19 | "go.uber.org/zap" 20 | "io" 21 | "log" 22 | "os" 23 | "strings" 24 | ) 25 | 26 | var ( 27 | RootDir string 28 | err error 29 | cf string 30 | MysqlDbDsn string 31 | MaxOpenConn int 32 | MaxIdleConn int 33 | RedisAddr string 34 | RedisPassword string 35 | RedisDb int 36 | MongoAddr string 37 | LeveldbPath string 38 | LoggerPath string 39 | EsUrl string 40 | ) 41 | 42 | var ( 43 | ip = flag.String("ip", "127.0.0.1", "The nacos of ip address") 44 | port = flag.Int("p", 7848, "The nacos of port") 45 | cfg = flag.String("c", "server-user.yml", "The nacos of Data ID") 46 | group = flag.String("g", "gin-frame", "The nacos of Group") 47 | ) 48 | 49 | func init() { 50 | flag.Parse() 51 | loadRemoteConfig(*ip, *port, *cfg, *group, &global.Config) 52 | if global.Config.IsEnableGOMAXPROCS { 53 | _process.GroRuntimeMaxCpu() 54 | } 55 | assignment() 56 | initDB() 57 | nacosRF.InitNacos(global.Config.Nacos) 58 | setUserServer() 59 | registerUserServer() 60 | } 61 | 62 | func loadRemoteConfig(ip string, port int, cfg string, group string, configs interface{}) { 63 | config.LoadCoreConfig(ip, port, cfg, group, configs) 64 | } 65 | 66 | // assignment 67 | func assignment() { 68 | MysqlDbDsn = global.Config.Mysql.DbDsn 69 | MaxOpenConn = global.Config.Mysql.MaxOpenConns 70 | MaxIdleConn = global.Config.Mysql.MaxIdleConns 71 | RedisAddr = global.Config.Redis.Addr 72 | RedisPassword = global.Config.Redis.Password 73 | RedisDb = global.Config.Redis.Db 74 | MongoAddr = global.Config.Mongo.Addr 75 | LeveldbPath = global.Config.LevelDb.Path 76 | LoggerPath = global.Config.Http.LogPath 77 | //EsUrl = global.Config.Elastic.Url 78 | } 79 | 80 | func initDB() { 81 | InitLog(LoggerPath) 82 | InitDb(MysqlDbDsn, MaxOpenConn, MaxIdleConn) 83 | InitRedis(RedisAddr, RedisPassword, RedisDb) 84 | InitMongo(MongoAddr) 85 | InitLevelDb(LeveldbPath) 86 | //go InitEs(EsUrl) 87 | } 88 | 89 | // 注册服务, 服务必须存在server_flag表中, 可通过后台可视化页面添加 90 | // server_name 需保持一致 91 | // 如: 用户服务为`user`,所有的用户服务server_name 都为`user`,依次类推 92 | func setUserServer() { 93 | ip := _ip.GetIp() 94 | server, err := serverDao.CheckIpIsNewServer(ip, _const.ServerNameU) 95 | if err != nil { 96 | ulogger.UserLogger.Error("==========> user服务初始化,检测是否为新服务失败 <==========\n", 97 | zap.String("ip", ip), zap.Error(err)) 98 | os.Exit(1) 99 | } 100 | if server.Id == 0 { 101 | ulogger.UserLogger.Error("==========> user服务初始化,库中服务未找到 <==========\n", 102 | zap.String("ip", ip), zap.Error(err)) 103 | os.Exit(1) 104 | } 105 | // 新服务注册 106 | err = cachedb.SetUserServerFlag(fmt.Sprintf("%s%s%s", ip, ":", _const.UserServerName), 107 | fmt.Sprintf("%s%d", _const.UserServerName, server.Sum)) 108 | if err != nil { 109 | os.Exit(1) 110 | } 111 | } 112 | 113 | func registerUserServer() { 114 | ip := _ip.GetIp() 115 | k := fmt.Sprintf("%s%s%s", ip, ":", _const.UserServerName) 116 | nacosRF.NacosInstance.Register(cachedb.GetUserServerFlag(k), global.Config.Nacos.Port) 117 | } 118 | 119 | // Boot 项目初始化 120 | func Boot() { 121 | errs := make(chan error) 122 | go func() { 123 | err = HttpServe() 124 | if err != nil { 125 | errs <- err 126 | } 127 | }() 128 | 129 | go func() { 130 | err = RunGrpcServer() 131 | if err != nil { 132 | errs <- err 133 | } 134 | }() 135 | 136 | go func() { 137 | err = WebsocketServer() 138 | if err != nil { 139 | errs <- err 140 | } 141 | }() 142 | 143 | go func() { 144 | err = _rpc.RpcServer() 145 | if err != nil { 146 | errs <- err 147 | } 148 | }() 149 | 150 | debugPrint("*****************************************************************") 151 | debugPrint("* Listening and serving HTTP on %s *\n", global.Config.Http.BindPort) 152 | debugPrint("* Listening and serving GRPC on %s *\n", global.Config.Grpc.Port) 153 | debugPrint("* Listening and serving Websocket on %s *\n", global.Config.Websocket.BindPort) 154 | debugPrint("* Listening and serving rpc on %s *\n", global.Config.Rpc.Listener) 155 | debugPrint("*****************************************************************") 156 | 157 | select { 158 | case err = <-errs: 159 | log.Fatalf("Run server err: %v", err) 160 | } 161 | 162 | } 163 | 164 | var DefaultWriter io.Writer = os.Stdout 165 | 166 | func debugPrint(format string, values ...any) { 167 | if gin.IsDebugging() { 168 | if !strings.HasSuffix(format, "\n") { 169 | format += "\n" 170 | } 171 | fmt.Fprintf(DefaultWriter, "[GIN-debug] "+format, values...) 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /server-user/boot/log.go: -------------------------------------------------------------------------------- 1 | package boot 2 | 3 | import ( 4 | _uber "github.com/mazezen/ginframe/server-common/pkg/uber" 5 | "github.com/mazezen/ginframe/server-user/ulogger" 6 | ) 7 | 8 | // InitLog init log 9 | func InitLog(filepath string) { 10 | logger := _uber.InitLogger(filepath) 11 | ulogger.SetLogger(logger) 12 | 13 | ulogger.UserLogger.Info("🚀🚀🚀🚀🚀🚀 logger success...🚀🚀🚀🚀🚀🚀") 14 | } 15 | -------------------------------------------------------------------------------- /server-user/boot/ws.go: -------------------------------------------------------------------------------- 1 | package boot 2 | 3 | import ( 4 | "fmt" 5 | "github.com/gin-gonic/gin" 6 | "github.com/mazezen/ginframe/server-user/global" 7 | "github.com/mazezen/ginframe/server-user/router" 8 | ) 9 | 10 | // WebsocketServer websocket服务 11 | func WebsocketServer() error { 12 | r := gin.Default() 13 | router.WsRouter(r) 14 | return r.Run(fmt.Sprintf("%s%s", ":", global.Config.Websocket.BindPort)) 15 | } 16 | -------------------------------------------------------------------------------- /server-user/build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | echo "开始编译" 3 | buildFileName="server-user" 4 | BuildTime=`date +'%Y.%m.%d.%H:%M:%S'` 5 | CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags "-w -s" -o ${buildFileName} 6 | echo "编译完成, 编译时间${BuildTime}" 7 | echo "开始压缩文件" 8 | upx -9 ${buildFileName} 9 | echo "完成压缩" 10 | -------------------------------------------------------------------------------- /server-user/cachedb/server.go: -------------------------------------------------------------------------------- 1 | package cachedb 2 | 3 | import ( 4 | "github.com/mazezen/ginframe/server-user/core" 5 | ) 6 | 7 | // SetUserServerFlag 初始化user服务唯一标识 8 | func SetUserServerFlag(ip, serverName string) error { 9 | return core.Rd.Set(ip, serverName, -1).Err() 10 | } 11 | 12 | // GetUserServerFlag 获取user服务唯一标识 13 | func GetUserServerFlag(k string) string { 14 | result, _ := core.Rd.Get(k).Result() 15 | return result 16 | } 17 | -------------------------------------------------------------------------------- /server-user/core/db.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | _leveldb "github.com/mazezen/ginframe/server-common/pkg/leveldb" 7 | leveldb1 "github.com/mazezen/leveldb" 8 | "go.mongodb.org/mongo-driver/bson" 9 | "go.mongodb.org/mongo-driver/bson/primitive" 10 | "go.mongodb.org/mongo-driver/mongo" 11 | "gopkg.in/redis.v5" 12 | "gorm.io/gorm" 13 | ) 14 | 15 | var ( 16 | Db *gorm.DB 17 | Rd *redis.Client 18 | mg *mongo.Client 19 | Ldb *leveldb1.LevelDB 20 | ) 21 | 22 | func SetMysql(e *gorm.DB) { 23 | Db = e 24 | } 25 | 26 | func SetRedis(_rd *redis.Client) { 27 | Rd = _rd 28 | } 29 | 30 | func SetMongo(_m *mongo.Client) { 31 | mg = _m 32 | } 33 | 34 | func SetLevelDB(ldb *leveldb1.LevelDB) { 35 | Ldb = ldb 36 | } 37 | 38 | type MongoClient struct{} 39 | 40 | // InsertCollection 写入 db 写入的数据库 collection 写入的文档(表) data 写入的数据 41 | func (mc *MongoClient) InsertCollection(db string, collection string, data interface{}) ( 42 | res *mongo.InsertOneResult, err error) { 43 | c := mg.Database(db).Collection(collection) 44 | return c.InsertOne(context.TODO(), data) 45 | } 46 | 47 | // BatchInsertCollection 批量写入 48 | func (mc *MongoClient) BatchInsertCollection(db string, collection string, data []interface{}) ( 49 | res *mongo.InsertManyResult, err error) { 50 | c := mg.Database(db).Collection(collection) 51 | return c.InsertMany(context.TODO(), data) 52 | } 53 | 54 | // UpdateOneRecord 修改单条记录 55 | func (mc *MongoClient) UpdateOneRecord(db string, collection string, id string, data bson.D) ( 56 | res *mongo.UpdateResult, err error) { 57 | c := mg.Database(db).Collection(collection) 58 | objId, err := primitive.ObjectIDFromHex(id) 59 | if err != nil { 60 | return nil, err 61 | } 62 | 63 | filter := bson.D{{"_id", objId}} 64 | d := bson.D{{"$set", data}} 65 | res, err = c.UpdateOne(context.TODO(), filter, d) 66 | return 67 | } 68 | 69 | // CountCollection 统计 70 | func (mc *MongoClient) CountCollection(db string, collection string, filter map[string]interface{}) (int64, int64, error) { 71 | c := mg.Database(db).Collection(collection) 72 | 73 | esCount, err := c.EstimatedDocumentCount(context.TODO()) 74 | if err != nil { 75 | return -1, -1, err 76 | } 77 | 78 | if len(filter) == 0 { 79 | count, err := c.CountDocuments(context.TODO(), bson.D{{}}) 80 | if err != nil { 81 | return -1, -1, err 82 | } 83 | return esCount, count, nil 84 | } 85 | 86 | if len(filter) > 0 { 87 | for k, v := range filter { 88 | count, err := c.CountDocuments(context.TODO(), bson.D{{k, v}}) 89 | if err != nil { 90 | return -1, -1, err 91 | } 92 | return esCount, count, nil 93 | } 94 | } 95 | 96 | return -1, -1, errors.New("查询条件异常") 97 | } 98 | 99 | // DeleteOneRecord 删除单条记录 100 | func (mc *MongoClient) DeleteOneRecord(db string, collection string, filter map[string]interface{}) ( 101 | res *mongo.DeleteResult, err error) { 102 | c := mg.Database(db).Collection(collection) 103 | for k, v := range filter { 104 | filter := bson.D{{k, v}} 105 | return c.DeleteOne(context.TODO(), filter) 106 | } 107 | return 108 | } 109 | 110 | // InitLevelDb init level db 111 | func (mc *MongoClient) InitLevelDb(path string) *leveldb1.LevelDB { 112 | return _leveldb.InitLevelDb(path) 113 | } 114 | -------------------------------------------------------------------------------- /server-user/core/es.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import "github.com/olivere/elastic" 4 | 5 | var ( 6 | Es *elastic.Client 7 | ) 8 | 9 | func SetEsClient(_es *elastic.Client) { 10 | Es = _es 11 | } 12 | -------------------------------------------------------------------------------- /server-user/daos/account/account.go: -------------------------------------------------------------------------------- 1 | package account 2 | 3 | import ( 4 | "github.com/mazezen/ginframe/server-user/models" 5 | ) 6 | 7 | func UserList(pageNum, pageSize int64) (int64, []*models.User, error) { 8 | a := new(models.User) 9 | return a.List(pageNum, pageSize) 10 | } 11 | -------------------------------------------------------------------------------- /server-user/daos/auth/login.go: -------------------------------------------------------------------------------- 1 | package auth 2 | 3 | import ( 4 | "github.com/mazezen/ginframe/server-user/models" 5 | ) 6 | 7 | func FindUserByUsername(username string) (*models.User, error) { 8 | m := new(models.User) 9 | admin, err := m.FindUserByUsername(username) 10 | if err != nil { 11 | return nil, err 12 | } 13 | return admin, nil 14 | } 15 | -------------------------------------------------------------------------------- /server-user/daos/serverDao/server.go: -------------------------------------------------------------------------------- 1 | package serverDao 2 | 3 | import "github.com/mazezen/ginframe/server-user/models" 4 | 5 | // CheckIpIsNewServer 检查当前启动服务是否是新服务 6 | func CheckIpIsNewServer(ip, serverName string) (*models.ServerFLag, error) { 7 | m := new(models.ServerFLag) 8 | s, err := m.FindUserByServerNameAndIP(serverName, ip) 9 | if err != nil { 10 | return nil, err 11 | } 12 | return s, nil 13 | } 14 | -------------------------------------------------------------------------------- /server-user/global/config.go: -------------------------------------------------------------------------------- 1 | // 公共的全局配置 package 2 | // GoAppConfig 框架应用配置 3 | // Http http服务配置 4 | // Websocket Websocket配置 5 | // Grpc Grpc配置 6 | // Mysql 数据库配置 7 | // Redis redis配置 8 | 9 | package global 10 | 11 | import ( 12 | "github.com/mazezen/ginframe/server-common/nacosRF" 13 | "time" 14 | ) 15 | 16 | var Config *GlobalConfig 17 | 18 | // GlobalConfig 框架应用配置 19 | type GlobalConfig struct { 20 | IsEnableGOMAXPROCS bool `json:"is_enable_gomaxprocs"` 21 | GinAppDebug string `json:"gin_app_debug"` 22 | GinAppName string `json:"gin_app_name"` 23 | Http Http `json:"http"` 24 | Websocket Websocket `json:"websocket"` 25 | Grpc Grpc `json:"grpc"` 26 | Nacos *nacosRF.NacosConfig `json:"nacos"` 27 | Rpc Rpc `json:"rpc"` 28 | Mysql Mysql `json:"mysql"` 29 | Redis Redis `json:"redis"` 30 | Mongo Mongo `json:"mongo"` 31 | LevelDb LevelDb `json:"level_db"` 32 | Elastic Elastic `json:"elastic"` 33 | Aes Aes `json:"aes"` 34 | Jwt Jwt `json:"jwt"` 35 | } 36 | 37 | // Http http服务配置 38 | type Http struct { 39 | BindPort string `json:"bind_port"` 40 | LogPath string `json:"log_path"` 41 | } 42 | 43 | // Websocket Websocket服务配置 44 | type Websocket struct { 45 | BindPort string `json:"bind_port"` 46 | } 47 | 48 | // Grpc Grpc配置 49 | type Grpc struct { 50 | Port string `json:"port"` 51 | } 52 | 53 | // Rpc Rpc配置 54 | type Rpc struct { 55 | Listener string `json:"listener"` 56 | } 57 | 58 | // Mysql 数据库配置 59 | type Mysql struct { 60 | DbDsn string `json:"db_dsn"` 61 | MaxOpenConns int `json:"max_open_conns"` 62 | MaxIdleConns int `json:"max_idle_conns"` 63 | } 64 | 65 | // Redis redis配置 66 | type Redis struct { 67 | Addr string `json:"addr"` 68 | Password string `json:"password"` 69 | Db int `json:"db"` 70 | } 71 | 72 | // Mongo mongo配置 73 | type Mongo struct { 74 | Addr string `json:"addr"` 75 | } 76 | 77 | type LevelDb struct { 78 | Path string `json:"path"` 79 | } 80 | 81 | type Elastic struct { 82 | Url string `json:"url"` 83 | } 84 | 85 | type Aes struct { 86 | Key string `json:"key"` 87 | Secret string `json:"secret"` 88 | } 89 | 90 | type Jwt struct { 91 | Expire time.Duration `json:"expire"` 92 | Secret string `json:"secret"` 93 | } 94 | -------------------------------------------------------------------------------- /server-user/grpcservices/impl/rpcUserService.go: -------------------------------------------------------------------------------- 1 | package impl 2 | 3 | import ( 4 | "github.com/mazezen/ginframe/server-user/models" 5 | "strconv" 6 | ) 7 | 8 | // GetUserInfo 获取管理员账号信息 9 | func GetUserInfo(id string) *models.User { 10 | aid, _ := strconv.Atoi(id) 11 | 12 | m := new(models.User) 13 | info, err := m.FindUserById(int64(aid)) 14 | if err != nil { 15 | return nil 16 | } 17 | return info 18 | } 19 | -------------------------------------------------------------------------------- /server-user/grpcservices/services/RpcUserService.go: -------------------------------------------------------------------------------- 1 | package services 2 | 3 | import ( 4 | "context" 5 | "github.com/mazezen/ginframe/server-common/utils/wtime" 6 | "github.com/mazezen/ginframe/server-user/grpcservices/impl" 7 | "github.com/mazezen/ginframe/server-user/pb" 8 | "github.com/spf13/cast" 9 | ) 10 | 11 | type RpcUserService struct { 12 | pb.UnimplementedRpcUserServiceServer 13 | } 14 | 15 | // GetUserInfo 获取管理员账号信息 16 | func (ras *RpcUserService) GetUserInfo(ctx context.Context, r *pb.GetUserInfoRequest) (*pb.GetUserInfoResponse, error) { 17 | admin := impl.GetUserInfo(r.Id) 18 | return &pb.GetUserInfoResponse{ 19 | Id: cast.ToInt64(r.Id), 20 | Username: admin.Username, 21 | Nickname: admin.Nickname, 22 | Phone: admin.Phone, 23 | Email: admin.Email, 24 | CreatedAt: wtime.WTtime.FormatTime(admin.CreatedAt), 25 | }, nil 26 | } 27 | -------------------------------------------------------------------------------- /server-user/handler/auth/login.go: -------------------------------------------------------------------------------- 1 | package auth 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "github.com/mazezen/ginframe/server-common/utils/enum" 6 | input2 "github.com/mazezen/ginframe/server-user/input" 7 | "github.com/mazezen/ginframe/server-user/service/auth" 8 | "github.com/spf13/cast" 9 | ) 10 | 11 | // LoginHandler login struct 12 | type LoginHandler struct{} 13 | 14 | // Login admin account login 15 | func (l *LoginHandler) Login(c *gin.Context) { 16 | input := &input2.LoginInput{} 17 | if err := c.Bind(input); err != nil { 18 | enum.Result.Error(c, enum.ApiCode.PARAMERR, cast.ToString(err)) 19 | return 20 | } 21 | out, err := auth.LoginService(input) 22 | if err != nil { 23 | enum.Result.Error(c, enum.ApiCode.FAILED, cast.ToString(err)) 24 | return 25 | } 26 | 27 | enum.Result.Success(c, out) 28 | } 29 | -------------------------------------------------------------------------------- /server-user/handler/user/user.go: -------------------------------------------------------------------------------- 1 | package user 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "github.com/mazezen/ginframe/server-common/utils/enum" 6 | input2 "github.com/mazezen/ginframe/server-user/input" 7 | out2 "github.com/mazezen/ginframe/server-user/out" 8 | "github.com/mazezen/ginframe/server-user/service/user" 9 | "github.com/spf13/cast" 10 | ) 11 | 12 | // UserHandler user handler struct 13 | type UserHandler struct{} 14 | 15 | // List user account list 16 | func (a *UserHandler) List(c *gin.Context) { 17 | param := new(input2.UserHandlerInput) 18 | if err := c.Bind(param); err != nil { 19 | enum.Result.Error(c, enum.ApiCode.PARAMERR, cast.ToString(err)) 20 | return 21 | } 22 | 23 | count, users := user.UserListService(param.PageNum, param.PageSize) 24 | res := &out2.UserOut{ 25 | Total: count, 26 | Data: users, 27 | } 28 | enum.Result.Success(c, res) 29 | } 30 | -------------------------------------------------------------------------------- /server-user/handler/ws.go: -------------------------------------------------------------------------------- 1 | package handler 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "github.com/gorilla/websocket" 6 | "github.com/mazezen/ginframe/server-user/ws" 7 | "log" 8 | "time" 9 | ) 10 | 11 | var ( 12 | //websocket 长连接 13 | wsConn *websocket.Conn 14 | err error 15 | conn *ws.Connection 16 | data []byte 17 | ) 18 | 19 | // WsPing ws router test 20 | func WsPing(c *gin.Context) { 21 | 22 | wsConn, err = ws.Upgrade.Upgrade(c.Writer, c.Request, nil) 23 | if err != nil { 24 | log.Fatal("http upgrade tcp failed", err) 25 | } 26 | 27 | conn, err = ws.InitConnection(wsConn) 28 | if err != nil { 29 | goto ERR 30 | } 31 | 32 | go func() { 33 | for { 34 | if err = conn.WriteMessage([]byte("hello ginframe")); err != nil { 35 | return 36 | } 37 | time.Sleep(time.Second * 1) 38 | } 39 | }() 40 | 41 | for { 42 | if data, err = conn.ReadMessage(); err != nil { 43 | goto ERR 44 | } 45 | if err = conn.WriteMessage(data); err != nil { 46 | goto ERR 47 | } 48 | } 49 | 50 | ERR: 51 | conn.Close() 52 | } 53 | -------------------------------------------------------------------------------- /server-user/input/login.go: -------------------------------------------------------------------------------- 1 | package input 2 | 3 | type LoginInput struct { 4 | Username string `json:"username" binding:"required"` 5 | Password string `json:"password" binding:"required"` 6 | } 7 | -------------------------------------------------------------------------------- /server-user/input/user.go: -------------------------------------------------------------------------------- 1 | package input 2 | 3 | type UserHandlerInput struct { 4 | PageNum int64 `json:"page_num"` 5 | PageSize int64 `json:"page_size"` 6 | } 7 | -------------------------------------------------------------------------------- /server-user/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/mazezen/ginframe/server-user/boot" 5 | ) 6 | 7 | func main() { 8 | boot.Boot() 9 | } 10 | -------------------------------------------------------------------------------- /server-user/middlewares/auth.go: -------------------------------------------------------------------------------- 1 | package middlewares 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | _jwt "github.com/mazezen/ginframe/server-common/pkg/jwt" 6 | "github.com/mazezen/ginframe/server-common/utils/enum" 7 | "github.com/mazezen/ginframe/server-user/global" 8 | "strings" 9 | "time" 10 | ) 11 | 12 | // AuthMiddleware auth token check 13 | func AuthMiddleware() gin.HandlerFunc { 14 | return func(c *gin.Context) { 15 | header := c.Request.Header.Get("Authorization") 16 | if header == "" { 17 | enum.Result.Error(c, enum.ApiCode.TOKENISNOTEXISTS, enum.ApiCode.GetMessage(enum.ApiCode.TOKENISNOTEXISTS)) 18 | c.Abort() 19 | return 20 | } 21 | 22 | split := strings.Split(header, " ") 23 | if len(split) != 2 { 24 | enum.Result.Error(c, enum.ApiCode.TOKENISVALID, enum.ApiCode.GetMessage(enum.ApiCode.TOKENISVALID)) 25 | c.Abort() 26 | return 27 | } 28 | expire := time.Hour * global.Config.Jwt.Expire 29 | instance := _jwt.NewJwtInstance(expire, global.Config.Jwt.Secret) 30 | 31 | _, err := instance.ParseToken(split[1]) 32 | if err != nil { 33 | enum.Result.Error(c, enum.ApiCode.TOKENISVALID, enum.ApiCode.GetMessage(enum.ApiCode.TOKENISVALID)) 34 | c.Abort() 35 | return 36 | } 37 | c.Next() 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /server-user/middlewares/userIsEnable.go: -------------------------------------------------------------------------------- 1 | package middlewares 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | _jwt "github.com/mazezen/ginframe/server-common/pkg/jwt" 6 | "github.com/mazezen/ginframe/server-common/utils/enum" 7 | "github.com/mazezen/ginframe/server-user/global" 8 | "github.com/mazezen/ginframe/server-user/models" 9 | "github.com/spf13/cast" 10 | "strings" 11 | "time" 12 | ) 13 | 14 | // CheckUserAccountIsEnable 检测账号登录状态是否被禁用 15 | func CheckUserAccountIsEnable() gin.HandlerFunc { 16 | return func(c *gin.Context) { 17 | header := c.Request.Header.Get("Authorization") 18 | split := strings.Split(header, " ") 19 | expire := time.Hour * global.Config.Jwt.Expire 20 | instance := _jwt.NewJwtInstance(expire, global.Config.Jwt.Secret) 21 | 22 | claims, _ := instance.ParseToken(split[1]) 23 | m := new(models.User) 24 | u, err := m.FindUserByUsername(claims.Username) 25 | if err != nil { 26 | enum.Result.Error(c, enum.ApiCode.FAILED, cast.ToString(err)) 27 | c.Abort() 28 | return 29 | } 30 | if u.Enable == 2 { 31 | enum.Result.Error(c, enum.ApiCode.USERISDISABLE, enum.ApiCode.GetMessage(enum.ApiCode.USERISDISABLE)) 32 | c.Abort() 33 | return 34 | } 35 | c.Next() 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /server-user/models/server.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import ( 4 | "github.com/mazezen/ginframe/server-user/core" 5 | "time" 6 | ) 7 | 8 | type ServerFLag struct { 9 | Id int64 `gorm:"column:id;primary_key;AUTO_INCREMENT;NOT NULL"` 10 | Flag string `gorm:"column:flag;NOT NULL;comment:'服务'"` 11 | ServerName string `gorm:"column:server_name;NOT NULL;comment:'服务名称'"` 12 | ServerIp string `gorm:"column:server_ip;NOT NULL;comment:'服务ip'"` 13 | Sum int `gorm:"column:sum;NOT NULL;comment:'服务累计数量'"` 14 | CreatedAt time.Time `gorm:"column:created_at;default:CURRENT_TIMESTAMP;NOT NULL;comment:'创建时间'"` 15 | UpdatedAt time.Time `gorm:"column:updated_at;default:CURRENT_TIMESTAMP;NOT NULL;comment:'更新时间'"` 16 | } 17 | 18 | func (se *ServerFLag) TableName() string { 19 | return "server_flag" 20 | } 21 | 22 | const ( 23 | NotFound = "record not found" 24 | ) 25 | 26 | // FindUserByServerNameAndIP 根据 server 查找server服务信息 27 | func (se *ServerFLag) FindUserByServerNameAndIP(serverName, ip string) (*ServerFLag, error) { 28 | s := &ServerFLag{} 29 | err := core.Db.Where("server_name = ?", serverName).Where("server_ip = ?", ip).First(s).Error 30 | if err != nil && err.Error() != NotFound { 31 | return nil, err 32 | } 33 | return s, nil 34 | } 35 | -------------------------------------------------------------------------------- /server-user/models/user.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import ( 4 | "github.com/mazezen/ginframe/server-common/utils/orm" 5 | "github.com/mazezen/ginframe/server-user/core" 6 | "time" 7 | ) 8 | 9 | type User struct { 10 | Id int64 `gorm:"column:id;primary_key;AUTO_INCREMENT;NOT NULL"` 11 | Username string `gorm:"column:username;NOT NULL;comment:'用户名'"` 12 | Nickname string `gorm:"column:nickname;NOT NULL;comment:'昵称'"` 13 | Phone string `gorm:"column:phone;NOT NULL;comment:'手机号'"` 14 | Email string `gorm:"column:email;NOT NULL;comment:'邮箱'"` 15 | Gender int8 `gorm:"column:gender;default:1;NOT NULL;comment:'性别'"` 16 | RoleId string `gorm:"column:role_id;NOT NULL;comment:'角色id'"` 17 | Password string `gorm:"column:password;NOT NULL;comment:'密码'"` 18 | Enable int8 `gorm:"column:enable;default:1;NOT NULL;comment:'是否启用 1: 启用 2: 禁用'"` 19 | CreatedAt time.Time `gorm:"column:created_at;default:CURRENT_TIMESTAMP;NOT NULL;comment:'创建时间'"` 20 | UpdatedAt time.Time `gorm:"column:updated_at;default:CURRENT_TIMESTAMP;NOT NULL;comment:'更新时间'"` 21 | } 22 | 23 | func (a *User) TableName() string { 24 | return "user" 25 | } 26 | 27 | // FindUserById 根据 id 查找user账户信息 28 | func (a *User) FindUserById(id int64) (user *User, err error) { 29 | if err = core.Db.Where("id = ?", id).First(user).Error; err != nil { 30 | return 31 | } 32 | return 33 | } 34 | 35 | // FindUserByUsername 根据 username 查找user账户信息 36 | func (a *User) FindUserByUsername(username string) (user *User, err error) { 37 | user = new(User) 38 | if err = core.Db.Where("username = ?", username).First(user).Error; err != nil { 39 | return 40 | } 41 | return 42 | } 43 | 44 | // FindUserByNickname 根据 nickname 查找user账户信息 45 | func (a *User) FindUserByNickname(nickname string) (user *User, err error) { 46 | if err = core.Db.Where("nickname", nickname).First(user).Error; err != nil { 47 | return 48 | } 49 | return 50 | } 51 | 52 | // List user列表 53 | func (a *User) List(page, pageSize int64) (int64, []*User, error) { 54 | page = 1 55 | pageSize = 10 56 | 57 | // 项目配置的默认分页 58 | s := make(map[string]interface{}) 59 | s["page"] = 1 60 | s["pageSize"] = 10 61 | 62 | var count int64 63 | us := make([]*User, 0) 64 | err := core.Db.Table("user").Scopes(orm.Paginate(page, pageSize, s)).Count(&count).Find(&us).Error 65 | if err != nil { 66 | return 0, nil, err 67 | } 68 | return count, us, nil 69 | } 70 | -------------------------------------------------------------------------------- /server-user/out/login.go: -------------------------------------------------------------------------------- 1 | package out 2 | 3 | type LoginOut struct { 4 | Token string `json:"token"` 5 | Username string `json:"username"` 6 | } 7 | -------------------------------------------------------------------------------- /server-user/out/user.go: -------------------------------------------------------------------------------- 1 | package out 2 | 3 | type UserOut struct { 4 | Total int64 `json:"total"` 5 | Data interface{} `json:"data"` 6 | } 7 | 8 | type Users struct { 9 | Id int64 `json:"id"` 10 | Username string `json:"username"` 11 | Nickname string `json:"nickname"` 12 | Phone string `json:"phone"` 13 | Email string `json:"email"` 14 | Gender int8 `json:"gender"` 15 | RoleId string `json:"role_id"` 16 | Enable int8 `json:"enable"` 17 | CreatedAt string `json:"created_at"` 18 | UpdatedAt string `json:"updated_at"` 19 | } 20 | -------------------------------------------------------------------------------- /server-user/pb/rpcUserService.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. DO NOT EDIT. 2 | // versions: 3 | // protoc-gen-go v1.30.0 4 | // protoc v3.19.0--rc1 5 | // source: rpcUserService.proto 6 | 7 | package pb 8 | 9 | import ( 10 | protoreflect "google.golang.org/protobuf/reflect/protoreflect" 11 | protoimpl "google.golang.org/protobuf/runtime/protoimpl" 12 | reflect "reflect" 13 | sync "sync" 14 | ) 15 | 16 | const ( 17 | // Verify that this generated code is sufficiently up-to-date. 18 | _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) 19 | // Verify that runtime/protoimpl is sufficiently up-to-date. 20 | _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) 21 | ) 22 | 23 | type GetUserInfoRequest struct { 24 | state protoimpl.MessageState 25 | sizeCache protoimpl.SizeCache 26 | unknownFields protoimpl.UnknownFields 27 | 28 | Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` 29 | } 30 | 31 | func (x *GetUserInfoRequest) Reset() { 32 | *x = GetUserInfoRequest{} 33 | if protoimpl.UnsafeEnabled { 34 | mi := &file_rpcUserService_proto_msgTypes[0] 35 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 36 | ms.StoreMessageInfo(mi) 37 | } 38 | } 39 | 40 | func (x *GetUserInfoRequest) String() string { 41 | return protoimpl.X.MessageStringOf(x) 42 | } 43 | 44 | func (*GetUserInfoRequest) ProtoMessage() {} 45 | 46 | func (x *GetUserInfoRequest) ProtoReflect() protoreflect.Message { 47 | mi := &file_rpcUserService_proto_msgTypes[0] 48 | if protoimpl.UnsafeEnabled && x != nil { 49 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 50 | if ms.LoadMessageInfo() == nil { 51 | ms.StoreMessageInfo(mi) 52 | } 53 | return ms 54 | } 55 | return mi.MessageOf(x) 56 | } 57 | 58 | // Deprecated: Use GetUserInfoRequest.ProtoReflect.Descriptor instead. 59 | func (*GetUserInfoRequest) Descriptor() ([]byte, []int) { 60 | return file_rpcUserService_proto_rawDescGZIP(), []int{0} 61 | } 62 | 63 | func (x *GetUserInfoRequest) GetId() string { 64 | if x != nil { 65 | return x.Id 66 | } 67 | return "" 68 | } 69 | 70 | type GetUserInfoResponse struct { 71 | state protoimpl.MessageState 72 | sizeCache protoimpl.SizeCache 73 | unknownFields protoimpl.UnknownFields 74 | 75 | Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` 76 | Username string `protobuf:"bytes,2,opt,name=username,proto3" json:"username,omitempty"` 77 | Nickname string `protobuf:"bytes,3,opt,name=nickname,proto3" json:"nickname,omitempty"` 78 | Phone string `protobuf:"bytes,4,opt,name=phone,proto3" json:"phone,omitempty"` 79 | Email string `protobuf:"bytes,5,opt,name=email,proto3" json:"email,omitempty"` 80 | CreatedAt string `protobuf:"bytes,6,opt,name=createdAt,proto3" json:"createdAt,omitempty"` 81 | } 82 | 83 | func (x *GetUserInfoResponse) Reset() { 84 | *x = GetUserInfoResponse{} 85 | if protoimpl.UnsafeEnabled { 86 | mi := &file_rpcUserService_proto_msgTypes[1] 87 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 88 | ms.StoreMessageInfo(mi) 89 | } 90 | } 91 | 92 | func (x *GetUserInfoResponse) String() string { 93 | return protoimpl.X.MessageStringOf(x) 94 | } 95 | 96 | func (*GetUserInfoResponse) ProtoMessage() {} 97 | 98 | func (x *GetUserInfoResponse) ProtoReflect() protoreflect.Message { 99 | mi := &file_rpcUserService_proto_msgTypes[1] 100 | if protoimpl.UnsafeEnabled && x != nil { 101 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 102 | if ms.LoadMessageInfo() == nil { 103 | ms.StoreMessageInfo(mi) 104 | } 105 | return ms 106 | } 107 | return mi.MessageOf(x) 108 | } 109 | 110 | // Deprecated: Use GetUserInfoResponse.ProtoReflect.Descriptor instead. 111 | func (*GetUserInfoResponse) Descriptor() ([]byte, []int) { 112 | return file_rpcUserService_proto_rawDescGZIP(), []int{1} 113 | } 114 | 115 | func (x *GetUserInfoResponse) GetId() int64 { 116 | if x != nil { 117 | return x.Id 118 | } 119 | return 0 120 | } 121 | 122 | func (x *GetUserInfoResponse) GetUsername() string { 123 | if x != nil { 124 | return x.Username 125 | } 126 | return "" 127 | } 128 | 129 | func (x *GetUserInfoResponse) GetNickname() string { 130 | if x != nil { 131 | return x.Nickname 132 | } 133 | return "" 134 | } 135 | 136 | func (x *GetUserInfoResponse) GetPhone() string { 137 | if x != nil { 138 | return x.Phone 139 | } 140 | return "" 141 | } 142 | 143 | func (x *GetUserInfoResponse) GetEmail() string { 144 | if x != nil { 145 | return x.Email 146 | } 147 | return "" 148 | } 149 | 150 | func (x *GetUserInfoResponse) GetCreatedAt() string { 151 | if x != nil { 152 | return x.CreatedAt 153 | } 154 | return "" 155 | } 156 | 157 | var File_rpcUserService_proto protoreflect.FileDescriptor 158 | 159 | var file_rpcUserService_proto_rawDesc = []byte{ 160 | 0x0a, 0x14, 0x72, 0x70, 0x63, 0x55, 0x73, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 161 | 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x02, 0x70, 0x62, 0x22, 0x24, 0x0a, 0x12, 0x47, 0x65, 162 | 0x74, 0x55, 0x73, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 163 | 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 164 | 0x22, 0xa7, 0x01, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 165 | 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 166 | 0x20, 0x01, 0x28, 0x03, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 167 | 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 168 | 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 169 | 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 170 | 0x12, 0x14, 0x0a, 0x05, 0x70, 0x68, 0x6f, 0x6e, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 171 | 0x05, 0x70, 0x68, 0x6f, 0x6e, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 172 | 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x1c, 0x0a, 0x09, 173 | 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 174 | 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x32, 0x52, 0x0a, 0x0e, 0x52, 0x70, 175 | 0x63, 0x55, 0x73, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x40, 0x0a, 0x0b, 176 | 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x16, 0x2e, 0x70, 0x62, 177 | 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 178 | 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 179 | 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x07, 180 | 0x5a, 0x05, 0x2e, 0x2e, 0x2f, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 181 | } 182 | 183 | var ( 184 | file_rpcUserService_proto_rawDescOnce sync.Once 185 | file_rpcUserService_proto_rawDescData = file_rpcUserService_proto_rawDesc 186 | ) 187 | 188 | func file_rpcUserService_proto_rawDescGZIP() []byte { 189 | file_rpcUserService_proto_rawDescOnce.Do(func() { 190 | file_rpcUserService_proto_rawDescData = protoimpl.X.CompressGZIP(file_rpcUserService_proto_rawDescData) 191 | }) 192 | return file_rpcUserService_proto_rawDescData 193 | } 194 | 195 | var file_rpcUserService_proto_msgTypes = make([]protoimpl.MessageInfo, 2) 196 | var file_rpcUserService_proto_goTypes = []interface{}{ 197 | (*GetUserInfoRequest)(nil), // 0: pb.GetUserInfoRequest 198 | (*GetUserInfoResponse)(nil), // 1: pb.GetUserInfoResponse 199 | } 200 | var file_rpcUserService_proto_depIdxs = []int32{ 201 | 0, // 0: pb.RpcUserService.GetUserInfo:input_type -> pb.GetUserInfoRequest 202 | 1, // 1: pb.RpcUserService.GetUserInfo:output_type -> pb.GetUserInfoResponse 203 | 1, // [1:2] is the sub-list for method output_type 204 | 0, // [0:1] is the sub-list for method input_type 205 | 0, // [0:0] is the sub-list for extension type_name 206 | 0, // [0:0] is the sub-list for extension extendee 207 | 0, // [0:0] is the sub-list for field type_name 208 | } 209 | 210 | func init() { file_rpcUserService_proto_init() } 211 | func file_rpcUserService_proto_init() { 212 | if File_rpcUserService_proto != nil { 213 | return 214 | } 215 | if !protoimpl.UnsafeEnabled { 216 | file_rpcUserService_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { 217 | switch v := v.(*GetUserInfoRequest); i { 218 | case 0: 219 | return &v.state 220 | case 1: 221 | return &v.sizeCache 222 | case 2: 223 | return &v.unknownFields 224 | default: 225 | return nil 226 | } 227 | } 228 | file_rpcUserService_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { 229 | switch v := v.(*GetUserInfoResponse); i { 230 | case 0: 231 | return &v.state 232 | case 1: 233 | return &v.sizeCache 234 | case 2: 235 | return &v.unknownFields 236 | default: 237 | return nil 238 | } 239 | } 240 | } 241 | type x struct{} 242 | out := protoimpl.TypeBuilder{ 243 | File: protoimpl.DescBuilder{ 244 | GoPackagePath: reflect.TypeOf(x{}).PkgPath(), 245 | RawDescriptor: file_rpcUserService_proto_rawDesc, 246 | NumEnums: 0, 247 | NumMessages: 2, 248 | NumExtensions: 0, 249 | NumServices: 1, 250 | }, 251 | GoTypes: file_rpcUserService_proto_goTypes, 252 | DependencyIndexes: file_rpcUserService_proto_depIdxs, 253 | MessageInfos: file_rpcUserService_proto_msgTypes, 254 | }.Build() 255 | File_rpcUserService_proto = out.File 256 | file_rpcUserService_proto_rawDesc = nil 257 | file_rpcUserService_proto_goTypes = nil 258 | file_rpcUserService_proto_depIdxs = nil 259 | } 260 | -------------------------------------------------------------------------------- /server-user/pb/rpcUserService_grpc.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go-grpc. DO NOT EDIT. 2 | // versions: 3 | // - protoc-gen-go-grpc v1.3.0 4 | // - protoc v3.19.0--rc1 5 | // source: rpcUserService.proto 6 | 7 | package pb 8 | 9 | import ( 10 | context "context" 11 | grpc "google.golang.org/grpc" 12 | codes "google.golang.org/grpc/codes" 13 | status "google.golang.org/grpc/status" 14 | ) 15 | 16 | // This is a compile-time assertion to ensure that this generated file 17 | // is compatible with the grpc package it is being compiled against. 18 | // Requires gRPC-Go v1.32.0 or later. 19 | const _ = grpc.SupportPackageIsVersion7 20 | 21 | const ( 22 | RpcUserService_GetUserInfo_FullMethodName = "/pb.RpcUserService/GetUserInfo" 23 | ) 24 | 25 | // RpcUserServiceClient is the client API for RpcUserService service. 26 | // 27 | // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. 28 | type RpcUserServiceClient interface { 29 | GetUserInfo(ctx context.Context, in *GetUserInfoRequest, opts ...grpc.CallOption) (*GetUserInfoResponse, error) 30 | } 31 | 32 | type rpcUserServiceClient struct { 33 | cc grpc.ClientConnInterface 34 | } 35 | 36 | func NewRpcUserServiceClient(cc grpc.ClientConnInterface) RpcUserServiceClient { 37 | return &rpcUserServiceClient{cc} 38 | } 39 | 40 | func (c *rpcUserServiceClient) GetUserInfo(ctx context.Context, in *GetUserInfoRequest, opts ...grpc.CallOption) (*GetUserInfoResponse, error) { 41 | out := new(GetUserInfoResponse) 42 | err := c.cc.Invoke(ctx, RpcUserService_GetUserInfo_FullMethodName, in, out, opts...) 43 | if err != nil { 44 | return nil, err 45 | } 46 | return out, nil 47 | } 48 | 49 | // RpcUserServiceServer is the server API for RpcUserService service. 50 | // All implementations must embed UnimplementedRpcUserServiceServer 51 | // for forward compatibility 52 | type RpcUserServiceServer interface { 53 | GetUserInfo(context.Context, *GetUserInfoRequest) (*GetUserInfoResponse, error) 54 | mustEmbedUnimplementedRpcUserServiceServer() 55 | } 56 | 57 | // UnimplementedRpcUserServiceServer must be embedded to have forward compatible implementations. 58 | type UnimplementedRpcUserServiceServer struct { 59 | } 60 | 61 | func (UnimplementedRpcUserServiceServer) GetUserInfo(context.Context, *GetUserInfoRequest) (*GetUserInfoResponse, error) { 62 | return nil, status.Errorf(codes.Unimplemented, "method GetUserInfo not implemented") 63 | } 64 | func (UnimplementedRpcUserServiceServer) mustEmbedUnimplementedRpcUserServiceServer() {} 65 | 66 | // UnsafeRpcUserServiceServer may be embedded to opt out of forward compatibility for this service. 67 | // Use of this interface is not recommended, as added methods to RpcUserServiceServer will 68 | // result in compilation errors. 69 | type UnsafeRpcUserServiceServer interface { 70 | mustEmbedUnimplementedRpcUserServiceServer() 71 | } 72 | 73 | func RegisterRpcUserServiceServer(s grpc.ServiceRegistrar, srv RpcUserServiceServer) { 74 | s.RegisterService(&RpcUserService_ServiceDesc, srv) 75 | } 76 | 77 | func _RpcUserService_GetUserInfo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { 78 | in := new(GetUserInfoRequest) 79 | if err := dec(in); err != nil { 80 | return nil, err 81 | } 82 | if interceptor == nil { 83 | return srv.(RpcUserServiceServer).GetUserInfo(ctx, in) 84 | } 85 | info := &grpc.UnaryServerInfo{ 86 | Server: srv, 87 | FullMethod: RpcUserService_GetUserInfo_FullMethodName, 88 | } 89 | handler := func(ctx context.Context, req interface{}) (interface{}, error) { 90 | return srv.(RpcUserServiceServer).GetUserInfo(ctx, req.(*GetUserInfoRequest)) 91 | } 92 | return interceptor(ctx, in, info, handler) 93 | } 94 | 95 | // RpcUserService_ServiceDesc is the grpc.ServiceDesc for RpcUserService service. 96 | // It's only intended for direct use with grpc.RegisterService, 97 | // and not to be introspected or modified (even as a copy) 98 | var RpcUserService_ServiceDesc = grpc.ServiceDesc{ 99 | ServiceName: "pb.RpcUserService", 100 | HandlerType: (*RpcUserServiceServer)(nil), 101 | Methods: []grpc.MethodDesc{ 102 | { 103 | MethodName: "GetUserInfo", 104 | Handler: _RpcUserService_GetUserInfo_Handler, 105 | }, 106 | }, 107 | Streams: []grpc.StreamDesc{}, 108 | Metadata: "rpcUserService.proto", 109 | } 110 | -------------------------------------------------------------------------------- /server-user/proto/rpcUserService.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package pb; 4 | 5 | option go_package = "../pb"; 6 | 7 | message GetUserInfoRequest { 8 | string id = 1; 9 | } 10 | 11 | message GetUserInfoResponse { 12 | int64 id = 1; 13 | string username = 2; 14 | string nickname = 3; 15 | string phone = 4; 16 | string email = 5; 17 | string createdAt = 6; 18 | } 19 | 20 | service RpcUserService { 21 | rpc GetUserInfo(GetUserInfoRequest) returns(GetUserInfoResponse){} 22 | } 23 | -------------------------------------------------------------------------------- /server-user/router/api.go: -------------------------------------------------------------------------------- 1 | package router 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "github.com/mazezen/ginframe/server-user/handler/auth" 6 | "github.com/mazezen/ginframe/server-user/handler/user" 7 | "github.com/mazezen/ginframe/server-user/middlewares" 8 | ) 9 | 10 | // ApiRouter http api routers 11 | func ApiRouter(r *gin.Engine) { 12 | 13 | v1Group := r.Group("/api/v1") 14 | setAuthRouter(v1Group) 15 | setUserRouter(v1Group) 16 | 17 | } 18 | 19 | // 登录授权 20 | func setAuthRouter(v1Group *gin.RouterGroup) { 21 | loginHandler := new(auth.LoginHandler) 22 | v1Group.POST("/login", loginHandler.Login) 23 | } 24 | 25 | // 用户 26 | func setUserRouter(v1Group *gin.RouterGroup) { 27 | userHandler := new(user.UserHandler) 28 | user := v1Group.Group("/user") 29 | user.Use(middlewares.AuthMiddleware()) 30 | user.Use(middlewares.CheckUserAccountIsEnable()) 31 | user.GET("/list", userHandler.List) 32 | } 33 | -------------------------------------------------------------------------------- /server-user/router/ws.go: -------------------------------------------------------------------------------- 1 | package router 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "github.com/mazezen/ginframe/server-user/handler" 6 | ) 7 | 8 | // WsRouter websocket routers 9 | func WsRouter(r *gin.Engine) { 10 | r.GET("/ws", handler.WsPing) 11 | } 12 | -------------------------------------------------------------------------------- /server-user/rpc/demo.go: -------------------------------------------------------------------------------- 1 | package _rpc 2 | 3 | import ( 4 | "errors" 5 | ) 6 | 7 | type Arith struct{} 8 | 9 | type ArithRequest struct { 10 | A int 11 | B int 12 | } 13 | 14 | type ArithResponse struct { 15 | Pro int 16 | Quo int 17 | Rem int 18 | } 19 | 20 | func (this *Arith) Multiply(req ArithRequest, res *ArithResponse) error { 21 | res.Pro = req.A * req.B 22 | return nil 23 | } 24 | 25 | func (this *Arith) Divide(req ArithRequest, res *ArithResponse) error { 26 | if req.B == 0 { 27 | return errors.New("divide by zero") 28 | } 29 | res.Quo = req.A / req.B 30 | res.Rem = req.A % req.B 31 | return nil 32 | } 33 | -------------------------------------------------------------------------------- /server-user/rpc/rpc.go: -------------------------------------------------------------------------------- 1 | package _rpc 2 | 3 | import ( 4 | "github.com/mazezen/ginframe/server-user/global" 5 | "log" 6 | "net" 7 | "net/http" 8 | "net/rpc" 9 | ) 10 | 11 | // RpcServer rpc server 12 | func RpcServer() error { 13 | 14 | rpc.Register(new(Arith)) 15 | 16 | rpc.HandleHTTP() 17 | addr := global.Config.Rpc.Listener 18 | l, err := net.Listen("tcp", addr) 19 | if err != nil { 20 | log.Fatalln("fatal error: ", err) 21 | } 22 | return http.Serve(l, nil) 23 | } 24 | -------------------------------------------------------------------------------- /server-user/run.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | # nacos服务地址 4 | nacos=192.168.0.40 5 | 6 | 7 | if [ ! -f 'server-user' ]; then 8 | echo 文件不存在! 待添加的安装包: 'server-user' 9 | exit 10 | fi 11 | 12 | echo "server-user..." 13 | sleep 3 14 | docker stop server-user 15 | 16 | sleep 2 17 | docker rm server-user 18 | 19 | docker rmi server-user 20 | echo "" 21 | 22 | echo "server-user packing..." 23 | sleep 3 24 | docker build -t server-user . 25 | echo "" 26 | 27 | echo "server-user running..." 28 | sleep 3 29 | 30 | docker run \ 31 | -p 9091:9091 \ 32 | -p 9092:9092 \ 33 | -p 9093:9093 \ 34 | -p 9094:9094 \ 35 | --name server-user \ 36 | --net host \ 37 | -v /mnt/server-user:/root/server-user/log \ 38 | -v /etc/localtime:/etc/localtime \ 39 | -v /data/leveldb_data:/root/server-user/leveldb_data \ 40 | -d server-user \ 41 | server-user -ip $nacos -p 7848 -c server-user.yml 42 | 43 | 44 | docker logs -f server-user | sed '/Started server-user application/q' 45 | 46 | echo "" -------------------------------------------------------------------------------- /server-user/scripts/generate_pb.sh: -------------------------------------------------------------------------------- 1 | cd ../proto && protoc --go_out=. --go-grpc_out=../pb *.proto -------------------------------------------------------------------------------- /server-user/service/auth/login.go: -------------------------------------------------------------------------------- 1 | package auth 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "github.com/dgrijalva/jwt-go" 7 | _jwt "github.com/mazezen/ginframe/server-common/pkg/jwt" 8 | "github.com/mazezen/ginframe/server-common/utils/encry" 9 | "github.com/mazezen/ginframe/server-user/daos/auth" 10 | "github.com/mazezen/ginframe/server-user/global" 11 | "github.com/mazezen/ginframe/server-user/input" 12 | out2 "github.com/mazezen/ginframe/server-user/out" 13 | "github.com/mazezen/ginframe/server-user/ulogger" 14 | "time" 15 | ) 16 | 17 | func LoginService(param *input.LoginInput) (*out2.LoginOut, error) { 18 | u, err := auth.FindUserByUsername(param.Username) 19 | if err != nil { 20 | ulogger.UserLogger.Error(fmt.Sprintf("username: %s 账号不存在", param.Username)) 21 | return nil, errors.New(fmt.Sprintf("username: %s 账号不存在", param.Username)) 22 | } 23 | 24 | err = encry.ComparePassword(u.Password, param.Password) 25 | if err != nil { 26 | ulogger.UserLogger.Error(fmt.Sprintf("username: %s 密码错误", param.Username)) 27 | return nil, errors.New(fmt.Sprintf("username: %s 密码错误", param.Username)) 28 | } 29 | 30 | expire := time.Hour * global.Config.Jwt.Expire 31 | instance := _jwt.NewJwtInstance(expire, global.Config.Jwt.Secret) 32 | claims := &_jwt.JwtClaims{ 33 | ID: u.Id, 34 | Username: u.Username, 35 | StandardClaims: jwt.StandardClaims{}, 36 | } 37 | 38 | token, err := instance.GenerateToken(claims) 39 | if err != nil { 40 | ulogger.UserLogger.Error(fmt.Sprintf("username: %s 签发token失败", param.Username)) 41 | return nil, errors.New(fmt.Sprintf("username: %s 签发token失败", param.Username)) 42 | } 43 | 44 | out := new(out2.LoginOut) 45 | out.Token = token 46 | out.Username = u.Username 47 | 48 | return out, nil 49 | 50 | } 51 | -------------------------------------------------------------------------------- /server-user/service/user/user.go: -------------------------------------------------------------------------------- 1 | package user 2 | 3 | import ( 4 | "github.com/mazezen/ginframe/server-common/utils/wtime" 5 | "github.com/mazezen/ginframe/server-user/daos/account" 6 | out2 "github.com/mazezen/ginframe/server-user/out" 7 | "github.com/mazezen/ginframe/server-user/ulogger" 8 | "go.uber.org/zap" 9 | ) 10 | 11 | func UserListService(pageNum, pageSize int64) (int64, []*out2.Users) { 12 | count, users, err := account.UserList(pageNum, pageSize) 13 | if err != nil { 14 | ulogger.UserLogger.Error("查询管理员账号列表失败, err: ", zap.Error(err)) 15 | return 0, nil 16 | } 17 | 18 | as := make([]*out2.Users, 0) 19 | for _, item := range users { 20 | a := &out2.Users{ 21 | Id: item.Id, 22 | Username: item.Username, 23 | Nickname: item.Nickname, 24 | Phone: item.Phone, 25 | Email: item.Email, 26 | Gender: item.Gender, 27 | RoleId: item.RoleId, 28 | Enable: item.Enable, 29 | CreatedAt: wtime.WTtime.FormatTime(item.CreatedAt), 30 | UpdatedAt: wtime.WTtime.FormatTime(item.UpdatedAt), 31 | } 32 | as = append(as, a) 33 | } 34 | 35 | return count, as 36 | } 37 | -------------------------------------------------------------------------------- /server-user/ulogger/logger.go: -------------------------------------------------------------------------------- 1 | package ulogger 2 | 3 | import "go.uber.org/zap" 4 | 5 | var UserLogger *zap.Logger 6 | 7 | // SetLogger set logger 8 | func SetLogger(_logger *zap.Logger) { 9 | UserLogger = _logger 10 | } 11 | -------------------------------------------------------------------------------- /server-user/up_package.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo " ========= 开始上传 server-user ========= " 4 | 5 | function scp_file1 { 6 | local file=$1 7 | local passwd="112233" 8 | expect -c" 9 | spawn scp ${file} root@192.168.0.72:/root/server-user 10 | expect { 11 | \"*password\" {set timeout 300; send \"${passwd}\r\";} 12 | } 13 | expect eof" 14 | } 15 | 16 | 17 | function scp_file2 { 18 | local file=$1 19 | local passwd="112233" 20 | expect -c" 21 | spawn scp ${file} root@192.168.0.73:/root/server-user 22 | expect { 23 | \"*password\" {set timeout 300; send \"${passwd}\r\";} 24 | } 25 | expect eof" 26 | } 27 | 28 | scp_file1 "server-user" 29 | 30 | echo " ========= server-user1 服务上传完成 ========= " 31 | 32 | #sleep 5 33 | 34 | echo " ========= 开始上传 server-user2 ========= " 35 | 36 | scp_file2 "server-user" 37 | 38 | echo " ========= server-user2 服务上传完成 ========= " 39 | 40 | -------------------------------------------------------------------------------- /server-user/ws/ws.go: -------------------------------------------------------------------------------- 1 | package ws 2 | 3 | import ( 4 | "errors" 5 | "github.com/gorilla/websocket" 6 | "net/http" 7 | "sync" 8 | ) 9 | 10 | var Upgrade = websocket.Upgrader{ 11 | ReadBufferSize: 1024, 12 | WriteBufferSize: 1024, 13 | CheckOrigin: func(r *http.Request) bool { 14 | return true 15 | }, 16 | } 17 | 18 | type Connection struct { 19 | wsConn *websocket.Conn 20 | inChan chan []byte 21 | outChan chan []byte 22 | closeChan chan byte 23 | mutex sync.Mutex 24 | isClosed bool 25 | } 26 | 27 | func (conn *Connection) ReadMessage() (data []byte, err error) { 28 | select { 29 | case data = <-conn.inChan: 30 | case <-conn.closeChan: 31 | err = errors.New("connection is closed") 32 | } 33 | return 34 | } 35 | 36 | func (conn *Connection) WriteMessage(data []byte) (err error) { 37 | select { 38 | case conn.outChan <- data: 39 | case <-conn.closeChan: 40 | err = errors.New("connection is closed") 41 | } 42 | return 43 | } 44 | 45 | func (conn *Connection) Close() { 46 | //线程安全的Close,可重入 47 | conn.wsConn.Close() 48 | conn.mutex.Lock() 49 | if !conn.isClosed { 50 | close(conn.closeChan) 51 | conn.isClosed = true 52 | } 53 | conn.mutex.Unlock() 54 | 55 | } 56 | 57 | func InitConnection(wsConn *websocket.Conn) (conn *Connection, err error) { 58 | conn = &Connection{ 59 | wsConn: wsConn, 60 | inChan: make(chan []byte, 1000), 61 | outChan: make(chan []byte, 1000), 62 | closeChan: make(chan byte, 1), 63 | } 64 | go conn.readLoop() 65 | go conn.writeLoop() 66 | return 67 | } 68 | 69 | func (conn *Connection) readLoop() { 70 | var ( 71 | data []byte 72 | err error 73 | ) 74 | for { 75 | if _, data, err = conn.wsConn.ReadMessage(); err != nil { 76 | goto ERR 77 | } 78 | select { 79 | case conn.inChan <- data: 80 | case <-conn.closeChan: 81 | goto ERR 82 | } 83 | 84 | } 85 | ERR: 86 | conn.Close() 87 | } 88 | func (conn *Connection) writeLoop() { 89 | var ( 90 | data []byte 91 | err error 92 | ) 93 | for { 94 | select { 95 | case data = <-conn.outChan: 96 | case <-conn.closeChan: 97 | goto ERR 98 | } 99 | if err = conn.wsConn.WriteMessage(websocket.TextMessage, data); err != nil { 100 | goto ERR 101 | } 102 | } 103 | ERR: 104 | conn.Close() 105 | } 106 | -------------------------------------------------------------------------------- /test/aes_test.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | import ( 4 | "fmt" 5 | "github.com/mazezen/ginframe/server-common/utils/encry" 6 | "testing" 7 | ) 8 | 9 | func TestAesEncryptDecrypt(t *testing.T) { 10 | instance, err := encry.NewAesEncryptInstance("bGcGfWb3Kg2s4gcG", "aebksHkG4jAEk2Ag") 11 | if err != nil { 12 | t.Fatal(err) 13 | } 14 | encrypt, err := instance.AesBase64Encrypt("1234566dfsdasd") 15 | if err != nil { 16 | t.Fatal(err) 17 | } 18 | fmt.Println(encrypt) 19 | 20 | fmt.Println("=======================================") 21 | 22 | decrypt, err := instance.AesBase64Decrypt(encrypt) 23 | if err != nil { 24 | t.Fatal(err) 25 | } 26 | fmt.Println(decrypt) 27 | } 28 | -------------------------------------------------------------------------------- /test/email_test.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | import ( 4 | "fmt" 5 | "github.com/mazezen/ginframe/server-common/utils/email" 6 | "os" 7 | "testing" 8 | ) 9 | 10 | func TestSend163Mail(t *testing.T) { 11 | from := os.Getenv("Mail163From") 12 | to := "" // 接收人的邮箱 13 | mailPassword := os.Getenv("Mail163Pass") 14 | mailServer := os.Getenv("Mail163Server") 15 | mailServerPort := os.Getenv("Mail163ServerPort") 16 | title := "单元测试,邮件发送" 17 | content := `能发送过去吗:" + 123456 + "` 18 | err := email.SendMail(from, to, title, content, mailServer, mailServerPort, mailPassword) 19 | if err != nil { 20 | t.Fatal(err) 21 | } 22 | fmt.Println("邮件发送成功...") 23 | } 24 | 25 | func TestSendQQMail(t *testing.T) { 26 | from := os.Getenv("MailQQFrom") 27 | to := "" // 接收人的邮箱 28 | mailPassword := os.Getenv("MailQQPass") 29 | mailServer := os.Getenv("MailQQServer") 30 | mailServerPort := os.Getenv("MailQQServerPort") 31 | title := "单元测试,邮件发送" 32 | content := fmt.Sprintf(` 33 | 34 | 35 | 36 | 37 | IM注册邮件 38 | 39 | 55 | 56 | 57 | 您好:您正在测试qq邮箱发送! 58 | 下面是您的验证码: 59 | %s 60 | 请注意查收!谢谢 61 | 62 | 如果可以请给项目点个star~项目地址 63 | 64 | `, "123456") 65 | err := email.SendMail(from, to, title, content, mailServer, mailServerPort, mailPassword) 66 | if err != nil { 67 | t.Fatal(err) 68 | } 69 | fmt.Println("邮件发送成功...") 70 | } 71 | 72 | func TestSend126Mail(t *testing.T) { 73 | from := os.Getenv("Mail126From") 74 | to := "xxxxx@qq.com" // 接收人的邮箱 75 | mailPassword := os.Getenv("Mail126Pass") 76 | mailServer := os.Getenv("Mail126Server") 77 | mailServerPort := os.Getenv("Mail126ServerPort") 78 | title := "单元测试,邮件发送" 79 | content := fmt.Sprintf(` 80 | 81 | 82 | 83 | 84 | IM注册邮件 85 | 86 | 102 | 103 | 104 | 您好:您正在测试qq邮箱发送! 105 | 下面是您的验证码: 106 | %s 107 | 请注意查收!谢谢 108 | 109 | 如果可以请给项目点个star~项目地址 110 | 111 | `, "123456") 112 | err := email.SendMail(from, to, title, content, mailServer, mailServerPort, mailPassword) 113 | if err != nil { 114 | t.Fatal(err) 115 | } 116 | fmt.Println("邮件发送成功...") 117 | } 118 | 119 | func TestSendEmailStartTls(t *testing.T) { 120 | from := os.Getenv("MailGmailFrom") 121 | to := "" // 接收人的邮箱 122 | mailPassword := os.Getenv("MailGmailPass") 123 | mailServer := os.Getenv("MailGmailServer") 124 | mailServerPort := os.Getenv("MailGmailServerPort") 125 | title := "单元测试,邮件发送" 126 | content := fmt.Sprintf(` 127 | 128 | 129 | 130 | 131 | IM注册邮件 132 | 133 | 149 | 150 | 151 | 您好:您正在测试qq邮箱发送! 152 | 下面是您的验证码: 153 | %s 154 | 请注意查收!谢谢 155 | 156 | 如果可以请给项目点个star~项目地址 157 | 158 | `, "123456") 159 | err := email.SendGmailEmail(from, to, title, content, mailServer, mailServerPort, mailPassword) 160 | if err != nil { 161 | t.Fatal(err) 162 | } 163 | fmt.Println("邮件发送成功...") 164 | } 165 | 166 | func TestSendGmail(t *testing.T) { 167 | from := os.Getenv("MailGmailFrom") 168 | to := []string{ 169 | "", // 接收人的邮箱1 170 | "", // 接收人的邮箱2 171 | } 172 | mailPassword := os.Getenv("MailGmailPass") 173 | mailServer := os.Getenv("MailGmailServer") 174 | mailServerPort := os.Getenv("MailGmailServerPort") 175 | content := []byte(fmt.Sprintf(` 176 | 177 | 178 | 179 | 180 | IM注册邮件 181 | 182 | 198 | 199 | 200 | 您好:您正在测试qq邮箱发送! 201 | 下面是您的验证码: 202 | %s 203 | 请注意查收!谢谢 204 | 205 | 如果可以请给项目点个star~项目地址 206 | 207 | `, "123456")) 208 | 209 | err := email.SendGmail(from, to, content, mailServer, mailServerPort, mailPassword) 210 | if err != nil { 211 | t.Fatal(err) 212 | } 213 | fmt.Println("邮件发送成功...") 214 | } 215 | -------------------------------------------------------------------------------- /test/httprequest_test.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | import ( 4 | "fmt" 5 | "github.com/mazezen/ginframe/server-common/pkg/httprequest" 6 | "testing" 7 | ) 8 | 9 | func TestHttpRequestTest(t *testing.T) { 10 | // 常用的第三方api汇总[获取天气] 11 | // 1. 随机用户(GET请求, JSON格式)。 12 | // results表示获取用户个数,也就是数组字段results的长度,默认为1;nat应该是国家简称,好像设置了也没啥用。 13 | url := "https://api.randomuser.me/?nat=US&results=1" 14 | h := make(map[string]string) 15 | h["Content-type"] = "application/json" 16 | p := make(map[string]interface{}) 17 | req := new(httprequest.HttpRequest) 18 | bytes, err := req.Get(url, h, p) 19 | if err != nil { 20 | t.Fatal(err) 21 | } 22 | fmt.Println(string(bytes)) 23 | } 24 | 25 | func TestHttpRequestPost(t *testing.T) { 26 | // { 27 | // "body": "千里走单骑", 28 | // "title": "关于山东为爱出拳", 29 | // "userId": 1, 30 | // "id": 101 31 | // } 32 | url := "http://jsonplaceholder.typicode.com/posts" 33 | h := make(map[string]string) 34 | h["Content-type"] = "application/json" 35 | p := make(map[string]interface{}) 36 | p["userId"] = 1 37 | p["title"] = "关于山东为爱出拳" 38 | p["body"] = "千里走单骑" 39 | req := new(httprequest.HttpRequest) 40 | bytes, err := req.Post(url, h, p) 41 | if err != nil { 42 | t.Fatal(err) 43 | } 44 | fmt.Println(string(bytes)) 45 | } 46 | -------------------------------------------------------------------------------- /test/map_test.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | import ( 4 | "fmt" 5 | "github.com/mazezen/ginframe/server-common/utils/maps" 6 | "testing" 7 | "time" 8 | ) 9 | 10 | func TestMergeMap(t *testing.T) { 11 | dest := make(map[interface{}]interface{}) 12 | dest["a"] = "fsdsdfasd" 13 | dest["b"] = 124 14 | 15 | src := make(map[interface{}]interface{}) 16 | src["a"] = "fsdsdfasd" 17 | src["b"] = 12 18 | src["g"] = []int{1, 2, 3} 19 | src["f"] = []string{"aaa", "bb", "ccc"} 20 | 21 | mergeMap := maps.MergeMap(dest, src) 22 | fmt.Println(mergeMap) 23 | } 24 | 25 | // 测试并发 写 - 读 - 删 26 | func TestConcurrencyRwMap(t *testing.T) { 27 | // 写 28 | rmap := maps.NewConcurrencyRwMap(1000) 29 | for i := 0; i < 300; i++ { 30 | go func(i int) { 31 | rmap.Set(fmt.Sprintf("%v", i), i*2) 32 | }(i) 33 | } 34 | time.Sleep(time.Second * 4) 35 | fmt.Println(len(rmap.Map)) 36 | fmt.Println(rmap.Map) 37 | 38 | // 读 39 | for i := 0; i < 300; i++ { 40 | go func(i int) { 41 | res := rmap.Get(fmt.Sprintf("%v", i)) 42 | fmt.Printf("res: key:%d => value: %d\n", i, res) 43 | }(i) 44 | } 45 | time.Sleep(time.Second * 4) 46 | 47 | // 删 48 | for i := 0; i < 30; i++ { 49 | go func(i int) { 50 | rmap.Delete(fmt.Sprintf("%v", i)) 51 | }(i) 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /test/regmatch_test.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | import ( 4 | "fmt" 5 | "github.com/mazezen/ginframe/server-common/utils/regmatch" 6 | "testing" 7 | ) 8 | 9 | func TestRegMatchPhone(t *testing.T) { 10 | ok := regmatch.RegMatchPhone("12346789") 11 | fmt.Println(ok) 12 | } 13 | 14 | // :010-1234567 15 | func TestRegLandLineNumber(t *testing.T) { 16 | ok := regmatch.RegLandLineNumber("010-4844") 17 | fmt.Println(ok) 18 | } 19 | 20 | // 4102241995412645845 21 | func TestRegIDCard(t *testing.T) { 22 | ok := regmatch.RegIDCard("xxxxxxxxxxxxxxxxxxxxxxxxxx") 23 | fmt.Println(ok) 24 | } 25 | 26 | // 1.160.10.240 27 | func TestRegIPV4(t *testing.T) { 28 | ok := regmatch.RegIPV4("1.160.10.240") 29 | fmt.Println(ok) 30 | } 31 | 32 | func TestRegIPV6(t *testing.T) { 33 | ok := regmatch.RegIPV6("1030::C9B4:FF12:48AA:1A2B") 34 | fmt.Println(ok) 35 | } 36 | 37 | func TestPassword(t *testing.T) { 38 | ok := regmatch.CheckPasswordLever("Aaba12345678@") 39 | fmt.Println(ok) 40 | } 41 | 42 | func TestRegUrl(t *testing.T) { 43 | ok := regmatch.RegUrl("https://www.baidu.com/") 44 | fmt.Println(ok) 45 | } 46 | 47 | func TestRegUrlPort(t *testing.T) { 48 | ok := regmatch.RegUrlPort("https://www.baidu.com:8080/") 49 | fmt.Println(ok) 50 | } 51 | 52 | func TestRegAmount(t *testing.T) { 53 | ok := regmatch.RegAmount("0.11") 54 | fmt.Println(ok) 55 | } 56 | -------------------------------------------------------------------------------- /test/rpc_test.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "net/rpc" 7 | "testing" 8 | ) 9 | 10 | type ArithRequest struct { 11 | A int 12 | B int 13 | } 14 | 15 | type ArithResponse struct { 16 | Pro int 17 | Quo int 18 | Rem int 19 | } 20 | 21 | func TestRpc(t *testing.T) { 22 | client, err := rpc.DialHTTP("tcp", "127.0.0.1:9094") 23 | if err != nil { 24 | log.Fatalln("dailing error: ", err) 25 | } 26 | 27 | req := ArithRequest{9, 2} 28 | var res ArithResponse 29 | 30 | err = client.Call("Arith.Multiply", req, &res) 31 | if err != nil { 32 | log.Fatalln("arith error: ", err) 33 | } 34 | fmt.Println(res) 35 | fmt.Printf("%d * %d = %d\n", req.A, req.B, res.Pro) 36 | } 37 | -------------------------------------------------------------------------------- /test/wordsfilter_test.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | import ( 4 | "github.com/mazezen/ginframe/server-common/utils/wordsfilter" 5 | "log" 6 | "testing" 7 | ) 8 | 9 | func Init() { 10 | filepath := "../utils/wordsfilter/words_filter.txt" 11 | wordsfilter.SetWordsFilter(filepath) 12 | } 13 | 14 | func TestContentFilter(t *testing.T) { 15 | Init() 16 | //fmt.Println(words) 17 | if wordsfilter.ContentFilter("SB") { 18 | log.Fatal("SB 是敏感词") 19 | } 20 | log.Fatal("SB 不是敏感词") 21 | } 22 | -------------------------------------------------------------------------------- /test/ws.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 52 | 53 | 54 | 55 | 56 | Click "Open" to create a connection to the server, 57 | "Send" to send a message to the server and "Close" to close the connection. 58 | You can change the message and send multiple times. 59 | 60 | 61 | Open 62 | Close 63 | 64 | Send 65 | 66 | 67 | 68 | 69 | 70 | --------------------------------------------------------------------------------
下面是您的验证码:
%s
请注意查收!谢谢
Click "Open" to create a connection to the server, 57 | "Send" to send a message to the server and "Close" to close the connection. 58 | You can change the message and send multiple times. 59 |