Compare commits

...

210 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
刘祥超
1b949bd056 版本号修改为1.0.1 2023-04-10 09:18:12 +08:00
刘祥超
c4e415a72f 修复一个单词拼写错误/如果创建服务时没有指定服务名,则自动取第一个域名作为服务名 2023-04-09 20:11:36 +08:00
刘祥超
39cb95184d 查询弱密码管理员时只查询已启用的管理员 2023-04-09 17:31:09 +08:00
刘祥超
a7abca6c09 Update sql.json 2023-04-09 17:23:37 +08:00
刘祥超
894eff89ba 去除不需要的接口 2023-04-09 17:04:32 +08:00
刘祥超
35558f1d38 版本号更改为1.0.0 2023-04-09 16:19:52 +08:00
刘祥超
5a93ec0e32 增加服务之间拷贝配置的API(开源版本只有定义,没有完全实现) 2023-04-09 16:01:23 +08:00
刘祥超
73164de93e 查询快过期证书时,只查询启用的 2023-04-08 09:15:03 +08:00
刘祥超
199349084e 提供批量更新服务配置API(阶段性提交) 2023-04-06 20:49:22 +08:00
刘祥超
648fc2cac3 审计日志列表增加级别筛选 2023-04-06 10:06:56 +08:00
刘祥超
43f34950f3 自动检查管理员弱密码并提醒 2023-04-04 17:26:08 +08:00
刘祥超
1f0182e4a5 优化错误提示 2023-04-04 15:56:44 +08:00
刘祥超
3f972571b0 5秒盾策略变化时只更新策略配置 2023-04-03 16:11:48 +08:00
刘祥超
0618ca9f8a 优化操作IP条目时检查用户ID的相关代码 2023-04-03 10:02:17 +08:00
刘祥超
efd0823b25 上传SQL 2023-04-01 21:46:54 +08:00
刘祥超
af5ca9faf5 修复删除IP名单中IP时状态设置错误的问题 2023-04-01 20:48:47 +08:00
刘祥超
87c5eeb829 可以批量上传IP名单 2023-03-31 21:42:15 +08:00
刘祥超
df775272be 提供修改网站名称的接口 2023-03-31 15:30:22 +08:00
刘祥超
dbeabe4379 节点中增加授权信息 2023-03-31 12:39:01 +08:00
刘祥超
dd33504416 IP库文件可以加密 2023-03-30 20:00:22 +08:00
刘祥超
d45dca4edb IP制品列表中增加文件尺寸 2023-03-29 20:09:00 +08:00
刘祥超
b4472271ce 优化证书到期提醒等相关消息 2023-03-28 16:52:04 +08:00
刘祥超
138eddf771 修复发送站内消息时将标题作为内容的Bug 2023-03-28 16:25:18 +08:00
刘祥超
f0667abe55 删除edgeServers表中的state索引,防止查询时产生索引冲突 2023-03-27 17:14:48 +08:00
刘祥超
873af38807 优化服务列表查询 2023-03-27 17:14:12 +08:00
刘祥超
9bf46af088 增加默认CC设置 2023-03-26 12:41:01 +08:00
刘祥超
3a3b5bca20 上传单个证书时也可以选择所属用户 2023-03-26 12:24:31 +08:00
刘祥超
4806025f89 实现自动匹配证书和批量选择证书功能 2023-03-25 20:51:08 +08:00
刘祥超
d7c757a2a1 增加批量上传证书接口、使用域名查询证书接口 2023-03-24 19:07:43 +08:00
刘祥超
3e8873d828 修复查看服务24小时流量统计会产生panic的问题 2023-03-23 15:45:03 +08:00
刘祥超
84484b6538 优化服务带宽查询速度 2023-03-23 11:23:16 +08:00
刘祥超
d36e9e80ee 上传流量数据时同时上传服务所属用户ID 2023-03-22 19:33:25 +08:00
刘祥超
1fb831ca58 修复测试用例 2023-03-22 19:10:52 +08:00
刘祥超
5e20553602 合并部分流量查询和带宽查询 2023-03-22 17:54:44 +08:00
刘祥超
0f83d8ec66 导出SQL结构时使用embed取代生成sql.go 2023-03-22 11:19:58 +08:00
刘祥超
e45a6cbcb5 优化域名查询程序 2023-03-21 11:38:20 +08:00
刘祥超
ba1fd07555 增加edge-api token --role=[admin|user|api]命令用来快速查询节点Token 2023-03-19 21:24:24 +08:00
刘祥超
a70b4bfaf3 更新相关库 2023-03-19 17:51:21 +08:00
刘祥超
9cf47ae1af DNS集群增加自动检测端口选项 2023-03-19 17:44:56 +08:00
刘祥超
7f58d65a57 修复DataMap无法在多个节点之间共享的问题 2023-03-19 10:26:05 +08:00
刘祥超
4d40dd03de 优化节点压缩程序 2023-03-18 22:44:23 +08:00
刘祥超
e3ce79c9fc 增加RPC消息最大尺寸到512MB 2023-03-18 22:44:04 +08:00
刘祥超
f543edac1a 节点组合配置时服务间可以共用证书数据 2023-03-18 22:18:13 +08:00
刘祥超
1ce11a5745 优化服务配置组合 2023-03-18 19:52:42 +08:00
刘祥超
ab56c7451a DNS解析发生变化时立即触发同步任务 2023-03-18 16:53:08 +08:00
刘祥超
9800bbb661 修复无法同时对相同对象执行多次DNS解析任务的问题 2023-03-18 16:40:00 +08:00
刘祥超
8c4d2e7301 查询节点DNS信息时可以区分节点是否已安装 2023-03-18 16:05:10 +08:00
刘祥超
2c17675b6a 增加分隔关键词函数 2023-03-18 11:10:44 +08:00
刘祥超
3b30705f33 在API节点启动时,如果无法连接到本地MySQL数据库,则尝试启动固定位置上的MySQL 2023-03-17 16:02:37 +08:00
刘祥超
4cd9c5071d 版本号更改为0.6.5 2023-03-17 15:53:52 +08:00
282 changed files with 71274 additions and 11039 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: 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

