Compare commits

..

184 Commits

Author SHA1 Message Date
刘祥超
d7d209f694 更改版本为0.4.6 2022-03-23 10:03:25 +08:00
刘祥超
83a88299c2 Update components.js 2022-03-21 08:23:34 +08:00
刘祥超
bfae3b86cc Age改为在缓存中的已存活时间 2022-03-20 21:18:51 +08:00
刘祥超
027ee4d336 GRPC通讯支持gzip压缩 2022-03-20 11:28:38 +08:00
刘祥超
b07a65c879 更新相关库 2022-03-20 10:46:09 +08:00
刘祥超
284b2762f5 优化界面 2022-03-18 20:21:00 +08:00
刘祥超
5ba6e3b332 改进文字 2022-03-18 17:02:36 +08:00
刘祥超
8b0e3d960a Update components.js 2022-03-17 19:59:58 +08:00
刘祥超
fba2953974 优化界面 2022-03-17 19:57:41 +08:00
刘祥超
a36b843eff 优化指标统计图表数字展示 2022-03-17 16:01:47 +08:00
刘祥超
0735bc2d8a 源站支持自定义回源主机名 2022-03-17 15:48:08 +08:00
刘祥超
69d6fd645b 修复访问日志按小时搜索无法上翻页的Bug 2022-03-17 12:31:45 +08:00
刘祥超
039b11d434 增加置顶集群功能 2022-03-17 11:12:24 +08:00
刘祥超
485581f680 优化界面 2022-03-17 10:36:30 +08:00
刘祥超
a0c2006e24 Update components.js 2022-03-16 22:48:04 +08:00
刘祥超
7a288c360d IPSet支持IPv6 2022-03-16 20:48:35 +08:00
刘祥超
597d39f651 优化文字 2022-03-16 17:07:46 +08:00
刘祥超
7d27f64b8a 节点可以单独设置缓存目录 2022-03-16 15:24:11 +08:00
刘祥超
bd280bdc53 改进文字 2022-03-14 19:25:19 +08:00
刘祥超
018429866e 优化文字提示 2022-03-14 16:24:09 +08:00
刘祥超
78ad6526b8 缓存策略可以使用存储类型筛选 2022-03-14 15:42:10 +08:00
刘祥超
8c6e960db7 实现回源跟随功能 2022-03-14 15:07:49 +08:00
刘祥超
46d38ff8c0 格式化部分图表中的数字 2022-03-14 12:04:46 +08:00
刘祥超
db6fe469ad 访问日志慢的时候增加指定域名查询建议 2022-03-11 20:35:42 +08:00
刘祥超
5a7630bcd1 增加证书OCSP错误日志管理 2022-03-11 20:27:45 +08:00
刘祥超
099b57169d 上传js 2022-03-10 21:32:56 +08:00
刘祥超
e22dfd3314 优化界面 2022-03-10 15:47:25 +08:00
刘祥超
be71992930 增加OCSP Stapling功能 2022-03-10 11:55:09 +08:00
刘祥超
37433178cb 支持使用小时筛选访问日志 2022-03-09 11:00:49 +08:00
刘祥超
14499a4564 增加对访问日志自动分表配置 2022-03-09 10:01:52 +08:00
刘祥超
0355777f59 优化文字 2022-03-06 19:48:50 +08:00
刘祥超
a55834c78d 优化界面 2022-03-04 17:00:01 +08:00
刘祥超
79bbb47459 更新TeaGo 2022-03-04 15:01:26 +08:00
刘祥超
d3bcf0605b 升级相关依赖库 2022-03-04 12:35:28 +08:00
刘祥超
19a02f3a40 实现基础的区间内容缓存(206 partial content) 2022-03-03 19:32:11 +08:00
刘祥超
db20e9308a 修复选择集群弹窗页面可能只显示前6个集群的Bug 2022-02-28 14:41:55 +08:00
刘祥超
b3f9f28554 优化界面显示 2022-02-27 21:20:49 +08:00
刘祥超
ea5bd3f346 可以在管理界面设置里设置默认每页显示数 2022-02-24 20:52:47 +08:00
刘祥超
5c13797639 缓存可以设置是否使用系统默认设置 2022-02-24 20:39:09 +08:00
刘祥超
f147905532 增加是否同步写入压缩缓存设置 2022-02-24 20:12:15 +08:00
刘祥超
a73314c12a 修改版本为0.4.5 2022-02-24 19:25:12 +08:00
刘祥超
619934a275 修复访问日志XSS漏洞 2022-02-23 17:34:54 +08:00
刘祥超
5fe1384e55 修改版本为0.4.4 2022-02-23 14:48:33 +08:00
刘祥超
9af2c4a18a 修改版本为v0.4.3 2022-02-21 18:32:03 +08:00
刘祥超
8f4c56b24a 更改版本为v0.4.2 2022-02-21 17:52:36 +08:00
刘祥超
5eb0f65934 更新截图 2022-02-21 11:53:51 +08:00
刘祥超
4ed4f165ac URL跳转可以设置是否保留参数 2022-02-20 09:17:30 +08:00
刘祥超
eb8419fda0 Update components.js 2022-02-17 17:24:23 +08:00
刘祥超
b4a7ee0e89 域名支持--(连续的连字符) 2022-02-17 17:24:14 +08:00
刘祥超
83ad1bc529 优化界面 2022-02-15 14:54:45 +08:00
刘祥超
56948d3035 优化菜单中badge显示 2022-02-14 08:58:31 +08:00
刘祥超
e71e5ad57e 支持默认价格设置 2022-01-23 20:16:02 +08:00
刘祥超
e06d1fa5b0 实现带宽计费套餐 2022-01-23 19:16:22 +08:00
刘祥超
460439f6bd 修复服务访问日志不能使用集群、节点筛选的Bug 2022-01-20 16:28:43 +08:00
刘祥超
4b4072a47e 优化界面 2022-01-20 15:53:46 +08:00
刘祥超
65d19d92e9 增加API方法调用耗时统计 2022-01-19 16:53:38 +08:00
刘祥超
79e52d1c6e 优化demo模式进入命令 2022-01-19 15:58:54 +08:00
刘祥超
59963ee7b9 修复检查更新配置不起作用的Bug 2022-01-18 19:29:42 +08:00
刘祥超
88273b1c9b 修改版本为v0.4.1 2022-01-17 10:53:28 +08:00
刘祥超
bc1eb994f9 Update components.js 2022-01-16 20:04:11 +08:00
刘祥超
136f0fd4bd 源站支持客户端证书 2022-01-16 19:51:26 +08:00
刘祥超
021dc13ce9 CAPTCHA增加多个选项 2022-01-16 16:54:20 +08:00
刘祥超
925b71489d Update components.js 2022-01-14 10:46:02 +08:00
刘祥超
580ce9f8f5 可以在IP名单、访问日志中跳到对应的WAF规则集 2022-01-14 10:45:58 +08:00
刘祥超
2b3d8c062d 优化界面 2022-01-13 15:05:57 +08:00
刘祥超
41858e091a Update components.js 2022-01-13 10:03:54 +08:00
刘祥超
5b7eaf08ae 实现open file cache 2022-01-12 21:09:11 +08:00
刘祥超
7362722adb 优化代码 2022-01-11 16:02:27 +08:00
刘祥超
8198ea8819 可以使用集群搜索WAF策略、缓存策略 2022-01-11 15:46:47 +08:00
刘祥超
cb615f4cbc Update components.js 2022-01-11 15:28:50 +08:00
刘祥超
6623fd8362 优化交互 2022-01-11 15:26:43 +08:00
刘祥超
7f8be85116 运行日志可以使用集群、节点筛选 2022-01-11 14:59:19 +08:00
刘祥超
c61381441c 访问日志可以使用集群和节点搜索 2022-01-11 12:04:03 +08:00
刘祥超
b3cecdfea2 实现自动SYN Flood防护 2022-01-10 19:54:29 +08:00
刘祥超
66f582df58 WAF规则增加备注信息/其他界面优化 2022-01-10 10:28:23 +08:00
刘祥超
7f6f7e11ce 生成components.js 2022-01-09 20:13:18 +08:00
刘祥超
0bdda313da WAF策略增加是否使用本地防火墙设置 2022-01-09 17:05:51 +08:00
刘祥超
d5e851cff7 优化界面 2022-01-09 10:47:03 +08:00
刘祥超
92f1ec13f9 优化界面 2022-01-09 10:43:37 +08:00
刘祥超
5376006754 优化文字提示 2022-01-08 16:49:46 +08:00
刘祥超
361979411e IP名单增加未读数、按未读筛选等操作 2022-01-08 16:48:45 +08:00
刘祥超
3981308083 优化代码 2022-01-06 11:13:36 +08:00
刘祥超
facd5e14cc 改进文字 2022-01-05 20:13:22 +08:00
刘祥超
ecce92c528 Update components.js 2022-01-05 15:54:22 +08:00
刘祥超
7696940989 用户列表可以使用待审核、关键词搜索 2022-01-05 11:12:28 +08:00
刘祥超
941ff46c2c 实现用户注册/审核功能 2022-01-05 10:45:28 +08:00
刘祥超
94036073de 优化请求脚本配置交互 2022-01-03 21:48:48 +08:00
刘祥超
13216f481c 尝试自动在firewalld中开放端口 2022-01-03 16:28:27 +08:00
刘祥超
eb35df8720 改进服务访问日志、设置页在手机下的显示 2022-01-03 14:50:11 +08:00
刘祥超
bf500fe1a4 增加格式化数字函数 2022-01-03 12:04:09 +08:00
刘祥超
c173e86e62 创建服务时默认选中统计 2022-01-03 11:27:01 +08:00
刘祥超
d4cb148272 WAF动作中各个超时/有效秒数最大值从10位改成9位 2022-01-03 11:17:33 +08:00
刘祥超
ffc3f8544e 节点运行日志增加标签筛选 2022-01-03 11:08:59 +08:00
刘祥超
b326bfe63a 优化文字 2021-12-31 19:45:14 +08:00
刘祥超
12f3f47ef9 实现初版边缘脚本 2021-12-31 15:20:59 +08:00
刘祥超
45734747c1 修改版本为0.4.0 2021-12-31 15:19:44 +08:00
刘祥超
37933d814c 修改版本号0.3.8 2021-12-31 11:38:55 +08:00
刘祥超
5b26287264 修复路由规则中不能设置响应Header的Bug 2021-12-28 20:12:29 +08:00
刘祥超
bac20b1d1f 自动检查更新被取消时,同时重置已发现的最新版本信息 2021-12-22 10:02:06 +08:00
刘祥超
904c641992 删除不必要的文件 2021-12-22 10:01:35 +08:00
刘祥超
36004bfd94 优化代码 2021-12-21 15:41:43 +08:00
刘祥超
0fcba7e90c 增加自动检查系统更新设置 2021-12-21 15:18:11 +08:00
刘祥超
2e9182933e 修改版本号为0.4.0 2021-12-20 20:01:55 +08:00
刘祥超
e3674fa2c1 优化文字 2021-12-20 09:35:36 +08:00
刘祥超
a14cbe1319 访问日志限制字段 2021-12-20 09:35:25 +08:00
刘祥超
c03c35de88 访问日志限制字段 2021-12-19 20:39:18 +08:00
刘祥超
dc6c649af8 优化文字提示等 2021-12-19 18:56:09 +08:00
刘祥超
b0d2bdb0ba 修复HSTS无法设置有效期的Bug 2021-12-18 17:23:55 +08:00
刘祥超
9239dd9a8b 调整单次通知更新任务的数量为500(原来200) 2021-12-17 14:25:40 +08:00
刘祥超
07a368a0bd 修改相关域名、文字等 2021-12-17 14:17:48 +08:00
刘祥超
b8d6d1c249 访问日志中缓存状态增加STALE 2021-12-17 11:55:12 +08:00
刘祥超
0f1d6a1ad2 实现stale cache配置 2021-12-16 17:27:09 +08:00
刘祥超
37c6928ffc 节点IP显示原始IP(如果已经切换到备用IP的话) 2021-12-16 15:18:21 +08:00
刘祥超
7478b6dbe0 优化代码 2021-12-15 20:46:42 +08:00
刘祥超
e3cd6e1441 增加在线检查最新版本功能 2021-12-15 20:13:10 +08:00
刘祥超
8081d968b6 Update components.js 2021-12-15 09:56:18 +08:00
刘祥超
a226eee6ef HTTP Header:实现请求方法、域名、状态码等限制,实现内容替换功能 2021-12-14 21:26:32 +08:00
刘祥超
8b5a21e593 访问日志查询过慢的时候,提示建议增加新的日志节点 2021-12-14 15:50:21 +08:00
刘祥超
2c71f6c6be 实现访问日志队列 2021-12-14 12:45:09 +08:00
刘祥超
1a50b01edf 优化代码 2021-12-13 10:53:49 +08:00
刘祥超
05f08eeb4c 优化坐标轴单位 2021-12-12 21:13:55 +08:00
刘祥超
fdc3ebb5c5 WAF添加规则:调整界面/增加正则表达式测试功能 2021-12-12 20:56:25 +08:00
刘祥超
8f06bccd48 WAF策略:可以修改分组代号/导入时可以根据名称合并/导出时可以导出停用的分组 2021-12-12 20:24:15 +08:00
刘祥超
16b4eb67d4 Update components.js 2021-12-12 17:14:46 +08:00
刘祥超
ffa545cb41 服务分组可以设置请求限制 2021-12-12 17:07:16 +08:00
刘祥超
f67454d51c 路由规则增加专属域名设置 2021-12-12 16:38:52 +08:00
刘祥超
8ae54c56db 增加排除扩展名条件 2021-12-12 16:14:56 +08:00
刘祥超
9a17adcc6f 请求条件增加不区分大小写选项 2021-12-12 16:11:25 +08:00
刘祥超
4dd6903025 优化界面 2021-12-12 11:58:16 +08:00
刘祥超
085770d0ad 实现请求连接数等限制/容量组件增加EB支持 2021-12-12 11:46:09 +08:00
刘祥超
fbaba7c37d 修复公共黑名单/白名单无法搜索的Bug 2021-12-10 11:12:49 +08:00
刘祥超
d5cea208d2 支持设置单节点最大线程数、单节点TCP最大连接数 2021-12-09 18:49:35 +08:00
刘祥超
36397adca4 修复服务统计图表颜色显示问题/Expires设置增加提示文字 2021-12-08 21:40:01 +08:00
刘祥超
4971e25d44 WAF看板最新拦截记录增加区域信息 2021-12-08 20:28:26 +08:00
刘祥超
150357441d 修复域名为空时点击审核页面为空的Bug 2021-12-08 20:20:10 +08:00
刘祥超
c4ee663285 重新生成components.js 2021-12-08 19:13:54 +08:00
刘祥超
8c95b4a9b9 多处访问日志增加单页显示条数选择 2021-12-08 19:13:34 +08:00
刘祥超
32ba919851 增加部分访问日志条数10->20 2021-12-08 17:49:30 +08:00
刘祥超
eb37345e85 可以在缓存条件里设置Expires Header 2021-12-08 17:41:12 +08:00
刘祥超
681e454917 修复编译时components.js可能没有更新的Bug 2021-12-08 10:03:27 +08:00
刘祥超
7c7b82dee4 优化地图标签 2021-12-08 09:37:46 +08:00
刘祥超
2ae47af8f0 增加批量增加节点IP接口 2021-12-07 18:22:46 +08:00
刘祥超
b72d91d0d4 访问日志实现记录和显示requestBody 2021-12-07 15:03:48 +08:00
刘祥超
56010e7203 缓存默认支持所有请求方法 2021-12-07 10:47:46 +08:00
刘祥超
f658698f7b 缓存支持请求方法设置 2021-12-07 10:45:49 +08:00
刘祥超
b708b9c6df 将缓存默认key改为${scheme}://${host}${requestPath}${isArgs}${args} 2021-12-07 10:04:50 +08:00
刘祥超
c2908e17fa SSH认证支持sudo 2021-12-06 19:24:30 +08:00
刘祥超
302daab824 服务看板增加区域地图 2021-12-06 09:16:23 +08:00
刘祥超
ec49f238d6 优化界面 2021-12-06 08:55:47 +08:00
刘祥超
3e43a5d866 上传components.js/优化地图样式 2021-12-05 20:59:07 +08:00
刘祥超
a99d5e68e9 商业版WAF看板增加地图 2021-12-05 19:38:14 +08:00
刘祥超
28514276ec 商业版首页增加地图/调低各个图表的高度,以便同时可以显示更多的图表 2021-12-05 18:59:20 +08:00
刘祥超
b611427c17 创建新服务时默认开启配置可以选择统计 2021-12-03 14:55:14 +08:00
刘祥超
ce7a4ead04 首页看板显示未审核的服务数、本周流量、昨日流量 2021-12-03 14:54:15 +08:00
刘祥超
5fe15a85fd 优化IPBox交互/优化TOA文字提示 2021-12-03 11:00:20 +08:00
刘祥超
ae412909f6 优化服务设置界面顶部菜单 2021-12-02 17:41:51 +08:00
刘祥超
c6ed579797 IPBox把IP加入黑名单可以选择过期时间/可以从已经添加的名单中删除/已经添加的名单中显示过期时间 2021-12-02 17:11:44 +08:00
刘祥超
b2a525268e WAF规则集中增加是否忽略局域网IP选项 2021-12-02 16:09:15 +08:00
刘祥超
eb78b4881c 多个提示页面增加请求ID 2021-12-02 14:45:51 +08:00
刘祥超
4ce6e5a9f6 访问日志弹窗中加入请求ID/优化Header添加/修改文字提示 2021-12-02 11:49:36 +08:00
刘祥超
15d7e75555 优化URL跳转文字提示 2021-12-02 10:39:22 +08:00
刘祥超
6453cc6ccc 缓存配置增加是否支持Cache-Control: max-age=... 2021-12-02 10:18:22 +08:00
刘祥超
d882a2eb63 缓存配置增加Age Header配置 2021-12-02 09:54:31 +08:00
刘祥超
065ac4aa25 增加generate.sh脚本用来生成文件 2021-12-02 09:46:46 +08:00
刘祥超
dea54fc55e 增加是否记录499选项 2021-12-01 21:13:15 +08:00
刘祥超
8f425bd9c7 当用户提交待审核域名时,给管理员发送消息 2021-12-01 17:19:50 +08:00
刘祥超
9d909d73b8 审核中服务增加提交审核时间/已通过域名标绿 2021-12-01 17:06:05 +08:00
刘祥超
b417d50a28 优化节点日志:可以批量设置服务错误日志为已修复等 2021-11-30 16:43:44 +08:00
刘祥超
aa93a2f702 优化编译脚本 2021-11-30 11:05:58 +08:00
刘祥超
ba7125e773 优化文字 2021-11-30 11:05:24 +08:00
刘祥超
46a7eaa4bb 商业版认证增加申请页面 2021-11-30 10:02:31 +08:00
刘祥超
887439a6fe 优化代码 2021-11-29 20:35:47 +08:00
刘祥超
0e2b07d06d 优化提示文字 2021-11-29 16:41:32 +08:00
刘祥超
b7d4bde11b 修改部分菜单名 2021-11-29 12:00:23 +08:00
刘祥超
9707360948 完善套餐 2021-11-28 20:11:48 +08:00
刘祥超
103a8eb092 修改版本号为0.3.7 2021-11-28 14:28:53 +08:00
刘祥超
dcba4f9376 节点同步不在图标上提示IP名单相关更新 2021-11-27 17:06:36 +08:00
刘祥超
12aaa6fcb1 更新生成的components.js 2021-11-27 17:06:03 +08:00
刘祥超
d8393481a4 修改域名变更时是否需要审核的初始状态 2021-11-25 12:10:23 +08:00
刘祥超
70d3202a2c 服务增加是否合并URL中的多余分隔符选项 2021-11-24 14:49:42 +08:00
刘祥超
c7f1bbc03d 版本号改为0.3.6 2021-11-24 14:03:56 +08:00
刘祥超
61a55cb3f4 优化命名 2021-11-24 11:58:01 +08:00
刘祥超
6a484af775 将版本修改为0.3.5.2 2021-11-24 10:29:59 +08:00
刘祥超
3074d41cf2 改进源站专属域名的文字提示和交互 2021-11-22 18:46:08 +08:00
525 changed files with 9795 additions and 4952 deletions

