Compare commits

..

206 Commits

Author SHA1 Message Date
刘祥超
6dfecd69b4 提供区域监控上报结果接口 2021-09-06 08:12:48 +08:00
刘祥超
dbc97bc8de 实现基本的区域监控终端管理功能 2021-09-05 11:10:18 +08:00
刘祥超
8308e2e83d 修复边缘节点无法下载文件的Bug 2021-09-03 15:15:27 +08:00
刘祥超
8227138168 修复DNS节点升级文件无法下载的Bug 2021-08-31 22:36:36 +08:00
刘祥超
2227a14ba4 增加独立的IP地址管理功能 2021-08-31 17:24:52 +08:00
刘祥超
6137b44408 企业认证信息中增加节点数限制 2021-08-30 18:57:11 +08:00
刘祥超
f654c65626 查询指标数据时增加索引 2021-08-30 15:23:51 +08:00
刘祥超
674574a6af Update go.mod 2021-08-30 10:56:44 +08:00
刘祥超
f02ab1aae2 优化数据库节点管理 2021-08-30 10:56:31 +08:00
刘祥超
55527bba09 健康检查失败10分钟内不重复提醒 2021-08-30 09:47:17 +08:00
刘祥超
821b607ef2 当修改节点在线状态时重置上线检查次数 2021-08-29 16:57:50 +08:00
刘祥超
afeee89a88 节点返回数据增加isUp字段 2021-08-29 16:57:20 +08:00
刘祥超
a983615464 修复节点转移集群后没有删除老的DNS记录的问题 2021-08-29 16:41:42 +08:00
刘祥超
bd596816d5 将健康检查连续下线次数从1升级为3/修复健康检查可能导致DNS不断同步的问题 2021-08-29 16:01:31 +08:00
刘祥超
ca233c3573 修复一个因为SQL_CACHE而导致子查询产生的错误 2021-08-29 14:07:12 +08:00
刘祥超
fd1f990a0e 访问日志表增加requestBody, responseBody(预留) 2021-08-29 10:37:42 +08:00
刘祥超
1796bb8f96 更新TeaGo,提升SQL解析效率、自动开启SQL查询缓存 2021-08-29 10:21:42 +08:00
刘祥超
3f5e4babc7 改进编译脚本 2021-08-26 16:29:19 +08:00
刘祥超
f508c16f92 删除plus文件 2021-08-26 14:40:07 +08:00
刘祥超
ac0bbd0b99 DNS服务商支持搜索 2021-08-25 18:47:01 +08:00
刘祥超
9017176efb 集群支持使用域名搜索 2021-08-25 18:39:17 +08:00
刘祥超
8b40634e74 节点如果没有设置DNS线路就使用默认线路 2021-08-25 17:16:24 +08:00
刘祥超
cf476f79d6 Admin看板增加默认集群ID 2021-08-25 11:41:23 +08:00
刘祥超
fc38a6ab7e 创建集群时自动创建缓存策略和WAF策略 2021-08-25 11:18:37 +08:00
刘祥超
e4f0dafc1a 增加忽略相似消息周期设置 2021-08-24 20:45:12 +08:00
刘祥超
b7fda0b9cc 消息接收人可以设置接收消息时间段 2021-08-24 17:46:11 +08:00
刘祥超
f4cc5aa087 通知媒介可以设置发送频率 2021-08-24 15:46:53 +08:00
刘祥超
f58724065d 通知媒介增加任务队列查看功能 2021-08-24 14:22:44 +08:00
刘祥超
1e6b42c00c 优化WAF日志查询速度 2021-08-22 16:20:40 +08:00
刘祥超
8d759a104b 优化WAF日志访问速度 2021-08-22 16:00:32 +08:00
刘祥超
72d7ceb94e 提升节点组合配置效率 2021-08-22 11:35:33 +08:00
刘祥超
53f7a0b77e Dashboard可以提示API节点升级 2021-08-21 19:43:46 +08:00
刘祥超
56000a8b8a 优化服务配置更新机制 2021-08-21 17:24:29 +08:00
刘祥超
ab7b2fee3a 自建DNS支持递归查询 2021-08-21 16:46:41 +08:00
刘祥超
d768d46854 DNS访问日志显示匹配的线路 2021-08-20 11:27:16 +08:00
刘祥超
b86c9aad6f 节点排行增加条数限制 2021-08-20 10:10:55 +08:00
刘祥超
df667c6ee6 添加DNS账号时自动读取DNS服务商下域名 2021-08-19 14:26:34 +08:00
刘祥超
70331805d7 节点IP地址可以设置阈值 2021-08-18 16:19:16 +08:00
刘祥超
71dbf86572 节点IP增加是否启用、是否在线状态 2021-08-18 09:24:18 +08:00
刘祥超
0df358d70d 调整版本为0.3.0 2021-08-17 09:44:22 +08:00
刘祥超
93a17ced7c 上传SQL 2021-08-15 20:20:06 +08:00
刘祥超
580d09ef99 IP库查询结果显示城市 2021-08-15 20:08:04 +08:00
刘祥超
fed725d45c 增加通过IP来搜索IP名单的API 2021-08-15 15:42:32 +08:00
刘祥超
350b514fc7 改进细节 2021-08-15 10:39:41 +08:00
刘祥超
71d2671c04 增加SSH认证建议接口 2021-08-14 21:33:17 +08:00
刘祥超
5a22146309 增加SSH登录建议端口接口 2021-08-14 18:07:20 +08:00
刘祥超
ac2fb4c84b 可以远程停止和启动DNS节点 2021-08-12 11:47:39 +08:00
刘祥超
c25e3f18e0 修复边缘节点和DNS节点安装文件冲突的问题 2021-08-11 21:14:01 +08:00
刘祥超
d3e4f28c69 实现DNS节点远程安装 2021-08-11 21:00:29 +08:00
刘祥超
363892efb2 改进脚本 2021-08-11 17:16:54 +08:00
刘祥超
cf36559eea 访问日志显示节点信息 2021-08-10 11:15:15 +08:00
刘祥超
fa3e0ca6ab 自建DNS增加解析测试 2021-08-09 18:41:30 +08:00
刘祥超
7229b0db34 NS日志增加remoteAddr字段 2021-08-09 15:19:38 +08:00
刘祥超
23871804b1 EdgeDNS支持内置线路 2021-08-09 13:57:58 +08:00
刘祥超
5e00bfa4c1 优化节点到API节点连接管理 2021-08-08 16:17:25 +08:00
刘祥超
473a2db335 数据有更改时发送通知 2021-08-08 15:47:48 +08:00
刘祥超
c893de8af7 DNS节点增加在线状态通知 2021-08-08 10:29:48 +08:00
刘祥超
a8cf04d178 访问日志搜索增加域名和IP搜索 2021-08-07 22:04:22 +08:00
刘祥超
e94a7f9a77 运行日志只显示已经设置集群的节点 2021-08-07 16:52:28 +08:00
刘祥超
ccf435ee8e 优化代码 2021-08-07 16:11:35 +08:00
刘祥超
7dc5c5f349 修复utils.DumpResponse()可能会忽略err的问题 2021-08-07 11:04:03 +08:00
刘祥超
566c04f080 边缘节点没有集群的时候视为删除 2021-08-07 10:12:17 +08:00
刘祥超
5a13c7663c 修复HTTPFirewallPolicyService.CheckHTTPFirewallPolicyIPStatus()可能panic的Bug 2021-08-06 14:48:05 +08:00
刘祥超
1df6d579d7 修改一处测试 2021-08-06 14:47:42 +08:00
刘祥超
20110495ab 修复unique key无法升级的问题 2021-08-06 14:22:17 +08:00
刘祥超
ce8d656d65 调整版本为0.2.9 2021-08-06 14:21:54 +08:00
刘祥超
186fe3c365 修复无法升级国家/地区数据的Bug 2021-08-05 20:36:16 +08:00
刘祥超
a9ce2f45df 修复导致无法安装的严重Bug 2021-08-05 19:53:54 +08:00
刘祥超
5105af9918 自建DNS增加全局配置 2021-08-05 16:08:01 +08:00
刘祥超
378c485219 统计节点分组中节点数量时判断节点集群是否存在 2021-08-05 11:28:58 +08:00
刘祥超
2465993e2c 域名解析支持华为云解析DNS 2021-08-04 22:14:54 +08:00
刘祥超
818c1c25a7 调整版本 2021-08-04 15:36:06 +08:00
刘祥超
77c67ccd3f 调整版本号 2021-08-03 14:00:44 +08:00
刘祥超
d855fdedde 修复一个DNS节点和边缘节点地址可能会冲突的问题 2021-08-03 13:35:29 +08:00
刘祥超
95c734c87a 调整版本号 2021-08-03 10:40:32 +08:00
刘祥超
89ff1927b7 使用upgrade命令升级数据库时增加日志显示 2021-08-02 15:23:02 +08:00
刘祥超
1a3aaf2846 节点运行日志增加记录源站ID 2021-08-01 21:54:44 +08:00
刘祥超
7d25019abb 更新SQL 2021-08-01 14:59:52 +08:00
刘祥超
4cfc7d5387 修改服务组合配置为动态 2021-08-01 14:56:08 +08:00
刘祥超
9245cf9cdb 各项统计支持单节点多集群 2021-08-01 11:13:46 +08:00
刘祥超
9e1e57dfd8 初步实现多集群共享节点 2021-07-31 22:23:11 +08:00
刘祥超
87f032bebd 使用ES存储访问日志时自动生成requestId 2021-07-29 17:34:44 +08:00
刘祥超
bda407fc3f 实现基本的访问日志策略 2021-07-29 16:50:59 +08:00
刘祥超
3b2f6060b8 上传统计数据时自动清理旧数据 2021-07-28 17:04:31 +08:00
刘祥超
a15ad7dd04 增加内置统计指标:请求来源统计 2021-07-26 16:50:34 +08:00
刘祥超
a415ef6070 指标图表可以设置忽略空值和其他对象值 2021-07-26 16:44:29 +08:00
刘祥超
d94a822f52 调整若干文字 2021-07-26 11:23:21 +08:00
刘祥超
9e3fb9cf66 版本调整为0.2.6 2021-07-26 11:23:12 +08:00
刘祥超
84a9916d3e 使用Sock管理进程启停 2021-07-25 17:46:47 +08:00
刘祥超
7d1ae0d242 更新SQL和编译脚本 2021-07-25 16:28:20 +08:00
刘祥超
3fbad22218 区分社区版和商业版 2021-07-25 15:46:12 +08:00
刘祥超
5fffc8a833 DNS支持TSIG 2021-07-25 15:08:17 +08:00
刘祥超
2c72d28c48 DNS服务支持密钥管理 2021-07-25 09:43:57 +08:00
刘祥超
45ea803e7a 获取DNS节点配置信息时增加节点UniqueId信息 2021-07-24 10:10:02 +08:00
刘祥超
edd4b59207 规则的内容长度从1024调整为4096 2021-07-23 10:58:07 +08:00
刘祥超
38ad11fda0 v0.2.5.1 2021-07-23 10:57:25 +08:00
刘祥超
961d9b4dbc DNS节点可以自动升级 2021-07-22 18:42:57 +08:00
刘祥超
6436e83d9e 更新SQL 2021-07-22 08:16:06 +08:00
刘祥超
b2d3d483e8 自动清理日志的时候也清理DNS访问日志 2021-07-21 22:12:52 +08:00
刘祥超
89ec81f6b1 修改无法在访问日志中搜索IP的Bug 2021-07-21 22:12:35 +08:00
刘祥超
5124169e28 编译脚本增加arm64 2021-07-21 22:11:59 +08:00
刘祥超
fe4eb3928e 设置 max_prepared_stmt_count 失败时提示更详细 2021-07-21 09:01:37 +08:00
刘祥超
514d968b20 修复访问日志无法查询IP的Bug 2021-07-21 08:08:31 +08:00
刘祥超
3cce13e671 域名排行增加条数限制 2021-07-21 08:08:16 +08:00
刘祥超
6d359b09f2 更新SQL 2021-07-20 22:24:30 +08:00
刘祥超
316b3485ca API节点列表API允许认证节点调用 2021-07-20 19:03:35 +08:00
刘祥超
31c20122b4 域名服务增加停用 /启用 2021-07-20 19:03:10 +08:00
刘祥超
7343d4bfac 增加API令牌相关API 2021-07-20 17:15:44 +08:00
刘祥超
330d5a3d21 在各个地方支持IPv6 2021-07-20 10:55:34 +08:00
刘祥超
709845064f 自动清理过期指标统计数据 2021-07-19 21:01:26 +08:00
刘祥超
be5a89e513 更新SQL 2021-07-19 20:38:59 +08:00
刘祥超
80328b9b5f 增加内置的统计指标 2021-07-19 20:38:30 +08:00
刘祥超
c6a09e131b Dashboard增加指标图表 2021-07-19 17:58:16 +08:00
刘祥超
f52ea4fa4f 优化通过IP查找日志 2021-07-18 17:09:06 +08:00
刘祥超
6cbda588f7 实现WAF通知和记录IP功能 2021-07-18 15:52:34 +08:00
刘祥超
f9e7c3a2e0 WAF支持更多动作 2021-07-14 22:46:23 +08:00
刘祥超
c370dada11 访问日志增加RemoteAddr字段以加速查询 2021-07-14 22:43:31 +08:00
刘祥超
8d71afc176 搜索节点时加入所在集群状态 2021-07-14 13:59:16 +08:00
刘祥超
a39a114316 IP测试时同时也检查绑定的IP名单 2021-07-13 15:49:16 +08:00
刘祥超
3f5c3568db 更新SQL 2021-07-13 15:10:19 +08:00
刘祥超
f50ff00f0b 路径规则改成路由规则 2021-07-13 14:30:30 +08:00
刘祥超
7caa5bee75 优化看板 2021-07-13 11:04:45 +08:00
刘祥超
bf5368929b 更新SQL 2021-07-12 17:37:44 +08:00
刘祥超
ff6d8d9ba3 实现数据看板--WAF 2021-07-12 16:57:02 +08:00
刘祥超
877d42a271 管理界面可以切换风格 2021-07-12 10:21:28 +08:00
刘祥超
21c51cbdc8 实现数据看板-DNS 2021-07-11 21:44:08 +08:00
刘祥超
45e4eb72ac 实现数据看板--用户 2021-07-11 18:05:57 +08:00
刘祥超
11c344eef4 看板增加缓存目录用量 2021-07-08 19:43:09 +08:00
刘祥超
17008d6b03 健康检查失败时,会自动尝试再次连接 2021-07-08 18:37:11 +08:00
刘祥超
5512efbb70 实现服务看板(企业版) 2021-07-07 19:55:37 +08:00
刘祥超
1e0a7612df 节点列表增加下行流量,节点列表可以按CPU、内存、下行流量排序 2021-07-07 15:18:48 +08:00
刘祥超
8589e0d373 实现节点看板(仅对企业版开放) 2021-07-06 20:06:34 +08:00
刘祥超
c5edaef356 优化API节点监听逻辑,提升兼容性
如果用户填写的GPRC监听端口中的地址无法监听,则尝试只监听端口
2021-07-06 15:19:39 +08:00
刘祥超
692eb04c93 DNS节点检查是否需要升级时,加入集群是否可用的条件 2021-07-06 10:27:14 +08:00
刘祥超
83d9a17c2b 集群看板增加指标相关图表 2021-07-05 16:37:53 +08:00
刘祥超
a4422ef7bd 更新SQL 2021-07-05 11:38:45 +08:00
刘祥超
e6e9fcc3c3 实现集群看板 2021-07-05 11:37:22 +08:00
刘祥超
7484243dff 实现基本的图表管理 2021-07-03 15:45:04 +08:00
刘祥超
907676d688 指标数据增加总和数据 2021-07-01 10:39:42 +08:00
刘祥超
54dbe1f3e4 实现基础的统计指标 2021-06-30 19:59:49 +08:00
刘祥超
98a2d61fd1 SSH认证--私钥认证方式增加用户名选项 2021-06-30 14:56:36 +08:00
刘祥超
e544e088be 统计创建浏览器、系统时限制名称长度 2021-06-29 19:38:14 +08:00
刘祥超
86c33256ca 修改版本为0.2.5 2021-06-28 10:32:06 +08:00
刘祥超
91ff73e4e4 更新用户节点版本 2021-06-27 22:22:11 +08:00
刘祥超
e68473a13f 更新SQL 2021-06-27 22:14:35 +08:00
刘祥超
5774beda6f 阶段性提交 2021-06-27 21:59:37 +08:00
刘祥超
4869c11d60 ip2region增加IP格式检查 2021-06-27 17:29:16 +08:00
刘祥超
4bc6f93902 统计时创建系统、浏览器信息时加锁 2021-06-27 15:17:18 +08:00
刘祥超
ce4e079752 修复WAF用户检查的Bug 2021-06-27 08:31:10 +08:00
刘祥超
488df3d150 服务列表可以搜索端口号 2021-06-25 11:05:02 +08:00
刘祥超
109e129cc5 ACME申请证书时可以设置回调URL 2021-06-24 09:27:39 +08:00
刘祥超
447f89399f 更新SQL 2021-06-23 13:13:26 +08:00
刘祥超
206c12c746 实现公用的IP名单 2021-06-23 13:12:54 +08:00
刘祥超
3c14310e3a 变更版本 2021-06-21 14:43:51 +08:00
刘祥超
50055c1045 提交SQL 2021-06-21 11:25:13 +08:00
刘祥超
cca97f5c51 管理员也支持AccessKey,Rest API增加所有的服务 2021-06-20 19:22:24 +08:00
刘祥超
1bfaf041ea 修复用户无法修改关联集群的Bug 2021-06-19 22:19:12 +08:00
刘祥超
927b5b6fd3 阶段性提交 2021-06-17 21:17:53 +08:00
刘祥超
1afaa0bc8d 调整版本为0.2.3 2021-06-17 18:45:55 +08:00
刘祥超
7312a7aa94 调整版本为0.2.2 2021-06-17 18:07:49 +08:00
刘祥超
fd18739b0a REST API输出时增加application/json; charset=utf-8 Header 2021-06-16 10:48:31 +08:00
刘祥超
d92f56e7fe 用户AccessKey:增加最近访问时间、修复AccessKey没有区分用户的Bug 2021-06-16 10:48:08 +08:00
刘祥超
a1a7ec8c93 调整边缘节点版本 2021-06-16 09:37:54 +08:00
刘祥超
951fdf0927 调整版本为0.2.1 2021-06-16 08:31:02 +08:00
刘祥超
7d3328f75b 节点日志计数从1开始(以前是0) 2021-06-14 20:39:39 +08:00
刘祥超
8db39a6b36 更新各个节点版本 2021-06-14 20:39:10 +08:00
刘祥超
71681b1c5d 提供下载最新边缘节点API 2021-06-10 19:21:45 +08:00
刘祥超
6b2a015015 创建缓存策略时默认加入缓存条件 2021-06-10 10:50:56 +08:00
刘祥超
9e74baf37b 路径规则、重写规则、URL跳转规则均支持匹配条件 2021-06-09 21:44:38 +08:00
刘祥超
b651d94bf5 请求统计增加即时、按天 2021-06-08 15:10:08 +08:00
刘祥超
b61433c5f8 更新SQL 2021-06-08 11:23:35 +08:00
刘祥超
c4d2191110 增加服务流量统计 2021-06-08 11:18:27 +08:00
刘祥超
f6159c646c 修改反向代理回源主机名默认值 2021-06-07 17:23:10 +08:00
刘祥超
9cc7d54b64 健康检查支持IPv6 2021-06-07 10:06:16 +08:00
刘祥超
05ce1d327b 边缘节点IP支持IPV6 2021-06-07 10:02:07 +08:00
刘祥超
111df18204 WAF策略支持搜索 2021-06-07 08:58:26 +08:00
刘祥超
bbcdf167b1 缓存策略列表支持搜索 2021-06-07 08:44:19 +08:00
刘祥超
d62a44b1ac 聚合服务相关日志 2021-06-06 13:40:33 +08:00
刘祥超
969bb2bcda 日志级别增加success 2021-06-06 13:40:25 +08:00
刘祥超
6dcd3f2a98 域名服务集群创建时可以选择开启访问日志 2021-06-05 15:39:02 +08:00
刘祥超
7936dc85a9 API认证超时时增加检查系统时钟提示 2021-06-04 15:34:58 +08:00
刘祥超
94c4098de5 兼容部分API老命名 2021-06-04 11:41:50 +08:00
刘祥超
5b0aef8d4a 修复用户创建服务时提示resource not found的问题 2021-06-04 11:23:01 +08:00
刘祥超
4571b95e4a 服务访问日志增加关键词搜索 2021-06-04 10:15:41 +08:00
刘祥超
b9cba4c7df DNS访问日志可以使用关键词搜索 2021-06-04 09:09:14 +08:00
刘祥超
b46b5dc05f 修复域名服务集群检测新版本节点的Bug 2021-06-03 22:08:38 +08:00
刘祥超
ef5630ba4a 实现在域名解析中使用EdgeDNS 2021-06-02 18:13:48 +08:00
刘祥超
fe6c610d56 更新SQL 2021-06-02 11:54:05 +08:00
刘祥超
442dd195ca 域名服务增加访问日志 2021-06-02 11:53:24 +08:00
刘祥超
e9e4abff03 实现域名、记录同步等API 2021-06-01 16:43:00 +08:00
刘祥超
2a3fbd080e [域名服务]实现基本的线路配置 2021-05-30 16:31:43 +08:00
刘祥超
9d7f1a2702 更新SQL 2021-05-27 17:29:31 +08:00
刘祥超
57dcbce775 实现基本的域名、记录管理 2021-05-27 17:09:07 +08:00
刘祥超
a71bf9ed79 实现最基本的域名服务节点管理 2021-05-26 14:40:05 +08:00
刘祥超
725692ce94 优化API命名 2021-05-25 17:48:55 +08:00
刘祥超
ea15096dc3 优化API命名 2021-05-25 17:08:58 +08:00
刘祥超
a07dbb718f 实现域名服务器集群管理 2021-05-25 15:49:13 +08:00
刘祥超
18381b76fb 变更版本为0.2.0 2021-05-25 15:49:04 +08:00
刘祥超
1d31245b4a 上传新SQL 2021-05-24 09:53:17 +08:00
刘祥超
f26bc337c9 缓存策略可以设置全局的缓存条件 2021-05-24 09:24:49 +08:00
刘祥超
05c2955211 SSH认证列表可以使用关键词搜索,返回内容增加用户名 2021-05-23 21:13:20 +08:00
刘祥超
f0ffa48390 节点日志增加服务ID、是否修复等字段 2021-05-23 20:46:51 +08:00
刘祥超
a472b8a3bd 修改版本 2021-05-20 19:41:33 +08:00
刘祥超
cfa2717838 实现日志消息聚合 2021-05-19 20:47:23 +08:00
刘祥超
aece12854e 节点日志可以通过日期、关键词、级别等筛选 2021-05-19 19:03:46 +08:00
刘祥超
02692029ee 增加darwin/arm64编译脚本 2021-05-13 14:57:04 +08:00
397 changed files with 24368 additions and 2886 deletions

2
.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
*_plus.go
*-plus.sh

View File

@@ -6,3 +6,4 @@
./build.sh linux mips64
./build.sh linux mips64le
./build.sh darwin amd64
./build.sh darwin arm64

View File

@@ -6,6 +6,8 @@ function build() {
DIST=$ROOT/"../dist/${NAME}"
OS=${1}
ARCH=${2}
TAG=${3}
NODE_ARCHITECTS=("amd64" "386" "arm64" "mips64" "mips64le")
if [ -z $OS ]; then
echo "usage: build.sh OS ARCH"
@@ -15,11 +17,14 @@ function build() {
echo "usage: build.sh OS ARCH"
exit
fi
if [ -z $TAG ]; then
TAG="community"
fi
VERSION=$(lookup-version $ROOT/../internal/const/const.go)
ZIP="${NAME}-${OS}-${ARCH}-v${VERSION}.zip"
ZIP="${NAME}-${OS}-${ARCH}-${TAG}-v${VERSION}.zip"
# check edge-node
# build edge-node
NodeVersion=$(lookup-version $ROOT"/../../EdgeNode/internal/const/const.go")
echo "building edge-node v${NodeVersion} ..."
EDGE_NODE_BUILD_SCRIPT=$ROOT"/../../EdgeNode/build/build.sh"
@@ -29,18 +34,47 @@ function build() {
fi
cd $ROOT"/../../EdgeNode/build"
echo "=============================="
architects=("amd64" "386" "arm64" "mips64" "mips64le")
for arch in "${architects[@]}"; do
./build.sh linux $arch
for arch in "${NODE_ARCHITECTS[@]}"; do
if [ ! -f $ROOT"/../../EdgeNode/dist/edge-node-linux-${arch}-${TAG}-v${NodeVersion}.zip" ]; then
./build.sh linux $arch $TAG
else
echo "use built node linux/$arch/v${NodeVersion}"
fi
done
echo "=============================="
cd -
rm -f $ROOT/deploy/*.zip
for arch in "${architects[@]}"; do
cp $ROOT"/../../EdgeNode/dist/edge-node-linux-${arch}-v${NodeVersion}.zip" $ROOT/deploy/
for arch in "${NODE_ARCHITECTS[@]}"; do
cp $ROOT"/../../EdgeNode/dist/edge-node-linux-${arch}-${TAG}-v${NodeVersion}.zip" $ROOT/deploy/edge-node-linux-${arch}-v${NodeVersion}.zip
done
# build edge-dns
if [ "$TAG" = "plus" ]; then
DNS_ROOT=$ROOT"/../../EdgeDNS"
if [ -d $DNS_ROOT ]; then
DNSNodeVersion=$(lookup-version $ROOT"/../../EdgeDNS/internal/const/const.go")
echo "building edge-dns ${DNSNodeVersion} ..."
EDGE_DNS_NODE_BUILD_SCRIPT=$ROOT"/../../EdgeDNS/build/build.sh"
if [ ! -f $EDGE_DNS_NODE_BUILD_SCRIPT ]; then
echo "unable to find edge-dns build script 'EdgeDNS/build/build.sh'"
exit
fi
cd $ROOT"/../../EdgeDNS/build"
echo "=============================="
architects=("amd64")
for arch in "${architects[@]}"; do
./build.sh linux $arch $TAG
done
echo "=============================="
cd -
for arch in "${architects[@]}"; do
cp $ROOT"/../../EdgeDNS/dist/edge-dns-linux-${arch}-v${DNSNodeVersion}.zip" $ROOT/deploy/edge-dns-linux-${arch}-v${DNSNodeVersion}.zip
done
fi
fi
# build sql
echo "building sql ..."
${ROOT}/sql.sh
@@ -62,16 +96,24 @@ function build() {
rm -f $DIST/resources/ipdata/ip2region/global_region.csv
rm -f $DIST/resources/ipdata/ip2region/ip.merge.txt
# building installer
echo "building installer ..."
architects=("amd64" "386")
# building edge installer
echo "building node installer ..."
architects=("amd64" "386" "arm64")
for arch in "${architects[@]}"; do
# TODO support arm, mips ...
env GOOS=linux GOARCH=${arch} go build --ldflags="-s -w" -o $ROOT/installers/edge-installer-helper-linux-${arch} $ROOT/../cmd/installer-helper/main.go
env GOOS=linux GOARCH=${arch} go build -tags $TAG --ldflags="-s -w" -o $ROOT/installers/edge-installer-helper-linux-${arch} $ROOT/../cmd/installer-helper/main.go
done
# building edge dns installer
echo "building dns node installer ..."
architects=("amd64" "386" "arm64")
for arch in "${architects[@]}"; do
# TODO support arm, mips ...
env GOOS=linux GOARCH=${arch} go build -tags $TAG --ldflags="-s -w" -o $ROOT/installers/edge-installer-dns-helper-linux-${arch} $ROOT/../cmd/installer-dns-helper/main.go
done
# building api node
env GOOS=$OS GOARCH=$ARCH go build --ldflags="-s -w" -o $DIST/bin/edge-api $ROOT/../cmd/edge-api/main.go
env GOOS=$OS GOARCH=$ARCH go build -tags $TAG --ldflags="-s -w" -o $DIST/bin/edge-api $ROOT/../cmd/edge-api/main.go
# delete hidden files
find $DIST -name ".DS_Store" -delete
@@ -102,4 +144,4 @@ function lookup-version() {
fi
}
build $1 $2
build $1 $2 $3

View File

@@ -44,12 +44,13 @@ func main() {
_, _ = os.Stdout.Write(resultJSON)
})
app.On("upgrade", func() {
fmt.Println("start ...")
executor, err := setup.NewSQLExecutorFromCmd()
if err != nil {
fmt.Println("ERROR: " + err.Error())
return
}
err = executor.Run()
err = executor.Run(true)
if err != nil {
fmt.Println("ERROR: " + err.Error())
return

View File

@@ -0,0 +1,73 @@
package main
import (
"flag"
"github.com/TeaOSLab/EdgeAPI/internal/utils"
"github.com/iwind/gosock/pkg/gosock"
"os"
"os/exec"
)
func main() {
cmd := ""
flag.StringVar(&cmd, "cmd", "", "command name: [unzip]")
// unzip
zipPath := ""
targetPath := ""
flag.StringVar(&zipPath, "zip", "", "zip path")
flag.StringVar(&targetPath, "target", "", "target dir")
// parse
flag.Parse()
if len(cmd) == 0 {
stderr("need '-cmd=COMMAND' argument")
} else if cmd == "test" {
// 检查是否正在运行
var sock = gosock.NewTmpSock("edge-dns")
if sock.IsListening() {
// 从systemd中停止
systemctl, _ := exec.LookPath("systemctl")
if len(systemctl) > 0 {
systemctlCmd := exec.Command(systemctl, "stop", "edge-dns")
_ = systemctlCmd.Run()
}
// 从进程中停止
if sock.IsListening() {
_, _ = sock.Send(&gosock.Command{
Code: "stop",
})
}
}
} else if cmd == "unzip" { // 解压
if len(zipPath) == 0 {
stderr("ERROR: need '-zip=PATH' argument")
return
}
if len(targetPath) == 0 {
stderr("ERROR: need '-target=TARGET' argument")
return
}
unzip := utils.NewUnzip(zipPath, targetPath)
err := unzip.Run()
if err != nil {
stderr("ERROR: " + err.Error())
return
}
stdout("ok")
} else {
stderr("ERROR: not recognized command '" + cmd + "'")
}
}
func stdout(s string) {
_, _ = os.Stdout.WriteString(s + "\n")
}
func stderr(s string) {
_, _ = os.Stderr.WriteString(s + "\n")
}

View File

@@ -3,8 +3,9 @@ package main
import (
"flag"
"github.com/TeaOSLab/EdgeAPI/internal/utils"
"net"
"github.com/iwind/gosock/pkg/gosock"
"os"
"os/exec"
)
func main() {
@@ -24,11 +25,21 @@ func main() {
stderr("need '-cmd=COMMAND' argument")
} else if cmd == "test" {
// 检查是否正在运行
path := os.TempDir() + "/edge-node.sock"
conn, err := net.Dial("unix", path)
if err == nil {
_ = conn.Close()
stderr("test node status: edge node is running now, can not install again")
var sock = gosock.NewTmpSock("edge-node")
if sock.IsListening() {
// 从systemd中停止
systemctl, _ := exec.LookPath("systemctl")
if len(systemctl) > 0 {
systemctlCmd := exec.Command(systemctl, "stop", "edge-node")
_ = systemctlCmd.Run()
}
// 从进程中停止
if sock.IsListening() {
_, _ = sock.Send(&gosock.Command{
Code: "stop",
})
}
}
} else if cmd == "unzip" { // 解压
if len(zipPath) == 0 {

19
go.mod
View File

@@ -4,6 +4,7 @@ go 1.15
replace github.com/TeaOSLab/EdgeCommon => ../EdgeCommon
require (
github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d // indirect
github.com/TeaOSLab/EdgeCommon v0.0.0-00010101000000-000000000000
@@ -13,15 +14,19 @@ require (
github.com/go-ole/go-ole v1.2.4 // indirect
github.com/go-sql-driver/mysql v1.5.0
github.com/go-yaml/yaml v2.1.0+incompatible
github.com/golang/protobuf v1.4.2
github.com/iwind/TeaGo v0.0.0-20210411134150-ddf57e240c2f
github.com/golang/protobuf v1.5.2
github.com/iwind/TeaGo v0.0.0-20210831140440-a2a442471b13
github.com/iwind/gosock v0.0.0-20210722083328-12b2d66abec3
github.com/json-iterator/go v1.1.11 // indirect
github.com/lionsoul2014/ip2region v2.2.0-release+incompatible
github.com/mozillazg/go-pinyin v0.18.0
github.com/pkg/sftp v1.12.0
github.com/shirou/gopsutil v2.20.9+incompatible
github.com/shirou/gopsutil v3.21.5+incompatible
github.com/tklauser/go-sysconf v0.3.6 // indirect
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299
google.golang.org/grpc v1.32.0
google.golang.org/protobuf v1.25.0
gopkg.in/yaml.v2 v2.4.0 // indirect
golang.org/x/net v0.0.0-20210614182718-04defd469f4e // indirect
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22
google.golang.org/genproto v0.0.0-20210617175327-b9e0b3197ced // indirect
google.golang.org/grpc v1.38.0
google.golang.org/protobuf v1.26.0
)

85
go.sum
View File

@@ -68,6 +68,7 @@ github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMn
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cloudflare/cloudflare-go v0.13.2/go.mod h1:27kfc1apuifUmJhp069y0+hwlKDg4bd8LWlu7oKeZvM=
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/cpu/goacmedns v0.0.3/go.mod h1:4MipLkI+qScwqtVxcNO6okBhbgRrr7/tKXUSgSL0teQ=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -83,6 +84,7 @@ github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFP
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/exoscale/egoscale v0.23.0/go.mod h1:hRo78jkjkCDKpivQdRBEpNYF5+cVpCJCPDg2/r45KaY=
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
@@ -132,8 +134,10 @@ github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrU
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
@@ -141,8 +145,9 @@ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5a
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
@@ -153,6 +158,7 @@ github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hf
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/gophercloud/gophercloud v0.6.1-0.20191122030953-d8ac278c1c9d/go.mod h1:ozGNgr9KYOVATV5jsgHl/ceCDXGuguqOZAzoQ/2vcNM=
@@ -174,23 +180,29 @@ github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/iij/doapi v0.0.0-20190504054126-0bbf12d6d7df/go.mod h1:QMZY7/J/KSQEhKWFeDesPjMj+wCHReeknARU3wqlyN4=
github.com/iwind/TeaGo v0.0.0-20200923021120-f5d76441fe9e/go.mod h1:KU4mS7QNiZ7QWEuDBk1zw0/Q2LrAPZv3tycEFBsuUwc=
github.com/iwind/TeaGo v0.0.0-20210125103732-4d79fc3c3d0b h1:niQL2t//041GUaqDPM5D+ldyr0Ng2WKwZJHPRLQhQtk=
github.com/iwind/TeaGo v0.0.0-20210125103732-4d79fc3c3d0b/go.mod h1:KU4mS7QNiZ7QWEuDBk1zw0/Q2LrAPZv3tycEFBsuUwc=
github.com/iwind/TeaGo v0.0.0-20210302120856-7588e79bdbe3 h1:k9K3HHMmkF7HYyIHz21AtmYH4Zdk/8OI98a8P0O8o1I=
github.com/iwind/TeaGo v0.0.0-20210302120856-7588e79bdbe3/go.mod h1:KU4mS7QNiZ7QWEuDBk1zw0/Q2LrAPZv3tycEFBsuUwc=
github.com/iwind/TeaGo v0.0.0-20210325033016-3279bdaa087d h1:FQTYJmZeCMdwM0Bz+C4h31SDBt04ap6A4JOjm+FfYwk=
github.com/iwind/TeaGo v0.0.0-20210325033016-3279bdaa087d/go.mod h1:KU4mS7QNiZ7QWEuDBk1zw0/Q2LrAPZv3tycEFBsuUwc=
github.com/iwind/TeaGo v0.0.0-20210411134150-ddf57e240c2f h1:r2O8PONj/KiuZjJHVHn7KlCePUIjNtgAmvLfgRafQ8o=
github.com/iwind/TeaGo v0.0.0-20210411134150-ddf57e240c2f/go.mod h1:KU4mS7QNiZ7QWEuDBk1zw0/Q2LrAPZv3tycEFBsuUwc=
github.com/iwind/TeaGo v0.0.0-20210628135026-38575a4ab060/go.mod h1:KU4mS7QNiZ7QWEuDBk1zw0/Q2LrAPZv3tycEFBsuUwc=
github.com/iwind/TeaGo v0.0.0-20210806054428-5534da0db9d1 h1:AZKkwTNEZYrpyv62zIkxpLJsWhfOS7OEFovAcwd0aco=
github.com/iwind/TeaGo v0.0.0-20210806054428-5534da0db9d1/go.mod h1:KU4mS7QNiZ7QWEuDBk1zw0/Q2LrAPZv3tycEFBsuUwc=
github.com/iwind/TeaGo v0.0.0-20210809112119-a57ed0e84e34 h1:ZCNQXLiGF5Z1cV3Pi03zCWzwwjPfsI5XhcrNhTvCFIU=
github.com/iwind/TeaGo v0.0.0-20210809112119-a57ed0e84e34/go.mod h1:KU4mS7QNiZ7QWEuDBk1zw0/Q2LrAPZv3tycEFBsuUwc=
github.com/iwind/TeaGo v0.0.0-20210824034952-1a56ad7d0b5e h1:GDCU57lQD6W9u5KT2834MmK022FSeAbskb7H0p2eaJY=
github.com/iwind/TeaGo v0.0.0-20210824034952-1a56ad7d0b5e/go.mod h1:KU4mS7QNiZ7QWEuDBk1zw0/Q2LrAPZv3tycEFBsuUwc=
github.com/iwind/TeaGo v0.0.0-20210829020150-9c36d31301a5 h1:ybjIXGT3E/ZbfkRhIb903WMfLyt2Uv5p4niAqi8jwvM=
github.com/iwind/TeaGo v0.0.0-20210829020150-9c36d31301a5/go.mod h1:KU4mS7QNiZ7QWEuDBk1zw0/Q2LrAPZv3tycEFBsuUwc=
github.com/iwind/TeaGo v0.0.0-20210831140440-a2a442471b13 h1:HuEJ5xJfujW1Q6rNDhOu5LQXEBB2qLPah3jYslT8Gz4=
github.com/iwind/TeaGo v0.0.0-20210831140440-a2a442471b13/go.mod h1:KU4mS7QNiZ7QWEuDBk1zw0/Q2LrAPZv3tycEFBsuUwc=
github.com/iwind/gosock v0.0.0-20210722083328-12b2d66abec3 h1:aBSonas7vFcgTj9u96/bWGILGv1ZbUSTLiOzcI1ZT6c=
github.com/iwind/gosock v0.0.0-20210722083328-12b2d66abec3/go.mod h1:H5Q7SXwbx3a97ecJkaS2sD77gspzE7HFUafBO0peEyA=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jmespath/go-jmespath v0.3.0 h1:OS12ieG61fsCg5+qLJ+SsW9NicxNkg3b25OyT2yCeUc=
github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik=
github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68=
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMWAQ=
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
@@ -287,8 +299,8 @@ github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6So
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sacloud/libsacloud v1.36.2/go.mod h1:P7YAOVmnIn3DKHqCZcUKYUXmSwGBm3yS7IBEjKVSrjg=
github.com/shirou/gopsutil v2.20.9+incompatible h1:msXs2frUV+O/JLva9EDLpuJ84PrFsdCTCQex8PUdtkQ=
github.com/shirou/gopsutil v2.20.9+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
github.com/shirou/gopsutil v3.21.5+incompatible h1:OloQyEerMi7JUrXiNzy8wQ5XN+baemxSl12QgIzt0jc=
github.com/shirou/gopsutil v3.21.5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
@@ -306,6 +318,10 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/tklauser/go-sysconf v0.3.6 h1:oc1sJWvKkmvIxhDHeKWvZS4f6AW+YcoguSfRF2/Hmo4=
github.com/tklauser/go-sysconf v0.3.6/go.mod h1:MkWzOF4RMCshBAMXuhXJs64Rte09mITnppBXY/rYEFI=
github.com/tklauser/numcpus v0.2.2 h1:oyhllyrScuYI6g+h/zUvNXNp1wy7x8qQy3t/piefldA=
github.com/tklauser/numcpus v0.2.2/go.mod h1:x3qojaO3uyYt0i56EW/VUYs7uBvdl2fkfZFu0T9wgjM=
github.com/transip/gotransip/v6 v6.2.0/go.mod h1:pQZ36hWWRahCUXkFWlx9Hs711gLd8J4qdgLdRzmtY+g=
github.com/uber-go/atomic v1.3.2/go.mod h1:/Ct5t2lcmbJ4OSe/waGBoaVvVqtO0bmtfVNex1PFV8g=
github.com/urfave/cli v1.22.4/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
@@ -313,6 +329,7 @@ github.com/vultr/govultr v0.5.0/go.mod h1:wZZXZbYbqyY1n3AldoeYNZK4Wnmmoq6dNFkvd5
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
@@ -356,6 +373,7 @@ golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHl
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
@@ -363,6 +381,7 @@ golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -389,8 +408,11 @@ golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200822124328-c89045814202 h1:VvcQYSHwXgi7W+TpUR6A9g6Up98WAHf3f/ulnJ62IyA=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210614182718-04defd469f4e h1:XpT3nA5TvE525Ne3hInMh6+GETgn27Zfm9dxsThnX2Q=
golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -401,8 +423,9 @@ 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-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180622082034-63fc586f45fe/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-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -437,13 +460,24 @@ golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299 h1:DYfZAGf2WMFjMxbgTjaC+2HC7NkNAQs+6Q8b9WEB/F4=
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210316164454-77fc1eacc6aa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22 h1:RqytpXGR1iVNX7psjB3ff8y7sNFinVFvkx1c8SjBkio=
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/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.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
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.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@@ -482,10 +516,12 @@ golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapK
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
@@ -521,8 +557,9 @@ google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20210617175327-b9e0b3197ced h1:c5geK1iMU3cDKtFrCVQIcjR3W+JOZMuhIyICMCTbtus=
google.golang.org/genproto v0.0.0-20210617175327-b9e0b3197ced/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24=
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.19.1/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
@@ -534,8 +571,9 @@ google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.32.0 h1:zWTV+LMdc3kaiJMSTOFz2UgSBgx8RNQoTGiZu3fR9S0=
google.golang.org/grpc v1.32.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.38.0 h1:/9BgsAsa5nWe26HqOlvlgJnqBuktYOLCgjCPqsa56W0=
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
@@ -544,8 +582,10 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@@ -573,9 +613,8 @@ gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ=
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

View File

@@ -0,0 +1,66 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package accesslogs
import (
"encoding/json"
"fmt"
"github.com/TeaOSLab/EdgeCommon/pkg/configutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"strconv"
"time"
)
type BaseStorage struct {
isOk bool
version int
}
func (this *BaseStorage) SetVersion(version int) {
this.version = version
}
func (this *BaseStorage) Version() int {
return this.version
}
func (this *BaseStorage) IsOk() bool {
return this.isOk
}
func (this *BaseStorage) SetOk(isOk bool) {
this.isOk = isOk
}
// Marshal 对日志进行编码
func (this *BaseStorage) Marshal(accessLog *pb.HTTPAccessLog) ([]byte, error) {
return json.Marshal(accessLog)
}
// FormatVariables 格式化字符串中的变量
func (this *BaseStorage) FormatVariables(s string) string {
now := time.Now()
return configutils.ParseVariables(s, func(varName string) (value string) {
switch varName {
case "year":
return strconv.Itoa(now.Year())
case "month":
return fmt.Sprintf("%02d", now.Month())
case "week":
_, week := now.ISOWeek()
return fmt.Sprintf("%02d", week)
case "day":
return fmt.Sprintf("%02d", now.Day())
case "hour":
return fmt.Sprintf("%02d", now.Hour())
case "minute":
return fmt.Sprintf("%02d", now.Minute())
case "second":
return fmt.Sprintf("%02d", now.Second())
case "date":
return fmt.Sprintf("%d%02d%02d", now.Year(), now.Month(), now.Day())
}
return varName
})
}

View File

@@ -0,0 +1,95 @@
package accesslogs
import (
"bytes"
"errors"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/iwind/TeaGo/logs"
"os/exec"
"sync"
)
// CommandStorage 通过命令行存储
type CommandStorage struct {
BaseStorage
config *serverconfigs.AccessLogCommandStorageConfig
writeLocker sync.Mutex
}
func NewCommandStorage(config *serverconfigs.AccessLogCommandStorageConfig) *CommandStorage {
return &CommandStorage{config: config}
}
func (this *CommandStorage) Config() interface{} {
return this.config
}
// Start 启动
func (this *CommandStorage) Start() error {
if len(this.config.Command) == 0 {
return errors.New("'command' should not be empty")
}
return nil
}
// 写入日志
func (this *CommandStorage) Write(accessLogs []*pb.HTTPAccessLog) error {
if len(accessLogs) == 0 {
return nil
}
this.writeLocker.Lock()
defer this.writeLocker.Unlock()
cmd := exec.Command(this.config.Command, this.config.Args...)
if len(this.config.Dir) > 0 {
cmd.Dir = this.config.Dir
}
stdout := bytes.NewBuffer([]byte{})
cmd.Stdout = stdout
w, err := cmd.StdinPipe()
if err != nil {
return err
}
err = cmd.Start()
if err != nil {
return err
}
for _, accessLog := range accessLogs {
data, err := this.Marshal(accessLog)
if err != nil {
logs.Error(err)
continue
}
_, err = w.Write(data)
if err != nil {
logs.Error(err)
}
_, err = w.Write([]byte("\n"))
if err != nil {
logs.Error(err)
}
}
_ = w.Close()
err = cmd.Wait()
if err != nil {
logs.Error(err)
if stdout.Len() > 0 {
logs.Error(errors.New(string(stdout.Bytes())))
}
}
return nil
}
// Close 关闭
func (this *CommandStorage) Close() error {
return nil
}

View File

@@ -0,0 +1,63 @@
package accesslogs
import (
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"os"
"os/exec"
"testing"
"time"
)
func TestCommandStorage_Write(t *testing.T) {
php, err := exec.LookPath("php")
if err != nil { // not found php, so we can not test
t.Log("php:", err)
return
}
cwd, err := os.Getwd()
if err != nil {
t.Fatal(err)
}
before := time.Now()
storage := NewCommandStorage(&serverconfigs.AccessLogCommandStorageConfig{
Command: php,
Args: []string{cwd + "/tests/command_storage.php"},
})
err = storage.Start()
if err != nil {
t.Fatal(err)
}
err = storage.Write([]*pb.HTTPAccessLog{
{
RequestMethod: "GET",
RequestPath: "/hello",
},
{
RequestMethod: "GET",
RequestPath: "/world",
},
{
RequestMethod: "GET",
RequestPath: "/lu",
},
{
RequestMethod: "GET",
RequestPath: "/ping",
},
})
if err != nil {
t.Fatal(err)
}
err = storage.Close()
if err != nil {
t.Fatal(err)
}
t.Log(time.Since(before).Seconds(), "seconds")
}

View File

@@ -0,0 +1,131 @@
package accesslogs
import (
"encoding/base64"
"encoding/json"
"errors"
"fmt"
teaconst "github.com/TeaOSLab/EdgeAPI/internal/const"
"github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
"github.com/TeaOSLab/EdgeAPI/internal/utils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"io/ioutil"
"net/http"
"regexp"
"strconv"
"strings"
"sync/atomic"
"time"
)
// ESStorage ElasticSearch存储策略
type ESStorage struct {
BaseStorage
config *serverconfigs.AccessLogESStorageConfig
}
func NewESStorage(config *serverconfigs.AccessLogESStorageConfig) *ESStorage {
return &ESStorage{config: config}
}
func (this *ESStorage) Config() interface{} {
return this.config
}
// Start 开启
func (this *ESStorage) Start() error {
if len(this.config.Endpoint) == 0 {
return errors.New("'endpoint' should not be nil")
}
if !regexp.MustCompile(`(?i)^(http|https)://`).MatchString(this.config.Endpoint) {
this.config.Endpoint = "http://" + this.config.Endpoint
}
if len(this.config.Index) == 0 {
return errors.New("'index' should not be nil")
}
if len(this.config.MappingType) == 0 {
return errors.New("'mappingType' should not be nil")
}
return nil
}
// 写入日志
func (this *ESStorage) Write(accessLogs []*pb.HTTPAccessLog) error {
if len(accessLogs) == 0 {
return nil
}
var requestId int64 = 1_0000_0000_0000_0000
bulk := &strings.Builder{}
indexName := this.FormatVariables(this.config.Index)
typeName := this.FormatVariables(this.config.MappingType)
for _, accessLog := range accessLogs {
if len(accessLog.RequestId) == 0 {
accessLog.RequestId = strconv.FormatInt(time.Now().UnixNano(), 10) + strconv.FormatInt(atomic.AddInt64(&requestId, 1), 10) + fmt.Sprintf("%08d", 1)
}
opData, err := json.Marshal(map[string]interface{}{
"index": map[string]interface{}{
"_index": indexName,
"_type": typeName,
"_id": accessLog.RequestId,
},
})
if err != nil {
remotelogs.Error("ACCESS_LOG_ES_STORAGE", "write failed: "+err.Error())
continue
}
data, err := this.Marshal(accessLog)
if err != nil {
remotelogs.Error("ACCESS_LOG_ES_STORAGE", "marshal data failed: "+err.Error())
continue
}
bulk.Write(opData)
bulk.WriteString("\n")
bulk.Write(data)
bulk.WriteString("\n")
}
if bulk.Len() == 0 {
return nil
}
req, err := http.NewRequest(http.MethodPost, this.config.Endpoint+"/_bulk", strings.NewReader(bulk.String()))
if err != nil {
return err
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("User-Agent", strings.ReplaceAll(teaconst.ProductName, " ", "-")+"/"+teaconst.Version)
if len(this.config.Username) > 0 || len(this.config.Password) > 0 {
req.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(this.config.Username+":"+this.config.Password)))
}
client := utils.SharedHttpClient(10 * time.Second)
defer func() {
_ = req.Body.Close()
}()
resp, err := client.Do(req)
if err != nil {
return err
}
defer func() {
_ = resp.Body.Close()
}()
if resp.StatusCode != http.StatusOK {
bodyData, _ := ioutil.ReadAll(resp.Body)
return errors.New("ElasticSearch response status code: " + fmt.Sprintf("%d", resp.StatusCode) + " content: " + string(bodyData))
}
return nil
}
// Close 关闭
func (this *ESStorage) Close() error {
return nil
}

View File

@@ -0,0 +1,53 @@
package accesslogs
import (
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"testing"
"time"
)
func TestESStorage_Write(t *testing.T) {
storage := NewESStorage(&serverconfigs.AccessLogESStorageConfig{
Endpoint: "http://127.0.0.1:9200",
Index: "logs",
MappingType: "accessLogs",
Username: "hello",
Password: "world",
})
err := storage.Start()
if err != nil {
t.Fatal(err)
}
{
err = storage.Write([]*pb.HTTPAccessLog{
{
RequestMethod: "POST",
RequestPath: "/1",
TimeLocal: time.Now().Format("2/Jan/2006:15:04:05 -0700"),
TimeISO8601: "2018-07-23T22:23:35+08:00",
Header: map[string]*pb.Strings{
"Content-Type": {Values: []string{"text/html"}},
},
},
{
RequestMethod: "GET",
RequestPath: "/2",
TimeLocal: time.Now().Format("2/Jan/2006:15:04:05 -0700"),
TimeISO8601: "2018-07-23T22:23:35+08:00",
Header: map[string]*pb.Strings{
"Content-Type": {Values: []string{"text/css"}},
},
},
})
if err != nil {
t.Fatal(err)
}
}
err = storage.Close()
if err != nil {
t.Fatal(err)
}
}

View File

@@ -0,0 +1,127 @@
package accesslogs
import (
"errors"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/iwind/TeaGo/logs"
"os"
"path/filepath"
"sync"
)
// FileStorage 文件存储策略
type FileStorage struct {
BaseStorage
config *serverconfigs.AccessLogFileStorageConfig
writeLocker sync.Mutex
files map[string]*os.File // path => *File
filesLocker sync.Mutex
}
func NewFileStorage(config *serverconfigs.AccessLogFileStorageConfig) *FileStorage {
return &FileStorage{
config: config,
}
}
func (this *FileStorage) Config() interface{} {
return this.config
}
// Start 开启
func (this *FileStorage) Start() error {
if len(this.config.Path) == 0 {
return errors.New("'path' should not be empty")
}
this.files = map[string]*os.File{}
return nil
}
// Write 写入日志
func (this *FileStorage) Write(accessLogs []*pb.HTTPAccessLog) error {
if len(accessLogs) == 0 {
return nil
}
fp := this.fp()
if fp == nil {
return errors.New("file pointer should not be nil")
}
this.writeLocker.Lock()
defer this.writeLocker.Unlock()
for _, accessLog := range accessLogs {
data, err := this.Marshal(accessLog)
if err != nil {
logs.Error(err)
continue
}
_, err = fp.Write(data)
if err != nil {
_ = this.Close()
break
}
_, _ = fp.WriteString("\n")
}
return nil
}
// Close 关闭
func (this *FileStorage) Close() error {
this.filesLocker.Lock()
defer this.filesLocker.Unlock()
var resultErr error
for _, f := range this.files {
err := f.Close()
if err != nil {
resultErr = err
}
}
return resultErr
}
func (this *FileStorage) fp() *os.File {
path := this.FormatVariables(this.config.Path)
this.filesLocker.Lock()
defer this.filesLocker.Unlock()
fp, ok := this.files[path]
if ok {
return fp
}
// 关闭其他的文件
for _, f := range this.files {
_ = f.Close()
}
// 是否创建文件目录
if this.config.AutoCreate {
dir := filepath.Dir(path)
_, err := os.Stat(dir)
if os.IsNotExist(err) {
err = os.MkdirAll(dir, 0777)
if err != nil {
logs.Error(err)
return nil
}
}
}
// 打开新文件
fp, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
if err != nil {
logs.Error(err)
return nil
}
this.files[path] = fp
return fp
}

View File

@@ -0,0 +1,70 @@
package accesslogs
import (
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/iwind/TeaGo/Tea"
"testing"
"time"
)
func TestFileStorage_Write(t *testing.T) {
storage := NewFileStorage(&serverconfigs.AccessLogFileStorageConfig{
Path: Tea.Root + "/logs/access-${date}.log",
})
err := storage.Start()
if err != nil {
t.Fatal(err)
}
{
err = storage.Write([]*pb.HTTPAccessLog{
{
RequestPath: "/hello",
},
{
RequestPath: "/world",
},
})
if err != nil {
t.Fatal(err)
}
}
{
err = storage.Write([]*pb.HTTPAccessLog{
{
RequestPath: "/1",
},
{
RequestPath: "/2",
},
})
if err != nil {
t.Fatal(err)
}
}
{
err = storage.Write([]*pb.HTTPAccessLog{
{
RequestMethod: "POST",
RequestPath: "/1",
TimeLocal: time.Now().Format("2/Jan/2006:15:04:05 -0700"),
},
{
RequestMethod: "GET",
RequestPath: "/2",
TimeLocal: time.Now().Format("2/Jan/2006:15:04:05 -0700"),
},
})
if err != nil {
t.Fatal(err)
}
}
err = storage.Close()
if err != nil {
t.Fatal(err)
}
}

View File

@@ -0,0 +1,30 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package accesslogs
import "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
// StorageInterface 日志存储接口
type StorageInterface interface {
// Version 获取版本
Version() int
// SetVersion 设置版本
SetVersion(version int)
IsOk() bool
SetOk(ok bool)
// Config 获取配置
Config() interface{}
// Start 开启
Start() error
// Write 写入日志
Write(accessLogs []*pb.HTTPAccessLog) error
// Close 关闭
Close() error
}

View File

@@ -0,0 +1,199 @@
package accesslogs
import (
"encoding/json"
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
"github.com/TeaOSLab/EdgeAPI/internal/errors"
"github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/lists"
"github.com/iwind/TeaGo/types"
"sync"
"time"
)
var SharedStorageManager = NewStorageManager()
type StorageManager struct {
storageMap map[int64]StorageInterface // policyId => Storage
locker sync.Mutex
}
func NewStorageManager() *StorageManager {
return &StorageManager{
storageMap: map[int64]StorageInterface{},
}
}
func (this *StorageManager) Start() {
var ticker = time.NewTicker(1 * time.Minute)
if Tea.IsTesting() {
ticker = time.NewTicker(5 * time.Second)
}
// 启动时执行一次
var err = this.Loop()
if err != nil {
remotelogs.Error("ACCESS_LOG_STORAGE_MANAGER", "update error: "+err.Error())
}
// 循环执行
for range ticker.C {
err := this.Loop()
if err != nil {
remotelogs.Error("ACCESS_LOG_STORAGE_MANAGER", "update error: "+err.Error())
}
}
}
// 写入日志
func (this *StorageManager) Write(policyId int64, accessLogs []*pb.HTTPAccessLog) error {
this.locker.Lock()
storage, ok := this.storageMap[policyId]
this.locker.Unlock()
if !ok {
return nil
}
if !storage.IsOk() {
return nil
}
return storage.Write(accessLogs)
}
// Loop 更新
func (this *StorageManager) Loop() error {
policies, err := models.SharedHTTPAccessLogPolicyDAO.FindAllEnabledAndOnPolicies(nil)
if err != nil {
return err
}
var policyIds = []int64{}
for _, policy := range policies {
if policy.IsOn == 1 {
policyIds = append(policyIds, int64(policy.Id))
}
}
this.locker.Lock()
defer this.locker.Unlock()
// 关闭不用的
for policyId, storage := range this.storageMap {
if !lists.ContainsInt64(policyIds, policyId) {
err := storage.Close()
if err != nil {
remotelogs.Error("ACCESS_LOG_STORAGE_MANAGER", "close '"+types.String(policyId)+"' failed: "+err.Error())
}
delete(this.storageMap, policyId)
remotelogs.Error("ACCESS_LOG_STORAGE_MANAGER", "remove '"+types.String(policyId)+"'")
}
}
for _, policy := range policies {
var policyId = int64(policy.Id)
storage, ok := this.storageMap[policyId]
if ok {
// 检查配置是否有变更
if types.Int(policy.Version) != storage.Version() {
err = storage.Close()
if err != nil {
remotelogs.Error("ACCESS_LOG_STORAGE_MANAGER", "close policy '"+types.String(policyId)+"' failed: "+err.Error())
// 继续往下执行
}
if len(policy.Options) > 0 {
err = json.Unmarshal([]byte(policy.Options), storage.Config())
if err != nil {
remotelogs.Error("ACCESS_LOG_STORAGE_MANAGER", "unmarshal policy '"+types.String(policyId)+"' config failed: "+err.Error())
storage.SetOk(false)
continue
}
}
storage.SetVersion(types.Int(policy.Version))
err := storage.Start()
if err != nil {
remotelogs.Error("ACCESS_LOG_STORAGE_MANAGER", "start policy '"+types.String(policyId)+"' failed: "+err.Error())
continue
}
storage.SetOk(true)
remotelogs.Println("ACCESS_LOG_STORAGE_MANAGER", "restart policy '"+types.String(policyId)+"'")
}
} else {
storage, err := this.createStorage(policy.Type, []byte(policy.Options))
if err != nil {
remotelogs.Error("ACCESS_LOG_STORAGE_MANAGER", "create policy '"+types.String(policyId)+"' failed: "+err.Error())
continue
}
storage.SetVersion(types.Int(policy.Version))
this.storageMap[policyId] = storage
err = storage.Start()
if err != nil {
remotelogs.Error("ACCESS_LOG_STORAGE_MANAGER", "start policy '"+types.String(policyId)+"' failed: "+err.Error())
continue
}
storage.SetOk(true)
remotelogs.Println("ACCESS_LOG_STORAGE_MANAGER", "start policy '"+types.String(policyId)+"'")
}
}
return nil
}
func (this *StorageManager) createStorage(storageType string, optionsJSON []byte) (StorageInterface, error) {
switch storageType {
case serverconfigs.AccessLogStorageTypeFile:
var config = &serverconfigs.AccessLogFileStorageConfig{}
if len(optionsJSON) > 0 {
err := json.Unmarshal(optionsJSON, config)
if err != nil {
return nil, err
}
}
return NewFileStorage(config), nil
case serverconfigs.AccessLogStorageTypeES:
var config = &serverconfigs.AccessLogESStorageConfig{}
if len(optionsJSON) > 0 {
err := json.Unmarshal(optionsJSON, config)
if err != nil {
return nil, err
}
}
return NewESStorage(config), nil
case serverconfigs.AccessLogStorageTypeTCP:
var config = &serverconfigs.AccessLogTCPStorageConfig{}
if len(optionsJSON) > 0 {
err := json.Unmarshal(optionsJSON, config)
if err != nil {
return nil, err
}
}
return NewTCPStorage(config), nil
case serverconfigs.AccessLogStorageTypeSyslog:
var config = &serverconfigs.AccessLogSyslogStorageConfig{}
if len(optionsJSON) > 0 {
err := json.Unmarshal(optionsJSON, config)
if err != nil {
return nil, err
}
}
return NewSyslogStorage(config), nil
case serverconfigs.AccessLogStorageTypeCommand:
var config = &serverconfigs.AccessLogCommandStorageConfig{}
if len(optionsJSON) > 0 {
err := json.Unmarshal(optionsJSON, config)
if err != nil {
return nil, err
}
}
return NewCommandStorage(config), nil
}
return nil, errors.New("invalid policy type '" + storageType + "'")
}

View File

@@ -0,0 +1,17 @@
package accesslogs
import (
"github.com/iwind/TeaGo/dbs"
"testing"
)
func TestStorageManager_Loop(t *testing.T) {
dbs.NotifyReady()
var storage = NewStorageManager()
err := storage.Loop()
if err != nil {
t.Fatal(err)
}
t.Log(storage.storageMap)
}

View File

@@ -0,0 +1,137 @@
package accesslogs
import (
"errors"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/iwind/TeaGo/logs"
"os/exec"
"runtime"
"strconv"
)
type SyslogStorageProtocol = string
const (
SyslogStorageProtocolTCP SyslogStorageProtocol = "tcp"
SyslogStorageProtocolUDP SyslogStorageProtocol = "udp"
SyslogStorageProtocolNone SyslogStorageProtocol = "none"
SyslogStorageProtocolSocket SyslogStorageProtocol = "socket"
)
type SyslogStoragePriority = int
// SyslogStorage syslog存储策略
type SyslogStorage struct {
BaseStorage
config *serverconfigs.AccessLogSyslogStorageConfig
exe string
}
func NewSyslogStorage(config *serverconfigs.AccessLogSyslogStorageConfig) *SyslogStorage {
return &SyslogStorage{config: config}
}
func (this *SyslogStorage) Config() interface{} {
return this.config
}
// Start 开启
func (this *SyslogStorage) Start() error {
if runtime.GOOS != "linux" {
return errors.New("'syslog' storage only works on linux")
}
exe, err := exec.LookPath("logger")
if err != nil {
return err
}
this.exe = exe
return nil
}
// 写入日志
func (this *SyslogStorage) Write(accessLogs []*pb.HTTPAccessLog) error {
if len(accessLogs) == 0 {
return nil
}
args := []string{}
if len(this.config.Tag) > 0 {
args = append(args, "-t", this.config.Tag)
}
if this.config.Priority >= 0 {
args = append(args, "-p", strconv.Itoa(this.config.Priority))
}
switch this.config.Protocol {
case SyslogStorageProtocolTCP:
args = append(args, "-T")
if len(this.config.ServerAddr) > 0 {
args = append(args, "-n", this.config.ServerAddr)
}
if this.config.ServerPort > 0 {
args = append(args, "-P", strconv.Itoa(this.config.ServerPort))
}
case SyslogStorageProtocolUDP:
args = append(args, "-d")
if len(this.config.ServerAddr) > 0 {
args = append(args, "-n", this.config.ServerAddr)
}
if this.config.ServerPort > 0 {
args = append(args, "-P", strconv.Itoa(this.config.ServerPort))
}
case SyslogStorageProtocolSocket:
args = append(args, "-u")
args = append(args, this.config.Socket)
case SyslogStorageProtocolNone:
// do nothing
}
args = append(args, "-S", "10240")
cmd := exec.Command(this.exe, args...)
w, err := cmd.StdinPipe()
if err != nil {
return err
}
err = cmd.Start()
if err != nil {
return err
}
for _, accessLog := range accessLogs {
data, err := this.Marshal(accessLog)
if err != nil {
logs.Error(err)
continue
}
_, err = w.Write(data)
if err != nil {
logs.Error(err)
}
_, err = w.Write([]byte("\n"))
if err != nil {
logs.Error(err)
}
}
_ = w.Close()
err = cmd.Wait()
if err != nil {
return err
}
return nil
}
// Close 关闭
func (this *SyslogStorage) Close() error {
return nil
}

View File

@@ -0,0 +1,111 @@
package accesslogs
import (
"errors"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/iwind/TeaGo/logs"
"net"
"sync"
)
// TCPStorage TCP存储策略
type TCPStorage struct {
BaseStorage
config *serverconfigs.AccessLogTCPStorageConfig
writeLocker sync.Mutex
connLocker sync.Mutex
conn net.Conn
}
func NewTCPStorage(config *serverconfigs.AccessLogTCPStorageConfig) *TCPStorage {
return &TCPStorage{config: config}
}
func (this *TCPStorage) Config() interface{} {
return this.config
}
// Start 开启
func (this *TCPStorage) Start() error {
if len(this.config.Network) == 0 {
return errors.New("'network' should not be empty")
}
if len(this.config.Addr) == 0 {
return errors.New("'addr' should not be empty")
}
return nil
}
// 写入日志
func (this *TCPStorage) Write(accessLogs []*pb.HTTPAccessLog) error {
if len(accessLogs) == 0 {
return nil
}
err := this.connect()
if err != nil {
return err
}
conn := this.conn
if conn == nil {
return errors.New("connection should not be nil")
}
this.writeLocker.Lock()
defer this.writeLocker.Unlock()
for _, accessLog := range accessLogs {
data, err := this.Marshal(accessLog)
if err != nil {
logs.Error(err)
continue
}
_, err = conn.Write(data)
if err != nil {
_ = this.Close()
break
}
_, err = conn.Write([]byte("\n"))
if err != nil {
_ = this.Close()
break
}
}
return nil
}
// Close 关闭
func (this *TCPStorage) Close() error {
this.connLocker.Lock()
defer this.connLocker.Unlock()
if this.conn != nil {
err := this.conn.Close()
this.conn = nil
return err
}
return nil
}
func (this *TCPStorage) connect() error {
this.connLocker.Lock()
defer this.connLocker.Unlock()
if this.conn != nil {
return nil
}
conn, err := net.Dial(this.config.Network, this.config.Addr)
if err != nil {
return err
}
this.conn = conn
return nil
}

View File

@@ -0,0 +1,72 @@
package accesslogs
import (
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"net"
"testing"
"time"
)
func TestTCPStorage_Write(t *testing.T) {
go func() {
server, err := net.Listen("tcp", "127.0.0.1:9981")
if err != nil {
t.Error(err)
return
}
for {
conn, err := server.Accept()
if err != nil {
break
}
buf := make([]byte, 1024)
for {
n, err := conn.Read(buf)
if n > 0 {
t.Log(string(buf[:n]))
}
if err != nil {
break
}
}
break
}
_ = server.Close()
}()
storage := NewTCPStorage(&serverconfigs.AccessLogTCPStorageConfig{
Network: "tcp",
Addr: "127.0.0.1:9981",
})
err := storage.Start()
if err != nil {
t.Fatal(err)
}
{
err = storage.Write([]*pb.HTTPAccessLog{
{
RequestMethod: "POST",
RequestPath: "/1",
TimeLocal: time.Now().Format("2/Jan/2006:15:04:05 -0700"),
},
{
RequestMethod: "GET",
RequestPath: "/2",
TimeLocal: time.Now().Format("2/Jan/2006:15:04:05 -0700"),
},
})
if err != nil {
t.Fatal(err)
}
}
time.Sleep(2 * time.Second)
err = storage.Close()
if err != nil {
t.Fatal(err)
}
}

View File

@@ -0,0 +1,24 @@
<?php
// test command storage
// open access log file
$fp = fopen("/tmp/goedge-command-storage.log", "a+");
// read access logs from stdin
$stdin = fopen("php://stdin", "r");
while(true) {
if (feof($stdin)) {
break;
}
$line = fgets($stdin);
// write to access log file
fwrite($fp, $line);
}
// close file pointers
fclose($fp);
fclose($stdin);
?>

View File

@@ -2,6 +2,7 @@ package acme
import (
"github.com/TeaOSLab/EdgeAPI/internal/dnsclients"
"github.com/TeaOSLab/EdgeAPI/internal/dnsclients/dnstypes"
"github.com/TeaOSLab/EdgeAPI/internal/errors"
"github.com/go-acme/lego/v4/challenge/dns01"
"strings"
@@ -24,15 +25,15 @@ func (this *DNSProvider) Present(domain, token, keyAuth string) error {
return errors.New("invalid fqdn value")
}
recordName := fqdn[:index]
record, err := this.raw.QueryRecord(domain, recordName, dnsclients.RecordTypeTXT)
record, err := this.raw.QueryRecord(domain, recordName, dnstypes.RecordTypeTXT)
if err != nil {
return errors.New("query DNS record failed: " + err.Error())
}
if record == nil {
err = this.raw.AddRecord(domain, &dnsclients.Record{
err = this.raw.AddRecord(domain, &dnstypes.Record{
Id: "",
Name: recordName,
Type: dnsclients.RecordTypeTXT,
Type: dnstypes.RecordTypeTXT,
Value: value,
Route: this.raw.DefaultRoute(),
})
@@ -40,9 +41,9 @@ func (this *DNSProvider) Present(domain, token, keyAuth string) error {
return errors.New("create DNS record failed: " + err.Error())
}
} else {
err = this.raw.UpdateRecord(domain, record, &dnsclients.Record{
err = this.raw.UpdateRecord(domain, record, &dnstypes.Record{
Name: recordName,
Type: dnsclients.RecordTypeTXT,
Type: dnstypes.RecordTypeTXT,
Value: value,
Route: this.raw.DefaultRoute(),
})

View File

@@ -39,7 +39,7 @@ func TestRequest_Run_DNS(t *testing.T) {
req := NewRequest(&Task{
User: user,
Type: TaskTypeDNS,
AuthType: AuthTypeDNS,
DNSProvider: dnsProvider,
DNSDomain: "yun4s.cn",
Domains: []string{"yun4s.cn"},
@@ -74,9 +74,9 @@ func TestRequest_Run_HTTP(t *testing.T) {
}
req := NewRequest(&Task{
User: user,
Type: TaskTypeHTTP,
Domains: []string{"teaos.cn", "www.teaos.cn", "meloy.cn"},
User: user,
AuthType: AuthTypeHTTP,
Domains: []string{"teaos.cn", "www.teaos.cn", "meloy.cn"},
})
certData, keyData, err := req.runHTTP()
if err != nil {

View File

@@ -2,8 +2,11 @@ package apps
import (
"fmt"
"github.com/iwind/TeaGo/Tea"
teaconst "github.com/TeaOSLab/EdgeAPI/internal/const"
"github.com/iwind/TeaGo/logs"
"github.com/iwind/TeaGo/maps"
"github.com/iwind/TeaGo/types"
"github.com/iwind/gosock/pkg/gosock"
"os"
"os/exec"
"runtime"
@@ -11,7 +14,7 @@ import (
"time"
)
// App命令帮助
// AppCmd App命令帮助
type AppCmd struct {
product string
version string
@@ -20,10 +23,14 @@ type AppCmd struct {
appendStrings []string
directives []*Directive
sock *gosock.Sock
}
func NewAppCmd() *AppCmd {
return &AppCmd{}
return &AppCmd{
sock: gosock.NewTmpSock(teaconst.ProcessName),
}
}
type CommandHelpOption struct {
@@ -31,25 +38,25 @@ type CommandHelpOption struct {
Description string
}
// 产品
// Product 产品
func (this *AppCmd) Product(product string) *AppCmd {
this.product = product
return this
}
// 版本
// Version 版本
func (this *AppCmd) Version(version string) *AppCmd {
this.version = version
return this
}
// 使用方法
// Usage 使用方法
func (this *AppCmd) Usage(usage string) *AppCmd {
this.usage = usage
return this
}
// 选项
// Option 选项
func (this *AppCmd) Option(code string, description string) *AppCmd {
this.options = append(this.options, &CommandHelpOption{
Code: code,
@@ -58,13 +65,13 @@ func (this *AppCmd) Option(code string, description string) *AppCmd {
return this
}
// 附加内容
// Append 附加内容
func (this *AppCmd) Append(appendString string) *AppCmd {
this.appendStrings = append(this.appendStrings, appendString)
return this
}
// 打印
// Print 打印
func (this *AppCmd) Print() {
fmt.Println(this.product + " v" + this.version)
@@ -103,7 +110,7 @@ func (this *AppCmd) Print() {
}
}
// 添加指令
// On 添加指令
func (this *AppCmd) On(arg string, callback func()) {
this.directives = append(this.directives, &Directive{
Arg: arg,
@@ -111,7 +118,7 @@ func (this *AppCmd) On(arg string, callback func()) {
})
}
// 运行
// Run 运行
func (this *AppCmd) Run(main func()) {
// 获取参数
args := os.Args[1:]
@@ -150,9 +157,6 @@ func (this *AppCmd) Run(main func()) {
return
}
// 记录PID
_ = this.writePid()
// 日志
writer := new(LogWriter)
writer.Init()
@@ -164,7 +168,7 @@ func (this *AppCmd) Run(main func()) {
// 版本号
func (this *AppCmd) runVersion() {
fmt.Println(this.product+" v"+this.version, "(build: "+runtime.Version(), runtime.GOOS, runtime.GOARCH+")")
fmt.Println(this.product+" v"+this.version, "(build: "+runtime.Version(), runtime.GOOS, runtime.GOARCH, teaconst.Tag+")")
}
// 帮助
@@ -174,9 +178,9 @@ func (this *AppCmd) runHelp() {
// 启动
func (this *AppCmd) runStart() {
proc := this.checkPid()
if proc != nil {
fmt.Println(this.product+" already started, pid:", proc.Pid)
var pid = this.getPID()
if pid > 0 {
fmt.Println(this.product+" already started, pid:", pid)
return
}
@@ -192,18 +196,15 @@ func (this *AppCmd) runStart() {
// 停止
func (this *AppCmd) runStop() {
proc := this.checkPid()
if proc == nil {
var pid = this.getPID()
if pid == 0 {
fmt.Println(this.product + " not started yet")
return
}
// 停止进程
_ = proc.Kill()
_, _ = this.sock.Send(&gosock.Command{Code: "stop"})
// 在Windows上经常不能及时释放资源
_ = DeletePid(Tea.Root + "/bin/pid")
fmt.Println(this.product+" stopped ok, pid:", proc.Pid)
fmt.Println(this.product+" stopped ok, pid:", types.String(pid))
}
// 重启
@@ -215,20 +216,24 @@ func (this *AppCmd) runRestart() {
// 状态
func (this *AppCmd) runStatus() {
proc := this.checkPid()
if proc == nil {
var pid = this.getPID()
if pid == 0 {
fmt.Println(this.product + " not started yet")
} else {
fmt.Println(this.product + " is running, pid: " + fmt.Sprintf("%d", proc.Pid))
return
}
fmt.Println(this.product + " is running, pid: " + types.String(pid))
}
// 检查PID
func (this *AppCmd) checkPid() *os.Process {
return CheckPid(Tea.Root + "/bin/pid")
}
// 获取当前的PID
func (this *AppCmd) getPID() int {
if !this.sock.IsListening() {
return 0
}
// 写入PID
func (this *AppCmd) writePid() error {
return WritePid(Tea.Root + "/bin/pid")
reply, err := this.sock.Send(&gosock.Command{Code: "pid"})
if err != nil {
return 0
}
return maps.NewMap(reply.Params).GetInt("pid")
}

View File

@@ -1,17 +0,0 @@
// +build !windows
package apps
import (
"os"
"syscall"
)
// lock file
func LockFile(fp *os.File) error {
return syscall.Flock(int(fp.Fd()), syscall.LOCK_EX|syscall.LOCK_NB)
}
func UnlockFile(fp *os.File) error {
return syscall.Flock(int(fp.Fd()), syscall.LOCK_UN)
}

View File

@@ -1,17 +0,0 @@
// +build windows
package apps
import (
"errors"
"os"
)
// lock file
func LockFile(fp *os.File) error {
return errors.New("not implemented on windows")
}
func UnlockFile(fp *os.File) error {
return errors.New("not implemented on windows")
}

View File

@@ -1,113 +0,0 @@
package apps
import (
"fmt"
"github.com/iwind/TeaGo/types"
"io/ioutil"
"os"
"runtime"
)
var pidFileList = []*os.File{}
// 检查Pid
func CheckPid(path string) *os.Process {
// windows上打开的文件是不能删除的
if runtime.GOOS == "windows" {
if os.Remove(path) == nil {
return nil
}
}
file, err := os.Open(path)
if err != nil {
return nil
}
defer func() {
_ = file.Close()
}()
// 是否能取得Lock
err = LockFile(file)
if err == nil {
_ = UnlockFile(file)
return nil
}
pidBytes, err := ioutil.ReadAll(file)
if err != nil {
return nil
}
pid := types.Int(string(pidBytes))
if pid <= 0 {
return nil
}
proc, _ := os.FindProcess(pid)
return proc
}
// 写入Pid
func WritePid(path string) error {
fp, err := os.OpenFile(path, os.O_CREATE|os.O_TRUNC|os.O_WRONLY|os.O_RDONLY, 0666)
if err != nil {
return err
}
if runtime.GOOS != "windows" {
err = LockFile(fp)
if err != nil {
return err
}
}
pidFileList = append(pidFileList, fp) // hold the file pointers
_, err = fp.WriteString(fmt.Sprintf("%d", os.Getpid()))
if err != nil {
return err
}
return nil
}
// 写入Ppid
func WritePpid(path string) error {
fp, err := os.OpenFile(path, os.O_CREATE|os.O_TRUNC|os.O_WRONLY|os.O_RDONLY, 0666)
if err != nil {
return err
}
if runtime.GOOS != "windows" {
err = LockFile(fp)
if err != nil {
return err
}
}
pidFileList = append(pidFileList, fp) // hold the file pointers
_, err = fp.WriteString(fmt.Sprintf("%d", os.Getppid()))
if err != nil {
return err
}
return nil
}
// 删除Pid
func DeletePid(path string) error {
_, err := os.Stat(path)
if err != nil {
if !os.IsNotExist(err) {
return nil
}
return err
}
for _, fp := range pidFileList {
_ = UnlockFile(fp)
_ = fp.Close()
}
return os.Remove(path)
}

8
internal/const/build.go Normal file
View File

@@ -0,0 +1,8 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
// +build community
package teaconst
const BuildCommunity = true
const BuildPlus = false
const Tag = "community"

View File

@@ -1,7 +1,7 @@
package teaconst
const (
Version = "0.1.0"
Version = "0.3.0"
ProductName = "Edge API"
ProcessName = "edge-api"
@@ -18,8 +18,9 @@ const (
// 其他节点版本号,用来检测是否有需要升级的节点
NodeVersion = "0.1.0"
UserNodeVersion = "0.0.7"
AuthorityNodeVersion = "0.0.1"
MonitorNodeVersion = "0.0.1"
NodeVersion = "0.3.0"
UserNodeVersion = "0.0.10"
AuthorityNodeVersion = "0.0.2"
MonitorNodeVersion = "0.0.3"
DNSNodeVersion = "0.2.0"
)

8
internal/const/vars.go Normal file
View File

@@ -0,0 +1,8 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package teaconst
var (
IsPlus = false
MaxNodes int32 = 0
)

View File

@@ -33,7 +33,7 @@ func TestDB_Instance(t *testing.T) {
if err == driver.ErrBadConn {
return
}
t.Fatal(i, "exec:", err)
t.Error(i, "exec:", err)
}
time.Sleep(1 * time.Second)
}

View File

@@ -1,6 +1,7 @@
package acme
import (
"bytes"
"encoding/json"
"github.com/TeaOSLab/EdgeAPI/internal/acme"
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
@@ -8,13 +9,17 @@ import (
dbutils "github.com/TeaOSLab/EdgeAPI/internal/db/utils"
"github.com/TeaOSLab/EdgeAPI/internal/dnsclients"
"github.com/TeaOSLab/EdgeAPI/internal/errors"
"github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
"github.com/TeaOSLab/EdgeAPI/internal/utils"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/sslconfigs"
"github.com/go-acme/lego/v4/registration"
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/logs"
"github.com/iwind/TeaGo/maps"
"github.com/iwind/TeaGo/types"
"net/http"
"time"
)
@@ -44,7 +49,7 @@ func init() {
})
}
// 启用条目
// EnableACMETask 启用条目
func (this *ACMETaskDAO) EnableACMETask(tx *dbs.Tx, id int64) error {
_, err := this.Query(tx).
Pk(id).
@@ -53,7 +58,7 @@ func (this *ACMETaskDAO) EnableACMETask(tx *dbs.Tx, id int64) error {
return err
}
// 禁用条目
// DisableACMETask 禁用条目
func (this *ACMETaskDAO) DisableACMETask(tx *dbs.Tx, id int64) error {
_, err := this.Query(tx).
Pk(id).
@@ -62,7 +67,7 @@ func (this *ACMETaskDAO) DisableACMETask(tx *dbs.Tx, id int64) error {
return err
}
// 查找启用中的条目
// FindEnabledACMETask 查找启用中的条目
func (this *ACMETaskDAO) FindEnabledACMETask(tx *dbs.Tx, id int64) (*ACMETask, error) {
result, err := this.Query(tx).
Pk(id).
@@ -74,7 +79,7 @@ func (this *ACMETaskDAO) FindEnabledACMETask(tx *dbs.Tx, id int64) (*ACMETask, e
return result.(*ACMETask), err
}
// 计算某个ACME用户相关的任务数量
// CountACMETasksWithACMEUserId 计算某个ACME用户相关的任务数量
func (this *ACMETaskDAO) CountACMETasksWithACMEUserId(tx *dbs.Tx, acmeUserId int64) (int64, error) {
return this.Query(tx).
State(ACMETaskStateEnabled).
@@ -82,7 +87,7 @@ func (this *ACMETaskDAO) CountACMETasksWithACMEUserId(tx *dbs.Tx, acmeUserId int
Count()
}
// 计算某个DNS服务商相关的任务数量
// CountACMETasksWithDNSProviderId 计算某个DNS服务商相关的任务数量
func (this *ACMETaskDAO) CountACMETasksWithDNSProviderId(tx *dbs.Tx, dnsProviderId int64) (int64, error) {
return this.Query(tx).
State(ACMETaskStateEnabled).
@@ -90,7 +95,7 @@ func (this *ACMETaskDAO) CountACMETasksWithDNSProviderId(tx *dbs.Tx, dnsProvider
Count()
}
// 停止某个证书相关任务
// DisableAllTasksWithCertId 停止某个证书相关任务
func (this *ACMETaskDAO) DisableAllTasksWithCertId(tx *dbs.Tx, certId int64) error {
_, err := this.Query(tx).
Attr("certId", certId).
@@ -99,7 +104,7 @@ func (this *ACMETaskDAO) DisableAllTasksWithCertId(tx *dbs.Tx, certId int64) err
return err
}
// 计算所有任务数量
// CountAllEnabledACMETasks 计算所有任务数量
func (this *ACMETaskDAO) CountAllEnabledACMETasks(tx *dbs.Tx, adminId int64, userId int64, isAvailable bool, isExpired bool, expiringDays int64, keyword string) (int64, error) {
query := dbutils.NewQuery(tx, this, adminId, userId)
if isAvailable || isExpired || expiringDays > 0 {
@@ -130,7 +135,7 @@ func (this *ACMETaskDAO) CountAllEnabledACMETasks(tx *dbs.Tx, adminId int64, use
Count()
}
// 列出单页任务
// ListEnabledACMETasks 列出单页任务
func (this *ACMETaskDAO) ListEnabledACMETasks(tx *dbs.Tx, adminId int64, userId int64, isAvailable bool, isExpired bool, expiringDays int64, keyword string, offset int64, size int64) (result []*ACMETask, err error) {
query := dbutils.NewQuery(tx, this, adminId, userId)
if isAvailable || isExpired || expiringDays > 0 {
@@ -161,8 +166,8 @@ func (this *ACMETaskDAO) ListEnabledACMETasks(tx *dbs.Tx, adminId int64, userId
return
}
// 创建任务
func (this *ACMETaskDAO) CreateACMETask(tx *dbs.Tx, adminId int64, userId int64, authType acme.AuthType, acmeUserId int64, dnsProviderId int64, dnsDomain string, domains []string, autoRenew bool) (int64, error) {
// CreateACMETask 创建任务
func (this *ACMETaskDAO) CreateACMETask(tx *dbs.Tx, adminId int64, userId int64, authType acme.AuthType, acmeUserId int64, dnsProviderId int64, dnsDomain string, domains []string, autoRenew bool, authURL string) (int64, error) {
op := NewACMETaskOperator()
op.AdminId = adminId
op.UserId = userId
@@ -182,6 +187,7 @@ func (this *ACMETaskDAO) CreateACMETask(tx *dbs.Tx, adminId int64, userId int64,
}
op.AutoRenew = autoRenew
op.AuthURL = authURL
op.IsOn = true
op.State = ACMETaskStateEnabled
err := this.Save(tx, op)
@@ -191,8 +197,8 @@ func (this *ACMETaskDAO) CreateACMETask(tx *dbs.Tx, adminId int64, userId int64,
return types.Int64(op.Id), nil
}
// 修改任务
func (this *ACMETaskDAO) UpdateACMETask(tx *dbs.Tx, acmeTaskId int64, acmeUserId int64, dnsProviderId int64, dnsDomain string, domains []string, autoRenew bool) error {
// UpdateACMETask 修改任务
func (this *ACMETaskDAO) UpdateACMETask(tx *dbs.Tx, acmeTaskId int64, acmeUserId int64, dnsProviderId int64, dnsDomain string, domains []string, autoRenew bool, authURL string) error {
if acmeTaskId <= 0 {
return errors.New("invalid acmeTaskId")
}
@@ -214,11 +220,12 @@ func (this *ACMETaskDAO) UpdateACMETask(tx *dbs.Tx, acmeTaskId int64, acmeUserId
}
op.AutoRenew = autoRenew
op.AuthURL = authURL
err := this.Save(tx, op)
return err
}
// 检查权限
// CheckACMETask 检查权限
func (this *ACMETaskDAO) CheckACMETask(tx *dbs.Tx, adminId int64, userId int64, acmeTaskId int64) (bool, error) {
return dbutils.NewQuery(tx, this, adminId, userId).
State(ACMETaskStateEnabled).
@@ -226,7 +233,7 @@ func (this *ACMETaskDAO) CheckACMETask(tx *dbs.Tx, adminId int64, userId int64,
Exist()
}
// 设置任务关联的证书
// UpdateACMETaskCert 设置任务关联的证书
func (this *ACMETaskDAO) UpdateACMETaskCert(tx *dbs.Tx, taskId int64, certId int64) error {
if taskId <= 0 {
return errors.New("invalid taskId")
@@ -239,7 +246,7 @@ func (this *ACMETaskDAO) UpdateACMETaskCert(tx *dbs.Tx, taskId int64, certId int
return err
}
// 执行任务并记录日志
// RunTask 执行任务并记录日志
func (this *ACMETaskDAO) RunTask(tx *dbs.Tx, taskId int64) (isOk bool, errMsg string, resultCertId int64) {
isOk, errMsg, resultCertId = this.runTaskWithoutLog(tx, taskId)
@@ -350,7 +357,33 @@ func (this *ACMETaskDAO) runTaskWithoutLog(tx *dbs.Tx, taskId int64) (isOk bool,
acmeRequest.OnAuth(func(domain, token, keyAuth string) {
err := SharedACMEAuthenticationDAO.CreateAuth(tx, taskId, domain, token, keyAuth)
if err != nil {
logs.Println("[ACME]write authentication to database error: " + err.Error())
remotelogs.Error("ACME", "write authentication to database error: "+err.Error())
} else {
// 调用校验URL
if len(task.AuthURL) > 0 {
authJSON, err := json.Marshal(maps.Map{
"domain": domain,
"token": token,
"key": keyAuth,
})
if err != nil {
remotelogs.Error("ACME", "encode auth data failed: '"+task.AuthURL+"'")
} else {
client := utils.SharedHttpClient(5 * time.Second)
req, err := http.NewRequest(http.MethodPost, task.AuthURL, bytes.NewReader(authJSON))
req.Header.Set("Content-Type", "application/json")
if err != nil {
remotelogs.Error("ACME", "parse auth url failed '"+task.AuthURL+"': "+err.Error())
} else {
resp, err := client.Do(req)
if err != nil {
remotelogs.Error("ACME", "call auth url failed '"+task.AuthURL+"': "+err.Error())
} else {
_ = resp.Body.Close()
}
}
}
}
}
})
certData, keyData, err := acmeRequest.Run()

View File

@@ -1,6 +1,6 @@
package acme
// ACME任务
// ACMETask ACME任务
type ACMETask struct {
Id uint64 `field:"id"` // ID
AdminId uint32 `field:"adminId"` // 管理员ID
@@ -15,6 +15,7 @@ type ACMETask struct {
CertId uint64 `field:"certId"` // 生成的证书ID
AutoRenew uint8 `field:"autoRenew"` // 是否自动更新
AuthType string `field:"authType"` // 认证类型
AuthURL string `field:"authURL"` // 认证URL
}
type ACMETaskOperator struct {
@@ -31,6 +32,7 @@ type ACMETaskOperator struct {
CertId interface{} // 生成的证书ID
AutoRenew interface{} // 是否自动更新
AuthType interface{} // 认证类型
AuthURL interface{} // 认证URL
}
func NewACMETaskOperator() *ACMETaskOperator {

View File

@@ -35,7 +35,7 @@ func init() {
})
}
// 启用条目
// EnableAdmin 启用条目
func (this *AdminDAO) EnableAdmin(tx *dbs.Tx, id int64) (rowsAffected int64, err error) {
return this.Query(tx).
Pk(id).
@@ -43,7 +43,7 @@ func (this *AdminDAO) EnableAdmin(tx *dbs.Tx, id int64) (rowsAffected int64, err
Update()
}
// 禁用条目
// DisableAdmin 禁用条目
func (this *AdminDAO) DisableAdmin(tx *dbs.Tx, id int64) (rowsAffected int64, err error) {
return this.Query(tx).
Pk(id).
@@ -51,7 +51,7 @@ func (this *AdminDAO) DisableAdmin(tx *dbs.Tx, id int64) (rowsAffected int64, er
Update()
}
// 查找启用中的条目
// FindEnabledAdmin 查找启用中的条目
func (this *AdminDAO) FindEnabledAdmin(tx *dbs.Tx, id int64) (*Admin, error) {
result, err := this.Query(tx).
Pk(id).
@@ -63,7 +63,7 @@ func (this *AdminDAO) FindEnabledAdmin(tx *dbs.Tx, id int64) (*Admin, error) {
return result.(*Admin), err
}
// 检查管理员是否存在
// ExistEnabledAdmin 检查管理员是否存在
func (this *AdminDAO) ExistEnabledAdmin(tx *dbs.Tx, adminId int64) (bool, error) {
return this.Query(tx).
Pk(adminId).
@@ -71,7 +71,7 @@ func (this *AdminDAO) ExistEnabledAdmin(tx *dbs.Tx, adminId int64) (bool, error)
Exist()
}
// 获取管理员名称
// FindAdminFullname 获取管理员名称
func (this *AdminDAO) FindAdminFullname(tx *dbs.Tx, adminId int64) (string, error) {
return this.Query(tx).
Pk(adminId).
@@ -79,7 +79,7 @@ func (this *AdminDAO) FindAdminFullname(tx *dbs.Tx, adminId int64) (string, erro
FindStringCol("")
}
// 检查用户名、密码
// CheckAdminPassword 检查用户名、密码
func (this *AdminDAO) CheckAdminPassword(tx *dbs.Tx, username string, encryptedPassword string) (int64, error) {
if len(username) == 0 || len(encryptedPassword) == 0 {
return 0, nil
@@ -94,7 +94,7 @@ func (this *AdminDAO) CheckAdminPassword(tx *dbs.Tx, username string, encryptedP
FindInt64Col(0)
}
// 根据用户名查询管理员ID
// FindAdminIdWithUsername 根据用户名查询管理员ID
func (this *AdminDAO) FindAdminIdWithUsername(tx *dbs.Tx, username string) (int64, error) {
one, err := this.Query(tx).
Attr("username", username).
@@ -110,7 +110,7 @@ func (this *AdminDAO) FindAdminIdWithUsername(tx *dbs.Tx, username string) (int6
return int64(one.(*Admin).Id), nil
}
// 更改管理员密码
// UpdateAdminPassword 更改管理员密码
func (this *AdminDAO) UpdateAdminPassword(tx *dbs.Tx, adminId int64, password string) error {
if adminId <= 0 {
return errors.New("invalid adminId")
@@ -122,7 +122,7 @@ func (this *AdminDAO) UpdateAdminPassword(tx *dbs.Tx, adminId int64, password st
return err
}
// 创建管理员
// CreateAdmin 创建管理员
func (this *AdminDAO) CreateAdmin(tx *dbs.Tx, username string, canLogin bool, password string, fullname string, isSuper bool, modulesJSON []byte) (int64, error) {
op := NewAdminOperator()
op.IsOn = true
@@ -144,7 +144,7 @@ func (this *AdminDAO) CreateAdmin(tx *dbs.Tx, username string, canLogin bool, pa
return types.Int64(op.Id), nil
}
// 修改管理员个人资料
// UpdateAdminInfo 修改管理员个人资料
func (this *AdminDAO) UpdateAdminInfo(tx *dbs.Tx, adminId int64, fullname string) error {
if adminId <= 0 {
return errors.New("invalid adminId")
@@ -156,7 +156,7 @@ func (this *AdminDAO) UpdateAdminInfo(tx *dbs.Tx, adminId int64, fullname string
return err
}
// 修改管理员详细信息
// UpdateAdmin 修改管理员详细信息
func (this *AdminDAO) UpdateAdmin(tx *dbs.Tx, adminId int64, username string, canLogin bool, password string, fullname string, isSuper bool, modulesJSON []byte, isOn bool) error {
if adminId <= 0 {
return errors.New("invalid adminId")
@@ -180,7 +180,7 @@ func (this *AdminDAO) UpdateAdmin(tx *dbs.Tx, adminId int64, username string, ca
return err
}
// 检查用户名是否存在
// CheckAdminUsername 检查用户名是否存在
func (this *AdminDAO) CheckAdminUsername(tx *dbs.Tx, adminId int64, username string) (bool, error) {
query := this.Query(tx).
State(AdminStateEnabled).
@@ -193,7 +193,7 @@ func (this *AdminDAO) CheckAdminUsername(tx *dbs.Tx, adminId int64, username str
return query.Exist()
}
// 修改管理员登录信息
// UpdateAdminLogin 修改管理员登录信息
func (this *AdminDAO) UpdateAdminLogin(tx *dbs.Tx, adminId int64, username string, password string) error {
if adminId <= 0 {
return errors.New("invalid adminId")
@@ -208,7 +208,7 @@ func (this *AdminDAO) UpdateAdminLogin(tx *dbs.Tx, adminId int64, username strin
return err
}
// 修改管理员可以管理的模块
// UpdateAdminModules 修改管理员可以管理的模块
func (this *AdminDAO) UpdateAdminModules(tx *dbs.Tx, adminId int64, allowModulesJSON []byte) error {
if adminId <= 0 {
return errors.New("invalid adminId")
@@ -223,25 +223,25 @@ func (this *AdminDAO) UpdateAdminModules(tx *dbs.Tx, adminId int64, allowModules
return nil
}
// 查询所有管理的权限
// FindAllAdminModules 查询所有管理的权限
func (this *AdminDAO) FindAllAdminModules(tx *dbs.Tx) (result []*Admin, err error) {
_, err = this.Query(tx).
State(AdminStateEnabled).
Attr("isOn", true).
Result("id", "modules", "isSuper", "fullname").
Result("id", "modules", "isSuper", "fullname", "theme").
Slice(&result).
FindAll()
return
}
// 计算所有管理员数量
// CountAllEnabledAdmins 计算所有管理员数量
func (this *AdminDAO) CountAllEnabledAdmins(tx *dbs.Tx) (int64, error) {
return this.Query(tx).
State(AdminStateEnabled).
Count()
}
// 列出单页的管理员
// ListEnabledAdmins 列出单页的管理员
func (this *AdminDAO) ListEnabledAdmins(tx *dbs.Tx, offset int64, size int64) (result []*Admin, err error) {
_, err = this.Query(tx).
State(AdminStateEnabled).
@@ -253,3 +253,11 @@ func (this *AdminDAO) ListEnabledAdmins(tx *dbs.Tx, offset int64, size int64) (r
FindAll()
return
}
// UpdateAdminTheme 设置管理员Theme
func (this *AdminDAO) UpdateAdminTheme(tx *dbs.Tx, adminId int64, theme string) error {
return this.Query(tx).
Pk(adminId).
Set("theme", theme).
UpdateQuickly()
}

View File

@@ -1,6 +1,6 @@
package models
// 管理员
// Admin 管理员
type Admin struct {
Id uint32 `field:"id"` // ID
IsOn uint8 `field:"isOn"` // 是否启用
@@ -13,6 +13,7 @@ type Admin struct {
State uint8 `field:"state"` // 状态
Modules string `field:"modules"` // 允许的模块
CanLogin uint8 `field:"canLogin"` // 是否可以登录
Theme string `field:"theme"` // 模板设置
}
type AdminOperator struct {
@@ -27,6 +28,7 @@ type AdminOperator struct {
State interface{} // 状态
Modules interface{} // 允许的模块
CanLogin interface{} // 是否可以登录
Theme interface{} // 模板设置
}
func NewAdminOperator() *AdminOperator {

View File

@@ -1,6 +1,7 @@
package models
import (
"github.com/TeaOSLab/EdgeAPI/internal/errors"
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
@@ -29,10 +30,23 @@ func init() {
})
}
// 生成AccessToken
func (this *APIAccessTokenDAO) GenerateAccessToken(tx *dbs.Tx, userId int64) (token string, expiresAt int64, err error) {
// GenerateAccessToken 生成AccessToken
func (this *APIAccessTokenDAO) GenerateAccessToken(tx *dbs.Tx, adminId int64, userId int64) (token string, expiresAt int64, err error) {
if adminId <= 0 && userId <= 0 {
err = errors.New("either 'adminId' or 'userId' should not be zero")
return
}
if adminId > 0 {
userId = 0
}
if userId > 0 {
adminId = 0
}
// 查询以前的
accessToken, err := this.Query(tx).
Attr("adminId", adminId).
Attr("userId", userId).
Find()
if err != nil {
@@ -48,6 +62,7 @@ func (this *APIAccessTokenDAO) GenerateAccessToken(tx *dbs.Tx, userId int64) (to
op.Id = accessToken.(*APIAccessToken).Id
}
op.AdminId = adminId
op.UserId = userId
op.Token = token
op.CreatedAt = time.Now().Unix()
@@ -56,7 +71,7 @@ func (this *APIAccessTokenDAO) GenerateAccessToken(tx *dbs.Tx, userId int64) (to
return
}
// 查找AccessToken
// FindAccessToken 查找AccessToken
func (this *APIAccessTokenDAO) FindAccessToken(tx *dbs.Tx, token string) (*APIAccessToken, error) {
one, err := this.Query(tx).
Attr("token", token).

View File

@@ -1,9 +1,10 @@
package models
// API访问令牌
// APIAccessToken API访问令牌
type APIAccessToken struct {
Id uint64 `field:"id"` // ID
UserId uint32 `field:"userId"` // 用户ID
AdminId uint32 `field:"adminId"` // 管理员ID
Token string `field:"token"` // 令牌
CreatedAt uint64 `field:"createdAt"` // 创建时间
ExpiredAt uint64 `field:"expiredAt"` // 过期时间
@@ -12,6 +13,7 @@ type APIAccessToken struct {
type APIAccessTokenOperator struct {
Id interface{} // ID
UserId interface{} // 用户ID
AdminId interface{} // 管理员ID
Token interface{} // 令牌
CreatedAt interface{} // 创建时间
ExpiredAt interface{} // 过期时间

View File

@@ -4,6 +4,7 @@ import (
"encoding/json"
"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"
@@ -97,7 +98,7 @@ func (this *APINodeDAO) CreateAPINode(tx *dbs.Tx, name string, description strin
return 0, err
}
secret := rands.String(32)
err = NewApiTokenDAO().CreateAPIToken(tx, uniqueId, secret, NodeRoleAPI)
err = NewApiTokenDAO().CreateAPIToken(tx, uniqueId, secret, nodeconfigs.NodeRoleAPI)
if err != nil {
return
}

View File

@@ -4,9 +4,10 @@ import (
"encoding/json"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/maps"
)
// 解析HTTP配置
// DecodeHTTP 解析HTTP配置
func (this *APINode) DecodeHTTP() (*serverconfigs.HTTPProtocolConfig, error) {
if !IsNotNull(this.Http) {
return nil, nil
@@ -25,8 +26,12 @@ func (this *APINode) DecodeHTTP() (*serverconfigs.HTTPProtocolConfig, error) {
return config, nil
}
// 解析HTTPS配置
func (this *APINode) DecodeHTTPS(tx *dbs.Tx) (*serverconfigs.HTTPSProtocolConfig, error) {
// DecodeHTTPS 解析HTTPS配置
func (this *APINode) DecodeHTTPS(tx *dbs.Tx, cacheMap maps.Map) (*serverconfigs.HTTPSProtocolConfig, error) {
if cacheMap == nil {
cacheMap = maps.Map{}
}
if !IsNotNull(this.Https) {
return nil, nil
}
@@ -44,7 +49,7 @@ func (this *APINode) DecodeHTTPS(tx *dbs.Tx) (*serverconfigs.HTTPSProtocolConfig
if config.SSLPolicyRef != nil {
policyId := config.SSLPolicyRef.SSLPolicyId
if policyId > 0 {
sslPolicy, err := SharedSSLPolicyDAO.ComposePolicyConfig(tx, policyId)
sslPolicy, err := SharedSSLPolicyDAO.ComposePolicyConfig(tx, policyId, cacheMap)
if err != nil {
return nil, err
}
@@ -62,7 +67,7 @@ func (this *APINode) DecodeHTTPS(tx *dbs.Tx) (*serverconfigs.HTTPSProtocolConfig
return config, nil
}
// 解析访问地址
// DecodeAccessAddrs 解析访问地址
func (this *APINode) DecodeAccessAddrs() ([]*serverconfigs.NetworkAddressConfig, error) {
if !IsNotNull(this.AccessAddrs) {
return nil, nil
@@ -82,7 +87,7 @@ func (this *APINode) DecodeAccessAddrs() ([]*serverconfigs.NetworkAddressConfig,
return addrConfigs, nil
}
// 解析访问地址,并返回字符串形式
// DecodeAccessAddrStrings 解析访问地址,并返回字符串形式
func (this *APINode) DecodeAccessAddrStrings() ([]string, error) {
addrs, err := this.DecodeAccessAddrs()
if err != nil {
@@ -95,7 +100,7 @@ func (this *APINode) DecodeAccessAddrStrings() ([]string, error) {
return result, nil
}
// 解析Rest HTTP配置
// DecodeRestHTTP 解析Rest HTTP配置
func (this *APINode) DecodeRestHTTP() (*serverconfigs.HTTPProtocolConfig, error) {
if this.RestIsOn != 1 {
return nil, nil
@@ -117,8 +122,11 @@ func (this *APINode) DecodeRestHTTP() (*serverconfigs.HTTPProtocolConfig, error)
return config, nil
}
// 解析HTTPS配置
func (this *APINode) DecodeRestHTTPS(tx *dbs.Tx) (*serverconfigs.HTTPSProtocolConfig, error) {
// DecodeRestHTTPS 解析HTTPS配置
func (this *APINode) DecodeRestHTTPS(tx *dbs.Tx, cacheMap maps.Map) (*serverconfigs.HTTPSProtocolConfig, error) {
if cacheMap == nil {
cacheMap = maps.Map{}
}
if this.RestIsOn != 1 {
return nil, nil
}
@@ -139,7 +147,7 @@ func (this *APINode) DecodeRestHTTPS(tx *dbs.Tx) (*serverconfigs.HTTPSProtocolCo
if config.SSLPolicyRef != nil {
policyId := config.SSLPolicyRef.SSLPolicyId
if policyId > 0 {
sslPolicy, err := SharedSSLPolicyDAO.ComposePolicyConfig(tx, policyId)
sslPolicy, err := SharedSSLPolicyDAO.ComposePolicyConfig(tx, policyId, cacheMap)
if err != nil {
return nil, err
}

View File

@@ -1,6 +1,7 @@
package models
import (
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
@@ -34,7 +35,7 @@ func init() {
})
}
// 启用条目
// EnableApiToken 启用条目
func (this *ApiTokenDAO) EnableApiToken(tx *dbs.Tx, id uint32) (rowsAffected int64, err error) {
return this.Query(tx).
Pk(id).
@@ -42,7 +43,7 @@ func (this *ApiTokenDAO) EnableApiToken(tx *dbs.Tx, id uint32) (rowsAffected int
Update()
}
// 禁用条目
// DisableApiToken 禁用条目
func (this *ApiTokenDAO) DisableApiToken(tx *dbs.Tx, id uint32) (rowsAffected int64, err error) {
return this.Query(tx).
Pk(id).
@@ -50,7 +51,7 @@ func (this *ApiTokenDAO) DisableApiToken(tx *dbs.Tx, id uint32) (rowsAffected in
Update()
}
// 查找启用中的条目
// FindEnabledApiToken 查找启用中的条目
func (this *ApiTokenDAO) FindEnabledApiToken(tx *dbs.Tx, id uint32) (*ApiToken, error) {
result, err := this.Query(tx).
Pk(id).
@@ -62,7 +63,7 @@ func (this *ApiTokenDAO) FindEnabledApiToken(tx *dbs.Tx, id uint32) (*ApiToken,
return result.(*ApiToken), err
}
// 获取可缓存的节点Token信息
// FindEnabledTokenWithNodeCacheable 获取可缓存的节点Token信息
func (this *ApiTokenDAO) FindEnabledTokenWithNodeCacheable(tx *dbs.Tx, nodeId string) (*ApiToken, error) {
SharedCacheLocker.RLock()
token, ok := apiTokenCacheMap[nodeId]
@@ -85,7 +86,7 @@ func (this *ApiTokenDAO) FindEnabledTokenWithNodeCacheable(tx *dbs.Tx, nodeId st
return nil, err
}
// 获取节点Token信息并可以缓存
// FindEnabledTokenWithNode 获取节点Token信息并可以缓存
func (this *ApiTokenDAO) FindEnabledTokenWithNode(tx *dbs.Tx, nodeId string) (*ApiToken, error) {
one, err := this.Query(tx).
Attr("nodeId", nodeId).
@@ -97,7 +98,7 @@ func (this *ApiTokenDAO) FindEnabledTokenWithNode(tx *dbs.Tx, nodeId string) (*A
return nil, err
}
// 根据角色获取节点
// FindEnabledTokenWithRole 根据角色获取节点
func (this *ApiTokenDAO) FindEnabledTokenWithRole(tx *dbs.Tx, role string) (*ApiToken, error) {
one, err := this.Query(tx).
Attr("role", role).
@@ -109,8 +110,8 @@ func (this *ApiTokenDAO) FindEnabledTokenWithRole(tx *dbs.Tx, role string) (*Api
return nil, err
}
// 保存API Token
func (this *ApiTokenDAO) CreateAPIToken(tx *dbs.Tx, nodeId string, secret string, role NodeRole) error {
// CreateAPIToken 保存API Token
func (this *ApiTokenDAO) CreateAPIToken(tx *dbs.Tx, nodeId string, secret string, role nodeconfigs.NodeRole) error {
op := NewApiTokenOperator()
op.NodeId = nodeId
op.Secret = secret
@@ -119,3 +120,13 @@ func (this *ApiTokenDAO) CreateAPIToken(tx *dbs.Tx, nodeId string, secret string
err := this.Save(tx, op)
return err
}
// FindAllEnabledAPITokens 读取API令牌
func (this *ApiTokenDAO) FindAllEnabledAPITokens(tx *dbs.Tx, role string) (result []*ApiToken, err error) {
_, err = this.Query(tx).
Attr("role", role).
State(ApiTokenStateEnabled).
Slice(&result).
FindAll()
return
}

View File

@@ -2,9 +2,11 @@ package authority
import (
"encoding/json"
teaconst "github.com/TeaOSLab/EdgeAPI/internal/const"
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
timeutil "github.com/iwind/TeaGo/utils/time"
"time"
)
@@ -26,6 +28,9 @@ var SharedAuthorityKeyDAO *AuthorityKeyDAO
func init() {
dbs.OnReady(func() {
SharedAuthorityKeyDAO = NewAuthorityKeyDAO()
// 初始化IsPlus值
_, _ = SharedAuthorityKeyDAO.IsPlus(nil)
})
}
@@ -72,7 +77,14 @@ func (this *AuthorityKeyDAO) ReadKey(tx *dbs.Tx) (key *AuthorityKey, err error)
if one == nil {
return nil, nil
}
return one.(*AuthorityKey), nil
key = one.(*AuthorityKey)
// 顺便更新相关变量
if key.DayTo >= timeutil.Format("Y-m-d") {
teaconst.IsPlus = true
}
return
}
// ResetKey 重置Key
@@ -81,3 +93,16 @@ func (this *AuthorityKeyDAO) ResetKey(tx *dbs.Tx) error {
Delete()
return err
}
// IsPlus 判断是否为企业版
func (this *AuthorityKeyDAO) IsPlus(tx *dbs.Tx) (bool, error) {
key, err := this.ReadKey(tx)
if err != nil {
return false, err
}
if key == nil {
return false, nil
}
teaconst.IsPlus = key.DayTo >= timeutil.Format("Y-m-d")
return teaconst.IsPlus, nil
}

View File

@@ -7,17 +7,17 @@ import (
)
func TestAuthorityKeyDAO_UpdateValue(t *testing.T) {
err := NewAuthorityKeyDAO().UpdateValue(nil, "12345678")
err := NewAuthorityKeyDAO().UpdateKey(nil, "12345678", "", "", "", []string{}, "")
if err != nil {
t.Fatal(err)
}
t.Logf("ok")
t.Log("ok")
}
func TestAuthorityKeyDAO_ReadValue(t *testing.T) {
value, err := NewAuthorityKeyDAO().ReadValue(nil)
value, err := NewAuthorityKeyDAO().ReadKey(nil)
if err != nil {
t.Fatal(err)
}
t.Logf(value)
t.Log(value)
}

View File

@@ -4,6 +4,7 @@ import (
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
"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"
@@ -113,7 +114,7 @@ func (this *AuthorityNodeDAO) CreateAuthorityNode(tx *dbs.Tx, name string, descr
return 0, err
}
secret := rands.String(32)
err = models.NewApiTokenDAO().CreateAPIToken(tx, uniqueId, secret, models.NodeRoleAuthority)
err = models.NewApiTokenDAO().CreateAPIToken(tx, uniqueId, secret, nodeconfigs.NodeRoleAuthority)
if err != nil {
return
}

View File

@@ -35,7 +35,7 @@ func init() {
})
}
// 启用条目
// EnableClientBrowser 启用条目
func (this *ClientBrowserDAO) EnableClientBrowser(tx *dbs.Tx, id uint32) error {
_, err := this.Query(tx).
Pk(id).
@@ -44,7 +44,7 @@ func (this *ClientBrowserDAO) EnableClientBrowser(tx *dbs.Tx, id uint32) error {
return err
}
// 禁用条目
// DisableClientBrowser 禁用条目
func (this *ClientBrowserDAO) DisableClientBrowser(tx *dbs.Tx, id uint32) error {
_, err := this.Query(tx).
Pk(id).
@@ -53,7 +53,7 @@ func (this *ClientBrowserDAO) DisableClientBrowser(tx *dbs.Tx, id uint32) error
return err
}
// 查找启用中的条目
// FindEnabledClientBrowser 查找启用中的条目
func (this *ClientBrowserDAO) FindEnabledClientBrowser(tx *dbs.Tx, id int64) (*ClientBrowser, error) {
result, err := this.Query(tx).
Pk(id).
@@ -65,7 +65,7 @@ func (this *ClientBrowserDAO) FindEnabledClientBrowser(tx *dbs.Tx, id int64) (*C
return result.(*ClientBrowser), err
}
// 根据主键查找名称
// FindClientBrowserName 根据主键查找名称
func (this *ClientBrowserDAO) FindClientBrowserName(tx *dbs.Tx, id uint32) (string, error) {
return this.Query(tx).
Pk(id).
@@ -73,7 +73,7 @@ func (this *ClientBrowserDAO) FindClientBrowserName(tx *dbs.Tx, id uint32) (stri
FindStringCol("")
}
// 根据浏览器名称查找浏览器ID
// FindBrowserIdWithNameCacheable 根据浏览器名称查找浏览器ID
func (this *ClientBrowserDAO) FindBrowserIdWithNameCacheable(tx *dbs.Tx, browserName string) (int64, error) {
SharedCacheLocker.RLock()
browserId, ok := clientBrowserNameAndIdCacheMap[browserName]
@@ -102,8 +102,28 @@ func (this *ClientBrowserDAO) FindBrowserIdWithNameCacheable(tx *dbs.Tx, browser
return browserId, nil
}
// 创建浏览器
// CreateBrowser 创建浏览器
func (this *ClientBrowserDAO) CreateBrowser(tx *dbs.Tx, browserName string) (int64, error) {
var maxlength = 50
if len(browserName) > maxlength {
browserName = browserName[:50]
}
SharedCacheLocker.Lock()
defer SharedCacheLocker.Unlock()
// 检查是否已经创建
browserId, err := this.Query(tx).
Attr("name", browserName).
ResultPk().
FindInt64Col(0)
if err != nil {
return 0, err
}
if browserId > 0 {
return browserId, nil
}
op := NewClientBrowserOperator()
op.Name = browserName
codes := []string{browserName}

View File

@@ -35,7 +35,7 @@ func init() {
})
}
// 启用条目
// EnableClientSystem 启用条目
func (this *ClientSystemDAO) EnableClientSystem(tx *dbs.Tx, id uint32) error {
_, err := this.Query(tx).
Pk(id).
@@ -44,7 +44,7 @@ func (this *ClientSystemDAO) EnableClientSystem(tx *dbs.Tx, id uint32) error {
return err
}
// 禁用条目
// DisableClientSystem 禁用条目
func (this *ClientSystemDAO) DisableClientSystem(tx *dbs.Tx, id uint32) error {
_, err := this.Query(tx).
Pk(id).
@@ -53,7 +53,7 @@ func (this *ClientSystemDAO) DisableClientSystem(tx *dbs.Tx, id uint32) error {
return err
}
// 查找启用中的条目
// FindEnabledClientSystem 查找启用中的条目
func (this *ClientSystemDAO) FindEnabledClientSystem(tx *dbs.Tx, id int64) (*ClientSystem, error) {
result, err := this.Query(tx).
Pk(id).
@@ -65,7 +65,7 @@ func (this *ClientSystemDAO) FindEnabledClientSystem(tx *dbs.Tx, id int64) (*Cli
return result.(*ClientSystem), err
}
// 根据主键查找名称
// FindClientSystemName 根据主键查找名称
func (this *ClientSystemDAO) FindClientSystemName(tx *dbs.Tx, id uint32) (string, error) {
return this.Query(tx).
Pk(id).
@@ -73,7 +73,7 @@ func (this *ClientSystemDAO) FindClientSystemName(tx *dbs.Tx, id uint32) (string
FindStringCol("")
}
// 根据操作系统名称查找系统ID
// FindSystemIdWithNameCacheable 根据操作系统名称查找系统ID
func (this *ClientSystemDAO) FindSystemIdWithNameCacheable(tx *dbs.Tx, systemName string) (int64, error) {
SharedCacheLocker.RLock()
systemId, ok := clientSystemNameAndIdCacheMap[systemName]
@@ -102,8 +102,28 @@ func (this *ClientSystemDAO) FindSystemIdWithNameCacheable(tx *dbs.Tx, systemNam
return systemId, nil
}
// 创建浏览器
// CreateSystem 创建浏览器
func (this *ClientSystemDAO) CreateSystem(tx *dbs.Tx, systemName string) (int64, error) {
var maxlength = 50
if len(systemName) > maxlength {
systemName = systemName[:50]
}
SharedCacheLocker.Lock()
defer SharedCacheLocker.Unlock()
// 检查是否已经创建
systemId, err := this.Query(tx).
Attr("name", systemName).
ResultPk().
FindInt64Col(0)
if err != nil {
return 0, err
}
if systemId > 0 {
return systemId, nil
}
op := NewClientSystemOperator()
op.Name = systemName

View File

@@ -39,7 +39,7 @@ func init() {
})
}
// 启用条目
// EnableDBNode 启用条目
func (this *DBNodeDAO) EnableDBNode(tx *dbs.Tx, id int64) error {
_, err := this.Query(tx).
Pk(id).
@@ -48,7 +48,7 @@ func (this *DBNodeDAO) EnableDBNode(tx *dbs.Tx, id int64) error {
return err
}
// 禁用条目
// DisableDBNode 禁用条目
func (this *DBNodeDAO) DisableDBNode(tx *dbs.Tx, id int64) error {
_, err := this.Query(tx).
Pk(id).
@@ -57,7 +57,7 @@ func (this *DBNodeDAO) DisableDBNode(tx *dbs.Tx, id int64) error {
return err
}
// 查找启用中的条目
// FindEnabledDBNode 查找启用中的条目
func (this *DBNodeDAO) FindEnabledDBNode(tx *dbs.Tx, id int64) (*DBNode, error) {
result, err := this.Query(tx).
Pk(id).
@@ -71,7 +71,7 @@ func (this *DBNodeDAO) FindEnabledDBNode(tx *dbs.Tx, id int64) (*DBNode, error)
return node, nil
}
// 根据主键查找名称
// FindDBNodeName 根据主键查找名称
func (this *DBNodeDAO) FindDBNodeName(tx *dbs.Tx, id int64) (string, error) {
return this.Query(tx).
Pk(id).
@@ -79,14 +79,14 @@ func (this *DBNodeDAO) FindDBNodeName(tx *dbs.Tx, id int64) (string, error) {
FindStringCol("")
}
// 计算可用的节点数量
// CountAllEnabledNodes 计算可用的节点数量
func (this *DBNodeDAO) CountAllEnabledNodes(tx *dbs.Tx) (int64, error) {
return this.Query(tx).
State(DBNodeStateEnabled).
Count()
}
// 获取单页的节点
// ListEnabledNodes 获取单页的节点
func (this *DBNodeDAO) ListEnabledNodes(tx *dbs.Tx, offset int64, size int64) (result []*DBNode, err error) {
_, err = this.Query(tx).
State(DBNodeStateEnabled).
@@ -101,7 +101,7 @@ func (this *DBNodeDAO) ListEnabledNodes(tx *dbs.Tx, offset int64, size int64) (r
return
}
// 创建节点
// CreateDBNode 创建节点
func (this *DBNodeDAO) CreateDBNode(tx *dbs.Tx, isOn bool, name string, description string, host string, port int32, database string, username string, password string, charset string) (int64, error) {
op := NewDBNodeOperator()
op.State = NodeStateEnabled
@@ -121,7 +121,7 @@ func (this *DBNodeDAO) CreateDBNode(tx *dbs.Tx, isOn bool, name string, descript
return types.Int64(op.Id), nil
}
// 修改节点
// UpdateNode 修改节点
func (this *DBNodeDAO) UpdateNode(tx *dbs.Tx, nodeId int64, isOn bool, name string, description string, host string, port int32, database string, username string, password string, charset string) error {
if nodeId <= 0 {
return errors.New("invalid nodeId")
@@ -141,7 +141,7 @@ func (this *DBNodeDAO) UpdateNode(tx *dbs.Tx, nodeId int64, isOn bool, name stri
return err
}
// 查找所有可用的数据库节点
// FindAllEnabledAndOnDBNodes 查找所有可用的数据库节点
func (this *DBNodeDAO) FindAllEnabledAndOnDBNodes(tx *dbs.Tx) (result []*DBNode, err error) {
_, err = this.Query(tx).
State(DBNodeStateEnabled).
@@ -155,7 +155,7 @@ func (this *DBNodeDAO) FindAllEnabledAndOnDBNodes(tx *dbs.Tx) (result []*DBNode,
return
}
// 加密密码
// EncodePassword 加密密码
func (this *DBNodeDAO) EncodePassword(password string) string {
if strings.HasPrefix(password, DBNodePasswordEncodedPrefix) {
return password
@@ -164,7 +164,7 @@ func (this *DBNodeDAO) EncodePassword(password string) string {
return DBNodePasswordEncodedPrefix + encodedString
}
// 解密密码
// DecodePassword 解密密码
func (this *DBNodeDAO) DecodePassword(password string) string {
if !strings.HasPrefix(password, DBNodePasswordEncodedPrefix) {
return password
@@ -176,3 +176,15 @@ func (this *DBNodeDAO) DecodePassword(password string) string {
}
return string(encrypt.MagicKeyDecode(data))
}
// CheckNodeIsOn 检查节点是否已经启用
func (this *DBNodeDAO) CheckNodeIsOn(tx *dbs.Tx, nodeId int64) (bool, error) {
isOn, err := this.Query(tx).
Pk(nodeId).
Result("isOn").
FindIntCol(0)
if err != nil {
return false, err
}
return isOn == 1, nil
}

View File

@@ -3,9 +3,10 @@ package models
import (
"fmt"
"github.com/TeaOSLab/EdgeAPI/internal/errors"
"github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
"github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/lists"
"github.com/iwind/TeaGo/logs"
timeutil "github.com/iwind/TeaGo/utils/time"
"hash/crc32"
"regexp"
@@ -15,16 +16,36 @@ import (
"time"
)
var accessLogDBMapping = map[int64]*dbs.DB{} // dbNodeId => DB
var accessLogDAOMapping = map[int64]*HTTPAccessLogDAOWrapper{} // dbNodeId => DAO
var accessLogDBMapping = map[int64]*dbs.DB{} // dbNodeId => DB
var accessLogLocker = &sync.RWMutex{}
var accessLogTableMapping = map[string]bool{} // tableName_crc(dsn) => true
type httpAccessLogDefinition struct {
Name string
HasRemoteAddr bool
HasDomain bool
Exists bool
}
// HTTP服务访问
var httpAccessLogDAOMapping = map[int64]*HTTPAccessLogDAOWrapper{} // dbNodeId => DAO
var httpAccessLogTableMapping = map[string]*httpAccessLogDefinition{} // tableName_crc(dsn) => true
// DNS服务访问
var nsAccessLogDAOMapping = map[int64]*NSAccessLogDAOWrapper{} // dbNodeId => DAO
var nsAccessLogTableMapping = map[string]bool{} // tableName_crc(dsn) => true
// HTTPAccessLogDAOWrapper HTTP访问日志DAO
type HTTPAccessLogDAOWrapper struct {
DAO *HTTPAccessLogDAO
NodeId int64
}
// NSAccessLogDAOWrapper NS访问日志DAO
type NSAccessLogDAOWrapper struct {
DAO *NSAccessLogDAO
NodeId int64
}
func init() {
initializer := NewDBNodeInitializer()
dbs.OnReadyDone(func() {
@@ -33,12 +54,26 @@ func init() {
}
// 获取获取DAO
func randomAccessLogDAO() (dao *HTTPAccessLogDAOWrapper) {
func randomHTTPAccessLogDAO() (dao *HTTPAccessLogDAOWrapper) {
accessLogLocker.RLock()
if len(accessLogDAOMapping) == 0 {
if len(httpAccessLogDAOMapping) == 0 {
dao = nil
} else {
for _, d := range accessLogDAOMapping {
for _, d := range httpAccessLogDAOMapping {
dao = d
break
}
}
accessLogLocker.RUnlock()
return
}
func randomNSAccessLogDAO() (dao *NSAccessLogDAOWrapper) {
accessLogLocker.RLock()
if len(nsAccessLogDAOMapping) == 0 {
dao = nil
} else {
for _, d := range nsAccessLogDAOMapping {
dao = d
break
}
@@ -48,7 +83,36 @@ func randomAccessLogDAO() (dao *HTTPAccessLogDAOWrapper) {
}
// 检查表格是否存在
func findAccessLogTableName(db *dbs.DB, day string) (tableName string, ok bool, err error) {
func findHTTPAccessLogTableName(db *dbs.DB, day string) (tableName string, hasRemoteAddr bool, hasDomain bool, ok bool, err error) {
if !regexp.MustCompile(`^\d{8}$`).MatchString(day) {
err = errors.New("invalid day '" + day + "', should be YYYYMMDD")
return
}
config, err := db.Config()
if err != nil {
return "", false, false, false, err
}
tableName = "edgeHTTPAccessLogs_" + day
cacheKey := tableName + "_" + fmt.Sprintf("%d", crc32.ChecksumIEEE([]byte(config.Dsn)))
accessLogLocker.RLock()
def, ok := httpAccessLogTableMapping[cacheKey]
accessLogLocker.RUnlock()
if ok {
return tableName, def.HasRemoteAddr, def.HasDomain, true, nil
}
def, err = findHTTPAccessLogTable(db, day, false)
if err != nil {
return tableName, false, false, false, err
}
return tableName, def.HasRemoteAddr, def.HasDomain, def.Exists, nil
}
func findNSAccessLogTableName(db *dbs.DB, day string) (tableName string, ok bool, err error) {
if !regexp.MustCompile(`^\d{8}$`).MatchString(day) {
err = errors.New("invalid day '" + day + "', should be YYYYMMDD")
return
@@ -59,11 +123,11 @@ func findAccessLogTableName(db *dbs.DB, day string) (tableName string, ok bool,
return "", false, err
}
tableName = "edgeHTTPAccessLogs_" + day
tableName = "edgeNSAccessLogs_" + day
cacheKey := tableName + "_" + fmt.Sprintf("%d", crc32.ChecksumIEEE([]byte(config.Dsn)))
accessLogLocker.RLock()
_, ok = accessLogTableMapping[cacheKey]
_, ok = nsAccessLogTableMapping[cacheKey]
accessLogLocker.RUnlock()
if ok {
return tableName, true, nil
@@ -78,10 +142,10 @@ func findAccessLogTableName(db *dbs.DB, day string) (tableName string, ok bool,
}
// 根据日期获取表名
func findAccessLogTable(db *dbs.DB, day string, force bool) (string, error) {
func findHTTPAccessLogTable(db *dbs.DB, day string, force bool) (*httpAccessLogDefinition, error) {
config, err := db.Config()
if err != nil {
return "", err
return nil, err
}
tableName := "edgeHTTPAccessLogs_" + day
@@ -89,7 +153,75 @@ func findAccessLogTable(db *dbs.DB, day string, force bool) (string, error) {
if !force {
accessLogLocker.RLock()
_, ok := accessLogTableMapping[cacheKey]
definition, ok := httpAccessLogTableMapping[cacheKey]
accessLogLocker.RUnlock()
if ok {
return definition, nil
}
}
tableNames, err := db.TableNames()
if err != nil {
return nil, err
}
if lists.ContainsString(tableNames, tableName) {
table, err := db.FindTable(tableName)
if err != nil {
return nil, err
}
accessLogLocker.Lock()
var definition = &httpAccessLogDefinition{
Name: tableName,
HasRemoteAddr: table.FindFieldWithName("remoteAddr") != nil,
HasDomain: table.FindFieldWithName("domain") != nil,
Exists: true,
}
httpAccessLogTableMapping[cacheKey] = definition
accessLogLocker.Unlock()
return definition, nil
}
if !force {
return &httpAccessLogDefinition{
Name: tableName,
HasRemoteAddr: true,
HasDomain: true,
Exists: false,
}, nil
}
// 创建表格
_, err = db.Exec("CREATE TABLE `" + tableName + "` (\n `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',\n `serverId` int(11) unsigned DEFAULT '0' COMMENT '服务ID',\n `nodeId` int(11) unsigned DEFAULT '0' COMMENT '节点ID',\n `status` int(3) unsigned DEFAULT '0' COMMENT '状态码',\n `createdAt` bigint(11) unsigned DEFAULT '0' COMMENT '创建时间',\n `content` json DEFAULT NULL COMMENT '日志内容',\n `requestId` varchar(128) DEFAULT NULL COMMENT '请求ID',\n `firewallPolicyId` int(11) unsigned DEFAULT '0' COMMENT 'WAF策略ID',\n `firewallRuleGroupId` int(11) unsigned DEFAULT '0' COMMENT 'WAF分组ID',\n `firewallRuleSetId` int(11) unsigned DEFAULT '0' COMMENT 'WAF集ID',\n `firewallRuleId` int(11) unsigned DEFAULT '0' COMMENT 'WAF规则ID',\n `remoteAddr` varchar(64) DEFAULT NULL COMMENT 'IP地址',\n `domain` varchar(128) DEFAULT NULL COMMENT '域名',\n `requestBody` blob COMMENT '请求内容',\n `responseBody` blob COMMENT '响应内容',\n PRIMARY KEY (`id`),\n KEY `serverId` (`serverId`),\n KEY `nodeId` (`nodeId`),\n KEY `serverId_status` (`serverId`,`status`),\n KEY `requestId` (`requestId`),\n KEY `firewallPolicyId` (`firewallPolicyId`),\n KEY `firewallRuleGroupId` (`firewallRuleGroupId`),\n KEY `firewallRuleSetId` (`firewallRuleSetId`),\n KEY `firewallRuleId` (`firewallRuleId`),\n KEY `remoteAddr` (`remoteAddr`),\n KEY `domain` (`domain`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='访问日志';")
if err != nil {
return nil, err
}
accessLogLocker.Lock()
var definition = &httpAccessLogDefinition{
Name: tableName,
HasRemoteAddr: true,
Exists: true,
}
httpAccessLogTableMapping[cacheKey] = definition
accessLogLocker.Unlock()
return definition, nil
}
func findNSAccessLogTable(db *dbs.DB, day string, force bool) (string, error) {
config, err := db.Config()
if err != nil {
return "", err
}
tableName := "edgeNSAccessLogs_" + day
cacheKey := tableName + "_" + fmt.Sprintf("%d", crc32.ChecksumIEEE([]byte(config.Dsn)))
if !force {
accessLogLocker.RLock()
_, ok := nsAccessLogTableMapping[cacheKey]
accessLogLocker.RUnlock()
if ok {
return tableName, nil
@@ -103,25 +235,25 @@ func findAccessLogTable(db *dbs.DB, day string, force bool) (string, error) {
if lists.ContainsString(tableNames, tableName) {
accessLogLocker.Lock()
accessLogTableMapping[cacheKey] = true
nsAccessLogTableMapping[cacheKey] = true
accessLogLocker.Unlock()
return tableName, nil
}
// 创建表格
_, err = db.Exec("CREATE TABLE `" + tableName + "` (\n `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',\n `serverId` int(11) unsigned DEFAULT '0' COMMENT '服务ID',\n `nodeId` int(11) unsigned DEFAULT '0' COMMENT '节点ID',\n `status` int(3) unsigned DEFAULT '0' COMMENT '状态码',\n `createdAt` bigint(11) unsigned DEFAULT '0' COMMENT '创建时间',\n `content` json DEFAULT NULL COMMENT '日志内容',\n `requestId` varchar(128) DEFAULT NULL COMMENT '请求ID',\n `firewallPolicyId` int(11) unsigned DEFAULT '0' COMMENT 'WAF策略ID',\n `firewallRuleGroupId` int(11) unsigned DEFAULT '0' COMMENT 'WAF分组ID',\n `firewallRuleSetId` int(11) unsigned DEFAULT '0' COMMENT 'WAF集ID',\n `firewallRuleId` int(11) unsigned DEFAULT '0' COMMENT 'WAF规则ID',\n PRIMARY KEY (`id`),\n KEY `serverId` (`serverId`),\n KEY `nodeId` (`nodeId`),\n KEY `serverId_status` (`serverId`,`status`),\n KEY `requestId` (`requestId`),\n KEY `firewallPolicyId` (`firewallPolicyId`),\n KEY `firewallRuleGroupId` (`firewallRuleGroupId`),\n KEY `firewallRuleSetId` (`firewallRuleSetId`),\n KEY `firewallRuleId` (`firewallRuleId`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='访问日志';")
_, err = db.Exec("CREATE TABLE `" + tableName + "` (\n `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',\n `nodeId` int(11) unsigned DEFAULT '0' COMMENT '节点ID',\n `domainId` int(11) unsigned DEFAULT '0' COMMENT '域名ID',\n `recordId` int(11) unsigned DEFAULT '0' COMMENT '记录ID',\n `content` json DEFAULT NULL COMMENT '访问数据',\n `requestId` varchar(128) DEFAULT NULL COMMENT '请求ID',\n `createdAt` bigint(11) unsigned DEFAULT '0' COMMENT '创建时间',\n `remoteAddr` varchar(128) DEFAULT NULL COMMENT 'IP',\n PRIMARY KEY (`id`),\n KEY `nodeId` (`nodeId`),\n KEY `domainId` (`domainId`),\n KEY `recordId` (`recordId`),\n KEY `requestId` (`requestId`),\n KEY `remoteAddr` (`remoteAddr`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='域名服务访问日志';")
if err != nil {
return tableName, err
}
accessLogLocker.Lock()
accessLogTableMapping[cacheKey] = true
nsAccessLogTableMapping[cacheKey] = true
accessLogLocker.Unlock()
return tableName, nil
}
// 初始化数据库连接
// DBNodeInitializer 初始化数据库连接
type DBNodeInitializer struct {
}
@@ -129,12 +261,12 @@ func NewDBNodeInitializer() *DBNodeInitializer {
return &DBNodeInitializer{}
}
// 启动
// Start 启动
func (this *DBNodeInitializer) Start() {
// 初始运行
err := this.loop()
if err != nil {
logs.Println("[DB_NODE]" + err.Error())
remotelogs.Error("DB_NODE", err.Error())
}
// 定时运行
@@ -142,7 +274,7 @@ func (this *DBNodeInitializer) Start() {
for range ticker.C {
err := this.loop()
if err != nil {
logs.Println("[DB_NODE]" + err.Error())
remotelogs.Error("DB_NODE", err.Error())
}
}
}
@@ -166,8 +298,9 @@ func (this *DBNodeInitializer) loop() error {
if !lists.ContainsInt64(nodeIds, nodeId) {
closingDbs = append(closingDbs, db)
delete(accessLogDBMapping, nodeId)
delete(accessLogDAOMapping, nodeId)
logs.Println("[DB_NODE]close db node '" + strconv.FormatInt(nodeId, 10) + "'")
delete(httpAccessLogDAOMapping, nodeId)
delete(nsAccessLogDAOMapping, nodeId)
remotelogs.Error("DB_NODE", "close db node '"+strconv.FormatInt(nodeId, 10)+"'")
}
}
accessLogLocker.Unlock()
@@ -188,7 +321,7 @@ func (this *DBNodeInitializer) loop() error {
// 检查配置是否有变化
oldConfig, err := db.Config()
if err != nil {
logs.Println("[DB_NODE]read database old config failed: " + err.Error())
remotelogs.Error("DB_NODE", "read database old config failed: "+err.Error())
continue
}
@@ -207,51 +340,98 @@ func (this *DBNodeInitializer) loop() error {
}
db, err := dbs.NewInstanceFromConfig(config)
if err != nil {
logs.Println("[DB_NODE]initialize database config failed: " + err.Error())
remotelogs.Error("DB_NODE", "initialize database config failed: "+err.Error())
continue
}
// 检查表是否存在
tableName, err := findAccessLogTable(db, timeutil.Format("Ymd"), false)
if err != nil {
if !strings.Contains(err.Error(), "1050") { // 非表格已存在错误
logs.Println("[DB_NODE]create first table in database node failed: " + err.Error())
// httpAccessLog
{
tableDef, err := findHTTPAccessLogTable(db, timeutil.Format("Ymd"), true)
if err != nil {
if !strings.Contains(err.Error(), "1050") { // 非表格已存在错误
remotelogs.Error("DB_NODE", "create first table in database node failed: "+err.Error())
// 创建节点日志
createLogErr := SharedNodeLogDAO.CreateLog(nil, NodeRoleDatabase, nodeId, "error", "ACCESS_LOG", "can not create access log table: "+err.Error(), time.Now().Unix())
if createLogErr != nil {
logs.Println("[NODE_LOG]" + createLogErr.Error())
// 创建节点日志
createLogErr := SharedNodeLogDAO.CreateLog(nil, nodeconfigs.NodeRoleDatabase, nodeId, 0, 0, "error", "ACCESS_LOG", "can not create access log table: "+err.Error(), time.Now().Unix())
if createLogErr != nil {
remotelogs.Error("NODE_LOG", createLogErr.Error())
}
continue
} else {
err = nil
}
continue
} else {
err = nil
}
daoObject := dbs.DAOObject{
Instance: db,
DB: node.Name + "(id:" + strconv.Itoa(int(node.Id)) + ")",
Table: tableDef.Name,
PkName: "id",
Model: new(HTTPAccessLog),
}
err = daoObject.Init()
if err != nil {
remotelogs.Error("DB_NODE", "initialize dao failed: "+err.Error())
continue
}
accessLogLocker.Lock()
accessLogDBMapping[nodeId] = db
dao := &HTTPAccessLogDAO{
DAOObject: daoObject,
}
httpAccessLogDAOMapping[nodeId] = &HTTPAccessLogDAOWrapper{
DAO: dao,
NodeId: nodeId,
}
accessLogLocker.Unlock()
}
daoObject := dbs.DAOObject{
Instance: db,
DB: node.Name + "(id:" + strconv.Itoa(int(node.Id)) + ")",
Table: tableName,
PkName: "id",
Model: new(HTTPAccessLog),
}
err = daoObject.Init()
if err != nil {
logs.Println("[DB_NODE]initialize dao failed: " + err.Error())
continue
}
// nsAccessLog
{
tableName, err := findNSAccessLogTable(db, timeutil.Format("Ymd"), false)
if err != nil {
if !strings.Contains(err.Error(), "1050") { // 非表格已存在错误
remotelogs.Error("DB_NODE", "create first table in database node failed: "+err.Error())
accessLogLocker.Lock()
accessLogDBMapping[nodeId] = db
dao := &HTTPAccessLogDAO{
DAOObject: daoObject,
// 创建节点日志
createLogErr := SharedNodeLogDAO.CreateLog(nil, nodeconfigs.NodeRoleDatabase, nodeId, 0, 0, "error", "ACCESS_LOG", "can not create access log table: "+err.Error(), time.Now().Unix())
if createLogErr != nil {
remotelogs.Error("NODE_LOG", createLogErr.Error())
}
continue
} else {
err = nil
}
}
daoObject := dbs.DAOObject{
Instance: db,
DB: node.Name + "(id:" + strconv.Itoa(int(node.Id)) + ")",
Table: tableName,
PkName: "id",
Model: new(NSAccessLog),
}
err = daoObject.Init()
if err != nil {
remotelogs.Error("DB_NODE", "initialize dao failed: "+err.Error())
continue
}
accessLogLocker.Lock()
accessLogDBMapping[nodeId] = db
dao := &NSAccessLogDAO{
DAOObject: daoObject,
}
nsAccessLogDAOMapping[nodeId] = &NSAccessLogDAOWrapper{
DAO: dao,
NodeId: nodeId,
}
accessLogLocker.Unlock()
}
accessLogDAOMapping[nodeId] = &HTTPAccessLogDAOWrapper{
DAO: dao,
NodeId: nodeId,
}
accessLogLocker.Unlock()
}
}

View File

@@ -12,13 +12,13 @@ func TestDBNodeInitializer_loop(t *testing.T) {
if err != nil {
t.Fatal(err)
}
t.Log(len(accessLogDBMapping), len(accessLogDAOMapping))
t.Log(len(accessLogDBMapping), len(httpAccessLogDAOMapping))
}
func TestFindAccessLogTable(t *testing.T) {
before := time.Now()
db := SharedHTTPAccessLogDAO.Instance
tableName, err := findAccessLogTable(db, "20201010", false)
tableName, err := findHTTPAccessLogTable(db, "20201010", false)
if err != nil {
t.Fatal(err)
}
@@ -26,7 +26,7 @@ func TestFindAccessLogTable(t *testing.T) {
t.Log(time.Since(before).Seconds()*1000, "ms")
before = time.Now()
tableName, err = findAccessLogTable(db, "20201010", false)
tableName, err = findHTTPAccessLogTable(db, "20201010", false)
if err != nil {
t.Fatal(err)
@@ -40,6 +40,6 @@ func BenchmarkFindAccessLogTable(b *testing.B) {
runtime.GOMAXPROCS(1)
for i := 0; i < b.N; i++ {
_, _ = findAccessLogTable(db, "20201010", false)
_, _ = findHTTPAccessLogTable(db, "20201010", false)
}
}

View File

@@ -2,7 +2,7 @@ package dns
import (
"encoding/json"
"github.com/TeaOSLab/EdgeAPI/internal/dnsclients"
"github.com/TeaOSLab/EdgeAPI/internal/dnsclients/dnstypes"
"github.com/TeaOSLab/EdgeAPI/internal/errors"
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
@@ -39,7 +39,7 @@ func init() {
})
}
// 启用条目
// EnableDNSDomain 启用条目
func (this *DNSDomainDAO) EnableDNSDomain(tx *dbs.Tx, id int64) error {
_, err := this.Query(tx).
Pk(id).
@@ -48,7 +48,7 @@ func (this *DNSDomainDAO) EnableDNSDomain(tx *dbs.Tx, id int64) error {
return err
}
// 禁用条目
// DisableDNSDomain 禁用条目
func (this *DNSDomainDAO) DisableDNSDomain(tx *dbs.Tx, id int64) error {
_, err := this.Query(tx).
Pk(id).
@@ -57,19 +57,29 @@ func (this *DNSDomainDAO) DisableDNSDomain(tx *dbs.Tx, id int64) error {
return err
}
// 查找启用中的条目
func (this *DNSDomainDAO) FindEnabledDNSDomain(tx *dbs.Tx, id int64) (*DNSDomain, error) {
// FindEnabledDNSDomain 查找启用中的条目
func (this *DNSDomainDAO) FindEnabledDNSDomain(tx *dbs.Tx, domainId int64, cacheMap maps.Map) (*DNSDomain, error) {
if cacheMap == nil {
cacheMap = maps.Map{}
}
var cacheKey = this.Table + ":record:" + types.String(domainId)
var cache = cacheMap.Get(cacheKey)
if cache != nil {
return cache.(*DNSDomain), nil
}
result, err := this.Query(tx).
Pk(id).
Pk(domainId).
Attr("state", DNSDomainStateEnabled).
Find()
if result == nil {
return nil, err
}
cacheMap[cacheKey] = result
return result.(*DNSDomain), err
}
// 根据主键查找名称
// FindDNSDomainName 根据主键查找名称
func (this *DNSDomainDAO) FindDNSDomainName(tx *dbs.Tx, id int64) (string, error) {
return this.Query(tx).
Pk(id).
@@ -77,7 +87,7 @@ func (this *DNSDomainDAO) FindDNSDomainName(tx *dbs.Tx, id int64) (string, error
FindStringCol("")
}
// 创建域名
// CreateDomain 创建域名
func (this *DNSDomainDAO) CreateDomain(tx *dbs.Tx, adminId int64, userId int64, providerId int64, name string) (int64, error) {
op := NewDNSDomainOperator()
op.ProviderId = providerId
@@ -86,6 +96,7 @@ func (this *DNSDomainDAO) CreateDomain(tx *dbs.Tx, adminId int64, userId int64,
op.Name = name
op.State = DNSDomainStateEnabled
op.IsOn = true
op.IsUp = true
err := this.Save(tx, op)
if err != nil {
return 0, err
@@ -93,7 +104,7 @@ func (this *DNSDomainDAO) CreateDomain(tx *dbs.Tx, adminId int64, userId int64,
return types.Int64(op.Id), nil
}
// 修改域名
// UpdateDomain 修改域名
func (this *DNSDomainDAO) UpdateDomain(tx *dbs.Tx, domainId int64, name string, isOn bool) error {
if domainId <= 0 {
return errors.New("invalid domainId")
@@ -109,7 +120,7 @@ func (this *DNSDomainDAO) UpdateDomain(tx *dbs.Tx, domainId int64, name string,
return nil
}
// 查询一个服务商下面的所有域名
// FindAllEnabledDomainsWithProviderId 查询一个服务商下面的所有域名
func (this *DNSDomainDAO) FindAllEnabledDomainsWithProviderId(tx *dbs.Tx, providerId int64) (result []*DNSDomain, err error) {
_, err = this.Query(tx).
State(DNSDomainStateEnabled).
@@ -120,7 +131,7 @@ func (this *DNSDomainDAO) FindAllEnabledDomainsWithProviderId(tx *dbs.Tx, provid
return
}
// 计算某个服务商下的域名数量
// CountAllEnabledDomainsWithProviderId 计算某个服务商下的域名数量
func (this *DNSDomainDAO) CountAllEnabledDomainsWithProviderId(tx *dbs.Tx, providerId int64) (int64, error) {
return this.Query(tx).
State(DNSDomainStateEnabled).
@@ -128,7 +139,7 @@ func (this *DNSDomainDAO) CountAllEnabledDomainsWithProviderId(tx *dbs.Tx, provi
Count()
}
// 更新域名数据
// UpdateDomainData 更新域名数据
func (this *DNSDomainDAO) UpdateDomainData(tx *dbs.Tx, domainId int64, data string) error {
if domainId <= 0 {
return errors.New("invalid domainId")
@@ -140,7 +151,7 @@ func (this *DNSDomainDAO) UpdateDomainData(tx *dbs.Tx, domainId int64, data stri
return err
}
// 更新域名解析记录
// UpdateDomainRecords 更新域名解析记录
func (this *DNSDomainDAO) UpdateDomainRecords(tx *dbs.Tx, domainId int64, recordsJSON []byte) error {
if domainId <= 0 {
return errors.New("invalid domainId")
@@ -153,7 +164,7 @@ func (this *DNSDomainDAO) UpdateDomainRecords(tx *dbs.Tx, domainId int64, record
return err
}
// 更新线路
// UpdateDomainRoutes 更新线路
func (this *DNSDomainDAO) UpdateDomainRoutes(tx *dbs.Tx, domainId int64, routesJSON []byte) error {
if domainId <= 0 {
return errors.New("invalid domainId")
@@ -166,8 +177,8 @@ func (this *DNSDomainDAO) UpdateDomainRoutes(tx *dbs.Tx, domainId int64, routesJ
return err
}
// 查找域名线路
func (this *DNSDomainDAO) FindDomainRoutes(tx *dbs.Tx, domainId int64) ([]*dnsclients.Route, error) {
// FindDomainRoutes 查找域名线路
func (this *DNSDomainDAO) FindDomainRoutes(tx *dbs.Tx, domainId int64) ([]*dnstypes.Route, error) {
routes, err := this.Query(tx).
Pk(domainId).
Result("routes").
@@ -178,7 +189,7 @@ func (this *DNSDomainDAO) FindDomainRoutes(tx *dbs.Tx, domainId int64) ([]*dnscl
if len(routes) == 0 || routes == "null" {
return nil, nil
}
result := []*dnsclients.Route{}
result := []*dnstypes.Route{}
err = json.Unmarshal([]byte(routes), &result)
if err != nil {
return nil, err
@@ -186,7 +197,7 @@ func (this *DNSDomainDAO) FindDomainRoutes(tx *dbs.Tx, domainId int64) ([]*dnscl
return result, nil
}
// 查找线路名称
// FindDomainRouteName 查找线路名称
func (this *DNSDomainDAO) FindDomainRouteName(tx *dbs.Tx, domainId int64, routeCode string) (string, error) {
routes, err := this.FindDomainRoutes(tx, domainId)
if err != nil {
@@ -200,10 +211,10 @@ func (this *DNSDomainDAO) FindDomainRouteName(tx *dbs.Tx, domainId int64, routeC
return "", nil
}
// 判断是否有域名可选
// ExistAvailableDomains 判断是否有域名可选
func (this *DNSDomainDAO) ExistAvailableDomains(tx *dbs.Tx) (bool, error) {
subQuery, err := SharedDNSProviderDAO.Query(tx).
Where("state=1"). // 这里要使用非变量
Where("state=1"). // 这里要使用非变量
ResultPk().
AsSQL()
if err != nil {
@@ -216,8 +227,10 @@ func (this *DNSDomainDAO) ExistAvailableDomains(tx *dbs.Tx) (bool, error) {
Exist()
}
// 检查域名解析记录是否存在
// ExistDomainRecord 检查域名解析记录是否存在
func (this *DNSDomainDAO) ExistDomainRecord(tx *dbs.Tx, domainId int64, recordName string, recordType string, recordRoute string, recordValue string) (bool, error) {
recordType = strings.ToUpper(recordType)
query := maps.Map{
"name": recordName,
"type": recordType,
@@ -239,10 +252,31 @@ func (this *DNSDomainDAO) ExistDomainRecord(tx *dbs.Tx, domainId int64, recordNa
}
}
}
recordType = strings.ToUpper(recordType)
return this.Query(tx).
Pk(domainId).
Where("JSON_CONTAINS(records, :query)").
Param("query", query.AsJSON()).
Exist()
}
// FindEnabledDomainWithName 根据名称查找某个域名
func (this *DNSDomainDAO) FindEnabledDomainWithName(tx *dbs.Tx, providerId int64, domainName string) (*DNSDomain, error) {
one, err := this.Query(tx).
State(DNSDomainStateEnabled).
Attr("isOn", true).
Attr("providerId", providerId).
Attr("name", domainName).
Find()
if one != nil {
return one.(*DNSDomain), nil
}
return nil, err
}
// UpdateDomainIsUp 设置是否在线
func (this *DNSDomainDAO) UpdateDomainIsUp(tx *dbs.Tx, domainId int64, isUp bool) error {
return this.Query(tx).
Pk(domainId).
Set("isUp", isUp).
UpdateQuickly()
}

View File

@@ -1,6 +1,6 @@
package dns
// 管理的域名
// DNSDomain 管理的域名
type DNSDomain struct {
Id uint32 `field:"id"` // ID
AdminId uint32 `field:"adminId"` // 管理员ID
@@ -14,6 +14,7 @@ type DNSDomain struct {
Data string `field:"data"` // 原始数据信息
Records string `field:"records"` // 所有解析记录
Routes string `field:"routes"` // 线路数据
IsUp uint8 `field:"isUp"` // 是否在线
State uint8 `field:"state"` // 状态
}
@@ -30,6 +31,7 @@ type DNSDomainOperator struct {
Data interface{} // 原始数据信息
Records interface{} // 所有解析记录
Routes interface{} // 线路数据
IsUp interface{} // 是否在线
State interface{} // 状态
}

View File

@@ -2,15 +2,15 @@ package dns
import (
"encoding/json"
"github.com/TeaOSLab/EdgeAPI/internal/dnsclients"
"github.com/TeaOSLab/EdgeAPI/internal/dnsclients/dnstypes"
)
// 获取所有的线路
func (this *DNSDomain) DecodeRoutes() ([]*dnsclients.Route, error) {
// DecodeRoutes 获取所有的线路
func (this *DNSDomain) DecodeRoutes() ([]*dnstypes.Route, error) {
if len(this.Routes) == 0 || this.Routes == "null" {
return nil, nil
}
result := []*dnsclients.Route{}
result := []*dnstypes.Route{}
err := json.Unmarshal([]byte(this.Routes), &result)
if err != nil {
return nil, err
@@ -18,7 +18,7 @@ func (this *DNSDomain) DecodeRoutes() ([]*dnsclients.Route, error) {
return result, nil
}
// 检查是否包含某个线路
// ContainsRouteCode 检查是否包含某个线路
func (this *DNSDomain) ContainsRouteCode(route string) (bool, error) {
routes, err := this.DecodeRoutes()
if err != nil {
@@ -32,13 +32,13 @@ func (this *DNSDomain) ContainsRouteCode(route string) (bool, error) {
return false, nil
}
// 获取所有的记录
func (this *DNSDomain) DecodeRecords() ([]*dnsclients.Record, error) {
// DecodeRecords 获取所有的记录
func (this *DNSDomain) DecodeRecords() ([]*dnstypes.Record, error) {
records := this.Records
if len(records) == 0 || records == "null" {
return nil, nil
}
result := []*dnsclients.Record{}
result := []*dnstypes.Record{}
err := json.Unmarshal([]byte(records), &result)
if err != nil {
return nil, err

View File

@@ -36,7 +36,7 @@ func init() {
})
}
// 启用条目
// EnableDNSProvider 启用条目
func (this *DNSProviderDAO) EnableDNSProvider(tx *dbs.Tx, id int64) error {
_, err := this.Query(tx).
Pk(id).
@@ -45,7 +45,7 @@ func (this *DNSProviderDAO) EnableDNSProvider(tx *dbs.Tx, id int64) error {
return err
}
// 禁用条目
// DisableDNSProvider 禁用条目
func (this *DNSProviderDAO) DisableDNSProvider(tx *dbs.Tx, id int64) error {
_, err := this.Query(tx).
Pk(id).
@@ -54,7 +54,7 @@ func (this *DNSProviderDAO) DisableDNSProvider(tx *dbs.Tx, id int64) error {
return err
}
// 查找启用中的条目
// FindEnabledDNSProvider 查找启用中的条目
func (this *DNSProviderDAO) FindEnabledDNSProvider(tx *dbs.Tx, id int64) (*DNSProvider, error) {
result, err := this.Query(tx).
Pk(id).
@@ -66,7 +66,7 @@ func (this *DNSProviderDAO) FindEnabledDNSProvider(tx *dbs.Tx, id int64) (*DNSPr
return result.(*DNSProvider), err
}
// 创建服务商
// CreateDNSProvider 创建服务商
func (this *DNSProviderDAO) CreateDNSProvider(tx *dbs.Tx, adminId int64, userId int64, providerType string, name string, apiParamsJSON []byte) (int64, error) {
op := NewDNSProviderOperator()
op.AdminId = adminId
@@ -84,7 +84,7 @@ func (this *DNSProviderDAO) CreateDNSProvider(tx *dbs.Tx, adminId int64, userId
return types.Int64(op.Id), nil
}
// 修改服务商
// UpdateDNSProvider 修改服务商
func (this *DNSProviderDAO) UpdateDNSProvider(tx *dbs.Tx, dnsProviderId int64, name string, apiParamsJSON []byte) error {
if dnsProviderId <= 0 {
return errors.New("invalid dnsProviderId")
@@ -106,16 +106,25 @@ func (this *DNSProviderDAO) UpdateDNSProvider(tx *dbs.Tx, dnsProviderId int64, n
return nil
}
// 计算服务商数量
func (this *DNSProviderDAO) CountAllEnabledDNSProviders(tx *dbs.Tx, adminId int64, userId int64) (int64, error) {
return dbutils.NewQuery(tx, this, adminId, userId).
State(DNSProviderStateEnabled).
// CountAllEnabledDNSProviders 计算服务商数量
func (this *DNSProviderDAO) CountAllEnabledDNSProviders(tx *dbs.Tx, adminId int64, userId int64, keyword string) (int64, error) {
var query = dbutils.NewQuery(tx, this, adminId, userId)
if len(keyword) > 0 {
query.Where("(name LIKE :keyword)").
Param("keyword", "%"+keyword+"%")
}
return query.State(DNSProviderStateEnabled).
Count()
}
// 列出单页服务商
func (this *DNSProviderDAO) ListEnabledDNSProviders(tx *dbs.Tx, adminId int64, userId int64, offset int64, size int64) (result []*DNSProvider, err error) {
_, err = dbutils.NewQuery(tx, this, adminId, userId).
// ListEnabledDNSProviders 列出单页服务商
func (this *DNSProviderDAO) ListEnabledDNSProviders(tx *dbs.Tx, adminId int64, userId int64, keyword string, offset int64, size int64) (result []*DNSProvider, err error) {
var query = dbutils.NewQuery(tx, this, adminId, userId)
if len(keyword) > 0 {
query.Where("(name LIKE :keyword)").
Param("keyword", "%"+keyword+"%")
}
_, err = query.
State(DNSProviderStateEnabled).
Offset(offset).
Limit(size).
@@ -125,7 +134,7 @@ func (this *DNSProviderDAO) ListEnabledDNSProviders(tx *dbs.Tx, adminId int64, u
return
}
// 列出所有服务商
// FindAllEnabledDNSProviders 列出所有服务商
func (this *DNSProviderDAO) FindAllEnabledDNSProviders(tx *dbs.Tx, adminId int64, userId int64) (result []*DNSProvider, err error) {
_, err = dbutils.NewQuery(tx, this, adminId, userId).
State(DNSProviderStateEnabled).
@@ -135,7 +144,7 @@ func (this *DNSProviderDAO) FindAllEnabledDNSProviders(tx *dbs.Tx, adminId int64
return
}
// 查询某个类型下的所有服务商
// FindAllEnabledDNSProvidersWithType 查询某个类型下的所有服务商
func (this *DNSProviderDAO) FindAllEnabledDNSProvidersWithType(tx *dbs.Tx, providerType string) (result []*DNSProvider, err error) {
_, err = this.Query(tx).
State(DNSProviderStateEnabled).
@@ -146,7 +155,7 @@ func (this *DNSProviderDAO) FindAllEnabledDNSProvidersWithType(tx *dbs.Tx, provi
return
}
// 更新数据更新时间
// UpdateProviderDataUpdatedTime 更新数据更新时间
func (this *DNSProviderDAO) UpdateProviderDataUpdatedTime(tx *dbs.Tx, providerId int64) error {
_, err := this.Query(tx).
Pk(providerId).

View File

@@ -9,7 +9,7 @@ import (
func TestDNSTaskDAO_CreateDNSTask(t *testing.T) {
dbs.NotifyReady()
err := SharedDNSTaskDAO.CreateDNSTask(nil, 1, 2, 3, "taskType")
err := SharedDNSTaskDAO.CreateDNSTask(nil, 1, 2, 3, 0, "taskType")
if err != nil {
t.Fatal(err)
}

View File

@@ -0,0 +1,207 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package dnsutils
import (
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
"github.com/TeaOSLab/EdgeAPI/internal/db/models/dns"
"github.com/TeaOSLab/EdgeAPI/internal/dnsclients"
"github.com/TeaOSLab/EdgeAPI/internal/errors"
"github.com/TeaOSLab/EdgeAPI/internal/utils/numberutils"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/dbs"
)
// CheckClusterDNS 检查集群的DNS问题
// 藏这么深是避免package循环引用的问题
func CheckClusterDNS(tx *dbs.Tx, cluster *models.NodeCluster) (issues []*pb.DNSIssue, err error) {
clusterId := int64(cluster.Id)
domainId := int64(cluster.DnsDomainId)
// 检查域名
domain, err := dns.SharedDNSDomainDAO.FindEnabledDNSDomain(tx, domainId, nil)
if err != nil {
return nil, err
}
if domain == nil {
issues = append(issues, &pb.DNSIssue{
Target: cluster.Name,
TargetId: clusterId,
Type: "cluster",
Description: "域名选择错误,需要重新选择",
Params: nil,
MustFix: true,
})
return
}
// Provider
provider, err := dns.SharedDNSProviderDAO.FindEnabledDNSProvider(tx, int64(domain.ProviderId))
if err != nil {
return nil, err
}
if provider == nil {
issues = append(issues, &pb.DNSIssue{
Target: cluster.Name,
TargetId: clusterId,
Type: "cluster",
Description: "域名服务商不可用,需要重新选择",
Params: nil,
MustFix: true,
})
return
}
paramsMap, err := provider.DecodeAPIParams()
if err != nil {
issues = append(issues, &pb.DNSIssue{
Target: cluster.Name,
TargetId: clusterId,
Type: "cluster",
Description: "域名服务商参数配置错误,需要重新配置",
Params: nil,
MustFix: true,
})
return
}
var dnsProvider = dnsclients.FindProvider(provider.Type)
if dnsProvider == nil {
issues = append(issues, &pb.DNSIssue{
Target: cluster.Name,
TargetId: clusterId,
Type: "cluster",
Description: "目前不支持\"" + provider.Type + "\"服务商,需要重新配置",
Params: nil,
MustFix: true,
})
return
}
err = dnsProvider.Auth(paramsMap)
if err != nil {
return
}
var defaultRoute = dnsProvider.DefaultRoute()
var hasDefaultRoute = len(defaultRoute) > 0
// 检查二级域名
if len(cluster.DnsName) == 0 {
issues = append(issues, &pb.DNSIssue{
Target: cluster.Name,
TargetId: clusterId,
Type: "cluster",
Description: "没有设置二级域名",
Params: nil,
MustFix: true,
})
return
}
// TODO 检查域名格式
// TODO 检查域名是否已解析
// 检查节点
nodes, err := models.SharedNodeDAO.FindAllEnabledNodesDNSWithClusterId(tx, clusterId, true)
if err != nil {
return nil, err
}
// TODO 检查节点数量不能为0
for _, node := range nodes {
nodeId := int64(node.Id)
routeCodes, err := node.DNSRouteCodesForDomainId(domainId)
if err != nil {
return nil, err
}
if len(routeCodes) == 0 && !hasDefaultRoute {
issues = append(issues, &pb.DNSIssue{
Target: node.Name,
TargetId: nodeId,
Type: "node",
Description: "没有选择节点所属线路",
Params: map[string]string{
"clusterName": cluster.Name,
"clusterId": numberutils.FormatInt64(clusterId),
},
MustFix: true,
})
continue
}
// 检查线路是否在已有线路中
for _, routeCode := range routeCodes {
routeOk, err := domain.ContainsRouteCode(routeCode)
if err != nil {
return nil, err
}
if !routeOk {
issues = append(issues, &pb.DNSIssue{
Target: node.Name,
TargetId: nodeId,
Type: "node",
Description: "线路已经失效,请重新选择",
Params: map[string]string{
"clusterName": cluster.Name,
"clusterId": numberutils.FormatInt64(clusterId),
},
MustFix: true,
})
continue
}
}
// 检查IP地址
ipAddr, err := models.SharedNodeIPAddressDAO.FindFirstNodeAccessIPAddress(tx, nodeId, nodeconfigs.NodeRoleNode)
if err != nil {
return nil, err
}
if len(ipAddr) == 0 {
issues = append(issues, &pb.DNSIssue{
Target: node.Name,
TargetId: nodeId,
Type: "node",
Description: "没有设置IP地址",
Params: map[string]string{
"clusterName": cluster.Name,
"clusterId": numberutils.FormatInt64(clusterId),
},
MustFix: true,
})
continue
}
// TODO 检查是否有解析记录
}
return
}
// FindDefaultDomainRoute 获取域名默认的线路
func FindDefaultDomainRoute(tx *dbs.Tx, domain *dns.DNSDomain) (string, error) {
if domain == nil {
return "", errors.New("can not find domain")
}
provider, err := dns.SharedDNSProviderDAO.FindEnabledDNSProvider(tx, int64(domain.ProviderId))
if err != nil {
return "", err
}
if provider == nil {
return "", errors.New("provider not found")
}
paramsMap, err := provider.DecodeAPIParams()
if err != nil {
return "", errors.New("decode provider params failed: " + err.Error())
}
var dnsProvider = dnsclients.FindProvider(provider.Type)
if dnsProvider == nil {
return "", errors.New("not supported provider type '" + provider.Type + "'")
}
err = dnsProvider.Auth(paramsMap)
if err != nil {
return "", err
}
return dnsProvider.DefaultRoute(), nil
}

View File

@@ -0,0 +1,29 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package dnsutils
import (
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
"github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/logs"
"testing"
)
func TestNodeClusterDAO_CheckClusterDNS(t *testing.T) {
dbs.NotifyReady()
var tx *dbs.Tx
cluster, err := models.SharedNodeClusterDAO.FindEnabledNodeCluster(tx, 34)
if err != nil {
t.Fatal(err)
}
if cluster == nil {
t.Log("cluster not found, skip the test")
return
}
issues, err := CheckClusterDNS(tx, cluster)
if err != nil {
t.Fatal(err)
}
logs.PrintAsJSON(issues, t)
}

View File

@@ -4,7 +4,9 @@ import (
"encoding/json"
"github.com/TeaOSLab/EdgeAPI/internal/configs"
"github.com/TeaOSLab/EdgeAPI/internal/errors"
"github.com/TeaOSLab/EdgeAPI/internal/utils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
@@ -12,6 +14,8 @@ import (
"github.com/iwind/TeaGo/logs"
"github.com/iwind/TeaGo/types"
timeutil "github.com/iwind/TeaGo/utils/time"
"net"
"net/http"
"regexp"
"sort"
"strconv"
@@ -41,9 +45,9 @@ func NewHTTPAccessLogDAO() *HTTPAccessLogDAO {
}).(*HTTPAccessLogDAO)
}
// 创建访问日志
// CreateHTTPAccessLogs 创建访问日志
func (this *HTTPAccessLogDAO) CreateHTTPAccessLogs(tx *dbs.Tx, accessLogs []*pb.HTTPAccessLog) error {
dao := randomAccessLogDAO()
dao := randomHTTPAccessLogDAO()
if dao == nil {
dao = &HTTPAccessLogDAOWrapper{
DAO: SharedHTTPAccessLogDAO,
@@ -53,7 +57,7 @@ func (this *HTTPAccessLogDAO) CreateHTTPAccessLogs(tx *dbs.Tx, accessLogs []*pb.
return this.CreateHTTPAccessLogsWithDAO(tx, dao, accessLogs)
}
// 使用特定的DAO创建访问日志
// CreateHTTPAccessLogsWithDAO 使用特定的DAO创建访问日志
func (this *HTTPAccessLogDAO) CreateHTTPAccessLogsWithDAO(tx *dbs.Tx, daoWrapper *HTTPAccessLogDAOWrapper, accessLogs []*pb.HTTPAccessLog) error {
if daoWrapper == nil {
return errors.New("dao should not be nil")
@@ -68,7 +72,7 @@ func (this *HTTPAccessLogDAO) CreateHTTPAccessLogsWithDAO(tx *dbs.Tx, daoWrapper
for _, accessLog := range accessLogs {
day := timeutil.Format("Ymd", time.Unix(accessLog.Timestamp, 0))
table, err := findAccessLogTable(dao.Instance, day, false)
tableDef, err := findHTTPAccessLogTable(dao.Instance, day, false)
if err != nil {
return err
}
@@ -84,6 +88,14 @@ func (this *HTTPAccessLogDAO) CreateHTTPAccessLogsWithDAO(tx *dbs.Tx, daoWrapper
fields["firewallRuleSetId"] = accessLog.FirewallRuleSetId
fields["firewallRuleId"] = accessLog.FirewallRuleId
// TODO 根据集群、服务设置获取IP
if tableDef.HasRemoteAddr {
fields["remoteAddr"] = accessLog.RemoteAddr
}
if tableDef.HasDomain {
fields["domain"] = accessLog.Host
}
content, err := json.Marshal(accessLog)
if err != nil {
return err
@@ -91,23 +103,25 @@ func (this *HTTPAccessLogDAO) CreateHTTPAccessLogsWithDAO(tx *dbs.Tx, daoWrapper
fields["content"] = content
_, err = dao.Query(tx).
Table(table).
Table(tableDef.Name).
Sets(fields).
Insert()
if err != nil {
// 是否为 Error 1146: Table 'xxx.xxx' doesn't exist 如果是,则创建表之后重试
if strings.Contains(err.Error(), "1146") {
table, err = findAccessLogTable(dao.Instance, day, true)
tableDef, err = findHTTPAccessLogTable(dao.Instance, day, true)
if err != nil {
return err
}
_, err = dao.Query(tx).
Table(table).
Table(tableDef.Name).
Sets(fields).
Insert()
if err != nil {
return err
}
} else {
logs.Println("HTTP_ACCESS_LOG", err.Error())
}
}
}
@@ -115,8 +129,21 @@ func (this *HTTPAccessLogDAO) CreateHTTPAccessLogsWithDAO(tx *dbs.Tx, daoWrapper
return nil
}
// 读取往前的 单页访问日志
func (this *HTTPAccessLogDAO) ListAccessLogs(tx *dbs.Tx, lastRequestId string, size int64, day string, serverId int64, reverse bool, hasError bool, firewallPolicyId int64, firewallRuleGroupId int64, firewallRuleSetId int64, hasFirewallPolicy bool, userId int64) (result []*HTTPAccessLog, nextLastRequestId string, hasMore bool, err error) {
// ListAccessLogs 读取往前的 单页访问日志
func (this *HTTPAccessLogDAO) ListAccessLogs(tx *dbs.Tx, lastRequestId string,
size int64,
day string,
serverId int64,
reverse bool,
hasError bool,
firewallPolicyId int64,
firewallRuleGroupId int64,
firewallRuleSetId int64,
hasFirewallPolicy bool,
userId int64,
keyword string,
ip string,
domain string) (result []*HTTPAccessLog, nextLastRequestId string, hasMore bool, err error) {
if len(day) != 8 {
return
}
@@ -126,18 +153,18 @@ func (this *HTTPAccessLogDAO) ListAccessLogs(tx *dbs.Tx, lastRequestId string, s
size = 1000
}
result, nextLastRequestId, err = this.listAccessLogs(tx, lastRequestId, size, day, serverId, reverse, hasError, firewallPolicyId, firewallRuleGroupId, firewallRuleSetId, hasFirewallPolicy, userId)
result, nextLastRequestId, err = this.listAccessLogs(tx, lastRequestId, size, day, serverId, reverse, hasError, firewallPolicyId, firewallRuleGroupId, firewallRuleSetId, hasFirewallPolicy, userId, keyword, ip, domain)
if err != nil || int64(len(result)) < size {
return
}
moreResult, _, _ := this.listAccessLogs(tx, nextLastRequestId, 1, day, serverId, reverse, hasError, firewallPolicyId, firewallRuleGroupId, firewallRuleSetId, hasFirewallPolicy, userId)
moreResult, _, _ := this.listAccessLogs(tx, nextLastRequestId, 1, day, serverId, reverse, hasError, firewallPolicyId, firewallRuleGroupId, firewallRuleSetId, hasFirewallPolicy, userId, keyword, ip, domain)
hasMore = len(moreResult) > 0
return
}
// 读取往前的单页访问日志
func (this *HTTPAccessLogDAO) listAccessLogs(tx *dbs.Tx, lastRequestId string, size int64, day string, serverId int64, reverse bool, hasError bool, firewallPolicyId int64, firewallRuleGroupId int64, firewallRuleSetId int64, hasFirewallPolicy bool, userId int64) (result []*HTTPAccessLog, nextLastRequestId string, err error) {
func (this *HTTPAccessLogDAO) listAccessLogs(tx *dbs.Tx, lastRequestId string, size int64, day string, serverId int64, reverse bool, hasError bool, firewallPolicyId int64, firewallRuleGroupId int64, firewallRuleSetId int64, hasFirewallPolicy bool, userId int64, keyword string, ip string, domain string) (result []*HTTPAccessLog, nextLastRequestId string, err error) {
if size <= 0 {
return nil, lastRequestId, nil
}
@@ -155,7 +182,7 @@ func (this *HTTPAccessLogDAO) listAccessLogs(tx *dbs.Tx, lastRequestId string, s
accessLogLocker.RLock()
daoList := []*HTTPAccessLogDAOWrapper{}
for _, daoWrapper := range accessLogDAOMapping {
for _, daoWrapper := range httpAccessLogDAOMapping {
daoList = append(daoList, daoWrapper)
}
accessLogLocker.RUnlock()
@@ -178,7 +205,7 @@ func (this *HTTPAccessLogDAO) listAccessLogs(tx *dbs.Tx, lastRequestId string, s
dao := daoWrapper.DAO
tableName, exists, err := findAccessLogTableName(dao.Instance, day)
tableName, hasRemoteAddrField, hasDomainField, exists, err := findHTTPAccessLogTableName(dao.Instance, day)
if !exists {
// 表格不存在则跳过
return
@@ -211,6 +238,106 @@ func (this *HTTPAccessLogDAO) listAccessLogs(tx *dbs.Tx, lastRequestId string, s
}
if hasFirewallPolicy {
query.Where("firewallPolicyId>0")
query.UseIndex("firewallPolicyId")
}
// keyword
if len(ip) > 0 {
// TODO 支持IP范围
if hasRemoteAddrField {
// IP格式
if strings.Contains(ip, ",") || strings.Contains(ip, "-") {
rangeConfig, err := shared.ParseIPRange(ip)
if err == nil {
if len(rangeConfig.IPFrom) > 0 && len(rangeConfig.IPTo) > 0 {
query.Between("INET_ATON(remoteAddr)", utils.IP2Long(rangeConfig.IPFrom), utils.IP2Long(rangeConfig.IPTo))
}
}
} else {
query.Attr("remoteAddr", ip)
query.UseIndex("remoteAddr")
}
} else {
query.Where("JSON_EXTRACT(content, '$.remoteAddr')=:ip1").
Param("ip1", ip)
}
}
if len(domain) > 0 {
if hasDomainField {
if strings.Contains(domain, "*") {
domain = strings.ReplaceAll(domain, "*", "%")
domain = regexp.MustCompile(`[^a-zA-Z0-9-.%]`).ReplaceAllString(domain, "")
query.Where("domain LIKE :host2").
Param("host2", domain)
} else {
query.Attr("domain", domain)
query.UseIndex("domain")
}
} else {
query.Where("JSON_EXTRACT(content, '$.host')=:host1").
Param("host1", domain)
}
}
if len(keyword) > 0 {
// remoteAddr
if hasRemoteAddrField && net.ParseIP(keyword) != nil {
query.Attr("remoteAddr", keyword)
} else if hasRemoteAddrField && regexp.MustCompile(`^ip:.+`).MatchString(keyword) {
keyword = keyword[3:]
pieces := strings.SplitN(keyword, ",", 2)
if len(pieces) == 1 || len(pieces[1]) == 0 {
query.Attr("remoteAddr", pieces[0])
} else {
query.Between("INET_ATON(remoteAddr)", utils.IP2Long(pieces[0]), utils.IP2Long(pieces[1]))
}
} else {
if regexp.MustCompile(`^ip:.+`).MatchString(keyword) {
keyword = keyword[3:]
}
useOriginKeyword := false
where := "JSON_EXTRACT(content, '$.remoteAddr') LIKE :keyword OR JSON_EXTRACT(content, '$.requestURI') LIKE :keyword OR JSON_EXTRACT(content, '$.host') LIKE :keyword OR JSON_EXTRACT(content, '$.userAgent') LIKE :keyword"
jsonKeyword, err := json.Marshal(keyword)
if err == nil {
where += " OR JSON_CONTAINS(content, :jsonKeyword, '$.tags')"
query.Param("jsonKeyword", jsonKeyword)
}
// 请求方法
if keyword == http.MethodGet ||
keyword == http.MethodPost ||
keyword == http.MethodHead ||
keyword == http.MethodConnect ||
keyword == http.MethodPut ||
keyword == http.MethodTrace ||
keyword == http.MethodOptions ||
keyword == http.MethodDelete ||
keyword == http.MethodPatch {
where += " OR JSON_EXTRACT(content, '$.requestMethod')=:originKeyword"
useOriginKeyword = true
}
// 响应状态码
if regexp.MustCompile(`^\d{3}$`).MatchString(keyword) {
where += " OR JSON_EXTRACT(content, '$.status')=:intKeyword"
query.Param("intKeyword", types.Int(keyword))
}
if regexp.MustCompile(`^\d{3}-\d{3}$`).MatchString(keyword) {
pieces := strings.Split(keyword, "-")
where += " OR JSON_EXTRACT(content, '$.status') BETWEEN :intKeyword1 AND :intKeyword2"
query.Param("intKeyword1", types.Int(pieces[0]))
query.Param("intKeyword2", types.Int(pieces[1]))
}
query.Where("("+where+")").
Param("keyword", "%"+keyword+"%")
if useOriginKeyword {
query.Param("originKeyword", keyword)
}
}
}
// offset
@@ -278,7 +405,7 @@ func (this *HTTPAccessLogDAO) listAccessLogs(tx *dbs.Tx, lastRequestId string, s
}
}
// 根据请求ID获取访问日志
// FindAccessLogWithRequestId 根据请求ID获取访问日志
func (this *HTTPAccessLogDAO) FindAccessLogWithRequestId(tx *dbs.Tx, requestId string) (*HTTPAccessLog, error) {
if !regexp.MustCompile(`^\d{30,}`).MatchString(requestId) {
return nil, errors.New("invalid requestId")
@@ -286,7 +413,7 @@ func (this *HTTPAccessLogDAO) FindAccessLogWithRequestId(tx *dbs.Tx, requestId s
accessLogLocker.RLock()
daoList := []*HTTPAccessLogDAOWrapper{}
for _, daoWrapper := range accessLogDAOMapping {
for _, daoWrapper := range httpAccessLogDAOMapping {
daoList = append(daoList, daoWrapper)
}
accessLogLocker.RUnlock()
@@ -309,7 +436,7 @@ func (this *HTTPAccessLogDAO) FindAccessLogWithRequestId(tx *dbs.Tx, requestId s
dao := daoWrapper.DAO
tableName, exists, err := findAccessLogTableName(dao.Instance, day)
tableName, _, _, exists, err := findHTTPAccessLogTableName(dao.Instance, day)
if err != nil {
logs.Println("[DB_NODE]" + err.Error())
return

View File

@@ -24,7 +24,7 @@ func TestCreateHTTPAccessLogs(t *testing.T) {
Status: 200,
Timestamp: time.Now().Unix(),
}
dao := randomAccessLogDAO()
dao := randomHTTPAccessLogDAO()
t.Log("dao:", dao)
err = SharedHTTPAccessLogDAO.CreateHTTPAccessLogsWithDAO(tx, dao, []*pb.HTTPAccessLog{accessLog})
if err != nil {
@@ -41,7 +41,7 @@ func TestHTTPAccessLogDAO_ListAccessLogs(t *testing.T) {
t.Fatal(err)
}
accessLogs, requestId, hasMore, err := SharedHTTPAccessLogDAO.ListAccessLogs(tx, "", 10, timeutil.Format("Ymd"), 0, false, false, 0, 0, 0, false, 0)
accessLogs, requestId, hasMore, err := SharedHTTPAccessLogDAO.ListAccessLogs(tx, "", 10, timeutil.Format("Ymd"), 0, false, false, 0, 0, 0, false, 0, "", "", "")
if err != nil {
t.Fatal(err)
}
@@ -68,7 +68,7 @@ func TestHTTPAccessLogDAO_ListAccessLogs_Page(t *testing.T) {
times := 0 // 防止循环次数太多
for {
before := time.Now()
accessLogs, requestId, hasMore, err := SharedHTTPAccessLogDAO.ListAccessLogs(tx, lastRequestId, 2, timeutil.Format("Ymd"), 0, false, false, 0, 0, 0, false, 0)
accessLogs, requestId, hasMore, err := SharedHTTPAccessLogDAO.ListAccessLogs(tx, lastRequestId, 2, timeutil.Format("Ymd"), 0, false, false, 0, 0, 0, false, 0, "", "", "")
cost := time.Since(before).Seconds()
if err != nil {
t.Fatal(err)
@@ -99,7 +99,7 @@ func TestHTTPAccessLogDAO_ListAccessLogs_Reverse(t *testing.T) {
}
before := time.Now()
accessLogs, requestId, hasMore, err := SharedHTTPAccessLogDAO.ListAccessLogs(tx, "16023261176446590001000000000000003500000004", 2, timeutil.Format("Ymd"), 0, true, false, 0, 0, 0, false, 0)
accessLogs, requestId, hasMore, err := SharedHTTPAccessLogDAO.ListAccessLogs(tx, "16023261176446590001000000000000003500000004", 2, timeutil.Format("Ymd"), 0, true, false, 0, 0, 0, false, 0, "", "", "")
cost := time.Since(before).Seconds()
if err != nil {
t.Fatal(err)
@@ -124,7 +124,7 @@ func TestHTTPAccessLogDAO_ListAccessLogs_Page_NotExists(t *testing.T) {
times := 0 // 防止循环次数太多
for {
before := time.Now()
accessLogs, requestId, hasMore, err := SharedHTTPAccessLogDAO.ListAccessLogs(tx, lastRequestId, 2, timeutil.Format("Ymd", time.Now().AddDate(0, 0, 1)), 0, false, false, 0, 0, 0, false, 0)
accessLogs, requestId, hasMore, err := SharedHTTPAccessLogDAO.ListAccessLogs(tx, lastRequestId, 2, timeutil.Format("Ymd", time.Now().AddDate(0, 0, 1)), 0, false, false, 0, 0, 0, false, 0, "", "", "")
cost := time.Since(before).Seconds()
if err != nil {
t.Fatal(err)

View File

@@ -1,6 +1,6 @@
package models
//
// HTTPAccessLog 访问日志
type HTTPAccessLog struct {
Id uint64 `field:"id"` // ID
ServerId uint32 `field:"serverId"` // 服务ID
@@ -13,6 +13,10 @@ type HTTPAccessLog struct {
FirewallRuleGroupId uint32 `field:"firewallRuleGroupId"` // WAF分组ID
FirewallRuleSetId uint32 `field:"firewallRuleSetId"` // WAF集ID
FirewallRuleId uint32 `field:"firewallRuleId"` // WAF规则ID
RemoteAddr string `field:"remoteAddr"` // IP地址
Domain string `field:"domain"` // 域名
RequestBody string `field:"requestBody"` // 请求内容
ResponseBody string `field:"responseBody"` // 响应内容
}
type HTTPAccessLogOperator struct {
@@ -27,6 +31,10 @@ type HTTPAccessLogOperator struct {
FirewallRuleGroupId interface{} // WAF分组ID
FirewallRuleSetId interface{} // WAF集ID
FirewallRuleId interface{} // WAF规则ID
RemoteAddr interface{} // IP地址
Domain interface{} // 域名
RequestBody interface{} // 请求内容
ResponseBody interface{} // 响应内容
}
func NewHTTPAccessLogOperator() *HTTPAccessLogOperator {

View File

@@ -5,7 +5,7 @@ import (
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
)
// 转换成PB对象
// ToPB 转换成PB对象
func (this *HTTPAccessLog) ToPB() (*pb.HTTPAccessLog, error) {
p := &pb.HTTPAccessLog{}
err := json.Unmarshal([]byte(this.Content), p)

View File

@@ -1,12 +1,13 @@
package models
import (
"bytes"
"encoding/json"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
"github.com/TeaOSLab/EdgeAPI/internal/errors"
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/maps"
)
const (
@@ -35,12 +36,12 @@ func init() {
})
}
// 初始化
// Init 初始化
func (this *HTTPAccessLogPolicyDAO) Init() {
_ = this.DAOObject.Init()
}
// 启用条目
// EnableHTTPAccessLogPolicy 启用条目
func (this *HTTPAccessLogPolicyDAO) EnableHTTPAccessLogPolicy(tx *dbs.Tx, id int64) error {
_, err := this.Query(tx).
Pk(id).
@@ -49,7 +50,7 @@ func (this *HTTPAccessLogPolicyDAO) EnableHTTPAccessLogPolicy(tx *dbs.Tx, id int
return err
}
// 禁用条目
// DisableHTTPAccessLogPolicy 禁用条目
func (this *HTTPAccessLogPolicyDAO) DisableHTTPAccessLogPolicy(tx *dbs.Tx, id int64) error {
_, err := this.Query(tx).
Pk(id).
@@ -58,7 +59,7 @@ func (this *HTTPAccessLogPolicyDAO) DisableHTTPAccessLogPolicy(tx *dbs.Tx, id in
return err
}
// 查找启用中的条目
// FindEnabledHTTPAccessLogPolicy 查找启用中的条目
func (this *HTTPAccessLogPolicyDAO) FindEnabledHTTPAccessLogPolicy(tx *dbs.Tx, id int64) (*HTTPAccessLogPolicy, error) {
result, err := this.Query(tx).
Pk(id).
@@ -70,7 +71,7 @@ func (this *HTTPAccessLogPolicyDAO) FindEnabledHTTPAccessLogPolicy(tx *dbs.Tx, i
return result.(*HTTPAccessLogPolicy), err
}
// 根据主键查找名称
// FindHTTPAccessLogPolicyName 根据主键查找名称
func (this *HTTPAccessLogPolicyDAO) FindHTTPAccessLogPolicyName(tx *dbs.Tx, id int64) (string, error) {
return this.Query(tx).
Pk(id).
@@ -78,51 +79,116 @@ func (this *HTTPAccessLogPolicyDAO) FindHTTPAccessLogPolicyName(tx *dbs.Tx, id i
FindStringCol("")
}
// 查找所有可用策略信息
func (this *HTTPAccessLogPolicyDAO) FindAllEnabledAccessLogPolicies(tx *dbs.Tx) (result []*HTTPAccessLogPolicy, err error) {
// CountAllEnabledPolicies 计算策略数量
func (this *HTTPAccessLogPolicyDAO) CountAllEnabledPolicies(tx *dbs.Tx) (int64, error) {
return this.Query(tx).
State(HTTPAccessLogPolicyStateEnabled).
Count()
}
// ListEnabledPolicies 查找所有可用策略信息
func (this *HTTPAccessLogPolicyDAO) ListEnabledPolicies(tx *dbs.Tx, offset int64, size int64) (result []*HTTPAccessLogPolicy, err error) {
_, err = this.Query(tx).
State(HTTPAccessLogPolicyStateEnabled).
DescPk().
Offset(offset).
Limit(size).
Slice(&result).
FindAll()
return
}
// 组合配置
func (this *HTTPAccessLogPolicyDAO) ComposeAccessLogPolicyConfig(tx *dbs.Tx, policyId int64) (*serverconfigs.HTTPAccessLogStoragePolicy, error) {
policy, err := this.FindEnabledHTTPAccessLogPolicy(tx, policyId)
if err != nil {
return nil, err
}
if policy == nil {
return nil, nil
}
config := &serverconfigs.HTTPAccessLogStoragePolicy{}
config.Id = int64(policy.Id)
config.IsOn = policy.IsOn == 1
config.Name = policy.Name
config.Type = policy.Type
// 选项
if IsNotNull(policy.Options) {
m := map[string]interface{}{}
err = json.Unmarshal([]byte(policy.Options), &m)
if err != nil {
return nil, err
}
config.Options = m
}
// 条件
if IsNotNull(policy.Conds) {
condsConfig := &shared.HTTPRequestCondsConfig{}
err = json.Unmarshal([]byte(policy.Conds), condsConfig)
if err != nil {
return nil, err
}
config.Conds = condsConfig
}
return config, nil
// FindAllEnabledAndOnPolicies 获取所有的策略信息
func (this *HTTPAccessLogPolicyDAO) FindAllEnabledAndOnPolicies(tx *dbs.Tx) (result []*HTTPAccessLogPolicy, err error) {
_, err = this.Query(tx).
State(HTTPAccessLogPolicyStateEnabled).
Attr("isOn", true).
Slice(&result).
FindAll()
return
}
// CreatePolicy 创建策略
func (this *HTTPAccessLogPolicyDAO) CreatePolicy(tx *dbs.Tx, name string, policyType string, optionsJSON []byte, condsJSON []byte, isPublic bool) (policyId int64, err error) {
var op = NewHTTPAccessLogPolicyOperator()
op.Name = name
op.Type = policyType
if len(optionsJSON) > 0 {
op.Options = optionsJSON
}
if len(condsJSON) > 0 {
op.Conds = condsJSON
}
op.IsPublic = isPublic
op.IsOn = true
op.State = HTTPAccessLogPolicyStateEnabled
return this.SaveInt64(tx, op)
}
// UpdatePolicy 修改策略
func (this *HTTPAccessLogPolicyDAO) UpdatePolicy(tx *dbs.Tx, policyId int64, name string, optionsJSON []byte, condsJSON []byte, isPublic bool, isOn bool) error {
if policyId <= 0 {
return errors.New("invalid policyId")
}
oldOne, err := this.Query(tx).
Pk(policyId).
Find()
if err != nil {
return err
}
if oldOne == nil {
return nil
}
var oldPolicy = oldOne.(*HTTPAccessLogPolicy)
var op = NewHTTPAccessLogPolicyOperator()
op.Id = policyId
op.Name = name
if len(optionsJSON) > 0 {
op.Options = optionsJSON
} else {
op.Options = "{}"
}
if len(condsJSON) > 0 {
op.Conds = condsJSON
} else {
op.Conds = "{}"
}
// 版本号
if len(oldPolicy.Options) == 0 || len(optionsJSON) == 0 {
op.Version = dbs.SQL("version+1")
} else {
var m1 = maps.Map{}
_ = json.Unmarshal([]byte(oldPolicy.Options), &m1)
var m2 = maps.Map{}
_ = json.Unmarshal(optionsJSON, &m2)
if bytes.Compare(m1.AsJSON(), m2.AsJSON()) != 0 {
op.Version = dbs.SQL("version+1")
}
}
op.IsPublic = isPublic
op.IsOn = isOn
return this.Save(tx, op)
}
// CancelAllPublicPolicies 取消别的公用的策略
func (this *HTTPAccessLogPolicyDAO) CancelAllPublicPolicies(tx *dbs.Tx) error {
return this.Query(tx).
State(HTTPAccessLogPolicyStateEnabled).
Set("isPublic", 0).
UpdateQuickly()
}
// FindCurrentPublicPolicyId 取得当前的公用策略
func (this *HTTPAccessLogPolicyDAO) FindCurrentPublicPolicyId(tx *dbs.Tx) (int64, error) {
return this.Query(tx).
State(HTTPAccessLogPolicyStateEnabled).
Attr("isPublic", 1).
ResultPk().
FindInt64Col(0)
}

View File

@@ -1,6 +1,6 @@
package models
// 访问日志策略
// HTTPAccessLogPolicy 访问日志策略
type HTTPAccessLogPolicy struct {
Id uint32 `field:"id"` // ID
TemplateId uint32 `field:"templateId"` // 模版ID
@@ -13,6 +13,8 @@ type HTTPAccessLogPolicy struct {
Type string `field:"type"` // 存储类型
Options string `field:"options"` // 存储选项
Conds string `field:"conds"` // 请求条件
IsPublic uint8 `field:"isPublic"` // 是否为公用
Version uint32 `field:"version"` // 版本号
}
type HTTPAccessLogPolicyOperator struct {
@@ -27,6 +29,8 @@ type HTTPAccessLogPolicyOperator struct {
Type interface{} // 存储类型
Options interface{} // 存储选项
Conds interface{} // 请求条件
IsPublic interface{} // 是否为公用
Version interface{} // 版本号
}
func NewHTTPAccessLogPolicyOperator() *HTTPAccessLogPolicyOperator {

View File

@@ -0,0 +1,148 @@
package models
import (
"encoding/json"
"github.com/TeaOSLab/EdgeAPI/internal/errors"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/maps"
"github.com/iwind/TeaGo/types"
)
const (
HTTPAuthPolicyStateEnabled = 1 // 已启用
HTTPAuthPolicyStateDisabled = 0 // 已禁用
)
type HTTPAuthPolicyDAO dbs.DAO
func NewHTTPAuthPolicyDAO() *HTTPAuthPolicyDAO {
return dbs.NewDAO(&HTTPAuthPolicyDAO{
DAOObject: dbs.DAOObject{
DB: Tea.Env,
Table: "edgeHTTPAuthPolicies",
Model: new(HTTPAuthPolicy),
PkName: "id",
},
}).(*HTTPAuthPolicyDAO)
}
var SharedHTTPAuthPolicyDAO *HTTPAuthPolicyDAO
func init() {
dbs.OnReady(func() {
SharedHTTPAuthPolicyDAO = NewHTTPAuthPolicyDAO()
})
}
// EnableHTTPAuthPolicy 启用条目
func (this *HTTPAuthPolicyDAO) EnableHTTPAuthPolicy(tx *dbs.Tx, id int64) error {
_, err := this.Query(tx).
Pk(id).
Set("state", HTTPAuthPolicyStateEnabled).
Update()
return err
}
// DisableHTTPAuthPolicy 禁用条目
func (this *HTTPAuthPolicyDAO) DisableHTTPAuthPolicy(tx *dbs.Tx, id int64) error {
_, err := this.Query(tx).
Pk(id).
Set("state", HTTPAuthPolicyStateDisabled).
Update()
return err
}
// FindEnabledHTTPAuthPolicy 查找启用中的条目
func (this *HTTPAuthPolicyDAO) FindEnabledHTTPAuthPolicy(tx *dbs.Tx, id int64) (*HTTPAuthPolicy, error) {
result, err := this.Query(tx).
Pk(id).
Attr("state", HTTPAuthPolicyStateEnabled).
Find()
if result == nil {
return nil, err
}
return result.(*HTTPAuthPolicy), err
}
// CreateHTTPAuthPolicy 创建策略
func (this *HTTPAuthPolicyDAO) CreateHTTPAuthPolicy(tx *dbs.Tx, name string, methodType string, paramsJSON []byte) (int64, error) {
op := NewHTTPAuthPolicyOperator()
op.Name = name
op.Type = methodType
op.Params = paramsJSON
op.IsOn = true
op.State = HTTPAuthPolicyStateEnabled
return this.SaveInt64(tx, op)
}
// UpdateHTTPAuthPolicy 修改策略
func (this *HTTPAuthPolicyDAO) UpdateHTTPAuthPolicy(tx *dbs.Tx, policyId int64, name string, paramsJSON []byte, isOn bool) error {
if policyId <= 0 {
return errors.New("invalid policyId")
}
op := NewHTTPAuthPolicyOperator()
op.Id = policyId
op.Name = name
op.Params = paramsJSON
op.IsOn = isOn
err := this.Save(tx, op)
if err != nil {
return err
}
return this.NotifyUpdate(tx, policyId)
}
// ComposePolicyConfig 组合配置
func (this *HTTPAuthPolicyDAO) ComposePolicyConfig(tx *dbs.Tx, policyId int64, cacheMap maps.Map) (*serverconfigs.HTTPAuthPolicy, error) {
if cacheMap == nil {
cacheMap = maps.Map{}
}
var cacheKey = this.Table + ":config:" + types.String(policyId)
var cache = cacheMap.Get(cacheKey)
if cache != nil {
return cache.(*serverconfigs.HTTPAuthPolicy), nil
}
policy, err := this.FindEnabledHTTPAuthPolicy(tx, policyId)
if err != nil {
return nil, err
}
if policy == nil {
return nil, nil
}
var config = &serverconfigs.HTTPAuthPolicy{
Id: int64(policy.Id),
Name: policy.Name,
IsOn: policy.IsOn == 1,
Type: policy.Type,
}
var params map[string]interface{}
if IsNotNull(policy.Params) {
err = json.Unmarshal([]byte(policy.Params), &params)
if err != nil {
return nil, err
}
config.Params = params
}
config.Params = params
cacheMap[cacheKey] = config
return config, nil
}
// NotifyUpdate 通知更改
func (this *HTTPAuthPolicyDAO) NotifyUpdate(tx *dbs.Tx, policyId int64) error {
webId, err := SharedHTTPWebDAO.FindEnabledWebIdWithHTTPAuthPolicyId(tx, policyId)
if err != nil {
return err
}
if webId > 0 {
return SharedHTTPWebDAO.NotifyUpdate(tx, webId)
}
return nil
}

View File

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

View File

@@ -0,0 +1,28 @@
package models
// HTTPAuthPolicy HTTP认证策略
type HTTPAuthPolicy struct {
Id uint64 `field:"id"` // ID
AdminId uint32 `field:"adminId"` // 管理员ID
UserId uint32 `field:"userId"` // 用户ID
IsOn uint8 `field:"isOn"` // 是否启用
Name string `field:"name"` // 名称
Type string `field:"type"` // 类型
Params string `field:"params"` // 参数
State uint8 `field:"state"` // 状态
}
type HTTPAuthPolicyOperator struct {
Id interface{} // ID
AdminId interface{} // 管理员ID
UserId interface{} // 用户ID
IsOn interface{} // 是否启用
Name interface{} // 名称
Type interface{} // 类型
Params interface{} // 参数
State interface{} // 状态
}
func NewHTTPAuthPolicyOperator() *HTTPAuthPolicyOperator {
return &HTTPAuthPolicyOperator{}
}

View File

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

View File

@@ -8,6 +8,7 @@ import (
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/maps"
"github.com/iwind/TeaGo/types"
)
@@ -37,12 +38,12 @@ func init() {
})
}
// 初始化
// Init 初始化
func (this *HTTPCachePolicyDAO) Init() {
_ = this.DAOObject.Init()
}
// 启用条目
// EnableHTTPCachePolicy 启用条目
func (this *HTTPCachePolicyDAO) EnableHTTPCachePolicy(tx *dbs.Tx, id int64) error {
_, err := this.Query(tx).
Pk(id).
@@ -51,7 +52,7 @@ func (this *HTTPCachePolicyDAO) EnableHTTPCachePolicy(tx *dbs.Tx, id int64) erro
return err
}
// 禁用条目
// DisableHTTPCachePolicy 禁用条目
func (this *HTTPCachePolicyDAO) DisableHTTPCachePolicy(tx *dbs.Tx, policyId int64) error {
_, err := this.Query(tx).
Pk(policyId).
@@ -63,7 +64,7 @@ func (this *HTTPCachePolicyDAO) DisableHTTPCachePolicy(tx *dbs.Tx, policyId int6
return this.NotifyUpdate(tx, policyId)
}
// 查找启用中的条目
// FindEnabledHTTPCachePolicy 查找启用中的条目
func (this *HTTPCachePolicyDAO) FindEnabledHTTPCachePolicy(tx *dbs.Tx, id int64) (*HTTPCachePolicy, error) {
result, err := this.Query(tx).
Pk(id).
@@ -75,7 +76,7 @@ func (this *HTTPCachePolicyDAO) FindEnabledHTTPCachePolicy(tx *dbs.Tx, id int64)
return result.(*HTTPCachePolicy), err
}
// 根据主键查找名称
// FindHTTPCachePolicyName 根据主键查找名称
func (this *HTTPCachePolicyDAO) FindHTTPCachePolicyName(tx *dbs.Tx, id int64) (string, error) {
return this.Query(tx).
Pk(id).
@@ -83,7 +84,7 @@ func (this *HTTPCachePolicyDAO) FindHTTPCachePolicyName(tx *dbs.Tx, id int64) (s
FindStringCol("")
}
// 查找所有可用的缓存策略
// FindAllEnabledCachePolicies 查找所有可用的缓存策略
func (this *HTTPCachePolicyDAO) FindAllEnabledCachePolicies(tx *dbs.Tx) (result []*HTTPCachePolicy, err error) {
_, err = this.Query(tx).
State(HTTPCachePolicyStateEnabled).
@@ -93,7 +94,7 @@ func (this *HTTPCachePolicyDAO) FindAllEnabledCachePolicies(tx *dbs.Tx) (result
return
}
// 创建缓存策略
// CreateCachePolicy 创建缓存策略
func (this *HTTPCachePolicyDAO) CreateCachePolicy(tx *dbs.Tx, isOn bool, name string, description string, capacityJSON []byte, maxKeys int64, maxSizeJSON []byte, storageType string, storageOptionsJSON []byte) (int64, error) {
op := NewHTTPCachePolicyOperator()
op.State = HTTPCachePolicyStateEnabled
@@ -111,14 +112,89 @@ func (this *HTTPCachePolicyDAO) CreateCachePolicy(tx *dbs.Tx, isOn bool, name st
if len(storageOptionsJSON) > 0 {
op.Options = storageOptionsJSON
}
err := this.Save(tx, op)
// 默认的缓存条件
cacheRef := &serverconfigs.HTTPCacheRef{
IsOn: true,
Key: "${scheme}://${host}${requestURI}",
Life: &shared.TimeDuration{Count: 2, Unit: shared.TimeDurationUnitHour},
Status: []int{200},
MaxSize: &shared.SizeCapacity{Count: 32, Unit: shared.SizeCapacityUnitMB},
SkipResponseSetCookie: true,
AllowChunkedEncoding: true,
Conds: &shared.HTTPRequestCondsConfig{
IsOn: true,
Connector: "or",
Groups: []*shared.HTTPRequestCondGroup{
{
IsOn: true,
Connector: "or",
Conds: []*shared.HTTPRequestCond{
{
Type: "url-extension",
IsRequest: true,
Param: "${requestPathExtension}",
Operator: shared.RequestCondOperatorIn,
Value: `[".html", ".js", ".css", ".gif", ".png", ".bmp", ".jpeg", ".jpg", ".webp", ".ico", ".pdf", ".ttf", ".eot", ".tiff", ".svg", ".svgz", ".eps", ".woff", ".otf", ".woff2", ".tif", ".csv", ".xls", ".xlsx", ".doc", ".docx", ".ppt", ".pptx", ".wav", ".mp3", ".mp4", ".ogg", ".mid", ".midi"]`,
},
},
Description: "初始化规则",
},
},
},
}
refsJSON, err := json.Marshal([]*serverconfigs.HTTPCacheRef{cacheRef})
if err != nil {
return 0, err
}
op.Refs = refsJSON
err = this.Save(tx, op)
if err != nil {
return 0, err
}
return types.Int64(op.Id), nil
}
// 修改缓存策略
// CreateDefaultCachePolicy 创建默认的缓存策略
func (this *HTTPCachePolicyDAO) CreateDefaultCachePolicy(tx *dbs.Tx, name string) (int64, error) {
var capacity = &shared.SizeCapacity{
Count: 64,
Unit: shared.SizeCapacityUnitGB,
}
capacityJSON, err := capacity.AsJSON()
if err != nil {
return 0, err
}
var maxSize = &shared.SizeCapacity{
Count: 256,
Unit: shared.SizeCapacityUnitMB,
}
if err != nil {
return 0, err
}
maxSizeJSON, err := maxSize.AsJSON()
if err != nil {
return 0, err
}
var storageOptions = &serverconfigs.HTTPFileCacheStorage{
Dir: "/opt/cache",
}
storageOptionsJSON, err := json.Marshal(storageOptions)
if err != nil {
return 0, err
}
policyId, err := this.CreateCachePolicy(tx, true, "\""+name+"\"缓存策略", "默认创建的缓存策略", capacityJSON, 0, maxSizeJSON, serverconfigs.CachePolicyStorageFile, storageOptionsJSON)
if err != nil {
return 0, err
}
return policyId, nil
}
// 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) error {
if policyId <= 0 {
return errors.New("invalid policyId")
@@ -147,8 +223,17 @@ func (this *HTTPCachePolicyDAO) UpdateCachePolicy(tx *dbs.Tx, policyId int64, is
return this.NotifyUpdate(tx, policyId)
}
// 组合配置
func (this *HTTPCachePolicyDAO) ComposeCachePolicy(tx *dbs.Tx, policyId int64) (*serverconfigs.HTTPCachePolicy, error) {
// ComposeCachePolicy 组合配置
func (this *HTTPCachePolicyDAO) ComposeCachePolicy(tx *dbs.Tx, policyId int64, cacheMap maps.Map) (*serverconfigs.HTTPCachePolicy, error) {
if cacheMap == nil {
cacheMap = maps.Map{}
}
var cacheKey = this.Table + ":config:" + types.String(policyId)
var cache = cacheMap.Get(cacheKey)
if cache != nil {
return cache.(*serverconfigs.HTTPCachePolicy), nil
}
policy, err := this.FindEnabledHTTPCachePolicy(tx, policyId)
if err != nil {
return nil, err
@@ -196,20 +281,41 @@ func (this *HTTPCachePolicyDAO) ComposeCachePolicy(tx *dbs.Tx, policyId int64) (
config.Options = m
}
// refs
if IsNotNull(policy.Refs) {
refs := []*serverconfigs.HTTPCacheRef{}
err = json.Unmarshal([]byte(policy.Refs), &refs)
if err != nil {
return nil, err
}
config.CacheRefs = refs
}
cacheMap[cacheKey] = config
return config, nil
}
// 计算可用缓存策略数量
func (this *HTTPCachePolicyDAO) CountAllEnabledHTTPCachePolicies(tx *dbs.Tx) (int64, error) {
return this.Query(tx).
State(HTTPCachePolicyStateEnabled).
Count()
// CountAllEnabledHTTPCachePolicies 计算可用缓存策略数量
func (this *HTTPCachePolicyDAO) CountAllEnabledHTTPCachePolicies(tx *dbs.Tx, keyword string) (int64, error) {
query := this.Query(tx).
State(HTTPCachePolicyStateEnabled)
if len(keyword) > 0 {
query.Where("(name LIKE :keyword)").
Param("keyword", "%"+keyword+"%")
}
return query.Count()
}
// 列出单页的缓存策略
func (this *HTTPCachePolicyDAO) ListEnabledHTTPCachePolicies(tx *dbs.Tx, offset int64, size int64) ([]*serverconfigs.HTTPCachePolicy, error) {
ones, err := this.Query(tx).
State(HTTPCachePolicyStateEnabled).
// ListEnabledHTTPCachePolicies 列出单页的缓存策略
func (this *HTTPCachePolicyDAO) ListEnabledHTTPCachePolicies(tx *dbs.Tx, keyword string, offset int64, size int64) ([]*serverconfigs.HTTPCachePolicy, error) {
query := this.Query(tx).
State(HTTPCachePolicyStateEnabled)
if len(keyword) > 0 {
query.Where("(name LIKE :keyword)").
Param("keyword", "%"+keyword+"%")
}
ones, err := query.
ResultPk().
Offset(offset).
Limit(size).
@@ -228,7 +334,7 @@ func (this *HTTPCachePolicyDAO) ListEnabledHTTPCachePolicies(tx *dbs.Tx, offset
cachePolicies := []*serverconfigs.HTTPCachePolicy{}
for _, policyId := range cachePolicyIds {
cachePolicyConfig, err := this.ComposeCachePolicy(tx, policyId)
cachePolicyConfig, err := this.ComposeCachePolicy(tx, policyId, nil)
if err != nil {
return nil, errors.Wrap(err)
}
@@ -237,7 +343,22 @@ func (this *HTTPCachePolicyDAO) ListEnabledHTTPCachePolicies(tx *dbs.Tx, offset
return cachePolicies, nil
}
// 通知更新
// UpdatePolicyRefs 设置默认的缓存条件
func (this *HTTPCachePolicyDAO) UpdatePolicyRefs(tx *dbs.Tx, policyId int64, refsJSON []byte) error {
if len(refsJSON) == 0 {
return nil
}
err := this.Query(tx).
Pk(policyId).
Set("refs", refsJSON).
UpdateQuickly()
if err != nil {
return err
}
return this.NotifyUpdate(tx, policyId)
}
// NotifyUpdate 通知更新
func (this *HTTPCachePolicyDAO) NotifyUpdate(tx *dbs.Tx, policyId int64) error {
webIds, err := SharedHTTPWebDAO.FindAllWebIdsWithCachePolicyId(tx, policyId)
if err != nil {

View File

@@ -1,6 +1,6 @@
package models
// HTTP缓存策略
// HTTPCachePolicy HTTP缓存策略
type HTTPCachePolicy struct {
Id uint32 `field:"id"` // ID
AdminId uint32 `field:"adminId"` // 管理员ID
@@ -16,6 +16,7 @@ type HTTPCachePolicy struct {
CreatedAt uint64 `field:"createdAt"` // 创建时间
State uint8 `field:"state"` // 状态
Description string `field:"description"` // 描述
Refs string `field:"refs"` // 默认的缓存设置
}
type HTTPCachePolicyOperator struct {
@@ -33,6 +34,7 @@ type HTTPCachePolicyOperator struct {
CreatedAt interface{} // 创建时间
State interface{} // 状态
Description interface{} // 描述
Refs interface{} // 默认的缓存设置
}
func NewHTTPCachePolicyOperator() *HTTPCachePolicyOperator {

View File

@@ -7,6 +7,7 @@ import (
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/lists"
"github.com/iwind/TeaGo/maps"
"github.com/iwind/TeaGo/types"
)
@@ -37,12 +38,12 @@ func init() {
})
}
// 初始化
// Init 初始化
func (this *HTTPFirewallPolicyDAO) Init() {
_ = this.DAOObject.Init()
}
// 启用条目
// EnableHTTPFirewallPolicy 启用条目
func (this *HTTPFirewallPolicyDAO) EnableHTTPFirewallPolicy(tx *dbs.Tx, id int64) error {
_, err := this.Query(tx).
Pk(id).
@@ -51,7 +52,7 @@ func (this *HTTPFirewallPolicyDAO) EnableHTTPFirewallPolicy(tx *dbs.Tx, id int64
return err
}
// 禁用条目
// DisableHTTPFirewallPolicy 禁用条目
func (this *HTTPFirewallPolicyDAO) DisableHTTPFirewallPolicy(tx *dbs.Tx, policyId int64) error {
_, err := this.Query(tx).
Pk(policyId).
@@ -64,7 +65,7 @@ func (this *HTTPFirewallPolicyDAO) DisableHTTPFirewallPolicy(tx *dbs.Tx, policyI
return this.NotifyUpdate(tx, policyId)
}
// 查找启用中的条目
// FindEnabledHTTPFirewallPolicy 查找启用中的条目
func (this *HTTPFirewallPolicyDAO) FindEnabledHTTPFirewallPolicy(tx *dbs.Tx, id int64) (*HTTPFirewallPolicy, error) {
result, err := this.Query(tx).
Pk(id).
@@ -76,7 +77,7 @@ func (this *HTTPFirewallPolicyDAO) FindEnabledHTTPFirewallPolicy(tx *dbs.Tx, id
return result.(*HTTPFirewallPolicy), err
}
// 根据主键查找名称
// FindHTTPFirewallPolicyName 根据主键查找名称
func (this *HTTPFirewallPolicyDAO) FindHTTPFirewallPolicyName(tx *dbs.Tx, id int64) (string, error) {
return this.Query(tx).
Pk(id).
@@ -84,7 +85,7 @@ func (this *HTTPFirewallPolicyDAO) FindHTTPFirewallPolicyName(tx *dbs.Tx, id int
FindStringCol("")
}
// 查找所有可用策略
// FindAllEnabledFirewallPolicies 查找所有可用策略
func (this *HTTPFirewallPolicyDAO) FindAllEnabledFirewallPolicies(tx *dbs.Tx) (result []*HTTPFirewallPolicy, err error) {
_, err = this.Query(tx).
State(HTTPFirewallPolicyStateEnabled).
@@ -94,7 +95,7 @@ func (this *HTTPFirewallPolicyDAO) FindAllEnabledFirewallPolicies(tx *dbs.Tx) (r
return
}
// 创建策略
// CreateFirewallPolicy 创建策略
func (this *HTTPFirewallPolicyDAO) CreateFirewallPolicy(tx *dbs.Tx, userId int64, serverId int64, isOn bool, name string, description string, inboundJSON []byte, outboundJSON []byte) (int64, error) {
op := NewHTTPFirewallPolicyOperator()
op.UserId = userId
@@ -113,8 +114,73 @@ func (this *HTTPFirewallPolicyDAO) CreateFirewallPolicy(tx *dbs.Tx, userId int64
return types.Int64(op.Id), err
}
// 修改策略的Inbound和Outbound
func (this *HTTPFirewallPolicyDAO) UpdateFirewallPolicyInboundAndOutbound(tx *dbs.Tx, policyId int64, inboundJSON []byte, outboundJSON []byte) error {
// CreateDefaultFirewallPolicy 创建默认的WAF策略
func (this *HTTPFirewallPolicyDAO) CreateDefaultFirewallPolicy(tx *dbs.Tx, name string) (int64, error) {
policyId, err := this.CreateFirewallPolicy(tx, 0, 0, true, "\""+name+"\"WAF策略", "默认创建的WAF策略", nil, nil)
if err != nil {
return 0, err
}
// 初始化
var groupCodes = []string{}
templatePolicy := firewallconfigs.HTTPFirewallTemplate()
for _, group := range templatePolicy.AllRuleGroups() {
groupCodes = append(groupCodes, group.Code)
}
inboundConfig := &firewallconfigs.HTTPFirewallInboundConfig{IsOn: true}
outboundConfig := &firewallconfigs.HTTPFirewallOutboundConfig{IsOn: true}
if templatePolicy.Inbound != nil {
for _, group := range templatePolicy.Inbound.Groups {
isOn := lists.ContainsString(groupCodes, group.Code)
group.IsOn = isOn
groupId, err := SharedHTTPFirewallRuleGroupDAO.CreateGroupFromConfig(tx, group)
if err != nil {
return 0, err
}
inboundConfig.GroupRefs = append(inboundConfig.GroupRefs, &firewallconfigs.HTTPFirewallRuleGroupRef{
IsOn: true,
GroupId: groupId,
})
}
}
if templatePolicy.Outbound != nil {
for _, group := range templatePolicy.Outbound.Groups {
isOn := lists.ContainsString(groupCodes, group.Code)
group.IsOn = isOn
groupId, err := SharedHTTPFirewallRuleGroupDAO.CreateGroupFromConfig(tx, group)
if err != nil {
return 0, err
}
outboundConfig.GroupRefs = append(outboundConfig.GroupRefs, &firewallconfigs.HTTPFirewallRuleGroupRef{
IsOn: true,
GroupId: groupId,
})
}
}
inboundConfigJSON, err := json.Marshal(inboundConfig)
if err != nil {
return 0, err
}
outboundConfigJSON, err := json.Marshal(outboundConfig)
if err != nil {
return 0, err
}
err = this.UpdateFirewallPolicyInboundAndOutbound(tx, policyId, inboundConfigJSON, outboundConfigJSON, false)
if err != nil {
return 0, err
}
return policyId, nil
}
// UpdateFirewallPolicyInboundAndOutbound 修改策略的Inbound和Outbound
func (this *HTTPFirewallPolicyDAO) UpdateFirewallPolicyInboundAndOutbound(tx *dbs.Tx, policyId int64, inboundJSON []byte, outboundJSON []byte, shouldNotify bool) error {
if policyId <= 0 {
return errors.New("invalid policyId")
}
@@ -135,10 +201,14 @@ func (this *HTTPFirewallPolicyDAO) UpdateFirewallPolicyInboundAndOutbound(tx *db
return err
}
return this.NotifyUpdate(tx, policyId)
if shouldNotify {
return this.NotifyUpdate(tx, policyId)
}
return nil
}
// 修改策略的Inbound
// UpdateFirewallPolicyInbound 修改策略的Inbound
func (this *HTTPFirewallPolicyDAO) UpdateFirewallPolicyInbound(tx *dbs.Tx, policyId int64, inboundJSON []byte) error {
if policyId <= 0 {
return errors.New("invalid policyId")
@@ -158,7 +228,7 @@ func (this *HTTPFirewallPolicyDAO) UpdateFirewallPolicyInbound(tx *dbs.Tx, polic
return this.NotifyUpdate(tx, policyId)
}
// 修改策略
// UpdateFirewallPolicy 修改策略
func (this *HTTPFirewallPolicyDAO) UpdateFirewallPolicy(tx *dbs.Tx, policyId int64, isOn bool, name string, description string, inboundJSON []byte, outboundJSON []byte, blockOptionsJSON []byte) error {
if policyId <= 0 {
return errors.New("invalid policyId")
@@ -189,18 +259,28 @@ func (this *HTTPFirewallPolicyDAO) UpdateFirewallPolicy(tx *dbs.Tx, policyId int
return this.NotifyUpdate(tx, policyId)
}
// 计算所有可用的策略数量
func (this *HTTPFirewallPolicyDAO) CountAllEnabledFirewallPolicies(tx *dbs.Tx) (int64, error) {
return this.Query(tx).
// CountAllEnabledFirewallPolicies 计算所有可用的策略数量
func (this *HTTPFirewallPolicyDAO) CountAllEnabledFirewallPolicies(tx *dbs.Tx, keyword string) (int64, error) {
query := this.Query(tx)
if len(keyword) > 0 {
query.Where("(name LIKE :keyword)").
Param("keyword", "%"+keyword+"%")
}
return query.
State(HTTPFirewallPolicyStateEnabled).
Attr("userId", 0).
Attr("serverId", 0).
Count()
}
// 列出单页的策略
func (this *HTTPFirewallPolicyDAO) ListEnabledFirewallPolicies(tx *dbs.Tx, offset int64, size int64) (result []*HTTPFirewallPolicy, err error) {
_, err = this.Query(tx).
// ListEnabledFirewallPolicies 列出单页的策略
func (this *HTTPFirewallPolicyDAO) ListEnabledFirewallPolicies(tx *dbs.Tx, keyword string, offset int64, size int64) (result []*HTTPFirewallPolicy, err error) {
query := this.Query(tx)
if len(keyword) > 0 {
query.Where("(name LIKE :keyword)").
Param("keyword", "%"+keyword+"%")
}
_, err = query.
State(HTTPFirewallPolicyStateEnabled).
Attr("userId", 0).
Attr("serverId", 0).
@@ -212,8 +292,17 @@ func (this *HTTPFirewallPolicyDAO) ListEnabledFirewallPolicies(tx *dbs.Tx, offse
return
}
// 组合策略配置
func (this *HTTPFirewallPolicyDAO) ComposeFirewallPolicy(tx *dbs.Tx, policyId int64) (*firewallconfigs.HTTPFirewallPolicy, error) {
// ComposeFirewallPolicy 组合策略配置
func (this *HTTPFirewallPolicyDAO) ComposeFirewallPolicy(tx *dbs.Tx, policyId int64, cacheMap maps.Map) (*firewallconfigs.HTTPFirewallPolicy, error) {
if cacheMap == nil {
cacheMap = maps.Map{}
}
var cacheKey = this.Table + ":config:" + types.String(policyId)
var cache = cacheMap.Get(cacheKey)
if cache != nil {
return cache.(*firewallconfigs.HTTPFirewallPolicy), nil
}
policy, err := this.FindEnabledHTTPFirewallPolicy(tx, policyId)
if err != nil {
return nil, err
@@ -294,10 +383,12 @@ func (this *HTTPFirewallPolicyDAO) ComposeFirewallPolicy(tx *dbs.Tx, policyId in
config.BlockOptions = blockAction
}
cacheMap[cacheKey] = config
return config, nil
}
// 检查用户防火墙策略
// CheckUserFirewallPolicy 检查用户防火墙策略
func (this *HTTPFirewallPolicyDAO) CheckUserFirewallPolicy(tx *dbs.Tx, userId int64, firewallPolicyId int64) error {
ok, err := this.Query(tx).
Pk(firewallPolicyId).
@@ -310,17 +401,31 @@ func (this *HTTPFirewallPolicyDAO) CheckUserFirewallPolicy(tx *dbs.Tx, userId in
return nil
}
// TODO 检查是否为用户Server所使用
// 检查是否为用户Server所使用
webIds, err := SharedHTTPWebDAO.FindAllWebIdsWithHTTPFirewallPolicyId(tx, firewallPolicyId)
if err != nil {
return err
}
for _, webId := range webIds {
err := SharedHTTPWebDAO.CheckUserWeb(tx, userId, webId)
if err != nil {
if err != ErrNotFound {
return err
}
} else {
return nil
}
}
return ErrNotFound
}
// 查找包含某个IPList的所有策略
// FindEnabledFirewallPolicyIdsWithIPListId 查找包含某个IPList的所有策略
func (this *HTTPFirewallPolicyDAO) FindEnabledFirewallPolicyIdsWithIPListId(tx *dbs.Tx, ipListId int64) ([]int64, error) {
ones, err := this.Query(tx).
ResultPk().
State(HTTPFirewallPolicyStateEnabled).
Where("(JSON_CONTAINS(inbound, :listQuery, '$.whiteListRef') OR JSON_CONTAINS(inbound, :listQuery, '$.blackListRef') )").
Where("(JSON_CONTAINS(inbound, :listQuery, '$.whiteListRef') OR JSON_CONTAINS(inbound, :listQuery, '$.blackListRef') OR JSON_CONTAINS(inbound, :listQuery, '$.publicWhiteListRefs') OR JSON_CONTAINS(inbound, :listQuery, '$.publicBlackListRefs'))").
Param("listQuery", maps.Map{"isOn": true, "listId": ipListId}.AsJSON()).
FindAll()
if err != nil {
@@ -333,7 +438,7 @@ func (this *HTTPFirewallPolicyDAO) FindEnabledFirewallPolicyIdsWithIPListId(tx *
return result, nil
}
// 查找包含某个规则分组的策略ID
// FindEnabledFirewallPolicyIdWithRuleGroupId 查找包含某个规则分组的策略ID
func (this *HTTPFirewallPolicyDAO) FindEnabledFirewallPolicyIdWithRuleGroupId(tx *dbs.Tx, ruleGroupId int64) (int64, error) {
return this.Query(tx).
ResultPk().
@@ -343,7 +448,7 @@ func (this *HTTPFirewallPolicyDAO) FindEnabledFirewallPolicyIdWithRuleGroupId(tx
FindInt64Col(0)
}
// 设置某个策略所属的服务ID
// UpdateFirewallPolicyServerId 设置某个策略所属的服务ID
func (this *HTTPFirewallPolicyDAO) UpdateFirewallPolicyServerId(tx *dbs.Tx, policyId int64, serverId int64) error {
_, err := this.Query(tx).
Pk(policyId).
@@ -352,7 +457,7 @@ func (this *HTTPFirewallPolicyDAO) UpdateFirewallPolicyServerId(tx *dbs.Tx, poli
return err
}
// 通知更新
// NotifyUpdate 通知更新
func (this *HTTPFirewallPolicyDAO) NotifyUpdate(tx *dbs.Tx, policyId int64) error {
webIds, err := SharedHTTPWebDAO.FindAllWebIdsWithHTTPFirewallPolicyId(tx, policyId)
if err != nil {

View File

@@ -37,12 +37,12 @@ func init() {
})
}
// 初始化
// Init 初始化
func (this *HTTPFirewallRuleGroupDAO) Init() {
_ = this.DAOObject.Init()
}
// 启用条目
// EnableHTTPFirewallRuleGroup 启用条目
func (this *HTTPFirewallRuleGroupDAO) EnableHTTPFirewallRuleGroup(tx *dbs.Tx, id int64) error {
_, err := this.Query(tx).
Pk(id).
@@ -51,7 +51,7 @@ func (this *HTTPFirewallRuleGroupDAO) EnableHTTPFirewallRuleGroup(tx *dbs.Tx, id
return err
}
// 禁用条目
// DisableHTTPFirewallRuleGroup 禁用条目
func (this *HTTPFirewallRuleGroupDAO) DisableHTTPFirewallRuleGroup(tx *dbs.Tx, id int64) error {
_, err := this.Query(tx).
Pk(id).
@@ -60,7 +60,7 @@ func (this *HTTPFirewallRuleGroupDAO) DisableHTTPFirewallRuleGroup(tx *dbs.Tx, i
return err
}
// 查找启用中的条目
// FindEnabledHTTPFirewallRuleGroup 查找启用中的条目
func (this *HTTPFirewallRuleGroupDAO) FindEnabledHTTPFirewallRuleGroup(tx *dbs.Tx, id int64) (*HTTPFirewallRuleGroup, error) {
result, err := this.Query(tx).
Pk(id).
@@ -72,7 +72,7 @@ func (this *HTTPFirewallRuleGroupDAO) FindEnabledHTTPFirewallRuleGroup(tx *dbs.T
return result.(*HTTPFirewallRuleGroup), err
}
// 根据主键查找名称
// FindHTTPFirewallRuleGroupName 根据主键查找名称
func (this *HTTPFirewallRuleGroupDAO) FindHTTPFirewallRuleGroupName(tx *dbs.Tx, id int64) (string, error) {
return this.Query(tx).
Pk(id).
@@ -80,7 +80,7 @@ func (this *HTTPFirewallRuleGroupDAO) FindHTTPFirewallRuleGroupName(tx *dbs.Tx,
FindStringCol("")
}
// 组合配置
// ComposeFirewallRuleGroup 组合配置
func (this *HTTPFirewallRuleGroupDAO) ComposeFirewallRuleGroup(tx *dbs.Tx, groupId int64) (*firewallconfigs.HTTPFirewallRuleGroup, error) {
group, err := this.FindEnabledHTTPFirewallRuleGroup(tx, groupId)
if err != nil {
@@ -117,7 +117,7 @@ func (this *HTTPFirewallRuleGroupDAO) ComposeFirewallRuleGroup(tx *dbs.Tx, group
return config, nil
}
// 从配置中创建分组
// CreateGroupFromConfig 从配置中创建分组
func (this *HTTPFirewallRuleGroupDAO) CreateGroupFromConfig(tx *dbs.Tx, groupConfig *firewallconfigs.HTTPFirewallRuleGroup) (int64, error) {
op := NewHTTPFirewallRuleGroupOperator()
op.IsOn = groupConfig.IsOn
@@ -150,7 +150,7 @@ func (this *HTTPFirewallRuleGroupDAO) CreateGroupFromConfig(tx *dbs.Tx, groupCon
return types.Int64(op.Id), nil
}
// 修改开启状态
// UpdateGroupIsOn 修改开启状态
func (this *HTTPFirewallRuleGroupDAO) UpdateGroupIsOn(tx *dbs.Tx, groupId int64, isOn bool) error {
_, err := this.Query(tx).
Pk(groupId).
@@ -162,7 +162,7 @@ func (this *HTTPFirewallRuleGroupDAO) UpdateGroupIsOn(tx *dbs.Tx, groupId int64,
return this.NotifyUpdate(tx, groupId)
}
// 创建分组
// CreateGroup 创建分组
func (this *HTTPFirewallRuleGroupDAO) CreateGroup(tx *dbs.Tx, isOn bool, name string, description string) (int64, error) {
op := NewHTTPFirewallRuleGroupOperator()
op.State = HTTPFirewallRuleStateEnabled
@@ -176,7 +176,7 @@ func (this *HTTPFirewallRuleGroupDAO) CreateGroup(tx *dbs.Tx, isOn bool, name st
return types.Int64(op.Id), nil
}
// 修改分组
// UpdateGroup 修改分组
func (this *HTTPFirewallRuleGroupDAO) UpdateGroup(tx *dbs.Tx, groupId int64, isOn bool, name string, description string) error {
if groupId <= 0 {
return errors.New("invalid groupId")
@@ -193,7 +193,7 @@ func (this *HTTPFirewallRuleGroupDAO) UpdateGroup(tx *dbs.Tx, groupId int64, isO
return this.NotifyUpdate(tx, groupId)
}
// 修改分组中的规则集
// UpdateGroupSets 修改分组中的规则集
func (this *HTTPFirewallRuleGroupDAO) UpdateGroupSets(tx *dbs.Tx, groupId int64, setsJSON []byte) error {
if groupId <= 0 {
return errors.New("invalid groupId")
@@ -208,7 +208,7 @@ func (this *HTTPFirewallRuleGroupDAO) UpdateGroupSets(tx *dbs.Tx, groupId int64,
return this.NotifyUpdate(tx, groupId)
}
// 根据规则集查找规则分组
// FindRuleGroupIdWithRuleSetId 根据规则集查找规则分组
func (this *HTTPFirewallRuleGroupDAO) FindRuleGroupIdWithRuleSetId(tx *dbs.Tx, setId int64) (int64, error) {
return this.Query(tx).
State(HTTPFirewallRuleStateEnabled).
@@ -218,7 +218,7 @@ func (this *HTTPFirewallRuleGroupDAO) FindRuleGroupIdWithRuleSetId(tx *dbs.Tx, s
FindInt64Col(0)
}
// 检查用户所属分组
// CheckUserRuleGroup 检查用户所属分组
func (this *HTTPFirewallRuleGroupDAO) CheckUserRuleGroup(tx *dbs.Tx, userId int64, groupId int64) error {
policyId, err := SharedHTTPFirewallPolicyDAO.FindEnabledFirewallPolicyIdWithRuleGroupId(tx, groupId)
if err != nil {
@@ -230,7 +230,7 @@ func (this *HTTPFirewallRuleGroupDAO) CheckUserRuleGroup(tx *dbs.Tx, userId int6
return SharedHTTPFirewallPolicyDAO.CheckUserFirewallPolicy(tx, userId, policyId)
}
// 通知更新
// NotifyUpdate 通知更新
func (this *HTTPFirewallRuleGroupDAO) NotifyUpdate(tx *dbs.Tx, groupId int64) error {
policyId, err := SharedHTTPFirewallPolicyDAO.FindEnabledFirewallPolicyIdWithRuleGroupId(tx, groupId)
if err != nil {

View File

@@ -37,12 +37,12 @@ func init() {
})
}
// 初始化
// Init 初始化
func (this *HTTPFirewallRuleSetDAO) Init() {
_ = this.DAOObject.Init()
}
// 启用条目
// EnableHTTPFirewallRuleSet 启用条目
func (this *HTTPFirewallRuleSetDAO) EnableHTTPFirewallRuleSet(tx *dbs.Tx, id int64) error {
_, err := this.Query(tx).
Pk(id).
@@ -51,7 +51,7 @@ func (this *HTTPFirewallRuleSetDAO) EnableHTTPFirewallRuleSet(tx *dbs.Tx, id int
return err
}
// 禁用条目
// DisableHTTPFirewallRuleSet 禁用条目
func (this *HTTPFirewallRuleSetDAO) DisableHTTPFirewallRuleSet(tx *dbs.Tx, ruleSetId int64) error {
_, err := this.Query(tx).
Pk(ruleSetId).
@@ -63,7 +63,7 @@ func (this *HTTPFirewallRuleSetDAO) DisableHTTPFirewallRuleSet(tx *dbs.Tx, ruleS
return this.NotifyUpdate(tx, ruleSetId)
}
// 查找启用中的条目
// FindEnabledHTTPFirewallRuleSet 查找启用中的条目
func (this *HTTPFirewallRuleSetDAO) FindEnabledHTTPFirewallRuleSet(tx *dbs.Tx, id int64) (*HTTPFirewallRuleSet, error) {
result, err := this.Query(tx).
Pk(id).
@@ -75,7 +75,7 @@ func (this *HTTPFirewallRuleSetDAO) FindEnabledHTTPFirewallRuleSet(tx *dbs.Tx, i
return result.(*HTTPFirewallRuleSet), err
}
// 根据主键查找名称
// FindHTTPFirewallRuleSetName 根据主键查找名称
func (this *HTTPFirewallRuleSetDAO) FindHTTPFirewallRuleSetName(tx *dbs.Tx, id int64) (string, error) {
return this.Query(tx).
Pk(id).
@@ -83,7 +83,7 @@ func (this *HTTPFirewallRuleSetDAO) FindHTTPFirewallRuleSetName(tx *dbs.Tx, id i
FindStringCol("")
}
// 组合配置
// ComposeFirewallRuleSet 组合配置
func (this *HTTPFirewallRuleSetDAO) ComposeFirewallRuleSet(tx *dbs.Tx, setId int64) (*firewallconfigs.HTTPFirewallRuleSet, error) {
set, err := this.FindEnabledHTTPFirewallRuleSet(tx, setId)
if err != nil {
@@ -118,20 +118,19 @@ func (this *HTTPFirewallRuleSetDAO) ComposeFirewallRuleSet(tx *dbs.Tx, setId int
}
}
config.Action = set.Action
if IsNotNull(set.ActionOptions) {
options := maps.Map{}
err = json.Unmarshal([]byte(set.ActionOptions), &options)
var actionConfigs = []*firewallconfigs.HTTPFirewallActionConfig{}
if len(set.Actions) > 0 {
err = json.Unmarshal([]byte(set.Actions), &actionConfigs)
if err != nil {
return nil, err
}
config.ActionOptions = options
config.Actions = actionConfigs
}
return config, nil
}
// 从配置中创建规则集
// CreateOrUpdateSetFromConfig 从配置中创建规则集
func (this *HTTPFirewallRuleSetDAO) CreateOrUpdateSetFromConfig(tx *dbs.Tx, setConfig *firewallconfigs.HTTPFirewallRuleSet) (int64, error) {
op := NewHTTPFirewallRuleSetOperator()
op.State = HTTPFirewallRuleSetStateEnabled
@@ -140,19 +139,19 @@ func (this *HTTPFirewallRuleSetDAO) CreateOrUpdateSetFromConfig(tx *dbs.Tx, setC
op.Name = setConfig.Name
op.Description = setConfig.Description
op.Connector = setConfig.Connector
op.Action = setConfig.Action
op.Code = setConfig.Code
if setConfig.ActionOptions != nil {
actionOptionsJSON, err := json.Marshal(setConfig.ActionOptions)
if len(setConfig.Actions) == 0 {
op.Actions = "[]"
} else {
actionsJSON, err := json.Marshal(setConfig.Actions)
if err != nil {
return 0, err
}
op.ActionOptions = actionOptionsJSON
} else {
op.ActionOptions = "{}"
op.Actions = actionsJSON
}
op.Code = setConfig.Code
// rules
ruleRefs := []*firewallconfigs.HTTPFirewallRuleRef{}
for _, ruleConfig := range setConfig.Rules {
@@ -186,7 +185,7 @@ func (this *HTTPFirewallRuleSetDAO) CreateOrUpdateSetFromConfig(tx *dbs.Tx, setC
return types.Int64(op.Id), nil
}
// 设置是否启用
// UpdateRuleSetIsOn 设置是否启用
func (this *HTTPFirewallRuleSetDAO) UpdateRuleSetIsOn(tx *dbs.Tx, ruleSetId int64, isOn bool) error {
if ruleSetId <= 0 {
return errors.New("invalid ruleSetId")
@@ -201,7 +200,7 @@ func (this *HTTPFirewallRuleSetDAO) UpdateRuleSetIsOn(tx *dbs.Tx, ruleSetId int6
return this.NotifyUpdate(tx, ruleSetId)
}
// 根据规则查找规则集
// FindEnabledRuleSetIdWithRuleId 根据规则查找规则集
func (this *HTTPFirewallRuleSetDAO) FindEnabledRuleSetIdWithRuleId(tx *dbs.Tx, ruleId int64) (int64, error) {
return this.Query(tx).
State(HTTPFirewallRuleStateEnabled).
@@ -211,7 +210,7 @@ func (this *HTTPFirewallRuleSetDAO) FindEnabledRuleSetIdWithRuleId(tx *dbs.Tx, r
FindInt64Col(0)
}
// 检查用户
// CheckUserRuleSet 检查用户
func (this *HTTPFirewallRuleSetDAO) CheckUserRuleSet(tx *dbs.Tx, userId int64, setId int64) error {
groupId, err := SharedHTTPFirewallRuleGroupDAO.FindRuleGroupIdWithRuleSetId(tx, setId)
if err != nil {
@@ -223,7 +222,7 @@ func (this *HTTPFirewallRuleSetDAO) CheckUserRuleSet(tx *dbs.Tx, userId int64, s
return SharedHTTPFirewallRuleGroupDAO.CheckUserRuleGroup(tx, userId, groupId)
}
// 通知更新
// NotifyUpdate 通知更新
func (this *HTTPFirewallRuleSetDAO) NotifyUpdate(tx *dbs.Tx, setId int64) error {
groupId, err := SharedHTTPFirewallRuleGroupDAO.FindRuleGroupIdWithRuleSetId(tx, setId)
if err != nil {

View File

@@ -1,6 +1,6 @@
package models
// 防火墙规则集
// HTTPFirewallRuleSet 防火墙规则集
type HTTPFirewallRuleSet struct {
Id uint32 `field:"id"` // ID
IsOn uint8 `field:"isOn"` // 是否启用
@@ -13,8 +13,9 @@ type HTTPFirewallRuleSet struct {
State uint8 `field:"state"` // 状态
AdminId uint32 `field:"adminId"` // 管理员ID
UserId uint32 `field:"userId"` // 用户ID
Action string `field:"action"` // 执行的动作
ActionOptions string `field:"actionOptions"` // 动作的选项
Action string `field:"action"` // 执行的动作(过期)
ActionOptions string `field:"actionOptions"` // 动作的选项(过期)
Actions string `field:"actions"` // 一组动作
}
type HTTPFirewallRuleSetOperator struct {
@@ -29,8 +30,9 @@ type HTTPFirewallRuleSetOperator struct {
State interface{} // 状态
AdminId interface{} // 管理员ID
UserId interface{} // 用户ID
Action interface{} // 执行的动作
ActionOptions interface{} // 动作的选项
Action interface{} // 执行的动作(过期)
ActionOptions interface{} // 动作的选项(过期)
Actions interface{} // 一组动作
}
func NewHTTPFirewallRuleSetOperator() *HTTPFirewallRuleSetOperator {

View File

@@ -4,9 +4,11 @@ import (
"encoding/json"
"errors"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/maps"
"github.com/iwind/TeaGo/types"
)
@@ -36,12 +38,12 @@ func init() {
})
}
// 初始化
// Init 初始化
func (this *HTTPLocationDAO) Init() {
_ = this.DAOObject.Init()
}
// 启用条目
// EnableHTTPLocation 启用条目
func (this *HTTPLocationDAO) EnableHTTPLocation(tx *dbs.Tx, id int64) error {
_, err := this.Query(tx).
Pk(id).
@@ -50,7 +52,7 @@ func (this *HTTPLocationDAO) EnableHTTPLocation(tx *dbs.Tx, id int64) error {
return err
}
// 禁用条目
// DisableHTTPLocation 禁用条目
func (this *HTTPLocationDAO) DisableHTTPLocation(tx *dbs.Tx, locationId int64) error {
_, err := this.Query(tx).
Pk(locationId).
@@ -62,7 +64,7 @@ func (this *HTTPLocationDAO) DisableHTTPLocation(tx *dbs.Tx, locationId int64) e
return this.NotifyUpdate(tx, locationId)
}
// 查找启用中的条目
// FindEnabledHTTPLocation 查找启用中的条目
func (this *HTTPLocationDAO) FindEnabledHTTPLocation(tx *dbs.Tx, id int64) (*HTTPLocation, error) {
result, err := this.Query(tx).
Pk(id).
@@ -74,7 +76,7 @@ func (this *HTTPLocationDAO) FindEnabledHTTPLocation(tx *dbs.Tx, id int64) (*HTT
return result.(*HTTPLocation), err
}
// 根据主键查找名称
// FindHTTPLocationName 根据主键查找名称
func (this *HTTPLocationDAO) FindHTTPLocationName(tx *dbs.Tx, id int64) (string, error) {
return this.Query(tx).
Pk(id).
@@ -82,8 +84,8 @@ func (this *HTTPLocationDAO) FindHTTPLocationName(tx *dbs.Tx, id int64) (string,
FindStringCol("")
}
// 创建路规则
func (this *HTTPLocationDAO) CreateLocation(tx *dbs.Tx, parentId int64, name string, pattern string, description string, isBreak bool) (int64, error) {
// CreateLocation 创建路规则
func (this *HTTPLocationDAO) CreateLocation(tx *dbs.Tx, parentId int64, name string, pattern string, description string, isBreak bool, condsJSON []byte) (int64, error) {
op := NewHTTPLocationOperator()
op.IsOn = true
op.State = HTTPLocationStateEnabled
@@ -92,6 +94,11 @@ func (this *HTTPLocationDAO) CreateLocation(tx *dbs.Tx, parentId int64, name str
op.Pattern = pattern
op.Description = description
op.IsBreak = isBreak
if len(condsJSON) > 0 {
op.Conds = condsJSON
}
err := this.Save(tx, op)
if err != nil {
return 0, err
@@ -99,8 +106,8 @@ func (this *HTTPLocationDAO) CreateLocation(tx *dbs.Tx, parentId int64, name str
return types.Int64(op.Id), nil
}
// 修改路规则
func (this *HTTPLocationDAO) UpdateLocation(tx *dbs.Tx, locationId int64, name string, pattern string, description string, isOn bool, isBreak bool) error {
// UpdateLocation 修改路规则
func (this *HTTPLocationDAO) UpdateLocation(tx *dbs.Tx, locationId int64, name string, pattern string, description string, isOn bool, isBreak bool, condsJSON []byte) error {
if locationId <= 0 {
return errors.New("invalid locationId")
}
@@ -111,6 +118,11 @@ func (this *HTTPLocationDAO) UpdateLocation(tx *dbs.Tx, locationId int64, name s
op.Description = description
op.IsOn = isOn
op.IsBreak = isBreak
if len(condsJSON) > 0 {
op.Conds = condsJSON
}
err := this.Save(tx, op)
if err != nil {
return err
@@ -118,8 +130,17 @@ func (this *HTTPLocationDAO) UpdateLocation(tx *dbs.Tx, locationId int64, name s
return this.NotifyUpdate(tx, locationId)
}
// 组合配置
func (this *HTTPLocationDAO) ComposeLocationConfig(tx *dbs.Tx, locationId int64) (*serverconfigs.HTTPLocationConfig, error) {
// ComposeLocationConfig 组合配置
func (this *HTTPLocationDAO) ComposeLocationConfig(tx *dbs.Tx, locationId int64, cacheMap maps.Map) (*serverconfigs.HTTPLocationConfig, error) {
if cacheMap == nil {
cacheMap = maps.Map{}
}
var cacheKey = this.Table + ":config:" + types.String(locationId)
var cacheConfig = cacheMap.Get(cacheKey)
if cacheConfig != nil {
return cacheConfig.(*serverconfigs.HTTPLocationConfig), nil
}
location, err := this.FindEnabledHTTPLocation(tx, locationId)
if err != nil {
return nil, err
@@ -139,7 +160,7 @@ func (this *HTTPLocationDAO) ComposeLocationConfig(tx *dbs.Tx, locationId int64)
// web
if location.WebId > 0 {
webConfig, err := SharedHTTPWebDAO.ComposeWebConfig(tx, int64(location.WebId))
webConfig, err := SharedHTTPWebDAO.ComposeWebConfig(tx, int64(location.WebId), cacheMap)
if err != nil {
return nil, err
}
@@ -155,7 +176,7 @@ func (this *HTTPLocationDAO) ComposeLocationConfig(tx *dbs.Tx, locationId int64)
}
config.ReverseProxyRef = ref
if ref.ReverseProxyId > 0 {
reverseProxyConfig, err := SharedReverseProxyDAO.ComposeReverseProxyConfig(tx, ref.ReverseProxyId)
reverseProxyConfig, err := SharedReverseProxyDAO.ComposeReverseProxyConfig(tx, ref.ReverseProxyId, cacheMap)
if err != nil {
return nil, err
}
@@ -163,10 +184,22 @@ func (this *HTTPLocationDAO) ComposeLocationConfig(tx *dbs.Tx, locationId int64)
}
}
// conds
if len(location.Conds) > 0 {
conds := &shared.HTTPRequestCondsConfig{}
err = json.Unmarshal([]byte(location.Conds), conds)
if err != nil {
return nil, err
}
config.Conds = conds
}
cacheMap[cacheKey] = config
return config, nil
}
// 查找反向代理设置
// FindLocationReverseProxy 查找反向代理设置
func (this *HTTPLocationDAO) FindLocationReverseProxy(tx *dbs.Tx, locationId int64) (*serverconfigs.ReverseProxyRef, error) {
refString, err := this.Query(tx).
Pk(locationId).
@@ -186,7 +219,7 @@ func (this *HTTPLocationDAO) FindLocationReverseProxy(tx *dbs.Tx, locationId int
return nil, nil
}
// 更改反向代理设置
// UpdateLocationReverseProxy 更改反向代理设置
func (this *HTTPLocationDAO) UpdateLocationReverseProxy(tx *dbs.Tx, locationId int64, reverseProxyJSON []byte) error {
if locationId <= 0 {
return errors.New("invalid locationId")
@@ -201,7 +234,7 @@ func (this *HTTPLocationDAO) UpdateLocationReverseProxy(tx *dbs.Tx, locationId i
return this.NotifyUpdate(tx, locationId)
}
// 查找WebId
// FindLocationWebId 查找WebId
func (this *HTTPLocationDAO) FindLocationWebId(tx *dbs.Tx, locationId int64) (int64, error) {
webId, err := this.Query(tx).
Pk(locationId).
@@ -210,7 +243,7 @@ func (this *HTTPLocationDAO) FindLocationWebId(tx *dbs.Tx, locationId int64) (in
return int64(webId), err
}
// 更改Web设置
// UpdateLocationWeb 更改Web设置
func (this *HTTPLocationDAO) UpdateLocationWeb(tx *dbs.Tx, locationId int64, webId int64) error {
if locationId <= 0 {
return errors.New("invalid locationId")
@@ -225,14 +258,14 @@ func (this *HTTPLocationDAO) UpdateLocationWeb(tx *dbs.Tx, locationId int64, web
return this.NotifyUpdate(tx, locationId)
}
// 转换引用为配置
func (this *HTTPLocationDAO) ConvertLocationRefs(tx *dbs.Tx, refs []*serverconfigs.HTTPLocationRef) (locations []*serverconfigs.HTTPLocationConfig, err error) {
// ConvertLocationRefs 转换引用为配置
func (this *HTTPLocationDAO) ConvertLocationRefs(tx *dbs.Tx, refs []*serverconfigs.HTTPLocationRef, cacheMap maps.Map) (locations []*serverconfigs.HTTPLocationConfig, err error) {
for _, ref := range refs {
config, err := this.ComposeLocationConfig(tx, ref.LocationId)
config, err := this.ComposeLocationConfig(tx, ref.LocationId, cacheMap)
if err != nil {
return nil, err
}
children, err := this.ConvertLocationRefs(tx, ref.Children)
children, err := this.ConvertLocationRefs(tx, ref.Children, cacheMap)
if err != nil {
return nil, err
}
@@ -243,7 +276,7 @@ func (this *HTTPLocationDAO) ConvertLocationRefs(tx *dbs.Tx, refs []*serverconfi
return
}
// 根据WebId查找LocationId
// FindEnabledLocationIdWithWebId 根据WebId查找LocationId
func (this *HTTPLocationDAO) FindEnabledLocationIdWithWebId(tx *dbs.Tx, webId int64) (locationId int64, err error) {
if webId <= 0 {
return
@@ -254,7 +287,17 @@ func (this *HTTPLocationDAO) FindEnabledLocationIdWithWebId(tx *dbs.Tx, webId in
FindInt64Col(0)
}
// 通知更新
// FindEnabledLocationIdWithReverseProxyId 查找包含某个反向代理的Server
func (this *HTTPLocationDAO) FindEnabledLocationIdWithReverseProxyId(tx *dbs.Tx, reverseProxyId int64) (serverId int64, err error) {
return this.Query(tx).
State(ServerStateEnabled).
Where("JSON_CONTAINS(reverseProxy, :jsonQuery)").
Param("jsonQuery", maps.Map{"reverseProxyId": reverseProxyId}.AsJSON()).
ResultPk().
FindInt64Col(0)
}
// NotifyUpdate 通知更新
func (this *HTTPLocationDAO) NotifyUpdate(tx *dbs.Tx, locationId int64) error {
webId, err := SharedHTTPWebDAO.FindEnabledWebIdWithLocationId(tx, locationId)
if err != nil {

View File

@@ -1,6 +1,6 @@
package models
// 路径规则配置
// HTTPLocation 路由规则配置
type HTTPLocation struct {
Id uint32 `field:"id"` // ID
TemplateId uint32 `field:"templateId"` // 模版ID

View File

@@ -7,6 +7,7 @@ import (
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/maps"
"github.com/iwind/TeaGo/types"
)
@@ -36,12 +37,12 @@ func init() {
})
}
// 初始化
// Init 初始化
func (this *HTTPPageDAO) Init() {
_ = this.DAOObject.Init()
}
// 启用条目
// EnableHTTPPage 启用条目
func (this *HTTPPageDAO) EnableHTTPPage(tx *dbs.Tx, pageId int64) error {
_, err := this.Query(tx).
Pk(pageId).
@@ -53,7 +54,7 @@ func (this *HTTPPageDAO) EnableHTTPPage(tx *dbs.Tx, pageId int64) error {
return this.NotifyUpdate(tx, pageId)
}
// 禁用条目
// DisableHTTPPage 禁用条目
func (this *HTTPPageDAO) DisableHTTPPage(tx *dbs.Tx, id int64) error {
_, err := this.Query(tx).
Pk(id).
@@ -62,7 +63,7 @@ func (this *HTTPPageDAO) DisableHTTPPage(tx *dbs.Tx, id int64) error {
return err
}
// 查找启用中的条目
// FindEnabledHTTPPage 查找启用中的条目
func (this *HTTPPageDAO) FindEnabledHTTPPage(tx *dbs.Tx, id int64) (*HTTPPage, error) {
result, err := this.Query(tx).
Pk(id).
@@ -74,7 +75,7 @@ func (this *HTTPPageDAO) FindEnabledHTTPPage(tx *dbs.Tx, id int64) (*HTTPPage, e
return result.(*HTTPPage), err
}
// 创建Page
// CreatePage 创建Page
func (this *HTTPPageDAO) CreatePage(tx *dbs.Tx, statusList []string, url string, newStatus int) (pageId int64, err error) {
op := NewHTTPPageOperator()
op.IsOn = true
@@ -97,7 +98,7 @@ func (this *HTTPPageDAO) CreatePage(tx *dbs.Tx, statusList []string, url string,
return types.Int64(op.Id), nil
}
// 修改Page
// UpdatePage 修改Page
func (this *HTTPPageDAO) UpdatePage(tx *dbs.Tx, pageId int64, statusList []string, url string, newStatus int) error {
if pageId <= 0 {
return errors.New("invalid pageId")
@@ -126,8 +127,17 @@ func (this *HTTPPageDAO) UpdatePage(tx *dbs.Tx, pageId int64, statusList []strin
return this.NotifyUpdate(tx, pageId)
}
// 组合配置
func (this *HTTPPageDAO) ComposePageConfig(tx *dbs.Tx, pageId int64) (*serverconfigs.HTTPPageConfig, error) {
// ComposePageConfig 组合配置
func (this *HTTPPageDAO) ComposePageConfig(tx *dbs.Tx, pageId int64, cacheMap maps.Map) (*serverconfigs.HTTPPageConfig, error) {
if cacheMap == nil {
cacheMap = maps.Map{}
}
var cacheKey = this.Table + ":config:" + types.String(pageId)
var cache = cacheMap.Get(cacheKey)
if cache != nil {
return cache.(*serverconfigs.HTTPPageConfig), nil
}
page, err := this.FindEnabledHTTPPage(tx, pageId)
if err != nil {
return nil, err
@@ -154,10 +164,12 @@ func (this *HTTPPageDAO) ComposePageConfig(tx *dbs.Tx, pageId int64) (*servercon
}
}
cacheMap[cacheKey] = config
return config, nil
}
// 通知更新
// NotifyUpdate 通知更新
func (this *HTTPPageDAO) NotifyUpdate(tx *dbs.Tx, pageId int64) error {
webId, err := SharedHTTPWebDAO.FindEnabledWebIdWithPageId(tx, pageId)
if err != nil {

View File

@@ -1,11 +1,14 @@
package models
import (
"encoding/json"
"errors"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/maps"
"github.com/iwind/TeaGo/types"
)
@@ -35,12 +38,12 @@ func init() {
})
}
// 初始化
// Init 初始化
func (this *HTTPRewriteRuleDAO) Init() {
_ = this.DAOObject.Init()
}
// 启用条目
// EnableHTTPRewriteRule 启用条目
func (this *HTTPRewriteRuleDAO) EnableHTTPRewriteRule(tx *dbs.Tx, id int64) error {
_, err := this.Query(tx).
Pk(id).
@@ -49,7 +52,7 @@ func (this *HTTPRewriteRuleDAO) EnableHTTPRewriteRule(tx *dbs.Tx, id int64) erro
return err
}
// 禁用条目
// DisableHTTPRewriteRule 禁用条目
func (this *HTTPRewriteRuleDAO) DisableHTTPRewriteRule(tx *dbs.Tx, rewriteRuleId int64) error {
_, err := this.Query(tx).
Pk(rewriteRuleId).
@@ -61,7 +64,7 @@ func (this *HTTPRewriteRuleDAO) DisableHTTPRewriteRule(tx *dbs.Tx, rewriteRuleId
return this.NotifyUpdate(tx, rewriteRuleId)
}
// 查找启用中的条目
// FindEnabledHTTPRewriteRule 查找启用中的条目
func (this *HTTPRewriteRuleDAO) FindEnabledHTTPRewriteRule(tx *dbs.Tx, id int64) (*HTTPRewriteRule, error) {
result, err := this.Query(tx).
Pk(id).
@@ -73,8 +76,17 @@ func (this *HTTPRewriteRuleDAO) FindEnabledHTTPRewriteRule(tx *dbs.Tx, id int64)
return result.(*HTTPRewriteRule), err
}
// 构造配置
func (this *HTTPRewriteRuleDAO) ComposeRewriteRule(tx *dbs.Tx, rewriteRuleId int64) (*serverconfigs.HTTPRewriteRule, error) {
// ComposeRewriteRule 构造配置
func (this *HTTPRewriteRuleDAO) ComposeRewriteRule(tx *dbs.Tx, rewriteRuleId int64, cacheMap maps.Map) (*serverconfigs.HTTPRewriteRule, error) {
if cacheMap == nil {
cacheMap = maps.Map{}
}
var cacheKey = this.Table + ":config:" + types.String(rewriteRuleId)
var cache = cacheMap.Get(cacheKey)
if cache != nil {
return cache.(*serverconfigs.HTTPRewriteRule), nil
}
rule, err := this.FindEnabledHTTPRewriteRule(tx, rewriteRuleId)
if err != nil {
return nil, err
@@ -93,11 +105,24 @@ func (this *HTTPRewriteRuleDAO) ComposeRewriteRule(tx *dbs.Tx, rewriteRuleId int
config.ProxyHost = rule.ProxyHost
config.IsBreak = rule.IsBreak == 1
config.WithQuery = rule.WithQuery == 1
// conds
if len(rule.Conds) > 0 {
conds := &shared.HTTPRequestCondsConfig{}
err = json.Unmarshal([]byte(rule.Conds), conds)
if err != nil {
return nil, err
}
config.Conds = conds
}
cacheMap[cacheKey] = config
return config, nil
}
// 创建规则
func (this *HTTPRewriteRuleDAO) CreateRewriteRule(tx *dbs.Tx, pattern string, replace string, mode string, redirectStatus int, isBreak bool, proxyHost string, withQuery bool, isOn bool) (int64, error) {
// 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) {
op := NewHTTPRewriteRuleOperator()
op.State = HTTPRewriteRuleStateEnabled
op.IsOn = isOn
@@ -109,12 +134,17 @@ func (this *HTTPRewriteRuleDAO) CreateRewriteRule(tx *dbs.Tx, pattern string, re
op.IsBreak = isBreak
op.WithQuery = withQuery
op.ProxyHost = proxyHost
if len(condsJSON) > 0 {
op.Conds = condsJSON
}
err := this.Save(tx, op)
return types.Int64(op.Id), err
}
// 修改规则
func (this *HTTPRewriteRuleDAO) UpdateRewriteRule(tx *dbs.Tx, rewriteRuleId int64, pattern string, replace string, mode string, redirectStatus int, isBreak bool, proxyHost string, withQuery bool, isOn bool) error {
// UpdateRewriteRule 修改规则
func (this *HTTPRewriteRuleDAO) UpdateRewriteRule(tx *dbs.Tx, rewriteRuleId int64, pattern string, replace string, mode string, redirectStatus int, isBreak bool, proxyHost string, withQuery bool, isOn bool, condsJSON []byte) error {
if rewriteRuleId <= 0 {
return errors.New("invalid rewriteRuleId")
}
@@ -128,6 +158,11 @@ func (this *HTTPRewriteRuleDAO) UpdateRewriteRule(tx *dbs.Tx, rewriteRuleId int6
op.IsBreak = isBreak
op.WithQuery = withQuery
op.ProxyHost = proxyHost
if len(condsJSON) > 0 {
op.Conds = condsJSON
}
err := this.Save(tx, op)
if err != nil {
return err
@@ -135,7 +170,7 @@ func (this *HTTPRewriteRuleDAO) UpdateRewriteRule(tx *dbs.Tx, rewriteRuleId int6
return this.NotifyUpdate(tx, rewriteRuleId)
}
// 通知更新
// NotifyUpdate 通知更新
func (this *HTTPRewriteRuleDAO) NotifyUpdate(tx *dbs.Tx, rewriteRuleId int64) error {
webId, err := SharedHTTPWebDAO.FindEnabledWebIdWithRewriteRuleId(tx, rewriteRuleId)
if err != nil {

View File

@@ -75,7 +75,16 @@ func (this *HTTPWebDAO) FindEnabledHTTPWeb(tx *dbs.Tx, id int64) (*HTTPWeb, erro
}
// ComposeWebConfig 组合配置
func (this *HTTPWebDAO) ComposeWebConfig(tx *dbs.Tx, webId int64) (*serverconfigs.HTTPWebConfig, error) {
func (this *HTTPWebDAO) ComposeWebConfig(tx *dbs.Tx, webId int64, cacheMap maps.Map) (*serverconfigs.HTTPWebConfig, error) {
if cacheMap == nil {
cacheMap = maps.Map{}
}
var cacheKey = this.Table + ":config:" + types.String(webId)
var cache = cacheMap.Get(cacheKey)
if cache != nil {
return cache.(*serverconfigs.HTTPWebConfig), nil
}
web, err := SharedHTTPWebDAO.FindEnabledHTTPWeb(tx, webId)
if err != nil {
return nil, err
@@ -181,7 +190,7 @@ func (this *HTTPWebDAO) ComposeWebConfig(tx *dbs.Tx, webId int64) (*serverconfig
return nil, err
}
for index, page := range pages {
pageConfig, err := SharedHTTPPageDAO.ComposePageConfig(tx, page.Id)
pageConfig, err := SharedHTTPPageDAO.ComposePageConfig(tx, page.Id, cacheMap)
if err != nil {
return nil, err
}
@@ -235,7 +244,7 @@ func (this *HTTPWebDAO) ComposeWebConfig(tx *dbs.Tx, webId int64) (*serverconfig
// 自定义防火墙设置
if firewallRef.FirewallPolicyId > 0 {
firewallPolicy, err := SharedHTTPFirewallPolicyDAO.ComposeFirewallPolicy(tx, firewallRef.FirewallPolicyId)
firewallPolicy, err := SharedHTTPFirewallPolicyDAO.ComposeFirewallPolicy(tx, firewallRef.FirewallPolicyId, cacheMap)
if err != nil {
return nil, err
}
@@ -247,7 +256,7 @@ func (this *HTTPWebDAO) ComposeWebConfig(tx *dbs.Tx, webId int64) (*serverconfig
}
}
// 路规则
// 路规则
if IsNotNull(web.Locations) {
refs := []*serverconfigs.HTTPLocationRef{}
err = json.Unmarshal([]byte(web.Locations), &refs)
@@ -257,7 +266,7 @@ func (this *HTTPWebDAO) ComposeWebConfig(tx *dbs.Tx, webId int64) (*serverconfig
if len(refs) > 0 {
config.LocationRefs = refs
locations, err := SharedHTTPLocationDAO.ConvertLocationRefs(tx, refs)
locations, err := SharedHTTPLocationDAO.ConvertLocationRefs(tx, refs, cacheMap)
if err != nil {
return nil, err
}
@@ -302,7 +311,7 @@ func (this *HTTPWebDAO) ComposeWebConfig(tx *dbs.Tx, webId int64) (*serverconfig
return nil, err
}
for _, ref := range refs {
rewriteRule, err := SharedHTTPRewriteRuleDAO.ComposeRewriteRule(tx, ref.RewriteRuleId)
rewriteRule, err := SharedHTTPRewriteRuleDAO.ComposeRewriteRule(tx, ref.RewriteRuleId, cacheMap)
if err != nil {
return nil, err
}
@@ -347,6 +356,29 @@ func (this *HTTPWebDAO) ComposeWebConfig(tx *dbs.Tx, webId int64) (*serverconfig
}
}
// 认证
if IsNotNull(web.Auth) {
authConfig := &serverconfigs.HTTPAuthConfig{}
err = json.Unmarshal([]byte(web.Auth), authConfig)
if err != nil {
return nil, err
}
var newRefs []*serverconfigs.HTTPAuthPolicyRef
for _, ref := range authConfig.PolicyRefs {
policyConfig, err := SharedHTTPAuthPolicyDAO.ComposePolicyConfig(tx, ref.AuthPolicyId, cacheMap)
if err != nil {
return nil, err
}
if policyConfig != nil {
ref.AuthPolicy = policyConfig
newRefs = append(newRefs, ref)
}
}
config.Auth = authConfig
}
cacheMap[cacheKey] = config
return config, nil
}
@@ -542,7 +574,7 @@ func (this *HTTPWebDAO) UpdateWebFirewall(tx *dbs.Tx, webId int64, firewallJSON
return this.NotifyUpdate(tx, webId)
}
// UpdateWebLocations 更改路规则配置
// UpdateWebLocations 更改路规则配置
func (this *HTTPWebDAO) UpdateWebLocations(tx *dbs.Tx, webId int64, locationsJSON []byte) error {
if webId <= 0 {
return errors.New("invalid webId")
@@ -622,6 +654,22 @@ func (this *HTTPWebDAO) UpdateWebRewriteRules(tx *dbs.Tx, webId int64, rewriteRu
return this.NotifyUpdate(tx, webId)
}
// UpdateWebAuth 修改认证信息
func (this *HTTPWebDAO) UpdateWebAuth(tx *dbs.Tx, webId int64, authJSON []byte) error {
if webId <= 0 {
return errors.New("invalid webId")
}
op := NewHTTPWebOperator()
op.Id = webId
op.Auth = JSONBytes(authJSON)
err := this.Save(tx, op)
if err != nil {
return err
}
return this.NotifyUpdate(tx, webId)
}
// FindAllWebIdsWithCachePolicyId 根据缓存策略ID查找所有的WebId
func (this *HTTPWebDAO) FindAllWebIdsWithCachePolicyId(tx *dbs.Tx, cachePolicyId int64) ([]int64, error) {
ones, err := this.Query(tx).
@@ -783,6 +831,16 @@ func (this *HTTPWebDAO) FindEnabledWebIdWithFastcgiId(tx *dbs.Tx, fastcgiId int6
FindInt64Col(0)
}
// FindEnabledWebIdWithHTTPAuthPolicyId 查找包含某个认证策略的Web
func (this *HTTPWebDAO) FindEnabledWebIdWithHTTPAuthPolicyId(tx *dbs.Tx, httpAuthPolicyId int64) (webId int64, err error) {
return this.Query(tx).
State(HTTPWebStateEnabled).
ResultPk().
Where("JSON_CONTAINS(auth, :jsonQuery, '$.policyRefs')").
Param("jsonQuery", maps.Map{"authPolicyId": httpAuthPolicyId}.AsJSON()).
FindInt64Col(0)
}
// FindWebServerId 查找使用此Web的Server
func (this *HTTPWebDAO) FindWebServerId(tx *dbs.Tx, webId int64) (serverId int64, err error) {
if webId <= 0 {

View File

@@ -23,11 +23,12 @@ type HTTPWeb struct {
Gzip string `field:"gzip"` // Gzip配置
Cache string `field:"cache"` // 缓存配置
Firewall string `field:"firewall"` // 防火墙设置
Locations string `field:"locations"` // 路规则配置
Locations string `field:"locations"` // 路规则配置
Websocket string `field:"websocket"` // Websocket设置
RewriteRules string `field:"rewriteRules"` // 重写规则配置
HostRedirects string `field:"hostRedirects"` // 域名跳转
Fastcgi string `field:"fastcgi"` // Fastcgi配置
Auth string `field:"auth"` // 认证策略配置
}
type HTTPWebOperator struct {
@@ -52,11 +53,12 @@ type HTTPWebOperator struct {
Gzip interface{} // Gzip配置
Cache interface{} // 缓存配置
Firewall interface{} // 防火墙设置
Locations interface{} // 路规则配置
Locations interface{} // 路规则配置
Websocket interface{} // Websocket设置
RewriteRules interface{} // 重写规则配置
HostRedirects interface{} // 域名跳转
Fastcgi interface{} // Fastcgi配置
Auth interface{} // 认证策略配置
}
func NewHTTPWebOperator() *HTTPWebOperator {

View File

@@ -3,6 +3,7 @@ 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"
@@ -46,7 +47,7 @@ func init() {
})
}
// 启用条目
// EnableIPItem 启用条目
func (this *IPItemDAO) EnableIPItem(tx *dbs.Tx, id int64) error {
_, err := this.Query(tx).
Pk(id).
@@ -55,7 +56,7 @@ func (this *IPItemDAO) EnableIPItem(tx *dbs.Tx, id int64) error {
return err
}
// 禁用条目
// DisableIPItem 禁用条目
func (this *IPItemDAO) DisableIPItem(tx *dbs.Tx, id int64) error {
version, err := SharedIPListDAO.IncreaseVersion(tx)
if err != nil {
@@ -74,7 +75,7 @@ func (this *IPItemDAO) DisableIPItem(tx *dbs.Tx, id int64) error {
return this.NotifyUpdate(tx, id)
}
// 查找启用中的条目
// FindEnabledIPItem 查找启用中的条目
func (this *IPItemDAO) FindEnabledIPItem(tx *dbs.Tx, id int64) (*IPItem, error) {
result, err := this.Query(tx).
Pk(id).
@@ -86,7 +87,17 @@ func (this *IPItemDAO) FindEnabledIPItem(tx *dbs.Tx, id int64) (*IPItem, error)
return result.(*IPItem), err
}
// 创建IP
// DisableOldIPItem 根据IP删除以前的旧记录
func (this *IPItemDAO) DisableOldIPItem(tx *dbs.Tx, listId int64, ipFrom string, ipTo string) error {
return this.Query(tx).
Attr("listId", listId).
Attr("ipFrom", ipFrom).
Attr("ipTo", ipTo).
Set("state", IPItemStateDisabled).
UpdateQuickly()
}
// CreateIPItem 创建IP
func (this *IPItemDAO) CreateIPItem(tx *dbs.Tx, listId int64, ipFrom string, ipTo string, expiredAt int64, reason string, itemType IPItemType, eventLevel string) (int64, error) {
version, err := SharedIPListDAO.IncreaseVersion(tx)
if err != nil {
@@ -121,7 +132,7 @@ func (this *IPItemDAO) CreateIPItem(tx *dbs.Tx, listId int64, ipFrom string, ipT
return itemId, nil
}
// 修改IP
// UpdateIPItem 修改IP
func (this *IPItemDAO) UpdateIPItem(tx *dbs.Tx, itemId int64, ipFrom string, ipTo string, expiredAt int64, reason string, itemType IPItemType, eventLevel string) error {
if itemId <= 0 {
return errors.New("invalid itemId")
@@ -165,7 +176,7 @@ func (this *IPItemDAO) UpdateIPItem(tx *dbs.Tx, itemId int64, ipFrom string, ipT
return this.NotifyUpdate(tx, itemId)
}
// 计算IP数量
// CountIPItemsWithListId 计算IP数量
func (this *IPItemDAO) CountIPItemsWithListId(tx *dbs.Tx, listId int64) (int64, error) {
return this.Query(tx).
State(IPItemStateEnabled).
@@ -173,7 +184,7 @@ func (this *IPItemDAO) CountIPItemsWithListId(tx *dbs.Tx, listId int64) (int64,
Count()
}
// 查找IP列表
// ListIPItemsWithListId 查找IP列表
func (this *IPItemDAO) ListIPItemsWithListId(tx *dbs.Tx, listId int64, offset int64, size int64) (result []*IPItem, err error) {
_, err = this.Query(tx).
State(IPItemStateEnabled).
@@ -186,7 +197,7 @@ func (this *IPItemDAO) ListIPItemsWithListId(tx *dbs.Tx, listId int64, offset in
return
}
// 根据版本号查找IP列表
// ListIPItemsAfterVersion 根据版本号查找IP列表
func (this *IPItemDAO) ListIPItemsAfterVersion(tx *dbs.Tx, version int64, size int64) (result []*IPItem, err error) {
_, err = this.Query(tx).
// 这里不要设置状态参数,因为我们要知道哪些是删除的
@@ -200,7 +211,7 @@ func (this *IPItemDAO) ListIPItemsAfterVersion(tx *dbs.Tx, version int64, size i
return
}
// 查找IPItem对应的列表ID
// FindItemListId 查找IPItem对应的列表ID
func (this *IPItemDAO) FindItemListId(tx *dbs.Tx, itemId int64) (int64, error) {
return this.Query(tx).
Pk(itemId).
@@ -208,7 +219,7 @@ func (this *IPItemDAO) FindItemListId(tx *dbs.Tx, itemId int64) (int64, error) {
FindInt64Col(0)
}
// 查找包含某个IP的Item
// FindEnabledItemContainsIP 查找包含某个IP的Item
func (this *IPItemDAO) FindEnabledItemContainsIP(tx *dbs.Tx, listId int64, ip uint64) (*IPItem, error) {
query := this.Query(tx).
Attr("listId", listId).
@@ -229,7 +240,29 @@ func (this *IPItemDAO) FindEnabledItemContainsIP(tx *dbs.Tx, listId int64, ip ui
return one.(*IPItem), nil
}
// 通知更新
// FindEnabledItemsWithIP 根据IP查找Item
func (this *IPItemDAO) FindEnabledItemsWithIP(tx *dbs.Tx, ip string) (result []*IPItem, err error) {
_, err = this.Query(tx).
Attr("ipFrom", ip).
Attr("ipTo", "").
Where("(expiredAt=0 OR expiredAt>:nowTime)").
Param("nowTime", time.Now().Unix()).
Where("listId IN (SELECT id FROM " + SharedIPListDAO.Table + " WHERE state=1)").
AscPk().
Slice(&result).
FindAll()
return
}
// ExistsEnabledItem 检查IP是否存在
func (this *IPItemDAO) ExistsEnabledItem(tx *dbs.Tx, itemId int64) (bool, error) {
return this.Query(tx).
Pk(itemId).
State(IPItemStateEnabled).
Exist()
}
// NotifyUpdate 通知更新
func (this *IPItemDAO) NotifyUpdate(tx *dbs.Tx, itemId int64) error {
// 获取ListId
listId, err := this.FindItemListId(tx, itemId)
@@ -284,7 +317,7 @@ func (this *IPItemDAO) NotifyUpdate(tx *dbs.Tx, itemId int64) error {
if len(resultClusterIds) > 0 {
for _, clusterId := range resultClusterIds {
err = SharedNodeTaskDAO.CreateClusterTask(tx, clusterId, NodeTaskTypeIPItemChanged)
err = SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleNode, clusterId, NodeTaskTypeIPItemChanged)
if err != nil {
return err
}

View File

@@ -2,6 +2,7 @@ package models
import (
"github.com/TeaOSLab/EdgeAPI/internal/errors"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/ipconfigs"
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
@@ -38,7 +39,7 @@ func init() {
})
}
// 启用条目
// EnableIPList 启用条目
func (this *IPListDAO) EnableIPList(tx *dbs.Tx, id int64) error {
_, err := this.Query(tx).
Pk(id).
@@ -47,7 +48,7 @@ func (this *IPListDAO) EnableIPList(tx *dbs.Tx, id int64) error {
return err
}
// 禁用条目
// DisableIPList 禁用条目
func (this *IPListDAO) DisableIPList(tx *dbs.Tx, id int64) error {
_, err := this.Query(tx).
Pk(id).
@@ -56,7 +57,7 @@ func (this *IPListDAO) DisableIPList(tx *dbs.Tx, id int64) error {
return err
}
// 查找启用中的条目
// FindEnabledIPList 查找启用中的条目
func (this *IPListDAO) FindEnabledIPList(tx *dbs.Tx, id int64) (*IPList, error) {
result, err := this.Query(tx).
Pk(id).
@@ -68,7 +69,7 @@ func (this *IPListDAO) FindEnabledIPList(tx *dbs.Tx, id int64) (*IPList, error)
return result.(*IPList), err
}
// 根据主键查找名称
// FindIPListName 根据主键查找名称
func (this *IPListDAO) FindIPListName(tx *dbs.Tx, id int64) (string, error) {
return this.Query(tx).
Pk(id).
@@ -76,7 +77,7 @@ func (this *IPListDAO) FindIPListName(tx *dbs.Tx, id int64) (string, error) {
FindStringCol("")
}
// 获取名单类型
// FindIPListTypeCacheable 获取名单类型
func (this *IPListDAO) FindIPListTypeCacheable(tx *dbs.Tx, listId int64) (string, error) {
// 检查缓存
SharedCacheLocker.RLock()
@@ -106,8 +107,8 @@ func (this *IPListDAO) FindIPListTypeCacheable(tx *dbs.Tx, listId int64) (string
return listType, nil
}
// 创建名单
func (this *IPListDAO) CreateIPList(tx *dbs.Tx, userId int64, listType ipconfigs.IPListType, name string, code string, timeoutJSON []byte) (int64, error) {
// CreateIPList 创建名单
func (this *IPListDAO) CreateIPList(tx *dbs.Tx, userId int64, listType ipconfigs.IPListType, name string, code string, timeoutJSON []byte, description string, isPublic bool) (int64, error) {
op := NewIPListOperator()
op.IsOn = true
op.UserId = userId
@@ -118,6 +119,8 @@ func (this *IPListDAO) CreateIPList(tx *dbs.Tx, userId int64, listType ipconfigs
if len(timeoutJSON) > 0 {
op.Timeout = timeoutJSON
}
op.Description = description
op.IsPublic = isPublic
err := this.Save(tx, op)
if err != nil {
return 0, err
@@ -125,8 +128,8 @@ func (this *IPListDAO) CreateIPList(tx *dbs.Tx, userId int64, listType ipconfigs
return types.Int64(op.Id), nil
}
// 修改名单
func (this *IPListDAO) UpdateIPList(tx *dbs.Tx, listId int64, name string, code string, timeoutJSON []byte) error {
// UpdateIPList 修改名单
func (this *IPListDAO) UpdateIPList(tx *dbs.Tx, listId int64, name string, code string, timeoutJSON []byte, description string) error {
if listId <= 0 {
return errors.New("invalid listId")
}
@@ -139,16 +142,17 @@ func (this *IPListDAO) UpdateIPList(tx *dbs.Tx, listId int64, name string, code
} else {
op.Timeout = "null"
}
op.Description = description
err := this.Save(tx, op)
return err
}
// 增加版本
// IncreaseVersion 增加版本
func (this *IPListDAO) IncreaseVersion(tx *dbs.Tx) (int64, error) {
return SharedSysLockerDAO.Increase(tx, "IP_LIST_VERSION", 1000000)
}
// 检查用户权限
// CheckUserIPList 检查用户权限
func (this *IPListDAO) CheckUserIPList(tx *dbs.Tx, userId int64, listId int64) error {
ok, err := this.Query(tx).
Pk(listId).
@@ -163,7 +167,49 @@ func (this *IPListDAO) CheckUserIPList(tx *dbs.Tx, userId int64, listId int64) e
return ErrNotFound
}
// 通知更新
// CountAllEnabledIPLists 计算名单数量
func (this *IPListDAO) CountAllEnabledIPLists(tx *dbs.Tx, listType string, isPublic bool, keyword string) (int64, error) {
var query = this.Query(tx).
State(IPListStateEnabled).
Attr("type", listType).
Attr("isPublic", isPublic)
if len(keyword) > 0 {
query.Where("(name LIKE :keyword OR description LIKE :keyword)").
Param("keyword", "%"+keyword+"%")
}
return query.Count()
}
// ListEnabledIPLists 列出单页名单
func (this *IPListDAO) ListEnabledIPLists(tx *dbs.Tx, listType string, isPublic bool, keyword string, offset int64, size int64) (result []*IPList, err error) {
var query = this.Query(tx).
State(IPListStateEnabled).
Attr("type", listType).
Attr("isPublic", isPublic)
if len(keyword) > 0 {
query.Where("(name LIKE :keyword OR description LIKE :keyword)").
Param("keyword", "%"+keyword+"%")
}
_, err = query.Offset(offset).
Limit(size).
DescPk().
Slice(&result).
FindAll()
return
}
// ExistsEnabledIPList 检查IP名单是否存在
func (this *IPListDAO) ExistsEnabledIPList(tx *dbs.Tx, listId int64) (bool, error) {
if listId <= 0 {
return false, nil
}
return this.Query(tx).
Pk(listId).
State(IPListStateEnabled).
Exist()
}
// NotifyUpdate 通知更新
func (this *IPListDAO) NotifyUpdate(tx *dbs.Tx, listId int64, taskType NodeTaskType) error {
httpFirewallPolicyIds, err := SharedHTTPFirewallPolicyDAO.FindEnabledFirewallPolicyIdsWithIPListId(tx, listId)
if err != nil {
@@ -208,7 +254,7 @@ func (this *IPListDAO) NotifyUpdate(tx *dbs.Tx, listId int64, taskType NodeTaskT
if len(resultClusterIds) > 0 {
for _, clusterId := range resultClusterIds {
err = SharedNodeTaskDAO.CreateClusterTask(tx, clusterId, taskType)
err = SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleNode, clusterId, taskType)
if err != nil {
return err
}

View File

@@ -1,32 +1,36 @@
package models
// IP名单
// IPList IP名单
type IPList struct {
Id uint32 `field:"id"` // ID
IsOn uint8 `field:"isOn"` // 是否启用
Type string `field:"type"` // 类型
AdminId uint32 `field:"adminId"` // 用户ID
UserId uint32 `field:"userId"` // 用户ID
Name string `field:"name"` // 列表名
Code string `field:"code"` // 代号
State uint8 `field:"state"` // 状态
CreatedAt uint64 `field:"createdAt"` // 创建时间
Timeout string `field:"timeout"` // 默认超时时间
Actions string `field:"actions"` // IP触发的动作
Id uint32 `field:"id"` // ID
IsOn uint8 `field:"isOn"` // 是否启用
Type string `field:"type"` // 类型
AdminId uint32 `field:"adminId"` // 用户ID
UserId uint32 `field:"userId"` // 用户ID
Name string `field:"name"` // 列表名
Code string `field:"code"` // 代号
State uint8 `field:"state"` // 状态
CreatedAt uint64 `field:"createdAt"` // 创建时间
Timeout string `field:"timeout"` // 默认超时时间
Actions string `field:"actions"` // IP触发的动作
Description string `field:"description"` // 描述
IsPublic uint8 `field:"isPublic"` // 是否公用
}
type IPListOperator struct {
Id interface{} // ID
IsOn interface{} // 是否启用
Type interface{} // 类型
AdminId interface{} // 用户ID
UserId interface{} // 用户ID
Name interface{} // 列表名
Code interface{} // 代号
State interface{} // 状态
CreatedAt interface{} // 创建时间
Timeout interface{} // 默认超时时间
Actions interface{} // IP触发的动作
Id interface{} // ID
IsOn interface{} // 是否启用
Type interface{} // 类型
AdminId interface{} // 用户ID
UserId interface{} // 用户ID
Name interface{} // 列表名
Code interface{} // 代号
State interface{} // 状态
CreatedAt interface{} // 创建时间
Timeout interface{} // 默认超时时间
Actions interface{} // IP触发的动作
Description interface{} // 描述
IsPublic interface{} // 是否公用
}
func NewIPListOperator() *IPListOperator {

View File

@@ -4,6 +4,7 @@ import (
"crypto/md5"
"fmt"
"github.com/TeaOSLab/EdgeAPI/internal/errors"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
@@ -28,8 +29,8 @@ const (
MessageTypeHealthCheckFailed MessageType = "HealthCheckFailed" // 节点健康检查失败
MessageTypeHealthCheckNodeUp MessageType = "HealthCheckNodeUp" // 因健康检查节点上线
MessageTypeHealthCheckNodeDown MessageType = "HealthCheckNodeDown" // 因健康检查节点下线
MessageTypeNodeInactive MessageType = "NodeInactive" // 节点不活跃
MessageTypeNodeActive MessageType = "NodeActive" // 节点活跃
MessageTypeNodeInactive MessageType = "NodeInactive" // 边缘节点不活跃
MessageTypeNodeActive MessageType = "NodeActive" // 边缘节点活跃
MessageTypeClusterDNSSyncFailed MessageType = "ClusterDNSSyncFailed" // DNS同步失败
MessageTypeSSLCertExpiring MessageType = "SSLCertExpiring" // SSL证书即将过期
MessageTypeSSLCertACMETaskFailed MessageType = "SSLCertACMETaskFailed" // SSL证书任务执行失败
@@ -38,6 +39,15 @@ const (
MessageTypeServerNamesAuditingSuccess MessageType = "ServerNamesAuditingSuccess" // 服务域名审核成功
MessageTypeServerNamesAuditingFailed MessageType = "ServerNamesAuditingFailed" // 服务域名审核失败
MessageTypeThresholdSatisfied MessageType = "ThresholdSatisfied" // 满足阈值
MessageTypeFirewallEvent MessageType = "FirewallEvent" // 防火墙事件
MessageTypeIPAddrUp MessageType = "IPAddrUp" // IP地址上线
MessageTypeIPAddrDown MessageType = "IPAddrDown" // IP地址下线
MessageTypeNSNodeInactive MessageType = "NSNodeInactive" // NS节点不活跃
MessageTypeNSNodeActive MessageType = "NSNodeActive" // NS节点活跃
MessageTypeReportNodeInactive MessageType = "ReportNodeInactive" // 区域监控节点节点不活跃
MessageTypeReportNodeActive MessageType = "ReportNodeActive" // 区域监控节点活跃
)
type MessageDAO dbs.DAO
@@ -92,18 +102,14 @@ func (this *MessageDAO) FindEnabledMessage(tx *dbs.Tx, id int64) (*Message, erro
}
// CreateClusterMessage 创建集群消息
func (this *MessageDAO) CreateClusterMessage(tx *dbs.Tx, clusterId int64, messageType MessageType, level string, subject string, body string, paramsJSON []byte) error {
_, err := this.createMessage(tx, clusterId, 0, messageType, level, subject, body, paramsJSON)
func (this *MessageDAO) CreateClusterMessage(tx *dbs.Tx, role string, clusterId int64, messageType MessageType, level string, subject string, body string, paramsJSON []byte) error {
_, err := this.createMessage(tx, role, clusterId, 0, messageType, level, subject, body, paramsJSON)
if err != nil {
return err
}
// 发送给媒介接收人
err = SharedMessageTaskDAO.CreateMessageTasks(tx, MessageTaskTarget{
ClusterId: clusterId,
NodeId: 0,
ServerId: 0,
}, messageType, subject, body)
err = SharedMessageTaskDAO.CreateMessageTasks(tx, role, 0, 0, 0, messageType, subject, body)
if err != nil {
return err
}
@@ -112,9 +118,9 @@ func (this *MessageDAO) CreateClusterMessage(tx *dbs.Tx, clusterId int64, messag
}
// CreateNodeMessage 创建节点消息
func (this *MessageDAO) CreateNodeMessage(tx *dbs.Tx, clusterId int64, nodeId int64, messageType MessageType, level string, subject string, body string, paramsJSON []byte) error {
func (this *MessageDAO) CreateNodeMessage(tx *dbs.Tx, role string, clusterId int64, nodeId int64, messageType MessageType, level string, subject string, body string, paramsJSON []byte) error {
// 检查N分钟内是否已经发送过
hash := this.calHash(subject, body, paramsJSON)
hash := this.calHash(role, clusterId, nodeId, subject, body, paramsJSON)
exists, err := this.Query(tx).
Attr("hash", hash).
Gt("createdAt", time.Now().Unix()-10*60). // 10分钟
@@ -126,33 +132,17 @@ func (this *MessageDAO) CreateNodeMessage(tx *dbs.Tx, clusterId int64, nodeId in
return nil
}
_, err = this.createMessage(tx, clusterId, nodeId, messageType, level, subject, body, paramsJSON)
_, err = this.createMessage(tx, role, clusterId, nodeId, messageType, level, subject, body, paramsJSON)
if err != nil {
return err
}
// 发送给媒介接收人 - 集群
err = SharedMessageTaskDAO.CreateMessageTasks(tx, MessageTaskTarget{
ClusterId: clusterId,
NodeId: 0,
ServerId: 0,
}, messageType, subject, body)
err = SharedMessageTaskDAO.CreateMessageTasks(tx, role, clusterId, nodeId, 0, messageType, subject, body)
if err != nil {
return err
}
// 发送给媒介接收人 - 节点
if nodeId > 0 {
err = SharedMessageTaskDAO.CreateMessageTasks(tx, MessageTaskTarget{
ClusterId: clusterId,
NodeId: nodeId,
ServerId: 0,
}, messageType, subject, body)
if err != nil {
return err
}
}
return nil
}
@@ -178,7 +168,7 @@ func (this *MessageDAO) CreateMessage(tx *dbs.Tx, adminId int64, userId int64, m
op.State = MessageStateEnabled
op.IsRead = false
op.Day = timeutil.Format("Ymd")
op.Hash = this.calHash(subject, body, paramsJSON)
op.Hash = this.calHash(nodeconfigs.NodeRoleAdmin, 0, 0, subject, body, paramsJSON)
err := this.Save(tx, op)
if err != nil {
return err
@@ -286,13 +276,14 @@ func (this *MessageDAO) CheckMessageUser(tx *dbs.Tx, messageId int64, adminId in
}
// 创建消息
func (this *MessageDAO) createMessage(tx *dbs.Tx, clusterId int64, nodeId int64, messageType MessageType, level string, subject string, body string, paramsJSON []byte) (int64, error) {
func (this *MessageDAO) createMessage(tx *dbs.Tx, role string, clusterId int64, nodeId int64, messageType MessageType, level string, subject string, body string, paramsJSON []byte) (int64, error) {
// TODO 检查同样的消息最近是否发送过
// 创建新消息
op := NewMessageOperator()
op.AdminId = 0 // TODO
op.UserId = 0 // TODO
op.Role = role
op.ClusterId = clusterId
op.NodeId = nodeId
op.Type = messageType
@@ -313,7 +304,7 @@ func (this *MessageDAO) createMessage(tx *dbs.Tx, clusterId int64, nodeId int64,
op.State = MessageStateEnabled
op.CreatedAt = time.Now().Unix()
op.Day = timeutil.Format("Ymd")
op.Hash = this.calHash(subject, body, paramsJSON)
op.Hash = this.calHash(role, clusterId, nodeId, subject, body, paramsJSON)
err := this.Save(tx, op)
if err != nil {
@@ -323,10 +314,11 @@ func (this *MessageDAO) createMessage(tx *dbs.Tx, clusterId int64, nodeId int64,
}
// 计算Hash
func (this *MessageDAO) calHash(subject string, body string, paramsJSON []byte) string {
func (this *MessageDAO) calHash(role string, clusterId int64, nodeId int64, subject string, body string, paramsJSON []byte) string {
h := md5.New()
h.Write([]byte(subject))
h.Write([]byte(body))
h.Write([]byte(role + "@" + types.String(clusterId) + "@" + types.String(nodeId)))
h.Write([]byte(subject + "@"))
h.Write([]byte(body + "@"))
h.Write(paramsJSON)
return fmt.Sprintf("%x", h.Sum(nil))
}

View File

@@ -1,6 +1,7 @@
package models
import (
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/dbs"
"testing"
@@ -11,7 +12,7 @@ func TestMessageDAO_CreateClusterMessage(t *testing.T) {
var tx *dbs.Tx
dao := NewMessageDAO()
err := dao.CreateClusterMessage(tx, 1, "test", "error", "123", "123", []byte("456"))
err := dao.CreateClusterMessage(tx, nodeconfigs.NodeRoleNode, 1, "test", "error", "123", "123", []byte("456"))
if err != nil {
t.Fatal(err)
}

View File

@@ -7,6 +7,7 @@ import (
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/maps"
"github.com/iwind/TeaGo/types"
)
const (
@@ -35,7 +36,7 @@ func init() {
})
}
// 启用条目
// EnableMessageMediaInstance 启用条目
func (this *MessageMediaInstanceDAO) EnableMessageMediaInstance(tx *dbs.Tx, id int64) error {
_, err := this.Query(tx).
Pk(id).
@@ -44,7 +45,7 @@ func (this *MessageMediaInstanceDAO) EnableMessageMediaInstance(tx *dbs.Tx, id i
return err
}
// 禁用条目
// DisableMessageMediaInstance 禁用条目
func (this *MessageMediaInstanceDAO) DisableMessageMediaInstance(tx *dbs.Tx, id int64) error {
_, err := this.Query(tx).
Pk(id).
@@ -53,20 +54,32 @@ func (this *MessageMediaInstanceDAO) DisableMessageMediaInstance(tx *dbs.Tx, id
return err
}
// 查找启用中的条目
func (this *MessageMediaInstanceDAO) FindEnabledMessageMediaInstance(tx *dbs.Tx, id int64) (*MessageMediaInstance, error) {
// FindEnabledMessageMediaInstance 查找启用中的条目
func (this *MessageMediaInstanceDAO) FindEnabledMessageMediaInstance(tx *dbs.Tx, instanceId int64, cacheMap maps.Map) (*MessageMediaInstance, error) {
if cacheMap == nil {
cacheMap = maps.Map{}
}
var cacheKey = this.Table + ":record:" + types.String(instanceId)
var cache = cacheMap.Get(cacheKey)
if cache != nil {
return cache.(*MessageMediaInstance), nil
}
result, err := this.Query(tx).
Pk(id).
Pk(instanceId).
Attr("state", MessageMediaInstanceStateEnabled).
Find()
if result == nil {
return nil, err
}
cacheMap[cacheKey] = result
return result.(*MessageMediaInstance), err
}
// 创建媒介实例
func (this *MessageMediaInstanceDAO) CreateMediaInstance(tx *dbs.Tx, name string, mediaType string, params maps.Map, description string) (int64, error) {
// CreateMediaInstance 创建媒介实例
func (this *MessageMediaInstanceDAO) CreateMediaInstance(tx *dbs.Tx, name string, mediaType string, params maps.Map, description string, rateJSON []byte, hashLifeSeconds int32) (int64, error) {
op := NewMessageMediaInstanceOperator()
op.Name = name
op.MediaType = mediaType
@@ -83,13 +96,18 @@ func (this *MessageMediaInstanceDAO) CreateMediaInstance(tx *dbs.Tx, name string
op.Description = description
if len(rateJSON) > 0 {
op.Rate = rateJSON
}
op.HashLife = hashLifeSeconds
op.IsOn = true
op.State = MessageMediaInstanceStateEnabled
return this.SaveInt64(tx, op)
}
// 修改媒介实例
func (this *MessageMediaInstanceDAO) UpdateMediaInstance(tx *dbs.Tx, instanceId int64, name string, mediaType string, params maps.Map, description string, isOn bool) error {
// UpdateMediaInstance 修改媒介实例
func (this *MessageMediaInstanceDAO) UpdateMediaInstance(tx *dbs.Tx, instanceId int64, name string, mediaType string, params maps.Map, description string, rateJSON []byte, hashLifeSeconds int32, isOn bool) error {
if instanceId <= 0 {
return errors.New("invalid instanceId")
}
@@ -109,12 +127,18 @@ func (this *MessageMediaInstanceDAO) UpdateMediaInstance(tx *dbs.Tx, instanceId
}
op.Params = paramsJSON
if len(rateJSON) > 0 {
op.Rate = rateJSON
}
op.HashLife = hashLifeSeconds
op.Description = description
op.IsOn = isOn
return this.Save(tx, op)
}
// 计算接收人数量
// CountAllEnabledMediaInstances 计算接收人数量
func (this *MessageMediaInstanceDAO) CountAllEnabledMediaInstances(tx *dbs.Tx, mediaType string, keyword string) (int64, error) {
query := this.Query(tx)
if len(mediaType) > 0 {
@@ -130,7 +154,7 @@ func (this *MessageMediaInstanceDAO) CountAllEnabledMediaInstances(tx *dbs.Tx, m
Count()
}
// 列出单页接收人
// ListAllEnabledMediaInstances 列出单页接收人
func (this *MessageMediaInstanceDAO) ListAllEnabledMediaInstances(tx *dbs.Tx, mediaType string, keyword string, offset int64, size int64) (result []*MessageMediaInstance, err error) {
query := this.Query(tx)
if len(mediaType) > 0 {
@@ -150,3 +174,15 @@ func (this *MessageMediaInstanceDAO) ListAllEnabledMediaInstances(tx *dbs.Tx, me
FindAll()
return
}
// FindInstanceHashLifeSeconds 获取单个实例的HashLife
func (this *MessageMediaInstanceDAO) FindInstanceHashLifeSeconds(tx *dbs.Tx, instanceId int64) (int32, error) {
hashLife, err := this.Query(tx).
Pk(instanceId).
Result("hashLife").
FindIntCol(0)
if err != nil {
return 0, err
}
return types.Int32(hashLife), nil
}

View File

@@ -1,6 +1,6 @@
package models
// 消息媒介接收人
// MessageMediaInstance 消息媒介接收人
type MessageMediaInstance struct {
Id uint32 `field:"id"` // ID
Name string `field:"name"` // 名称
@@ -8,7 +8,9 @@ type MessageMediaInstance struct {
MediaType string `field:"mediaType"` // 媒介类型
Params string `field:"params"` // 媒介参数
Description string `field:"description"` // 备注
Rate string `field:"rate"` // 发送频率
State uint8 `field:"state"` // 状态
HashLife int32 `field:"hashLife"` // HASH有效期
}
type MessageMediaInstanceOperator struct {
@@ -18,7 +20,9 @@ type MessageMediaInstanceOperator struct {
MediaType interface{} // 媒介类型
Params interface{} // 媒介参数
Description interface{} // 备注
Rate interface{} // 发送频率
State interface{} // 状态
HashLife interface{} // HASH有效期
}
func NewMessageMediaInstanceOperator() *MessageMediaInstanceOperator {

View File

@@ -5,6 +5,7 @@ type Message struct {
Id uint64 `field:"id"` // ID
AdminId uint32 `field:"adminId"` // 管理员ID
UserId uint32 `field:"userId"` // 用户ID
Role string `field:"role"` // 角色
ClusterId uint32 `field:"clusterId"` // 集群ID
NodeId uint32 `field:"nodeId"` // 节点ID
Level string `field:"level"` // 级别
@@ -23,6 +24,7 @@ type MessageOperator struct {
Id interface{} // ID
AdminId interface{} // 管理员ID
UserId interface{} // 用户ID
Role interface{} // 角色
ClusterId interface{} // 集群ID
NodeId interface{} // 节点ID
Level interface{} // 级别

View File

@@ -75,11 +75,12 @@ func (this *MessageReceiverDAO) DisableReceivers(tx *dbs.Tx, clusterId int64, no
}
// CreateReceiver 创建接收人
func (this *MessageReceiverDAO) CreateReceiver(tx *dbs.Tx, target MessageTaskTarget, messageType MessageType, params maps.Map, recipientId int64, recipientGroupId int64) (int64, error) {
func (this *MessageReceiverDAO) CreateReceiver(tx *dbs.Tx, role string, clusterId int64, nodeId int64, serverId int64, messageType MessageType, params maps.Map, recipientId int64, recipientGroupId int64) (int64, error) {
op := NewMessageReceiverOperator()
op.ClusterId = target.ClusterId
op.NodeId = target.NodeId
op.ServerId = target.ServerId
op.Role = role
op.ClusterId = clusterId
op.NodeId = nodeId
op.ServerId = serverId
op.Type = messageType
if params == nil {
@@ -98,15 +99,16 @@ func (this *MessageReceiverDAO) CreateReceiver(tx *dbs.Tx, target MessageTaskTar
}
// FindAllEnabledReceivers 查询接收人
func (this *MessageReceiverDAO) FindAllEnabledReceivers(tx *dbs.Tx, target MessageTaskTarget, messageType string) (result []*MessageReceiver, err error) {
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("clusterId", target.ClusterId).
Attr("nodeId", target.NodeId).
Attr("serverId", target.ServerId).
Attr("role", role).
Attr("clusterId", clusterId).
Attr("nodeId", nodeId).
Attr("serverId", serverId).
State(MessageReceiverStateEnabled).
AscPk().
Slice(&result).
@@ -115,15 +117,102 @@ func (this *MessageReceiverDAO) FindAllEnabledReceivers(tx *dbs.Tx, target Messa
}
// CountAllEnabledReceivers 计算接收人数量
func (this *MessageReceiverDAO) CountAllEnabledReceivers(tx *dbs.Tx, target MessageTaskTarget, 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)
if len(messageType) > 0 {
query.Attr("type", []string{"*", messageType}) // *表示所有的
}
return query.
Attr("clusterId", target.ClusterId).
Attr("nodeId", target.NodeId).
Attr("serverId", target.ServerId).
Attr("role", role).
Attr("clusterId", clusterId).
Attr("nodeId", nodeId).
Attr("serverId", serverId).
State(MessageReceiverStateEnabled).
Count()
}
// FindEnabledBestFitReceivers 查询最适合的接收人
func (this *MessageReceiverDAO) FindEnabledBestFitReceivers(tx *dbs.Tx, role string, clusterId int64, nodeId int64, serverId int64, messageType string) (result []*MessageReceiver, err error) {
// serverId优先
query := this.Query(tx)
if len(messageType) > 0 {
query.Attr("type", []string{"*", messageType}) // *表示所有的
}
if len(role) > 0 {
query.Attr("role", role)
}
if serverId > 0 {
query.Attr("serverId", serverId)
} else if nodeId > 0 {
query.Attr("nodeId", nodeId)
} else if clusterId > 0 {
query.Attr("clusterId", clusterId)
}
_, err = query.
State(MessageReceiverStateEnabled).
AscPk().
Slice(&result).
FindAll()
if err != nil || len(result) > 0 {
return
}
// nodeId优先
if serverId > 0 && nodeId > 0 {
query = this.Query(tx)
if len(messageType) > 0 {
query.Attr("type", []string{"*", messageType}) // *表示所有的
}
if len(role) > 0 {
query.Attr("role", role)
}
query.Attr("nodeId", nodeId)
_, err = query.
State(MessageReceiverStateEnabled).
AscPk().
Slice(&result).
FindAll()
if err != nil || len(result) > 0 {
return
}
}
// clusterId优先
if (serverId > 0 || nodeId > 0) && clusterId > 0 {
query = this.Query(tx)
if len(messageType) > 0 {
query.Attr("type", []string{"*", messageType}) // *表示所有的
}
if len(role) > 0 {
query.Attr("role", role)
}
query.Attr("clusterId", clusterId)
_, err = query.
State(MessageReceiverStateEnabled).
AscPk().
Slice(&result).
FindAll()
if err != nil || len(result) > 0 {
return
}
}
// 去掉集群ID
query = this.Query(tx)
if len(messageType) > 0 {
query.Attr("type", []string{"*", messageType}) // *表示所有的
}
if len(role) > 0 {
query.Attr("role", role)
}
_, err = query.
State(MessageReceiverStateEnabled).
AscPk().
Slice(&result).
FindAll()
if err != nil || len(result) > 0 {
return
}
return
}

View File

@@ -1,6 +1,30 @@
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

@@ -3,6 +3,7 @@ package models
// MessageReceiver 消息通知接收人
type MessageReceiver struct {
Id uint32 `field:"id"` // ID
Role string `field:"role"` // 节点角色
ClusterId uint32 `field:"clusterId"` // 集群ID
NodeId uint32 `field:"nodeId"` // 节点ID
ServerId uint32 `field:"serverId"` // 服务ID
@@ -15,6 +16,7 @@ type MessageReceiver struct {
type MessageReceiverOperator struct {
Id interface{} // ID
Role interface{} // 节点角色
ClusterId interface{} // 集群ID
NodeId interface{} // 节点ID
ServerId interface{} // 服务ID

View File

@@ -7,6 +7,9 @@ import (
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/maps"
"github.com/iwind/TeaGo/types"
"regexp"
)
const (
@@ -54,19 +57,32 @@ func (this *MessageRecipientDAO) DisableMessageRecipient(tx *dbs.Tx, id int64) e
}
// FindEnabledMessageRecipient 查找启用中的条目
func (this *MessageRecipientDAO) FindEnabledMessageRecipient(tx *dbs.Tx, id int64) (*MessageRecipient, error) {
func (this *MessageRecipientDAO) FindEnabledMessageRecipient(tx *dbs.Tx, recipientId int64, cacheMap maps.Map,
) (*MessageRecipient, error) {
if cacheMap == nil {
cacheMap = maps.Map{}
}
var cacheKey = this.Table + ":record:" + types.String(recipientId)
var cache = cacheMap.Get(cacheKey)
if cache != nil {
return cache.(*MessageRecipient), nil
}
result, err := this.Query(tx).
Pk(id).
Pk(recipientId).
Attr("state", MessageRecipientStateEnabled).
Find()
if result == nil {
return nil, err
}
cacheMap[cacheKey] = result
return result.(*MessageRecipient), err
}
// CreateRecipient 创建接收人
func (this *MessageRecipientDAO) CreateRecipient(tx *dbs.Tx, adminId int64, instanceId int64, user string, groupIds []int64, description string) (int64, error) {
func (this *MessageRecipientDAO) CreateRecipient(tx *dbs.Tx, adminId int64, instanceId int64, user string, groupIds []int64, description string, timeFrom string, timeTo string) (int64, error) {
op := NewMessageRecipientOperator()
op.AdminId = adminId
op.InstanceId = instanceId
@@ -83,13 +99,22 @@ func (this *MessageRecipientDAO) CreateRecipient(tx *dbs.Tx, adminId int64, inst
}
op.GroupIds = groupIdsJSON
// 判断格式
var timeReg = regexp.MustCompile(`^\d+:\d+:\d+$`)
if timeReg.MatchString(timeFrom) {
op.TimeFrom = timeFrom
}
if timeReg.MatchString(timeTo) {
op.TimeTo = timeTo
}
op.IsOn = true
op.State = MessageRecipientStateEnabled
return this.SaveInt64(tx, op)
}
// UpdateRecipient 修改接收人
func (this *MessageRecipientDAO) UpdateRecipient(tx *dbs.Tx, recipientId int64, adminId int64, instanceId int64, user string, groupIds []int64, description string, isOn bool) error {
func (this *MessageRecipientDAO) UpdateRecipient(tx *dbs.Tx, recipientId int64, adminId int64, instanceId int64, user string, groupIds []int64, description string, timeFrom string, timeTo string, isOn bool) error {
if recipientId <= 0 {
return errors.New("invalid recipientId")
}
@@ -111,6 +136,20 @@ func (this *MessageRecipientDAO) UpdateRecipient(tx *dbs.Tx, recipientId int64,
op.GroupIds = groupIdsJSON
op.Description = description
// 判断格式
var timeReg = regexp.MustCompile(`^\d+:\d+:\d+$`)
if timeReg.MatchString(timeFrom) {
op.TimeFrom = timeFrom
} else {
op.TimeFrom = dbs.SQL("NULL")
}
if timeReg.MatchString(timeTo) {
op.TimeTo = timeTo
} else {
op.TimeTo = dbs.SQL("NULL")
}
op.IsOn = isOn
return this.Save(tx, op)
}
@@ -187,3 +226,11 @@ func (this *MessageRecipientDAO) FindAllEnabledAndOnRecipientIdsWithGroup(tx *db
}
return result, nil
}
// FindRecipientInstanceId 查找接收人的媒介
func (this *MessageRecipientDAO) FindRecipientInstanceId(tx *dbs.Tx, recipientId int64) (int64, error) {
return this.Query(tx).
Pk(recipientId).
Result("instanceId").
FindInt64Col(0)
}

View File

@@ -1,6 +1,6 @@
package models
// 消息媒介接收人
// MessageRecipient 消息媒介接收人
type MessageRecipient struct {
Id uint32 `field:"id"` // ID
AdminId uint32 `field:"adminId"` // 管理员ID
@@ -9,6 +9,8 @@ type MessageRecipient struct {
User string `field:"user"` // 接收人信息
GroupIds string `field:"groupIds"` // 分组ID
State uint8 `field:"state"` // 状态
TimeFrom string `field:"timeFrom"` // 开始时间
TimeTo string `field:"timeTo"` // 结束时间
Description string `field:"description"` // 备注
}
@@ -20,6 +22,8 @@ type MessageRecipientOperator struct {
User interface{} // 接收人信息
GroupIds interface{} // 分组ID
State interface{} // 状态
TimeFrom interface{} // 开始时间
TimeTo interface{} // 结束时间
Description interface{} // 备注
}

View File

@@ -1,9 +0,0 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package models
type MessageTaskTarget struct {
ClusterId int64
NodeId int64
ServerId int64
}

View File

@@ -2,9 +2,15 @@ package models
import (
"github.com/TeaOSLab/EdgeAPI/internal/errors"
"github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/rands"
"github.com/iwind/TeaGo/types"
stringutil "github.com/iwind/TeaGo/utils/string"
timeutil "github.com/iwind/TeaGo/utils/time"
"time"
)
@@ -35,6 +41,21 @@ func NewMessageTaskDAO() *MessageTaskDAO {
var SharedMessageTaskDAO *MessageTaskDAO
func init() {
dbs.OnReadyDone(func() {
// 清理数据任务
var ticker = time.NewTicker(time.Duration(rands.Int(24, 48)) * time.Hour)
go func() {
for range ticker.C {
err := SharedMessageTaskDAO.CleanExpiredMessageTasks(nil, 30) // 只保留30天
if err != nil {
remotelogs.Error("SharedMessageTaskDAO", "clean expired data failed: "+err.Error())
}
}
}()
})
}
func init() {
dbs.OnReady(func() {
SharedMessageTaskDAO = NewMessageTaskDAO()
@@ -73,13 +94,46 @@ func (this *MessageTaskDAO) FindEnabledMessageTask(tx *dbs.Tx, id int64) (*Messa
// CreateMessageTask 创建任务
func (this *MessageTaskDAO) CreateMessageTask(tx *dbs.Tx, recipientId int64, instanceId int64, user string, subject string, body string, isPrimary bool) (int64, error) {
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
}
}
}
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)
@@ -93,6 +147,8 @@ func (this *MessageTaskDAO) FindSendingMessageTasks(tx *dbs.Tx, size int64) (res
_, 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).
@@ -101,6 +157,28 @@ func (this *MessageTaskDAO) FindSendingMessageTasks(tx *dbs.Tx, size int64) (res
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 {
@@ -117,8 +195,8 @@ func (this *MessageTaskDAO) UpdateMessageTaskStatus(tx *dbs.Tx, taskId int64, st
}
// CreateMessageTasks 从集群、节点或者服务中创建任务
func (this *MessageTaskDAO) CreateMessageTasks(tx *dbs.Tx, target MessageTaskTarget, messageType MessageType, subject string, body string) error {
receivers, err := SharedMessageReceiverDAO.FindAllEnabledReceivers(tx, target, messageType)
func (this *MessageTaskDAO) CreateMessageTasks(tx *dbs.Tx, role nodeconfigs.NodeRole, clusterId int64, nodeId int64, serverId int64, messageType MessageType, subject string, body string) error {
receivers, err := SharedMessageReceiverDAO.FindEnabledBestFitReceivers(tx, role, clusterId, nodeId, serverId, messageType)
if err != nil {
return err
}
@@ -150,3 +228,16 @@ func (this *MessageTaskDAO) CreateMessageTasks(tx *dbs.Tx, target MessageTaskTar
return nil
}
// CleanExpiredMessageTasks 清理
func (this *MessageTaskDAO) CleanExpiredMessageTasks(tx *dbs.Tx, days int) error {
if days <= 0 {
days = 30
}
var day = timeutil.Format("Ymd", time.Now().AddDate(0, 0, -days))
_, err := this.Query(tx).
Where("(day IS NULL OR day<:day)").
Param("day", day).
Delete()
return err
}

View File

@@ -3,4 +3,20 @@ package models
import (
_ "github.com/go-sql-driver/mysql"
_ "github.com/iwind/TeaGo/bootstrap"
"github.com/iwind/TeaGo/dbs"
"testing"
)
func TestMessageTaskDAO_FindSendingMessageTasks(t *testing.T) {
dbs.NotifyReady()
var tx *dbs.Tx
tasks, err := NewMessageTaskDAO().FindSendingMessageTasks(tx, 100)
if err != nil {
t.Fatal(err)
}
t.Log(len(tasks), "tasks")
for _, task := range tasks {
t.Log("task:", task.Id, "recipient:", task.RecipientId)
}
}

View File

@@ -1,13 +1,32 @@
package models
import (
"github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/rands"
timeutil "github.com/iwind/TeaGo/utils/time"
"time"
)
type MessageTaskLogDAO dbs.DAO
func init() {
dbs.OnReadyDone(func() {
// 清理数据任务
var ticker = time.NewTicker(time.Duration(rands.Int(24, 48)) * time.Hour)
go func() {
for range ticker.C {
err := SharedMessageTaskLogDAO.CleanExpiredLogs(nil, 30) // 只保留30天
if err != nil {
remotelogs.Error("SharedMessageTaskLogDAO", "clean expired data failed: "+err.Error())
}
}
}()
})
}
func NewMessageTaskLogDAO() *MessageTaskLogDAO {
return dbs.NewDAO(&MessageTaskLogDAO{
DAOObject: dbs.DAOObject{
@@ -27,25 +46,28 @@ func init() {
})
}
// 创建日志
// CreateLog 创建日志
func (this *MessageTaskLogDAO) CreateLog(tx *dbs.Tx, taskId int64, isOk bool, errMsg string, response string) error {
op := NewMessageTaskLogOperator()
op.TaskId = taskId
op.IsOk = isOk
op.Error = errMsg
op.Response = response
op.Day = timeutil.Format("Ymd")
return this.Save(tx, op)
}
// 计算日志数量
// CountLogs 计算日志数量
func (this *MessageTaskLogDAO) CountLogs(tx *dbs.Tx) (int64, error) {
return this.Query(tx).
Where("taskId IN (SELECT id FROM " + SharedMessageTaskDAO.Table + ")").
Count()
}
// 列出单页日志
// ListLogs 列出单页日志
func (this *MessageTaskLogDAO) ListLogs(tx *dbs.Tx, offset int64, size int64) (result []*MessageTaskLog, err error) {
_, err = this.Query(tx).
Where("taskId IN (SELECT id FROM " + SharedMessageTaskDAO.Table + ")").
Offset(offset).
Limit(size).
DescPk().
@@ -53,3 +75,16 @@ func (this *MessageTaskLogDAO) ListLogs(tx *dbs.Tx, offset int64, size int64) (r
FindAll()
return
}
// CleanExpiredLogs 清理
func (this *MessageTaskLogDAO) CleanExpiredLogs(tx *dbs.Tx, days int) error {
if days <= 0 {
days = 30
}
var day = timeutil.Format("Ymd", time.Now().AddDate(0, 0, -days))
_, err := this.Query(tx).
Where("(day IS NULL OR day<:day)").
Param("day", day).
Delete()
return err
}

View File

@@ -1,6 +1,6 @@
package models
// 消息发送日志
// MessageTaskLog 消息发送日志
type MessageTaskLog struct {
Id uint64 `field:"id"` // ID
TaskId uint64 `field:"taskId"` // 任务ID
@@ -8,6 +8,7 @@ type MessageTaskLog struct {
IsOk uint8 `field:"isOk"` // 是否成功
Error string `field:"error"` // 错误信息
Response string `field:"response"` // 响应信息
Day string `field:"day"` // YYYYMMDD
}
type MessageTaskLogOperator struct {
@@ -17,6 +18,7 @@ type MessageTaskLogOperator struct {
IsOk interface{} // 是否成功
Error interface{} // 错误信息
Response interface{} // 响应信息
Day interface{} // YYYYMMDD
}
func NewMessageTaskLogOperator() *MessageTaskLogOperator {

View File

@@ -1,9 +1,10 @@
package models
//
// MessageTask 消息发送相关任务
type MessageTask struct {
Id uint64 `field:"id"` // ID
RecipientId uint32 `field:"recipientId"` // 接收人ID
Hash string `field:"hash"` // SUM标识
InstanceId uint32 `field:"instanceId"` // 媒介实例ID
User string `field:"user"` // 接收用户标识
Subject string `field:"subject"` // 标题
@@ -13,12 +14,14 @@ type MessageTask struct {
SentAt uint64 `field:"sentAt"` // 最后一次发送时间
State uint8 `field:"state"` // 状态
Result string `field:"result"` // 结果
Day string `field:"day"` // YYYYMMDD
IsPrimary uint8 `field:"isPrimary"` // 是否优先
}
type MessageTaskOperator struct {
Id interface{} // ID
RecipientId interface{} // 接收人ID
Hash interface{} // SUM标识
InstanceId interface{} // 媒介实例ID
User interface{} // 接收用户标识
Subject interface{} // 标题
@@ -28,6 +31,7 @@ type MessageTaskOperator struct {
SentAt interface{} // 最后一次发送时间
State interface{} // 状态
Result interface{} // 结果
Day interface{} // YYYYMMDD
IsPrimary interface{} // 是否优先
}

View File

@@ -0,0 +1,177 @@
package models
import (
"encoding/json"
"github.com/TeaOSLab/EdgeAPI/internal/errors"
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/maps"
)
const (
MetricChartStateEnabled = 1 // 已启用
MetricChartStateDisabled = 0 // 已禁用
)
type MetricChartDAO dbs.DAO
func NewMetricChartDAO() *MetricChartDAO {
return dbs.NewDAO(&MetricChartDAO{
DAOObject: dbs.DAOObject{
DB: Tea.Env,
Table: "edgeMetricCharts",
Model: new(MetricChart),
PkName: "id",
},
}).(*MetricChartDAO)
}
var SharedMetricChartDAO *MetricChartDAO
func init() {
dbs.OnReady(func() {
SharedMetricChartDAO = NewMetricChartDAO()
})
}
// EnableMetricChart 启用条目
func (this *MetricChartDAO) EnableMetricChart(tx *dbs.Tx, chartId int64) error {
_, err := this.Query(tx).
Pk(chartId).
Set("state", MetricChartStateEnabled).
Update()
return err
}
// DisableMetricChart 禁用条目
func (this *MetricChartDAO) DisableMetricChart(tx *dbs.Tx, chartId int64) error {
_, err := this.Query(tx).
Pk(chartId).
Set("state", MetricChartStateDisabled).
Update()
return err
}
// FindEnabledMetricChart 查找启用中的条目
func (this *MetricChartDAO) FindEnabledMetricChart(tx *dbs.Tx, chartId int64) (*MetricChart, error) {
result, err := this.Query(tx).
Pk(chartId).
Attr("state", MetricChartStateEnabled).
Find()
if result == nil {
return nil, err
}
return result.(*MetricChart), err
}
// FindMetricChartName 根据主键查找名称
func (this *MetricChartDAO) FindMetricChartName(tx *dbs.Tx, chartId int64) (string, error) {
return this.Query(tx).
Pk(chartId).
Result("name").
FindStringCol("")
}
// CreateChart 创建图表
func (this *MetricChartDAO) CreateChart(tx *dbs.Tx, itemId int64, name string, chartType string, widthDiv int32, maxItems int32, params maps.Map, ignoreEmptyKeys bool, ignoredKeys []string) (int64, error) {
op := NewMetricChartOperator()
op.ItemId = itemId
op.Name = name
op.Type = chartType
op.WidthDiv = widthDiv
op.MaxItems = maxItems
if params == nil {
params = maps.Map{}
}
paramsJSON, err := json.Marshal(params)
if err != nil {
return 0, err
}
op.Params = paramsJSON
op.IgnoreEmptyKeys = ignoreEmptyKeys
if len(ignoredKeys) == 0 {
op.IgnoredKeys = "[]"
} else {
ignoredKeysJSON, err := json.Marshal(ignoredKeys)
if err != nil {
return 0, err
}
op.IgnoredKeys = ignoredKeysJSON
}
op.IsOn = true
op.State = MetricChartStateEnabled
return this.SaveInt64(tx, op)
}
// UpdateChart 修改图表
func (this *MetricChartDAO) UpdateChart(tx *dbs.Tx, chartId int64, name string, chartType string, widthDiv int32, maxItems int32, params maps.Map, ignoreEmptyKeys bool, ignoredKeys []string, isOn bool) error {
if chartId <= 0 {
return errors.New("invalid chartId")
}
op := NewMetricChartOperator()
op.Id = chartId
op.Name = name
op.Type = chartType
op.WidthDiv = widthDiv
op.MaxItems = maxItems
if params == nil {
params = maps.Map{}
}
paramsJSON, err := json.Marshal(params)
if err != nil {
return err
}
op.Params = paramsJSON
op.IgnoreEmptyKeys = ignoreEmptyKeys
if len(ignoredKeys) == 0 {
op.IgnoredKeys = "[]"
} else {
ignoredKeysJSON, err := json.Marshal(ignoredKeys)
if err != nil {
return err
}
op.IgnoredKeys = ignoredKeysJSON
}
op.IsOn = isOn
return this.Save(tx, op)
}
// CountEnabledCharts 计算图表数量
func (this *MetricChartDAO) CountEnabledCharts(tx *dbs.Tx, itemId int64) (int64, error) {
return this.Query(tx).
Attr("itemId", itemId).
State(MetricChartStateEnabled).
Count()
}
// ListEnabledCharts 列出单页图表
func (this *MetricChartDAO) ListEnabledCharts(tx *dbs.Tx, itemId int64, offset int64, size int64) (result []*MetricChart, err error) {
_, err = this.Query(tx).
Attr("itemId", itemId).
State(MetricChartStateEnabled).
Offset(offset).
Limit(size).
DescPk().
Slice(&result).
FindAll()
return
}
// FindAllEnabledCharts 查找所有图表
func (this *MetricChartDAO) FindAllEnabledCharts(tx *dbs.Tx, itemId int64) (result []*MetricChart, err error) {
_, err = this.Query(tx).
Attr("itemId", itemId).
State(MetricChartStateEnabled).
DescPk().
Slice(&result).
FindAll()
return
}

View File

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

View File

@@ -0,0 +1,38 @@
package models
// MetricChart 指标图表
type MetricChart struct {
Id uint32 `field:"id"` // ID
ItemId uint32 `field:"itemId"` // 指标ID
Name string `field:"name"` // 名称
Code string `field:"code"` // 代号
Type string `field:"type"` // 图形类型
WidthDiv int32 `field:"widthDiv"` // 宽度划分
Params string `field:"params"` // 图形参数
Order uint32 `field:"order"` // 排序
IsOn uint8 `field:"isOn"` // 是否启用
State uint8 `field:"state"` // 状态
MaxItems uint32 `field:"maxItems"` // 最多条目
IgnoreEmptyKeys uint8 `field:"ignoreEmptyKeys"` // 忽略空的键值
IgnoredKeys string `field:"ignoredKeys"` // 忽略键值
}
type MetricChartOperator struct {
Id interface{} // ID
ItemId interface{} // 指标ID
Name interface{} // 名称
Code interface{} // 代号
Type interface{} // 图形类型
WidthDiv interface{} // 宽度划分
Params interface{} // 图形参数
Order interface{} // 排序
IsOn interface{} // 是否启用
State interface{} // 状态
MaxItems interface{} // 最多条目
IgnoreEmptyKeys interface{} // 忽略空的键值
IgnoredKeys interface{} // 忽略键值
}
func NewMetricChartOperator() *MetricChartOperator {
return &MetricChartOperator{}
}

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