@@ -17,6 +17,7 @@ import (
"github.com/iwind/gosock/pkg/gosock" "github.com/iwind/gosock/pkg/gosock"
"log" "log"
"os" "os"
"strings"
) )
func main() { func main() {
@@ -188,6 +189,38 @@ func main() {
} }
} }
}) })
app.On("token", func() {
var role = ""
if len(os.Args) <= 2 {
fmt.Println("require --role parameter")
return
}
var set = flag.NewFlagSet("", flag.ExitOnError)
set.StringVar(&role, "role", "", "edge-api token --role=[admin|user|api]")
_ = set.Parse(os.Args[2:])
var sock = gosock.NewTmpSock(teaconst.ProcessName)
reply, err := sock.Send(&gosock.Command{Code: "lookupToken", Params: map[string]any{
"role": role,
}})
if err != nil {
fmt.Println("[ERROR]" + err.Error())
} else {
var resultMap = maps.NewMap(reply.Params)
if resultMap.GetBool("isOk") {
var tokens = resultMap.GetSlice("tokens")
fmt.Printf("%-35s | %-35s\n", "nodeId", "secret")
fmt.Println(strings.Repeat("-", 70))
for _, tokenMap := range tokens {
var m = maps.NewMap(tokenMap)
fmt.Printf("%-35s | %-35s\n", m.GetString("nodeId"), m.GetString("secret"))
}
} else {
fmt.Println("[ERROR]" + resultMap.GetString("err"))
}
}
})
app.Run(func() { app.Run(func() {
nodes.NewAPINode().Start() nodes.NewAPINode().Start()

View File

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

View File

@@ -4,12 +4,11 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"github.com/TeaOSLab/EdgeAPI/internal/setup" "github.com/TeaOSLab/EdgeAPI/internal/setup"
"github.com/iwind/TeaGo/Tea"
_ "github.com/iwind/TeaGo/bootstrap" _ "github.com/iwind/TeaGo/bootstrap"
"github.com/iwind/TeaGo/dbs" "github.com/iwind/TeaGo/dbs"
"go/format"
"os" "os"
"path/filepath" "path/filepath"
"strconv"
) )
func main() { func main() {
@@ -23,11 +22,6 @@ func main() {
fmt.Println("[ERROR]" + err.Error()) fmt.Println("[ERROR]" + err.Error())
return return
} }
resultsJSON, err := json.Marshal(results)
if err != nil {
fmt.Println("[ERROR]" + err.Error())
return
}
prettyResultsJSON, err := json.MarshalIndent(results, "", " ") prettyResultsJSON, err := json.MarshalIndent(results, "", " ")
if err != nil { if err != nil {
@@ -35,52 +29,8 @@ func main() {
return return
} }
// 写入到 sql.go 中
dir, _ := os.Getwd()
var sqlFile string
for i := 0; i < 5; i++ {
lookupFile := dir + "/internal/setup/sql.go"
_, err = os.Stat(lookupFile)
if err != nil {
dir = filepath.Dir(dir)
continue
}
sqlFile = lookupFile
}
if len(sqlFile) == 0 {
fmt.Println("[ERROR]can not find sql.go")
return
}
content := []byte(`package setup
import (
"encoding/json"
"github.com/iwind/TeaGo/logs"
)
// 最新版本的数据库SQL语句用来对比并升级已有的数据库
// 由 sql-dump/main.go 自动生成
func init() {
err := json.Unmarshal([]byte(` + strconv.Quote(string(resultsJSON)) + `), LatestSQLResult)
if err != nil {
logs.Println("[ERROR]load sql failed: " + err.Error())
}
}
`)
dst, err := format.Source(content)
if err != nil {
fmt.Println("[ERROR]format code failed: " + err.Error())
return
}
err = os.WriteFile(sqlFile, dst, 0666)
if err != nil {
fmt.Println("[ERROR]write file failed: " + err.Error())
return
}
// 写入到 sql.json 中 // 写入到 sql.json 中
var dir = filepath.Dir(Tea.Root)
err = os.WriteFile(dir+"/internal/setup/sql.json", prettyResultsJSON, 0666) err = os.WriteFile(dir+"/internal/setup/sql.json", prettyResultsJSON, 0666)
if err != nil { if err != nil {
fmt.Println("[ERROR]" + err.Error()) fmt.Println("[ERROR]" + err.Error())

23
go.mod
View File

@@ -10,25 +10,26 @@ require (
github.com/andybalholm/brotli v1.0.4 github.com/andybalholm/brotli v1.0.4
github.com/cespare/xxhash v1.1.0 github.com/cespare/xxhash v1.1.0
github.com/cespare/xxhash/v2 v2.1.1 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-sql-driver/mysql v1.5.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/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/iwind/gosock v0.0.0-20220505115348-f88412125a62
github.com/miekg/dns v1.1.50 github.com/miekg/dns v1.1.50
github.com/mozillazg/go-pinyin v0.18.0 github.com/mozillazg/go-pinyin v0.18.0
github.com/pkg/sftp v1.12.0 github.com/pkg/sftp v1.12.0
github.com/shirou/gopsutil/v3 v3.22.2 github.com/shirou/gopsutil/v3 v3.22.2
github.com/smartwalle/alipay/v3 v3.1.7 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.7.0 golang.org/x/net v0.8.0
golang.org/x/sys v0.5.0 golang.org/x/sys v0.8.0
google.golang.org/grpc v1.45.0 google.golang.org/grpc v1.45.0
gopkg.in/yaml.v3 v3.0.1 gopkg.in/yaml.v3 v3.0.1
) )
require ( 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/go-ole/go-ole v1.2.6 // indirect
github.com/golang/protobuf v1.5.2 // indirect github.com/golang/protobuf v1.5.2 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect
@@ -40,13 +41,15 @@ require (
github.com/pkg/errors v0.9.1 // indirect github.com/pkg/errors v0.9.1 // indirect
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
github.com/smartwalle/crypto4go v1.0.2 // 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/technoweenie/multipartstreamer v1.0.1 // indirect
github.com/tklauser/go-sysconf v0.3.9 // indirect github.com/tklauser/go-sysconf v0.3.9 // indirect
github.com/tklauser/numcpus v0.3.0 // indirect github.com/tklauser/numcpus v0.3.0 // indirect
github.com/yusufpapurcu/wmi v1.2.2 // indirect github.com/yusufpapurcu/wmi v1.2.2 // indirect
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect golang.org/x/mod v0.8.0 // indirect
golang.org/x/text v0.7.0 // indirect golang.org/x/text v0.8.0 // indirect
golang.org/x/tools v0.1.12 // indirect golang.org/x/tools v0.6.0 // indirect
google.golang.org/genproto v0.0.0-20220317150908-0efb43f6373e // indirect google.golang.org/genproto v0.0.0-20220317150908-0efb43f6373e // indirect
google.golang.org/protobuf v1.28.0 // indirect google.golang.org/protobuf v1.28.0 // indirect
gopkg.in/ini.v1 v1.66.6 // indirect gopkg.in/ini.v1 v1.66.6 // indirect

61
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/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/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/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.2.0 h1:HN5dHm3WBOgndBH6E8V0q2jIYIR3s9yglV8k/+MN3u4=
github.com/cenkalti/backoff/v4 v4.1.3/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= 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/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 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= 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 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= 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/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-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= 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 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 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/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.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.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
@@ -38,13 +41,16 @@ 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/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.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.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/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-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= github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-redis/redis/v8 v8.0.0-beta.7/go.mod h1:FGJAWDWFht1sQ4qxyJHZZbVyvnVcKQN0E3u5/5lRz+g= github.com/go-redis/redis/v8 v8.0.0-beta.7/go.mod h1:FGJAWDWFht1sQ4qxyJHZZbVyvnVcKQN0E3u5/5lRz+g=
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc=
github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible h1:2cauKuaELYAEARXRkq2LrJ0yDDv1rW7+wrTEdVL3uaU= github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible h1:2cauKuaELYAEARXRkq2LrJ0yDDv1rW7+wrTEdVL3uaU=
github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible/go.mod h1:qf9acutJ8cwBUhm1bqgz6Bei9/C/c93FPDljKWwsOgM= github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible/go.mod h1:qf9acutJ8cwBUhm1bqgz6Bei9/C/c93FPDljKWwsOgM=
github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A= github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A=
@@ -78,12 +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/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/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-20210411134150-ddf57e240c2f/go.mod h1:KU4mS7QNiZ7QWEuDBk1zw0/Q2LrAPZv3tycEFBsuUwc=
github.com/iwind/TeaGo v0.0.0-20230109112127-225731e65eea h1:e5jlcUN13pNzUbyNW8Ag2Ev5K/2ppgY0m5grqTeFI6Q= github.com/iwind/TeaGo v0.0.0-20230704135818-4a5646ab1f5b h1:yYUaxnc04uzfr7C9HBN52ZZvcQomND+C5aZTpjOUYFI=
github.com/iwind/TeaGo v0.0.0-20230109112127-225731e65eea/go.mod h1:fi/Pq+/5m2HZoseM+39dMF57ANXRt6w4PkGu3NXPc5s= github.com/iwind/TeaGo v0.0.0-20230704135818-4a5646ab1f5b/go.mod h1:fi/Pq+/5m2HZoseM+39dMF57ANXRt6w4PkGu3NXPc5s=
github.com/iwind/TeaGo v0.0.0-20230303070415-9d0689db6456 h1:xv3AVaxuwjThkBDptAfsFSmuHQIrRrvt8BRaekWnsvs=
github.com/iwind/TeaGo v0.0.0-20230303070415-9d0689db6456/go.mod h1:fi/Pq+/5m2HZoseM+39dMF57ANXRt6w4PkGu3NXPc5s=
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/gosock v0.0.0-20220505115348-f88412125a62 h1:HJH6RDheAY156DnIfJSD/bEvqyXzsZuE2gzs8PuUjoo= 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/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= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
@@ -99,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/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 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/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.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 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= 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 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA=
github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= 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= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@@ -143,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/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 h1:qLC7fQah7D6K1B0ujays3HV9gkFtllcxhzImRR7ArPQ=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= 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/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.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.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.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= 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 h1:XRztA5MXiR1TIRHxH2uNxXxaIkKQDeX7m2XsSOlQEnM=
github.com/technoweenie/multipartstreamer v1.0.1/go.mod h1:jNVxdtShOxzAsukZwTSw6MDx5eUJoiEBsSvzDU9uzog= github.com/technoweenie/multipartstreamer v1.0.1/go.mod h1:jNVxdtShOxzAsukZwTSw6MDx5eUJoiEBsSvzDU9uzog=
github.com/tklauser/go-sysconf v0.3.9 h1:JeUVdAOWhhxVcU6Eqr/ATFHgXk/mmiItdKeJPev3vTo= github.com/tklauser/go-sysconf v0.3.9 h1:JeUVdAOWhhxVcU6Eqr/ATFHgXk/mmiItdKeJPev3vTo=
@@ -165,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-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-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/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.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE=
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= 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-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-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20200513190911-00229845015e/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw= golang.org/x/exp v0.0.0-20200513190911-00229845015e/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw=
@@ -179,8 +190,8 @@ golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCc
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s= golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -194,8 +205,8 @@ golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g= golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -203,7 +214,7 @@ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw= golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -225,17 +236,19 @@ 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-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-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.0.0-20220111092808-5a964db01320/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0 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.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.5.0 h1:n2a8QNdAb0sZNpU9R1ALUXBbY+w51fCQDN+7EdxNBsY= golang.org/x/term v0.6.0 h1:clScbb1cHjoCkyRbWwBEUZ5H/tIFu5TAXIqaZD0Gcjw=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
@@ -244,8 +257,8 @@ golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBn
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU= golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

View File

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

View File

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

View File

@@ -1,6 +1,7 @@
package acme package acme
import ( import (
"fmt"
teaconst "github.com/TeaOSLab/EdgeAPI/internal/const" teaconst "github.com/TeaOSLab/EdgeAPI/internal/const"
"github.com/TeaOSLab/EdgeAPI/internal/errors" "github.com/TeaOSLab/EdgeAPI/internal/errors"
"github.com/go-acme/lego/v4/certcrypto" "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() var resource = this.task.User.GetRegistration()
if resource != nil { if resource != nil {
resource, err = client.Registration.QueryRegistration() _, err = client.Registration.QueryRegistration()
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
} else { } else {
if this.task.Provider.RequireEAB { if this.task.Provider.RequireEAB {
resource, err := client.Registration.RegisterWithExternalAccountBinding(registration.RegisterEABOptions{ resource, err = client.Registration.RegisterWithExternalAccountBinding(registration.RegisterEABOptions{
TermsOfServiceAgreed: true, TermsOfServiceAgreed: true,
Kid: this.task.Account.EABKid, Kid: this.task.Account.EABKid,
HmacEncoded: this.task.Account.EABKey, HmacEncoded: this.task.Account.EABKey,
}) })
if err != nil { 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) err = this.task.User.Register(resource)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
} else { } else {
resource, err := client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true}) resource, err = client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
@@ -134,7 +135,7 @@ func (this *Request) runDNS() (certData []byte, keyData []byte, err error) {
} }
certResource, err := client.Certificate.Obtain(request) certResource, err := client.Certificate.Obtain(request)
if err != nil { 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 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() var resource = this.task.User.GetRegistration()
if resource != nil { if resource != nil {
resource, err = client.Registration.QueryRegistration() _, err = client.Registration.QueryRegistration()
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
} else { } else {
if this.task.Provider.RequireEAB { if this.task.Provider.RequireEAB {
resource, err := client.Registration.RegisterWithExternalAccountBinding(registration.RegisterEABOptions{ resource, err = client.Registration.RegisterWithExternalAccountBinding(registration.RegisterEABOptions{
TermsOfServiceAgreed: true, TermsOfServiceAgreed: true,
Kid: this.task.Account.EABKid, Kid: this.task.Account.EABKid,
HmacEncoded: this.task.Account.EABKey, HmacEncoded: this.task.Account.EABKey,
}) })
if err != nil { 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) err = this.task.User.Register(resource)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
} else { } else {
resource, err := client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true}) resource, err = client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }

View File

@@ -1,6 +1,7 @@
package apps package apps
import ( import (
"errors"
"fmt" "fmt"
teaconst "github.com/TeaOSLab/EdgeAPI/internal/const" teaconst "github.com/TeaOSLab/EdgeAPI/internal/const"
"github.com/iwind/TeaGo/logs" "github.com/iwind/TeaGo/logs"
@@ -9,8 +10,10 @@ import (
"github.com/iwind/gosock/pkg/gosock" "github.com/iwind/gosock/pkg/gosock"
"os" "os"
"os/exec" "os/exec"
"path/filepath"
"runtime" "runtime"
"strconv" "strconv"
"strings"
"time" "time"
) )
@@ -184,13 +187,16 @@ func (this *AppCmd) runStart() {
return return
} }
cmd := exec.Command(os.Args[0]) var cmd = exec.Command(this.exe())
err := cmd.Start() err := cmd.Start()
if err != nil { if err != nil {
fmt.Println(this.product+" start failed:", err.Error()) fmt.Println(this.product+" start failed:", err.Error())
return return
} }
// create symbolic links
_ = this.createSymLinks()
fmt.Println(this.product+" started ok, pid:", cmd.Process.Pid) 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") 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 package teaconst
const ( const (
Version = "0.6.4.2" Version = "1.2.11"
ProductName = "Edge API" ProductName = "Edge API"
ProcessName = "edge-api" ProcessName = "edge-api"
ProductNameZH = "Edge" ProductNameZH = "Edge"
GlobalProductName = "GoEdge"
Role = "api" Role = "api"
EncryptKey = "8f983f4d69b83aaa0d74b21a212f6967" EncryptKey = "8f983f4d69b83aaa0d74b21a212f6967"
@@ -18,7 +20,7 @@ const (
// 其他节点版本号,用来检测是否有需要升级的节点 // 其他节点版本号,用来检测是否有需要升级的节点
NodeVersion = "0.6.4.2" NodeVersion = "1.2.10"
// SQLVersion SQL版本号 // SQLVersion SQL版本号
SQLVersion = "11" SQLVersion = "11"

View File

@@ -14,6 +14,7 @@ import (
var ( var (
IsPlus = false IsPlus = false
Edition = ""
MaxNodes int32 = 0 MaxNodes int32 = 0
NodeId int64 = 0 NodeId int64 = 0
Debug = false Debug = false

View File

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

View File

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

View File

@@ -1,6 +1,7 @@
package models package models
import ( import (
dbutils "github.com/TeaOSLab/EdgeAPI/internal/db/utils"
"github.com/TeaOSLab/EdgeAPI/internal/errors" "github.com/TeaOSLab/EdgeAPI/internal/errors"
_ "github.com/go-sql-driver/mysql" _ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea" "github.com/iwind/TeaGo/Tea"
@@ -266,17 +267,36 @@ func (this *AdminDAO) FindAllAdminModules(tx *dbs.Tx) (result []*Admin, err erro
} }
// CountAllEnabledAdmins 计算所有管理员数量 // CountAllEnabledAdmins 计算所有管理员数量
func (this *AdminDAO) CountAllEnabledAdmins(tx *dbs.Tx) (int64, error) { func (this *AdminDAO) CountAllEnabledAdmins(tx *dbs.Tx, keyword string, hasWeakPasswords bool) (int64, error) {
return this.Query(tx). var query = this.Query(tx)
if len(keyword) > 0 {
query.Where("(username LIKE :keyword OR fullname LIKE :keyword)")
query.Param("keyword", dbutils.QuoteLike(keyword))
}
if hasWeakPasswords {
query.Attr("password", weakPasswords)
query.Attr("isOn", true)
}
return query.
State(AdminStateEnabled). State(AdminStateEnabled).
Count() Count()
} }
// ListEnabledAdmins 列出单页的管理员 // ListEnabledAdmins 列出单页的管理员
func (this *AdminDAO) ListEnabledAdmins(tx *dbs.Tx, offset int64, size int64) (result []*Admin, err error) { func (this *AdminDAO) ListEnabledAdmins(tx *dbs.Tx, keyword string, hasWeakPasswords bool, offset int64, size int64) (result []*Admin, err error) {
_, err = this.Query(tx). var query = this.Query(tx)
if len(keyword) > 0 {
query.Where("(username LIKE :keyword OR fullname LIKE :keyword)")
query.Param("keyword", dbutils.QuoteLike(keyword))
}
if hasWeakPasswords {
query.Attr("password", weakPasswords)
query.Attr("isOn", true)
}
_, err = query.
State(AdminStateEnabled). State(AdminStateEnabled).
Result("id", "isOn", "username", "fullname", "isSuper", "createdAt", "canLogin"). Result("id", "isOn", "username", "fullname", "isSuper", "createdAt", "canLogin", "password").
Offset(offset). Offset(offset).
Limit(size). Limit(size).
DescPk(). DescPk().
@@ -292,3 +312,15 @@ func (this *AdminDAO) UpdateAdminTheme(tx *dbs.Tx, adminId int64, theme string)
Set("theme", theme). Set("theme", theme).
UpdateQuickly() UpdateQuickly()
} }
// CheckSuperAdmin 检查管理员是否为超级管理员
func (this *AdminDAO) CheckSuperAdmin(tx *dbs.Tx, adminId int64) (bool, error) {
if adminId <= 0 {
return false, nil
}
return this.Query(tx).
Pk(adminId).
State(AdminStateEnabled).
Attr("isSuper", true).
Exist()
}

View File

@@ -2,6 +2,22 @@ package models
import "github.com/iwind/TeaGo/dbs" 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 管理员 // Admin 管理员
type Admin struct { type Admin struct {
Id uint32 `field:"id"` // ID Id uint32 `field:"id"` // ID
@@ -16,6 +32,7 @@ type Admin struct {
Modules dbs.JSON `field:"modules"` // 允许的模块 Modules dbs.JSON `field:"modules"` // 允许的模块
CanLogin bool `field:"canLogin"` // 是否可以登录 CanLogin bool `field:"canLogin"` // 是否可以登录
Theme string `field:"theme"` // 模板设置 Theme string `field:"theme"` // 模板设置
Lang string `field:"lang"` // 语言代号
} }
type AdminOperator struct { type AdminOperator struct {
@@ -31,6 +48,7 @@ type AdminOperator struct {
Modules any // 允许的模块 Modules any // 允许的模块
CanLogin any // 是否可以登录 CanLogin any // 是否可以登录
Theme any // 模板设置 Theme any // 模板设置
Lang any // 语言代号
} }
func NewAdminOperator() *AdminOperator { func NewAdminOperator() *AdminOperator {

View File

@@ -1 +1,42 @@
package models package models
import stringutil "github.com/iwind/TeaGo/utils/string"
// 弱密码集合
var weakPasswords = []string{}
func init() {
// 初始化弱密码集合
for _, password := range []string{
"123",
"1234",
"12345",
"123456",
"12345678",
"123456789",
"000000",
"111111",
"666666",
"888888",
"654321",
"123456789",
"password",
"qwerty",
"admin",
} {
weakPasswords = append(weakPasswords, stringutil.Md5(password))
}
}
func (this *Admin) HasWeakPassword() bool {
if len(this.Password) == 0 {
return false
}
for _, weakPassword := range weakPasswords {
if weakPassword == this.Password {
return true
}
}
return false
}

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) { func (this *APINodeDAO) CountAllLowerVersionNodes(tx *dbs.Tx, version string) (int64, error) {
return this.Query(tx). return this.Query(tx).
State(APINodeStateEnabled). State(APINodeStateEnabled).
Attr("isOn", true).
Where("status IS NOT NULL"). Where("status IS NOT NULL").
Where("(JSON_EXTRACT(status, '$.buildVersionCode') IS NULL OR JSON_EXTRACT(status, '$.buildVersionCode')<:version)"). Where("(JSON_EXTRACT(status, '$.buildVersionCode') IS NULL OR JSON_EXTRACT(status, '$.buildVersionCode')<:version)").
Param("version", utils.VersionToLong(version)). Param("version", utils.VersionToLong(version)).

View File

@@ -1,6 +1,7 @@
package models package models
import ( import (
"context"
"encoding/json" "encoding/json"
"github.com/TeaOSLab/EdgeAPI/internal/utils" "github.com/TeaOSLab/EdgeAPI/internal/utils"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs" "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
@@ -37,7 +38,7 @@ func (this *APINode) DecodeHTTPS(tx *dbs.Tx, cacheMap *utils.CacheMap) (*serverc
return nil, err return nil, err
} }
err = config.Init() err = config.Init(context.TODO())
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -45,7 +46,7 @@ func (this *APINode) DecodeHTTPS(tx *dbs.Tx, cacheMap *utils.CacheMap) (*serverc
if config.SSLPolicyRef != nil { if config.SSLPolicyRef != nil {
var policyId = config.SSLPolicyRef.SSLPolicyId var policyId = config.SSLPolicyRef.SSLPolicyId
if policyId > 0 { if policyId > 0 {
sslPolicy, err := SharedSSLPolicyDAO.ComposePolicyConfig(tx, policyId, false, cacheMap) sslPolicy, err := SharedSSLPolicyDAO.ComposePolicyConfig(tx, policyId, false, nil, cacheMap)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -55,7 +56,7 @@ func (this *APINode) DecodeHTTPS(tx *dbs.Tx, cacheMap *utils.CacheMap) (*serverc
} }
} }
err = config.Init() err = config.Init(context.TODO())
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -129,13 +130,13 @@ func (this *APINode) DecodeRestHTTPS(tx *dbs.Tx, cacheMap *utils.CacheMap) (*ser
if !IsNotNull(this.RestHTTPS) { if !IsNotNull(this.RestHTTPS) {
return nil, nil return nil, nil
} }
config := &serverconfigs.HTTPSProtocolConfig{} var config = &serverconfigs.HTTPSProtocolConfig{}
err := json.Unmarshal(this.RestHTTPS, config) err := json.Unmarshal(this.RestHTTPS, config)
if err != nil { if err != nil {
return nil, err return nil, err
} }
err = config.Init() err = config.Init(context.TODO())
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -143,7 +144,7 @@ func (this *APINode) DecodeRestHTTPS(tx *dbs.Tx, cacheMap *utils.CacheMap) (*ser
if config.SSLPolicyRef != nil { if config.SSLPolicyRef != nil {
policyId := config.SSLPolicyRef.SSLPolicyId policyId := config.SSLPolicyRef.SSLPolicyId
if policyId > 0 { if policyId > 0 {
sslPolicy, err := SharedSSLPolicyDAO.ComposePolicyConfig(tx, policyId, false, cacheMap) sslPolicy, err := SharedSSLPolicyDAO.ComposePolicyConfig(tx, policyId, false, nil, cacheMap)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -153,7 +154,7 @@ func (this *APINode) DecodeRestHTTPS(tx *dbs.Tx, cacheMap *utils.CacheMap) (*ser
} }
} }
err = config.Init() err = config.Init(context.TODO())
if err != nil { if err != nil {
return nil, err 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) { func (this *AuthorityNodeDAO) CountAllLowerVersionNodes(tx *dbs.Tx, version string) (int64, error) {
return this.Query(tx). return this.Query(tx).
State(AuthorityNodeStateEnabled). State(AuthorityNodeStateEnabled).
Attr("isOn", true).
Where("status IS NOT NULL"). Where("status IS NOT NULL").
Where("(JSON_EXTRACT(status, '$.buildVersionCode') IS NULL OR JSON_EXTRACT(status, '$.buildVersionCode')<:version)"). Where("(JSON_EXTRACT(status, '$.buildVersionCode') IS NULL OR JSON_EXTRACT(status, '$.buildVersionCode')<:version)").
Param("version", utils.VersionToLong(version)). Param("version", utils.VersionToLong(version)).

View File

@@ -12,13 +12,16 @@ import (
type DNSTaskType = string type DNSTaskType = string
const ( const (
DNSTaskTypeClusterChange DNSTaskType = "clusterChange" DNSTaskTypeClusterChange DNSTaskType = "clusterChange" // 集群节点、服务发生变化
DNSTaskTypeClusterNodesChange DNSTaskType = "clusterNodesChange" // 集群中节点发生变化
DNSTaskTypeClusterRemoveDomain DNSTaskType = "clusterRemoveDomain" // 从集群中移除域名 DNSTaskTypeClusterRemoveDomain DNSTaskType = "clusterRemoveDomain" // 从集群中移除域名
DNSTaskTypeNodeChange DNSTaskType = "nodeChange" DNSTaskTypeNodeChange DNSTaskType = "nodeChange"
DNSTaskTypeServerChange DNSTaskType = "serverChange" DNSTaskTypeServerChange DNSTaskType = "serverChange"
DNSTaskTypeDomainChange DNSTaskType = "domainChange" DNSTaskTypeDomainChange DNSTaskType = "domainChange"
) )
var DNSTasksNotifier = make(chan bool, 2)
type DNSTaskDAO dbs.DAO type DNSTaskDAO dbs.DAO
func NewDNSTaskDAO() *DNSTaskDAO { func NewDNSTaskDAO() *DNSTaskDAO {
@@ -58,13 +61,24 @@ func (this *DNSTaskDAO) CreateDNSTask(tx *dbs.Tx, clusterId int64, serverId int6
"error": "", "error": "",
"version": time.Now().UnixNano(), "version": time.Now().UnixNano(),
}, maps.Map{ }, maps.Map{
"updatedAt": time.Now().Unix(), "updatedAt": time.Now().Unix(),
"isDone": false, "isDone": false,
"isOk": false, "isOk": false,
"error": "", "error": "",
"version": time.Now().UnixNano(), "version": time.Now().UnixNano(),
"countFails": 0,
}) })
return err if err != nil {
return err
}
// 通知更新
select {
case DNSTasksNotifier <- true:
default:
}
return nil
} }
// CreateClusterTask 生成集群变更任务 // CreateClusterTask 生成集群变更任务
@@ -95,7 +109,7 @@ func (this *DNSTaskDAO) CreateDomainTask(tx *dbs.Tx, domainId int64, taskType DN
// FindAllDoingTasks 查找所有正在执行的任务 // FindAllDoingTasks 查找所有正在执行的任务
func (this *DNSTaskDAO) FindAllDoingTasks(tx *dbs.Tx) (result []*DNSTask, err error) { func (this *DNSTaskDAO) FindAllDoingTasks(tx *dbs.Tx) (result []*DNSTask, err error) {
_, err = this.Query(tx). _, err = this.Query(tx).
Attr("isDone", 0). Where("(isDone=0 OR (isDone=1 AND isOk=0 AND countFails<3))"). // 3 = retry times
Asc("version"). Asc("version").
AscPk(). AscPk().
Slice(&result). Slice(&result).
@@ -142,6 +156,12 @@ func (this *DNSTaskDAO) DeleteDNSTask(tx *dbs.Tx, taskId int64) error {
return err return err
} }
// DeleteAllDNSTasks 删除所有任务
func (this *DNSTaskDAO) DeleteAllDNSTasks(tx *dbs.Tx) error {
return this.Query(tx).
DeleteQuickly()
}
// UpdateDNSTaskError 设置任务错误 // UpdateDNSTaskError 设置任务错误
func (this *DNSTaskDAO) UpdateDNSTaskError(tx *dbs.Tx, taskId int64, err string) error { func (this *DNSTaskDAO) UpdateDNSTaskError(tx *dbs.Tx, taskId int64, err string) error {
if taskId <= 0 { if taskId <= 0 {
@@ -152,22 +172,60 @@ func (this *DNSTaskDAO) UpdateDNSTaskError(tx *dbs.Tx, taskId int64, err string)
op.IsDone = true op.IsDone = true
op.Error = err op.Error = err
op.IsOk = false op.IsOk = false
op.CountFails = dbs.SQL("countFails+1")
return this.Save(tx, op) return this.Save(tx, op)
} }
// UpdateDNSTaskDone 设置任务完成 // UpdateDNSTaskDone 设置任务完成
func (this *DNSTaskDAO) UpdateDNSTaskDone(tx *dbs.Tx, taskId int64) error { func (this *DNSTaskDAO) UpdateDNSTaskDone(tx *dbs.Tx, taskId int64, taskVersion int64) error {
if taskId <= 0 { if taskId <= 0 {
return errors.New("invalid taskId") return errors.New("invalid taskId")
} }
currentVersion, err := this.Query(tx).
Pk(taskId).
Result("version").
FindInt64Col(0)
if err != nil {
return err
}
// 如果版本号发生变化,则说明有新的要执行的任务
if taskVersion > 0 && currentVersion > 0 && currentVersion != taskVersion {
return nil
}
var op = NewDNSTaskOperator() var op = NewDNSTaskOperator()
op.Id = taskId op.Id = taskId
op.IsDone = true op.IsDone = true
op.IsOk = true op.IsOk = true
op.CountFails = 0
op.Error = "" op.Error = ""
return this.Save(tx, op) 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 删除集群相关任务 // DeleteDNSTasksWithClusterId 删除集群相关任务
func (this *DNSTaskDAO) DeleteDNSTasksWithClusterId(tx *dbs.Tx, clusterId int64) error { func (this *DNSTaskDAO) DeleteDNSTasksWithClusterId(tx *dbs.Tx, clusterId int64) error {
if clusterId <= 0 { if clusterId <= 0 {

View File

@@ -1,17 +1,28 @@
package dns package dns_test
import ( import (
"github.com/TeaOSLab/EdgeAPI/internal/db/models/dns"
_ "github.com/go-sql-driver/mysql" _ "github.com/go-sql-driver/mysql"
_ "github.com/iwind/TeaGo/bootstrap" _ "github.com/iwind/TeaGo/bootstrap"
"github.com/iwind/TeaGo/dbs" "github.com/iwind/TeaGo/dbs"
"testing" "testing"
"time"
) )
func TestDNSTaskDAO_CreateDNSTask(t *testing.T) { func TestDNSTaskDAO_CreateDNSTask(t *testing.T) {
dbs.NotifyReady() 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 { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
t.Log("ok") 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 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更新任务 // DNSTask DNS更新任务
type DNSTask struct { type DNSTask struct {
Id uint64 `field:"id"` // ID Id uint64 `field:"id"` // ID
@@ -14,6 +32,7 @@ type DNSTask struct {
IsOk bool `field:"isOk"` // 是否成功 IsOk bool `field:"isOk"` // 是否成功
Error string `field:"error"` // 错误信息 Error string `field:"error"` // 错误信息
Version uint64 `field:"version"` // 版本 Version uint64 `field:"version"` // 版本
CountFails uint32 `field:"countFails"` // 尝试失败次数
} }
type DNSTaskOperator struct { type DNSTaskOperator struct {
@@ -29,6 +48,7 @@ type DNSTaskOperator struct {
IsOk any // 是否成功 IsOk any // 是否成功
Error any // 错误信息 Error any // 错误信息
Version any // 版本 Version any // 版本
CountFails any // 尝试失败次数
} }
func NewDNSTaskOperator() *DNSTaskOperator { func NewDNSTaskOperator() *DNSTaskOperator {

View File

@@ -3,6 +3,7 @@
package dnsutils package dnsutils
import ( import (
"fmt"
"github.com/TeaOSLab/EdgeAPI/internal/db/models" "github.com/TeaOSLab/EdgeAPI/internal/db/models"
"github.com/TeaOSLab/EdgeAPI/internal/db/models/dns" "github.com/TeaOSLab/EdgeAPI/internal/db/models/dns"
"github.com/TeaOSLab/EdgeAPI/internal/dnsclients" "github.com/TeaOSLab/EdgeAPI/internal/dnsclients"
@@ -105,7 +106,7 @@ func CheckClusterDNS(tx *dbs.Tx, cluster *models.NodeCluster, checkNodeIssues bo
// 检查节点 // 检查节点
if checkNodeIssues { if checkNodeIssues {
nodes, err := models.SharedNodeDAO.FindAllEnabledNodesDNSWithClusterId(tx, clusterId, true, clusterDNSConfig != nil && clusterDNSConfig.IncludingLnNodes) nodes, err := models.SharedNodeDAO.FindAllEnabledNodesDNSWithClusterId(tx, clusterId, true, clusterDNSConfig != nil && clusterDNSConfig.IncludingLnNodes, true)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -162,17 +163,36 @@ func CheckClusterDNS(tx *dbs.Tx, cluster *models.NodeCluster, checkNodeIssues bo
return nil, err return nil, err
} }
if len(ipAddr) == 0 { if len(ipAddr) == 0 {
issues = append(issues, &pb.DNSIssue{ // 检查是否有离线
Target: node.Name, anyIPAddr, _, err := models.SharedNodeIPAddressDAO.FindFirstNodeAccessIPAddress(tx, nodeId, false, nodeconfigs.NodeRoleNode)
TargetId: nodeId, if err != nil {
Type: "node", return nil, err
Description: "没有设置IP地址", }
Params: map[string]string{ if len(anyIPAddr) > 0 {
"clusterName": cluster.Name, issues = append(issues, &pb.DNSIssue{
"clusterId": numberutils.FormatInt64(clusterId), Target: node.Name,
}, TargetId: nodeId,
MustFix: true, 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 continue
} }
@@ -198,7 +218,7 @@ func FindDefaultDomainRoute(tx *dbs.Tx, domain *dns.DNSDomain) (string, error) {
} }
paramsMap, err := provider.DecodeAPIParams() paramsMap, err := provider.DecodeAPIParams()
if err != nil { 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)) var dnsProvider = dnsclients.FindProvider(provider.Type, int64(provider.Id))
if dnsProvider == nil { if dnsProvider == nil {

View File

@@ -232,12 +232,12 @@ Loop:
// CreateHTTPAccessLog 写入单条访问日志 // CreateHTTPAccessLog 写入单条访问日志
func (this *HTTPAccessLogDAO) CreateHTTPAccessLog(tx *dbs.Tx, dao *HTTPAccessLogDAO, accessLog *pb.HTTPAccessLog) error { func (this *HTTPAccessLogDAO) CreateHTTPAccessLog(tx *dbs.Tx, dao *HTTPAccessLogDAO, accessLog *pb.HTTPAccessLog) error {
var day = "" var day string
// 注意:如果你修改了 TimeISO8601 的逻辑,这里也需要同步修改 // 注意:如果你修改了 TimeISO8601 的逻辑,这里也需要同步修改
if len(accessLog.TimeISO8601) > 10 { if len(accessLog.TimeISO8601) > 10 {
day = strings.ReplaceAll(accessLog.TimeISO8601[:10], "-", "") day = strings.ReplaceAll(accessLog.TimeISO8601[:10], "-", "")
} else { } else {
timeutil.FormatTime("Ymd", accessLog.Timestamp) day = timeutil.FormatTime("Ymd", accessLog.Timestamp)
} }
tableDef, err := SharedHTTPAccessLogManager.FindLastTable(dao.Instance, day, true) 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 protoReg = regexp.MustCompile(`proto:(\S+)`)
var schemeReg = regexp.MustCompile(`scheme:(\S+)`) var schemeReg = regexp.MustCompile(`scheme:(\S+)`)
var methodReg = regexp.MustCompile(`(?:method|requestMethod):(\S+)`) var methodReg = regexp.MustCompile(`(?:method|requestMethod):(\S+)`)
var refererReg = regexp.MustCompile(`referer:(\S+)`)
var count = len(tableQueries) var count = len(tableQueries)
var wg = &sync.WaitGroup{} var wg = &sync.WaitGroup{}
@@ -613,6 +614,11 @@ func (this *HTTPAccessLogDAO) listAccessLogs(tx *dbs.Tx,
var matches = methodReg.FindStringSubmatch(keyword) var matches = methodReg.FindStringSubmatch(keyword)
query.Where("JSON_EXTRACT(content, '$.requestMethod')=:keyword"). query.Where("JSON_EXTRACT(content, '$.requestMethod')=:keyword").
Param("keyword", strings.ToUpper(matches[1])) 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 !isSpecialKeyword {
if regexp.MustCompile(`^ip:.+`).MatchString(keyword) { 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 + "%"} { for _, prefix := range []string{"edgeHTTPAccessLogs_" + day + "%", "edgehttpaccesslogs_" + day + "%"} {
ones, columnNames, err := db.FindPreparedOnes(`SHOW TABLES LIKE '` + prefix + `'`) ones, columnNames, err := db.FindPreparedOnes(`SHOW TABLES LIKE '` + prefix + `'`)
if err != nil { 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] 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 + "%"} { for _, prefix := range []string{"edgeHTTPAccessLogs_" + day + "%", "edgehttpaccesslogs_" + day + "%"} {
ones, columnNames, err := db.FindPreparedOnes(`SHOW TABLES LIKE '` + prefix + `'`) ones, columnNames, err := db.FindPreparedOnes(`SHOW TABLES LIKE '` + prefix + `'`)
if err != nil { 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] var columnName = columnNames[0]
@@ -373,7 +373,7 @@ func (this *HTTPAccessLogManager) findTableWithoutCache(db *dbs.DB, day string,
var lastInt64Id = types.Int64(lastId) var lastInt64Id = types.Int64(lastId)
if accessLogRowsPerTable > 0 && lastInt64Id >= accessLogRowsPerTable { if accessLogRowsPerTable > 0 && lastInt64Id >= accessLogRowsPerTable {
// create next partial table // create next partial table
var nextTableName = "" var nextTableName string
if accessLogTableMainReg.MatchString(lastTableName) { if accessLogTableMainReg.MatchString(lastTableName) {
nextTableName = prefix + "_0001" nextTableName = prefix + "_0001"
} else if accessLogTablePartialReg.MatchString(lastTableName) { } else if accessLogTablePartialReg.MatchString(lastTableName) {

View File

@@ -96,6 +96,27 @@ func (this *HTTPAuthPolicyDAO) UpdateHTTPAuthPolicy(tx *dbs.Tx, policyId int64,
return this.NotifyUpdate(tx, policyId) return this.NotifyUpdate(tx, policyId)
} }
// CloneAuthPolicy 复制策略
func (this *HTTPAuthPolicyDAO) CloneAuthPolicy(tx *dbs.Tx, fromPolicyId int64) (int64, error) {
policyOne, err := this.Query(tx).
Pk(fromPolicyId).
Find()
if err != nil || policyOne == nil {
return 0, err
}
var policy = policyOne.(*HTTPAuthPolicy)
var op = NewHTTPAuthPolicyOperator()
op.IsOn = policy.IsOn
op.Name = policy.Name
op.Type = policy.Type
if len(policy.Params) > 0 {
op.Params = policy.Params
}
op.State = policy.State
return this.SaveInt64(tx, op)
}
// ComposePolicyConfig 组合配置 // ComposePolicyConfig 组合配置
func (this *HTTPAuthPolicyDAO) ComposePolicyConfig(tx *dbs.Tx, policyId int64, cacheMap *utils.CacheMap) (*serverconfigs.HTTPAuthPolicy, error) { func (this *HTTPAuthPolicyDAO) ComposePolicyConfig(tx *dbs.Tx, policyId int64, cacheMap *utils.CacheMap) (*serverconfigs.HTTPAuthPolicy, error) {
if cacheMap == nil { if cacheMap == nil {

View File

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

View File

@@ -2,6 +2,26 @@ package models
import "github.com/iwind/TeaGo/dbs" 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缓存策略 // HTTPCachePolicy HTTP缓存策略
type HTTPCachePolicy struct { type HTTPCachePolicy struct {
Id uint32 `field:"id"` // ID Id uint32 `field:"id"` // ID
@@ -20,25 +40,27 @@ type HTTPCachePolicy struct {
Description string `field:"description"` // 描述 Description string `field:"description"` // 描述
Refs dbs.JSON `field:"refs"` // 默认的缓存设置 Refs dbs.JSON `field:"refs"` // 默认的缓存设置
SyncCompressionCache uint8 `field:"syncCompressionCache"` // 是否同步写入压缩缓存 SyncCompressionCache uint8 `field:"syncCompressionCache"` // 是否同步写入压缩缓存
FetchTimeout dbs.JSON `field:"fetchTimeout"` // 预热超时时间
} }
type HTTPCachePolicyOperator struct { type HTTPCachePolicyOperator struct {
Id interface{} // ID Id any // ID
AdminId interface{} // 管理员ID AdminId any // 管理员ID
UserId interface{} // 用户ID UserId any // 用户ID
TemplateId interface{} // 模版ID TemplateId any // 模版ID
IsOn interface{} // 是否启用 IsOn any // 是否启用
Name interface{} // 名称 Name any // 名称
Capacity interface{} // 容量数据 Capacity any // 容量数据
MaxKeys interface{} // 最多Key值 MaxKeys any // 最多Key值
MaxSize interface{} // 最大缓存内容尺寸 MaxSize any // 最大缓存内容尺寸
Type interface{} // 存储类型 Type any // 存储类型
Options interface{} // 存储选项 Options any // 存储选项
CreatedAt interface{} // 创建时间 CreatedAt any // 创建时间
State interface{} // 状态 State any // 状态
Description interface{} // 描述 Description any // 描述
Refs interface{} // 默认的缓存设置 Refs any // 默认的缓存设置
SyncCompressionCache interface{} // 是否同步写入压缩缓存 SyncCompressionCache any // 是否同步写入压缩缓存
FetchTimeout any // 预热超时时间
} }
func NewHTTPCachePolicyOperator() *HTTPCachePolicyOperator { func NewHTTPCachePolicyOperator() *HTTPCachePolicyOperator {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -84,7 +84,7 @@ func (this *HTTPFirewallRuleSetDAO) FindHTTPFirewallRuleSetName(tx *dbs.Tx, id i
} }
// ComposeFirewallRuleSet 组合配置 // 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) set, err := this.FindEnabledHTTPFirewallRuleSet(tx, setId)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -92,7 +92,7 @@ func (this *HTTPFirewallRuleSetDAO) ComposeFirewallRuleSet(tx *dbs.Tx, setId int
if set == nil { if set == nil {
return nil, nil return nil, nil
} }
config := &firewallconfigs.HTTPFirewallRuleSet{} var config = &firewallconfigs.HTTPFirewallRuleSet{}
config.Id = int64(set.Id) config.Id = int64(set.Id)
config.IsOn = set.IsOn config.IsOn = set.IsOn
config.Name = set.Name config.Name = set.Name
@@ -102,7 +102,7 @@ func (this *HTTPFirewallRuleSetDAO) ComposeFirewallRuleSet(tx *dbs.Tx, setId int
config.IgnoreLocal = set.IgnoreLocal == 1 config.IgnoreLocal = set.IgnoreLocal == 1
if IsNotNull(set.Rules) { if IsNotNull(set.Rules) {
ruleRefs := []*firewallconfigs.HTTPFirewallRuleRef{} var ruleRefs = []*firewallconfigs.HTTPFirewallRuleRef{}
err = json.Unmarshal(set.Rules, &ruleRefs) err = json.Unmarshal(set.Rules, &ruleRefs)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -128,6 +128,29 @@ func (this *HTTPFirewallRuleSetDAO) ComposeFirewallRuleSet(tx *dbs.Tx, setId int
config.Actions = actionConfigs 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 return config, nil
} }
@@ -212,6 +235,28 @@ func (this *HTTPFirewallRuleSetDAO) FindEnabledRuleSetIdWithRuleId(tx *dbs.Tx, r
FindInt64Col(0) 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 检查用户 // CheckUserRuleSet 检查用户
func (this *HTTPFirewallRuleSetDAO) CheckUserRuleSet(tx *dbs.Tx, userId int64, setId int64) error { func (this *HTTPFirewallRuleSetDAO) CheckUserRuleSet(tx *dbs.Tx, userId int64, setId int64) error {
groupId, err := SharedHTTPFirewallRuleGroupDAO.FindRuleGroupIdWithRuleSetId(tx, setId) 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") return errors.New("invalid policyId")
} }
if headerNames == nil {
headerNames = []string{}
}
namesJSON, err := json.Marshal(headerNames) namesJSON, err := json.Marshal(headerNames)
if err != nil { if err != nil {
return err return err
@@ -164,7 +167,31 @@ func (this *HTTPHeaderPolicyDAO) UpdateDeletingHeaders(tx *dbs.Tx, policyId int6
var op = NewHTTPHeaderPolicyOperator() var op = NewHTTPHeaderPolicyOperator()
op.Id = policyId 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) err = this.Save(tx, op)
if err != nil { if err != nil {
return err return err
@@ -220,9 +247,19 @@ func (this *HTTPHeaderPolicyDAO) ComposeHeaderPolicyConfig(tx *dbs.Tx, headerPol
config.DeleteHeaders = headers 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 // CORS
if IsNotNull(policy.Cors) { if IsNotNull(policy.Cors) {
var corsConfig = &shared.HTTPCORSHeaderConfig{} var corsConfig = shared.NewHTTPCORSHeaderConfig()
err = json.Unmarshal(policy.Cors, corsConfig) err = json.Unmarshal(policy.Cors, corsConfig)
if err != nil { if err != nil {
return nil, err return nil, err

View File

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

View File

@@ -150,7 +150,7 @@ func (this *HTTPLocationDAO) UpdateLocation(tx *dbs.Tx, locationId int64, name s
} }
// ComposeLocationConfig 组合配置 // ComposeLocationConfig 组合配置
func (this *HTTPLocationDAO) ComposeLocationConfig(tx *dbs.Tx, locationId int64, cacheMap *utils.CacheMap) (*serverconfigs.HTTPLocationConfig, error) { func (this *HTTPLocationDAO) ComposeLocationConfig(tx *dbs.Tx, locationId int64, forNode bool, dataMap *shared.DataMap, cacheMap *utils.CacheMap) (*serverconfigs.HTTPLocationConfig, error) {
if cacheMap == nil { if cacheMap == nil {
cacheMap = utils.NewCacheMap() cacheMap = utils.NewCacheMap()
} }
@@ -168,7 +168,7 @@ func (this *HTTPLocationDAO) ComposeLocationConfig(tx *dbs.Tx, locationId int64,
return nil, nil return nil, nil
} }
config := &serverconfigs.HTTPLocationConfig{} var config = &serverconfigs.HTTPLocationConfig{}
config.Id = int64(location.Id) config.Id = int64(location.Id)
config.IsOn = location.IsOn config.IsOn = location.IsOn
config.Description = location.Description config.Description = location.Description
@@ -179,7 +179,7 @@ func (this *HTTPLocationDAO) ComposeLocationConfig(tx *dbs.Tx, locationId int64,
// web // web
if location.WebId > 0 { if location.WebId > 0 {
webConfig, err := SharedHTTPWebDAO.ComposeWebConfig(tx, int64(location.WebId), cacheMap) webConfig, err := SharedHTTPWebDAO.ComposeWebConfig(tx, int64(location.WebId), true, forNode, dataMap, cacheMap)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -195,7 +195,7 @@ func (this *HTTPLocationDAO) ComposeLocationConfig(tx *dbs.Tx, locationId int64,
} }
config.ReverseProxyRef = ref config.ReverseProxyRef = ref
if ref.ReverseProxyId > 0 { if ref.ReverseProxyId > 0 {
reverseProxyConfig, err := SharedReverseProxyDAO.ComposeReverseProxyConfig(tx, ref.ReverseProxyId, cacheMap) reverseProxyConfig, err := SharedReverseProxyDAO.ComposeReverseProxyConfig(tx, ref.ReverseProxyId, dataMap, cacheMap)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -292,13 +292,13 @@ func (this *HTTPLocationDAO) UpdateLocationWeb(tx *dbs.Tx, locationId int64, web
} }
// ConvertLocationRefs 转换引用为配置 // ConvertLocationRefs 转换引用为配置
func (this *HTTPLocationDAO) ConvertLocationRefs(tx *dbs.Tx, refs []*serverconfigs.HTTPLocationRef, cacheMap *utils.CacheMap) (locations []*serverconfigs.HTTPLocationConfig, err error) { func (this *HTTPLocationDAO) ConvertLocationRefs(tx *dbs.Tx, refs []*serverconfigs.HTTPLocationRef, forNode bool, dataMap *shared.DataMap, cacheMap *utils.CacheMap) (locations []*serverconfigs.HTTPLocationConfig, err error) {
for _, ref := range refs { for _, ref := range refs {
config, err := this.ComposeLocationConfig(tx, ref.LocationId, cacheMap) config, err := this.ComposeLocationConfig(tx, ref.LocationId, forNode, dataMap, cacheMap)
if err != nil { if err != nil {
return nil, err return nil, err
} }
children, err := this.ConvertLocationRefs(tx, ref.Children, cacheMap) children, err := this.ConvertLocationRefs(tx, ref.Children, forNode, dataMap, cacheMap)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -133,6 +133,32 @@ func (this *HTTPPageDAO) UpdatePage(tx *dbs.Tx, pageId int64, statusList []strin
return this.NotifyUpdate(tx, pageId) return this.NotifyUpdate(tx, pageId)
} }
// ClonePage 克隆页面
func (this *HTTPPageDAO) ClonePage(tx *dbs.Tx, fromPageId int64) (newPageId int64, err error) {
if fromPageId <= 0 {
return
}
pageOne, err := this.Query(tx).
Pk(fromPageId).
Find()
if err != nil || pageOne == nil {
return 0, err
}
var page = pageOne.(*HTTPPage)
var op = NewHTTPPageOperator()
op.IsOn = page.IsOn
if len(page.StatusList) > 0 {
op.StatusList = page.StatusList
}
op.Url = page.Url
op.NewStatus = page.NewStatus
op.Body = page.Body
op.BodyType = page.BodyType
op.State = page.State
return this.SaveInt64(tx, op)
}
// ComposePageConfig 组合配置 // ComposePageConfig 组合配置
func (this *HTTPPageDAO) ComposePageConfig(tx *dbs.Tx, pageId int64, cacheMap *utils.CacheMap) (*serverconfigs.HTTPPageConfig, error) { func (this *HTTPPageDAO) ComposePageConfig(tx *dbs.Tx, pageId int64, cacheMap *utils.CacheMap) (*serverconfigs.HTTPPageConfig, error) {
if cacheMap == nil { if cacheMap == nil {

View File

@@ -124,8 +124,9 @@ func (this *HTTPRewriteRuleDAO) ComposeRewriteRule(tx *dbs.Tx, rewriteRuleId int
} }
// CreateRewriteRule 创建规则 // 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() var op = NewHTTPRewriteRuleOperator()
op.UserId = userId
op.State = HTTPRewriteRuleStateEnabled op.State = HTTPRewriteRuleStateEnabled
op.IsOn = isOn op.IsOn = isOn
@@ -172,6 +173,34 @@ func (this *HTTPRewriteRuleDAO) UpdateRewriteRule(tx *dbs.Tx, rewriteRuleId int6
return this.NotifyUpdate(tx, rewriteRuleId) 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 通知更新 // NotifyUpdate 通知更新
func (this *HTTPRewriteRuleDAO) NotifyUpdate(tx *dbs.Tx, rewriteRuleId int64) error { func (this *HTTPRewriteRuleDAO) NotifyUpdate(tx *dbs.Tx, rewriteRuleId int64) error {
webId, err := SharedHTTPWebDAO.FindEnabledWebIdWithRewriteRuleId(tx, rewriteRuleId) webId, err := SharedHTTPWebDAO.FindEnabledWebIdWithRewriteRuleId(tx, rewriteRuleId)

View File

@@ -77,7 +77,7 @@ func (this *HTTPWebDAO) FindEnabledHTTPWeb(tx *dbs.Tx, id int64) (*HTTPWeb, erro
} }
// ComposeWebConfig 组合配置 // ComposeWebConfig 组合配置
func (this *HTTPWebDAO) ComposeWebConfig(tx *dbs.Tx, webId int64, cacheMap *utils.CacheMap) (*serverconfigs.HTTPWebConfig, error) { func (this *HTTPWebDAO) ComposeWebConfig(tx *dbs.Tx, webId int64, isLocationOrGroup bool, forNode bool, dataMap *shared.DataMap, cacheMap *utils.CacheMap) (*serverconfigs.HTTPWebConfig, error) {
if cacheMap == nil { if cacheMap == nil {
cacheMap = utils.NewCacheMap() cacheMap = utils.NewCacheMap()
} }
@@ -101,113 +101,139 @@ func (this *HTTPWebDAO) ComposeWebConfig(tx *dbs.Tx, webId int64, cacheMap *util
// root // root
if IsNotNull(web.Root) { if IsNotNull(web.Root) {
rootConfig := &serverconfigs.HTTPRootConfig{} var rootConfig = serverconfigs.NewHTTPRootConfig()
err = json.Unmarshal(web.Root, rootConfig) err = json.Unmarshal(web.Root, rootConfig)
if err != nil { if err != nil {
return nil, err return nil, err
} }
config.Root = rootConfig if this.shouldCompose(isLocationOrGroup, forNode, rootConfig.IsPrior, rootConfig.IsOn) {
config.Root = rootConfig
}
} }
// compression // compression
if IsNotNull(web.Compression) { if IsNotNull(web.Compression) {
compression := &serverconfigs.HTTPCompressionConfig{} var compressionConfig = &serverconfigs.HTTPCompressionConfig{}
err = json.Unmarshal(web.Compression, compression) err = json.Unmarshal(web.Compression, compressionConfig)
if err != nil { if err != nil {
return nil, err return nil, err
} }
config.Compression = compression
// gzip if this.shouldCompose(isLocationOrGroup, forNode, compressionConfig.IsPrior, compressionConfig.IsOn) {
if compression.GzipRef != nil && compression.GzipRef.Id > 0 { config.Compression = compressionConfig
gzipConfig, err := SharedHTTPGzipDAO.ComposeGzipConfig(tx, compression.GzipRef.Id)
if err != nil { // gzip
return nil, err if compressionConfig.GzipRef != nil && compressionConfig.GzipRef.Id > 0 {
gzipConfig, err := SharedHTTPGzipDAO.ComposeGzipConfig(tx, compressionConfig.GzipRef.Id)
if err != nil {
return nil, err
}
compressionConfig.Gzip = gzipConfig
}
// brotli
if compressionConfig.BrotliRef != nil && compressionConfig.BrotliRef.Id > 0 {
brotliConfig, err := SharedHTTPBrotliPolicyDAO.ComposeBrotliConfig(tx, compressionConfig.BrotliRef.Id)
if err != nil {
return nil, err
}
compressionConfig.Brotli = brotliConfig
}
// deflate
if compressionConfig.DeflateRef != nil && compressionConfig.DeflateRef.Id > 0 {
deflateConfig, err := SharedHTTPDeflatePolicyDAO.ComposeDeflateConfig(tx, compressionConfig.DeflateRef.Id)
if err != nil {
return nil, err
}
compressionConfig.Deflate = deflateConfig
} }
compression.Gzip = gzipConfig
} }
}
// brotli // Optimization
if compression.BrotliRef != nil && compression.BrotliRef.Id > 0 { if IsNotNull(web.Optimization) {
brotliConfig, err := SharedHTTPBrotliPolicyDAO.ComposeBrotliConfig(tx, compression.BrotliRef.Id) var optimizationConfig = serverconfigs.NewHTTPPageOptimizationConfig()
if err != nil { err = json.Unmarshal(web.Optimization, optimizationConfig)
return nil, err if err != nil {
} return nil, err
compression.Brotli = brotliConfig
} }
if this.shouldCompose(isLocationOrGroup, forNode, optimizationConfig.IsPrior, true) {
// deflate config.Optimization = optimizationConfig
if compression.DeflateRef != nil && compression.DeflateRef.Id > 0 {
deflateConfig, err := SharedHTTPDeflatePolicyDAO.ComposeDeflateConfig(tx, compression.DeflateRef.Id)
if err != nil {
return nil, err
}
compression.Deflate = deflateConfig
} }
} }
// charset // charset
if IsNotNull(web.Charset) { if IsNotNull(web.Charset) {
charsetConfig := &serverconfigs.HTTPCharsetConfig{} var charsetConfig = &serverconfigs.HTTPCharsetConfig{}
err = json.Unmarshal(web.Charset, charsetConfig) err = json.Unmarshal(web.Charset, charsetConfig)
if err != nil { if err != nil {
return nil, err return nil, err
} }
config.Charset = charsetConfig if this.shouldCompose(isLocationOrGroup, forNode, charsetConfig.IsPrior, charsetConfig.IsOn) {
config.Charset = charsetConfig
}
} }
// headers // headers
if IsNotNull(web.RequestHeader) { if IsNotNull(web.RequestHeader) {
ref := &shared.HTTPHeaderPolicyRef{} var ref = &shared.HTTPHeaderPolicyRef{}
err = json.Unmarshal(web.RequestHeader, ref) err = json.Unmarshal(web.RequestHeader, ref)
if err != nil { if err != nil {
return nil, err return nil, err
} }
config.RequestHeaderPolicyRef = ref if this.shouldCompose(isLocationOrGroup, forNode, ref.IsPrior, ref.IsOn) {
config.RequestHeaderPolicyRef = ref
if ref.HeaderPolicyId > 0 { if ref.HeaderPolicyId > 0 {
headerPolicy, err := SharedHTTPHeaderPolicyDAO.ComposeHeaderPolicyConfig(tx, ref.HeaderPolicyId) headerPolicy, err := SharedHTTPHeaderPolicyDAO.ComposeHeaderPolicyConfig(tx, ref.HeaderPolicyId)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if headerPolicy != nil { if headerPolicy != nil {
config.RequestHeaderPolicy = headerPolicy config.RequestHeaderPolicy = headerPolicy
}
} }
} }
} }
if IsNotNull(web.ResponseHeader) { if IsNotNull(web.ResponseHeader) {
ref := &shared.HTTPHeaderPolicyRef{} var ref = &shared.HTTPHeaderPolicyRef{}
err = json.Unmarshal(web.ResponseHeader, ref) err = json.Unmarshal(web.ResponseHeader, ref)
if err != nil { if err != nil {
return nil, err return nil, err
} }
config.ResponseHeaderPolicyRef = ref if this.shouldCompose(isLocationOrGroup, forNode, ref.IsPrior, ref.IsOn) {
config.ResponseHeaderPolicyRef = ref
if ref.HeaderPolicyId > 0 { if ref.HeaderPolicyId > 0 {
headerPolicy, err := SharedHTTPHeaderPolicyDAO.ComposeHeaderPolicyConfig(tx, ref.HeaderPolicyId) headerPolicy, err := SharedHTTPHeaderPolicyDAO.ComposeHeaderPolicyConfig(tx, ref.HeaderPolicyId)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if headerPolicy != nil { if headerPolicy != nil {
config.ResponseHeaderPolicy = headerPolicy config.ResponseHeaderPolicy = headerPolicy
}
} }
} }
} }
// shutdown // shutdown
if IsNotNull(web.Shutdown) { if IsNotNull(web.Shutdown) {
shutdownConfig := &serverconfigs.HTTPShutdownConfig{} var shutdownConfig = &serverconfigs.HTTPShutdownConfig{}
err = json.Unmarshal(web.Shutdown, shutdownConfig) err = json.Unmarshal(web.Shutdown, shutdownConfig)
if err != nil { if err != nil {
return nil, err return nil, err
} }
config.Shutdown = shutdownConfig if this.shouldCompose(isLocationOrGroup, forNode, shutdownConfig.IsPrior, shutdownConfig.IsOn) {
config.Shutdown = shutdownConfig
}
} }
// pages // pages
// TODO 检查forNode参数
if IsNotNull(web.Pages) { if IsNotNull(web.Pages) {
pages := []*serverconfigs.HTTPPageConfig{} var pages = []*serverconfigs.HTTPPageConfig{}
err = json.Unmarshal(web.Pages, &pages) err = json.Unmarshal(web.Pages, &pages)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -226,62 +252,72 @@ func (this *HTTPWebDAO) ComposeWebConfig(tx *dbs.Tx, webId int64, cacheMap *util
// 访问日志 // 访问日志
if IsNotNull(web.AccessLog) { if IsNotNull(web.AccessLog) {
accessLogConfig := &serverconfigs.HTTPAccessLogRef{} var accessLogConfig = &serverconfigs.HTTPAccessLogRef{}
err = json.Unmarshal(web.AccessLog, accessLogConfig) err = json.Unmarshal(web.AccessLog, accessLogConfig)
if err != nil { if err != nil {
return nil, err return nil, err
} }
config.AccessLogRef = accessLogConfig if this.shouldCompose(isLocationOrGroup, forNode, accessLogConfig.IsPrior, accessLogConfig.IsOn) {
config.AccessLogRef = accessLogConfig
}
} }
// 统计配置 // 统计配置
if IsNotNull(web.Stat) { if IsNotNull(web.Stat) {
statRef := &serverconfigs.HTTPStatRef{} var statRef = &serverconfigs.HTTPStatRef{}
err = json.Unmarshal(web.Stat, statRef) err = json.Unmarshal(web.Stat, statRef)
if err != nil { if err != nil {
return nil, err return nil, err
} }
config.StatRef = statRef if this.shouldCompose(isLocationOrGroup, forNode, statRef.IsPrior, statRef.IsOn) {
config.StatRef = statRef
}
} }
// 缓存配置 // 缓存配置
if IsNotNull(web.Cache) { if IsNotNull(web.Cache) {
cacheConfig := &serverconfigs.HTTPCacheConfig{} var cacheConfig = &serverconfigs.HTTPCacheConfig{}
err = json.Unmarshal(web.Cache, &cacheConfig) err = json.Unmarshal(web.Cache, &cacheConfig)
if err != nil { if err != nil {
return nil, err return nil, err
} }
config.Cache = cacheConfig
if this.shouldCompose(isLocationOrGroup, forNode, cacheConfig.IsPrior, cacheConfig.IsOn) {
config.Cache = cacheConfig
}
// 暂不支持自定义缓存策略设置,因为同一个集群下的服务需要集中管理 // 暂不支持自定义缓存策略设置,因为同一个集群下的服务需要集中管理
} }
// 防火墙配置 // 防火墙配置
if IsNotNull(web.Firewall) { if IsNotNull(web.Firewall) {
firewallRef := &firewallconfigs.HTTPFirewallRef{} var firewallRef = &firewallconfigs.HTTPFirewallRef{}
err = json.Unmarshal(web.Firewall, firewallRef) err = json.Unmarshal(web.Firewall, firewallRef)
if err != nil { if err != nil {
return nil, err return nil, err
} }
config.FirewallRef = firewallRef if this.shouldCompose(isLocationOrGroup, forNode, firewallRef.IsPrior, firewallRef.IsOn) {
config.FirewallRef = firewallRef
// 自定义防火墙设置 // 自定义防火墙设置
if firewallRef.FirewallPolicyId > 0 { if firewallRef.FirewallPolicyId > 0 {
firewallPolicy, err := SharedHTTPFirewallPolicyDAO.ComposeFirewallPolicy(tx, firewallRef.FirewallPolicyId, cacheMap) firewallPolicy, err := SharedHTTPFirewallPolicyDAO.ComposeFirewallPolicy(tx, firewallRef.FirewallPolicyId, forNode, cacheMap)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if firewallPolicy == nil { if firewallPolicy == nil {
config.FirewallRef = nil config.FirewallRef = nil
} else { } else {
config.FirewallPolicy = firewallPolicy config.FirewallPolicy = firewallPolicy
}
} }
} }
} }
// 路由规则 // 路由规则
// TODO 检查forNode参数
if IsNotNull(web.Locations) { if IsNotNull(web.Locations) {
refs := []*serverconfigs.HTTPLocationRef{} var refs = []*serverconfigs.HTTPLocationRef{}
err = json.Unmarshal(web.Locations, &refs) err = json.Unmarshal(web.Locations, &refs)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -289,7 +325,7 @@ func (this *HTTPWebDAO) ComposeWebConfig(tx *dbs.Tx, webId int64, cacheMap *util
if len(refs) > 0 { if len(refs) > 0 {
config.LocationRefs = refs config.LocationRefs = refs
locations, err := SharedHTTPLocationDAO.ConvertLocationRefs(tx, refs, cacheMap) locations, err := SharedHTTPLocationDAO.ConvertLocationRefs(tx, refs, forNode, dataMap, cacheMap)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -299,36 +335,41 @@ func (this *HTTPWebDAO) ComposeWebConfig(tx *dbs.Tx, webId int64, cacheMap *util
// 跳转 // 跳转
if IsNotNull(web.RedirectToHttps) { if IsNotNull(web.RedirectToHttps) {
redirectToHTTPSConfig := &serverconfigs.HTTPRedirectToHTTPSConfig{} var redirectToHTTPSConfig = &serverconfigs.HTTPRedirectToHTTPSConfig{}
err = json.Unmarshal(web.RedirectToHttps, redirectToHTTPSConfig) err = json.Unmarshal(web.RedirectToHttps, redirectToHTTPSConfig)
if err != nil { if err != nil {
return nil, err return nil, err
} }
config.RedirectToHttps = redirectToHTTPSConfig if this.shouldCompose(isLocationOrGroup, forNode, redirectToHTTPSConfig.IsPrior, redirectToHTTPSConfig.IsOn) {
config.RedirectToHttps = redirectToHTTPSConfig
}
} }
// Websocket // Websocket
if IsNotNull(web.Websocket) { if IsNotNull(web.Websocket) {
ref := &serverconfigs.HTTPWebsocketRef{} var ref = &serverconfigs.HTTPWebsocketRef{}
err = json.Unmarshal(web.Websocket, ref) err = json.Unmarshal(web.Websocket, ref)
if err != nil { if err != nil {
return nil, err return nil, err
} }
config.WebsocketRef = ref if this.shouldCompose(isLocationOrGroup, forNode, ref.IsPrior, ref.IsOn) {
if ref.WebsocketId > 0 { config.WebsocketRef = ref
websocketConfig, err := SharedHTTPWebsocketDAO.ComposeWebsocketConfig(tx, ref.WebsocketId) if ref.WebsocketId > 0 {
if err != nil { websocketConfig, err := SharedHTTPWebsocketDAO.ComposeWebsocketConfig(tx, ref.WebsocketId)
return nil, err if err != nil {
} return nil, err
if websocketConfig != nil { }
config.Websocket = websocketConfig if websocketConfig != nil {
config.Websocket = websocketConfig
}
} }
} }
} }
// 重写规则 // 重写规则
// TODO 检查forNode参数
if IsNotNull(web.RewriteRules) { if IsNotNull(web.RewriteRules) {
refs := []*serverconfigs.HTTPRewriteRef{} var refs = []*serverconfigs.HTTPRewriteRef{}
err = json.Unmarshal(web.RewriteRules, &refs) err = json.Unmarshal(web.RewriteRules, &refs)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -346,8 +387,9 @@ func (this *HTTPWebDAO) ComposeWebConfig(tx *dbs.Tx, webId int64, cacheMap *util
} }
// 主机跳转 // 主机跳转
// TODO 检查forNode参数
if IsNotNull(web.HostRedirects) { if IsNotNull(web.HostRedirects) {
redirects := []*serverconfigs.HTTPHostRedirectConfig{} var redirects = []*serverconfigs.HTTPHostRedirectConfig{}
err = json.Unmarshal(web.HostRedirects, &redirects) err = json.Unmarshal(web.HostRedirects, &redirects)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -357,25 +399,28 @@ func (this *HTTPWebDAO) ComposeWebConfig(tx *dbs.Tx, webId int64, cacheMap *util
// Fastcgi // Fastcgi
if IsNotNull(web.Fastcgi) { if IsNotNull(web.Fastcgi) {
ref := &serverconfigs.HTTPFastcgiRef{} var ref = &serverconfigs.HTTPFastcgiRef{}
err = json.Unmarshal(web.Fastcgi, ref) err = json.Unmarshal(web.Fastcgi, ref)
if err != nil { if err != nil {
return nil, err return nil, err
} }
config.FastcgiRef = ref
if len(ref.FastcgiIds) > 0 { if this.shouldCompose(isLocationOrGroup, forNode, ref.IsPrior, ref.IsOn) {
list := []*serverconfigs.HTTPFastcgiConfig{} config.FastcgiRef = ref
for _, fastcgiId := range ref.FastcgiIds {
fastcgiConfig, err := SharedHTTPFastcgiDAO.ComposeFastcgiConfig(tx, fastcgiId) if len(ref.FastcgiIds) > 0 {
if err != nil { list := []*serverconfigs.HTTPFastcgiConfig{}
return nil, err for _, fastcgiId := range ref.FastcgiIds {
} fastcgiConfig, err := SharedHTTPFastcgiDAO.ComposeFastcgiConfig(tx, fastcgiId)
if fastcgiConfig != nil { if err != nil {
list = append(list, fastcgiConfig) return nil, err
}
if fastcgiConfig != nil {
list = append(list, fastcgiConfig)
}
} }
config.FastcgiList = list
} }
config.FastcgiList = list
} }
} }
@@ -386,19 +431,21 @@ func (this *HTTPWebDAO) ComposeWebConfig(tx *dbs.Tx, webId int64, cacheMap *util
if err != nil { if err != nil {
return nil, err return nil, err
} }
var newRefs []*serverconfigs.HTTPAuthPolicyRef if this.shouldCompose(isLocationOrGroup, forNode, authConfig.IsPrior, authConfig.IsOn) {
for _, ref := range authConfig.PolicyRefs { var newRefs []*serverconfigs.HTTPAuthPolicyRef
policyConfig, err := SharedHTTPAuthPolicyDAO.ComposePolicyConfig(tx, ref.AuthPolicyId, cacheMap) for _, ref := range authConfig.PolicyRefs {
if err != nil { policyConfig, err := SharedHTTPAuthPolicyDAO.ComposePolicyConfig(tx, ref.AuthPolicyId, cacheMap)
return nil, err if err != nil {
} return nil, err
if policyConfig != nil { }
ref.AuthPolicy = policyConfig if policyConfig != nil {
newRefs = append(newRefs, ref) ref.AuthPolicy = policyConfig
authConfig.PolicyRefs = newRefs newRefs = append(newRefs, ref)
authConfig.PolicyRefs = newRefs
}
} }
config.Auth = authConfig
} }
config.Auth = authConfig
} }
// WebP // WebP
@@ -408,7 +455,9 @@ func (this *HTTPWebDAO) ComposeWebConfig(tx *dbs.Tx, webId int64, cacheMap *util
if err != nil { if err != nil {
return nil, err return nil, err
} }
config.WebP = webpConfig if this.shouldCompose(isLocationOrGroup, forNode, webpConfig.IsPrior, webpConfig.IsOn) {
config.WebP = webpConfig
}
} }
// RemoteAddr // RemoteAddr
@@ -418,7 +467,9 @@ func (this *HTTPWebDAO) ComposeWebConfig(tx *dbs.Tx, webId int64, cacheMap *util
if err != nil { if err != nil {
return nil, err return nil, err
} }
config.RemoteAddr = remoteAddrConfig if this.shouldCompose(isLocationOrGroup, forNode, remoteAddrConfig.IsPrior, remoteAddrConfig.IsOn) {
config.RemoteAddr = remoteAddrConfig
}
} }
// mergeSlashes // mergeSlashes
@@ -427,25 +478,24 @@ func (this *HTTPWebDAO) ComposeWebConfig(tx *dbs.Tx, webId int64, cacheMap *util
// 请求限制 // 请求限制
if len(web.RequestLimit) > 0 { if len(web.RequestLimit) > 0 {
var requestLimitConfig = &serverconfigs.HTTPRequestLimitConfig{} var requestLimitConfig = &serverconfigs.HTTPRequestLimitConfig{}
if len(web.RequestLimit) > 0 { err = json.Unmarshal(web.RequestLimit, requestLimitConfig)
err = json.Unmarshal(web.RequestLimit, requestLimitConfig) if err != nil {
if err != nil { return nil, err
return nil, err }
} if this.shouldCompose(isLocationOrGroup, forNode, requestLimitConfig.IsPrior, requestLimitConfig.IsOn) {
config.RequestLimit = requestLimitConfig config.RequestLimit = requestLimitConfig
} }
} }
// 请求脚本 // 请求脚本
// TODO 检查forNode设置
if len(web.RequestScripts) > 0 { if len(web.RequestScripts) > 0 {
var requestScriptsConfig = &serverconfigs.HTTPRequestScriptsConfig{} var requestScriptsConfig = &serverconfigs.HTTPRequestScriptsConfig{}
if len(web.RequestScripts) > 0 { err = json.Unmarshal(web.RequestScripts, requestScriptsConfig)
err = json.Unmarshal(web.RequestScripts, requestScriptsConfig) if err != nil {
if err != nil { return nil, err
return nil, err
}
config.RequestScripts = requestScriptsConfig
} }
config.RequestScripts = requestScriptsConfig
} }
// UAM // UAM
@@ -455,27 +505,41 @@ func (this *HTTPWebDAO) ComposeWebConfig(tx *dbs.Tx, webId int64, cacheMap *util
if err != nil { if err != nil {
return nil, err return nil, err
} }
config.UAM = uamConfig if this.shouldCompose(isLocationOrGroup, forNode, uamConfig.IsPrior, uamConfig.IsOn) {
config.UAM = uamConfig
}
} }
// CC // CC
if teaconst.IsPlus && IsNotNull(web.Cc) { if teaconst.IsPlus && IsNotNull(web.Cc) {
var ccConfig = &serverconfigs.HTTPCCConfig{} var ccConfig = serverconfigs.DefaultHTTPCCConfig()
err = json.Unmarshal(web.Cc, ccConfig) err = json.Unmarshal(web.Cc, ccConfig)
if err != nil { if err != nil {
return nil, err return nil, err
} }
config.CC = ccConfig 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 // Referers
if IsNotNull(web.Referers) { if IsNotNull(web.Referers) {
var referersConfig = &serverconfigs.ReferersConfig{} var referersConfig = serverconfigs.NewReferersConfig()
err = json.Unmarshal(web.Referers, referersConfig) err = json.Unmarshal(web.Referers, referersConfig)
if err != nil { if err != nil {
return nil, err return nil, err
} }
config.Referers = referersConfig if this.shouldCompose(isLocationOrGroup, forNode, referersConfig.IsPrior, referersConfig.IsOn) {
config.Referers = referersConfig
}
} }
// User-Agent // User-Agent
@@ -485,7 +549,9 @@ func (this *HTTPWebDAO) ComposeWebConfig(tx *dbs.Tx, webId int64, cacheMap *util
if err != nil { if err != nil {
return nil, err return nil, err
} }
config.UserAgent = userAgentConfig if this.shouldCompose(isLocationOrGroup, forNode, userAgentConfig.IsPrior, userAgentConfig.IsOn) {
config.UserAgent = userAgentConfig
}
} }
if cacheMap != nil { if cacheMap != nil {
@@ -504,7 +570,21 @@ func (this *HTTPWebDAO) CreateWeb(tx *dbs.Tx, adminId int64, userId int64, rootJ
if len(rootJSON) > 0 { if len(rootJSON) > 0 {
op.Root = JSONBytes(rootJSON) 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 { if err != nil {
return 0, err return 0, err
} }
@@ -528,14 +608,42 @@ func (this *HTTPWebDAO) UpdateWeb(tx *dbs.Tx, webId int64, rootJSON []byte) erro
} }
// UpdateWebCompression 修改压缩配置 // 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 { if webId <= 0 {
return errors.New("invalid webId") return errors.New("invalid webId")
} }
compressionJSON, err := json.Marshal(compressionConfig)
if err != nil {
return err
}
var op = NewHTTPWebOperator() var op = NewHTTPWebOperator()
op.Id = webId op.Id = webId
op.Compression = JSONBytes(compressionConfig) op.Compression = compressionJSON
err := this.Save(tx, op) 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 { if err != nil {
return err return err
} }
@@ -1110,8 +1218,6 @@ func (this *HTTPWebDAO) UpdateWebHostRedirects(tx *dbs.Tx, webId int64, hostRedi
return this.NotifyUpdate(tx, webId) return this.NotifyUpdate(tx, webId)
} }
// 通用设置
// FindWebHostRedirects 查找主机跳转 // FindWebHostRedirects 查找主机跳转
func (this *HTTPWebDAO) FindWebHostRedirects(tx *dbs.Tx, webId int64) ([]byte, error) { func (this *HTTPWebDAO) FindWebHostRedirects(tx *dbs.Tx, webId int64) ([]byte, error) {
col, err := this.Query(tx). col, err := this.Query(tx).
@@ -1352,3 +1458,11 @@ func (this *HTTPWebDAO) NotifyUpdate(tx *dbs.Tx, webId int64) error {
return nil return nil
} }
// 检查是否应该组合配置
func (this *HTTPWebDAO) shouldCompose(isLocationOrGroup bool, forNode bool, isPrior bool, isOn bool) bool {
if !forNode {
return true
}
return (!isLocationOrGroup && isOn) || (isLocationOrGroup && isPrior)
}

View File

@@ -2,6 +2,47 @@ package models
import "github.com/iwind/TeaGo/dbs" 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 // HTTPWeb HTTP Web
type HTTPWeb struct { type HTTPWeb struct {
Id uint32 `field:"id"` // ID Id uint32 `field:"id"` // ID
@@ -41,6 +82,7 @@ type HTTPWeb struct {
Cc dbs.JSON `field:"cc"` // CC设置 Cc dbs.JSON `field:"cc"` // CC设置
Referers dbs.JSON `field:"referers"` // 防盗链设置 Referers dbs.JSON `field:"referers"` // 防盗链设置
UserAgent dbs.JSON `field:"userAgent"` // UserAgent设置 UserAgent dbs.JSON `field:"userAgent"` // UserAgent设置
Optimization dbs.JSON `field:"optimization"` // 页面优化配置
} }
type HTTPWebOperator struct { type HTTPWebOperator struct {
@@ -81,6 +123,7 @@ type HTTPWebOperator struct {
Cc any // CC设置 Cc any // CC设置
Referers any // 防盗链设置 Referers any // 防盗链设置
UserAgent any // UserAgent设置 UserAgent any // UserAgent设置
Optimization any // 页面优化配置
} }
func NewHTTPWebOperator() *HTTPWebOperator { func NewHTTPWebOperator() *HTTPWebOperator {

View File

@@ -159,6 +159,31 @@ func (this *HTTPWebsocketDAO) UpdateWebsocket(tx *dbs.Tx, websocketId int64, han
return this.NotifyUpdate(tx, websocketId) return this.NotifyUpdate(tx, websocketId)
} }
// CloneWebsocket 复制配置
func (this *HTTPWebsocketDAO) CloneWebsocket(tx *dbs.Tx, fromWebsocketId int64) (newWebsocketId int64, err error) {
websocketOne, err := this.Query(tx).
Pk(fromWebsocketId).
Find()
if err != nil || websocketOne == nil {
return 0, err
}
var websocket = websocketOne.(*HTTPWebsocket)
var op = NewHTTPWebsocketOperator()
op.State = websocket.State
op.IsOn = websocket.IsOn
if len(websocket.HandshakeTimeout) > 0 {
op.HandshakeTimeout = websocket.HandshakeTimeout
}
op.AllowAllOrigins = websocket.AllowAllOrigins
if len(websocket.AllowedOrigins) > 0 {
op.AllowedOrigins = websocket.AllowedOrigins
}
op.RequestSameOrigin = websocket.RequestSameOrigin
op.RequestOrigin = websocket.RequestOrigin
return this.SaveInt64(tx, op)
}
// NotifyUpdate 通知更新 // NotifyUpdate 通知更新
func (this *HTTPWebsocketDAO) NotifyUpdate(tx *dbs.Tx, websocketId int64) error { func (this *HTTPWebsocketDAO) NotifyUpdate(tx *dbs.Tx, websocketId int64) error {
webId, err := SharedHTTPWebDAO.FindEnabledWebIdWithWebsocketId(tx, websocketId) webId, err := SharedHTTPWebDAO.FindEnabledWebIdWithWebsocketId(tx, websocketId)

View File

@@ -2,7 +2,7 @@ package models
import "github.com/iwind/TeaGo/dbs" import "github.com/iwind/TeaGo/dbs"
// Websocket设置 // HTTPWebsocket Websocket设置
type HTTPWebsocket struct { type HTTPWebsocket struct {
Id uint32 `field:"id"` // ID Id uint32 `field:"id"` // ID
AdminId uint32 `field:"adminId"` // 管理员ID AdminId uint32 `field:"adminId"` // 管理员ID
@@ -15,20 +15,22 @@ type HTTPWebsocket struct {
AllowedOrigins dbs.JSON `field:"allowedOrigins"` // 支持的源域名列表 AllowedOrigins dbs.JSON `field:"allowedOrigins"` // 支持的源域名列表
RequestSameOrigin uint8 `field:"requestSameOrigin"` // 是否请求一样的Origin RequestSameOrigin uint8 `field:"requestSameOrigin"` // 是否请求一样的Origin
RequestOrigin string `field:"requestOrigin"` // 请求Origin RequestOrigin string `field:"requestOrigin"` // 请求Origin
WebId uint64 `field:"webId"` // Web
} }
type HTTPWebsocketOperator struct { type HTTPWebsocketOperator struct {
Id interface{} // ID Id any // ID
AdminId interface{} // 管理员ID AdminId any // 管理员ID
UserId interface{} // 用户ID UserId any // 用户ID
CreatedAt interface{} // 创建时间 CreatedAt any // 创建时间
State interface{} // 状态 State any // 状态
IsOn interface{} // 是否启用 IsOn any // 是否启用
HandshakeTimeout interface{} // 握手超时时间 HandshakeTimeout any // 握手超时时间
AllowAllOrigins interface{} // 是否支持所有源 AllowAllOrigins any // 是否支持所有源
AllowedOrigins interface{} // 支持的源域名列表 AllowedOrigins any // 支持的源域名列表
RequestSameOrigin interface{} // 是否请求一样的Origin RequestSameOrigin any // 是否请求一样的Origin
RequestOrigin interface{} // 请求Origin RequestOrigin any // 请求Origin
WebId any // Web
} }
func NewHTTPWebsocketOperator() *HTTPWebsocketOperator { func NewHTTPWebsocketOperator() *HTTPWebsocketOperator {

View File

@@ -14,6 +14,7 @@ import (
"github.com/iwind/TeaGo/lists" "github.com/iwind/TeaGo/lists"
"github.com/iwind/TeaGo/types" "github.com/iwind/TeaGo/types"
"math" "math"
"net"
"time" "time"
) )
@@ -75,13 +76,21 @@ func (this *IPItemDAO) EnableIPItem(tx *dbs.Tx, id int64) error {
} }
// DisableIPItem 禁用条目 // DisableIPItem 禁用条目
func (this *IPItemDAO) DisableIPItem(tx *dbs.Tx, id int64) error { func (this *IPItemDAO) DisableIPItem(tx *dbs.Tx, id int64, sourceUserId int64) error {
version, err := SharedIPListDAO.IncreaseVersion(tx) version, err := SharedIPListDAO.IncreaseVersion(tx)
if err != nil { if err != nil {
return err return err
} }
_, err = this.Query(tx). var query = this.Query(tx)
// 检查权限
if sourceUserId > 0 {
query.Where("(sourceUserId=:sourceUserId OR listId IN (SELECT id FROM " + SharedIPListDAO.Table + " WHERE userId=:sourceUserId AND state=1))")
query.Param("sourceUserId", sourceUserId)
}
_, err = query.
Pk(id). Pk(id).
Set("state", IPItemStateDisabled). Set("state", IPItemStateDisabled).
Set("version", version). Set("version", version).
@@ -94,7 +103,7 @@ func (this *IPItemDAO) DisableIPItem(tx *dbs.Tx, id int64) error {
} }
// DisableIPItemsWithIP 禁用某个IP相关条目 // DisableIPItemsWithIP 禁用某个IP相关条目
func (this *IPItemDAO) DisableIPItemsWithIP(tx *dbs.Tx, ipFrom string, ipTo string, userId int64, listId int64) error { func (this *IPItemDAO) DisableIPItemsWithIP(tx *dbs.Tx, ipFrom string, ipTo string, sourceUserId int64, listId int64) error {
if len(ipFrom) == 0 { if len(ipFrom) == 0 {
return errors.New("invalid 'ipFrom'") return errors.New("invalid 'ipFrom'")
} }
@@ -106,16 +115,13 @@ func (this *IPItemDAO) DisableIPItemsWithIP(tx *dbs.Tx, ipFrom string, ipTo stri
State(IPItemStateEnabled) State(IPItemStateEnabled)
if listId > 0 { if listId > 0 {
if userId > 0 {
err := SharedIPListDAO.CheckUserIPList(tx, userId, listId)
if err != nil {
return err
}
}
query.Attr("listId", listId) query.Attr("listId", listId)
} }
if sourceUserId > 0 {
query.Attr("sourceUserId", sourceUserId)
}
ones, err := query.FindAll() ones, err := query.FindAll()
if err != nil { if err != nil {
return err return err
@@ -125,14 +131,6 @@ func (this *IPItemDAO) DisableIPItemsWithIP(tx *dbs.Tx, ipFrom string, ipTo stri
for _, one := range ones { for _, one := range ones {
var item = one.(*IPItem) var item = one.(*IPItem)
var itemId = int64(item.Id) var itemId = int64(item.Id)
var itemListId = int64(item.ListId)
if itemListId != listId && userId > 0 {
err = SharedIPListDAO.CheckUserIPList(tx, userId, itemListId)
if err != nil {
// ignore error
continue
}
}
itemIds = append(itemIds, itemId) itemIds = append(itemIds, itemId)
} }
@@ -213,11 +211,12 @@ func (this *IPItemDAO) DeleteOldItem(tx *dbs.Tx, listId int64, ipFrom string, ip
Attr("listId", listId). Attr("listId", listId).
Attr("ipFrom", ipFrom). Attr("ipFrom", ipFrom).
Attr("ipTo", ipTo). Attr("ipTo", ipTo).
Set("state", IPItemStateEnabled). Attr("state", IPItemStateEnabled).
FindAll() FindAll()
if err != nil { if err != nil {
return err return err
} }
for _, one := range ones { for _, one := range ones {
var itemId = int64(one.(*IPItem).Id) var itemId = int64(one.(*IPItem).Id)
version, err := SharedIPListDAO.IncreaseVersion(tx) version, err := SharedIPListDAO.IncreaseVersion(tx)
@@ -253,7 +252,8 @@ func (this *IPItemDAO) CreateIPItem(tx *dbs.Tx,
sourceServerId int64, sourceServerId int64,
sourceHTTPFirewallPolicyId int64, sourceHTTPFirewallPolicyId int64,
sourceHTTPFirewallRuleGroupId int64, sourceHTTPFirewallRuleGroupId int64,
sourceHTTPFirewallRuleSetId int64) (int64, error) { sourceHTTPFirewallRuleSetId int64,
shouldNotify bool) (int64, error) {
version, err := SharedIPListDAO.IncreaseVersion(tx) version, err := SharedIPListDAO.IncreaseVersion(tx)
if err != nil { if err != nil {
return 0, err return 0, err
@@ -282,6 +282,15 @@ func (this *IPItemDAO) CreateIPItem(tx *dbs.Tx,
op.SourceHTTPFirewallRuleGroupId = sourceHTTPFirewallRuleGroupId op.SourceHTTPFirewallRuleGroupId = sourceHTTPFirewallRuleGroupId
op.SourceHTTPFirewallRuleSetId = sourceHTTPFirewallRuleSetId op.SourceHTTPFirewallRuleSetId = sourceHTTPFirewallRuleSetId
// 服务所属用户
if sourceServerId > 0 {
userId, err := SharedServerDAO.FindServerUserId(tx, sourceServerId)
if err != nil {
return 0, err
}
op.SourceUserId = userId
}
var autoAdded = listId == firewallconfigs.GlobalListId || sourceNodeId > 0 || sourceServerId > 0 || sourceHTTPFirewallPolicyId > 0 var autoAdded = listId == firewallconfigs.GlobalListId || sourceNodeId > 0 || sourceServerId > 0 || sourceHTTPFirewallPolicyId > 0
if autoAdded { if autoAdded {
op.IsRead = 0 op.IsRead = 0
@@ -301,9 +310,11 @@ func (this *IPItemDAO) CreateIPItem(tx *dbs.Tx,
return itemId, nil return itemId, nil
} }
err = this.NotifyUpdate(tx, itemId) if shouldNotify {
if err != nil { err = this.NotifyUpdate(tx, itemId)
return 0, err if err != nil {
return 0, err
}
} }
return itemId, nil return itemId, nil
} }
@@ -353,10 +364,15 @@ func (this *IPItemDAO) UpdateIPItem(tx *dbs.Tx, itemId int64, ipFrom string, ipT
} }
// CountIPItemsWithListId 计算IP数量 // CountIPItemsWithListId 计算IP数量
func (this *IPItemDAO) CountIPItemsWithListId(tx *dbs.Tx, listId int64, keyword string, ipFrom string, ipTo string, eventLevel string) (int64, error) { func (this *IPItemDAO) CountIPItemsWithListId(tx *dbs.Tx, listId int64, sourceUserId int64, keyword string, ipFrom string, ipTo string, eventLevel string) (int64, error) {
var query = this.Query(tx). var query = this.Query(tx).
State(IPItemStateEnabled). State(IPItemStateEnabled).
Attr("listId", listId) Attr("listId", listId)
if sourceUserId > 0 {
if listId <= 0 || listId == firewallconfigs.GlobalListId {
query.Attr("sourceUserId", sourceUserId)
}
}
if len(keyword) > 0 { if len(keyword) > 0 {
query.Where("(ipFrom LIKE :keyword OR ipTo LIKE :keyword)"). query.Where("(ipFrom LIKE :keyword OR ipTo LIKE :keyword)").
Param("keyword", dbutils.QuoteLike(keyword)) Param("keyword", dbutils.QuoteLike(keyword))
@@ -374,10 +390,15 @@ func (this *IPItemDAO) CountIPItemsWithListId(tx *dbs.Tx, listId int64, keyword
} }
// ListIPItemsWithListId 查找IP列表 // ListIPItemsWithListId 查找IP列表
func (this *IPItemDAO) ListIPItemsWithListId(tx *dbs.Tx, listId int64, keyword string, ipFrom string, ipTo string, eventLevel string, offset int64, size int64) (result []*IPItem, err error) { func (this *IPItemDAO) ListIPItemsWithListId(tx *dbs.Tx, listId int64, sourceUserId int64, keyword string, ipFrom string, ipTo string, eventLevel string, offset int64, size int64) (result []*IPItem, err error) {
var query = this.Query(tx). var query = this.Query(tx).
State(IPItemStateEnabled). State(IPItemStateEnabled).
Attr("listId", listId) Attr("listId", listId)
if sourceUserId > 0 {
if listId <= 0 || listId == firewallconfigs.GlobalListId {
query.Attr("sourceUserId", sourceUserId)
}
}
if len(keyword) > 0 { if len(keyword) > 0 {
query.Where("(ipFrom LIKE :keyword OR ipTo LIKE :keyword)"). query.Where("(ipFrom LIKE :keyword OR ipTo LIKE :keyword)").
Param("keyword", dbutils.QuoteLike(keyword)) Param("keyword", dbutils.QuoteLike(keyword))
@@ -403,10 +424,10 @@ func (this *IPItemDAO) ListIPItemsWithListId(tx *dbs.Tx, listId int64, keyword s
// ListIPItemsAfterVersion 根据版本号查找IP列表 // ListIPItemsAfterVersion 根据版本号查找IP列表
func (this *IPItemDAO) ListIPItemsAfterVersion(tx *dbs.Tx, version int64, size int64) (result []*IPItem, err error) { func (this *IPItemDAO) ListIPItemsAfterVersion(tx *dbs.Tx, version int64, size int64) (result []*IPItem, err error) {
_, err = this.Query(tx). _, err = this.Query(tx).
UseIndex("version").
// 这里不要设置状态参数,因为我们要知道哪些是删除的 // 这里不要设置状态参数,因为我们要知道哪些是删除的
Gt("version", version). Gt("version", version).
Asc("version"). Asc("version").
Asc("id").
Limit(size). Limit(size).
Slice(&result). Slice(&result).
FindAll() FindAll()
@@ -466,10 +487,23 @@ func (this *IPItemDAO) ExistsEnabledItem(tx *dbs.Tx, itemId int64) (bool, error)
} }
// CountAllEnabledIPItems 计算数量 // CountAllEnabledIPItems 计算数量
func (this *IPItemDAO) CountAllEnabledIPItems(tx *dbs.Tx, keyword string, ip string, listId int64, unread bool, eventLevel string, listType string) (int64, 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) var query = this.Query(tx)
if sourceUserId > 0 {
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 { 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 { if len(ip) > 0 {
query.Attr("ipFrom", ip) query.Attr("ipFrom", ip)
@@ -499,10 +533,23 @@ func (this *IPItemDAO) CountAllEnabledIPItems(tx *dbs.Tx, keyword string, ip str
} }
// ListAllEnabledIPItems 搜索所有IP // ListAllEnabledIPItems 搜索所有IP
func (this *IPItemDAO) ListAllEnabledIPItems(tx *dbs.Tx, keyword string, ip string, listId int64, unread bool, eventLevel string, listType string, offset int64, size int64) (result []*IPItem, err error) { 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) var query = this.Query(tx)
if sourceUserId > 0 {
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 { 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 { if len(ip) > 0 {
query.Attr("ipFrom", ip) query.Attr("ipFrom", ip)
@@ -536,11 +583,17 @@ func (this *IPItemDAO) ListAllEnabledIPItems(tx *dbs.Tx, keyword string, ip stri
} }
// UpdateItemsRead 设置所有未已读 // UpdateItemsRead 设置所有未已读
func (this *IPItemDAO) UpdateItemsRead(tx *dbs.Tx) error { func (this *IPItemDAO) UpdateItemsRead(tx *dbs.Tx, sourceUserId int64) error {
return this.Query(tx). var query = this.Query(tx).
Attr("isRead", 0). Attr("isRead", 0).
Set("isRead", 1). Set("isRead", 1)
UpdateQuickly()
if sourceUserId > 0 {
query.Attr("sourceUserId", sourceUserId)
query.UseIndex("sourceUserId")
}
return query.UpdateQuickly()
} }
// CleanExpiredIPItems 清除过期数据 // CleanExpiredIPItems 清除过期数据
@@ -621,6 +674,9 @@ func (this *IPItemDAO) NotifyUpdate(tx *dbs.Tx, itemId int64) error {
} }
} else { } else {
clusterIds, err := SharedNodeClusterDAO.FindAllEnabledNodeClusterIds(tx) clusterIds, err := SharedNodeClusterDAO.FindAllEnabledNodeClusterIds(tx)
if err != nil {
return err
}
for _, clusterId := range clusterIds { for _, clusterId := range clusterIds {
err = SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleNode, clusterId, 0, 0, NodeTaskTypeIPItemChanged) err = SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleNode, clusterId, 0, 0, NodeTaskTypeIPItemChanged)
if err != nil { if err != nil {

View File

@@ -51,12 +51,12 @@ func TestIPItemDAO_CreateManyIPs(t *testing.T) {
var dao = models.NewIPItemDAO() var dao = models.NewIPItemDAO()
var n = 10 var n = 10
for i := 0; i < n; i++ { for i := 0; i < n; i++ {
itemId, err := dao.CreateIPItem(tx, firewallconfigs.GlobalListId, "192."+types.String(rands.Int(0, 255))+"."+types.String(rands.Int(0, 255))+"."+types.String(rands.Int(0, 255)), "", time.Now().Unix()+86400, "test", models.IPItemTypeIPv4, "warning", 0, 0, 0, 0, 0, 0, 0) itemId, err := dao.CreateIPItem(tx, firewallconfigs.GlobalListId, "192."+types.String(rands.Int(0, 255))+"."+types.String(rands.Int(0, 255))+"."+types.String(rands.Int(0, 255)), "", time.Now().Unix()+86400, "test", models.IPItemTypeIPv4, "warning", 0, 0, 0, 0, 0, 0, 0, false)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
_ = itemId _ = itemId
/**err = dao.Query(tx).Pk(itemId).Set("state", 0).UpdateQuickly() /**err = dao.Query(tx).Pk(itemId).Attr("state", 0).UpdateQuickly()
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
}**/ }**/

View File

@@ -23,32 +23,34 @@ type IPItem struct {
SourceHTTPFirewallPolicyId uint32 `field:"sourceHTTPFirewallPolicyId"` // 来源策略ID SourceHTTPFirewallPolicyId uint32 `field:"sourceHTTPFirewallPolicyId"` // 来源策略ID
SourceHTTPFirewallRuleGroupId uint32 `field:"sourceHTTPFirewallRuleGroupId"` // 来源规则集分组ID SourceHTTPFirewallRuleGroupId uint32 `field:"sourceHTTPFirewallRuleGroupId"` // 来源规则集分组ID
SourceHTTPFirewallRuleSetId uint32 `field:"sourceHTTPFirewallRuleSetId"` // 来源规则集ID SourceHTTPFirewallRuleSetId uint32 `field:"sourceHTTPFirewallRuleSetId"` // 来源规则集ID
SourceUserId uint64 `field:"sourceUserId"` // 用户ID
IsRead bool `field:"isRead"` // 是否已读 IsRead bool `field:"isRead"` // 是否已读
} }
type IPItemOperator struct { type IPItemOperator struct {
Id interface{} // ID Id any // ID
ListId interface{} // 所属名单ID ListId any // 所属名单ID
Type interface{} // 类型 Type any // 类型
IpFrom interface{} // 开始IP IpFrom any // 开始IP
IpTo interface{} // 结束IP IpTo any // 结束IP
IpFromLong interface{} // 开始IP整型 IpFromLong any // 开始IP整型
IpToLong interface{} // 结束IP整型 IpToLong any // 结束IP整型
Version interface{} // 版本 Version any // 版本
CreatedAt interface{} // 创建时间 CreatedAt any // 创建时间
UpdatedAt interface{} // 修改时间 UpdatedAt any // 修改时间
Reason interface{} // 加入说明 Reason any // 加入说明
EventLevel interface{} // 事件级别 EventLevel any // 事件级别
State interface{} // 状态 State any // 状态
ExpiredAt interface{} // 过期时间 ExpiredAt any // 过期时间
ServerId interface{} // 有效范围服务ID ServerId any // 有效范围服务ID
NodeId interface{} // 有效范围节点ID NodeId any // 有效范围节点ID
SourceNodeId interface{} // 来源节点ID SourceNodeId any // 来源节点ID
SourceServerId interface{} // 来源服务ID SourceServerId any // 来源服务ID
SourceHTTPFirewallPolicyId interface{} // 来源策略ID SourceHTTPFirewallPolicyId any // 来源策略ID
SourceHTTPFirewallRuleGroupId interface{} // 来源规则集分组ID SourceHTTPFirewallRuleGroupId any // 来源规则集分组ID
SourceHTTPFirewallRuleSetId interface{} // 来源规则集ID SourceHTTPFirewallRuleSetId any // 来源规则集ID
IsRead interface{} // 是否已读 SourceUserId any // 用户ID
IsRead any // 是否已读
} }
func NewIPItemOperator() *IPItemOperator { func NewIPItemOperator() *IPItemOperator {

View File

@@ -3,6 +3,7 @@ package models
import ( import (
"encoding/json" "encoding/json"
"errors" "errors"
"fmt"
"github.com/TeaOSLab/EdgeAPI/internal/db/models/regions" "github.com/TeaOSLab/EdgeAPI/internal/db/models/regions"
"github.com/TeaOSLab/EdgeAPI/internal/utils" "github.com/TeaOSLab/EdgeAPI/internal/utils"
"github.com/TeaOSLab/EdgeCommon/pkg/iplibrary" "github.com/TeaOSLab/EdgeCommon/pkg/iplibrary"
@@ -72,7 +73,7 @@ func (this *IPLibraryFileDAO) FindEnabledIPLibraryFile(tx *dbs.Tx, id int64) (*I
} }
// CreateLibraryFile 创建文件 // CreateLibraryFile 创建文件
func (this *IPLibraryFileDAO) CreateLibraryFile(tx *dbs.Tx, name string, template string, emptyValues []string, fileId int64, countries []string, provinces [][2]string, cities [][3]string, towns [][4]string, providers []string) (int64, error) { func (this *IPLibraryFileDAO) CreateLibraryFile(tx *dbs.Tx, name string, template string, emptyValues []string, password string, fileId int64, countries []string, provinces [][2]string, cities [][3]string, towns [][4]string, providers []string) (int64, error) {
var op = NewIPLibraryFileOperator() var op = NewIPLibraryFileOperator()
op.Name = name op.Name = name
op.Template = template op.Template = template
@@ -86,6 +87,8 @@ func (this *IPLibraryFileDAO) CreateLibraryFile(tx *dbs.Tx, name string, templat
} }
op.EmptyValues = emptyValuesJSON op.EmptyValues = emptyValuesJSON
op.Password = password
op.FileId = fileId op.FileId = fileId
if countries == nil { if countries == nil {
@@ -297,7 +300,7 @@ func (this *IPLibraryFileDAO) GenerateIPLibrary(tx *dbs.Tx, libraryFileId int64)
var libraryFile = one.(*IPLibraryFile) var libraryFile = one.(*IPLibraryFile)
template, err := iplibrary.NewTemplate(libraryFile.Template) template, err := iplibrary.NewTemplate(libraryFile.Template)
if err != nil { 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) var fileId = int64(libraryFile.FileId)
@@ -312,17 +315,17 @@ func (this *IPLibraryFileDAO) GenerateIPLibrary(tx *dbs.Tx, libraryFileId int64)
if os.IsNotExist(err) { if os.IsNotExist(err) {
err = os.Mkdir(dir, 0777) err = os.Mkdir(dir, 0777)
if err != nil { 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 { } 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() { } else if !stat.IsDir() {
_ = os.Remove(dir) _ = os.Remove(dir)
err = os.Mkdir(dir, 0777) err = os.Mkdir(dir, 0777)
if err != nil { 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)
} }
} }
@@ -337,7 +340,7 @@ func (this *IPLibraryFileDAO) GenerateIPLibrary(tx *dbs.Tx, libraryFileId int64)
var countries = []*iplibrary.Country{} var countries = []*iplibrary.Country{}
for _, country := range dbCountries { for _, country := range dbCountries {
countries = append(countries, &iplibrary.Country{ countries = append(countries, &iplibrary.Country{
Id: country.Id, Id: types.Uint16(country.ValueId),
Name: country.DisplayName(), Name: country.DisplayName(),
Codes: country.AllCodes(), Codes: country.AllCodes(),
}) })
@@ -352,7 +355,7 @@ func (this *IPLibraryFileDAO) GenerateIPLibrary(tx *dbs.Tx, libraryFileId int64)
var provinces = []*iplibrary.Province{} var provinces = []*iplibrary.Province{}
for _, province := range dbProvinces { for _, province := range dbProvinces {
provinces = append(provinces, &iplibrary.Province{ provinces = append(provinces, &iplibrary.Province{
Id: province.Id, Id: types.Uint16(province.ValueId),
Name: province.DisplayName(), Name: province.DisplayName(),
Codes: province.AllCodes(), Codes: province.AllCodes(),
}) })
@@ -367,7 +370,7 @@ func (this *IPLibraryFileDAO) GenerateIPLibrary(tx *dbs.Tx, libraryFileId int64)
var cities = []*iplibrary.City{} var cities = []*iplibrary.City{}
for _, city := range dbCities { for _, city := range dbCities {
cities = append(cities, &iplibrary.City{ cities = append(cities, &iplibrary.City{
Id: city.Id, Id: city.ValueId,
Name: city.DisplayName(), Name: city.DisplayName(),
Codes: city.AllCodes(), Codes: city.AllCodes(),
}) })
@@ -382,7 +385,7 @@ func (this *IPLibraryFileDAO) GenerateIPLibrary(tx *dbs.Tx, libraryFileId int64)
var towns = []*iplibrary.Town{} var towns = []*iplibrary.Town{}
for _, town := range dbTowns { for _, town := range dbTowns {
towns = append(towns, &iplibrary.Town{ towns = append(towns, &iplibrary.Town{
Id: town.Id, Id: town.ValueId,
Name: town.DisplayName(), Name: town.DisplayName(),
Codes: town.AllCodes(), Codes: town.AllCodes(),
}) })
@@ -397,7 +400,7 @@ func (this *IPLibraryFileDAO) GenerateIPLibrary(tx *dbs.Tx, libraryFileId int64)
var providers = []*iplibrary.Provider{} var providers = []*iplibrary.Provider{}
for _, provider := range dbProviders { for _, provider := range dbProviders {
providers = append(providers, &iplibrary.Provider{ providers = append(providers, &iplibrary.Provider{
Id: provider.Id, Id: types.Uint16(provider.ValueId),
Name: provider.DisplayName(), Name: provider.DisplayName(),
Codes: provider.AllCodes(), Codes: provider.AllCodes(),
}) })
@@ -414,7 +417,7 @@ func (this *IPLibraryFileDAO) GenerateIPLibrary(tx *dbs.Tx, libraryFileId int64)
Towns: towns, Towns: towns,
Providers: providers, Providers: providers,
} }
writer, err := iplibrary.NewFileWriter(filePath, meta) writer, err := iplibrary.NewFileWriter(filePath, meta, libraryFile.Password)
if err != nil { if err != nil {
return err return err
} }
@@ -426,7 +429,7 @@ func (this *IPLibraryFileDAO) GenerateIPLibrary(tx *dbs.Tx, libraryFileId int64)
err = writer.WriteMeta() err = writer.WriteMeta()
if err != nil { 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) chunkIds, err := SharedFileChunkDAO.FindAllFileChunkIds(tx, fileId)
@@ -438,35 +441,35 @@ func (this *IPLibraryFileDAO) GenerateIPLibrary(tx *dbs.Tx, libraryFileId int64)
var countryMap = map[string]int64{} // countryName => countryId var countryMap = map[string]int64{} // countryName => countryId
for _, country := range dbCountries { for _, country := range dbCountries {
for _, code := range country.AllCodes() { for _, code := range country.AllCodes() {
countryMap[code] = int64(country.Id) countryMap[code] = int64(country.ValueId)
} }
} }
var provinceMap = map[string]int64{} // countryId_provinceName => provinceId var provinceMap = map[string]int64{} // countryId_provinceName => provinceId
for _, province := range dbProvinces { for _, province := range dbProvinces {
for _, code := range province.AllCodes() { 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 var cityMap = map[string]int64{} // provinceId_cityName => cityId
for _, city := range dbCities { for _, city := range dbCities {
for _, code := range city.AllCodes() { 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 var townMap = map[string]int64{} // cityId_townName => townId
for _, town := range dbTowns { for _, town := range dbTowns {
for _, code := range town.AllCodes() { 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 var providerMap = map[string]int64{} // providerName => providerId
for _, provider := range dbProviders { for _, provider := range dbProviders {
for _, code := range provider.AllCodes() { for _, code := range provider.AllCodes() {
providerMap[code] = int64(provider.Id) providerMap[code] = int64(provider.ValueId)
} }
} }
@@ -501,7 +504,7 @@ func (this *IPLibraryFileDAO) GenerateIPLibrary(tx *dbs.Tx, libraryFileId int64)
err = writer.Write(ipFrom, ipTo, countryId, provinceId, cityId, townId, providerId) err = writer.Write(ipFrom, ipTo, countryId, provinceId, cityId, townId, providerId)
if err != nil { if err != nil {
return errors.New("write failed: " + err.Error()) return fmt.Errorf("write failed: %w", err)
} }
return nil return nil
@@ -534,7 +537,7 @@ func (this *IPLibraryFileDAO) GenerateIPLibrary(tx *dbs.Tx, libraryFileId int64)
// 将生成的内容写入到文件 // 将生成的内容写入到文件
stat, err = os.Stat(filePath) stat, err = os.Stat(filePath)
if err != nil { 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) generatedFileId, err := SharedFileDAO.CreateFile(tx, 0, 0, "ipLibraryFile", "", libraryCode+".db", stat.Size(), "", false)
if err != nil { if err != nil {
@@ -543,7 +546,7 @@ func (this *IPLibraryFileDAO) GenerateIPLibrary(tx *dbs.Tx, libraryFileId int64)
fp, err := os.Open(filePath) fp, err := os.Open(filePath)
if err != nil { 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) var buf = make([]byte, 256*1024)
for { for {

View File

@@ -18,6 +18,7 @@ type IPLibraryFile struct {
Towns dbs.JSON `field:"towns"` // 区县 Towns dbs.JSON `field:"towns"` // 区县
Providers dbs.JSON `field:"providers"` // ISP服务商 Providers dbs.JSON `field:"providers"` // ISP服务商
Code string `field:"code"` // 文件代号 Code string `field:"code"` // 文件代号
Password string `field:"password"` // 密码
CreatedAt uint64 `field:"createdAt"` // 上传时间 CreatedAt uint64 `field:"createdAt"` // 上传时间
State uint8 `field:"state"` // 状态 State uint8 `field:"state"` // 状态
} }
@@ -37,6 +38,7 @@ type IPLibraryFileOperator struct {
Towns any // 区县 Towns any // 区县
Providers any // ISP服务商 Providers any // ISP服务商
Code any // 文件代号 Code any // 文件代号
Password any // 密码
CreatedAt any // 上传时间 CreatedAt any // 上传时间
State any // 状态 State any // 状态
} }

View File

@@ -11,6 +11,7 @@ import (
"github.com/iwind/TeaGo/Tea" "github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs" "github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/lists" "github.com/iwind/TeaGo/lists"
"github.com/iwind/TeaGo/maps"
"github.com/iwind/TeaGo/types" "github.com/iwind/TeaGo/types"
) )
@@ -61,12 +62,16 @@ func (this *IPListDAO) EnableIPList(tx *dbs.Tx, id int64) error {
} }
// DisableIPList 禁用条目 // 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). _, err := this.Query(tx).
Pk(id). Pk(listId).
Set("state", IPListStateDisabled). Set("state", IPListStateDisabled).
Update() Update()
return err if err != nil {
return err
}
return this.NotifyUpdate(tx, listId, NodeTaskTypeIPListDeleted+"@"+string(maps.Map{"listId": listId}.AsJSON()))
} }
// FindEnabledIPList 查找启用中的条目 // FindEnabledIPList 查找启用中的条目
@@ -258,11 +263,35 @@ func (this *IPListDAO) ExistsEnabledIPList(tx *dbs.Tx, listId int64) (bool, erro
// NotifyUpdate 通知更新 // NotifyUpdate 通知更新
func (this *IPListDAO) NotifyUpdate(tx *dbs.Tx, listId int64, taskType NodeTaskType) error { func (this *IPListDAO) NotifyUpdate(tx *dbs.Tx, listId int64, taskType NodeTaskType) error {
// WAF策略中的
httpFirewallPolicyIds, err := SharedHTTPFirewallPolicyDAO.FindEnabledFirewallPolicyIdsWithIPListId(tx, listId) httpFirewallPolicyIds, err := SharedHTTPFirewallPolicyDAO.FindEnabledFirewallPolicyIdsWithIPListId(tx, listId)
if err != nil { if err != nil {
return err 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 { for _, policyId := range httpFirewallPolicyIds {
// 集群 // 集群
clusterIds, err := SharedNodeClusterDAO.FindAllEnabledNodeClusterIdsWithHTTPFirewallPolicyId(tx, policyId) clusterIds, err := SharedNodeClusterDAO.FindAllEnabledNodeClusterIdsWithHTTPFirewallPolicyId(tx, policyId)

View File

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

View File

@@ -1,9 +1,11 @@
package models package models
import ( import (
"encoding/json"
dbutils "github.com/TeaOSLab/EdgeAPI/internal/db/utils" dbutils "github.com/TeaOSLab/EdgeAPI/internal/db/utils"
"github.com/TeaOSLab/EdgeAPI/internal/errors" "github.com/TeaOSLab/EdgeAPI/internal/errors"
"github.com/TeaOSLab/EdgeAPI/internal/utils" "github.com/TeaOSLab/EdgeAPI/internal/utils"
"github.com/TeaOSLab/EdgeCommon/pkg/langs"
_ "github.com/go-sql-driver/mysql" _ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea" "github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs" "github.com/iwind/TeaGo/dbs"
@@ -36,7 +38,7 @@ func init() {
} }
// CreateLog 创建管理员日志 // 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() var op = NewLogOperator()
op.Level = level op.Level = level
op.Description = utils.LimitString(description, 1000) 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 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.Day = timeutil.Format("Ymd")
op.Type = LogTypeAdmin op.Type = LogTypeAdmin
err := this.Save(tx, op) err := this.Save(tx, op)
@@ -60,11 +72,11 @@ func (this *LogDAO) CreateLog(tx *dbs.Tx, adminType string, adminId int64, level
} }
// CountLogs 计算所有日志数量 // CountLogs 计算所有日志数量
func (this *LogDAO) CountLogs(tx *dbs.Tx, dayFrom string, dayTo string, keyword string, userType string) (int64, error) { func (this *LogDAO) CountLogs(tx *dbs.Tx, dayFrom string, dayTo string, keyword string, userType string, level string) (int64, error) {
dayFrom = this.formatDay(dayFrom) dayFrom = this.formatDay(dayFrom)
dayTo = this.formatDay(dayTo) dayTo = this.formatDay(dayTo)
query := this.Query(tx) var query = this.Query(tx)
if len(dayFrom) > 0 { if len(dayFrom) > 0 {
query.Gte("day", dayFrom) query.Gte("day", dayFrom)
@@ -76,6 +88,9 @@ func (this *LogDAO) CountLogs(tx *dbs.Tx, dayFrom string, dayTo string, keyword
query.Where("(description LIKE :keyword OR ip LIKE :keyword OR action LIKE :keyword)"). query.Where("(description LIKE :keyword OR ip LIKE :keyword OR action LIKE :keyword)").
Param("keyword", dbutils.QuoteLike(keyword)) Param("keyword", dbutils.QuoteLike(keyword))
} }
if len(level) > 0 {
query.Attr("level", level)
}
// 用户类型 // 用户类型
switch userType { switch userType {
@@ -89,11 +104,11 @@ func (this *LogDAO) CountLogs(tx *dbs.Tx, dayFrom string, dayTo string, keyword
} }
// ListLogs 列出单页日志 // ListLogs 列出单页日志
func (this *LogDAO) ListLogs(tx *dbs.Tx, offset int64, size int64, dayFrom string, dayTo string, keyword string, userType string) (result []*Log, err error) { func (this *LogDAO) ListLogs(tx *dbs.Tx, offset int64, size int64, dayFrom string, dayTo string, keyword string, userType string, level string) (result []*Log, err error) {
dayFrom = this.formatDay(dayFrom) dayFrom = this.formatDay(dayFrom)
dayTo = this.formatDay(dayTo) dayTo = this.formatDay(dayTo)
query := this.Query(tx) var query = this.Query(tx)
if len(dayFrom) > 0 { if len(dayFrom) > 0 {
query.Gte("day", dayFrom) query.Gte("day", dayFrom)
} }
@@ -105,6 +120,10 @@ func (this *LogDAO) ListLogs(tx *dbs.Tx, offset int64, size int64, dayFrom strin
Param("keyword", dbutils.QuoteLike(keyword)) Param("keyword", dbutils.QuoteLike(keyword))
} }
if len(level) > 0 {
query.Attr("level", level)
}
// 用户类型 // 用户类型
switch userType { switch userType {
case "admin": case "admin":

View File

@@ -1,34 +1,60 @@
package models 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 { type Log struct {
Id uint32 `field:"id"` // ID Id uint32 `field:"id"` // ID
Level string `field:"level"` // 级别 Level string `field:"level"` // 级别
Description string `field:"description"` // 描述 Description string `field:"description"` // 描述
CreatedAt uint64 `field:"createdAt"` // 创建时间 CreatedAt uint64 `field:"createdAt"` // 创建时间
Action string `field:"action"` // 动作 Action string `field:"action"` // 动作
UserId uint32 `field:"userId"` // 用户ID UserId uint32 `field:"userId"` // 用户ID
AdminId uint32 `field:"adminId"` // 管理员ID AdminId uint32 `field:"adminId"` // 管理员ID
ProviderId uint32 `field:"providerId"` // 供应商ID ProviderId uint32 `field:"providerId"` // 供应商ID
Ip string `field:"ip"` // IP地址 Ip string `field:"ip"` // IP地址
Type string `field:"type"` // 类型admin, user Type string `field:"type"` // 类型admin, user
Day string `field:"day"` // 日期 Day string `field:"day"` // 日期
BillId uint32 `field:"billId"` // 账单ID BillId uint32 `field:"billId"` // 账单ID
LangMessageCode string `field:"langMessageCode"` // 多语言消息代号
LangMessageArgs dbs.JSON `field:"langMessageArgs"` // 多语言参数
Params dbs.JSON `field:"params"` // 关联对象参数
} }
type LogOperator struct { type LogOperator struct {
Id interface{} // ID Id any // ID
Level interface{} // 级别 Level any // 级别
Description interface{} // 描述 Description any // 描述
CreatedAt interface{} // 创建时间 CreatedAt any // 创建时间
Action interface{} // 动作 Action any // 动作
UserId interface{} // 用户ID UserId any // 用户ID
AdminId interface{} // 管理员ID AdminId any // 管理员ID
ProviderId interface{} // 供应商ID ProviderId any // 供应商ID
Ip interface{} // IP地址 Ip any // IP地址
Type interface{} // 类型admin, user Type any // 类型admin, user
Day interface{} // 日期 Day any // 日期
BillId interface{} // 账单ID BillId any // 账单ID
LangMessageCode any // 多语言消息代号
LangMessageArgs any // 多语言参数
Params any // 关联对象参数
} }
func NewLogOperator() *LogOperator { func NewLogOperator() *LogOperator {

View File

@@ -27,6 +27,8 @@ const (
type MessageType = string type MessageType = string
const ( const (
MessageTypeAll MessageType = "*"
// 这里的命名问题(首字母大写)为历史遗留问题,暂不修改 // 这里的命名问题(首字母大写)为历史遗留问题,暂不修改
MessageTypeHealthCheckFailed MessageType = "HealthCheckFailed" // 节点健康检查失败 MessageTypeHealthCheckFailed MessageType = "HealthCheckFailed" // 节点健康检查失败
@@ -52,7 +54,9 @@ const (
MessageTypeReportNodeInactive MessageType = "ReportNodeInactive" // 区域监控节点节点不活跃 MessageTypeReportNodeInactive MessageType = "ReportNodeInactive" // 区域监控节点节点不活跃
MessageTypeReportNodeActive MessageType = "ReportNodeActive" // 区域监控节点活跃 MessageTypeReportNodeActive MessageType = "ReportNodeActive" // 区域监控节点活跃
MessageTypeConnectivity MessageType = "Connectivity" MessageTypeConnectivity MessageType = "Connectivity" // 连通性
MessageTypeNodeSchedule MessageType = "NodeSchedule" // 节点调度信息
MessageTypeNodeOfflineDay MessageType = "NodeOfflineDay" // 节点到下线日期
) )
type MessageDAO dbs.DAO 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 { if err != nil {
return err return err
} }
@@ -155,7 +159,7 @@ func (this *MessageDAO) CreateNodeMessage(tx *dbs.Tx, role string, clusterId int
// CreateMessage 创建普通消息 // CreateMessage 创建普通消息
func (this *MessageDAO) CreateMessage(tx *dbs.Tx, adminId int64, userId int64, messageType MessageType, level string, subject string, body string, paramsJSON []byte) error { func (this *MessageDAO) CreateMessage(tx *dbs.Tx, adminId int64, userId int64, messageType MessageType, level string, subject string, body string, paramsJSON []byte) error {
body = utils.LimitString(subject, 100) subject = utils.LimitString(subject, 100)
body = utils.LimitString(body, 1024) body = utils.LimitString(body, 1024)
var op = NewMessageOperator() var op = NewMessageOperator()

View File

@@ -4,8 +4,6 @@ import (
_ "github.com/go-sql-driver/mysql" _ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea" "github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs" "github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/lists"
"github.com/iwind/TeaGo/maps"
) )
const ( const (
@@ -34,7 +32,7 @@ func init() {
}) })
} }
// 启用条目 // EnableMessageMedia 启用条目
func (this *MessageMediaDAO) EnableMessageMedia(tx *dbs.Tx, id int64) error { func (this *MessageMediaDAO) EnableMessageMedia(tx *dbs.Tx, id int64) error {
_, err := this.Query(tx). _, err := this.Query(tx).
Pk(id). Pk(id).
@@ -43,7 +41,7 @@ func (this *MessageMediaDAO) EnableMessageMedia(tx *dbs.Tx, id int64) error {
return err return err
} }
// 禁用条目 // DisableMessageMedia 禁用条目
func (this *MessageMediaDAO) DisableMessageMedia(tx *dbs.Tx, id int64) error { func (this *MessageMediaDAO) DisableMessageMedia(tx *dbs.Tx, id int64) error {
_, err := this.Query(tx). _, err := this.Query(tx).
Pk(id). Pk(id).
@@ -52,7 +50,7 @@ func (this *MessageMediaDAO) DisableMessageMedia(tx *dbs.Tx, id int64) error {
return err return err
} }
// 查找启用中的条目 // FindEnabledMessageMedia 查找启用中的条目
func (this *MessageMediaDAO) FindEnabledMessageMedia(tx *dbs.Tx, id int64) (*MessageMedia, error) { func (this *MessageMediaDAO) FindEnabledMessageMedia(tx *dbs.Tx, id int64) (*MessageMedia, error) {
result, err := this.Query(tx). result, err := this.Query(tx).
Pk(id). Pk(id).
@@ -64,7 +62,7 @@ func (this *MessageMediaDAO) FindEnabledMessageMedia(tx *dbs.Tx, id int64) (*Mes
return result.(*MessageMedia), err return result.(*MessageMedia), err
} }
// 根据主键查找名称 // FindMessageMediaName 根据主键查找名称
func (this *MessageMediaDAO) FindMessageMediaName(tx *dbs.Tx, id int64) (string, error) { func (this *MessageMediaDAO) FindMessageMediaName(tx *dbs.Tx, id int64) (string, error) {
return this.Query(tx). return this.Query(tx).
Pk(id). Pk(id).
@@ -72,7 +70,7 @@ func (this *MessageMediaDAO) FindMessageMediaName(tx *dbs.Tx, id int64) (string,
FindStringCol("") FindStringCol("")
} }
// 查询所有可用媒介 // FindAllEnabledMessageMedias 查询所有可用媒介
func (this *MessageMediaDAO) FindAllEnabledMessageMedias(tx *dbs.Tx) (result []*MessageMedia, err error) { func (this *MessageMediaDAO) FindAllEnabledMessageMedias(tx *dbs.Tx) (result []*MessageMedia, err error) {
_, err = this.Query(tx). _, err = this.Query(tx).
State(MessageMediaStateEnabled). State(MessageMediaStateEnabled).
@@ -82,74 +80,3 @@ func (this *MessageMediaDAO) FindAllEnabledMessageMedias(tx *dbs.Tx) (result []*
FindAll() FindAll()
return 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) 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 计算接收人数量 // CountAllEnabledReceivers 计算接收人数量
func (this *MessageReceiverDAO) CountAllEnabledReceivers(tx *dbs.Tx, role string, clusterId int64, nodeId int64, serverId int64, messageType string) (int64, error) { func (this *MessageReceiverDAO) CountAllEnabledReceivers(tx *dbs.Tx, role string, clusterId int64, nodeId int64, serverId int64, messageType string) (int64, error) {
query := this.Query(tx) query := this.Query(tx)
@@ -146,6 +128,8 @@ func (this *MessageReceiverDAO) FindEnabledBestFitReceivers(tx *dbs.Tx, role str
} else if nodeId > 0 { } else if nodeId > 0 {
query.Attr("nodeId", nodeId) query.Attr("nodeId", nodeId)
} else if clusterId > 0 { } else if clusterId > 0 {
query.Attr("serverId", 0)
query.Attr("nodeId", 0)
query.Attr("clusterId", clusterId) query.Attr("clusterId", clusterId)
} }
_, err = query. _, 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 package models
import ( 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/goman"
"github.com/TeaOSLab/EdgeAPI/internal/remotelogs" "github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
_ "github.com/go-sql-driver/mysql" _ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea" "github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs" "github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/rands" "github.com/iwind/TeaGo/rands"
"github.com/iwind/TeaGo/types"
stringutil "github.com/iwind/TeaGo/utils/string"
timeutil "github.com/iwind/TeaGo/utils/time" timeutil "github.com/iwind/TeaGo/utils/time"
"time" "time"
) )
type MessageTaskStatus = int
const ( const (
MessageTaskStateEnabled = 1 // 已启用 MessageTaskStateEnabled = 1 // 已启用
MessageTaskStateDisabled = 0 // 已禁用 MessageTaskStateDisabled = 0 // 已禁用
MessageTaskStatusNone MessageTaskStatus = 0 // 普通状态
MessageTaskStatusSending MessageTaskStatus = 1 // 发送中
MessageTaskStatusSuccess MessageTaskStatus = 2 // 发送成功
MessageTaskStatusFailed MessageTaskStatus = 3 // 发送失败
) )
type MessageTaskDAO dbs.DAO type MessageTaskDAO dbs.DAO
@@ -94,151 +82,6 @@ func (this *MessageTaskDAO) FindEnabledMessageTask(tx *dbs.Tx, id int64) (*Messa
return result.(*MessageTask), err 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 清理 // CleanExpiredMessageTasks 清理
func (this *MessageTaskDAO) CleanExpiredMessageTasks(tx *dbs.Tx, days int) error { func (this *MessageTaskDAO) CleanExpiredMessageTasks(tx *dbs.Tx, days int) error {
if days <= 0 { 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域名 // NSDomain DNS域名
type NSDomain struct { type NSDomain struct {
Id uint64 `field:"id"` // ID Id uint64 `field:"id"` // ID
ClusterId uint32 `field:"clusterId"` // 集群ID ClusterId uint32 `field:"clusterId"` // 集群ID
UserId uint32 `field:"userId"` // 用户ID UserId uint32 `field:"userId"` // 用户ID
IsOn bool `field:"isOn"` // 是否启用 IsOn bool `field:"isOn"` // 是否启用
Name string `field:"name"` // 域名 Name string `field:"name"` // 域名
GroupIds dbs.JSON `field:"groupIds"` // 分组ID GroupIds dbs.JSON `field:"groupIds"` // 分组ID
Tsig dbs.JSON `field:"tsig"` // TSIG配置 Tsig dbs.JSON `field:"tsig"` // TSIG配置
VerifyTXT string `field:"verifyTXT"` // 验证用的TXT VerifyTXT string `field:"verifyTXT"` // 验证用的TXT
VerifyExpiresAt uint64 `field:"verifyExpiresAt"` // 验证TXT过期时间 VerifyExpiresAt uint64 `field:"verifyExpiresAt"` // 验证TXT过期时间
CreatedAt uint64 `field:"createdAt"` // 创建时间 RecordsHealthCheck dbs.JSON `field:"recordsHealthCheck"` // 记录健康检查设置
Version uint64 `field:"version"` // 版本号 CreatedAt uint64 `field:"createdAt"` // 创建时间
Status string `field:"status"` // 状态none|verified Version uint64 `field:"version"` // 版本号
State uint8 `field:"state"` // 状态 Status string `field:"status"` // 状态none|verified
State uint8 `field:"state"` // 状态
} }
type NSDomainOperator struct { type NSDomainOperator struct {
Id any // ID Id any // ID
ClusterId any // 集群ID ClusterId any // 集群ID
UserId any // 用户ID UserId any // 用户ID
IsOn any // 是否启用 IsOn any // 是否启用
Name any // 域名 Name any // 域名
GroupIds any // 分组ID GroupIds any // 分组ID
Tsig any // TSIG配置 Tsig any // TSIG配置
VerifyTXT any // 验证用的TXT VerifyTXT any // 验证用的TXT
VerifyExpiresAt any // 验证TXT过期时间 VerifyExpiresAt any // 验证TXT过期时间
CreatedAt any // 创建时间 RecordsHealthCheck any // 记录健康检查设置
Version any // 版本号 CreatedAt any // 创建时间
Status any // 状态none|verified Version any // 版本号
State any // 状态 Status any // 状态none|verified
State any // 状态
} }
func NewNSDomainOperator() *NSDomainOperator { func NewNSDomainOperator() *NSDomainOperator {

View File

@@ -20,6 +20,10 @@ type NSRecord struct {
Ttl uint32 `field:"ttl"` // TTL Ttl uint32 `field:"ttl"` // TTL
Weight uint32 `field:"weight"` // 权重 Weight uint32 `field:"weight"` // 权重
RouteIds dbs.JSON `field:"routeIds"` // 线路 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"` // 创建时间 CreatedAt uint64 `field:"createdAt"` // 创建时间
Version uint64 `field:"version"` // 版本号 Version uint64 `field:"version"` // 版本号
State uint8 `field:"state"` // 状态 State uint8 `field:"state"` // 状态
@@ -42,6 +46,10 @@ type NSRecordOperator struct {
Ttl any // TTL Ttl any // TTL
Weight any // 权重 Weight any // 权重
RouteIds any // 线路 RouteIds any // 线路
HealthCheck any // 健康检查配置
CountUp any // 连续上线次数
CountDown any // 连续离线次数
IsUp any // 是否在线
CreatedAt any // 创建时间 CreatedAt any // 创建时间
Version any // 版本号 Version any // 版本号
State 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 ( import (
_ "github.com/go-sql-driver/mysql" _ "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 查找所有可用的集群 // FindAllEnableClusters 查找所有可用的集群
func (this *NodeClusterDAO) FindAllEnableClusters(tx *dbs.Tx) (result []*NodeCluster, err error) { func (this *NodeClusterDAO) FindAllEnableClusters(tx *dbs.Tx) (result []*NodeCluster, err error) {
_, err = this.Query(tx). _, 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). State(NodeClusterStateEnabled).
Slice(&result). Slice(&result).
Desc("isPinned"). Desc("isPinned").
@@ -125,7 +126,7 @@ func (this *NodeClusterDAO) FindAllEnableClusterIds(tx *dbs.Tx) (result []int64,
} }
// CreateCluster 创建集群 // 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) uniqueId, err := this.GenUniqueId(tx)
if err != nil { if err != nil {
return 0, err return 0, err
@@ -175,7 +176,7 @@ func (this *NodeClusterDAO) CreateCluster(tx *dbs.Tx, adminId int64, name string
// 全局服务配置 // 全局服务配置
if globalServerConfig == nil { if globalServerConfig == nil {
globalServerConfig = serverconfigs.DefaultGlobalServerConfig() globalServerConfig = serverconfigs.NewGlobalServerConfig()
} }
globalServerConfigJSON, err := json.Marshal(globalServerConfig) globalServerConfigJSON, err := json.Marshal(globalServerConfig)
if err != nil { if err != nil {
@@ -188,6 +189,7 @@ func (this *NodeClusterDAO) CreateCluster(tx *dbs.Tx, adminId int64, name string
op.UniqueId = uniqueId op.UniqueId = uniqueId
op.Secret = secret op.Secret = secret
op.AutoInstallNftables = autoInstallNftables op.AutoInstallNftables = autoInstallNftables
op.AutoSystemTuning = autoSystemTuning
op.State = NodeClusterStateEnabled op.State = NodeClusterStateEnabled
err = this.Save(tx, op) err = this.Save(tx, op)
if err != nil { if err != nil {
@@ -198,7 +200,7 @@ func (this *NodeClusterDAO) CreateCluster(tx *dbs.Tx, adminId int64, name string
} }
// UpdateCluster 修改集群 // 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 { if clusterId <= 0 {
return errors.New("invalid clusterId") return errors.New("invalid clusterId")
} }
@@ -225,6 +227,7 @@ func (this *NodeClusterDAO) UpdateCluster(tx *dbs.Tx, clusterId int64, name stri
op.AutoRemoteStart = autoRemoteStart op.AutoRemoteStart = autoRemoteStart
op.AutoInstallNftables = autoInstallTables op.AutoInstallNftables = autoInstallTables
op.AutoSystemTuning = autoSystemTuning
if sshParams != nil { if sshParams != nil {
sshParamsJSON, err := json.Marshal(sshParams) sshParamsJSON, err := json.Marshal(sshParams)
@@ -262,19 +265,40 @@ func (this *NodeClusterDAO) CountAllEnabledClusters(tx *dbs.Tx, keyword string)
// ListEnabledClusters 列出单页集群 // ListEnabledClusters 列出单页集群
func (this *NodeClusterDAO) ListEnabledClusters(tx *dbs.Tx, keyword string, offset, size int64) (result []*NodeCluster, err error) { 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) State(NodeClusterStateEnabled)
if len(keyword) > 0 { 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)))"). 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)) Param("keyword", dbutils.QuoteLike(keyword))
} }
_, err = query. _, 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). Offset(offset).
Limit(size). Limit(size).
Slice(&result). Slice(&result).
Desc("isPinned"). Desc("isPinned").
DescPk(). DescPk().
FindAll() FindAll()
return return
} }
@@ -625,10 +649,10 @@ func (this *NodeClusterDAO) FindClusterTOAConfig(tx *dbs.Tx, clusterId int64, ca
return nil, err return nil, err
} }
if !IsNotNull([]byte(toa)) { 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) err = json.Unmarshal([]byte(toa), config)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -653,7 +677,7 @@ func (this *NodeClusterDAO) UpdateClusterTOA(tx *dbs.Tx, clusterId int64, toaJSO
if err != nil { if err != nil {
return err return err
} }
return this.NotifyUpdate(tx, clusterId) return this.NotifyTOAUpdate(tx, clusterId)
} }
// CountAllEnabledNodeClustersWithHTTPCachePolicyId 计算使用某个缓存策略的集群数量 // CountAllEnabledNodeClustersWithHTTPCachePolicyId 计算使用某个缓存策略的集群数量
@@ -928,11 +952,12 @@ func (this *NodeClusterDAO) GenUniqueId(tx *dbs.Tx) (string, error) {
// FindLatestNodeClusters 查询最近访问的集群 // FindLatestNodeClusters 查询最近访问的集群
func (this *NodeClusterDAO) FindLatestNodeClusters(tx *dbs.Tx, size int64) (result []*NodeCluster, err error) { func (this *NodeClusterDAO) FindLatestNodeClusters(tx *dbs.Tx, size int64) (result []*NodeCluster, err error) {
itemTable := SharedLatestItemDAO.Table var itemTable = SharedLatestItemDAO.Table
itemType := LatestItemTypeCluster var itemType = LatestItemTypeCluster
_, err = this.Query(tx). _, err = this.Query(tx).
Result(this.Table+".id", this.Table+".name"). Result(this.Table+".id", this.Table+".name").
Join(SharedLatestItemDAO, dbs.QueryJoinRight, this.Table+".id="+itemTable+".itemId AND "+itemTable+".itemType='"+itemType+"'"). 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))"). // 优先一个星期以内的 Asc("CEIL((UNIX_TIMESTAMP() - " + itemTable + ".updatedAt) / (7 * 86400))"). // 优先一个星期以内的
Desc(itemTable + ".count"). Desc(itemTable + ".count").
State(NodeClusterStateEnabled). State(NodeClusterStateEnabled).
@@ -996,7 +1021,7 @@ func (this *NodeClusterDAO) FindClusterBasicInfo(tx *dbs.Tx, clusterId int64, ca
cluster, err := this.Query(tx). cluster, err := this.Query(tx).
Pk(clusterId). Pk(clusterId).
State(NodeClusterStateEnabled). 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() Find()
if err != nil || cluster == nil { if err != nil || cluster == nil {
return nil, err return nil, err
@@ -1077,7 +1102,7 @@ func (this *NodeClusterDAO) UpdateClusterUAMPolicy(tx *dbs.Tx, clusterId int64,
return err return err
} }
return this.NotifyUpdate(tx, clusterId) return this.NotifyUAMUpdate(tx, clusterId)
} }
uamPolicyJSON, err := json.Marshal(uamPolicy) uamPolicyJSON, err := json.Marshal(uamPolicy)
@@ -1092,10 +1117,10 @@ func (this *NodeClusterDAO) UpdateClusterUAMPolicy(tx *dbs.Tx, clusterId int64,
return err return err
} }
return this.NotifyUpdate(tx, clusterId) return this.NotifyUAMUpdate(tx, clusterId)
} }
// FindClusterUAMPolicy 查询设置 // FindClusterUAMPolicy 查询UAM设置
func (this *NodeClusterDAO) FindClusterUAMPolicy(tx *dbs.Tx, clusterId int64, cacheMap *utils.CacheMap) (*nodeconfigs.UAMPolicy, error) { func (this *NodeClusterDAO) FindClusterUAMPolicy(tx *dbs.Tx, clusterId int64, cacheMap *utils.CacheMap) (*nodeconfigs.UAMPolicy, error) {
var cacheKey = this.Table + ":FindClusterUAMPolicy:" + types.String(clusterId) var cacheKey = this.Table + ":FindClusterUAMPolicy:" + types.String(clusterId)
if cacheMap != nil { if cacheMap != nil {
@@ -1113,11 +1138,12 @@ func (this *NodeClusterDAO) FindClusterUAMPolicy(tx *dbs.Tx, clusterId int64, ca
return nil, err return nil, err
} }
var policy = nodeconfigs.NewUAMPolicy()
if IsNull(uamJSON) { if IsNull(uamJSON) {
return nodeconfigs.DefaultUAMPolicy, nil return policy, nil
} }
var policy = &nodeconfigs.UAMPolicy{}
err = json.Unmarshal(uamJSON, policy) err = json.Unmarshal(uamJSON, policy)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -1125,6 +1151,205 @@ func (this *NodeClusterDAO) FindClusterUAMPolicy(tx *dbs.Tx, clusterId int64, ca
return policy, nil 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设置 // FindClusterDDoSProtection 获取集群的DDoS设置
func (this *NodeClusterDAO) FindClusterDDoSProtection(tx *dbs.Tx, clusterId int64) (*ddosconfigs.ProtectionConfig, error) { func (this *NodeClusterDAO) FindClusterDDoSProtection(tx *dbs.Tx, clusterId int64) (*ddosconfigs.ProtectionConfig, error) {
one, err := this.Query(tx). one, err := this.Query(tx).
@@ -1174,7 +1399,7 @@ func (this *NodeClusterDAO) FindClusterGlobalServerConfig(tx *dbs.Tx, clusterId
return nil, err return nil, err
} }
var config = serverconfigs.DefaultGlobalServerConfig() var config = serverconfigs.NewGlobalServerConfig()
if IsNull(configJSON) { if IsNull(configJSON) {
return config, nil return config, nil
} }
@@ -1190,7 +1415,7 @@ func (this *NodeClusterDAO) FindClusterGlobalServerConfig(tx *dbs.Tx, clusterId
// UpdateClusterGlobalServerConfig 修改全局服务配置 // UpdateClusterGlobalServerConfig 修改全局服务配置
func (this *NodeClusterDAO) UpdateClusterGlobalServerConfig(tx *dbs.Tx, clusterId int64, config *serverconfigs.GlobalServerConfig) error { func (this *NodeClusterDAO) UpdateClusterGlobalServerConfig(tx *dbs.Tx, clusterId int64, config *serverconfigs.GlobalServerConfig) error {
if config == nil { if config == nil {
config = serverconfigs.DefaultGlobalServerConfig() config = serverconfigs.NewGlobalServerConfig()
} }
configJSON, err := json.Marshal(config) configJSON, err := json.Marshal(config)
if err != nil { if err != nil {
@@ -1212,12 +1437,33 @@ func (this *NodeClusterDAO) NotifyUpdate(tx *dbs.Tx, clusterId int64) error {
return SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleNode, clusterId, 0, 0, NodeTaskTypeConfigChanged) return SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleNode, clusterId, 0, 0, NodeTaskTypeConfigChanged)
} }
// NotifyUAMUpdate 通知UAM更新
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更新 // NotifyDNSUpdate 通知DNS更新
// TODO 更新新的DNS解析记录的同时需要删除老的DNS解析记录 // TODO 更新新的DNS解析记录的同时需要删除老的DNS解析记录
func (this *NodeClusterDAO) NotifyDNSUpdate(tx *dbs.Tx, clusterId int64) error { func (this *NodeClusterDAO) NotifyDNSUpdate(tx *dbs.Tx, clusterId int64) error {
err := dns.SharedDNSTaskDAO.CreateClusterTask(tx, clusterId, dns.DNSTaskTypeClusterChange) return dns.SharedDNSTaskDAO.CreateClusterTask(tx, clusterId, dns.DNSTaskTypeClusterChange)
if err != nil {
return err
}
return nil
} }

View File

@@ -2,6 +2,50 @@ package models
import "github.com/iwind/TeaGo/dbs" 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 节点集群 // NodeCluster 节点集群
type NodeCluster struct { type NodeCluster struct {
Id uint32 `field:"id"` // ID Id uint32 `field:"id"` // ID
@@ -41,6 +85,10 @@ type NodeCluster struct {
AutoRemoteStart bool `field:"autoRemoteStart"` // 自动远程启动 AutoRemoteStart bool `field:"autoRemoteStart"` // 自动远程启动
AutoInstallNftables bool `field:"autoInstallNftables"` // 自动安装nftables AutoInstallNftables bool `field:"autoInstallNftables"` // 自动安装nftables
IsAD bool `field:"isAD"` // 是否为高防集群 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 { type NodeClusterOperator struct {
@@ -81,6 +129,10 @@ type NodeClusterOperator struct {
AutoRemoteStart any // 自动远程启动 AutoRemoteStart any // 自动远程启动
AutoInstallNftables any // 自动安装nftables AutoInstallNftables any // 自动安装nftables
IsAD any // 是否为高防集群 IsAD any // 是否为高防集群
HttpPages any // 自定义页面设置
Cc any // CC设置
Http3 any // HTTP3设置
AutoSystemTuning any // 是否自动调整系统参数
} }
func NewNodeClusterOperator() *NodeClusterOperator { func NewNodeClusterOperator() *NodeClusterOperator {

View File

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

View File

@@ -18,7 +18,6 @@ import (
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs" "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/ddosconfigs" "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/ddosconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared" "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
"github.com/TeaOSLab/EdgeCommon/pkg/systemconfigs"
_ "github.com/go-sql-driver/mysql" _ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea" "github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs" "github.com/iwind/TeaGo/dbs"
@@ -27,6 +26,7 @@ import (
"github.com/iwind/TeaGo/rands" "github.com/iwind/TeaGo/rands"
"github.com/iwind/TeaGo/types" "github.com/iwind/TeaGo/types"
timeutil "github.com/iwind/TeaGo/utils/time" timeutil "github.com/iwind/TeaGo/utils/time"
"sort"
"strconv" "strconv"
"strings" "strings"
"time" "time"
@@ -295,6 +295,7 @@ func (this *NodeDAO) CountAllEnabledNodes(tx *dbs.Tx) (int64, error) {
func (this *NodeDAO) CountAllEnabledOfflineNodes(tx *dbs.Tx) (int64, error) { func (this *NodeDAO) CountAllEnabledOfflineNodes(tx *dbs.Tx) (int64, error) {
return this.Query(tx). return this.Query(tx).
State(NodeStateEnabled). State(NodeStateEnabled).
Attr("isOn", true).
Where("clusterId IN (SELECT id FROM "+SharedNodeClusterDAO.Table+" WHERE state=:clusterState)"). Where("clusterId IN (SELECT id FROM "+SharedNodeClusterDAO.Table+" WHERE state=:clusterState)").
Param("clusterState", NodeClusterStateEnabled). Param("clusterState", NodeClusterStateEnabled).
Where("(status IS NULL OR NOT JSON_EXTRACT(status, '$.isActive') OR UNIX_TIMESTAMP()-JSON_EXTRACT(status, '$.updatedAt')>60)"). 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 { 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)) Param("keyword", dbutils.QuoteLike(keyword))
} }
@@ -840,7 +841,24 @@ func (this *NodeDAO) UpdateNodeStatus(tx *dbs.Tx, nodeId int64, nodeStatus *node
Set("isActive", true). Set("isActive", true).
Set("status", nodeStatusJSON). Set("status", nodeStatusJSON).
Update() Update()
return err if err != nil {
return err
}
// 自动设置安装状态
isInstalled, err := this.Query(tx).
Pk(nodeId).
Result("isInstalled").
FindBoolCol()
if err != nil {
return err
}
if !isInstalled {
return this.UpdateNodeIsInstalled(tx, nodeId, true)
}
return nil
} }
// FindNodeStatus 获取节点状态 // FindNodeStatus 获取节点状态
@@ -885,7 +903,10 @@ func (this *NodeDAO) UpdateNodeIsInstalled(tx *dbs.Tx, nodeId int64, isInstalled
Set("isInstalled", isInstalled). Set("isInstalled", isInstalled).
Set("installStatus", "null"). // 重置安装状态 Set("installStatus", "null"). // 重置安装状态
Update() Update()
return err if err != nil {
return err
}
return this.NotifyDNSUpdate(tx, nodeId)
} }
// FindNodeInstallStatus 查询节点的安装状态 // FindNodeInstallStatus 查询节点的安装状态
@@ -942,11 +963,16 @@ func (this *NodeDAO) UpdateNodeInstallStatus(tx *dbs.Tx, nodeId int64, status *N
// ComposeNodeConfig 组合配置 // ComposeNodeConfig 组合配置
// TODO 提升运行速度 // TODO 提升运行速度
func (this *NodeDAO) ComposeNodeConfig(tx *dbs.Tx, nodeId int64, cacheMap *utils.CacheMap) (*nodeconfigs.NodeConfig, error) { func (this *NodeDAO) ComposeNodeConfig(tx *dbs.Tx, nodeId int64, dataMap *shared.DataMap, cacheMap *utils.CacheMap) (*nodeconfigs.NodeConfig, error) {
if cacheMap == nil { if cacheMap == nil {
cacheMap = utils.NewCacheMap() cacheMap = utils.NewCacheMap()
} }
// 放入到缓存中,以便于后面继续使用
if dataMap != nil {
cacheMap.Put("DataMap", dataMap)
}
node, err := this.FindEnabledNode(tx, nodeId) node, err := this.FindEnabledNode(tx, nodeId)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -961,6 +987,7 @@ func (this *NodeDAO) ComposeNodeConfig(tx *dbs.Tx, nodeId int64, cacheMap *utils
var config = &nodeconfigs.NodeConfig{ var config = &nodeconfigs.NodeConfig{
Id: int64(node.Id), Id: int64(node.Id),
Edition: teaconst.Edition,
NodeId: node.UniqueId, NodeId: node.UniqueId,
Secret: node.Secret, Secret: node.Secret,
IsOn: node.IsOn, IsOn: node.IsOn,
@@ -973,8 +1000,17 @@ func (this *NodeDAO) ComposeNodeConfig(tx *dbs.Tx, nodeId int64, cacheMap *utils
GroupId: int64(node.GroupId), GroupId: int64(node.GroupId),
EnableIPLists: node.EnableIPLists, EnableIPLists: node.EnableIPLists,
APINodeAddrs: node.DecodeAPINodeAddrs(), APINodeAddrs: node.DecodeAPINodeAddrs(),
DataMap: dataMap,
} }
// 待更新服务ID
updatingServerListId, err := SharedUpdatingServerListDAO.FindLatestId(tx)
if err != nil {
return nil, err
}
config.UpdatingServerListId = updatingServerListId
// API节点IP // API节点IP
apiNodeIPs, err := SharedAPINodeDAO.FindAllEnabledAPIAccessIPs(tx, cacheMap) apiNodeIPs, err := SharedAPINodeDAO.FindAllEnabledAPIAccessIPs(tx, cacheMap)
if err != nil { if err != nil {
@@ -1003,13 +1039,11 @@ func (this *NodeDAO) ComposeNodeConfig(tx *dbs.Tx, nodeId int64, cacheMap *utils
if err != nil { if err != nil {
return nil, err return nil, err
} }
for _, clusterServer := range clusterServers { servers = append(servers, clusterServers...)
servers = append(servers, clusterServer)
}
} }
for _, server := range servers { for _, server := range servers {
serverConfig, err := SharedServerDAO.ComposeServerConfig(tx, server, false, cacheMap, true, false) serverConfig, err := SharedServerDAO.ComposeServerConfig(tx, server, false, dataMap, cacheMap, true, false)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -1023,33 +1057,15 @@ func (this *NodeDAO) ComposeNodeConfig(tx *dbs.Tx, nodeId int64, cacheMap *utils
} }
} }
// 全局设置
// 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 var clusterIndex = 0
config.WebPImagePolicies = map[int64]*nodeconfigs.WebPImagePolicy{} config.WebPImagePolicies = map[int64]*nodeconfigs.WebPImagePolicy{}
config.UAMPolicies = map[int64]*nodeconfigs.UAMPolicy{} 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{} var allowIPMaps = map[string]bool{}
for _, clusterId := range clusterIds { for _, clusterId := range clusterIds {
nodeCluster, err := SharedNodeClusterDAO.FindClusterBasicInfo(tx, clusterId, cacheMap) nodeCluster, err := SharedNodeClusterDAO.FindClusterBasicInfo(tx, clusterId, cacheMap)
@@ -1077,7 +1093,7 @@ func (this *NodeDAO) ComposeNodeConfig(tx *dbs.Tx, nodeId int64, cacheMap *utils
// 防火墙 // 防火墙
var httpFirewallPolicyId = int64(nodeCluster.HttpFirewallPolicyId) var httpFirewallPolicyId = int64(nodeCluster.HttpFirewallPolicyId)
if httpFirewallPolicyId > 0 { if httpFirewallPolicyId > 0 {
firewallPolicy, err := SharedHTTPFirewallPolicyDAO.ComposeFirewallPolicy(tx, httpFirewallPolicyId, cacheMap) firewallPolicy, err := SharedHTTPFirewallPolicyDAO.ComposeFirewallPolicy(tx, httpFirewallPolicyId, true, cacheMap)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -1089,12 +1105,15 @@ func (this *NodeDAO) ComposeNodeConfig(tx *dbs.Tx, nodeId int64, cacheMap *utils
// 缓存策略 // 缓存策略
var httpCachePolicyId = int64(nodeCluster.CachePolicyId) var httpCachePolicyId = int64(nodeCluster.CachePolicyId)
if httpCachePolicyId > 0 { if httpCachePolicyId > 0 {
cachePolicy, err := SharedHTTPCachePolicyDAO.ComposeCachePolicy(tx, httpCachePolicyId, cacheMap) if !lists.ContainsInt64(cachePolicyIds, httpCachePolicyId) {
if err != nil { cachePolicyIds = append(cachePolicyIds, httpCachePolicyId)
return nil, err cachePolicy, err := SharedHTTPCachePolicyDAO.ComposeCachePolicy(tx, httpCachePolicyId, cacheMap)
} if err != nil {
if cachePolicy != nil { return nil, err
config.HTTPCachePolicies = append(config.HTTPCachePolicies, cachePolicy) }
if cachePolicy != nil {
config.HTTPCachePolicies = append(config.HTTPCachePolicies, cachePolicy)
}
} }
} }
@@ -1135,7 +1154,7 @@ func (this *NodeDAO) ComposeNodeConfig(tx *dbs.Tx, nodeId int64, cacheMap *utils
// UAM // UAM
if IsNotNull(nodeCluster.Uam) { if IsNotNull(nodeCluster.Uam) {
var uamPolicy = &nodeconfigs.UAMPolicy{} var uamPolicy = nodeconfigs.NewUAMPolicy()
err = json.Unmarshal(nodeCluster.Uam, uamPolicy) err = json.Unmarshal(nodeCluster.Uam, uamPolicy)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -1143,9 +1162,63 @@ func (this *NodeDAO) ComposeNodeConfig(tx *dbs.Tx, nodeId int64, cacheMap *utils
config.UAMPolicies[clusterId] = uamPolicy 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 // 自动安装nftables
if clusterIndex == 0 { if clusterIndex == 0 {
config.AutoInstallNftables = nodeCluster.AutoInstallNftables config.AutoInstallNftables = nodeCluster.AutoInstallNftables
config.AutoSystemTuning = nodeCluster.AutoSystemTuning
} }
clusterIndex++ clusterIndex++
@@ -1359,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) { func (this *NodeDAO) FindAllEnabledNodesWithGrantId(tx *dbs.Tx, grantId int64) (result []*Node, err error) {
_, err = this.Query(tx). _, err = this.Query(tx).
State(NodeStateEnabled). 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())). Param("grantParam", string(maps.Map{"grantId": grantId}.AsJSON())).
Where("clusterId IN (SELECT id FROM edgeNodeClusters WHERE state=1)"). Where("clusterId IN (SELECT id FROM edgeNodeClusters WHERE state=1)").
Slice(&result). Slice(&result).
@@ -1393,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) { func (this *NodeDAO) CountAllLowerVersionNodesWithClusterId(tx *dbs.Tx, clusterId int64, os string, arch string, version string) (int64, error) {
return this.Query(tx). return this.Query(tx).
State(NodeStateEnabled). State(NodeStateEnabled).
Attr("isOn", true).
Attr("clusterId", clusterId). Attr("clusterId", clusterId).
Where("status IS NOT NULL"). Where("status IS NOT NULL").
Where("JSON_EXTRACT(status, '$.os')=:os"). Where("JSON_EXTRACT(status, '$.os')=:os").
@@ -1426,6 +1500,7 @@ func (this *NodeDAO) FindAllLowerVersionNodesWithClusterId(tx *dbs.Tx, clusterId
func (this *NodeDAO) CountAllLowerVersionNodes(tx *dbs.Tx, version string) (int64, error) { func (this *NodeDAO) CountAllLowerVersionNodes(tx *dbs.Tx, version string) (int64, error) {
return this.Query(tx). return this.Query(tx).
State(NodeStateEnabled). State(NodeStateEnabled).
Attr("isOn", true).
Where("clusterId IN (SELECT id FROM "+SharedNodeClusterDAO.Table+" WHERE state=1)"). Where("clusterId IN (SELECT id FROM "+SharedNodeClusterDAO.Table+" WHERE state=1)").
Where("status IS NOT NULL"). Where("status IS NOT NULL").
Where("(JSON_EXTRACT(status, '$.buildVersionCode') IS NULL OR JSON_EXTRACT(status, '$.buildVersionCode')<:version)"). Where("(JSON_EXTRACT(status, '$.buildVersionCode') IS NULL OR JSON_EXTRACT(status, '$.buildVersionCode')<:version)").
@@ -1495,7 +1570,7 @@ func (this *NodeDAO) UpdateNodeRegionId(tx *dbs.Tx, nodeId int64, regionId int64
} }
// FindAllEnabledNodesDNSWithClusterId 获取一个集群的节点DNS信息 // FindAllEnabledNodesDNSWithClusterId 获取一个集群的节点DNS信息
func (this *NodeDAO) FindAllEnabledNodesDNSWithClusterId(tx *dbs.Tx, clusterId int64, includeSecondaryNodes bool, includingLnNodes bool) (result []*Node, err error) { func (this *NodeDAO) FindAllEnabledNodesDNSWithClusterId(tx *dbs.Tx, clusterId int64, includeSecondaryNodes bool, includingLnNodes bool, isInstalled bool) (result []*Node, err error) {
if clusterId <= 0 { if clusterId <= 0 {
return nil, nil return nil, nil
} }
@@ -1514,7 +1589,8 @@ func (this *NodeDAO) FindAllEnabledNodesDNSWithClusterId(tx *dbs.Tx, clusterId i
State(NodeStateEnabled). State(NodeStateEnabled).
Attr("isOn", true). Attr("isOn", true).
Attr("isUp", true). Attr("isUp", true).
Result("id", "name", "dnsRoutes", "isOn"). Attr("isInstalled", isInstalled).
Result("id", "name", "dnsRoutes", "isOn", "offlineDay", "actionStatus", "isBackupForCluster", "isBackupForGroup", "backupIPs", "clusterId", "groupId").
DescPk(). DescPk().
Slice(&result). Slice(&result).
FindAll() FindAll()
@@ -1539,7 +1615,7 @@ func (this *NodeDAO) FindEnabledNodeDNS(tx *dbs.Tx, nodeId int64) (*Node, error)
one, err := this.Query(tx). one, err := this.Query(tx).
State(NodeStateEnabled). State(NodeStateEnabled).
Pk(nodeId). Pk(nodeId).
Result("id", "name", "dnsRoutes", "clusterId", "isOn"). Result("id", "name", "dnsRoutes", "clusterId", "isOn", "offlineDay", "isBackupForCluster", "isBackupForGroup", "actionStatus").
Find() Find()
if one == nil { if one == nil {
return nil, err return nil, err
@@ -2023,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))) var secretHash = fmt.Sprintf("%x", sha256.Sum256([]byte(node.UniqueId+"@"+node.Secret)))
for _, clusterId := range node.AllClusterIds() { for _, clusterId := range node.AllClusterIds() {
parentNodeConfigs, _ := result[clusterId] var parentNodeConfigs = result[clusterId]
parentNodeConfigs = append(parentNodeConfigs, &nodeconfigs.ParentNodeConfig{ parentNodeConfigs = append(parentNodeConfigs, &nodeconfigs.ParentNodeConfig{
Id: int64(node.Id), Id: int64(node.Id),
Addrs: addrStrings, Addrs: addrStrings,
SecretHash: secretHash, SecretHash: secretHash,
}) })
// 排序
sort.Slice(parentNodeConfigs, func(i, j int) bool {
return parentNodeConfigs[i].Id < parentNodeConfigs[j].Id
})
result[clusterId] = parentNodeConfigs 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 { func (this *NodeDAO) composeExtConfig(tx *dbs.Tx, config *nodeconfigs.NodeConfig, clusterIds []int64, cacheMap *utils.CacheMap) error {
return nil return nil
} }
// CheckNodeIPAddresses 检查节点IP地址
func (this *NodeDAO) CheckNodeIPAddresses(tx *dbs.Tx, node *Node) (shouldSkip bool, shouldOverwrite bool, ipAddressStrings []string, err error) {
return
}

View File

@@ -4,9 +4,11 @@
package models_test package models_test
import ( import (
"encoding/json"
teaconst "github.com/TeaOSLab/EdgeAPI/internal/const" teaconst "github.com/TeaOSLab/EdgeAPI/internal/const"
"github.com/TeaOSLab/EdgeAPI/internal/db/models" "github.com/TeaOSLab/EdgeAPI/internal/db/models"
"github.com/TeaOSLab/EdgeAPI/internal/utils" "github.com/TeaOSLab/EdgeAPI/internal/utils"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
_ "github.com/go-sql-driver/mysql" _ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/dbs" "github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/logs" "github.com/iwind/TeaGo/logs"
@@ -47,21 +49,40 @@ func TestNodeDAO_FindEnabledNodeClusterIds(t *testing.T) {
func TestNodeDAO_ComposeNodeConfig(t *testing.T) { func TestNodeDAO_ComposeNodeConfig(t *testing.T) {
dbs.NotifyReady() dbs.NotifyReady()
before := time.Now() var before = time.Now()
defer func() {
t.Log(time.Since(before).Seconds()*1000, "ms")
}()
var tx *dbs.Tx var tx *dbs.Tx
var cacheMap = utils.NewCacheMap() var cacheMap = utils.NewCacheMap()
nodeConfig, err := models.SharedNodeDAO.ComposeNodeConfig(tx, 48, cacheMap) var dataMap = shared.NewDataMap()
//var dataMap *nodeconfigs.DataMap
nodeConfig, err := models.SharedNodeDAO.ComposeNodeConfig(tx, 48, dataMap, cacheMap)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
nodeConfig.DataMap = dataMap
t.Log(len(nodeConfig.Servers), "servers") t.Log(len(nodeConfig.Servers), "servers")
t.Log(cacheMap.Len(), "items") t.Log(cacheMap.Len(), "items")
// old: 77ms => new: 56ms t.Log(time.Since(before).Seconds()*1000, "ms")
data, err := json.Marshal(nodeConfig)
if err != nil {
t.Fatal(err)
}
t.Log(len(data), "bytes")
{
nodeConfig, err = models.SharedNodeDAO.ComposeNodeConfig(tx, 148, dataMap, cacheMap)
if err != nil {
t.Fatal(err)
}
t.Log(len(nodeConfig.DataMap.Map), "items in dataMap")
data, err = json.Marshal(nodeConfig)
if err != nil {
t.Fatal(err)
}
t.Log(len(data), "bytes")
}
} }
func TestNodeDAO_ComposeNodeConfig_ParentNodes(t *testing.T) { func TestNodeDAO_ComposeNodeConfig_ParentNodes(t *testing.T) {
@@ -71,7 +92,7 @@ func TestNodeDAO_ComposeNodeConfig_ParentNodes(t *testing.T) {
var tx *dbs.Tx var tx *dbs.Tx
var cacheMap = utils.NewCacheMap() var cacheMap = utils.NewCacheMap()
nodeConfig, err := models.SharedNodeDAO.ComposeNodeConfig(tx, 48, cacheMap) nodeConfig, err := models.SharedNodeDAO.ComposeNodeConfig(tx, 48, nil, cacheMap)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }

View File

@@ -307,7 +307,7 @@ func (this *NodeIPAddressDAO) FindFirstNodeAccessIPAddressId(tx *dbs.Tx, nodeId
FindInt64Col(0) FindInt64Col(0)
} }
// FindNodeAccessAndUpIPAddresses 查找节点所有的可访问的IP地址 // FindNodeAccessAndUpIPAddresses 查找节点所有的可访问且在线的IP地址
func (this *NodeIPAddressDAO) FindNodeAccessAndUpIPAddresses(tx *dbs.Tx, nodeId int64, role nodeconfigs.NodeRole) (result []*NodeIPAddress, err error) { func (this *NodeIPAddressDAO) FindNodeAccessAndUpIPAddresses(tx *dbs.Tx, nodeId int64, role nodeconfigs.NodeRole) (result []*NodeIPAddress, err error) {
if len(role) == 0 { if len(role) == 0 {
role = nodeconfigs.NodeRoleNode role = nodeconfigs.NodeRoleNode
@@ -326,6 +326,24 @@ func (this *NodeIPAddressDAO) FindNodeAccessAndUpIPAddresses(tx *dbs.Tx, nodeId
return 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地址数量 // CountAllEnabledIPAddresses 计算IP地址数量
// TODO 目前支持边缘节点将来支持NS节点 // TODO 目前支持边缘节点将来支持NS节点
func (this *NodeIPAddressDAO) CountAllEnabledIPAddresses(tx *dbs.Tx, role string, nodeClusterId int64, upState configutils.BoolState, keyword string) (int64, error) { 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解析器 DnsResolver dbs.JSON `field:"dnsResolver"` // DNS解析器
EnableIPLists bool `field:"enableIPLists"` // 启用IP名单 EnableIPLists bool `field:"enableIPLists"` // 启用IP名单
ApiNodeAddrs dbs.JSON `field:"apiNodeAddrs"` // API节点地址 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 { type NodeOperator struct {
@@ -85,6 +91,12 @@ type NodeOperator struct {
DnsResolver any // DNS解析器 DnsResolver any // DNS解析器
EnableIPLists any // 启用IP名单 EnableIPLists any // 启用IP名单
ApiNodeAddrs any // API节点地址 ApiNodeAddrs any // API节点地址
OfflineDay any // 下线日期YYYYMMDD
OfflineIsNotified any // 下线是否已通知
IsBackupForCluster any // 是否为集群备用节点
IsBackupForGroup any // 是否为分组备用节点
BackupIPs any // 备用IP
ActionStatus any // 当前动作配置
} }
func NewNodeOperator() *NodeOperator { func NewNodeOperator() *NodeOperator {

View File

@@ -7,6 +7,7 @@ import (
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs" "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/ddosconfigs" "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/ddosconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared" "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
timeutil "github.com/iwind/TeaGo/utils/time"
"sort" "sort"
"time" "time"
) )
@@ -16,7 +17,7 @@ func (this *Node) DecodeInstallStatus() (*NodeInstallStatus, error) {
if len(this.InstallStatus) == 0 { if len(this.InstallStatus) == 0 {
return NewNodeInstallStatus(), nil return NewNodeInstallStatus(), nil
} }
status := &NodeInstallStatus{} var status = &NodeInstallStatus{}
err := json.Unmarshal(this.InstallStatus, status) err := json.Unmarshal(this.InstallStatus, status)
if err != nil { if err != nil {
return NewNodeInstallStatus(), err return NewNodeInstallStatus(), err
@@ -37,7 +38,7 @@ func (this *Node) DecodeStatus() (*nodeconfigs.NodeStatus, error) {
if len(this.Status) == 0 { if len(this.Status) == 0 {
return nil, nil return nil, nil
} }
status := &nodeconfigs.NodeStatus{} var status = &nodeconfigs.NodeStatus{}
err := json.Unmarshal(this.Status, status) err := json.Unmarshal(this.Status, status)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -47,7 +48,7 @@ func (this *Node) DecodeStatus() (*nodeconfigs.NodeStatus, error) {
// DNSRouteCodes 所有的DNS线路 // DNSRouteCodes 所有的DNS线路
func (this *Node) DNSRouteCodes() map[int64][]string { 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 { if len(this.DnsRoutes) == 0 {
return routes return routes
} }
@@ -61,7 +62,7 @@ func (this *Node) DNSRouteCodes() map[int64][]string {
// DNSRouteCodesForDomainId DNS线路 // DNSRouteCodesForDomainId DNS线路
func (this *Node) DNSRouteCodesForDomainId(dnsDomainId int64) ([]string, error) { 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 { if len(this.DnsRoutes) == 0 {
return nil, nil return nil, nil
} }
@@ -69,8 +70,7 @@ func (this *Node) DNSRouteCodesForDomainId(dnsDomainId int64) ([]string, error)
if err != nil { if err != nil {
return nil, err return nil, err
} }
domainRoutes, _ := routes[dnsDomainId] var domainRoutes = routes[dnsDomainId]
if len(domainRoutes) > 0 { if len(domainRoutes) > 0 {
sort.Strings(domainRoutes) sort.Strings(domainRoutes)
} }
@@ -80,7 +80,7 @@ func (this *Node) DNSRouteCodesForDomainId(dnsDomainId int64) ([]string, error)
// DecodeConnectedAPINodeIds 连接的API // DecodeConnectedAPINodeIds 连接的API
func (this *Node) DecodeConnectedAPINodeIds() ([]int64, error) { func (this *Node) DecodeConnectedAPINodeIds() ([]int64, error) {
apiNodeIds := []int64{} var apiNodeIds = []int64{}
if IsNotNull(this.ConnectedAPINodes) { if IsNotNull(this.ConnectedAPINodes) {
err := json.Unmarshal(this.ConnectedAPINodes, &apiNodeIds) err := json.Unmarshal(this.ConnectedAPINodes, &apiNodeIds)
if err != nil { if err != nil {
@@ -214,3 +214,8 @@ func (this *Node) DecodeAPINodeAddrs() []*serverconfigs.NetworkAddressConfig {
} }
return result 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/dbs"
"github.com/iwind/TeaGo/maps" "github.com/iwind/TeaGo/maps"
"github.com/iwind/TeaGo/types" "github.com/iwind/TeaGo/types"
"strings"
"time" "time"
) )
@@ -19,11 +20,18 @@ const (
NodeTaskTypeConfigChanged NodeTaskType = "configChanged" // 节点整体配置变化 NodeTaskTypeConfigChanged NodeTaskType = "configChanged" // 节点整体配置变化
NodeTaskTypeDDosProtectionChanged NodeTaskType = "ddosProtectionChanged" // 节点DDoS配置变更 NodeTaskTypeDDosProtectionChanged NodeTaskType = "ddosProtectionChanged" // 节点DDoS配置变更
NodeTaskTypeGlobalServerConfigChanged NodeTaskType = "globalServerConfigChanged" // 全局服务设置变化 NodeTaskTypeGlobalServerConfigChanged NodeTaskType = "globalServerConfigChanged" // 全局服务设置变化
NodeTaskTypeIPListDeleted NodeTaskType = "ipListDeleted" // IPList被删除
NodeTaskTypeIPItemChanged NodeTaskType = "ipItemChanged" // IP条目变更 NodeTaskTypeIPItemChanged NodeTaskType = "ipItemChanged" // IP条目变更
NodeTaskTypeNodeVersionChanged NodeTaskType = "nodeVersionChanged" // 节点版本变化 NodeTaskTypeNodeVersionChanged NodeTaskType = "nodeVersionChanged" // 节点版本变化
NodeTaskTypeScriptsChanged NodeTaskType = "scriptsChanged" // 脚本配置变化 NodeTaskTypeScriptsChanged NodeTaskType = "scriptsChanged" // 脚本配置变化
NodeTaskTypeNodeLevelChanged NodeTaskType = "nodeLevelChanged" // 节点级别变化 NodeTaskTypeNodeLevelChanged NodeTaskType = "nodeLevelChanged" // 节点级别变化
NodeTaskTypeUserServersStateChanged NodeTaskType = "userServersStateChanged" // 用户服务状态变化 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相关 // NS相关
@@ -228,6 +236,12 @@ func (this *NodeTaskDAO) DeleteNodeTasks(tx *dbs.Tx, role string, nodeId int64)
return err return err
} }
// DeleteAllNodeTasks 删除所有节点相关任务
func (this *NodeTaskDAO) DeleteAllNodeTasks(tx *dbs.Tx) error {
return this.Query(tx).
DeleteQuickly()
}
// FindDoingNodeTasks 查询一个节点的所有任务 // FindDoingNodeTasks 查询一个节点的所有任务
func (this *NodeTaskDAO) FindDoingNodeTasks(tx *dbs.Tx, role string, nodeId int64, version int64) (result []*NodeTask, err error) { func (this *NodeTaskDAO) FindDoingNodeTasks(tx *dbs.Tx, role string, nodeId int64, version int64) (result []*NodeTask, err error) {
if nodeId <= 0 { if nodeId <= 0 {
@@ -236,6 +250,7 @@ func (this *NodeTaskDAO) FindDoingNodeTasks(tx *dbs.Tx, role string, nodeId int6
var query = this.Query(tx). var query = this.Query(tx).
Attr("role", role). Attr("role", role).
Attr("nodeId", nodeId). Attr("nodeId", nodeId).
UseIndex("nodeId").
Asc("version") Asc("version")
if version > 0 { if version > 0 {
query.Lt("LENGTH(version)", 19) // 兼容以往版本 query.Lt("LENGTH(version)", 19) // 兼容以往版本
@@ -252,6 +267,23 @@ func (this *NodeTaskDAO) FindDoingNodeTasks(tx *dbs.Tx, role string, nodeId int6
// UpdateNodeTaskDone 修改节点任务的完成状态 // UpdateNodeTaskDone 修改节点任务的完成状态
func (this *NodeTaskDAO) UpdateNodeTaskDone(tx *dbs.Tx, taskId int64, isOk bool, errorMessage string) error { 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). var query = this.Query(tx).
Pk(taskId) Pk(taskId)
if !isOk { if !isOk {
@@ -261,8 +293,9 @@ func (this *NodeTaskDAO) UpdateNodeTaskDone(tx *dbs.Tx, taskId int64, isOk bool,
} }
query.Set("version", version) query.Set("version", version)
} }
_, err := query. _, err := query.
Set("isDone", 1). Set("isDone", true).
Set("isOk", isOk). Set("isOk", isOk).
Set("error", errorMessage). Set("error", errorMessage).
Update() Update()
@@ -294,8 +327,8 @@ func (this *NodeTaskDAO) FindAllDoingNodeTasksWithClusterId(tx *dbs.Tx, role str
Gt("nodeId", 0). Gt("nodeId", 0).
Where("(isDone=0 OR (isDone=1 AND isOk=0))"). Where("(isDone=0 OR (isDone=1 AND isOk=0))").
Desc("isDone"). Desc("isDone").
Asc().
Asc("nodeId"). Asc("nodeId").
AscPk().
Slice(&result). Slice(&result).
FindAll() FindAll()
return return

View File

@@ -1,17 +1,19 @@
package models package models_test
import ( import (
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs" "github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
_ "github.com/go-sql-driver/mysql" _ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/dbs" "github.com/iwind/TeaGo/dbs"
"testing" "testing"
"time"
) )
func TestNodeTaskDAO_CreateNodeTask(t *testing.T) { func TestNodeTaskDAO_CreateNodeTask(t *testing.T) {
dbs.NotifyReady() dbs.NotifyReady()
var tx *dbs.Tx var tx *dbs.Tx
err := SharedNodeTaskDAO.CreateNodeTask(tx, nodeconfigs.NodeRoleNode, 1, 2, 0, 0, NodeTaskTypeConfigChanged) err := models.SharedNodeTaskDAO.CreateNodeTask(tx, nodeconfigs.NodeRoleNode, 1, 2, 0, 0, models.NodeTaskTypeConfigChanged)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -22,7 +24,7 @@ func TestNodeTaskDAO_CreateClusterTask(t *testing.T) {
dbs.NotifyReady() dbs.NotifyReady()
var tx *dbs.Tx var tx *dbs.Tx
err := SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleNode, 1, 0, 0, NodeTaskTypeConfigChanged) err := models.SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleNode, 1, 0, 0, models.NodeTaskTypeConfigChanged)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -33,9 +35,31 @@ func TestNodeTaskDAO_ExtractClusterTask(t *testing.T) {
dbs.NotifyReady() dbs.NotifyReady()
var tx *dbs.Tx var tx *dbs.Tx
err := SharedNodeTaskDAO.ExtractNodeClusterTask(tx, 1, 0, 0, NodeTaskTypeConfigChanged) err := models.SharedNodeTaskDAO.ExtractNodeClusterTask(tx, 1, 0, 0, models.NodeTaskTypeConfigChanged)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
t.Log("ok") t.Log("ok")
} }
func TestNodeTaskDAO_FindDoingNodeTasks(t *testing.T) {
var tx *dbs.Tx
var dao = models.NewNodeTaskDAO()
var before = time.Now()
defer func() {
t.Log(time.Since(before).Seconds()*1000, "ms")
}()
_, err := dao.FindDoingNodeTasks(tx, "node", 48, 0)
if err != nil {
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 ( import (
"github.com/TeaOSLab/EdgeAPI/internal/errors" "github.com/TeaOSLab/EdgeAPI/internal/errors"
@@ -22,7 +22,7 @@ func init() {
var ticker = time.NewTicker(time.Duration(rands.Int(24, 48)) * time.Hour) var ticker = time.NewTicker(time.Duration(rands.Int(24, 48)) * time.Hour)
goman.New(func() { goman.New(func() {
for range ticker.C { for range ticker.C {
err := SharedNodeTrafficDailyStatDAO.Clean(nil, 30) // 只保留N天 err := SharedNodeTrafficDailyStatDAO.CleanDefaultDays(nil, 32) // 只保留N天
if err != nil { if err != nil {
remotelogs.Error("NodeTrafficDailyStatDAO", "clean expired data failed: "+err.Error()) 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 { if err != nil {
return err return err
} }
return nil
// 触发钩子
return this.increaseDailyStatHook(tx, role, nodeId)
} }
// FindDailyStats 获取日期之间统计 // FindDailyStats 获取日期之间统计
@@ -132,11 +134,27 @@ func (this *NodeTrafficDailyStatDAO) SumDailyStat(tx *dbs.Tx, role string, nodeI
return one.(*NodeTrafficDailyStat), nil return one.(*NodeTrafficDailyStat), nil
} }
// Clean 清理历史数据 // CleanDays 清理历史数据
func (this *NodeTrafficDailyStatDAO) Clean(tx *dbs.Tx, days int) error { func (this *NodeTrafficDailyStatDAO) CleanDays(tx *dbs.Tx, days int) error {
var day = timeutil.Format("Ymd", time.Now().AddDate(0, 0, -days)) var day = timeutil.Format("Ymd", time.Now().AddDate(0, 0, -days))
_, err := this.Query(tx). _, err := this.Query(tx).
Lt("day", day). Lt("day", day).
Delete() Delete()
return err 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 ( import (
_ "github.com/go-sql-driver/mysql" _ "github.com/go-sql-driver/mysql"

View File

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

View File

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

View File

@@ -37,11 +37,15 @@ func init() {
// CreateValue 创建值 // CreateValue 创建值
func (this *NodeValueDAO) CreateValue(tx *dbs.Tx, clusterId int64, role nodeconfigs.NodeRole, nodeId int64, item string, valueJSON []byte, createdAt int64) error { 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 day = timeutil.FormatTime("Ymd", createdAt)
var hour = timeutil.FormatTime("YmdH", createdAt) var hour = timeutil.FormatTime("YmdH", createdAt)
var minute = timeutil.FormatTime("YmdHi", createdAt) var minute = timeutil.FormatTime("YmdHi", createdAt)
return this.Query(tx). err := this.Query(tx).
InsertOrUpdateQuickly(maps.Map{ InsertOrUpdateQuickly(maps.Map{
"clusterId": clusterId, "clusterId": clusterId,
"role": role, "role": role,
@@ -55,6 +59,17 @@ func (this *NodeValueDAO) CreateValue(tx *dbs.Tx, clusterId int64, role nodeconf
}, maps.Map{ }, maps.Map{
"value": valueJSON, "value": valueJSON,
}) })
if err != nil {
return err
}
// 触发钩子
err = this.nodeValueHook(tx, role, nodeId, item, valueJSON)
if err != nil {
return err
}
return nil
} }
// Clean 清除数据 // Clean 清除数据
@@ -324,7 +339,7 @@ func (this *NodeValueDAO) SumNodeClusterValues(tx *dbs.Tx, role string, clusterI
// FindLatestNodeValue 获取最近一条数据 // FindLatestNodeValue 获取最近一条数据
func (this *NodeValueDAO) FindLatestNodeValue(tx *dbs.Tx, role string, nodeId int64, item string) (*NodeValue, error) { 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). one, err := this.Query(tx).
Attr("role", role). 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设置 Tcp dbs.JSON `field:"tcp"` // TCP设置
Tls dbs.JSON `field:"tls"` // TLS设置 Tls dbs.JSON `field:"tls"` // TLS设置
Udp dbs.JSON `field:"udp"` // UDP设置 Udp dbs.JSON `field:"udp"` // UDP设置
Doh dbs.JSON `field:"doh"` // DoH设置
DdosProtection dbs.JSON `field:"ddosProtection"` // DDoS防护设置 DdosProtection dbs.JSON `field:"ddosProtection"` // DDoS防护设置
Hosts dbs.JSON `field:"hosts"` // DNS主机地址 Hosts dbs.JSON `field:"hosts"` // DNS主机地址
Soa dbs.JSON `field:"soa"` // SOA配置 Soa dbs.JSON `field:"soa"` // SOA配置
@@ -24,6 +25,7 @@ type NSCluster struct {
SoaSerial uint64 `field:"soaSerial"` // SOA序列号 SoaSerial uint64 `field:"soaSerial"` // SOA序列号
Email string `field:"email"` // 管理员邮箱 Email string `field:"email"` // 管理员邮箱
DetectAgents bool `field:"detectAgents"` // 是否监测Agents DetectAgents bool `field:"detectAgents"` // 是否监测Agents
CheckingPorts bool `field:"checkingPorts"` // 自动检测端口
} }
type NSClusterOperator struct { type NSClusterOperator struct {
@@ -38,6 +40,7 @@ type NSClusterOperator struct {
Tcp any // TCP设置 Tcp any // TCP设置
Tls any // TLS设置 Tls any // TLS设置
Udp any // UDP设置 Udp any // UDP设置
Doh any // DoH设置
DdosProtection any // DDoS防护设置 DdosProtection any // DDoS防护设置
Hosts any // DNS主机地址 Hosts any // DNS主机地址
Soa any // SOA配置 Soa any // SOA配置
@@ -47,6 +50,7 @@ type NSClusterOperator struct {
SoaSerial any // SOA序列号 SoaSerial any // SOA序列号
Email any // 管理员邮箱 Email any // 管理员邮箱
DetectAgents any // 是否监测Agents DetectAgents any // 是否监测Agents
CheckingPorts any // 自动检测端口
} }
func NewNSClusterOperator() *NSClusterOperator { func NewNSClusterOperator() *NSClusterOperator {

View File

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

View File

@@ -5,6 +5,7 @@ import (
"errors" "errors"
"github.com/TeaOSLab/EdgeAPI/internal/utils" "github.com/TeaOSLab/EdgeAPI/internal/utils"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs" "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/shared"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/sslconfigs" "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/sslconfigs"
_ "github.com/go-sql-driver/mysql" _ "github.com/go-sql-driver/mysql"
@@ -91,7 +92,8 @@ func (this *OriginDAO) CreateOrigin(tx *dbs.Tx,
adminId int64, adminId int64,
userId int64, userId int64,
name string, name string,
addrJSON string, addrJSON []byte,
ossConfig *ossconfigs.OSSConfig,
description string, description string,
weight int32, isOn bool, weight int32, isOn bool,
connTimeout *shared.TimeDuration, connTimeout *shared.TimeDuration,
@@ -102,7 +104,8 @@ func (this *OriginDAO) CreateOrigin(tx *dbs.Tx,
certRef *sslconfigs.SSLCertRef, certRef *sslconfigs.SSLCertRef,
domains []string, domains []string,
host string, host string,
followPort bool) (originId int64, err error) { followPort bool,
http2Enabled bool) (originId int64, err error) {
var op = NewOriginOperator() var op = NewOriginOperator()
op.AdminId = adminId op.AdminId = adminId
op.UserId = userId op.UserId = userId
@@ -141,7 +144,18 @@ func (this *OriginDAO) CreateOrigin(tx *dbs.Tx,
op.MaxIdleConns = 0 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 op.Description = description
if weight < 0 { if weight < 0 {
weight = 0 weight = 0
@@ -169,6 +183,7 @@ func (this *OriginDAO) CreateOrigin(tx *dbs.Tx,
op.Host = host op.Host = host
op.FollowPort = followPort op.FollowPort = followPort
op.Http2Enabled = http2Enabled
op.State = OriginStateEnabled op.State = OriginStateEnabled
err = this.Save(tx, op) err = this.Save(tx, op)
@@ -182,7 +197,8 @@ func (this *OriginDAO) CreateOrigin(tx *dbs.Tx,
func (this *OriginDAO) UpdateOrigin(tx *dbs.Tx, func (this *OriginDAO) UpdateOrigin(tx *dbs.Tx,
originId int64, originId int64,
name string, name string,
addrJSON string, addrJSON []byte,
ossConfig *ossconfigs.OSSConfig,
description string, description string,
weight int32, weight int32,
isOn bool, isOn bool,
@@ -194,14 +210,25 @@ func (this *OriginDAO) UpdateOrigin(tx *dbs.Tx,
certRef *sslconfigs.SSLCertRef, certRef *sslconfigs.SSLCertRef,
domains []string, domains []string,
host string, host string,
followPort bool) error { followPort bool,
http2Enabled bool) error {
if originId <= 0 { if originId <= 0 {
return errors.New("invalid originId") return errors.New("invalid originId")
} }
var op = NewOriginOperator() var op = NewOriginOperator()
op.Id = originId op.Id = originId
op.Name = name op.Name = name
op.Addr = addrJSON op.Addr = addrJSON
if ossConfig != nil {
ossConfigJSON, err := json.Marshal(ossConfig)
if err != nil {
return err
}
op.Oss = ossConfigJSON
}
op.Description = description op.Description = description
if weight < 0 { if weight < 0 {
weight = 0 weight = 0
@@ -266,6 +293,7 @@ func (this *OriginDAO) UpdateOrigin(tx *dbs.Tx,
op.Host = host op.Host = host
op.FollowPort = followPort op.FollowPort = followPort
op.Http2Enabled = http2Enabled
err := this.Save(tx, op) err := this.Save(tx, op)
if err != nil { if err != nil {
@@ -275,8 +303,67 @@ func (this *OriginDAO) UpdateOrigin(tx *dbs.Tx,
return this.NotifyUpdate(tx, originId) return this.NotifyUpdate(tx, originId)
} }
// CloneOrigin 复制源站
func (this *OriginDAO) CloneOrigin(tx *dbs.Tx, fromOriginId int64) (newOriginId int64, err error) {
if fromOriginId <= 0 {
return
}
originOne, err := this.Find(tx, fromOriginId)
if err != nil || originOne == nil {
return
}
var origin = originOne.(*Origin)
var op = NewOriginOperator()
op.IsOn = origin.IsOn
op.Name = origin.Name
op.Version = origin.Version
if IsNotNull(origin.Addr) {
op.Addr = origin.Addr
}
op.Description = origin.Description
op.Code = origin.Code
op.Weight = origin.Weight
if IsNotNull(origin.ConnTimeout) {
op.ConnTimeout = origin.ConnTimeout
}
if IsNotNull(origin.ReadTimeout) {
op.ReadTimeout = origin.ReadTimeout
}
if IsNotNull(origin.IdleTimeout) {
op.IdleTimeout = origin.IdleTimeout
}
op.MaxFails = origin.MaxFails
op.MaxConns = origin.MaxConns
op.MaxIdleConns = origin.MaxIdleConns
op.HttpRequestURI = origin.HttpRequestURI
if IsNotNull(origin.HttpRequestHeader) {
op.HttpRequestHeader = origin.HttpRequestHeader
}
if IsNotNull(origin.HttpResponseHeader) {
op.HttpResponseHeader = origin.HttpResponseHeader
}
op.Host = origin.Host
if IsNotNull(origin.HealthCheck) {
op.HealthCheck = origin.HealthCheck
}
if IsNotNull(origin.Cert) {
// TODO 需要Clone证书
op.Cert = origin.Cert
}
if IsNotNull(origin.Ftp) {
op.Ftp = origin.Ftp
}
if IsNotNull(origin.Domains) {
op.Domains = origin.Domains
}
op.FollowPort = origin.FollowPort
op.Http2Enabled = origin.Http2Enabled
op.State = origin.State
return this.SaveInt64(tx, op)
}
// ComposeOriginConfig 将源站信息转换为配置 // ComposeOriginConfig 将源站信息转换为配置
func (this *OriginDAO) ComposeOriginConfig(tx *dbs.Tx, originId int64, cacheMap *utils.CacheMap) (*serverconfigs.OriginConfig, error) { func (this *OriginDAO) ComposeOriginConfig(tx *dbs.Tx, originId int64, dataMap *shared.DataMap, cacheMap *utils.CacheMap) (*serverconfigs.OriginConfig, error) {
if cacheMap == nil { if cacheMap == nil {
cacheMap = utils.NewCacheMap() cacheMap = utils.NewCacheMap()
} }
@@ -309,8 +396,10 @@ func (this *OriginDAO) ComposeOriginConfig(tx *dbs.Tx, originId int64, cacheMap
RequestHost: origin.Host, RequestHost: origin.Host,
Domains: origin.DecodeDomains(), Domains: origin.DecodeDomains(),
FollowPort: origin.FollowPort, FollowPort: origin.FollowPort,
HTTP2Enabled: origin.Http2Enabled,
} }
// addr
if IsNotNull(origin.Addr) { if IsNotNull(origin.Addr) {
var addr = &serverconfigs.NetworkAddressConfig{} var addr = &serverconfigs.NetworkAddressConfig{}
err = json.Unmarshal(origin.Addr, addr) err = json.Unmarshal(origin.Addr, addr)
@@ -320,6 +409,16 @@ func (this *OriginDAO) ComposeOriginConfig(tx *dbs.Tx, originId int64, cacheMap
config.Addr = addr 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) { if IsNotNull(origin.ConnTimeout) {
var connTimeout = &shared.TimeDuration{} var connTimeout = &shared.TimeDuration{}
err = json.Unmarshal(origin.ConnTimeout, &connTimeout) err = json.Unmarshal(origin.ConnTimeout, &connTimeout)
@@ -403,7 +502,7 @@ func (this *OriginDAO) ComposeOriginConfig(tx *dbs.Tx, originId int64, cacheMap
} }
config.CertRef = ref config.CertRef = ref
if ref.CertId > 0 { if ref.CertId > 0 {
certConfig, err := SharedSSLCertDAO.ComposeCertConfig(tx, ref.CertId, false, cacheMap) certConfig, err := SharedSSLCertDAO.ComposeCertConfig(tx, ref.CertId, false, dataMap, cacheMap)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -8,7 +8,7 @@ import (
func TestOriginServerDAO_ComposeOriginConfig(t *testing.T) { func TestOriginServerDAO_ComposeOriginConfig(t *testing.T) {
var tx *dbs.Tx var tx *dbs.Tx
config, err := SharedOriginDAO.ComposeOriginConfig(tx, 1, nil) config, err := SharedOriginDAO.ComposeOriginConfig(tx, 1, nil, nil)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }

View File

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

View File

@@ -61,15 +61,28 @@ func (this *PlanDAO) DisablePlan(tx *dbs.Tx, id int64) error {
} }
// FindEnabledPlan 查找启用中的条目 // 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). result, err := this.Query(tx).
Pk(id). Pk(planId).
Attr("state", PlanStateEnabled). Attr("state", PlanStateEnabled).
Find() Find()
if result == nil { if result == nil {
return nil, err return nil, err
} }
return result.(*Plan), err
if cacheMap != nil {
cacheMap.Put(cacheKey, result)
}
return result.(*Plan), nil
} }
// FindPlanName 根据主键查找名称 // 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" 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 用户套餐 // Plan 用户套餐
type Plan struct { type Plan struct {
Id uint32 `field:"id"` // ID Id uint32 `field:"id"` // ID
IsOn bool `field:"isOn"` // 是否启用 IsOn bool `field:"isOn"` // 是否启用
Name string `field:"name"` // 套餐名 Name string `field:"name"` // 套餐名
ClusterId uint32 `field:"clusterId"` // 集群ID ClusterId uint32 `field:"clusterId"` // 集群ID
TrafficLimit dbs.JSON `field:"trafficLimit"` // 流量限制 TrafficLimit dbs.JSON `field:"trafficLimit"` // 流量限制
Features dbs.JSON `field:"features"` // 允许的功能 Features dbs.JSON `field:"features"` // 允许的功能
TrafficPrice dbs.JSON `field:"trafficPrice"` // 流量价格设定 TrafficPrice dbs.JSON `field:"trafficPrice"` // 流量价格设定
BandwidthPrice dbs.JSON `field:"bandwidthPrice"` // 带宽价格 BandwidthPrice dbs.JSON `field:"bandwidthPrice"` // 带宽价格
MonthlyPrice float64 `field:"monthlyPrice"` // 月付 MonthlyPrice float64 `field:"monthlyPrice"` // 月付
SeasonallyPrice float64 `field:"seasonallyPrice"` // 季付 SeasonallyPrice float64 `field:"seasonallyPrice"` // 季付
YearlyPrice float64 `field:"yearlyPrice"` // 年付 YearlyPrice float64 `field:"yearlyPrice"` // 年付
PriceType string `field:"priceType"` // 价格类型 PriceType string `field:"priceType"` // 价格类型
Order uint32 `field:"order"` // 排序 Order uint32 `field:"order"` // 排序
State uint8 `field:"state"` // 状态 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 { type PlanOperator struct {
Id interface{} // ID Id any // ID
IsOn interface{} // 是否启用 IsOn any // 是否启用
Name interface{} // 套餐名 Name any // 套餐名
ClusterId interface{} // 集群ID ClusterId any // 集群ID
TrafficLimit interface{} // 流量限制 TrafficLimit any // 流量限制
Features interface{} // 允许的功能 Features any // 允许的功能
TrafficPrice interface{} // 流量价格设定 TrafficPrice any // 流量价格设定
BandwidthPrice interface{} // 带宽价格 BandwidthPrice any // 带宽价格
MonthlyPrice interface{} // 月付 MonthlyPrice any // 月付
SeasonallyPrice interface{} // 季付 SeasonallyPrice any // 季付
YearlyPrice interface{} // 年付 YearlyPrice any // 年付
PriceType interface{} // 价格类型 PriceType any // 价格类型
Order interface{} // 排序 Order any // 排序
State interface{} // 状态 State any // 状态
TotalServers any // 可以绑定的网站数量
TotalServerNamesPerServer any // 每个网站可以绑定的域名数量
TotalServerNames any // 总域名数量
MonthlyRequests any // 每月访问量额度
DailyRequests any // 每日访问量额度
} }
func NewPlanOperator() *PlanOperator { func NewPlanOperator() *PlanOperator {

View File

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

View File

@@ -2,9 +2,22 @@ package regions
import "github.com/iwind/TeaGo/dbs" 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 区域-城市 // RegionCity 区域-城市
type RegionCity struct { type RegionCity struct {
Id uint32 `field:"id"` // ID Id1 uint32 `field:"id"` // ID
ValueId uint32 `field:"valueId"` // 实际ID
ProvinceId uint32 `field:"provinceId"` // 省份ID ProvinceId uint32 `field:"provinceId"` // 省份ID
Name string `field:"name"` // 名称 Name string `field:"name"` // 名称
Codes dbs.JSON `field:"codes"` // 代号 Codes dbs.JSON `field:"codes"` // 代号
@@ -15,14 +28,15 @@ type RegionCity struct {
} }
type RegionCityOperator struct { type RegionCityOperator struct {
Id interface{} // ID Id any // ID
ProvinceId interface{} // 省份ID ValueId any // 实际ID
Name interface{} // 名称 ProvinceId any // 省份ID
Codes interface{} // 代号 Name any // 名称
CustomName interface{} // 自定义名称 Codes any // 代号
CustomCodes interface{} // 自定义代号 CustomName any // 自定义名称
State interface{} // 状态 CustomCodes any // 自定义代号
DataId interface{} // 原始数据ID State any // 状态
DataId any // 原始数据ID
} }
func NewRegionCityOperator() *RegionCityOperator { func NewRegionCityOperator() *RegionCityOperator {

View File

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

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