mirror of
https://github.com/bufanyun/hotgo.git
synced 2025-01-23 10:50:24 +08:00
This commit is contained in:
parent
ab912d0ba6
commit
1acc6d17c4
@ -67,10 +67,11 @@
|
||||
14. 插件应用:支持一键生成插件模板,每个插件之间开发隔离,拥有独立多应用入口、独立配置。完美支持多人协同开发、插件插拔不会对原系统产生影响等。
|
||||
15. 服务监控:监视当前系统CPU、内存、磁盘、网络、堆栈等相关信息。
|
||||
16. 附件管理:文件上传,多种上传方式适配。
|
||||
17. 消息队列:同时兼容 kafka、redis、rocketmq、磁盘队列,一键配置切换到场景适用的MQ。
|
||||
18. 通知公告:采用websocket实时推送在线用户最新通知、公告、私信消息。
|
||||
19. 地区编码:整合国内通用省市区编码,运用于项目于一身,支持动态省市区选项。
|
||||
20. 常用工具:集成常用的工具包和命令行工具,可以快速开发自定义命令行,多种启动入口。
|
||||
17. TCP服务:基于gtcp的应用化实例,支持长连接、断线重连、自动维护心跳、服务登录、服务授权等。主要用于网络服务进程之间的消息通讯。
|
||||
18. 消息队列:同时兼容 kafka、redis、rocketmq、磁盘队列,一键配置切换到场景适用的MQ。
|
||||
19. 通知公告:采用websocket实时推送在线用户最新通知、公告、私信消息。
|
||||
20. 地区编码:整合国内通用省市区编码,运用于项目于一身,支持动态省市区选项。
|
||||
21. 常用工具:集成常用的工具包和命令行工具,可以快速开发自定义命令行,多种启动入口。
|
||||
|
||||
|
||||
> HotGo开源以来得到了大家的很多支持,本项目初衷只为互相学习交流,没有任何盈利性目的!欢迎为HotGo贡献代码或提供建议!
|
||||
|
@ -26,6 +26,7 @@
|
||||
- 工具方法
|
||||
- RESTful Api
|
||||
- Websocket服务器
|
||||
- TCP服务器
|
||||
- 单元测试
|
||||
|
||||
#### 插件模块开发
|
||||
|
@ -27,7 +27,7 @@ git clone https://github.com/bufanyun/hotgo.git && cd hotgo
|
||||
|
||||
1、服务端:
|
||||
- 项目数据库文件 `storage/data/db.sql` 创建数据库并导入
|
||||
- 修改配置 `manifest/config/config.yaml.bak` 复制改为`manifest/config/config.yaml`
|
||||
- 将配置文件 `manifest/config/config.yaml.bak` 复制后改为`manifest/config/config.yaml`
|
||||
- 将`manifest/config/config.yaml`中的数据库配置改为你自己的:
|
||||
```yaml
|
||||
database:
|
||||
|
@ -29,6 +29,7 @@
|
||||
|
||||
> 报错信息:panic: possible config files "config" or "config.toml/yaml/yml/json/ini/xml/properties" not found in resource manager or following system searching paths:
|
||||
|
||||
这是因为系统没有找到配置文件,修改配置 `manifest/config/config.yaml.bak` 复制改为`manifest/config/config.yaml`
|
||||
这是因为系统没有找到配置文件,将配置文件 `manifest/config/config.yaml.bak` 复制后改为`manifest/config/config.yaml`
|
||||
|
||||
|
||||
详细请参考 - [系统安装](start-installation.md)
|
||||
|
@ -11,6 +11,16 @@
|
||||
|
||||
> 如果升级(覆盖)代码后打开会出现 sql 报错, 请检查更新的数据库格式或自行调整
|
||||
|
||||
### v2.4.2
|
||||
updated 2023.03.11
|
||||
- 修复:修复字典管理列表无法添加/编辑问题
|
||||
- 优化:优化代码生成文档
|
||||
- 优化:优化部门树形选项排序问题
|
||||
- 优化:优化基础设置中的LOGO图片上传组件
|
||||
- 优化:优化黑名单IP过滤策略
|
||||
- 增加:增加基于gtcp实现的C/S服务器,为后续多服务通讯建立基础库
|
||||
- 优化:gf版本升级到v2.3.3
|
||||
|
||||
### v2.3.5
|
||||
updated 2023.02.26
|
||||
|
||||
|
@ -26,10 +26,12 @@
|
||||
- 表自增长字段为 `id`
|
||||
|
||||
|
||||
### 生成配置
|
||||
### 生成模板配置
|
||||
|
||||
- 注意:线上环境务必将allowedIPs参数设为空,考虑到项目安全问题请勿线上生成使用!
|
||||
|
||||
- 默认配置路径:server/manifest/config/config.yaml
|
||||
|
||||
```yaml
|
||||
hggen:
|
||||
allowedIPs: ["127.0.0.1", "*"] # 白名单,*代表所有,只有允许的IP后台才能使用生成代码功能
|
||||
@ -88,6 +90,46 @@ hggen:
|
||||
templatePath: "./resource/generate/default/cron"
|
||||
```
|
||||
|
||||
### 生成dao、service配置
|
||||
|
||||
|
||||
- hotgo在生成dao、service配置时,默认了和gf官方一致的配置方式和代码生成规则。所以无论你是通过hotgo亦或gf命令生成,最终代码格式完全一致,遵循一致的代码规范。
|
||||
|
||||
- 默认配置路径:server/hack/config.yaml
|
||||
|
||||
```yaml
|
||||
gfcli:
|
||||
build:
|
||||
name: "hotgo" # 编译后的可执行文件名称
|
||||
# arch: "all" #不填默认当前系统架构,可选:386,amd64,arm,all
|
||||
# system: "all" #不填默认当前系统平台,可选:linux,darwin,windows,all
|
||||
mod: "none"
|
||||
cgo: 0
|
||||
packSrc: "resource" # 将resource目录打包进可执行文件,静态资源无需单独部署
|
||||
packDst: "internal/packed/packed.go" # 打包后生成的Go文件路径,一般使用相对路径指定到本项目目录中
|
||||
version: ""
|
||||
output: "./temp/hotgo" # 可执行文件生成路径
|
||||
extra: ""
|
||||
|
||||
gen:
|
||||
dao:
|
||||
- link: "mysql:hotgo:hg123456.@tcp(127.0.0.1:3306)/hotgo?loc=Local&parseTime=true"
|
||||
group: "default" # 分组 使用hotgo代码生成功能时必须填
|
||||
# tables: "" # 指定当前数据库中需要执行代码生成的数据表。如果为空,表示数据库的所有表都会生成。
|
||||
tablesEx: "hg_sys_addons_install" # 指定当前数据库中需要排除代码生成的数据表。
|
||||
removePrefix: "hg_"
|
||||
descriptionTag: true
|
||||
noModelComment: true
|
||||
jsonCase: "CamelLower"
|
||||
gJsonSupport: true
|
||||
clear: true
|
||||
|
||||
service: # 生成业务配置
|
||||
srcFolder: "internal/logic"
|
||||
dstFolder: "internal/service"
|
||||
dstFileNameCase: "CamelLower"
|
||||
clear: true
|
||||
```
|
||||
|
||||
### 一个生成增删改查列表例子
|
||||
|
||||
@ -223,8 +265,6 @@ INSERT INTO `hg_test_table` (`id`, `category_id`, `title`, `description`, `conte
|
||||
|
||||
> 由于gf版本更新较常出现向下不兼容的情况,所以我们为了保证生成代码的依赖稳定性,我们将gf-cli工具内置到了系统中并做了一些在线执行的调整。
|
||||
|
||||
- 我们会定期更新和gf最新版本生成功能保持一致,这样不论是你通过gf命令还是通过后台生成的代码格式都是一样的,遵循相同的代码规范和开发方式
|
||||
|
||||
- 后续我们也将开放在线运行`gf gen dao`、`gf gen service`功能。在做插件开发时也会支持到在线生成插件下的service接口,这将会使得插件开发更加方便
|
||||
|
||||
### 自定义生成模板
|
||||
|
@ -49,8 +49,8 @@
|
||||
|--------------|----------------------|----------------------|
|
||||
| status | 状态字段(任意int类型) | Select (单选下拉框) |
|
||||
| created_at | 创建时间字段 | TimeRange (时间范围选择) |
|
||||
| province_id | 省份字段(任意int类型) | CitySelector (省市区选择) |
|
||||
| city_id | 省份字段(任意int类型) | CitySelector (省市区选择) |
|
||||
| province_id | 省份ID字段(任意int类型) | CitySelector (省市区选择) |
|
||||
| city_id | 城市ID字段(任意int类型) | CitySelector (省市区选择) |
|
||||
| 任意字串符字段 | 长度>= 200 and <= 500 | InputTextarea (文本域) |
|
||||
| 任意字串符字段 | 长度> 500 | InputEditor (富文本) |
|
||||
|
||||
|
@ -17,6 +17,18 @@ build:
|
||||
all:
|
||||
gf run main.go --args "all"
|
||||
|
||||
.PHONY: http
|
||||
http:
|
||||
gf run main.go --args "http"
|
||||
|
||||
.PHONY: queue
|
||||
queue:
|
||||
gf run main.go --args "queue"
|
||||
|
||||
.PHONY: auth
|
||||
auth:
|
||||
gf run main.go --args "auth"
|
||||
|
||||
# 启动web服务
|
||||
.PHONY: web
|
||||
web:
|
||||
|
@ -14,10 +14,11 @@ require (
|
||||
github.com/casbin/casbin/v2 v2.55.0
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible
|
||||
github.com/forgoer/openssl v1.4.0
|
||||
github.com/fwhezfwhez/errorx v1.1.0
|
||||
github.com/go-resty/resty/v2 v2.7.0
|
||||
github.com/gogf/gf/contrib/drivers/mysql/v2 v2.3.2
|
||||
github.com/gogf/gf/contrib/nosql/redis/v2 v2.3.2
|
||||
github.com/gogf/gf/v2 v2.3.2
|
||||
github.com/gogf/gf/contrib/drivers/mysql/v2 v2.3.3
|
||||
github.com/gogf/gf/contrib/nosql/redis/v2 v2.3.3
|
||||
github.com/gogf/gf/v2 v2.3.3
|
||||
github.com/gomodule/redigo v1.8.8
|
||||
github.com/gorilla/websocket v1.5.0
|
||||
github.com/kayon/iploc v0.0.0-20200312105652-bda3e968a794
|
||||
@ -26,8 +27,9 @@ require (
|
||||
github.com/shirou/gopsutil v3.21.11+incompatible
|
||||
github.com/shopspring/decimal v1.3.1
|
||||
github.com/ufilesdk-dev/ufile-gosdk v1.0.3
|
||||
github.com/xtaci/kcp-go v5.4.20+incompatible
|
||||
github.com/xuri/excelize/v2 v2.6.0
|
||||
golang.org/x/tools v0.1.12
|
||||
golang.org/x/tools v0.6.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
||||
@ -56,6 +58,7 @@ require (
|
||||
github.com/go-ole/go-ole v1.2.6 // indirect
|
||||
github.com/go-redis/redis/v8 v8.11.5 // indirect
|
||||
github.com/go-sql-driver/mysql v1.7.0 // indirect
|
||||
github.com/gofrs/uuid v4.0.0+incompatible // indirect
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
|
||||
github.com/golang/mock v1.6.0 // indirect
|
||||
github.com/golang/snappy v0.0.4 // indirect
|
||||
@ -71,6 +74,8 @@ require (
|
||||
github.com/jcmturner/rpc/v2 v2.0.3 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/klauspost/compress v1.15.6 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.1.1 // indirect
|
||||
github.com/klauspost/reedsolomon v1.11.7 // indirect
|
||||
github.com/magiconair/properties v1.8.7 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.17 // indirect
|
||||
@ -83,27 +88,30 @@ require (
|
||||
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect
|
||||
github.com/richardlehane/mscfb v1.0.4 // indirect
|
||||
github.com/richardlehane/msoleps v1.0.1 // indirect
|
||||
github.com/rivo/uniseg v0.4.3 // indirect
|
||||
github.com/rivo/uniseg v0.4.4 // indirect
|
||||
github.com/sirupsen/logrus v1.8.1 // indirect
|
||||
github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161 // indirect
|
||||
github.com/templexxx/xor v0.0.0-20191217153810-f85b25db303b // indirect
|
||||
github.com/tidwall/gjson v1.2.1 // indirect
|
||||
github.com/tidwall/match v1.0.1 // indirect
|
||||
github.com/tidwall/pretty v0.0.0-20190325153808-1166b9ac2b65 // indirect
|
||||
github.com/tjfoc/gmsm v1.3.2 // indirect
|
||||
github.com/tklauser/go-sysconf v0.3.10 // indirect
|
||||
github.com/tklauser/numcpus v0.4.0 // indirect
|
||||
github.com/xtaci/lossyconn v0.0.0-20200209145036-adba10fffc37 // indirect
|
||||
github.com/xuri/efp v0.0.0-20220407160117-ad0f7a785be8 // indirect
|
||||
github.com/xuri/nfp v0.0.0-20220409054826-5e722a1d9e22 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.2 // indirect
|
||||
go.opentelemetry.io/otel v1.13.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk v1.13.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.13.0 // indirect
|
||||
go.opentelemetry.io/otel v1.14.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk v1.14.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.14.0 // indirect
|
||||
go.uber.org/atomic v1.7.0 // indirect
|
||||
golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 // indirect
|
||||
golang.org/x/image v0.0.0-20211028202545-6944b10bf410 // indirect
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
|
||||
golang.org/x/net v0.7.0 // indirect
|
||||
golang.org/x/sys v0.5.0 // indirect
|
||||
golang.org/x/text v0.7.0 // indirect
|
||||
golang.org/x/mod v0.8.0 // indirect
|
||||
golang.org/x/net v0.8.0 // indirect
|
||||
golang.org/x/sys v0.6.0 // indirect
|
||||
golang.org/x/text v0.8.0 // indirect
|
||||
gopkg.in/ini.v1 v1.56.0 // indirect
|
||||
stathat.com/c/consistent v1.0.0 // indirect
|
||||
)
|
||||
|
@ -135,6 +135,8 @@ github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5
|
||||
github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
|
||||
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
|
||||
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
|
||||
github.com/fwhezfwhez/errorx v1.1.0 h1:795cMWZFM+thQfKaC5Cjnp/h6naUEbsoQxOb/yvwn0c=
|
||||
github.com/fwhezfwhez/errorx v1.1.0/go.mod h1:epOraH2nrfmf4JUao5290NFuXw9t6MZnzgwoW5guABE=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
@ -161,13 +163,15 @@ github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ
|
||||
github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||
github.com/gogf/gf/contrib/drivers/mysql/v2 v2.3.2 h1:BZww6QOFgiN/YvovUtN64sgnq59TIg8vtkG8AL6eSl0=
|
||||
github.com/gogf/gf/contrib/drivers/mysql/v2 v2.3.2/go.mod h1:z+/0qiOwMroAnj5ESuobTv0l5P83rf+XR3r6Fj8WJyk=
|
||||
github.com/gogf/gf/contrib/nosql/redis/v2 v2.3.2 h1:AsYganxtge0nz7eYDYdvGH6E2pRe5IuK45/OLHIFrj8=
|
||||
github.com/gogf/gf/contrib/nosql/redis/v2 v2.3.2/go.mod h1:V9o2BF9ovJnaZhHImHAanqUgjX4kI51lgU45u5rPqvw=
|
||||
github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw=
|
||||
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||
github.com/gogf/gf/contrib/drivers/mysql/v2 v2.3.3 h1:McqosVS9Bm7SzmsMTwfVT0YX6i/Is2aRn/XfqW/0iSI=
|
||||
github.com/gogf/gf/contrib/drivers/mysql/v2 v2.3.3/go.mod h1:z+/0qiOwMroAnj5ESuobTv0l5P83rf+XR3r6Fj8WJyk=
|
||||
github.com/gogf/gf/contrib/nosql/redis/v2 v2.3.3 h1:t1DA5NbyOk7FrDtFtJ5nS+RuGkmhJ9dUsQQKh5G3LOE=
|
||||
github.com/gogf/gf/contrib/nosql/redis/v2 v2.3.3/go.mod h1:V9o2BF9ovJnaZhHImHAanqUgjX4kI51lgU45u5rPqvw=
|
||||
github.com/gogf/gf/v2 v2.0.0/go.mod h1:apktt6TleWtCIwpz63vBqUnw8MX8gWKoZyxgDpXFtgM=
|
||||
github.com/gogf/gf/v2 v2.3.2 h1:nlJ0zuDWqFb93/faZmr7V+GADx/lzz5Unz/9x6OJ2u8=
|
||||
github.com/gogf/gf/v2 v2.3.2/go.mod h1:tsbmtwcAl2chcYoq/fP9W2FZf06aw4i89X34nbSHo9Y=
|
||||
github.com/gogf/gf/v2 v2.3.3 h1:3iry6kybjvuryTtjypG9oUuxrQ0URMT7j0DVg7FFnaw=
|
||||
github.com/gogf/gf/v2 v2.3.3/go.mod h1:tsbmtwcAl2chcYoq/fP9W2FZf06aw4i89X34nbSHo9Y=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
|
||||
@ -286,6 +290,10 @@ github.com/kayon/iploc v0.0.0-20200312105652-bda3e968a794/go.mod h1:IwrOeG3O3K9v
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.15.6 h1:6D9PcO8QWu0JyaQ2zUMmu16T1T+zjjEpP91guRsvDfY=
|
||||
github.com/klauspost/compress v1.15.6/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU=
|
||||
github.com/klauspost/cpuid/v2 v2.1.1 h1:t0wUqjowdm8ezddV5k0tLWVklVuvLJpoHeb4WBdydm0=
|
||||
github.com/klauspost/cpuid/v2 v2.1.1/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
|
||||
github.com/klauspost/reedsolomon v1.11.7 h1:9uaHU0slncktTEEg4+7Vl7q7XUNMBUOK4R9gnKhMjAU=
|
||||
github.com/klauspost/reedsolomon v1.11.7/go.mod h1:4bXRN+cVzMdml6ti7qLouuYi32KHJ5MGv0Qd8a47h6A=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
@ -376,8 +384,8 @@ github.com/richardlehane/mscfb v1.0.4/go.mod h1:YzVpcZg9czvAuhk9T+a3avCpcFPMUWm7
|
||||
github.com/richardlehane/msoleps v1.0.1 h1:RfrALnSNXzmXLbGct/P2b4xkFz4e8Gmj/0Vj9M9xC1o=
|
||||
github.com/richardlehane/msoleps v1.0.1/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rivo/uniseg v0.4.3 h1:utMvzDsuh3suAEnhH0RdHmoPbU648o6CvXxTx4SBMOw=
|
||||
github.com/rivo/uniseg v0.4.3/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||
github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
|
||||
github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k=
|
||||
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||
@ -409,7 +417,11 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
||||
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
|
||||
github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161 h1:89CEmDvlq/F7SJEOqkIdNDGJXrQIhuIx9D2DBXjavSU=
|
||||
github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161/go.mod h1:wM7WEvslTq+iOEAMDLSzhVuOt5BRZ05WirO+b09GHQU=
|
||||
github.com/templexxx/xor v0.0.0-20191217153810-f85b25db303b h1:fj5tQ8acgNUr6O8LEplsxDhUIe2573iLkJc+PqnzZTI=
|
||||
github.com/templexxx/xor v0.0.0-20191217153810-f85b25db303b/go.mod h1:5XA7W9S6mni3h5uvOC75dA3m9CCCaS83lltmc0ukdi4=
|
||||
github.com/tidwall/gjson v1.2.1 h1:j0efZLrZUvNerEf6xqoi0NjWMK5YlLrR7Guo/dxY174=
|
||||
github.com/tidwall/gjson v1.2.1/go.mod h1:c/nTNbUr0E0OrXEhq1pwa8iEgc2DOt4ZZqAt1HtCkPA=
|
||||
github.com/tidwall/match v1.0.1 h1:PnKP62LPNxHKTwvHHZZzdOAOCtsJTjo6dZLCwpKm5xc=
|
||||
@ -428,6 +440,10 @@ github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/X
|
||||
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
|
||||
github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g=
|
||||
github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8=
|
||||
github.com/xtaci/kcp-go v5.4.20+incompatible h1:TN1uey3Raw0sTz0Fg8GkfM0uH3YwzhnZWQ1bABv5xAg=
|
||||
github.com/xtaci/kcp-go v5.4.20+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45a+AZwO7eyRCmEIbtvE=
|
||||
github.com/xtaci/lossyconn v0.0.0-20200209145036-adba10fffc37 h1:EWU6Pktpas0n8lLQwDsRyZfmkPeRbdgPtW609es+/9E=
|
||||
github.com/xtaci/lossyconn v0.0.0-20200209145036-adba10fffc37/go.mod h1:HpMP7DB2CyokmAh4lp0EQnnWhmycP/TvwBGzvuie+H0=
|
||||
github.com/xuri/efp v0.0.0-20220407160117-ad0f7a785be8 h1:3X7aE0iLKJ5j+tz58BpvIZkXNV7Yq4jC93Z/rbN2Fxk=
|
||||
github.com/xuri/efp v0.0.0-20220407160117-ad0f7a785be8/go.mod h1:ybY/Jr0T0GTCnYjKqmdwxyxn2BQf2RcQIIvex5QldPI=
|
||||
github.com/xuri/excelize/v2 v2.6.0 h1:m/aXAzSAqxgt74Nfd+sNzpzVKhTGl7+S9nbG4A57mF4=
|
||||
@ -450,16 +466,16 @@ go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opentelemetry.io/otel v1.0.0/go.mod h1:AjRVh9A5/5DE7S+mZtTR6t8vpKKryam+0lREnfmS4cg=
|
||||
go.opentelemetry.io/otel v1.7.0/go.mod h1:5BdUoMIz5WEs0vt0CUEMtSSaTSHBBVwrhnz7+nrD5xk=
|
||||
go.opentelemetry.io/otel v1.13.0 h1:1ZAKnNQKwBBxFtww/GwxNUyTf0AxkZzrukO8MeXqe4Y=
|
||||
go.opentelemetry.io/otel v1.13.0/go.mod h1:FH3RtdZCzRkJYFTCsAKDy9l/XYjMdNv6QrkFFB8DvVg=
|
||||
go.opentelemetry.io/otel v1.14.0 h1:/79Huy8wbf5DnIPhemGB+zEPVwnN6fuQybr/SRXa6hM=
|
||||
go.opentelemetry.io/otel v1.14.0/go.mod h1:o4buv+dJzx8rohcUeRmWUZhqupFvzWis188WlggnNeU=
|
||||
go.opentelemetry.io/otel/sdk v1.0.0/go.mod h1:PCrDHlSy5x1kjezSdL37PhbFUMjrsLRshJ2zCzeXwbM=
|
||||
go.opentelemetry.io/otel/sdk v1.7.0/go.mod h1:uTEOTwaqIVuTGiJN7ii13Ibp75wJmYUDe374q6cZwUU=
|
||||
go.opentelemetry.io/otel/sdk v1.13.0 h1:BHib5g8MvdqS65yo2vV1s6Le42Hm6rrw08qU6yz5JaM=
|
||||
go.opentelemetry.io/otel/sdk v1.13.0/go.mod h1:YLKPx5+6Vx/o1TCUYYs+bpymtkmazOMT6zoRrC7AQ7I=
|
||||
go.opentelemetry.io/otel/sdk v1.14.0 h1:PDCppFRDq8A1jL9v6KMI6dYesaq+DFcDZvjsoGvxGzY=
|
||||
go.opentelemetry.io/otel/sdk v1.14.0/go.mod h1:bwIC5TjrNG6QDCHNWvW4HLHtUQ4I+VQDsnjhvyZCALM=
|
||||
go.opentelemetry.io/otel/trace v1.0.0/go.mod h1:PXTWqayeFUlJV1YDNhsJYB184+IvAH814St6o6ajzIs=
|
||||
go.opentelemetry.io/otel/trace v1.7.0/go.mod h1:fzLSB9nqR2eXzxPXb2JW9IKE+ScyXA48yyE4TNvoHqU=
|
||||
go.opentelemetry.io/otel/trace v1.13.0 h1:CBgRZ6ntv+Amuj1jDsMhZtlAPT6gbyIRdaIzFhfBSdY=
|
||||
go.opentelemetry.io/otel/trace v1.13.0/go.mod h1:muCvmmO9KKpvuXSf3KKAXXB2ygNYHQ+ZfI5X08d3tds=
|
||||
go.opentelemetry.io/otel/trace v1.14.0 h1:wp2Mmvj41tDsyAJXiWDWpfNsOiIyd38fy85pyKcFq/M=
|
||||
go.opentelemetry.io/otel/trace v1.14.0/go.mod h1:8avnQLK+CG77yNLUae4ea2JDQ6iT+gozhnZjy/rw9G8=
|
||||
go.uber.org/atomic v1.5.1/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
|
||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
@ -510,8 +526,8 @@ golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzB
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@ -551,8 +567,8 @@ golang.org/x/net v0.0.0-20211029224645-99673261e6eb/go.mod h1:9nx3DQGgdP8bBQD5qx
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220407224826-aac1ed45d8e3/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
|
||||
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
|
||||
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
@ -625,10 +641,11 @@ golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
@ -639,8 +656,8 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.3.8-0.20211105212822-18b340fc7af2/go.mod h1:EFNZuWvGYxIRUEX+K8UmCFwYmZjqcrnq15ZuVldZkZ0=
|
||||
golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
|
||||
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
@ -690,8 +707,8 @@ golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc
|
||||
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
|
||||
golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
|
@ -13,20 +13,18 @@ gfcli:
|
||||
output: "./temp/hotgo" # 可执行文件生成路径
|
||||
extra: ""
|
||||
|
||||
# gf生成代码,如果你想调整hotgo中代码生成的相关dao、service代码,同样也受用于此配置
|
||||
gen:
|
||||
dao:
|
||||
- link: "mysql:hotgo:hg123456.@tcp(127.0.0.1:3306)/hotgo?loc=Local&parseTime=true"
|
||||
group: "default" # 分组。使用hotgo代码生成功能时必须填
|
||||
# path: "./app"
|
||||
# tables: "" #指定当前数据库中需要执行代码生成的数据表。如果为空,表示数据库的所有表都会生成。
|
||||
tablesEx: "hg_sys_addons_install" #指定当前数据库中需要排除代码生成的数据表。
|
||||
group: "default" # 分组 使用hotgo代码生成功能时必须填
|
||||
# tables: "" # 指定当前数据库中需要执行代码生成的数据表。如果为空,表示数据库的所有表都会生成。
|
||||
tablesEx: "hg_sys_addons_install" # 指定当前数据库中需要排除代码生成的数据表。
|
||||
removePrefix: "hg_"
|
||||
descriptionTag: true
|
||||
noModelComment: true
|
||||
jsonCase: "CamelLower"
|
||||
gJsonSupport: true
|
||||
clear: true
|
||||
clear: false
|
||||
|
||||
# service: # 生成业务配置
|
||||
# srcFolder: "internal/logic"
|
||||
|
33
server/internal/cmd/auth.go
Normal file
33
server/internal/cmd/auth.go
Normal file
@ -0,0 +1,33 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/gogf/gf/v2/os/gcmd"
|
||||
"hotgo/internal/service"
|
||||
"os"
|
||||
)
|
||||
|
||||
var (
|
||||
Auth = &gcmd.Command{
|
||||
Name: "auth",
|
||||
Brief: "系统授权,当为第三方客户开发应用项目不想将源码和可执行文件让其随意使用时,可以通过授权的方式约束使用方。",
|
||||
Description: `目前已实现,一对一、一对多、有效期授权,具体使用可以参考现有逻辑结合实际场景进行改造`,
|
||||
Func: func(ctx context.Context, parser *gcmd.Parser) (err error) {
|
||||
service.TCPAuth().Start(ctx)
|
||||
|
||||
// 退出信号监听
|
||||
signalListen(ctx, func(sig os.Signal) {
|
||||
service.TCPAuth().Stop(ctx)
|
||||
})
|
||||
|
||||
// 信号监听
|
||||
signalListen(ctx, signalHandlerForOverall)
|
||||
select {
|
||||
case <-serverCloseSignal:
|
||||
// ...
|
||||
}
|
||||
|
||||
return
|
||||
},
|
||||
}
|
||||
)
|
@ -80,7 +80,7 @@ var (
|
||||
)
|
||||
|
||||
func init() {
|
||||
if err := Main.AddCommand(Http, Queue, Tools, All, Help); err != nil {
|
||||
if err := Main.AddCommand(Http, Queue, Tools, Auth, All, Help); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
serverCloseSignal = make(chan struct{}, 1)
|
||||
|
@ -9,20 +9,10 @@ package cmd
|
||||
import (
|
||||
"context"
|
||||
"github.com/gogf/gf/v2/os/gproc"
|
||||
"hotgo/internal/crons"
|
||||
"hotgo/internal/websocket"
|
||||
"hotgo/utility/simple"
|
||||
"os"
|
||||
)
|
||||
|
||||
func signalHandlerForCron(sig os.Signal) {
|
||||
crons.StopALL()
|
||||
}
|
||||
|
||||
func signalHandlerForWebSocket(sig os.Signal) {
|
||||
websocket.Stop()
|
||||
}
|
||||
|
||||
func signalHandlerForOverall(sig os.Signal) {
|
||||
serverCloseSignal <- struct{}{}
|
||||
}
|
||||
|
@ -10,10 +10,13 @@ import (
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/net/ghttp"
|
||||
"github.com/gogf/gf/v2/os/gcmd"
|
||||
"hotgo/internal/crons"
|
||||
"hotgo/internal/library/addons"
|
||||
"hotgo/internal/library/casbin"
|
||||
"hotgo/internal/router"
|
||||
"hotgo/internal/service"
|
||||
"hotgo/internal/websocket"
|
||||
"os"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -68,12 +71,20 @@ var (
|
||||
// 启动定时任务
|
||||
service.SysCron().StartCron(ctx)
|
||||
|
||||
// 信号监听
|
||||
signalListen(ctx, signalHandlerForCron, signalHandlerForWebSocket)
|
||||
//// 启动TCP服务
|
||||
//service.TCPServer().Start(ctx)
|
||||
|
||||
// https
|
||||
setSSL(ctx, s)
|
||||
|
||||
// 退出信号监听
|
||||
signalListen(ctx, func(sig os.Signal) {
|
||||
s.Shutdown()
|
||||
crons.StopALL()
|
||||
websocket.Stop()
|
||||
//service.TCPServer().Stop(ctx)
|
||||
})
|
||||
|
||||
// Just run the server.
|
||||
s.Run()
|
||||
|
||||
|
@ -7,5 +7,5 @@ package consts
|
||||
|
||||
// VersionApp HotGo版本
|
||||
const (
|
||||
VersionApp = "2.3.5"
|
||||
VersionApp = "2.4.2"
|
||||
)
|
||||
|
@ -16,6 +16,7 @@ import (
|
||||
"hotgo/internal/consts"
|
||||
"hotgo/internal/dao"
|
||||
"hotgo/internal/model/entity"
|
||||
"hotgo/utility/simple"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
@ -161,7 +162,9 @@ func Stop(sysCron *entity.SysCron) (err error) {
|
||||
func Once(ctx context.Context, sysCron *entity.SysCron) error {
|
||||
for _, v := range cronList {
|
||||
if v.GetName() == sysCron.Name {
|
||||
go v.Execute(ctx)
|
||||
simple.SafeGo(ctx, func(ctx context.Context) {
|
||||
v.Execute(ctx)
|
||||
})
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
109
server/internal/dao/internal/sys_serve_license.go
Normal file
109
server/internal/dao/internal/sys_serve_license.go
Normal file
@ -0,0 +1,109 @@
|
||||
// ==========================================================================
|
||||
// Code generated by GoFrame CLI tool. DO NOT EDIT.
|
||||
// ==========================================================================
|
||||
|
||||
package internal
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
// SysServeLicenseDao is the data access object for table hg_sys_serve_license.
|
||||
type SysServeLicenseDao struct {
|
||||
table string // table is the underlying table name of the DAO.
|
||||
group string // group is the database configuration group name of current DAO.
|
||||
columns SysServeLicenseColumns // columns contains all the column names of Table for convenient usage.
|
||||
}
|
||||
|
||||
// SysServeLicenseColumns defines and stores column names for table hg_sys_serve_license.
|
||||
type SysServeLicenseColumns struct {
|
||||
Id string // 许可ID
|
||||
Group string // 分组
|
||||
Name string // 许可名称
|
||||
Appid string // 应用ID
|
||||
SecretKey string // 应用秘钥
|
||||
Desc string // 授权说明
|
||||
RemoteAddr string // 最后连接地址
|
||||
Online string // 在线数量
|
||||
OnlineLimit string // 在线数量限制,默认1
|
||||
LoginTimes string // 登录次数
|
||||
LastLoginAt string // 最后登录时间
|
||||
LastActiveAt string // 最后活跃时间
|
||||
Routes string // 路由表,空使用默认分组路由
|
||||
AllowedIps string // 白名单,*代表所有,只有允许的IP才能连接到tcp服务
|
||||
EndAt string // 授权结束时间
|
||||
Remark string // 备注
|
||||
Status string // 状态
|
||||
CreatedAt string // 创建时间
|
||||
UpdatedAt string // 修改时间
|
||||
}
|
||||
|
||||
// sysServeLicenseColumns holds the columns for table hg_sys_serve_license.
|
||||
var sysServeLicenseColumns = SysServeLicenseColumns{
|
||||
Id: "id",
|
||||
Group: "group",
|
||||
Name: "name",
|
||||
Appid: "appid",
|
||||
SecretKey: "secret_key",
|
||||
Desc: "desc",
|
||||
RemoteAddr: "remote_addr",
|
||||
Online: "online",
|
||||
OnlineLimit: "online_limit",
|
||||
LoginTimes: "login_times",
|
||||
LastLoginAt: "last_login_at",
|
||||
LastActiveAt: "last_active_at",
|
||||
Routes: "routes",
|
||||
AllowedIps: "allowed_ips",
|
||||
EndAt: "end_at",
|
||||
Remark: "remark",
|
||||
Status: "status",
|
||||
CreatedAt: "created_at",
|
||||
UpdatedAt: "updated_at",
|
||||
}
|
||||
|
||||
// NewSysServeLicenseDao creates and returns a new DAO object for table data access.
|
||||
func NewSysServeLicenseDao() *SysServeLicenseDao {
|
||||
return &SysServeLicenseDao{
|
||||
group: "default",
|
||||
table: "hg_sys_serve_license",
|
||||
columns: sysServeLicenseColumns,
|
||||
}
|
||||
}
|
||||
|
||||
// DB retrieves and returns the underlying raw database management object of current DAO.
|
||||
func (dao *SysServeLicenseDao) DB() gdb.DB {
|
||||
return g.DB(dao.group)
|
||||
}
|
||||
|
||||
// Table returns the table name of current dao.
|
||||
func (dao *SysServeLicenseDao) Table() string {
|
||||
return dao.table
|
||||
}
|
||||
|
||||
// Columns returns all column names of current dao.
|
||||
func (dao *SysServeLicenseDao) Columns() SysServeLicenseColumns {
|
||||
return dao.columns
|
||||
}
|
||||
|
||||
// Group returns the configuration group name of database of current dao.
|
||||
func (dao *SysServeLicenseDao) Group() string {
|
||||
return dao.group
|
||||
}
|
||||
|
||||
// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation.
|
||||
func (dao *SysServeLicenseDao) Ctx(ctx context.Context) *gdb.Model {
|
||||
return dao.DB().Model(dao.table).Safe().Ctx(ctx)
|
||||
}
|
||||
|
||||
// Transaction wraps the transaction logic using function f.
|
||||
// It rollbacks the transaction and returns the error from function f if it returns non-nil error.
|
||||
// It commits the transaction and returns nil if function f returns nil.
|
||||
//
|
||||
// Note that, you should not Commit or Rollback the transaction in function f
|
||||
// as it is automatically handled by this function.
|
||||
func (dao *SysServeLicenseDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) {
|
||||
return dao.Ctx(ctx).Transaction(ctx, f)
|
||||
}
|
27
server/internal/dao/sys_serve_license.go
Normal file
27
server/internal/dao/sys_serve_license.go
Normal file
@ -0,0 +1,27 @@
|
||||
// =================================================================================
|
||||
// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.
|
||||
// =================================================================================
|
||||
|
||||
package dao
|
||||
|
||||
import (
|
||||
"hotgo/internal/dao/internal"
|
||||
)
|
||||
|
||||
// internalSysServeLicenseDao is internal type for wrapping internal DAO implements.
|
||||
type internalSysServeLicenseDao = *internal.SysServeLicenseDao
|
||||
|
||||
// sysServeLicenseDao is the data access object for table hg_sys_serve_license.
|
||||
// You can define custom methods on it to extend its functionality as you wish.
|
||||
type sysServeLicenseDao struct {
|
||||
internalSysServeLicenseDao
|
||||
}
|
||||
|
||||
var (
|
||||
// SysServeLicense is globally public accessible object for table hg_sys_serve_license operations.
|
||||
SysServeLicense = sysServeLicenseDao{
|
||||
internal.NewSysServeLicenseDao(),
|
||||
}
|
||||
)
|
||||
|
||||
// Fill with you ideas below.
|
@ -9,13 +9,13 @@ import (
|
||||
"hotgo/internal/library/hggen/internal/utility/utils"
|
||||
)
|
||||
|
||||
func doClear(ctx context.Context, dirPath string) {
|
||||
func doClear(ctx context.Context, dirPath string, force bool) {
|
||||
files, err := gfile.ScanDirFile(dirPath, "*.go", true)
|
||||
if err != nil {
|
||||
mlog.Fatal(err)
|
||||
}
|
||||
for _, file := range files {
|
||||
if utils.IsFileDoNotEdit(file) {
|
||||
if force || utils.IsFileDoNotEdit(file) {
|
||||
if err = gfile.Remove(file); err != nil {
|
||||
mlog.Print(err)
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ func generateDao(ctx context.Context, in CGenDaoInternalInput) {
|
||||
dirPathDaoInternal = gfile.Join(dirPathDao, "internal")
|
||||
)
|
||||
if in.Clear {
|
||||
doClear(ctx, dirPathDao)
|
||||
doClear(ctx, dirPathDao, true)
|
||||
}
|
||||
for i := 0; i < len(in.TableNames); i++ {
|
||||
generateDaoSingle(ctx, generateDaoSingleInput{
|
||||
|
@ -18,7 +18,7 @@ import (
|
||||
func generateDo(ctx context.Context, in CGenDaoInternalInput) {
|
||||
var dirPathDo = gfile.Join(in.Path, in.DoPath)
|
||||
if in.Clear {
|
||||
doClear(ctx, dirPathDo)
|
||||
doClear(ctx, dirPathDo, false)
|
||||
}
|
||||
in.NoJsonTag = true
|
||||
in.DescriptionTag = false
|
||||
|
@ -16,7 +16,7 @@ import (
|
||||
func generateEntity(ctx context.Context, in CGenDaoInternalInput) {
|
||||
var dirPathEntity = gfile.Join(in.Path, in.EntityPath)
|
||||
if in.Clear {
|
||||
doClear(ctx, dirPathEntity)
|
||||
doClear(ctx, dirPathEntity, false)
|
||||
}
|
||||
// Model content.
|
||||
for i, tableName := range in.TableNames {
|
||||
|
322
server/internal/library/network/tcp/client.go
Normal file
322
server/internal/library/network/tcp/client.go
Normal file
@ -0,0 +1,322 @@
|
||||
package tcp
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/v2/encoding/gjson"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/net/gtcp"
|
||||
"github.com/gogf/gf/v2/os/gctx"
|
||||
"github.com/gogf/gf/v2/os/glog"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
"hotgo/utility/simple"
|
||||
"reflect"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// ClientConfig 客户端配置
|
||||
type ClientConfig struct {
|
||||
Addr string
|
||||
Auth *AuthMeta
|
||||
Timeout time.Duration
|
||||
ConnectInterval time.Duration
|
||||
MaxConnectCount uint
|
||||
ConnectCount uint
|
||||
AutoReconnect bool
|
||||
LoginEvent CallbackEvent
|
||||
CloseEvent CallbackEvent
|
||||
}
|
||||
|
||||
// Client 客户端
|
||||
type Client struct {
|
||||
Ctx context.Context
|
||||
Logger *glog.Logger
|
||||
IsLogin bool // 是否已登录
|
||||
addr string
|
||||
auth *AuthMeta
|
||||
timeout time.Duration
|
||||
connectInterval time.Duration
|
||||
maxConnectCount uint
|
||||
connectCount uint
|
||||
autoReconnect bool
|
||||
loginEvent CallbackEvent
|
||||
closeEvent CallbackEvent
|
||||
sync.Mutex
|
||||
heartbeat int64
|
||||
routers map[string]RouterHandler
|
||||
conn *gtcp.Conn
|
||||
wg sync.WaitGroup
|
||||
closeFlag bool // 关闭标签,关闭以后可以重连
|
||||
stopFlag bool // 停止标签,停止以后不能重连
|
||||
}
|
||||
|
||||
func NewClient(config *ClientConfig) (client *Client, err error) {
|
||||
client = new(Client)
|
||||
|
||||
if config == nil {
|
||||
err = gerror.New("config is nil")
|
||||
return
|
||||
}
|
||||
|
||||
if config.Addr == "" {
|
||||
err = gerror.New("client address is not set")
|
||||
return
|
||||
}
|
||||
|
||||
if config.Auth == nil {
|
||||
err = gerror.New("client auth cannot be empty")
|
||||
return
|
||||
}
|
||||
|
||||
if config.Auth.Group == "" || config.Auth.Name == "" {
|
||||
err = gerror.New("Auth.Group or Auth.Group is nil")
|
||||
return
|
||||
}
|
||||
|
||||
client.Ctx = gctx.New()
|
||||
client.autoReconnect = true
|
||||
client.addr = config.Addr
|
||||
client.auth = config.Auth
|
||||
client.loginEvent = config.LoginEvent
|
||||
client.closeEvent = config.CloseEvent
|
||||
|
||||
logger := glog.New()
|
||||
path := g.Cfg().MustGet(client.Ctx, "logger.path", "logs/logger").String()
|
||||
if err = logger.SetPath(fmt.Sprintf("%s/tcp.client/%s.%s", path, config.Auth.Group, config.Auth.Name)); err != nil {
|
||||
return
|
||||
}
|
||||
client.Logger = logger
|
||||
|
||||
if config.ConnectInterval <= 0 {
|
||||
client.connectInterval = 5 * time.Second
|
||||
client.Logger.Debugf(client.Ctx, "invalid connectInterval, reset to %v", client.connectInterval)
|
||||
} else {
|
||||
client.connectInterval = config.ConnectInterval
|
||||
}
|
||||
|
||||
if config.Timeout <= 0 {
|
||||
client.timeout = 10 * time.Second
|
||||
client.Logger.Debugf(client.Ctx, "invalid timeout, reset to %v", client.timeout)
|
||||
} else {
|
||||
client.timeout = config.Timeout
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Start 启动
|
||||
func (client *Client) Start() (err error) {
|
||||
client.Lock()
|
||||
defer client.Unlock()
|
||||
|
||||
if client.stopFlag {
|
||||
err = gerror.New("client is stop")
|
||||
return
|
||||
}
|
||||
|
||||
if client.conn != nil {
|
||||
return gerror.New("client is running")
|
||||
}
|
||||
|
||||
client.IsLogin = false
|
||||
client.connectCount = 0
|
||||
client.closeFlag = false
|
||||
client.stopFlag = false
|
||||
|
||||
client.wg.Add(1)
|
||||
simple.SafeGo(client.Ctx, func(ctx context.Context) {
|
||||
client.connect()
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// RegisterRouter 注册路由
|
||||
func (client *Client) RegisterRouter(routers map[string]RouterHandler) (err error) {
|
||||
if client.conn != nil {
|
||||
return gerror.New("client is running")
|
||||
}
|
||||
|
||||
client.Lock()
|
||||
defer client.Unlock()
|
||||
|
||||
if client.routers == nil {
|
||||
client.routers = make(map[string]RouterHandler)
|
||||
// 默认路由
|
||||
client.routers = map[string]RouterHandler{
|
||||
"ResponseServerHeartbeat": client.onResponseServerHeartbeat,
|
||||
"ResponseServerLogin": client.onResponseServerLogin,
|
||||
}
|
||||
}
|
||||
|
||||
for i, router := range routers {
|
||||
_, ok := client.routers[i]
|
||||
if ok {
|
||||
return gerror.Newf("client route duplicate registration:%v", i)
|
||||
}
|
||||
client.routers[i] = router
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (client *Client) dial() *gtcp.Conn {
|
||||
for {
|
||||
conn, err := gtcp.NewConn(client.addr, client.timeout)
|
||||
if err == nil || client.closeFlag {
|
||||
return conn
|
||||
}
|
||||
|
||||
if client.maxConnectCount > 0 {
|
||||
if client.connectCount < client.maxConnectCount {
|
||||
client.connectCount += 1
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
client.Logger.Debugf(client.Ctx, "connect to %v error: %v", client.addr, err)
|
||||
time.Sleep(client.connectInterval)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
func (client *Client) connect() {
|
||||
defer client.wg.Done()
|
||||
|
||||
goto reconnect
|
||||
reconnect:
|
||||
conn := client.dial()
|
||||
if conn == nil {
|
||||
client.Logger.Debugf(client.Ctx, "client dial failed")
|
||||
return
|
||||
}
|
||||
|
||||
client.Lock()
|
||||
if client.closeFlag {
|
||||
client.Unlock()
|
||||
conn.Close()
|
||||
client.Logger.Debugf(client.Ctx, "client connect but closeFlag is true")
|
||||
return
|
||||
}
|
||||
|
||||
client.conn = conn
|
||||
client.connectCount = 0
|
||||
client.heartbeat = gtime.Timestamp()
|
||||
|
||||
client.read()
|
||||
client.Unlock()
|
||||
|
||||
client.serverLogin()
|
||||
client.startCron()
|
||||
}
|
||||
|
||||
func (client *Client) read() {
|
||||
simple.SafeGo(client.Ctx, func(ctx context.Context) {
|
||||
defer func() {
|
||||
client.Close()
|
||||
client.Logger.Debugf(client.Ctx, "client are about to be reconnected..")
|
||||
time.Sleep(client.connectInterval)
|
||||
client.Start()
|
||||
}()
|
||||
|
||||
for {
|
||||
if client.conn == nil {
|
||||
client.Logger.Debugf(client.Ctx, "client client.conn is nil, server closed")
|
||||
break
|
||||
}
|
||||
|
||||
msg, err := RecvPkg(client.conn)
|
||||
if err != nil {
|
||||
client.Logger.Debugf(client.Ctx, "client RecvPkg err:%+v, server closed", err)
|
||||
break
|
||||
}
|
||||
|
||||
if client.routers == nil {
|
||||
client.Logger.Debugf(client.Ctx, "client RecvPkg routers is nil")
|
||||
break
|
||||
}
|
||||
|
||||
if msg == nil {
|
||||
client.Logger.Debugf(client.Ctx, "client RecvPkg msg is nil")
|
||||
break
|
||||
}
|
||||
|
||||
f, ok := client.routers[msg.Router]
|
||||
if !ok {
|
||||
client.Logger.Debugf(client.Ctx, "client RecvPkg invalid message: %+v", msg)
|
||||
continue
|
||||
}
|
||||
f(msg.Data, client.conn)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Close 关闭同服务器的链接
|
||||
func (client *Client) Close() {
|
||||
client.Lock()
|
||||
defer client.Unlock()
|
||||
|
||||
client.IsLogin = false
|
||||
client.closeFlag = true
|
||||
if client.conn != nil {
|
||||
client.conn.Close()
|
||||
client.conn = nil
|
||||
}
|
||||
|
||||
if client.closeEvent != nil {
|
||||
client.closeEvent()
|
||||
}
|
||||
client.wg.Wait()
|
||||
}
|
||||
|
||||
// Stop 停止服务
|
||||
func (client *Client) Stop() {
|
||||
if client.stopFlag {
|
||||
return
|
||||
}
|
||||
client.stopFlag = true
|
||||
client.stopCron()
|
||||
client.Close()
|
||||
}
|
||||
|
||||
// Destroy 销毁当前连接
|
||||
func (client *Client) Destroy() {
|
||||
client.stopCron()
|
||||
if client.conn != nil {
|
||||
client.conn.Close()
|
||||
client.conn = nil
|
||||
}
|
||||
}
|
||||
|
||||
// Write
|
||||
func (client *Client) Write(data interface{}) error {
|
||||
client.Lock()
|
||||
defer client.Unlock()
|
||||
|
||||
if client.conn == nil {
|
||||
return gerror.New("client conn is nil")
|
||||
}
|
||||
|
||||
if client.closeFlag {
|
||||
return gerror.New("client conn is closed")
|
||||
}
|
||||
|
||||
if data == nil {
|
||||
return gerror.New("client Write message is nil")
|
||||
}
|
||||
|
||||
// 签名
|
||||
SetSign(data, gctx.CtxId(client.Ctx), client.auth.AppId, client.auth.SecretKey)
|
||||
|
||||
msgType := reflect.TypeOf(data)
|
||||
if msgType == nil || msgType.Kind() != reflect.Ptr {
|
||||
return gerror.Newf("client json message pointer required: %+v", data)
|
||||
}
|
||||
msg := &Message{Router: msgType.Elem().Name(), Data: data}
|
||||
|
||||
client.Logger.Debugf(client.Ctx, "client Write Router:%v, data:%+v", msg.Router, gjson.New(data).String())
|
||||
|
||||
return SendPkg(client.conn, msg)
|
||||
}
|
37
server/internal/library/network/tcp/client_cron.go
Normal file
37
server/internal/library/network/tcp/client_cron.go
Normal file
@ -0,0 +1,37 @@
|
||||
package tcp
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/v2/os/gcron"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
)
|
||||
|
||||
func (client *Client) getCronKey(s string) string {
|
||||
return fmt.Sprintf("tcp.client_%s_%s:%s", s, client.auth.Group, client.auth.Name)
|
||||
}
|
||||
|
||||
func (client *Client) stopCron() {
|
||||
for _, v := range gcron.Entries() {
|
||||
gcron.Remove(v.Name)
|
||||
}
|
||||
}
|
||||
|
||||
func (client *Client) startCron() {
|
||||
// 心跳超时检查
|
||||
if gcron.Search(client.getCronKey(cronHeartbeatVerify)) == nil {
|
||||
gcron.AddSingleton(client.Ctx, "@every 600s", func(ctx context.Context) {
|
||||
if client.heartbeat < gtime.Timestamp()-600 {
|
||||
client.Logger.Debugf(client.Ctx, "client heartbeat timeout, about to reconnect..")
|
||||
client.Destroy()
|
||||
}
|
||||
}, client.getCronKey(cronHeartbeatVerify))
|
||||
}
|
||||
|
||||
// 心跳
|
||||
if gcron.Search(client.getCronKey(cronHeartbeat)) == nil {
|
||||
gcron.AddSingleton(client.Ctx, "@every 120s", func(ctx context.Context) {
|
||||
client.serverHeartbeat()
|
||||
}, client.getCronKey(cronHeartbeat))
|
||||
}
|
||||
}
|
61
server/internal/library/network/tcp/client_handle.go
Normal file
61
server/internal/library/network/tcp/client_handle.go
Normal file
@ -0,0 +1,61 @@
|
||||
package tcp
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/errors/gcode"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"hotgo/internal/model/input/msgin"
|
||||
)
|
||||
|
||||
// serverLogin 心跳
|
||||
func (client *Client) serverHeartbeat() {
|
||||
if err := client.Write(&msgin.ServerHeartbeat{}); err != nil {
|
||||
client.Logger.Debugf(client.Ctx, "client WriteMsg ServerHeartbeat err:%+v", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// serverLogin 服务登陆
|
||||
func (client *Client) serverLogin() {
|
||||
data := &msgin.ServerLogin{
|
||||
Group: client.auth.Group,
|
||||
Name: client.auth.Name,
|
||||
}
|
||||
|
||||
if err := client.Write(data); err != nil {
|
||||
client.Logger.Debugf(client.Ctx, "client WriteMsg ServerLogin err:%+v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if client.loginEvent != nil {
|
||||
client.loginEvent()
|
||||
}
|
||||
}
|
||||
|
||||
func (client *Client) onResponseServerLogin(args ...interface{}) {
|
||||
var in *msgin.ResponseServerLogin
|
||||
if err := gconv.Scan(args[0], &in); err != nil {
|
||||
client.Logger.Infof(client.Ctx, "onResponseServerLogin message Scan failed:%+v, args:%+v", err, args[0])
|
||||
return
|
||||
}
|
||||
client.Logger.Infof(client.Ctx, "onResponseServerLogin in:%+v", *in)
|
||||
|
||||
if in.Code != gcode.CodeOK.Code() {
|
||||
client.IsLogin = false
|
||||
client.Logger.Warningf(client.Ctx, "onResponseServerLogin quit err:%v", in.Message)
|
||||
client.Destroy()
|
||||
return
|
||||
}
|
||||
client.IsLogin = true
|
||||
}
|
||||
|
||||
func (client *Client) onResponseServerHeartbeat(args ...interface{}) {
|
||||
var in *msgin.ResponseServerHeartbeat
|
||||
if err := gconv.Scan(args[0], &in); err != nil {
|
||||
client.Logger.Infof(client.Ctx, "onResponseServerHeartbeat message Scan failed:%+v, args:%+v", err, args)
|
||||
return
|
||||
}
|
||||
|
||||
client.heartbeat = gtime.Timestamp()
|
||||
client.Logger.Infof(client.Ctx, "onResponseServerHeartbeat in:%+v", *in)
|
||||
}
|
25
server/internal/library/network/tcp/model.go
Normal file
25
server/internal/library/network/tcp/model.go
Normal file
@ -0,0 +1,25 @@
|
||||
package tcp
|
||||
|
||||
// 定时任务
|
||||
const (
|
||||
cronHeartbeatVerify = "tcpHeartbeatVerify"
|
||||
cronHeartbeat = "tcpHeartbeat"
|
||||
)
|
||||
|
||||
// 认证分组
|
||||
const (
|
||||
ClientGroupCron = "cron" // 定时任务
|
||||
ClientGroupQueue = "queue" // 消息队列
|
||||
ClientGroupAuth = "auth" // 服务授权
|
||||
)
|
||||
|
||||
// AuthMeta 认证元数据
|
||||
type AuthMeta struct {
|
||||
Group string `json:"group"`
|
||||
Name string `json:"name"`
|
||||
AppId string `json:"appId"`
|
||||
SecretKey string `json:"secretKey"`
|
||||
}
|
||||
|
||||
// CallbackEvent 回调事件
|
||||
type CallbackEvent func()
|
39
server/internal/library/network/tcp/router.go
Normal file
39
server/internal/library/network/tcp/router.go
Normal file
@ -0,0 +1,39 @@
|
||||
package tcp
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/net/gtcp"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
)
|
||||
|
||||
type RouterHandler func(args ...interface{})
|
||||
|
||||
// Message 路由消息
|
||||
type Message struct {
|
||||
Router string `json:"router"`
|
||||
Data interface{} `json:"data"`
|
||||
}
|
||||
|
||||
func SendPkg(conn *gtcp.Conn, message *Message) error {
|
||||
b, err := json.Marshal(message)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return conn.SendPkg(b)
|
||||
}
|
||||
|
||||
func RecvPkg(conn *gtcp.Conn) (*Message, error) {
|
||||
if data, err := conn.RecvPkg(); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
var msg = new(Message)
|
||||
if err = gconv.Scan(data, &msg); err != nil {
|
||||
return nil, gerror.Newf("invalid package structure: %s", err.Error())
|
||||
}
|
||||
if msg.Router == "" {
|
||||
return nil, gerror.Newf("message is not routed: %+v", msg)
|
||||
}
|
||||
return msg, err
|
||||
}
|
||||
}
|
278
server/internal/library/network/tcp/server.go
Normal file
278
server/internal/library/network/tcp/server.go
Normal file
@ -0,0 +1,278 @@
|
||||
package tcp
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/v2/encoding/gjson"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/net/gtcp"
|
||||
"github.com/gogf/gf/v2/os/gctx"
|
||||
"github.com/gogf/gf/v2/os/glog"
|
||||
"reflect"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type ClientConn struct {
|
||||
Conn *gtcp.Conn
|
||||
Auth *AuthMeta
|
||||
heartbeat int64
|
||||
mutex sync.Mutex
|
||||
}
|
||||
|
||||
type ServerConfig struct {
|
||||
Name string // 服务名称
|
||||
Addr string // 监听地址
|
||||
}
|
||||
|
||||
type Server struct {
|
||||
Ctx context.Context
|
||||
Logger *glog.Logger
|
||||
addr string
|
||||
name string
|
||||
ln *gtcp.Server
|
||||
wgLn sync.WaitGroup
|
||||
mutex sync.Mutex
|
||||
closeFlag bool
|
||||
clients map[string]*ClientConn // 已登录的认证客户端
|
||||
mutexConns sync.Mutex
|
||||
wgConns sync.WaitGroup
|
||||
cronRouters map[string]RouterHandler // 路由
|
||||
queueRouters map[string]RouterHandler
|
||||
authRouters map[string]RouterHandler
|
||||
}
|
||||
|
||||
func NewServer(config *ServerConfig) (server *Server, err error) {
|
||||
if config == nil {
|
||||
err = gerror.New("config is nil")
|
||||
return
|
||||
}
|
||||
|
||||
if config.Addr == "" {
|
||||
err = gerror.New("server address is not set")
|
||||
return
|
||||
}
|
||||
|
||||
if config.Name == "" {
|
||||
config.Name = "hotgo"
|
||||
}
|
||||
|
||||
server = new(Server)
|
||||
server.Ctx = gctx.New()
|
||||
server.addr = config.Addr
|
||||
server.name = config.Name
|
||||
server.ln = gtcp.NewServer(server.addr, server.accept, config.Name)
|
||||
server.clients = make(map[string]*ClientConn)
|
||||
server.closeFlag = false
|
||||
|
||||
logger := glog.New()
|
||||
path := g.Cfg().MustGet(server.Ctx, "logger.path", "logs/logger").String()
|
||||
if err = logger.SetPath(fmt.Sprintf("%s/tcp.server/%s", path, config.Name)); err != nil {
|
||||
return
|
||||
}
|
||||
server.Logger = logger
|
||||
|
||||
server.startCron()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (server *Server) accept(conn *gtcp.Conn) {
|
||||
defer func() {
|
||||
server.mutexConns.Lock()
|
||||
conn.Close()
|
||||
// 从登录列表中移除
|
||||
if _, ok := server.clients[conn.RemoteAddr().String()]; ok {
|
||||
delete(server.clients, conn.RemoteAddr().String())
|
||||
}
|
||||
server.mutexConns.Unlock()
|
||||
}()
|
||||
|
||||
for {
|
||||
msg, err := RecvPkg(conn)
|
||||
if err != nil {
|
||||
server.Logger.Debugf(server.Ctx, "RecvPkg err:%+v, client closed.", err)
|
||||
break
|
||||
}
|
||||
|
||||
client := server.getLoginConn(conn)
|
||||
|
||||
switch msg.Router {
|
||||
case "ServerLogin": // 服务登录
|
||||
server.onServerLogin(msg.Data, conn)
|
||||
case "ServerHeartbeat": // 心跳
|
||||
if client == nil {
|
||||
server.Logger.Infof(server.Ctx, "conn not connected, ignore the heartbeat, msg:%+v", msg)
|
||||
continue
|
||||
}
|
||||
server.onServerHeartbeat(msg, client)
|
||||
default: // 通用路由消息处理
|
||||
if client == nil {
|
||||
server.Logger.Warningf(server.Ctx, "conn is not logged in but sends a routing message. actively conn disconnect, msg:%+v", msg)
|
||||
time.Sleep(time.Second)
|
||||
conn.Close()
|
||||
return
|
||||
}
|
||||
server.handleRouterMsg(msg, client)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// handleRouterMsg 处理路由消息
|
||||
func (server *Server) handleRouterMsg(msg *Message, client *ClientConn) {
|
||||
|
||||
// 验证签名
|
||||
err := VerifySign(msg.Data, client.Auth.AppId, client.Auth.SecretKey)
|
||||
if err != nil {
|
||||
server.Logger.Warningf(server.Ctx, "handleRouterMsg VerifySign err:%+v message: %+v", err, msg)
|
||||
return
|
||||
}
|
||||
|
||||
handle := func(routers map[string]RouterHandler, group string) {
|
||||
if routers == nil {
|
||||
server.Logger.Debugf(server.Ctx, "handleRouterMsg route is not initialized %v message: %+v", group, msg)
|
||||
return
|
||||
}
|
||||
f, ok := routers[msg.Router]
|
||||
if !ok {
|
||||
server.Logger.Debugf(server.Ctx, "handleRouterMsg invalid %v message: %+v", group, msg)
|
||||
return
|
||||
}
|
||||
f(msg.Data, client)
|
||||
}
|
||||
|
||||
switch client.Auth.Group {
|
||||
case ClientGroupCron:
|
||||
handle(server.cronRouters, client.Auth.Group)
|
||||
case ClientGroupQueue:
|
||||
handle(server.queueRouters, client.Auth.Group)
|
||||
case ClientGroupAuth:
|
||||
handle(server.authRouters, client.Auth.Group)
|
||||
default:
|
||||
server.Logger.Warningf(server.Ctx, "group is not registered: %+v", client.Auth.Group)
|
||||
}
|
||||
}
|
||||
|
||||
// getLoginConn 获取指定已登录的连接
|
||||
func (server *Server) getLoginConn(conn *gtcp.Conn) *ClientConn {
|
||||
client, ok := server.clients[conn.RemoteAddr().String()]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return client
|
||||
}
|
||||
|
||||
// getLoginConn 获取指定appid的所有连接
|
||||
func (server *Server) getAppIdClients(appid string) (list []*ClientConn) {
|
||||
for _, v := range server.clients {
|
||||
if v.Auth.AppId == appid {
|
||||
list = append(list, v)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// RegisterAuthRouter 注册授权路由
|
||||
func (server *Server) RegisterAuthRouter(routers map[string]RouterHandler) {
|
||||
server.mutex.Lock()
|
||||
defer server.mutex.Unlock()
|
||||
|
||||
if server.authRouters == nil {
|
||||
server.authRouters = make(map[string]RouterHandler)
|
||||
}
|
||||
|
||||
for i, router := range routers {
|
||||
_, ok := server.authRouters[i]
|
||||
if ok {
|
||||
server.Logger.Debugf(server.Ctx, "server authRouters duplicate registration:%v", i)
|
||||
continue
|
||||
}
|
||||
server.authRouters[i] = router
|
||||
}
|
||||
}
|
||||
|
||||
// RegisterCronRouter 注册任务路由
|
||||
func (server *Server) RegisterCronRouter(routers map[string]RouterHandler) {
|
||||
server.mutex.Lock()
|
||||
defer server.mutex.Unlock()
|
||||
|
||||
if server.cronRouters == nil {
|
||||
server.cronRouters = make(map[string]RouterHandler)
|
||||
}
|
||||
|
||||
for i, router := range routers {
|
||||
_, ok := server.cronRouters[i]
|
||||
if ok {
|
||||
server.Logger.Debugf(server.Ctx, "server cronRouters duplicate registration:%v", i)
|
||||
continue
|
||||
}
|
||||
server.cronRouters[i] = router
|
||||
}
|
||||
}
|
||||
|
||||
// RegisterQueueRouter 注册队列路由
|
||||
func (server *Server) RegisterQueueRouter(routers map[string]RouterHandler) {
|
||||
server.mutex.Lock()
|
||||
defer server.mutex.Unlock()
|
||||
|
||||
if server.queueRouters == nil {
|
||||
server.queueRouters = make(map[string]RouterHandler)
|
||||
}
|
||||
|
||||
for i, router := range routers {
|
||||
_, ok := server.queueRouters[i]
|
||||
if ok {
|
||||
server.Logger.Debugf(server.Ctx, "server queueRouters duplicate registration:%v", i)
|
||||
continue
|
||||
}
|
||||
server.queueRouters[i] = router
|
||||
}
|
||||
}
|
||||
|
||||
func (server *Server) Listen() (err error) {
|
||||
server.wgLn.Add(1)
|
||||
defer server.wgLn.Done()
|
||||
return server.ln.Run()
|
||||
}
|
||||
|
||||
// Close 关闭服务
|
||||
func (server *Server) Close() {
|
||||
if server.closeFlag {
|
||||
return
|
||||
}
|
||||
server.closeFlag = true
|
||||
|
||||
server.stopCron()
|
||||
|
||||
server.mutexConns.Lock()
|
||||
for _, client := range server.clients {
|
||||
client.Conn.Close()
|
||||
}
|
||||
server.clients = nil
|
||||
server.mutexConns.Unlock()
|
||||
server.wgConns.Wait()
|
||||
|
||||
if server.ln != nil {
|
||||
server.ln.Close()
|
||||
}
|
||||
server.wgLn.Wait()
|
||||
}
|
||||
|
||||
// Write 向指定客户端发送消息
|
||||
func (server *Server) Write(conn *gtcp.Conn, data interface{}) (err error) {
|
||||
if server.closeFlag {
|
||||
return gerror.New("service is down")
|
||||
}
|
||||
|
||||
msgType := reflect.TypeOf(data)
|
||||
if msgType == nil || msgType.Kind() != reflect.Ptr {
|
||||
return gerror.Newf("json message pointer required: %+v", data)
|
||||
}
|
||||
|
||||
msg := &Message{Router: msgType.Elem().Name(), Data: data}
|
||||
|
||||
server.Logger.Debugf(server.Ctx, "server Write Router:%v, data:%+v", msg.Router, gjson.New(data).String())
|
||||
|
||||
return SendPkg(conn, msg)
|
||||
}
|
35
server/internal/library/network/tcp/server_cron.go
Normal file
35
server/internal/library/network/tcp/server_cron.go
Normal file
@ -0,0 +1,35 @@
|
||||
package tcp
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/v2/os/gcron"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
)
|
||||
|
||||
func (server *Server) getCronKey(s string) string {
|
||||
return fmt.Sprintf("tcp.server_%s_%s", s, server.name)
|
||||
}
|
||||
|
||||
func (server *Server) stopCron() {
|
||||
for _, v := range gcron.Entries() {
|
||||
gcron.Remove(v.Name)
|
||||
}
|
||||
}
|
||||
|
||||
func (server *Server) startCron() {
|
||||
// 心跳超时检查
|
||||
if gcron.Search(server.getCronKey(cronHeartbeatVerify)) == nil {
|
||||
gcron.AddSingleton(server.Ctx, "@every 300s", func(ctx context.Context) {
|
||||
if server.clients == nil {
|
||||
return
|
||||
}
|
||||
for _, client := range server.clients {
|
||||
if client.heartbeat < gtime.Timestamp()-300 {
|
||||
client.Conn.Close()
|
||||
server.Logger.Debugf(server.Ctx, "client heartbeat timeout, about to reconnect.. auth:%+v", client.Auth)
|
||||
}
|
||||
}
|
||||
}, server.getCronKey(cronHeartbeatVerify))
|
||||
}
|
||||
}
|
150
server/internal/library/network/tcp/server_handle.go
Normal file
150
server/internal/library/network/tcp/server_handle.go
Normal file
@ -0,0 +1,150 @@
|
||||
package tcp
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/net/gtcp"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"hotgo/internal/consts"
|
||||
"hotgo/internal/model/entity"
|
||||
"hotgo/internal/model/input/msgin"
|
||||
"hotgo/utility/convert"
|
||||
)
|
||||
|
||||
func (server *Server) onServerLogin(args ...interface{}) {
|
||||
var (
|
||||
in = new(msgin.ServerLogin)
|
||||
conn = args[1].(*gtcp.Conn)
|
||||
res = new(msgin.ResponseServerLogin)
|
||||
models *entity.SysServeLicense
|
||||
)
|
||||
|
||||
if err := gconv.Scan(args[0], &in); err != nil {
|
||||
server.Logger.Infof(server.Ctx, "onServerLogin message Scan failed:%+v, args:%+v", err, args)
|
||||
return
|
||||
}
|
||||
server.Logger.Infof(server.Ctx, "onServerLogin in:%+v", *in)
|
||||
|
||||
err := g.Model("sys_serve_license").
|
||||
Ctx(server.Ctx).
|
||||
Where("appid = ?", in.AppId).
|
||||
Scan(&models)
|
||||
|
||||
if err != nil {
|
||||
res.Code = 1
|
||||
res.Message = err.Error()
|
||||
server.Write(conn, res)
|
||||
return
|
||||
}
|
||||
|
||||
if models == nil {
|
||||
res.Code = 2
|
||||
res.Message = "授权信息不存在"
|
||||
server.Write(conn, res)
|
||||
return
|
||||
}
|
||||
|
||||
// 验证签名
|
||||
if err = VerifySign(in, models.Appid, models.SecretKey); err != nil {
|
||||
res.Code = 3
|
||||
res.Message = "签名错误,请联系管理员"
|
||||
server.Write(conn, res)
|
||||
return
|
||||
}
|
||||
|
||||
if models.Status != consts.StatusEnabled {
|
||||
res.Code = 4
|
||||
res.Message = "授权已禁用,请联系管理员"
|
||||
server.Write(conn, res)
|
||||
return
|
||||
}
|
||||
|
||||
if models.Group != in.Group {
|
||||
res.Code = 5
|
||||
res.Message = "你登录的授权分组未得到授权,请联系管理员"
|
||||
server.Write(conn, res)
|
||||
return
|
||||
}
|
||||
|
||||
if models.EndAt.Before(gtime.Now()) {
|
||||
res.Code = 6
|
||||
res.Message = "授权已过期,请联系管理员"
|
||||
server.Write(conn, res)
|
||||
return
|
||||
}
|
||||
|
||||
allowedIps := convert.IpFilterStrategy(models.AllowedIps)
|
||||
if _, ok := allowedIps["*"]; !ok {
|
||||
ip := gstr.StrTillEx(conn.RemoteAddr().String(), ":")
|
||||
if _, ok2 := allowedIps[ip]; !ok2 {
|
||||
res.Code = 7
|
||||
res.Message = "IP(" + ip + ")未授权,请联系管理员"
|
||||
server.Write(conn, res)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 检查是否存在多地登录,如果连接超出上限,直接将所有已连接断开,然后在吧新的连接加入进来
|
||||
clients := server.getAppIdClients(models.Appid)
|
||||
online := len(clients) + 1
|
||||
if online > models.OnlineLimit {
|
||||
online = 1
|
||||
res2 := new(msgin.ResponseServerLogin)
|
||||
res2.Code = 8
|
||||
res2.Message = "授权登录端超出上限,请联系管理员"
|
||||
for _, client := range clients {
|
||||
server.Write(client.Conn, res2)
|
||||
client.Conn.Close()
|
||||
}
|
||||
}
|
||||
|
||||
server.mutexConns.Lock()
|
||||
server.clients[conn.RemoteAddr().String()] = &ClientConn{
|
||||
Conn: conn,
|
||||
Auth: &AuthMeta{
|
||||
Group: in.Group,
|
||||
Name: in.Name,
|
||||
AppId: in.AppId,
|
||||
SecretKey: models.SecretKey,
|
||||
},
|
||||
heartbeat: gtime.Timestamp(),
|
||||
}
|
||||
server.mutexConns.Unlock()
|
||||
|
||||
server.Write(conn, res)
|
||||
|
||||
_, err = g.Model("sys_serve_license").
|
||||
Ctx(server.Ctx).
|
||||
Where("id = ?", models.Id).Data(g.Map{
|
||||
"online": online,
|
||||
"login_times": models.LoginTimes + 1,
|
||||
"last_login_at": gtime.Now(),
|
||||
"last_active_at": gtime.Now(),
|
||||
"remote_addr": conn.RemoteAddr().String(),
|
||||
}).Update()
|
||||
if err != nil {
|
||||
server.Logger.Warningf(server.Ctx, "onServerLogin Update err:%+v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (server *Server) onServerHeartbeat(args ...interface{}) {
|
||||
var in *msgin.ServerHeartbeat
|
||||
if err := gconv.Scan(args, &in); err != nil {
|
||||
server.Logger.Infof(server.Ctx, "onServerHeartbeat message Scan failed:%+v, args:%+v", err, args)
|
||||
return
|
||||
}
|
||||
client := args[1].(*ClientConn)
|
||||
client.heartbeat = gtime.Timestamp()
|
||||
|
||||
server.Write(client.Conn, &msgin.ResponseServerHeartbeat{})
|
||||
|
||||
_, err := g.Model("sys_serve_license").
|
||||
Ctx(server.Ctx).
|
||||
Where("appid = ?", client.Auth.AppId).Data(g.Map{
|
||||
"last_active_at": gtime.Now(),
|
||||
}).Update()
|
||||
if err != nil {
|
||||
server.Logger.Warningf(server.Ctx, "onServerHeartbeat Update err:%+v", err)
|
||||
}
|
||||
}
|
41
server/internal/library/network/tcp/sign.go
Normal file
41
server/internal/library/network/tcp/sign.go
Normal file
@ -0,0 +1,41 @@
|
||||
package tcp
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"hotgo/internal/model/input/msgin"
|
||||
)
|
||||
|
||||
type Sign interface {
|
||||
SetSign(traceID, appId, secretKey string)
|
||||
}
|
||||
|
||||
// SetSign 设置签名
|
||||
func SetSign(data interface{}, traceID, appId, secretKey string) {
|
||||
if c, ok := data.(Sign); ok {
|
||||
c.SetSign(traceID, appId, secretKey)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// VerifySign 验证签名
|
||||
func VerifySign(data interface{}, appId, secretKey string) (err error) {
|
||||
// 无密钥,无需签名
|
||||
if secretKey == "" {
|
||||
return
|
||||
}
|
||||
|
||||
var in *msgin.Request
|
||||
if err = gconv.Scan(data, &in); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if appId != in.AppId {
|
||||
return gerror.New("appId invalid")
|
||||
}
|
||||
|
||||
if in.Sign != in.GetSign(secretKey) {
|
||||
return gerror.New("sign invalid")
|
||||
}
|
||||
return
|
||||
}
|
@ -10,5 +10,7 @@ import (
|
||||
_ "hotgo/internal/logic/hook"
|
||||
_ "hotgo/internal/logic/middleware"
|
||||
_ "hotgo/internal/logic/sys"
|
||||
_ "hotgo/internal/logic/tcpclient"
|
||||
_ "hotgo/internal/logic/tcpserver"
|
||||
_ "hotgo/internal/logic/view"
|
||||
)
|
||||
|
@ -3,7 +3,6 @@
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
package sys
|
||||
|
||||
import (
|
||||
@ -11,13 +10,12 @@ import (
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"hotgo/internal/consts"
|
||||
"hotgo/internal/dao"
|
||||
"hotgo/internal/global"
|
||||
"hotgo/internal/model/input/sysin"
|
||||
"hotgo/internal/service"
|
||||
"hotgo/utility/convert"
|
||||
"hotgo/utility/validate"
|
||||
)
|
||||
|
||||
@ -176,91 +174,12 @@ func (s *sSysBlacklist) Load(ctx context.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
matchStrategy := func(originIp string) {
|
||||
// 多个IP
|
||||
if gstr.Contains(originIp, ",") {
|
||||
ips := gstr.Explode(",", originIp)
|
||||
if len(ips) > 0 {
|
||||
for _, ip := range ips {
|
||||
if !validate.IsIp(ip) {
|
||||
continue
|
||||
}
|
||||
global.Blacklists[ip] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// IP段
|
||||
if gstr.Contains(originIp, "/24") {
|
||||
segment := gstr.Replace(originIp, "/24", "")
|
||||
if !validate.IsIp(segment) {
|
||||
return
|
||||
}
|
||||
|
||||
var (
|
||||
start = gstr.Explode(".", segment)
|
||||
prefix = gstr.Implode(".", start[:len(start)-1]) + "."
|
||||
index = gconv.Int(start[len(start)-1])
|
||||
)
|
||||
|
||||
if index < 1 {
|
||||
index = 1
|
||||
}
|
||||
|
||||
for i := index; i <= 254; i++ {
|
||||
global.Blacklists[prefix+gconv.String(i)] = struct{}{}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// IP范围
|
||||
if gstr.Contains(originIp, "-") {
|
||||
originIps := gstr.Explode("-", originIp)
|
||||
if len(originIps) != 2 {
|
||||
return
|
||||
}
|
||||
|
||||
if !validate.IsIp(originIps[0]) || !validate.IsIp(originIps[1]) {
|
||||
return
|
||||
}
|
||||
|
||||
var (
|
||||
start = gstr.Explode(".", originIps[0])
|
||||
prefix = gstr.Implode(".", start[:len(start)-1]) + "."
|
||||
startIndex = gconv.Int(gstr.SubStrFromREx(originIps[0], "."))
|
||||
endIndex = gconv.Int(gstr.SubStrFromREx(originIps[1], "."))
|
||||
)
|
||||
|
||||
if startIndex >= endIndex {
|
||||
global.Blacklists[originIps[0]] = struct{}{}
|
||||
return
|
||||
}
|
||||
|
||||
if startIndex < 1 {
|
||||
startIndex = 1
|
||||
}
|
||||
|
||||
if endIndex > 254 {
|
||||
endIndex = 254
|
||||
}
|
||||
|
||||
for i := startIndex; i <= endIndex; i++ {
|
||||
global.Blacklists[prefix+gconv.String(i)] = struct{}{}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 指定IP
|
||||
if validate.IsIp(originIp) {
|
||||
global.Blacklists[originIp] = struct{}{}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
for _, v := range array {
|
||||
matchStrategy(v.String())
|
||||
list := convert.IpFilterStrategy(v.String())
|
||||
if len(list) > 0 {
|
||||
for k, _ := range list {
|
||||
global.Blacklists[k] = struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
110
server/internal/logic/tcpclient/auth.go
Normal file
110
server/internal/logic/tcpclient/auth.go
Normal file
@ -0,0 +1,110 @@
|
||||
package tcpclient
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/gogf/gf/v2/errors/gcode"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gcron"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"hotgo/internal/library/network/tcp"
|
||||
"hotgo/internal/model/input/msgin"
|
||||
"hotgo/internal/service"
|
||||
"hotgo/utility/simple"
|
||||
)
|
||||
|
||||
// tcp授权
|
||||
type sTCPAuth struct {
|
||||
client *tcp.Client
|
||||
}
|
||||
|
||||
func init() {
|
||||
service.RegisterTCPAuth(newTCPAuth())
|
||||
}
|
||||
|
||||
func newTCPAuth() *sTCPAuth {
|
||||
return &sTCPAuth{}
|
||||
}
|
||||
|
||||
// Start 启动服务
|
||||
func (s *sTCPAuth) Start(ctx context.Context) {
|
||||
g.Log().Debug(ctx, "TCPAuth start..")
|
||||
simple.SafeGo(ctx, func(ctx context.Context) {
|
||||
client, err := tcp.NewClient(&tcp.ClientConfig{
|
||||
Addr: "127.0.0.1:8099",
|
||||
Auth: &tcp.AuthMeta{
|
||||
Group: "auth",
|
||||
Name: "auth1",
|
||||
AppId: "mengshuai",
|
||||
SecretKey: "123456",
|
||||
},
|
||||
LoginEvent: s.loginEvent,
|
||||
CloseEvent: s.closeEvent,
|
||||
})
|
||||
if err != nil {
|
||||
g.Log().Infof(ctx, "TCPAuth NewClient fail:%+v", err)
|
||||
return
|
||||
}
|
||||
|
||||
s.client = client
|
||||
|
||||
err = s.client.RegisterRouter(map[string]tcp.RouterHandler{
|
||||
"ResponseAuthSummary": s.onResponseAuthSummary, // 获取授权信息
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
g.Log().Infof(ctx, "TCPAuth RegisterRouter fail:%+v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if err = s.client.Start(); err != nil {
|
||||
g.Log().Infof(ctx, "TCPAuth Start fail:%+v", err)
|
||||
return
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Stop 关闭服务
|
||||
func (s *sTCPAuth) Stop(ctx context.Context) {
|
||||
if s.client != nil {
|
||||
s.client.Stop()
|
||||
g.Log().Debug(ctx, "TCPAuth stop..")
|
||||
}
|
||||
}
|
||||
|
||||
func (s *sTCPAuth) loginEvent() {
|
||||
// 登录成功后立即请求一次授权信息
|
||||
s.client.Write(&msgin.AuthSummary{})
|
||||
|
||||
// 定时检查授权
|
||||
gcron.Add(s.client.Ctx, "@every 1200s", func(ctx context.Context) {
|
||||
if !s.client.IsLogin {
|
||||
g.Log().Infof(ctx, "TCPAuthVerify client is not logged in, skipped")
|
||||
return
|
||||
}
|
||||
s.client.Write(&msgin.AuthSummary{})
|
||||
}, "TCPAuthVerify")
|
||||
}
|
||||
|
||||
func (s *sTCPAuth) closeEvent() {
|
||||
// 关闭连接后,删除定时检查授权
|
||||
gcron.Remove("TCPAuthVerify")
|
||||
}
|
||||
|
||||
func (s *sTCPAuth) onResponseAuthSummary(args ...interface{}) {
|
||||
var in *msgin.ResponseAuthSummary
|
||||
if err := gconv.Scan(args[0], &in); err != nil {
|
||||
s.client.Logger.Infof(s.client.Ctx, "ResponseAuthSummary message Scan failed:%+v, args:%+v", err, args[0])
|
||||
return
|
||||
}
|
||||
s.client.Logger.Infof(s.client.Ctx, "onResponseAuthSummary in:%+v", *in)
|
||||
|
||||
// 授权异常
|
||||
if in.Code != gcode.CodeOK.Code() {
|
||||
s.client.Logger.Infof(s.client.Ctx, "onResponseAuthSummary authorization verification failed:%+v", in.Message)
|
||||
s.client.Destroy()
|
||||
return
|
||||
}
|
||||
|
||||
// 授权通过
|
||||
// 后续可以做一些操作...
|
||||
}
|
73
server/internal/logic/tcpserver/auth_handle.go
Normal file
73
server/internal/logic/tcpserver/auth_handle.go
Normal file
@ -0,0 +1,73 @@
|
||||
package tcpserver
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"hotgo/internal/consts"
|
||||
"hotgo/internal/dao"
|
||||
"hotgo/internal/library/network/tcp"
|
||||
"hotgo/internal/model/entity"
|
||||
"hotgo/internal/model/input/msgin"
|
||||
)
|
||||
|
||||
// onAuthSummary 获取授权信息
|
||||
func (s *sTCPServer) onAuthSummary(args ...interface{}) {
|
||||
var (
|
||||
in *msgin.AuthSummary
|
||||
client = args[1].(*tcp.ClientConn)
|
||||
res = new(msgin.ResponseAuthSummary)
|
||||
models *entity.SysServeLicense
|
||||
)
|
||||
|
||||
if err := gconv.Scan(args, &in); err != nil {
|
||||
s.serv.Logger.Infof(s.serv.Ctx, "onAuthSummary message Scan failed:%+v, args:%+v", err, args)
|
||||
return
|
||||
}
|
||||
|
||||
if client.Auth == nil {
|
||||
res.Code = 1
|
||||
res.Message = "登录信息获取失败,请重新登录"
|
||||
s.serv.Write(client.Conn, res)
|
||||
return
|
||||
}
|
||||
|
||||
if err := dao.SysServeLicense.Ctx(s.serv.Ctx).Where("appid = ?", client.Auth.AppId).Scan(&models); err != nil {
|
||||
res.Code = 2
|
||||
res.Message = err.Error()
|
||||
s.serv.Write(client.Conn, res)
|
||||
return
|
||||
}
|
||||
|
||||
if models == nil {
|
||||
res.Code = 3
|
||||
res.Message = "授权信息不存在"
|
||||
s.serv.Write(client.Conn, res)
|
||||
return
|
||||
}
|
||||
|
||||
if models.Status != consts.StatusEnabled {
|
||||
res.Code = 4
|
||||
res.Message = "授权已禁用,请联系管理员"
|
||||
s.serv.Write(client.Conn, res)
|
||||
return
|
||||
}
|
||||
|
||||
if models.Group != client.Auth.Group {
|
||||
res.Code = 5
|
||||
res.Message = "你登录的授权分组未得到授权,请联系管理员"
|
||||
s.serv.Write(client.Conn, res)
|
||||
return
|
||||
}
|
||||
|
||||
if models.EndAt.Before(gtime.Now()) {
|
||||
res.Code = 6
|
||||
res.Message = "授权已过期,请联系管理员"
|
||||
s.serv.Write(client.Conn, res)
|
||||
return
|
||||
}
|
||||
|
||||
res.Data = new(msgin.AuthSummaryData)
|
||||
res.Data.EndAt = models.EndAt
|
||||
res.Data.Online = models.Online
|
||||
s.serv.Write(client.Conn, res)
|
||||
}
|
68
server/internal/logic/tcpserver/init.go
Normal file
68
server/internal/logic/tcpserver/init.go
Normal file
@ -0,0 +1,68 @@
|
||||
package tcpserver
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"hotgo/internal/library/network/tcp"
|
||||
"hotgo/internal/service"
|
||||
"hotgo/utility/simple"
|
||||
)
|
||||
|
||||
type sTCPServer struct {
|
||||
serv *tcp.Server
|
||||
}
|
||||
|
||||
func init() {
|
||||
service.RegisterTCPServer(newTCPServer())
|
||||
}
|
||||
|
||||
func newTCPServer() *sTCPServer {
|
||||
return &sTCPServer{}
|
||||
}
|
||||
|
||||
// Start 启动服务
|
||||
func (s *sTCPServer) Start(ctx context.Context) {
|
||||
simple.SafeGo(ctx, func(ctx context.Context) {
|
||||
g.Log().Debug(ctx, "TCPServer start..")
|
||||
|
||||
server, err := tcp.NewServer(&tcp.ServerConfig{
|
||||
Name: "hotgo",
|
||||
Addr: g.Cfg().MustGet(ctx, "tcpServe.address").String(),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
g.Log().Warningf(ctx, "TCPServer start fail:%+v", err)
|
||||
return
|
||||
}
|
||||
|
||||
s.serv = server
|
||||
|
||||
// 消息队列路由
|
||||
s.serv.RegisterQueueRouter(map[string]tcp.RouterHandler{
|
||||
// ...
|
||||
})
|
||||
|
||||
// 定时任务路由
|
||||
s.serv.RegisterCronRouter(map[string]tcp.RouterHandler{
|
||||
// ...
|
||||
})
|
||||
|
||||
// 授权服务路由
|
||||
s.serv.RegisterAuthRouter(map[string]tcp.RouterHandler{
|
||||
"AuthSummary": s.onAuthSummary, // 获取授权信息
|
||||
})
|
||||
|
||||
// 服务监听
|
||||
if err := s.serv.Listen(); err != nil {
|
||||
g.Log().Warningf(ctx, "TCPServer Listen err:%v", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Stop 关闭服务
|
||||
func (s *sTCPServer) Stop(ctx context.Context) {
|
||||
if s.serv != nil {
|
||||
s.serv.Close()
|
||||
g.Log().Debug(ctx, "TCPServer stop..")
|
||||
}
|
||||
}
|
35
server/internal/model/do/sys_serve_license.go
Normal file
35
server/internal/model/do/sys_serve_license.go
Normal file
@ -0,0 +1,35 @@
|
||||
// =================================================================================
|
||||
// Code generated by GoFrame CLI tool. DO NOT EDIT.
|
||||
// =================================================================================
|
||||
|
||||
package do
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/encoding/gjson"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
)
|
||||
|
||||
// SysServeLicense is the golang structure of table hg_sys_serve_license for DAO operations like Where/Data.
|
||||
type SysServeLicense struct {
|
||||
g.Meta `orm:"table:hg_sys_serve_license, do:true"`
|
||||
Id interface{} // 许可ID
|
||||
Group interface{} // 分组
|
||||
Name interface{} // 许可名称
|
||||
Appid interface{} // 应用ID
|
||||
SecretKey interface{} // 应用秘钥
|
||||
Desc interface{} // 授权说明
|
||||
RemoteAddr interface{} // 最后连接地址
|
||||
Online interface{} // 在线数量
|
||||
OnlineLimit interface{} // 在线数量限制,默认1
|
||||
LoginTimes interface{} // 登录次数
|
||||
LastLoginAt *gtime.Time // 最后登录时间
|
||||
LastActiveAt *gtime.Time // 最后活跃时间
|
||||
Routes *gjson.Json // 路由表,空使用默认分组路由
|
||||
AllowedIps interface{} // 白名单,*代表所有,只有允许的IP才能连接到tcp服务
|
||||
EndAt *gtime.Time // 授权结束时间
|
||||
Remark interface{} // 备注
|
||||
Status interface{} // 状态
|
||||
CreatedAt *gtime.Time // 创建时间
|
||||
UpdatedAt *gtime.Time // 修改时间
|
||||
}
|
33
server/internal/model/entity/sys_serve_license.go
Normal file
33
server/internal/model/entity/sys_serve_license.go
Normal file
@ -0,0 +1,33 @@
|
||||
// =================================================================================
|
||||
// Code generated by GoFrame CLI tool. DO NOT EDIT.
|
||||
// =================================================================================
|
||||
|
||||
package entity
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/encoding/gjson"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
)
|
||||
|
||||
// SysServeLicense is the golang structure for table sys_serve_license.
|
||||
type SysServeLicense struct {
|
||||
Id int64 `json:"id" description:"许可ID"`
|
||||
Group string `json:"group" description:"分组"`
|
||||
Name string `json:"name" description:"许可名称"`
|
||||
Appid string `json:"appid" description:"应用ID"`
|
||||
SecretKey string `json:"secretKey" description:"应用秘钥"`
|
||||
Desc string `json:"desc" description:"授权说明"`
|
||||
RemoteAddr string `json:"remoteAddr" description:"最后连接地址"`
|
||||
Online int `json:"online" description:"在线数量"`
|
||||
OnlineLimit int `json:"onlineLimit" description:"在线数量限制,默认1"`
|
||||
LoginTimes int64 `json:"loginTimes" description:"登录次数"`
|
||||
LastLoginAt *gtime.Time `json:"lastLoginAt" description:"最后登录时间"`
|
||||
LastActiveAt *gtime.Time `json:"lastActiveAt" description:"最后活跃时间"`
|
||||
Routes *gjson.Json `json:"routes" description:"路由表,空使用默认分组路由"`
|
||||
AllowedIps string `json:"allowedIps" description:"白名单,*代表所有,只有允许的IP才能连接到tcp服务"`
|
||||
EndAt *gtime.Time `json:"endAt" description:"授权结束时间"`
|
||||
Remark string `json:"remark" description:"备注"`
|
||||
Status int `json:"status" description:"状态"`
|
||||
CreatedAt *gtime.Time `json:"createdAt" description:"创建时间"`
|
||||
UpdatedAt *gtime.Time `json:"updatedAt" description:"修改时间"`
|
||||
}
|
19
server/internal/model/input/msgin/auth.go
Normal file
19
server/internal/model/input/msgin/auth.go
Normal file
@ -0,0 +1,19 @@
|
||||
package msgin
|
||||
|
||||
import "github.com/gogf/gf/v2/os/gtime"
|
||||
|
||||
// AuthSummary 授权摘要
|
||||
type AuthSummary struct {
|
||||
Request
|
||||
}
|
||||
|
||||
// ResponseAuthSummary 响应授权摘要
|
||||
type ResponseAuthSummary struct {
|
||||
Response
|
||||
Data *AuthSummaryData `json:"data,omitempty" description:"数据集"`
|
||||
}
|
||||
|
||||
type AuthSummaryData struct {
|
||||
EndAt *gtime.Time `json:"end_at" description:"授权过期时间"`
|
||||
Online int `json:"online" description:"在线人数"`
|
||||
}
|
61
server/internal/model/input/msgin/common.go
Normal file
61
server/internal/model/input/msgin/common.go
Normal file
@ -0,0 +1,61 @@
|
||||
package msgin
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
"hotgo/utility/encrypt"
|
||||
)
|
||||
|
||||
type Request struct {
|
||||
AppId string `json:"appID" v:"0" example:"d0bb93048bc5c9164cdee845dcb7f820" description:"应用ID"`
|
||||
TraceID string `json:"traceID" v:"0" example:"d0bb93048bc5c9164cdee845dcb7f820" description:"链路ID"`
|
||||
Timestamp int64 `json:"timestamp" example:"1640966400" description:"服务器时间戳"`
|
||||
Sign string `json:"sign" example:"d0bb93048bc5c9164cdee845dcb7f820" description:"签名"`
|
||||
}
|
||||
|
||||
func (i *Request) SetSign(traceID, appId, secretKey string) {
|
||||
i.AppId = appId
|
||||
i.TraceID = traceID
|
||||
i.Timestamp = gtime.Timestamp()
|
||||
i.Sign = i.GetSign(secretKey)
|
||||
}
|
||||
|
||||
func (i *Request) GetSign(secretKey string) string {
|
||||
return encrypt.Md5ToString(fmt.Sprintf("%s%s%s%s", i.AppId, i.TraceID, i.Timestamp, secretKey))
|
||||
}
|
||||
|
||||
type Response struct {
|
||||
Code int `json:"code" example:"0" description:"状态码"`
|
||||
Message string `json:"message,omitempty" example:"操作成功" description:"提示消息"`
|
||||
//Data interface{} `json:"data,omitempty" description:"数据集"`
|
||||
}
|
||||
|
||||
// ServerHeartbeat 心跳
|
||||
type ServerHeartbeat struct {
|
||||
}
|
||||
|
||||
// ResponseServerHeartbeat 响应心跳
|
||||
type ResponseServerHeartbeat struct {
|
||||
Response
|
||||
}
|
||||
|
||||
// ServerLogin 服务登录
|
||||
type ServerLogin struct {
|
||||
Request
|
||||
Group string
|
||||
Name string
|
||||
}
|
||||
|
||||
// ResponseServerLogin 响应服务登录
|
||||
type ResponseServerLogin struct {
|
||||
Response
|
||||
}
|
||||
|
||||
// ServerOffline 服务离线
|
||||
type ServerOffline struct {
|
||||
}
|
||||
|
||||
// ResponseServerOffline 响应服务离线
|
||||
type ResponseServerOffline struct {
|
||||
Response
|
||||
}
|
@ -114,7 +114,6 @@ type (
|
||||
)
|
||||
|
||||
var (
|
||||
localAdminPost IAdminPost
|
||||
localAdminRole IAdminRole
|
||||
localAdminDept IAdminDept
|
||||
localAdminMember IAdminMember
|
||||
@ -122,41 +121,9 @@ var (
|
||||
localAdminMenu IAdminMenu
|
||||
localAdminMonitor IAdminMonitor
|
||||
localAdminNotice IAdminNotice
|
||||
localAdminPost IAdminPost
|
||||
)
|
||||
|
||||
func AdminDept() IAdminDept {
|
||||
if localAdminDept == nil {
|
||||
panic("implement not found for interface IAdminDept, forgot register?")
|
||||
}
|
||||
return localAdminDept
|
||||
}
|
||||
|
||||
func RegisterAdminDept(i IAdminDept) {
|
||||
localAdminDept = i
|
||||
}
|
||||
|
||||
func AdminMember() IAdminMember {
|
||||
if localAdminMember == nil {
|
||||
panic("implement not found for interface IAdminMember, forgot register?")
|
||||
}
|
||||
return localAdminMember
|
||||
}
|
||||
|
||||
func RegisterAdminMember(i IAdminMember) {
|
||||
localAdminMember = i
|
||||
}
|
||||
|
||||
func AdminMemberPost() IAdminMemberPost {
|
||||
if localAdminMemberPost == nil {
|
||||
panic("implement not found for interface IAdminMemberPost, forgot register?")
|
||||
}
|
||||
return localAdminMemberPost
|
||||
}
|
||||
|
||||
func RegisterAdminMemberPost(i IAdminMemberPost) {
|
||||
localAdminMemberPost = i
|
||||
}
|
||||
|
||||
func AdminMenu() IAdminMenu {
|
||||
if localAdminMenu == nil {
|
||||
panic("implement not found for interface IAdminMenu, forgot register?")
|
||||
@ -211,3 +178,36 @@ func AdminRole() IAdminRole {
|
||||
func RegisterAdminRole(i IAdminRole) {
|
||||
localAdminRole = i
|
||||
}
|
||||
|
||||
func AdminDept() IAdminDept {
|
||||
if localAdminDept == nil {
|
||||
panic("implement not found for interface IAdminDept, forgot register?")
|
||||
}
|
||||
return localAdminDept
|
||||
}
|
||||
|
||||
func RegisterAdminDept(i IAdminDept) {
|
||||
localAdminDept = i
|
||||
}
|
||||
|
||||
func AdminMember() IAdminMember {
|
||||
if localAdminMember == nil {
|
||||
panic("implement not found for interface IAdminMember, forgot register?")
|
||||
}
|
||||
return localAdminMember
|
||||
}
|
||||
|
||||
func RegisterAdminMember(i IAdminMember) {
|
||||
localAdminMember = i
|
||||
}
|
||||
|
||||
func AdminMemberPost() IAdminMemberPost {
|
||||
if localAdminMemberPost == nil {
|
||||
panic("implement not found for interface IAdminMemberPost, forgot register?")
|
||||
}
|
||||
return localAdminMemberPost
|
||||
}
|
||||
|
||||
func RegisterAdminMemberPost(i IAdminMemberPost) {
|
||||
localAdminMemberPost = i
|
||||
}
|
||||
|
@ -17,148 +17,6 @@ import (
|
||||
)
|
||||
|
||||
type (
|
||||
ISysAddonsConfig interface {
|
||||
GetConfigByGroup(ctx context.Context, in sysin.GetAddonsConfigInp) (res *sysin.GetAddonsConfigModel, err error)
|
||||
ConversionType(ctx context.Context, models *entity.SysAddonsConfig) (value interface{}, err error)
|
||||
UpdateConfigByGroup(ctx context.Context, in sysin.UpdateAddonsConfigInp) error
|
||||
}
|
||||
ISysAttachment interface {
|
||||
Delete(ctx context.Context, in sysin.AttachmentDeleteInp) error
|
||||
Edit(ctx context.Context, in sysin.AttachmentEditInp) (err error)
|
||||
Status(ctx context.Context, in sysin.AttachmentStatusInp) (err error)
|
||||
MaxSort(ctx context.Context, in sysin.AttachmentMaxSortInp) (*sysin.AttachmentMaxSortModel, error)
|
||||
View(ctx context.Context, in sysin.AttachmentViewInp) (res *sysin.AttachmentViewModel, err error)
|
||||
List(ctx context.Context, in sysin.AttachmentListInp) (list []*sysin.AttachmentListModel, totalCount int, err error)
|
||||
Add(ctx context.Context, meta *sysin.UploadFileMeta, fullPath, drive string) (data *entity.SysAttachment, err error)
|
||||
}
|
||||
ISysBlacklist interface {
|
||||
Delete(ctx context.Context, in sysin.BlacklistDeleteInp) (err error)
|
||||
Edit(ctx context.Context, in sysin.BlacklistEditInp) (err error)
|
||||
Status(ctx context.Context, in sysin.BlacklistStatusInp) (err error)
|
||||
MaxSort(ctx context.Context, in sysin.BlacklistMaxSortInp) (*sysin.BlacklistMaxSortModel, error)
|
||||
View(ctx context.Context, in sysin.BlacklistViewInp) (res *sysin.BlacklistViewModel, err error)
|
||||
List(ctx context.Context, in sysin.BlacklistListInp) (list []*sysin.BlacklistListModel, totalCount int, err error)
|
||||
VariableLoad(ctx context.Context, err error)
|
||||
Load(ctx context.Context)
|
||||
}
|
||||
ISysEmsLog interface {
|
||||
Delete(ctx context.Context, in sysin.EmsLogDeleteInp) error
|
||||
Edit(ctx context.Context, in sysin.EmsLogEditInp) (err error)
|
||||
Status(ctx context.Context, in sysin.EmsLogStatusInp) (err error)
|
||||
View(ctx context.Context, in sysin.EmsLogViewInp) (res *sysin.EmsLogViewModel, err error)
|
||||
List(ctx context.Context, in sysin.EmsLogListInp) (list []*sysin.EmsLogListModel, totalCount int, err error)
|
||||
Send(ctx context.Context, in sysin.SendEmsInp) (err error)
|
||||
GetTemplate(ctx context.Context, template string, config *model.EmailConfig) (val string, err error)
|
||||
AllowSend(ctx context.Context, models *entity.SysEmsLog, config *model.EmailConfig) (err error)
|
||||
VerifyCode(ctx context.Context, in sysin.VerifyEmsCodeInp) (err error)
|
||||
}
|
||||
ISysGenCodes interface {
|
||||
Delete(ctx context.Context, in sysin.GenCodesDeleteInp) error
|
||||
Edit(ctx context.Context, in sysin.GenCodesEditInp) (res *sysin.GenCodesEditModel, err error)
|
||||
Status(ctx context.Context, in sysin.GenCodesStatusInp) (err error)
|
||||
MaxSort(ctx context.Context, in sysin.GenCodesMaxSortInp) (*sysin.GenCodesMaxSortModel, error)
|
||||
View(ctx context.Context, in sysin.GenCodesViewInp) (res *sysin.GenCodesViewModel, err error)
|
||||
List(ctx context.Context, in sysin.GenCodesListInp) (list []*sysin.GenCodesListModel, totalCount int, err error)
|
||||
Selects(ctx context.Context, in sysin.GenCodesSelectsInp) (res *sysin.GenCodesSelectsModel, err error)
|
||||
TableSelect(ctx context.Context, in sysin.GenCodesTableSelectInp) (res []*sysin.GenCodesTableSelectModel, err error)
|
||||
ColumnSelect(ctx context.Context, in sysin.GenCodesColumnSelectInp) (res []*sysin.GenCodesColumnSelectModel, err error)
|
||||
ColumnList(ctx context.Context, in sysin.GenCodesColumnListInp) (res []*sysin.GenCodesColumnListModel, err error)
|
||||
Preview(ctx context.Context, in sysin.GenCodesPreviewInp) (res *sysin.GenCodesPreviewModel, err error)
|
||||
Build(ctx context.Context, in sysin.GenCodesBuildInp) (err error)
|
||||
}
|
||||
ISysServeLog interface {
|
||||
Model(ctx context.Context) *gdb.Model
|
||||
List(ctx context.Context, in sysin.ServeLogListInp) (list []*sysin.ServeLogListModel, totalCount int, err error)
|
||||
Export(ctx context.Context, in sysin.ServeLogListInp) (err error)
|
||||
Delete(ctx context.Context, in sysin.ServeLogDeleteInp) (err error)
|
||||
View(ctx context.Context, in sysin.ServeLogViewInp) (res *sysin.ServeLogViewModel, err error)
|
||||
RealWrite(ctx context.Context, models entity.SysServeLog) (err error)
|
||||
}
|
||||
ISysSmsLog interface {
|
||||
Delete(ctx context.Context, in sysin.SmsLogDeleteInp) error
|
||||
Edit(ctx context.Context, in sysin.SmsLogEditInp) (err error)
|
||||
Status(ctx context.Context, in sysin.SmsLogStatusInp) (err error)
|
||||
MaxSort(ctx context.Context, in sysin.SmsLogMaxSortInp) (*sysin.SmsLogMaxSortModel, error)
|
||||
View(ctx context.Context, in sysin.SmsLogViewInp) (res *sysin.SmsLogViewModel, err error)
|
||||
List(ctx context.Context, in sysin.SmsLogListInp) (list []*sysin.SmsLogListModel, totalCount int, err error)
|
||||
SendCode(ctx context.Context, in sysin.SendCodeInp) (err error)
|
||||
GetTemplate(ctx context.Context, template string, config *model.SmsConfig) (val string, err error)
|
||||
AllowSend(ctx context.Context, models *entity.SysSmsLog, config *model.SmsConfig) (err error)
|
||||
VerifyCode(ctx context.Context, in sysin.VerifyCodeInp) (err error)
|
||||
}
|
||||
ISysAddons interface {
|
||||
List(ctx context.Context, in sysin.AddonsListInp) (list []*sysin.AddonsListModel, totalCount int, err error)
|
||||
Selects(ctx context.Context, in sysin.AddonsSelectsInp) (res *sysin.AddonsSelectsModel, err error)
|
||||
Build(ctx context.Context, in sysin.AddonsBuildInp) (err error)
|
||||
Install(ctx context.Context, in sysin.AddonsInstallInp) (err error)
|
||||
Upgrade(ctx context.Context, in sysin.AddonsUpgradeInp) (err error)
|
||||
UnInstall(ctx context.Context, in sysin.AddonsUnInstallInp) (err error)
|
||||
}
|
||||
ISysConfig interface {
|
||||
GetLoadCache(ctx context.Context) (conf *model.CacheConfig, err error)
|
||||
GetLoadGenerate(ctx context.Context) (conf *model.GenerateConfig, err error)
|
||||
GetSms(ctx context.Context) (conf *model.SmsConfig, err error)
|
||||
GetGeo(ctx context.Context) (conf *model.GeoConfig, err error)
|
||||
GetUpload(ctx context.Context) (conf *model.UploadConfig, err error)
|
||||
GetSmtp(ctx context.Context) (conf *model.EmailConfig, err error)
|
||||
GetBasic(ctx context.Context) (conf *model.BasicConfig, err error)
|
||||
GetLoadSSL(ctx context.Context) (conf *model.SSLConfig, err error)
|
||||
GetLoadLog(ctx context.Context) (conf *model.LogConfig, err error)
|
||||
GetLoadServeLog(ctx context.Context) (conf *model.ServeLogConfig, err error)
|
||||
GetConfigByGroup(ctx context.Context, in sysin.GetConfigInp) (*sysin.GetConfigModel, error)
|
||||
ConversionType(ctx context.Context, models *entity.SysConfig) (value interface{}, err error)
|
||||
UpdateConfigByGroup(ctx context.Context, in sysin.UpdateConfigInp) error
|
||||
}
|
||||
ISysLog interface {
|
||||
Export(ctx context.Context, in sysin.LogListInp) (err error)
|
||||
RealWrite(ctx context.Context, commonLog entity.SysLog) (err error)
|
||||
AutoLog(ctx context.Context) error
|
||||
AnalysisLog(ctx context.Context) entity.SysLog
|
||||
View(ctx context.Context, in sysin.LogViewInp) (res *sysin.LogViewModel, err error)
|
||||
Delete(ctx context.Context, in sysin.LogDeleteInp) (err error)
|
||||
List(ctx context.Context, in sysin.LogListInp) (list []*sysin.LogListModel, totalCount int, err error)
|
||||
}
|
||||
ISysLoginLog interface {
|
||||
Model(ctx context.Context) *gdb.Model
|
||||
List(ctx context.Context, in sysin.LoginLogListInp) (list []*sysin.LoginLogListModel, totalCount int, err error)
|
||||
Export(ctx context.Context, in sysin.LoginLogListInp) (err error)
|
||||
Delete(ctx context.Context, in sysin.LoginLogDeleteInp) (err error)
|
||||
View(ctx context.Context, in sysin.LoginLogViewInp) (res *sysin.LoginLogViewModel, err error)
|
||||
Push(ctx context.Context, in sysin.LoginLogPushInp)
|
||||
RealWrite(ctx context.Context, models entity.SysLoginLog) (err error)
|
||||
}
|
||||
ISysCronGroup interface {
|
||||
Delete(ctx context.Context, in sysin.CronGroupDeleteInp) error
|
||||
Edit(ctx context.Context, in sysin.CronGroupEditInp) (err error)
|
||||
Status(ctx context.Context, in sysin.CronGroupStatusInp) (err error)
|
||||
MaxSort(ctx context.Context, in sysin.CronGroupMaxSortInp) (*sysin.CronGroupMaxSortModel, error)
|
||||
View(ctx context.Context, in sysin.CronGroupViewInp) (res *sysin.CronGroupViewModel, err error)
|
||||
List(ctx context.Context, in sysin.CronGroupListInp) (list []*sysin.CronGroupListModel, totalCount int, err error)
|
||||
Select(ctx context.Context, in sysin.CronGroupSelectInp) (res *sysin.CronGroupSelectModel, err error)
|
||||
}
|
||||
ISysCurdDemo interface {
|
||||
Model(ctx context.Context, option ...*handler.Option) *gdb.Model
|
||||
List(ctx context.Context, in sysin.CurdDemoListInp) (list []*sysin.CurdDemoListModel, totalCount int, err error)
|
||||
Export(ctx context.Context, in sysin.CurdDemoListInp) (err error)
|
||||
Edit(ctx context.Context, in sysin.CurdDemoEditInp) (err error)
|
||||
Delete(ctx context.Context, in sysin.CurdDemoDeleteInp) (err error)
|
||||
MaxSort(ctx context.Context, in sysin.CurdDemoMaxSortInp) (res *sysin.CurdDemoMaxSortModel, err error)
|
||||
View(ctx context.Context, in sysin.CurdDemoViewInp) (res *sysin.CurdDemoViewModel, err error)
|
||||
Status(ctx context.Context, in sysin.CurdDemoStatusInp) (err error)
|
||||
Switch(ctx context.Context, in sysin.CurdDemoSwitchInp) (err error)
|
||||
}
|
||||
ISysDictData interface {
|
||||
Delete(ctx context.Context, in sysin.DictDataDeleteInp) error
|
||||
Edit(ctx context.Context, in sysin.DictDataEditInp) (err error)
|
||||
List(ctx context.Context, in sysin.DictDataListInp) (list []*sysin.DictDataListModel, totalCount int, err error)
|
||||
Select(ctx context.Context, in sysin.DataSelectInp) (list sysin.DataSelectModel, err error)
|
||||
}
|
||||
ISysDictType interface {
|
||||
Tree(ctx context.Context) (list []*sysin.DictTypeTree, err error)
|
||||
Delete(ctx context.Context, in sysin.DictTypeDeleteInp) error
|
||||
Edit(ctx context.Context, in sysin.DictTypeEditInp) (err error)
|
||||
TreeSelect(ctx context.Context, in sysin.DictTreeSelectInp) (list []*sysin.DictTypeTree, err error)
|
||||
}
|
||||
ISysProvinces interface {
|
||||
Tree(ctx context.Context) (list []g.Map, err error)
|
||||
Delete(ctx context.Context, in sysin.ProvincesDeleteInp) error
|
||||
@ -181,28 +39,302 @@ type (
|
||||
List(ctx context.Context, in sysin.CronListInp) (list []*sysin.CronListModel, totalCount int, err error)
|
||||
OnlineExec(ctx context.Context, in sysin.OnlineExecInp) (err error)
|
||||
}
|
||||
ISysCronGroup interface {
|
||||
Delete(ctx context.Context, in sysin.CronGroupDeleteInp) error
|
||||
Edit(ctx context.Context, in sysin.CronGroupEditInp) (err error)
|
||||
Status(ctx context.Context, in sysin.CronGroupStatusInp) (err error)
|
||||
MaxSort(ctx context.Context, in sysin.CronGroupMaxSortInp) (*sysin.CronGroupMaxSortModel, error)
|
||||
View(ctx context.Context, in sysin.CronGroupViewInp) (res *sysin.CronGroupViewModel, err error)
|
||||
List(ctx context.Context, in sysin.CronGroupListInp) (list []*sysin.CronGroupListModel, totalCount int, err error)
|
||||
Select(ctx context.Context, in sysin.CronGroupSelectInp) (res *sysin.CronGroupSelectModel, err error)
|
||||
}
|
||||
ISysEmsLog interface {
|
||||
Delete(ctx context.Context, in sysin.EmsLogDeleteInp) error
|
||||
Edit(ctx context.Context, in sysin.EmsLogEditInp) (err error)
|
||||
Status(ctx context.Context, in sysin.EmsLogStatusInp) (err error)
|
||||
View(ctx context.Context, in sysin.EmsLogViewInp) (res *sysin.EmsLogViewModel, err error)
|
||||
List(ctx context.Context, in sysin.EmsLogListInp) (list []*sysin.EmsLogListModel, totalCount int, err error)
|
||||
Send(ctx context.Context, in sysin.SendEmsInp) (err error)
|
||||
GetTemplate(ctx context.Context, template string, config *model.EmailConfig) (val string, err error)
|
||||
AllowSend(ctx context.Context, models *entity.SysEmsLog, config *model.EmailConfig) (err error)
|
||||
VerifyCode(ctx context.Context, in sysin.VerifyEmsCodeInp) (err error)
|
||||
}
|
||||
ISysLoginLog interface {
|
||||
Model(ctx context.Context) *gdb.Model
|
||||
List(ctx context.Context, in sysin.LoginLogListInp) (list []*sysin.LoginLogListModel, totalCount int, err error)
|
||||
Export(ctx context.Context, in sysin.LoginLogListInp) (err error)
|
||||
Delete(ctx context.Context, in sysin.LoginLogDeleteInp) (err error)
|
||||
View(ctx context.Context, in sysin.LoginLogViewInp) (res *sysin.LoginLogViewModel, err error)
|
||||
Push(ctx context.Context, in sysin.LoginLogPushInp)
|
||||
RealWrite(ctx context.Context, models entity.SysLoginLog) (err error)
|
||||
}
|
||||
ISysAddons interface {
|
||||
List(ctx context.Context, in sysin.AddonsListInp) (list []*sysin.AddonsListModel, totalCount int, err error)
|
||||
Selects(ctx context.Context, in sysin.AddonsSelectsInp) (res *sysin.AddonsSelectsModel, err error)
|
||||
Build(ctx context.Context, in sysin.AddonsBuildInp) (err error)
|
||||
Install(ctx context.Context, in sysin.AddonsInstallInp) (err error)
|
||||
Upgrade(ctx context.Context, in sysin.AddonsUpgradeInp) (err error)
|
||||
UnInstall(ctx context.Context, in sysin.AddonsUnInstallInp) (err error)
|
||||
}
|
||||
ISysGenCodes interface {
|
||||
Delete(ctx context.Context, in sysin.GenCodesDeleteInp) error
|
||||
Edit(ctx context.Context, in sysin.GenCodesEditInp) (res *sysin.GenCodesEditModel, err error)
|
||||
Status(ctx context.Context, in sysin.GenCodesStatusInp) (err error)
|
||||
MaxSort(ctx context.Context, in sysin.GenCodesMaxSortInp) (*sysin.GenCodesMaxSortModel, error)
|
||||
View(ctx context.Context, in sysin.GenCodesViewInp) (res *sysin.GenCodesViewModel, err error)
|
||||
List(ctx context.Context, in sysin.GenCodesListInp) (list []*sysin.GenCodesListModel, totalCount int, err error)
|
||||
Selects(ctx context.Context, in sysin.GenCodesSelectsInp) (res *sysin.GenCodesSelectsModel, err error)
|
||||
TableSelect(ctx context.Context, in sysin.GenCodesTableSelectInp) (res []*sysin.GenCodesTableSelectModel, err error)
|
||||
ColumnSelect(ctx context.Context, in sysin.GenCodesColumnSelectInp) (res []*sysin.GenCodesColumnSelectModel, err error)
|
||||
ColumnList(ctx context.Context, in sysin.GenCodesColumnListInp) (res []*sysin.GenCodesColumnListModel, err error)
|
||||
Preview(ctx context.Context, in sysin.GenCodesPreviewInp) (res *sysin.GenCodesPreviewModel, err error)
|
||||
Build(ctx context.Context, in sysin.GenCodesBuildInp) (err error)
|
||||
}
|
||||
ISysAddonsConfig interface {
|
||||
GetConfigByGroup(ctx context.Context, in sysin.GetAddonsConfigInp) (res *sysin.GetAddonsConfigModel, err error)
|
||||
ConversionType(ctx context.Context, models *entity.SysAddonsConfig) (value interface{}, err error)
|
||||
UpdateConfigByGroup(ctx context.Context, in sysin.UpdateAddonsConfigInp) error
|
||||
}
|
||||
ISysAttachment interface {
|
||||
Delete(ctx context.Context, in sysin.AttachmentDeleteInp) error
|
||||
Edit(ctx context.Context, in sysin.AttachmentEditInp) (err error)
|
||||
Status(ctx context.Context, in sysin.AttachmentStatusInp) (err error)
|
||||
MaxSort(ctx context.Context, in sysin.AttachmentMaxSortInp) (*sysin.AttachmentMaxSortModel, error)
|
||||
View(ctx context.Context, in sysin.AttachmentViewInp) (res *sysin.AttachmentViewModel, err error)
|
||||
List(ctx context.Context, in sysin.AttachmentListInp) (list []*sysin.AttachmentListModel, totalCount int, err error)
|
||||
Add(ctx context.Context, meta *sysin.UploadFileMeta, fullPath, drive string) (data *entity.SysAttachment, err error)
|
||||
}
|
||||
ISysServeLog interface {
|
||||
Model(ctx context.Context) *gdb.Model
|
||||
List(ctx context.Context, in sysin.ServeLogListInp) (list []*sysin.ServeLogListModel, totalCount int, err error)
|
||||
Export(ctx context.Context, in sysin.ServeLogListInp) (err error)
|
||||
Delete(ctx context.Context, in sysin.ServeLogDeleteInp) (err error)
|
||||
View(ctx context.Context, in sysin.ServeLogViewInp) (res *sysin.ServeLogViewModel, err error)
|
||||
RealWrite(ctx context.Context, models entity.SysServeLog) (err error)
|
||||
}
|
||||
ISysSmsLog interface {
|
||||
Delete(ctx context.Context, in sysin.SmsLogDeleteInp) error
|
||||
Edit(ctx context.Context, in sysin.SmsLogEditInp) (err error)
|
||||
Status(ctx context.Context, in sysin.SmsLogStatusInp) (err error)
|
||||
MaxSort(ctx context.Context, in sysin.SmsLogMaxSortInp) (*sysin.SmsLogMaxSortModel, error)
|
||||
View(ctx context.Context, in sysin.SmsLogViewInp) (res *sysin.SmsLogViewModel, err error)
|
||||
List(ctx context.Context, in sysin.SmsLogListInp) (list []*sysin.SmsLogListModel, totalCount int, err error)
|
||||
SendCode(ctx context.Context, in sysin.SendCodeInp) (err error)
|
||||
GetTemplate(ctx context.Context, template string, config *model.SmsConfig) (val string, err error)
|
||||
AllowSend(ctx context.Context, models *entity.SysSmsLog, config *model.SmsConfig) (err error)
|
||||
VerifyCode(ctx context.Context, in sysin.VerifyCodeInp) (err error)
|
||||
}
|
||||
ISysDictType interface {
|
||||
Tree(ctx context.Context) (list []*sysin.DictTypeTree, err error)
|
||||
Delete(ctx context.Context, in sysin.DictTypeDeleteInp) error
|
||||
Edit(ctx context.Context, in sysin.DictTypeEditInp) (err error)
|
||||
TreeSelect(ctx context.Context, in sysin.DictTreeSelectInp) (list []*sysin.DictTypeTree, err error)
|
||||
}
|
||||
ISysLog interface {
|
||||
Export(ctx context.Context, in sysin.LogListInp) (err error)
|
||||
RealWrite(ctx context.Context, commonLog entity.SysLog) (err error)
|
||||
AutoLog(ctx context.Context) error
|
||||
AnalysisLog(ctx context.Context) entity.SysLog
|
||||
View(ctx context.Context, in sysin.LogViewInp) (res *sysin.LogViewModel, err error)
|
||||
Delete(ctx context.Context, in sysin.LogDeleteInp) (err error)
|
||||
List(ctx context.Context, in sysin.LogListInp) (list []*sysin.LogListModel, totalCount int, err error)
|
||||
}
|
||||
ISysBlacklist interface {
|
||||
Delete(ctx context.Context, in sysin.BlacklistDeleteInp) (err error)
|
||||
Edit(ctx context.Context, in sysin.BlacklistEditInp) (err error)
|
||||
Status(ctx context.Context, in sysin.BlacklistStatusInp) (err error)
|
||||
MaxSort(ctx context.Context, in sysin.BlacklistMaxSortInp) (*sysin.BlacklistMaxSortModel, error)
|
||||
View(ctx context.Context, in sysin.BlacklistViewInp) (res *sysin.BlacklistViewModel, err error)
|
||||
List(ctx context.Context, in sysin.BlacklistListInp) (list []*sysin.BlacklistListModel, totalCount int, err error)
|
||||
VariableLoad(ctx context.Context, err error)
|
||||
Load(ctx context.Context)
|
||||
}
|
||||
ISysConfig interface {
|
||||
GetLoadCache(ctx context.Context) (conf *model.CacheConfig, err error)
|
||||
GetLoadGenerate(ctx context.Context) (conf *model.GenerateConfig, err error)
|
||||
GetSms(ctx context.Context) (conf *model.SmsConfig, err error)
|
||||
GetGeo(ctx context.Context) (conf *model.GeoConfig, err error)
|
||||
GetUpload(ctx context.Context) (conf *model.UploadConfig, err error)
|
||||
GetSmtp(ctx context.Context) (conf *model.EmailConfig, err error)
|
||||
GetBasic(ctx context.Context) (conf *model.BasicConfig, err error)
|
||||
GetLoadSSL(ctx context.Context) (conf *model.SSLConfig, err error)
|
||||
GetLoadLog(ctx context.Context) (conf *model.LogConfig, err error)
|
||||
GetLoadServeLog(ctx context.Context) (conf *model.ServeLogConfig, err error)
|
||||
GetConfigByGroup(ctx context.Context, in sysin.GetConfigInp) (*sysin.GetConfigModel, error)
|
||||
ConversionType(ctx context.Context, models *entity.SysConfig) (value interface{}, err error)
|
||||
UpdateConfigByGroup(ctx context.Context, in sysin.UpdateConfigInp) error
|
||||
}
|
||||
ISysCurdDemo interface {
|
||||
Model(ctx context.Context, option ...*handler.Option) *gdb.Model
|
||||
List(ctx context.Context, in sysin.CurdDemoListInp) (list []*sysin.CurdDemoListModel, totalCount int, err error)
|
||||
Export(ctx context.Context, in sysin.CurdDemoListInp) (err error)
|
||||
Edit(ctx context.Context, in sysin.CurdDemoEditInp) (err error)
|
||||
Delete(ctx context.Context, in sysin.CurdDemoDeleteInp) (err error)
|
||||
MaxSort(ctx context.Context, in sysin.CurdDemoMaxSortInp) (res *sysin.CurdDemoMaxSortModel, err error)
|
||||
View(ctx context.Context, in sysin.CurdDemoViewInp) (res *sysin.CurdDemoViewModel, err error)
|
||||
Status(ctx context.Context, in sysin.CurdDemoStatusInp) (err error)
|
||||
Switch(ctx context.Context, in sysin.CurdDemoSwitchInp) (err error)
|
||||
}
|
||||
ISysDictData interface {
|
||||
Delete(ctx context.Context, in sysin.DictDataDeleteInp) error
|
||||
Edit(ctx context.Context, in sysin.DictDataEditInp) (err error)
|
||||
List(ctx context.Context, in sysin.DictDataListInp) (list []*sysin.DictDataListModel, totalCount int, err error)
|
||||
Select(ctx context.Context, in sysin.DataSelectInp) (list sysin.DataSelectModel, err error)
|
||||
}
|
||||
)
|
||||
|
||||
var (
|
||||
localSysCron ISysCron
|
||||
localSysAddonsConfig ISysAddonsConfig
|
||||
localSysAttachment ISysAttachment
|
||||
localSysBlacklist ISysBlacklist
|
||||
localSysEmsLog ISysEmsLog
|
||||
localSysGenCodes ISysGenCodes
|
||||
localSysServeLog ISysServeLog
|
||||
localSysSmsLog ISysSmsLog
|
||||
localSysAddonsConfig ISysAddonsConfig
|
||||
localSysBlacklist ISysBlacklist
|
||||
localSysConfig ISysConfig
|
||||
localSysLog ISysLog
|
||||
localSysLoginLog ISysLoginLog
|
||||
localSysAddons ISysAddons
|
||||
localSysCurdDemo ISysCurdDemo
|
||||
localSysDictData ISysDictData
|
||||
localSysDictType ISysDictType
|
||||
localSysProvinces ISysProvinces
|
||||
localSysLog ISysLog
|
||||
localSysCron ISysCron
|
||||
localSysCronGroup ISysCronGroup
|
||||
localSysEmsLog ISysEmsLog
|
||||
localSysLoginLog ISysLoginLog
|
||||
localSysProvinces ISysProvinces
|
||||
localSysAddons ISysAddons
|
||||
localSysGenCodes ISysGenCodes
|
||||
)
|
||||
|
||||
func SysDictData() ISysDictData {
|
||||
if localSysDictData == nil {
|
||||
panic("implement not found for interface ISysDictData, forgot register?")
|
||||
}
|
||||
return localSysDictData
|
||||
}
|
||||
|
||||
func RegisterSysDictData(i ISysDictData) {
|
||||
localSysDictData = i
|
||||
}
|
||||
|
||||
func SysDictType() ISysDictType {
|
||||
if localSysDictType == nil {
|
||||
panic("implement not found for interface ISysDictType, forgot register?")
|
||||
}
|
||||
return localSysDictType
|
||||
}
|
||||
|
||||
func RegisterSysDictType(i ISysDictType) {
|
||||
localSysDictType = i
|
||||
}
|
||||
|
||||
func SysLog() ISysLog {
|
||||
if localSysLog == nil {
|
||||
panic("implement not found for interface ISysLog, forgot register?")
|
||||
}
|
||||
return localSysLog
|
||||
}
|
||||
|
||||
func RegisterSysLog(i ISysLog) {
|
||||
localSysLog = i
|
||||
}
|
||||
|
||||
func SysBlacklist() ISysBlacklist {
|
||||
if localSysBlacklist == nil {
|
||||
panic("implement not found for interface ISysBlacklist, forgot register?")
|
||||
}
|
||||
return localSysBlacklist
|
||||
}
|
||||
|
||||
func RegisterSysBlacklist(i ISysBlacklist) {
|
||||
localSysBlacklist = i
|
||||
}
|
||||
|
||||
func SysConfig() ISysConfig {
|
||||
if localSysConfig == nil {
|
||||
panic("implement not found for interface ISysConfig, forgot register?")
|
||||
}
|
||||
return localSysConfig
|
||||
}
|
||||
|
||||
func RegisterSysConfig(i ISysConfig) {
|
||||
localSysConfig = i
|
||||
}
|
||||
|
||||
func SysCurdDemo() ISysCurdDemo {
|
||||
if localSysCurdDemo == nil {
|
||||
panic("implement not found for interface ISysCurdDemo, forgot register?")
|
||||
}
|
||||
return localSysCurdDemo
|
||||
}
|
||||
|
||||
func RegisterSysCurdDemo(i ISysCurdDemo) {
|
||||
localSysCurdDemo = i
|
||||
}
|
||||
|
||||
func SysLoginLog() ISysLoginLog {
|
||||
if localSysLoginLog == nil {
|
||||
panic("implement not found for interface ISysLoginLog, forgot register?")
|
||||
}
|
||||
return localSysLoginLog
|
||||
}
|
||||
|
||||
func RegisterSysLoginLog(i ISysLoginLog) {
|
||||
localSysLoginLog = i
|
||||
}
|
||||
|
||||
func SysProvinces() ISysProvinces {
|
||||
if localSysProvinces == nil {
|
||||
panic("implement not found for interface ISysProvinces, forgot register?")
|
||||
}
|
||||
return localSysProvinces
|
||||
}
|
||||
|
||||
func RegisterSysProvinces(i ISysProvinces) {
|
||||
localSysProvinces = i
|
||||
}
|
||||
|
||||
func SysCron() ISysCron {
|
||||
if localSysCron == nil {
|
||||
panic("implement not found for interface ISysCron, forgot register?")
|
||||
}
|
||||
return localSysCron
|
||||
}
|
||||
|
||||
func RegisterSysCron(i ISysCron) {
|
||||
localSysCron = i
|
||||
}
|
||||
|
||||
func SysCronGroup() ISysCronGroup {
|
||||
if localSysCronGroup == nil {
|
||||
panic("implement not found for interface ISysCronGroup, forgot register?")
|
||||
}
|
||||
return localSysCronGroup
|
||||
}
|
||||
|
||||
func RegisterSysCronGroup(i ISysCronGroup) {
|
||||
localSysCronGroup = i
|
||||
}
|
||||
|
||||
func SysEmsLog() ISysEmsLog {
|
||||
if localSysEmsLog == nil {
|
||||
panic("implement not found for interface ISysEmsLog, forgot register?")
|
||||
}
|
||||
return localSysEmsLog
|
||||
}
|
||||
|
||||
func RegisterSysEmsLog(i ISysEmsLog) {
|
||||
localSysEmsLog = i
|
||||
}
|
||||
|
||||
func SysAddons() ISysAddons {
|
||||
if localSysAddons == nil {
|
||||
panic("implement not found for interface ISysAddons, forgot register?")
|
||||
}
|
||||
return localSysAddons
|
||||
}
|
||||
|
||||
func RegisterSysAddons(i ISysAddons) {
|
||||
localSysAddons = i
|
||||
}
|
||||
|
||||
func SysGenCodes() ISysGenCodes {
|
||||
if localSysGenCodes == nil {
|
||||
panic("implement not found for interface ISysGenCodes, forgot register?")
|
||||
@ -214,17 +346,6 @@ func RegisterSysGenCodes(i ISysGenCodes) {
|
||||
localSysGenCodes = i
|
||||
}
|
||||
|
||||
func SysServeLog() ISysServeLog {
|
||||
if localSysServeLog == nil {
|
||||
panic("implement not found for interface ISysServeLog, forgot register?")
|
||||
}
|
||||
return localSysServeLog
|
||||
}
|
||||
|
||||
func RegisterSysServeLog(i ISysServeLog) {
|
||||
localSysServeLog = i
|
||||
}
|
||||
|
||||
func SysSmsLog() ISysSmsLog {
|
||||
if localSysSmsLog == nil {
|
||||
panic("implement not found for interface ISysSmsLog, forgot register?")
|
||||
@ -258,134 +379,13 @@ func RegisterSysAttachment(i ISysAttachment) {
|
||||
localSysAttachment = i
|
||||
}
|
||||
|
||||
func SysBlacklist() ISysBlacklist {
|
||||
if localSysBlacklist == nil {
|
||||
panic("implement not found for interface ISysBlacklist, forgot register?")
|
||||
func SysServeLog() ISysServeLog {
|
||||
if localSysServeLog == nil {
|
||||
panic("implement not found for interface ISysServeLog, forgot register?")
|
||||
}
|
||||
return localSysBlacklist
|
||||
return localSysServeLog
|
||||
}
|
||||
|
||||
func RegisterSysBlacklist(i ISysBlacklist) {
|
||||
localSysBlacklist = i
|
||||
}
|
||||
|
||||
func SysEmsLog() ISysEmsLog {
|
||||
if localSysEmsLog == nil {
|
||||
panic("implement not found for interface ISysEmsLog, forgot register?")
|
||||
}
|
||||
return localSysEmsLog
|
||||
}
|
||||
|
||||
func RegisterSysEmsLog(i ISysEmsLog) {
|
||||
localSysEmsLog = i
|
||||
}
|
||||
|
||||
func SysAddons() ISysAddons {
|
||||
if localSysAddons == nil {
|
||||
panic("implement not found for interface ISysAddons, forgot register?")
|
||||
}
|
||||
return localSysAddons
|
||||
}
|
||||
|
||||
func RegisterSysAddons(i ISysAddons) {
|
||||
localSysAddons = i
|
||||
}
|
||||
|
||||
func SysConfig() ISysConfig {
|
||||
if localSysConfig == nil {
|
||||
panic("implement not found for interface ISysConfig, forgot register?")
|
||||
}
|
||||
return localSysConfig
|
||||
}
|
||||
|
||||
func RegisterSysConfig(i ISysConfig) {
|
||||
localSysConfig = i
|
||||
}
|
||||
|
||||
func SysLog() ISysLog {
|
||||
if localSysLog == nil {
|
||||
panic("implement not found for interface ISysLog, forgot register?")
|
||||
}
|
||||
return localSysLog
|
||||
}
|
||||
|
||||
func RegisterSysLog(i ISysLog) {
|
||||
localSysLog = i
|
||||
}
|
||||
|
||||
func SysLoginLog() ISysLoginLog {
|
||||
if localSysLoginLog == nil {
|
||||
panic("implement not found for interface ISysLoginLog, forgot register?")
|
||||
}
|
||||
return localSysLoginLog
|
||||
}
|
||||
|
||||
func RegisterSysLoginLog(i ISysLoginLog) {
|
||||
localSysLoginLog = i
|
||||
}
|
||||
|
||||
func SysProvinces() ISysProvinces {
|
||||
if localSysProvinces == nil {
|
||||
panic("implement not found for interface ISysProvinces, forgot register?")
|
||||
}
|
||||
return localSysProvinces
|
||||
}
|
||||
|
||||
func RegisterSysProvinces(i ISysProvinces) {
|
||||
localSysProvinces = i
|
||||
}
|
||||
|
||||
func SysCronGroup() ISysCronGroup {
|
||||
if localSysCronGroup == nil {
|
||||
panic("implement not found for interface ISysCronGroup, forgot register?")
|
||||
}
|
||||
return localSysCronGroup
|
||||
}
|
||||
|
||||
func RegisterSysCronGroup(i ISysCronGroup) {
|
||||
localSysCronGroup = i
|
||||
}
|
||||
|
||||
func SysCurdDemo() ISysCurdDemo {
|
||||
if localSysCurdDemo == nil {
|
||||
panic("implement not found for interface ISysCurdDemo, forgot register?")
|
||||
}
|
||||
return localSysCurdDemo
|
||||
}
|
||||
|
||||
func RegisterSysCurdDemo(i ISysCurdDemo) {
|
||||
localSysCurdDemo = i
|
||||
}
|
||||
|
||||
func SysDictData() ISysDictData {
|
||||
if localSysDictData == nil {
|
||||
panic("implement not found for interface ISysDictData, forgot register?")
|
||||
}
|
||||
return localSysDictData
|
||||
}
|
||||
|
||||
func RegisterSysDictData(i ISysDictData) {
|
||||
localSysDictData = i
|
||||
}
|
||||
|
||||
func SysDictType() ISysDictType {
|
||||
if localSysDictType == nil {
|
||||
panic("implement not found for interface ISysDictType, forgot register?")
|
||||
}
|
||||
return localSysDictType
|
||||
}
|
||||
|
||||
func RegisterSysDictType(i ISysDictType) {
|
||||
localSysDictType = i
|
||||
}
|
||||
|
||||
func SysCron() ISysCron {
|
||||
if localSysCron == nil {
|
||||
panic("implement not found for interface ISysCron, forgot register?")
|
||||
}
|
||||
return localSysCron
|
||||
}
|
||||
|
||||
func RegisterSysCron(i ISysCron) {
|
||||
localSysCron = i
|
||||
func RegisterSysServeLog(i ISysServeLog) {
|
||||
localSysServeLog = i
|
||||
}
|
||||
|
32
server/internal/service/tcpclient.go
Normal file
32
server/internal/service/tcpclient.go
Normal file
@ -0,0 +1,32 @@
|
||||
// ================================================================================
|
||||
// Code generated by GoFrame CLI tool. DO NOT EDIT.
|
||||
// You can delete these comments if you wish manually maintain this interface file.
|
||||
// ================================================================================
|
||||
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
type (
|
||||
ITCPAuth interface {
|
||||
Start(ctx context.Context)
|
||||
Stop(ctx context.Context)
|
||||
}
|
||||
)
|
||||
|
||||
var (
|
||||
localTCPAuth ITCPAuth
|
||||
)
|
||||
|
||||
func TCPAuth() ITCPAuth {
|
||||
if localTCPAuth == nil {
|
||||
panic("implement not found for interface ITCPAuth, forgot register?")
|
||||
}
|
||||
return localTCPAuth
|
||||
}
|
||||
|
||||
func RegisterTCPAuth(i ITCPAuth) {
|
||||
localTCPAuth = i
|
||||
}
|
32
server/internal/service/tcpserver.go
Normal file
32
server/internal/service/tcpserver.go
Normal file
@ -0,0 +1,32 @@
|
||||
// ================================================================================
|
||||
// Code generated by GoFrame CLI tool. DO NOT EDIT.
|
||||
// You can delete these comments if you wish manually maintain this interface file.
|
||||
// ================================================================================
|
||||
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
type (
|
||||
ITCPServer interface {
|
||||
Start(ctx context.Context)
|
||||
Stop(ctx context.Context)
|
||||
}
|
||||
)
|
||||
|
||||
var (
|
||||
localTCPServer ITCPServer
|
||||
)
|
||||
|
||||
func TCPServer() ITCPServer {
|
||||
if localTCPServer == nil {
|
||||
panic("implement not found for interface ITCPServer, forgot register?")
|
||||
}
|
||||
return localTCPServer
|
||||
}
|
||||
|
||||
func RegisterTCPServer(i ITCPServer) {
|
||||
localTCPServer = i
|
||||
}
|
@ -51,6 +51,10 @@ server:
|
||||
pprofPattern: "/pprof" # 开启PProf时有效,表示PProf特性的页面访问路径,对当前Server绑定的所有域名有效。
|
||||
|
||||
|
||||
tcpServe:
|
||||
address: ":8099" # tcp服务监听地址
|
||||
|
||||
|
||||
# Global logging.
|
||||
logger:
|
||||
level: "all"
|
||||
|
File diff suppressed because one or more lines are too long
102
server/utility/convert/match.go
Normal file
102
server/utility/convert/match.go
Normal file
@ -0,0 +1,102 @@
|
||||
package convert
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"hotgo/utility/validate"
|
||||
)
|
||||
|
||||
// IpFilterStrategy ip过滤策略
|
||||
func IpFilterStrategy(originIp string) (list map[string]struct{}) {
|
||||
list = make(map[string]struct{})
|
||||
|
||||
// 所有IP
|
||||
if originIp == "*" {
|
||||
list["*"] = struct{}{}
|
||||
return
|
||||
}
|
||||
|
||||
// 多个IP
|
||||
if gstr.Contains(originIp, ",") {
|
||||
ips := gstr.Explode(",", originIp)
|
||||
if len(ips) > 0 {
|
||||
for _, ip := range ips {
|
||||
if !validate.IsIp(ip) {
|
||||
continue
|
||||
}
|
||||
list[ip] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// IP段
|
||||
if gstr.Contains(originIp, "/24") {
|
||||
segment := gstr.Replace(originIp, "/24", "")
|
||||
if !validate.IsIp(segment) {
|
||||
return
|
||||
}
|
||||
|
||||
var (
|
||||
start = gstr.Explode(".", segment)
|
||||
prefix = gstr.Implode(".", start[:len(start)-1]) + "."
|
||||
index = gconv.Int(start[len(start)-1])
|
||||
)
|
||||
|
||||
if index < 1 {
|
||||
index = 1
|
||||
}
|
||||
|
||||
for i := index; i <= 254; i++ {
|
||||
list[prefix+gconv.String(i)] = struct{}{}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// IP范围
|
||||
if gstr.Contains(originIp, "-") {
|
||||
originIps := gstr.Explode("-", originIp)
|
||||
if len(originIps) != 2 {
|
||||
return
|
||||
}
|
||||
|
||||
if !validate.IsIp(originIps[0]) || !validate.IsIp(originIps[1]) {
|
||||
return
|
||||
}
|
||||
|
||||
var (
|
||||
start = gstr.Explode(".", originIps[0])
|
||||
prefix = gstr.Implode(".", start[:len(start)-1]) + "."
|
||||
startIndex = gconv.Int(gstr.SubStrFromREx(originIps[0], "."))
|
||||
endIndex = gconv.Int(gstr.SubStrFromREx(originIps[1], "."))
|
||||
)
|
||||
|
||||
if startIndex >= endIndex {
|
||||
list[originIps[0]] = struct{}{}
|
||||
return
|
||||
}
|
||||
|
||||
if startIndex < 1 {
|
||||
startIndex = 1
|
||||
}
|
||||
|
||||
if endIndex > 254 {
|
||||
endIndex = 254
|
||||
}
|
||||
|
||||
for i := startIndex; i <= endIndex; i++ {
|
||||
list[prefix+gconv.String(i)] = struct{}{}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 指定IP
|
||||
if validate.IsIp(originIp) {
|
||||
list[originIp] = struct{}{}
|
||||
return
|
||||
}
|
||||
|
||||
return list
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "hotgo",
|
||||
"version": "2.3.5",
|
||||
"version": "2.4.2",
|
||||
"author": {
|
||||
"name": "MengShuai",
|
||||
"email": "133814250@qq.com",
|
||||
|
@ -7,15 +7,8 @@
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="网站logo" path="basicLogo">
|
||||
<BasicUpload
|
||||
:action="`${uploadUrl}/admin/upload/image`"
|
||||
:headers="uploadHeaders"
|
||||
:data="{ type: 0 }"
|
||||
name="file"
|
||||
:width="100"
|
||||
:height="100"
|
||||
<UploadImage
|
||||
:maxNumber="1"
|
||||
@uploadChange="uploadChange"
|
||||
v-model:value="formValue.basicLogo"
|
||||
:helpText="
|
||||
'网站logo适用于客户端使用,图片大小不超过' + componentSetting.upload.maxSize + 'MB'
|
||||
@ -90,36 +83,13 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { reactive, ref, unref, onMounted } from 'vue';
|
||||
import { ref, onMounted } from 'vue';
|
||||
import { useDialog, useMessage } from 'naive-ui';
|
||||
import { BasicUpload } from '@/components/Upload';
|
||||
import { useGlobSetting } from '@/hooks/setting';
|
||||
import { useUserStoreWidthOut } from '@/store/modules/user';
|
||||
import componentSetting from '@/settings/componentSetting';
|
||||
import { getConfig, updateConfig } from '@/api/sys/config';
|
||||
|
||||
const group = ref('basic');
|
||||
|
||||
const show = ref(false);
|
||||
|
||||
const useUserStore = useUserStoreWidthOut();
|
||||
|
||||
const globSetting = useGlobSetting();
|
||||
|
||||
const { uploadUrl } = globSetting;
|
||||
|
||||
const uploadHeaders = reactive({
|
||||
Authorization: useUserStore.token,
|
||||
});
|
||||
|
||||
const rules = {
|
||||
basicName: {
|
||||
required: true,
|
||||
message: '请输入网站名称',
|
||||
trigger: 'blur',
|
||||
},
|
||||
};
|
||||
|
||||
const formRef: any = ref(null);
|
||||
const message = useMessage();
|
||||
const dialog = useDialog();
|
||||
@ -139,6 +109,14 @@
|
||||
basicSystemOpen: true,
|
||||
});
|
||||
|
||||
const rules = {
|
||||
basicName: {
|
||||
required: true,
|
||||
message: '请输入网站名称',
|
||||
trigger: 'blur',
|
||||
},
|
||||
};
|
||||
|
||||
function systemOpenChange(value) {
|
||||
if (!value) {
|
||||
dialog.warning({
|
||||
@ -169,15 +147,6 @@
|
||||
});
|
||||
}
|
||||
|
||||
function uploadChange(list: string[]) {
|
||||
// 单图模式,只需要第一个索引
|
||||
if (list.length > 0) {
|
||||
formValue.value.basicLogo = unref(list[0]);
|
||||
} else {
|
||||
formValue.value.basicLogo = unref('');
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
load();
|
||||
});
|
||||
|
@ -112,7 +112,7 @@
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), { checkedId: 0 });
|
||||
const typeList = ref([]);
|
||||
const typeList = ref<any>([]);
|
||||
const rules = {
|
||||
label: {
|
||||
required: true,
|
||||
@ -304,15 +304,16 @@
|
||||
reloadTable();
|
||||
}
|
||||
|
||||
watch(props, (_newVal, _oldVal) => {
|
||||
params.value.typeId = _newVal.checkedId;
|
||||
formParams.value.typeId = _newVal.checkedId;
|
||||
watch(props, (newVal, _oldVal) => {
|
||||
params.value.typeId = newVal.checkedId;
|
||||
formParams.value.typeId = newVal.checkedId;
|
||||
actionRef.value.reload();
|
||||
setDictSelect();
|
||||
});
|
||||
|
||||
async function setDictSelect() {
|
||||
typeList.value = await getDictSelect({});
|
||||
const tmp = await getDictSelect({});
|
||||
typeList.value = tmp.list;
|
||||
if (typeList.value === undefined || typeList.value === null) {
|
||||
typeList.value = [];
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user