Compare commits

..

160 Commits

Author SHA1 Message Date
刘祥超
0d6c064194 将版本号修改为1.2.11 2023-10-17 13:49:39 +08:00
刘祥超
180e86c643 修复消息通知不能指定集群的Bug 2023-10-17 13:49:23 +08:00
刘祥超
86b04b2b6b 将临时的1.2.9.1升级程序版本号修改为1.2.10 2023-10-15 15:10:36 +08:00
刘祥超
7a5ec79ace 将版本号修改为1.2.10 2023-10-15 13:34:18 +08:00
刘祥超
7290ffd2cd 取消默认反向代理默认的50X重试 2023-10-15 09:40:39 +08:00
刘祥超
2f361c5bcc 优化消息任务相关代码 2023-10-15 09:39:46 +08:00
刘祥超
500d72aaf3 WAF记录IP动作中IP名单如果为空时,默认为全局黑名单 2023-10-15 09:34:20 +08:00
刘祥超
9fc391d1e8 删除不必要的代码 2023-10-14 18:15:54 +08:00
刘祥超
c86e3e2047 优化消息通知相关代码 2023-10-14 17:16:08 +08:00
刘祥超
7e72a90f53 优化消息发送相关代码/删除监控相关代码 2023-10-12 20:11:21 +08:00
刘祥超
7692fed38d 支持批量复制WAF设置 2023-10-09 19:52:51 +08:00
刘祥超
bdd7d2a181 申请证书任务列表区分管理员和用户 2023-10-09 16:18:32 +08:00
刘祥超
118c3f79e4 证书列表区分管理员和用户证书 2023-10-09 15:54:00 +08:00
刘祥超
804a33a002 访问日志列表搜索增加请求来源查询语法:referer:example.com 2023-10-08 17:52:53 +08:00
刘祥超
fe00588039 集群设置中增加“自动调节系统参数”选项 2023-10-08 15:08:28 +08:00
刘祥超
67aac200a7 修复常用网站、常用集群查询可能因为updatedAt过大导致的SQL错误 2023-09-22 16:41:44 +08:00
刘祥超
3e01ad4b68 节点配置中对父级节点进行排序,以保证查找的稳定性 2023-09-22 11:55:47 +08:00
刘祥超
b39690484e 将升级程序中的1.2.10改成1.2.9.1,方便在测试版本中也能升级 2023-09-18 17:02:54 +08:00
刘祥超
31a69ecb12 将全局设置的TCP相关设置移到“集群设置--网站设置”中 2023-09-18 16:55:45 +08:00
刘祥超
94b95beadf 将全局的通用设置--域名审核设置移到“集群设置--网站设置”中 2023-09-18 16:09:11 +08:00
刘祥超
6143f08cf2 IP名单删除任务完成后删除任务 2023-09-14 09:12:19 +08:00
刘祥超
73a5814fd6 版本号修改为1.2.9 2023-09-13 17:37:41 +08:00
刘祥超
448152d5c2 优化删除IP名单时操作 2023-09-13 17:16:00 +08:00
刘祥超
eedb3fb338 将节点版本号修改为1.2.9 2023-09-12 15:03:00 +08:00
刘祥超
06f6f68f3a 增加自动升级一处WAF规则 2023-09-12 14:59:07 +08:00
刘祥超
903e524e80 优化访客IP地址设置 2023-09-07 18:03:28 +08:00
刘祥超
fa6b4fcaee 套餐增加请求数(日/月)限制 2023-09-07 11:46:03 +08:00
刘祥超
67cc8e515f 修复一个测试用例 2023-09-06 18:19:25 +08:00
刘祥超
fa29817920 统计带宽计算增加最小样本数 2023-09-06 18:14:08 +08:00
刘祥超
794c3bc132 优化套餐升级程序 2023-09-06 18:01:41 +08:00
刘祥超
9e481d31ac 重新实现套餐相关功能 2023-09-06 16:30:47 +08:00
刘祥超
4ebc03af75 调用自定义HTTP DNS时增加action(值为GetDomains) 2023-08-28 16:28:08 +08:00
刘祥超
80e2face67 更新Agent IP库 2023-08-27 11:58:14 +08:00
刘祥超
815a5187d5 反向代理增加是否重试50X选项,默认为启用 2023-08-20 15:49:34 +08:00
刘祥超
1d7bc42fba 修复节点状态监控中磁盘空间可能为0的问题 2023-08-18 16:01:24 +08:00
刘祥超
1eb9cca793 将WAF策略中的默认省份封禁提示内容长度从255修改为65535 2023-08-14 12:54:11 +08:00
刘祥超
8766f5b1a9 修改版本号为1.2.8 2023-08-14 12:24:29 +08:00
刘祥超
823e42626d DNS任务增加失败重试 2023-08-13 15:26:59 +08:00
刘祥超
c5308cf41c 生成节点时去除停用的WAF规则集 2023-08-13 10:51:52 +08:00
刘祥超
3053157c6e 将节点的api.yaml改为api_node.yaml 2023-08-12 15:27:09 +08:00
刘祥超
d1ba141c65 优化错误处理相关代码 2023-08-11 16:13:33 +08:00
刘祥超
034ababead 静态分发增加例外URL、限制URL、排除隐藏文件等选项 2023-08-10 11:27:05 +08:00
刘祥超
f5450e37be WAF策略可以自定义默认的区域/省份封禁提示 2023-08-10 10:30:50 +08:00
刘祥超
549fca93e6 将版本号修改为1.2.7 2023-08-09 14:24:16 +08:00
刘祥超
efa0f33256 Update .golangci.yaml 2023-08-09 08:11:53 +08:00
刘祥超
977a12843c 添加golangci-lint配置 2023-08-08 18:36:24 +08:00
刘祥超
6de2834a8c 优化代码 2023-08-08 16:46:17 +08:00
刘祥超
51f91e1603 优化代码 2023-08-08 12:09:20 +08:00
刘祥超
d27b7c8fa1 允许用户调用获取缓存策略信息API 2023-08-07 19:55:57 +08:00
刘祥超
c5098c66af 缓存策略增加预热超时时间设置(默认20分钟) 2023-08-06 17:07:48 +08:00
刘祥超
c2635b0d04 修复默认WAF策略模板中分组不能默认关闭的问题 2023-08-02 17:15:26 +08:00
刘祥超
41a1a6a2e5 更新SQL 2023-08-02 17:02:39 +08:00
刘祥超
e437117e69 WAF策略增加“最多检查内容尺寸“选项 2023-08-02 16:59:38 +08:00
刘祥超
fdc8f78229 优化CC配置 2023-08-01 19:50:01 +08:00
刘祥超
2f78d76a1a 修复系统服务相关代码可能不执行的问题 2023-08-01 16:19:05 +08:00
刘祥超
742f2f0216 启动时自动创建相关软链接 2023-08-01 10:47:13 +08:00
刘祥超
89a606329f 修复自定义页面无法保存的问题 2023-07-31 09:46:00 +08:00
刘祥超
3bba79d14c 优化统计 2023-07-31 09:45:48 +08:00
刘祥超
9f9787e30f 版本号更改为1.2.6 2023-07-28 09:27:08 +08:00
刘祥超
529016d4d5 版本号更改为1.2.5 2023-07-26 15:30:37 +08:00
刘祥超
63942bfb08 将版本号修改为1.2.4 2023-07-26 10:19:02 +08:00
刘祥超
f4e4f32f9c 修复SysLocker无法写入新Key的问题 2023-07-26 10:18:52 +08:00
刘祥超
0a3c740502 版本号修改为1.2.3 2023-07-25 13:17:59 +08:00
刘祥超
9a3438e066 优化IP名单使用IP搜索查询速度 2023-07-25 12:26:12 +08:00
刘祥超
814b82e1b6 优化TOA相关代码 2023-07-24 15:33:44 +08:00
刘祥超
89cfd175cd 优化TOA相关API 2023-07-24 09:56:43 +08:00
刘祥超
860816719e 单个节点所在多个集群共用一个缓存策略时只加载其中一个 2023-07-20 16:54:34 +08:00
刘祥超
caa936f0ac 大幅提升SysLocker自增性能 2023-07-20 14:25:42 +08:00
刘祥超
97836a89eb 优化代码 2023-07-19 18:49:23 +08:00
刘祥超
84483dce61 版本号更改为1.2.2 2023-07-18 14:33:53 +08:00
刘祥超
a4eb7a47f3 更新SQL 2023-07-16 19:12:10 +08:00
刘祥超
20c84d7fe5 手动同步集群任务后把所有相关任务标记为已完成 2023-07-14 10:04:44 +08:00
刘祥超
9d5acd2b36 优化代码 2023-07-12 17:10:33 +08:00
刘祥超
7508f6b92b 增加页面优化相关API 2023-07-11 19:46:00 +08:00
刘祥超
379030fe71 版本号改为1.2.1 2023-07-09 17:38:09 +08:00
刘祥超
10027eea20 缓存策略移除“容纳Key数量”选项 2023-07-08 18:50:58 +08:00
刘祥超
69f25a176b 提交SQL 2023-07-07 18:52:37 +08:00
刘祥超
ac19f06b6c 网站列表增加QPS和攻击QPS信息 2023-07-07 18:51:36 +08:00
刘祥超
87a81f59c7 修复查询网站日流量统计时可能不兼容MySQL8的问题 2023-07-07 17:35:23 +08:00
刘祥超
7389e5e54b 远程安装时可以覆盖运行中的文件 2023-07-07 15:59:51 +08:00
刘祥超
e6792b8188 优化自定义页面设置,页面URL不再支持填写本地文件 2023-07-07 11:48:48 +08:00
刘祥超
a037546cfa 优化代码 2023-07-07 09:52:53 +08:00
刘祥超
8efaacf1ef 国家/地区、省份等相关表增加真实ID字段,防止数据表被用户修改时无法对应 2023-07-07 09:52:46 +08:00
刘祥超
a38dd1cef8 “集群设置 -- 网站设置”增加“允许记录访问日志”选项 2023-07-05 15:29:11 +08:00
刘祥超
77521112d0 试用 executils.LookPath()代替 exec.LookPath() 2023-07-05 11:34:52 +08:00
刘祥超
4f9a5d238c 优化本地mysql服务自动启动逻辑 2023-07-05 11:14:51 +08:00
刘祥超
d5fb39ed50 更新TeaGo库 2023-07-05 09:25:27 +08:00
刘祥超
58a84083ae 优化自增锁性能 2023-07-04 22:02:17 +08:00
刘祥超
9f564a4739 重写规则API支持用户操作 2023-07-04 18:31:12 +08:00
刘祥超
c20accbf58 减少在自增锁中生成的sql statements 2023-07-04 14:42:14 +08:00
刘祥超
3f21b3148e 优化代码 2023-07-03 17:12:24 +08:00
刘祥超
74e909a501 增加清空节点同步任务、清空DNS同步任务API 2023-07-02 17:29:19 +08:00
刘祥超
4150ee1b47 优化自增锁算法 2023-07-02 15:27:49 +08:00
刘祥超
df04de2151 修复测试用例 2023-07-02 15:25:13 +08:00
刘祥超
4dc5d9aa7e 修复自动生成的用户没有绑定集群、用户名不规范的问题 2023-07-02 14:30:46 +08:00
刘祥超
0ef7e6ccd8 增加部分数据清理周期设置 2023-07-01 17:54:40 +08:00
刘祥超
ed2b831e5a 查找当前API节点版本中增加角色 2023-07-01 15:09:54 +08:00
刘祥超
5d392ecd43 优化代码 2023-06-30 19:06:55 +08:00
刘祥超
ea147d7506 优化代码 2023-06-30 19:01:47 +08:00
刘祥超
b45136c2c8 优化代码 2023-06-30 18:54:45 +08:00
刘祥超
530e1513ec 日志API增加多语言代号参数 2023-06-30 18:10:11 +08:00
刘祥超
6c60677b72 添加多语言最基础代码 2023-06-28 09:11:20 +08:00
刘祥超
a1bec5e578 创建Web配置时自动设置访客IP获取方式为“直接获取” 2023-06-23 17:05:52 +08:00
刘祥超
9dece058d9 优化查询所有集群性能 2023-06-23 16:23:21 +08:00
刘祥超
89df6ae6bf 优化集群列表性能 2023-06-23 16:15:22 +08:00
刘祥超
85b6e6428c 源站支持HTTP/2 2023-06-23 11:44:02 +08:00
刘祥超
0df204a1df 初始化时修改默认生成的用户名,并将用户自动关联到默认集群 2023-06-21 11:51:07 +08:00
刘祥超
ecef94b700 增加简化版的创建TCP网站API 2023-06-18 17:14:24 +08:00
刘祥超
a493bbb280 增加简化版的创建HTTP网站API 2023-06-18 16:20:00 +08:00
刘祥超
eee902abec 优化错误提示 2023-06-16 08:17:00 +08:00
刘祥超
2aceb4fb4d 版本号改为1.2.0 2023-06-12 14:42:26 +08:00
刘祥超
c1bbcc8dab 已停用的节点不计算在离线节点里 2023-06-12 14:10:18 +08:00
刘祥超
262f8a5594 已经停用的节点不提示需要升级 2023-06-12 14:04:50 +08:00
刘祥超
a85b49a377 智能DNS实现DoH功能 2023-06-11 17:57:31 +08:00
刘祥超
75e353db0e 初步实现对象存储源站 2023-06-07 17:25:20 +08:00
刘祥超
ccbb14836e 修复因serverId传入0而可能删除WAF策略的问题 2023-06-06 15:03:18 +08:00
刘祥超
7fbc61aa21 改进DNS域名解析相关函数 2023-06-05 12:36:29 +08:00
刘祥超
8b804cb500 修复一个测试用例 2023-06-04 09:38:13 +08:00
刘祥超
3ddb95731a Update sql.json 2023-06-03 09:08:44 +08:00
刘祥超
beeb46ab7f 修复节点IP为IPv6时无法健康检查的问题 2023-06-02 14:46:38 +08:00
刘祥超
a65255e4e5 优化代码 2023-06-01 18:08:45 +08:00
刘祥超
b7768ea0c0 初步实现HTTP3 2023-06-01 17:46:10 +08:00
刘祥超
9d2ecf6822 提供用户某日刷新/预热缓存数量查询API 2023-05-28 18:00:51 +08:00
刘祥超
1a6d160a33 优化创建缓存任务时域名检查速度 2023-05-28 17:44:27 +08:00
刘祥超
b69132e1ca 版本号改为1.1.0 2023-05-28 16:06:53 +08:00
刘祥超
19890c209f 优化健康检查代码 2023-05-28 15:13:15 +08:00
刘祥超
1534436435 ACMETaskService.FindEnabledACMETask()返回信息中增加关联的证书信息 2023-05-25 14:55:46 +08:00
刘祥超
c087d1cba2 Update sql.json 2023-05-25 14:55:09 +08:00
刘祥超
cfc2ec5e4b 优化代码 2023-05-23 19:50:28 +08:00
刘祥超
af9c8523e9 实现集群CC防护策略设置 2023-05-23 19:16:30 +08:00
刘祥超
00977cf33e 实现集群自定义页面 2023-05-22 17:30:33 +08:00
刘祥超
fc2d018207 优化自定义页面配置存储 2023-05-22 10:04:46 +08:00
刘祥超
8569eebfee 修复使用localhost连接数据库时不能自动尝试启动的问题 2023-05-20 16:58:14 +08:00
刘祥超
73d72f0d33 HTTP Header中支持设置非标Header 2023-05-19 19:54:10 +08:00
刘祥超
c4b8540171 HTTP Header - CORS跨域设置增加多个选项 2023-05-19 16:34:24 +08:00
刘祥超
85219ac2ef 增加复制节点动作API 2023-05-19 11:12:24 +08:00
刘祥超
6976454bde 实现基础的智能调度 2023-05-17 18:42:21 +08:00
刘祥超
813ce44ceb 修复AscPk()写成Asc()的问题 2023-05-12 15:34:18 +08:00
刘祥超
294b57ca60 非超级用户不提示弱密码管理员 2023-05-06 14:04:21 +08:00
刘祥超
22010190b2 智能 DNS实现健康检查 2023-05-03 17:09:55 +08:00
刘祥超
cc4cd9c620 防盗链增加”同时检查Origin选项“ 2023-05-02 17:11:22 +08:00
刘祥超
5df9c0f1fd 检查节点认证时增加状态参数 2023-04-26 11:26:42 +08:00
刘祥超
dc3594a08d 集群健康检查可以同时检查单节点的多个IP 2023-04-26 10:50:29 +08:00
刘祥超
49ba1336cd 修复用户可能无法删除IP的问题 2023-04-25 11:28:04 +08:00
刘祥超
96db5af237 修复用户端无法查看IP名单的Bug 2023-04-25 11:18:09 +08:00
刘祥超
476ff91bf8 版本号修改为1.0.4 2023-04-24 10:18:26 +08:00
刘祥超
ac6b10489e DNSPod支持自定义线路分组 2023-04-24 09:37:26 +08:00
刘祥超
9352e1837f 创建初始化用户 2023-04-23 20:13:55 +08:00
刘祥超
ddec102d18 远程升级API节点时自动上传边缘节点安装文件 2023-04-23 19:42:51 +08:00
刘祥超
0d50b9b0cc 创建ACME用户、ACME任务时可以指定平台用户 2023-04-23 15:00:13 +08:00
刘祥超
20b4b47eea 优化edgeIPItems索引 2023-04-23 09:44:06 +08:00
刘祥超
ee8396c760 修复在节点列表中不能同时使用关键词和排序的问题 2023-04-21 15:27:24 +08:00
刘祥超
c3fa6a753a 修复只有一个泛域名时无法查询匹配证书的问题 2023-04-21 10:41:20 +08:00
刘祥超
fbe4de2e94 节点版本号修改为1.1.0 2023-04-19 21:02:01 +08:00
刘祥超
f5c7108799 IP库查询提供更多信息 2023-04-19 20:36:48 +08:00
刘祥超
5825a7e654 修复一处访问日志可能无法正确获得对应日期的问题 2023-04-18 17:54:01 +08:00
刘祥超
a6911117af 优化可用内存检查 2023-04-11 18:52:43 +08:00
刘祥超
b428db4f5e 版本号改为1.1.0 2023-04-10 21:03:31 +08:00
刘祥超
e4145a2059 优化启动速度 2023-04-10 20:57:38 +08:00
刘祥超
af13357985 创建缓存任务接口增加参数校验 2023-04-10 17:13:20 +08:00
250 changed files with 63592 additions and 9554 deletions

75
.golangci.yaml Normal file
View File

@@ -0,0 +1,75 @@
# https://golangci-lint.run/usage/configuration/
linters:
enable-all: true
disable:
- ifshort
- exhaustivestruct
- golint
- nosnakecase
- scopelint
- varcheck
- structcheck
- interfacer
- maligned
- deadcode
- dogsled
- wrapcheck
- wastedassign
- varnamelen
- testpackage
- thelper
- nilerr
- sqlclosecheck
- paralleltest
- nonamedreturns
- nlreturn
- nakedret
- ireturn
- interfacebloat
- gosmopolitan
- gomnd
- goerr113
- gochecknoglobals
- exhaustruct
- errorlint
- depguard
- exhaustive
- containedctx
- wsl
- cyclop
- dupword
- errchkjson
- contextcheck
- tagalign
- dupl
- forbidigo
- funlen
- goconst
- godox
- gosec
- lll
- nestif
- revive
- unparam
- stylecheck
- gocritic
- gofumpt
- gomoddirectives
- godot
- gofmt
- gocognit
- mirror
- gocyclo
- gochecknoinits
- gci
- maintidx
- prealloc
- goimports
- errname
- musttag
- forcetypeassert
- whitespace
- noctx
- tagliatelle
- nilnil

View File

@@ -12,4 +12,5 @@ dbs:
fields:
bool: [ "uamIsOn", "followPort", "requestHostExcludingPort", "autoRemoteStart", "autoInstallNftables" ]
bool: [ "uamIsOn", "followPort", "requestHostExcludingPort", "autoRemoteStart", "autoInstallNftables", "enableIPLists", "detectAgents", "checkingPorts", "enableRecordHealthCheck", "offlineIsNotified", "http2Enabled", "http3Enabled", "enableHTTP2", "retry50X", "autoSystemTuning" ]

View File