View File

@@ -28,5 +28,4 @@
有什么问题和建议都可以加入QQ群 `659832182`
## 感谢
* 感谢[JetBrains公司](https://www.jetbrains.com/)提供免费的IDE开发Licence。
* 感谢[Gitee](https://gitee.com/)提供国内源代码托管平台

View File

@@ -20,6 +20,18 @@ function build() {
TAG="community"
fi
# checking environment
echo "checking required commands ..."
commands=("zip" "unzip" "go" "find" "sed")
for cmd in "${commands[@]}"; do
if [ `which ${cmd}` ]; then
echo "checking ${cmd}: ok"
else
echo "checking ${cmd}: not found"
return
fi
done
VERSION=$(lookup-version $ROOT/../internal/const/const.go)
ZIP="${NAME}-${OS}-${ARCH}-${TAG}-v${VERSION}.zip"
@@ -38,6 +50,10 @@ function build() {
echo "=============================="
cd -
# generate files
echo "generating files ..."
go run -tags $TAG $ROOT/../cmd/edge-admin/main.go generate
# create dir & copy files
echo "copying ..."
if [ ! -d $DIST ]; then
@@ -51,6 +67,19 @@ function build() {
rm -f $DIST/web/tmp/*
cp $ROOT/configs/server.template.yaml $DIST/configs/
# change _plus.[ext] to .[ext]
if [ "${TAG}" = "plus" ]; then
echo "converting filenames ..."
exts=("html" "js" "css")
for ext in "${exts[@]}"; do
pattern="*_plus."${ext}
find $DIST/web/views -type f -name $pattern | \
while read filename; do
mv ${filename} "${filename/_plus."${ext}"/."${ext}"}"
done
done
fi
EDGE_API_ZIP_FILE=$ROOT"/../../EdgeAPI/dist/edge-api-${OS}-${ARCH}-${TAG}-v${APINodeVersion}.zip"
cp $EDGE_API_ZIP_FILE $DIST/
cd $DIST/
@@ -58,10 +87,6 @@ function build() {
rm -f $(basename $EDGE_API_ZIP_FILE)
cd -
# generate files
echo "generating files ..."
go run -tags $TAG $ROOT/../cmd/edge-admin/main.go generate
# build
echo "building "${NAME}" ..."
env GOOS=$OS GOARCH=$ARCH go build -tags $TAG -ldflags="-s -w" -o $DIST/bin/${NAME} $ROOT/../cmd/edge-admin/main.go

3
build/generate.sh Executable file
View File

@@ -0,0 +1,3 @@
#!/usr/bin/env bash
go run -tags=community ../cmd/edge-admin/main.go generate

View File

@@ -9,6 +9,7 @@ import (
"github.com/TeaOSLab/EdgeAdmin/internal/nodes"
_ "github.com/TeaOSLab/EdgeAdmin/internal/web"
_ "github.com/iwind/TeaGo/bootstrap"
"github.com/iwind/TeaGo/maps"
"github.com/iwind/gosock/pkg/gosock"
)
@@ -64,12 +65,17 @@ func main() {
fmt.Println("[ERROR]the service not started yet, you should start the service first")
return
}
_, err := sock.Send(&gosock.Command{Code: "demo"})
reply, err := sock.Send(&gosock.Command{Code: "demo"})
if err != nil {
fmt.Println("[ERROR]change demo mode failed: " + err.Error())
return
}
fmt.Println("change demo mode successfully")
var isDemo = maps.NewMap(reply.Params).GetBool("isDemo")
if isDemo {
fmt.Println("change demo mode to: on")
} else {
fmt.Println("change demo mode to: off")
}
})
app.On("generate", func() {
err := gen.Generate()

Binary file not shown.

Before

Width:  |  Height:  |  Size: 203 KiB

After

Width:  |  Height:  |  Size: 225 KiB

12
go.mod
View File

@@ -8,9 +8,8 @@ require (
github.com/TeaOSLab/EdgeCommon v0.0.0-00010101000000-000000000000
github.com/cespare/xxhash v1.1.0
github.com/go-sql-driver/mysql v1.5.0
github.com/go-yaml/yaml v2.1.0+incompatible
github.com/google/go-cmp v0.5.6 // indirect
github.com/iwind/TeaGo v0.0.0-20211026123858-7de7a21cad24
github.com/iwind/TeaGo v0.0.0-20220304043459-0dd944a5b475
github.com/iwind/gosock v0.0.0-20211103081026-ee4652210ca4
github.com/json-iterator/go v1.1.12 // indirect
github.com/miekg/dns v1.1.35
@@ -18,9 +17,8 @@ require (
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
github.com/tealeg/xlsx/v3 v3.2.3
github.com/xlzd/gotp v0.0.0-20181030022105-c8557ba2c119
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
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8
google.golang.org/grpc v1.45.0
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
)

88
go.sum
View File

@@ -1,10 +1,12 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/DataDog/sketches-go v0.0.0-20190923095040-43f19ad77ff7/go.mod h1:Q5DbzQ+3AkgGwymQO7aZFNP7ns2lZKGtvRBzRXfdi60=
github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
@@ -14,6 +16,10 @@ github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -21,18 +27,18 @@ github.com/dgryski/go-rendezvous v0.0.0-20200624174652-8d2f3be8b2d9/go.mod h1:cu
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/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/frankban/quicktest v1.5.0 h1:Tb4jWdSpdjKzTUicPnY61PZxKbDoGa7ABbrReT3gQVY=
github.com/frankban/quicktest v1.5.0/go.mod h1:jaStnuzAqU1AJdCO0l53JDCJrVDKcS03DbaAcR7Ks/o=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-redis/redis/v8 v8.0.0-beta.7/go.mod h1:FGJAWDWFht1sQ4qxyJHZZbVyvnVcKQN0E3u5/5lRz+g=
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-yaml/yaml v2.1.0+incompatible h1:RYi2hDdss1u4YE7GwixGzWwVo47T8UQwnTLB6vQiq+o=
github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
@@ -45,6 +51,7 @@ github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:W
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/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.4.3/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=
@@ -60,17 +67,17 @@ github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/iwind/TeaGo v0.0.0-20210628135026-38575a4ab060/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/TeaGo v0.0.0-20211026123858-7de7a21cad24 h1:1cGulkD2SNJJRok5OKwyhP/Ddm+PgSWKOupn0cR36/A=
github.com/iwind/TeaGo v0.0.0-20211026123858-7de7a21cad24/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/iwind/TeaGo v0.0.0-20220304042834-d8b5103e9027 h1:4knh28YgldmEtu8QG8pgQhUaI3i//qRjOdEyj9OVqXA=
github.com/iwind/TeaGo v0.0.0-20220304042834-d8b5103e9027/go.mod h1:IyKPaIhjbjsTctPguMWJZDHuBHu+XiYcV5ZEDxQpq94=
github.com/iwind/TeaGo v0.0.0-20220304043459-0dd944a5b475 h1:EseyfFaQOjWanGiby9KMw7PjDBMg/95tLDgIw/ns0Cw=
github.com/iwind/TeaGo v0.0.0-20220304043459-0dd944a5b475/go.mod h1:HRHK0zoC/og3c9/hKosD9yYVMTnnzm3PgXUdhRYHaLc=
github.com/iwind/gosock v0.0.0-20211103081026-ee4652210ca4 h1:VWGsCqTzObdlbf7UUE3oceIpcEKi4C/YBUszQXk118A=
github.com/iwind/gosock v0.0.0-20211103081026-ee4652210ca4/go.mod h1:H5Q7SXwbx3a97ecJkaS2sD77gspzE7HFUafBO0peEyA=
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.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
@@ -81,11 +88,9 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/miekg/dns v1.1.35 h1:oTfOaDH+mZkdcgdIjH6yBajRGtIwcwcaR+rt23ZSrJs=
github.com/miekg/dns v1.1.35/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
@@ -118,17 +123,19 @@ github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasO
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/tealeg/xlsx/v3 v3.2.3 h1:MXnVh+9Y8cUglowItTy2HL3Kv6z+q/0aNjeKuTsVqZQ=
github.com/tealeg/xlsx/v3 v3.2.3/go.mod h1:0hGmAEoZ48SS1ZAE6eqZJkJVXgOMY+8a33vjXa8S8HA=
github.com/xlzd/gotp v0.0.0-20181030022105-c8557ba2c119 h1:YyPWX3jLOtYKulBR6AScGIs74lLrJcgeKRwcbAuQOG4=
github.com/xlzd/gotp v0.0.0-20181030022105-c8557ba2c119/go.mod h1:/nuTSlK+okRfR/vnIPqR89fFKonnWPiZymN5ydRJkX8=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
go.opentelemetry.io/otel v0.7.0/go.mod h1:aZMyHG5TqDOXEgH2tyLiXSUKly1jT3yqE9PmrzIeCdo=
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20200513190911-00229845015e/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw=
@@ -137,27 +144,28 @@ golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+o
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
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.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=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/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-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210614182718-04defd469f4e h1:XpT3nA5TvE525Ne3hInMh6+GETgn27Zfm9dxsThnX2Q=
golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f h1:oA4XRj0qtSt8Yo1Zms0CUlsT3KG69V2UGQWPBxujDmc=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -175,30 +183,29 @@ golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
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-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/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9 h1:nhht2DYV/Sn3qOayu8lM+cU1ii9sTLUeBQwQQfUHtrs=
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8 h1:OH54vjqzRWmbJ62fjuhxy7AxFFgoHN0/DPc/UrL8cAs=
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.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/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.1.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/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
@@ -208,17 +215,23 @@ google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20191009194640-548a555dbc03/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
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/genproto v0.0.0-20220303160752-862486edd9cc h1:fb/ViRpv3ln/LvbqZtTpoOd1YQDNH12gaGZreoSFovE=
google.golang.org/genproto v0.0.0-20220303160752-862486edd9cc/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
google.golang.org/genproto v0.0.0-20220317150908-0efb43f6373e h1:fNKDNuUyC4WH+inqDMpfXDdfvwfYILbsX+oskGZ8hxg=
google.golang.org/genproto v0.0.0-20220317150908-0efb43f6373e/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.27.0/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/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/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.44.0 h1:weqSxi/TMs1SqFRMHCtBgXRs8k3X39QIDEZ0pRcttUg=
google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
google.golang.org/grpc v1.45.0 h1:NEpgUqV3Z+ZjkqMsxMg11IaDrXY4RY6CQukSGK0uI1M=
google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ=
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=
@@ -229,8 +242,9 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
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=
google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
@@ -239,13 +253,15 @@ gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMy
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
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/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=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

View File

@@ -11,10 +11,6 @@ import (
var sharedAdminUIConfig *systemconfigs.AdminUIConfig = nil
const (
AdminUISettingName = "adminUIConfig"
)
func LoadAdminUIConfig() (*systemconfigs.AdminUIConfig, error) {
locker.Lock()
defer locker.Unlock()
@@ -41,7 +37,7 @@ func UpdateAdminUIConfig(uiConfig *systemconfigs.AdminUIConfig) error {
return err
}
_, err = rpcClient.SysSettingRPC().UpdateSysSetting(rpcClient.Context(0), &pb.UpdateSysSettingRequest{
Code: AdminUISettingName,
Code: systemconfigs.SettingCodeAdminUIConfig,
ValueJSON: valueJSON,
})
if err != nil {
@@ -52,7 +48,7 @@ func UpdateAdminUIConfig(uiConfig *systemconfigs.AdminUIConfig) error {
return nil
}
// 是否显示财务信息
// ShowFinance 是否显示财务信息
func ShowFinance() bool {
config, _ := LoadAdminUIConfig()
if config != nil && !config.ShowFinance {
@@ -70,7 +66,7 @@ func loadAdminUIConfig() (*systemconfigs.AdminUIConfig, error) {
return nil, err
}
resp, err := rpcClient.SysSettingRPC().ReadSysSetting(rpcClient.Context(0), &pb.ReadSysSettingRequest{
Code: AdminUISettingName,
Code: systemconfigs.SettingCodeAdminUIConfig,
})
if err != nil {
return nil, err
@@ -98,5 +94,6 @@ func defaultAdminUIConfig() *systemconfigs.AdminUIConfig {
ShowOpenSourceInfo: true,
ShowVersion: true,
ShowFinance: true,
DefaultPageSize: 10,
}
}

View File

@@ -2,8 +2,8 @@ package configs
import (
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
"github.com/go-yaml/yaml"
"github.com/iwind/TeaGo/Tea"
"gopkg.in/yaml.v3"
"io/ioutil"
"os"
"path/filepath"

View File

@@ -11,7 +11,9 @@ import (
var plusConfigFile = "plus.cache.json"
type PlusConfig struct {
IsPlus bool `json:"isPlus"`
IsPlus bool `json:"isPlus"`
Components []string `json:"components"`
DayTo string `json:"dayTo"`
}
func ReadPlusConfig() *PlusConfig {

View File

@@ -1,9 +1,9 @@
package teaconst
const (
Version = "0.3.5.1"
Version = "0.4.6"
APINodeVersion = "0.3.5"
APINodeVersion = "0.4.6"
ProductName = "Edge Admin"
ProcessName = "edge-admin"
@@ -18,4 +18,5 @@ const (
CookieSID = "edgesid"
SystemdServiceName = "edge-admin"
UpdatesURL = "https://goedge.cn/api/boot/versions?os=${os}&arch=${arch}"
)

View File

@@ -1,6 +1,7 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
//go:build community
// +build community
package teaconst
// IsPlus 是否为企业版
var IsPlus = false

View File

@@ -4,9 +4,10 @@ package teaconst
var (
IsRecoverMode = false
)
var (
IsDemoMode = false
ErrorDemoOperation = "DEMO模式下无法进行创建、修改、删除等操作"
NewVersionCode = "" // 有新的版本
NewVersionDownloadURL = "" // 新版本下载地址
)

View File

@@ -0,0 +1,12 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package goman
import "time"
type Instance struct {
Id uint64
CreatedTime time.Time
File string
Line int
}

81
internal/goman/lib.go Normal file
View File

@@ -0,0 +1,81 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package goman
import (
"runtime"
"sync"
"time"
)
var locker = &sync.Mutex{}
var instanceMap = map[uint64]*Instance{} // id => *Instance
var instanceId = uint64(0)
// New 新创建goroutine
func New(f func()) {
_, file, line, _ := runtime.Caller(1)
go func() {
locker.Lock()
instanceId++
var instance = &Instance{
Id: instanceId,
CreatedTime: time.Now(),
}
instance.File = file
instance.Line = line
instanceMap[instanceId] = instance
locker.Unlock()
// run function
f()
locker.Lock()
delete(instanceMap, instanceId)
locker.Unlock()
}()
}
// NewWithArgs 创建带有参数的goroutine
func NewWithArgs(f func(args ...interface{}), args ...interface{}) {
_, file, line, _ := runtime.Caller(1)
go func() {
locker.Lock()
instanceId++
var instance = &Instance{
Id: instanceId,
CreatedTime: time.Now(),
}
instance.File = file
instance.Line = line
instanceMap[instanceId] = instance
locker.Unlock()
// run function
f(args...)
locker.Lock()
delete(instanceMap, instanceId)
locker.Unlock()
}()
}
// List 列出所有正在运行goroutine
func List() []*Instance {
locker.Lock()
defer locker.Unlock()
var result = []*Instance{}
for _, instance := range instanceMap {
result = append(result, instance)
}
return result
}

View File

@@ -0,0 +1,28 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package goman
import (
"testing"
"time"
)
func TestNew(t *testing.T) {
New(func() {
t.Log("Hello")
t.Log(List())
})
time.Sleep(1 * time.Second)
t.Log(List())
time.Sleep(1 * time.Second)
}
func TestNewWithArgs(t *testing.T) {
NewWithArgs(func(args ...interface{}) {
t.Log(args[0], args[1])
}, 1, 2)
time.Sleep(1 * time.Second)
}

View File

@@ -325,7 +325,9 @@ func (this *AdminNode) listenSock() error {
_ = cmd.ReplyOk()
case "demo":
teaconst.IsDemoMode = !teaconst.IsDemoMode
_ = cmd.ReplyOk()
_ = cmd.Reply(&gosock.Command{
Params: map[string]interface{}{"isDemo": teaconst.IsDemoMode},
})
case "info":
exePath, _ := os.Executable()
_ = cmd.Reply(&gosock.Command{

View File

@@ -16,6 +16,8 @@ import (
"google.golang.org/grpc"
"google.golang.org/grpc/connectivity"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/credentials/insecure"
"google.golang.org/grpc/encoding/gzip"
"google.golang.org/grpc/metadata"
"net/url"
"sync"
@@ -161,6 +163,10 @@ func (this *RPCClient) APINodeRPC() pb.APINodeServiceClient {
return pb.NewAPINodeServiceClient(this.pickConn())
}
func (this *RPCClient) APIMethodStatRPC() pb.APIMethodStatServiceClient {
return pb.NewAPIMethodStatServiceClient(this.pickConn())
}
func (this *RPCClient) UserNodeRPC() pb.UserNodeServiceClient {
return pb.NewUserNodeServiceClient(this.pickConn())
}
@@ -382,6 +388,10 @@ func (this *RPCClient) UserBillRPC() pb.UserBillServiceClient {
return pb.NewUserBillServiceClient(this.pickConn())
}
func (this *RPCClient) ServerBillRPC() pb.ServerBillServiceClient {
return pb.NewServerBillServiceClient(this.pickConn())
}
func (this *RPCClient) UserAccountRPC() pb.UserAccountServiceClient {
return pb.NewUserAccountServiceClient(this.pickConn())
}
@@ -552,12 +562,14 @@ func (this *RPCClient) init() error {
return errors.New("parse endpoint failed: " + err.Error())
}
var conn *grpc.ClientConn
var callOptions = grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(128*1024*1024),
grpc.UseCompressor(gzip.Name))
if u.Scheme == "http" {
conn, err = grpc.Dial(u.Host, grpc.WithInsecure(), grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(128*1024*1024)))
conn, err = grpc.Dial(u.Host, grpc.WithTransportCredentials(insecure.NewCredentials()), callOptions)
} else if u.Scheme == "https" {
conn, err = grpc.Dial(u.Host, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{
InsecureSkipVerify: true,
})), grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(128*1024*1024)))
})), callOptions)
} else {
return errors.New("parse endpoint failed: invalid scheme '" + u.Scheme + "'")
}

View File

@@ -18,7 +18,7 @@ func TestRPCClient_NodeRPC(t *testing.T) {
if err != nil {
t.Fatal(err)
}
rpc, err := NewRPCClient(config)
rpc, err := NewRPCClient(config, true)
if err != nil {
t.Fatal(err)
}
@@ -41,7 +41,7 @@ func TestRPC_Dial_HTTP(t *testing.T) {
},
NodeId: "a7e55782dab39bce0901058a1e14a0e6",
Secret: "lvyPobI3BszkJopz5nPTocOs0OLkEJ7y",
})
}, true)
if err != nil {
t.Fatal(err)
}
@@ -62,7 +62,7 @@ func TestRPC_Dial_HTTP_2(t *testing.T) {
},
NodeId: "a7e55782dab39bce0901058a1e14a0e6",
Secret: "lvyPobI3BszkJopz5nPTocOs0OLkEJ7y",
})
}, true)
if err != nil {
t.Fatal(err)
}
@@ -83,7 +83,7 @@ func TestRPC_Dial_HTTPS(t *testing.T) {
},
NodeId: "a7e55782dab39bce0901058a1e14a0e6",
Secret: "lvyPobI3BszkJopz5nPTocOs0OLkEJ7y",
})
}, true)
if err != nil {
t.Fatal(err)
}

View File

@@ -0,0 +1,131 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package tasks
import (
"encoding/json"
"errors"
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
"github.com/TeaOSLab/EdgeAdmin/internal/events"
"github.com/TeaOSLab/EdgeAdmin/internal/goman"
"github.com/TeaOSLab/EdgeAdmin/internal/rpc"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/systemconfigs"
"github.com/iwind/TeaGo/logs"
"github.com/iwind/TeaGo/maps"
stringutil "github.com/iwind/TeaGo/utils/string"
"io/ioutil"
"net/http"
"runtime"
"strings"
"time"
)
func init() {
events.On(events.EventStart, func() {
var task = NewCheckUpdatesTask()
goman.New(func() {
task.Start()
})
})
}
type CheckUpdatesTask struct {
ticker *time.Ticker
}
func NewCheckUpdatesTask() *CheckUpdatesTask {
return &CheckUpdatesTask{}
}
func (this *CheckUpdatesTask) Start() {
this.ticker = time.NewTicker(12 * time.Hour)
for range this.ticker.C {
err := this.Loop()
if err != nil {
logs.Println("[TASK][CHECK_UPDATES_TASK]" + err.Error())
}
}
}
func (this *CheckUpdatesTask) Loop() error {
// 检查是否开启
rpcClient, err := rpc.SharedRPC()
if err != nil {
return err
}
valueResp, err := rpcClient.SysSettingRPC().ReadSysSetting(rpcClient.Context(0), &pb.ReadSysSettingRequest{Code: systemconfigs.SettingCodeCheckUpdates})
if err != nil {
return err
}
var valueJSON = valueResp.ValueJSON
var config = &systemconfigs.CheckUpdatesConfig{AutoCheck: false}
if len(valueJSON) > 0 {
err = json.Unmarshal(valueJSON, config)
if err != nil {
return errors.New("decode config failed: " + err.Error())
}
if !config.AutoCheck {
return nil
}
} else {
return nil
}
// 开始检查
type Response struct {
Code int `json:"code"`
Message string `json:"message"`
Data interface{} `json:"data"`
}
// 目前支持Linux
if runtime.GOOS != "linux" {
return nil
}
var apiURL = teaconst.UpdatesURL
apiURL = strings.ReplaceAll(apiURL, "${os}", runtime.GOOS)
apiURL = strings.ReplaceAll(apiURL, "${arch}", runtime.GOARCH)
resp, err := http.Get(apiURL)
if err != nil {
return errors.New("read api failed: " + err.Error())
}
defer func() {
_ = resp.Body.Close()
}()
data, err := ioutil.ReadAll(resp.Body)
if err != nil {
return errors.New("read api failed: " + err.Error())
}
var apiResponse = &Response{}
err = json.Unmarshal(data, apiResponse)
if err != nil {
return errors.New("decode version data failed: " + err.Error())
}
if apiResponse.Code != 200 {
return errors.New("invalid response: " + apiResponse.Message)
}
var m = maps.NewMap(apiResponse.Data)
var dlHost = m.GetString("host")
var versions = m.GetSlice("versions")
if len(versions) > 0 {
for _, version := range versions {
var vMap = maps.NewMap(version)
if vMap.GetString("code") == "admin" {
var latestVersion = vMap.GetString("version")
if stringutil.VersionCompare(teaconst.Version, latestVersion) < 0 {
teaconst.NewVersionCode = latestVersion
teaconst.NewVersionDownloadURL = dlHost + vMap.GetString("url")
return nil
}
}
}
}
return nil
}

View File

@@ -6,6 +6,7 @@ import (
"github.com/TeaOSLab/EdgeAdmin/internal/configs"
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
"github.com/TeaOSLab/EdgeAdmin/internal/events"
"github.com/TeaOSLab/EdgeAdmin/internal/goman"
"github.com/TeaOSLab/EdgeAdmin/internal/rpc"
"github.com/TeaOSLab/EdgeAdmin/internal/setup"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
@@ -23,7 +24,9 @@ import (
func init() {
events.On(events.EventStart, func() {
task := NewSyncAPINodesTask()
go task.Start()
goman.New(func() {
task.Start()
})
})
}

View File

@@ -3,6 +3,7 @@ package tasks
import (
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
"github.com/TeaOSLab/EdgeAdmin/internal/events"
"github.com/TeaOSLab/EdgeAdmin/internal/goman"
"github.com/TeaOSLab/EdgeAdmin/internal/rpc"
"github.com/TeaOSLab/EdgeAdmin/internal/setup"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/nodes/nodeutils"
@@ -17,7 +18,9 @@ import (
func init() {
events.On(events.EventStart, func() {
task := NewSyncClusterTask()
go task.Start()
goman.New(func() {
task.Start()
})
})
}
@@ -51,7 +54,7 @@ func (this *SyncClusterTask) loop() error {
}
ctx := rpcClient.Context(0)
tasksResp, err := rpcClient.NodeTaskRPC().FindNotifyingNodeTasks(ctx, &pb.FindNotifyingNodeTasksRequest{Size: 100})
tasksResp, err := rpcClient.NodeTaskRPC().FindNotifyingNodeTasks(ctx, &pb.FindNotifyingNodeTasksRequest{Size: 500})
if err != nil {
return err
}

View File

@@ -1,14 +1,17 @@
package utils
import (
"bytes"
"encoding/binary"
"errors"
"github.com/iwind/TeaGo/types"
"math/big"
"net"
"regexp"
"strings"
)
// 将IP转换为整型
// IP2Long 将IP转换为整型
func IP2Long(ip string) uint64 {
s := net.ParseIP(ip)
if len(s) != 16 {
@@ -23,7 +26,7 @@ func IP2Long(ip string) uint64 {
return uint64(binary.BigEndian.Uint32(s.To4()))
}
// 判断是否为IPv4
// IsIPv4 判断是否为IPv4
func IsIPv4(ip string) bool {
if !regexp.MustCompile(`^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$`).MatchString(ip) {
return false
@@ -34,10 +37,100 @@ func IsIPv4(ip string) bool {
return true
}
// 判断是否为IPv6
// IsIPv6 判断是否为IPv6
func IsIPv6(ip string) bool {
if !strings.Contains(ip, ":") {
return false
}
return len(net.ParseIP(ip)) == net.IPv6len
}
// ExtractIP 分解IP
// 只支持D段掩码的CIDR
// 最多只记录255个值
func ExtractIP(ipStrings string) ([]string, error) {
ipStrings = strings.ReplaceAll(ipStrings, " ", "")
// CIDR
if strings.Contains(ipStrings, "/") {
_, cidrNet, err := net.ParseCIDR(ipStrings)
if err != nil {
return nil, err
}
var index = strings.Index(ipStrings, "/")
var ipFrom = ipStrings[:index]
var bits = types.Int(ipStrings[index+1:])
if bits < 24 {
return nil, errors.New("CIDR bits should be greater than 24")
}
var ipv4 = net.ParseIP(ipFrom).To4()
if len(ipv4) == 0 {
return nil, errors.New("support IPv4 only")
}
var result = []string{}
ipv4[3] = 0 // 从0开始
for i := 0; i <= 255; i++ {
if cidrNet.Contains(ipv4) {
result = append(result, ipv4.String())
}
ipv4 = NextIP(ipv4)
}
return result, nil
}
// IP Range
if strings.Contains(ipStrings, "-") {
var index = strings.Index(ipStrings, "-")
var ipFromString = ipStrings[:index]
var ipToString = ipStrings[index+1:]
var ipFrom = net.ParseIP(ipFromString).To4()
if len(ipFrom) == 0 {
return nil, errors.New("invalid ip '" + ipFromString + "'")
}
var ipTo = net.ParseIP(ipToString).To4()
if len(ipTo) == 0 {
return nil, errors.New("invalid ip '" + ipToString + "'")
}
if bytes.Compare(ipFrom, ipTo) > 0 {
ipFrom, ipTo = ipTo, ipFrom
}
var result = []string{}
for i := 0; i < 255; i++ {
if bytes.Compare(ipFrom, ipTo) > 0 {
break
}
result = append(result, ipFrom.String())
ipFrom = NextIP(ipFrom)
}
return result, nil
}
return []string{ipStrings}, nil
}
// NextIP IP增加1
func NextIP(prevIP net.IP) net.IP {
var ip = make(net.IP, len(prevIP))
copy(ip, prevIP)
var index = len(ip) - 1
for {
if ip[index] == 255 {
ip[index] = 0
index--
if index < 0 {
break
}
} else {
ip[index]++
break
}
}
return ip
}

View File

@@ -1,6 +1,7 @@
package utils
import (
"net"
"testing"
)
@@ -83,3 +84,27 @@ func TestIsIPv6(t *testing.T) {
}
}
}
func TestExtractIP(t *testing.T) {
t.Log(ExtractIP("192.168.1.100"))
}
func TestExtractIP_CIDR(t *testing.T) {
t.Log(ExtractIP("192.168.2.100/24"))
}
func TestExtractIP_Range(t *testing.T) {
t.Log(ExtractIP("192.168.2.100 - 192.168.4.2"))
}
func TestNextIP(t *testing.T) {
for _, ip := range []string{"192.168.1.1", "0.0.0.0", "255.255.255.255", "192.168.2.255", "192.168.255.255"} {
t.Log(ip+":", NextIP(net.ParseIP(ip).To4()))
}
}
func TestNextIP_Copy(t *testing.T) {
var ip = net.ParseIP("192.168.1.100")
var nextIP = NextIP(ip)
t.Log(ip, nextIP)
}

24
internal/utils/json.go Normal file
View File

@@ -0,0 +1,24 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package utils
import (
"encoding/json"
"reflect"
)
// JSONClone 使用JSON克隆对象
func JSONClone(v interface{}) (interface{}, error) {
data, err := json.Marshal(v)
if err != nil {
return nil, err
}
var nv = reflect.New(reflect.TypeOf(v).Elem()).Interface()
err = json.Unmarshal(data, nv)
if err != nil {
return nil, err
}
return nv, nil
}

View File

@@ -0,0 +1,25 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package utils_test
import (
"github.com/TeaOSLab/EdgeAdmin/internal/utils"
"testing"
)
func TestJSONClone(t *testing.T) {
type A struct {
B int `json:"b"`
C string `json:"c"`
}
var a = &A{B: 123, C: "456"}
for i := 0; i < 5; i++ {
c, err := utils.JSONClone(a)
if err != nil {
t.Fatal(err)
}
t.Logf("%p, %#v", c, c)
}
}

View File

@@ -0,0 +1,27 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
//go:build community
// +build community
package nodelogutils
import (
"github.com/iwind/TeaGo/maps"
)
// FindCommonTags 查找常用的标签
func FindNodeCommonTags() []maps.Map {
return []maps.Map{
{
"name": "端口监听",
"code": "LISTENER",
},
{
"name": "WAF",
"code": "WAF",
},
{
"name": "访问日志",
"code": "ACCESS_LOG",
},
}
}

View File

@@ -2,6 +2,7 @@ package numberutils
import (
"fmt"
"github.com/iwind/TeaGo/types"
"strconv"
)
@@ -13,38 +14,43 @@ func FormatInt(value int) string {
return strconv.Itoa(value)
}
func Pow1024(n int) int64 {
if n <= 0 {
return 1
}
if n == 1 {
return 1024
}
return Pow1024(n-1) * 1024
}
func FormatBytes(bytes int64) string {
if bytes < 1024 {
if bytes < Pow1024(1) {
return FormatInt64(bytes) + "B"
} else if bytes < 1024*1024 {
return fmt.Sprintf("%.2fKB", float64(bytes)/1024)
} else if bytes < 1024*1024*1024 {
return fmt.Sprintf("%.2fMB", float64(bytes)/1024/1024)
} else if bytes < 1024*1024*1024*1024 {
return fmt.Sprintf("%.2fGB", float64(bytes)/1024/1024/1024)
} else if bytes < 1024*1024*1024*1024*1024 {
return fmt.Sprintf("%.2fTB", float64(bytes)/1024/1024/1024/1024)
} else if bytes < 1024*1024*1024*1024*1024*1024 {
return fmt.Sprintf("%.2fPB", float64(bytes)/1024/1024/1024/1024/1024)
} else if bytes < Pow1024(2) {
return fmt.Sprintf("%.2fKB", float64(bytes)/float64(Pow1024(1)))
} else if bytes < Pow1024(3) {
return fmt.Sprintf("%.2fMB", float64(bytes)/float64(Pow1024(2)))
} else if bytes < Pow1024(4) {
return fmt.Sprintf("%.2fGB", float64(bytes)/float64(Pow1024(3)))
} else if bytes < Pow1024(5) {
return fmt.Sprintf("%.2fTB", float64(bytes)/float64(Pow1024(4)))
} else if bytes < Pow1024(6) {
return fmt.Sprintf("%.2fPB", float64(bytes)/float64(Pow1024(5)))
} else {
return fmt.Sprintf("%.2fEB", float64(bytes)/1024/1024/1024/1024/1024/1024)
return fmt.Sprintf("%.2fEB", float64(bytes)/float64(Pow1024(6)))
}
}
func FormatBits(bits int64) string {
if bits < 1000 {
return FormatInt64(bits) + "B"
} else if bits < 1000*1000 {
return fmt.Sprintf("%.2fKB", float64(bits)/1000)
} else if bits < 1000*1000*1000 {
return fmt.Sprintf("%.2fMB", float64(bits)/1000/1000)
} else if bits < 1000*1000*1000*1000 {
return fmt.Sprintf("%.2fGB", float64(bits)/1000/1000/1000)
} else if bits < 1000*1000*1000*1000*1000 {
return fmt.Sprintf("%.2fTB", float64(bits)/1000/1000/1000/1000)
} else if bits < 1000*1000*1000*1000*1000*1000 {
return fmt.Sprintf("%.2fPB", float64(bits)/1000/1000/1000/1000/1000)
} else {
return fmt.Sprintf("%.2fEB", float64(bits)/1000/1000/1000/1000/1000/1000)
func FormatCount(count int64) string {
if count < 1000 {
return types.String(count)
}
if count < 1000 * 1000 {
return fmt.Sprintf("%.1fK", float32(count)/1000)
}
if count < 1000 * 1000 * 1000{
return fmt.Sprintf("%.1fM", float32(count)/1000/1000)
}
return fmt.Sprintf("%.1fB", float32(count)/1000/1000/1000)
}

View File

@@ -0,0 +1,26 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package numberutils
import "testing"
func TestFormatBytes(t *testing.T) {
t.Log(FormatBytes(1))
t.Log(FormatBytes(1000))
t.Log(FormatBytes(1_000_000))
t.Log(FormatBytes(1_000_000_000))
t.Log(FormatBytes(1_000_000_000_000))
t.Log(FormatBytes(1_000_000_000_000_000))
t.Log(FormatBytes(1_000_000_000_000_000_000))
t.Log(FormatBytes(9_000_000_000_000_000_000))
}
func TestFormatCount(t *testing.T) {
t.Log(FormatCount(1))
t.Log(FormatCount(1000))
t.Log(FormatCount(1500))
t.Log(FormatCount(1_000_000))
t.Log(FormatCount(1_500_000))
t.Log(FormatCount(1_000_000_000))
t.Log(FormatCount(1_500_000_000))
}

View File

@@ -4,6 +4,7 @@ import (
"context"
"errors"
"fmt"
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
"github.com/TeaOSLab/EdgeAdmin/internal/oplogs"
"github.com/TeaOSLab/EdgeAdmin/internal/rpc"
"github.com/TeaOSLab/EdgeAdmin/internal/utils"
@@ -55,7 +56,14 @@ func (this *ParentAction) NewPage(total int64, size ...int64) *Page {
if len(size) > 0 {
return NewActionPage(this, total, size[0])
}
return NewActionPage(this, total, 10)
var pageSize int64 = 10
adminConfig, err := configloaders.LoadAdminUIConfig()
if err == nil && adminConfig.DefaultPageSize > 0 {
pageSize = int64(adminConfig.DefaultPageSize)
}
return NewActionPage(this, total, pageSize)
}
func (this *ParentAction) Nav(mainMenu string, tab string, firstMenu string) {

View File

@@ -9,6 +9,7 @@ import (
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/iwind/TeaGo/logs"
"github.com/iwind/TeaGo/maps"
timeutil "github.com/iwind/TeaGo/utils/time"
"time"
)
@@ -26,11 +27,11 @@ func (this *IndexAction) RunGet(params struct{}) {
this.ErrorPage(err)
return
}
count := countResp.Count
page := this.NewPage(count)
var count = countResp.Count
var page = this.NewPage(count)
this.Data["page"] = page.AsHTML()
nodeMaps := []maps.Map{}
var nodeMaps = []maps.Map{}
if count > 0 {
nodesResp, err := this.RPC().APINodeRPC().ListEnabledAPINodes(this.AdminContext(), &pb.ListEnabledAPINodesRequest{
Offset: page.Offset,
@@ -106,5 +107,13 @@ func (this *IndexAction) RunGet(params struct{}) {
}
this.Data["nodes"] = nodeMaps
// 检查是否有调试数据
countMethodStatsResp, err := this.RPC().APIMethodStatRPC().CountAPIMethodStatsWithDay(this.AdminContext(), &pb.CountAPIMethodStatsWithDayRequest{Day: timeutil.Format("Ymd")})
if err != nil {
this.ErrorPage(err)
return
}
this.Data["hasMethodStats"] = countMethodStatsResp.Count > 0
this.Show()
}

View File

@@ -16,6 +16,7 @@ func init() {
Helper(settingutils.NewAdvancedHelper("apiNodes")).
Prefix("/api").
Get("", new(IndexAction)).
Get("/methodStats", new(MethodStatsAction)).
GetPost("/node/createPopup", new(node.CreatePopupAction)).
Post("/delete", new(DeleteAction)).
EndAll()

View File

@@ -0,0 +1,78 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package api
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/maps"
timeutil "github.com/iwind/TeaGo/utils/time"
"sort"
"strings"
)
type MethodStatsAction struct {
actionutils.ParentAction
}
func (this *MethodStatsAction) Init() {
this.Nav("", "", "")
}
func (this *MethodStatsAction) RunGet(params struct {
Order string
Method string
Tag string
}) {
this.Data["order"] = params.Order
this.Data["method"] = params.Method
this.Data["tag"] = params.Tag
statsResp, err := this.RPC().APIMethodStatRPC().FindAPIMethodStatsWithDay(this.AdminContext(), &pb.FindAPIMethodStatsWithDayRequest{Day: timeutil.Format("Ymd")})
if err != nil {
this.ErrorPage(err)
return
}
var pbStats = statsResp.ApiMethodStats
switch params.Order {
case "method":
sort.Slice(pbStats, func(i, j int) bool {
return pbStats[i].Method < pbStats[j].Method
})
case "costMs.desc":
sort.Slice(pbStats, func(i, j int) bool {
return pbStats[i].CostMs > pbStats[j].CostMs
})
case "peekMs.desc":
sort.Slice(pbStats, func(i, j int) bool {
return pbStats[i].PeekMs > pbStats[j].PeekMs
})
case "calls.desc":
sort.Slice(pbStats, func(i, j int) bool {
return pbStats[i].CountCalls > pbStats[j].CountCalls
})
}
var statMaps = []maps.Map{}
for _, stat := range pbStats {
if len(params.Method) > 0 && !strings.Contains(strings.ToLower(stat.Method), strings.ToLower(params.Method)) {
continue
}
if len(params.Tag) > 0 && !strings.Contains(strings.ToLower(stat.Tag), strings.ToLower(params.Tag)) {
continue
}
statMaps = append(statMaps, maps.Map{
"id": stat.Id,
"method": stat.Method,
"tag": stat.Tag,
"costMs": stat.CostMs,
"peekMs": stat.PeekMs,
"countCalls": stat.CountCalls,
})
}
this.Data["stats"] = statMaps
this.Show()
}

View File

@@ -3,6 +3,7 @@ package cluster
import (
"encoding/json"
"github.com/TeaOSLab/EdgeAdmin/internal/oplogs"
"github.com/TeaOSLab/EdgeAdmin/internal/utils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/grants/grantutils"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
@@ -167,9 +168,13 @@ func (this *CreateNodeAction) RunPost(params struct {
nodeId := createResp.NodeId
// IP地址
var resultIPAddresses = []string{}
for _, addr := range ipAddresses {
var resultAddrIds = []int64{}
addrId := addr.GetInt64("id")
if addrId > 0 {
resultAddrIds = append(resultAddrIds, addrId)
_, err = this.RPC().NodeIPAddressRPC().UpdateNodeIPAddressNodeId(this.AdminContext(), &pb.UpdateNodeIPAddressNodeIdRequest{
NodeIPAddressId: addrId,
NodeId: nodeId,
@@ -178,20 +183,50 @@ func (this *CreateNodeAction) RunPost(params struct {
this.ErrorPage(err)
return
}
resultIPAddresses = append(resultIPAddresses, addr.GetString("ip"))
} else {
createResp, err := this.RPC().NodeIPAddressRPC().CreateNodeIPAddress(this.AdminContext(), &pb.CreateNodeIPAddressRequest{
NodeId: nodeId,
Role: nodeconfigs.NodeRoleNode,
Name: addr.GetString("name"),
Ip: addr.GetString("ip"),
CanAccess: addr.GetBool("canAccess"),
IsUp: addr.GetBool("isUp"),
})
var ipStrings = addr.GetString("ip")
result, err := utils.ExtractIP(ipStrings)
if err != nil {
this.ErrorPage(err)
return
this.Fail("节点创建成功但是保存IP失败" + err.Error())
}
resultIPAddresses = append(resultIPAddresses, result...)
if len(result) == 1 {
// 单个创建
createResp, err := this.RPC().NodeIPAddressRPC().CreateNodeIPAddress(this.AdminContext(), &pb.CreateNodeIPAddressRequest{
NodeId: nodeId,
Role: nodeconfigs.NodeRoleNode,
Name: addr.GetString("name"),
Ip: result[0],
CanAccess: addr.GetBool("canAccess"),
IsUp: addr.GetBool("isUp"),
})
if err != nil {
this.ErrorPage(err)
return
}
addrId = createResp.NodeIPAddressId
resultAddrIds = append(resultAddrIds, addrId)
} else if len(result) > 1 {
// 批量创建
createResp, err := this.RPC().NodeIPAddressRPC().CreateNodeIPAddresses(this.AdminContext(), &pb.CreateNodeIPAddressesRequest{
NodeId: nodeId,
Role: nodeconfigs.NodeRoleNode,
Name: addr.GetString("name"),
IpList: result,
CanAccess: addr.GetBool("canAccess"),
IsUp: addr.GetBool("isUp"),
GroupValue: ipStrings,
})
if err != nil {
this.ErrorPage(err)
return
}
resultAddrIds = append(resultAddrIds, createResp.NodeIPAddressIds...)
}
addrId = createResp.NodeIPAddressId
}
// 阈值
@@ -202,13 +237,16 @@ func (this *CreateNodeAction) RunPost(params struct {
this.ErrorPage(err)
return
}
_, err = this.RPC().NodeIPAddressThresholdRPC().UpdateAllNodeIPAddressThresholds(this.AdminContext(), &pb.UpdateAllNodeIPAddressThresholdsRequest{
NodeIPAddressId: addrId,
NodeIPAddressThresholdsJSON: thresholdsJSON,
})
if err != nil {
this.ErrorPage(err)
return
for _, addrId := range resultAddrIds {
_, err = this.RPC().NodeIPAddressThresholdRPC().UpdateAllNodeIPAddressThresholds(this.AdminContext(), &pb.UpdateAllNodeIPAddressThresholdsRequest{
NodeIPAddressId: addrId,
NodeIPAddressThresholdsJSON: thresholdsJSON,
})
if err != nil {
this.ErrorPage(err)
return
}
}
}
}
@@ -224,11 +262,6 @@ func (this *CreateNodeAction) RunPost(params struct {
return
}
if nodeResp.Node != nil {
var addresses = []string{}
for _, addrMap := range ipAddresses {
addresses = append(addresses, addrMap.GetString("ip"))
}
var grantMap maps.Map = nil
grantId := params.GrantId
if grantId > 0 {
@@ -253,7 +286,7 @@ func (this *CreateNodeAction) RunPost(params struct {
"name": nodeResp.Node.Name,
"uniqueId": nodeResp.Node.UniqueId,
"secret": nodeResp.Node.Secret,
"addresses": addresses,
"addresses": resultIPAddresses,
"login": maps.Map{
"id": 0,
"name": "SSH",

View File

@@ -86,9 +86,16 @@ func (this *DetailAction) RunGet(params struct {
return
}
// 是否有备用IP
var originIP = addr.Ip
if len(addr.BackupIP) > 0 {
addr.Ip = addr.BackupIP
}
ipAddressMaps = append(ipAddressMaps, maps.Map{
"id": addr.Id,
"name": addr.Name,
"originIP": originIP,
"ip": addr.Ip,
"canAccess": addr.CanAccess,
"isOn": addr.IsOn,

View File

@@ -1,6 +1,7 @@
package node
import (
"github.com/TeaOSLab/EdgeAdmin/internal/utils/nodelogutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/node/nodeutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
@@ -23,6 +24,7 @@ func (this *LogsAction) RunGet(params struct {
DayTo string
Keyword string
Level string
Tag string
}) {
// 初始化节点信息(用于菜单)
_, err := nodeutils.InitNodeInfo(this.Parent(), params.NodeId)
@@ -31,11 +33,14 @@ func (this *LogsAction) RunGet(params struct {
return
}
this.Data["tags"] = nodelogutils.FindNodeCommonTags()
this.Data["nodeId"] = params.NodeId
this.Data["dayFrom"] = params.DayFrom
this.Data["dayTo"] = params.DayTo
this.Data["keyword"] = params.Keyword
this.Data["level"] = params.Level
this.Data["tag"] = params.Tag
countResp, err := this.RPC().NodeLogRPC().CountNodeLogs(this.AdminContext(), &pb.CountNodeLogsRequest{
Role: "node",
@@ -44,6 +49,7 @@ func (this *LogsAction) RunGet(params struct {
DayTo: params.DayTo,
Keyword: params.Keyword,
Level: params.Level,
Tag: params.Tag,
})
if err != nil {
this.ErrorPage(err)
@@ -59,6 +65,7 @@ func (this *LogsAction) RunGet(params struct {
DayTo: params.DayTo,
Keyword: params.Keyword,
Level: params.Level,
Tag: params.Tag,
Offset: page.Offset,
Size: page.Size,
})

View File

@@ -60,11 +60,15 @@ func InitNodeInfo(parentAction *actionutils.ParentAction, nodeId int64) (*pb.Nod
"name": "DNS设置",
"url": prefix + "/settings/dns?" + query,
"isActive": menuItem == "dns",
"isOn": len(node.DnsRoutes) > 0,
},
{
"name": "缓存设置",
"url": prefix + "/settings/cache?" + query,
"isActive": menuItem == "cache",
"isOn": len(node.CacheDiskDir) > 0 ||
(node.MaxCacheDiskCapacity != nil && node.MaxCacheDiskCapacity.Count > 0) ||
(node.MaxCacheMemoryCapacity != nil && node.MaxCacheMemoryCapacity.Count > 0),
},
}
if teaconst.IsPlus {
@@ -81,11 +85,13 @@ func InitNodeInfo(parentAction *actionutils.ParentAction, nodeId int64) (*pb.Nod
"name": "SSH设置",
"url": prefix + "/settings/ssh?" + query,
"isActive": menuItem == "ssh",
"isOn": node.NodeLogin != nil,
},
{
"name": "系统设置",
"url": prefix + "/settings/system?" + query,
"isActive": menuItem == "system",
"isOn": node.MaxCPU > 0,
},
}...)
parentAction.Data["leftMenuItems"] = menuItems

View File

@@ -17,7 +17,7 @@ type IndexAction struct {
}
func (this *IndexAction) Init() {
this.Nav("", "", "update")
this.Nav("", "node", "update")
this.SecondMenu("cache")
}
@@ -59,6 +59,7 @@ func (this *IndexAction) RunGet(params struct {
var nodeMap = this.Data["node"].(maps.Map)
nodeMap["maxCacheDiskCapacity"] = maxCacheDiskCapacity
nodeMap["cacheDiskDir"] = node.CacheDiskDir
nodeMap["maxCacheMemoryCapacity"] = maxCacheMemoryCapacity
this.Show()
@@ -67,6 +68,7 @@ func (this *IndexAction) RunGet(params struct {
func (this *IndexAction) RunPost(params struct {
NodeId int64
MaxCacheDiskCapacityJSON []byte
CacheDiskDir string
MaxCacheMemoryCapacityJSON []byte
Must *actions.Must
@@ -106,6 +108,7 @@ func (this *IndexAction) RunPost(params struct {
_, err := this.RPC().NodeRPC().UpdateNodeCache(this.AdminContext(), &pb.UpdateNodeCacheRequest{
NodeId: params.NodeId,
MaxCacheDiskCapacity: pbMaxCacheDiskCapacity,
CacheDiskDir: params.CacheDiskDir,
MaxCacheMemoryCapacity: pbMaxCacheMemoryCapacity,
})
if err != nil {

View File

@@ -16,7 +16,7 @@ type IndexAction struct {
}
func (this *IndexAction) Init() {
this.Nav("", "", "update")
this.Nav("", "node", "update")
this.SecondMenu("dns")
}

View File

@@ -17,7 +17,7 @@ type IndexAction struct {
}
func (this *IndexAction) Init() {
this.Nav("", "", "update")
this.Nav("", "node", "update")
this.SecondMenu("ssh")
}

View File

@@ -15,7 +15,7 @@ type IndexAction struct {
}
func (this *IndexAction) Init() {
this.Nav("", "", "update")
this.Nav("", "node", "update")
this.SecondMenu("system")
}

View File

@@ -15,7 +15,7 @@ type IndexAction struct {
}
func (this *IndexAction) Init() {
this.Nav("", "", "update")
this.Nav("", "node", "update")
this.SecondMenu("threshold")
}

View File

@@ -34,6 +34,8 @@ func (this *CreatePopupAction) RunPost(params struct {
// ipset
IpsetWhiteName string
IpsetBlackName string
IpsetWhiteNameIPv6 string
IpsetBlackNameIPv6 string
IpsetAutoAddToIPTables bool
IpsetAutoAddToFirewalld bool
@@ -49,7 +51,7 @@ func (this *CreatePopupAction) RunPost(params struct {
Must *actions.Must
CSRF *actionutils.CSRF
}) {
defer this.CreateLogInfo("创建WAF动作")
defer this.CreateLogInfo("创建集群 %d 的WAF动作", params.ClusterId)
params.Must.
Field("name", params.Name).
@@ -66,11 +68,19 @@ func (this *CreatePopupAction) RunPost(params struct {
Match(`^\w+$`, "请输入正确的IPSet白名单名称").
Field("ipsetBlackName", params.IpsetBlackName).
Require("请输入IPSet黑名单名称").
Match(`^\w+$`, "请输入正确的IPSet黑名单名称")
Match(`^\w+$`, "请输入正确的IPSet黑名单名称").
Field("ipsetWhiteNameIPv6", params.IpsetWhiteNameIPv6).
Require("请输入IPSet IPv6白名单名称").
Match(`^\w+$`, "请输入正确的IPSet IPv6白名单名称").
Field("ipsetBlackNameIPv6", params.IpsetBlackNameIPv6).
Require("请输入IPSet IPv6黑名单名称").
Match(`^\w+$`, "请输入正确的IPSet IPv6黑名单名称")
actionParams = &firewallconfigs.FirewallActionIPSetConfig{
WhiteName: params.IpsetWhiteName,
BlackName: params.IpsetBlackName,
WhiteNameIPv6: params.IpsetWhiteNameIPv6,
BlackNameIPv6: params.IpsetBlackNameIPv6,
AutoAddToIPTables: params.IpsetAutoAddToIPTables,
AutoAddToFirewalld: params.IpsetAutoAddToFirewalld,
}

View File

@@ -63,6 +63,8 @@ func (this *UpdatePopupAction) RunPost(params struct {
// ipset
IpsetWhiteName string
IpsetBlackName string
IpsetWhiteNameIPv6 string
IpsetBlackNameIPv6 string
IpsetAutoAddToIPTables bool
IpsetAutoAddToFirewalld bool
@@ -95,11 +97,19 @@ func (this *UpdatePopupAction) RunPost(params struct {
Match(`^\w+$`, "请输入正确的IPSet白名单名称").
Field("ipsetBlackName", params.IpsetBlackName).
Require("请输入IPSet黑名单名称").
Match(`^\w+$`, "请输入正确的IPSet黑名单名称")
Match(`^\w+$`, "请输入正确的IPSet黑名单名称").
Field("ipsetWhiteNameIPv6", params.IpsetWhiteNameIPv6).
Require("请输入IPSet IPv6白名单名称").
Match(`^\w+$`, "请输入正确的IPSet IPv6白名单名称").
Field("ipsetBlackNameIPv6", params.IpsetBlackNameIPv6).
Require("请输入IPSet IPv6黑名单名称").
Match(`^\w+$`, "请输入正确的IPSet IPv6黑名单名称")
actionParams = &firewallconfigs.FirewallActionIPSetConfig{
WhiteName: params.IpsetWhiteName,
BlackName: params.IpsetBlackName,
WhiteNameIPv6: params.IpsetWhiteNameIPv6,
BlackNameIPv6: params.IpsetBlackNameIPv6,
AutoAddToIPTables: params.IpsetAutoAddToIPTables,
AutoAddToFirewalld: params.IpsetAutoAddToFirewalld,
}

View File

@@ -8,6 +8,7 @@ import (
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/actions"
"github.com/iwind/TeaGo/maps"
"github.com/iwind/TeaGo/types"
)
type IndexAction struct {
@@ -65,22 +66,34 @@ func (this *IndexAction) RunGet(params struct {
this.Data["timeZoneLocation"] = nodeconfigs.FindTimeZoneLocation(cluster.TimeZone)
this.Data["cluster"] = maps.Map{
"id": cluster.Id,
"name": cluster.Name,
"installDir": cluster.InstallDir,
"timeZone": cluster.TimeZone,
"id": cluster.Id,
"name": cluster.Name,
"installDir": cluster.InstallDir,
"timeZone": cluster.TimeZone,
"nodeMaxThreads": cluster.NodeMaxThreads,
"nodeTCPMaxConnections": cluster.NodeTCPMaxConnections,
"autoOpenPorts": cluster.AutoOpenPorts,
}
// 默认值
this.Data["defaultNodeMaxThreads"] = nodeconfigs.DefaultMaxThreads
this.Data["defaultNodeMaxThreadsMin"] = nodeconfigs.DefaultMaxThreadsMin
this.Data["defaultNodeMaxThreadsMax"] = nodeconfigs.DefaultMaxThreadsMax
this.Data["defaultNodeTCPMaxConnections"] = nodeconfigs.DefaultTCPMaxConnections
this.Show()
}
// RunPost 保存设置
func (this *IndexAction) RunPost(params struct {
ClusterId int64
Name string
GrantId int64
InstallDir string
TimeZone string
ClusterId int64
Name string
GrantId int64
InstallDir string
TimeZone string
NodeMaxThreads int32
NodeTCPMaxConnections int32
AutoOpenPorts bool
Must *actions.Must
}) {
@@ -91,12 +104,22 @@ func (this *IndexAction) RunPost(params struct {
Field("name", params.Name).
Require("请输入集群名称")
if params.NodeMaxThreads > 0 {
params.Must.
Field("nodeMaxThreads", params.NodeMaxThreads).
Gte(int64(nodeconfigs.DefaultMaxThreadsMin), "单节点最大线程数最小值不能小于"+types.String(nodeconfigs.DefaultMaxThreadsMin)).
Lte(int64(nodeconfigs.DefaultMaxThreadsMax), "单节点最大线程数最大值不能大于"+types.String(nodeconfigs.DefaultMaxThreadsMax))
}
_, err := this.RPC().NodeClusterRPC().UpdateNodeCluster(this.AdminContext(), &pb.UpdateNodeClusterRequest{
NodeClusterId: params.ClusterId,
Name: params.Name,
NodeGrantId: params.GrantId,
InstallDir: params.InstallDir,
TimeZone: params.TimeZone,
NodeClusterId: params.ClusterId,
Name: params.Name,
NodeGrantId: params.GrantId,
InstallDir: params.InstallDir,
TimeZone: params.TimeZone,
NodeMaxThreads: params.NodeMaxThreads,
NodeTCPMaxConnections: params.NodeTCPMaxConnections,
AutoOpenPorts: params.AutoOpenPorts,
})
if err != nil {
this.ErrorPage(err)

View File

@@ -27,6 +27,14 @@ func (this *CreateAction) RunGet(params struct{}) {
}
this.Data["hasDomains"] = hasDomainsResp.Exist
// 集群总数
totalResp, err := this.RPC().NodeClusterRPC().CountAllEnabledNodeClusters(this.AdminContext(), &pb.CountAllEnabledNodeClustersRequest{})
if err != nil {
this.ErrorPage(err)
return
}
this.Data["totalNodeClusters"] = totalResp.Count
this.Show()
}

View File

@@ -30,6 +30,7 @@ func (this *CreateAction) RunPost(params struct {
PrivateKey string
Passphrase string
Description string
Su bool
Must *actions.Must
}) {
@@ -61,6 +62,7 @@ func (this *CreateAction) RunPost(params struct {
PrivateKey: params.PrivateKey,
Passphrase: params.Passphrase,
Description: params.Description,
Su: params.Su,
NodeId: 0,
})
if err != nil {

View File

@@ -31,6 +31,7 @@ func (this *CreatePopupAction) RunPost(params struct {
PrivateKey string
Passphrase string
Description string
Su bool
Must *actions.Must
}) {
@@ -62,6 +63,7 @@ func (this *CreatePopupAction) RunPost(params struct {
PrivateKey: params.PrivateKey,
Passphrase: params.Passphrase,
Description: params.Description,
Su: params.Su,
NodeId: 0,
})
if err != nil {
@@ -74,6 +76,7 @@ func (this *CreatePopupAction) RunPost(params struct {
"name": params.Name,
"method": params.Method,
"methodName": grantutils.FindGrantMethodName(params.Method),
"username": params.Username,
}
// 创建日志

View File

@@ -60,6 +60,7 @@ func (this *UpdateAction) RunPost(params struct {
PrivateKey string
Passphrase string
Description string
Su bool
Must *actions.Must
}) {
@@ -97,6 +98,7 @@ func (this *UpdateAction) RunPost(params struct {
PrivateKey: params.PrivateKey,
Passphrase: params.Passphrase,
Description: params.Description,
Su: params.Su,
NodeId: 0,
})
if err != nil {

View File

@@ -44,6 +44,7 @@ func (this *UpdatePopupAction) RunGet(params struct {
"description": grant.Description,
"privateKey": grant.PrivateKey,
"passphrase": grant.Passphrase,
"su": grant.Su,
}
this.Show()
@@ -59,6 +60,7 @@ func (this *UpdatePopupAction) RunPost(params struct {
PrivateKey string
Passphrase string
Description string
Su bool
Must *actions.Must
}) {
@@ -96,6 +98,7 @@ func (this *UpdatePopupAction) RunPost(params struct {
Passphrase: params.Passphrase,
Description: params.Description,
NodeId: params.NodeId,
Su: params.Su,
})
if err != nil {
this.ErrorPage(err)
@@ -108,6 +111,7 @@ func (this *UpdatePopupAction) RunPost(params struct {
"name": params.Name,
"method": params.Method,
"methodName": grantutils.FindGrantMethodName(params.Method),
"username": params.Username,
}
this.Success()

View File

@@ -29,6 +29,14 @@ func (this *IndexAction) RunGet(params struct {
this.Data["searchType"] = params.SearchType
this.Data["isSearching"] = isSearching
// 集群总数
totalResp, err := this.RPC().NodeClusterRPC().CountAllEnabledNodeClusters(this.AdminContext(), &pb.CountAllEnabledNodeClustersRequest{})
if err != nil {
this.ErrorPage(err)
return
}
this.Data["totalNodeClusters"] = totalResp.Count
// 常用的集群
latestClusterMaps := []maps.Map{}
if !isSearching {
@@ -137,6 +145,7 @@ func (this *IndexAction) RunGet(params struct {
"dnsDomainName": dnsDomainName,
"countServers": countServersResp.Count,
"timeZone": cluster.TimeZone,
"isPinned": cluster.IsPinned,
})
}
}

View File

@@ -16,13 +16,14 @@ func init() {
Prefix("/clusters").
Get("", new(IndexAction)).
GetPost("/create", new(CreateAction)).
Post("/pin", new(PinAction)).
// 只要登录即可访问的Action
EndHelpers().
Helper(helpers.NewUserMustAuth(configloaders.AdminModuleCodeCommon)).
Post("/options", new(OptionsAction)).
Post("/nodeOptions", new(NodeOptionsAction)).
GetPost("/selectPopup", new(SelectPopupAction)).
EndAll()
})
}

View File

@@ -1,6 +1,7 @@
package logs
import (
"github.com/TeaOSLab/EdgeAdmin/internal/utils/nodelogutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
@@ -21,17 +22,26 @@ func (this *IndexAction) Init() {
}
func (this *IndexAction) RunGet(params struct {
DayFrom string
DayTo string
Keyword string
Level string
Type string
DayFrom string
DayTo string
Keyword string
Level string
Type string
Tag string
ClusterId int64
NodeId int64
}) {
this.Data["dayFrom"] = params.DayFrom
this.Data["dayTo"] = params.DayTo
this.Data["keyword"] = params.Keyword
this.Data["level"] = params.Level
this.Data["type"] = params.Type
this.Data["tag"] = params.Tag
this.Data["clusterId"] = params.ClusterId
this.Data["nodeId"] = params.NodeId
// 常见标签
this.Data["tags"] = nodelogutils.FindNodeCommonTags()
// 未读数量
countUnreadResp, err := this.RPC().NodeLogRPC().CountNodeLogs(this.AdminContext(), &pb.CountNodeLogsRequest{
@@ -46,13 +56,15 @@ func (this *IndexAction) RunGet(params struct {
// 日志数量
countResp, err := this.RPC().NodeLogRPC().CountNodeLogs(this.AdminContext(), &pb.CountNodeLogsRequest{
NodeId: 0,
Role: nodeconfigs.NodeRoleNode,
DayFrom: params.DayFrom,
DayTo: params.DayTo,
Keyword: params.Keyword,
Level: params.Level,
IsUnread: params.Type == "unread",
NodeClusterId: params.ClusterId,
NodeId: params.NodeId,
Role: nodeconfigs.NodeRoleNode,
DayFrom: params.DayFrom,
DayTo: params.DayTo,
Keyword: params.Keyword,
Level: params.Level,
IsUnread: params.Type == "unread",
Tag: params.Tag,
})
if err != nil {
this.ErrorPage(err)
@@ -63,15 +75,17 @@ func (this *IndexAction) RunGet(params struct {
this.Data["page"] = page.AsHTML()
logsResp, err := this.RPC().NodeLogRPC().ListNodeLogs(this.AdminContext(), &pb.ListNodeLogsRequest{
NodeId: 0,
Role: nodeconfigs.NodeRoleNode,
DayFrom: params.DayFrom,
DayTo: params.DayTo,
Keyword: params.Keyword,
Level: params.Level,
IsUnread: params.Type == "unread",
Offset: page.Offset,
Size: page.Size,
NodeClusterId: params.ClusterId,
NodeId: params.NodeId,
Role: nodeconfigs.NodeRoleNode,
DayFrom: params.DayFrom,
DayTo: params.DayTo,
Keyword: params.Keyword,
Level: params.Level,
IsUnread: params.Type == "unread",
Tag: params.Tag,
Offset: page.Offset,
Size: page.Size,
})
if err != nil {
this.ErrorPage(err)

View File

@@ -0,0 +1,34 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package clusters
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/maps"
)
type NodeOptionsAction struct {
actionutils.ParentAction
}
func (this *NodeOptionsAction) RunPost(params struct {
ClusterId int64
}) {
resp, err := this.RPC().NodeRPC().FindAllEnabledNodesWithNodeClusterId(this.AdminContext(), &pb.FindAllEnabledNodesWithNodeClusterIdRequest{NodeClusterId: params.ClusterId})
if err != nil {
this.ErrorPage(err)
return
}
var nodeMaps = []maps.Map{}
for _, node := range resp.Nodes {
nodeMaps = append(nodeMaps, maps.Map{
"id": node.Id,
"name": node.Name,
})
}
this.Data["nodes"] = nodeMaps
this.Success()
}

View File

@@ -0,0 +1,34 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package clusters
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
)
type PinAction struct {
actionutils.ParentAction
}
func (this *PinAction) RunPost(params struct {
ClusterId int64
IsPinned bool
}) {
if params.IsPinned {
defer this.CreateLogInfo("置顶集群 %d", params.ClusterId)
} else {
defer this.CreateLogInfo("取消置顶集群 %d", params.ClusterId)
}
_, err := this.RPC().NodeClusterRPC().UpdateNodeClusterPinned(this.AdminContext(), &pb.UpdateNodeClusterPinnedRequest{
NodeClusterId: params.ClusterId,
IsPinned: params.IsPinned,
})
if err != nil {
this.ErrorPage(err)
return
}
this.Success()
}

View File

@@ -35,11 +35,11 @@ func (this *SelectPopupAction) RunGet(params struct {
return
}
var count = countResp.Count
var page = this.NewPage(count)
page.Size = 6
var pageSize int64 = 6
if params.PageSize > 0 {
page.Size = params.PageSize
pageSize = params.PageSize
}
var page = this.NewPage(count, pageSize)
this.Data["page"] = page.AsHTML()
clustersResp, err := this.RPC().NodeClusterRPC().ListEnabledNodeClusters(this.AdminContext(), &pb.ListEnabledNodeClustersRequest{

View File

@@ -10,7 +10,9 @@ type CheckAction struct {
}
func (this *CheckAction) RunPost(params struct{}) {
resp, err := this.RPC().NodeTaskRPC().ExistsNodeTasks(this.AdminContext(), &pb.ExistsNodeTasksRequest{})
resp, err := this.RPC().NodeTaskRPC().ExistsNodeTasks(this.AdminContext(), &pb.ExistsNodeTasksRequest{
ExcludeTypes: []string{"ipItemChanged"},
})
if err != nil {
this.ErrorPage(err)
return

View File

@@ -40,6 +40,11 @@ func (this *IndexAction) RunGet(params struct{}) {
}
}
// 版本更新
this.Data["currentVersionCode"] = teaconst.Version
this.Data["newVersionCode"] = teaconst.NewVersionCode
this.Data["newVersionDownloadURL"] = teaconst.NewVersionDownloadURL
this.Show()
}

View File

@@ -17,7 +17,7 @@ func ValidateDomainFormat(domain string) bool {
if piece == "-" ||
strings.HasPrefix(piece, "-") ||
strings.HasSuffix(piece, "-") ||
strings.Contains(piece, "--") ||
//strings.Contains(piece, "--") ||
len(piece) > 63 ||
!regexp.MustCompile(`^[a-z0-9-]+$`).MatchString(piece) {
return false
@@ -75,7 +75,7 @@ func ValidateRecordName(name string) bool {
if piece == "-" ||
strings.HasPrefix(piece, "-") ||
strings.HasSuffix(piece, "-") ||
strings.Contains(piece, "--") ||
//strings.Contains(piece, "--") ||
len(piece) > 63 ||
!regexp.MustCompile(`^[_a-z0-9-]+$`).MatchString(piece) {
return false

View File

@@ -3,6 +3,7 @@ package ipAddresses
import (
"encoding/json"
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
"github.com/TeaOSLab/EdgeAdmin/internal/utils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
"github.com/iwind/TeaGo/actions"
@@ -39,9 +40,15 @@ func (this *CreatePopupAction) RunPost(params struct {
Field("ip", params.IP).
Require("请输入IP地址")
ip := net.ParseIP(params.IP)
if len(ip) == 0 {
this.FailField("ip", "请输入正确的IP")
result, err := utils.ExtractIP(params.IP)
if err != nil {
this.Fail("IP格式错误'" + params.IP + "'")
}
for _, ip := range result {
if len(net.ParseIP(ip)) == 0 {
this.FailField("ip", "请输入正确的IP")
}
}
// 阈值设置

View File

@@ -2,6 +2,7 @@ package ipaddressutils
import (
"encoding/json"
"github.com/TeaOSLab/EdgeAdmin/internal/utils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
@@ -16,8 +17,11 @@ func UpdateNodeIPAddresses(parentAction *actionutils.ParentAction, nodeId int64,
return err
}
for _, addr := range addresses {
var resultAddrIds = []int64{}
addrId := addr.GetInt64("id")
if addrId > 0 {
resultAddrIds = append(resultAddrIds, addrId)
var isOn = false
if !addr.Has("isOn") { // 兼容老版本
isOn = true
@@ -37,18 +41,40 @@ func UpdateNodeIPAddresses(parentAction *actionutils.ParentAction, nodeId int64,
return err
}
} else {
createResp, err := parentAction.RPC().NodeIPAddressRPC().CreateNodeIPAddress(parentAction.AdminContext(), &pb.CreateNodeIPAddressRequest{
NodeId: nodeId,
Role: role,
Name: addr.GetString("name"),
Ip: addr.GetString("ip"),
CanAccess: addr.GetBool("canAccess"),
IsUp: addr.GetBool("isUp"),
})
if err != nil {
return err
var ipStrings = addr.GetString("ip")
result, _ := utils.ExtractIP(ipStrings)
if len(result) == 1 {
// 单个创建
createResp, err := parentAction.RPC().NodeIPAddressRPC().CreateNodeIPAddress(parentAction.AdminContext(), &pb.CreateNodeIPAddressRequest{
NodeId: nodeId,
Role: role,
Name: addr.GetString("name"),
Ip: result[0],
CanAccess: addr.GetBool("canAccess"),
IsUp: addr.GetBool("isUp"),
})
if err != nil {
return err
}
addrId = createResp.NodeIPAddressId
resultAddrIds = append(resultAddrIds, addrId)
} else if len(result) > 1 {
// 批量创建
createResp, err := parentAction.RPC().NodeIPAddressRPC().CreateNodeIPAddresses(parentAction.AdminContext(), &pb.CreateNodeIPAddressesRequest{
NodeId: nodeId,
Role: role,
Name: addr.GetString("name"),
IpList: result,
CanAccess: addr.GetBool("canAccess"),
IsUp: addr.GetBool("isUp"),
GroupValue: ipStrings,
})
if err != nil {
return err
}
resultAddrIds = append(resultAddrIds, createResp.NodeIPAddressIds...)
}
addrId = createResp.NodeIPAddressId
}
// 保存阈值
@@ -58,12 +84,25 @@ func UpdateNodeIPAddresses(parentAction *actionutils.ParentAction, nodeId int64,
if err != nil {
return err
}
_, err = parentAction.RPC().NodeIPAddressThresholdRPC().UpdateAllNodeIPAddressThresholds(parentAction.AdminContext(), &pb.UpdateAllNodeIPAddressThresholdsRequest{
NodeIPAddressId: addrId,
NodeIPAddressThresholdsJSON: thresholdsJSON,
})
if err != nil {
return err
for _, addrId := range resultAddrIds {
_, err = parentAction.RPC().NodeIPAddressThresholdRPC().UpdateAllNodeIPAddressThresholds(parentAction.AdminContext(), &pb.UpdateAllNodeIPAddressThresholdsRequest{
NodeIPAddressId: addrId,
NodeIPAddressThresholdsJSON: thresholdsJSON,
})
if err != nil {
return err
}
}
} else {
for _, addrId := range resultAddrIds {
_, err = parentAction.RPC().NodeIPAddressThresholdRPC().UpdateAllNodeIPAddressThresholds(parentAction.AdminContext(), &pb.UpdateAllNodeIPAddressThresholdsRequest{
NodeIPAddressId: addrId,
NodeIPAddressThresholdsJSON: []byte("[]"),
})
if err != nil {
return err
}
}
}
}

View File

@@ -3,6 +3,7 @@ package ipAddresses
import (
"encoding/json"
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
"github.com/TeaOSLab/EdgeAdmin/internal/utils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
@@ -57,9 +58,22 @@ func (this *UpdatePopupAction) RunPost(params struct {
}
}
ip := net.ParseIP(params.IP)
if len(ip) == 0 {
this.Fail("请输入正确的IP")
if params.AddressId > 0 {
ip := net.ParseIP(params.IP)
if len(ip) == 0 {
this.Fail("请输入正确的IP")
}
} else {
result, err := utils.ExtractIP(params.IP)
if err != nil {
this.Fail("IP格式错误'" + params.IP + "'")
}
for _, ip := range result {
if len(net.ParseIP(ip)) == 0 {
this.FailField("ip", "请输入正确的IP")
}
}
}
var thresholds = []*nodeconfigs.IPAddressThresholdConfig{}

View File

@@ -1,173 +0,0 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package logs
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/lists"
"github.com/iwind/TeaGo/maps"
timeutil "github.com/iwind/TeaGo/utils/time"
"net"
"regexp"
"strings"
)
type IndexAction struct {
actionutils.ParentAction
}
func (this *IndexAction) Init() {
this.Nav("", "", "")
}
func (this *IndexAction) RunGet(params struct {
RequestId string
Keyword string
Day string
}) {
day := strings.ReplaceAll(params.Day, "-", "")
if !regexp.MustCompile(`^\d{8}$`).MatchString(day) {
day = timeutil.Format("Ymd")
}
this.Data["keyword"] = params.Keyword
this.Data["day"] = day[:4] + "-" + day[4:6] + "-" + day[6:]
this.Data["path"] = this.Request.URL.Path
var size = int64(10)
resp, err := this.RPC().NSAccessLogRPC().ListNSAccessLogs(this.AdminContext(), &pb.ListNSAccessLogsRequest{
RequestId: params.RequestId,
NsNodeId: 0,
NsDomainId: 0,
NsRecordId: 0,
Size: size,
Day: day,
Keyword: params.Keyword,
Reverse: false,
})
if err != nil {
this.ErrorPage(err)
return
}
ipList := []string{}
nodeIds := []int64{}
domainIds := []int64{}
if len(resp.NsAccessLogs) == 0 {
this.Data["accessLogs"] = []interface{}{}
} else {
this.Data["accessLogs"] = resp.NsAccessLogs
for _, accessLog := range resp.NsAccessLogs {
// IP
if len(accessLog.RemoteAddr) > 0 {
// 去掉端口
ip, _, err := net.SplitHostPort(accessLog.RemoteAddr)
if err == nil {
accessLog.RemoteAddr = ip
if !lists.ContainsString(ipList, ip) {
ipList = append(ipList, ip)
}
}
}
// 节点
if !lists.ContainsInt64(nodeIds, accessLog.NsNodeId) {
nodeIds = append(nodeIds, accessLog.NsNodeId)
}
// 域名
if !lists.ContainsInt64(domainIds, accessLog.NsDomainId) {
domainIds = append(domainIds, accessLog.NsDomainId)
}
}
}
this.Data["hasMore"] = resp.HasMore
this.Data["nextRequestId"] = resp.RequestId
// 上一个requestId
this.Data["hasPrev"] = false
this.Data["lastRequestId"] = ""
if len(params.RequestId) > 0 {
this.Data["hasPrev"] = true
prevResp, err := this.RPC().NSAccessLogRPC().ListNSAccessLogs(this.AdminContext(), &pb.ListNSAccessLogsRequest{
RequestId: params.RequestId,
NsNodeId: 0,
NsDomainId: 0,
NsRecordId: 0,
Day: day,
Keyword: params.Keyword,
Size: size,
Reverse: true,
})
if err != nil {
this.ErrorPage(err)
return
}
if int64(len(prevResp.NsAccessLogs)) == size {
this.Data["lastRequestId"] = prevResp.RequestId
}
}
// 根据IP查询区域
regionMap := map[string]string{} // ip => region
if len(ipList) > 0 {
resp, err := this.RPC().IPLibraryRPC().LookupIPRegions(this.AdminContext(), &pb.LookupIPRegionsRequest{IpList: ipList})
if err != nil {
this.ErrorPage(err)
return
}
if resp.IpRegionMap != nil {
for ip, region := range resp.IpRegionMap {
if len(region.Isp) > 0 {
region.Summary += " | " + region.Isp
}
regionMap[ip] = region.Summary
}
}
}
this.Data["regions"] = regionMap
// 节点信息
nodeMap := map[int64]interface{}{} // node id => { ... }
for _, nodeId := range nodeIds {
nodeResp, err := this.RPC().NSNodeRPC().FindEnabledNSNode(this.AdminContext(), &pb.FindEnabledNSNodeRequest{NsNodeId: nodeId})
if err != nil {
this.ErrorPage(err)
return
}
node := nodeResp.NsNode
if node != nil {
nodeMap[node.Id] = maps.Map{
"id": node.Id,
"name": node.Name,
"cluster": maps.Map{
"id": node.NsCluster.Id,
"name": node.NsCluster.Name,
},
}
}
}
this.Data["nodes"] = nodeMap
// 域名信息
domainMap := map[int64]interface{}{} // domain id => { ... }
for _, domainId := range domainIds {
domainResp, err := this.RPC().NSDomainRPC().FindEnabledNSDomain(this.AdminContext(), &pb.FindEnabledNSDomainRequest{NsDomainId: domainId})
if err != nil {
this.ErrorPage(err)
return
}
domain := domainResp.NsDomain
if domain != nil {
domainMap[domain.Id] = maps.Map{
"id": domain.Id,
"name": domain.Name,
}
}
}
this.Data["domains"] = domainMap
this.Show()
}

View File

@@ -1,109 +0,0 @@
package cluster
import (
"encoding/json"
"github.com/TeaOSLab/EdgeAdmin/internal/oplogs"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/actions"
"github.com/iwind/TeaGo/maps"
)
// CreateNodeAction 创建节点
type CreateNodeAction struct {
actionutils.ParentAction
}
func (this *CreateNodeAction) Init() {
this.Nav("", "node", "create")
this.SecondMenu("nodes")
}
func (this *CreateNodeAction) RunGet(params struct {
ClusterId int64
}) {
this.Show()
}
func (this *CreateNodeAction) RunPost(params struct {
Name string
IpAddressesJSON []byte
ClusterId int64
Must *actions.Must
}) {
params.Must.
Field("name", params.Name).
Require("请输入节点名称")
if len(params.IpAddressesJSON) == 0 {
this.Fail("请至少添加一个IP地址")
}
// 检查cluster
if params.ClusterId <= 0 {
this.Fail("请选择所在集群")
}
clusterResp, err := this.RPC().NSClusterRPC().FindEnabledNSCluster(this.AdminContext(), &pb.FindEnabledNSClusterRequest{NsClusterId: params.ClusterId})
if err != nil {
this.ErrorPage(err)
return
}
if clusterResp.NsCluster == nil {
this.Fail("选择的集群不存在")
}
// IP地址
ipAddresses := []maps.Map{}
if len(params.IpAddressesJSON) > 0 {
err := json.Unmarshal(params.IpAddressesJSON, &ipAddresses)
if err != nil {
this.ErrorPage(err)
return
}
}
if len(ipAddresses) == 0 {
this.Fail("请至少输入一个IP地址")
}
// 保存
createResp, err := this.RPC().NSNodeRPC().CreateNSNode(this.AdminContext(), &pb.CreateNSNodeRequest{
Name: params.Name,
NodeClusterId: params.ClusterId,
})
if err != nil {
this.ErrorPage(err)
return
}
nodeId := createResp.NsNodeId
// IP地址
for _, addrMap := range ipAddresses {
addressId := addrMap.GetInt64("id")
if addressId > 0 {
_, err = this.RPC().NodeIPAddressRPC().UpdateNodeIPAddressNodeId(this.AdminContext(), &pb.UpdateNodeIPAddressNodeIdRequest{
NodeIPAddressId: addressId,
NodeId: nodeId,
})
} else {
_, err = this.RPC().NodeIPAddressRPC().CreateNodeIPAddress(this.AdminContext(), &pb.CreateNodeIPAddressRequest{
NodeId: nodeId,
Role: nodeconfigs.NodeRoleDNS,
Name: addrMap.GetString("name"),
Ip: addrMap.GetString("ip"),
CanAccess: addrMap.GetBool("canAccess"),
IsUp: addrMap.GetBool("isUp"),
})
}
if err != nil {
this.ErrorPage(err)
return
}
}
// 创建日志
defer this.CreateLog(oplogs.LevelInfo, "创建域名服务节点 %d", nodeId)
this.Success()
}

View File

@@ -1,38 +0,0 @@
package cluster
import (
"github.com/TeaOSLab/EdgeAdmin/internal/oplogs"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
)
type DeleteAction struct {
actionutils.ParentAction
}
func (this *DeleteAction) Init() {
this.Nav("", "delete", "index")
this.SecondMenu("nodes")
}
func (this *DeleteAction) RunGet(params struct{}) {
this.Show()
}
func (this *DeleteAction) RunPost(params struct {
ClusterId int64
}) {
// 创建日志
defer this.CreateLog(oplogs.LevelInfo, "删除域名服务集群 %d", params.ClusterId)
// TODO 如果有用户在使用此集群,就不能删除
// 删除
_, err := this.RPC().NSClusterRPC().DeleteNSCluster(this.AdminContext(), &pb.DeleteNSCluster{NsClusterId: params.ClusterId})
if err != nil {
this.ErrorPage(err)
return
}
this.Success()
}

View File

@@ -1,26 +0,0 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package cluster
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
)
type DeleteNodeAction struct {
actionutils.ParentAction
}
func (this *DeleteNodeAction) RunPost(params struct {
NodeId int64
}) {
defer this.CreateLogInfo("删除域名服务节点 %d", params.NodeId)
_, err := this.RPC().NSNodeRPC().DeleteNSNode(this.AdminContext(), &pb.DeleteNSNodeRequest{NsNodeId: params.NodeId})
if err != nil {
this.ErrorPage(err)
return
}
this.Success()
}

View File

@@ -1,141 +0,0 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package cluster
import (
"encoding/json"
"fmt"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/logs"
"github.com/iwind/TeaGo/maps"
"github.com/iwind/TeaGo/types"
"time"
)
type IndexAction struct {
actionutils.ParentAction
}
func (this *IndexAction) Init() {
this.Nav("", "node", "index")
}
func (this *IndexAction) RunGet(params struct {
ClusterId int64
InstalledState int
ActiveState int
Keyword string
}) {
this.Data["installState"] = params.InstalledState
this.Data["activeState"] = params.ActiveState
this.Data["keyword"] = params.Keyword
countAllResp, err := this.RPC().NSNodeRPC().CountAllEnabledNSNodesMatch(this.AdminContext(), &pb.CountAllEnabledNSNodesMatchRequest{
NsClusterId: params.ClusterId,
})
if err != nil {
this.ErrorPage(err)
return
}
this.Data["countAll"] = countAllResp.Count
countResp, err := this.RPC().NSNodeRPC().CountAllEnabledNSNodesMatch(this.AdminContext(), &pb.CountAllEnabledNSNodesMatchRequest{
NsClusterId: params.ClusterId,
InstallState: types.Int32(params.InstalledState),
ActiveState: types.Int32(params.ActiveState),
Keyword: params.Keyword,
})
if err != nil {
this.ErrorPage(err)
return
}
page := this.NewPage(countResp.Count)
this.Data["page"] = page.AsHTML()
nodesResp, err := this.RPC().NSNodeRPC().ListEnabledNSNodesMatch(this.AdminContext(), &pb.ListEnabledNSNodesMatchRequest{
Offset: page.Offset,
Size: page.Size,
NsClusterId: params.ClusterId,
InstallState: types.Int32(params.InstalledState),
ActiveState: types.Int32(params.ActiveState),
Keyword: params.Keyword,
})
if err != nil {
this.ErrorPage(err)
return
}
nodeMaps := []maps.Map{}
for _, node := range nodesResp.NsNodes {
// 状态
status := &nodeconfigs.NodeStatus{}
if len(node.StatusJSON) > 0 {
err = json.Unmarshal(node.StatusJSON, &status)
if err != nil {
logs.Error(err)
continue
}
status.IsActive = status.IsActive && time.Now().Unix()-status.UpdatedAt <= 60 // N秒之内认为活跃
}
// IP
ipAddressesResp, err := this.RPC().NodeIPAddressRPC().FindAllEnabledNodeIPAddressesWithNodeId(this.AdminContext(), &pb.FindAllEnabledNodeIPAddressesWithNodeIdRequest{
NodeId: node.Id,
Role: nodeconfigs.NodeRoleDNS,
})
if err != nil {
this.ErrorPage(err)
return
}
ipAddresses := []maps.Map{}
for _, addr := range ipAddressesResp.NodeIPAddresses {
ipAddresses = append(ipAddresses, maps.Map{
"id": addr.Id,
"name": addr.Name,
"ip": addr.Ip,
"canAccess": addr.CanAccess,
"isOn": addr.IsOn,
"isUp": addr.IsUp,
})
}
nodeMaps = append(nodeMaps, maps.Map{
"id": node.Id,
"name": node.Name,
"isInstalled": node.IsInstalled,
"isOn": node.IsOn,
"isUp": node.IsUp,
"installStatus": maps.Map{
"isRunning": node.InstallStatus.IsRunning,
"isFinished": node.InstallStatus.IsFinished,
"isOk": node.InstallStatus.IsOk,
"error": node.InstallStatus.Error,
},
"status": maps.Map{
"isActive": node.IsActive,
"updatedAt": status.UpdatedAt,
"hostname": status.Hostname,
"cpuUsage": status.CPUUsage,
"cpuUsageText": fmt.Sprintf("%.2f%%", status.CPUUsage*100),
"memUsage": status.MemoryUsage,
"memUsageText": fmt.Sprintf("%.2f%%", status.MemoryUsage*100),
},
"ipAddresses": ipAddresses,
})
}
this.Data["nodes"] = nodeMaps
// 记录最近访问
_, err = this.RPC().LatestItemRPC().IncreaseLatestItem(this.AdminContext(), &pb.IncreaseLatestItemRequest{
ItemType: "nsCluster",
ItemId: params.ClusterId,
})
if err != nil {
this.ErrorPage(err)
return
}
this.Show()
}

View File

@@ -1,129 +0,0 @@
package cluster
import (
"encoding/json"
"github.com/TeaOSLab/EdgeAdmin/internal/oplogs"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/grants/grantutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/actions"
"github.com/iwind/TeaGo/maps"
)
type UpdateNodeSSHAction struct {
actionutils.ParentAction
}
func (this *UpdateNodeSSHAction) Init() {
this.Nav("", "", "")
}
func (this *UpdateNodeSSHAction) RunGet(params struct {
NodeId int64
}) {
nodeResp, err := this.RPC().NSNodeRPC().FindEnabledNSNode(this.AdminContext(), &pb.FindEnabledNSNodeRequest{NsNodeId: params.NodeId})
if err != nil {
this.ErrorPage(err)
return
}
if nodeResp.NsNode == nil {
this.NotFound("node", params.NodeId)
return
}
node := nodeResp.NsNode
this.Data["node"] = maps.Map{
"id": node.Id,
"name": node.Name,
}
if nodeResp.NsNode.NsCluster != nil {
this.Data["clusterId"] = nodeResp.NsNode.NsCluster.Id
} else {
this.Data["clusterId"] = 0
}
// SSH
loginParams := maps.Map{
"host": "",
"port": "",
"grantId": 0,
}
this.Data["loginId"] = 0
if node.NodeLogin != nil {
this.Data["loginId"] = node.NodeLogin.Id
if len(node.NodeLogin.Params) > 0 {
err = json.Unmarshal(node.NodeLogin.Params, &loginParams)
if err != nil {
this.ErrorPage(err)
return
}
}
}
this.Data["params"] = loginParams
// 认证信息
grantId := loginParams.GetInt64("grantId")
grantResp, err := this.RPC().NodeGrantRPC().FindEnabledNodeGrant(this.AdminContext(), &pb.FindEnabledNodeGrantRequest{NodeGrantId: grantId})
if err != nil {
this.ErrorPage(err)
}
var grantMap maps.Map = nil
if grantResp.NodeGrant != nil {
grantMap = maps.Map{
"id": grantResp.NodeGrant.Id,
"name": grantResp.NodeGrant.Name,
"method": grantResp.NodeGrant.Method,
"methodName": grantutils.FindGrantMethodName(grantResp.NodeGrant.Method),
}
}
this.Data["grant"] = grantMap
this.Show()
}
func (this *UpdateNodeSSHAction) RunPost(params struct {
NodeId int64
LoginId int64
SshHost string
SshPort int
GrantId int64
Must *actions.Must
}) {
params.Must.
Field("sshHost", params.SshHost).
Require("请输入SSH主机地址").
Field("sshPort", params.SshPort).
Gt(0, "SSH主机端口需要大于0").
Lt(65535, "SSH主机端口需要小于65535")
if params.GrantId <= 0 {
this.Fail("需要选择或填写至少一个认证信息")
}
login := &pb.NodeLogin{
Id: params.LoginId,
Name: "SSH",
Type: "ssh",
Params: maps.Map{
"grantId": params.GrantId,
"host": params.SshHost,
"port": params.SshPort,
}.AsJSON(),
}
_, err := this.RPC().NSNodeRPC().UpdateNSNodeLogin(this.AdminContext(), &pb.UpdateNSNodeLoginRequest{
NsNodeId: params.NodeId,
NodeLogin: login,
})
if err != nil {
this.ErrorPage(err)
return
}
// 创建日志
defer this.CreateLog(oplogs.LevelInfo, "修改节点 %d 配置", params.NodeId)
this.Success()
}

View File

@@ -1,17 +0,0 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package cluster
import "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
type UpgradeRemoteAction struct {
actionutils.ParentAction
}
func (this *UpgradeRemoteAction) Init() {
this.Nav("", "", "")
}
func (this *UpgradeRemoteAction) RunGet(params struct{}) {
this.Show()
}

View File

@@ -1,98 +0,0 @@
package clusterutils
import (
"github.com/TeaOSLab/EdgeAdmin/internal/rpc"
"github.com/TeaOSLab/EdgeAdmin/internal/utils/numberutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/actions"
"github.com/iwind/TeaGo/logs"
"github.com/iwind/TeaGo/maps"
"net/http"
"strconv"
)
// ClusterHelper 单个集群的帮助
type ClusterHelper struct {
}
func NewClusterHelper() *ClusterHelper {
return &ClusterHelper{}
}
func (this *ClusterHelper) BeforeAction(actionPtr actions.ActionWrapper) (goNext bool) {
action := actionPtr.Object()
if action.Request.Method != http.MethodGet {
return true
}
action.Data["teaMenu"] = "ns"
selectedTabbar := action.Data.GetString("mainTab")
clusterId := action.ParamInt64("clusterId")
clusterIdString := strconv.FormatInt(clusterId, 10)
action.Data["clusterId"] = clusterId
if clusterId > 0 {
rpcClient, err := rpc.SharedRPC()
if err != nil {
logs.Error(err)
return
}
clusterResp, err := rpcClient.NSClusterRPC().FindEnabledNSCluster(actionPtr.(actionutils.ActionInterface).AdminContext(), &pb.FindEnabledNSClusterRequest{
NsClusterId: clusterId,
})
if err != nil {
logs.Error(err)
return
}
cluster := clusterResp.NsCluster
if cluster == nil {
action.WriteString("can not find ns cluster")
return
}
tabbar := actionutils.NewTabbar()
tabbar.Add("集群列表", "", "/ns/clusters", "", false)
tabbar.Add("集群节点", "", "/ns/clusters/cluster?clusterId="+clusterIdString, "server", selectedTabbar == "node")
tabbar.Add("集群设置", "", "/ns/clusters/cluster/settings?clusterId="+clusterIdString, "setting", selectedTabbar == "setting")
tabbar.Add("删除集群", "", "/ns/clusters/cluster/delete?clusterId="+clusterIdString, "trash", selectedTabbar == "delete")
{
m := tabbar.Add("当前集群:"+cluster.Name, "", "/ns/clusters/cluster?clusterId="+clusterIdString, "", false)
m["right"] = true
}
actionutils.SetTabbar(action, tabbar)
// 左侧菜单
secondMenuItem := action.Data.GetString("secondMenuItem")
switch selectedTabbar {
case "setting":
action.Data["leftMenuItems"] = this.createSettingMenu(cluster, secondMenuItem)
}
}
return true
}
// 设置菜单
func (this *ClusterHelper) createSettingMenu(cluster *pb.NSCluster, selectedItem string) (items []maps.Map) {
clusterId := numberutils.FormatInt64(cluster.Id)
return []maps.Map{
{
"name": "基础设置",
"url": "/ns/clusters/cluster/settings?clusterId=" + clusterId,
"isActive": selectedItem == "basic",
},
{
"name": "访问日志",
"url": "/ns/clusters/cluster/settings/accessLog?clusterId=" + clusterId,
"isActive": selectedItem == "accessLog",
},
{
"name": "递归DNS",
"url": "/ns/clusters/cluster/settings/recursion?clusterId=" + clusterId,
"isActive": selectedItem == "recursion",
},
}
}

View File

@@ -1,68 +0,0 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package clusters
import (
"encoding/json"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/dnsconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/actions"
)
type CreateAction struct {
actionutils.ParentAction
}
func (this *CreateAction) Init() {
this.Nav("", "", "create")
}
func (this *CreateAction) RunGet(params struct{}) {
// 默认的访问日志设置
this.Data["accessLogRef"] = &dnsconfigs.NSAccessLogRef{
IsOn: true,
}
this.Show()
}
func (this *CreateAction) RunPost(params struct {
Name string
AccessLogJSON []byte
Must *actions.Must
CSRF *actionutils.CSRF
}) {
var clusterId int64
defer func() {
this.CreateLogInfo("创建域名服务集群 %d", clusterId)
}()
params.Must.
Field("name", params.Name).
Require("请输入集群名称")
// 校验访问日志设置
ref := &dnsconfigs.NSAccessLogRef{}
err := json.Unmarshal(params.AccessLogJSON, ref)
if err != nil {
this.Fail("数据格式错误:" + err.Error())
}
err = ref.Init()
if err != nil {
this.Fail("数据格式错误:" + err.Error())
}
resp, err := this.RPC().NSClusterRPC().CreateNSCluster(this.AdminContext(), &pb.CreateNSClusterRequest{
Name: params.Name,
AccessLogJSON: params.AccessLogJSON,
})
if err != nil {
this.ErrorPage(err)
return
}
clusterId = resp.NsClusterId
this.Success()
}

View File

@@ -1,77 +0,0 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package clusters
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/configutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/maps"
"github.com/iwind/TeaGo/types"
)
type IndexAction struct {
actionutils.ParentAction
}
func (this *IndexAction) Init() {
this.Nav("", "", "index")
}
func (this *IndexAction) RunGet(params struct{}) {
countResp, err := this.RPC().NSClusterRPC().CountAllEnabledNSClusters(this.AdminContext(), &pb.CountAllEnabledNSClustersRequest{})
if err != nil {
this.ErrorPage(err)
return
}
count := countResp.Count
page := this.NewPage(count)
this.Data["page"] = page.AsHTML()
clustersResp, err := this.RPC().NSClusterRPC().ListEnabledNSClusters(this.AdminContext(), &pb.ListEnabledNSClustersRequest{
Offset: page.Offset,
Size: page.Size,
})
if err != nil {
this.ErrorPage(err)
return
}
clusterMaps := []maps.Map{}
for _, cluster := range clustersResp.NsClusters {
// 全部节点数量
countNodesResp, err := this.RPC().NSNodeRPC().CountAllEnabledNSNodesMatch(this.AdminContext(), &pb.CountAllEnabledNSNodesMatchRequest{NsClusterId: cluster.Id})
if err != nil {
this.ErrorPage(err)
return
}
// 在线节点
countActiveNodesResp, err := this.RPC().NSNodeRPC().CountAllEnabledNSNodesMatch(this.AdminContext(), &pb.CountAllEnabledNSNodesMatchRequest{
NsClusterId: cluster.Id,
ActiveState: types.Int32(configutils.BoolStateYes),
})
if err != nil {
this.ErrorPage(err)
return
}
// 需要升级的节点
countUpgradeNodesResp, err := this.RPC().NSNodeRPC().CountAllUpgradeNSNodesWithNSClusterId(this.AdminContext(), &pb.CountAllUpgradeNSNodesWithNSClusterIdRequest{NsClusterId: cluster.Id})
if err != nil {
this.ErrorPage(err)
return
}
clusterMaps = append(clusterMaps, maps.Map{
"id": cluster.Id,
"name": cluster.Name,
"isOn": cluster.IsOn,
"countAllNodes": countNodesResp.Count,
"countActiveNodes": countActiveNodesResp.Count,
"countUpgradeNodes": countUpgradeNodesResp.Count,
})
}
this.Data["clusters"] = clusterMaps
this.Show()
}

View File

@@ -1,88 +0,0 @@
package logs
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/maps"
timeutil "github.com/iwind/TeaGo/utils/time"
)
type IndexAction struct {
actionutils.ParentAction
}
func (this *IndexAction) Init() {
}
func (this *IndexAction) RunGet(params struct {
DayFrom string
DayTo string
Keyword string
Level string
}) {
this.Data["dayFrom"] = params.DayFrom
this.Data["dayTo"] = params.DayTo
this.Data["keyword"] = params.Keyword
this.Data["level"] = params.Level
countResp, err := this.RPC().NodeLogRPC().CountNodeLogs(this.AdminContext(), &pb.CountNodeLogsRequest{
NodeId: 0,
Role: nodeconfigs.NodeRoleDNS,
DayFrom: params.DayFrom,
DayTo: params.DayTo,
Keyword: params.Keyword,
Level: params.Level,
})
if err != nil {
this.ErrorPage(err)
return
}
count := countResp.Count
page := this.NewPage(count)
this.Data["page"] = page.AsHTML()
logsResp, err := this.RPC().NodeLogRPC().ListNodeLogs(this.AdminContext(), &pb.ListNodeLogsRequest{
NodeId: 0,
Role: nodeconfigs.NodeRoleDNS,
DayFrom: params.DayFrom,
DayTo: params.DayTo,
Keyword: params.Keyword,
Level: params.Level,
Offset: page.Offset,
Size: page.Size,
})
logs := []maps.Map{}
for _, log := range logsResp.NodeLogs {
// 节点信息
nodeResp, err := this.RPC().NSNodeRPC().FindEnabledNSNode(this.AdminContext(), &pb.FindEnabledNSNodeRequest{NsNodeId: log.NodeId})
if err != nil {
continue
}
node := nodeResp.NsNode
if node == nil || node.NsCluster == nil {
continue
}
logs = append(logs, maps.Map{
"tag": log.Tag,
"description": log.Description,
"createdTime": timeutil.FormatTime("Y-m-d H:i:s", log.CreatedAt),
"level": log.Level,
"isToday": timeutil.FormatTime("Y-m-d", log.CreatedAt) == timeutil.Format("Y-m-d"),
"count": log.Count,
"node": maps.Map{
"id": node.Id,
"cluster": maps.Map{
"id": node.NsCluster.Id,
"name": node.NsCluster.Name,
},
"name": node.Name,
},
})
}
this.Data["logs"] = logs
this.Show()
}

View File

@@ -1,30 +0,0 @@
package clusters
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/maps"
)
type OptionsAction struct {
actionutils.ParentAction
}
func (this *OptionsAction) RunPost(params struct{}) {
clustersResp, err := this.RPC().NSClusterRPC().FindAllEnabledNSClusters(this.AdminContext(), &pb.FindAllEnabledNSClustersRequest{})
if err != nil {
this.ErrorPage(err)
return
}
clusterMaps := []maps.Map{}
for _, cluster := range clustersResp.NsClusters {
clusterMaps = append(clusterMaps, maps.Map{
"id": cluster.Id,
"name": cluster.Name,
})
}
this.Data["clusters"] = clusterMaps
this.Success()
}

View File

@@ -1,156 +0,0 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package test
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/dns/domains/domainutils"
"github.com/TeaOSLab/EdgeCommon/pkg/dnsconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/actions"
"github.com/iwind/TeaGo/maps"
"github.com/iwind/TeaGo/types"
"github.com/miekg/dns"
"net"
"regexp"
)
type IndexAction struct {
actionutils.ParentAction
}
func (this *IndexAction) Init() {
this.Nav("", "", "")
}
func (this *IndexAction) RunGet(params struct{}) {
// 集群列表
clustersResp, err := this.RPC().NSClusterRPC().FindAllEnabledNSClusters(this.AdminContext(), &pb.FindAllEnabledNSClustersRequest{})
if err != nil {
this.ErrorPage(err)
return
}
var clusterMaps = []maps.Map{}
for _, cluster := range clustersResp.NsClusters {
if !cluster.IsOn {
continue
}
countNodesResp, err := this.RPC().NSNodeRPC().CountAllEnabledNSNodesMatch(this.AdminContext(), &pb.CountAllEnabledNSNodesMatchRequest{
NsClusterId: cluster.Id,
InstallState: 0,
ActiveState: 0,
Keyword: "",
})
if err != nil {
this.ErrorPage(err)
return
}
var countNodes = countNodesResp.Count
if countNodes <= 0 {
continue
}
clusterMaps = append(clusterMaps, maps.Map{
"id": cluster.Id,
"name": cluster.Name,
"countNodes": countNodes,
})
}
this.Data["clusters"] = clusterMaps
// 记录类型
this.Data["recordTypes"] = dnsconfigs.FindAllRecordTypeDefinitions()
this.Show()
}
func (this *IndexAction) RunPost(params struct {
NodeId int64
Domain string
Type string
Ip string
ClientIP string
Must *actions.Must
}) {
nodeResp, err := this.RPC().NSNodeRPC().FindEnabledNSNode(this.AdminContext(), &pb.FindEnabledNSNodeRequest{NsNodeId: params.NodeId})
if err != nil {
this.ErrorPage(err)
return
}
var node = nodeResp.NsNode
if node == nil {
this.Fail("找不到要测试的节点")
}
var isOk = false
var errMsg string
var isNetError = false
var result string
defer func() {
this.Data["isOk"] = isOk
this.Data["err"] = errMsg
this.Data["isNetErr"] = isNetError
this.Data["result"] = result
this.Success()
}()
if !domainutils.ValidateDomainFormat(params.Domain) {
errMsg = "域名格式错误"
return
}
recordType, ok := dns.StringToType[params.Type]
if !ok {
errMsg = "不支持此记录类型"
return
}
if len(params.ClientIP) > 0 && net.ParseIP(params.ClientIP) == nil {
errMsg = "客户端IP格式不正确"
return
}
var optionId int64
if len(params.ClientIP) > 0 {
optionResp, err := this.RPC().NSQuestionOptionRPC().CreateNSQuestionOption(this.AdminContext(), &pb.CreateNSQuestionOptionRequest{
Name: "setRemoteAddr",
ValuesJSON: maps.Map{"ip": params.ClientIP}.AsJSON(),
})
if err != nil {
this.ErrorPage(err)
return
}
optionId = optionResp.NsQuestionOptionId
defer func() {
_, err = this.RPC().NSQuestionOptionRPC().DeleteNSQuestionOption(this.AdminContext(), &pb.DeleteNSQuestionOptionRequest{NsQuestionOptionId: optionId})
if err != nil {
this.ErrorPage(err)
}
}()
}
c := new(dns.Client)
m := new(dns.Msg)
var domain = params.Domain + "."
if optionId > 0 {
domain = "$" + types.String(optionId) + "-" + domain
}
m.SetQuestion(domain, recordType)
r, _, err := c.Exchange(m, params.Ip+":53")
if err != nil {
errMsg = "解析过程中出错:" + err.Error()
// 是否为网络错误
if regexp.MustCompile(`timeout|connect`).MatchString(err.Error()) {
isNetError = true
}
return
}
result = r.String()
result = regexp.MustCompile(`\$\d+-`).ReplaceAllString(result, "")
isOk = true
}

View File

@@ -1,59 +0,0 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package test
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/maps"
)
type NodeOptionsAction struct {
actionutils.ParentAction
}
func (this *NodeOptionsAction) RunPost(params struct {
ClusterId int64
}) {
nodesResp, err := this.RPC().NSNodeRPC().FindAllEnabledNSNodesWithNSClusterId(this.AdminContext(), &pb.FindAllEnabledNSNodesWithNSClusterIdRequest{NsClusterId: params.ClusterId})
if err != nil {
this.ErrorPage(err)
return
}
var nodeMaps = []maps.Map{}
for _, node := range nodesResp.NsNodes {
if !node.IsOn {
continue
}
addressesResp, err := this.RPC().NodeIPAddressRPC().FindAllEnabledNodeIPAddressesWithNodeId(this.AdminContext(), &pb.FindAllEnabledNodeIPAddressesWithNodeIdRequest{
NodeId: node.Id,
Role: nodeconfigs.NodeRoleDNS,
})
if err != nil {
this.ErrorPage(err)
return
}
var addresses = addressesResp.NodeIPAddresses
if len(addresses) == 0 {
continue
}
var addrs = []string{}
for _, addr := range addresses {
if addr.CanAccess {
addrs = append(addrs, addr.Ip)
}
}
nodeMaps = append(nodeMaps, maps.Map{
"id": node.Id,
"name": node.Name,
"addrs": addrs,
})
}
this.Data["nodes"] = nodeMaps
this.Success()
}

View File

@@ -1,34 +0,0 @@
package users
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/maps"
)
type OptionsAction struct {
actionutils.ParentAction
}
func (this *OptionsAction) RunPost(params struct{}) {
usersResp, err := this.RPC().UserRPC().ListEnabledUsers(this.AdminContext(), &pb.ListEnabledUsersRequest{
Offset: 0,
Size: 10000, // TODO 改进 <ns-user-selector> 组件
})
if err != nil {
this.ErrorPage(err)
return
}
userMaps := []maps.Map{}
for _, user := range usersResp.Users {
userMaps = append(userMaps, maps.Map{
"id": user.Id,
"fullname": user.Fullname,
"username": user.Username,
})
}
this.Data["users"] = userMaps
this.Success()
}

View File

@@ -26,14 +26,14 @@ func (this *CertPopupAction) RunGet(params struct {
return
}
certConfig := &sslconfigs.SSLCertConfig{}
var certConfig = &sslconfigs.SSLCertConfig{}
err = json.Unmarshal(certResp.SslCertJSON, certConfig)
if err != nil {
this.ErrorPage(err)
return
}
reverseCommonNames := []string{}
var reverseCommonNames = []string{}
for i := len(certConfig.CommonNames) - 1; i >= 0; i-- {
reverseCommonNames = append(reverseCommonNames, certConfig.CommonNames[i])
}
@@ -62,7 +62,7 @@ func (this *CertPopupAction) RunGet(params struct {
this.ErrorPage(err)
return
}
serverMaps := []maps.Map{}
var serverMaps = []maps.Map{}
for _, server := range serversResp.Servers {
serverMaps = append(serverMaps, maps.Map{
"id": server.Id,

View File

@@ -1,8 +1,11 @@
package certs
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/actions"
"github.com/iwind/TeaGo/maps"
"github.com/iwind/TeaGo/types"
"net/http"
)
@@ -13,14 +16,29 @@ func NewHelper() *Helper {
return &Helper{}
}
func (this *Helper) BeforeAction(action *actions.ActionObject) {
func (this *Helper) BeforeAction(actionWrapper actions.ActionWrapper) {
var action = actionWrapper.Object()
if action.Request.Method != http.MethodGet {
return
}
action.Data["teaMenu"] = "servers"
action.Data["leftMenuItems"] = []maps.Map{
var countOCSP int64 = 0
parentAction, ok := actionWrapper.(actionutils.ActionInterface)
if ok {
countOCSPResp, err := parentAction.RPC().SSLCertRPC().CountAllSSLCertsWithOCSPError(parentAction.AdminContext(), &pb.CountAllSSLCertsWithOCSPErrorRequest{})
if err == nil {
countOCSP = countOCSPResp.Count
}
}
var ocspMenuName = "OCSP日志"
if countOCSP > 0 {
ocspMenuName += "(" + types.String(countOCSP) + ")"
}
var menu = []maps.Map{
{
"name": "证书",
"url": "/servers/certs",
@@ -31,5 +49,11 @@ func (this *Helper) BeforeAction(action *actions.ActionObject) {
"url": "/servers/certs/acme",
"isActive": action.Data.GetString("leftMenuItem") == "acme",
},
{
"name": ocspMenuName,
"url": "/servers/certs/ocsp",
"isActive": action.Data.GetString("leftMenuItem") == "ocsp",
},
}
action.Data["leftMenuItems"] = menu
}

View File

@@ -25,12 +25,12 @@ func (this *IndexAction) RunGet(params struct {
this.Data["type"] = params.Type
this.Data["keyword"] = params.Keyword
countAll := int64(0)
countCA := int64(0)
countAvailable := int64(0)
countExpired := int64(0)
count7Days := int64(0)
count30Days := int64(0)
var countAll = int64(0)
var countCA = int64(0)
var countAvailable = int64(0)
var countExpired = int64(0)
var count7Days = int64(0)
var count30Days = int64(0)
// 计算数量
{
@@ -147,7 +147,7 @@ func (this *IndexAction) RunGet(params struct {
return
}
certConfigs := []*sslconfigs.SSLCertConfig{}
var certConfigs = []*sslconfigs.SSLCertConfig{}
err = json.Unmarshal(listResp.SslCertsJSON, &certConfigs)
if err != nil {
this.ErrorPage(err)
@@ -155,8 +155,8 @@ func (this *IndexAction) RunGet(params struct {
}
this.Data["certs"] = certConfigs
certMaps := []maps.Map{}
nowTime := time.Now().Unix()
var certMaps = []maps.Map{}
var nowTime = time.Now().Unix()
for _, certConfig := range certConfigs {
countServersResp, err := this.RPC().ServerRPC().CountAllEnabledServersWithSSLCertId(this.AdminContext(), &pb.CountAllEnabledServersWithSSLCertIdRequest{SslCertId: certConfig.Id})
if err != nil {

View File

@@ -5,6 +5,7 @@ import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/certs/acme"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/certs/acme/accounts"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/certs/acme/users"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/certs/ocsp"
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
"github.com/iwind/TeaGo"
)
@@ -55,6 +56,14 @@ func init() {
GetPost("/updatePopup", new(accounts.UpdatePopupAction)).
Post("/delete", new(accounts.DeleteAction)).
// OCSP
Prefix("/servers/certs/ocsp").
Data("leftMenuItem", "ocsp").
Get("", new(ocsp.IndexAction)).
Post("/reset", new(ocsp.ResetAction)).
Post("/resetAll", new(ocsp.ResetAllAction)).
Post("/ignore", new(ocsp.IgnoreAction)).
//
EndAll()
})

View File

@@ -0,0 +1,26 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package ocsp
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
)
type IgnoreAction struct {
actionutils.ParentAction
}
func (this *IgnoreAction) RunPost(params struct {
CertIds []int64
}) {
defer this.CreateLogInfo("忽略一组证书的OCSP状态")
_, err := this.RPC().SSLCertRPC().IgnoreSSLCertsWithOCSPError(this.AdminContext(), &pb.IgnoreSSLCertsWithOCSPErrorRequest{SslCertIds: params.CertIds})
if err != nil {
this.ErrorPage(err)
return
}
this.Success()
}

View File

@@ -0,0 +1,65 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package ocsp
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/maps"
timeutil "github.com/iwind/TeaGo/utils/time"
"time"
)
type IndexAction struct {
actionutils.ParentAction
}
func (this *IndexAction) Init() {
this.SecondMenu("ocsp")
}
func (this *IndexAction) RunGet(params struct {
Keyword string
}) {
this.Data["keyword"] = params.Keyword
countResp, err := this.RPC().SSLCertRPC().CountAllSSLCertsWithOCSPError(this.AdminContext(), &pb.CountAllSSLCertsWithOCSPErrorRequest{Keyword: params.Keyword})
if err != nil {
this.ErrorPage(err)
return
}
var count = countResp.Count
var page = this.NewPage(count)
this.Data["page"] = page.AsHTML()
certsResp, err := this.RPC().SSLCertRPC().ListSSLCertsWithOCSPError(this.AdminContext(), &pb.ListSSLCertsWithOCSPErrorRequest{
Keyword: params.Keyword,
Offset: page.Offset,
Size: page.Size,
})
if err != nil {
this.ErrorPage(err)
return
}
var certMaps = []maps.Map{}
for _, cert := range certsResp.SslCerts {
certMaps = append(certMaps, maps.Map{
"id": cert.Id,
"isOn": cert.IsOn,
"dnsNames": cert.DnsNames,
"commonNames": cert.CommonNames,
"hasOCSP": len(cert.Ocsp) > 0,
"ocspIsUpdated": cert.OcspIsUpdated,
"ocspError": cert.OcspError,
"isCA": cert.IsCA,
"isACME": cert.IsACME,
"name": cert.Name,
"isExpired": cert.TimeEndAt < time.Now().Unix(),
"beginDay": timeutil.FormatTime("Y-m-d", cert.TimeBeginAt),
"endDay": timeutil.FormatTime("Y-m-d", cert.TimeEndAt),
})
}
this.Data["certs"] = certMaps
this.Show()
}

View File

@@ -0,0 +1,26 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package ocsp
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
)
type ResetAction struct {
actionutils.ParentAction
}
func (this *ResetAction) RunPost(params struct {
CertIds []int64
}) {
defer this.CreateLogInfo("重置一组证书的OCSP状态")
_, err := this.RPC().SSLCertRPC().ResetSSLCertsWithOCSPError(this.AdminContext(), &pb.ResetSSLCertsWithOCSPErrorRequest{SslCertIds: params.CertIds})
if err != nil {
this.ErrorPage(err)
return
}
this.Success()
}

View File

@@ -0,0 +1,24 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package ocsp
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
)
type ResetAllAction struct {
actionutils.ParentAction
}
func (this *ResetAllAction) RunPost(params struct{}) {
defer this.CreateLogInfo("忽略所有证书的OCSP状态")
_, err := this.RPC().SSLCertRPC().ResetAllSSLCertsWithOCSPError(this.AdminContext(), &pb.ResetAllSSLCertsWithOCSPErrorRequest{})
if err != nil {
this.ErrorPage(err)
return
}
this.Success()
}

View File

@@ -31,10 +31,12 @@ func (this *CreatePopupAction) RunPost(params struct {
// file
FileDir string
FileMemoryCapacityJSON []byte
FileOpenFileCacheMax int
CapacityJSON []byte
MaxSizeJSON []byte
MaxKeys int64
CapacityJSON []byte
MaxSizeJSON []byte
MaxKeys int64
SyncCompressionCache bool
Description string
IsOn bool
@@ -62,15 +64,23 @@ func (this *CreatePopupAction) RunPost(params struct {
}
}
var openFileCacheConfig *serverconfigs.OpenFileCacheConfig
if params.FileOpenFileCacheMax > 0 {
openFileCacheConfig = &serverconfigs.OpenFileCacheConfig{
IsOn: true,
Max: params.FileOpenFileCacheMax,
}
}
options = &serverconfigs.HTTPFileCacheStorage{
Dir: params.FileDir,
MemoryPolicy: &serverconfigs.HTTPCachePolicy{
Capacity: memoryCapacity,
},
OpenFileCache: openFileCacheConfig,
}
case serverconfigs.CachePolicyStorageMemory:
options = &serverconfigs.HTTPMemoryCacheStorage{
}
options = &serverconfigs.HTTPMemoryCacheStorage{}
default:
this.Fail("请选择正确的缓存类型")
}
@@ -81,14 +91,15 @@ func (this *CreatePopupAction) RunPost(params struct {
return
}
createResp, err := this.RPC().HTTPCachePolicyRPC().CreateHTTPCachePolicy(this.AdminContext(), &pb.CreateHTTPCachePolicyRequest{
IsOn: params.IsOn,
Name: params.Name,
Description: params.Description,
CapacityJSON: params.CapacityJSON,
MaxKeys: params.MaxKeys,
MaxSizeJSON: params.MaxSizeJSON,
Type: params.Type,
OptionsJSON: optionsJSON,
IsOn: params.IsOn,
Name: params.Name,
Description: params.Description,
CapacityJSON: params.CapacityJSON,
MaxKeys: params.MaxKeys,
MaxSizeJSON: params.MaxSizeJSON,
Type: params.Type,
OptionsJSON: optionsJSON,
SyncCompressionCache: params.SyncCompressionCache,
})
if err != nil {
this.ErrorPage(err)

View File

@@ -17,12 +17,18 @@ func (this *IndexAction) Init() {
}
func (this *IndexAction) RunGet(params struct {
Keyword string
ClusterId int64
Keyword string
StorageType string
}) {
this.Data["keyword"] = params.Keyword
this.Data["clusterId"] = params.ClusterId
this.Data["storageType"] = params.StorageType
countResp, err := this.RPC().HTTPCachePolicyRPC().CountAllEnabledHTTPCachePolicies(this.AdminContext(), &pb.CountAllEnabledHTTPCachePoliciesRequest{
Keyword: params.Keyword,
NodeClusterId: params.ClusterId,
Keyword: params.Keyword,
Type: params.StorageType,
})
if err != nil {
this.ErrorPage(err)
@@ -33,9 +39,11 @@ func (this *IndexAction) RunGet(params struct {
this.Data["page"] = page.AsHTML()
listResp, err := this.RPC().HTTPCachePolicyRPC().ListEnabledHTTPCachePolicies(this.AdminContext(), &pb.ListEnabledHTTPCachePoliciesRequest{
Keyword: params.Keyword,
Offset: page.Offset,
Size: page.Size,
Keyword: params.Keyword,
NodeClusterId: params.ClusterId,
Type: params.StorageType,
Offset: page.Offset,
Size: page.Size,
})
if err != nil {
this.ErrorPage(err)
@@ -66,5 +74,8 @@ func (this *IndexAction) RunGet(params struct {
}
this.Data["infos"] = infos
// 所有的存储类型
this.Data["storageTypes"] = serverconfigs.AllCachePolicyStorageTypes
this.Show()
}

View File

@@ -55,10 +55,12 @@ func (this *UpdateAction) RunPost(params struct {
// file
FileDir string
FileMemoryCapacityJSON []byte
FileOpenFileCacheMax int
CapacityJSON []byte
MaxSizeJSON []byte
MaxKeys int64
CapacityJSON []byte
MaxSizeJSON []byte
MaxKeys int64
SyncCompressionCache bool
Description string
IsOn bool
@@ -91,15 +93,23 @@ func (this *UpdateAction) RunPost(params struct {
}
}
var openFileCacheConfig *serverconfigs.OpenFileCacheConfig
if params.FileOpenFileCacheMax > 0 {
openFileCacheConfig = &serverconfigs.OpenFileCacheConfig{
IsOn: true,
Max: params.FileOpenFileCacheMax,
}
}
options = &serverconfigs.HTTPFileCacheStorage{
Dir: params.FileDir,
MemoryPolicy: &serverconfigs.HTTPCachePolicy{
Capacity: memoryCapacity,
},
OpenFileCache: openFileCacheConfig,
}
case serverconfigs.CachePolicyStorageMemory:
options = &serverconfigs.HTTPMemoryCacheStorage{
}
options = &serverconfigs.HTTPMemoryCacheStorage{}
default:
this.Fail("请选择正确的缓存类型")
}
@@ -126,15 +136,16 @@ func (this *UpdateAction) RunPost(params struct {
}
_, err = this.RPC().HTTPCachePolicyRPC().UpdateHTTPCachePolicy(this.AdminContext(), &pb.UpdateHTTPCachePolicyRequest{
HttpCachePolicyId: params.CachePolicyId,
IsOn: params.IsOn,
Name: params.Name,
Description: params.Description,
CapacityJSON: params.CapacityJSON,
MaxKeys: params.MaxKeys,
MaxSizeJSON: params.MaxSizeJSON,
Type: params.Type,
OptionsJSON: optionsJSON,
HttpCachePolicyId: params.CachePolicyId,
IsOn: params.IsOn,
Name: params.Name,
Description: params.Description,
CapacityJSON: params.CapacityJSON,
MaxKeys: params.MaxKeys,
MaxSizeJSON: params.MaxSizeJSON,
Type: params.Type,
OptionsJSON: optionsJSON,
SyncCompressionCache: params.SyncCompressionCache,
})
if err != nil {
this.ErrorPage(err)

View File

@@ -33,7 +33,7 @@ func (this *IndexAction) RunGet(params struct{}) {
globalConfig := &serverconfigs.GlobalConfig{}
// 默认值
globalConfig.HTTPAll.DomainAuditingIsOn = true
globalConfig.HTTPAll.DomainAuditingIsOn = false
if len(valueJSON) > 0 {
err = json.Unmarshal(valueJSON, globalConfig)

View File

@@ -30,6 +30,7 @@ func (this *CreateGroupPopupAction) RunPost(params struct {
Type string
Name string
Code string
Description string
IsOn bool
@@ -52,6 +53,7 @@ func (this *CreateGroupPopupAction) RunPost(params struct {
createResp, err := this.RPC().HTTPFirewallRuleGroupRPC().CreateHTTPFirewallRuleGroup(this.AdminContext(), &pb.CreateHTTPFirewallRuleGroupRequest{
IsOn: params.IsOn,
Name: params.Name,
Code: params.Code,
Description: params.Description,
})
if err != nil {

View File

@@ -61,6 +61,7 @@ func (this *CreateRulePopupAction) RunPost(params struct {
OptionsJSON []byte
Value string
Case bool
Description string
Must *actions.Must
}) {
@@ -91,6 +92,7 @@ func (this *CreateRulePopupAction) RunPost(params struct {
rule.Operator = params.Operator
rule.Value = params.Value
rule.IsCaseInsensitive = params.Case
rule.Description = params.Description
if len(params.OptionsJSON) > 0 {
options := []maps.Map{}

View File

@@ -73,6 +73,7 @@ func (this *CreateSetPopupAction) RunPost(params struct {
RulesJSON []byte
Connector string
ActionsJSON []byte
IgnoreLocal bool
Must *actions.Must
}) {
@@ -124,6 +125,7 @@ func (this *CreateSetPopupAction) RunPost(params struct {
RuleRefs: nil,
Rules: rules,
Actions: actionConfigs,
IgnoreLocal: params.IgnoreLocal,
}
setConfigJSON, err := json.Marshal(setConfig)

View File

@@ -32,24 +32,36 @@ func (this *ExportAction) RunGet(params struct {
return
}
inboundGroups := []*firewallconfigs.HTTPFirewallRuleGroup{}
outboundGroups := []*firewallconfigs.HTTPFirewallRuleGroup{}
enabledInboundGroups := []*firewallconfigs.HTTPFirewallRuleGroup{}
enabledOutboundGroups := []*firewallconfigs.HTTPFirewallRuleGroup{}
disabledInboundGroups := []*firewallconfigs.HTTPFirewallRuleGroup{}
disabledOutboundGroups := []*firewallconfigs.HTTPFirewallRuleGroup{}
if policy.Inbound != nil {
for _, g := range policy.Inbound.Groups {
if g.IsOn {
inboundGroups = append(inboundGroups, g)
enabledInboundGroups = append(enabledInboundGroups, g)
} else {
disabledInboundGroups = append(disabledInboundGroups, g)
}
}
}
if policy.Outbound != nil {
for _, g := range policy.Outbound.Groups {
if g.IsOn {
outboundGroups = append(outboundGroups, g)
enabledOutboundGroups = append(enabledOutboundGroups, g)
} else {
disabledOutboundGroups = append(disabledOutboundGroups, g)
}
}
}
this.Data["inboundGroups"] = inboundGroups
this.Data["outboundGroups"] = outboundGroups
this.Data["enabledInboundGroups"] = enabledInboundGroups
this.Data["enabledOutboundGroups"] = enabledOutboundGroups
this.Data["disabledInboundGroups"] = disabledInboundGroups
this.Data["disabledOutboundGroups"] = disabledOutboundGroups
this.Show()
}
@@ -116,5 +128,6 @@ func (this *ExportAction) RunPost(params struct {
ttlcache.DefaultCache.Write(key, configJSON, time.Now().Unix()+600)
this.Data["key"] = key
this.Data["id"] = params.FirewallPolicyId
this.Success()
}

View File

@@ -3,6 +3,7 @@ package waf
import (
"github.com/TeaOSLab/EdgeAdmin/internal/ttlcache"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/iwind/TeaGo/types"
"strconv"
)
@@ -15,7 +16,8 @@ func (this *ExportDownloadAction) Init() {
}
func (this *ExportDownloadAction) RunGet(params struct {
Key string
Key string
PolicyId int64
}) {
item := ttlcache.DefaultCache.Read(params.Key)
if item == nil || item.Value == nil {
@@ -27,7 +29,7 @@ func (this *ExportDownloadAction) RunGet(params struct {
data, ok := item.Value.([]byte)
if ok {
this.AddHeader("Content-Disposition", "attachment; filename=\"WAF.json\";")
this.AddHeader("Content-Disposition", "attachment; filename=\"WAF-"+types.String(params.PolicyId)+".json\";")
this.AddHeader("Content-Length", strconv.Itoa(len(data)))
this.Write(data)
} else {

View File

@@ -87,6 +87,7 @@ func (this *GroupAction) RunGet(params struct {
"operator": rule.Operator,
"value": rule.Value,
"isCaseInsensitive": rule.IsCaseInsensitive,
"description": rule.Description,
"isComposed": firewallconfigs.CheckCheckpointIsComposed(rule.Prefix()),
"checkpointOptions": rule.CheckpointOptions,
"err": errString,

View File

@@ -43,7 +43,8 @@ func (this *GroupsAction) RunGet(params struct {
"isOn": g.IsOn,
"description": g.Description,
"countSets": len(g.Sets),
"canDelete": len(g.Code) == 0,
"isTemplate": g.IsTemplate,
"canDelete": !g.IsTemplate,
})
}
}
@@ -60,7 +61,8 @@ func (this *GroupsAction) RunGet(params struct {
"isOn": g.IsOn,
"description": g.Description,
"countSets": len(g.Sets),
"canDelete": len(g.Code) == 0,
"isTemplate": g.IsTemplate,
"canDelete": !g.IsTemplate,
})
}
}

View File

@@ -17,12 +17,15 @@ func (this *IndexAction) Init() {
}
func (this *IndexAction) RunGet(params struct {
Keyword string
Keyword string
ClusterId int64
}) {
this.Data["keyword"] = params.Keyword
this.Data["clusterId"] = params.ClusterId
countResp, err := this.RPC().HTTPFirewallPolicyRPC().CountAllEnabledHTTPFirewallPolicies(this.AdminContext(), &pb.CountAllEnabledHTTPFirewallPoliciesRequest{
Keyword: params.Keyword,
NodeClusterId: params.ClusterId,
Keyword: params.Keyword,
})
if err != nil {
this.ErrorPage(err)
@@ -32,9 +35,10 @@ func (this *IndexAction) RunGet(params struct {
page := this.NewPage(count)
listResp, err := this.RPC().HTTPFirewallPolicyRPC().ListEnabledHTTPFirewallPolicies(this.AdminContext(), &pb.ListEnabledHTTPFirewallPoliciesRequest{
Keyword: params.Keyword,
Offset: page.Offset,
Size: page.Size,
NodeClusterId: params.ClusterId,
Keyword: params.Keyword,
Offset: page.Offset,
Size: page.Size,
})
if err != nil {
this.ErrorPage(err)

View File

@@ -41,6 +41,7 @@ func init() {
GetPost("/updateSetPopup", new(UpdateSetPopupAction)).
Post("/count", new(CountAction)).
Get("/selectPopup", new(SelectPopupAction)).
Post("/testRegexp", new(TestRegexpAction)).
// IP管理
GetPost("/ipadmin", new(ipadmin.IndexAction)).

View File

@@ -47,7 +47,7 @@ func (this *IndexAction) RunGet(params struct {
return
}
countryMaps := []maps.Map{}
for _, country := range countriesResp.Countries {
for _, country := range countriesResp.RegionCountries {
countryMaps = append(countryMaps, maps.Map{
"id": country.Id,
"name": country.Name,

View File

@@ -7,6 +7,7 @@ import (
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
"github.com/iwind/TeaGo/maps"
timeutil "github.com/iwind/TeaGo/utils/time"
"time"
)
type ListsAction struct {
@@ -109,6 +110,7 @@ func (this *ListsAction) RunGet(params struct {
"sourceGroup": sourceGroupMap,
"sourceSet": sourceSetMap,
"sourceServer": sourceServerMap,
"lifeSeconds": item.ExpiredAt - time.Now().Unix(),
})
}
this.Data["items"] = itemMaps

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