@@ -52,7 +52,7 @@ func main() {
return
}
unzip := helpers.NewUnzip(zipPath, targetPath)
var unzip = helpers.NewUnzip(zipPath, targetPath)
err := unzip.Run()
if err != nil {
stderr("ERROR: " + err.Error())

13
go.mod
View File

@@ -10,25 +10,26 @@ require (
github.com/andybalholm/brotli v1.0.4
github.com/cespare/xxhash v1.1.0
github.com/cespare/xxhash/v2 v2.1.1
github.com/go-acme/lego/v4 v4.9.0
github.com/fsnotify/fsnotify v1.6.0
github.com/go-acme/lego/v4 v4.10.2
github.com/go-sql-driver/mysql v1.7.0
github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible
github.com/iwind/TeaGo v0.0.0-20230304012706-c1f4a4e27470
github.com/iwind/TeaGo v0.0.0-20230704135818-4a5646ab1f5b
github.com/iwind/gosock v0.0.0-20220505115348-f88412125a62
github.com/miekg/dns v1.1.50
github.com/mozillazg/go-pinyin v0.18.0
github.com/pkg/sftp v1.12.0
github.com/shirou/gopsutil/v3 v3.22.2
github.com/smartwalle/alipay/v3 v3.1.7
golang.org/x/crypto v0.1.0
golang.org/x/crypto v0.5.0
golang.org/x/net v0.8.0
golang.org/x/sys v0.6.0
golang.org/x/sys v0.8.0
google.golang.org/grpc v1.45.0
gopkg.in/yaml.v3 v3.0.1
)
require (
github.com/cenkalti/backoff/v4 v4.1.3 // indirect
github.com/cenkalti/backoff/v4 v4.2.0 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
@@ -40,6 +41,8 @@ require (
github.com/pkg/errors v0.9.1 // indirect
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
github.com/smartwalle/crypto4go v1.0.2 // indirect
github.com/tdewolff/minify/v2 v2.12.7 // indirect
github.com/tdewolff/parse/v2 v2.6.6 // indirect
github.com/technoweenie/multipartstreamer v1.0.1 // indirect
github.com/tklauser/go-sysconf v0.3.9 // indirect
github.com/tklauser/numcpus v0.3.0 // indirect

32
go.sum
View File

@@ -12,13 +12,14 @@ github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY
github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM=
github.com/cenkalti/backoff/v4 v4.1.3 h1:cFAlzYUlVYDysBEH2T5hyJZMh3+5+WCBvSnK6Q8UtC4=
github.com/cenkalti/backoff/v4 v4.1.3/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
github.com/cenkalti/backoff/v4 v4.2.0 h1:HN5dHm3WBOgndBH6E8V0q2jIYIR3s9yglV8k/+MN3u4=
github.com/cenkalti/backoff/v4 v4.2.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cheekybits/is v0.0.0-20150225183255-68e9c0620927/go.mod h1:h/aW8ynjgkuj+NQRlZcDbAbM1ORAbXjXX77sX7T289U=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
@@ -30,6 +31,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgryski/go-rendezvous v0.0.0-20200624174652-8d2f3be8b2d9/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/djherbis/atime v1.1.0/go.mod h1:28OF6Y8s3NQWwacXc5eZTsEsiMzp7LF8MbXE+XJPdBE=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
@@ -38,6 +41,8 @@ github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
@@ -79,8 +84,8 @@ github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/iwind/TeaGo v0.0.0-20210411134150-ddf57e240c2f/go.mod h1:KU4mS7QNiZ7QWEuDBk1zw0/Q2LrAPZv3tycEFBsuUwc=
github.com/iwind/TeaGo v0.0.0-20230304012706-c1f4a4e27470 h1:TuRxvKRv9PxKVijWOkUnZm5TeanQqWGUJyPx9u6cra4=
github.com/iwind/TeaGo v0.0.0-20230304012706-c1f4a4e27470/go.mod h1:fi/Pq+/5m2HZoseM+39dMF57ANXRt6w4PkGu3NXPc5s=
github.com/iwind/TeaGo v0.0.0-20230704135818-4a5646ab1f5b h1:yYUaxnc04uzfr7C9HBN52ZZvcQomND+C5aZTpjOUYFI=
github.com/iwind/TeaGo v0.0.0-20230704135818-4a5646ab1f5b/go.mod h1:fi/Pq+/5m2HZoseM+39dMF57ANXRt6w4PkGu3NXPc5s=
github.com/iwind/gosock v0.0.0-20220505115348-f88412125a62 h1:HJH6RDheAY156DnIfJSD/bEvqyXzsZuE2gzs8PuUjoo=
github.com/iwind/gosock v0.0.0-20220505115348-f88412125a62/go.mod h1:H5Q7SXwbx3a97ecJkaS2sD77gspzE7HFUafBO0peEyA=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
@@ -96,10 +101,11 @@ github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8=
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
github.com/matryer/try v0.0.0-20161228173917-9ac251b645a2/go.mod h1:0KeJpeMD6o+O4hW7qJOT7vyQPKrWmj26uf5wMc/IiIs=
github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA=
github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@@ -140,12 +146,20 @@ github.com/smartwalle/crypto4go v1.0.2 h1:9DUEOOsPhmp00438L4oBdcL8EZG1zumecft5bW
github.com/smartwalle/crypto4go v1.0.2/go.mod h1:LQ7vCZIb7BE5+MuMtJBuO8ORkkQ01m4DXDBWPzLbkMY=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72 h1:qLC7fQah7D6K1B0ujays3HV9gkFtllcxhzImRR7ArPQ=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
github.com/tdewolff/minify/v2 v2.12.7 h1:pBzz2tAfz5VghOXiQIsSta6srhmTeinQPjRDHWoumCA=
github.com/tdewolff/minify/v2 v2.12.7/go.mod h1:ZRKTheiOGyLSK8hOZWWv+YoJAECzDivNgAlVYDHp/Ws=
github.com/tdewolff/parse/v2 v2.6.6 h1:Yld+0CrKUJaCV78DL1G2nk3C9lKrxyRTux5aaK/AkDo=
github.com/tdewolff/parse/v2 v2.6.6/go.mod h1:woz0cgbLwFdtbjJu8PIKxhW05KplTFQkOdX78o+Jgrs=
github.com/tdewolff/test v1.0.7/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE=
github.com/tdewolff/test v1.0.9 h1:SswqJCmeN4B+9gEAi/5uqT0qpi1y2/2O47V/1hhGZT0=
github.com/tdewolff/test v1.0.9/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE=
github.com/technoweenie/multipartstreamer v1.0.1 h1:XRztA5MXiR1TIRHxH2uNxXxaIkKQDeX7m2XsSOlQEnM=
github.com/technoweenie/multipartstreamer v1.0.1/go.mod h1:jNVxdtShOxzAsukZwTSw6MDx5eUJoiEBsSvzDU9uzog=
github.com/tklauser/go-sysconf v0.3.9 h1:JeUVdAOWhhxVcU6Eqr/ATFHgXk/mmiItdKeJPev3vTo=
@@ -162,8 +176,8 @@ golang.org/x/crypto v0.0.0-20190506204251-e1dfcc566284/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU=
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
golang.org/x/crypto v0.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE=
golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20200513190911-00229845015e/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw=
@@ -222,8 +236,10 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210816074244-15123e1e1f71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220111092808-5a964db01320/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.6.0 h1:clScbb1cHjoCkyRbWwBEUZ5H/tIFu5TAXIqaZD0Gcjw=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=

View File

@@ -130,6 +130,9 @@ func TestGenerate_EAB(t *testing.T) {
} else {
reg, err = client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})
}
if err != nil {
t.Fatal(err)
}
myUser.Registration = reg
request := certificate.ObtainRequest{

View File

@@ -1,6 +1,7 @@
package acme
import (
"fmt"
"github.com/TeaOSLab/EdgeAPI/internal/dnsclients"
"github.com/TeaOSLab/EdgeAPI/internal/dnsclients/dnstypes"
"github.com/TeaOSLab/EdgeAPI/internal/errors"
@@ -45,7 +46,7 @@ func (this *DNSProvider) Present(domain, token, keyAuth string) error {
if !wasDeleted {
records, err := this.raw.QueryRecords(this.dnsDomain, recordName, dnstypes.RecordTypeTXT)
if err != nil {
return errors.New("query DNS record failed: " + err.Error())
return fmt.Errorf("query DNS record failed: %w", err)
}
for _, record := range records {
err = this.raw.DeleteRecord(this.dnsDomain, record)
@@ -67,7 +68,7 @@ func (this *DNSProvider) Present(domain, token, keyAuth string) error {
Route: this.raw.DefaultRoute(),
})
if err != nil {
return errors.New("create DNS record failed: " + err.Error())
return fmt.Errorf("create DNS record failed: %w", err)
}
return nil

View File

@@ -1,6 +1,7 @@
package acme
import (
"fmt"
teaconst "github.com/TeaOSLab/EdgeAPI/internal/const"
"github.com/TeaOSLab/EdgeAPI/internal/errors"
"github.com/go-acme/lego/v4/certcrypto"
@@ -92,26 +93,26 @@ func (this *Request) runDNS() (certData []byte, keyData []byte, err error) {
// 注册用户
var resource = this.task.User.GetRegistration()
if resource != nil {
resource, err = client.Registration.QueryRegistration()
_, err = client.Registration.QueryRegistration()
if err != nil {
return nil, nil, err
}
} else {
if this.task.Provider.RequireEAB {
resource, err := client.Registration.RegisterWithExternalAccountBinding(registration.RegisterEABOptions{
resource, err = client.Registration.RegisterWithExternalAccountBinding(registration.RegisterEABOptions{
TermsOfServiceAgreed: true,
Kid: this.task.Account.EABKid,
HmacEncoded: this.task.Account.EABKey,
})
if err != nil {
return nil, nil, errors.New("register user failed: " + err.Error())
return nil, nil, fmt.Errorf("register user failed: %w", err)
}
err = this.task.User.Register(resource)
if err != nil {
return nil, nil, err
}
} else {
resource, err := client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})
resource, err = client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})
if err != nil {
return nil, nil, err
}
@@ -134,7 +135,7 @@ func (this *Request) runDNS() (certData []byte, keyData []byte, err error) {
}
certResource, err := client.Certificate.Obtain(request)
if err != nil {
return nil, nil, errors.New("obtain cert failed: " + err.Error())
return nil, nil, fmt.Errorf("obtain cert failed: %w", err)
}
return certResource.Certificate, certResource.PrivateKey, nil
@@ -165,26 +166,26 @@ func (this *Request) runHTTP() (certData []byte, keyData []byte, err error) {
// 注册用户
var resource = this.task.User.GetRegistration()
if resource != nil {
resource, err = client.Registration.QueryRegistration()
_, err = client.Registration.QueryRegistration()
if err != nil {
return nil, nil, err
}
} else {
if this.task.Provider.RequireEAB {
resource, err := client.Registration.RegisterWithExternalAccountBinding(registration.RegisterEABOptions{
resource, err = client.Registration.RegisterWithExternalAccountBinding(registration.RegisterEABOptions{
TermsOfServiceAgreed: true,
Kid: this.task.Account.EABKid,
HmacEncoded: this.task.Account.EABKey,
})
if err != nil {
return nil, nil, errors.New("register user failed: " + err.Error())
return nil, nil, fmt.Errorf("register user failed: %w", err)
}
err = this.task.User.Register(resource)
if err != nil {
return nil, nil, err
}
} else {
resource, err := client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})
resource, err = client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})
if err != nil {
return nil, nil, err
}

View File

@@ -1,6 +1,7 @@
package apps
import (
"errors"
"fmt"
teaconst "github.com/TeaOSLab/EdgeAPI/internal/const"
"github.com/iwind/TeaGo/logs"
@@ -9,8 +10,10 @@ import (
"github.com/iwind/gosock/pkg/gosock"
"os"
"os/exec"
"path/filepath"
"runtime"
"strconv"
"strings"
"time"
)
@@ -184,13 +187,16 @@ func (this *AppCmd) runStart() {
return
}
cmd := exec.Command(os.Args[0])
var cmd = exec.Command(this.exe())
err := cmd.Start()
if err != nil {
fmt.Println(this.product+" start failed:", err.Error())
return
}
// create symbolic links
_ = this.createSymLinks()
fmt.Println(this.product+" started ok, pid:", cmd.Process.Pid)
}
@@ -237,3 +243,58 @@ func (this *AppCmd) getPID() int {
}
return maps.NewMap(reply.Params).GetInt("pid")
}
func (this *AppCmd) exe() string {
var exe, _ = os.Executable()
if len(exe) == 0 {
exe = os.Args[0]
}
return exe
}
// 创建软链接
func (this *AppCmd) createSymLinks() error {
if runtime.GOOS != "linux" {
return nil
}
var exe, _ = os.Executable()
if len(exe) == 0 {
return nil
}
var errorList = []string{}
// bin
{
var target = "/usr/bin/" + teaconst.ProcessName
old, _ := filepath.EvalSymlinks(target)
if old != exe {
_ = os.Remove(target)
err := os.Symlink(exe, target)
if err != nil {
errorList = append(errorList, err.Error())
}
}
}
// log
{
var realPath = filepath.Dir(filepath.Dir(exe)) + "/logs/run.log"
var target = "/var/log/" + teaconst.ProcessName + ".log"
old, _ := filepath.EvalSymlinks(target)
if old != realPath {
_ = os.Remove(target)
err := os.Symlink(realPath, target)
if err != nil {
errorList = append(errorList, err.Error())
}
}
}
if len(errorList) > 0 {
return errors.New(strings.Join(errorList, "\n"))
}
return nil
}

View File

@@ -1,12 +1,14 @@
package teaconst
const (
Version = "1.0.1"
Version = "1.2.11"
ProductName = "Edge API"
ProcessName = "edge-api"
ProductNameZH = "Edge"
GlobalProductName = "GoEdge"
Role = "api"
EncryptKey = "8f983f4d69b83aaa0d74b21a212f6967"
@@ -18,7 +20,7 @@ const (
// 其他节点版本号,用来检测是否有需要升级的节点
NodeVersion = "1.0.1"
NodeVersion = "1.2.10"
// SQLVersion SQL版本号
SQLVersion = "11"

View File

@@ -2,6 +2,7 @@ package acme
import (
"bytes"
"context"
"encoding/json"
acmeutils "github.com/TeaOSLab/EdgeAPI/internal/acme"
teaconst "github.com/TeaOSLab/EdgeAPI/internal/const"
@@ -106,9 +107,17 @@ func (this *ACMETaskDAO) DisableAllTasksWithCertId(tx *dbs.Tx, certId int64) err
}
// CountAllEnabledACMETasks 计算所有任务数量
func (this *ACMETaskDAO) CountAllEnabledACMETasks(tx *dbs.Tx, userId int64, isAvailable bool, isExpired bool, expiringDays int64, keyword string) (int64, error) {
func (this *ACMETaskDAO) CountAllEnabledACMETasks(tx *dbs.Tx, userId int64, isAvailable bool, isExpired bool, expiringDays int64, keyword string, userOnly bool) (int64, error) {
var query = this.Query(tx)
query.Attr("userId", userId) // 这个条件必须加上
if userId > 0 {
query.Attr("userId", userId)
} else {
if userOnly {
query.Gt("userId", 0)
} else {
query.Attr("userId", 0)
}
}
if isAvailable || isExpired || expiringDays > 0 {
query.Gt("certId", 0)
@@ -138,9 +147,17 @@ func (this *ACMETaskDAO) CountAllEnabledACMETasks(tx *dbs.Tx, userId int64, isAv
}
// ListEnabledACMETasks 列出单页任务
func (this *ACMETaskDAO) ListEnabledACMETasks(tx *dbs.Tx, userId int64, isAvailable bool, isExpired bool, expiringDays int64, keyword string, offset int64, size int64) (result []*ACMETask, err error) {
func (this *ACMETaskDAO) ListEnabledACMETasks(tx *dbs.Tx, userId int64, isAvailable bool, isExpired bool, expiringDays int64, keyword string, userOnly bool, offset int64, size int64) (result []*ACMETask, err error) {
var query = this.Query(tx)
query.Attr("userId", userId) // 这个条件必须加上
if userId > 0 {
query.Attr("userId", userId)
} else {
if userOnly {
query.Gt("userId", 0)
} else {
query.Attr("userId", 0)
}
}
if isAvailable || isExpired || expiringDays > 0 {
query.Gt("certId", 0)
@@ -228,8 +245,8 @@ func (this *ACMETaskDAO) UpdateACMETask(tx *dbs.Tx, acmeTaskId int64, acmeUserId
return err
}
// CheckACMETask 检查权限
func (this *ACMETaskDAO) CheckACMETask(tx *dbs.Tx, userId int64, acmeTaskId int64) (bool, error) {
// CheckUserACMETask 检查用户权限
func (this *ACMETaskDAO) CheckUserACMETask(tx *dbs.Tx, userId int64, acmeTaskId int64) (bool, error) {
var query = this.Query(tx)
if userId > 0 {
query.Attr("userId", userId)
@@ -241,6 +258,15 @@ func (this *ACMETaskDAO) CheckACMETask(tx *dbs.Tx, userId int64, acmeTaskId int6
Exist()
}
// FindACMETaskUserId 查找任务所属用户ID
func (this *ACMETaskDAO) FindACMETaskUserId(tx *dbs.Tx, taskId int64) (userId int64, err error) {
return this.Query(tx).
Pk(taskId).
Result("userId").
FindInt64Col(0)
}
// UpdateACMETaskCert 设置任务关联的证书
func (this *ACMETaskDAO) UpdateACMETaskCert(tx *dbs.Tx, taskId int64, certId int64) error {
if taskId <= 0 {
@@ -434,7 +460,7 @@ func (this *ACMETaskDAO) runTaskWithoutLog(tx *dbs.Tx, taskId int64) (isOk bool,
CertData: certData,
KeyData: keyData,
}
err = sslConfig.Init(nil)
err = sslConfig.Init(context.Background())
if err != nil {
errMsg = "证书生成成功,但是分析证书信息时发生错误:" + err.Error()
return

View File

@@ -131,6 +131,8 @@ func (this *ACMEUserDAO) CountACMEUsersWithAdminId(tx *dbs.Tx, adminId int64, us
}
if userId > 0 {
query.Attr("userId", userId)
} else {
query.Attr("userId", 0)
}
if accountId > 0 {
query.Attr("accountId", accountId)
@@ -149,6 +151,8 @@ func (this *ACMEUserDAO) ListACMEUsers(tx *dbs.Tx, adminId int64, userId int64,
}
if userId > 0 {
query.Attr("userId", userId)
} else {
query.Attr("userId", 0)
}
_, err = query.

View File

@@ -2,6 +2,22 @@ package models
import "github.com/iwind/TeaGo/dbs"
const (
AdminField_Id dbs.FieldName = "id" // ID
AdminField_IsOn dbs.FieldName = "isOn" // 是否启用
AdminField_Username dbs.FieldName = "username" // 用户名
AdminField_Password dbs.FieldName = "password" // 密码
AdminField_Fullname dbs.FieldName = "fullname" // 全名
AdminField_IsSuper dbs.FieldName = "isSuper" // 是否为超级管理员
AdminField_CreatedAt dbs.FieldName = "createdAt" // 创建时间
AdminField_UpdatedAt dbs.FieldName = "updatedAt" // 修改时间
AdminField_State dbs.FieldName = "state" // 状态
AdminField_Modules dbs.FieldName = "modules" // 允许的模块
AdminField_CanLogin dbs.FieldName = "canLogin" // 是否可以登录
AdminField_Theme dbs.FieldName = "theme" // 模板设置
AdminField_Lang dbs.FieldName = "lang" // 语言代号
)
// Admin 管理员
type Admin struct {
Id uint32 `field:"id"` // ID
@@ -16,6 +32,7 @@ type Admin struct {
Modules dbs.JSON `field:"modules"` // 允许的模块
CanLogin bool `field:"canLogin"` // 是否可以登录
Theme string `field:"theme"` // 模板设置
Lang string `field:"lang"` // 语言代号
}
type AdminOperator struct {
@@ -31,6 +48,7 @@ type AdminOperator struct {
Modules any // 允许的模块
CanLogin any // 是否可以登录
Theme any // 模板设置
Lang any // 语言代号
}
func NewAdminOperator() *AdminOperator {

View File

@@ -335,6 +335,7 @@ func (this *APINodeDAO) UpdateAPINodeStatus(tx *dbs.Tx, apiNodeId int64, statusJ
func (this *APINodeDAO) CountAllLowerVersionNodes(tx *dbs.Tx, version string) (int64, error) {
return this.Query(tx).
State(APINodeStateEnabled).
Attr("isOn", true).
Where("status IS NOT NULL").
Where("(JSON_EXTRACT(status, '$.buildVersionCode') IS NULL OR JSON_EXTRACT(status, '$.buildVersionCode')<:version)").
Param("version", utils.VersionToLong(version)).

View File

@@ -1,6 +1,7 @@
package models
import (
"context"
"encoding/json"
"github.com/TeaOSLab/EdgeAPI/internal/utils"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
@@ -37,7 +38,7 @@ func (this *APINode) DecodeHTTPS(tx *dbs.Tx, cacheMap *utils.CacheMap) (*serverc
return nil, err
}
err = config.Init(nil)
err = config.Init(context.TODO())
if err != nil {
return nil, err
}
@@ -55,7 +56,7 @@ func (this *APINode) DecodeHTTPS(tx *dbs.Tx, cacheMap *utils.CacheMap) (*serverc
}
}
err = config.Init(nil)
err = config.Init(context.TODO())
if err != nil {
return nil, err
}
@@ -135,7 +136,7 @@ func (this *APINode) DecodeRestHTTPS(tx *dbs.Tx, cacheMap *utils.CacheMap) (*ser
return nil, err
}
err = config.Init(nil)
err = config.Init(context.TODO())
if err != nil {
return nil, err
}
@@ -153,7 +154,7 @@ func (this *APINode) DecodeRestHTTPS(tx *dbs.Tx, cacheMap *utils.CacheMap) (*ser
}
}
err = config.Init(nil)
err = config.Init(context.TODO())
if err != nil {
return nil, err
}

View File

@@ -210,6 +210,7 @@ func (this *AuthorityNodeDAO) UpdateNodeStatus(tx *dbs.Tx, nodeId int64, nodeSta
func (this *AuthorityNodeDAO) CountAllLowerVersionNodes(tx *dbs.Tx, version string) (int64, error) {
return this.Query(tx).
State(AuthorityNodeStateEnabled).
Attr("isOn", true).
Where("status IS NOT NULL").
Where("(JSON_EXTRACT(status, '$.buildVersionCode') IS NULL OR JSON_EXTRACT(status, '$.buildVersionCode')<:version)").
Param("version", utils.VersionToLong(version)).

View File

@@ -12,7 +12,8 @@ import (
type DNSTaskType = string
const (
DNSTaskTypeClusterChange DNSTaskType = "clusterChange"
DNSTaskTypeClusterChange DNSTaskType = "clusterChange" // 集群节点、服务发生变化
DNSTaskTypeClusterNodesChange DNSTaskType = "clusterNodesChange" // 集群中节点发生变化
DNSTaskTypeClusterRemoveDomain DNSTaskType = "clusterRemoveDomain" // 从集群中移除域名
DNSTaskTypeNodeChange DNSTaskType = "nodeChange"
DNSTaskTypeServerChange DNSTaskType = "serverChange"
@@ -60,11 +61,12 @@ func (this *DNSTaskDAO) CreateDNSTask(tx *dbs.Tx, clusterId int64, serverId int6
"error": "",
"version": time.Now().UnixNano(),
}, maps.Map{
"updatedAt": time.Now().Unix(),
"isDone": false,
"isOk": false,
"error": "",
"version": time.Now().UnixNano(),
"updatedAt": time.Now().Unix(),
"isDone": false,
"isOk": false,
"error": "",
"version": time.Now().UnixNano(),
"countFails": 0,
})
if err != nil {
return err
@@ -107,7 +109,7 @@ func (this *DNSTaskDAO) CreateDomainTask(tx *dbs.Tx, domainId int64, taskType DN
// FindAllDoingTasks 查找所有正在执行的任务
func (this *DNSTaskDAO) FindAllDoingTasks(tx *dbs.Tx) (result []*DNSTask, err error) {
_, err = this.Query(tx).
Attr("isDone", 0).
Where("(isDone=0 OR (isDone=1 AND isOk=0 AND countFails<3))"). // 3 = retry times
Asc("version").
AscPk().
Slice(&result).
@@ -154,6 +156,12 @@ func (this *DNSTaskDAO) DeleteDNSTask(tx *dbs.Tx, taskId int64) error {
return err
}
// DeleteAllDNSTasks 删除所有任务
func (this *DNSTaskDAO) DeleteAllDNSTasks(tx *dbs.Tx) error {
return this.Query(tx).
DeleteQuickly()
}
// UpdateDNSTaskError 设置任务错误
func (this *DNSTaskDAO) UpdateDNSTaskError(tx *dbs.Tx, taskId int64, err string) error {
if taskId <= 0 {
@@ -164,6 +172,7 @@ func (this *DNSTaskDAO) UpdateDNSTaskError(tx *dbs.Tx, taskId int64, err string)
op.IsDone = true
op.Error = err
op.IsOk = false
op.CountFails = dbs.SQL("countFails+1")
return this.Save(tx, op)
}
@@ -190,10 +199,33 @@ func (this *DNSTaskDAO) UpdateDNSTaskDone(tx *dbs.Tx, taskId int64, taskVersion
op.Id = taskId
op.IsDone = true
op.IsOk = true
op.CountFails = 0
op.Error = ""
return this.Save(tx, op)
}
// GenerateVersion 生成最新的版本号
func (this *DNSTaskDAO) GenerateVersion() int64 {
return time.Now().UnixNano()
}
// UpdateClusterDNSTasksDone 设置所有集群任务完成
func (this *DNSTaskDAO) UpdateClusterDNSTasksDone(tx *dbs.Tx, clusterId int64, maxVersion int64) error {
if clusterId <= 0 || maxVersion <= 0 {
return nil
}
return this.Query(tx).
Attr("clusterId", clusterId).
Attr("isOk", false).
Lte("version", maxVersion).
Set("isDone", true).
Set("isOk", true).
Set("error", "").
Set("countFails", 0).
UpdateQuickly()
}
// DeleteDNSTasksWithClusterId 删除集群相关任务
func (this *DNSTaskDAO) DeleteDNSTasksWithClusterId(tx *dbs.Tx, clusterId int64) error {
if clusterId <= 0 {

View File

@@ -1,17 +1,28 @@
package dns
package dns_test
import (
"github.com/TeaOSLab/EdgeAPI/internal/db/models/dns"
_ "github.com/go-sql-driver/mysql"
_ "github.com/iwind/TeaGo/bootstrap"
"github.com/iwind/TeaGo/dbs"
"testing"
"time"
)
func TestDNSTaskDAO_CreateDNSTask(t *testing.T) {
dbs.NotifyReady()
err := SharedDNSTaskDAO.CreateDNSTask(nil, 1, 2, 3, 0, "cdn", "taskType")
err := dns.SharedDNSTaskDAO.CreateDNSTask(nil, 1, 2, 3, 0, "cdn", "taskType")
if err != nil {
t.Fatal(err)
}
t.Log("ok")
}
func TestDNSTaskDAO_UpdateClusterDNSTasksDone(t *testing.T) {
var dao = dns.NewDNSTaskDAO()
var tx *dbs.Tx
err := dao.UpdateClusterDNSTasksDone(tx, 46, time.Now().UnixNano())
if err != nil {
t.Fatal(err)
}
}

View File

@@ -1,5 +1,23 @@
package dns
import "github.com/iwind/TeaGo/dbs"
const (
DNSTaskField_Id dbs.FieldName = "id" // ID
DNSTaskField_ClusterId dbs.FieldName = "clusterId" // 集群ID
DNSTaskField_ServerId dbs.FieldName = "serverId" // 服务ID
DNSTaskField_NodeId dbs.FieldName = "nodeId" // 节点ID
DNSTaskField_DomainId dbs.FieldName = "domainId" // 域名ID
DNSTaskField_RecordName dbs.FieldName = "recordName" // 记录名
DNSTaskField_Type dbs.FieldName = "type" // 任务类型
DNSTaskField_UpdatedAt dbs.FieldName = "updatedAt" // 更新时间
DNSTaskField_IsDone dbs.FieldName = "isDone" // 是否已完成
DNSTaskField_IsOk dbs.FieldName = "isOk" // 是否成功
DNSTaskField_Error dbs.FieldName = "error" // 错误信息
DNSTaskField_Version dbs.FieldName = "version" // 版本
DNSTaskField_CountFails dbs.FieldName = "countFails" // 尝试失败次数
)
// DNSTask DNS更新任务
type DNSTask struct {
Id uint64 `field:"id"` // ID
@@ -14,6 +32,7 @@ type DNSTask struct {
IsOk bool `field:"isOk"` // 是否成功
Error string `field:"error"` // 错误信息
Version uint64 `field:"version"` // 版本
CountFails uint32 `field:"countFails"` // 尝试失败次数
}
type DNSTaskOperator struct {
@@ -29,6 +48,7 @@ type DNSTaskOperator struct {
IsOk any // 是否成功
Error any // 错误信息
Version any // 版本
CountFails any // 尝试失败次数
}
func NewDNSTaskOperator() *DNSTaskOperator {

View File

@@ -3,6 +3,7 @@
package dnsutils
import (
"fmt"
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
"github.com/TeaOSLab/EdgeAPI/internal/db/models/dns"
"github.com/TeaOSLab/EdgeAPI/internal/dnsclients"
@@ -162,17 +163,36 @@ func CheckClusterDNS(tx *dbs.Tx, cluster *models.NodeCluster, checkNodeIssues bo
return nil, err
}
if len(ipAddr) == 0 {
issues = append(issues, &pb.DNSIssue{
Target: node.Name,
TargetId: nodeId,
Type: "node",
Description: "没有设置IP地址",
Params: map[string]string{
"clusterName": cluster.Name,
"clusterId": numberutils.FormatInt64(clusterId),
},
MustFix: true,
})
// 检查是否有离线
anyIPAddr, _, err := models.SharedNodeIPAddressDAO.FindFirstNodeAccessIPAddress(tx, nodeId, false, nodeconfigs.NodeRoleNode)
if err != nil {
return nil, err
}
if len(anyIPAddr) > 0 {
issues = append(issues, &pb.DNSIssue{
Target: node.Name,
TargetId: nodeId,
Type: "node",
Description: "节点所有IP地址处于离线状态",
Params: map[string]string{
"clusterName": cluster.Name,
"clusterId": numberutils.FormatInt64(clusterId),
},
MustFix: true,
})
} else {
issues = append(issues, &pb.DNSIssue{
Target: node.Name,
TargetId: nodeId,
Type: "node",
Description: "没有设置可用的IP地址",
Params: map[string]string{
"clusterName": cluster.Name,
"clusterId": numberutils.FormatInt64(clusterId),
},
MustFix: true,
})
}
continue
}
@@ -198,7 +218,7 @@ func FindDefaultDomainRoute(tx *dbs.Tx, domain *dns.DNSDomain) (string, error) {
}
paramsMap, err := provider.DecodeAPIParams()
if err != nil {
return "", errors.New("decode provider params failed: " + err.Error())
return "", fmt.Errorf("decode provider params failed: %w", err)
}
var dnsProvider = dnsclients.FindProvider(provider.Type, int64(provider.Id))
if dnsProvider == nil {

View File

@@ -232,12 +232,12 @@ Loop:
// CreateHTTPAccessLog 写入单条访问日志
func (this *HTTPAccessLogDAO) CreateHTTPAccessLog(tx *dbs.Tx, dao *HTTPAccessLogDAO, accessLog *pb.HTTPAccessLog) error {
var day = ""
var day string
// 注意:如果你修改了 TimeISO8601 的逻辑,这里也需要同步修改
if len(accessLog.TimeISO8601) > 10 {
day = strings.ReplaceAll(accessLog.TimeISO8601[:10], "-", "")
} else {
timeutil.FormatTime("Ymd", accessLog.Timestamp)
day = timeutil.FormatTime("Ymd", accessLog.Timestamp)
}
tableDef, err := SharedHTTPAccessLogManager.FindLastTable(dao.Instance, day, true)
@@ -461,6 +461,7 @@ func (this *HTTPAccessLogDAO) listAccessLogs(tx *dbs.Tx,
var protoReg = regexp.MustCompile(`proto:(\S+)`)
var schemeReg = regexp.MustCompile(`scheme:(\S+)`)
var methodReg = regexp.MustCompile(`(?:method|requestMethod):(\S+)`)
var refererReg = regexp.MustCompile(`referer:(\S+)`)
var count = len(tableQueries)
var wg = &sync.WaitGroup{}
@@ -613,6 +614,11 @@ func (this *HTTPAccessLogDAO) listAccessLogs(tx *dbs.Tx,
var matches = methodReg.FindStringSubmatch(keyword)
query.Where("JSON_EXTRACT(content, '$.requestMethod')=:keyword").
Param("keyword", strings.ToUpper(matches[1]))
} else if refererReg.MatchString(keyword) {
isSpecialKeyword = true
var matches = refererReg.FindStringSubmatch(keyword)
query.Where("JSON_EXTRACT(content, '$.referer') LIKE :keyword").
Param("keyword", dbutils.QuoteLike(matches[1]))
}
if !isSpecialKeyword {
if regexp.MustCompile(`^ip:.+`).MatchString(keyword) {

View File

@@ -41,7 +41,7 @@ func (this *HTTPAccessLogManager) FindTableNames(db *dbs.DB, day string) ([]stri
for _, prefix := range []string{"edgeHTTPAccessLogs_" + day + "%", "edgehttpaccesslogs_" + day + "%"} {
ones, columnNames, err := db.FindPreparedOnes(`SHOW TABLES LIKE '` + prefix + `'`)
if err != nil {
return nil, errors.New("query table names error: " + err.Error())
return nil, fmt.Errorf("query table names error: %w", err)
}
var columnName = columnNames[0]
@@ -88,7 +88,7 @@ func (this *HTTPAccessLogManager) FindTables(db *dbs.DB, day string) ([]*httpAcc
for _, prefix := range []string{"edgeHTTPAccessLogs_" + day + "%", "edgehttpaccesslogs_" + day + "%"} {
ones, columnNames, err := db.FindPreparedOnes(`SHOW TABLES LIKE '` + prefix + `'`)
if err != nil {
return nil, errors.New("query table names error: " + err.Error())
return nil, fmt.Errorf("query table names error: %w", err)
}
var columnName = columnNames[0]
@@ -373,7 +373,7 @@ func (this *HTTPAccessLogManager) findTableWithoutCache(db *dbs.DB, day string,
var lastInt64Id = types.Int64(lastId)
if accessLogRowsPerTable > 0 && lastInt64Id >= accessLogRowsPerTable {
// create next partial table
var nextTableName = ""
var nextTableName string
if accessLogTableMainReg.MatchString(lastTableName) {
nextTableName = prefix + "_0001"
} else if accessLogTablePartialReg.MatchString(lastTableName) {

View File

@@ -96,7 +96,7 @@ func (this *HTTPCachePolicyDAO) FindAllEnabledCachePolicies(tx *dbs.Tx) (result
}
// CreateCachePolicy 创建缓存策略
func (this *HTTPCachePolicyDAO) CreateCachePolicy(tx *dbs.Tx, isOn bool, name string, description string, capacityJSON []byte, maxKeys int64, maxSizeJSON []byte, storageType string, storageOptionsJSON []byte, syncCompressionCache bool) (int64, error) {
func (this *HTTPCachePolicyDAO) CreateCachePolicy(tx *dbs.Tx, isOn bool, name string, description string, capacityJSON []byte, maxSizeJSON []byte, storageType string, storageOptionsJSON []byte, syncCompressionCache bool, fetchTimeoutJSON []byte) (int64, error) {
var op = NewHTTPCachePolicyOperator()
op.State = HTTPCachePolicyStateEnabled
op.IsOn = isOn
@@ -105,7 +105,6 @@ func (this *HTTPCachePolicyDAO) CreateCachePolicy(tx *dbs.Tx, isOn bool, name st
if len(capacityJSON) > 0 {
op.Capacity = capacityJSON
}
op.MaxKeys = maxKeys
if len(maxSizeJSON) > 0 {
op.MaxSize = maxSizeJSON
}
@@ -115,6 +114,10 @@ func (this *HTTPCachePolicyDAO) CreateCachePolicy(tx *dbs.Tx, isOn bool, name st
}
op.SyncCompressionCache = syncCompressionCache
if len(fetchTimeoutJSON) > 0 {
op.FetchTimeout = fetchTimeoutJSON
}
// 默认的缓存条件
cacheRef := &serverconfigs.HTTPCacheRef{
IsOn: true,
@@ -184,7 +187,7 @@ func (this *HTTPCachePolicyDAO) CreateDefaultCachePolicy(tx *dbs.Tx, name string
return 0, err
}
policyId, err := this.CreateCachePolicy(tx, true, "\""+name+"\"缓存策略", "默认创建的缓存策略", capacityJSON, 0, maxSizeJSON, serverconfigs.CachePolicyStorageFile, storageOptionsJSON, false)
policyId, err := this.CreateCachePolicy(tx, true, "\""+name+"\"缓存策略", "默认创建的缓存策略", capacityJSON, maxSizeJSON, serverconfigs.CachePolicyStorageFile, storageOptionsJSON, false, nil)
if err != nil {
return 0, err
}
@@ -192,7 +195,7 @@ func (this *HTTPCachePolicyDAO) CreateDefaultCachePolicy(tx *dbs.Tx, name string
}
// UpdateCachePolicy 修改缓存策略
func (this *HTTPCachePolicyDAO) UpdateCachePolicy(tx *dbs.Tx, policyId int64, isOn bool, name string, description string, capacityJSON []byte, maxKeys int64, maxSizeJSON []byte, storageType string, storageOptionsJSON []byte, syncCompressionCache bool) error {
func (this *HTTPCachePolicyDAO) UpdateCachePolicy(tx *dbs.Tx, policyId int64, isOn bool, name string, description string, capacityJSON []byte, maxSizeJSON []byte, storageType string, storageOptionsJSON []byte, syncCompressionCache bool, fetchTimeoutJSON []byte) error {
if policyId <= 0 {
return errors.New("invalid policyId")
}
@@ -205,7 +208,6 @@ func (this *HTTPCachePolicyDAO) UpdateCachePolicy(tx *dbs.Tx, policyId int64, is
if len(capacityJSON) > 0 {
op.Capacity = capacityJSON
}
op.MaxKeys = maxKeys
if len(maxSizeJSON) > 0 {
op.MaxSize = maxSizeJSON
}
@@ -214,6 +216,9 @@ func (this *HTTPCachePolicyDAO) UpdateCachePolicy(tx *dbs.Tx, policyId int64, is
op.Options = storageOptionsJSON
}
op.SyncCompressionCache = syncCompressionCache
if len(fetchTimeoutJSON) > 0 {
op.FetchTimeout = fetchTimeoutJSON
}
err := this.Save(tx, op)
if err != nil {
return err
@@ -239,7 +244,7 @@ func (this *HTTPCachePolicyDAO) ComposeCachePolicy(tx *dbs.Tx, policyId int64, c
if policy == nil {
return nil, nil
}
config := &serverconfigs.HTTPCachePolicy{}
var config = &serverconfigs.HTTPCachePolicy{}
config.Id = int64(policy.Id)
config.IsOn = policy.IsOn
config.Name = policy.Name
@@ -248,7 +253,7 @@ func (this *HTTPCachePolicyDAO) ComposeCachePolicy(tx *dbs.Tx, policyId int64, c
// capacity
if IsNotNull(policy.Capacity) {
capacityConfig := &shared.SizeCapacity{}
var capacityConfig = &shared.SizeCapacity{}
err = json.Unmarshal(policy.Capacity, capacityConfig)
if err != nil {
return nil, err
@@ -256,11 +261,9 @@ func (this *HTTPCachePolicyDAO) ComposeCachePolicy(tx *dbs.Tx, policyId int64, c
config.Capacity = capacityConfig
}
config.MaxKeys = types.Int64(policy.MaxKeys)
// max size
if IsNotNull(policy.MaxSize) {
maxSizeConfig := &shared.SizeCapacity{}
var maxSizeConfig = &shared.SizeCapacity{}
err = json.Unmarshal(policy.MaxSize, maxSizeConfig)
if err != nil {
return nil, err
@@ -272,7 +275,7 @@ func (this *HTTPCachePolicyDAO) ComposeCachePolicy(tx *dbs.Tx, policyId int64, c
// options
if IsNotNull(policy.Options) {
m := map[string]interface{}{}
var m = map[string]any{}
err = json.Unmarshal(policy.Options, &m)
if err != nil {
return nil, errors.Wrap(err)
@@ -282,7 +285,7 @@ func (this *HTTPCachePolicyDAO) ComposeCachePolicy(tx *dbs.Tx, policyId int64, c
// refs
if IsNotNull(policy.Refs) {
refs := []*serverconfigs.HTTPCacheRef{}
var refs = []*serverconfigs.HTTPCacheRef{}
err = json.Unmarshal(policy.Refs, &refs)
if err != nil {
return nil, err
@@ -290,6 +293,16 @@ func (this *HTTPCachePolicyDAO) ComposeCachePolicy(tx *dbs.Tx, policyId int64, c
config.CacheRefs = refs
}
// fetch timeout
if IsNotNull(policy.FetchTimeout) {
var timeoutDuration = &shared.TimeDuration{}
err = json.Unmarshal(policy.FetchTimeout, timeoutDuration)
if err != nil {
return nil, err
}
config.FetchTimeout = timeoutDuration
}
if cacheMap != nil {
cacheMap.Put(cacheKey, config)
}

View File

@@ -2,6 +2,26 @@ package models
import "github.com/iwind/TeaGo/dbs"
const (
HTTPCachePolicyField_Id dbs.FieldName = "id" // ID
HTTPCachePolicyField_AdminId dbs.FieldName = "adminId" // 管理员ID
HTTPCachePolicyField_UserId dbs.FieldName = "userId" // 用户ID
HTTPCachePolicyField_TemplateId dbs.FieldName = "templateId" // 模版ID
HTTPCachePolicyField_IsOn dbs.FieldName = "isOn" // 是否启用
HTTPCachePolicyField_Name dbs.FieldName = "name" // 名称
HTTPCachePolicyField_Capacity dbs.FieldName = "capacity" // 容量数据
HTTPCachePolicyField_MaxKeys dbs.FieldName = "maxKeys" // 最多Key值
HTTPCachePolicyField_MaxSize dbs.FieldName = "maxSize" // 最大缓存内容尺寸
HTTPCachePolicyField_Type dbs.FieldName = "type" // 存储类型
HTTPCachePolicyField_Options dbs.FieldName = "options" // 存储选项
HTTPCachePolicyField_CreatedAt dbs.FieldName = "createdAt" // 创建时间
HTTPCachePolicyField_State dbs.FieldName = "state" // 状态
HTTPCachePolicyField_Description dbs.FieldName = "description" // 描述
HTTPCachePolicyField_Refs dbs.FieldName = "refs" // 默认的缓存设置
HTTPCachePolicyField_SyncCompressionCache dbs.FieldName = "syncCompressionCache" // 是否同步写入压缩缓存
HTTPCachePolicyField_FetchTimeout dbs.FieldName = "fetchTimeout" // 预热超时时间
)
// HTTPCachePolicy HTTP缓存策略
type HTTPCachePolicy struct {
Id uint32 `field:"id"` // ID
@@ -20,25 +40,27 @@ type HTTPCachePolicy struct {
Description string `field:"description"` // 描述
Refs dbs.JSON `field:"refs"` // 默认的缓存设置
SyncCompressionCache uint8 `field:"syncCompressionCache"` // 是否同步写入压缩缓存
FetchTimeout dbs.JSON `field:"fetchTimeout"` // 预热超时时间
}
type HTTPCachePolicyOperator struct {
Id interface{} // ID
AdminId interface{} // 管理员ID
UserId interface{} // 用户ID
TemplateId interface{} // 模版ID
IsOn interface{} // 是否启用
Name interface{} // 名称
Capacity interface{} // 容量数据
MaxKeys interface{} // 最多Key值
MaxSize interface{} // 最大缓存内容尺寸
Type interface{} // 存储类型
Options interface{} // 存储选项
CreatedAt interface{} // 创建时间
State interface{} // 状态
Description interface{} // 描述
Refs interface{} // 默认的缓存设置
SyncCompressionCache interface{} // 是否同步写入压缩缓存
Id any // ID
AdminId any // 管理员ID
UserId any // 用户ID
TemplateId any // 模版ID
IsOn any // 是否启用
Name any // 名称
Capacity any // 容量数据
MaxKeys any // 最多Key值
MaxSize any // 最大缓存内容尺寸
Type any // 存储类型
Options any // 存储选项
CreatedAt any // 创建时间
State any // 状态
Description any // 描述
Refs any // 默认的缓存设置
SyncCompressionCache any // 是否同步写入压缩缓存
FetchTimeout any // 预热超时时间
}
func NewHTTPCachePolicyOperator() *HTTPCachePolicyOperator {

View File

@@ -33,7 +33,7 @@ func init() {
var ticker = time.NewTicker(time.Duration(rands.Int(24, 48)) * time.Hour)
goman.New(func() {
for range ticker.C {
err := SharedHTTPCacheTaskDAO.Clean(nil, 30) // 只保留N天
err := SharedHTTPCacheTaskDAO.CleanDefaultDays(nil, 30) // 只保留N天
if err != nil {
remotelogs.Error("HTTPCacheTaskDAO", "clean expired data failed: "+err.Error())
}
@@ -228,8 +228,8 @@ func (this *HTTPCacheTaskDAO) CheckUserTask(tx *dbs.Tx, userId int64, taskId int
return nil
}
// Clean 清理以往的任务
func (this *HTTPCacheTaskDAO) Clean(tx *dbs.Tx, days int) error {
// CleanDays 清理N天以前的任务
func (this *HTTPCacheTaskDAO) CleanDays(tx *dbs.Tx, days int) error {
if days <= 0 {
days = 30
}
@@ -248,6 +248,23 @@ func (this *HTTPCacheTaskDAO) Clean(tx *dbs.Tx, days int) error {
return err
}
// CleanDefaultDays 清除任务
func (this *HTTPCacheTaskDAO) CleanDefaultDays(tx *dbs.Tx, defaultDays int) error {
databaseConfig, err := SharedSysSettingDAO.ReadDatabaseConfig(tx)
if err != nil {
return err
}
if databaseConfig != nil && databaseConfig.HTTPCacheTask.Clean.Days > 0 {
defaultDays = databaseConfig.HTTPCacheTask.Clean.Days
}
if defaultDays <= 0 {
defaultDays = 30
}
return this.CleanDays(tx, defaultDays)
}
// NotifyChange 发送通知
func (this *HTTPCacheTaskDAO) NotifyChange(tx *dbs.Tx, taskId int64) error {
// TODO

View File

@@ -11,7 +11,7 @@ import (
func TestHTTPCacheTaskDAO_Clean(t *testing.T) {
dbs.NotifyReady()
err := models.SharedHTTPCacheTaskDAO.Clean(nil, 30)
err := models.SharedHTTPCacheTaskDAO.CleanDays(nil, 30)
if err != nil {
t.Fatal(err)
}

View File

@@ -132,7 +132,7 @@ func (this *HTTPFirewallPolicyDAO) CreateFirewallPolicy(tx *dbs.Tx, userId int64
op.Outbound = outboundJSON
}
if userId <= 0 && serverGroupId <=0 && serverId <= 0 {
if userId <= 0 && serverGroupId <= 0 && serverId <= 0 {
// synFlood
var synFloodConfig = firewallconfigs.DefaultSYNFloodConfig()
synFloodJSON, err := json.Marshal(synFloodConfig)
@@ -172,16 +172,18 @@ func (this *HTTPFirewallPolicyDAO) CreateDefaultFirewallPolicy(tx *dbs.Tx, name
// 初始化
var groupCodes = []string{}
templatePolicy := firewallconfigs.HTTPFirewallTemplate()
var templatePolicy = firewallconfigs.HTTPFirewallTemplate()
for _, group := range templatePolicy.AllRuleGroups() {
groupCodes = append(groupCodes, group.Code)
if group.IsOn {
groupCodes = append(groupCodes, group.Code)
}
}
var inboundConfig = &firewallconfigs.HTTPFirewallInboundConfig{IsOn: true}
var outboundConfig = &firewallconfigs.HTTPFirewallOutboundConfig{IsOn: true}
if templatePolicy.Inbound != nil {
for _, group := range templatePolicy.Inbound.Groups {
isOn := lists.ContainsString(groupCodes, group.Code)
var isOn = lists.ContainsString(groupCodes, group.Code)
group.IsOn = isOn
groupId, err := SharedHTTPFirewallRuleGroupDAO.CreateGroupFromConfig(tx, group)
@@ -196,7 +198,7 @@ func (this *HTTPFirewallPolicyDAO) CreateDefaultFirewallPolicy(tx *dbs.Tx, name
}
if templatePolicy.Outbound != nil {
for _, group := range templatePolicy.Outbound.Groups {
isOn := lists.ContainsString(groupCodes, group.Code)
var isOn = lists.ContainsString(groupCodes, group.Code)
group.IsOn = isOn
groupId, err := SharedHTTPFirewallRuleGroupDAO.CreateGroupFromConfig(tx, group)
@@ -277,6 +279,31 @@ func (this *HTTPFirewallPolicyDAO) UpdateFirewallPolicyInbound(tx *dbs.Tx, polic
return this.NotifyUpdate(tx, policyId)
}
// UpdateFirewallPolicyInboundRegion 修改入站封禁区域设置
func (this *HTTPFirewallPolicyDAO) UpdateFirewallPolicyInboundRegion(tx *dbs.Tx, policyId int64, regionConfig *firewallconfigs.HTTPFirewallRegionConfig) error {
var inboundConfig = &firewallconfigs.HTTPFirewallInboundConfig{IsOn: true}
inboundJSON, err := this.Query(tx).
Pk(policyId).
Result("inbound").
FindJSONCol()
if err != nil {
return err
}
if IsNotNull(inboundJSON) {
err = json.Unmarshal(inboundJSON, inboundConfig)
if err != nil {
return err
}
}
inboundConfig.Region = regionConfig
newInboundJSON, err := json.Marshal(inboundConfig)
if err != nil {
return err
}
return this.UpdateFirewallPolicyInbound(tx, policyId, newInboundJSON)
}
// UpdateFirewallPolicy 修改策略
func (this *HTTPFirewallPolicyDAO) UpdateFirewallPolicy(tx *dbs.Tx,
policyId int64,
@@ -290,7 +317,10 @@ func (this *HTTPFirewallPolicyDAO) UpdateFirewallPolicy(tx *dbs.Tx,
mode firewallconfigs.FirewallMode,
useLocalFirewall bool,
synFloodConfig *firewallconfigs.SYNFloodConfig,
logConfig *firewallconfigs.HTTPFirewallPolicyLogConfig) error {
logConfig *firewallconfigs.HTTPFirewallPolicyLogConfig,
maxRequestBodySize int64,
denyCountryHTML string,
denyProvinceHTML string) error {
if policyId <= 0 {
return errors.New("invalid policyId")
}
@@ -338,6 +368,10 @@ func (this *HTTPFirewallPolicyDAO) UpdateFirewallPolicy(tx *dbs.Tx,
}
op.UseLocalFirewall = useLocalFirewall
op.MaxRequestBodySize = maxRequestBodySize
op.DenyCountryHTML = denyCountryHTML
op.DenyProvinceHTML = denyProvinceHTML
err := this.Save(tx, op)
if err != nil {
return err
@@ -390,7 +424,7 @@ func (this *HTTPFirewallPolicyDAO) ListEnabledFirewallPolicies(tx *dbs.Tx, clust
}
// ComposeFirewallPolicy 组合策略配置
func (this *HTTPFirewallPolicyDAO) ComposeFirewallPolicy(tx *dbs.Tx, policyId int64, cacheMap *utils.CacheMap) (*firewallconfigs.HTTPFirewallPolicy, error) {
func (this *HTTPFirewallPolicyDAO) ComposeFirewallPolicy(tx *dbs.Tx, policyId int64, forNode bool, cacheMap *utils.CacheMap) (*firewallconfigs.HTTPFirewallPolicy, error) {
if cacheMap == nil {
cacheMap = utils.NewCacheMap()
}
@@ -414,6 +448,9 @@ func (this *HTTPFirewallPolicyDAO) ComposeFirewallPolicy(tx *dbs.Tx, policyId in
config.Name = policy.Name
config.Description = policy.Description
config.UseLocalFirewall = policy.UseLocalFirewall == 1
config.MaxRequestBodySize = int64(policy.MaxRequestBodySize)
config.DenyCountryHTML = policy.DenyCountryHTML
config.DenyProvinceHTML = policy.DenyProvinceHTML
if len(policy.Mode) == 0 {
policy.Mode = firewallconfigs.FirewallModeDefend
@@ -421,18 +458,18 @@ func (this *HTTPFirewallPolicyDAO) ComposeFirewallPolicy(tx *dbs.Tx, policyId in
config.Mode = policy.Mode
// Inbound
inbound := &firewallconfigs.HTTPFirewallInboundConfig{}
var inbound = &firewallconfigs.HTTPFirewallInboundConfig{}
if IsNotNull(policy.Inbound) {
err = json.Unmarshal(policy.Inbound, inbound)
if err != nil {
return nil, err
}
if len(inbound.GroupRefs) > 0 {
resultGroupRefs := []*firewallconfigs.HTTPFirewallRuleGroupRef{}
resultGroups := []*firewallconfigs.HTTPFirewallRuleGroup{}
var resultGroupRefs = []*firewallconfigs.HTTPFirewallRuleGroupRef{}
var resultGroups = []*firewallconfigs.HTTPFirewallRuleGroup{}
for _, groupRef := range inbound.GroupRefs {
groupConfig, err := SharedHTTPFirewallRuleGroupDAO.ComposeFirewallRuleGroup(tx, groupRef.GroupId)
groupConfig, err := SharedHTTPFirewallRuleGroupDAO.ComposeFirewallRuleGroup(tx, groupRef.GroupId, forNode)
if err != nil {
return nil, err
}
@@ -449,18 +486,18 @@ func (this *HTTPFirewallPolicyDAO) ComposeFirewallPolicy(tx *dbs.Tx, policyId in
config.Inbound = inbound
// Outbound
outbound := &firewallconfigs.HTTPFirewallOutboundConfig{}
var outbound = &firewallconfigs.HTTPFirewallOutboundConfig{}
if IsNotNull(policy.Outbound) {
err = json.Unmarshal(policy.Outbound, outbound)
if err != nil {
return nil, err
}
if len(outbound.GroupRefs) > 0 {
resultGroupRefs := []*firewallconfigs.HTTPFirewallRuleGroupRef{}
resultGroups := []*firewallconfigs.HTTPFirewallRuleGroup{}
var resultGroupRefs = []*firewallconfigs.HTTPFirewallRuleGroupRef{}
var resultGroups = []*firewallconfigs.HTTPFirewallRuleGroup{}
for _, groupRef := range outbound.GroupRefs {
groupConfig, err := SharedHTTPFirewallRuleGroupDAO.ComposeFirewallRuleGroup(tx, groupRef.GroupId)
groupConfig, err := SharedHTTPFirewallRuleGroupDAO.ComposeFirewallRuleGroup(tx, groupRef.GroupId, forNode)
if err != nil {
return nil, err
}
@@ -611,6 +648,10 @@ func (this *HTTPFirewallPolicyDAO) UpdateFirewallPolicyServerId(tx *dbs.Tx, poli
// FindFirewallPolicyIdsWithServerId 查找服务独立关联的策略IDs
func (this *HTTPFirewallPolicyDAO) FindFirewallPolicyIdsWithServerId(tx *dbs.Tx, serverId int64) ([]int64, error) {
if serverId <= 0 {
return nil, nil
}
var result = []int64{}
ones, err := this.Query(tx).
Attr("serverId", serverId).

View File

@@ -2,49 +2,80 @@ package models
import "github.com/iwind/TeaGo/dbs"
const (
HTTPFirewallPolicyField_Id dbs.FieldName = "id" // ID
HTTPFirewallPolicyField_TemplateId dbs.FieldName = "templateId" // 模版ID
HTTPFirewallPolicyField_AdminId dbs.FieldName = "adminId" // 管理员ID
HTTPFirewallPolicyField_UserId dbs.FieldName = "userId" // 用户ID
HTTPFirewallPolicyField_ServerId dbs.FieldName = "serverId" // 服务ID
HTTPFirewallPolicyField_GroupId dbs.FieldName = "groupId" // 服务分组ID
HTTPFirewallPolicyField_State dbs.FieldName = "state" // 状态
HTTPFirewallPolicyField_CreatedAt dbs.FieldName = "createdAt" // 创建时间
HTTPFirewallPolicyField_IsOn dbs.FieldName = "isOn" // 是否启用
HTTPFirewallPolicyField_Name dbs.FieldName = "name" // 名称
HTTPFirewallPolicyField_Description dbs.FieldName = "description" // 描述
HTTPFirewallPolicyField_Inbound dbs.FieldName = "inbound" // 入站规则
HTTPFirewallPolicyField_Outbound dbs.FieldName = "outbound" // 出站规则
HTTPFirewallPolicyField_BlockOptions dbs.FieldName = "blockOptions" // BLOCK选项
HTTPFirewallPolicyField_CaptchaOptions dbs.FieldName = "captchaOptions" // 验证码选项
HTTPFirewallPolicyField_Mode dbs.FieldName = "mode" // 模式
HTTPFirewallPolicyField_UseLocalFirewall dbs.FieldName = "useLocalFirewall" // 是否自动使用本地防火墙
HTTPFirewallPolicyField_SynFlood dbs.FieldName = "synFlood" // SynFlood防御设置
HTTPFirewallPolicyField_Log dbs.FieldName = "log" // 日志配置
HTTPFirewallPolicyField_MaxRequestBodySize dbs.FieldName = "maxRequestBodySize" // 可以检查的最大请求内容尺寸
HTTPFirewallPolicyField_DenyCountryHTML dbs.FieldName = "denyCountryHTML" // 区域封禁提示
HTTPFirewallPolicyField_DenyProvinceHTML dbs.FieldName = "denyProvinceHTML" // 省份封禁提示
)
// HTTPFirewallPolicy HTTP防火墙
type HTTPFirewallPolicy struct {
Id uint32 `field:"id"` // ID
TemplateId uint32 `field:"templateId"` // 模版ID
AdminId uint32 `field:"adminId"` // 管理员ID
UserId uint32 `field:"userId"` // 用户ID
ServerId uint32 `field:"serverId"` // 服务ID
GroupId uint32 `field:"groupId"` // 服务分组ID
State uint8 `field:"state"` // 状态
CreatedAt uint64 `field:"createdAt"` // 创建时间
IsOn bool `field:"isOn"` // 是否启用
Name string `field:"name"` // 名称
Description string `field:"description"` // 描述
Inbound dbs.JSON `field:"inbound"` // 入站规则
Outbound dbs.JSON `field:"outbound"` // 出站规则
BlockOptions dbs.JSON `field:"blockOptions"` // BLOCK选项
CaptchaOptions dbs.JSON `field:"captchaOptions"` // 验证码选项
Mode string `field:"mode"` // 模式
UseLocalFirewall uint8 `field:"useLocalFirewall"` // 是否自动使用本地防火墙
SynFlood dbs.JSON `field:"synFlood"` // SynFlood防御设置
Log dbs.JSON `field:"log"` // 日志配置
Id uint32 `field:"id"` // ID
TemplateId uint32 `field:"templateId"` // 模版ID
AdminId uint32 `field:"adminId"` // 管理员ID
UserId uint32 `field:"userId"` // 用户ID
ServerId uint32 `field:"serverId"` // 服务ID
GroupId uint32 `field:"groupId"` // 服务分组ID
State uint8 `field:"state"` // 状态
CreatedAt uint64 `field:"createdAt"` // 创建时间
IsOn bool `field:"isOn"` // 是否启用
Name string `field:"name"` // 名称
Description string `field:"description"` // 描述
Inbound dbs.JSON `field:"inbound"` // 入站规则
Outbound dbs.JSON `field:"outbound"` // 出站规则
BlockOptions dbs.JSON `field:"blockOptions"` // BLOCK选项
CaptchaOptions dbs.JSON `field:"captchaOptions"` // 验证码选项
Mode string `field:"mode"` // 模式
UseLocalFirewall uint8 `field:"useLocalFirewall"` // 是否自动使用本地防火墙
SynFlood dbs.JSON `field:"synFlood"` // SynFlood防御设置
Log dbs.JSON `field:"log"` // 日志配置
MaxRequestBodySize uint32 `field:"maxRequestBodySize"` // 可以检查的最大请求内容尺寸
DenyCountryHTML string `field:"denyCountryHTML"` // 区域封禁提示
DenyProvinceHTML string `field:"denyProvinceHTML"` // 省份封禁提示
}
type HTTPFirewallPolicyOperator struct {
Id interface{} // ID
TemplateId interface{} // 模版ID
AdminId interface{} // 管理员ID
UserId interface{} // 用户ID
ServerId interface{} // 服务ID
GroupId interface{} // 服务分组ID
State interface{} // 状态
CreatedAt interface{} // 创建时间
IsOn interface{} // 是否启用
Name interface{} // 名称
Description interface{} // 描述
Inbound interface{} // 入站规则
Outbound interface{} // 出站规则
BlockOptions interface{} // BLOCK选项
CaptchaOptions interface{} // 验证码选项
Mode interface{} // 模式
UseLocalFirewall interface{} // 是否自动使用本地防火墙
SynFlood interface{} // SynFlood防御设置
Log interface{} // 日志配置
Id any // ID
TemplateId any // 模版ID
AdminId any // 管理员ID
UserId any // 用户ID
ServerId any // 服务ID
GroupId any // 服务分组ID
State any // 状态
CreatedAt any // 创建时间
IsOn any // 是否启用
Name any // 名称
Description any // 描述
Inbound any // 入站规则
Outbound any // 出站规则
BlockOptions any // BLOCK选项
CaptchaOptions any // 验证码选项
Mode any // 模式
UseLocalFirewall any // 是否自动使用本地防火墙
SynFlood any // SynFlood防御设置
Log any // 日志配置
MaxRequestBodySize any // 可以检查的最大请求内容尺寸
DenyCountryHTML any // 区域封禁提示
DenyProvinceHTML any // 省份封禁提示
}
func NewHTTPFirewallPolicyOperator() *HTTPFirewallPolicyOperator {

View File

@@ -81,7 +81,7 @@ func (this *HTTPFirewallRuleGroupDAO) FindHTTPFirewallRuleGroupName(tx *dbs.Tx,
}
// ComposeFirewallRuleGroup 组合配置
func (this *HTTPFirewallRuleGroupDAO) ComposeFirewallRuleGroup(tx *dbs.Tx, groupId int64) (*firewallconfigs.HTTPFirewallRuleGroup, error) {
func (this *HTTPFirewallRuleGroupDAO) ComposeFirewallRuleGroup(tx *dbs.Tx, groupId int64, forNode bool) (*firewallconfigs.HTTPFirewallRuleGroup, error) {
group, err := this.FindEnabledHTTPFirewallRuleGroup(tx, groupId)
if err != nil {
return nil, err
@@ -89,7 +89,7 @@ func (this *HTTPFirewallRuleGroupDAO) ComposeFirewallRuleGroup(tx *dbs.Tx, group
if group == nil {
return nil, nil
}
config := &firewallconfigs.HTTPFirewallRuleGroup{}
var config = &firewallconfigs.HTTPFirewallRuleGroup{}
config.Id = int64(group.Id)
config.IsOn = group.IsOn
config.Name = group.Name
@@ -98,17 +98,17 @@ func (this *HTTPFirewallRuleGroupDAO) ComposeFirewallRuleGroup(tx *dbs.Tx, group
config.IsTemplate = group.IsTemplate
if IsNotNull(group.Sets) {
setRefs := []*firewallconfigs.HTTPFirewallRuleSetRef{}
var setRefs = []*firewallconfigs.HTTPFirewallRuleSetRef{}
err = json.Unmarshal(group.Sets, &setRefs)
if err != nil {
return nil, err
}
for _, setRef := range setRefs {
setConfig, err := SharedHTTPFirewallRuleSetDAO.ComposeFirewallRuleSet(tx, setRef.SetId)
setConfig, err := SharedHTTPFirewallRuleSetDAO.ComposeFirewallRuleSet(tx, setRef.SetId, forNode)
if err != nil {
return nil, err
}
if setConfig != nil {
if setConfig != nil && (!forNode || setConfig.IsOn) {
config.SetRefs = append(config.SetRefs, setRef)
config.Sets = append(config.Sets, setConfig)
}

View File

@@ -84,7 +84,7 @@ func (this *HTTPFirewallRuleSetDAO) FindHTTPFirewallRuleSetName(tx *dbs.Tx, id i
}
// ComposeFirewallRuleSet 组合配置
func (this *HTTPFirewallRuleSetDAO) ComposeFirewallRuleSet(tx *dbs.Tx, setId int64) (*firewallconfigs.HTTPFirewallRuleSet, error) {
func (this *HTTPFirewallRuleSetDAO) ComposeFirewallRuleSet(tx *dbs.Tx, setId int64, forNode bool) (*firewallconfigs.HTTPFirewallRuleSet, error) {
set, err := this.FindEnabledHTTPFirewallRuleSet(tx, setId)
if err != nil {
return nil, err
@@ -92,7 +92,7 @@ func (this *HTTPFirewallRuleSetDAO) ComposeFirewallRuleSet(tx *dbs.Tx, setId int
if set == nil {
return nil, nil
}
config := &firewallconfigs.HTTPFirewallRuleSet{}
var config = &firewallconfigs.HTTPFirewallRuleSet{}
config.Id = int64(set.Id)
config.IsOn = set.IsOn
config.Name = set.Name
@@ -102,7 +102,7 @@ func (this *HTTPFirewallRuleSetDAO) ComposeFirewallRuleSet(tx *dbs.Tx, setId int
config.IgnoreLocal = set.IgnoreLocal == 1
if IsNotNull(set.Rules) {
ruleRefs := []*firewallconfigs.HTTPFirewallRuleRef{}
var ruleRefs = []*firewallconfigs.HTTPFirewallRuleRef{}
err = json.Unmarshal(set.Rules, &ruleRefs)
if err != nil {
return nil, err
@@ -128,6 +128,29 @@ func (this *HTTPFirewallRuleSetDAO) ComposeFirewallRuleSet(tx *dbs.Tx, setId int
config.Actions = actionConfigs
}
// 检查各个选项
for _, actionConfig := range actionConfigs {
if actionConfig.Code == firewallconfigs.HTTPFirewallActionRecordIP { // 记录IP动作
if actionConfig.Options != nil {
var ipListId = actionConfig.Options.GetInt64("ipListId")
if ipListId <= 0 { // default list id
if forNode {
actionConfig.Options["ipListId"] = firewallconfigs.GlobalListId
}
actionConfig.Options["ipListIsDeleted"] = false
} else {
exists, err := SharedIPListDAO.ExistsEnabledIPList(tx, ipListId)
if err != nil {
return nil, err
}
if !exists {
actionConfig.Options["ipListIsDeleted"] = true
}
}
}
}
}
return config, nil
}
@@ -212,6 +235,28 @@ func (this *HTTPFirewallRuleSetDAO) FindEnabledRuleSetIdWithRuleId(tx *dbs.Tx, r
FindInt64Col(0)
}
// FindAllEnabledRuleSetIdsWithIPListId 根据IP名单ID查找对应动作的WAF规则集
func (this *HTTPFirewallRuleSetDAO) FindAllEnabledRuleSetIdsWithIPListId(tx *dbs.Tx, ipListId int64) (setIds []int64, err error) {
ones, err := this.Query(tx).
State(HTTPFirewallRuleStateEnabled).
Where("JSON_CONTAINS(actions, :jsonQuery)").
Param("jsonQuery", maps.Map{
"code": firewallconfigs.HTTPFirewallActionRecordIP,
"options": maps.Map{
"ipListId": ipListId,
},
}.AsJSON()).
ResultPk().
FindAll()
if err != nil {
return nil, err
}
for _, one := range ones {
setIds = append(setIds, int64(one.(*HTTPFirewallRuleSet).Id))
}
return
}
// CheckUserRuleSet 检查用户
func (this *HTTPFirewallRuleSetDAO) CheckUserRuleSet(tx *dbs.Tx, userId int64, setId int64) error {
groupId, err := SharedHTTPFirewallRuleGroupDAO.FindRuleGroupIdWithRuleSetId(tx, setId)

View File

@@ -157,6 +157,9 @@ func (this *HTTPHeaderPolicyDAO) UpdateDeletingHeaders(tx *dbs.Tx, policyId int6
return errors.New("invalid policyId")
}
if headerNames == nil {
headerNames = []string{}
}
namesJSON, err := json.Marshal(headerNames)
if err != nil {
return err
@@ -164,7 +167,31 @@ func (this *HTTPHeaderPolicyDAO) UpdateDeletingHeaders(tx *dbs.Tx, policyId int6
var op = NewHTTPHeaderPolicyOperator()
op.Id = policyId
op.DeleteHeaders = string(namesJSON)
op.DeleteHeaders = namesJSON
err = this.Save(tx, op)
if err != nil {
return err
}
return this.NotifyUpdate(tx, policyId)
}
// UpdateNonStandardHeaders 修改非标Headers
func (this *HTTPHeaderPolicyDAO) UpdateNonStandardHeaders(tx *dbs.Tx, policyId int64, headerNames []string) error {
if policyId <= 0 {
return errors.New("invalid policyId")
}
if headerNames == nil {
headerNames = []string{}
}
namesJSON, err := json.Marshal(headerNames)
if err != nil {
return err
}
var op = NewHTTPHeaderPolicyOperator()
op.Id = policyId
op.NonStandardHeaders = namesJSON
err = this.Save(tx, op)
if err != nil {
return err
@@ -220,9 +247,19 @@ func (this *HTTPHeaderPolicyDAO) ComposeHeaderPolicyConfig(tx *dbs.Tx, headerPol
config.DeleteHeaders = headers
}
// Non-Standard Headers
if IsNotNull(policy.NonStandardHeaders) {
var headers = []string{}
err = json.Unmarshal(policy.NonStandardHeaders, &headers)
if err != nil {
return nil, err
}
config.NonStandardHeaders = headers
}
// CORS
if IsNotNull(policy.Cors) {
var corsConfig = &shared.HTTPCORSHeaderConfig{}
var corsConfig = shared.NewHTTPCORSHeaderConfig()
err = json.Unmarshal(policy.Cors, corsConfig)
if err != nil {
return nil, err

View File

@@ -4,35 +4,37 @@ import "github.com/iwind/TeaGo/dbs"
// HTTPHeaderPolicy Header定义
type HTTPHeaderPolicy struct {
Id uint32 `field:"id"` // ID
IsOn bool `field:"isOn"` // 是否启用
State uint8 `field:"state"` // 状态
AdminId uint32 `field:"adminId"` // 管理员ID
UserId uint32 `field:"userId"` // 用户ID
CreatedAt uint64 `field:"createdAt"` // 创建时间
AddHeaders dbs.JSON `field:"addHeaders"` // 添加的Header
AddTrailers dbs.JSON `field:"addTrailers"` // 添加的Trailers
SetHeaders dbs.JSON `field:"setHeaders"` // 设置Header
ReplaceHeaders dbs.JSON `field:"replaceHeaders"` // 替换Header内容
Expires dbs.JSON `field:"expires"` // Expires单独设置
DeleteHeaders dbs.JSON `field:"deleteHeaders"` // 删除的Headers
Cors dbs.JSON `field:"cors"` // CORS配置
Id uint32 `field:"id"` // ID
IsOn bool `field:"isOn"` // 是否启用
State uint8 `field:"state"` // 状态
AdminId uint32 `field:"adminId"` // 管理员ID
UserId uint32 `field:"userId"` // 用户ID
CreatedAt uint64 `field:"createdAt"` // 创建时间
AddHeaders dbs.JSON `field:"addHeaders"` // 添加的Header
AddTrailers dbs.JSON `field:"addTrailers"` // 添加的Trailers
SetHeaders dbs.JSON `field:"setHeaders"` // 设置Header
ReplaceHeaders dbs.JSON `field:"replaceHeaders"` // 替换Header内容
Expires dbs.JSON `field:"expires"` // Expires单独设置
DeleteHeaders dbs.JSON `field:"deleteHeaders"` // 删除的Headers
NonStandardHeaders dbs.JSON `field:"nonStandardHeaders"` // 非标Headers
Cors dbs.JSON `field:"cors"` // CORS配置
}
type HTTPHeaderPolicyOperator struct {
Id any // ID
IsOn any // 是否启用
State any // 状态
AdminId any // 管理员ID
UserId any // 用户ID
CreatedAt any // 创建时间
AddHeaders any // 添加的Header
AddTrailers any // 添加的Trailers
SetHeaders any // 设置Header
ReplaceHeaders any // 替换Header内容
Expires any // Expires单独设置
DeleteHeaders any // 删除的Headers
Cors any // CORS配置
Id any // ID
IsOn any // 是否启用
State any // 状态
AdminId any // 管理员ID
UserId any // 用户ID
CreatedAt any // 创建时间
AddHeaders any // 添加的Header
AddTrailers any // 添加的Trailers
SetHeaders any // 设置Header
ReplaceHeaders any // 替换Header内容
Expires any // Expires单独设置
DeleteHeaders any // 删除的Headers
NonStandardHeaders any // 非标Headers
Cors any // CORS配置
}
func NewHTTPHeaderPolicyOperator() *HTTPHeaderPolicyOperator {

View File

@@ -124,8 +124,9 @@ func (this *HTTPRewriteRuleDAO) ComposeRewriteRule(tx *dbs.Tx, rewriteRuleId int
}
// CreateRewriteRule 创建规则
func (this *HTTPRewriteRuleDAO) CreateRewriteRule(tx *dbs.Tx, pattern string, replace string, mode string, redirectStatus int, isBreak bool, proxyHost string, withQuery bool, isOn bool, condsJSON []byte) (int64, error) {
func (this *HTTPRewriteRuleDAO) CreateRewriteRule(tx *dbs.Tx, userId int64, pattern string, replace string, mode string, redirectStatus int, isBreak bool, proxyHost string, withQuery bool, isOn bool, condsJSON []byte) (int64, error) {
var op = NewHTTPRewriteRuleOperator()
op.UserId = userId
op.State = HTTPRewriteRuleStateEnabled
op.IsOn = isOn
@@ -172,6 +173,34 @@ func (this *HTTPRewriteRuleDAO) UpdateRewriteRule(tx *dbs.Tx, rewriteRuleId int6
return this.NotifyUpdate(tx, rewriteRuleId)
}
func (this *HTTPRewriteRuleDAO) CheckUserRewriteRule(tx *dbs.Tx, userId int64, rewriteRuleId int64) error {
if rewriteRuleId <= 0 {
return ErrNotFound
}
exists, err := this.Query(tx).
Pk(rewriteRuleId).
Attr("userId", userId).
Exist()
if err != nil {
return err
}
if !exists {
return ErrNotFound
}
webId, err := SharedHTTPWebDAO.FindEnabledWebIdWithRewriteRuleId(tx, rewriteRuleId)
if err != nil {
return err
}
if webId <= 0 {
return ErrNotFound
}
return SharedHTTPWebDAO.CheckUserWeb(tx, userId, webId)
}
// NotifyUpdate 通知更新
func (this *HTTPRewriteRuleDAO) NotifyUpdate(tx *dbs.Tx, rewriteRuleId int64) error {
webId, err := SharedHTTPWebDAO.FindEnabledWebIdWithRewriteRuleId(tx, rewriteRuleId)

View File

@@ -101,7 +101,7 @@ func (this *HTTPWebDAO) ComposeWebConfig(tx *dbs.Tx, webId int64, isLocationOrGr
// root
if IsNotNull(web.Root) {
var rootConfig = &serverconfigs.HTTPRootConfig{}
var rootConfig = serverconfigs.NewHTTPRootConfig()
err = json.Unmarshal(web.Root, rootConfig)
if err != nil {
return nil, err
@@ -151,6 +151,18 @@ func (this *HTTPWebDAO) ComposeWebConfig(tx *dbs.Tx, webId int64, isLocationOrGr
}
}
// Optimization
if IsNotNull(web.Optimization) {
var optimizationConfig = serverconfigs.NewHTTPPageOptimizationConfig()
err = json.Unmarshal(web.Optimization, optimizationConfig)
if err != nil {
return nil, err
}
if this.shouldCompose(isLocationOrGroup, forNode, optimizationConfig.IsPrior, true) {
config.Optimization = optimizationConfig
}
}
// charset
if IsNotNull(web.Charset) {
var charsetConfig = &serverconfigs.HTTPCharsetConfig{}
@@ -289,7 +301,7 @@ func (this *HTTPWebDAO) ComposeWebConfig(tx *dbs.Tx, webId int64, isLocationOrGr
// 自定义防火墙设置
if firewallRef.FirewallPolicyId > 0 {
firewallPolicy, err := SharedHTTPFirewallPolicyDAO.ComposeFirewallPolicy(tx, firewallRef.FirewallPolicyId, cacheMap)
firewallPolicy, err := SharedHTTPFirewallPolicyDAO.ComposeFirewallPolicy(tx, firewallRef.FirewallPolicyId, forNode, cacheMap)
if err != nil {
return nil, err
}
@@ -507,12 +519,20 @@ func (this *HTTPWebDAO) ComposeWebConfig(tx *dbs.Tx, webId int64, isLocationOrGr
}
if this.shouldCompose(isLocationOrGroup, forNode, ccConfig.IsPrior, ccConfig.IsOn) {
config.CC = ccConfig
if forNode {
for index, threshold := range ccConfig.Thresholds {
if index < len(serverconfigs.DefaultHTTPCCThresholds) {
threshold.MergeIfEmpty(serverconfigs.DefaultHTTPCCThresholds[index])
}
}
}
}
}
// Referers
if IsNotNull(web.Referers) {
var referersConfig = &serverconfigs.ReferersConfig{}
var referersConfig = serverconfigs.NewReferersConfig()
err = json.Unmarshal(web.Referers, referersConfig)
if err != nil {
return nil, err
@@ -550,7 +570,21 @@ func (this *HTTPWebDAO) CreateWeb(tx *dbs.Tx, adminId int64, userId int64, rootJ
if len(rootJSON) > 0 {
op.Root = JSONBytes(rootJSON)
}
err := this.Save(tx, op)
// 设置默认的remote-addr
// set default remote-addr config
var remoteAddrConfig = &serverconfigs.HTTPRemoteAddrConfig{
IsOn: true,
Value: "${rawRemoteAddr}",
Type: serverconfigs.HTTPRemoteAddrTypeDefault,
}
remoteAddrConfigJSON, err := json.Marshal(remoteAddrConfig)
if err != nil {
return 0, err
}
op.RemoteAddr = remoteAddrConfigJSON
err = this.Save(tx, op)
if err != nil {
return 0, err
}
@@ -574,14 +608,42 @@ func (this *HTTPWebDAO) UpdateWeb(tx *dbs.Tx, webId int64, rootJSON []byte) erro
}
// UpdateWebCompression 修改压缩配置
func (this *HTTPWebDAO) UpdateWebCompression(tx *dbs.Tx, webId int64, compressionConfig []byte) error {
func (this *HTTPWebDAO) UpdateWebCompression(tx *dbs.Tx, webId int64, compressionConfig *serverconfigs.HTTPCompressionConfig) error {
if webId <= 0 {
return errors.New("invalid webId")
}
compressionJSON, err := json.Marshal(compressionConfig)
if err != nil {
return err
}
var op = NewHTTPWebOperator()
op.Id = webId
op.Compression = JSONBytes(compressionConfig)
err := this.Save(tx, op)
op.Compression = compressionJSON
err = this.Save(tx, op)
if err != nil {
return err
}
return this.NotifyUpdate(tx, webId)
}
// UpdateWebOptimization 修改页面优化配置
func (this *HTTPWebDAO) UpdateWebOptimization(tx *dbs.Tx, webId int64, optimizationConfig *serverconfigs.HTTPPageOptimizationConfig) error {
if webId <= 0 {
return errors.New("invalid webId")
}
optimizationJSON, err := json.Marshal(optimizationConfig)
if err != nil {
return err
}
var op = NewHTTPWebOperator()
op.Id = webId
op.Optimization = optimizationJSON
err = this.Save(tx, op)
if err != nil {
return err
}

View File

@@ -2,6 +2,47 @@ package models
import "github.com/iwind/TeaGo/dbs"
const (
HTTPWebField_Id dbs.FieldName = "id" // ID
HTTPWebField_IsOn dbs.FieldName = "isOn" // 是否启用
HTTPWebField_TemplateId dbs.FieldName = "templateId" // 模版ID
HTTPWebField_AdminId dbs.FieldName = "adminId" // 管理员ID
HTTPWebField_UserId dbs.FieldName = "userId" // 用户ID
HTTPWebField_State dbs.FieldName = "state" // 状态
HTTPWebField_CreatedAt dbs.FieldName = "createdAt" // 创建时间
HTTPWebField_Root dbs.FieldName = "root" // 根目录
HTTPWebField_Charset dbs.FieldName = "charset" // 字符集
HTTPWebField_Shutdown dbs.FieldName = "shutdown" // 临时关闭页面配置
HTTPWebField_Pages dbs.FieldName = "pages" // 特殊页面
HTTPWebField_RedirectToHttps dbs.FieldName = "redirectToHttps" // 跳转到HTTPS设置
HTTPWebField_Indexes dbs.FieldName = "indexes" // 首页文件列表
HTTPWebField_MaxRequestBodySize dbs.FieldName = "maxRequestBodySize" // 最大允许的请求内容尺寸
HTTPWebField_RequestHeader dbs.FieldName = "requestHeader" // 请求Header配置
HTTPWebField_ResponseHeader dbs.FieldName = "responseHeader" // 响应Header配置
HTTPWebField_AccessLog dbs.FieldName = "accessLog" // 访问日志配置
HTTPWebField_Stat dbs.FieldName = "stat" // 统计配置
HTTPWebField_Gzip dbs.FieldName = "gzip" // Gzip配置v0.3.2弃用)
HTTPWebField_Compression dbs.FieldName = "compression" // 压缩配置
HTTPWebField_Cache dbs.FieldName = "cache" // 缓存配置
HTTPWebField_Firewall dbs.FieldName = "firewall" // 防火墙设置
HTTPWebField_Locations dbs.FieldName = "locations" // 路由规则配置
HTTPWebField_Websocket dbs.FieldName = "websocket" // Websocket设置
HTTPWebField_RewriteRules dbs.FieldName = "rewriteRules" // 重写规则配置
HTTPWebField_HostRedirects dbs.FieldName = "hostRedirects" // 域名跳转
HTTPWebField_Fastcgi dbs.FieldName = "fastcgi" // Fastcgi配置
HTTPWebField_Auth dbs.FieldName = "auth" // 认证策略配置
HTTPWebField_Webp dbs.FieldName = "webp" // WebP配置
HTTPWebField_RemoteAddr dbs.FieldName = "remoteAddr" // 客户端IP配置
HTTPWebField_MergeSlashes dbs.FieldName = "mergeSlashes" // 是否合并路径中的斜杠
HTTPWebField_RequestLimit dbs.FieldName = "requestLimit" // 请求限制
HTTPWebField_RequestScripts dbs.FieldName = "requestScripts" // 请求脚本
HTTPWebField_Uam dbs.FieldName = "uam" // UAM设置
HTTPWebField_Cc dbs.FieldName = "cc" // CC设置
HTTPWebField_Referers dbs.FieldName = "referers" // 防盗链设置
HTTPWebField_UserAgent dbs.FieldName = "userAgent" // UserAgent设置
HTTPWebField_Optimization dbs.FieldName = "optimization" // 页面优化配置
)
// HTTPWeb HTTP Web
type HTTPWeb struct {
Id uint32 `field:"id"` // ID
@@ -41,6 +82,7 @@ type HTTPWeb struct {
Cc dbs.JSON `field:"cc"` // CC设置
Referers dbs.JSON `field:"referers"` // 防盗链设置
UserAgent dbs.JSON `field:"userAgent"` // UserAgent设置
Optimization dbs.JSON `field:"optimization"` // 页面优化配置
}
type HTTPWebOperator struct {
@@ -81,6 +123,7 @@ type HTTPWebOperator struct {
Cc any // CC设置
Referers any // 防盗链设置
UserAgent any // UserAgent设置
Optimization any // 页面优化配置
}
func NewHTTPWebOperator() *HTTPWebOperator {

View File

@@ -14,6 +14,7 @@ import (
"github.com/iwind/TeaGo/lists"
"github.com/iwind/TeaGo/types"
"math"
"net"
"time"
)
@@ -82,8 +83,11 @@ func (this *IPItemDAO) DisableIPItem(tx *dbs.Tx, id int64, sourceUserId int64) e
}
var query = this.Query(tx)
// 检查权限
if sourceUserId > 0 {
query.Attr("sourceUserId", sourceUserId)
query.Where("(sourceUserId=:sourceUserId OR listId IN (SELECT id FROM " + SharedIPListDAO.Table + " WHERE userId=:sourceUserId AND state=1))")
query.Param("sourceUserId", sourceUserId)
}
_, err = query.
@@ -365,7 +369,9 @@ func (this *IPItemDAO) CountIPItemsWithListId(tx *dbs.Tx, listId int64, sourceUs
State(IPItemStateEnabled).
Attr("listId", listId)
if sourceUserId > 0 {
query.Attr("sourceUserId", sourceUserId)
if listId <= 0 || listId == firewallconfigs.GlobalListId {
query.Attr("sourceUserId", sourceUserId)
}
}
if len(keyword) > 0 {
query.Where("(ipFrom LIKE :keyword OR ipTo LIKE :keyword)").
@@ -389,7 +395,9 @@ func (this *IPItemDAO) ListIPItemsWithListId(tx *dbs.Tx, listId int64, sourceUse
State(IPItemStateEnabled).
Attr("listId", listId)
if sourceUserId > 0 {
query.Attr("sourceUserId", sourceUserId)
if listId <= 0 || listId == firewallconfigs.GlobalListId {
query.Attr("sourceUserId", sourceUserId)
}
}
if len(keyword) > 0 {
query.Where("(ipFrom LIKE :keyword OR ipTo LIKE :keyword)").
@@ -416,10 +424,10 @@ func (this *IPItemDAO) ListIPItemsWithListId(tx *dbs.Tx, listId int64, sourceUse
// ListIPItemsAfterVersion 根据版本号查找IP列表
func (this *IPItemDAO) ListIPItemsAfterVersion(tx *dbs.Tx, version int64, size int64) (result []*IPItem, err error) {
_, err = this.Query(tx).
UseIndex("version").
// 这里不要设置状态参数,因为我们要知道哪些是删除的
Gt("version", version).
Asc("version").
Asc("id").
Limit(size).
Slice(&result).
FindAll()
@@ -482,11 +490,20 @@ func (this *IPItemDAO) ExistsEnabledItem(tx *dbs.Tx, itemId int64) (bool, error)
func (this *IPItemDAO) CountAllEnabledIPItems(tx *dbs.Tx, sourceUserId int64, keyword string, ip string, listId int64, unread bool, eventLevel string, listType string) (int64, error) {
var query = this.Query(tx)
if sourceUserId > 0 {
query.Attr("sourceUserId", sourceUserId)
query.UseIndex("sourceUserId")
if listId <= 0 {
query.Where("((listId=" + types.String(firewallconfigs.GlobalListId) + " AND sourceUserId=:sourceUserId) OR listId IN (SELECT id FROM " + SharedIPListDAO.Table + " WHERE userId=:sourceUserId AND state=1))")
query.Param("sourceUserId", sourceUserId)
} else if listId == firewallconfigs.GlobalListId {
query.Attr("sourceUserId", sourceUserId)
query.UseIndex("sourceUserId")
}
}
if len(keyword) > 0 {
query.Like("ipFrom", dbutils.QuoteLike(keyword))
if net.ParseIP(keyword) != nil { // 是一个IP地址
query.Attr("ipFrom", keyword)
} else {
query.Like("ipFrom", dbutils.QuoteLike(keyword))
}
}
if len(ip) > 0 {
query.Attr("ipFrom", ip)
@@ -519,11 +536,20 @@ func (this *IPItemDAO) CountAllEnabledIPItems(tx *dbs.Tx, sourceUserId int64, ke
func (this *IPItemDAO) ListAllEnabledIPItems(tx *dbs.Tx, sourceUserId int64, keyword string, ip string, listId int64, unread bool, eventLevel string, listType string, offset int64, size int64) (result []*IPItem, err error) {
var query = this.Query(tx)
if sourceUserId > 0 {
query.Attr("sourceUserId", sourceUserId)
query.UseIndex("sourceUserId")
if listId <= 0 {
query.Where("((listId=" + types.String(firewallconfigs.GlobalListId) + " AND sourceUserId=:sourceUserId) OR listId IN (SELECT id FROM " + SharedIPListDAO.Table + " WHERE userId=:sourceUserId AND state=1))")
query.Param("sourceUserId", sourceUserId)
} else if listId == firewallconfigs.GlobalListId {
query.Attr("sourceUserId", sourceUserId)
query.UseIndex("sourceUserId")
}
}
if len(keyword) > 0 {
query.Like("ipFrom", dbutils.QuoteLike(keyword))
if net.ParseIP(keyword) != nil { // 是一个IP地址
query.Attr("ipFrom", keyword)
} else {
query.Like("ipFrom", dbutils.QuoteLike(keyword))
}
}
if len(ip) > 0 {
query.Attr("ipFrom", ip)
@@ -648,6 +674,9 @@ func (this *IPItemDAO) NotifyUpdate(tx *dbs.Tx, itemId int64) error {
}
} else {
clusterIds, err := SharedNodeClusterDAO.FindAllEnabledNodeClusterIds(tx)
if err != nil {
return err
}
for _, clusterId := range clusterIds {
err = SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleNode, clusterId, 0, 0, NodeTaskTypeIPItemChanged)
if err != nil {

View File

@@ -3,6 +3,7 @@ package models
import (
"encoding/json"
"errors"
"fmt"
"github.com/TeaOSLab/EdgeAPI/internal/db/models/regions"
"github.com/TeaOSLab/EdgeAPI/internal/utils"
"github.com/TeaOSLab/EdgeCommon/pkg/iplibrary"
@@ -299,7 +300,7 @@ func (this *IPLibraryFileDAO) GenerateIPLibrary(tx *dbs.Tx, libraryFileId int64)
var libraryFile = one.(*IPLibraryFile)
template, err := iplibrary.NewTemplate(libraryFile.Template)
if err != nil {
return errors.New("create template from '" + libraryFile.Template + "' failed: " + err.Error())
return fmt.Errorf("create template from '%s' failed: %w", libraryFile.Template, err)
}
var fileId = int64(libraryFile.FileId)
@@ -314,17 +315,17 @@ func (this *IPLibraryFileDAO) GenerateIPLibrary(tx *dbs.Tx, libraryFileId int64)
if os.IsNotExist(err) {
err = os.Mkdir(dir, 0777)
if err != nil {
return errors.New("can not open dir '" + dir + "' to write: " + err.Error())
return fmt.Errorf("can not open dir '%s' to write: %w", dir, err)
}
} else {
return errors.New("can not open dir '" + dir + "' to write: " + err.Error())
return fmt.Errorf("can not open dir '%s' to write: %w", dir, err)
}
} else if !stat.IsDir() {
_ = os.Remove(dir)
err = os.Mkdir(dir, 0777)
if err != nil {
return errors.New("can not open dir '" + dir + "' to write: " + err.Error())
return fmt.Errorf("can not open dir '%s' to write: %w", dir, err)
}
}
@@ -339,7 +340,7 @@ func (this *IPLibraryFileDAO) GenerateIPLibrary(tx *dbs.Tx, libraryFileId int64)
var countries = []*iplibrary.Country{}
for _, country := range dbCountries {
countries = append(countries, &iplibrary.Country{
Id: types.Uint16(country.Id),
Id: types.Uint16(country.ValueId),
Name: country.DisplayName(),
Codes: country.AllCodes(),
})
@@ -354,7 +355,7 @@ func (this *IPLibraryFileDAO) GenerateIPLibrary(tx *dbs.Tx, libraryFileId int64)
var provinces = []*iplibrary.Province{}
for _, province := range dbProvinces {
provinces = append(provinces, &iplibrary.Province{
Id: types.Uint16(province.Id),
Id: types.Uint16(province.ValueId),
Name: province.DisplayName(),
Codes: province.AllCodes(),
})
@@ -369,7 +370,7 @@ func (this *IPLibraryFileDAO) GenerateIPLibrary(tx *dbs.Tx, libraryFileId int64)
var cities = []*iplibrary.City{}
for _, city := range dbCities {
cities = append(cities, &iplibrary.City{
Id: city.Id,
Id: city.ValueId,
Name: city.DisplayName(),
Codes: city.AllCodes(),
})
@@ -384,7 +385,7 @@ func (this *IPLibraryFileDAO) GenerateIPLibrary(tx *dbs.Tx, libraryFileId int64)
var towns = []*iplibrary.Town{}
for _, town := range dbTowns {
towns = append(towns, &iplibrary.Town{
Id: town.Id,
Id: town.ValueId,
Name: town.DisplayName(),
Codes: town.AllCodes(),
})
@@ -399,7 +400,7 @@ func (this *IPLibraryFileDAO) GenerateIPLibrary(tx *dbs.Tx, libraryFileId int64)
var providers = []*iplibrary.Provider{}
for _, provider := range dbProviders {
providers = append(providers, &iplibrary.Provider{
Id: types.Uint16(provider.Id),
Id: types.Uint16(provider.ValueId),
Name: provider.DisplayName(),
Codes: provider.AllCodes(),
})
@@ -428,7 +429,7 @@ func (this *IPLibraryFileDAO) GenerateIPLibrary(tx *dbs.Tx, libraryFileId int64)
err = writer.WriteMeta()
if err != nil {
return errors.New("write meta failed: " + err.Error())
return fmt.Errorf("write meta failed: %w", err)
}
chunkIds, err := SharedFileChunkDAO.FindAllFileChunkIds(tx, fileId)
@@ -440,35 +441,35 @@ func (this *IPLibraryFileDAO) GenerateIPLibrary(tx *dbs.Tx, libraryFileId int64)
var countryMap = map[string]int64{} // countryName => countryId
for _, country := range dbCountries {
for _, code := range country.AllCodes() {
countryMap[code] = int64(country.Id)
countryMap[code] = int64(country.ValueId)
}
}
var provinceMap = map[string]int64{} // countryId_provinceName => provinceId
for _, province := range dbProvinces {
for _, code := range province.AllCodes() {
provinceMap[types.String(province.CountryId)+"_"+code] = int64(province.Id)
provinceMap[types.String(province.CountryId)+"_"+code] = int64(province.ValueId)
}
}
var cityMap = map[string]int64{} // provinceId_cityName => cityId
for _, city := range dbCities {
for _, code := range city.AllCodes() {
cityMap[types.String(city.ProvinceId)+"_"+code] = int64(city.Id)
cityMap[types.String(city.ProvinceId)+"_"+code] = int64(city.ValueId)
}
}
var townMap = map[string]int64{} // cityId_townName => townId
for _, town := range dbTowns {
for _, code := range town.AllCodes() {
townMap[types.String(town.CityId)+"_"+code] = int64(town.Id)
townMap[types.String(town.CityId)+"_"+code] = int64(town.ValueId)
}
}
var providerMap = map[string]int64{} // providerName => providerId
for _, provider := range dbProviders {
for _, code := range provider.AllCodes() {
providerMap[code] = int64(provider.Id)
providerMap[code] = int64(provider.ValueId)
}
}
@@ -503,7 +504,7 @@ func (this *IPLibraryFileDAO) GenerateIPLibrary(tx *dbs.Tx, libraryFileId int64)
err = writer.Write(ipFrom, ipTo, countryId, provinceId, cityId, townId, providerId)
if err != nil {
return errors.New("write failed: " + err.Error())
return fmt.Errorf("write failed: %w", err)
}
return nil
@@ -536,7 +537,7 @@ func (this *IPLibraryFileDAO) GenerateIPLibrary(tx *dbs.Tx, libraryFileId int64)
// 将生成的内容写入到文件
stat, err = os.Stat(filePath)
if err != nil {
return errors.New("stat generated file failed: " + err.Error())
return fmt.Errorf("stat generated file failed: %w", err)
}
generatedFileId, err := SharedFileDAO.CreateFile(tx, 0, 0, "ipLibraryFile", "", libraryCode+".db", stat.Size(), "", false)
if err != nil {
@@ -545,7 +546,7 @@ func (this *IPLibraryFileDAO) GenerateIPLibrary(tx *dbs.Tx, libraryFileId int64)
fp, err := os.Open(filePath)
if err != nil {
return errors.New("open generated file failed: " + err.Error())
return fmt.Errorf("open generated file failed: %w", err)
}
var buf = make([]byte, 256*1024)
for {

View File

@@ -11,6 +11,7 @@ import (
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/lists"
"github.com/iwind/TeaGo/maps"
"github.com/iwind/TeaGo/types"
)
@@ -61,12 +62,16 @@ func (this *IPListDAO) EnableIPList(tx *dbs.Tx, id int64) error {
}
// DisableIPList 禁用条目
func (this *IPListDAO) DisableIPList(tx *dbs.Tx, id int64) error {
func (this *IPListDAO) DisableIPList(tx *dbs.Tx, listId int64) error {
_, err := this.Query(tx).
Pk(id).
Pk(listId).
Set("state", IPListStateDisabled).
Update()
return err
if err != nil {
return err
}
return this.NotifyUpdate(tx, listId, NodeTaskTypeIPListDeleted+"@"+string(maps.Map{"listId": listId}.AsJSON()))
}
// FindEnabledIPList 查找启用中的条目
@@ -258,11 +263,35 @@ func (this *IPListDAO) ExistsEnabledIPList(tx *dbs.Tx, listId int64) (bool, erro
// NotifyUpdate 通知更新
func (this *IPListDAO) NotifyUpdate(tx *dbs.Tx, listId int64, taskType NodeTaskType) error {
// WAF策略中的
httpFirewallPolicyIds, err := SharedHTTPFirewallPolicyDAO.FindEnabledFirewallPolicyIdsWithIPListId(tx, listId)
if err != nil {
return err
}
resultClusterIds := []int64{}
// 规则集动作中使用此名单的策略
ruleSetIds, err := SharedHTTPFirewallRuleSetDAO.FindAllEnabledRuleSetIdsWithIPListId(tx, listId)
if err != nil {
return err
}
for _, ruleSetId := range ruleSetIds {
ruleGroupId, err := SharedHTTPFirewallRuleGroupDAO.FindRuleGroupIdWithRuleSetId(tx, ruleSetId)
if err != nil {
return err
}
if ruleGroupId > 0 {
policyId, err := SharedHTTPFirewallPolicyDAO.FindEnabledFirewallPolicyIdWithRuleGroupId(tx, ruleGroupId)
if err != nil {
return err
}
if policyId > 0 && !lists.ContainsInt64(httpFirewallPolicyIds, policyId) {
httpFirewallPolicyIds = append(httpFirewallPolicyIds, policyId)
}
}
}
// 查找集群
var resultClusterIds = []int64{}
for _, policyId := range httpFirewallPolicyIds {
// 集群
clusterIds, err := SharedNodeClusterDAO.FindAllEnabledNodeClusterIdsWithHTTPFirewallPolicyId(tx, policyId)

View File

@@ -1,6 +1,7 @@
package models
import (
"errors"
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/dbs"
"runtime"
@@ -27,7 +28,7 @@ func TestIPListDAO_CheckUserIPList(t *testing.T) {
{
err := NewIPListDAO().CheckUserIPList(tx, 1, 100)
if err == ErrNotFound {
if err != nil && errors.Is(err, ErrNotFound) {
t.Log("not found")
} else {
t.Log(err)
@@ -36,7 +37,7 @@ func TestIPListDAO_CheckUserIPList(t *testing.T) {
{
err := NewIPListDAO().CheckUserIPList(tx, 1, 85)
if err == ErrNotFound {
if err != nil && errors.Is(err, ErrNotFound) {
t.Log("not found")
} else {
t.Log(err)
@@ -45,7 +46,7 @@ func TestIPListDAO_CheckUserIPList(t *testing.T) {
{
err := NewIPListDAO().CheckUserIPList(tx, 1, 17)
if err == ErrNotFound {
if err != nil && errors.Is(err, ErrNotFound) {
t.Log("not found")
} else {
t.Log(err)
@@ -53,6 +54,17 @@ func TestIPListDAO_CheckUserIPList(t *testing.T) {
}
}
func TestIPListDAO_NotifyUpdate(t *testing.T) {
dbs.NotifyReady()
var dao = NewIPListDAO()
var tx *dbs.Tx
err := dao.NotifyUpdate(tx, 104, NodeTaskTypeIPListDeleted)
if err != nil {
t.Fatal(err)
}
}
func BenchmarkIPListDAO_IncreaseVersion(b *testing.B) {
runtime.GOMAXPROCS(1)
@@ -65,4 +77,3 @@ func BenchmarkIPListDAO_IncreaseVersion(b *testing.B) {
_, _ = dao.IncreaseVersion(tx)
}
}

View File

@@ -1,9 +1,11 @@
package models
import (
"encoding/json"
dbutils "github.com/TeaOSLab/EdgeAPI/internal/db/utils"
"github.com/TeaOSLab/EdgeAPI/internal/errors"
"github.com/TeaOSLab/EdgeAPI/internal/utils"
"github.com/TeaOSLab/EdgeCommon/pkg/langs"
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
@@ -36,7 +38,7 @@ func init() {
}
// CreateLog 创建管理员日志
func (this *LogDAO) CreateLog(tx *dbs.Tx, adminType string, adminId int64, level string, description string, action string, ip string) error {
func (this *LogDAO) CreateLog(tx *dbs.Tx, adminType string, adminId int64, level string, description string, action string, ip string, langMessageCode langs.MessageCode, langMessageArgs []any) error {
var op = NewLogOperator()
op.Level = level
op.Description = utils.LimitString(description, 1000)
@@ -53,6 +55,16 @@ func (this *LogDAO) CreateLog(tx *dbs.Tx, adminType string, adminId int64, level
op.ProviderId = adminId
}
// i18n
op.LangMessageCode = langMessageCode
if len(langMessageArgs) > 0 {
langMessageArgsJSON, err := json.Marshal(langMessageArgs)
if err != nil {
return err
}
op.LangMessageArgs = langMessageArgsJSON
}
op.Day = timeutil.Format("Ymd")
op.Type = LogTypeAdmin
err := this.Save(tx, op)

View File

@@ -1,34 +1,60 @@
package models
// 操作日志
import "github.com/iwind/TeaGo/dbs"
const (
LogField_Id dbs.FieldName = "id" // ID
LogField_Level dbs.FieldName = "level" // 级别
LogField_Description dbs.FieldName = "description" // 描述
LogField_CreatedAt dbs.FieldName = "createdAt" // 创建时间
LogField_Action dbs.FieldName = "action" // 动作
LogField_UserId dbs.FieldName = "userId" // 用户ID
LogField_AdminId dbs.FieldName = "adminId" // 管理员ID
LogField_ProviderId dbs.FieldName = "providerId" // 供应商ID
LogField_Ip dbs.FieldName = "ip" // IP地址
LogField_Type dbs.FieldName = "type" // 类型admin, user
LogField_Day dbs.FieldName = "day" // 日期
LogField_BillId dbs.FieldName = "billId" // 账单ID
LogField_LangMessageCode dbs.FieldName = "langMessageCode" // 多语言消息代号
LogField_LangMessageArgs dbs.FieldName = "langMessageArgs" // 多语言参数
LogField_Params dbs.FieldName = "params" // 关联对象参数
)
// Log 操作日志
type Log struct {
Id uint32 `field:"id"` // ID
Level string `field:"level"` // 级别
Description string `field:"description"` // 描述
CreatedAt uint64 `field:"createdAt"` // 创建时间
Action string `field:"action"` // 动作
UserId uint32 `field:"userId"` // 用户ID
AdminId uint32 `field:"adminId"` // 管理员ID
ProviderId uint32 `field:"providerId"` // 供应商ID
Ip string `field:"ip"` // IP地址
Type string `field:"type"` // 类型admin, user
Day string `field:"day"` // 日期
BillId uint32 `field:"billId"` // 账单ID
Id uint32 `field:"id"` // ID
Level string `field:"level"` // 级别
Description string `field:"description"` // 描述
CreatedAt uint64 `field:"createdAt"` // 创建时间
Action string `field:"action"` // 动作
UserId uint32 `field:"userId"` // 用户ID
AdminId uint32 `field:"adminId"` // 管理员ID
ProviderId uint32 `field:"providerId"` // 供应商ID
Ip string `field:"ip"` // IP地址
Type string `field:"type"` // 类型admin, user
Day string `field:"day"` // 日期
BillId uint32 `field:"billId"` // 账单ID
LangMessageCode string `field:"langMessageCode"` // 多语言消息代号
LangMessageArgs dbs.JSON `field:"langMessageArgs"` // 多语言参数
Params dbs.JSON `field:"params"` // 关联对象参数
}
type LogOperator struct {
Id interface{} // ID
Level interface{} // 级别
Description interface{} // 描述
CreatedAt interface{} // 创建时间
Action interface{} // 动作
UserId interface{} // 用户ID
AdminId interface{} // 管理员ID
ProviderId interface{} // 供应商ID
Ip interface{} // IP地址
Type interface{} // 类型admin, user
Day interface{} // 日期
BillId interface{} // 账单ID
Id any // ID
Level any // 级别
Description any // 描述
CreatedAt any // 创建时间
Action any // 动作
UserId any // 用户ID
AdminId any // 管理员ID
ProviderId any // 供应商ID
Ip any // IP地址
Type any // 类型admin, user
Day any // 日期
BillId any // 账单ID
LangMessageCode any // 多语言消息代号
LangMessageArgs any // 多语言参数
Params any // 关联对象参数
}
func NewLogOperator() *LogOperator {

View File

@@ -27,6 +27,8 @@ const (
type MessageType = string
const (
MessageTypeAll MessageType = "*"
// 这里的命名问题(首字母大写)为历史遗留问题,暂不修改
MessageTypeHealthCheckFailed MessageType = "HealthCheckFailed" // 节点健康检查失败
@@ -52,7 +54,9 @@ const (
MessageTypeReportNodeInactive MessageType = "ReportNodeInactive" // 区域监控节点节点不活跃
MessageTypeReportNodeActive MessageType = "ReportNodeActive" // 区域监控节点活跃
MessageTypeConnectivity MessageType = "Connectivity"
MessageTypeConnectivity MessageType = "Connectivity" // 连通性
MessageTypeNodeSchedule MessageType = "NodeSchedule" // 节点调度信息
MessageTypeNodeOfflineDay MessageType = "NodeOfflineDay" // 节点到下线日期
)
type MessageDAO dbs.DAO
@@ -114,7 +118,7 @@ func (this *MessageDAO) CreateClusterMessage(tx *dbs.Tx, role string, clusterId
}
// 发送给媒介接收人
err = SharedMessageTaskDAO.CreateMessageTasks(tx, role, 0, 0, 0, messageType, subject, body)
err = SharedMessageTaskDAO.CreateMessageTasks(tx, role, clusterId, 0, 0, messageType, subject, body)
if err != nil {
return err
}

View File

@@ -4,8 +4,6 @@ import (
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/lists"
"github.com/iwind/TeaGo/maps"
)
const (
@@ -34,7 +32,7 @@ func init() {
})
}
// 启用条目
// EnableMessageMedia 启用条目
func (this *MessageMediaDAO) EnableMessageMedia(tx *dbs.Tx, id int64) error {
_, err := this.Query(tx).
Pk(id).
@@ -43,7 +41,7 @@ func (this *MessageMediaDAO) EnableMessageMedia(tx *dbs.Tx, id int64) error {
return err
}
// 禁用条目
// DisableMessageMedia 禁用条目
func (this *MessageMediaDAO) DisableMessageMedia(tx *dbs.Tx, id int64) error {
_, err := this.Query(tx).
Pk(id).
@@ -52,7 +50,7 @@ func (this *MessageMediaDAO) DisableMessageMedia(tx *dbs.Tx, id int64) error {
return err
}
// 查找启用中的条目
// FindEnabledMessageMedia 查找启用中的条目
func (this *MessageMediaDAO) FindEnabledMessageMedia(tx *dbs.Tx, id int64) (*MessageMedia, error) {
result, err := this.Query(tx).
Pk(id).
@@ -64,7 +62,7 @@ func (this *MessageMediaDAO) FindEnabledMessageMedia(tx *dbs.Tx, id int64) (*Mes
return result.(*MessageMedia), err
}
// 根据主键查找名称
// FindMessageMediaName 根据主键查找名称
func (this *MessageMediaDAO) FindMessageMediaName(tx *dbs.Tx, id int64) (string, error) {
return this.Query(tx).
Pk(id).
@@ -72,7 +70,7 @@ func (this *MessageMediaDAO) FindMessageMediaName(tx *dbs.Tx, id int64) (string,
FindStringCol("")
}
// 查询所有可用媒介
// FindAllEnabledMessageMedias 查询所有可用媒介
func (this *MessageMediaDAO) FindAllEnabledMessageMedias(tx *dbs.Tx) (result []*MessageMedia, err error) {
_, err = this.Query(tx).
State(MessageMediaStateEnabled).
@@ -82,74 +80,3 @@ func (this *MessageMediaDAO) FindAllEnabledMessageMedias(tx *dbs.Tx) (result []*
FindAll()
return
}
// 设置当前所有可用的媒介
func (this *MessageMediaDAO) UpdateMessageMedias(tx *dbs.Tx, mediaMaps []maps.Map) error {
// 新的媒介信息
mediaTypes := []string{}
for index, m := range mediaMaps {
order := len(mediaMaps) - index
mediaType := m.GetString("type")
mediaTypes = append(mediaTypes, mediaType)
name := m.GetString("name")
description := m.GetString("description")
userDescription := m.GetString("userDescription")
isOn := m.GetBool("isOn")
mediaId, err := this.Query(tx).
ResultPk().
Attr("type", mediaType).
FindInt64Col(0)
if err != nil {
return err
}
var op = NewMessageMediaOperator()
if mediaId > 0 {
op.Id = mediaId
}
op.Name = name
op.Type = mediaType
op.Description = description
op.UserDescription = userDescription
op.IsOn = isOn
op.Order = order
op.State = MessageMediaStateEnabled
err = this.Save(tx, op)
if err != nil {
return err
}
}
// 老的媒介信息
ones, err := this.Query(tx).
FindAll()
if err != nil {
return err
}
for _, one := range ones {
mediaType := one.(*MessageMedia).Type
if !lists.ContainsString(mediaTypes, mediaType) {
err := this.Query(tx).
Pk(one.(*MessageMedia).Id).
Set("state", MessageMediaStateDisabled).
UpdateQuickly()
if err != nil {
return err
}
}
}
return nil
}
// 根据类型查找媒介
func (this *MessageMediaDAO) FindEnabledMediaWithType(tx *dbs.Tx, mediaType string) (*MessageMedia, error) {
one, err := this.Query(tx).
Attr("type", mediaType).
State(MessageMediaStateEnabled).
Find()
if one == nil || err != nil {
return nil, err
}
return one.(*MessageMedia), nil
}

View File

@@ -98,24 +98,6 @@ func (this *MessageReceiverDAO) CreateReceiver(tx *dbs.Tx, role string, clusterI
return this.SaveInt64(tx, op)
}
// FindAllEnabledReceivers 查询接收人
func (this *MessageReceiverDAO) FindAllEnabledReceivers(tx *dbs.Tx, role string, clusterId int64, nodeId int64, serverId int64, messageType string) (result []*MessageReceiver, err error) {
query := this.Query(tx)
if len(messageType) > 0 {
query.Attr("type", []string{"*", messageType}) // *表示所有的
}
_, err = query.
Attr("role", role).
Attr("clusterId", clusterId).
Attr("nodeId", nodeId).
Attr("serverId", serverId).
State(MessageReceiverStateEnabled).
AscPk().
Slice(&result).
FindAll()
return
}
// CountAllEnabledReceivers 计算接收人数量
func (this *MessageReceiverDAO) CountAllEnabledReceivers(tx *dbs.Tx, role string, clusterId int64, nodeId int64, serverId int64, messageType string) (int64, error) {
query := this.Query(tx)
@@ -146,6 +128,8 @@ func (this *MessageReceiverDAO) FindEnabledBestFitReceivers(tx *dbs.Tx, role str
} else if nodeId > 0 {
query.Attr("nodeId", nodeId)
} else if clusterId > 0 {
query.Attr("serverId", 0)
query.Attr("nodeId", 0)
query.Attr("clusterId", clusterId)
}
_, err = query.

View File

@@ -1,30 +0,0 @@
package models
import (
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
_ "github.com/go-sql-driver/mysql"
_ "github.com/iwind/TeaGo/bootstrap"
"github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/logs"
"testing"
)
func TestMessageReceiverDAO_FindEnabledBestFitReceivers(t *testing.T) {
var tx *dbs.Tx
{
receivers, err := NewMessageReceiverDAO().FindEnabledBestFitReceivers(tx, nodeconfigs.NodeRoleNode, 18, 1, 2, "*")
if err != nil {
t.Fatal(err)
}
logs.PrintAsJSON(receivers, t)
}
{
receivers, err := NewMessageReceiverDAO().FindEnabledBestFitReceivers(tx, nodeconfigs.NodeRoleNode, 30, 1, 2, "*")
if err != nil {
t.Fatal(err)
}
logs.PrintAsJSON(receivers, t)
}
}

View File

@@ -1,31 +1,19 @@
package models
import (
teaconst "github.com/TeaOSLab/EdgeAPI/internal/const"
"github.com/TeaOSLab/EdgeAPI/internal/errors"
"github.com/TeaOSLab/EdgeAPI/internal/goman"
"github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/rands"
"github.com/iwind/TeaGo/types"
stringutil "github.com/iwind/TeaGo/utils/string"
timeutil "github.com/iwind/TeaGo/utils/time"
"time"
)
type MessageTaskStatus = int
const (
MessageTaskStateEnabled = 1 // 已启用
MessageTaskStateDisabled = 0 // 已禁用
MessageTaskStatusNone MessageTaskStatus = 0 // 普通状态
MessageTaskStatusSending MessageTaskStatus = 1 // 发送中
MessageTaskStatusSuccess MessageTaskStatus = 2 // 发送成功
MessageTaskStatusFailed MessageTaskStatus = 3 // 发送失败
)
type MessageTaskDAO dbs.DAO
@@ -94,151 +82,6 @@ func (this *MessageTaskDAO) FindEnabledMessageTask(tx *dbs.Tx, id int64) (*Messa
return result.(*MessageTask), err
}
// CreateMessageTask 创建任务
func (this *MessageTaskDAO) CreateMessageTask(tx *dbs.Tx, recipientId int64, instanceId int64, user string, subject string, body string, isPrimary bool) (int64, error) {
if !teaconst.IsPlus {
return 0, nil
}
var hash = stringutil.Md5(types.String(recipientId) + "@" + types.String(instanceId) + "@" + user + "@" + subject + "@" + types.String(isPrimary))
recipientInstanceId, err := SharedMessageRecipientDAO.FindRecipientInstanceId(tx, recipientId)
if err != nil {
return 0, err
}
if recipientInstanceId > 0 {
hashLifeSeconds, err := SharedMessageMediaInstanceDAO.FindInstanceHashLifeSeconds(tx, recipientInstanceId)
if err != nil {
return 0, err
}
if hashLifeSeconds >= 0 { // 意味着此值如果小于0则不做判断
lastMessageAt, err := this.Query(tx).
Attr("hash", hash).
Result("createdAt").
DescPk().
FindInt64Col(0)
if err != nil {
return 0, err
}
// 对于同一个人N分钟内消息不重复发送
if hashLifeSeconds <= 0 {
hashLifeSeconds = 60
}
if lastMessageAt > 0 && time.Now().Unix()-lastMessageAt < int64(hashLifeSeconds) {
return 0, nil
}
}
}
var op = NewMessageTaskOperator()
op.RecipientId = recipientId
op.InstanceId = instanceId
op.Hash = hash
op.User = user
op.Subject = subject
op.Body = body
op.IsPrimary = isPrimary
op.Day = timeutil.Format("Ymd")
op.Status = MessageTaskStatusNone
op.State = MessageTaskStateEnabled
return this.SaveInt64(tx, op)
}
// FindSendingMessageTasks 查找需要发送的任务
func (this *MessageTaskDAO) FindSendingMessageTasks(tx *dbs.Tx, size int64) (result []*MessageTask, err error) {
if size <= 0 {
return nil, nil
}
_, err = this.Query(tx).
State(MessageTaskStateEnabled).
Attr("status", MessageTaskStatusNone).
Where("(recipientId=0 OR recipientId IN (SELECT id FROM "+SharedMessageRecipientDAO.Table+" WHERE state=1 AND isOn=1 AND (timeFrom IS NULL OR timeTo IS NULL OR :time BETWEEN timeFrom AND timeTo)))").
Param("time", timeutil.Format("H:i:s")).
Desc("isPrimary").
AscPk().
Limit(size).
Slice(&result).
FindAll()
return
}
// CountMessageTasksWithStatus 根据状态计算任务数量
func (this *MessageTaskDAO) CountMessageTasksWithStatus(tx *dbs.Tx, status MessageTaskStatus) (int64, error) {
return this.Query(tx).
State(MessageTaskStateEnabled).
Attr("status", status).
Count()
}
// ListMessageTasksWithStatus 根据状态列出单页任务
func (this *MessageTaskDAO) ListMessageTasksWithStatus(tx *dbs.Tx, status MessageTaskStatus, offset int64, size int64) (result []*MessageTask, err error) {
_, err = this.Query(tx).
State(MessageTaskStateEnabled).
Attr("status", status).
Desc("isPrimary").
AscPk().
Offset(offset).
Limit(size).
Slice(&result).
FindAll()
return
}
// UpdateMessageTaskStatus 设置发送的状态
func (this *MessageTaskDAO) UpdateMessageTaskStatus(tx *dbs.Tx, taskId int64, status MessageTaskStatus, result []byte) error {
if taskId <= 0 {
return errors.New("invalid taskId")
}
var op = NewMessageTaskOperator()
op.Id = taskId
op.Status = status
op.SentAt = time.Now().Unix()
if len(result) > 0 {
op.Result = result
}
return this.Save(tx, op)
}
// CreateMessageTasks 从集群、节点或者服务中创建任务
func (this *MessageTaskDAO) CreateMessageTasks(tx *dbs.Tx, role nodeconfigs.NodeRole, clusterId int64, nodeId int64, serverId int64, messageType MessageType, subject string, body string) error {
if !teaconst.IsPlus {
return nil
}
receivers, err := SharedMessageReceiverDAO.FindEnabledBestFitReceivers(tx, role, clusterId, nodeId, serverId, messageType)
if err != nil {
return err
}
allRecipientIds := []int64{}
for _, receiver := range receivers {
if receiver.RecipientId > 0 {
allRecipientIds = append(allRecipientIds, int64(receiver.RecipientId))
} else if receiver.RecipientGroupId > 0 {
recipientIds, err := SharedMessageRecipientDAO.FindAllEnabledAndOnRecipientIdsWithGroup(tx, int64(receiver.RecipientGroupId))
if err != nil {
return err
}
allRecipientIds = append(allRecipientIds, recipientIds...)
}
}
sentMap := map[int64]bool{} // recipientId => bool 用来检查是否已经发送,防止重复发送给某个接收人
for _, recipientId := range allRecipientIds {
_, ok := sentMap[recipientId]
if ok {
continue
}
sentMap[recipientId] = true
_, err := this.CreateMessageTask(tx, recipientId, 0, "", subject, body, false)
if err != nil {
return err
}
}
return nil
}
// CleanExpiredMessageTasks 清理
func (this *MessageTaskDAO) CleanExpiredMessageTasks(tx *dbs.Tx, days int) error {
if days <= 0 {

View File

@@ -0,0 +1,14 @@
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
//go:build !plus
package models
import (
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
"github.com/iwind/TeaGo/dbs"
)
// CreateMessageTasks 从集群、节点或者服务中创建任务
func (this *MessageTaskDAO) CreateMessageTasks(tx *dbs.Tx, role nodeconfigs.NodeRole, clusterId int64, nodeId int64, serverId int64, messageType MessageType, subject string, body string) error {
return nil
}

View File

@@ -1,214 +0,0 @@
package models
import (
"github.com/TeaOSLab/EdgeAPI/internal/errors"
"github.com/TeaOSLab/EdgeAPI/internal/utils"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/rands"
"github.com/iwind/TeaGo/types"
)
const (
MonitorNodeStateEnabled = 1 // 已启用
MonitorNodeStateDisabled = 0 // 已禁用
)
type MonitorNodeDAO dbs.DAO
func NewMonitorNodeDAO() *MonitorNodeDAO {
return dbs.NewDAO(&MonitorNodeDAO{
DAOObject: dbs.DAOObject{
DB: Tea.Env,
Table: "edgeMonitorNodes",
Model: new(MonitorNode),
PkName: "id",
},
}).(*MonitorNodeDAO)
}
var SharedMonitorNodeDAO *MonitorNodeDAO
func init() {
dbs.OnReady(func() {
SharedMonitorNodeDAO = NewMonitorNodeDAO()
})
}
// EnableMonitorNode 启用条目
func (this *MonitorNodeDAO) EnableMonitorNode(tx *dbs.Tx, id int64) error {
_, err := this.Query(tx).
Pk(id).
Set("state", MonitorNodeStateEnabled).
Update()
return err
}
// DisableMonitorNode 禁用条目
func (this *MonitorNodeDAO) DisableMonitorNode(tx *dbs.Tx, nodeId int64) error {
_, err := this.Query(tx).
Pk(nodeId).
Set("state", MonitorNodeStateDisabled).
Update()
if err != nil {
return err
}
// 删除运行日志
return SharedNodeLogDAO.DeleteNodeLogs(tx, nodeconfigs.NodeRoleMonitor, nodeId)
}
// FindEnabledMonitorNode 查找启用中的条目
func (this *MonitorNodeDAO) FindEnabledMonitorNode(tx *dbs.Tx, id int64) (*MonitorNode, error) {
result, err := this.Query(tx).
Pk(id).
Attr("state", MonitorNodeStateEnabled).
Find()
if result == nil {
return nil, err
}
return result.(*MonitorNode), err
}
// FindMonitorNodeName 根据主键查找名称
func (this *MonitorNodeDAO) FindMonitorNodeName(tx *dbs.Tx, id int64) (string, error) {
return this.Query(tx).
Pk(id).
Result("name").
FindStringCol("")
}
// FindAllEnabledMonitorNodes 列出所有可用监控节点
func (this *MonitorNodeDAO) FindAllEnabledMonitorNodes(tx *dbs.Tx) (result []*MonitorNode, err error) {
_, err = this.Query(tx).
State(MonitorNodeStateEnabled).
Desc("order").
AscPk().
Slice(&result).
FindAll()
return
}
// CountAllEnabledMonitorNodes 计算监控节点数量
func (this *MonitorNodeDAO) CountAllEnabledMonitorNodes(tx *dbs.Tx) (int64, error) {
return this.Query(tx).
State(MonitorNodeStateEnabled).
Count()
}
// ListEnabledMonitorNodes 列出单页的监控节点
func (this *MonitorNodeDAO) ListEnabledMonitorNodes(tx *dbs.Tx, offset int64, size int64) (result []*MonitorNode, err error) {
_, err = this.Query(tx).
State(MonitorNodeStateEnabled).
Offset(offset).
Limit(size).
Desc("order").
DescPk().
Slice(&result).
FindAll()
return
}
// CreateMonitorNode 创建监控节点
func (this *MonitorNodeDAO) CreateMonitorNode(tx *dbs.Tx, name string, description string, isOn bool) (nodeId int64, err error) {
uniqueId, err := this.GenUniqueId(tx)
if err != nil {
return 0, err
}
secret := rands.String(32)
err = NewApiTokenDAO().CreateAPIToken(tx, uniqueId, secret, nodeconfigs.NodeRoleMonitor)
if err != nil {
return
}
var op = NewMonitorNodeOperator()
op.IsOn = isOn
op.UniqueId = uniqueId
op.Secret = secret
op.Name = name
op.Description = description
op.State = NodeStateEnabled
err = this.Save(tx, op)
if err != nil {
return
}
return types.Int64(op.Id), nil
}
// UpdateMonitorNode 修改监控节点
func (this *MonitorNodeDAO) UpdateMonitorNode(tx *dbs.Tx, nodeId int64, name string, description string, isOn bool) error {
if nodeId <= 0 {
return errors.New("invalid nodeId")
}
var op = NewMonitorNodeOperator()
op.Id = nodeId
op.Name = name
op.Description = description
op.IsOn = isOn
err := this.Save(tx, op)
return err
}
// FindEnabledMonitorNodeWithUniqueId 根据唯一ID获取节点信息
func (this *MonitorNodeDAO) FindEnabledMonitorNodeWithUniqueId(tx *dbs.Tx, uniqueId string) (*MonitorNode, error) {
result, err := this.Query(tx).
Attr("uniqueId", uniqueId).
Attr("state", MonitorNodeStateEnabled).
Find()
if result == nil {
return nil, err
}
return result.(*MonitorNode), err
}
// FindEnabledMonitorNodeIdWithUniqueId 根据唯一ID获取节点ID
func (this *MonitorNodeDAO) FindEnabledMonitorNodeIdWithUniqueId(tx *dbs.Tx, uniqueId string) (int64, error) {
return this.Query(tx).
Attr("uniqueId", uniqueId).
Attr("state", MonitorNodeStateEnabled).
ResultPk().
FindInt64Col(0)
}
// GenUniqueId 生成唯一ID
func (this *MonitorNodeDAO) GenUniqueId(tx *dbs.Tx) (string, error) {
for {
uniqueId := rands.HexString(32)
ok, err := this.Query(tx).
Attr("uniqueId", uniqueId).
Exist()
if err != nil {
return "", err
}
if ok {
continue
}
return uniqueId, nil
}
}
// UpdateNodeStatus 更改节点状态
func (this *MonitorNodeDAO) UpdateNodeStatus(tx *dbs.Tx, nodeId int64, statusJSON []byte) error {
if statusJSON == nil {
return nil
}
_, err := this.Query(tx).
Pk(nodeId).
Set("status", string(statusJSON)).
Update()
return err
}
// CountAllLowerVersionNodes 计算所有节点中低于某个版本的节点数量
func (this *MonitorNodeDAO) CountAllLowerVersionNodes(tx *dbs.Tx, version string) (int64, error) {
return this.Query(tx).
State(MonitorNodeStateEnabled).
Where("status IS NOT NULL").
Where("(JSON_EXTRACT(status, '$.buildVersionCode') IS NULL OR JSON_EXTRACT(status, '$.buildVersionCode')<:version)").
Param("version", utils.VersionToLong(version)).
Count()
}

View File

@@ -1,38 +0,0 @@
package models
import "github.com/iwind/TeaGo/dbs"
// MonitorNode 监控节点
type MonitorNode struct {
Id uint32 `field:"id"` // ID
IsOn bool `field:"isOn"` // 是否启用
UniqueId string `field:"uniqueId"` // 唯一ID
Secret string `field:"secret"` // 密钥
Name string `field:"name"` // 名称
Description string `field:"description"` // 描述
Order uint32 `field:"order"` // 排序
State uint8 `field:"state"` // 状态
CreatedAt uint64 `field:"createdAt"` // 创建时间
AdminId uint32 `field:"adminId"` // 管理员ID
Weight uint32 `field:"weight"` // 权重
Status dbs.JSON `field:"status"` // 运行状态
}
type MonitorNodeOperator struct {
Id interface{} // ID
IsOn interface{} // 是否启用
UniqueId interface{} // 唯一ID
Secret interface{} // 密钥
Name interface{} // 名称
Description interface{} // 描述
Order interface{} // 排序
State interface{} // 状态
CreatedAt interface{} // 创建时间
AdminId interface{} // 管理员ID
Weight interface{} // 权重
Status interface{} // 运行状态
}
func NewMonitorNodeOperator() *MonitorNodeOperator {
return &MonitorNodeOperator{}
}

View File

@@ -0,0 +1,33 @@
package nameservers
import (
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
)
const (
NSDomainStateEnabled = 1 // 已启用
NSDomainStateDisabled = 0 // 已禁用
)
type NSDomainDAO dbs.DAO
func NewNSDomainDAO() *NSDomainDAO {
return dbs.NewDAO(&NSDomainDAO{
DAOObject: dbs.DAOObject{
DB: Tea.Env,
Table: "edgeNSDomains",
Model: new(NSDomain),
PkName: "id",
},
}).(*NSDomainDAO)
}
var SharedNSDomainDAO *NSDomainDAO
func init() {
dbs.OnReady(func() {
SharedNSDomainDAO = NewNSDomainDAO()
})
}

View File

@@ -0,0 +1,6 @@
package nameservers_test
import (
_ "github.com/go-sql-driver/mysql"
_ "github.com/iwind/TeaGo/bootstrap"
)

View File

@@ -4,35 +4,37 @@ import "github.com/iwind/TeaGo/dbs"
// NSDomain DNS域名
type NSDomain struct {
Id uint64 `field:"id"` // ID
ClusterId uint32 `field:"clusterId"` // 集群ID
UserId uint32 `field:"userId"` // 用户ID
IsOn bool `field:"isOn"` // 是否启用
Name string `field:"name"` // 域名
GroupIds dbs.JSON `field:"groupIds"` // 分组ID
Tsig dbs.JSON `field:"tsig"` // TSIG配置
VerifyTXT string `field:"verifyTXT"` // 验证用的TXT
VerifyExpiresAt uint64 `field:"verifyExpiresAt"` // 验证TXT过期时间
CreatedAt uint64 `field:"createdAt"` // 创建时间
Version uint64 `field:"version"` // 版本号
Status string `field:"status"` // 状态none|verified
State uint8 `field:"state"` // 状态
Id uint64 `field:"id"` // ID
ClusterId uint32 `field:"clusterId"` // 集群ID
UserId uint32 `field:"userId"` // 用户ID
IsOn bool `field:"isOn"` // 是否启用
Name string `field:"name"` // 域名
GroupIds dbs.JSON `field:"groupIds"` // 分组ID
Tsig dbs.JSON `field:"tsig"` // TSIG配置
VerifyTXT string `field:"verifyTXT"` // 验证用的TXT
VerifyExpiresAt uint64 `field:"verifyExpiresAt"` // 验证TXT过期时间
RecordsHealthCheck dbs.JSON `field:"recordsHealthCheck"` // 记录健康检查设置
CreatedAt uint64 `field:"createdAt"` // 创建时间
Version uint64 `field:"version"` // 版本号
Status string `field:"status"` // 状态none|verified
State uint8 `field:"state"` // 状态
}
type NSDomainOperator struct {
Id any // ID
ClusterId any // 集群ID
UserId any // 用户ID
IsOn any // 是否启用
Name any // 域名
GroupIds any // 分组ID
Tsig any // TSIG配置
VerifyTXT any // 验证用的TXT
VerifyExpiresAt any // 验证TXT过期时间
CreatedAt any // 创建时间
Version any // 版本号
Status any // 状态none|verified
State any // 状态
Id any // ID
ClusterId any // 集群ID
UserId any // 用户ID
IsOn any // 是否启用
Name any // 域名
GroupIds any // 分组ID
Tsig any // TSIG配置
VerifyTXT any // 验证用的TXT
VerifyExpiresAt any // 验证TXT过期时间
RecordsHealthCheck any // 记录健康检查设置
CreatedAt any // 创建时间
Version any // 版本号
Status any // 状态none|verified
State any // 状态
}
func NewNSDomainOperator() *NSDomainOperator {

View File

@@ -20,6 +20,10 @@ type NSRecord struct {
Ttl uint32 `field:"ttl"` // TTL
Weight uint32 `field:"weight"` // 权重
RouteIds dbs.JSON `field:"routeIds"` // 线路
HealthCheck dbs.JSON `field:"healthCheck"` // 健康检查配置
CountUp uint32 `field:"countUp"` // 连续上线次数
CountDown uint32 `field:"countDown"` // 连续离线次数
IsUp bool `field:"isUp"` // 是否在线
CreatedAt uint64 `field:"createdAt"` // 创建时间
Version uint64 `field:"version"` // 版本号
State uint8 `field:"state"` // 状态
@@ -42,6 +46,10 @@ type NSRecordOperator struct {
Ttl any // TTL
Weight any // 权重
RouteIds any // 线路
HealthCheck any // 健康检查配置
CountUp any // 连续上线次数
CountDown any // 连续离线次数
IsUp any // 是否在线
CreatedAt any // 创建时间
Version any // 版本号
State any // 状态

View File

@@ -0,0 +1,63 @@
package models
import (
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
)
const (
NodeActionStateEnabled = 1 // 已启用
NodeActionStateDisabled = 0 // 已禁用
)
type NodeActionDAO dbs.DAO
func NewNodeActionDAO() *NodeActionDAO {
return dbs.NewDAO(&NodeActionDAO{
DAOObject: dbs.DAOObject{
DB: Tea.Env,
Table: "edgeNodeActions",
Model: new(NodeAction),
PkName: "id",
},
}).(*NodeActionDAO)
}
var SharedNodeActionDAO *NodeActionDAO
func init() {
dbs.OnReady(func() {
SharedNodeActionDAO = NewNodeActionDAO()
})
}
// EnableNodeAction 启用条目
func (this *NodeActionDAO) EnableNodeAction(tx *dbs.Tx, id uint64) error {
_, err := this.Query(tx).
Pk(id).
Set("state", NodeActionStateEnabled).
Update()
return err
}
// DisableNodeAction 禁用条目
func (this *NodeActionDAO) DisableNodeAction(tx *dbs.Tx, id int64) error {
_, err := this.Query(tx).
Pk(id).
Set("state", NodeActionStateDisabled).
Update()
return err
}
// FindEnabledNodeAction 查找启用中的条目
func (this *NodeActionDAO) FindEnabledNodeAction(tx *dbs.Tx, id int64) (*NodeAction, error) {
result, err := this.Query(tx).
Pk(id).
State(NodeActionStateEnabled).
Find()
if result == nil {
return nil, err
}
return result.(*NodeAction), err
}

View File

@@ -1,4 +1,4 @@
package models
package models_test
import (
_ "github.com/go-sql-driver/mysql"

View File

@@ -0,0 +1,32 @@
package models
import "github.com/iwind/TeaGo/dbs"
// NodeAction 节点智能调度设置
type NodeAction struct {
Id uint64 `field:"id"` // ID
NodeId uint64 `field:"nodeId"` // 节点ID
Role string `field:"role"` // 角色
IsOn bool `field:"isOn"` // 是否启用
Conds dbs.JSON `field:"conds"` // 条件
Action dbs.JSON `field:"action"` // 动作
Duration dbs.JSON `field:"duration"` // 持续时间
Order uint32 `field:"order"` // 排序
State uint8 `field:"state"` // 状态
}
type NodeActionOperator struct {
Id any // ID
NodeId any // 节点ID
Role any // 角色
IsOn any // 是否启用
Conds any // 条件
Action any // 动作
Duration any // 持续时间
Order any // 排序
State any // 状态
}
func NewNodeActionOperator() *NodeActionOperator {
return &NodeActionOperator{}
}

View File

@@ -100,6 +100,7 @@ func (this *NodeClusterDAO) FindNodeClusterName(tx *dbs.Tx, clusterId int64) (st
// FindAllEnableClusters 查找所有可用的集群
func (this *NodeClusterDAO) FindAllEnableClusters(tx *dbs.Tx) (result []*NodeCluster, err error) {
_, err = this.Query(tx).
Result(NodeClusterField_Id, NodeClusterField_Name, NodeClusterField_IsOn, NodeClusterField_HealthCheck, NodeClusterField_AutoRemoteStart, NodeClusterField_AutoRegister, NodeClusterField_CreatedAt, NodeClusterField_UniqueId, NodeClusterField_Secret).
State(NodeClusterStateEnabled).
Slice(&result).
Desc("isPinned").
@@ -125,7 +126,7 @@ func (this *NodeClusterDAO) FindAllEnableClusterIds(tx *dbs.Tx) (result []int64,
}
// CreateCluster 创建集群
func (this *NodeClusterDAO) CreateCluster(tx *dbs.Tx, adminId int64, name string, grantId int64, installDir string, dnsDomainId int64, dnsName string, dnsTTL int32, cachePolicyId int64, httpFirewallPolicyId int64, systemServices map[string]maps.Map, globalServerConfig *serverconfigs.GlobalServerConfig, autoInstallNftables bool) (clusterId int64, err error) {
func (this *NodeClusterDAO) CreateCluster(tx *dbs.Tx, adminId int64, name string, grantId int64, installDir string, dnsDomainId int64, dnsName string, dnsTTL int32, cachePolicyId int64, httpFirewallPolicyId int64, systemServices map[string]maps.Map, globalServerConfig *serverconfigs.GlobalServerConfig, autoInstallNftables bool, autoSystemTuning bool) (clusterId int64, err error) {
uniqueId, err := this.GenUniqueId(tx)
if err != nil {
return 0, err
@@ -175,7 +176,7 @@ func (this *NodeClusterDAO) CreateCluster(tx *dbs.Tx, adminId int64, name string
// 全局服务配置
if globalServerConfig == nil {
globalServerConfig = serverconfigs.DefaultGlobalServerConfig()
globalServerConfig = serverconfigs.NewGlobalServerConfig()
}
globalServerConfigJSON, err := json.Marshal(globalServerConfig)
if err != nil {
@@ -188,6 +189,7 @@ func (this *NodeClusterDAO) CreateCluster(tx *dbs.Tx, adminId int64, name string
op.UniqueId = uniqueId
op.Secret = secret
op.AutoInstallNftables = autoInstallNftables
op.AutoSystemTuning = autoSystemTuning
op.State = NodeClusterStateEnabled
err = this.Save(tx, op)
if err != nil {
@@ -198,7 +200,7 @@ func (this *NodeClusterDAO) CreateCluster(tx *dbs.Tx, adminId int64, name string
}
// UpdateCluster 修改集群
func (this *NodeClusterDAO) UpdateCluster(tx *dbs.Tx, clusterId int64, name string, grantId int64, installDir string, timezone string, nodeMaxThreads int32, autoOpenPorts bool, clockConfig *nodeconfigs.ClockConfig, autoRemoteStart bool, autoInstallTables bool, sshParams *nodeconfigs.SSHParams) error {
func (this *NodeClusterDAO) UpdateCluster(tx *dbs.Tx, clusterId int64, name string, grantId int64, installDir string, timezone string, nodeMaxThreads int32, autoOpenPorts bool, clockConfig *nodeconfigs.ClockConfig, autoRemoteStart bool, autoInstallTables bool, sshParams *nodeconfigs.SSHParams, autoSystemTuning bool) error {
if clusterId <= 0 {
return errors.New("invalid clusterId")
}
@@ -225,6 +227,7 @@ func (this *NodeClusterDAO) UpdateCluster(tx *dbs.Tx, clusterId int64, name stri
op.AutoRemoteStart = autoRemoteStart
op.AutoInstallNftables = autoInstallTables
op.AutoSystemTuning = autoSystemTuning
if sshParams != nil {
sshParamsJSON, err := json.Marshal(sshParams)
@@ -262,19 +265,40 @@ func (this *NodeClusterDAO) CountAllEnabledClusters(tx *dbs.Tx, keyword string)
// ListEnabledClusters 列出单页集群
func (this *NodeClusterDAO) ListEnabledClusters(tx *dbs.Tx, keyword string, offset, size int64) (result []*NodeCluster, err error) {
query := this.Query(tx).
var query = this.Query(tx).
State(NodeClusterStateEnabled)
if len(keyword) > 0 {
query.Where("(name LIKE :keyword OR dnsName like :keyword OR (dnsDomainId > 0 AND dnsDomainId IN (SELECT id FROM "+dns.SharedDNSDomainDAO.Table+" WHERE name LIKE :keyword AND state=1)))").
Param("keyword", dbutils.QuoteLike(keyword))
}
_, err = query.
Result(
NodeClusterField_Id,
NodeClusterField_Name,
NodeClusterField_IsOn,
NodeClusterField_IsPinned,
NodeClusterField_InstallDir,
NodeClusterField_HttpFirewallPolicyId,
NodeClusterField_AdminId,
NodeClusterField_IsOn,
NodeClusterField_IsAD,
NodeClusterField_UserId,
NodeClusterField_DnsName,
NodeClusterField_DnsDomainId,
NodeClusterField_Dns,
NodeClusterField_CreatedAt,
NodeClusterField_UniqueId,
NodeClusterField_Secret,
NodeClusterField_GrantId,
NodeClusterField_TimeZone,
).
Offset(offset).
Limit(size).
Slice(&result).
Desc("isPinned").
DescPk().
FindAll()
return
}
@@ -625,10 +649,10 @@ func (this *NodeClusterDAO) FindClusterTOAConfig(tx *dbs.Tx, clusterId int64, ca
return nil, err
}
if !IsNotNull([]byte(toa)) {
return nodeconfigs.DefaultTOAConfig(), nil
return nodeconfigs.NewTOAConfig(), nil
}
config := &nodeconfigs.TOAConfig{}
var config = nodeconfigs.NewTOAConfig()
err = json.Unmarshal([]byte(toa), config)
if err != nil {
return nil, err
@@ -653,7 +677,7 @@ func (this *NodeClusterDAO) UpdateClusterTOA(tx *dbs.Tx, clusterId int64, toaJSO
if err != nil {
return err
}
return this.NotifyUpdate(tx, clusterId)
return this.NotifyTOAUpdate(tx, clusterId)
}
// CountAllEnabledNodeClustersWithHTTPCachePolicyId 计算使用某个缓存策略的集群数量
@@ -928,11 +952,12 @@ func (this *NodeClusterDAO) GenUniqueId(tx *dbs.Tx) (string, error) {
// FindLatestNodeClusters 查询最近访问的集群
func (this *NodeClusterDAO) FindLatestNodeClusters(tx *dbs.Tx, size int64) (result []*NodeCluster, err error) {
itemTable := SharedLatestItemDAO.Table
itemType := LatestItemTypeCluster
var itemTable = SharedLatestItemDAO.Table
var itemType = LatestItemTypeCluster
_, err = this.Query(tx).
Result(this.Table+".id", this.Table+".name").
Join(SharedLatestItemDAO, dbs.QueryJoinRight, this.Table+".id="+itemTable+".itemId AND "+itemTable+".itemType='"+itemType+"'").
Where(itemTable + ".updatedAt<=UNIX_TIMESTAMP()"). // VERY IMPORTANT
Asc("CEIL((UNIX_TIMESTAMP() - " + itemTable + ".updatedAt) / (7 * 86400))"). // 优先一个星期以内的
Desc(itemTable + ".count").
State(NodeClusterStateEnabled).
@@ -996,7 +1021,7 @@ func (this *NodeClusterDAO) FindClusterBasicInfo(tx *dbs.Tx, clusterId int64, ca
cluster, err := this.Query(tx).
Pk(clusterId).
State(NodeClusterStateEnabled).
Result("id", "name", "timeZone", "nodeMaxThreads", "cachePolicyId", "httpFirewallPolicyId", "autoOpenPorts", "webp", "uam", "isOn", "ddosProtection", "clock", "globalServerConfig", "autoInstallNftables").
Result("id", "name", "timeZone", "nodeMaxThreads", "cachePolicyId", "httpFirewallPolicyId", "autoOpenPorts", "webp", "uam", "cc", "httpPages", "http3", "isOn", "ddosProtection", "clock", "globalServerConfig", "autoInstallNftables", "autoSystemTuning").
Find()
if err != nil || cluster == nil {
return nil, err
@@ -1095,7 +1120,7 @@ func (this *NodeClusterDAO) UpdateClusterUAMPolicy(tx *dbs.Tx, clusterId int64,
return this.NotifyUAMUpdate(tx, clusterId)
}
// FindClusterUAMPolicy 查询设置
// FindClusterUAMPolicy 查询UAM设置
func (this *NodeClusterDAO) FindClusterUAMPolicy(tx *dbs.Tx, clusterId int64, cacheMap *utils.CacheMap) (*nodeconfigs.UAMPolicy, error) {
var cacheKey = this.Table + ":FindClusterUAMPolicy:" + types.String(clusterId)
if cacheMap != nil {
@@ -1113,11 +1138,12 @@ func (this *NodeClusterDAO) FindClusterUAMPolicy(tx *dbs.Tx, clusterId int64, ca
return nil, err
}
var policy = nodeconfigs.NewUAMPolicy()
if IsNull(uamJSON) {
return nodeconfigs.DefaultUAMPolicy, nil
return policy, nil
}
var policy = &nodeconfigs.UAMPolicy{}
err = json.Unmarshal(uamJSON, policy)
if err != nil {
return nil, err
@@ -1125,6 +1151,205 @@ func (this *NodeClusterDAO) FindClusterUAMPolicy(tx *dbs.Tx, clusterId int64, ca
return policy, nil
}
// UpdateClusterHTTPCCPolicy 修改CC策略设置
func (this *NodeClusterDAO) UpdateClusterHTTPCCPolicy(tx *dbs.Tx, clusterId int64, httpCCPolicy *nodeconfigs.HTTPCCPolicy) error {
if httpCCPolicy == nil {
err := this.Query(tx).
Pk(clusterId).
Set("cc", dbs.SQL("null")).
UpdateQuickly()
if err != nil {
return err
}
return this.NotifyHTTPCCUpdate(tx, clusterId)
}
httpCCPolicyJSON, err := json.Marshal(httpCCPolicy)
if err != nil {
return err
}
err = this.Query(tx).
Pk(clusterId).
Set("cc", httpCCPolicyJSON).
UpdateQuickly()
if err != nil {
return err
}
return this.NotifyHTTPCCUpdate(tx, clusterId)
}
// FindClusterHTTPCCPolicy 查询CC策略设置
func (this *NodeClusterDAO) FindClusterHTTPCCPolicy(tx *dbs.Tx, clusterId int64, cacheMap *utils.CacheMap) (*nodeconfigs.HTTPCCPolicy, error) {
var cacheKey = this.Table + ":FindClusterHTTPCCPolicy:" + types.String(clusterId)
if cacheMap != nil {
cache, ok := cacheMap.Get(cacheKey)
if ok {
return cache.(*nodeconfigs.HTTPCCPolicy), nil
}
}
httpCCJSON, err := this.Query(tx).
Pk(clusterId).
Result("cc").
FindJSONCol()
if err != nil {
return nil, err
}
if IsNull(httpCCJSON) {
return nodeconfigs.NewHTTPCCPolicy(), nil
}
var policy = nodeconfigs.NewHTTPCCPolicy()
err = json.Unmarshal(httpCCJSON, policy)
if err != nil {
return nil, err
}
return policy, nil
}
// UpdateClusterHTTP3Policy 修改HTTP3策略设置
func (this *NodeClusterDAO) UpdateClusterHTTP3Policy(tx *dbs.Tx, clusterId int64, http3Policy *nodeconfigs.HTTP3Policy) error {
if http3Policy == nil {
err := this.Query(tx).
Pk(clusterId).
Set("http3", dbs.SQL("null")).
UpdateQuickly()
if err != nil {
return err
}
return this.NotifyHTTP3Update(tx, clusterId)
}
http3PolicyJSON, err := json.Marshal(http3Policy)
if err != nil {
return err
}
err = this.Query(tx).
Pk(clusterId).
Set("http3", http3PolicyJSON).
UpdateQuickly()
if err != nil {
return err
}
return this.NotifyHTTP3Update(tx, clusterId)
}
// FindClusterHTTP3Policy 查询HTTP3策略设置
func (this *NodeClusterDAO) FindClusterHTTP3Policy(tx *dbs.Tx, clusterId int64, cacheMap *utils.CacheMap) (*nodeconfigs.HTTP3Policy, error) {
var cacheKey = this.Table + ":FindClusterHTTP3Policy:" + types.String(clusterId)
if cacheMap != nil {
cache, ok := cacheMap.Get(cacheKey)
if ok {
return cache.(*nodeconfigs.HTTP3Policy), nil
}
}
http3PolicyJSON, err := this.Query(tx).
Pk(clusterId).
Result("http3").
FindJSONCol()
if err != nil {
return nil, err
}
if IsNull(http3PolicyJSON) {
return nodeconfigs.NewHTTP3Policy(), nil
}
var policy = nodeconfigs.NewHTTP3Policy()
err = json.Unmarshal(http3PolicyJSON, policy)
if err != nil {
return nil, err
}
return policy, nil
}
// UpdateClusterHTTPPagesPolicy 修改自定义页面设置
func (this *NodeClusterDAO) UpdateClusterHTTPPagesPolicy(tx *dbs.Tx, clusterId int64, httpPagesPolicy *nodeconfigs.HTTPPagesPolicy) error {
if httpPagesPolicy == nil {
err := this.Query(tx).
Pk(clusterId).
Set("httpPages", dbs.SQL("null")).
UpdateQuickly()
if err != nil {
return err
}
return this.NotifyHTTPPagesPolicyUpdate(tx, clusterId)
}
// 移除不需要保存的内容
var newPages = []*serverconfigs.HTTPPageConfig{}
for _, page := range httpPagesPolicy.Pages {
newPages = append(newPages, &serverconfigs.HTTPPageConfig{Id: page.Id})
}
httpPagesPolicy.Pages = newPages
httpPagesPolicyJSON, err := json.Marshal(httpPagesPolicy)
if err != nil {
return err
}
err = this.Query(tx).
Pk(clusterId).
Set("httpPages", httpPagesPolicyJSON).
UpdateQuickly()
if err != nil {
return err
}
return this.NotifyHTTPPagesPolicyUpdate(tx, clusterId)
}
// FindClusterHTTPPagesPolicy 查询自定义页面设置
func (this *NodeClusterDAO) FindClusterHTTPPagesPolicy(tx *dbs.Tx, clusterId int64, cacheMap *utils.CacheMap) (*nodeconfigs.HTTPPagesPolicy, error) {
var cacheKey = this.Table + ":FindClusterHTTPPagesPolicy:" + types.String(clusterId)
if cacheMap != nil {
cache, ok := cacheMap.Get(cacheKey)
if ok {
return cache.(*nodeconfigs.HTTPPagesPolicy), nil
}
}
pagesJSON, err := this.Query(tx).
Pk(clusterId).
Result("httpPages").
FindJSONCol()
if err != nil {
return nil, err
}
if IsNull(pagesJSON) {
return nodeconfigs.NewHTTPPagesPolicy(), nil
}
var policy = nodeconfigs.NewHTTPPagesPolicy()
err = json.Unmarshal(pagesJSON, policy)
if err != nil {
return nil, err
}
// 读取Page信息
var newPages = []*serverconfigs.HTTPPageConfig{}
for _, page := range policy.Pages {
pageConfig, err := SharedHTTPPageDAO.ComposePageConfig(tx, page.Id, cacheMap)
if err != nil {
return nil, err
}
if pageConfig == nil {
continue
}
newPages = append(newPages, pageConfig)
}
policy.Pages = newPages
return policy, nil
}
// FindClusterDDoSProtection 获取集群的DDoS设置
func (this *NodeClusterDAO) FindClusterDDoSProtection(tx *dbs.Tx, clusterId int64) (*ddosconfigs.ProtectionConfig, error) {
one, err := this.Query(tx).
@@ -1174,7 +1399,7 @@ func (this *NodeClusterDAO) FindClusterGlobalServerConfig(tx *dbs.Tx, clusterId
return nil, err
}
var config = serverconfigs.DefaultGlobalServerConfig()
var config = serverconfigs.NewGlobalServerConfig()
if IsNull(configJSON) {
return config, nil
}
@@ -1190,7 +1415,7 @@ func (this *NodeClusterDAO) FindClusterGlobalServerConfig(tx *dbs.Tx, clusterId
// UpdateClusterGlobalServerConfig 修改全局服务配置
func (this *NodeClusterDAO) UpdateClusterGlobalServerConfig(tx *dbs.Tx, clusterId int64, config *serverconfigs.GlobalServerConfig) error {
if config == nil {
config = serverconfigs.DefaultGlobalServerConfig()
config = serverconfigs.NewGlobalServerConfig()
}
configJSON, err := json.Marshal(config)
if err != nil {
@@ -1217,12 +1442,28 @@ func (this *NodeClusterDAO) NotifyUAMUpdate(tx *dbs.Tx, clusterId int64) error {
return SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleNode, clusterId, 0, 0, NodeTaskTypeUAMPolicyChanged)
}
// NotifyHTTPCCUpdate 通知HTTP CC更新
func (this *NodeClusterDAO) NotifyHTTPCCUpdate(tx *dbs.Tx, clusterId int64) error {
return SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleNode, clusterId, 0, 0, NodeTaskTypeHTTPCCPolicyChanged)
}
// NotifyHTTP3Update 通知HTTP3更新
func (this *NodeClusterDAO) NotifyHTTP3Update(tx *dbs.Tx, clusterId int64) error {
return SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleNode, clusterId, 0, 0, NodeTaskTypeHTTP3PolicyChanged)
}
// NotifyHTTPPagesPolicyUpdate 通知HTTP Pages更新
func (this *NodeClusterDAO) NotifyHTTPPagesPolicyUpdate(tx *dbs.Tx, clusterId int64) error {
return SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleNode, clusterId, 0, 0, NodeTaskTypeHTTPPagesPolicyChanged)
}
// NotifyTOAUpdate 通知TOA变化
func (this *NodeClusterDAO) NotifyTOAUpdate(tx *dbs.Tx, clusterId int64) error {
return SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleNode, clusterId, 0, 0, NodeTaskTypeTOAChanged)
}
// NotifyDNSUpdate 通知DNS更新
// TODO 更新新的DNS解析记录的同时需要删除老的DNS解析记录
func (this *NodeClusterDAO) NotifyDNSUpdate(tx *dbs.Tx, clusterId int64) error {
err := dns.SharedDNSTaskDAO.CreateClusterTask(tx, clusterId, dns.DNSTaskTypeClusterChange)
if err != nil {
return err
}
return nil
return dns.SharedDNSTaskDAO.CreateClusterTask(tx, clusterId, dns.DNSTaskTypeClusterChange)
}

View File

@@ -2,6 +2,50 @@ package models
import "github.com/iwind/TeaGo/dbs"
const (
NodeClusterField_Id dbs.FieldName = "id" // ID
NodeClusterField_AdminId dbs.FieldName = "adminId" // 管理员ID
NodeClusterField_UserId dbs.FieldName = "userId" // 用户ID
NodeClusterField_IsOn dbs.FieldName = "isOn" // 是否启用
NodeClusterField_Name dbs.FieldName = "name" // 名称
NodeClusterField_UseAllAPINodes dbs.FieldName = "useAllAPINodes" // 是否使用所有API节点
NodeClusterField_ApiNodes dbs.FieldName = "apiNodes" // 使用的API节点
NodeClusterField_InstallDir dbs.FieldName = "installDir" // 安装目录
NodeClusterField_Order dbs.FieldName = "order" // 排序
NodeClusterField_CreatedAt dbs.FieldName = "createdAt" // 创建时间
NodeClusterField_GrantId dbs.FieldName = "grantId" // 默认认证方式
NodeClusterField_SshParams dbs.FieldName = "sshParams" // SSH默认参数
NodeClusterField_State dbs.FieldName = "state" // 状态
NodeClusterField_AutoRegister dbs.FieldName = "autoRegister" // 是否开启自动注册
NodeClusterField_UniqueId dbs.FieldName = "uniqueId" // 唯一ID
NodeClusterField_Secret dbs.FieldName = "secret" // 密钥
NodeClusterField_HealthCheck dbs.FieldName = "healthCheck" // 健康检查
NodeClusterField_DnsName dbs.FieldName = "dnsName" // DNS名称
NodeClusterField_DnsDomainId dbs.FieldName = "dnsDomainId" // 域名ID
NodeClusterField_Dns dbs.FieldName = "dns" // DNS配置
NodeClusterField_Toa dbs.FieldName = "toa" // TOA配置
NodeClusterField_CachePolicyId dbs.FieldName = "cachePolicyId" // 缓存策略ID
NodeClusterField_HttpFirewallPolicyId dbs.FieldName = "httpFirewallPolicyId" // WAF策略ID
NodeClusterField_AccessLog dbs.FieldName = "accessLog" // 访问日志设置
NodeClusterField_SystemServices dbs.FieldName = "systemServices" // 系统服务设置
NodeClusterField_TimeZone dbs.FieldName = "timeZone" // 时区
NodeClusterField_NodeMaxThreads dbs.FieldName = "nodeMaxThreads" // 节点最大线程数
NodeClusterField_DdosProtection dbs.FieldName = "ddosProtection" // DDoS防护设置
NodeClusterField_AutoOpenPorts dbs.FieldName = "autoOpenPorts" // 是否自动尝试开放端口
NodeClusterField_IsPinned dbs.FieldName = "isPinned" // 是否置顶
NodeClusterField_Webp dbs.FieldName = "webp" // WebP设置
NodeClusterField_Uam dbs.FieldName = "uam" // UAM设置
NodeClusterField_Clock dbs.FieldName = "clock" // 时钟配置
NodeClusterField_GlobalServerConfig dbs.FieldName = "globalServerConfig" // 全局服务配置
NodeClusterField_AutoRemoteStart dbs.FieldName = "autoRemoteStart" // 自动远程启动
NodeClusterField_AutoInstallNftables dbs.FieldName = "autoInstallNftables" // 自动安装nftables
NodeClusterField_IsAD dbs.FieldName = "isAD" // 是否为高防集群
NodeClusterField_HttpPages dbs.FieldName = "httpPages" // 自定义页面设置
NodeClusterField_Cc dbs.FieldName = "cc" // CC设置
NodeClusterField_Http3 dbs.FieldName = "http3" // HTTP3设置
NodeClusterField_AutoSystemTuning dbs.FieldName = "autoSystemTuning" // 是否自动调整系统参数
)
// NodeCluster 节点集群
type NodeCluster struct {
Id uint32 `field:"id"` // ID
@@ -41,6 +85,10 @@ type NodeCluster struct {
AutoRemoteStart bool `field:"autoRemoteStart"` // 自动远程启动
AutoInstallNftables bool `field:"autoInstallNftables"` // 自动安装nftables
IsAD bool `field:"isAD"` // 是否为高防集群
HttpPages dbs.JSON `field:"httpPages"` // 自定义页面设置
Cc dbs.JSON `field:"cc"` // CC设置
Http3 dbs.JSON `field:"http3"` // HTTP3设置
AutoSystemTuning bool `field:"autoSystemTuning"` // 是否自动调整系统参数
}
type NodeClusterOperator struct {
@@ -81,6 +129,10 @@ type NodeClusterOperator struct {
AutoRemoteStart any // 自动远程启动
AutoInstallNftables any // 自动安装nftables
IsAD any // 是否为高防集群
HttpPages any // 自定义页面设置
Cc any // CC设置
Http3 any // HTTP3设置
AutoSystemTuning any // 是否自动调整系统参数
}
func NewNodeClusterOperator() *NodeClusterOperator {

View File

@@ -60,7 +60,7 @@ func (this *NodeCluster) DecodeClock() *nodeconfigs.ClockConfig {
// DecodeGlobalServerConfig 解析全局服务配置
func (this *NodeCluster) DecodeGlobalServerConfig() *serverconfigs.GlobalServerConfig {
var config = serverconfigs.DefaultGlobalServerConfig()
var config = serverconfigs.NewGlobalServerConfig()
if IsNotNull(this.GlobalServerConfig) {
err := json.Unmarshal(this.GlobalServerConfig, config)
if err != nil {

View File

@@ -18,7 +18,6 @@ import (
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/ddosconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
"github.com/TeaOSLab/EdgeCommon/pkg/systemconfigs"
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
@@ -27,6 +26,7 @@ import (
"github.com/iwind/TeaGo/rands"
"github.com/iwind/TeaGo/types"
timeutil "github.com/iwind/TeaGo/utils/time"
"sort"
"strconv"
"strings"
"time"
@@ -295,6 +295,7 @@ func (this *NodeDAO) CountAllEnabledNodes(tx *dbs.Tx) (int64, error) {
func (this *NodeDAO) CountAllEnabledOfflineNodes(tx *dbs.Tx) (int64, error) {
return this.Query(tx).
State(NodeStateEnabled).
Attr("isOn", true).
Where("clusterId IN (SELECT id FROM "+SharedNodeClusterDAO.Table+" WHERE state=:clusterState)").
Param("clusterState", NodeClusterStateEnabled).
Where("(status IS NULL OR NOT JSON_EXTRACT(status, '$.isActive') OR UNIX_TIMESTAMP()-JSON_EXTRACT(status, '$.updatedAt')>60)").
@@ -356,7 +357,7 @@ func (this *NodeDAO) ListEnabledNodesMatch(tx *dbs.Tx,
// 关键词
if len(keyword) > 0 {
query.Where("(name LIKE :keyword OR JSON_EXTRACT(status,'$.hostname') LIKE :keyword OR id IN (SELECT nodeId FROM "+SharedNodeIPAddressDAO.Table+" WHERE ip LIKE :keyword))").
query.Where("(name LIKE :keyword OR JSON_EXTRACT(status,'$.hostname') LIKE :keyword OR "+this.Table+".id IN (SELECT nodeId FROM "+SharedNodeIPAddressDAO.Table+" WHERE ip LIKE :keyword))").
Param("keyword", dbutils.QuoteLike(keyword))
}
@@ -1038,9 +1039,7 @@ func (this *NodeDAO) ComposeNodeConfig(tx *dbs.Tx, nodeId int64, dataMap *shared
if err != nil {
return nil, err
}
for _, clusterServer := range clusterServers {
servers = append(servers, clusterServer)
}
servers = append(servers, clusterServers...)
}
for _, server := range servers {
@@ -1058,33 +1057,15 @@ func (this *NodeDAO) ComposeNodeConfig(tx *dbs.Tx, nodeId int64, dataMap *shared
}
}
// 全局设置
// TODO 根据用户的不同读取不同的全局设置
var settingCacheKey = "SharedSysSettingDAO:" + systemconfigs.SettingCodeServerGlobalConfig
settingJSONCache, ok := cacheMap.Get(settingCacheKey)
var settingJSON = []byte{}
if ok {
settingJSON = settingJSONCache.([]byte)
} else {
settingJSON, err = SharedSysSettingDAO.ReadSetting(tx, systemconfigs.SettingCodeServerGlobalConfig)
if err != nil {
return nil, err
}
cacheMap.Put(settingCacheKey, settingJSON)
}
if len(settingJSON) > 0 {
globalConfig := &serverconfigs.GlobalConfig{}
err = json.Unmarshal(settingJSON, globalConfig)
if err != nil {
return nil, err
}
config.GlobalConfig = globalConfig
}
var clusterIndex = 0
config.WebPImagePolicies = map[int64]*nodeconfigs.WebPImagePolicy{}
config.UAMPolicies = map[int64]*nodeconfigs.UAMPolicy{}
config.HTTPCCPolicies = map[int64]*nodeconfigs.HTTPCCPolicy{}
config.HTTP3Policies = map[int64]*nodeconfigs.HTTP3Policy{}
config.HTTPPagesPolicies = map[int64]*nodeconfigs.HTTPPagesPolicy{}
var cachePolicyIds = []int64{}
var allowIPMaps = map[string]bool{}
for _, clusterId := range clusterIds {
nodeCluster, err := SharedNodeClusterDAO.FindClusterBasicInfo(tx, clusterId, cacheMap)
@@ -1112,7 +1093,7 @@ func (this *NodeDAO) ComposeNodeConfig(tx *dbs.Tx, nodeId int64, dataMap *shared
// 防火墙
var httpFirewallPolicyId = int64(nodeCluster.HttpFirewallPolicyId)
if httpFirewallPolicyId > 0 {
firewallPolicy, err := SharedHTTPFirewallPolicyDAO.ComposeFirewallPolicy(tx, httpFirewallPolicyId, cacheMap)
firewallPolicy, err := SharedHTTPFirewallPolicyDAO.ComposeFirewallPolicy(tx, httpFirewallPolicyId, true, cacheMap)
if err != nil {
return nil, err
}
@@ -1124,12 +1105,15 @@ func (this *NodeDAO) ComposeNodeConfig(tx *dbs.Tx, nodeId int64, dataMap *shared
// 缓存策略
var httpCachePolicyId = int64(nodeCluster.CachePolicyId)
if httpCachePolicyId > 0 {
cachePolicy, err := SharedHTTPCachePolicyDAO.ComposeCachePolicy(tx, httpCachePolicyId, cacheMap)
if err != nil {
return nil, err
}
if cachePolicy != nil {
config.HTTPCachePolicies = append(config.HTTPCachePolicies, cachePolicy)
if !lists.ContainsInt64(cachePolicyIds, httpCachePolicyId) {
cachePolicyIds = append(cachePolicyIds, httpCachePolicyId)
cachePolicy, err := SharedHTTPCachePolicyDAO.ComposeCachePolicy(tx, httpCachePolicyId, cacheMap)
if err != nil {
return nil, err
}
if cachePolicy != nil {
config.HTTPCachePolicies = append(config.HTTPCachePolicies, cachePolicy)
}
}
}
@@ -1170,7 +1154,7 @@ func (this *NodeDAO) ComposeNodeConfig(tx *dbs.Tx, nodeId int64, dataMap *shared
// UAM
if IsNotNull(nodeCluster.Uam) {
var uamPolicy = &nodeconfigs.UAMPolicy{}
var uamPolicy = nodeconfigs.NewUAMPolicy()
err = json.Unmarshal(nodeCluster.Uam, uamPolicy)
if err != nil {
return nil, err
@@ -1178,9 +1162,63 @@ func (this *NodeDAO) ComposeNodeConfig(tx *dbs.Tx, nodeId int64, dataMap *shared
config.UAMPolicies[clusterId] = uamPolicy
}
// HTTP CC Policy
if IsNotNull(nodeCluster.Cc) {
var ccPolicy = nodeconfigs.NewHTTPCCPolicy()
err = json.Unmarshal(nodeCluster.Cc, ccPolicy)
if err != nil {
return nil, err
}
// 集成默认设置
for i := 0; i < len(serverconfigs.DefaultHTTPCCThresholds); i++ {
if i < len(ccPolicy.Thresholds) {
ccPolicy.Thresholds[i].MergeIfEmpty(serverconfigs.DefaultHTTPCCThresholds[i])
}
}
config.HTTPCCPolicies[clusterId] = ccPolicy
}
// HTTP3 Policy
if IsNotNull(nodeCluster.Http3) {
var http3Policy = nodeconfigs.NewHTTP3Policy()
err = json.Unmarshal(nodeCluster.Http3, http3Policy)
if err != nil {
return nil, err
}
config.HTTP3Policies[clusterId] = http3Policy
}
// HTTP Pages Policy
if IsNotNull(nodeCluster.HttpPages) {
var httpPagesPolicy = nodeconfigs.NewHTTPPagesPolicy()
err = json.Unmarshal(nodeCluster.HttpPages, httpPagesPolicy)
if err != nil {
return nil, err
}
if httpPagesPolicy.IsOn {
var newPages = []*serverconfigs.HTTPPageConfig{}
for _, page := range httpPagesPolicy.Pages {
pageConfig, err := SharedHTTPPageDAO.ComposePageConfig(tx, page.Id, cacheMap)
if err != nil {
return nil, err
}
if pageConfig != nil && pageConfig.IsOn {
newPages = append(newPages, pageConfig)
}
}
httpPagesPolicy.Pages = newPages
if len(newPages) > 0 {
config.HTTPPagesPolicies[clusterId] = httpPagesPolicy
}
}
}
// 自动安装nftables
if clusterIndex == 0 {
config.AutoInstallNftables = nodeCluster.AutoInstallNftables
config.AutoSystemTuning = nodeCluster.AutoSystemTuning
}
clusterIndex++
@@ -1394,7 +1432,7 @@ func (this *NodeDAO) CountAllEnabledNodesWithGrantId(tx *dbs.Tx, grantId int64)
func (this *NodeDAO) FindAllEnabledNodesWithGrantId(tx *dbs.Tx, grantId int64) (result []*Node, err error) {
_, err = this.Query(tx).
State(NodeStateEnabled).
Where("id IN (SELECT nodeId FROM edgeNodeLogins WHERE type='ssh' AND JSON_CONTAINS(params, :grantParam))").
Where("id IN (SELECT nodeId FROM edgeNodeLogins WHERE type='ssh' AND JSON_CONTAINS(params, :grantParam) AND state=1)").
Param("grantParam", string(maps.Map{"grantId": grantId}.AsJSON())).
Where("clusterId IN (SELECT id FROM edgeNodeClusters WHERE state=1)").
Slice(&result).
@@ -1428,6 +1466,7 @@ func (this *NodeDAO) FindAllNotInstalledNodesWithClusterId(tx *dbs.Tx, clusterId
func (this *NodeDAO) CountAllLowerVersionNodesWithClusterId(tx *dbs.Tx, clusterId int64, os string, arch string, version string) (int64, error) {
return this.Query(tx).
State(NodeStateEnabled).
Attr("isOn", true).
Attr("clusterId", clusterId).
Where("status IS NOT NULL").
Where("JSON_EXTRACT(status, '$.os')=:os").
@@ -1461,6 +1500,7 @@ func (this *NodeDAO) FindAllLowerVersionNodesWithClusterId(tx *dbs.Tx, clusterId
func (this *NodeDAO) CountAllLowerVersionNodes(tx *dbs.Tx, version string) (int64, error) {
return this.Query(tx).
State(NodeStateEnabled).
Attr("isOn", true).
Where("clusterId IN (SELECT id FROM "+SharedNodeClusterDAO.Table+" WHERE state=1)").
Where("status IS NOT NULL").
Where("(JSON_EXTRACT(status, '$.buildVersionCode') IS NULL OR JSON_EXTRACT(status, '$.buildVersionCode')<:version)").
@@ -1550,7 +1590,7 @@ func (this *NodeDAO) FindAllEnabledNodesDNSWithClusterId(tx *dbs.Tx, clusterId i
Attr("isOn", true).
Attr("isUp", true).
Attr("isInstalled", isInstalled).
Result("id", "name", "dnsRoutes", "isOn").
Result("id", "name", "dnsRoutes", "isOn", "offlineDay", "actionStatus", "isBackupForCluster", "isBackupForGroup", "backupIPs", "clusterId", "groupId").
DescPk().
Slice(&result).
FindAll()
@@ -1575,7 +1615,7 @@ func (this *NodeDAO) FindEnabledNodeDNS(tx *dbs.Tx, nodeId int64) (*Node, error)
one, err := this.Query(tx).
State(NodeStateEnabled).
Pk(nodeId).
Result("id", "name", "dnsRoutes", "clusterId", "isOn").
Result("id", "name", "dnsRoutes", "clusterId", "isOn", "offlineDay", "isBackupForCluster", "isBackupForGroup", "actionStatus").
Find()
if one == nil {
return nil, err
@@ -2059,12 +2099,18 @@ func (this *NodeDAO) FindParentNodeConfigs(tx *dbs.Tx, nodeId int64, groupId int
var secretHash = fmt.Sprintf("%x", sha256.Sum256([]byte(node.UniqueId+"@"+node.Secret)))
for _, clusterId := range node.AllClusterIds() {
parentNodeConfigs, _ := result[clusterId]
var parentNodeConfigs = result[clusterId]
parentNodeConfigs = append(parentNodeConfigs, &nodeconfigs.ParentNodeConfig{
Id: int64(node.Id),
Addrs: addrStrings,
SecretHash: secretHash,
})
// 排序
sort.Slice(parentNodeConfigs, func(i, j int) bool {
return parentNodeConfigs[i].Id < parentNodeConfigs[j].Id
})
result[clusterId] = parentNodeConfigs
}
}

View File

@@ -18,3 +18,8 @@ func (this *NodeDAO) loadServersFromCluster(tx *dbs.Tx, clusterId int64, serverI
func (this *NodeDAO) composeExtConfig(tx *dbs.Tx, config *nodeconfigs.NodeConfig, clusterIds []int64, cacheMap *utils.CacheMap) error {
return nil
}
// CheckNodeIPAddresses 检查节点IP地址
func (this *NodeDAO) CheckNodeIPAddresses(tx *dbs.Tx, node *Node) (shouldSkip bool, shouldOverwrite bool, ipAddressStrings []string, err error) {
return
}

View File

@@ -307,7 +307,7 @@ func (this *NodeIPAddressDAO) FindFirstNodeAccessIPAddressId(tx *dbs.Tx, nodeId
FindInt64Col(0)
}
// FindNodeAccessAndUpIPAddresses 查找节点所有的可访问的IP地址
// FindNodeAccessAndUpIPAddresses 查找节点所有的可访问且在线的IP地址
func (this *NodeIPAddressDAO) FindNodeAccessAndUpIPAddresses(tx *dbs.Tx, nodeId int64, role nodeconfigs.NodeRole) (result []*NodeIPAddress, err error) {
if len(role) == 0 {
role = nodeconfigs.NodeRoleNode
@@ -326,6 +326,24 @@ func (this *NodeIPAddressDAO) FindNodeAccessAndUpIPAddresses(tx *dbs.Tx, nodeId
return
}
// FindNodeAccessIPAddresses 查找节点所有的可访问的IP地址包括在线和离线
func (this *NodeIPAddressDAO) FindNodeAccessIPAddresses(tx *dbs.Tx, nodeId int64, role nodeconfigs.NodeRole) (result []*NodeIPAddress, err error) {
if len(role) == 0 {
role = nodeconfigs.NodeRoleNode
}
_, err = this.Query(tx).
Attr("role", role).
Attr("nodeId", nodeId).
State(NodeIPAddressStateEnabled).
Attr("canAccess", true).
Attr("isOn", true).
Desc("order").
AscPk().
Slice(&result).
FindAll()
return
}
// CountAllEnabledIPAddresses 计算IP地址数量
// TODO 目前支持边缘节点将来支持NS节点
func (this *NodeIPAddressDAO) CountAllEnabledIPAddresses(tx *dbs.Tx, role string, nodeClusterId int64, upState configutils.BoolState, keyword string) (int64, error) {

View File

@@ -43,6 +43,12 @@ type Node struct {
DnsResolver dbs.JSON `field:"dnsResolver"` // DNS解析器
EnableIPLists bool `field:"enableIPLists"` // 启用IP名单
ApiNodeAddrs dbs.JSON `field:"apiNodeAddrs"` // API节点地址
OfflineDay string `field:"offlineDay"` // 下线日期YYYYMMDD
OfflineIsNotified bool `field:"offlineIsNotified"` // 下线是否已通知
IsBackupForCluster bool `field:"isBackupForCluster"` // 是否为集群备用节点
IsBackupForGroup bool `field:"isBackupForGroup"` // 是否为分组备用节点
BackupIPs dbs.JSON `field:"backupIPs"` // 备用IP
ActionStatus dbs.JSON `field:"actionStatus"` // 当前动作配置
}
type NodeOperator struct {
@@ -85,6 +91,12 @@ type NodeOperator struct {
DnsResolver any // DNS解析器
EnableIPLists any // 启用IP名单
ApiNodeAddrs any // API节点地址
OfflineDay any // 下线日期YYYYMMDD
OfflineIsNotified any // 下线是否已通知
IsBackupForCluster any // 是否为集群备用节点
IsBackupForGroup any // 是否为分组备用节点
BackupIPs any // 备用IP
ActionStatus any // 当前动作配置
}
func NewNodeOperator() *NodeOperator {

View File

@@ -7,6 +7,7 @@ import (
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/ddosconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
timeutil "github.com/iwind/TeaGo/utils/time"
"sort"
"time"
)
@@ -16,7 +17,7 @@ func (this *Node) DecodeInstallStatus() (*NodeInstallStatus, error) {
if len(this.InstallStatus) == 0 {
return NewNodeInstallStatus(), nil
}
status := &NodeInstallStatus{}
var status = &NodeInstallStatus{}
err := json.Unmarshal(this.InstallStatus, status)
if err != nil {
return NewNodeInstallStatus(), err
@@ -37,7 +38,7 @@ func (this *Node) DecodeStatus() (*nodeconfigs.NodeStatus, error) {
if len(this.Status) == 0 {
return nil, nil
}
status := &nodeconfigs.NodeStatus{}
var status = &nodeconfigs.NodeStatus{}
err := json.Unmarshal(this.Status, status)
if err != nil {
return nil, err
@@ -47,7 +48,7 @@ func (this *Node) DecodeStatus() (*nodeconfigs.NodeStatus, error) {
// DNSRouteCodes 所有的DNS线路
func (this *Node) DNSRouteCodes() map[int64][]string {
routes := map[int64][]string{} // domainId => routes
var routes = map[int64][]string{} // domainId => routes
if len(this.DnsRoutes) == 0 {
return routes
}
@@ -61,7 +62,7 @@ func (this *Node) DNSRouteCodes() map[int64][]string {
// DNSRouteCodesForDomainId DNS线路
func (this *Node) DNSRouteCodesForDomainId(dnsDomainId int64) ([]string, error) {
routes := map[int64][]string{} // domainId => routes
var routes = map[int64][]string{} // domainId => routes
if len(this.DnsRoutes) == 0 {
return nil, nil
}
@@ -69,8 +70,7 @@ func (this *Node) DNSRouteCodesForDomainId(dnsDomainId int64) ([]string, error)
if err != nil {
return nil, err
}
domainRoutes, _ := routes[dnsDomainId]
var domainRoutes = routes[dnsDomainId]
if len(domainRoutes) > 0 {
sort.Strings(domainRoutes)
}
@@ -80,7 +80,7 @@ func (this *Node) DNSRouteCodesForDomainId(dnsDomainId int64) ([]string, error)
// DecodeConnectedAPINodeIds 连接的API
func (this *Node) DecodeConnectedAPINodeIds() ([]int64, error) {
apiNodeIds := []int64{}
var apiNodeIds = []int64{}
if IsNotNull(this.ConnectedAPINodes) {
err := json.Unmarshal(this.ConnectedAPINodes, &apiNodeIds)
if err != nil {
@@ -214,3 +214,8 @@ func (this *Node) DecodeAPINodeAddrs() []*serverconfigs.NetworkAddressConfig {
}
return result
}
// CheckIsOffline 检查是否已经离线
func (this *Node) CheckIsOffline() bool {
return len(this.OfflineDay) > 0 && this.OfflineDay < timeutil.Format("Ymd")
}

View File

@@ -0,0 +1,9 @@
// Copyright 2023 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
//go:build !plus
package models
// HasScheduleSettings 检查是否设置了调度
func (this *Node) HasScheduleSettings() bool {
return false
}

View File

@@ -8,6 +8,7 @@ import (
"github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/maps"
"github.com/iwind/TeaGo/types"
"strings"
"time"
)
@@ -19,13 +20,18 @@ const (
NodeTaskTypeConfigChanged NodeTaskType = "configChanged" // 节点整体配置变化
NodeTaskTypeDDosProtectionChanged NodeTaskType = "ddosProtectionChanged" // 节点DDoS配置变更
NodeTaskTypeGlobalServerConfigChanged NodeTaskType = "globalServerConfigChanged" // 全局服务设置变化
NodeTaskTypeIPListDeleted NodeTaskType = "ipListDeleted" // IPList被删除
NodeTaskTypeIPItemChanged NodeTaskType = "ipItemChanged" // IP条目变更
NodeTaskTypeNodeVersionChanged NodeTaskType = "nodeVersionChanged" // 节点版本变化
NodeTaskTypeScriptsChanged NodeTaskType = "scriptsChanged" // 脚本配置变化
NodeTaskTypeNodeLevelChanged NodeTaskType = "nodeLevelChanged" // 节点级别变化
NodeTaskTypeUserServersStateChanged NodeTaskType = "userServersStateChanged" // 用户服务状态变化
NodeTaskTypeUAMPolicyChanged NodeTaskType = "uamPolicyChanged" // UAM策略变化
NodeTaskTypeHTTPPagesPolicyChanged NodeTaskType = "httpPagesPolicyChanged" // 自定义页面变化
NodeTaskTypeHTTPCCPolicyChanged NodeTaskType = "httpCCPolicyChanged" // CC策略变化
NodeTaskTypeHTTP3PolicyChanged NodeTaskType = "http3PolicyChanged" // HTTP3策略变化
NodeTaskTypeUpdatingServers NodeTaskType = "updatingServers" // 更新一组服务
NodeTaskTypeTOAChanged NodeTaskType = "toaChanged" // TOA配置变化
// NS相关
@@ -230,6 +236,12 @@ func (this *NodeTaskDAO) DeleteNodeTasks(tx *dbs.Tx, role string, nodeId int64)
return err
}
// DeleteAllNodeTasks 删除所有节点相关任务
func (this *NodeTaskDAO) DeleteAllNodeTasks(tx *dbs.Tx) error {
return this.Query(tx).
DeleteQuickly()
}
// FindDoingNodeTasks 查询一个节点的所有任务
func (this *NodeTaskDAO) FindDoingNodeTasks(tx *dbs.Tx, role string, nodeId int64, version int64) (result []*NodeTask, err error) {
if nodeId <= 0 {
@@ -255,6 +267,23 @@ func (this *NodeTaskDAO) FindDoingNodeTasks(tx *dbs.Tx, role string, nodeId int6
// UpdateNodeTaskDone 修改节点任务的完成状态
func (this *NodeTaskDAO) UpdateNodeTaskDone(tx *dbs.Tx, taskId int64, isOk bool, errorMessage string) error {
if isOk {
// 特殊任务删除
taskType, err := this.Query(tx).
Pk(taskId).
Result("type").
FindStringCol("")
if err != nil {
return err
}
if strings.HasPrefix(taskType, NodeTaskTypeIPListDeleted+"@") {
return this.Query(tx).
Pk(taskId).
DeleteQuickly()
}
}
// 其他任务标记为完成
var query = this.Query(tx).
Pk(taskId)
if !isOk {
@@ -264,8 +293,9 @@ func (this *NodeTaskDAO) UpdateNodeTaskDone(tx *dbs.Tx, taskId int64, isOk bool,
}
query.Set("version", version)
}
_, err := query.
Set("isDone", 1).
Set("isDone", true).
Set("isOk", isOk).
Set("error", errorMessage).
Update()
@@ -297,8 +327,8 @@ func (this *NodeTaskDAO) FindAllDoingNodeTasksWithClusterId(tx *dbs.Tx, role str
Gt("nodeId", 0).
Where("(isDone=0 OR (isDone=1 AND isOk=0))").
Desc("isDone").
Asc().
Asc("nodeId").
AscPk().
Slice(&result).
FindAll()
return

View File

@@ -54,3 +54,12 @@ func TestNodeTaskDAO_FindDoingNodeTasks(t *testing.T) {
t.Fatal(err)
}
}
func TestNodeTaskDAO_UpdateNodeTaskDone(t *testing.T) {
var tx *dbs.Tx
var dao = models.NewNodeTaskDAO()
err := dao.UpdateNodeTaskDone(tx, 1741, true, "")
if err != nil {
t.Fatal(err)
}
}

View File

@@ -1,4 +1,4 @@
package stats
package models
import (
"github.com/TeaOSLab/EdgeAPI/internal/errors"
@@ -22,7 +22,7 @@ func init() {
var ticker = time.NewTicker(time.Duration(rands.Int(24, 48)) * time.Hour)
goman.New(func() {
for range ticker.C {
err := SharedNodeTrafficDailyStatDAO.Clean(nil, 30) // 只保留N天
err := SharedNodeTrafficDailyStatDAO.CleanDefaultDays(nil, 32) // 只保留N天
if err != nil {
remotelogs.Error("NodeTrafficDailyStatDAO", "clean expired data failed: "+err.Error())
}
@@ -84,7 +84,9 @@ func (this *NodeTrafficDailyStatDAO) IncreaseDailyStat(tx *dbs.Tx, clusterId int
if err != nil {
return err
}
return nil
// 触发钩子
return this.increaseDailyStatHook(tx, role, nodeId)
}
// FindDailyStats 获取日期之间统计
@@ -132,11 +134,27 @@ func (this *NodeTrafficDailyStatDAO) SumDailyStat(tx *dbs.Tx, role string, nodeI
return one.(*NodeTrafficDailyStat), nil
}
// Clean 清理历史数据
func (this *NodeTrafficDailyStatDAO) Clean(tx *dbs.Tx, days int) error {
// CleanDays 清理历史数据
func (this *NodeTrafficDailyStatDAO) CleanDays(tx *dbs.Tx, days int) error {
var day = timeutil.Format("Ymd", time.Now().AddDate(0, 0, -days))
_, err := this.Query(tx).
Lt("day", day).
Delete()
return err
}
func (this *NodeTrafficDailyStatDAO) CleanDefaultDays(tx *dbs.Tx, defaultDays int) error {
databaseConfig, err := SharedSysSettingDAO.ReadDatabaseConfig(tx)
if err != nil {
return err
}
if databaseConfig != nil && databaseConfig.NodeTrafficDailyStat.Clean.Days > 0 {
defaultDays = databaseConfig.NodeTrafficDailyStat.Clean.Days
}
if defaultDays <= 0 {
defaultDays = 32
}
return this.CleanDays(tx, defaultDays)
}

View File

@@ -0,0 +1,14 @@
// Copyright 2023 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
//go:build !plus
package models
import (
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
"github.com/iwind/TeaGo/dbs"
)
// 增加日统计Hook
func (this *NodeTrafficDailyStatDAO) increaseDailyStatHook(tx *dbs.Tx, role nodeconfigs.NodeRole, nodeId int64) error {
return nil
}

View File

@@ -1,4 +1,4 @@
package stats
package models
import (
_ "github.com/go-sql-driver/mysql"

View File

@@ -1,4 +1,4 @@
package stats
package models
// NodeTrafficDailyStat 总的流量统计(按天)
type NodeTrafficDailyStat struct {

View File

@@ -0,0 +1 @@
package models

View File

@@ -37,11 +37,15 @@ func init() {
// CreateValue 创建值
func (this *NodeValueDAO) CreateValue(tx *dbs.Tx, clusterId int64, role nodeconfigs.NodeRole, nodeId int64, item string, valueJSON []byte, createdAt int64) error {
if len(valueJSON) == 0 {
return errors.New("'valueJSON' should not be nil")
}
var day = timeutil.FormatTime("Ymd", createdAt)
var hour = timeutil.FormatTime("YmdH", createdAt)
var minute = timeutil.FormatTime("YmdHi", createdAt)
return this.Query(tx).
err := this.Query(tx).
InsertOrUpdateQuickly(maps.Map{
"clusterId": clusterId,
"role": role,
@@ -55,6 +59,17 @@ func (this *NodeValueDAO) CreateValue(tx *dbs.Tx, clusterId int64, role nodeconf
}, maps.Map{
"value": valueJSON,
})
if err != nil {
return err
}
// 触发钩子
err = this.nodeValueHook(tx, role, nodeId, item, valueJSON)
if err != nil {
return err
}
return nil
}
// Clean 清除数据
@@ -324,7 +339,7 @@ func (this *NodeValueDAO) SumNodeClusterValues(tx *dbs.Tx, role string, clusterI
// FindLatestNodeValue 获取最近一条数据
func (this *NodeValueDAO) FindLatestNodeValue(tx *dbs.Tx, role string, nodeId int64, item string) (*NodeValue, error) {
fromMinute := timeutil.FormatTime("YmdHi", time.Now().Unix()-int64(60))
var fromMinute = timeutil.FormatTime("YmdHi", time.Now().Unix()-int64(60))
one, err := this.Query(tx).
Attr("role", role).

View File

@@ -0,0 +1,14 @@
// Copyright 2023 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
//go:build !plus
package models
import (
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
"github.com/iwind/TeaGo/dbs"
)
// 节点值变更Hook
func (this *NodeValueDAO) nodeValueHook(tx *dbs.Tx, role nodeconfigs.NodeRole, nodeId int64, item nodeconfigs.NodeValueItem, valueJSON []byte) error {
return nil
}

View File

@@ -15,6 +15,7 @@ type NSCluster struct {
Tcp dbs.JSON `field:"tcp"` // TCP设置
Tls dbs.JSON `field:"tls"` // TLS设置
Udp dbs.JSON `field:"udp"` // UDP设置
Doh dbs.JSON `field:"doh"` // DoH设置
DdosProtection dbs.JSON `field:"ddosProtection"` // DDoS防护设置
Hosts dbs.JSON `field:"hosts"` // DNS主机地址
Soa dbs.JSON `field:"soa"` // SOA配置
@@ -39,6 +40,7 @@ type NSClusterOperator struct {
Tcp any // TCP设置
Tls any // TLS设置
Udp any // UDP设置
Doh any // DoH设置
DdosProtection any // DDoS防护设置
Hosts any // DNS主机地址
Soa any // SOA配置

View File

@@ -93,6 +93,7 @@ func (this *NSNodeDAO) CountAllLowerVersionNodesWithClusterId(tx *dbs.Tx, cluste
return this.Query(tx).
State(NSNodeStateEnabled).
Attr("clusterId", clusterId).
Attr("isOn", true).
Where("status IS NOT NULL").
Where("JSON_EXTRACT(status, '$.os')=:os").
Where("JSON_EXTRACT(status, '$.arch')=:arch").
@@ -161,6 +162,7 @@ func (this *NSNodeDAO) UpdateNodeStatus(tx *dbs.Tx, nodeId int64, nodeStatus *no
func (this *NSNodeDAO) CountAllLowerVersionNodes(tx *dbs.Tx, version string) (int64, error) {
return this.Query(tx).
State(NSNodeStateEnabled).
Attr("isOn", true).
Where("clusterId IN (SELECT id FROM "+SharedNSClusterDAO.Table+" WHERE state=1)").
Where("status IS NOT NULL").
Where("(JSON_EXTRACT(status, '$.buildVersionCode') IS NULL OR JSON_EXTRACT(status, '$.buildVersionCode')<:version)").

View File

@@ -5,6 +5,7 @@ import (
"errors"
"github.com/TeaOSLab/EdgeAPI/internal/utils"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/ossconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/sslconfigs"
_ "github.com/go-sql-driver/mysql"
@@ -91,7 +92,8 @@ func (this *OriginDAO) CreateOrigin(tx *dbs.Tx,
adminId int64,
userId int64,
name string,
addrJSON string,
addrJSON []byte,
ossConfig *ossconfigs.OSSConfig,
description string,
weight int32, isOn bool,
connTimeout *shared.TimeDuration,
@@ -102,7 +104,8 @@ func (this *OriginDAO) CreateOrigin(tx *dbs.Tx,
certRef *sslconfigs.SSLCertRef,
domains []string,
host string,
followPort bool) (originId int64, err error) {
followPort bool,
http2Enabled bool) (originId int64, err error) {
var op = NewOriginOperator()
op.AdminId = adminId
op.UserId = userId
@@ -141,7 +144,18 @@ func (this *OriginDAO) CreateOrigin(tx *dbs.Tx,
op.MaxIdleConns = 0
}
op.Addr = addrJSON
if len(addrJSON) > 0 {
op.Addr = addrJSON
}
if ossConfig != nil {
ossConfigJSON, err := json.Marshal(ossConfig)
if err != nil {
return 0, err
}
op.Oss = ossConfigJSON
}
op.Description = description
if weight < 0 {
weight = 0
@@ -169,6 +183,7 @@ func (this *OriginDAO) CreateOrigin(tx *dbs.Tx,
op.Host = host
op.FollowPort = followPort
op.Http2Enabled = http2Enabled
op.State = OriginStateEnabled
err = this.Save(tx, op)
@@ -182,7 +197,8 @@ func (this *OriginDAO) CreateOrigin(tx *dbs.Tx,
func (this *OriginDAO) UpdateOrigin(tx *dbs.Tx,
originId int64,
name string,
addrJSON string,
addrJSON []byte,
ossConfig *ossconfigs.OSSConfig,
description string,
weight int32,
isOn bool,
@@ -194,14 +210,25 @@ func (this *OriginDAO) UpdateOrigin(tx *dbs.Tx,
certRef *sslconfigs.SSLCertRef,
domains []string,
host string,
followPort bool) error {
followPort bool,
http2Enabled bool) error {
if originId <= 0 {
return errors.New("invalid originId")
}
var op = NewOriginOperator()
op.Id = originId
op.Name = name
op.Addr = addrJSON
if ossConfig != nil {
ossConfigJSON, err := json.Marshal(ossConfig)
if err != nil {
return err
}
op.Oss = ossConfigJSON
}
op.Description = description
if weight < 0 {
weight = 0
@@ -266,6 +293,7 @@ func (this *OriginDAO) UpdateOrigin(tx *dbs.Tx,
op.Host = host
op.FollowPort = followPort
op.Http2Enabled = http2Enabled
err := this.Save(tx, op)
if err != nil {
@@ -329,6 +357,7 @@ func (this *OriginDAO) CloneOrigin(tx *dbs.Tx, fromOriginId int64) (newOriginId
op.Domains = origin.Domains
}
op.FollowPort = origin.FollowPort
op.Http2Enabled = origin.Http2Enabled
op.State = origin.State
return this.SaveInt64(tx, op)
}
@@ -367,8 +396,10 @@ func (this *OriginDAO) ComposeOriginConfig(tx *dbs.Tx, originId int64, dataMap *
RequestHost: origin.Host,
Domains: origin.DecodeDomains(),
FollowPort: origin.FollowPort,
HTTP2Enabled: origin.Http2Enabled,
}
// addr
if IsNotNull(origin.Addr) {
var addr = &serverconfigs.NetworkAddressConfig{}
err = json.Unmarshal(origin.Addr, addr)
@@ -378,6 +409,16 @@ func (this *OriginDAO) ComposeOriginConfig(tx *dbs.Tx, originId int64, dataMap *
config.Addr = addr
}
// oss
if IsNotNull(origin.Oss) {
var ossConfig = ossconfigs.NewOSSConfig()
err = json.Unmarshal(origin.Oss, ossConfig)
if err != nil {
return nil, err
}
config.OSS = ossConfig
}
if IsNotNull(origin.ConnTimeout) {
var connTimeout = &shared.TimeDuration{}
err = json.Unmarshal(origin.ConnTimeout, &connTimeout)

View File

@@ -11,6 +11,7 @@ type Origin struct {
Name string `field:"name"` // 名称
Version uint32 `field:"version"` // 版本
Addr dbs.JSON `field:"addr"` // 地址
Oss dbs.JSON `field:"oss"` // OSS配置
Description string `field:"description"` // 描述
Code string `field:"code"` // 代号
Weight uint32 `field:"weight"` // 权重
@@ -31,36 +32,39 @@ type Origin struct {
Domains dbs.JSON `field:"domains"` // 所属域名
FollowPort bool `field:"followPort"` // 端口跟随
State uint8 `field:"state"` // 状态
Http2Enabled bool `field:"http2Enabled"` // 是否支持HTTP/2
}
type OriginOperator struct {
Id interface{} // ID
AdminId interface{} // 管理员ID
UserId interface{} // 用户ID
IsOn interface{} // 是否启用
Name interface{} // 名称
Version interface{} // 版本
Addr interface{} // 地址
Description interface{} // 描述
Code interface{} // 代号
Weight interface{} // 权重
ConnTimeout interface{} // 连接超时
ReadTimeout interface{} // 超时
IdleTimeout interface{} // 空闲连接超时
MaxFails interface{} // 最多失败次数
MaxConns interface{} // 最大并发连接
MaxIdleConns interface{} // 最多空闲连接数
HttpRequestURI interface{} // 转发后的请求URI
HttpRequestHeader interface{} // 请求Header配置
HttpResponseHeader interface{} // 响应Header配置
Host interface{} // 自定义主机名
HealthCheck interface{} // 健康检查设置
Cert interface{} // 证书设置
Ftp interface{} // FTP相关设置
CreatedAt interface{} // 创建时间
Domains interface{} // 所属域名
FollowPort interface{} // 端口跟随
State interface{} // 状态
Id any // ID
AdminId any // 管理员ID
UserId any // 用户ID
IsOn any // 是否启用
Name any // 名称
Version any // 版本
Addr any // 地址
Oss any // OSS配置
Description any // 描述
Code any // 代号
Weight any // 权重
ConnTimeout any // 连接超时
ReadTimeout any // 超时
IdleTimeout any // 空闲连接超时
MaxFails any // 最多失败次
MaxConns any // 最大并发连接数
MaxIdleConns any // 最多空闲连接数
HttpRequestURI any // 转发后的请求URI
HttpRequestHeader any // 请求Header配置
HttpResponseHeader any // 响应Header配置
Host any // 自定义主机名
HealthCheck any // 健康检查设置
Cert any // 证书设置
Ftp any // FTP相关设置
CreatedAt any // 创建时间
Domains any // 所属域名
FollowPort any // 端口跟随
State any // 状态
Http2Enabled any // 是否支持HTTP/2
}
func NewOriginOperator() *OriginOperator {

View File

@@ -61,15 +61,28 @@ func (this *PlanDAO) DisablePlan(tx *dbs.Tx, id int64) error {
}
// FindEnabledPlan 查找启用中的条目
func (this *PlanDAO) FindEnabledPlan(tx *dbs.Tx, id int64) (*Plan, error) {
func (this *PlanDAO) FindEnabledPlan(tx *dbs.Tx, planId int64, cacheMap *utils.CacheMap) (*Plan, error) {
var cacheKey = this.Table + ":FindEnabledPlan:" + types.String(planId)
if cacheMap != nil {
cache, _ := cacheMap.Get(cacheKey)
if cache != nil {
return cache.(*Plan), nil
}
}
result, err := this.Query(tx).
Pk(id).
Pk(planId).
Attr("state", PlanStateEnabled).
Find()
if result == nil {
return nil, err
}
return result.(*Plan), err
if cacheMap != nil {
cacheMap.Put(cacheKey, result)
}
return result.(*Plan), nil
}
// FindPlanName 根据主键查找名称

View File

@@ -0,0 +1,6 @@
package models_test
import (
_ "github.com/go-sql-driver/mysql"
_ "github.com/iwind/TeaGo/bootstrap"
)

View File

@@ -2,39 +2,71 @@ package models
import "github.com/iwind/TeaGo/dbs"
const (
PlanField_Id dbs.FieldName = "id" // ID
PlanField_IsOn dbs.FieldName = "isOn" // 是否启用
PlanField_Name dbs.FieldName = "name" // 套餐名
PlanField_ClusterId dbs.FieldName = "clusterId" // 集群ID
PlanField_TrafficLimit dbs.FieldName = "trafficLimit" // 流量限制
PlanField_Features dbs.FieldName = "features" // 允许的功能
PlanField_TrafficPrice dbs.FieldName = "trafficPrice" // 流量价格设定
PlanField_BandwidthPrice dbs.FieldName = "bandwidthPrice" // 带宽价格
PlanField_MonthlyPrice dbs.FieldName = "monthlyPrice" // 月付
PlanField_SeasonallyPrice dbs.FieldName = "seasonallyPrice" // 季付
PlanField_YearlyPrice dbs.FieldName = "yearlyPrice" // 年付
PlanField_PriceType dbs.FieldName = "priceType" // 价格类型
PlanField_Order dbs.FieldName = "order" // 排序
PlanField_State dbs.FieldName = "state" // 状态
PlanField_TotalServers dbs.FieldName = "totalServers" // 可以绑定的网站数量
PlanField_TotalServerNamesPerServer dbs.FieldName = "totalServerNamesPerServer" // 每个网站可以绑定的域名数量
PlanField_TotalServerNames dbs.FieldName = "totalServerNames" // 总域名数量
PlanField_MonthlyRequests dbs.FieldName = "monthlyRequests" // 每月访问量额度
PlanField_DailyRequests dbs.FieldName = "dailyRequests" // 每日访问量额度
)
// Plan 用户套餐
type Plan struct {
Id uint32 `field:"id"` // ID
IsOn bool `field:"isOn"` // 是否启用
Name string `field:"name"` // 套餐名
ClusterId uint32 `field:"clusterId"` // 集群ID
TrafficLimit dbs.JSON `field:"trafficLimit"` // 流量限制
Features dbs.JSON `field:"features"` // 允许的功能
TrafficPrice dbs.JSON `field:"trafficPrice"` // 流量价格设定
BandwidthPrice dbs.JSON `field:"bandwidthPrice"` // 带宽价格
MonthlyPrice float64 `field:"monthlyPrice"` // 月付
SeasonallyPrice float64 `field:"seasonallyPrice"` // 季付
YearlyPrice float64 `field:"yearlyPrice"` // 年付
PriceType string `field:"priceType"` // 价格类型
Order uint32 `field:"order"` // 排序
State uint8 `field:"state"` // 状态
Id uint32 `field:"id"` // ID
IsOn bool `field:"isOn"` // 是否启用
Name string `field:"name"` // 套餐名
ClusterId uint32 `field:"clusterId"` // 集群ID
TrafficLimit dbs.JSON `field:"trafficLimit"` // 流量限制
Features dbs.JSON `field:"features"` // 允许的功能
TrafficPrice dbs.JSON `field:"trafficPrice"` // 流量价格设定
BandwidthPrice dbs.JSON `field:"bandwidthPrice"` // 带宽价格
MonthlyPrice float64 `field:"monthlyPrice"` // 月付
SeasonallyPrice float64 `field:"seasonallyPrice"` // 季付
YearlyPrice float64 `field:"yearlyPrice"` // 年付
PriceType string `field:"priceType"` // 价格类型
Order uint32 `field:"order"` // 排序
State uint8 `field:"state"` // 状态
TotalServers uint32 `field:"totalServers"` // 可以绑定的网站数量
TotalServerNamesPerServer uint32 `field:"totalServerNamesPerServer"` // 每个网站可以绑定的域名数量
TotalServerNames uint32 `field:"totalServerNames"` // 总域名数量
MonthlyRequests uint64 `field:"monthlyRequests"` // 每月访问量额度
DailyRequests uint64 `field:"dailyRequests"` // 每日访问量额度
}
type PlanOperator struct {
Id interface{} // ID
IsOn interface{} // 是否启用
Name interface{} // 套餐名
ClusterId interface{} // 集群ID
TrafficLimit interface{} // 流量限制
Features interface{} // 允许的功能
TrafficPrice interface{} // 流量价格设定
BandwidthPrice interface{} // 带宽价格
MonthlyPrice interface{} // 月付
SeasonallyPrice interface{} // 季付
YearlyPrice interface{} // 年付
PriceType interface{} // 价格类型
Order interface{} // 排序
State interface{} // 状态
Id any // ID
IsOn any // 是否启用
Name any // 套餐名
ClusterId any // 集群ID
TrafficLimit any // 流量限制
Features any // 允许的功能
TrafficPrice any // 流量价格设定
BandwidthPrice any // 带宽价格
MonthlyPrice any // 月付
SeasonallyPrice any // 季付
YearlyPrice any // 年付
PriceType any // 价格类型
Order any // 排序
State any // 状态
TotalServers any // 可以绑定的网站数量
TotalServerNamesPerServer any // 每个网站可以绑定的域名数量
TotalServerNames any // 总域名数量
MonthlyRequests any // 每月访问量额度
DailyRequests any // 每日访问量额度
}
func NewPlanOperator() *PlanOperator {

View File

@@ -42,7 +42,7 @@ func init() {
// EnableRegionCity 启用条目
func (this *RegionCityDAO) EnableRegionCity(tx *dbs.Tx, id uint32) error {
_, err := this.Query(tx).
Pk(id).
Attr("valueId", id).
Set("state", RegionCityStateEnabled).
Update()
return err
@@ -51,7 +51,7 @@ func (this *RegionCityDAO) EnableRegionCity(tx *dbs.Tx, id uint32) error {
// DisableRegionCity 禁用条目
func (this *RegionCityDAO) DisableRegionCity(tx *dbs.Tx, id uint32) error {
_, err := this.Query(tx).
Pk(id).
Attr("valueId", id).
Set("state", RegionCityStateDisabled).
Update()
return err
@@ -60,7 +60,7 @@ func (this *RegionCityDAO) DisableRegionCity(tx *dbs.Tx, id uint32) error {
// FindEnabledRegionCity 查找启用中的条目
func (this *RegionCityDAO) FindEnabledRegionCity(tx *dbs.Tx, id int64) (*RegionCity, error) {
result, err := this.Query(tx).
Pk(id).
Attr("valueId", id).
Attr("state", RegionCityStateEnabled).
Find()
if result == nil {
@@ -72,7 +72,7 @@ func (this *RegionCityDAO) FindEnabledRegionCity(tx *dbs.Tx, id int64) (*RegionC
// FindRegionCityName 根据主键查找名称
func (this *RegionCityDAO) FindRegionCityName(tx *dbs.Tx, id uint32) (string, error) {
return this.Query(tx).
Pk(id).
Attr("valueId", id).
Result("name").
FindStringCol("")
}
@@ -81,7 +81,7 @@ func (this *RegionCityDAO) FindRegionCityName(tx *dbs.Tx, id uint32) (string, er
func (this *RegionCityDAO) FindCityWithDataId(tx *dbs.Tx, dataId string) (int64, error) {
return this.Query(tx).
Attr("dataId", dataId).
ResultPk().
Result(RegionCityField_ValueId).
FindInt64Col(0)
}
@@ -93,7 +93,7 @@ func (this *RegionCityDAO) CreateCity(tx *dbs.Tx, provinceId int64, name string,
op.DataId = dataId
op.State = RegionCityStateEnabled
codes := []string{name}
var codes = []string{name}
codesJSON, err := json.Marshal(codes)
if err != nil {
return 0, err
@@ -103,7 +103,18 @@ func (this *RegionCityDAO) CreateCity(tx *dbs.Tx, provinceId int64, name string,
if err != nil {
return 0, err
}
return types.Int64(op.Id), nil
var cityId = types.Int64(op.Id)
// value id
err = this.Query(tx).
Pk(cityId).
Set(RegionCityField_ValueId, cityId).
UpdateQuickly()
if err != nil {
return 0, err
}
return cityId, nil
}
// FindCityIdWithName 根据城市名查找城市ID
@@ -113,7 +124,7 @@ func (this *RegionCityDAO) FindCityIdWithName(tx *dbs.Tx, provinceId int64, city
Where("(name=:cityName OR customName=:cityName OR JSON_CONTAINS(codes, :cityNameJSON) OR JSON_CONTAINS(customCodes, :cityNameJSON))").
Param("cityName", cityName).
Param("cityNameJSON", strconv.Quote(cityName)). // 查询的需要是个JSON字符串所以这里加双引号
ResultPk().
Result(RegionCityField_ValueId).
FindInt64Col(0)
}
@@ -147,7 +158,7 @@ func (this *RegionCityDAO) UpdateCityCustom(tx *dbs.Tx, cityId int64, customName
}
return this.Query(tx).
Pk(cityId).
Attr(RegionCityField_ValueId, cityId).
Set("customName", customName).
Set("customCodes", customCodesJSON).
UpdateQuickly()

View File

@@ -2,9 +2,22 @@ package regions
import "github.com/iwind/TeaGo/dbs"
const (
RegionCityField_Id dbs.FieldName = "id" // ID
RegionCityField_ValueId dbs.FieldName = "valueId" // 实际ID
RegionCityField_ProvinceId dbs.FieldName = "provinceId" // 省份ID
RegionCityField_Name dbs.FieldName = "name" // 名称
RegionCityField_Codes dbs.FieldName = "codes" // 代号
RegionCityField_CustomName dbs.FieldName = "customName" // 自定义名称
RegionCityField_CustomCodes dbs.FieldName = "customCodes" // 自定义代号
RegionCityField_State dbs.FieldName = "state" // 状态
RegionCityField_DataId dbs.FieldName = "dataId" // 原始数据ID
)
// RegionCity 区域-城市
type RegionCity struct {
Id uint32 `field:"id"` // ID
Id1 uint32 `field:"id"` // ID
ValueId uint32 `field:"valueId"` // 实际ID
ProvinceId uint32 `field:"provinceId"` // 省份ID
Name string `field:"name"` // 名称
Codes dbs.JSON `field:"codes"` // 代号
@@ -15,14 +28,15 @@ type RegionCity struct {
}
type RegionCityOperator struct {
Id interface{} // ID
ProvinceId interface{} // 省份ID
Name interface{} // 名称
Codes interface{} // 代号
CustomName interface{} // 自定义名称
CustomCodes interface{} // 自定义代号
State interface{} // 状态
DataId interface{} // 原始数据ID
Id any // ID
ValueId any // 实际ID
ProvinceId any // 省份ID
Name any // 名称
Codes any // 代号
CustomName any // 自定义名称
CustomCodes any // 自定义代号
State any // 状态
DataId any // 原始数据ID
}
func NewRegionCityOperator() *RegionCityOperator {

View File

@@ -4,6 +4,7 @@ import (
"encoding/json"
"github.com/TeaOSLab/EdgeAPI/internal/utils"
"github.com/TeaOSLab/EdgeAPI/internal/utils/numberutils"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/regionconfigs"
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
@@ -20,10 +21,6 @@ const (
RegionCountryStateDisabled = 0 // 已禁用
)
const (
CountryChinaId = 1
)
var regionCountryIdAndNameCacheMap = map[int64]string{} // country id => name
type RegionCountryDAO dbs.DAO
@@ -50,7 +47,7 @@ func init() {
// EnableRegionCountry 启用条目
func (this *RegionCountryDAO) EnableRegionCountry(tx *dbs.Tx, id uint32) error {
_, err := this.Query(tx).
Pk(id).
Attr("valueId", id).
Set("state", RegionCountryStateEnabled).
Update()
return err
@@ -59,7 +56,7 @@ func (this *RegionCountryDAO) EnableRegionCountry(tx *dbs.Tx, id uint32) error {
// DisableRegionCountry 禁用条目
func (this *RegionCountryDAO) DisableRegionCountry(tx *dbs.Tx, id int64) error {
_, err := this.Query(tx).
Pk(id).
Attr("valueId", id).
Set("state", RegionCountryStateDisabled).
Update()
return err
@@ -68,7 +65,7 @@ func (this *RegionCountryDAO) DisableRegionCountry(tx *dbs.Tx, id int64) error {
// FindEnabledRegionCountry 查找启用中的条目
func (this *RegionCountryDAO) FindEnabledRegionCountry(tx *dbs.Tx, id int64) (*RegionCountry, error) {
result, err := this.Query(tx).
Pk(id).
Attr("valueId", id).
Attr("state", RegionCountryStateEnabled).
Find()
if result == nil {
@@ -88,7 +85,7 @@ func (this *RegionCountryDAO) FindRegionCountryName(tx *dbs.Tx, id int64) (strin
}
name, err := this.Query(tx).
Pk(id).
Attr("valueId", id).
Result("name").
FindStringCol("")
if err != nil {
@@ -105,7 +102,7 @@ func (this *RegionCountryDAO) FindRegionCountryName(tx *dbs.Tx, id int64) (strin
func (this *RegionCountryDAO) FindCountryIdWithDataId(tx *dbs.Tx, dataId string) (int64, error) {
return this.Query(tx).
Attr("dataId", dataId).
ResultPk().
Result(RegionCountryField_ValueId).
FindInt64Col(0)
}
@@ -115,7 +112,7 @@ func (this *RegionCountryDAO) FindCountryIdWithName(tx *dbs.Tx, countryName stri
Where("(name=:countryName OR JSON_CONTAINS(codes, :countryNameJSON) OR customName=:countryName OR JSON_CONTAINS(customCodes, :countryNameJSON))").
Param("countryName", countryName).
Param("countryNameJSON", strconv.Quote(countryName)). // 查询的需要是个JSON字符串所以这里加双引号
ResultPk().
Result(RegionCountryField_ValueId).
FindInt64Col(0)
}
@@ -130,6 +127,9 @@ func (this *RegionCountryDAO) CreateCountry(tx *dbs.Tx, name string, dataId stri
pinyinResult = append(pinyinResult, strings.Join(piece, " "))
}
pinyinJSON, err := json.Marshal([]string{strings.Join(pinyinResult, " ")})
if err != nil {
return 0, err
}
op.Pinyin = pinyinJSON
codes := []string{name}
@@ -145,16 +145,61 @@ func (this *RegionCountryDAO) CreateCountry(tx *dbs.Tx, name string, dataId stri
if err != nil {
return 0, err
}
return types.Int64(op.Id), nil
var countryId = types.Int64(op.Id)
err = this.Query(tx).
Pk(countryId).
Set(RegionCountryField_ValueId, countryId).
UpdateQuickly()
if err != nil {
return 0, err
}
return countryId, nil
}
// FindAllEnabledCountriesOrderByPinyin 查找所有可用的国家并按拼音排序
func (this *RegionCountryDAO) FindAllEnabledCountriesOrderByPinyin(tx *dbs.Tx) (result []*RegionCountry, err error) {
_, err = this.Query(tx).
ones, err := this.Query(tx).
State(RegionCountryStateEnabled).
Slice(&result).
Asc("pinyin").
Asc("JSON_EXTRACT(pinyin, '$[0]')").
FindAll()
if err != nil {
return nil, err
}
// resort China special regions
var chinaRegionMap = map[int64]*RegionCountry{} // countryId => *RegionCountry
for _, one := range ones {
var country = one.(*RegionCountry)
var valueId = int64(country.ValueId)
if regionconfigs.CheckRegionIsInGreaterChina(valueId) {
chinaRegionMap[valueId] = country
}
}
for _, one := range ones {
var country = one.(*RegionCountry)
var valueId = int64(country.ValueId)
if valueId == regionconfigs.RegionChinaId {
result = append(result, country)
// add hk, tw, mo, mainland ...
for _, subRegionId := range regionconfigs.FindAllGreaterChinaSubRegionIds() {
subRegion, ok := chinaRegionMap[subRegionId]
if ok {
result = append(result, subRegion)
}
}
continue
}
if regionconfigs.CheckRegionIsInGreaterChina(valueId) {
continue
}
result = append(result, country)
}
return
}
@@ -163,7 +208,7 @@ func (this *RegionCountryDAO) FindAllCountries(tx *dbs.Tx) (result []*RegionCoun
_, err = this.Query(tx).
State(RegionCountryStateEnabled).
Slice(&result).
AscPk().
Asc(RegionCountryField_ValueId).
FindAll()
return
}
@@ -185,7 +230,7 @@ func (this *RegionCountryDAO) UpdateCountryCustom(tx *dbs.Tx, countryId int64, c
}()
return this.Query(tx).
Pk(countryId).
Attr("valueId", countryId).
Set("customName", customName).
Set("customCodes", customCodesJSON).
UpdateQuickly()

View File

@@ -2,9 +2,25 @@ package regions
import "github.com/iwind/TeaGo/dbs"
const (
RegionCountryField_Id dbs.FieldName = "id" // ID
RegionCountryField_ValueId dbs.FieldName = "valueId" // 实际ID
RegionCountryField_ValueCode dbs.FieldName = "valueCode" // 值代号
RegionCountryField_Name dbs.FieldName = "name" // 名称
RegionCountryField_Codes dbs.FieldName = "codes" // 代号
RegionCountryField_CustomName dbs.FieldName = "customName" // 自定义名称
RegionCountryField_CustomCodes dbs.FieldName = "customCodes" // 自定义代号
RegionCountryField_State dbs.FieldName = "state" // 状态
RegionCountryField_DataId dbs.FieldName = "dataId" // 原始数据ID
RegionCountryField_Pinyin dbs.FieldName = "pinyin" // 拼音
RegionCountryField_IsCommon dbs.FieldName = "isCommon" // 是否常用
)
// RegionCountry 区域-国家/地区
type RegionCountry struct {
Id uint32 `field:"id"` // ID
Id1 uint32 `field:"id"` // ID
ValueId uint32 `field:"valueId"` // 实际ID
ValueCode string `field:"valueCode"` // 值代号
Name string `field:"name"` // 名称
Codes dbs.JSON `field:"codes"` // 代号
CustomName string `field:"customName"` // 自定义名称
@@ -12,17 +28,21 @@ type RegionCountry struct {
State uint8 `field:"state"` // 状态
DataId string `field:"dataId"` // 原始数据ID
Pinyin dbs.JSON `field:"pinyin"` // 拼音
IsCommon bool `field:"isCommon"` // 是否常用
}
type RegionCountryOperator struct {
Id interface{} // ID
Name interface{} // 名称
Codes interface{} // 代号
CustomName interface{} // 自定义名称
CustomCodes interface{} // 自定义代号
State interface{} // 状态
DataId interface{} // 原始数据ID
Pinyin interface{} // 拼音
Id any // ID
ValueId any // 实际ID
ValueCode any // 代号
Name any // 名称
Codes any // 代号
CustomName any // 自定义名称
CustomCodes any // 自定义代号
State any // 状态
DataId any // 原始数据ID
Pinyin any // 拼音
IsCommon any // 是否常用
}
func NewRegionCountryOperator() *RegionCountryOperator {

View File

@@ -41,7 +41,7 @@ func init() {
// EnableRegionProvider 启用条目
func (this *RegionProviderDAO) EnableRegionProvider(tx *dbs.Tx, id uint32) error {
_, err := this.Query(tx).
Pk(id).
Attr("valueId", id).
Set("state", RegionProviderStateEnabled).
Update()
return err
@@ -50,7 +50,7 @@ func (this *RegionProviderDAO) EnableRegionProvider(tx *dbs.Tx, id uint32) error
// DisableRegionProvider 禁用条目
func (this *RegionProviderDAO) DisableRegionProvider(tx *dbs.Tx, id uint32) error {
_, err := this.Query(tx).
Pk(id).
Attr("valueId", id).
Set("state", RegionProviderStateDisabled).
Update()
return err
@@ -59,7 +59,7 @@ func (this *RegionProviderDAO) DisableRegionProvider(tx *dbs.Tx, id uint32) erro
// FindEnabledRegionProvider 查找启用中的条目
func (this *RegionProviderDAO) FindEnabledRegionProvider(tx *dbs.Tx, id int64) (*RegionProvider, error) {
result, err := this.Query(tx).
Pk(id).
Attr("valueId", id).
Attr("state", RegionProviderStateEnabled).
Find()
if result == nil {
@@ -71,7 +71,7 @@ func (this *RegionProviderDAO) FindEnabledRegionProvider(tx *dbs.Tx, id int64) (
// FindRegionProviderName 根据主键查找名称
func (this *RegionProviderDAO) FindRegionProviderName(tx *dbs.Tx, id uint32) (string, error) {
return this.Query(tx).
Pk(id).
Attr("valueId", id).
Result("name").
FindStringCol("")
}
@@ -82,7 +82,7 @@ func (this *RegionProviderDAO) FindProviderIdWithName(tx *dbs.Tx, providerName s
Where("(name=:providerName OR customName=:providerName OR JSON_CONTAINS(codes, :providerNameJSON) OR JSON_CONTAINS(customCodes, :providerNameJSON))").
Param("providerName", providerName).
Param("providerNameJSON", strconv.Quote(providerName)). // 查询的需要是个JSON字符串所以这里加双引号
ResultPk().
Result(RegionProviderField_ValueId).
FindInt64Col(0)
}
@@ -96,7 +96,20 @@ func (this *RegionProviderDAO) CreateProvider(tx *dbs.Tx, name string) (int64, e
return 0, err
}
op.Codes = codesJSON
return this.SaveInt64(tx, op)
providerId, err := this.SaveInt64(tx, op)
if err != nil {
return 0, err
}
err = this.Query(tx).
Pk(providerId).
Set(RegionProviderField_ValueId, providerId).
UpdateQuickly()
if err != nil {
return 0, err
}
return providerId, nil
}
// FindAllEnabledProviders 查找所有服务商
@@ -119,7 +132,7 @@ func (this *RegionProviderDAO) UpdateProviderCustom(tx *dbs.Tx, providerId int64
}
return this.Query(tx).
Pk(providerId).
Attr("valueId", providerId).
Set("customName", customName).
Set("customCodes", customCodesJSON).
UpdateQuickly()

View File

@@ -2,9 +2,20 @@ package regions
import "github.com/iwind/TeaGo/dbs"
const (
RegionProviderField_Id dbs.FieldName = "id" // ID
RegionProviderField_ValueId dbs.FieldName = "valueId" // 实际ID
RegionProviderField_Name dbs.FieldName = "name" // 名称
RegionProviderField_Codes dbs.FieldName = "codes" // 代号
RegionProviderField_CustomName dbs.FieldName = "customName" // 自定义名称
RegionProviderField_CustomCodes dbs.FieldName = "customCodes" // 自定义代号
RegionProviderField_State dbs.FieldName = "state" // 状态
)
// RegionProvider 区域-运营商
type RegionProvider struct {
Id uint32 `field:"id"` // ID
Id1 uint32 `field:"id"` // ID
ValueId uint32 `field:"valueId"` // 实际ID
Name string `field:"name"` // 名称
Codes dbs.JSON `field:"codes"` // 代号
CustomName string `field:"customName"` // 自定义名称
@@ -13,12 +24,13 @@ type RegionProvider struct {
}
type RegionProviderOperator struct {
Id interface{} // ID
Name interface{} // 名称
Codes interface{} // 代号
CustomName interface{} // 自定义名称
CustomCodes interface{} // 自定义代号
State interface{} // 状态
Id any // ID
ValueId any // 实际ID
Name any // 名称
Codes any // 代号
CustomName any // 自定义名称
CustomCodes any // 自定义代号
State any // 状态
}
func NewRegionProviderOperator() *RegionProviderOperator {

View File

@@ -42,7 +42,7 @@ func init() {
// EnableRegionProvince 启用条目
func (this *RegionProvinceDAO) EnableRegionProvince(tx *dbs.Tx, id int64) error {
_, err := this.Query(tx).
Pk(id).
Attr("valueId", id).
Set("state", RegionProvinceStateEnabled).
Update()
return err
@@ -51,7 +51,7 @@ func (this *RegionProvinceDAO) EnableRegionProvince(tx *dbs.Tx, id int64) error
// DisableRegionProvince 禁用条目
func (this *RegionProvinceDAO) DisableRegionProvince(tx *dbs.Tx, id int64) error {
_, err := this.Query(tx).
Pk(id).
Attr("valueId", id).
Set("state", RegionProvinceStateDisabled).
Update()
return err
@@ -60,7 +60,7 @@ func (this *RegionProvinceDAO) DisableRegionProvince(tx *dbs.Tx, id int64) error
// FindEnabledRegionProvince 查找启用中的条目
func (this *RegionProvinceDAO) FindEnabledRegionProvince(tx *dbs.Tx, id int64) (*RegionProvince, error) {
result, err := this.Query(tx).
Pk(id).
Attr("valueId", id).
Attr("state", RegionProvinceStateEnabled).
Find()
if result == nil {
@@ -72,7 +72,7 @@ func (this *RegionProvinceDAO) FindEnabledRegionProvince(tx *dbs.Tx, id int64) (
// FindRegionProvinceName 根据主键查找名称
func (this *RegionProvinceDAO) FindRegionProvinceName(tx *dbs.Tx, id int64) (string, error) {
return this.Query(tx).
Pk(id).
Attr("valueId", id).
Result("name").
FindStringCol("")
}
@@ -81,7 +81,7 @@ func (this *RegionProvinceDAO) FindRegionProvinceName(tx *dbs.Tx, id int64) (str
func (this *RegionProvinceDAO) FindProvinceIdWithDataId(tx *dbs.Tx, dataId string) (int64, error) {
return this.Query(tx).
Attr("dataId", dataId).
ResultPk().
Result(RegionProvinceField_ValueId).
FindInt64Col(0)
}
@@ -92,7 +92,7 @@ func (this *RegionProvinceDAO) FindProvinceIdWithName(tx *dbs.Tx, countryId int6
Where("(name=:provinceName OR customName=:provinceName OR JSON_CONTAINS(codes, :provinceNameJSON) OR JSON_CONTAINS(customCodes, :provinceNameJSON))").
Param("provinceName", provinceName).
Param("provinceNameJSON", strconv.Quote(provinceName)). // 查询的需要是个JSON字符串所以这里加双引号
ResultPk().
Result(RegionProvinceField_ValueId).
FindInt64Col(0)
}
@@ -104,7 +104,7 @@ func (this *RegionProvinceDAO) CreateProvince(tx *dbs.Tx, countryId int64, name
op.DataId = dataId
op.State = RegionProvinceStateEnabled
codes := []string{name}
var codes = []string{name}
codesJSON, err := json.Marshal(codes)
if err != nil {
return 0, err
@@ -114,7 +114,17 @@ func (this *RegionProvinceDAO) CreateProvince(tx *dbs.Tx, countryId int64, name
if err != nil {
return 0, err
}
return types.Int64(op.Id), nil
var provinceId = types.Int64(op.Id)
err = this.Query(tx).
Pk(provinceId).
Set(RegionProvinceField_ValueId, provinceId).
UpdateQuickly()
if err != nil {
return 0, err
}
return provinceId, nil
}
// FindAllEnabledProvincesWithCountryId 查找某个国家/地区的所有省份
@@ -122,7 +132,7 @@ func (this *RegionProvinceDAO) FindAllEnabledProvincesWithCountryId(tx *dbs.Tx,
_, err = this.Query(tx).
State(RegionProvinceStateEnabled).
Attr("countryId", countryId).
Asc().
Asc(RegionProvinceField_ValueId).
Slice(&result).
FindAll()
return
@@ -132,7 +142,7 @@ func (this *RegionProvinceDAO) FindAllEnabledProvincesWithCountryId(tx *dbs.Tx,
func (this *RegionProvinceDAO) FindAllEnabledProvinces(tx *dbs.Tx) (result []*RegionProvince, err error) {
_, err = this.Query(tx).
State(RegionProvinceStateEnabled).
Asc().
Asc(RegionProvinceField_ValueId).
Slice(&result).
FindAll()
return
@@ -149,7 +159,7 @@ func (this *RegionProvinceDAO) UpdateProvinceCustom(tx *dbs.Tx, provinceId int64
}
return this.Query(tx).
Pk(provinceId).
Attr("valueId", provinceId).
Set("customName", customName).
Set("customCodes", customCodesJSON).
UpdateQuickly()

View File

@@ -2,9 +2,22 @@ package regions
import "github.com/iwind/TeaGo/dbs"
const (
RegionProvinceField_Id dbs.FieldName = "id" // ID
RegionProvinceField_ValueId dbs.FieldName = "valueId" // 实际ID
RegionProvinceField_CountryId dbs.FieldName = "countryId" // 国家ID
RegionProvinceField_Name dbs.FieldName = "name" // 名称
RegionProvinceField_Codes dbs.FieldName = "codes" // 代号
RegionProvinceField_CustomName dbs.FieldName = "customName" // 自定义名称
RegionProvinceField_CustomCodes dbs.FieldName = "customCodes" // 自定义代号
RegionProvinceField_State dbs.FieldName = "state" // 状态
RegionProvinceField_DataId dbs.FieldName = "dataId" // 原始数据ID
)
// RegionProvince 区域-省份
type RegionProvince struct {
Id uint32 `field:"id"` // ID
Id1 uint32 `field:"id"` // ID
ValueId uint32 `field:"valueId"` // 实际ID
CountryId uint32 `field:"countryId"` // 国家ID
Name string `field:"name"` // 名称
Codes dbs.JSON `field:"codes"` // 代号
@@ -15,14 +28,15 @@ type RegionProvince struct {
}
type RegionProvinceOperator struct {
Id interface{} // ID
CountryId interface{} // 国家ID
Name interface{} // 名称
Codes interface{} // 代号
CustomName interface{} // 自定义名称
CustomCodes interface{} // 自定义代号
State interface{} // 状态
DataId interface{} // 原始数据ID
Id any // ID
ValueId any // 实际ID
CountryId any // 国家ID
Name any // 名称
Codes any // 代号
CustomName any // 自定义名称
CustomCodes any // 自定义代号
State any // 状态
DataId any // 原始数据ID
}
func NewRegionProvinceOperator() *RegionProvinceOperator {

View File

@@ -41,7 +41,7 @@ func init() {
// EnableRegionTown 启用条目
func (this *RegionTownDAO) EnableRegionTown(tx *dbs.Tx, id uint32) error {
_, err := this.Query(tx).
Pk(id).
Attr("valueId", id).
Set("state", RegionTownStateEnabled).
Update()
return err
@@ -50,7 +50,7 @@ func (this *RegionTownDAO) EnableRegionTown(tx *dbs.Tx, id uint32) error {
// DisableRegionTown 禁用条目
func (this *RegionTownDAO) DisableRegionTown(tx *dbs.Tx, id uint32) error {
_, err := this.Query(tx).
Pk(id).
Attr("valueId", id).
Set("state", RegionTownStateDisabled).
Update()
return err
@@ -59,7 +59,7 @@ func (this *RegionTownDAO) DisableRegionTown(tx *dbs.Tx, id uint32) error {
// FindEnabledRegionTown 查找启用中的区县
func (this *RegionTownDAO) FindEnabledRegionTown(tx *dbs.Tx, id int64) (*RegionTown, error) {
result, err := this.Query(tx).
Pk(id).
Attr("valueId", id).
Attr("state", RegionTownStateEnabled).
Find()
if result == nil {
@@ -72,7 +72,7 @@ func (this *RegionTownDAO) FindEnabledRegionTown(tx *dbs.Tx, id int64) (*RegionT
func (this *RegionTownDAO) FindAllRegionTowns(tx *dbs.Tx) (result []*RegionTown, err error) {
_, err = this.Query(tx).
State(RegionTownStateEnabled).
AscPk().
Asc(RegionTownField_ValueId).
Slice(&result).
FindAll()
return
@@ -83,7 +83,7 @@ func (this *RegionTownDAO) FindAllRegionTownsWithCityId(tx *dbs.Tx, cityId int64
_, err = this.Query(tx).
State(RegionTownStateEnabled).
Attr("cityId", cityId).
AscPk().
Asc(RegionTownField_ValueId).
Slice(&result).
FindAll()
return
@@ -96,14 +96,14 @@ func (this *RegionTownDAO) FindTownIdWithName(tx *dbs.Tx, cityId int64, townName
Where("(name=:townName OR customName=:townName OR JSON_CONTAINS(codes, :townNameJSON) OR JSON_CONTAINS(customCodes, :townNameJSON))").
Param("townName", townName).
Param("townNameJSON", strconv.Quote(townName)). // 查询的需要是个JSON字符串所以这里加双引号
ResultPk().
Result(RegionTownField_ValueId).
FindInt64Col(0)
}
// FindRegionTownName 根据主键查找名称
func (this *RegionTownDAO) FindRegionTownName(tx *dbs.Tx, id uint32) (string, error) {
return this.Query(tx).
Pk(id).
Attr("valueId", id).
Result("name").
FindStringCol("")
}
@@ -118,7 +118,7 @@ func (this *RegionTownDAO) UpdateTownCustom(tx *dbs.Tx, townId int64, customName
return err
}
return this.Query(tx).
Pk(townId).
Attr("valueId", townId).
Set("customName", customName).
Set("customCodes", customCodesJSON).
UpdateQuickly()
@@ -176,5 +176,18 @@ func (this *RegionTownDAO) CreateTown(tx *dbs.Tx, cityId int64, townName string)
op.Codes = codes
op.State = RegionTownStateEnabled
return this.SaveInt64(tx, op)
townId, err := this.SaveInt64(tx, op)
if err != nil {
return 0, err
}
err = this.Query(tx).
Pk(townId).
Set(RegionTownField_ValueId, townId).
UpdateQuickly()
if err != nil {
return 0, err
}
return townId, nil
}

View File

@@ -2,9 +2,22 @@ package regions
import "github.com/iwind/TeaGo/dbs"
const (
RegionTownField_Id dbs.FieldName = "id" // ID
RegionTownField_ValueId dbs.FieldName = "valueId" // 真实ID
RegionTownField_CityId dbs.FieldName = "cityId" // 城市ID
RegionTownField_Name dbs.FieldName = "name" // 名称
RegionTownField_Codes dbs.FieldName = "codes" // 代号
RegionTownField_CustomName dbs.FieldName = "customName" // 自定义名称
RegionTownField_CustomCodes dbs.FieldName = "customCodes" // 自定义代号
RegionTownField_State dbs.FieldName = "state" // 状态
RegionTownField_DataId dbs.FieldName = "dataId" // 原始数据ID
)
// RegionTown 区域-省份
type RegionTown struct {
Id uint32 `field:"id"` // ID
Id1 uint32 `field:"id"` // ID
ValueId uint32 `field:"valueId"` // 真实ID
CityId uint32 `field:"cityId"` // 城市ID
Name string `field:"name"` // 名称
Codes dbs.JSON `field:"codes"` // 代号
@@ -15,14 +28,15 @@ type RegionTown struct {
}
type RegionTownOperator struct {
Id interface{} // ID
CityId interface{} // 城市ID
Name interface{} // 名称
Codes interface{} // 代号
CustomName interface{} // 自定义名称
CustomCodes interface{} // 自定义代号
State interface{} // 状态
DataId interface{} // 原始数据ID
Id any // ID
ValueId any // 真实ID
CityId any // 城市ID
Name any // 名称
Codes any // 代号
CustomName any // 自定义名称
CustomCodes any // 自定义代号
State any // 状态
DataId any // 原始数据ID
}
func NewRegionTownOperator() *RegionTownOperator {

View File

@@ -99,7 +99,7 @@ func (this *ReverseProxyDAO) ComposeReverseProxyConfig(tx *dbs.Tx, reverseProxyI
return nil, nil
}
var config = &serverconfigs.ReverseProxyConfig{}
var config = serverconfigs.NewReverseProxyConfig()
config.Id = int64(reverseProxy.Id)
config.IsOn = reverseProxy.IsOn
config.RequestHostType = types.Int8(reverseProxy.RequestHostType)
@@ -109,6 +109,7 @@ func (this *ReverseProxyDAO) ComposeReverseProxyConfig(tx *dbs.Tx, reverseProxyI
config.StripPrefix = reverseProxy.StripPrefix
config.AutoFlush = reverseProxy.AutoFlush == 1
config.FollowRedirects = reverseProxy.FollowRedirects == 1
config.Retry50X = reverseProxy.Retry50X
var schedulingConfig = &serverconfigs.SchedulingConfig{}
if IsNotNull(reverseProxy.Scheduling) {
@@ -218,6 +219,7 @@ func (this *ReverseProxyDAO) CreateReverseProxy(tx *dbs.Tx, adminId int64, userI
op.AdminId = adminId
op.UserId = userId
op.RequestHostType = serverconfigs.RequestHostTypeProxyServer
op.Retry50X = true
defaultHeaders := []string{"X-Real-IP", "X-Forwarded-For", "X-Forwarded-By", "X-Forwarded-Host", "X-Forwarded-Proto"}
defaultHeadersJSON, err := json.Marshal(defaultHeaders)
@@ -425,7 +427,8 @@ func (this *ReverseProxyDAO) UpdateReverseProxy(tx *dbs.Tx,
maxConns int32,
maxIdleConns int32,
proxyProtocolJSON []byte,
followRedirects bool) error {
followRedirects bool,
retry50X bool) error {
if reverseProxyId <= 0 {
return errors.New("invalid reverseProxyId")
}
@@ -490,6 +493,8 @@ func (this *ReverseProxyDAO) UpdateReverseProxy(tx *dbs.Tx,
op.ProxyProtocol = proxyProtocolJSON
}
op.Retry50X = retry50X
err = this.Save(tx, op)
if err != nil {
return err

View File

@@ -2,6 +2,34 @@ package models
import "github.com/iwind/TeaGo/dbs"
const (
ReverseProxyField_Id dbs.FieldName = "id" // ID
ReverseProxyField_AdminId dbs.FieldName = "adminId" // 管理员ID
ReverseProxyField_UserId dbs.FieldName = "userId" // 用户ID
ReverseProxyField_TemplateId dbs.FieldName = "templateId" // 模版ID
ReverseProxyField_IsOn dbs.FieldName = "isOn" // 是否启用
ReverseProxyField_Scheduling dbs.FieldName = "scheduling" // 调度算法
ReverseProxyField_PrimaryOrigins dbs.FieldName = "primaryOrigins" // 主要源站
ReverseProxyField_BackupOrigins dbs.FieldName = "backupOrigins" // 备用源站
ReverseProxyField_StripPrefix dbs.FieldName = "stripPrefix" // 去除URL前缀
ReverseProxyField_RequestHostType dbs.FieldName = "requestHostType" // 请求Host类型
ReverseProxyField_RequestHost dbs.FieldName = "requestHost" // 请求Host
ReverseProxyField_RequestHostExcludingPort dbs.FieldName = "requestHostExcludingPort" // 移除请求Host中的域名
ReverseProxyField_RequestURI dbs.FieldName = "requestURI" // 请求URI
ReverseProxyField_AutoFlush dbs.FieldName = "autoFlush" // 是否自动刷新缓冲区
ReverseProxyField_AddHeaders dbs.FieldName = "addHeaders" // 自动添加的Header列表
ReverseProxyField_State dbs.FieldName = "state" // 状态
ReverseProxyField_CreatedAt dbs.FieldName = "createdAt" // 创建时间
ReverseProxyField_ConnTimeout dbs.FieldName = "connTimeout" // 连接超时时间
ReverseProxyField_ReadTimeout dbs.FieldName = "readTimeout" // 读取超时时间
ReverseProxyField_IdleTimeout dbs.FieldName = "idleTimeout" // 空闲超时时间
ReverseProxyField_MaxConns dbs.FieldName = "maxConns" // 最大并发连接数
ReverseProxyField_MaxIdleConns dbs.FieldName = "maxIdleConns" // 最大空闲连接数
ReverseProxyField_ProxyProtocol dbs.FieldName = "proxyProtocol" // Proxy Protocol配置
ReverseProxyField_FollowRedirects dbs.FieldName = "followRedirects" // 回源跟随
ReverseProxyField_Retry50X dbs.FieldName = "retry50X" // 启用50X重试
)
// ReverseProxy 反向代理配置
type ReverseProxy struct {
Id uint32 `field:"id"` // ID
@@ -28,33 +56,35 @@ type ReverseProxy struct {
MaxIdleConns uint32 `field:"maxIdleConns"` // 最大空闲连接数
ProxyProtocol dbs.JSON `field:"proxyProtocol"` // Proxy Protocol配置
FollowRedirects uint8 `field:"followRedirects"` // 回源跟随
Retry50X bool `field:"retry50X"` // 启用50X重试
}
type ReverseProxyOperator struct {
Id interface{} // ID
AdminId interface{} // 管理员ID
UserId interface{} // 用户ID
TemplateId interface{} // 模版ID
IsOn interface{} // 是否启用
Scheduling interface{} // 调度算法
PrimaryOrigins interface{} // 主要源站
BackupOrigins interface{} // 备用源站
StripPrefix interface{} // 去除URL前缀
RequestHostType interface{} // 请求Host类型
RequestHost interface{} // 请求Host
RequestHostExcludingPort interface{} // 移除请求Host中的域名
RequestURI interface{} // 请求URI
AutoFlush interface{} // 是否自动刷新缓冲区
AddHeaders interface{} // 自动添加的Header列表
State interface{} // 状态
CreatedAt interface{} // 创建时间
ConnTimeout interface{} // 连接超时时间
ReadTimeout interface{} // 读取超时时间
IdleTimeout interface{} // 空闲超时时间
MaxConns interface{} // 最大并发连接数
MaxIdleConns interface{} // 最大空闲连接数
ProxyProtocol interface{} // Proxy Protocol配置
FollowRedirects interface{} // 回源跟随
Id any // ID
AdminId any // 管理员ID
UserId any // 用户ID
TemplateId any // 模版ID
IsOn any // 是否启用
Scheduling any // 调度算法
PrimaryOrigins any // 主要源站
BackupOrigins any // 备用源站
StripPrefix any // 去除URL前缀
RequestHostType any // 请求Host类型
RequestHost any // 请求Host
RequestHostExcludingPort any // 移除请求Host中的域名
RequestURI any // 请求URI
AutoFlush any // 是否自动刷新缓冲区
AddHeaders any // 自动添加的Header列表
State any // 状态
CreatedAt any // 创建时间
ConnTimeout any // 连接超时时间
ReadTimeout any // 读取超时时间
IdleTimeout any // 空闲超时时间
MaxConns any // 最大并发连接数
MaxIdleConns any // 最大空闲连接数
ProxyProtocol any // Proxy Protocol配置
FollowRedirects any // 回源跟随
Retry50X any // 启用50X重试
}
func NewReverseProxyOperator() *ReverseProxyOperator {

View File

@@ -25,7 +25,7 @@ import (
type ServerBandwidthStatDAO dbs.DAO
const (
ServerBandwidthStatTablePartials = 20 // 分表数量
ServerBandwidthStatTablePartitions = 20 // 分表数量
)
func init() {
@@ -34,7 +34,7 @@ func init() {
var ticker = time.NewTicker(time.Duration(rands.Int(24, 48)) * time.Hour)
goman.New(func() {
for range ticker.C {
err := SharedServerBandwidthStatDAO.Clean(nil)
err := SharedServerBandwidthStatDAO.CleanDefaultDays(nil, 100)
if err != nil {
remotelogs.Error("SharedServerBandwidthStatDAO", "clean expired data failed: "+err.Error())
}
@@ -63,15 +63,15 @@ func init() {
}
// UpdateServerBandwidth 写入数据
// 暂时不使用region区分
func (this *ServerBandwidthStatDAO) UpdateServerBandwidth(tx *dbs.Tx, userId int64, serverId int64, regionId int64, day string, timeAt string, bytes int64, totalBytes int64, cachedBytes int64, attackBytes int64, countRequests int64, countCachedRequests int64, countAttackRequests int64) error {
// 现在不需要把 userPlanId 加入到数据表unique key中因为只会影响5分钟统计影响非常有限
func (this *ServerBandwidthStatDAO) UpdateServerBandwidth(tx *dbs.Tx, userId int64, serverId int64, regionId int64, userPlanId int64, day string, timeAt string, bandwidthBytes int64, totalBytes int64, cachedBytes int64, attackBytes int64, countRequests int64, countCachedRequests int64, countAttackRequests int64) error {
if serverId <= 0 {
return errors.New("invalid server id '" + types.String(serverId) + "'")
}
return this.Query(tx).
Table(this.partialTable(serverId)).
Param("bytes", bytes).
Param("bytes", bandwidthBytes).
Param("totalBytes", totalBytes).
Param("cachedBytes", cachedBytes).
Param("attackBytes", attackBytes).
@@ -84,7 +84,7 @@ func (this *ServerBandwidthStatDAO) UpdateServerBandwidth(tx *dbs.Tx, userId int
"regionId": regionId,
"day": day,
"timeAt": timeAt,
"bytes": bytes,
"bytes": bandwidthBytes,
"totalBytes": totalBytes,
"avgBytes": totalBytes / 300,
"cachedBytes": cachedBytes,
@@ -92,6 +92,7 @@ func (this *ServerBandwidthStatDAO) UpdateServerBandwidth(tx *dbs.Tx, userId int
"countRequests": countRequests,
"countCachedRequests": countCachedRequests,
"countAttackRequests": countAttackRequests,
"userPlanId": userPlanId,
}, maps.Map{
"bytes": dbs.SQL("bytes+:bytes"),
"avgBytes": dbs.SQL("(totalBytes+:totalBytes)/300"), // 因为生成SQL语句时会自动将avgBytes排在totalBytes之前所以这里不用担心先后顺序的问题
@@ -379,14 +380,18 @@ func (this *ServerBandwidthStatDAO) FindAllServerStatsWithMonth(tx *dbs.Tx, serv
}
// FindMonthlyPercentile 获取某月内百分位
func (this *ServerBandwidthStatDAO) FindMonthlyPercentile(tx *dbs.Tx, serverId int64, month string, percentile int, useAvg bool) (result int64, err error) {
func (this *ServerBandwidthStatDAO) FindMonthlyPercentile(tx *dbs.Tx, serverId int64, month string, percentile int, useAvg bool, noPlan bool, minSamples int) (result int64, err error) {
if percentile <= 0 {
percentile = 95
}
// 如果是100%以上,则快速返回
if percentile >= 100 {
result, err = this.Query(tx).
var query = this.Query(tx)
if noPlan {
query.Attr("userPlanId", 0)
}
result, err = query.
Table(this.partialTable(serverId)).
Attr("serverId", serverId).
Result(this.bytesField(useAvg)).
@@ -398,7 +403,11 @@ func (this *ServerBandwidthStatDAO) FindMonthlyPercentile(tx *dbs.Tx, serverId i
}
// 总数量
total, err := this.Query(tx).
var totalQuery = this.Query(tx)
if noPlan {
totalQuery.Attr("userPlanId", 0)
}
total, err := totalQuery.
Table(this.partialTable(serverId)).
Attr("serverId", serverId).
Between("day", month+"01", month+"31").
@@ -406,7 +415,7 @@ func (this *ServerBandwidthStatDAO) FindMonthlyPercentile(tx *dbs.Tx, serverId i
if err != nil {
return 0, err
}
if total == 0 {
if total == 0 || total < int64(minSamples) {
return 0, nil
}
@@ -417,7 +426,11 @@ func (this *ServerBandwidthStatDAO) FindMonthlyPercentile(tx *dbs.Tx, serverId i
}
// 查询 nth 位置
result, err = this.Query(tx).
var query = this.Query(tx)
if noPlan {
query.Attr("userPlanId", 0)
}
result, err = query.
Table(this.partialTable(serverId)).
Attr("serverId", serverId).
Result(this.bytesField(useAvg)).
@@ -745,9 +758,77 @@ func (this *ServerBandwidthStatDAO) SumDailyStat(tx *dbs.Tx, serverId int64, reg
return
}
// Clean 清理过期数据
func (this *ServerBandwidthStatDAO) Clean(tx *dbs.Tx) error {
var day = timeutil.Format("Ymd", time.Now().AddDate(0, 0, -100)) // 保留大约3个月的数据
// SumMonthlyBytes 统计某个网站单月总流量
func (this *ServerBandwidthStatDAO) SumMonthlyBytes(tx *dbs.Tx, serverId int64, month string, noPlan bool) (int64, error) {
if !regexputils.YYYYMM.MatchString(month) {
return 0, errors.New("invalid month '" + month + "'")
}
// 兼容以往版本
hasFullData, err := this.HasFullData(tx, serverId, month)
if err != nil {
return 0, err
}
if !hasFullData {
return SharedServerDailyStatDAO.SumMonthlyBytes(tx, serverId, month)
}
var query = this.Query(tx)
if noPlan {
query.Attr("userPlanId", 0)
}
return query.
Table(this.partialTable(serverId)).
Between("day", month+"01", month+"31").
Attr("serverId", serverId).
SumInt64("totalBytes", 0)
}
// SumServerMonthlyWithRegion 根据服务计算某月合计
// month 格式为YYYYMM
func (this *ServerBandwidthStatDAO) SumServerMonthlyWithRegion(tx *dbs.Tx, serverId int64, regionId int64, month string, noPlan bool) (int64, error) {
var query = this.Query(tx)
query.Table(this.partialTable(serverId))
if regionId > 0 {
query.Attr("regionId", regionId)
}
if noPlan {
query.Attr("userPlanId", 0)
}
return query.Between("day", month+"01", month+"31").
Attr("serverId", serverId).
SumInt64("totalBytes", 0)
}
// FindDistinctServerIdsWithoutPlanAtPartition 查找没有绑定套餐的有流量网站
func (this *ServerBandwidthStatDAO) FindDistinctServerIdsWithoutPlanAtPartition(tx *dbs.Tx, partitionIndex int, month string) (serverIds []int64, err error) {
ones, err := this.Query(tx).
Table(this.partialTable(int64(partitionIndex))).
Between("day", month+"01", month+"31").
Attr("userPlanId", 0). // 没有绑定套餐
Result("DISTINCT serverId").
FindAll()
if err != nil {
return nil, err
}
for _, one := range ones {
var serverId = int64(one.(*ServerBandwidthStat).ServerId)
if serverId <= 0 {
continue
}
serverIds = append(serverIds, serverId)
}
return
}
// CountPartitions 查看分区数量
func (this *ServerBandwidthStatDAO) CountPartitions() int {
return ServerBandwidthStatTablePartitions
}
// CleanDays 清理过期数据
func (this *ServerBandwidthStatDAO) CleanDays(tx *dbs.Tx, days int) error {
var day = timeutil.Format("Ymd", time.Now().AddDate(0, 0, -days)) // 保留大约3个月的数据
return this.runBatch(func(table string, locker *sync.Mutex) error {
_, err := this.Query(tx).
Table(table).
@@ -757,13 +838,29 @@ func (this *ServerBandwidthStatDAO) Clean(tx *dbs.Tx) error {
})
}
func (this *ServerBandwidthStatDAO) CleanDefaultDays(tx *dbs.Tx, defaultDays int) error {
databaseConfig, err := SharedSysSettingDAO.ReadDatabaseConfig(tx)
if err != nil {
return err
}
if databaseConfig != nil && databaseConfig.ServerBandwidthStat.Clean.Days > 0 {
defaultDays = databaseConfig.ServerBandwidthStat.Clean.Days
}
if defaultDays <= 0 {
defaultDays = 100
}
return this.CleanDays(tx, defaultDays)
}
// 批量执行
func (this *ServerBandwidthStatDAO) runBatch(f func(table string, locker *sync.Mutex) error) error {
var locker = &sync.Mutex{}
var wg = sync.WaitGroup{}
wg.Add(ServerBandwidthStatTablePartials)
wg.Add(ServerBandwidthStatTablePartitions)
var resultErr error
for i := 0; i < ServerBandwidthStatTablePartials; i++ {
for i := 0; i < ServerBandwidthStatTablePartitions; i++ {
var table = this.partialTable(int64(i))
go func(table string) {
defer wg.Done()
@@ -780,7 +877,7 @@ func (this *ServerBandwidthStatDAO) runBatch(f func(table string, locker *sync.M
// 获取分区表
func (this *ServerBandwidthStatDAO) partialTable(serverId int64) string {
return this.Table + "_" + types.String(serverId%int64(ServerBandwidthStatTablePartials))
return this.Table + "_" + types.String(serverId%int64(ServerBandwidthStatTablePartitions))
}
// 获取字节字段
@@ -828,6 +925,11 @@ func (this *ServerBandwidthStatDAO) fixServerStats(stats []*ServerBandwidthStat,
// HasFullData 检查一个月是否完整数据
// 是为了兼容以前数据,以前的表中没有缓存流量、请求数等字段
func (this *ServerBandwidthStatDAO) HasFullData(tx *dbs.Tx, serverId int64, month string) (bool, error) {
// 最迟在2024年完成过渡
if time.Now().Year() >= 2024 {
return true, nil
}
var monthKey = month + "@" + types.String(serverId)
if !regexputils.YYYYMM.MatchString(month) {

View File

@@ -16,7 +16,7 @@ import (
func TestServerBandwidthStatDAO_UpdateServerBandwidth(t *testing.T) {
var dao = models.NewServerBandwidthStatDAO()
var tx *dbs.Tx
err := dao.UpdateServerBandwidth(tx, 1, 1, 0, timeutil.Format("Ymd"), timeutil.FormatTime("Hi", time.Now().Unix()/300*300), 1024, 300, 0, 0, 0, 0, 0)
err := dao.UpdateServerBandwidth(tx, 1, 1, 0, 0, timeutil.Format("Ymd"), timeutil.FormatTime("Hi", time.Now().Unix()/300*300), 1024, 300, 0, 0, 0, 0, 0)
if err != nil {
t.Fatal(err)
}
@@ -33,7 +33,7 @@ func TestSeverBandwidthStatDAO_InsertManyStats(t *testing.T) {
}
var day = timeutil.Format("Ymd", time.Now().AddDate(0, 0, -rands.Int(0, 200)))
var minute = fmt.Sprintf("%02d%02d", rands.Int(0, 23), rands.Int(0, 59))
err := dao.UpdateServerBandwidth(tx, 1, int64(rands.Int(1, 10000)), 0, day, minute, 1024, 300, 0, 0, 0, 0, 0)
err := dao.UpdateServerBandwidth(tx, 1, int64(rands.Int(1, 10000)), 0, 0, day, minute, 1024, 300, 0, 0, 0, 0, 0)
if err != nil {
t.Fatal(err)
}
@@ -44,8 +44,10 @@ func TestSeverBandwidthStatDAO_InsertManyStats(t *testing.T) {
func TestServerBandwidthStatDAO_FindMonthlyPercentile(t *testing.T) {
var dao = models.NewServerBandwidthStatDAO()
var tx *dbs.Tx
t.Log(dao.FindMonthlyPercentile(tx, 23, timeutil.Format("Ym"), 95, false))
t.Log(dao.FindMonthlyPercentile(tx, 23, timeutil.Format("Ym"), 95, true))
t.Log(dao.FindMonthlyPercentile(tx, 23, timeutil.Format("Ym"), 95, false, false, 0))
t.Log(dao.FindMonthlyPercentile(tx, 23, timeutil.Format("Ym"), 95, true, false, 0))
t.Log(dao.FindMonthlyPercentile(tx, 23, timeutil.Format("Ym"), 95, true, false, 100))
t.Log(dao.FindMonthlyPercentile(tx, 23, timeutil.Format("Ym"), 95, true, true, 0))
}
func TestServerBandwidthStatDAO_FindAllServerStatsWithMonth(t *testing.T) {
@@ -72,11 +74,11 @@ func TestServerBandwidthStatDAO_FindAllServerStatsWithDay(t *testing.T) {
}
}
func TestServerBandwidthStatDAO_Clean(t *testing.T) {
func TestServerBandwidthStatDAO_CleanDays(t *testing.T) {
var dao = models.NewServerBandwidthStatDAO()
var tx *dbs.Tx
var before = time.Now()
err := dao.Clean(tx)
err := dao.CleanDays(tx, 100)
if err != nil {
t.Fatal(err)
}
@@ -114,3 +116,32 @@ func TestServerBandwidthStatDAO_FindBandwidthStatsBetweenDays(t *testing.T) {
t.Log(stat.Day, stat.TimeAt, "bytes:", stat.Bytes, "bits:", stat.Bits)
}
}
func TestServerBandwidthStatDAO_SumServerMonthlyWithRegion(t *testing.T) {
var dao = models.NewServerBandwidthStatDAO()
var tx *dbs.Tx
{
totalBytes, err := dao.SumServerMonthlyWithRegion(tx, 23, 0, timeutil.Format("Ym"), false)
if err != nil {
t.Fatal(err)
}
t.Log("with plan:", totalBytes)
}
{
totalBytes, err := dao.SumServerMonthlyWithRegion(tx, 23, 0, timeutil.Format("Ym"), true)
if err != nil {
t.Fatal(err)
}
t.Log("without plan:", totalBytes)
}
}
func TestServerBandwidthStatDAO_SumMonthlyBytes(t *testing.T) {
var dao = models.NewServerBandwidthStatDAO()
var tx *dbs.Tx
totalBytes, err := dao.SumMonthlyBytes(tx, 23, timeutil.Format("Ym"), false)
if err != nil {
t.Fatal(err)
}
t.Log("total bytes:", totalBytes)
}

View File

@@ -1,11 +1,32 @@
package models
import "github.com/iwind/TeaGo/dbs"
const (
ServerBandwidthStatField_Id dbs.FieldName = "id" // ID
ServerBandwidthStatField_UserId dbs.FieldName = "userId" // 用户ID
ServerBandwidthStatField_ServerId dbs.FieldName = "serverId" // 服务ID
ServerBandwidthStatField_RegionId dbs.FieldName = "regionId" // 区域ID
ServerBandwidthStatField_UserPlanId dbs.FieldName = "userPlanId" // 用户套餐ID
ServerBandwidthStatField_Day dbs.FieldName = "day" // 日期YYYYMMDD
ServerBandwidthStatField_TimeAt dbs.FieldName = "timeAt" // 时间点HHMM
ServerBandwidthStatField_Bytes dbs.FieldName = "bytes" // 带宽字节
ServerBandwidthStatField_AvgBytes dbs.FieldName = "avgBytes" // 平均流量
ServerBandwidthStatField_CachedBytes dbs.FieldName = "cachedBytes" // 缓存的流量
ServerBandwidthStatField_AttackBytes dbs.FieldName = "attackBytes" // 攻击流量
ServerBandwidthStatField_CountRequests dbs.FieldName = "countRequests" // 请求数
ServerBandwidthStatField_CountCachedRequests dbs.FieldName = "countCachedRequests" // 缓存的请求数
ServerBandwidthStatField_CountAttackRequests dbs.FieldName = "countAttackRequests" // 攻击请求数
ServerBandwidthStatField_TotalBytes dbs.FieldName = "totalBytes" // 总流量
)
// ServerBandwidthStat 服务峰值带宽统计
type ServerBandwidthStat struct {
Id uint64 `field:"id"` // ID
UserId uint64 `field:"userId"` // 用户ID
ServerId uint64 `field:"serverId"` // 服务ID
RegionId uint32 `field:"regionId"` // 区域ID
UserPlanId uint64 `field:"userPlanId"` // 用户套餐ID
Day string `field:"day"` // 日期YYYYMMDD
TimeAt string `field:"timeAt"` // 时间点HHMM
Bytes uint64 `field:"bytes"` // 带宽字节
@@ -23,6 +44,7 @@ type ServerBandwidthStatOperator struct {
UserId any // 用户ID
ServerId any // 服务ID
RegionId any // 区域ID
UserPlanId any // 用户套餐ID
Day any // 日期YYYYMMDD
TimeAt any // 时间点HHMM
Bytes any // 带宽字节

View File

@@ -16,6 +16,7 @@ import (
"github.com/iwind/TeaGo/types"
timeutil "github.com/iwind/TeaGo/utils/time"
"regexp"
"sort"
"strings"
"time"
)
@@ -28,7 +29,7 @@ func init() {
var ticker = time.NewTicker(time.Duration(rands.Int(24, 48)) * time.Hour)
goman.New(func() {
for range ticker.C {
err := SharedServerDailyStatDAO.Clean(nil, 60) // 只保留 N 天,时间需要长一些,因为需要用来生成账单
err := SharedServerDailyStatDAO.CleanDefaultDays(nil, 60) // 只保留 N 天,时间需要长一些,因为需要用来生成账单
if err != nil {
logs.Println("ServerDailyStatDAO", "clean expired data failed: "+err.Error())
}
@@ -118,7 +119,7 @@ func (this *ServerDailyStatDAO) SaveStats(tx *dbs.Tx, stats []*pb.ServerDailySta
// 更新流量限制状态
if stat.CheckTrafficLimiting {
trafficLimitConfig, err := SharedServerDAO.CalculateServerTrafficLimitConfig(tx, stat.ServerId, cacheMap)
trafficLimitConfig, err := SharedServerDAO.FindServerTrafficLimitConfig(tx, stat.ServerId, cacheMap)
if err != nil {
return err
}
@@ -128,7 +129,7 @@ func (this *ServerDailyStatDAO) SaveStats(tx *dbs.Tx, stats []*pb.ServerDailySta
return err
}
err = SharedServerDAO.UpdateServerTrafficLimitStatus(tx, trafficLimitConfig, stat.ServerId, false)
err = SharedServerDAO.RenewServerTrafficLimitStatus(tx, trafficLimitConfig, stat.ServerId, false)
if err != nil {
return err
}
@@ -139,6 +140,7 @@ func (this *ServerDailyStatDAO) SaveStats(tx *dbs.Tx, stats []*pb.ServerDailySta
return nil
}
// SumCurrentDailyStat 查找当前时刻的数据统计
func (this *ServerDailyStatDAO) SumCurrentDailyStat(tx *dbs.Tx, serverId int64) (*ServerDailyStat, error) {
var day = timeutil.Format("Ymd")
@@ -163,7 +165,7 @@ func (this *ServerDailyStatDAO) SumServerMonthlyWithRegion(tx *dbs.Tx, serverId
if regionId > 0 {
query.Attr("regionId", regionId)
}
return query.Between("day", month+"01", month+"32").
return query.Between("day", month+"01", month+"31").
Attr("serverId", serverId).
SumInt64("bytes", 0)
}
@@ -177,7 +179,7 @@ func (this *ServerDailyStatDAO) SumUserMonthlyWithoutPlan(tx *dbs.Tx, userId int
}
return query.
Attr("planId", 0).
Between("day", month+"01", month+"32").
Between("day", month+"01", month+"31").
Attr("userId", userId).
SumInt64("bytes", 0)
}
@@ -189,7 +191,7 @@ func (this *ServerDailyStatDAO) SumUserMonthlyPeek(tx *dbs.Tx, userId int64, reg
if regionId > 0 {
query.Attr("regionId", regionId)
}
max, err := query.Between("day", month+"01", month+"32").
max, err := query.Between("day", month+"01", month+"31").
Attr("userId", userId).
Max("bytes", 0)
if err != nil {
@@ -513,7 +515,8 @@ func (this *ServerDailyStatDAO) FindStatsWithDay(tx *dbs.Tx, serverId int64, day
Result("SUM(bytes) AS bytes", "SUM(cachedBytes) AS cachedBytes", "SUM(countRequests) AS countRequests", "SUM(countCachedRequests) AS countCachedRequests", "SUM(countAttackRequests) AS countAttackRequests", "SUM(attackBytes) AS attackBytes", "day", "timeFrom", "MIN(timeTo) AS timeTo").
Attr("serverId", serverId).
Attr("day", day).
Group("day").Group("timeFrom", dbs.QueryOrderDesc)
Group("day").
Group("timeFrom")
if len(timeFrom) > 0 {
query.Gte("timeFrom", timeFrom)
@@ -530,6 +533,11 @@ func (this *ServerDailyStatDAO) FindStatsWithDay(tx *dbs.Tx, serverId int64, day
return nil, err
}
// sort results
sort.Slice(result, func(i, j int) bool {
return result[i].TimeFrom < result[j].TimeFrom
})
return
}
@@ -637,7 +645,7 @@ func (this *ServerDailyStatDAO) FindStatsBetweenDays(tx *dbs.Tx, userId int64, s
// month YYYYMM
func (this *ServerDailyStatDAO) FindMonthlyStatsWithPlan(tx *dbs.Tx, month string) (result []*ServerDailyStat, err error) {
_, err = this.Query(tx).
Between("day", month+"01", month+"32").
Between("day", month+"01", month+"31").
Gt("planId", 0).
Slice(&result).
FindAll()
@@ -673,8 +681,8 @@ func (this *ServerDailyStatDAO) compatFindHourlyStats(tx *dbs.Tx, serverId int64
result = append(result, stat)
} else {
result = append(result, &ServerDailyStat{
Hour: hour,
Day: hour[:8],
Hour: hour,
Day: hour[:8],
TimeFrom: hour[8:] + "00",
})
}
@@ -742,11 +750,27 @@ func (this *ServerDailyStatDAO) UpdateStatFee(tx *dbs.Tx, statId int64, fee floa
UpdateQuickly()
}
// Clean 清理历史数据
func (this *ServerDailyStatDAO) Clean(tx *dbs.Tx, days int) error {
// CleanDays 清理历史数据
func (this *ServerDailyStatDAO) CleanDays(tx *dbs.Tx, days int) error {
var day = timeutil.Format("Ymd", time.Now().AddDate(0, 0, -days))
_, err := this.Query(tx).
Lt("day", day).
Delete()
return err
}
func (this *ServerDailyStatDAO) CleanDefaultDays(tx *dbs.Tx, defaultDays int) error {
databaseConfig, err := SharedSysSettingDAO.ReadDatabaseConfig(tx)
if err != nil {
return err
}
if databaseConfig != nil && databaseConfig.ServerDailyStat.Clean.Days > 0 {
defaultDays = databaseConfig.ServerDailyStat.Clean.Days
}
if defaultDays <= 0 {
defaultDays = 60
}
return this.CleanDays(tx, defaultDays)
}

View File

@@ -140,6 +140,6 @@ func TestServerDailyStatDAO_FindStatsWithDay(t *testing.T) {
t.Fatal(err)
}
for _, stat := range stats {
t.Log(stat.TimeFrom, stat.TimeTo, stat.Bytes)
t.Log(stat.Day, stat.TimeFrom, stat.TimeTo, stat.Bytes)
}
}

View File

@@ -3,11 +3,13 @@ package models
import (
"encoding/json"
"errors"
"fmt"
teaconst "github.com/TeaOSLab/EdgeAPI/internal/const"
"github.com/TeaOSLab/EdgeAPI/internal/db/models/dns"
dbutils "github.com/TeaOSLab/EdgeAPI/internal/db/utils"
"github.com/TeaOSLab/EdgeAPI/internal/utils"
"github.com/TeaOSLab/EdgeAPI/internal/utils/numberutils"
"github.com/TeaOSLab/EdgeAPI/internal/utils/regexputils"
"github.com/TeaOSLab/EdgeCommon/pkg/configutils"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
@@ -354,6 +356,9 @@ func (this *ServerDAO) UpdateServerBasic(tx *dbs.Tx, serverId int64, name string
// UpdateServerGroupIds 修改服务所在分组
func (this *ServerDAO) UpdateServerGroupIds(tx *dbs.Tx, serverId int64, groupIds []int64) error {
if serverId <= 0 {
return errors.New("serverId should not be smaller than 0")
}
if groupIds == nil {
groupIds = []int64{}
}
@@ -390,6 +395,10 @@ func (this *ServerDAO) UpdateUserServerBasic(tx *dbs.Tx, serverId int64, name st
// UpdateServerIsOn 修复服务是否启用
func (this *ServerDAO) UpdateServerIsOn(tx *dbs.Tx, serverId int64, isOn bool) error {
if serverId <= 0 {
return errors.New("serverId should not be smaller than 0")
}
_, err := this.Query(tx).
Pk(serverId).
Set("isOn", isOn).
@@ -775,7 +784,7 @@ func (this *ServerDAO) CountAllEnabledServers(tx *dbs.Tx) (int64, error) {
// 参数:
//
// groupId 分组ID如果为-1则搜索没有分组的服务
func (this *ServerDAO) CountAllEnabledServersMatch(tx *dbs.Tx, groupId int64, keyword string, userId int64, clusterId int64, auditingFlag configutils.BoolState, protocolFamilies []string) (int64, error) {
func (this *ServerDAO) CountAllEnabledServersMatch(tx *dbs.Tx, groupId int64, keyword string, userId int64, clusterId int64, auditingFlag configutils.BoolState, protocolFamilies []string, userPlanId int64) (int64, error) {
query := this.Query(tx).
State(ServerStateEnabled)
if groupId > 0 {
@@ -822,6 +831,10 @@ func (this *ServerDAO) CountAllEnabledServersMatch(tx *dbs.Tx, groupId int64, ke
query.Where("(" + strings.Join(protocolConds, " OR ") + ")")
}
if userPlanId > 0 {
query.Attr("userPlanId", userPlanId)
}
return query.Count()
}
@@ -896,6 +909,22 @@ func (this *ServerDAO) ListEnabledServersMatch(tx *dbs.Tx, offset int64, size in
query.Desc("IF(FIND_IN_SET(bandwidthTime, :times), bandwidthBytes, 0)")
query.Param("times", strings.Join(times, ","))
query.DescPk()
case "requestsAsc":
query.Asc("IF(FIND_IN_SET(bandwidthTime, :times), countRequests, 0)")
query.Param("times", strings.Join(times, ","))
query.DescPk()
case "requestsDesc":
query.Desc("IF(FIND_IN_SET(bandwidthTime, :times), countRequests, 0)")
query.Param("times", strings.Join(times, ","))
query.DescPk()
case "attackRequestsAsc":
query.Asc("IF(FIND_IN_SET(bandwidthTime, :times), countAttackRequests, 0)")
query.Param("times", strings.Join(times, ","))
query.DescPk()
case "attackRequestsDesc":
query.Desc("IF(FIND_IN_SET(bandwidthTime, :times), countAttackRequests, 0)")
query.Param("times", strings.Join(times, ","))
query.DescPk()
default:
query.DescPk()
}
@@ -906,6 +935,8 @@ func (this *ServerDAO) ListEnabledServersMatch(tx *dbs.Tx, offset int64, size in
for _, server := range result {
if len(server.BandwidthTime) > 0 && !lists.ContainsString(times, server.BandwidthTime) {
server.BandwidthBytes = 0
server.CountRequests = 0
server.CountAttackRequests = 0
}
}
@@ -1291,12 +1322,13 @@ func (this *ServerDAO) ComposeServerConfig(tx *dbs.Tx, server *Server, ignoreCer
}
// 套餐是否依然有效
plan, err := SharedPlanDAO.FindEnabledPlan(tx, int64(userPlan.PlanId))
plan, err := SharedPlanDAO.FindEnabledPlan(tx, int64(userPlan.PlanId), cacheMap)
if err != nil {
return nil, err
}
if plan != nil {
config.UserPlan = &serverconfigs.UserPlanConfig{
Id: int64(userPlan.Id),
DayTo: userPlan.DayTo,
Plan: &serverconfigs.PlanConfig{
Id: int64(plan.Id),
@@ -1316,16 +1348,14 @@ func (this *ServerDAO) ComposeServerConfig(tx *dbs.Tx, server *Server, ignoreCer
}
}
if config.TrafficLimit != nil && config.TrafficLimit.IsOn && !config.TrafficLimit.IsEmpty() {
if len(server.TrafficLimitStatus) > 0 {
var status = &serverconfigs.TrafficLimitStatus{}
err := json.Unmarshal(server.TrafficLimitStatus, status)
if err != nil {
return nil, err
}
if status.IsValid() {
config.TrafficLimitStatus = status
}
if len(server.TrafficLimitStatus) > 0 {
var status = &serverconfigs.TrafficLimitStatus{}
err := json.Unmarshal(server.TrafficLimitStatus, status)
if err != nil {
return nil, err
}
if status.IsValid() {
config.TrafficLimitStatus = status
}
}
@@ -1594,12 +1624,16 @@ func (this *ServerDAO) FindAllEnabledServersWithDomain(tx *dbs.Tx, domain string
}
// FindEnabledServerWithDomain 根据域名查找服务集群ID
func (this *ServerDAO) FindEnabledServerWithDomain(tx *dbs.Tx, domain string) (server *Server, err error) {
func (this *ServerDAO) FindEnabledServerWithDomain(tx *dbs.Tx, userId int64, domain string) (server *Server, err error) {
if len(domain) == 0 {
return
}
one, err := this.Query(tx).
var query = this.Query(tx)
if userId > 0 {
query.Attr("userId", userId)
}
one, err := query.
State(ServerStateEnabled).
Where("JSON_CONTAINS(plainServerNames, :domain)").
Param("domain", strconv.Quote(domain)).
@@ -1618,7 +1652,11 @@ func (this *ServerDAO) FindEnabledServerWithDomain(tx *dbs.Tx, domain string) (s
var dotIndex = strings.Index(domain, ".")
if dotIndex > 0 {
var wildcardDomain = "*." + domain[dotIndex+1:]
one, err = this.Query(tx).
var wildcardQuery = this.Query(tx)
if userId > 0 {
wildcardQuery.Attr("userId", userId)
}
one, err = wildcardQuery.
State(ServerStateEnabled).
Where("JSON_CONTAINS(plainServerNames, :domain)").
Param("domain", strconv.Quote(wildcardDomain)).
@@ -1761,6 +1799,7 @@ func (this *ServerDAO) FindServerUserId(tx *dbs.Tx, serverId int64) (userId int6
}
// FindServerUserPlanId 查找服务的套餐ID
// TODO 需要缓存
func (this *ServerDAO) FindServerUserPlanId(tx *dbs.Tx, serverId int64) (userPlanId int64, err error) {
return this.Query(tx).
Pk(serverId).
@@ -2006,11 +2045,12 @@ func (this *ServerDAO) GenDNSName(tx *dbs.Tx) (string, error) {
// FindLatestServers 查询最近访问的服务
func (this *ServerDAO) FindLatestServers(tx *dbs.Tx, size int64) (result []*Server, err error) {
itemTable := SharedLatestItemDAO.Table
itemType := LatestItemTypeServer
var itemTable = SharedLatestItemDAO.Table
var itemType = LatestItemTypeServer
_, err = this.Query(tx).
Result(this.Table+".id", this.Table+".name").
Join(SharedLatestItemDAO, dbs.QueryJoinRight, this.Table+".id="+itemTable+".itemId AND "+itemTable+".itemType='"+itemType+"'").
Where(itemTable + ".updatedAt<=UNIX_TIMESTAMP()"). // VERY IMPORTANT
Asc("CEIL((UNIX_TIMESTAMP() - " + itemTable + ".updatedAt) / (7 * 86400))"). // 优先一个星期以内的
Desc(itemTable + ".count").
State(NodeClusterStateEnabled).
@@ -2145,6 +2185,10 @@ func (this *ServerDAO) FindFirstHTTPOrHTTPSPortWithClusterId(tx *dbs.Tx, cluster
// NotifyServerPortsUpdate 通知服务端口变化
func (this *ServerDAO) NotifyServerPortsUpdate(tx *dbs.Tx, serverId int64) error {
if serverId <= 0 {
return nil
}
one, err := this.Query(tx).
Pk(serverId).
Result("tcp", "tls", "udp", "http", "https").
@@ -2269,94 +2313,17 @@ func (this *ServerDAO) FindServerTrafficLimitConfig(tx *dbs.Tx, serverId int64,
return nil, err
}
var limit = &serverconfigs.TrafficLimitConfig{}
if serverOne == nil {
return limit, nil
}
var trafficLimit = serverOne.(*Server).TrafficLimit
if len(trafficLimit) > 0 {
err = json.Unmarshal([]byte(trafficLimit), limit)
if err != nil {
return nil, err
}
}
if cacheMap != nil {
cacheMap.Put(cacheKey, limit)
}
return limit, nil
}
// CalculateServerTrafficLimitConfig 计算服务的流量限制
// TODO 优化性能
func (this *ServerDAO) CalculateServerTrafficLimitConfig(tx *dbs.Tx, serverId int64, cacheMap *utils.CacheMap) (*serverconfigs.TrafficLimitConfig, error) {
if cacheMap == nil {
cacheMap = utils.NewCacheMap()
}
var cacheKey = this.Table + ":FindServerTrafficLimitConfig:" + types.String(serverId)
result, ok := cacheMap.Get(cacheKey)
if ok {
return result.(*serverconfigs.TrafficLimitConfig), nil
}
serverOne, err := this.Query(tx).
Pk(serverId).
Result("trafficLimit", "userPlanId").
Find()
if err != nil {
return nil, err
}
var limitConfig = &serverconfigs.TrafficLimitConfig{}
if serverOne == nil {
return limitConfig, nil
}
var trafficLimit = serverOne.(*Server).TrafficLimit
var userPlanId = int64(serverOne.(*Server).UserPlanId)
var trafficLimitJSON = serverOne.(*Server).TrafficLimit
if len(trafficLimit) == 0 {
if userPlanId > 0 {
userPlan, err := SharedUserPlanDAO.FindEnabledUserPlan(tx, userPlanId, cacheMap)
if err != nil {
return nil, err
}
if userPlan != nil {
planLimit, err := SharedPlanDAO.FindEnabledPlanTrafficLimit(tx, int64(userPlan.PlanId), cacheMap)
if err != nil {
return nil, err
}
if planLimit != nil {
return planLimit, nil
}
}
}
return limitConfig, nil
}
err = json.Unmarshal(trafficLimit, limitConfig)
if err != nil {
return nil, err
}
if !limitConfig.IsOn {
if userPlanId > 0 {
userPlan, err := SharedUserPlanDAO.FindEnabledUserPlan(tx, userPlanId, cacheMap)
if err != nil {
return nil, err
}
if userPlan != nil {
planLimit, err := SharedPlanDAO.FindEnabledPlanTrafficLimit(tx, int64(userPlan.PlanId), cacheMap)
if err != nil {
return nil, err
}
if planLimit != nil {
return planLimit, nil
}
}
if len(trafficLimitJSON) > 0 {
err = json.Unmarshal(trafficLimitJSON, limitConfig)
if err != nil {
return nil, err
}
}
@@ -2386,11 +2353,11 @@ func (this *ServerDAO) UpdateServerTrafficLimitConfig(tx *dbs.Tx, serverId int64
}
// 更新状态
return this.UpdateServerTrafficLimitStatus(tx, trafficLimitConfig, serverId, true)
return this.RenewServerTrafficLimitStatus(tx, trafficLimitConfig, serverId, true)
}
// UpdateServerTrafficLimitStatus 修改服务的流量限制状态
func (this *ServerDAO) UpdateServerTrafficLimitStatus(tx *dbs.Tx, trafficLimitConfig *serverconfigs.TrafficLimitConfig, serverId int64, isUpdatingConfig bool) error {
// RenewServerTrafficLimitStatus 根据限流配置更新网站的流量限制状态
func (this *ServerDAO) RenewServerTrafficLimitStatus(tx *dbs.Tx, trafficLimitConfig *serverconfigs.TrafficLimitConfig, serverId int64, isUpdatingConfig bool) error {
if !trafficLimitConfig.IsOn {
if isUpdatingConfig {
return this.NotifyUpdate(tx, serverId)
@@ -2427,9 +2394,11 @@ func (this *ServerDAO) UpdateServerTrafficLimitStatus(tx *dbs.Tx, trafficLimitCo
var untilDay = ""
// daily
var dateType = ""
if trafficLimitConfig.DailyBytes() > 0 {
if server.TrafficDay == timeutil.Format("Ymd") && server.TotalDailyTraffic >= float64(trafficLimitConfig.DailyBytes())/(1<<30) {
untilDay = timeutil.Format("Ymd")
dateType = "day"
}
}
@@ -2437,6 +2406,7 @@ func (this *ServerDAO) UpdateServerTrafficLimitStatus(tx *dbs.Tx, trafficLimitCo
if server.TrafficMonth == timeutil.Format("Ym") && trafficLimitConfig.MonthlyBytes() > 0 {
if server.TotalMonthlyTraffic >= float64(trafficLimitConfig.MonthlyBytes())/(1<<30) {
untilDay = timeutil.Format("Ym32")
dateType = "month"
}
}
@@ -2444,12 +2414,17 @@ func (this *ServerDAO) UpdateServerTrafficLimitStatus(tx *dbs.Tx, trafficLimitCo
if trafficLimitConfig.TotalBytes() > 0 {
if server.TotalTraffic >= float64(trafficLimitConfig.TotalBytes())/(1<<30) {
untilDay = "30000101"
dateType = "total"
}
}
var isChanged = oldStatus.UntilDay != untilDay
if isChanged {
statusJSON, err := json.Marshal(&serverconfigs.TrafficLimitStatus{UntilDay: untilDay})
statusJSON, err := json.Marshal(&serverconfigs.TrafficLimitStatus{
UntilDay: untilDay,
DateType: dateType,
TargetType: serverconfigs.TrafficLimitTargetTraffic,
})
if err != nil {
return err
}
@@ -2470,8 +2445,97 @@ func (this *ServerDAO) UpdateServerTrafficLimitStatus(tx *dbs.Tx, trafficLimitCo
return nil
}
// UpdateServerTrafficLimitStatus 修改网站的流量限制状态
func (this *ServerDAO) UpdateServerTrafficLimitStatus(tx *dbs.Tx, serverId int64, day string, planId int64, dateType string, targetType string) error {
if !regexputils.YYYYMMDD.MatchString(day) {
return errors.New("invalid 'day' format")
}
if serverId <= 0 {
return nil
}
// lookup old status
statusJSON, err := this.Query(tx).
Pk(serverId).
Result(ServerField_TrafficLimitStatus).
FindJSONCol()
if err != nil {
return err
}
if IsNotNull(statusJSON) {
var oldStatus = &serverconfigs.TrafficLimitStatus{}
err = json.Unmarshal(statusJSON, oldStatus)
if err != nil {
return err
}
if len(oldStatus.UntilDay) > 0 && oldStatus.UntilDay >= day /** 如果已经限制,且比当前日期长,则无需重复 **/ {
// no need to change
return nil
}
}
var status = &serverconfigs.TrafficLimitStatus{
UntilDay: day,
PlanId: planId,
DateType: dateType,
TargetType: targetType,
}
statusJSON, err = json.Marshal(status)
if err != nil {
return err
}
err = this.Query(tx).
Pk(serverId).
Set(ServerField_TrafficLimitStatus, statusJSON).
UpdateQuickly()
if err != nil {
return err
}
return this.NotifyUpdate(tx, serverId)
}
// UpdateServersTrafficLimitStatusWithUserPlanId 修改某个套餐下的网站的流量限制状态
func (this *ServerDAO) UpdateServersTrafficLimitStatusWithUserPlanId(tx *dbs.Tx, userPlanId int64, day string, planId int64, dateType string, targetType serverconfigs.TrafficLimitTarget) error {
if userPlanId <= 0 {
return nil
}
servers, err := this.Query(tx).
State(ServerStateEnabled).
Attr("userPlanId", userPlanId).
ResultPk().
FindAll()
if err != nil {
return err
}
for _, server := range servers {
var serverId = int64(server.(*Server).Id)
err = this.UpdateServerTrafficLimitStatus(tx, serverId, day, planId, dateType, targetType)
if err != nil {
return err
}
}
return nil
}
// ResetServersTrafficLimitStatusWithPlanId 重置网站限流状态
func (this *ServerDAO) ResetServersTrafficLimitStatusWithPlanId(tx *dbs.Tx, planId int64) error {
return this.Query(tx).
Where("JSON_EXTRACT(trafficLimitStatus, '$.planId')=:planId").
Param("planId", planId).
Set("trafficLimitStatus", dbs.SQL("NULL")).
UpdateQuickly()
}
// IncreaseServerTotalTraffic 增加服务的总流量
func (this *ServerDAO) IncreaseServerTotalTraffic(tx *dbs.Tx, serverId int64, bytes int64) error {
if serverId <= 0 {
return errors.New("serverId should not be smaller than 0")
}
var gb = float64(bytes) / (1 << 30)
var day = timeutil.Format("Ymd")
var month = timeutil.Format("Ym")
@@ -2507,17 +2571,16 @@ func (this *ServerDAO) FindEnabledServerIdWithUserPlanId(tx *dbs.Tx, userPlanId
FindInt64Col(0)
}
// FindEnabledServerWithUserPlanId 查找使用某个套餐的服务
func (this *ServerDAO) FindEnabledServerWithUserPlanId(tx *dbs.Tx, userPlanId int64) (*Server, error) {
one, err := this.Query(tx).
// FindEnabledServersWithUserPlanId 查找使用某个套餐的网站
func (this *ServerDAO) FindEnabledServersWithUserPlanId(tx *dbs.Tx, userPlanId int64) (result []*Server, err error) {
_, err = this.Query(tx).
State(ServerStateEnabled).
Attr("userPlanId", userPlanId).
Result("id", "name", "serverNames", "type").
Find()
if err != nil || one == nil {
return nil, err
}
return one.(*Server), nil
AscPk().
Slice(&result).
FindAll()
return
}
// UpdateServersClusterIdWithPlanId 修改套餐所在集群
@@ -2531,6 +2594,10 @@ func (this *ServerDAO) UpdateServersClusterIdWithPlanId(tx *dbs.Tx, planId int64
// UpdateServerUserPlanId 设置服务所属套餐
func (this *ServerDAO) UpdateServerUserPlanId(tx *dbs.Tx, serverId int64, userPlanId int64) error {
if serverId <= 0 {
return errors.New("serverId should not be smaller than 0")
}
oldClusterId, err := this.Query(tx).
Pk(serverId).
Result("clusterId").
@@ -2598,7 +2665,7 @@ func (this *ServerDAO) UpdateServerUserPlanId(tx *dbs.Tx, serverId int64, userPl
return errors.New("can not find user plan with id '" + types.String(userPlanId) + "'")
}
plan, err := SharedPlanDAO.FindEnabledPlan(tx, int64(userPlan.PlanId))
plan, err := SharedPlanDAO.FindEnabledPlan(tx, int64(userPlan.PlanId), nil)
if err != nil {
return err
}
@@ -2638,6 +2705,10 @@ func (this *ServerDAO) UpdateServerUserPlanId(tx *dbs.Tx, serverId int64, userPl
// FindServerLastUserPlanIdAndUserId 查找最后使用的套餐
func (this *ServerDAO) FindServerLastUserPlanIdAndUserId(tx *dbs.Tx, serverId int64) (userPlanId int64, userId int64, err error) {
if serverId <= 0 {
return 0, 0, errors.New("serverId should not be smaller than 0")
}
one, err := this.Query(tx).
Pk(serverId).
Result("lastUserPlanId", "userId").
@@ -2651,6 +2722,10 @@ func (this *ServerDAO) FindServerLastUserPlanIdAndUserId(tx *dbs.Tx, serverId in
// UpdateServerUAM 开启UAM
func (this *ServerDAO) UpdateServerUAM(tx *dbs.Tx, serverId int64, uamConfig *serverconfigs.UAMConfig) error {
if serverId <= 0 {
return errors.New("serverId should not be smaller than 0")
}
if uamConfig == nil {
return nil
}
@@ -2702,7 +2777,7 @@ func (this *ServerDAO) FindUserServerClusterIds(tx *dbs.Tx, userId int64) ([]int
// UpdateServerBandwidth 更新服务带宽
// fullTime YYYYMMDDHHII
func (this *ServerDAO) UpdateServerBandwidth(tx *dbs.Tx, serverId int64, fullTime string, bandwidthBytes int64) error {
func (this *ServerDAO) UpdateServerBandwidth(tx *dbs.Tx, serverId int64, fullTime string, bandwidthBytes int64, countRequests int64, countAttackRequests int64) error {
if serverId <= 0 {
return nil
}
@@ -2723,13 +2798,19 @@ func (this *ServerDAO) UpdateServerBandwidth(tx *dbs.Tx, serverId int64, fullTim
Pk(serverId).
Set("bandwidthTime", fullTime).
Set("bandwidthBytes", bandwidthBytes).
Set("countRequests", countRequests).
Set("countAttackRequests", countAttackRequests).
UpdateQuickly()
} else {
return this.Query(tx).
Pk(serverId).
Set("bandwidthTime", fullTime).
Set("bandwidthBytes", dbs.SQL("bandwidthBytes+:bytes")).
Set("countRequests", dbs.SQL("countRequests+:countRequests")).
Set("countAttackRequests", dbs.SQL("countAttackRequests+:countAttackRequests")).
Param("bytes", bandwidthBytes).
Param("countRequests", countRequests).
Param("countAttackRequests", countAttackRequests).
UpdateQuickly()
}
}
@@ -2822,8 +2903,95 @@ func (this *ServerDAO) FindEnabledServersWithIds(tx *dbs.Tx, serverIds []int64)
return
}
// CountAllServerNamesWithUserId 计算某个用户下的所有域名数
func (this *ServerDAO) CountAllServerNamesWithUserId(tx *dbs.Tx, userId int64, userPlanId int64) (int64, error) {
if userId <= 0 {
return 0, nil
}
var query = this.Query(tx).
Attr("userId", userId).
State(ServerStateEnabled).
Where("JSON_TYPE(plainServerNames)='ARRAY'")
if userPlanId > 0 {
query.Attr("userPlanId", userPlanId)
}
return query.
SumInt64("JSON_LENGTH(plainServerNames)", 0)
}
// CountServerNames 计算某个网站下的所有域名数
func (this *ServerDAO) CountServerNames(tx *dbs.Tx, serverId int64) (int64, error) {
if serverId <= 0 {
return 0, nil
}
return this.Query(tx).
Result("JSON_LENGTH(plainServerNames)").
Pk(serverId).
State(ServerStateEnabled).
Where("JSON_TYPE(plainServerNames)='ARRAY'").
FindInt64Col(0)
}
// CheckServerPlanQuota 检查网站套餐限制
func (this *ServerDAO) CheckServerPlanQuota(tx *dbs.Tx, serverId int64, countServerNames int) error {
if serverId <= 0 {
return errors.New("invalid 'serverId'")
}
if countServerNames <= 0 {
return nil
}
userPlanId, err := this.FindServerUserPlanId(tx, serverId)
if err != nil {
return err
}
if userPlanId <= 0 {
return nil
}
userPlan, err := SharedUserPlanDAO.FindEnabledUserPlan(tx, userPlanId, nil)
if err != nil {
return err
}
if userPlan == nil {
return fmt.Errorf("invalid user plan with id %q", types.String(userPlanId))
}
if userPlan.IsExpired() {
return errors.New("the user plan has been expired")
}
if userPlan.UserId == 0 {
return nil
}
plan, err := SharedPlanDAO.FindEnabledPlan(tx, int64(userPlan.PlanId), nil)
if err != nil {
return err
}
if plan == nil {
return fmt.Errorf("invalid plan with id %q", types.String(userPlan.PlanId))
}
if plan.TotalServerNames > 0 {
totalServerNames, err := this.CountAllServerNamesWithUserId(tx, int64(userPlan.UserId), userPlanId)
if err != nil {
return err
}
if totalServerNames+int64(countServerNames) > int64(plan.TotalServerNames) {
return errors.New("server names over plan quota")
}
}
if plan.TotalServerNamesPerServer > 0 {
if countServerNames > types.Int(plan.TotalServerNamesPerServer) {
return errors.New("server names per server over plan quota")
}
}
return nil
}
// NotifyUpdate 同步服务所在的集群
func (this *ServerDAO) NotifyUpdate(tx *dbs.Tx, serverId int64) error {
if serverId <= 0 {
return nil
}
// 创建任务
clusterId, err := this.FindServerClusterId(tx, serverId)
if err != nil {
@@ -2837,6 +3005,9 @@ func (this *ServerDAO) NotifyUpdate(tx *dbs.Tx, serverId int64) error {
// NotifyClusterUpdate 同步指定的集群
func (this *ServerDAO) NotifyClusterUpdate(tx *dbs.Tx, clusterId, serverId int64) error {
if serverId <= 0 {
return nil
}
if clusterId <= 0 {
return nil
}
@@ -2845,6 +3016,10 @@ func (this *ServerDAO) NotifyClusterUpdate(tx *dbs.Tx, clusterId, serverId int64
// NotifyDNSUpdate 通知当前集群DNS更新
func (this *ServerDAO) NotifyDNSUpdate(tx *dbs.Tx, serverId int64) error {
if serverId <= 0 {
return nil
}
clusterId, err := this.Query(tx).
Pk(serverId).
Result("clusterId").
@@ -2870,6 +3045,10 @@ func (this *ServerDAO) NotifyDNSUpdate(tx *dbs.Tx, serverId int64) error {
// NotifyClusterDNSUpdate 通知某个集群中的DNS更新
func (this *ServerDAO) NotifyClusterDNSUpdate(tx *dbs.Tx, clusterId int64, serverId int64) error {
if serverId <= 0 {
return nil
}
dnsInfo, err := SharedNodeClusterDAO.FindClusterDNSInfo(tx, clusterId, nil)
if err != nil {
return err
@@ -2885,6 +3064,10 @@ func (this *ServerDAO) NotifyClusterDNSUpdate(tx *dbs.Tx, clusterId int64, serve
// NotifyDisable 通知禁用
func (this *ServerDAO) NotifyDisable(tx *dbs.Tx, serverId int64) error {
if serverId <= 0 {
return nil
}
// 禁用缓存策略相关的内容
policyIds, err := SharedHTTPFirewallPolicyDAO.FindFirewallPolicyIdsWithServerId(tx, serverId)
if err != nil {

Some files were not shown because too many files have changed in this diff Show More