Compare commits

...

442 Commits

Author SHA1 Message Date
耗子 01eb10bda3 fix: ci 2025-02-06 01:29:58 +08:00
耗子 86376503ac feat: alova.js替换axios 2025-02-06 01:01:18 +08:00
耗子 39fd752825 feat: alova.js替换axios 2025-02-06 00:41:34 +08:00
耗子 0b6eed5fed feat: alova.js替换axios 2025-02-06 00:01:22 +08:00
耗子 9a81c77167 feat: alova.js替换axios 2025-02-05 23:18:36 +08:00
耗子 03c375e7d9 Merge remote-tracking branch 'origin/main' 2025-02-05 22:43:50 +08:00
耗子 645e6d663f feat: alova.js替换axios 2025-02-05 22:43:40 +08:00
renovate[bot] 2b112d735f chore(deps): Update dependency vite to v6.1.0 (#521)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-05 14:38:07 +00:00
耗子 4632cf7d58 Merge remote-tracking branch 'origin/main' 2025-02-05 21:50:31 +08:00
耗子 b15262b5ce feat: 统统变any 2025-02-05 21:49:48 +08:00
renovate[bot] b25456e2fa chore(deps): Update dependency @iconify/json to v2.2.303 (#520)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-05 10:10:15 +00:00
耗子 398bdce676 Merge remote-tracking branch 'origin/main' 2025-02-04 23:52:42 +08:00
耗子 d25c035fc0 feat: axios转alova.js 2025-02-04 23:52:36 +08:00
renovate[bot] 486cbe047b chore(deps): Update module github.com/go-chi/chi/v5 to v5.2.1 (#519)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-04 13:39:23 +00:00
耗子 06d620ac06 fix: lint 2025-02-04 20:40:47 +08:00
耗子 aa661972cc fix: lint 2025-02-04 20:34:44 +08:00
耗子 74261f4045 fix: 修复恢复数据库压缩备份pattern contains path separator 2025-02-04 20:28:27 +08:00
耗子 50ec26ef03 fix: 部分tips出错时未关闭 2025-02-04 18:47:55 +08:00
renovate[bot] dff6d27e04 chore(deps): Update dependency @types/node to v22.13.1 (#518)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-04 00:59:00 +00:00
renovate[bot] e3703975ee chore(deps): Lock file maintenance (#517)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-03 02:01:08 +00:00
renovate[bot] 0cd49a3b18 chore(deps): Update non-major dependencies (#516)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-02 08:58:45 +00:00
renovate[bot] 1ad51e0fa0 chore(deps): Update dependency @types/node to v22.13.0 (#515)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-31 20:51:44 +00:00
renovate[bot] 405d8390bb chore(deps): Update dependency vue-i18n to v11.1.0 (#514)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-31 05:43:15 +00:00
renovate[bot] c4727dca27 chore(deps): Update dependency cronstrue to v2.54.0 (#513)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-30 15:03:03 +00:00
renovate[bot] 19d1169491 chore(deps): Update dependency @iconify/json to v2.2.301 (#512)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-30 09:40:43 +00:00
renovate[bot] e95fb840f7 chore(deps): Update module github.com/samber/lo to v1.49.1 (#511)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-28 12:34:36 +00:00
renovate[bot] 2e0def62ba chore(deps): Update dependency @types/node to v22.12.0 (#510)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-28 10:29:48 +00:00
renovate[bot] a4d12f8590 chore(deps): Update dependency @iconify/json to v2.2.300 (#509)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-27 08:59:23 +00:00
renovate[bot] 8a2c2411af chore(deps): Lock file maintenance (#508)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-27 01:18:52 +00:00
renovate[bot] e79d4b43cc chore(deps): Update module github.com/samber/lo to v1.49.0 (#507)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-27 01:18:15 +00:00
renovate[bot] 169b8c74f7 chore(deps): Update non-major dependencies (#506)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-26 08:52:19 +00:00
renovate[bot] 68eb239619 chore(deps): Update dependency @types/node to v22.10.10 (#505)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-23 18:36:50 +00:00
renovate[bot] 93f4797d44 chore(deps): Update non-major dependencies (#504)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-23 09:23:21 +00:00
renovate[bot] 170453e5ec chore(deps): Update dependency @types/node to v22.10.8 (#503)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-23 05:56:05 +00:00
renovate[bot] 6e44504378 chore(deps): Update non-major dependencies (#502)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-22 10:08:54 +00:00
renovate[bot] 27c851ba8e chore(deps): Update module github.com/go-rat/utils to v1.0.9 (#501)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-22 01:02:01 +00:00
renovate[bot] 03c71a3fe6 chore(deps): Update dependency vite to v6.0.11 (#500)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-21 12:26:49 +00:00
renovate[bot] 95d88cc9a8 chore(deps): Update non-major dependencies (#499)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-20 22:07:23 +00:00
renovate[bot] db909f1235 chore(deps): Update module github.com/go-rat/utils to v1.0.8 (#498)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-20 17:53:32 +00:00
renovate[bot] 27c0451d00 chore(deps): Update dependency vite to v6.0.9 (#497)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-20 14:29:12 +00:00
renovate[bot] 6b66552350 chore(deps): Update non-major dependencies (#496)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-20 09:08:55 +00:00
renovate[bot] c873f850bb chore(deps): Lock file maintenance (#495)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-20 01:37:08 +00:00
renovate[bot] 61b93c81e6 chore(deps): Update dependency @vue/eslint-config-prettier to v10.2.0 (#494)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-18 09:22:48 +00:00
耗子 7181390d94 Merge remote-tracking branch 'origin/main' 2025-01-18 01:39:34 +08:00
耗子 2a9a6301ac feat: 优化systemd服务文件权限 2025-01-18 01:39:18 +08:00
renovate[bot] 22222f0fd7 chore(deps): Update dependency @iconify/json to v2.2.297 (#493)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-17 16:54:08 +00:00
renovate[bot] 74380a5d37 chore(deps): Update dependency @iconify/json to v2.2.296 (#492)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-17 09:14:25 +00:00
耗子 43764cf364 Merge remote-tracking branch 'origin/main' 2025-01-17 03:45:25 +08:00
耗子 6cec736467 fix: lint 2025-01-17 03:45:19 +08:00
renovate[bot] d9138ddf89 chore(deps): Update non-major dependencies to v65.4.2 (#491)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-16 09:51:17 +00:00
renovate[bot] 73c2c31ce6 chore(deps): Update dependency @types/node to v22.10.7 (#490)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-16 05:27:09 +00:00
耗子 f6bd27a0cb feat: 添加新赞助商 2025-01-16 01:36:42 +08:00
耗子 47df0ab396 feat: 添加新赞助商 2025-01-16 01:35:35 +08:00
耗子 35d7049bc1 Merge remote-tracking branch 'origin/main' 2025-01-16 01:29:46 +08:00
耗子 438f7fd458 feat: 添加新赞助商 2025-01-16 01:29:40 +08:00
renovate[bot] 5cc2ae1a32 chore(deps): Update dependency cronstrue to v2.53.0 (#489)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-15 17:04:25 +00:00
耗子 f4af1319c9 Merge remote-tracking branch 'origin/main' 2025-01-16 01:00:26 +08:00
耗子 c966920e29 feat: rename slogGorm to sloggorm 2025-01-16 01:00:21 +08:00
renovate[bot] a80b0ff8d4 chore(deps): Lock file maintenance (#488)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-14 19:52:06 +00:00
renovate[bot] c1ed51767a chore(deps): Lock file maintenance (#487)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-14 19:40:55 +00:00
renovate[bot] 7b8575b6dd chore(deps): Update dependency @vue/eslint-config-typescript to v14.3.0 (#486)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-14 19:40:14 +00:00
renovate[bot] 48c41c7fd5 chore(deps): Update dependency unplugin-icons to v22 (#483)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-14 11:14:08 +00:00
renovate[bot] 16791f3acb chore(deps): Update unocss monorepo to v65 (#485)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-14 11:12:03 +00:00
renovate[bot] 34e00731b5 chore(deps): Update dependency unplugin-vue-components to v28 (#484)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-14 19:07:57 +08:00
renovate[bot] c54bff44cb chore(deps): Update dependency unplugin-auto-import to v19 (#482)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-14 19:07:33 +08:00
renovate[bot] 3b738406c6 chore(deps): Update non-major dependencies (#481)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-14 10:20:26 +00:00
耗子 3f83119b39 fix: 日志切割脚本没有单引号 2025-01-14 18:06:34 +08:00
耗子 0eae148737 fix: 重命名之后文件列表没有刷新 2025-01-07 15:04:40 +08:00
耗子 7a648097d2 fix: redis支持设置密码情况下查看负载 2025-01-06 04:57:05 +08:00
耗子 6de5e799ea fix: 文件重命名错误提示文件已存在 2025-01-05 20:33:19 +08:00
耗子 36d7575f0b fix: test 2025-01-05 19:56:58 +08:00
耗子 48a49db67b fix: 解压缩不支持.gz 2025-01-05 19:53:19 +08:00
耗子 a573a6e44f feat: 有任务运行则跳过自动更新 2025-01-02 21:52:31 +08:00
耗子 d6b016d5e8 feat: 移除面板证书续签并将证书有效期固定为10年 2025-01-02 21:33:53 +08:00
耗子 645a6d2b98 feat: 自动更新失败后尝试修复 2025-01-02 21:32:13 +08:00
耗子 7dc98096a5 fix: 面板任务 2025-01-02 21:21:27 +08:00
耗子 4f5961d7f7 refactor: 重构应用加载器 2025-01-02 21:11:06 +08:00
耗子 4beb040b3d feat: 初始化默认启用自动更新 2025-01-02 19:21:17 +08:00
耗子 092da898b8 feat: 优化证书参数 2025-01-02 19:20:32 +08:00
耗子 818c5b466b fix: ed25519貌似没法正常使用 2025-01-02 19:13:48 +08:00
耗子 5dc14ef1bb feat(#419): 面板自动更新 2025-01-02 19:00:19 +08:00
耗子 813a8f42cf fix: lint 2025-01-02 18:35:45 +08:00
耗子 47fbbe7134 feat: 修改自动任务日志描述 2025-01-02 18:11:18 +08:00
耗子 50d988a62b feat: 自动续签面板证书 2025-01-02 18:07:07 +08:00
耗子 8e3d929def feat: 使用ed25519生成自签名证书 2025-01-02 18:01:17 +08:00
耗子 3022c91eb3 fix: mysql包含特殊字符连接失败 2025-01-01 21:15:13 +08:00
耗子 185f0fdb95 feat: 文件管理优化 2025-01-01 17:32:59 +08:00
耗子 a46b028275 refactor: 新年快乐 2025-01-01 16:01:18 +08:00
耗子 e525d70a03 refactor: 新年快乐 2025-01-01 16:00:33 +08:00
耗子 8b0e7bcaa9 refactor: 新年快乐 2025-01-01 15:33:47 +08:00
耗子 c88d2baf42 refactor: 新年快乐 2025-01-01 15:30:23 +08:00
renovate[bot] 3d53dd1069 chore(deps): Update dependency @types/node to v22.10.3 (#478)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-01 04:49:58 +00:00
耗子 d8a4e7080f feat: 将缓存同步移到安装脚本 2024-12-30 11:49:48 +08:00
耗子 bafdaa460b Merge remote-tracking branch 'origin/main' 2024-12-30 11:48:24 +08:00
耗子 ca5b357e6b feat: 升级面板后清理下载文件 2024-12-30 11:48:18 +08:00
renovate[bot] b28fb497c5 chore(deps): Lock file maintenance (#477)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-30 01:15:12 +00:00
耗子 484eb24083 feat: fix 命令支持修复数据库 2024-12-29 21:34:19 +08:00
耗子 ee48623545 Merge remote-tracking branch 'origin/main' 2024-12-29 21:23:43 +08:00
耗子 48a20c4dce feat: fix 命令支持修复数据库 2024-12-29 21:23:36 +08:00
耗子 3e15f83275 fix: 优化命令行退出 2024-12-29 21:19:33 +08:00
renovate[bot] ac88896ab3 chore(deps): Update dependency @fontsource-variable/jetbrains-mono to v5.1.2 (#476)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-29 12:36:49 +00:00
耗子 4ba50a5556 fix: 应用列表操作列宽度 2024-12-29 16:20:12 +08:00
耗子 75dcaca0b6 fix: s3fs挂载与卸载 2024-12-29 16:16:24 +08:00
耗子 f67c02a0ec feat: 优化命令行数据库迁移 2024-12-29 15:29:34 +08:00
耗子 cff89253c8 fix: cli数据库迁移 2024-12-29 15:13:50 +08:00
耗子 40d6b2c090 fix: 安全登录 2024-12-29 11:28:22 +08:00
耗子 5337620cee fix: pgsql拓展安装 2024-12-29 03:51:57 +08:00
耗子 3bdfb7f9af workflow: fix version 2024-12-29 03:29:22 +08:00
耗子 d51d419086 fix: 验证器错误 2024-12-29 03:13:30 +08:00
renovate[bot] 70d9e5e83c chore(deps): Update dependency @iconify/json to v2.2.290 (#474)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-28 19:00:57 +00:00
耗子 31d1df1371 workflow: try fix copy 2024-12-29 02:55:12 +08:00
耗子 96cc85393a workflow: try fix copy 2024-12-29 02:52:46 +08:00
耗子 e5839678b3 chore: optimize auto import 2024-12-29 02:44:56 +08:00
耗子 f7b0798e8c chore: add .eslintrc-auto-import.json to gitignore 2024-12-29 02:22:18 +08:00
耗子 7c3e11a0c0 workflow: fix goreleaser 2024-12-29 02:18:35 +08:00
耗子 f3baff2aeb fix: 版权声明 2024-12-29 02:11:04 +08:00
耗子 ba544e3305 feat: 优化内存参数 2024-12-29 02:09:12 +08:00
耗子 37119d1402 feat[文件]: 优化未知用户显示 2024-12-29 02:08:26 +08:00
耗子 2d0a0d5293 fix: fix #443 2024-12-29 01:54:37 +08:00
耗子 7d48a80bf0 feat: 优化证书列表操作列 2024-12-29 01:52:42 +08:00
耗子 def1f2d62c Merge remote-tracking branch 'origin/main' 2024-12-29 01:49:23 +08:00
耗子 b5f2475cf9 feat: 优化验证规则 2024-12-29 01:49:15 +08:00
renovate[bot] e9a6fc0d6e chore(deps): Update dependency typescript to v5.7.2 (#473)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-28 17:45:33 +00:00
耗子 f71456db0e feat: 优化验证规则 2024-12-29 01:41:19 +08:00
耗子 3b332cf7a6 fix: nginx parser 2024-12-29 00:54:19 +08:00
renovate[bot] 50979e1904 chore(deps): Update dependency echarts to v5.6.0 (#472)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-28 11:23:43 +00:00
耗子 84b154f1b9 feat: 添加pgsql拓展 2024-12-27 13:04:40 +08:00
耗子 ca7865664f chore: update renovate config 2024-12-27 13:02:10 +08:00
耗子 67537ef617 fix: build 2024-12-27 13:01:05 +08:00
耗子 bd365c4e15 chore: update dependences 2024-12-27 12:56:59 +08:00
renovate[bot] d47a764848 chore(deps): Update non-major dependencies 2024-12-26 19:07:29 +00:00
renovate[bot] 69d5d5cb21 chore(deps): Update dependency vue-i18n to v11 (#470)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-25 08:17:02 +08:00
renovate[bot] b5150193d0 chore(deps): Lock file maintenance (#469)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-23 04:58:48 +00:00
耗子 d3309c3a72 workflow: 合并前后端工作流 2024-12-20 15:55:30 +08:00
耗子 bbe07f7bdd workflow: 合并前后端工作流 2024-12-20 15:51:48 +08:00
耗子 c5b23aaa57 chore: add .gitkeep 2024-12-20 15:11:29 +08:00
耗子 ef60a44fbf chore: update build config 2024-12-20 15:07:10 +08:00
耗子 0bea527004 chore: update renovate config 2024-12-20 12:56:06 +08:00
renovate[bot] c1b270851a chore(deps): Update module github.com/mholt/acmez/v3 to v3.0.0 (#467)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-19 21:01:50 +00:00
耗子 b264e5d884 chore: update renovate config 2024-12-19 18:43:38 +08:00
renovate[bot] 2deced3458 chore(deps): Update all dependencies (#466)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-19 18:30:34 +08:00
renovate[bot] 6c274f1644 chore(deps): Update dependency @iconify/json to v2.2.286 (#465)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-19 18:22:00 +08:00
renovate[bot] a279a4508c chore(deps): Update all dependencies (#464)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-19 00:41:11 +00:00
renovate[bot] 12b5daf305 chore(deps): Update module github.com/spf13/cast to v1.7.1 (#463)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-18 12:25:16 +00:00
耗子 03c74b2187 feat(跑分): 降低 aes 测试难度 2024-12-18 11:06:20 +08:00
renovate[bot] c3e0bf7aed chore(deps): Update dependency @iconify/json to v2.2.285 (#461)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-17 20:22:35 +08:00
renovate[bot] cd815fb7cd chore(deps): Update module github.com/TheTNB/acmez/v3 to v3.0.0-20241217024017-a2f2c48efdcc (#460)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-17 16:20:35 +08:00
renovate[bot] 8d7084091e chore(deps): Update all dependencies (#459)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-17 15:52:28 +08:00
renovate[bot] 98eeec73b6 chore(deps): Update dependency pinia-plugin-persistedstate to v4.2.0 (#457)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-17 00:09:12 +00:00
renovate[bot] 5542ec2f4b chore(deps): Update dependency npm-run-all2 to v7.0.2 (#456)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-16 21:46:55 +00:00
renovate[bot] 1565bcfee3 chore(deps): Update dependency @iconify/json to v2.2.284 (#454)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-16 19:00:24 +00:00
renovate[bot] 0f1181210a chore(deps): Update all dependencies (#453)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-16 12:56:44 +00:00
renovate[bot] a27cae1e3f chore(deps): Update dependency unplugin-vue-components to ^0.28.0 (#452)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-16 14:23:20 +08:00
耗子 c2621836fe fix: render release 2024-12-16 12:25:19 +08:00
renovate[bot] aae3951638 chore(deps): Lock file maintenance (#451)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-16 11:36:08 +08:00
renovate[bot] 083c6bfada chore(deps): Lock file maintenance (#450)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-16 11:34:20 +08:00
renovate[bot] 34fbda8bd8 chore(deps): Lock file maintenance (#449)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-16 03:01:43 +00:00
renovate[bot] f8aa8934f1 chore(deps): Update module github.com/go-chi/chi/v5 to v5.2.0 (#447)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-16 10:00:22 +08:00
renovate[bot] c09907610e chore(deps): Lock file maintenance (#448)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-16 10:00:10 +08:00
耗子 ed31eb6e64 feat: go mod tidy 2024-12-16 03:06:07 +08:00
耗子 015fb76d4c feat: 生成mock 2024-12-16 02:53:46 +08:00
耗子 a70f3901f7 fix: 计划任务启用后仍显示未启用 2024-12-16 02:50:10 +08:00
耗子 a3bd4c5bcc feat: 同步验证器修改 2024-12-16 02:41:32 +08:00
耗子 a64660d0cb refactor: 应用支持依赖注入 2024-12-16 02:01:31 +08:00
耗子 1fdc86cc0a fix: lint 2024-12-15 23:31:08 +08:00
耗子 fe4f0d6dea feat: 中间件注入 2024-12-15 23:25:45 +08:00
耗子 8116ea7767 fix: jobs 2024-12-15 23:16:08 +08:00
耗子 2050a96dcf fix: 加解密 2024-12-15 23:04:50 +08:00
耗子 cd1d7c9757 refactor: 初步实现依赖注入 2024-12-15 23:01:17 +08:00
耗子 24af7bab5f refactor: 替换验证器 2024-12-15 19:44:49 +08:00
耗子 81be655113 feat: 修改phpredis的描述 2024-12-15 17:36:40 +08:00
耗子 5b5e10dee0 chore: 优化bug模板 2024-12-15 17:30:27 +08:00
耗子 c73e3d0f18 chore: 优化ci及问题模板 2024-12-15 17:17:10 +08:00
耗子 af25b676f8 chore: 优化ci及问题模板 2024-12-15 17:14:39 +08:00
耗子 f8b718d99f workflow: remove auto reply 2024-12-15 17:05:30 +08:00
renovate[bot] 7792174409 chore(deps): Update dependency marked to v15.0.4 (#444)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-15 06:14:53 +00:00
耗子 6eced537f4 workflow: 缩短运行间隔 2024-12-15 02:45:39 +08:00
耗子 7315b3d443 feat: 移除内存优化 2024-12-15 01:43:03 +08:00
耗子 567b5ea82e feat: 更新文档 2024-12-14 18:51:42 +08:00
耗子 8d4a2c38ca feat: 更新文档 2024-12-14 18:48:54 +08:00
耗子 3ffafee82e feat: 更新文档 2024-12-14 18:44:21 +08:00
renovate[bot] 423cd48e18 chore(deps): Update module github.com/mholt/acmez/v3 to v3.0.0-20241214053340-45433dfc1161 (#442)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-14 09:32:50 +00:00
renovate[bot] b169514666 chore(deps): Update dependency eslint to v9.17.0 (#441)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-14 00:05:37 +00:00
renovate[bot] c15000d307 chore(deps): Update all dependencies (#440)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-13 12:10:48 +00:00
renovate[bot] 27d2eaaaff chore(deps): Update dependency sass to v1.83.0 (#439)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-13 09:09:05 +08:00
renovate[bot] 48e52f2f94 chore(deps): Update dependency @iconify/json to v2.2.282 (#438)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-12 13:52:53 +00:00
renovate[bot] 1252a02d66 chore(deps): Update module github.com/bddjr/hlfhr to v1.3.5 (#437)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-12 06:28:49 +00:00
renovate[bot] 38c99f4226 chore(deps): Update module golang.org/x/crypto to v0.31.0 (#436)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-11 22:19:00 +00:00
renovate[bot] 906e606e1b chore(deps): Update all dependencies (#435)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-11 23:20:17 +08:00
renovate[bot] b47b8b5675 chore(deps): Update dependency monaco-editor to v0.52.2 (#434)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-10 00:47:59 +08:00
耗子 1902a59ebd feat: 优化客户端hash使用sha256计算 2024-12-10 00:46:24 +08:00
耗子 939d108c56 Merge remote-tracking branch 'origin/main'
# Conflicts:
#	go.sum
2024-12-10 00:40:47 +08:00
耗子 19a0d2368e feat: 优化移除zap 2024-12-10 00:39:16 +08:00
renovate[bot] 984e320074 chore(deps): Update all dependencies (#433)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-09 22:20:04 +08:00
renovate[bot] 2d203ded01 chore(deps): Lock file maintenance (#432)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-09 03:58:07 +00:00
renovate[bot] bc72ece7c0 chore(deps): Update dependency @iconify/vue to v4.2.0 (#431)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-07 17:27:35 +08:00
耗子 6393721d7a fix: 数据库链接内存泄漏 2024-12-07 04:09:50 +08:00
renovate[bot] 9cfc2417d6 chore(deps): Update dependency @iconify/json to v2.2.280 (#430)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-06 19:25:33 +08:00
renovate[bot] d37433ce9f chore(deps): Update dependency vite to v6.0.3 (#429)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-05 20:11:22 +00:00
耗子 ef3badd400 docs: update ui.png 2024-12-05 21:10:53 +08:00
耗子 0986a02a94 docs: update alipay qr code 2024-12-05 21:07:27 +08:00
renovate[bot] 38c7c3a477 chore(deps): Update github.com/tufanbarisyildirim/gonginx digest to 3234810 (#428)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-05 20:59:57 +08:00
renovate[bot] 20a6441d22 chore(deps): Update all dependencies (#427)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-05 10:28:28 +08:00
renovate[bot] bfa189e6fb chore(deps): Update dependency pinia to v2.3.0 (#426)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-04 18:50:39 +00:00
renovate[bot] 4bc7fd3df8 chore(deps): Update module github.com/bddjr/hlfhr to v1.3.1 (#425)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-04 17:58:46 +08:00
renovate[bot] 276ca5dbbd chore(deps): Update all dependencies (#424)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-04 16:43:54 +08:00
renovate[bot] 857637ece6 chore(deps): Update module github.com/bddjr/hlfhr to v1.3.0 (#423)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-04 02:03:45 +08:00
耗子 9ce41bc02c ci: fix release 2024-12-03 22:17:15 +08:00
耗子 2f87de40da feat: 优化白屏加载 2024-12-03 22:08:31 +08:00
renovate[bot] b47bd5c14d chore(deps): Update module github.com/bddjr/hlfhr to v1.2.6 (#422)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-03 22:00:52 +08:00
耗子 a0d92d594c fix: 侧边栏滚不动 2024-12-03 21:56:13 +08:00
renovate[bot] c8ebadfc4d chore(deps): Update all dependencies (#421)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-03 21:18:32 +08:00
耗子 a3bbbfa87c feat: 进程管理 2024-12-03 21:14:27 +08:00
耗子 8c7a65a8b6 feat: 优化会话key 2024-12-03 17:20:04 +08:00
耗子 4b9ce222ba feat: 替换论坛链接 2024-12-03 17:07:27 +08:00
耗子 29ad4f5f34 Merge remote-tracking branch 'origin/main' 2024-12-03 16:42:45 +08:00
耗子 a505a6be92 fix: lint 2024-12-03 16:42:22 +08:00
renovate[bot] d21a9f0559 chore(deps): Update dependency sass to v1.81.1 (#420)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-03 06:33:21 +00:00
耗子 a5eee5eeec feat: 数据库密码复制 2024-12-03 11:02:20 +08:00
耗子 fc87cd0360 feat: logo 自定义 2024-12-03 10:55:39 +08:00
耗子 fc97709ebf feat: 优化安全登录 2024-12-03 04:03:21 +08:00
耗子 7bc716cff6 feat: 实现安全登录 2024-12-03 03:46:28 +08:00
耗子 128f44ca55 workflow: 更新ci文件 2024-12-03 00:01:26 +08:00
耗子 2ebe0ba47d chore: 优化编译信息展示 2024-12-02 23:39:52 +08:00
耗子 1fee3632fc chore: 优化编译注入 2024-12-02 23:18:16 +08:00
耗子 f66ce68e36 chore: 版本号自动注入测试 2024-12-02 22:48:50 +08:00
耗子 599ea2c245 chore: 版本号自动注入测试 2024-12-02 22:45:49 +08:00
renovate[bot] 674c48cce3 chore(deps): Update all dependencies to ^0.65.0 (#418)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-02 20:21:57 +08:00
renovate[bot] 18ba92f44b chore(deps): Update module github.com/bddjr/hlfhr to v1.2.5 (#417)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-02 15:25:55 +08:00
renovate[bot] e8f7e1af76 chore(deps): Update dependency vite to v6.0.2 (#416)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-02 15:23:12 +08:00
renovate[bot] 9ae19208cb chore(deps): Lock file maintenance (#415)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-02 04:30:11 +00:00
renovate[bot] ee13b03748 chore(deps): Update dependency naive-ui to v2.40.3 (#414)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-02 02:17:12 +08:00
耗子 1cbb42a008 docs: 更新赞助说明 2024-12-01 22:48:38 +08:00
renovate[bot] 4a7258009d chore(deps): Update module github.com/urfave/cli/v3 to v3.0.0-beta1 (#413)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-01 05:38:06 +08:00
renovate[bot] 84158b2398 chore(deps): Update dependency @iconify/json to v2.2.278 (#412)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-30 19:26:07 +08:00
renovate[bot] 460ab12af3 chore(deps): Update dependency eslint-plugin-vue to v9.32.0 (#411)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-30 15:49:38 +08:00
renovate[bot] 78de211e49 chore(deps): Update all dependencies (#410)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-30 03:38:03 +00:00
renovate[bot] 234180f160 chore(deps): Update all dependencies (#408)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-29 22:59:40 +08:00
renovate[bot] f25a809dc9 chore(deps): Update github.com/devhaozi/tencentcloud digest to 7d4e898 (#407)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-29 19:20:28 +08:00
renovate[bot] 0651f0efc9 chore(deps): Update dawidd6/action-download-artifact action to v7 (#406)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-29 19:19:39 +08:00
耗子 8d58adfab4 chore: update dependences 2024-11-29 18:47:34 +08:00
耗子 0b08e59b6e Merge remote-tracking branch 'origin/main'
# Conflicts:
#	go.sum
2024-11-29 18:47:24 +08:00
耗子 6a60895eac chore: update dependences 2024-11-29 18:47:13 +08:00
renovate[bot] 37c10e65a4 chore(deps): Update dependency marked to v15.0.3 (#405)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-29 16:31:44 +08:00
renovate[bot] 695318d96e chore(deps): Update module github.com/urfave/cli/v3 to v3.0.0-alpha9.7 (#404)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-29 00:19:01 +00:00
耗子 40a57792ff feat: 发布v2.3.22 2024-11-29 02:39:36 +08:00
耗子 7c75508b25 feat: 菜单隐藏 2024-11-29 02:30:12 +08:00
耗子 7da21e3d6a feat: 菜单优化1 2024-11-29 01:28:09 +08:00
renovate[bot] e7ddedea76 chore(deps): Update dependency pinia to v2.2.8 (#403)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-29 00:03:28 +08:00
耗子 7a656595d9 Merge remote-tracking branch 'origin/main' 2024-11-28 23:52:13 +08:00
renovate[bot] 5087399b26 chore(deps): Update dependency vite-plugin-vue-devtools to v7.6.7 (#402)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-28 23:51:59 +08:00
耗子 110b40edd7 feat(网站): 支持选择伪静态规则 2024-11-28 23:51:01 +08:00
耗子 fec09652b7 fix: base64 decode 2024-11-28 20:45:22 +08:00
耗子 1dc0042507 feat(文件): 图片支持预览 2024-11-28 20:32:16 +08:00
renovate[bot] 746d2297fe chore(deps): Update dependency @iconify/json to v2.2.277 (#401)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-28 18:08:56 +08:00
renovate[bot] 7736143928 chore(deps): Update all dependencies (#400)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-28 17:54:50 +08:00
renovate[bot] a680a46a22 chore(deps): Update all dependencies (#399)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-28 01:45:00 +08:00
耗子 bdd1565221 chore: bump vite to v6 2024-11-28 01:40:08 +08:00
renovate[bot] c0e32b46c5 chore(deps): Update all dependencies 2024-11-27 12:12:41 +00:00
renovate[bot] 03b3ea3a8b chore(deps): Update all dependencies (#397)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-27 12:11:40 +00:00
耗子 5efeceecdb fix: 在线更新点不动 2024-11-27 04:00:17 +08:00
耗子 52587e9cb3 fix: postgresql 数据库删除 2024-11-27 03:52:37 +08:00
耗子 c2aa4a4904 feat: 去除迁移的强校验 2024-11-27 03:48:43 +08:00
耗子 0f0ab6b678 feat: 发布v2.3.21 2024-11-27 03:36:24 +08:00
renovate[bot] 6902d4dd2c chore(deps): Update all dependencies (#395)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-27 03:34:26 +08:00
耗子 1b7406ebfa feat: 更新php8.4拓展 2024-11-27 03:32:52 +08:00
耗子 8d729aaf48 feat: 数据库服务器支持修改 2024-11-27 03:29:41 +08:00
耗子 c2ae9dc4a1 feat: 优化数据库删除 2024-11-27 03:09:40 +08:00
耗子 5d5633b31a feat: 优化创建网站创建数据库 2024-11-27 02:14:16 +08:00
耗子 3677d0317c feat: 数据库管理优化2 2024-11-27 01:45:58 +08:00
耗子 cd8a10d799 feat: 数据库管理优化1 2024-11-27 01:08:14 +08:00
耗子 3926bb83c1 fix: swoole和ioncube不支持php84 2024-11-27 00:02:00 +08:00
耗子 e666396b03 fix: mysql用户删除 2024-11-26 22:51:17 +08:00
renovate[bot] ad12a83c0f chore(deps): Update all dependencies (#393)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-26 14:56:08 +08:00
renovate[bot] bc66c49fe2 chore(deps): Update all dependencies (#392)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-26 02:26:01 +00:00
耗子 01a4ec8800 fix: PHP84 管理页 2024-11-26 04:44:44 +08:00
耗子 637fb83398 feat: 发布v2.3.20 2024-11-26 04:15:29 +08:00
耗子 ff67ace165 feat: 添加CLI命令 2024-11-26 04:06:04 +08:00
renovate[bot] c1580afadf chore(deps): Update all dependencies (#390)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-26 03:52:29 +08:00
耗子 9a2e68e24e feat: 数据库管理基本完成 2024-11-26 03:50:54 +08:00
耗子 3fbaecbe9e feat: 数据库用户管理2 2024-11-26 03:19:33 +08:00
耗子 a2c96993d3 feat: update node 22 2024-11-26 02:40:02 +08:00
耗子 2208ff1c29 fix: build 2024-11-26 02:27:24 +08:00
耗子 146c9aadbd feat: update eslint to v9 2024-11-26 02:19:20 +08:00
耗子 929219e487 feat: update eslint to v9 2024-11-26 02:18:45 +08:00
耗子 7aca6587af fix: 文件名称检查支持中文 2024-11-26 01:18:08 +08:00
renovate[bot] a8575bcda9 chore(deps): Lock file maintenance (#388)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-25 22:10:09 +08:00
renovate[bot] bdaa3c005b chore(deps): Update module github.com/urfave/cli/v3 to v3.0.0-alpha9.5 (#389)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-25 22:09:50 +08:00
renovate[bot] e6fe1e48f7 chore(deps): Update all dependencies (#387)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-25 22:07:01 +08:00
耗子 33cb41cf42 feat: 优化数据库信息获取 2024-11-25 03:18:36 +08:00
耗子 0df2a9107d feat: 数据库用户接口 2024-11-25 03:01:02 +08:00
耗子 7f61793b36 feat: php 8.4 2024-11-25 01:45:19 +08:00
耗子 7d9de56a82 feat: 重构数据库1 2024-11-24 20:46:25 +08:00
renovate[bot] 18148b15b0 chore(deps): Update all dependencies (#385)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-23 06:31:26 +00:00
耗子 ad989337b3 docs: update README 2024-11-23 03:07:20 +08:00
耗子 81d32420c0 docs: update README 2024-11-23 02:55:15 +08:00
耗子 5538f7498b fix: lock typescript to fix build 2024-11-23 02:47:19 +08:00
耗子 371d2b3ac0 Merge remote-tracking branch 'origin/main' 2024-11-23 02:37:39 +08:00
renovate[bot] ff17aee372 chore(deps): Update all dependencies (#383)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-23 02:37:31 +08:00
耗子 9e1d525b20 feat: 数据库权限 2024-11-23 01:53:08 +08:00
renovate[bot] f6526c15fa chore(deps): Update all dependencies (#382)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-22 23:48:18 +08:00
耗子 be3ae54efe fix: lint 2024-11-22 23:29:49 +08:00
耗子 214b804062 feat: 数据库同步及fail2ban重构 2024-11-22 22:46:26 +08:00
耗子 e1f074f116 feat: 防火墙正确处理多ip规则 2024-11-22 19:52:02 +08:00
耗子 a96bbf3dfb feat: 数据库管理提交1 2024-11-22 02:58:31 +08:00
renovate[bot] 39d2eee676 chore(deps): Update dependency cronstrue to v2.52.0 (#381)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-22 02:19:32 +08:00
renovate[bot] 8c17b295a2 chore(deps): Update all dependencies (#380)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-21 12:30:55 +00:00
renovate[bot] 452ef92d8f chore(deps): Update dependency marked to v15.0.2 (#379)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-21 04:33:59 +00:00
耗子 df49e167a9 feat: 优化php状态使用json接口获取 2024-11-20 20:26:18 +08:00
耗子 f3aa240aa9 Merge remote-tracking branch 'origin/main' 2024-11-20 20:24:22 +08:00
renovate[bot] d81f4df8b6 chore(deps): Update module github.com/go-resty/resty/v2 to v2.16.1 (#378)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-20 15:42:04 +08:00
renovate[bot] 4c2f9f1bbc chore(deps): Update dependency @types/node to v22.9.1 (#377)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-19 21:49:41 +00:00
renovate[bot] e2080b0603 chore(deps): Update dependency @iconify/json to v2.2.274 (#376)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-19 18:55:05 +00:00
renovate[bot] 53eb005531 chore(deps): Update dependency md-editor-v3 to v5.0.2 (#375)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-19 13:21:45 +00:00
renovate[bot] 9ae7b5201c chore(deps): Update dependency unplugin-auto-import to v0.18.5 (#374)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-19 04:05:51 +00:00
耗子 119411a3ce fix: 优化样式 2024-11-19 01:56:17 +08:00
耗子 112fc30437 feat: 阻止删除关键目录 2024-11-19 01:26:06 +08:00
renovate[bot] dea96649d7 chore(deps): Update module github.com/bddjr/hlfhr to v1.2.4 (#373)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-19 01:03:03 +08:00
renovate[bot] 2d136e40c5 chore(deps): Update dependency marked to v15.0.1 (#372)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-18 16:55:27 +08:00
耗子 11e4d05181 Merge remote-tracking branch 'origin/main' 2024-11-18 14:13:16 +08:00
耗子 50381dff0c feat: 防跨站使用网站目录而不是运行目录 2024-11-18 14:13:09 +08:00
renovate[bot] 8e40d9a75d chore(deps): Lock file maintenance (#371)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-18 03:39:07 +00:00
耗子 8251a9a70e Merge remote-tracking branch 'origin/main' 2024-11-18 03:54:54 +08:00
耗子 0297ccbf28 feat: 优化商店缓存更新防止挤爆接口 2024-11-18 03:54:48 +08:00
renovate[bot] a9113f3e4c chore(deps): Update module github.com/bddjr/hlfhr to v1.2.2 (#370)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-18 02:30:58 +08:00
耗子 17918c0f1f fix: build 2024-11-18 00:26:59 +08:00
耗子 9509cfa4e2 Merge remote-tracking branch 'origin/main' 2024-11-18 00:18:34 +08:00
耗子 1e32f9addc feat: 修改部分菜单名称 2024-11-18 00:18:20 +08:00
renovate[bot] abe2e1fd3d chore(deps): Update module github.com/bddjr/hlfhr to v1.2.0 (#369)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-17 21:37:19 +08:00
耗子 cbf9bdc926 fix: 证书为空时页面js报错 2024-11-17 19:47:58 +08:00
renovate[bot] ab4a94c32d chore(deps): Update module github.com/go-playground/validator/v10 to v10.23.0 (#368)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-17 03:30:56 +08:00
耗子 0ba29c7c40 feat: 防跨站避免覆盖修改 2024-11-16 21:40:00 +08:00
耗子 e99c71b8e1 feat: 文件删除显示文件名 2024-11-16 20:58:28 +08:00
renovate[bot] b95b035991 chore(deps): Update dependency @iconify/json to v2.2.273 (#367)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-16 12:02:08 +00:00
renovate[bot] 5959cab965 chore(deps): Update github.com/tufanbarisyildirim/gonginx digest to 128af6d (#366)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-15 22:05:01 +00:00
renovate[bot] d4668f2a7e chore(deps): Update all dependencies (#365)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-16 00:21:53 +08:00
耗子 e1fb498aa5 docs: 更新 star 历史 2024-11-15 21:57:54 +08:00
renovate[bot] 6413d6462c chore(deps): Update all dependencies (#364)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-15 16:07:50 +08:00
renovate[bot] 3f9fce7841 chore(deps): Update dependency sass to v1.81.0 (#363)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-15 06:38:30 +00:00
renovate[bot] 58d100e636 chore(deps): Update codecov/codecov-action action to v5 (#362)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-15 00:14:11 +00:00
renovate[bot] 98d57b6c23 chore(deps): Update dependency @vue-js-cron/naive-ui to v2.0.8 (#361)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-14 21:34:49 +00:00
耗子 3a8c7784f5 chore: 更新描述 2024-11-14 19:34:10 +08:00
renovate[bot] 02bfddcf03 chore(deps): Update all dependencies (#360)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-14 10:59:43 +00:00
renovate[bot] 55750796b3 chore(deps): Update dependency @vitejs/plugin-vue to v5.2.0 (#359)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-13 22:35:09 +08:00
renovate[bot] 692f8ca030 chore(deps): Update dependency md-editor-v3 to v5 (#358)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-13 12:08:00 +00:00
renovate[bot] fbe99ea4dd chore(deps): Update dependency sass to v1.80.7 (#357)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-13 13:36:15 +08:00
耗子 d34438d90e Merge remote-tracking branch 'origin/main' 2024-11-13 12:01:54 +08:00
耗子 47e114d43e feat: 修改面板端口前检查占用 2024-11-13 12:01:47 +08:00
renovate[bot] 0b9bba45d7 chore(deps): Update dependency @iconify/json to v2.2.271 (#356)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-12 23:31:09 +08:00
耗子 00ea2f40e2 fix: 创建网站未创建postgres数据库 2024-11-12 19:39:47 +08:00
耗子 5183653dbb fix: 创建网站未保存备注 2024-11-12 19:24:44 +08:00
renovate[bot] 9f7d8e413e chore(deps): Update all dependencies (#355)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-12 10:47:29 +00:00
耗子 4450d2c8d1 fix: test 2024-11-12 12:56:17 +08:00
耗子 b5f7458344 fix: 带 i 属性的文件无法保存 2024-11-12 03:14:53 +08:00
耗子 da44f1a8fe feat: 发布v2.3.19 2024-11-12 02:50:24 +08:00
耗子 0317aa1401 feat: redis添加清空 2024-11-12 02:46:54 +08:00
renovate[bot] 90fc48f478 chore(deps): Update dependency vite to v5.4.11 (#354)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-11 14:21:13 +00:00
renovate[bot] a8178cbcd6 chore(deps): Update all dependencies (#353)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-11 15:12:12 +08:00
耗子 91ecd04c27 feat: 优化登录中间件使用白名单 2024-11-11 14:28:00 +08:00
耗子 6743ac9621 fix: 防止首页报错 2024-11-11 14:19:36 +08:00
耗子 5606d980be fix: cli下修改端口后自动放行 2024-11-11 14:13:18 +08:00
renovate[bot] 34300431a4 chore(deps): Lock file maintenance (#352)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-11 08:25:44 +08:00
耗子 6f0f4c69ef feat: 初步完成redis操作方法 2024-11-11 02:22:23 +08:00
耗子 5fba45e3a4 feat: 初步完成redis操作方法 2024-11-11 02:22:17 +08:00
耗子 bb140ade7b feat: 优化app路由加载 2024-11-11 01:07:37 +08:00
耗子 1316c50a57 feat: php支持设置为cli默认版本 2024-11-11 01:04:09 +08:00
耗子 f14b4f5c54 Merge remote-tracking branch 'origin/main' 2024-11-11 00:47:48 +08:00
耗子 b08eb6bf1f feat: 优化目录输入自动清理多余的斜杠和空格 2024-11-11 00:47:09 +08:00
renovate[bot] 7f5869f805 chore(deps): Update dependency @vue/tsconfig to ^0.6.0 (#351)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-11 00:38:26 +08:00
耗子 ecadaa9bbc fix: lint 2024-11-10 18:37:44 +08:00
耗子 60b9350625 feat: 优化删除和写入支持自动去除ia属性 2024-11-10 18:25:01 +08:00
耗子 d64f099f8e feat: 发布v2.3.18 2024-11-10 08:37:38 +08:00
耗子 294a78cd95 feat: 优化删除检查 2024-11-10 03:26:08 +08:00
renovate[bot] 8294a1a74e chore(deps): Update module github.com/urfave/cli/v3 to v3.0.0-alpha9.3 (#349)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-10 02:28:09 +08:00
renovate[bot] c403efd762 chore(deps): Update dependency @iconify/json to v2.2.270 (#348)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-09 18:02:04 +08:00
耗子 cf8dfca4c0 Merge remote-tracking branch 'origin/main' 2024-11-09 18:00:15 +08:00
耗子 e552caa38f feat: 修改ip获取地址 2024-11-09 18:00:09 +08:00
renovate[bot] ddff13990a chore(deps): Update dependency marked to v15 (#347)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-09 06:58:36 +00:00
renovate[bot] 27f79ea7a3 chore(deps): Update dependency pinia-plugin-persistedstate to v4.1.3 (#346)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-09 01:32:12 +00:00
耗子 04d570197a feat: 添加redis驱动 2024-11-09 02:41:47 +08:00
renovate[bot] 8e74428023 chore(deps): Update all dependencies (#345)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-09 01:10:12 +08:00
renovate[bot] f4c09324b7 chore(deps): Update dependency md-editor-v3 to v4.21.3 (#344)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-08 11:08:41 +00:00
renovate[bot] ee6a12fac2 chore(deps): Update module golang.org/x/crypto to v0.29.0 (#343)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-08 03:10:34 +00:00
renovate[bot] ba429068ad chore(deps): Update dependency marked to v14.1.4 (#342)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-07 21:48:01 +00:00
renovate[bot] 711ccb4504 chore(deps): Update dependency @iconify/json to v2.2.269 (#341)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-07 19:09:13 +08:00
耗子 7d6e078e20 chore: 添加新合作 2024-11-07 16:58:49 +08:00
耗子 d3a7c9e29c feat: 数据库密码可以为空(本地认证) 2024-11-07 02:37:29 +08:00
耗子 10d22bfbc0 feat: 初始化数据库服务 2024-11-07 02:27:17 +08:00
耗子 724d05d980 feat: 优化数据库模型 2024-11-07 02:13:24 +08:00
耗子 690e7f0391 feat: 重命名安全为数据库 2024-11-07 01:12:38 +08:00
耗子 a28fc592d1 feat: 优化数据库模型 2024-11-07 00:52:12 +08:00
耗子 ff7e76ac2b feat: 初始化数据库条目模型 2024-11-07 00:49:11 +08:00
耗子 f2eb3a180c feat: 对部分密码进行加密 2024-11-07 00:25:09 +08:00
renovate[bot] 020a4ad870 chore(deps): Update all dependencies (#340)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-06 22:16:57 +08:00
renovate[bot] b5e7cfc069 chore(deps): Update all dependencies (#339)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-05 21:31:06 +08:00
renovate[bot] 52f8a6f045 chore(deps): Update dependency @types/node to v22.9.0 (#338)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-05 05:13:50 +00:00
耗子 3831d47a23 feat(文件): 路径切换后清空已选择 2024-11-05 02:57:30 +08:00
耗子 3a579f2346 feat: 运行等待任务前标记先前运行中的任务为失败 2024-11-04 17:59:13 +08:00
耗子 e85e8dffb3 fix: lint 2024-11-04 17:48:46 +08:00
耗子 e18d40b0ab feat: 防止任务重复提交 2024-11-04 17:47:39 +08:00
renovate[bot] c308b8e42c chore(deps): Update all dependencies (#336)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-04 12:40:20 +08:00
renovate[bot] cafded526f chore(deps): Lock file maintenance (#335)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-04 04:24:39 +00:00
renovate[bot] 99aa6c99d8 chore(deps): Update dependency pinia to v2.2.6 (#334)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-04 01:11:37 +00:00
耗子 e0daee4766 feat: 移动部分方法到utils 2024-11-04 03:04:34 +08:00
耗子 bf8c832b32 feat: 去掉重复的方法 2024-11-04 02:33:15 +08:00
耗子 2d35cbc176 fix: lint 2024-11-03 16:46:05 +08:00
renovate[bot] 6b51f58856 chore(deps): Update dependency @types/node to v22.8.7 (#330)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-03 07:25:33 +00:00
renovate[bot] f58c680ced chore(deps): Update dependency @iconify/json to v2.2.267 (#329)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-02 19:49:40 +00:00
耗子 9c6d0b5837 feat: php拓展安装添加确认弹窗 2024-11-02 21:28:29 +08:00
耗子 d069cbec75 feat: 负载条不允许超过100% 2024-11-02 21:22:35 +08:00
耗子 9b252aa8f6 docs: 更新文档 2024-11-02 20:02:43 +08:00
耗子 a52d06e3cb feat: 添加memcached php拓展 2024-11-02 19:26:38 +08:00
耗子 c25c78bfef feat: 发布v2.3.17 2024-11-02 18:32:54 +08:00
耗子 567f3ab693 fix: lint 2024-11-02 18:18:29 +08:00
耗子 aa162e12db feat: 支持memcached 2024-11-02 17:48:52 +08:00
renovate[bot] 7169b90c1d chore(deps): Update dependency sass to v1.80.6 (#328)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-02 03:07:42 +00:00
耗子 5e1001f10f docs: update README 2024-11-02 03:36:33 +08:00
耗子 8e26589c80 feat: 提升最低TLS到1.3 2024-11-02 03:34:21 +08:00
耗子 27ec65650d feat: 替换go默认的logger 2024-11-02 01:12:17 +08:00
耗子 e2345a8285 workflow: 合并codecov与test 2024-11-02 00:43:01 +08:00
耗子 4ebe20d7f8 workflow: issue lock修改为手动触发 2024-11-02 00:37:02 +08:00
renovate[bot] 8f5872b284 chore(deps): Update dependency alova to v3.2.0 (#327)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-02 00:34:24 +08:00
耗子 75c6522453 fix: lint 2024-11-01 23:07:51 +08:00
耗子 ff34cc72cc fix: lint 2024-11-01 21:54:06 +08:00
耗子 e2fb1080da Merge remote-tracking branch 'origin/main' 2024-11-01 21:42:27 +08:00
耗子 b96c6ad899 feat: php支持74和80 2024-11-01 21:42:20 +08:00
renovate[bot] c1a4fb0904 chore(deps): Update all dependencies (#326)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-01 09:46:35 +08:00
renovate[bot] 5c50da27c5 chore(deps): Update dependency @vue-js-cron/naive-ui to v2.0.7 (#325)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-31 18:48:45 +00:00
耗子 336a9bc675 fix: 文件管理bug 2024-10-31 21:49:58 +08:00
耗子 ea3bf37687 fix: 7z list 2024-10-31 18:38:03 +08:00
耗子 79e09f9cb7 chore: debug 2024-10-31 18:32:08 +08:00
耗子 d73c988073 chore: debug 2024-10-31 18:32:01 +08:00
耗子 9641ae7f34 chore: debug 2024-10-31 18:31:56 +08:00
耗子 fd2c89a480 chore: debug 2024-10-31 18:27:01 +08:00
耗子 526f192200 feat(文件): 解压时只设置压缩包内文件的权限 2024-10-31 18:20:54 +08:00
renovate[bot] 6423953aeb chore(deps): Update dependency @types/node to v22.8.5 (#324)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-31 17:07:19 +08:00
耗子 1091ec8a23 Merge remote-tracking branch 'origin/main' 2024-10-31 12:35:38 +08:00
耗子 2cbc641b2d feat(文件): 优化解压,保存时的权限设置 2024-10-31 12:35:31 +08:00
renovate[bot] f4d23211e3 chore(deps): Update dependency @vueuse/core to v11.2.0 (#323)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-31 01:16:52 +00:00
耗子 1b6086bb0b docs: 更新bug模板 2024-10-31 04:11:13 +08:00
耗子 f399e9fcec fix: 应用更新按钮错位 2024-10-31 04:11:03 +08:00
renovate[bot] 17cf1ada0e chore(deps): Update all dependencies (#321)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-31 03:43:36 +08:00
467 changed files with 22856 additions and 10334 deletions
+1 -4
View File
@@ -1,4 +1 @@
# These are supported funding model platforms
open_collective: tnb
custom: [ 'https://afdian.com/a/TheTNB' ]
custom: [ 'https://afdian.com/a/tnblabs' ]
+11 -29
View File
@@ -19,48 +19,30 @@ body:
options:
- label: 我已经搜索了现有的 Issues, Discussions 和 Google (I've searched the existing Issues, Discussions and Google)
required: true
- label: 我已经阅读了 README 中除版本记录以外的所有内容 (I've read everything in the README except the version notes)
- label: 我已经阅读了文档中除版本记录以外的所有内容 (I've read everything in the documentation except the version notes)
required: true
- label: 我在提问题之前至少花费了 5 分钟来思考和准备 (I spend at least 5 minutes thinking and preparing before asking a question)
required: true
- label: 我没有改动过面板及系统的任何文件 (I have not changed any files of the panel and system)
required: false
- label: 这个问题可以被稳定复现 (The problem can be stably reproduced)
required: false
- label: 问题是在更新之后产生的 (The problem is generated after upgrading)
required: false
- type: dropdown
- type: input
id: system
attributes:
label: 操作系统 (Operating System)
label: 系统版本 (OS Version)
description: |
请提供安装面板的操作系统
Please provide the operating system on which the panel is installed.
options:
- RockyLinux
- AlmaLinux
- Debian
- Other
validations:
required: true
- type: input
id: system-version
attributes:
label: 操作系统版本 (Operating System Version)
description: |
请提供操作系统的版本号。
Please provide the version number of the operating system.
placeholder: "9.0"
请提供服务器所使用的操作系统及其版本号
Please provide the operating system and its version number used by the server.
placeholder: "Ubuntu 24.04"
validations:
required: true
- type: input
id: version
attributes:
label: 耗子面板版本 (Rat Panel Version)
label: 面板版本 (Panel Version)
description: |
请提供面板的版本号。
Please provide the version number of the panel.
placeholder: "2.0.0"
placeholder: "2.3.0"
validations:
required: true
- type: textarea
@@ -94,7 +76,7 @@ body:
简明概要地描述您期望发生的事情。
Briefly describe what you expect to happen.
validations:
required: true
required: false
- type: textarea
id: logs
attributes:
@@ -104,8 +86,8 @@ body:
Please copy and paste any relevant log output.
可以把文件拖入这个区域以添加日志文件。
Files can be dragged into this area to add log files.
面板日志文件可在安装目录 `panel/storage/logs` 中找到。
Panel log files can be found in the installation directory `panel/storage/logs`.
面板日志文件可在面板目录 `storage/logs` 中找到。
Panel log files can be found in the panel directory `storage/logs`.
validations:
required: false
- type: textarea
+1 -1
View File
@@ -2,4 +2,4 @@ blank_issues_enabled: false
contact_links:
- name: ❓ 讨论、问答和非项目问题 (Discussions, questions, and non-project issues)
url: https://jq.qq.com/?_wv=1027&k=I1oJKSTH
about: 其他不明之处,请移步我们的QQ群 12370907 (For other unclear things, please move to our qq group 12370907)
about: 其他不明之处,请移步我们的QQ群 12370907 (For other unclear things, please move to our qq group 12370907)
File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 97 KiB

After

Width:  |  Height:  |  Size: 210 KiB

-55
View File
@@ -1,55 +0,0 @@
name: Backend
on:
push:
branches:
- main
pull_request:
jobs:
build:
runs-on: ubuntu-24.04
strategy:
matrix:
goarch: [ amd64, arm64 ]
fail-fast: true
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Go
uses: actions/setup-go@v5
with:
cache: true
go-version: 'stable'
- name: Install dependencies
run: go mod tidy
- name: Wait for frontend build
uses: lewagon/wait-on-check-action@v1.3.4
with:
ref: ${{ github.event.pull_request.head.sha || github.sha }}
check-name: 'build (frontend)'
repo-token: ${{ secrets.GITHUB_TOKEN }}
- name: Download frontend
uses: dawidd6/action-download-artifact@v6
with:
workflow: frontend.yml
name: frontend
path: internal/embed/frontend
check_artifacts: true
- name: Build ${{ matrix.goarch }}
env:
CGO_ENABLED: 0
GOOS: linux
GOARCH: ${{ matrix.goarch }}
run: |
go build -ldflags '-s -w --extldflags "-static"' -o web-${{ matrix.goarch }} ./cmd/web
go build -ldflags '-s -w --extldflags "-static"' -o cli-${{ matrix.goarch }} ./cmd/cli
- name: Compress ${{ matrix.goarch }}
run: |
upx --best --lzma web-${{ matrix.goarch }}
upx --best --lzma cli-${{ matrix.goarch }}
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.goarch }}
path: |
web-${{ matrix.goarch }}
cli-${{ matrix.goarch }}
+95
View File
@@ -0,0 +1,95 @@
name: Build
on:
push:
branches:
- main
pull_request:
jobs:
frontend:
runs-on: ubuntu-24.04
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: latest
run_install: true
package_json_file: web/package.json
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 22
cache: 'pnpm'
cache-dependency-path: web/pnpm-lock.yaml
- name: Build frontend
working-directory: web
run: |
cp .env.production .env
cp settings/proxy-config.example.ts settings/proxy-config.ts
pnpm build
- name: Upload frontend
uses: actions/upload-artifact@v4
with:
name: frontend
path: web/dist/
backend:
needs: frontend
runs-on: ubuntu-24.04
strategy:
matrix:
goarch: [ amd64, arm64 ]
fail-fast: true
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Go
uses: actions/setup-go@v5
with:
cache: true
go-version: 'stable'
- name: Install dependencies
run: go mod tidy
- name: Download frontend
uses: actions/download-artifact@v4
with:
name: frontend
path: internal/embed/frontend
- name: Set build info
run: |
echo "VERSION=$(git describe --tags --abbrev=0 2>/dev/null | sed 's/^v//' || echo '0.0.0')" >> $GITHUB_ENV
echo "BUILD_TIME=$(date -u '+%F %T UTC')" >> $GITHUB_ENV
echo "COMMIT_HASH=$(git rev-parse --short HEAD)" >> $GITHUB_ENV
echo "GO_VERSION=$(go version | cut -d' ' -f3)" >> $GITHUB_ENV
echo "BUILD_ID=${{ github.run_id }}" >> $GITHUB_ENV
echo "BUILD_USER=$(whoami)" >> $GITHUB_ENV
echo "BUILD_HOST=$(hostname)" >> $GITHUB_ENV
- name: Build ${{ matrix.goarch }}
env:
CGO_ENABLED: 0
GOOS: linux
GOARCH: ${{ matrix.goarch }}
run: |
LDFLAGS="-s -w --extldflags '-static'"
LDFLAGS="${LDFLAGS} -X 'github.com/tnb-labs/panel/internal/app.Version=${VERSION}'"
LDFLAGS="${LDFLAGS} -X 'github.com/tnb-labs/panel/internal/app.BuildTime=${BUILD_TIME}'"
LDFLAGS="${LDFLAGS} -X 'github.com/tnb-labs/panel/internal/app.CommitHash=${COMMIT_HASH}'"
LDFLAGS="${LDFLAGS} -X 'github.com/tnb-labs/panel/internal/app.GoVersion=${GO_VERSION}'"
LDFLAGS="${LDFLAGS} -X 'github.com/tnb-labs/panel/internal/app.BuildID=${BUILD_ID}'"
LDFLAGS="${LDFLAGS} -X 'github.com/tnb-labs/panel/internal/app.BuildUser=${BUILD_USER}'"
LDFLAGS="${LDFLAGS} -X 'github.com/tnb-labs/panel/internal/app.BuildHost=${BUILD_HOST}'"
go build -ldflags "${LDFLAGS}" -o web-${{ matrix.goarch }} ./cmd/web
go build -ldflags "${LDFLAGS}" -o cli-${{ matrix.goarch }} ./cmd/cli
- name: Compress ${{ matrix.goarch }}
run: |
upx --best --lzma web-${{ matrix.goarch }}
upx --best --lzma cli-${{ matrix.goarch }}
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: backend-${{ matrix.goarch }}
path: |
web-${{ matrix.goarch }}
cli-${{ matrix.goarch }}
-26
View File
@@ -1,26 +0,0 @@
name: Codecov
on:
push:
branches:
- main
pull_request:
jobs:
codecov:
runs-on: ubuntu-24.04
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Go
uses: actions/setup-go@v5
with:
cache: true
go-version: 'stable'
- name: Install dependencies
run: go mod tidy
- name: Run tests with coverage
run: sudo go test -v -coverprofile="coverage.out" ./...
- name: Upload coverage report to Codecov
uses: codecov/codecov-action@v4
with:
file: ./coverage.out
token: ${{ secrets.CODECOV }}
-42
View File
@@ -1,42 +0,0 @@
name: Frontend
on:
push:
branches:
- main
pull_request:
jobs:
build:
name: build (frontend)
runs-on: ubuntu-24.04
defaults:
run:
working-directory: web
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: latest
run_install: true
package_json_file: web/package.json
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: 'pnpm'
cache-dependency-path: web/pnpm-lock.yaml
- name: Build frontend
# We need to run the dev server first to generate the auto-imports files
run: |
cp .env.production .env
cp settings/proxy-config.example.ts settings/proxy-config.ts
pnpm dev &
sleep 5
kill %1
pnpm build
- name: Upload frontend
uses: actions/upload-artifact@v4
with:
name: frontend
path: web/dist/ # https://github.com/actions/upload-artifact/issues/541
+23 -12
View File
@@ -18,23 +18,34 @@ jobs:
with:
cache: true
go-version: 'stable'
- name: Wait for frontend build
uses: lewagon/wait-on-check-action@v1.3.4
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
ref: ${{ github.event.pull_request.head.sha || github.sha }}
check-name: 'build (frontend)'
repo-token: ${{ secrets.GITHUB_TOKEN }}
- name: Download frontend
uses: dawidd6/action-download-artifact@v6
version: latest
run_install: true
package_json_file: web/package.json
- name: Setup Node.js
uses: actions/setup-node@v4
with:
workflow: frontend.yml
name: frontend
path: internal/embed/frontend
check_artifacts: true
node-version: 22
cache: 'pnpm'
cache-dependency-path: web/pnpm-lock.yaml
- name: Build frontend
working-directory: web
run: |
cp .env.production .env
cp settings/proxy-config.example.ts settings/proxy-config.ts
pnpm build
- name: Set environment variables
run: |
echo "GOVERSION=$(go version | cut -d' ' -f3)" >> $GITHUB_ENV
echo "HOSTNAME=$(hostname)" >> $GITHUB_ENV
- name: Clear node_modules
run: rm -rf node_modules
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@v6
with:
version: latest
args: release --clean
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+2 -5
View File
@@ -1,11 +1,8 @@
name: Issue Auto Lock
on:
schedule:
- cron: "0 */6 * * *"
- cron: "*/5 * * * *"
workflow_dispatch:
push:
branches:
- main
issues:
types: [ opened ]
permissions:
@@ -22,4 +19,4 @@ jobs:
with:
gh_repo: ${{ github.repository }}
gh_token: ${{ secrets.GITHUB_TOKEN }}
issue_labels: "⭐ No Star"
issue_labels: "⭐ No Star"
+3 -17
View File
@@ -11,20 +11,6 @@ jobs:
pull-requests: write
runs-on: ubuntu-24.04
steps:
- name: ✏️ Feature
if: github.event.label.name == '✏️ Feature'
uses: actions-cool/issues-helper@v3
with:
actions: 'create-comment'
token: ${{ secrets.GITHUB_TOKEN }}
issue-number: ${{ github.event.issue.number }}
body: |
Hi @${{ github.event.issue.user.login }} 👋
我们认为您的建议非常有价值!欢迎提交 PR,请包含相应的测试用例、文档等,并确保 CI 通过,感谢和期待您的贡献!
We think your suggestion is very valuable! Welcome to submit a PR, please include test cases, documentation, etc., and ensure that the CI is passed, thank you and look forward to your contribution!
![干](https://github.com/TheTNB/panel/assets/115467771/fb04debf-3f4c-4fac-a0b8-c3455f8e57a0)
- name: ☢️ Bug
if: github.event.label.name == '☢️ Bug'
uses: actions-cool/issues-helper@v3
@@ -35,7 +21,7 @@ jobs:
body: |
Hi @${{ github.event.issue.user.login }} 👋
我们认为您的反馈非常有价值!欢迎提交 PR,请包含相应的测试用例、文档等,并确保 CI 通过,感谢和期待您的贡献!
We think your feedback is very valuable! Welcome to submit a PR, please include test cases, documentation, etc., and ensure that the CI is passed, thank you and look forward to your contribution!
感谢提交 Bug,请确保您的描述清晰,日志完整,最好能提供复现步骤,以便我们更快定位问题并解决。
Thanks for submitting a bug, please make sure your description is clear, log is complete, and it is best to provide a reproduction step so that we can locate and solve the problem faster.
![](https://github.com/TheTNB/panel/assets/115467771/fb04debf-3f4c-4fac-a0b8-c3455f8e57a0)
![Log](https://github.com/user-attachments/assets/0ce7a32d-cc79-4bef-91fc-5bec1d0ed376)
+3 -22
View File
@@ -24,23 +24,6 @@ jobs:
skip-cache: true
version: latest
args: --timeout=30m ./...
nilaway:
runs-on: ubuntu-24.04
if: false
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Go
uses: actions/setup-go@v5
with:
cache: true
go-version: 'stable'
- name: Install dependencies
run: go mod tidy
- name: Install NilAway
run: go install go.uber.org/nilaway/cmd/nilaway@latest
- name: Run NilAway
run: nilaway -include-pkgs="github.com/TheTNB/panel" ./...
govulncheck:
runs-on: ubuntu-24.04
steps:
@@ -57,9 +40,6 @@ jobs:
run: govulncheck ./...
frontend:
runs-on: ubuntu-24.04
defaults:
run:
working-directory: web
steps:
- name: Checkout
uses: actions/checkout@v4
@@ -72,8 +52,9 @@ jobs:
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
node-version: 22
cache: 'pnpm'
cache-dependency-path: web/pnpm-lock.yaml
- name: Run pnpm lint
run: pnpm lint
working-directory: web
run: pnpm lint
+22
View File
@@ -0,0 +1,22 @@
name: Mockery
on:
push:
branches:
- main
pull_request:
jobs:
mockery:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install Mockery
run: |
go install github.com/vektra/mockery/v2@latest
- name: Generate Mocks
run: |
~/go/bin/mockery
- uses: stefanzweifel/git-auto-commit-action@v5
name: Commit changes
with:
commit_message: "chore: update mocks"
+6 -1
View File
@@ -21,4 +21,9 @@ jobs:
run: |
cp config.example.yml config.yml
- name: Run tests
run: sudo go test ./...
run: sudo go test -v -coverprofile="coverage.out" ./...
- name: Upload coverage report to Codecov
uses: codecov/codecov-action@v5
with:
file: ./coverage.out
token: ${{ secrets.CODECOV }}
+14
View File
@@ -14,6 +14,13 @@ builds:
- arm64
ldflags:
- -s -w --extldflags "-static"
- -X 'github.com/tnb-labs/panel/internal/app.Version={{ .Version }}'
- -X 'github.com/tnb-labs/panel/internal/app.BuildTime={{ .Now.Format "2006-01-02 15:04:05 MST" }}'
- -X 'github.com/tnb-labs/panel/internal/app.CommitHash={{ .ShortCommit }}'
- -X 'github.com/tnb-labs/panel/internal/app.GoVersion={{ .Env.GOVERSION }}'
- -X 'github.com/tnb-labs/panel/internal/app.BuildID={{ .Env.GITHUB_RUN_ID }}'
- -X 'github.com/tnb-labs/panel/internal/app.BuildUser={{ .Env.USER }}'
- -X 'github.com/tnb-labs/panel/internal/app.BuildHost={{ .Env.HOSTNAME }}'
- id: cli
main: ./cmd/cli
binary: cli
@@ -26,6 +33,13 @@ builds:
- arm64
ldflags:
- -s -w --extldflags "-static"
- -X 'github.com/tnb-labs/panel/internal/app.Version={{ .Version }}'
- -X 'github.com/tnb-labs/panel/internal/app.BuildTime={{ .Now.Format "2006-01-02 15:04:05 MST" }}'
- -X 'github.com/tnb-labs/panel/internal/app.CommitHash={{ .ShortCommit }}'
- -X 'github.com/tnb-labs/panel/internal/app.GoVersion={{ .Env.GOVERSION }}'
- -X 'github.com/tnb-labs/panel/internal/app.BuildID={{ .Env.GITHUB_RUN_ID }}'
- -X 'github.com/tnb-labs/panel/internal/app.BuildUser={{ .Env.USER }}'
- -X 'github.com/tnb-labs/panel/internal/app.BuildHost={{ .Env.HOSTNAME }}'
upx:
- enabled: true
+11
View File
@@ -0,0 +1,11 @@
with-expecter: True
disable-version-string: True
dir: mocks/{{ replaceAll .InterfaceDirRelative "internal" "" }}
mockname: "{{.InterfaceName}}"
outpkg: "{{.PackageName}}"
filename: "{{.InterfaceName}}.go"
all: True
packages:
github.com/tnb-labs/panel/internal/biz:
config:
recursive: True
+38 -126
View File
@@ -4,132 +4,52 @@
<h1 align="center" style="font-size: 40px">耗子面板</h1>
<p align="center">
<a href="https://trendshift.io/repositories/10950" target="_blank"><img src="https://trendshift.io/api/badge/repositories/10950" alt="TheTNB%2Fpanel | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a>
</p>
<div align="center">
<p align="center">
<a href="https://github.com/TheTNB/panel/releases"><img src="https://img.shields.io/github/release/TheTNB/panel.svg"></a>
<a href="https://github.com/TheTNB/panel/actions"><img src="https://github.com/TheTNB/panel/actions/workflows/test.yml/badge.svg"></a>
<a href="https://goreportcard.com/report/github.com/TheTNB/panel"><img src="https://goreportcard.com/badge/github.com/TheTNB/panel"></a>
<a href="https://img.shields.io/github/license/TheTNB/panel"><img src="https://img.shields.io/github/license/TheTNB/panel"></a>
<a href="https://app.fossa.com/projects/git%2Bgithub.com%2FTheTNB%2Fpanel?ref=badge_shield"><img src="https://app.fossa.com/api/projects/git%2Bgithub.com%2FTheTNB%2Fpanel.svg?type=shield" alt="FOSSA Status"></a>
</p>
[![Go](https://img.shields.io/github/go-mod/go-version/tnb-labs/panel)](https://go.dev/)
[![Release](https://img.shields.io/github/release/tnb-labs/panel.svg)](https://github.com/tnb-labs/panel/releases)
[![Test](https://github.com/tnb-labs/panel/actions/workflows/test.yml/badge.svg)](https://github.com/tnb-labs/panel/actions)
[![Report Card](https://goreportcard.com/badge/github.com/tnb-labs/panel)](https://goreportcard.com/report/github.com/tnb-labs/panel)
[![Stars](https://img.shields.io/github/stars/tnb-labs/panel?style=flat)](https://github.com/tnb-labs/panel)
[![License](https://img.shields.io/github/license/tnb-labs/panel)](https://www.gnu.org/licenses/agpl-3.0.html)
耗子面板是使用 Golang + Vue 开发的开源轻量 Linux 服务器运维管理面板。
</div>
QQ群:[12370907](https://jq.qq.com/?_wv=1027&k=I1oJKSTH) | 微信群:[复制此链接](https://work.weixin.qq.com/gm/d8ebf618553398d454e3378695c858b6) | 论坛:[tom.moe](https://tom.moe) | 赞助:[爱发电](https://afdian.com/a/TheTNB)
企业级全能服务器运维管理面板。简单轻量,高效运维。
官网:[panel.haozi.net](https://panel.haozi.net) | QQ群:[12370907](https://jq.qq.com/?_wv=1027&k=I1oJKSTH) | 微信群:[复制此链接](https://work.weixin.qq.com/gm/d8ebf618553398d454e3378695c858b6)
## 优势
1. **极低占用:** 在 Debian 下部署面板 + LNMP 环境,内存占用不到 500 MB,遥遥领先于使用容器化的其他面板。
2. **低破坏性:** 面板的设计理念是尽可能减少对系统的额外修改,在同类面板中,我们对系统的修改最少
3. **追随时代:** 面板所有组件均走在时代前沿,更新快,功能强大,安全性有保障。
4. **高效运维:** 面板界面简洁,操作简单,无需繁琐的配置,即可快速部署各类环境、调整应用设置。
5. **离线运行:** 面板运行可不依赖任何外部服务,您甚至可以在部署完成后停止面板进程,不会对已部署服务造成任何影响
6. **久经考验:** 我们生产环境自 2022 年即开始使用,已稳定运行 2 年无事故。
7. **开源开放:** 面板开源,您可以自由修改、审计面板源码,安全性有保障。
1. **极低占用:** Go 语言开发,安装包小,占用低,单文件运行,不会对系统性能造成影响
2. **低破坏性:** 设计为尽可能减少对系统的额外修改,在同类产品中,我们对系统的修改最少
3. **追随时代:** 整体设计走在时代前沿,对新系统兼容性好,在同类产品中处于领先地位
4. **高效运维:** 功能完善,自定义能力强,既可快速部署小型网站,也可基于定制化需求部署复杂应用
5. **离线运行:** 支持离线模式,甚至可以在部署完成后停止面板进程,不会对已服务造成任何影响
6. **安全稳定:** 面板采用业界多种技术保障本体安全性,已在我们的多个生存环境中长期稳定运行
7. **全面开源:** 少有的全开源面板,您可以在遵守开源协议的前提下对面板自由修改、二次开发
8. **全面开源:** 承诺面板本体未来不会引入任何收费/授权功能,永久免费使用
## UI 截图
![UI 截图](.github/assets/ui.png)
## 运行环境
## 快速安装
耗子面板支持 `amd64` | `arm64` 架构下的主流系统,下表中的系统均已测试 LNMP 环境安装。
[https://ratpanel.github.io/quickstart/install.html](https://ratpanel.github.io/quickstart/install.html)
优先建议使用标注**推荐**的系统,无特殊情况不建议使用标注**不推荐**的系统。
## 合作伙伴
不在下表中的其他系统,可自行尝试安装,但不提供技术支持(接受相关 PR 提交)。
如果耗子面板对您有帮助,欢迎赞助我们,同时感谢以下支持者/赞助商的支持:
| 系统 | 版本 | 备注 |
|---------------------|-----|-----|
| AlmaLinux | 9 | 推荐 |
| AlmaLinux | 8 | 不推荐 |
| RockyLinux | 9 | 支持 |
| RockyLinux | 8 | 不推荐 |
| CentOS Stream | 9 | 不推荐 |
| CentOS Stream | 8 | 不推荐 |
| Ubuntu | 24 | 推荐 |
| Ubuntu | 22 | 支持 |
| Debian | 12 | 推荐 |
| Debian | 11 | 支持 |
| OpenCloudOS | 9 | 支持 |
| TencentOS Server | 4 | 支持 |
| TencentOS Server | 3.1 | 不推荐 |
| Alibaba Cloud Linux | 3.2 | 不推荐 |
| Anolis | 8 | 不推荐 |
| openEuler | 22 | 不推荐 |
随着系统版本的不断更新,我们亦可能会终止部分过于老旧的系统的支持,以保证面板的健壮性。
## 安装面板
> **Warning**
> 安装面板前,您需要了解 LNMP 环境的基本知识,以及如何处理常见的 LNMP 环境问题,我们不建议 0 基础的用户安装和使用耗子面板。
如果您的服务器有未挂载的数据盘,可在安装前以`root`用户登录服务器运行以下命令自动挂载,面板安装后不支持跨目录迁移。
```shell
curl -fsLm 10 -o auto_mount.sh https://dl.cdn.haozi.net/panel/auto_mount.sh && bash auto_mount.sh
```
准备就绪后,请以`root`用户登录服务器,运行以下命令安装面板:
**当前 v2.3.x 为测试版本,欢迎帮助我们测试在不同操作系统下的兼容性。**
```shell
curl -fsLm 10 -o install.sh https://dl.cdn.haozi.net/panel/install.sh && bash install.sh
```
## 卸载面板
优先建议备份数据重装系统,这样可以保证系统纯净。
如果您无法重装系统,请以`root`用户登录服务器,执行以下命令卸载面板:
```shell
curl -fsLm 10 -o uninstall.sh https://dl.cdn.haozi.net/panel/uninstall.sh && bash uninstall.sh
```
卸载面板前请务必备份好所有数据,提前卸载面板全部应用。卸载后数据将**无法恢复**!
## 日常维护
使用`panel-cli`命令进行日常维护:
```shell
panel-cli
```
在 [文档](https://tom.moe/docs?category=57) 中查看更多使用方法和技巧。
## 问题反馈
使用类问题,可在 [Moe Tom](https://tom.moe) 提问或寻求 AI 帮助,亦可在群里寻求付费支持。
面板自身问题,可在 GitHub 的`Issues`页面提交问题反馈,注意[提问的智慧](https://github.com/ryanhanwu/How-To-Ask-Questions-The-Smart-Way/blob/main/README-zh_CN.md)。
## 赞助商
如果耗子面板对您有帮助,欢迎[赞助我们](https://afdian.com/a/TheTNB),感谢以下支持者/赞助商的支持:
**同时接受云资源赞助,可通过QQ群咨询联系**
### 资金
![支付宝](https://github.com/user-attachments/assets/d000b147-6da1-467a-9d80-9a3e8078602a) ![微信](https://github.com/user-attachments/assets/a53ff212-7076-487e-88bd-c93f6e98df1d)
<a href="https://www.weixiaoduo.com/">
<img height="80" src=".github/assets/wxd.png" alt="微晓朵">
</a>
### 服务器
<a href="https://www.dkdun.cn/aff/MQZZNVHQ">
<img height="80" src=".github/assets/dk.png" alt="林枫云">
</a>
### CDN
<a href="https://su.sctes.com/register?code=8st689ujpmm2p">
<img height="80" src=".github/assets/sctes.png" alt="无畏云加速">
</a>
@@ -139,33 +59,25 @@ panel-cli
<a href="https://scdn.ddunyun.com/">
<img height="80" src=".github/assets/ddunyun.png" alt="盾云SCDN">
</a>
### 赞助商们
<a href="https://hongtoutong.com">
<img height="80" src=".github/assets/htt.png" alt="红透通">
</a>
<a href="https://1ms.run">
<img height="80" src=".github/assets/1ms.svg" alt="毫秒镜像提供经过审核的 Docker 镜像加速服务">
</a>
<p align="center">
<a target="_blank" href="https://afdian.com/a/TheTNB">
<img alt="sponsors" src="https://github.com/TheTNB/sponsor/blob/main/sponsors.svg?raw=true"/>
<a target="_blank" href="https://afdian.com/a/tnblabs">
<img alt="sponsors" src="https://github.com/tnb-labs/sponsor/blob/main/sponsors.svg?raw=true"/>
</a>
</p>
## 贡献者
这个项目的存在要归功于所有做出贡献的人,参与贡献请先查看贡献代码部分。
<a href="https://github.com/TheTNB/panel/graphs/contributors">
<img alt="contributors" src="https://contrib.rocks/image?repo=TheTNB/panel"/>
</a>
## Star 历史
<a href="https://star-history.com/#TheTNB/panel&Date">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=TheTNB/panel&type=Date&theme=dark" />
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=TheTNB/panel&type=Date" />
<img alt="Star History Chart" src="https://api.star-history.com/svg?repos=TheTNB/panel&type=Date" />
</picture>
<a href="https://star-history.com/#tnb-labs/panel&Date">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=tnb-labs/panel&type=Date&theme=dark" />
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=tnb-labs/panel&type=Date" />
<img alt="Star History Chart" src="https://api.star-history.com/svg?repos=tnb-labs/panel&type=Date" />
</picture>
</a>
## 免责声明
严禁使用耗子面板从事任何非法活动,非法站点请勿向我们请求任何形式的技术支持,如果在技术支持过程中发现非法内容,我们将立即停止技术支持并留存相关证据。
+38 -126
View File
@@ -4,132 +4,52 @@
<h1 align="center" style="font-size: 40px">Rat Panel</h1>
<p align="center">
<a href="https://trendshift.io/repositories/10950" target="_blank"><img src="https://trendshift.io/api/badge/repositories/10950" alt="TheTNB%2Fpanel | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a>
</p>
<div align="center">
<p align="center">
<a href="https://github.com/TheTNB/panel/releases"><img src="https://img.shields.io/github/release/TheTNB/panel.svg"></a>
<a href="https://github.com/TheTNB/panel/actions"><img src="https://github.com/TheTNB/panel/actions/workflows/test.yml/badge.svg"></a>
<a href="https://goreportcard.com/report/github.com/TheTNB/panel"><img src="https://goreportcard.com/badge/github.com/TheTNB/panel"></a>
<a href="https://img.shields.io/github/license/TheTNB/panel"><img src="https://img.shields.io/github/license/TheTNB/panel"></a>
<a href="https://app.fossa.com/projects/git%2Bgithub.com%2FTheTNB%2Fpanel?ref=badge_shield"><img src="https://app.fossa.com/api/projects/git%2Bgithub.com%2FTheTNB%2Fpanel.svg?type=shield" alt="FOSSA Status"></a>
</p>
[![Go](https://img.shields.io/github/go-mod/go-version/tnb-labs/panel)](https://go.dev/)
[![Release](https://img.shields.io/github/release/tnb-labs/panel.svg)](https://github.com/tnb-labs/panel/releases)
[![Test](https://github.com/tnb-labs/panel/actions/workflows/test.yml/badge.svg)](https://github.com/tnb-labs/panel/actions)
[![Report Card](https://goreportcard.com/badge/github.com/tnb-labs/panel)](https://goreportcard.com/report/github.com/tnb-labs/panel)
[![Stars](https://img.shields.io/github/stars/tnb-labs/panel?style=flat)](https://github.com/tnb-labs/panel)
[![License](https://img.shields.io/github/license/tnb-labs/panel)](https://www.gnu.org/licenses/agpl-3.0.html)
The Rat Panel is an open source lightweight Linux server operation and maintenance management panel developed using Golang and Vue.
</div>
QQ group: [12370907](https://jq.qq.com/?_wv=1027&k=I1oJKSTH) | WeChat group: [Copy this link](https://work.weixin.qq.com/gm/d8ebf618553398d454e3378695c858b6) | Forum: [tom.moe](https://tom.moe) | Sponsor: [Open Collective](https://opencollective.com/tnb)
Enterprise-level all-in-one server operation and maintenance management panel. Simple and lightweight, efficient operation and maintenance.
Website: [panel.haozi.net](https://panel.haozi.net) | QQ group: [12370907](https://jq.qq.com/?_wv=1027&k=I1oJKSTH) | WeChat group: [Copy this link](https://work.weixin.qq.com/gm/d8ebf618553398d454e3378695c858b6)
## Advantages
1. **Extremely low usage:** Deploying the panel + LNMP environment under Debian, the memory usage is less than 500 MB, far ahead of other panels using containerization.
2. **Low destructiveness:** The design concept of the panel is to minimize the additional modifications to the system. Among similar panels, we have made the least modifications to the system.
3. **Follow the times:** All components of the panel are at the forefront of the times, updated quickly, powerful functions, and guaranteed security.
4. **Efficient operation and maintenance:** The panel is simple and easy to operate, and you can quickly deploy various environments and adjust application settings without complicated configuration.
5. **Offline operation:** The panel can run without relying on any external services. You can even stop the panel process after deployment is complete, and it will not affect the deployed services.
6. **Tested by time:** We have been using it in production environment since 2022, and it has been running stably for 2 year without any accidents.
7. **Open source and open:** The panel is open source, you can freely modify and audit the panel source code, and the security is guaranteed.
1. **Extremely low occupancy:** Developed in Go language, small installation package, low occupancy, single file operation, will not affect system performance
2. **Low Destructiveness:** Designed to minimize additional modifications to the system, we make the fewest modifications to the system among similar products
3. **Follow the Times:** The overall design is at the forefront of the times, with good compatibility with new systems, leading in the same type of products
4. **Efficient Operation and Maintenance:** Complete functions, strong customization capabilities, can quickly deploy small websites, and deploy complex applications based on customized requirements
5. **Offline Operation:** Support offline mode, and even stop the panel process after deployment, without affecting any existing services
6. **Safe and Stable:** The panel adopts a variety of industry technologies to ensure the security of the body, and has been running stably in multiple survival environments for a long time
7. **Fully Open Source:** Few fully open source panels, you can freely modify and develop the panel on the premise of complying with the open source agreement
8. **Permanently free:** Commit to the panel body will not introduce any charging/authorization functions in the future, and will be permanently free to use
## UI Screenshots
![UI Screenshots](.github/assets/ui.png)
## Operating Environment
## Quick Install
Rat Panel supports mainstream systems under the `amd64` | `arm64` architecture, and the systems in the table below have been tested for LNMP environment installation.
[https://ratpanel.github.io/quickstart/install.html](https://ratpanel.github.io/quickstart/install.html)
It is recommended to use the systems marked **Recommended** first, and not recommended to use the systems marked **Not recommended** without special circumstances.
## Partners
For other systems not listed in the table below, you can try to install them by yourself, but there is no technical support will be provided (accept related PR submissions).
If the Rat Panel is helpful to you, welcome to sponsor us, also thanks to the following supporters/sponsors:
| OS | Version | Note |
|---------------------|---------|-----------------|
| AlmaLinux | 9 | Recommended |
| AlmaLinux | 8 | Not recommended |
| RockyLinux | 9 | Support |
| RockyLinux | 8 | Not recommended |
| CentOS Stream | 9 | Not recommended |
| CentOS Stream | 8 | Not recommended |
| Ubuntu | 24 | Recommended |
| Ubuntu | 22 | Support |
| Debian | 12 | Recommended |
| Debian | 11 | Support |
| OpenCloudOS | 9 | Support |
| TencentOS Server | 4 | Support |
| TencentOS Server | 3.1 | Not recommended |
| Alibaba Cloud Linux | 3.2 | Not recommended |
| Anolis | 8 | Not recommended |
| openEuler | 22 | Not recommended |
As system versions are constantly updated, we may also terminate support for some older systems to ensure the robustness of the panel.
## Install Panel
> **Warning**
> Before installing the panel, you need to understand the basic knowledge of the LNMP environment and how to deal with common LNMP environment problems. We are not recommended for users with zero basic knowledge to install and use Rat Panel.
If your server has an unmounted data disk, you can run the following command as the `root` user to automatically mount it before installation. The panel does not support cross-directory migration after installation.
```shell
curl -fsLm 10 -o auto_mount.sh https://dl.cdn.haozi.net/panel/auto_mount.sh && bash auto_mount.sh
```
After you are ready, log in to the server as the `root` user and run the following command to install the panel:
**Current v2.3.x is a test version, welcome to help us test compatibility on different operating systems.**
```shell
curl -fsLm 10 -o install.sh https://dl.cdn.haozi.net/panel/install.sh && bash install.sh
```
## Uninstall Panel
Recommended to back up data and reinstall the system first, so that the system can be kept clean.
If you are unable to reinstall the system, log in to the server as the `root` user and execute the following command to uninstall the panel:
```shell
curl -fsLm 10 -o uninstall.sh https://dl.cdn.haozi.net/panel/uninstall.sh && bash uninstall.sh
```
Before uninstalling the panel, please be sure to back up all data and uninstall all panel plugins in advance. The data will **not be recoverable** after uninstallation!
## Daily Maintenance
Use `panel-cli` command for daily maintenance:
```shell
panel-cli
```
See more usage methods and tips in [Document](https://tom.moe/docs?category=57).
## Feedback
For usage issues, you can ask questions in the [Moe Tom](https://tom.moe) or seek AI help. You can also seek paid support in the group.
For issues with the panel itself, you can submit feedback on the `Issues` page of GitHub. Please note [the wisdom of asking questions](http://www.catb.org/~esr/faqs/smart-questions.html).
## Sponsor
If the Rat Panel is helpful to you, welcome to [sponsor us](https://opencollective.com/tnb), thanks to the following supporters/sponsors:
**Accept cloud resources and financial sponsorship, you can contact us through QQ group**
### Financial
![Alipay](https://github.com/user-attachments/assets/d000b147-6da1-467a-9d80-9a3e8078602a) ![WeChat](https://github.com/user-attachments/assets/a53ff212-7076-487e-88bd-c93f6e98df1d)
<a href="https://www.weixiaoduo.com/">
<img height="80" src=".github/assets/wxd.png" alt="微晓朵">
</a>
### Server
<a href="https://www.dkdun.cn/aff/MQZZNVHQ">
<img height="80" src=".github/assets/dk.png" alt="林枫云">
</a>
### CDN
<a href="https://su.sctes.com/register?code=8st689ujpmm2p">
<img height="80" src=".github/assets/sctes.png" alt="无畏云加速">
</a>
@@ -139,33 +59,25 @@ If the Rat Panel is helpful to you, welcome to [sponsor us](https://opencollecti
<a href="https://scdn.ddunyun.com/">
<img height="80" src=".github/assets/ddunyun.png" alt="盾云SCDN">
</a>
### Sponsors
<a href="https://hongtoutong.com">
<img height="80" src=".github/assets/htt.png" alt="红透通">
</a>
<a href="https://1ms.run">
<img height="80" src=".github/assets/1ms.svg" alt="毫秒镜像提供经过审核的 Docker 镜像加速服务">
</a>
<p align="center">
<a target="_blank" href="https://afdian.com/a/TheTNB">
<img alt="sponsors" src="https://github.com/TheTNB/sponsor/blob/main/sponsors.svg?raw=true"/>
<a target="_blank" href="https://afdian.com/a/tnblabs">
<img alt="sponsors" src="https://github.com/tnb-labs/sponsor/blob/main/sponsors.svg?raw=true"/>
</a>
</p>
## Contributor
This project owes its existence to all those who have contributed. To contribute, please check the contributed code section first.
<a href="https://github.com/TheTNB/panel/graphs/contributors">
<img alt="contributors" src="https://contrib.rocks/image?repo=TheTNB/panel"/>
</a>
## Star History
<a href="https://star-history.com/#TheTNB/panel&Date">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=TheTNB/panel&type=Date&theme=dark" />
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=TheTNB/panel&type=Date" />
<img alt="Star History Chart" src="https://api.star-history.com/svg?repos=TheTNB/panel&type=Date" />
</picture>
<a href="https://star-history.com/#tnb-labs/panel&Date">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=tnb-labs/panel&type=Date&theme=dark" />
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=tnb-labs/panel&type=Date" />
<img alt="Star History Chart" src="https://api.star-history.com/svg?repos=tnb-labs/panel&type=Date" />
</picture>
</a>
## Disclaimer
It is strictly prohibited to use the Rat Panel to engage in any illegal activities. Please do not request any form of technical support from us for illegal sites. If illegal content is discovered during the technical support process, we will immediately stop technical support and retain relevant evidence.
+14 -4
View File
@@ -1,5 +1,5 @@
/*
Copyright (C) 2022 - now HaoZi Technology Co., Ltd.
Copyright (C) 2022 - now Rat Technology Co., Ltd.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
@@ -17,11 +17,21 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
package main
import (
"os"
_ "time/tzdata"
"github.com/TheTNB/panel/internal/bootstrap"
)
func main() {
bootstrap.BootCli()
if os.Geteuid() != 0 {
panic("panel must run as root")
}
cli, err := initCli()
if err != nil {
panic(err)
}
if err = cli.Run(); err != nil {
panic(err)
}
}
+19
View File
@@ -0,0 +1,19 @@
//go:build wireinject
package main
import (
"github.com/google/wire"
"github.com/tnb-labs/panel/internal/app"
"github.com/tnb-labs/panel/internal/apps"
"github.com/tnb-labs/panel/internal/bootstrap"
"github.com/tnb-labs/panel/internal/data"
"github.com/tnb-labs/panel/internal/route"
"github.com/tnb-labs/panel/internal/service"
)
// initCli init command line.
func initCli() (*app.Cli, error) {
panic(wire.Build(bootstrap.ProviderSet, route.ProviderSet, service.ProviderSet, data.ProviderSet, apps.ProviderSet, app.NewCli))
}
+100
View File
@@ -0,0 +1,100 @@
// Code generated by Wire. DO NOT EDIT.
//go:generate go run -mod=mod github.com/google/wire/cmd/wire
//go:build !wireinject
// +build !wireinject
package main
import (
"github.com/tnb-labs/panel/internal/app"
"github.com/tnb-labs/panel/internal/apps/benchmark"
"github.com/tnb-labs/panel/internal/apps/docker"
"github.com/tnb-labs/panel/internal/apps/fail2ban"
"github.com/tnb-labs/panel/internal/apps/frp"
"github.com/tnb-labs/panel/internal/apps/gitea"
"github.com/tnb-labs/panel/internal/apps/memcached"
"github.com/tnb-labs/panel/internal/apps/mysql"
"github.com/tnb-labs/panel/internal/apps/nginx"
"github.com/tnb-labs/panel/internal/apps/php74"
"github.com/tnb-labs/panel/internal/apps/php80"
"github.com/tnb-labs/panel/internal/apps/php81"
"github.com/tnb-labs/panel/internal/apps/php82"
"github.com/tnb-labs/panel/internal/apps/php83"
"github.com/tnb-labs/panel/internal/apps/php84"
"github.com/tnb-labs/panel/internal/apps/phpmyadmin"
"github.com/tnb-labs/panel/internal/apps/podman"
"github.com/tnb-labs/panel/internal/apps/postgresql"
"github.com/tnb-labs/panel/internal/apps/pureftpd"
"github.com/tnb-labs/panel/internal/apps/redis"
"github.com/tnb-labs/panel/internal/apps/rsync"
"github.com/tnb-labs/panel/internal/apps/s3fs"
"github.com/tnb-labs/panel/internal/apps/supervisor"
"github.com/tnb-labs/panel/internal/apps/toolbox"
"github.com/tnb-labs/panel/internal/bootstrap"
"github.com/tnb-labs/panel/internal/data"
"github.com/tnb-labs/panel/internal/route"
"github.com/tnb-labs/panel/internal/service"
)
import (
_ "time/tzdata"
)
// Injectors from wire.go:
// initCli init command line.
func initCli() (*app.Cli, error) {
koanf, err := bootstrap.NewConf()
if err != nil {
return nil, err
}
logger := bootstrap.NewLog(koanf)
db, err := bootstrap.NewDB(koanf, logger)
if err != nil {
return nil, err
}
cacheRepo := data.NewCacheRepo(db)
queue := bootstrap.NewQueue()
taskRepo := data.NewTaskRepo(db, logger, queue)
appRepo := data.NewAppRepo(db, cacheRepo, taskRepo)
userRepo := data.NewUserRepo(db)
settingRepo := data.NewSettingRepo(db, koanf, taskRepo)
databaseServerRepo := data.NewDatabaseServerRepo(db, logger)
databaseUserRepo := data.NewDatabaseUserRepo(db, databaseServerRepo)
databaseRepo := data.NewDatabaseRepo(db, databaseServerRepo, databaseUserRepo)
certRepo := data.NewCertRepo(db)
certAccountRepo := data.NewCertAccountRepo(db, userRepo)
websiteRepo := data.NewWebsiteRepo(db, cacheRepo, databaseRepo, databaseServerRepo, databaseUserRepo, certRepo, certAccountRepo)
backupRepo := data.NewBackupRepo(db, settingRepo, websiteRepo)
cliService := service.NewCliService(koanf, db, appRepo, cacheRepo, userRepo, settingRepo, backupRepo, websiteRepo, databaseServerRepo)
cli := route.NewCli(cliService)
command := bootstrap.NewCli(cli)
gormigrate := bootstrap.NewMigrate(db)
benchmarkApp := benchmark.NewApp()
dockerApp := docker.NewApp()
fail2banApp := fail2ban.NewApp(websiteRepo)
frpApp := frp.NewApp()
giteaApp := gitea.NewApp()
memcachedApp := memcached.NewApp()
mysqlApp := mysql.NewApp(settingRepo)
nginxApp := nginx.NewApp()
php74App := php74.NewApp(taskRepo)
php80App := php80.NewApp(taskRepo)
php81App := php81.NewApp(taskRepo)
php82App := php82.NewApp(taskRepo)
php83App := php83.NewApp(taskRepo)
php84App := php84.NewApp(taskRepo)
phpmyadminApp := phpmyadmin.NewApp()
podmanApp := podman.NewApp()
postgresqlApp := postgresql.NewApp()
pureftpdApp := pureftpd.NewApp()
redisApp := redis.NewApp()
rsyncApp := rsync.NewApp()
s3fsApp := s3fs.NewApp(settingRepo)
supervisorApp := supervisor.NewApp()
toolboxApp := toolbox.NewApp()
loader := bootstrap.NewLoader(benchmarkApp, dockerApp, fail2banApp, frpApp, giteaApp, memcachedApp, mysqlApp, nginxApp, php74App, php80App, php81App, php82App, php83App, php84App, phpmyadminApp, podmanApp, postgresqlApp, pureftpdApp, redisApp, rsyncApp, s3fsApp, supervisorApp, toolboxApp)
appCli := app.NewCli(command, gormigrate, loader)
return appCli, nil
}
+18 -4
View File
@@ -1,5 +1,5 @@
/*
Copyright (C) 2022 - now HaoZi Technology Co., Ltd.
Copyright (C) 2022 - now Rat Technology Co., Ltd.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
@@ -17,11 +17,25 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
package main
import (
"os"
"runtime/debug"
_ "time/tzdata"
"github.com/TheTNB/panel/internal/bootstrap"
)
func main() {
bootstrap.BootWeb()
if os.Geteuid() != 0 {
panic("panel must run as root")
}
debug.SetGCPercent(10)
debug.SetMemoryLimit(128 << 20)
web, err := initWeb()
if err != nil {
panic(err)
}
if err = web.Run(); err != nil {
panic(err)
}
}
+21
View File
@@ -0,0 +1,21 @@
//go:build wireinject
package main
import (
"github.com/google/wire"
"github.com/tnb-labs/panel/internal/app"
"github.com/tnb-labs/panel/internal/apps"
"github.com/tnb-labs/panel/internal/bootstrap"
"github.com/tnb-labs/panel/internal/data"
"github.com/tnb-labs/panel/internal/http/middleware"
"github.com/tnb-labs/panel/internal/job"
"github.com/tnb-labs/panel/internal/route"
"github.com/tnb-labs/panel/internal/service"
)
// initWeb init application.
func initWeb() (*app.Web, error) {
panic(wire.Build(bootstrap.ProviderSet, middleware.ProviderSet, route.ProviderSet, service.ProviderSet, data.ProviderSet, apps.ProviderSet, job.ProviderSet, app.NewWeb))
}
+155
View File
@@ -0,0 +1,155 @@
// Code generated by Wire. DO NOT EDIT.
//go:generate go run -mod=mod github.com/google/wire/cmd/wire
//go:build !wireinject
// +build !wireinject
package main
import (
"github.com/tnb-labs/panel/internal/app"
"github.com/tnb-labs/panel/internal/apps/benchmark"
"github.com/tnb-labs/panel/internal/apps/docker"
"github.com/tnb-labs/panel/internal/apps/fail2ban"
"github.com/tnb-labs/panel/internal/apps/frp"
"github.com/tnb-labs/panel/internal/apps/gitea"
"github.com/tnb-labs/panel/internal/apps/memcached"
"github.com/tnb-labs/panel/internal/apps/mysql"
"github.com/tnb-labs/panel/internal/apps/nginx"
"github.com/tnb-labs/panel/internal/apps/php74"
"github.com/tnb-labs/panel/internal/apps/php80"
"github.com/tnb-labs/panel/internal/apps/php81"
"github.com/tnb-labs/panel/internal/apps/php82"
"github.com/tnb-labs/panel/internal/apps/php83"
"github.com/tnb-labs/panel/internal/apps/php84"
"github.com/tnb-labs/panel/internal/apps/phpmyadmin"
"github.com/tnb-labs/panel/internal/apps/podman"
"github.com/tnb-labs/panel/internal/apps/postgresql"
"github.com/tnb-labs/panel/internal/apps/pureftpd"
"github.com/tnb-labs/panel/internal/apps/redis"
"github.com/tnb-labs/panel/internal/apps/rsync"
"github.com/tnb-labs/panel/internal/apps/s3fs"
"github.com/tnb-labs/panel/internal/apps/supervisor"
"github.com/tnb-labs/panel/internal/apps/toolbox"
"github.com/tnb-labs/panel/internal/bootstrap"
"github.com/tnb-labs/panel/internal/data"
"github.com/tnb-labs/panel/internal/http/middleware"
"github.com/tnb-labs/panel/internal/job"
"github.com/tnb-labs/panel/internal/route"
"github.com/tnb-labs/panel/internal/service"
)
import (
_ "time/tzdata"
)
// Injectors from wire.go:
// initWeb init application.
func initWeb() (*app.Web, error) {
koanf, err := bootstrap.NewConf()
if err != nil {
return nil, err
}
logger := bootstrap.NewLog(koanf)
db, err := bootstrap.NewDB(koanf, logger)
if err != nil {
return nil, err
}
manager, err := bootstrap.NewSession(koanf, db)
if err != nil {
return nil, err
}
cacheRepo := data.NewCacheRepo(db)
queue := bootstrap.NewQueue()
taskRepo := data.NewTaskRepo(db, logger, queue)
appRepo := data.NewAppRepo(db, cacheRepo, taskRepo)
middlewares := middleware.NewMiddlewares(koanf, logger, manager, appRepo)
userRepo := data.NewUserRepo(db)
userService := service.NewUserService(koanf, manager, userRepo)
databaseServerRepo := data.NewDatabaseServerRepo(db, logger)
databaseUserRepo := data.NewDatabaseUserRepo(db, databaseServerRepo)
databaseRepo := data.NewDatabaseRepo(db, databaseServerRepo, databaseUserRepo)
certRepo := data.NewCertRepo(db)
certAccountRepo := data.NewCertAccountRepo(db, userRepo)
websiteRepo := data.NewWebsiteRepo(db, cacheRepo, databaseRepo, databaseServerRepo, databaseUserRepo, certRepo, certAccountRepo)
settingRepo := data.NewSettingRepo(db, koanf, taskRepo)
cronRepo := data.NewCronRepo(db)
backupRepo := data.NewBackupRepo(db, settingRepo, websiteRepo)
dashboardService := service.NewDashboardService(koanf, taskRepo, websiteRepo, appRepo, settingRepo, cronRepo, backupRepo)
taskService := service.NewTaskService(taskRepo)
websiteService := service.NewWebsiteService(websiteRepo, settingRepo)
databaseService := service.NewDatabaseService(databaseRepo)
databaseServerService := service.NewDatabaseServerService(databaseServerRepo)
databaseUserService := service.NewDatabaseUserService(databaseUserRepo)
backupService := service.NewBackupService(backupRepo)
certService := service.NewCertService(certRepo)
certDNSRepo := data.NewCertDNSRepo(db)
certDNSService := service.NewCertDNSService(certDNSRepo)
certAccountService := service.NewCertAccountService(certAccountRepo)
appService := service.NewAppService(appRepo, cacheRepo, settingRepo)
cronService := service.NewCronService(cronRepo)
processService := service.NewProcessService()
safeRepo := data.NewSafeRepo()
safeService := service.NewSafeService(safeRepo)
firewallService := service.NewFirewallService()
sshRepo := data.NewSSHRepo(db)
sshService := service.NewSSHService(sshRepo)
containerRepo := data.NewContainerRepo()
containerService := service.NewContainerService(containerRepo)
containerNetworkRepo := data.NewContainerNetworkRepo()
containerNetworkService := service.NewContainerNetworkService(containerNetworkRepo)
containerImageRepo := data.NewContainerImageRepo()
containerImageService := service.NewContainerImageService(containerImageRepo)
containerVolumeRepo := data.NewContainerVolumeRepo()
containerVolumeService := service.NewContainerVolumeService(containerVolumeRepo)
fileService := service.NewFileService(taskRepo)
monitorRepo := data.NewMonitorRepo(db, settingRepo)
monitorService := service.NewMonitorService(settingRepo, monitorRepo)
settingService := service.NewSettingService(settingRepo)
systemctlService := service.NewSystemctlService()
benchmarkApp := benchmark.NewApp()
dockerApp := docker.NewApp()
fail2banApp := fail2ban.NewApp(websiteRepo)
frpApp := frp.NewApp()
giteaApp := gitea.NewApp()
memcachedApp := memcached.NewApp()
mysqlApp := mysql.NewApp(settingRepo)
nginxApp := nginx.NewApp()
php74App := php74.NewApp(taskRepo)
php80App := php80.NewApp(taskRepo)
php81App := php81.NewApp(taskRepo)
php82App := php82.NewApp(taskRepo)
php83App := php83.NewApp(taskRepo)
php84App := php84.NewApp(taskRepo)
phpmyadminApp := phpmyadmin.NewApp()
podmanApp := podman.NewApp()
postgresqlApp := postgresql.NewApp()
pureftpdApp := pureftpd.NewApp()
redisApp := redis.NewApp()
rsyncApp := rsync.NewApp()
s3fsApp := s3fs.NewApp(settingRepo)
supervisorApp := supervisor.NewApp()
toolboxApp := toolbox.NewApp()
loader := bootstrap.NewLoader(benchmarkApp, dockerApp, fail2banApp, frpApp, giteaApp, memcachedApp, mysqlApp, nginxApp, php74App, php80App, php81App, php82App, php83App, php84App, phpmyadminApp, podmanApp, postgresqlApp, pureftpdApp, redisApp, rsyncApp, s3fsApp, supervisorApp, toolboxApp)
http := route.NewHttp(userService, dashboardService, taskService, websiteService, databaseService, databaseServerService, databaseUserService, backupService, certService, certDNSService, certAccountService, appService, cronService, processService, safeService, firewallService, sshService, containerService, containerNetworkService, containerImageService, containerVolumeService, fileService, monitorService, settingService, systemctlService, loader)
wsService := service.NewWsService(koanf, sshRepo)
ws := route.NewWs(wsService)
mux, err := bootstrap.NewRouter(middlewares, http, ws)
if err != nil {
return nil, err
}
server, err := bootstrap.NewHttp(koanf, mux)
if err != nil {
return nil, err
}
gormigrate := bootstrap.NewMigrate(db)
jobs := job.NewJobs(db, logger, settingRepo, certRepo, backupRepo, cacheRepo, taskRepo)
cron, err := bootstrap.NewCron(koanf, logger, jobs)
if err != nil {
return nil, err
}
validation := bootstrap.NewValidator(db)
web := app.NewWeb(koanf, mux, server, gormigrate, cron, queue, validation)
return web, nil
}
+33 -33
View File
@@ -1,50 +1,48 @@
module github.com/TheTNB/panel
module github.com/tnb-labs/panel
go 1.23
require (
github.com/bddjr/hlfhr v1.1.3
github.com/bddjr/hlfhr v1.3.8
github.com/beevik/ntp v1.4.3
github.com/creack/pty v1.1.23
github.com/creack/pty v1.1.24
github.com/expr-lang/expr v1.16.9
github.com/glebarez/sqlite v1.11.0
github.com/go-chi/chi/v5 v5.1.0
github.com/go-chi/chi/v5 v5.2.1
github.com/go-gormigrate/gormigrate/v2 v2.1.3
github.com/go-playground/locales v0.14.1
github.com/go-playground/universal-translator v0.18.1
github.com/go-playground/validator/v10 v10.22.1
github.com/go-rat/chix v1.1.4
github.com/go-rat/gormstore v1.0.6
github.com/go-rat/sessions v1.0.11
github.com/go-rat/utils v1.0.3
github.com/go-resty/resty/v2 v2.15.3
github.com/go-rat/utils v1.0.9
github.com/go-resty/resty/v2 v2.16.5
github.com/go-sql-driver/mysql v1.8.1
github.com/golang-cz/httplog v0.0.0-20241002114323-98e09d6f537a
github.com/gomodule/redigo v1.9.2
github.com/google/wire v0.6.0
github.com/gookit/validate v1.5.4
github.com/gorilla/websocket v1.5.3
github.com/hashicorp/go-version v1.7.0
github.com/knadh/koanf/parsers/yaml v0.1.0
github.com/knadh/koanf/providers/file v1.1.2
github.com/knadh/koanf/v2 v2.1.1
github.com/knadh/koanf/v2 v2.1.2
github.com/lib/pq v1.10.9
github.com/libdns/alidns v1.0.3
github.com/libdns/cloudflare v0.1.1
github.com/libdns/huaweicloud v0.2.2
github.com/libdns/huaweicloud v0.3.1
github.com/libdns/libdns v0.2.2
github.com/libdns/tencentcloud v1.0.0
github.com/mholt/acmez/v2 v2.0.3
github.com/libdns/tencentcloud v1.2.0
github.com/mholt/acmez/v3 v3.0.1
github.com/orandin/slog-gorm v1.4.0
github.com/robfig/cron/v3 v3.0.1
github.com/samber/lo v1.47.0
github.com/samber/lo v1.49.1
github.com/sethvargo/go-limiter v1.0.0
github.com/shirou/gopsutil v2.21.11+incompatible
github.com/spf13/cast v1.7.0
github.com/stretchr/testify v1.9.0
github.com/tufanbarisyildirim/gonginx v0.0.0-20241013191809-e73b7dd454e8
github.com/urfave/cli/v3 v3.0.0-alpha9.1
go.uber.org/zap v1.27.0
go.uber.org/zap/exp v0.3.0
golang.org/x/crypto v0.28.0
golang.org/x/net v0.30.0
github.com/spf13/cast v1.7.1
github.com/stretchr/testify v1.10.0
github.com/tufanbarisyildirim/gonginx v0.0.0-20250120210832-12a9c7ae0c8a
github.com/urfave/cli/v3 v3.0.0-beta1
golang.org/x/crypto v0.32.0
golang.org/x/net v0.34.0
gopkg.in/natefinch/lumberjack.v2 v2.2.1
gopkg.in/yaml.v3 v3.0.1
gorm.io/gorm v1.25.12
@@ -53,40 +51,42 @@ require (
require (
filippo.io/edwards25519 v1.1.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/devhaozi/huaweicloud-sdk-go-v3 v0.0.0-20241018211007-bbebb6de5db7 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.5 // indirect
github.com/gabriel-vasile/mimetype v1.4.8 // indirect
github.com/glebarez/go-sqlite v1.22.0 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect
github.com/go-rat/securecookie v1.0.1 // indirect
github.com/go-viper/mapstructure/v2 v2.0.0 // indirect
github.com/go-viper/mapstructure/v2 v2.2.1 // indirect
github.com/gofiber/schema v1.2.0 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/gookit/filter v1.2.2 // indirect
github.com/gookit/goutil v0.6.18 // indirect
github.com/jaevor/go-nanoid v1.4.0 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/knadh/koanf/maps v0.1.1 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/ncruces/go-strftime v0.1.9 // indirect
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.597 // indirect
github.com/stretchr/objx v0.5.2 // indirect
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1051 // indirect
github.com/tklauser/go-sysconf v0.3.14 // indirect
github.com/tklauser/numcpus v0.8.0 // indirect
github.com/yusufpapurcu/wmi v1.2.4 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/sys v0.26.0 // indirect
golang.org/x/text v0.19.0 // indirect
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 // indirect
golang.org/x/sys v0.29.0 // indirect
golang.org/x/text v0.21.0 // indirect
modernc.org/libc v1.60.1 // indirect
modernc.org/mathutil v1.6.0 // indirect
modernc.org/memory v1.8.0 // indirect
modernc.org/sqlite v1.32.0 // indirect
)
replace github.com/mholt/acmez/v2 => github.com/TheTNB/acmez/v2 v2.0.0-20241025203320-cc718c4c870b
replace (
github.com/libdns/tencentcloud => github.com/devhaozi/tencentcloud v0.0.0-20241129095955-7d4e898ce504
github.com/mholt/acmez/v3 => github.com/tnb-labs/acmez/v3 v3.0.0-20250101070450-67fb7b3d86d1
)
+85 -88
View File
@@ -1,18 +1,15 @@
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
github.com/TheTNB/acmez/v2 v2.0.0-20241025203320-cc718c4c870b h1:1iVxCglpEJ/kq48YcujkWq8SeOacMuMmuekMmGyOSPA=
github.com/TheTNB/acmez/v2 v2.0.0-20241025203320-cc718c4c870b/go.mod h1:pQ1ysaDeGrIMvJ9dfJMk5kJNkn7L2sb3UhyrX6Q91cw=
github.com/bddjr/hlfhr v1.1.3 h1:O1Vxi7Qf0tOs9oGoSb3Q9KAGTSfh/EXyVMVSO9V1m90=
github.com/bddjr/hlfhr v1.1.3/go.mod h1:oyIv4Q9JpCgZFdtH3KyTNWp7YYRWl4zl8k4ozrMAB4g=
github.com/bddjr/hlfhr v1.3.8 h1:QQ6KYgtnBbvYvCWuu/tOnBZamKAPtJzesj2qbjgyn7o=
github.com/bddjr/hlfhr v1.3.8/go.mod h1:oyIv4Q9JpCgZFdtH3KyTNWp7YYRWl4zl8k4ozrMAB4g=
github.com/beevik/ntp v1.4.3 h1:PlbTvE5NNy4QHmA4Mg57n7mcFTmr1W1j3gcK7L1lqho=
github.com/beevik/ntp v1.4.3/go.mod h1:Unr8Zg+2dRn7d8bHFuehIMSvvUYssHMxW3Q5Nx4RW5Q=
github.com/creack/pty v1.1.23 h1:4M6+isWdcStXEf15G/RbrMPOQj1dZ7HPZCGwE4kOeP0=
github.com/creack/pty v1.1.23/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s=
github.com/creack/pty v1.1.24/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/devhaozi/huaweicloud-sdk-go-v3 v0.0.0-20241018211007-bbebb6de5db7 h1:AjCMD0AEGHHbcIpvRcrI8rMA+Us5F4uUt3B3KSpiYN8=
github.com/devhaozi/huaweicloud-sdk-go-v3 v0.0.0-20241018211007-bbebb6de5db7/go.mod h1:Gz/Ng6WCvYc1Q2smuPvow9kszfyH47wtnpZzvdD2juA=
github.com/devhaozi/tencentcloud v0.0.0-20241129095955-7d4e898ce504 h1:Wk7RQyamGDfAz+5hZIT/GIm6ay5cORztgYVXOJTobKY=
github.com/devhaozi/tencentcloud v0.0.0-20241129095955-7d4e898ce504/go.mod h1:o0+WCxQ7LGLtyjnjYU4HbGW9uVjN44SdUDhxdUYLGPw=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/expr-lang/expr v1.16.9 h1:WUAzmR0JNI9JCiF0/ewwHB1gmcGw5wW7nWt8gc6PpCI=
@@ -21,26 +18,18 @@ github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHk
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/gabriel-vasile/mimetype v1.4.5 h1:J7wGKdGu33ocBOhGy0z653k/lFKLFDPJMG8Gql0kxn4=
github.com/gabriel-vasile/mimetype v1.4.5/go.mod h1:ibHel+/kbxn9x2407k1izTA1S81ku1z/DlgOW2QE0M4=
github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM=
github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8=
github.com/glebarez/go-sqlite v1.22.0 h1:uAcMJhaA6r3LHMTFgP0SifzgXg46yJkgxqyuyec+ruQ=
github.com/glebarez/go-sqlite v1.22.0/go.mod h1:PlBIdHe0+aUEFn+r2/uthrWq4FxbzugL0L8Li6yQJbc=
github.com/glebarez/sqlite v1.11.0 h1:wSG0irqzP6VurnMEpFGer5Li19RpIRi2qvQz++w0GMw=
github.com/glebarez/sqlite v1.11.0/go.mod h1:h8/o8j5wiAsqSPoWELDUdJXhjAhsVliSn7bWZjOhrgQ=
github.com/go-chi/chi/v5 v5.1.0 h1:acVI1TYaD+hhedDJ3r54HyA6sExp3HfXq7QWEEY/xMw=
github.com/go-chi/chi/v5 v5.1.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
github.com/go-chi/chi/v5 v5.2.1 h1:KOIHODQj58PmL80G2Eak4WdvUzjSJSm0vG72crDCqb8=
github.com/go-chi/chi/v5 v5.2.1/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops=
github.com/go-gormigrate/gormigrate/v2 v2.1.3 h1:ei3Vq/rpPI/jCJY9mRHJAKg5vU+EhZyWhBAkaAomQuw=
github.com/go-gormigrate/gormigrate/v2 v2.1.3/go.mod h1:VJ9FIOBAur+NmQ8c4tDVwOuiJcgupTG105FexPFrXzA=
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.22.1 h1:40JcKH+bBNGFczGuoBYgX4I6m/i27HYW8P9FDk5PbgA=
github.com/go-playground/validator/v10 v10.22.1/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
github.com/go-rat/chix v1.1.4 h1:YVDwF4vrlkm5hmlDGWKoiWPgP98pJooBvhsto8UWq+o=
github.com/go-rat/chix v1.1.4/go.mod h1:eKUTG7GXqMS278PH0QZi8yMWZddvMfxqWu7mverM6kQ=
github.com/go-rat/gormstore v1.0.6 h1:YxmaY6n3JoTk6o9RXoZ1+cQ6HQL+ayf/6d8D76ydCAc=
@@ -49,26 +38,40 @@ github.com/go-rat/securecookie v1.0.1 h1:HW0fpKmB+FjJzXTw8ABOwBJ+XrPmRBSZqHhmrv8
github.com/go-rat/securecookie v1.0.1/go.mod h1:tP/ObWYyjmcpabQ7WTon/i2lBSip/Aolliw2llXuPDU=
github.com/go-rat/sessions v1.0.11 h1:2eTUvhEBtymrAtwv71LlGHNylz+Ad2SgY3jg/sSUboA=
github.com/go-rat/sessions v1.0.11/go.mod h1:Ray/GCbuhm4U9xpjFFSCfOTCEn91puEhAXX5creHE9g=
github.com/go-rat/utils v1.0.3 h1:SqH/O0KYq4SBv8naSAjJA4hC45/d8NLNrTCONfqjbFM=
github.com/go-rat/utils v1.0.3/go.mod h1:4WNPlrF57KmeGZN3HOeBgdBVLJL3xgba4QRP/t6pKrE=
github.com/go-resty/resty/v2 v2.15.3 h1:bqff+hcqAflpiF591hhJzNdkRsFhlB96CYfBwSFvql8=
github.com/go-resty/resty/v2 v2.15.3/go.mod h1:0fHAoK7JoBy/Ch36N8VFeMsK7xQOHhvWaC3iOktwmIU=
github.com/go-rat/utils v1.0.9 h1:16zq6CpeULJgoW+TaJZ+gS4EPl0tQYAcuAdx3/GNCNs=
github.com/go-rat/utils v1.0.9/go.mod h1:LhzbrdsTHIo6Rjlz27Nh8edkugmoxbZjN87iV+ch+5M=
github.com/go-resty/resty/v2 v2.16.5 h1:hBKqmWrr7uRc3euHVqmh1HTHcKn99Smr7o5spptdhTM=
github.com/go-resty/resty/v2 v2.16.5/go.mod h1:hkJtXbA2iKHzJheXYvQ8snQES5ZLGKMwQ07xAwp/fiA=
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
github.com/go-viper/mapstructure/v2 v2.0.0 h1:dhn8MZ1gZ0mzeodTG3jt5Vj/o87xZKuNAprG2mQfMfc=
github.com/go-viper/mapstructure/v2 v2.0.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss=
github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
github.com/gofiber/schema v1.2.0 h1:j+ZRrNnUa/0ZuWrn/6kAtAufEr4jCJ+JuTURAMxNSZg=
github.com/gofiber/schema v1.2.0/go.mod h1:YYwj01w3hVfaNjhtJzaqetymL56VW642YS3qZPhuE6c=
github.com/golang-cz/httplog v0.0.0-20241002114323-98e09d6f537a h1:BAyyIK6rc6Tq9vT2KVlPJXD8EVv/LpaFwn4fgfLwtHg=
github.com/golang-cz/httplog v0.0.0-20241002114323-98e09d6f537a/go.mod h1:bgk4Ij/0OQ89UeoFFAQrSNhbbr4rKJ0fwWfo7wc+TCc=
github.com/gomodule/redigo v1.9.2 h1:HrutZBLhSIU8abiSfW8pj8mPhOyMYjZT/wcA4/L9L9s=
github.com/gomodule/redigo v1.9.2/go.mod h1:KsU3hiK/Ay8U42qpaJk+kuNa3C+spxapWpM+ywhcgtw=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd h1:gbpYu9NMq8jhDVbvlGkMFWCjLFlqqEZjEmObmhUy6Vo=
github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw=
github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/wire v0.6.0 h1:HBkoIh4BdSxoyo9PveV8giw7ZsaBOvzWKfcg/6MrVwI=
github.com/google/wire v0.6.0/go.mod h1:F4QhpQ9EDIdJ1Mbop/NZBRB+5yrR6qg3BnctaoUk6NA=
github.com/gookit/color v1.5.4 h1:FZmqs7XOyGgCAxmWyPslpiok1k05wmY3SJTytgvYFs0=
github.com/gookit/color v1.5.4/go.mod h1:pZJOeOS8DM43rXbp4AZo1n9zCU2qjpcRko0b6/QJi9w=
github.com/gookit/filter v1.2.2 h1:LSBQLk4M4fpfhaOG0hJ/GJ+qu+2+lLddgxlGfzcd8VQ=
github.com/gookit/filter v1.2.2/go.mod h1:y4xpiqM/fV9g9yT/Vg5OWUq4q9siPj0UlH9O57xYuGs=
github.com/gookit/goutil v0.6.18 h1:MUVj0G16flubWT8zYVicIuisUiHdgirPAkmnfD2kKgw=
github.com/gookit/goutil v0.6.18/go.mod h1:AY/5sAwKe7Xck+mEbuxj0n/bc3qwrGNe3Oeulln7zBA=
github.com/gookit/validate v1.5.4 h1:nwBo6vULnVUeNFCOde6RKFRbOCKJXVMnWR0ghedacLg=
github.com/gookit/validate v1.5.4/go.mod h1:p9sRPfpvYB4vXICBpEPzv8FoAky+XhUOhWQghgmmat4=
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY=
@@ -85,29 +88,23 @@ github.com/knadh/koanf/parsers/yaml v0.1.0 h1:ZZ8/iGfRLvKSaMEECEBPM1HQslrZADk8fP
github.com/knadh/koanf/parsers/yaml v0.1.0/go.mod h1:cvbUDC7AL23pImuQP0oRw/hPuccrNBS2bps8asS0CwY=
github.com/knadh/koanf/providers/file v1.1.2 h1:aCC36YGOgV5lTtAFz2qkgtWdeQsgfxUkxDOe+2nQY3w=
github.com/knadh/koanf/providers/file v1.1.2/go.mod h1:/faSBcv2mxPVjFrXck95qeoyoZ5myJ6uxN8OOVNJJCI=
github.com/knadh/koanf/v2 v2.1.1 h1:/R8eXqasSTsmDCsAyYj+81Wteg8AqrV9CP6gvsTsOmM=
github.com/knadh/koanf/v2 v2.1.1/go.mod h1:4mnTRbZCK+ALuBXHZMjDfG9y714L7TykVnZkXbMU3Es=
github.com/knadh/koanf/v2 v2.1.2 h1:I2rtLRqXRy1p01m/utEtpZSSA6dcJbgGVuE27kW2PzQ=
github.com/knadh/koanf/v2 v2.1.2/go.mod h1:Gphfaen0q1Fc1HTgJgSTC4oRX9R2R5ErYMZJy8fLJBo=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/libdns/alidns v1.0.3 h1:LFHuGnbseq5+HCeGa1aW8awyX/4M2psB9962fdD2+yQ=
github.com/libdns/alidns v1.0.3/go.mod h1:e18uAG6GanfRhcJj6/tps2rCMzQJaYVcGKT+ELjdjGE=
github.com/libdns/cloudflare v0.1.1 h1:FVPfWwP8zZCqj268LZjmkDleXlHPlFU9KC4OJ3yn054=
github.com/libdns/cloudflare v0.1.1/go.mod h1:9VK91idpOjg6v7/WbjkEW49bSCxj00ALesIFDhJ8PBU=
github.com/libdns/huaweicloud v0.2.2 h1:DvaWLiPJ0hoOvvPafKXgWv4gG33O8cqEu87GJeXYtbc=
github.com/libdns/huaweicloud v0.2.2/go.mod h1:F9vNIca+Cq1ZJiMCSkHQUdvXEGY6UbLoaYI3Py9CFDs=
github.com/libdns/huaweicloud v0.3.1 h1:wro0zpG86JKL3QVEaV/xfHW/59rmqwMYhcbl16w9EYg=
github.com/libdns/huaweicloud v0.3.1/go.mod h1:6s5ZIwLUr2qKsQz2SRNo7uh8X5uJohxoBR95rtSpNcI=
github.com/libdns/libdns v0.2.0/go.mod h1:yQCXzk1lEZmmCPa857bnk4TsOiqYasqpyOEeSObbb40=
github.com/libdns/libdns v0.2.2 h1:O6ws7bAfRPaBsgAYt8MDe2HcNBGC29hkZ9MX2eUSX3s=
github.com/libdns/libdns v0.2.2/go.mod h1:4Bj9+5CQiNMVGf87wjX4CY3HQJypUHRuLvlsfsZqLWQ=
github.com/libdns/tencentcloud v1.0.0 h1:u4LXnYu/lu/9P5W+MCVPeSDnwI+6w+DxYhQ1wSnQOuU=
github.com/libdns/tencentcloud v1.0.0/go.mod h1:NlCgPumzUsZWSOo1+Q/Hfh8G6TNRAaTUeWQdg6LbtUI=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
@@ -128,66 +125,65 @@ github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/samber/lo v1.47.0 h1:z7RynLwP5nbyRscyvcD043DWYoOcYRv3mV8lBeqOCLc=
github.com/samber/lo v1.47.0/go.mod h1:RmDH9Ct32Qy3gduHQuKJ3gW1fMHAnE/fAzQuf6He5cU=
github.com/samber/lo v1.49.1 h1:4BIFyVfuQSEpluc7Fua+j1NolZHiEHEpaSEKdsH0tew=
github.com/samber/lo v1.49.1/go.mod h1:dO6KHFzUKXgP8LDhU0oI8d2hekjXnGOu0DB8Jecxd6o=
github.com/sethvargo/go-limiter v1.0.0 h1:JqW13eWEMn0VFv86OKn8wiYJY/m250WoXdrjRV0kLe4=
github.com/sethvargo/go-limiter v1.0.0/go.mod h1:01b6tW25Ap+MeLYBuD4aHunMrJoNO5PVUFdS9rac3II=
github.com/shirou/gopsutil v2.21.11+incompatible h1:lOGOyCG67a5dv2hq5Z1BLDUqqKp3HkbjPcz5j6XMS0U=
github.com/shirou/gopsutil v2.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w=
github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.597 h1:C0GHdLTfikLVoEzfhgPfrZ7LwlG0xiCmk6iwNKE+xs0=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.597/go.mod h1:7sCQWVkxcsR38nffDW057DRGk8mUjK1Ing/EFOK8s8Y=
github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y=
github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1051 h1:3mg0L9vv9eO8UN4Oa7vNawe6yUIuXf9D0Q79rUmnblo=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1051/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
github.com/tklauser/go-sysconf v0.3.14 h1:g5vzr9iPFFz24v2KZXs/pvpvh8/V9Fw6vQK5ZZb78yU=
github.com/tklauser/go-sysconf v0.3.14/go.mod h1:1ym4lWMLUOhuBOPGtRcJm7tEGX4SCYNEEEtghGG/8uY=
github.com/tklauser/numcpus v0.8.0 h1:Mx4Wwe/FjZLeQsK/6kt2EOepwwSl7SmJrK5bV/dXYgY=
github.com/tklauser/numcpus v0.8.0/go.mod h1:ZJZlAY+dmR4eut8epnzf0u/VwodKmryxR8txiloSqBE=
github.com/tufanbarisyildirim/gonginx v0.0.0-20241013191809-e73b7dd454e8 h1:7yw1yHkylDcu/CwY4hEEe8MycDLo7B9LjcqwhoL8NrM=
github.com/tufanbarisyildirim/gonginx v0.0.0-20241013191809-e73b7dd454e8/go.mod h1:itu4KWRgrfEwGcfNka+rV4houuirUau53i0diN4lG5g=
github.com/urfave/cli/v3 v3.0.0-alpha9.1 h1:1fJU+bltkwN8lF4Sni/X0i1d8XwPIrS82ivZ8qsp/q4=
github.com/urfave/cli/v3 v3.0.0-alpha9.1/go.mod h1:FnIeEMYu+ko8zP1F9Ypr3xkZMIDqW3DR92yUtY39q1Y=
github.com/tnb-labs/acmez/v3 v3.0.0-20250101070450-67fb7b3d86d1 h1:7IhZYEiBWy3KfKi9wZkv4Um8QYYF2fYzQ+xNrOx/tHI=
github.com/tnb-labs/acmez/v3 v3.0.0-20250101070450-67fb7b3d86d1/go.mod h1:L1wOU06KKvq7tswuMDwKdcHeKpFFgkppZy/y0DFxagQ=
github.com/tufanbarisyildirim/gonginx v0.0.0-20250120210832-12a9c7ae0c8a h1:bFMBmB409YhHd+B4yfM7JPYTCgxnQjqzIfFOiN4Tpsc=
github.com/tufanbarisyildirim/gonginx v0.0.0-20250120210832-12a9c7ae0c8a/go.mod h1:hdMWBc1+TyB6G5ZZBBgPWQ8cjRZ6zpYdhal0uu6E9QM=
github.com/urfave/cli/v3 v3.0.0-beta1 h1:6DTaaUarcM0wX7qj5Hcvs+5Dm3dyUTBbEwIWAjcw9Zg=
github.com/urfave/cli/v3 v3.0.0-beta1/go.mod h1:FnIeEMYu+ko8zP1F9Ypr3xkZMIDqW3DR92yUtY39q1Y=
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
go.uber.org/zap/exp v0.3.0 h1:6JYzdifzYkGmTdRR59oYH+Ng7k49H9qVpWwNSsGJj3U=
go.uber.org/zap/exp v0.3.0/go.mod h1:5I384qq7XGxYyByIhHm6jg5CHkGY0nsTfbDLgDDlgJQ=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw=
golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U=
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 h1:yqrTHse8TCMW1M1ZCP+VAR/l0kKxwaAIqN/il7x4voA=
golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8/go.mod h1:tujkw807nyEEAamNbDrEGzRav+ilXA7PCRAd6xsmwiU=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8=
golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4=
golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4=
golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU=
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -197,42 +193,43 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
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/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24=
golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M=
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY=
golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg=
golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U=
golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg=
golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI=
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps=
golang.org/x/tools v0.29.0 h1:Xx0h3TtM9rzQpQuR4dKLrdglAmCEN5Oi+P74JdhdzXE=
golang.org/x/tools v0.29.0/go.mod h1:KMQVMRsVxU6nHCFXrBPhDB8XncLNLM0lIy/F14RP588=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/gorm v1.25.12 h1:I0u8i2hWQItBq1WfE0o2+WuL9+8L21K9e2HHSTE/0f8=
+37
View File
@@ -0,0 +1,37 @@
package app
import (
"context"
"fmt"
"os"
"github.com/go-gormigrate/gormigrate/v2"
"github.com/urfave/cli/v3"
"github.com/tnb-labs/panel/pkg/apploader"
)
type Cli struct {
cmd *cli.Command
migrator *gormigrate.Gormigrate
}
func NewCli(cmd *cli.Command, migrator *gormigrate.Gormigrate, _ *apploader.Loader) *Cli {
IsCli = true
return &Cli{
cmd: cmd,
migrator: migrator,
}
}
func (r *Cli) Run() error {
// migrate database
// 这里不处理错误,这么做是为了在异常时用户可以用 fix 命令尝试修复
_ = r.migrator.Migrate()
if err := r.cmd.Run(context.TODO(), os.Args); err != nil {
fmt.Printf("|-%v\n", err)
}
return nil
}
+17 -32
View File
@@ -1,32 +1,6 @@
package app
import (
"log/slog"
"github.com/go-chi/chi/v5"
ut "github.com/go-playground/universal-translator"
"github.com/go-playground/validator/v10"
"github.com/go-rat/sessions"
"github.com/knadh/koanf/v2"
"github.com/robfig/cron/v3"
"gorm.io/gorm"
"github.com/TheTNB/panel/pkg/queue"
)
var (
Conf *koanf.Koanf
Http *chi.Mux
Orm *gorm.DB
Validator *validator.Validate
Translator *ut.Translator
Session *sessions.Manager
Cron *cron.Cron
Queue *queue.Queue
Logger *slog.Logger
)
// 定义面板状态常量
// 面板状态常量
const (
StatusNormal = iota
StatusMaintain
@@ -37,9 +11,20 @@ const (
// 面板全局变量
var (
Root string
Version string
Locale string
IsCli bool
Status = StatusNormal
Key string // 密钥
Root string // 根目录
Locale string // 语言
IsCli bool // 是否命令行
Status = StatusNormal // 面板状态
)
// 自动注入
var (
Version = "0.0.0"
BuildTime string
CommitHash string
GoVersion string
BuildID string
BuildUser string
BuildHost string
)
+70
View File
@@ -0,0 +1,70 @@
package app
import (
"context"
"errors"
"fmt"
"net/http"
"path/filepath"
"github.com/bddjr/hlfhr"
"github.com/go-chi/chi/v5"
"github.com/go-gormigrate/gormigrate/v2"
"github.com/gookit/validate"
"github.com/knadh/koanf/v2"
"github.com/robfig/cron/v3"
"github.com/tnb-labs/panel/pkg/queue"
)
type Web struct {
conf *koanf.Koanf
router *chi.Mux
server *hlfhr.Server
migrator *gormigrate.Gormigrate
cron *cron.Cron
queue *queue.Queue
}
func NewWeb(conf *koanf.Koanf, router *chi.Mux, server *hlfhr.Server, migrator *gormigrate.Gormigrate, cron *cron.Cron, queue *queue.Queue, _ *validate.Validation) *Web {
return &Web{
conf: conf,
router: router,
server: server,
migrator: migrator,
cron: cron,
queue: queue,
}
}
func (r *Web) Run() error {
// migrate database
if err := r.migrator.Migrate(); err != nil {
return err
}
fmt.Println("[DB] database migrated")
// start cron scheduler
r.cron.Start()
fmt.Println("[CRON] cron scheduler started")
// start queue
r.queue.Run(context.TODO())
// run http server
if r.conf.Bool("http.tls") {
cert := filepath.Join(Root, "panel/storage/cert.pem")
key := filepath.Join(Root, "panel/storage/cert.key")
fmt.Println("[HTTP] listening and serving on port", r.conf.MustInt("http.port"), "with tls")
if err := r.server.ListenAndServeTLS(cert, key); !errors.Is(err, http.ErrServerClosed) {
return err
}
} else {
fmt.Println("[HTTP] listening and serving on port", r.conf.MustInt("http.port"))
if err := r.server.ListenAndServe(); !errors.Is(err, http.ErrServerClosed) {
return err
}
}
return nil
}
+55
View File
@@ -0,0 +1,55 @@
package apps
import (
"github.com/google/wire"
"github.com/tnb-labs/panel/internal/apps/benchmark"
"github.com/tnb-labs/panel/internal/apps/docker"
"github.com/tnb-labs/panel/internal/apps/fail2ban"
"github.com/tnb-labs/panel/internal/apps/frp"
"github.com/tnb-labs/panel/internal/apps/gitea"
"github.com/tnb-labs/panel/internal/apps/memcached"
"github.com/tnb-labs/panel/internal/apps/mysql"
"github.com/tnb-labs/panel/internal/apps/nginx"
"github.com/tnb-labs/panel/internal/apps/php74"
"github.com/tnb-labs/panel/internal/apps/php80"
"github.com/tnb-labs/panel/internal/apps/php81"
"github.com/tnb-labs/panel/internal/apps/php82"
"github.com/tnb-labs/panel/internal/apps/php83"
"github.com/tnb-labs/panel/internal/apps/php84"
"github.com/tnb-labs/panel/internal/apps/phpmyadmin"
"github.com/tnb-labs/panel/internal/apps/podman"
"github.com/tnb-labs/panel/internal/apps/postgresql"
"github.com/tnb-labs/panel/internal/apps/pureftpd"
"github.com/tnb-labs/panel/internal/apps/redis"
"github.com/tnb-labs/panel/internal/apps/rsync"
"github.com/tnb-labs/panel/internal/apps/s3fs"
"github.com/tnb-labs/panel/internal/apps/supervisor"
"github.com/tnb-labs/panel/internal/apps/toolbox"
)
var ProviderSet = wire.NewSet(
benchmark.NewApp,
docker.NewApp,
fail2ban.NewApp,
frp.NewApp,
gitea.NewApp,
memcached.NewApp,
mysql.NewApp,
nginx.NewApp,
php74.NewApp,
php80.NewApp,
php81.NewApp,
php82.NewApp,
php83.NewApp,
php84.NewApp,
phpmyadmin.NewApp,
podman.NewApp,
postgresql.NewApp,
pureftpd.NewApp,
redis.NewApp,
rsync.NewApp,
s3fs.NewApp,
supervisor.NewApp,
toolbox.NewApp,
)
@@ -21,18 +21,24 @@ import (
"sync"
"time"
"github.com/TheTNB/panel/internal/service"
"github.com/go-chi/chi/v5"
"github.com/tnb-labs/panel/internal/service"
)
type Service struct {
type App struct {
}
func NewService() *Service {
return &Service{}
func NewApp() *App {
return &App{}
}
func (s *App) Route(r chi.Router) {
r.Post("/test", s.Test)
}
// Test 运行测试
func (s *Service) Test(w http.ResponseWriter, r *http.Request) {
func (s *App) Test(w http.ResponseWriter, r *http.Request) {
req, err := service.Bind[Test](r)
if err != nil {
service.Error(w, http.StatusUnprocessableEntity, "%v", err)
@@ -73,7 +79,7 @@ func (s *Service) Test(w http.ResponseWriter, r *http.Request) {
}
// calculateCpuScore 计算CPU成绩
func (s *Service) calculateCpuScore(duration time.Duration) int {
func (s *App) calculateCpuScore(duration time.Duration) int {
score := int((10 / duration.Seconds()) * float64(3000))
if score < 0 {
@@ -83,7 +89,7 @@ func (s *Service) calculateCpuScore(duration time.Duration) int {
}
// calculateScore 计算内存/硬盘成绩
func (s *Service) calculateScore(duration time.Duration) int {
func (s *App) calculateScore(duration time.Duration) int {
score := int((20 / duration.Seconds()) * float64(30000))
if score < 0 {
@@ -94,7 +100,7 @@ func (s *Service) calculateScore(duration time.Duration) int {
// 图像处理
func (s *Service) imageProcessing(multi bool) int {
func (s *App) imageProcessing(multi bool) int {
n := 1
if multi {
n = runtime.NumCPU()
@@ -107,7 +113,7 @@ func (s *Service) imageProcessing(multi bool) int {
return s.calculateCpuScore(duration)
}
func (s *Service) imageProcessingTask(numThreads int) error {
func (s *App) imageProcessingTask(numThreads int) error {
img := image.NewRGBA(image.Rect(0, 0, 4000, 4000))
for x := 0; x < 4000; x++ {
for y := 0; y < 4000; y++ {
@@ -156,7 +162,7 @@ func (s *Service) imageProcessingTask(numThreads int) error {
// 机器学习(矩阵乘法)
func (s *Service) machineLearning(multi bool) int {
func (s *App) machineLearning(multi bool) int {
n := 1
if multi {
n = runtime.NumCPU()
@@ -167,7 +173,7 @@ func (s *Service) machineLearning(multi bool) int {
return s.calculateCpuScore(duration)
}
func (s *Service) machineLearningTask(numThreads int) {
func (s *App) machineLearningTask(numThreads int) {
size := 900
a := make([][]float64, size)
b := make([][]float64, size)
@@ -214,7 +220,7 @@ func (s *Service) machineLearningTask(numThreads int) {
// 数学问题(计算斐波那契数)
func (s *Service) compileSimulationSingle(multi bool) int {
func (s *App) compileSimulationSingle(multi bool) int {
n := 1
if multi {
n = runtime.NumCPU()
@@ -248,7 +254,7 @@ func (s *Service) compileSimulationSingle(multi bool) int {
}
// 斐波那契函数
func (s *Service) fib(n int) *big.Int {
func (s *App) fib(n int) *big.Int {
if n < 2 {
return big.NewInt(int64(n))
}
@@ -265,7 +271,7 @@ func (s *Service) fib(n int) *big.Int {
// AES加密
func (s *Service) encryptionTest(multi bool) int {
func (s *App) encryptionTest(multi bool) int {
n := 1
if multi {
n = runtime.NumCPU()
@@ -278,9 +284,9 @@ func (s *Service) encryptionTest(multi bool) int {
return s.calculateCpuScore(duration)
}
func (s *Service) encryptionTestTask(numThreads int) error {
func (s *App) encryptionTestTask(numThreads int) error {
key := []byte("abcdefghijklmnopqrstuvwxyz123456")
dataSize := 1 * 1024 * 1024 * 1024 // 1GB
dataSize := 1024 * 1024 * 512 // 512 MB
plaintext := []byte(strings.Repeat("A", dataSize))
block, err := aes.NewCipher(key)
if err != nil {
@@ -320,7 +326,7 @@ func (s *Service) encryptionTestTask(numThreads int) error {
// 压缩/解压缩
func (s *Service) compressionTest(multi bool) int {
func (s *App) compressionTest(multi bool) int {
n := 1
if multi {
n = runtime.NumCPU()
@@ -331,7 +337,7 @@ func (s *Service) compressionTest(multi bool) int {
return s.calculateCpuScore(duration)
}
func (s *Service) compressionTestTask(numThreads int) {
func (s *App) compressionTestTask(numThreads int) {
data := []byte(strings.Repeat("耗子面板", 50000000))
chunkSize := len(data) / numThreads
@@ -381,7 +387,7 @@ func (s *Service) compressionTestTask(numThreads int) {
// 物理仿真(N体问题)
func (s *Service) physicsSimulation(multi bool) int {
func (s *App) physicsSimulation(multi bool) int {
n := 1
if multi {
n = runtime.NumCPU()
@@ -392,7 +398,7 @@ func (s *Service) physicsSimulation(multi bool) int {
return s.calculateCpuScore(duration)
}
func (s *Service) physicsSimulationTask(numThreads int) {
func (s *App) physicsSimulationTask(numThreads int) {
const (
numBodies = 4000
steps = 30
@@ -479,7 +485,7 @@ func (s *Service) physicsSimulationTask(numThreads int) {
// JSON解析
func (s *Service) jsonProcessing(multi bool) int {
func (s *App) jsonProcessing(multi bool) int {
n := 1
if multi {
n = runtime.NumCPU()
@@ -490,7 +496,7 @@ func (s *Service) jsonProcessing(multi bool) int {
return s.calculateCpuScore(duration)
}
func (s *Service) jsonProcessingTask(numThreads int) {
func (s *App) jsonProcessingTask(numThreads int) {
numElements := 1000000
elementsPerThread := numElements / numThreads
@@ -531,7 +537,7 @@ func (s *Service) jsonProcessingTask(numThreads int) {
// 内存性能
func (s *Service) memoryTestTask() map[string]any {
func (s *App) memoryTestTask() map[string]any {
results := make(map[string]any)
dataSize := 500 * 1024 * 1024 // 500 MB
data := make([]byte, dataSize)
@@ -549,7 +555,7 @@ func (s *Service) memoryTestTask() map[string]any {
return results
}
func (s *Service) memoryBandwidthTest(data []byte) string {
func (s *App) memoryBandwidthTest(data []byte) string {
dataSize := len(data)
startTime := time.Now()
@@ -566,7 +572,7 @@ func (s *Service) memoryBandwidthTest(data []byte) string {
return fmt.Sprintf("%.2f MB/s", speed)
}
func (s *Service) memoryLatencyTest(data []byte) string {
func (s *App) memoryLatencyTest(data []byte) string {
dataSize := len(data)
indices := rand.Perm(dataSize)
@@ -585,7 +591,7 @@ func (s *Service) memoryLatencyTest(data []byte) string {
// 硬盘IO
func (s *Service) diskTestTask() map[string]any {
func (s *App) diskTestTask() map[string]any {
results := make(map[string]any)
blockSizes := []int64{4 * 1024, 64 * 1024, 512 * 1024, 1 * 1024 * 1024} // 4K, 64K, 512K, 1M
fileSize := int64(100 * 1024 * 1024) // 100MB 文件
@@ -601,7 +607,7 @@ func (s *Service) diskTestTask() map[string]any {
return results
}
func (s *Service) diskIOTest(blockSize int64, fileSize int64) map[string]any {
func (s *App) diskIOTest(blockSize int64, fileSize int64) map[string]any {
result := make(map[string]any)
tempFile := fmt.Sprintf("tempfile_%d", blockSize)
defer os.Remove(tempFile)
@@ -619,7 +625,7 @@ func (s *Service) diskIOTest(blockSize int64, fileSize int64) map[string]any {
return result
}
func (s *Service) diskWriteTest(fileName string, blockSize int64, fileSize int64) (float64, float64) {
func (s *App) diskWriteTest(fileName string, blockSize int64, fileSize int64) (float64, float64) {
totalBlocks := fileSize / blockSize
data := make([]byte, blockSize)
@@ -653,7 +659,7 @@ func (s *Service) diskWriteTest(fileName string, blockSize int64, fileSize int64
return speed, iops
}
func (s *Service) diskReadTest(fileName string, blockSize int64, fileSize int64) (float64, float64) {
func (s *App) diskReadTest(fileName string, blockSize int64, fileSize int64) (float64, float64) {
totalBlocks := fileSize / blockSize
data := make([]byte, blockSize)
-18
View File
@@ -1,18 +0,0 @@
package benchmark
import (
"github.com/go-chi/chi/v5"
"github.com/TheTNB/panel/pkg/apploader"
"github.com/TheTNB/panel/pkg/types"
)
func init() {
apploader.Register(&types.App{
Slug: "benchmark",
Route: func(r chi.Router) {
service := NewService()
r.Post("/test", service.Test)
},
})
}
+1 -1
View File
@@ -1,6 +1,6 @@
package benchmark
type Test struct {
Name string `json:"name" validate:"required,oneof=image machine compile encryption compression physics json memory disk"`
Name string `json:"name" validate:"required|in:image,machine,compile,encryption,compression,physics,json,memory,disk"`
Multi bool `json:"multi"`
}
@@ -3,18 +3,25 @@ package docker
import (
"net/http"
"github.com/TheTNB/panel/internal/service"
"github.com/TheTNB/panel/pkg/io"
"github.com/TheTNB/panel/pkg/systemctl"
"github.com/go-chi/chi/v5"
"github.com/tnb-labs/panel/internal/service"
"github.com/tnb-labs/panel/pkg/io"
"github.com/tnb-labs/panel/pkg/systemctl"
)
type Service struct{}
type App struct{}
func NewService() *Service {
return &Service{}
func NewApp() *App {
return &App{}
}
func (s *Service) GetConfig(w http.ResponseWriter, r *http.Request) {
func (s *App) Route(r chi.Router) {
r.Get("/config", s.GetConfig)
r.Post("/config", s.UpdateConfig)
}
func (s *App) GetConfig(w http.ResponseWriter, r *http.Request) {
config, err := io.Read("/etc/docker/daemon.json")
if err != nil {
service.Error(w, http.StatusInternalServerError, "%v", err)
@@ -24,7 +31,7 @@ func (s *Service) GetConfig(w http.ResponseWriter, r *http.Request) {
service.Success(w, config)
}
func (s *Service) UpdateConfig(w http.ResponseWriter, r *http.Request) {
func (s *App) UpdateConfig(w http.ResponseWriter, r *http.Request) {
req, err := service.Bind[UpdateConfig](r)
if err != nil {
service.Error(w, http.StatusUnprocessableEntity, "%v", err)
-19
View File
@@ -1,19 +0,0 @@
package docker
import (
"github.com/go-chi/chi/v5"
"github.com/TheTNB/panel/pkg/apploader"
"github.com/TheTNB/panel/pkg/types"
)
func init() {
apploader.Register(&types.App{
Slug: "docker",
Route: func(r chi.Router) {
service := NewService()
r.Get("/config", service.GetConfig)
r.Post("/config", service.UpdateConfig)
},
})
}
@@ -6,31 +6,40 @@ import (
"regexp"
"strings"
"github.com/go-chi/chi/v5"
"github.com/go-rat/chix"
"github.com/go-rat/utils/str"
"github.com/spf13/cast"
"github.com/TheTNB/panel/internal/app"
"github.com/TheTNB/panel/internal/biz"
"github.com/TheTNB/panel/internal/data"
"github.com/TheTNB/panel/internal/service"
"github.com/TheTNB/panel/pkg/io"
"github.com/TheTNB/panel/pkg/os"
"github.com/TheTNB/panel/pkg/shell"
"github.com/TheTNB/panel/pkg/str"
"github.com/tnb-labs/panel/internal/app"
"github.com/tnb-labs/panel/internal/biz"
"github.com/tnb-labs/panel/internal/service"
"github.com/tnb-labs/panel/pkg/io"
"github.com/tnb-labs/panel/pkg/shell"
)
type Service struct {
type App struct {
websiteRepo biz.WebsiteRepo
}
func NewService() *Service {
return &Service{
websiteRepo: data.NewWebsiteRepo(),
func NewApp(website biz.WebsiteRepo) *App {
return &App{
websiteRepo: website,
}
}
func (s *App) Route(r chi.Router) {
r.Get("/jails", s.List)
r.Post("/jails", s.Create)
r.Delete("/jails", s.Delete)
r.Get("/jails/{name}", s.BanList)
r.Post("/unban", s.Unban)
r.Post("/whiteList", s.SetWhiteList)
r.Get("/whiteList", s.GetWhiteList)
}
// List 所有规则
func (s *Service) List(w http.ResponseWriter, r *http.Request) {
func (s *App) List(w http.ResponseWriter, r *http.Request) {
raw, err := io.Read("/etc/fail2ban/jail.local")
if err != nil {
service.Error(w, http.StatusUnprocessableEntity, "%v", err)
@@ -55,7 +64,6 @@ func (s *Service) List(w http.ResponseWriter, r *http.Request) {
continue
}
jailEnabled := strings.Contains(jailRaw, "enabled = true")
jailLogPath := regexp.MustCompile(`logpath = (.*)`).FindStringSubmatch(jailRaw)
jailMaxRetry := regexp.MustCompile(`maxretry = (.*)`).FindStringSubmatch(jailRaw)
jailFindTime := regexp.MustCompile(`findtime = (.*)`).FindStringSubmatch(jailRaw)
jailBanTime := regexp.MustCompile(`bantime = (.*)`).FindStringSubmatch(jailRaw)
@@ -63,7 +71,6 @@ func (s *Service) List(w http.ResponseWriter, r *http.Request) {
jails = append(jails, Jail{
Name: jailName,
Enabled: jailEnabled,
LogPath: jailLogPath[1],
MaxRetry: cast.ToInt(jailMaxRetry[1]),
FindTime: cast.ToInt(jailFindTime[1]),
BanTime: cast.ToInt(jailBanTime[1]),
@@ -79,7 +86,7 @@ func (s *Service) List(w http.ResponseWriter, r *http.Request) {
}
// Create 添加规则
func (s *Service) Create(w http.ResponseWriter, r *http.Request) {
func (s *App) Create(w http.ResponseWriter, r *http.Request) {
req, err := service.Bind[Add](r)
if err != nil {
service.Error(w, http.StatusUnprocessableEntity, "%v", err)
@@ -128,7 +135,6 @@ port = ` + ports + `
maxretry = ` + jailMaxRetry + `
findtime = ` + jailFindTime + `
bantime = ` + jailBanTime + `
action = %(action_mwl)s
logpath = ` + app.Root + `/wwwlogs/` + website.Name + `.log
# ` + jailWebsiteName + `-` + jailWebsiteMode + `-END
`
@@ -158,25 +164,17 @@ ignoreregex =
}
case "service":
var logPath string
var filter string
var port string
var err error
switch jailName {
case "ssh":
if os.IsDebian() || os.IsUbuntu() {
logPath = "/var/log/auth.log"
} else {
logPath = "/var/log/secure"
}
filter = "sshd"
port, err = shell.Execf("cat /etc/ssh/sshd_config | grep 'Port ' | awk '{print $2}'")
case "mysql":
logPath = app.Root + "/server/mysql/mysql-error.log"
filter = "mysqld-auth"
port, err = shell.Execf("cat %s/server/mysql/conf/my.cnf | grep 'port' | head -n 1 | awk '{print $3}'", app.Root)
case "pure-ftpd":
logPath = "/var/log/messages"
filter = "pure-ftpd"
port, err = shell.Execf(`cat %s/server/pure-ftpd/etc/pure-ftpd.conf | grep "Bind" | awk '{print $2}' | awk -F "," '{print $2}'`, app.Root)
default:
@@ -197,8 +195,6 @@ port = ` + port + `
maxretry = ` + jailMaxRetry + `
findtime = ` + jailFindTime + `
bantime = ` + jailBanTime + `
action = %(action_mwl)s
logpath = ` + logPath + `
# ` + jailName + `-END
`
raw += rule
@@ -208,7 +204,7 @@ logpath = ` + logPath + `
}
}
if _, err := shell.Execf("fail2ban-client reload"); err != nil {
if _, err = shell.Execf("fail2ban-client reload"); err != nil {
service.Error(w, http.StatusInternalServerError, "重载配置失败")
return
}
@@ -217,7 +213,7 @@ logpath = ` + logPath + `
}
// Delete 删除规则
func (s *Service) Delete(w http.ResponseWriter, r *http.Request) {
func (s *App) Delete(w http.ResponseWriter, r *http.Request) {
req, err := service.Bind[Delete](r)
if err != nil {
service.Error(w, http.StatusUnprocessableEntity, "%v", err)
@@ -251,7 +247,7 @@ func (s *Service) Delete(w http.ResponseWriter, r *http.Request) {
}
// BanList 获取封禁列表
func (s *Service) BanList(w http.ResponseWriter, r *http.Request) {
func (s *App) BanList(w http.ResponseWriter, r *http.Request) {
req, err := service.Bind[BanList](r)
if err != nil {
service.Error(w, http.StatusUnprocessableEntity, "%v", err)
@@ -296,7 +292,7 @@ func (s *Service) BanList(w http.ResponseWriter, r *http.Request) {
}
// Unban 解封
func (s *Service) Unban(w http.ResponseWriter, r *http.Request) {
func (s *App) Unban(w http.ResponseWriter, r *http.Request) {
req, err := service.Bind[Unban](r)
if err != nil {
service.Error(w, http.StatusUnprocessableEntity, "%v", err)
@@ -312,7 +308,7 @@ func (s *Service) Unban(w http.ResponseWriter, r *http.Request) {
}
// SetWhiteList 设置白名单
func (s *Service) SetWhiteList(w http.ResponseWriter, r *http.Request) {
func (s *App) SetWhiteList(w http.ResponseWriter, r *http.Request) {
req, err := service.Bind[SetWhiteList](r)
if err != nil {
service.Error(w, http.StatusUnprocessableEntity, "%v", err)
@@ -346,7 +342,7 @@ func (s *Service) SetWhiteList(w http.ResponseWriter, r *http.Request) {
}
// GetWhiteList 获取白名单
func (s *Service) GetWhiteList(w http.ResponseWriter, r *http.Request) {
func (s *App) GetWhiteList(w http.ResponseWriter, r *http.Request) {
raw, err := io.Read("/etc/fail2ban/jail.local")
if err != nil {
service.Error(w, http.StatusUnprocessableEntity, "%v", err)
-24
View File
@@ -1,24 +0,0 @@
package fail2ban
import (
"github.com/go-chi/chi/v5"
"github.com/TheTNB/panel/pkg/apploader"
"github.com/TheTNB/panel/pkg/types"
)
func init() {
apploader.Register(&types.App{
Slug: "fail2ban",
Route: func(r chi.Router) {
service := NewService()
r.Get("/jails", service.List)
r.Post("/jails", service.Create)
r.Delete("/jails", service.Delete)
r.Get("/jails/{name}", service.BanList)
r.Post("/unban", service.Unban)
r.Post("/whiteList", service.SetWhiteList)
r.Get("/whiteList", service.GetWhiteList)
},
})
}
-1
View File
@@ -3,7 +3,6 @@ package fail2ban
type Jail struct {
Name string `json:"name"`
Enabled bool `json:"enabled"`
LogPath string `json:"log_path"`
MaxRetry int `json:"max_retry"`
FindTime int `json:"find_time"`
BanTime int `json:"ban_time"`
@@ -4,19 +4,26 @@ import (
"fmt"
"net/http"
"github.com/TheTNB/panel/internal/app"
"github.com/TheTNB/panel/internal/service"
"github.com/TheTNB/panel/pkg/io"
"github.com/TheTNB/panel/pkg/systemctl"
"github.com/go-chi/chi/v5"
"github.com/tnb-labs/panel/internal/app"
"github.com/tnb-labs/panel/internal/service"
"github.com/tnb-labs/panel/pkg/io"
"github.com/tnb-labs/panel/pkg/systemctl"
)
type Service struct{}
type App struct{}
func NewService() *Service {
return &Service{}
func NewApp() *App {
return &App{}
}
func (s *Service) GetConfig(w http.ResponseWriter, r *http.Request) {
func (s *App) Route(r chi.Router) {
r.Get("/config", s.GetConfig)
r.Post("/config", s.UpdateConfig)
}
func (s *App) GetConfig(w http.ResponseWriter, r *http.Request) {
req, err := service.Bind[Name](r)
if err != nil {
service.Error(w, http.StatusUnprocessableEntity, "%v", err)
@@ -32,7 +39,7 @@ func (s *Service) GetConfig(w http.ResponseWriter, r *http.Request) {
service.Success(w, config)
}
func (s *Service) UpdateConfig(w http.ResponseWriter, r *http.Request) {
func (s *App) UpdateConfig(w http.ResponseWriter, r *http.Request) {
req, err := service.Bind[UpdateConfig](r)
if err != nil {
service.Error(w, http.StatusUnprocessableEntity, "%v", err)
-19
View File
@@ -1,19 +0,0 @@
package frp
import (
"github.com/go-chi/chi/v5"
"github.com/TheTNB/panel/pkg/apploader"
"github.com/TheTNB/panel/pkg/types"
)
func init() {
apploader.Register(&types.App{
Slug: "frp",
Route: func(r chi.Router) {
service := NewService()
r.Get("/config", service.GetConfig)
r.Post("/config", service.UpdateConfig)
},
})
}
@@ -4,24 +4,31 @@ import (
"fmt"
"net/http"
"github.com/TheTNB/panel/internal/app"
"github.com/TheTNB/panel/internal/service"
"github.com/TheTNB/panel/pkg/io"
"github.com/TheTNB/panel/pkg/systemctl"
"github.com/go-chi/chi/v5"
"github.com/tnb-labs/panel/internal/app"
"github.com/tnb-labs/panel/internal/service"
"github.com/tnb-labs/panel/pkg/io"
"github.com/tnb-labs/panel/pkg/systemctl"
)
type Service struct{}
type App struct{}
func NewService() *Service {
return &Service{}
func NewApp() *App {
return &App{}
}
func (s *Service) GetConfig(w http.ResponseWriter, r *http.Request) {
func (s *App) Route(r chi.Router) {
r.Get("/config", s.GetConfig)
r.Post("/config", s.UpdateConfig)
}
func (s *App) GetConfig(w http.ResponseWriter, r *http.Request) {
config, _ := io.Read(fmt.Sprintf("%s/server/gitea/app.ini", app.Root))
service.Success(w, config)
}
func (s *Service) UpdateConfig(w http.ResponseWriter, r *http.Request) {
func (s *App) UpdateConfig(w http.ResponseWriter, r *http.Request) {
req, err := service.Bind[UpdateConfig](r)
if err != nil {
service.Error(w, http.StatusUnprocessableEntity, "%v", err)
-19
View File
@@ -1,19 +0,0 @@
package gitea
import (
"github.com/go-chi/chi/v5"
"github.com/TheTNB/panel/pkg/apploader"
"github.com/TheTNB/panel/pkg/types"
)
func init() {
apploader.Register(&types.App{
Slug: "gitea",
Route: func(r chi.Router) {
service := NewService()
r.Get("/config", service.GetConfig)
r.Post("/config", service.UpdateConfig)
},
})
}
-28
View File
@@ -1,28 +0,0 @@
package apps
import (
"github.com/go-chi/chi/v5"
_ "github.com/TheTNB/panel/internal/apps/benchmark"
_ "github.com/TheTNB/panel/internal/apps/docker"
_ "github.com/TheTNB/panel/internal/apps/fail2ban"
_ "github.com/TheTNB/panel/internal/apps/frp"
_ "github.com/TheTNB/panel/internal/apps/gitea"
_ "github.com/TheTNB/panel/internal/apps/mysql"
_ "github.com/TheTNB/panel/internal/apps/nginx"
_ "github.com/TheTNB/panel/internal/apps/php"
_ "github.com/TheTNB/panel/internal/apps/phpmyadmin"
_ "github.com/TheTNB/panel/internal/apps/podman"
_ "github.com/TheTNB/panel/internal/apps/postgresql"
_ "github.com/TheTNB/panel/internal/apps/pureftpd"
_ "github.com/TheTNB/panel/internal/apps/redis"
_ "github.com/TheTNB/panel/internal/apps/rsync"
_ "github.com/TheTNB/panel/internal/apps/s3fs"
_ "github.com/TheTNB/panel/internal/apps/supervisor"
_ "github.com/TheTNB/panel/internal/apps/toolbox"
"github.com/TheTNB/panel/pkg/apploader"
)
func Boot(r chi.Router) {
apploader.Boot(r)
}
+105
View File
@@ -0,0 +1,105 @@
package memcached
import (
"bufio"
"net"
"net/http"
"regexp"
"github.com/go-chi/chi/v5"
"github.com/tnb-labs/panel/internal/service"
"github.com/tnb-labs/panel/pkg/io"
"github.com/tnb-labs/panel/pkg/systemctl"
"github.com/tnb-labs/panel/pkg/types"
)
type App struct{}
func NewApp() *App {
return &App{}
}
func (s *App) Route(r chi.Router) {
r.Get("/load", s.Load)
r.Get("/config", s.GetConfig)
r.Post("/config", s.UpdateConfig)
}
func (s *App) Load(w http.ResponseWriter, r *http.Request) {
status, err := systemctl.Status("memcached")
if err != nil {
service.Error(w, http.StatusInternalServerError, "failed to get Memcached status: %v", err)
return
}
if !status {
service.Success(w, []types.NV{})
return
}
conn, err := net.Dial("tcp", "127.0.0.1:11211")
if err != nil {
service.Success(w, []types.NV{})
return
}
defer conn.Close()
_, err = conn.Write([]byte("stats\nquit\n"))
if err != nil {
service.Error(w, http.StatusInternalServerError, "failed to write to Memcached: %v", err)
return
}
data := make([]types.NV, 0)
re := regexp.MustCompile(`STAT\s(\S+)\s(\S+)`)
scanner := bufio.NewScanner(conn)
for scanner.Scan() {
line := scanner.Text()
if matches := re.FindStringSubmatch(line); len(matches) == 3 {
data = append(data, types.NV{
Name: matches[1],
Value: matches[2],
})
}
if line == "END" {
break
}
}
if err = scanner.Err(); err != nil {
service.Error(w, http.StatusInternalServerError, "failed to read from Memcached: %v", err)
return
}
service.Success(w, data)
}
func (s *App) GetConfig(w http.ResponseWriter, r *http.Request) {
config, err := io.Read("/etc/systemd/system/memcached.service")
if err != nil {
service.Error(w, http.StatusInternalServerError, "%v", err)
return
}
service.Success(w, config)
}
func (s *App) UpdateConfig(w http.ResponseWriter, r *http.Request) {
req, err := service.Bind[UpdateConfig](r)
if err != nil {
service.Error(w, http.StatusUnprocessableEntity, "%v", err)
return
}
if err = io.Write("/etc/systemd/system/memcached.service", req.Config, 0644); err != nil {
service.Error(w, http.StatusInternalServerError, "%v", err)
return
}
if err = systemctl.Restart("memcached"); err != nil {
service.Error(w, http.StatusInternalServerError, "%v", err)
return
}
service.Success(w, nil)
}
+5
View File
@@ -0,0 +1,5 @@
package memcached
type UpdateConfig struct {
Config string `form:"config" json:"config" validate:"required"`
}
@@ -6,32 +6,43 @@ import (
"os"
"regexp"
"github.com/go-chi/chi/v5"
"github.com/spf13/cast"
"github.com/TheTNB/panel/internal/app"
"github.com/TheTNB/panel/internal/biz"
"github.com/TheTNB/panel/internal/data"
"github.com/TheTNB/panel/internal/service"
"github.com/TheTNB/panel/pkg/db"
"github.com/TheTNB/panel/pkg/io"
"github.com/TheTNB/panel/pkg/shell"
"github.com/TheTNB/panel/pkg/str"
"github.com/TheTNB/panel/pkg/systemctl"
"github.com/TheTNB/panel/pkg/types"
"github.com/tnb-labs/panel/internal/app"
"github.com/tnb-labs/panel/internal/biz"
"github.com/tnb-labs/panel/internal/service"
"github.com/tnb-labs/panel/pkg/db"
"github.com/tnb-labs/panel/pkg/io"
"github.com/tnb-labs/panel/pkg/shell"
"github.com/tnb-labs/panel/pkg/systemctl"
"github.com/tnb-labs/panel/pkg/tools"
"github.com/tnb-labs/panel/pkg/types"
)
type Service struct {
type App struct {
settingRepo biz.SettingRepo
}
func NewService() *Service {
return &Service{
settingRepo: data.NewSettingRepo(),
func NewApp(setting biz.SettingRepo) *App {
return &App{
settingRepo: setting,
}
}
func (s *App) Route(r chi.Router) {
r.Get("/load", s.Load)
r.Get("/config", s.GetConfig)
r.Post("/config", s.UpdateConfig)
r.Post("/clearErrorLog", s.ClearErrorLog)
r.Get("/slowLog", s.SlowLog)
r.Post("/clearSlowLog", s.ClearSlowLog)
r.Get("/rootPassword", s.GetRootPassword)
r.Post("/rootPassword", s.SetRootPassword)
}
// GetConfig 获取配置
func (s *Service) GetConfig(w http.ResponseWriter, r *http.Request) {
func (s *App) GetConfig(w http.ResponseWriter, r *http.Request) {
config, err := io.Read(app.Root + "/server/mysql/conf/my.cnf")
if err != nil {
service.Error(w, http.StatusInternalServerError, "获取配置失败")
@@ -42,7 +53,7 @@ func (s *Service) GetConfig(w http.ResponseWriter, r *http.Request) {
}
// UpdateConfig 保存配置
func (s *Service) UpdateConfig(w http.ResponseWriter, r *http.Request) {
func (s *App) UpdateConfig(w http.ResponseWriter, r *http.Request) {
req, err := service.Bind[UpdateConfig](r)
if err != nil {
service.Error(w, http.StatusUnprocessableEntity, "%v", err)
@@ -63,7 +74,7 @@ func (s *Service) UpdateConfig(w http.ResponseWriter, r *http.Request) {
}
// Load 获取负载
func (s *Service) Load(w http.ResponseWriter, r *http.Request) {
func (s *App) Load(w http.ResponseWriter, r *http.Request) {
rootPassword, err := s.settingRepo.Get(biz.SettingKeyMySQLRootPassword)
if err != nil {
service.Error(w, http.StatusInternalServerError, "获取root密码失败")
@@ -123,7 +134,7 @@ func (s *Service) Load(w http.ResponseWriter, r *http.Request) {
if len(matches) > 1 {
d := map[string]string{"name": expression.name, "value": matches[1]}
if expression.name == "发送" || expression.name == "接收" {
d["value"] = str.FormatBytes(cast.ToFloat64(matches[1]))
d["value"] = tools.FormatBytes(cast.ToFloat64(matches[1]))
}
load = append(load, d)
@@ -142,14 +153,9 @@ func (s *Service) Load(w http.ResponseWriter, r *http.Request) {
service.Success(w, load)
}
// ErrorLog 获取错误日志
func (s *Service) ErrorLog(w http.ResponseWriter, r *http.Request) {
service.Success(w, fmt.Sprintf("%s/server/mysql/mysql-error.log", app.Root))
}
// ClearErrorLog 清空错误日志
func (s *Service) ClearErrorLog(w http.ResponseWriter, r *http.Request) {
if _, err := shell.Execf("echo '' > %s/server/mysql/mysql-error.log", app.Root); err != nil {
func (s *App) ClearErrorLog(w http.ResponseWriter, r *http.Request) {
if err := systemctl.LogsClear("mysqld"); err != nil {
service.Error(w, http.StatusInternalServerError, "%v", err)
return
}
@@ -158,12 +164,12 @@ func (s *Service) ClearErrorLog(w http.ResponseWriter, r *http.Request) {
}
// SlowLog 获取慢查询日志
func (s *Service) SlowLog(w http.ResponseWriter, r *http.Request) {
func (s *App) SlowLog(w http.ResponseWriter, r *http.Request) {
service.Success(w, fmt.Sprintf("%s/server/mysql/mysql-slow.log", app.Root))
}
// ClearSlowLog 清空慢查询日志
func (s *Service) ClearSlowLog(w http.ResponseWriter, r *http.Request) {
func (s *App) ClearSlowLog(w http.ResponseWriter, r *http.Request) {
if _, err := shell.Execf("echo '' > %s/server/mysql/mysql-slow.log", app.Root); err != nil {
service.Error(w, http.StatusInternalServerError, "%v", err)
return
@@ -173,7 +179,7 @@ func (s *Service) ClearSlowLog(w http.ResponseWriter, r *http.Request) {
}
// GetRootPassword 获取root密码
func (s *Service) GetRootPassword(w http.ResponseWriter, r *http.Request) {
func (s *App) GetRootPassword(w http.ResponseWriter, r *http.Request) {
rootPassword, err := s.settingRepo.Get(biz.SettingKeyMySQLRootPassword)
if err != nil {
service.Error(w, http.StatusInternalServerError, "获取root密码失败")
@@ -188,7 +194,7 @@ func (s *Service) GetRootPassword(w http.ResponseWriter, r *http.Request) {
}
// SetRootPassword 设置root密码
func (s *Service) SetRootPassword(w http.ResponseWriter, r *http.Request) {
func (s *App) SetRootPassword(w http.ResponseWriter, r *http.Request) {
req, err := service.Bind[SetRootPassword](r)
if err != nil {
service.Error(w, http.StatusUnprocessableEntity, "%v", err)
@@ -204,7 +210,8 @@ func (s *Service) SetRootPassword(w http.ResponseWriter, r *http.Request) {
return
}
} else {
if err = mysql.UserPassword("root", req.Password); err != nil {
defer mysql.Close()
if err = mysql.UserPassword("root", req.Password, "localhost"); err != nil {
service.Error(w, http.StatusInternalServerError, "%v", err)
return
}
@@ -217,7 +224,7 @@ func (s *Service) SetRootPassword(w http.ResponseWriter, r *http.Request) {
service.Success(w, nil)
}
func (s *Service) getSock() string {
func (s *App) getSock() string {
if io.Exists("/tmp/mysql.sock") {
return "/tmp/mysql.sock"
}
-26
View File
@@ -1,26 +0,0 @@
package mysql
import (
"github.com/go-chi/chi/v5"
"github.com/TheTNB/panel/pkg/apploader"
"github.com/TheTNB/panel/pkg/types"
)
func init() {
apploader.Register(&types.App{
Slug: "mysql",
Route: func(r chi.Router) {
service := NewService()
r.Get("/load", service.Load)
r.Get("/config", service.GetConfig)
r.Post("/config", service.UpdateConfig)
r.Get("/errorLog", service.ErrorLog)
r.Post("/clearErrorLog", service.ClearErrorLog)
r.Get("/slowLog", service.SlowLog)
r.Post("/clearSlowLog", service.ClearSlowLog)
r.Get("/rootPassword", service.GetRootPassword)
r.Post("/rootPassword", service.SetRootPassword)
},
})
}
+1 -1
View File
@@ -5,5 +5,5 @@ type UpdateConfig struct {
}
type SetRootPassword struct {
Password string `form:"password" json:"password" validate:"required,password"`
Password string `form:"password" json:"password" validate:"required|password"`
}
@@ -6,27 +6,36 @@ import (
"regexp"
"time"
"github.com/go-chi/chi/v5"
"github.com/go-resty/resty/v2"
"github.com/spf13/cast"
"github.com/TheTNB/panel/internal/app"
"github.com/TheTNB/panel/internal/service"
"github.com/TheTNB/panel/pkg/io"
"github.com/TheTNB/panel/pkg/shell"
"github.com/TheTNB/panel/pkg/str"
"github.com/TheTNB/panel/pkg/systemctl"
"github.com/TheTNB/panel/pkg/types"
"github.com/tnb-labs/panel/internal/app"
"github.com/tnb-labs/panel/internal/service"
"github.com/tnb-labs/panel/pkg/io"
"github.com/tnb-labs/panel/pkg/shell"
"github.com/tnb-labs/panel/pkg/systemctl"
"github.com/tnb-labs/panel/pkg/tools"
"github.com/tnb-labs/panel/pkg/types"
)
type Service struct {
type App struct {
// Dependent services
}
func NewService() *Service {
return &Service{}
func NewApp() *App {
return &App{}
}
func (s *Service) GetConfig(w http.ResponseWriter, r *http.Request) {
func (s *App) Route(r chi.Router) {
r.Get("/load", s.Load)
r.Get("/config", s.GetConfig)
r.Post("/config", s.SaveConfig)
r.Get("/errorLog", s.ErrorLog)
r.Post("/clearErrorLog", s.ClearErrorLog)
}
func (s *App) GetConfig(w http.ResponseWriter, r *http.Request) {
config, err := io.Read(fmt.Sprintf("%s/server/nginx/conf/nginx.conf", app.Root))
if err != nil {
service.Error(w, http.StatusInternalServerError, "获取配置失败")
@@ -36,7 +45,7 @@ func (s *Service) GetConfig(w http.ResponseWriter, r *http.Request) {
service.Success(w, config)
}
func (s *Service) SaveConfig(w http.ResponseWriter, r *http.Request) {
func (s *App) SaveConfig(w http.ResponseWriter, r *http.Request) {
req, err := service.Bind[UpdateConfig](r)
if err != nil {
service.Error(w, http.StatusUnprocessableEntity, "%v", err)
@@ -57,11 +66,11 @@ func (s *Service) SaveConfig(w http.ResponseWriter, r *http.Request) {
service.Success(w, nil)
}
func (s *Service) ErrorLog(w http.ResponseWriter, r *http.Request) {
func (s *App) ErrorLog(w http.ResponseWriter, r *http.Request) {
service.Success(w, fmt.Sprintf("%s/%s", app.Root, "wwwlogs/nginx-error.log"))
}
func (s *Service) ClearErrorLog(w http.ResponseWriter, r *http.Request) {
func (s *App) ClearErrorLog(w http.ResponseWriter, r *http.Request) {
if _, err := shell.Execf("echo '' > %s/%s", app.Root, "wwwlogs/nginx-error.log"); err != nil {
service.Error(w, http.StatusInternalServerError, "%v", err)
return
@@ -70,7 +79,7 @@ func (s *Service) ClearErrorLog(w http.ResponseWriter, r *http.Request) {
service.Success(w, nil)
}
func (s *Service) Load(w http.ResponseWriter, r *http.Request) {
func (s *App) Load(w http.ResponseWriter, r *http.Request) {
client := resty.New().SetTimeout(10 * time.Second)
resp, err := client.R().Get("http://127.0.0.1/nginx_status")
if err != nil || !resp.IsSuccess() {
@@ -95,7 +104,7 @@ func (s *Service) Load(w http.ResponseWriter, r *http.Request) {
service.Error(w, http.StatusInternalServerError, "获取负载失败")
return
}
mem := str.FormatBytes(cast.ToFloat64(out))
mem := tools.FormatBytes(cast.ToFloat64(out))
data = append(data, types.NV{
Name: "内存占用",
Value: mem,
-22
View File
@@ -1,22 +0,0 @@
package nginx
import (
"github.com/go-chi/chi/v5"
"github.com/TheTNB/panel/pkg/apploader"
"github.com/TheTNB/panel/pkg/types"
)
func init() {
apploader.Register(&types.App{
Slug: "nginx",
Route: func(r chi.Router) {
service := NewService()
r.Get("/load", service.Load)
r.Get("/config", service.GetConfig)
r.Post("/config", service.SaveConfig)
r.Get("/errorLog", service.ErrorLog)
r.Post("/clearErrorLog", service.ClearErrorLog)
},
})
}
@@ -4,36 +4,64 @@ import (
"fmt"
"net/http"
"net/url"
"regexp"
"slices"
"strings"
"time"
"github.com/go-chi/chi/v5"
"github.com/go-resty/resty/v2"
"github.com/spf13/cast"
"github.com/TheTNB/panel/internal/app"
"github.com/TheTNB/panel/internal/biz"
"github.com/TheTNB/panel/internal/data"
"github.com/TheTNB/panel/internal/service"
"github.com/TheTNB/panel/pkg/io"
"github.com/TheTNB/panel/pkg/shell"
"github.com/TheTNB/panel/pkg/types"
"github.com/tnb-labs/panel/internal/app"
"github.com/tnb-labs/panel/internal/biz"
"github.com/tnb-labs/panel/internal/service"
"github.com/tnb-labs/panel/pkg/io"
"github.com/tnb-labs/panel/pkg/shell"
"github.com/tnb-labs/panel/pkg/types"
)
type Service struct {
type App struct {
version uint
taskRepo biz.TaskRepo
}
func NewService(version uint) *Service {
return &Service{
version: version,
taskRepo: data.NewTaskRepo(),
func NewApp(task biz.TaskRepo) *App {
return &App{
taskRepo: task,
}
}
func (s *Service) GetConfig(w http.ResponseWriter, r *http.Request) {
func (s *App) Route(version uint) func(r chi.Router) {
return func(r chi.Router) {
php := new(App)
php.version = version
php.taskRepo = s.taskRepo
r.Post("/setCli", php.SetCli)
r.Get("/config", php.GetConfig)
r.Post("/config", php.UpdateConfig)
r.Get("/fpmConfig", php.GetFPMConfig)
r.Post("/fpmConfig", php.UpdateFPMConfig)
r.Get("/load", php.Load)
r.Get("/errorLog", php.ErrorLog)
r.Get("/slowLog", php.SlowLog)
r.Post("/clearErrorLog", php.ClearErrorLog)
r.Post("/clearSlowLog", php.ClearSlowLog)
r.Get("/extensions", php.ExtensionList)
r.Post("/extensions", php.InstallExtension)
r.Delete("/extensions", php.UninstallExtension)
}
}
func (s *App) SetCli(w http.ResponseWriter, r *http.Request) {
if _, err := shell.Execf("ln -sf %s/server/php/%d/bin/php /usr/bin/php", app.Root, s.version); err != nil {
service.Error(w, http.StatusInternalServerError, "%v", err)
return
}
service.Success(w, nil)
}
func (s *App) GetConfig(w http.ResponseWriter, r *http.Request) {
config, err := io.Read(fmt.Sprintf("%s/server/php/%d/etc/php.ini", app.Root, s.version))
if err != nil {
service.Error(w, http.StatusInternalServerError, "%v", err)
@@ -43,7 +71,7 @@ func (s *Service) GetConfig(w http.ResponseWriter, r *http.Request) {
service.Success(w, config)
}
func (s *Service) UpdateConfig(w http.ResponseWriter, r *http.Request) {
func (s *App) UpdateConfig(w http.ResponseWriter, r *http.Request) {
req, err := service.Bind[UpdateConfig](r)
if err != nil {
service.Error(w, http.StatusUnprocessableEntity, "%v", err)
@@ -58,7 +86,7 @@ func (s *Service) UpdateConfig(w http.ResponseWriter, r *http.Request) {
service.Success(w, nil)
}
func (s *Service) GetFPMConfig(w http.ResponseWriter, r *http.Request) {
func (s *App) GetFPMConfig(w http.ResponseWriter, r *http.Request) {
config, err := io.Read(fmt.Sprintf("%s/server/php/%d/etc/php-fpm.conf", app.Root, s.version))
if err != nil {
service.Error(w, http.StatusInternalServerError, "%v", err)
@@ -68,7 +96,7 @@ func (s *Service) GetFPMConfig(w http.ResponseWriter, r *http.Request) {
service.Success(w, config)
}
func (s *Service) UpdateFPMConfig(w http.ResponseWriter, r *http.Request) {
func (s *App) UpdateFPMConfig(w http.ResponseWriter, r *http.Request) {
req, err := service.Bind[UpdateConfig](r)
if err != nil {
service.Error(w, http.StatusUnprocessableEntity, "%v", err)
@@ -83,42 +111,41 @@ func (s *Service) UpdateFPMConfig(w http.ResponseWriter, r *http.Request) {
service.Success(w, nil)
}
func (s *Service) Load(w http.ResponseWriter, r *http.Request) {
func (s *App) Load(w http.ResponseWriter, r *http.Request) {
var raw map[string]any
client := resty.New().SetTimeout(10 * time.Second)
resp, err := client.R().Get(fmt.Sprintf("http://127.0.0.1/phpfpm_status/%d", s.version))
if err != nil || !resp.IsSuccess() {
_, err := client.R().SetResult(&raw).Get(fmt.Sprintf("http://127.0.0.1/phpfpm_status/%d?json", s.version))
if err != nil {
service.Success(w, []types.NV{})
return
}
raw := resp.String()
dataKeys := []string{"应用池", "工作模式", "启动时间", "接受连接", "监听队列", "最大监听队列", "监听队列长度", "空闲进程数量", "活动进程数量", "总进程数量", "最大活跃进程数量", "达到进程上限次数", "慢请求"}
regexKeys := []string{"pool", "process manager", "start time", "accepted conn", "listen queue", "max listen queue", "listen queue len", "idle processes", "active processes", "total processes", "max active processes", "max children reached", "slow requests"}
rawKeys := []string{"pool", "process manager", "start time", "accepted conn", "listen queue", "max listen queue", "listen queue len", "idle processes", "active processes", "total processes", "max active processes", "max children reached", "slow requests"}
loads := make([]types.NV, len(dataKeys))
loads := make([]types.NV, 0)
for i := range dataKeys {
loads[i].Name = dataKeys[i]
r := regexp.MustCompile(fmt.Sprintf("%s:\\s+(.*)", regexKeys[i]))
match := r.FindStringSubmatch(raw)
if len(match) > 1 {
loads[i].Value = strings.TrimSpace(match[1])
v, ok := raw[rawKeys[i]]
if ok {
loads = append(loads, types.NV{
Name: dataKeys[i],
Value: cast.ToString(v),
})
}
}
service.Success(w, loads)
}
func (s *Service) ErrorLog(w http.ResponseWriter, r *http.Request) {
func (s *App) ErrorLog(w http.ResponseWriter, r *http.Request) {
service.Success(w, fmt.Sprintf("%s/server/php/%d/var/log/php-fpm.log", app.Root, s.version))
}
func (s *Service) SlowLog(w http.ResponseWriter, r *http.Request) {
func (s *App) SlowLog(w http.ResponseWriter, r *http.Request) {
service.Success(w, fmt.Sprintf("%s/server/php/%d/var/log/slow.log", app.Root, s.version))
}
func (s *Service) ClearErrorLog(w http.ResponseWriter, r *http.Request) {
func (s *App) ClearErrorLog(w http.ResponseWriter, r *http.Request) {
if _, err := shell.Execf("echo '' > %s/server/php/%d/var/log/php-fpm.log", app.Root, s.version); err != nil {
service.Error(w, http.StatusInternalServerError, "%v", err)
return
@@ -127,7 +154,7 @@ func (s *Service) ClearErrorLog(w http.ResponseWriter, r *http.Request) {
service.Success(w, nil)
}
func (s *Service) ClearSlowLog(w http.ResponseWriter, r *http.Request) {
func (s *App) ClearSlowLog(w http.ResponseWriter, r *http.Request) {
if _, err := shell.Execf("echo '' > %s/server/php/%d/var/log/slow.log", app.Root, s.version); err != nil {
service.Error(w, http.StatusInternalServerError, "%v", err)
return
@@ -136,19 +163,8 @@ func (s *Service) ClearSlowLog(w http.ResponseWriter, r *http.Request) {
service.Success(w, nil)
}
func (s *Service) ExtensionList(w http.ResponseWriter, r *http.Request) {
func (s *App) ExtensionList(w http.ResponseWriter, r *http.Request) {
extensions := s.getExtensions()
// ionCube 只支持 PHP 8.3 以下版本
if cast.ToUint(s.version) < 83 {
extensions = append(extensions, Extension{
Name: "ionCube",
Slug: "ionCube Loader",
Description: "ionCube 是一个专业级的 PHP 加密解密工具。",
Installed: false,
})
}
raw, err := shell.Execf("%s/server/php/%d/bin/php -m", app.Root, s.version)
if err != nil {
service.Error(w, http.StatusInternalServerError, "%v", err)
@@ -170,7 +186,7 @@ func (s *Service) ExtensionList(w http.ResponseWriter, r *http.Request) {
service.Success(w, extensions)
}
func (s *Service) InstallExtension(w http.ResponseWriter, r *http.Request) {
func (s *App) InstallExtension(w http.ResponseWriter, r *http.Request) {
req, err := service.Bind[ExtensionSlug](r)
if err != nil {
service.Error(w, http.StatusUnprocessableEntity, "%v", err)
@@ -182,10 +198,10 @@ func (s *Service) InstallExtension(w http.ResponseWriter, r *http.Request) {
return
}
cmd := fmt.Sprintf(`curl -fsLm 10 --retry 3 "https://dl.cdn.haozi.net/panel/php_exts/%s.sh" | bash -s -- "install" "%d" >> /tmp/%s.log 2>&1`, url.QueryEscape(req.Slug), s.version, req.Slug)
officials := []string{"fileinfo", "exif", "imap", "pdo_pgsql", "zip", "bz2", "readline", "snmp", "ldap", "enchant", "pspell", "calendar", "gmp", "sysvmsg", "sysvsem", "sysvshm", "xsl", "intl", "gettext"}
cmd := fmt.Sprintf(`curl -fsLm 10 --retry 3 'https://dl.cdn.haozi.net/panel/php_exts/%s.sh' | bash -s -- 'install' '%d' >> '/tmp/%s.log' 2>&1`, url.PathEscape(req.Slug), s.version, req.Slug)
officials := []string{"fileinfo", "exif", "imap", "pgsql", "pdo_pgsql", "zip", "bz2", "readline", "snmp", "ldap", "enchant", "pspell", "calendar", "gmp", "sysvmsg", "sysvsem", "sysvshm", "xsl", "intl", "gettext"}
if slices.Contains(officials, req.Slug) {
cmd = fmt.Sprintf(`curl -fsLm 10 --retry 3 "https://dl.cdn.haozi.net/panel/php_exts/official.sh" | bash -s -- "install" "%d" "%s" >> /tmp/%s.log 2>&1`, s.version, req.Slug, req.Slug)
cmd = fmt.Sprintf(`curl -fsLm 10 --retry 3 'https://dl.cdn.haozi.net/panel/php_exts/official.sh' | bash -s -- 'install' '%d' '%s' >> '/tmp/%s.log' 2>&1`, s.version, req.Slug, req.Slug)
}
task := new(biz.Task)
@@ -201,7 +217,7 @@ func (s *Service) InstallExtension(w http.ResponseWriter, r *http.Request) {
service.Success(w, nil)
}
func (s *Service) UninstallExtension(w http.ResponseWriter, r *http.Request) {
func (s *App) UninstallExtension(w http.ResponseWriter, r *http.Request) {
req, err := service.Bind[ExtensionSlug](r)
if err != nil {
service.Error(w, http.StatusUnprocessableEntity, "%v", err)
@@ -213,10 +229,10 @@ func (s *Service) UninstallExtension(w http.ResponseWriter, r *http.Request) {
return
}
cmd := fmt.Sprintf(`curl -fsLm 10 --retry 3 "https://dl.cdn.haozi.net/panel/php_exts/%s.sh" | bash -s -- "uninstall" "%d" >> /tmp/%s.log 2>&1`, url.QueryEscape(req.Slug), s.version, req.Slug)
officials := []string{"fileinfo", "exif", "imap", "pdo_pgsql", "zip", "bz2", "readline", "snmp", "ldap", "enchant", "pspell", "calendar", "gmp", "sysvmsg", "sysvsem", "sysvshm", "xsl", "intl", "gettext"}
cmd := fmt.Sprintf(`curl -fsLm 10 --retry 3 'https://dl.cdn.haozi.net/panel/php_exts/%s.sh' | bash -s -- 'uninstall' '%d' >> '/tmp/%s.log' 2>&1`, url.PathEscape(req.Slug), s.version, req.Slug)
officials := []string{"fileinfo", "exif", "imap", "pgsql", "pdo_pgsql", "zip", "bz2", "readline", "snmp", "ldap", "enchant", "pspell", "calendar", "gmp", "sysvmsg", "sysvsem", "sysvshm", "xsl", "intl", "gettext"}
if slices.Contains(officials, req.Slug) {
cmd = fmt.Sprintf(`curl -fsLm 10 --retry 3 "https://dl.cdn.haozi.net/panel/php_exts/official.sh" | bash -s -- "uninstall" "%d" "%s" >> /tmp/%s.log 2>&1`, s.version, req.Slug, req.Slug)
cmd = fmt.Sprintf(`curl -fsLm 10 --retry 3 'https://dl.cdn.haozi.net/panel/php_exts/official.sh' | bash -s -- 'uninstall' '%d' '%s' >> '/tmp/%s.log' 2>&1`, s.version, req.Slug, req.Slug)
}
task := new(biz.Task)
@@ -232,142 +248,160 @@ func (s *Service) UninstallExtension(w http.ResponseWriter, r *http.Request) {
service.Success(w, nil)
}
func (s *Service) getExtensions() []Extension {
func (s *App) getExtensions() []Extension {
extensions := []Extension{
{
Name: "fileinfo",
Slug: "fileinfo",
Description: "Fileinfo 是一个用于识别文件类型的库",
Description: "Fileinfo 是一个用于识别文件类型的库",
},
{
Name: "OPcache",
Slug: "Zend OPcache",
Description: "OPcache 通过将 PHP 脚本预编译的字节码存储到共享内存中来提升 PHP 的性能,存储预编译字节码可以省去每次加载和解析 PHP 脚本的开销",
Description: "OPcache 通过将 PHP 脚本预编译的字节码存储到共享内存中来提升 PHP 的性能,存储预编译字节码可以省去每次加载和解析 PHP 脚本的开销",
},
{
Name: "PhpRedis",
Name: "Redis",
Slug: "redis",
Description: "PhpRedis 是一个用 C 语言编写的 PHP 模块,用来连接并操作 Redis 数据库上的数据",
Description: "PhpRedis 是一个用 C 语言编写的 PHP 模块,用来连接并操作 Redis 数据库上的数据(需先安装 igbinary 拓展)",
},
{
Name: "Memcached",
Slug: "memcached",
Description: "Memcached 使用 libmemcached 库连接 Memcached 服务器",
},
{
Name: "ImageMagick",
Slug: "imagick",
Description: "ImageMagick 是一个免费的创建、编辑、合成图片的软件",
Description: "ImageMagick 是一个免费的创建、编辑、合成图片的软件",
},
{
Name: "exif",
Slug: "exif",
Description: "通过 exif 扩展,您可以操作图像元数据",
Description: "通过 exif 扩展,您可以操作图像元数据",
},
{
Name: "pgsql",
Slug: "pgsql",
Description: "pgsql 是一个驱动程序,它启用从 PHP 到 PostgreSQL 数据库的访问(需先安装 PostgreSQL 应用)",
},
{
Name: "pdo_pgsql",
Slug: "pdo_pgsql",
Description: "(需先安装PostgreSQLpdo_pgsql 是一个驱动程序,它实现了 PHP 数据对象(PDO)接口以启用从 PHP 到 PostgreSQL 数据库的访问",
Description: "pdo_pgsql 是一个驱动程序,它实现了 PHP 数据对象(PDO)接口以启用从 PHP 到 PostgreSQL 数据库的访问(需先安装 PostgreSQL 应用)",
},
{
Name: "imap",
Slug: "imap",
Description: "IMAP 扩展允许 PHP 读取、搜索、删除、下载和管理邮件",
Description: "IMAP 扩展允许 PHP 读取、搜索、删除、下载和管理邮件",
},
{
Name: "zip",
Slug: "zip",
Description: "Zip 是一个用于处理 ZIP 文件的库",
Description: "Zip 是一个用于处理 ZIP 文件的库",
},
{
Name: "bz2",
Slug: "bz2",
Description: "Bzip2 是一个用于压缩和解压缩文件的库",
Description: "Bzip2 是一个用于压缩和解压缩文件的库",
},
{
Name: "readline",
Slug: "readline",
Description: "Readline 是一个库,它提供了一种用于处理文本的接口",
Description: "Readline 是一个库,它提供了一种用于处理文本的接口",
},
{
Name: "snmp",
Slug: "snmp",
Description: "SNMP 是一种用于网络管理的协议",
Description: "SNMP 是一种用于网络管理的协议",
},
{
Name: "ldap",
Slug: "ldap",
Description: "LDAP 是一种用于访问目录服务的协议",
Description: "LDAP 是一种用于访问目录服务的协议",
},
{
Name: "enchant",
Slug: "enchant",
Description: "Enchant 是一个拼写检查库",
Description: "Enchant 是一个拼写检查库",
},
{
Name: "pspell",
Slug: "pspell",
Description: "Pspell 是一个拼写检查库",
Description: "Pspell 是一个拼写检查库",
},
{
Name: "calendar",
Slug: "calendar",
Description: "Calendar 是一个用于处理日期的库",
Description: "Calendar 是一个用于处理日期的库",
},
{
Name: "gmp",
Slug: "gmp",
Description: "GMP 是一个用于处理大整数的库",
Description: "GMP 是一个用于处理大整数的库",
},
{
Name: "sysvmsg",
Slug: "sysvmsg",
Description: "Sysvmsg 是一个用于处理 System V 消息队列的库",
Description: "Sysvmsg 是一个用于处理 System V 消息队列的库",
},
{
Name: "sysvsem",
Slug: "sysvsem",
Description: "Sysvsem 是一个用于处理 System V 信号量的库",
Description: "Sysvsem 是一个用于处理 System V 信号量的库",
},
{
Name: "sysvshm",
Slug: "sysvshm",
Description: "Sysvshm 是一个用于处理 System V 共享内存的库",
Description: "Sysvshm 是一个用于处理 System V 共享内存的库",
},
{
Name: "xsl",
Slug: "xsl",
Description: "XSL 是一个用于处理 XML 文档的库",
Description: "XSL 是一个用于处理 XML 文档的库",
},
{
Name: "intl",
Slug: "intl",
Description: "Intl 是一个用于处理国际化和本地化的库",
Description: "Intl 是一个用于处理国际化和本地化的库",
},
{
Name: "gettext",
Slug: "gettext",
Description: "Gettext 是一个用于处理多语言的库",
Description: "Gettext 是一个用于处理多语言的库",
},
{
Name: "igbinary",
Slug: "igbinary",
Description: "Igbinary 是一个用于序列化和反序列化数据的库",
},
{
Name: "Swoole",
Slug: "swoole",
Description: "Swoole 是一个用于构建高性能的异步并发服务器的 PHP 扩展。",
},
{
Name: "Swow",
Slug: "Swow",
Description: "Swow 是一个用于构建高性能的异步并发服务器的 PHP 扩展。",
Description: "Igbinary 是一个用于序列化和反序列化数据的库",
},
}
// ionCube 支持 PHP 8.3 以下版本
if cast.ToUint(s.version) < 83 {
// ionCube Swoole 不支持 PHP 8.4
if cast.ToUint(s.version) < 84 {
extensions = append(extensions, Extension{
Name: "ionCube",
Slug: "ionCube Loader",
Description: "ionCube 是一个专业级的 PHP 加密解密工具",
Installed: false,
Description: "ionCube 是一个专业级的 PHP 加密解密工具(需在 OPcache 之后安装)",
})
extensions = append(extensions, Extension{
Name: "Swoole",
Slug: "swoole",
Description: "Swoole 是一个用于构建高性能的异步并发服务器的 PHP 扩展",
})
}
// Swow 不支持 PHP 8.0 以下版本且目前不支持 PHP 8.4
if cast.ToUint(s.version) >= 80 && cast.ToUint(s.version) < 84 {
extensions = append(extensions, Extension{
Name: "Swow",
Slug: "Swow",
Description: "Swow 是一个用于构建高性能的异步并发服务器的 PHP 扩展",
})
}
// PHP 8.4 移除了 pspell 和 imap 并且不再建议使用
if cast.ToUint(s.version) >= 84 {
extensions = slices.DeleteFunc(extensions, func(extension Extension) bool {
return extension.Slug == "pspell" || extension.Slug == "imap"
})
}
@@ -387,7 +421,7 @@ func (s *Service) getExtensions() []Extension {
return extensions
}
func (s *Service) checkExtension(slug string) bool {
func (s *App) checkExtension(slug string) bool {
extensions := s.getExtensions()
for _, item := range extensions {
-83
View File
@@ -1,83 +0,0 @@
package php
import (
"github.com/go-chi/chi/v5"
"github.com/TheTNB/panel/pkg/apploader"
"github.com/TheTNB/panel/pkg/types"
)
func init() {
apploader.Register(&types.App{
Slug: "php80",
Route: func(r chi.Router) {
service := NewService(80)
r.Get("/load", service.Load)
r.Get("/config", service.GetConfig)
r.Post("/config", service.UpdateConfig)
r.Get("/fpmConfig", service.GetFPMConfig)
r.Post("/fpmConfig", service.UpdateFPMConfig)
r.Get("/errorLog", service.ErrorLog)
r.Get("/slowLog", service.SlowLog)
r.Post("/clearErrorLog", service.ClearErrorLog)
r.Post("/clearSlowLog", service.ClearSlowLog)
r.Get("/extensions", service.ExtensionList)
r.Post("/extensions", service.InstallExtension)
r.Delete("/extensions", service.UninstallExtension)
},
})
apploader.Register(&types.App{
Slug: "php81",
Route: func(r chi.Router) {
service := NewService(81)
r.Get("/load", service.Load)
r.Get("/config", service.GetConfig)
r.Post("/config", service.UpdateConfig)
r.Get("/fpmConfig", service.GetFPMConfig)
r.Post("/fpmConfig", service.UpdateFPMConfig)
r.Get("/errorLog", service.ErrorLog)
r.Get("/slowLog", service.SlowLog)
r.Post("/clearErrorLog", service.ClearErrorLog)
r.Post("/clearSlowLog", service.ClearSlowLog)
r.Get("/extensions", service.ExtensionList)
r.Post("/extensions", service.InstallExtension)
r.Delete("/extensions", service.UninstallExtension)
},
})
apploader.Register(&types.App{
Slug: "php82",
Route: func(r chi.Router) {
service := NewService(82)
r.Get("/load", service.Load)
r.Get("/config", service.GetConfig)
r.Post("/config", service.UpdateConfig)
r.Get("/fpmConfig", service.GetFPMConfig)
r.Post("/fpmConfig", service.UpdateFPMConfig)
r.Get("/errorLog", service.ErrorLog)
r.Get("/slowLog", service.SlowLog)
r.Post("/clearErrorLog", service.ClearErrorLog)
r.Post("/clearSlowLog", service.ClearSlowLog)
r.Get("/extensions", service.ExtensionList)
r.Post("/extensions", service.InstallExtension)
r.Delete("/extensions", service.UninstallExtension)
},
})
apploader.Register(&types.App{
Slug: "php83",
Route: func(r chi.Router) {
service := NewService(83)
r.Get("/load", service.Load)
r.Get("/config", service.GetConfig)
r.Post("/config", service.UpdateConfig)
r.Get("/fpmConfig", service.GetFPMConfig)
r.Post("/fpmConfig", service.UpdateFPMConfig)
r.Get("/errorLog", service.ErrorLog)
r.Get("/slowLog", service.SlowLog)
r.Post("/clearErrorLog", service.ClearErrorLog)
r.Post("/clearSlowLog", service.ClearSlowLog)
r.Get("/extensions", service.ExtensionList)
r.Post("/extensions", service.InstallExtension)
r.Delete("/extensions", service.UninstallExtension)
},
})
}
+22
View File
@@ -0,0 +1,22 @@
package php74
import (
"github.com/go-chi/chi/v5"
"github.com/tnb-labs/panel/internal/apps/php"
"github.com/tnb-labs/panel/internal/biz"
)
type App struct {
php *php.App
}
func NewApp(task biz.TaskRepo) *App {
return &App{
php: php.NewApp(task),
}
}
func (s *App) Route(r chi.Router) {
s.php.Route(74)(r)
}
+22
View File
@@ -0,0 +1,22 @@
package php80
import (
"github.com/go-chi/chi/v5"
"github.com/tnb-labs/panel/internal/apps/php"
"github.com/tnb-labs/panel/internal/biz"
)
type App struct {
php *php.App
}
func NewApp(task biz.TaskRepo) *App {
return &App{
php: php.NewApp(task),
}
}
func (s *App) Route(r chi.Router) {
s.php.Route(80)(r)
}
+22
View File
@@ -0,0 +1,22 @@
package php81
import (
"github.com/go-chi/chi/v5"
"github.com/tnb-labs/panel/internal/apps/php"
"github.com/tnb-labs/panel/internal/biz"
)
type App struct {
php *php.App
}
func NewApp(task biz.TaskRepo) *App {
return &App{
php: php.NewApp(task),
}
}
func (s *App) Route(r chi.Router) {
s.php.Route(81)(r)
}
+22
View File
@@ -0,0 +1,22 @@
package php82
import (
"github.com/go-chi/chi/v5"
"github.com/tnb-labs/panel/internal/apps/php"
"github.com/tnb-labs/panel/internal/biz"
)
type App struct {
php *php.App
}
func NewApp(task biz.TaskRepo) *App {
return &App{
php: php.NewApp(task),
}
}
func (s *App) Route(r chi.Router) {
s.php.Route(82)(r)
}
+22
View File
@@ -0,0 +1,22 @@
package php83
import (
"github.com/go-chi/chi/v5"
"github.com/tnb-labs/panel/internal/apps/php"
"github.com/tnb-labs/panel/internal/biz"
)
type App struct {
php *php.App
}
func NewApp(task biz.TaskRepo) *App {
return &App{
php: php.NewApp(task),
}
}
func (s *App) Route(r chi.Router) {
s.php.Route(83)(r)
}
+22
View File
@@ -0,0 +1,22 @@
package php84
import (
"github.com/go-chi/chi/v5"
"github.com/tnb-labs/panel/internal/apps/php"
"github.com/tnb-labs/panel/internal/biz"
)
type App struct {
php *php.App
}
func NewApp(task biz.TaskRepo) *App {
return &App{
php: php.NewApp(task),
}
}
func (s *App) Route(r chi.Router) {
s.php.Route(84)(r)
}
@@ -3,28 +3,37 @@ package phpmyadmin
import (
"fmt"
"net/http"
"os"
"regexp"
"strings"
"github.com/go-chi/chi/v5"
"github.com/go-rat/chix"
"github.com/spf13/cast"
"github.com/TheTNB/panel/internal/app"
"github.com/TheTNB/panel/internal/service"
"github.com/TheTNB/panel/pkg/firewall"
"github.com/TheTNB/panel/pkg/io"
"github.com/TheTNB/panel/pkg/shell"
"github.com/TheTNB/panel/pkg/systemctl"
"github.com/tnb-labs/panel/internal/app"
"github.com/tnb-labs/panel/internal/service"
"github.com/tnb-labs/panel/pkg/firewall"
"github.com/tnb-labs/panel/pkg/io"
"github.com/tnb-labs/panel/pkg/shell"
"github.com/tnb-labs/panel/pkg/systemctl"
)
type Service struct{}
type App struct{}
func NewService() *Service {
return &Service{}
func NewApp() *App {
return &App{}
}
func (s *Service) Info(w http.ResponseWriter, r *http.Request) {
files, err := io.ReadDir(fmt.Sprintf("%s/server/phpmyadmin", app.Root))
func (s *App) Route(r chi.Router) {
r.Get("/info", s.Info)
r.Post("/port", s.UpdatePort)
r.Get("/config", s.GetConfig)
r.Post("/config", s.UpdateConfig)
}
func (s *App) Info(w http.ResponseWriter, r *http.Request) {
files, err := os.ReadDir(fmt.Sprintf("%s/server/phpmyadmin", app.Root))
if err != nil {
service.Error(w, http.StatusInternalServerError, "找不到 phpMyAdmin 目录")
return
@@ -58,7 +67,7 @@ func (s *Service) Info(w http.ResponseWriter, r *http.Request) {
})
}
func (s *Service) UpdatePort(w http.ResponseWriter, r *http.Request) {
func (s *App) UpdatePort(w http.ResponseWriter, r *http.Request) {
req, err := service.Bind[UpdatePort](r)
if err != nil {
service.Error(w, http.StatusUnprocessableEntity, "%v", err)
@@ -98,7 +107,7 @@ func (s *Service) UpdatePort(w http.ResponseWriter, r *http.Request) {
service.Success(w, nil)
}
func (s *Service) GetConfig(w http.ResponseWriter, r *http.Request) {
func (s *App) GetConfig(w http.ResponseWriter, r *http.Request) {
config, err := io.Read(fmt.Sprintf("%s/server/vhost/phpmyadmin.conf", app.Root))
if err != nil {
service.Error(w, http.StatusInternalServerError, "%v", err)
@@ -108,7 +117,7 @@ func (s *Service) GetConfig(w http.ResponseWriter, r *http.Request) {
service.Success(w, config)
}
func (s *Service) UpdateConfig(w http.ResponseWriter, r *http.Request) {
func (s *App) UpdateConfig(w http.ResponseWriter, r *http.Request) {
req, err := service.Bind[UpdateConfig](r)
if err != nil {
service.Error(w, http.StatusUnprocessableEntity, "%v", err)
-21
View File
@@ -1,21 +0,0 @@
package phpmyadmin
import (
"github.com/go-chi/chi/v5"
"github.com/TheTNB/panel/pkg/apploader"
"github.com/TheTNB/panel/pkg/types"
)
func init() {
apploader.Register(&types.App{
Slug: "phpmyadmin",
Route: func(r chi.Router) {
service := NewService()
r.Get("/info", service.Info)
r.Post("/port", service.UpdatePort)
r.Get("/config", service.GetConfig)
r.Post("/config", service.UpdateConfig)
},
})
}
+1 -1
View File
@@ -5,5 +5,5 @@ type UpdateConfig struct {
}
type UpdatePort struct {
Port uint `form:"port" json:"port" validate:"required,number,gte=1,lte=65535"`
Port uint `form:"port" json:"port" validate:"required|number|min:1|max:65535"`
}
@@ -3,18 +3,27 @@ package podman
import (
"net/http"
"github.com/TheTNB/panel/internal/service"
"github.com/TheTNB/panel/pkg/io"
"github.com/TheTNB/panel/pkg/systemctl"
"github.com/go-chi/chi/v5"
"github.com/tnb-labs/panel/internal/service"
"github.com/tnb-labs/panel/pkg/io"
"github.com/tnb-labs/panel/pkg/systemctl"
)
type Service struct{}
type App struct{}
func NewService() *Service {
return &Service{}
func NewApp() *App {
return &App{}
}
func (s *Service) GetRegistryConfig(w http.ResponseWriter, r *http.Request) {
func (s *App) Route(r chi.Router) {
r.Get("/registryConfig", s.GetRegistryConfig)
r.Post("/registryConfig", s.UpdateRegistryConfig)
r.Get("/storageConfig", s.GetStorageConfig)
r.Post("/storageConfig", s.UpdateStorageConfig)
}
func (s *App) GetRegistryConfig(w http.ResponseWriter, r *http.Request) {
config, err := io.Read("/etc/containers/registries.conf")
if err != nil {
service.Error(w, http.StatusInternalServerError, "%v", err)
@@ -24,7 +33,7 @@ func (s *Service) GetRegistryConfig(w http.ResponseWriter, r *http.Request) {
service.Success(w, config)
}
func (s *Service) UpdateRegistryConfig(w http.ResponseWriter, r *http.Request) {
func (s *App) UpdateRegistryConfig(w http.ResponseWriter, r *http.Request) {
req, err := service.Bind[UpdateConfig](r)
if err != nil {
service.Error(w, http.StatusUnprocessableEntity, "%v", err)
@@ -44,7 +53,7 @@ func (s *Service) UpdateRegistryConfig(w http.ResponseWriter, r *http.Request) {
service.Success(w, nil)
}
func (s *Service) GetStorageConfig(w http.ResponseWriter, r *http.Request) {
func (s *App) GetStorageConfig(w http.ResponseWriter, r *http.Request) {
config, err := io.Read("/etc/containers/storage.conf")
if err != nil {
service.Error(w, http.StatusInternalServerError, "%v", err)
@@ -54,7 +63,7 @@ func (s *Service) GetStorageConfig(w http.ResponseWriter, r *http.Request) {
service.Success(w, config)
}
func (s *Service) UpdateStorageConfig(w http.ResponseWriter, r *http.Request) {
func (s *App) UpdateStorageConfig(w http.ResponseWriter, r *http.Request) {
req, err := service.Bind[UpdateConfig](r)
if err != nil {
service.Error(w, http.StatusUnprocessableEntity, "%v", err)
-21
View File
@@ -1,21 +0,0 @@
package podman
import (
"github.com/go-chi/chi/v5"
"github.com/TheTNB/panel/pkg/apploader"
"github.com/TheTNB/panel/pkg/types"
)
func init() {
apploader.Register(&types.App{
Slug: "podman",
Route: func(r chi.Router) {
service := NewService()
r.Get("/registryConfig", service.GetRegistryConfig)
r.Post("/registryConfig", service.UpdateRegistryConfig)
r.Get("/storageConfig", service.GetStorageConfig)
r.Post("/storageConfig", service.UpdateStorageConfig)
},
})
}
@@ -5,22 +5,34 @@ import (
"net/http"
"time"
"github.com/TheTNB/panel/internal/app"
"github.com/TheTNB/panel/internal/service"
"github.com/TheTNB/panel/pkg/io"
"github.com/TheTNB/panel/pkg/shell"
"github.com/TheTNB/panel/pkg/systemctl"
"github.com/TheTNB/panel/pkg/types"
"github.com/go-chi/chi/v5"
"github.com/tnb-labs/panel/internal/app"
"github.com/tnb-labs/panel/internal/service"
"github.com/tnb-labs/panel/pkg/io"
"github.com/tnb-labs/panel/pkg/shell"
"github.com/tnb-labs/panel/pkg/systemctl"
"github.com/tnb-labs/panel/pkg/types"
)
type Service struct{}
type App struct{}
func NewService() *Service {
return &Service{}
func NewApp() *App {
return &App{}
}
func (s *App) Route(r chi.Router) {
r.Get("/config", s.GetConfig)
r.Post("/config", s.UpdateConfig)
r.Get("/userConfig", s.GetUserConfig)
r.Post("/userConfig", s.UpdateUserConfig)
r.Get("/load", s.Load)
r.Get("/log", s.Log)
r.Post("/clearLog", s.ClearLog)
}
// GetConfig 获取配置
func (s *Service) GetConfig(w http.ResponseWriter, r *http.Request) {
func (s *App) GetConfig(w http.ResponseWriter, r *http.Request) {
// 获取配置
config, err := io.Read(fmt.Sprintf("%s/server/postgresql/data/postgresql.conf", app.Root))
if err != nil {
@@ -32,7 +44,7 @@ func (s *Service) GetConfig(w http.ResponseWriter, r *http.Request) {
}
// UpdateConfig 保存配置
func (s *Service) UpdateConfig(w http.ResponseWriter, r *http.Request) {
func (s *App) UpdateConfig(w http.ResponseWriter, r *http.Request) {
req, err := service.Bind[UpdateConfig](r)
if err != nil {
service.Error(w, http.StatusUnprocessableEntity, "%v", err)
@@ -53,7 +65,7 @@ func (s *Service) UpdateConfig(w http.ResponseWriter, r *http.Request) {
}
// GetUserConfig 获取用户配置
func (s *Service) GetUserConfig(w http.ResponseWriter, r *http.Request) {
func (s *App) GetUserConfig(w http.ResponseWriter, r *http.Request) {
// 获取配置
config, err := io.Read(fmt.Sprintf("%s/server/postgresql/data/pg_hba.conf", app.Root))
if err != nil {
@@ -65,7 +77,7 @@ func (s *Service) GetUserConfig(w http.ResponseWriter, r *http.Request) {
}
// UpdateUserConfig 保存用户配置
func (s *Service) UpdateUserConfig(w http.ResponseWriter, r *http.Request) {
func (s *App) UpdateUserConfig(w http.ResponseWriter, r *http.Request) {
req, err := service.Bind[UpdateConfig](r)
if err != nil {
service.Error(w, http.StatusUnprocessableEntity, "%v", err)
@@ -86,7 +98,7 @@ func (s *Service) UpdateUserConfig(w http.ResponseWriter, r *http.Request) {
}
// Load 获取负载
func (s *Service) Load(w http.ResponseWriter, r *http.Request) {
func (s *App) Load(w http.ResponseWriter, r *http.Request) {
status, _ := systemctl.Status("postgresql")
if !status {
service.Success(w, []types.NV{})
@@ -131,12 +143,12 @@ func (s *Service) Load(w http.ResponseWriter, r *http.Request) {
}
// Log 获取日志
func (s *Service) Log(w http.ResponseWriter, r *http.Request) {
func (s *App) Log(w http.ResponseWriter, r *http.Request) {
service.Success(w, fmt.Sprintf("%s/server/postgresql/logs/postgresql-%s.log", app.Root, time.Now().Format(time.DateOnly)))
}
// ClearLog 清空日志
func (s *Service) ClearLog(w http.ResponseWriter, r *http.Request) {
func (s *App) ClearLog(w http.ResponseWriter, r *http.Request) {
if _, err := shell.Execf("rm -rf %s/server/postgresql/logs/postgresql-*.log", app.Root); err != nil {
service.Error(w, http.StatusInternalServerError, "%v", err)
return
-24
View File
@@ -1,24 +0,0 @@
package postgresql
import (
"github.com/go-chi/chi/v5"
"github.com/TheTNB/panel/pkg/apploader"
"github.com/TheTNB/panel/pkg/types"
)
func init() {
apploader.Register(&types.App{
Slug: "postgresql",
Route: func(r chi.Router) {
service := NewService()
r.Get("/config", service.GetConfig)
r.Post("/config", service.UpdateConfig)
r.Get("/userConfig", service.GetUserConfig)
r.Post("/userConfig", service.UpdateUserConfig)
r.Get("/load", service.Load)
r.Get("/log", service.Log)
r.Post("/clearLog", service.ClearLog)
},
})
}
@@ -5,25 +5,35 @@ import (
"regexp"
"strings"
"github.com/go-chi/chi/v5"
"github.com/go-rat/chix"
"github.com/spf13/cast"
"github.com/TheTNB/panel/internal/app"
"github.com/TheTNB/panel/internal/service"
"github.com/TheTNB/panel/pkg/firewall"
"github.com/TheTNB/panel/pkg/io"
"github.com/TheTNB/panel/pkg/shell"
"github.com/TheTNB/panel/pkg/systemctl"
"github.com/tnb-labs/panel/internal/app"
"github.com/tnb-labs/panel/internal/service"
"github.com/tnb-labs/panel/pkg/firewall"
"github.com/tnb-labs/panel/pkg/io"
"github.com/tnb-labs/panel/pkg/shell"
"github.com/tnb-labs/panel/pkg/systemctl"
)
type Service struct{}
type App struct{}
func NewService() *Service {
return &Service{}
func NewApp() *App {
return &App{}
}
func (s *App) Route(r chi.Router) {
r.Get("/users", s.List)
r.Post("/users", s.Create)
r.Delete("/users/{username}", s.Delete)
r.Post("/users/{username}/password", s.ChangePassword)
r.Get("/port", s.GetPort)
r.Post("/port", s.UpdatePort)
}
// List 获取用户列表
func (s *Service) List(w http.ResponseWriter, r *http.Request) {
func (s *App) List(w http.ResponseWriter, r *http.Request) {
listRaw, err := shell.Execf("pure-pw list")
if err != nil {
service.Success(w, chix.M{
@@ -55,7 +65,7 @@ func (s *Service) List(w http.ResponseWriter, r *http.Request) {
}
// Create 创建用户
func (s *Service) Create(w http.ResponseWriter, r *http.Request) {
func (s *App) Create(w http.ResponseWriter, r *http.Request) {
req, err := service.Bind[Create](r)
if err != nil {
service.Error(w, http.StatusUnprocessableEntity, "%v", err)
@@ -91,7 +101,7 @@ func (s *Service) Create(w http.ResponseWriter, r *http.Request) {
}
// Delete 删除用户
func (s *Service) Delete(w http.ResponseWriter, r *http.Request) {
func (s *App) Delete(w http.ResponseWriter, r *http.Request) {
req, err := service.Bind[Delete](r)
if err != nil {
service.Error(w, http.StatusUnprocessableEntity, "%v", err)
@@ -111,7 +121,7 @@ func (s *Service) Delete(w http.ResponseWriter, r *http.Request) {
}
// ChangePassword 修改密码
func (s *Service) ChangePassword(w http.ResponseWriter, r *http.Request) {
func (s *App) ChangePassword(w http.ResponseWriter, r *http.Request) {
req, err := service.Bind[ChangePassword](r)
if err != nil {
service.Error(w, http.StatusUnprocessableEntity, "%v", err)
@@ -131,7 +141,7 @@ func (s *Service) ChangePassword(w http.ResponseWriter, r *http.Request) {
}
// GetPort 获取端口
func (s *Service) GetPort(w http.ResponseWriter, r *http.Request) {
func (s *App) GetPort(w http.ResponseWriter, r *http.Request) {
port, err := shell.Execf(`cat %s/server/pure-ftpd/etc/pure-ftpd.conf | grep "Bind" | awk '{print $2}' | awk -F "," '{print $2}'`, app.Root)
if err != nil {
service.Error(w, http.StatusInternalServerError, "获取PureFtpd端口失败")
@@ -142,7 +152,7 @@ func (s *Service) GetPort(w http.ResponseWriter, r *http.Request) {
}
// UpdatePort 设置端口
func (s *Service) UpdatePort(w http.ResponseWriter, r *http.Request) {
func (s *App) UpdatePort(w http.ResponseWriter, r *http.Request) {
req, err := service.Bind[UpdatePort](r)
if err != nil {
service.Error(w, http.StatusUnprocessableEntity, "%v", err)
-23
View File
@@ -1,23 +0,0 @@
package pureftpd
import (
"github.com/go-chi/chi/v5"
"github.com/TheTNB/panel/pkg/apploader"
"github.com/TheTNB/panel/pkg/types"
)
func init() {
apploader.Register(&types.App{
Slug: "pureftpd",
Route: func(r chi.Router) {
service := NewService()
r.Get("/users", service.List)
r.Post("/users", service.Create)
r.Delete("/users/{username}", service.Delete)
r.Post("/users/{username}/password", service.ChangePassword)
r.Get("/port", service.GetPort)
r.Post("/port", service.UpdatePort)
},
})
}
+3 -3
View File
@@ -2,7 +2,7 @@ package pureftpd
type Create struct {
Username string `form:"username" json:"username" validate:"required"`
Password string `form:"password" json:"password" validate:"required,password"`
Password string `form:"password" json:"password" validate:"required|password"`
Path string `form:"path" json:"path" validate:"required"`
}
@@ -12,9 +12,9 @@ type Delete struct {
type ChangePassword struct {
Username string `form:"username" json:"username" validate:"required"`
Password string `form:"password" json:"password" validate:"required,password"`
Password string `form:"password" json:"password" validate:"required|password"`
}
type UpdatePort struct {
Port uint `form:"port" json:"port" validate:"required"`
Port uint `form:"port" json:"port" validate:"required|number|min:1|max:65535"`
}
@@ -3,23 +3,32 @@ package redis
import (
"fmt"
"net/http"
"regexp"
"strings"
"github.com/TheTNB/panel/internal/app"
"github.com/TheTNB/panel/internal/service"
"github.com/TheTNB/panel/pkg/io"
"github.com/TheTNB/panel/pkg/shell"
"github.com/TheTNB/panel/pkg/systemctl"
"github.com/TheTNB/panel/pkg/types"
"github.com/go-chi/chi/v5"
"github.com/tnb-labs/panel/internal/app"
"github.com/tnb-labs/panel/internal/service"
"github.com/tnb-labs/panel/pkg/io"
"github.com/tnb-labs/panel/pkg/shell"
"github.com/tnb-labs/panel/pkg/systemctl"
"github.com/tnb-labs/panel/pkg/types"
)
type Service struct{}
type App struct{}
func NewService() *Service {
return &Service{}
func NewApp() *App {
return &App{}
}
func (s *Service) Load(w http.ResponseWriter, r *http.Request) {
func (s *App) Route(r chi.Router) {
r.Get("/load", s.Load)
r.Get("/config", s.GetConfig)
r.Post("/config", s.UpdateConfig)
}
func (s *App) Load(w http.ResponseWriter, r *http.Request) {
status, err := systemctl.Status("redis")
if err != nil {
service.Error(w, http.StatusInternalServerError, "获取 Redis 状态失败")
@@ -30,7 +39,20 @@ func (s *Service) Load(w http.ResponseWriter, r *http.Request) {
return
}
raw, err := shell.Execf("redis-cli info")
// 检查 Redis 密码
withPassword := ""
config, err := io.Read(fmt.Sprintf("%s/server/redis/redis.conf", app.Root))
if err != nil {
service.Error(w, http.StatusInternalServerError, "%v", err)
return
}
re := regexp.MustCompile(`requirepass\s+(.+)`)
matches := re.FindStringSubmatch(config)
if len(matches) == 2 {
withPassword = " -a " + matches[1]
}
raw, err := shell.Execf("redis-cli%s info", withPassword)
if err != nil {
service.Error(w, http.StatusInternalServerError, "获取 Redis 负载失败")
return
@@ -65,7 +87,7 @@ func (s *Service) Load(w http.ResponseWriter, r *http.Request) {
service.Success(w, data)
}
func (s *Service) GetConfig(w http.ResponseWriter, r *http.Request) {
func (s *App) GetConfig(w http.ResponseWriter, r *http.Request) {
config, err := io.Read(fmt.Sprintf("%s/server/redis/redis.conf", app.Root))
if err != nil {
service.Error(w, http.StatusInternalServerError, "%v", err)
@@ -75,7 +97,7 @@ func (s *Service) GetConfig(w http.ResponseWriter, r *http.Request) {
service.Success(w, config)
}
func (s *Service) UpdateConfig(w http.ResponseWriter, r *http.Request) {
func (s *App) UpdateConfig(w http.ResponseWriter, r *http.Request) {
req, err := service.Bind[UpdateConfig](r)
if err != nil {
service.Error(w, http.StatusUnprocessableEntity, "%v", err)
-20
View File
@@ -1,20 +0,0 @@
package redis
import (
"github.com/go-chi/chi/v5"
"github.com/TheTNB/panel/pkg/apploader"
"github.com/TheTNB/panel/pkg/types"
)
func init() {
apploader.Register(&types.App{
Slug: "redis",
Route: func(r chi.Router) {
service := NewService()
r.Get("/load", service.Load)
r.Get("/config", service.GetConfig)
r.Post("/config", service.UpdateConfig)
},
})
}
@@ -6,22 +6,32 @@ import (
"regexp"
"strings"
"github.com/go-chi/chi/v5"
"github.com/go-rat/chix"
"github.com/go-rat/utils/str"
"github.com/TheTNB/panel/internal/service"
"github.com/TheTNB/panel/pkg/io"
"github.com/TheTNB/panel/pkg/shell"
"github.com/TheTNB/panel/pkg/str"
"github.com/TheTNB/panel/pkg/systemctl"
"github.com/tnb-labs/panel/internal/service"
"github.com/tnb-labs/panel/pkg/io"
"github.com/tnb-labs/panel/pkg/shell"
"github.com/tnb-labs/panel/pkg/systemctl"
)
type Service struct{}
type App struct{}
func NewService() *Service {
return &Service{}
func NewApp() *App {
return &App{}
}
func (s *Service) List(w http.ResponseWriter, r *http.Request) {
func (s *App) Route(r chi.Router) {
r.Get("/modules", s.List)
r.Post("/modules", s.Create)
r.Post("/modules/{name}", s.Update)
r.Delete("/modules/{name}", s.Delete)
r.Get("/config", s.GetConfig)
r.Post("/config", s.UpdateConfig)
}
func (s *App) List(w http.ResponseWriter, r *http.Request) {
config, err := io.Read("/etc/rsyncd.conf")
if err != nil {
service.Error(w, http.StatusInternalServerError, "%v", err)
@@ -86,7 +96,7 @@ func (s *Service) List(w http.ResponseWriter, r *http.Request) {
})
}
func (s *Service) Create(w http.ResponseWriter, r *http.Request) {
func (s *App) Create(w http.ResponseWriter, r *http.Request) {
req, err := service.Bind[Create](r)
if err != nil {
service.Error(w, http.StatusUnprocessableEntity, "%v", err)
@@ -114,11 +124,11 @@ secrets file = /etc/rsyncd.secrets
# ` + req.Name + `-END
`
if err = io.WriteAppend("/etc/rsyncd.conf", conf); err != nil {
if err = io.WriteAppend("/etc/rsyncd.conf", conf, 0644); err != nil {
service.Error(w, http.StatusInternalServerError, "%v", err)
return
}
if err = io.WriteAppend("/etc/rsyncd.secrets", fmt.Sprintf(`%s:%s\n`, req.AuthUser, req.Secret)); err != nil {
if err = io.WriteAppend("/etc/rsyncd.secrets", fmt.Sprintf(`%s:%s\n`, req.AuthUser, req.Secret), 0600); err != nil {
service.Error(w, http.StatusInternalServerError, "%v", err)
return
}
@@ -131,7 +141,7 @@ secrets file = /etc/rsyncd.secrets
service.Success(w, nil)
}
func (s *Service) Delete(w http.ResponseWriter, r *http.Request) {
func (s *App) Delete(w http.ResponseWriter, r *http.Request) {
req, err := service.Bind[Delete](r)
if err != nil {
service.Error(w, http.StatusUnprocessableEntity, "%v", err)
@@ -173,7 +183,7 @@ func (s *Service) Delete(w http.ResponseWriter, r *http.Request) {
service.Success(w, nil)
}
func (s *Service) Update(w http.ResponseWriter, r *http.Request) {
func (s *App) Update(w http.ResponseWriter, r *http.Request) {
req, err := service.Bind[Update](r)
if err != nil {
service.Error(w, http.StatusUnprocessableEntity, "%v", err)
@@ -216,7 +226,7 @@ secrets file = /etc/rsyncd.secrets
service.Error(w, http.StatusInternalServerError, "%v", err)
return
}
if err = io.WriteAppend("/etc/rsyncd.secrets", fmt.Sprintf(`%s:%s\n`, req.AuthUser, req.Secret)); err != nil {
if err = io.WriteAppend("/etc/rsyncd.secrets", fmt.Sprintf(`%s:%s\n`, req.AuthUser, req.Secret), 0600); err != nil {
service.Error(w, http.StatusInternalServerError, "%v", err)
return
}
@@ -229,7 +239,7 @@ secrets file = /etc/rsyncd.secrets
service.Success(w, nil)
}
func (s *Service) GetConfig(w http.ResponseWriter, r *http.Request) {
func (s *App) GetConfig(w http.ResponseWriter, r *http.Request) {
config, err := io.Read("/etc/rsyncd.conf")
if err != nil {
service.Error(w, http.StatusInternalServerError, "%v", err)
@@ -239,7 +249,7 @@ func (s *Service) GetConfig(w http.ResponseWriter, r *http.Request) {
service.Success(w, config)
}
func (s *Service) UpdateConfig(w http.ResponseWriter, r *http.Request) {
func (s *App) UpdateConfig(w http.ResponseWriter, r *http.Request) {
req, err := service.Bind[UpdateConfig](r)
if err != nil {
service.Error(w, http.StatusUnprocessableEntity, "%v", err)
-23
View File
@@ -1,23 +0,0 @@
package rsync
import (
"github.com/go-chi/chi/v5"
"github.com/TheTNB/panel/pkg/apploader"
"github.com/TheTNB/panel/pkg/types"
)
func init() {
apploader.Register(&types.App{
Slug: "rsync",
Route: func(r chi.Router) {
service := NewService()
r.Get("/modules", service.List)
r.Post("/modules", service.Create)
r.Post("/modules/{name}", service.Update)
r.Delete("/modules/{name}", service.Delete)
r.Get("/config", service.GetConfig)
r.Post("/config", service.UpdateConfig)
},
})
}
@@ -3,40 +3,47 @@ package s3fs
import (
"encoding/json"
"net/http"
"os"
"strings"
"time"
"github.com/go-chi/chi/v5"
"github.com/go-rat/chix"
"github.com/spf13/cast"
"github.com/TheTNB/panel/internal/biz"
"github.com/TheTNB/panel/internal/data"
"github.com/TheTNB/panel/internal/service"
"github.com/TheTNB/panel/pkg/io"
"github.com/TheTNB/panel/pkg/shell"
"github.com/tnb-labs/panel/internal/biz"
"github.com/tnb-labs/panel/internal/service"
"github.com/tnb-labs/panel/pkg/io"
"github.com/tnb-labs/panel/pkg/shell"
)
type Service struct {
type App struct {
settingRepo biz.SettingRepo
}
func NewService() *Service {
return &Service{
settingRepo: data.NewSettingRepo(),
func NewApp(setting biz.SettingRepo) *App {
return &App{
settingRepo: setting,
}
}
func (s *App) Route(r chi.Router) {
r.Get("/mounts", s.List)
r.Post("/mounts", s.Create)
r.Delete("/mounts", s.Delete)
}
// List 所有 S3fs 挂载
func (s *Service) List(w http.ResponseWriter, r *http.Request) {
func (s *App) List(w http.ResponseWriter, r *http.Request) {
var s3fsList []Mount
list, err := s.settingRepo.Get("s3fs", "[]")
if err != nil {
service.Error(w, http.StatusInternalServerError, "获取 S3fs 挂载失败")
service.Error(w, http.StatusInternalServerError, "failed to get s3fs list")
return
}
if err = json.Unmarshal([]byte(list), &s3fsList); err != nil {
service.Error(w, http.StatusInternalServerError, "获取 S3fs 挂载失败")
service.Error(w, http.StatusInternalServerError, "failed to get s3fs list")
return
}
@@ -49,7 +56,7 @@ func (s *Service) List(w http.ResponseWriter, r *http.Request) {
}
// Create 添加 S3fs 挂载
func (s *Service) Create(w http.ResponseWriter, r *http.Request) {
func (s *App) Create(w http.ResponseWriter, r *http.Request) {
req, err := service.Bind[Create](r)
if err != nil {
service.Error(w, http.StatusUnprocessableEntity, "%v", err)
@@ -58,36 +65,36 @@ func (s *Service) Create(w http.ResponseWriter, r *http.Request) {
// 检查下地域节点中是否包含bucket,如果包含了,肯定是错误的
if strings.Contains(req.URL, req.Bucket) {
service.Error(w, http.StatusUnprocessableEntity, "地域节点不能包含 Bucket 名称")
service.Error(w, http.StatusUnprocessableEntity, "endpoint should not contain bucket")
return
}
// 检查挂载目录是否存在且为空
if !io.Exists(req.Path) {
if err = io.Mkdir(req.Path, 0755); err != nil {
service.Error(w, http.StatusUnprocessableEntity, "挂载目录创建失败")
if err = os.MkdirAll(req.Path, 0755); err != nil {
service.Error(w, http.StatusUnprocessableEntity, "failed to create mount path: %v", err)
return
}
}
if !io.Empty(req.Path) {
service.Error(w, http.StatusUnprocessableEntity, "挂载目录必须为空")
service.Error(w, http.StatusUnprocessableEntity, "mount path is not empty")
return
}
var s3fsList []Mount
list, err := s.settingRepo.Get("s3fs", "[]")
if err != nil {
service.Error(w, http.StatusInternalServerError, "获取 S3fs 挂载失败")
service.Error(w, http.StatusInternalServerError, "failed to get s3fs list")
return
}
if err = json.Unmarshal([]byte(list), &s3fsList); err != nil {
service.Error(w, http.StatusInternalServerError, "获取 S3fs 挂载失败")
service.Error(w, http.StatusInternalServerError, "failed to get s3fs list")
return
}
for _, s := range s3fsList {
if s.Path == req.Path {
service.Error(w, http.StatusUnprocessableEntity, "路径已存在")
service.Error(w, http.StatusUnprocessableEntity, "mount path already exists")
return
}
}
@@ -95,21 +102,21 @@ func (s *Service) Create(w http.ResponseWriter, r *http.Request) {
id := time.Now().UnixMicro()
password := req.Ak + ":" + req.Sk
if err = io.Write("/etc/passwd-s3fs-"+cast.ToString(id), password, 0600); err != nil {
service.Error(w, http.StatusInternalServerError, "添加 S3fs 挂载失败")
service.Error(w, http.StatusInternalServerError, "failed to create passwd file: %v", err)
return
}
if _, err = shell.Execf(`echo 's3fs#%s %s fuse _netdev,allow_other,nonempty,url=%s,passwd_file=/etc/passwd-s3fs-%s 0 0' >> /etc/fstab`, req.Bucket, req.Path, req.URL, cast.ToString(id)); err != nil {
service.Error(w, http.StatusInternalServerError, "%v", err)
return
}
if mountCheck, err := shell.Execf("mount -a"); err != nil {
if _, err = shell.Execf("mount -a"); err != nil {
_, _ = shell.Execf(`sed -i 's@^s3fs#%s\s%s.*$@@g' /etc/fstab`, req.Bucket, req.Path)
service.Error(w, http.StatusInternalServerError, "/etc/fstab有误:%s", mountCheck)
service.Error(w, http.StatusInternalServerError, "invalid /etc/fstab: %v", err)
return
}
if _, err := shell.Execf(`df -h | grep '%s'`, req.Path); err != nil {
if _, err = shell.Execf(`df -h | grep '%s'`, req.Path); err != nil {
_, _ = shell.Execf(`sed -i 's@^s3fs#%s\s%s.*$@@g' /etc/fstab`, req.Bucket, req.Path)
service.Error(w, http.StatusInternalServerError, "挂载失败,请检查配置是否正确")
service.Error(w, http.StatusInternalServerError, "mount failed: %v", err)
return
}
@@ -121,12 +128,12 @@ func (s *Service) Create(w http.ResponseWriter, r *http.Request) {
})
encoded, err := json.Marshal(s3fsList)
if err != nil {
service.Error(w, http.StatusInternalServerError, "添加 S3fs 挂载失败")
service.Error(w, http.StatusInternalServerError, "failed to add s3fs mount")
return
}
if err = s.settingRepo.Set("s3fs", string(encoded)); err != nil {
service.Error(w, http.StatusInternalServerError, "添加 S3fs 挂载失败")
service.Error(w, http.StatusInternalServerError, "failed to add s3fs mount")
return
}
@@ -134,7 +141,7 @@ func (s *Service) Create(w http.ResponseWriter, r *http.Request) {
}
// Delete 删除 S3fs 挂载
func (s *Service) Delete(w http.ResponseWriter, r *http.Request) {
func (s *App) Delete(w http.ResponseWriter, r *http.Request) {
req, err := service.Bind[Delete](r)
if err != nil {
service.Error(w, http.StatusUnprocessableEntity, "%v", err)
@@ -144,11 +151,11 @@ func (s *Service) Delete(w http.ResponseWriter, r *http.Request) {
var s3fsList []Mount
list, err := s.settingRepo.Get("s3fs", "[]")
if err != nil {
service.Error(w, http.StatusInternalServerError, "获取 S3fs 挂载失败")
service.Error(w, http.StatusInternalServerError, "failed to get s3fs list")
return
}
if err = json.Unmarshal([]byte(list), &s3fsList); err != nil {
service.Error(w, http.StatusInternalServerError, "获取 S3fs 挂载失败")
service.Error(w, http.StatusInternalServerError, "failed to get s3fs list")
return
}
@@ -160,15 +167,15 @@ func (s *Service) Delete(w http.ResponseWriter, r *http.Request) {
}
}
if mount.ID == 0 {
service.Error(w, http.StatusUnprocessableEntity, "挂载不存在")
service.Error(w, http.StatusUnprocessableEntity, "mount not found")
return
}
if _, err = shell.Execf(`fusermount -u '%s'`, mount.Path); err != nil {
if _, err = shell.Execf(`fusermount -uz '%s'`, mount.Path); err != nil {
service.Error(w, http.StatusInternalServerError, "%v", err)
return
}
if _, err = shell.Execf(`umount '%s'`, mount.Path); err != nil {
if _, err = shell.Execf(`umount -lfq '%s'`, mount.Path); err != nil {
service.Error(w, http.StatusInternalServerError, "%v", err)
return
}
@@ -176,8 +183,8 @@ func (s *Service) Delete(w http.ResponseWriter, r *http.Request) {
service.Error(w, http.StatusInternalServerError, "%v", err)
return
}
if mountCheck, err := shell.Execf("mount -a"); err != nil {
service.Error(w, http.StatusInternalServerError, "/etc/fstab有误:%s", mountCheck)
if _, err = shell.Execf("mount -a"); err != nil {
service.Error(w, http.StatusInternalServerError, "invalid /etc/fstab: %v", err)
return
}
if err = io.Remove("/etc/passwd-s3fs-" + cast.ToString(mount.ID)); err != nil {
@@ -193,11 +200,11 @@ func (s *Service) Delete(w http.ResponseWriter, r *http.Request) {
}
encoded, err := json.Marshal(newS3fsList)
if err != nil {
service.Error(w, http.StatusInternalServerError, "删除 S3fs 挂载失败")
service.Error(w, http.StatusInternalServerError, "failed to delete s3fs mount")
return
}
if err = s.settingRepo.Set("s3fs", string(encoded)); err != nil {
service.Error(w, http.StatusInternalServerError, "删除 S3fs 挂载失败")
service.Error(w, http.StatusInternalServerError, "failed to delete s3fs mount")
return
}
-20
View File
@@ -1,20 +0,0 @@
package s3fs
import (
"github.com/go-chi/chi/v5"
"github.com/TheTNB/panel/pkg/apploader"
"github.com/TheTNB/panel/pkg/types"
)
func init() {
apploader.Register(&types.App{
Slug: "s3fs",
Route: func(r chi.Router) {
service := NewService()
r.Get("/mounts", service.List)
r.Post("/mounts", service.Create)
r.Delete("/mounts", service.Delete)
},
})
}
@@ -4,21 +4,22 @@ import (
"net/http"
"strings"
"github.com/go-chi/chi/v5"
"github.com/go-rat/chix"
"github.com/spf13/cast"
"github.com/TheTNB/panel/internal/service"
"github.com/TheTNB/panel/pkg/io"
"github.com/TheTNB/panel/pkg/os"
"github.com/TheTNB/panel/pkg/shell"
"github.com/TheTNB/panel/pkg/systemctl"
"github.com/tnb-labs/panel/internal/service"
"github.com/tnb-labs/panel/pkg/io"
"github.com/tnb-labs/panel/pkg/os"
"github.com/tnb-labs/panel/pkg/shell"
"github.com/tnb-labs/panel/pkg/systemctl"
)
type Service struct {
type App struct {
name string
}
func NewService() *Service {
func NewApp() *App {
var name string
if os.IsRHEL() {
name = "supervisord"
@@ -26,18 +27,35 @@ func NewService() *Service {
name = "supervisor"
}
return &Service{
return &App{
name: name,
}
}
func (s *App) Route(r chi.Router) {
r.Get("/service", s.Service)
r.Post("/clearLog", s.ClearLog)
r.Get("/config", s.GetConfig)
r.Post("/config", s.UpdateConfig)
r.Get("/processes", s.Processes)
r.Post("/processes/{process}/start", s.StartProcess)
r.Post("/processes/{process}/stop", s.StopProcess)
r.Post("/processes/{process}/restart", s.RestartProcess)
r.Get("/processes/{process}/log", s.ProcessLog)
r.Post("/processes/{process}/clearLog", s.ClearProcessLog)
r.Get("/processes/{process}", s.ProcessConfig)
r.Post("/processes/{process}", s.UpdateProcessConfig)
r.Delete("/processes/{process}", s.DeleteProcess)
r.Post("/processes", s.CreateProcess)
}
// Service 获取服务名称
func (s *Service) Service(w http.ResponseWriter, r *http.Request) {
func (s *App) Service(w http.ResponseWriter, r *http.Request) {
service.Success(w, s.name)
}
// ClearLog 清空日志
func (s *Service) ClearLog(w http.ResponseWriter, r *http.Request) {
func (s *App) ClearLog(w http.ResponseWriter, r *http.Request) {
if _, err := shell.Execf(`echo "" > /var/log/supervisor/supervisord.log`); err != nil {
service.Error(w, http.StatusInternalServerError, "%v", err)
return
@@ -47,7 +65,7 @@ func (s *Service) ClearLog(w http.ResponseWriter, r *http.Request) {
}
// GetConfig 获取配置
func (s *Service) GetConfig(w http.ResponseWriter, r *http.Request) {
func (s *App) GetConfig(w http.ResponseWriter, r *http.Request) {
var config string
var err error
if os.IsRHEL() {
@@ -65,7 +83,7 @@ func (s *Service) GetConfig(w http.ResponseWriter, r *http.Request) {
}
// UpdateConfig 保存配置
func (s *Service) UpdateConfig(w http.ResponseWriter, r *http.Request) {
func (s *App) UpdateConfig(w http.ResponseWriter, r *http.Request) {
req, err := service.Bind[UpdateConfig](r)
if err != nil {
service.Error(w, http.StatusUnprocessableEntity, "%v", err)
@@ -92,7 +110,7 @@ func (s *Service) UpdateConfig(w http.ResponseWriter, r *http.Request) {
}
// Processes 进程列表
func (s *Service) Processes(w http.ResponseWriter, r *http.Request) {
func (s *App) Processes(w http.ResponseWriter, r *http.Request) {
out, err := shell.Execf(`supervisorctl status | awk '{print $1}'`)
if err != nil {
service.Error(w, http.StatusInternalServerError, "%v", err)
@@ -131,7 +149,7 @@ func (s *Service) Processes(w http.ResponseWriter, r *http.Request) {
}
// StartProcess 启动进程
func (s *Service) StartProcess(w http.ResponseWriter, r *http.Request) {
func (s *App) StartProcess(w http.ResponseWriter, r *http.Request) {
req, err := service.Bind[ProcessName](r)
if err != nil {
service.Error(w, http.StatusUnprocessableEntity, "%v", err)
@@ -147,7 +165,7 @@ func (s *Service) StartProcess(w http.ResponseWriter, r *http.Request) {
}
// StopProcess 停止进程
func (s *Service) StopProcess(w http.ResponseWriter, r *http.Request) {
func (s *App) StopProcess(w http.ResponseWriter, r *http.Request) {
req, err := service.Bind[ProcessName](r)
if err != nil {
service.Error(w, http.StatusUnprocessableEntity, "%v", err)
@@ -163,7 +181,7 @@ func (s *Service) StopProcess(w http.ResponseWriter, r *http.Request) {
}
// RestartProcess 重启进程
func (s *Service) RestartProcess(w http.ResponseWriter, r *http.Request) {
func (s *App) RestartProcess(w http.ResponseWriter, r *http.Request) {
req, err := service.Bind[ProcessName](r)
if err != nil {
service.Error(w, http.StatusUnprocessableEntity, "%v", err)
@@ -179,7 +197,7 @@ func (s *Service) RestartProcess(w http.ResponseWriter, r *http.Request) {
}
// ProcessLog 进程日志
func (s *Service) ProcessLog(w http.ResponseWriter, r *http.Request) {
func (s *App) ProcessLog(w http.ResponseWriter, r *http.Request) {
req, err := service.Bind[ProcessName](r)
if err != nil {
service.Error(w, http.StatusUnprocessableEntity, "%v", err)
@@ -202,7 +220,7 @@ func (s *Service) ProcessLog(w http.ResponseWriter, r *http.Request) {
}
// ClearProcessLog 清空进程日志
func (s *Service) ClearProcessLog(w http.ResponseWriter, r *http.Request) {
func (s *App) ClearProcessLog(w http.ResponseWriter, r *http.Request) {
req, err := service.Bind[ProcessName](r)
if err != nil {
service.Error(w, http.StatusUnprocessableEntity, "%v", err)
@@ -230,7 +248,7 @@ func (s *Service) ClearProcessLog(w http.ResponseWriter, r *http.Request) {
}
// ProcessConfig 获取进程配置
func (s *Service) ProcessConfig(w http.ResponseWriter, r *http.Request) {
func (s *App) ProcessConfig(w http.ResponseWriter, r *http.Request) {
req, err := service.Bind[ProcessName](r)
if err != nil {
service.Error(w, http.StatusUnprocessableEntity, "%v", err)
@@ -253,7 +271,7 @@ func (s *Service) ProcessConfig(w http.ResponseWriter, r *http.Request) {
}
// UpdateProcessConfig 保存进程配置
func (s *Service) UpdateProcessConfig(w http.ResponseWriter, r *http.Request) {
func (s *App) UpdateProcessConfig(w http.ResponseWriter, r *http.Request) {
req, err := service.Bind[UpdateProcessConfig](r)
if err != nil {
service.Error(w, http.StatusUnprocessableEntity, "%v", err)
@@ -279,7 +297,7 @@ func (s *Service) UpdateProcessConfig(w http.ResponseWriter, r *http.Request) {
}
// CreateProcess 添加进程
func (s *Service) CreateProcess(w http.ResponseWriter, r *http.Request) {
func (s *App) CreateProcess(w http.ResponseWriter, r *http.Request) {
req, err := service.Bind[CreateProcess](r)
if err != nil {
service.Error(w, http.StatusUnprocessableEntity, "%v", err)
@@ -318,7 +336,7 @@ stdout_logfile_maxbytes=2MB
}
// DeleteProcess 删除进程
func (s *Service) DeleteProcess(w http.ResponseWriter, r *http.Request) {
func (s *App) DeleteProcess(w http.ResponseWriter, r *http.Request) {
req, err := service.Bind[ProcessName](r)
if err != nil {
service.Error(w, http.StatusUnprocessableEntity, "%v", err)
-31
View File
@@ -1,31 +0,0 @@
package supervisor
import (
"github.com/go-chi/chi/v5"
"github.com/TheTNB/panel/pkg/apploader"
"github.com/TheTNB/panel/pkg/types"
)
func init() {
apploader.Register(&types.App{
Slug: "supervisor",
Route: func(r chi.Router) {
service := NewService()
r.Get("/service", service.Service)
r.Post("/clearLog", service.ClearLog)
r.Get("/config", service.GetConfig)
r.Post("/config", service.UpdateConfig)
r.Get("/processes", service.Processes)
r.Post("/processes/{process}/start", service.StartProcess)
r.Post("/processes/{process}/stop", service.StopProcess)
r.Post("/processes/{process}/restart", service.RestartProcess)
r.Get("/processes/{process}/log", service.ProcessLog)
r.Post("/processes/{process}/clearLog", service.ClearProcessLog)
r.Get("/processes/{process}", service.ProcessConfig)
r.Post("/processes/{process}", service.UpdateProcessConfig)
r.Delete("/processes/{process}", service.DeleteProcess)
r.Post("/processes", service.CreateProcess)
},
})
}
+1 -1
View File
@@ -18,5 +18,5 @@ type CreateProcess struct {
User string `form:"user" json:"user" validate:"required"`
Path string `form:"path" json:"path" validate:"required"`
Command string `form:"command" json:"command" validate:"required"`
Num int `form:"num" json:"num" validate:"required,gte=1"`
Num int `form:"num" json:"num" validate:"required|min:1"`
}
@@ -6,26 +6,43 @@ import (
"regexp"
"strings"
"github.com/go-chi/chi/v5"
"github.com/go-rat/chix"
"github.com/spf13/cast"
"github.com/TheTNB/panel/internal/app"
"github.com/TheTNB/panel/internal/service"
"github.com/TheTNB/panel/pkg/io"
"github.com/TheTNB/panel/pkg/ntp"
"github.com/TheTNB/panel/pkg/shell"
"github.com/TheTNB/panel/pkg/str"
"github.com/TheTNB/panel/pkg/types"
"github.com/tnb-labs/panel/internal/app"
"github.com/tnb-labs/panel/internal/service"
"github.com/tnb-labs/panel/pkg/io"
"github.com/tnb-labs/panel/pkg/ntp"
"github.com/tnb-labs/panel/pkg/shell"
"github.com/tnb-labs/panel/pkg/tools"
"github.com/tnb-labs/panel/pkg/types"
)
type Service struct{}
type App struct{}
func NewService() *Service {
return &Service{}
func NewApp() *App {
return &App{}
}
func (s *App) Route(r chi.Router) {
r.Get("/dns", s.GetDNS)
r.Post("/dns", s.UpdateDNS)
r.Get("/swap", s.GetSWAP)
r.Post("/swap", s.UpdateSWAP)
r.Get("/timezone", s.GetTimezone)
r.Post("/timezone", s.UpdateTimezone)
r.Post("/time", s.UpdateTime)
r.Post("/syncTime", s.SyncTime)
r.Get("/hostname", s.GetHostname)
r.Post("/hostname", s.UpdateHostname)
r.Get("/hosts", s.GetHosts)
r.Post("/hosts", s.UpdateHosts)
r.Post("/rootPassword", s.UpdateRootPassword)
}
// GetDNS 获取 DNS 信息
func (s *Service) GetDNS(w http.ResponseWriter, r *http.Request) {
func (s *App) GetDNS(w http.ResponseWriter, r *http.Request) {
raw, err := io.Read("/etc/resolv.conf")
if err != nil {
service.Error(w, http.StatusInternalServerError, "%v", err)
@@ -46,7 +63,7 @@ func (s *Service) GetDNS(w http.ResponseWriter, r *http.Request) {
}
// UpdateDNS 设置 DNS 信息
func (s *Service) UpdateDNS(w http.ResponseWriter, r *http.Request) {
func (s *App) UpdateDNS(w http.ResponseWriter, r *http.Request) {
req, err := service.Bind[DNS](r)
if err != nil {
service.Error(w, http.StatusUnprocessableEntity, "%v", err)
@@ -66,7 +83,7 @@ func (s *Service) UpdateDNS(w http.ResponseWriter, r *http.Request) {
}
// GetSWAP 获取 SWAP 信息
func (s *Service) GetSWAP(w http.ResponseWriter, r *http.Request) {
func (s *App) GetSWAP(w http.ResponseWriter, r *http.Request) {
var total, used, free string
var size int64
if io.Exists(filepath.Join(app.Root, "swap")) {
@@ -77,7 +94,7 @@ func (s *Service) GetSWAP(w http.ResponseWriter, r *http.Request) {
}
size = file.Size() / 1024 / 1024
total = str.FormatBytes(float64(file.Size()))
total = tools.FormatBytes(float64(file.Size()))
} else {
size = 0
total = "0.00 B"
@@ -91,8 +108,8 @@ func (s *Service) GetSWAP(w http.ResponseWriter, r *http.Request) {
match := regexp.MustCompile(`Swap:\s+(\d+)\s+(\d+)\s+(\d+)`).FindStringSubmatch(raw)
if len(match) >= 4 {
used = str.FormatBytes(cast.ToFloat64(match[2]) * 1024)
free = str.FormatBytes(cast.ToFloat64(match[3]) * 1024)
used = tools.FormatBytes(cast.ToFloat64(match[2]) * 1024)
free = tools.FormatBytes(cast.ToFloat64(match[3]) * 1024)
}
service.Success(w, chix.M{
@@ -104,7 +121,7 @@ func (s *Service) GetSWAP(w http.ResponseWriter, r *http.Request) {
}
// UpdateSWAP 设置 SWAP 信息
func (s *Service) UpdateSWAP(w http.ResponseWriter, r *http.Request) {
func (s *App) UpdateSWAP(w http.ResponseWriter, r *http.Request) {
req, err := service.Bind[SWAP](r)
if err != nil {
service.Error(w, http.StatusUnprocessableEntity, "%v", err)
@@ -134,7 +151,7 @@ func (s *Service) UpdateSWAP(w http.ResponseWriter, r *http.Request) {
return
}
if cast.ToInt64(free)*1024 < req.Size*1024*1024 {
service.Error(w, http.StatusInternalServerError, "硬盘空间不足,当前剩余%s", str.FormatBytes(cast.ToFloat64(free)))
service.Error(w, http.StatusInternalServerError, "硬盘空间不足,当前剩余%s", tools.FormatBytes(cast.ToFloat64(free)))
return
}
@@ -172,7 +189,7 @@ func (s *Service) UpdateSWAP(w http.ResponseWriter, r *http.Request) {
}
// GetTimezone 获取时区
func (s *Service) GetTimezone(w http.ResponseWriter, r *http.Request) {
func (s *App) GetTimezone(w http.ResponseWriter, r *http.Request) {
raw, err := shell.Execf("timedatectl | grep zone")
if err != nil {
service.Error(w, http.StatusInternalServerError, "获取时区信息失败")
@@ -207,7 +224,7 @@ func (s *Service) GetTimezone(w http.ResponseWriter, r *http.Request) {
}
// UpdateTimezone 设置时区
func (s *Service) UpdateTimezone(w http.ResponseWriter, r *http.Request) {
func (s *App) UpdateTimezone(w http.ResponseWriter, r *http.Request) {
req, err := service.Bind[Timezone](r)
if err != nil {
service.Error(w, http.StatusUnprocessableEntity, "%v", err)
@@ -223,7 +240,7 @@ func (s *Service) UpdateTimezone(w http.ResponseWriter, r *http.Request) {
}
// UpdateTime 设置时间
func (s *Service) UpdateTime(w http.ResponseWriter, r *http.Request) {
func (s *App) UpdateTime(w http.ResponseWriter, r *http.Request) {
req, err := service.Bind[Time](r)
if err != nil {
service.Error(w, http.StatusUnprocessableEntity, "%v", err)
@@ -240,7 +257,7 @@ func (s *Service) UpdateTime(w http.ResponseWriter, r *http.Request) {
}
// SyncTime 同步时间
func (s *Service) SyncTime(w http.ResponseWriter, r *http.Request) {
func (s *App) SyncTime(w http.ResponseWriter, r *http.Request) {
now, err := ntp.Now()
if err != nil {
service.Error(w, http.StatusInternalServerError, "%v", err)
@@ -256,13 +273,13 @@ func (s *Service) SyncTime(w http.ResponseWriter, r *http.Request) {
}
// GetHostname 获取主机名
func (s *Service) GetHostname(w http.ResponseWriter, r *http.Request) {
func (s *App) GetHostname(w http.ResponseWriter, r *http.Request) {
hostname, _ := io.Read("/etc/hostname")
service.Success(w, strings.TrimSpace(hostname))
}
// UpdateHostname 设置主机名
func (s *Service) UpdateHostname(w http.ResponseWriter, r *http.Request) {
func (s *App) UpdateHostname(w http.ResponseWriter, r *http.Request) {
req, err := service.Bind[Hostname](r)
if err != nil {
service.Error(w, http.StatusUnprocessableEntity, "%v", err)
@@ -281,13 +298,13 @@ func (s *Service) UpdateHostname(w http.ResponseWriter, r *http.Request) {
}
// GetHosts 获取 hosts 信息
func (s *Service) GetHosts(w http.ResponseWriter, r *http.Request) {
func (s *App) GetHosts(w http.ResponseWriter, r *http.Request) {
hosts, _ := io.Read("/etc/hosts")
service.Success(w, hosts)
}
// UpdateHosts 设置 hosts 信息
func (s *Service) UpdateHosts(w http.ResponseWriter, r *http.Request) {
func (s *App) UpdateHosts(w http.ResponseWriter, r *http.Request) {
req, err := service.Bind[Hosts](r)
if err != nil {
service.Error(w, http.StatusUnprocessableEntity, "%v", err)
@@ -303,7 +320,7 @@ func (s *Service) UpdateHosts(w http.ResponseWriter, r *http.Request) {
}
// UpdateRootPassword 设置 root 密码
func (s *Service) UpdateRootPassword(w http.ResponseWriter, r *http.Request) {
func (s *App) UpdateRootPassword(w http.ResponseWriter, r *http.Request) {
req, err := service.Bind[Password](r)
if err != nil {
service.Error(w, http.StatusUnprocessableEntity, "%v", err)
-30
View File
@@ -1,30 +0,0 @@
package toolbox
import (
"github.com/go-chi/chi/v5"
"github.com/TheTNB/panel/pkg/apploader"
"github.com/TheTNB/panel/pkg/types"
)
func init() {
apploader.Register(&types.App{
Slug: "toolbox",
Route: func(r chi.Router) {
service := NewService()
r.Get("/dns", service.GetDNS)
r.Post("/dns", service.UpdateDNS)
r.Get("/swap", service.GetSWAP)
r.Post("/swap", service.UpdateSWAP)
r.Get("/timezone", service.GetTimezone)
r.Post("/timezone", service.UpdateTimezone)
r.Post("/time", service.UpdateTime)
r.Post("/syncTime", service.SyncTime)
r.Get("/hostname", service.GetHostname)
r.Post("/hostname", service.UpdateHostname)
r.Get("/hosts", service.GetHosts)
r.Post("/hosts", service.UpdateHosts)
r.Post("/rootPassword", service.UpdateRootPassword)
},
})
}
+3 -3
View File
@@ -8,7 +8,7 @@ type DNS struct {
}
type SWAP struct {
Size int64 `form:"size" json:"size" validate:"gte=0"`
Size int64 `form:"size" json:"size" validate:"min:0"`
}
type Timezone struct {
@@ -20,7 +20,7 @@ type Time struct {
}
type Hostname struct {
Hostname string `form:"hostname" json:"hostname" validate:"required,regex=^[a-zA-Z0-9][a-zA-Z0-9-]{061}[a-zA-Z0-9]$"`
Hostname string `form:"hostname" json:"hostname" validate:"required|regex:^[a-zA-Z0-9][a-zA-Z0-9-]{0,61}[a-zA-Z0-9]$"`
}
type Hosts struct {
@@ -28,5 +28,5 @@ type Hosts struct {
}
type Password struct {
Password string `form:"password" json:"password" validate:"required,password"`
Password string `form:"password" json:"password" validate:"required|password"`
}
+1 -2
View File
@@ -3,7 +3,7 @@ package biz
import (
"time"
"github.com/TheTNB/panel/pkg/api"
"github.com/tnb-labs/panel/pkg/api"
)
type App struct {
@@ -30,5 +30,4 @@ type AppRepo interface {
UnInstall(slug string) error
Update(slug string) error
UpdateShow(slug string, show bool) error
UpdateCache() error
}
+3 -1
View File
@@ -1,6 +1,6 @@
package biz
import "github.com/TheTNB/panel/pkg/types"
import "github.com/tnb-labs/panel/pkg/types"
type BackupType string
@@ -21,4 +21,6 @@ type BackupRepo interface {
ClearExpired(path, prefix string, save int) error
CutoffLog(path, target string) error
GetPath(typ BackupType) (string, error)
FixPanel() error
UpdatePanel(version, url, checksum string) error
}
+2
View File
@@ -19,4 +19,6 @@ type Cache struct {
type CacheRepo interface {
Get(key CacheKey, defaultValue ...string) (string, error)
Set(key CacheKey, value string) error
UpdateApps() error
UpdateRewrites() error
}
+3 -3
View File
@@ -3,9 +3,9 @@ package biz
import (
"time"
"github.com/TheTNB/panel/internal/http/request"
"github.com/TheTNB/panel/pkg/acme"
"github.com/TheTNB/panel/pkg/types"
"github.com/tnb-labs/panel/internal/http/request"
"github.com/tnb-labs/panel/pkg/acme"
"github.com/tnb-labs/panel/pkg/types"
)
type Cert struct {
+1 -1
View File
@@ -3,7 +3,7 @@ package biz
import (
"time"
"github.com/TheTNB/panel/internal/http/request"
"github.com/tnb-labs/panel/internal/http/request"
)
type CertAccount struct {
+3 -3
View File
@@ -3,14 +3,14 @@ package biz
import (
"time"
"github.com/TheTNB/panel/internal/http/request"
"github.com/TheTNB/panel/pkg/acme"
"github.com/tnb-labs/panel/internal/http/request"
"github.com/tnb-labs/panel/pkg/acme"
)
type CertDNS struct {
ID uint `gorm:"primaryKey" json:"id"`
Name string `gorm:"not null" json:"name"` // 备注名称
Type string `gorm:"not null" json:"type"` // DNS 提供商 (dnspod, tencent, aliyun, cloudflare)
Type string `gorm:"not null" json:"type"` // DNS 提供商 (tencent, aliyun, cloudflare)
Data acme.DNSParam `gorm:"not null;serializer:json" json:"dns_param"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
+2 -2
View File
@@ -1,8 +1,8 @@
package biz
import (
"github.com/TheTNB/panel/internal/http/request"
"github.com/TheTNB/panel/pkg/types"
"github.com/tnb-labs/panel/internal/http/request"
"github.com/tnb-labs/panel/pkg/types"
)
type ContainerRepo interface {
+2 -2
View File
@@ -1,8 +1,8 @@
package biz
import (
"github.com/TheTNB/panel/internal/http/request"
"github.com/TheTNB/panel/pkg/types"
"github.com/tnb-labs/panel/internal/http/request"
"github.com/tnb-labs/panel/pkg/types"
)
type ContainerImageRepo interface {
+2 -2
View File
@@ -1,8 +1,8 @@
package biz
import (
"github.com/TheTNB/panel/internal/http/request"
"github.com/TheTNB/panel/pkg/types"
"github.com/tnb-labs/panel/internal/http/request"
"github.com/tnb-labs/panel/pkg/types"
)
type ContainerNetworkRepo interface {
+2 -2
View File
@@ -1,8 +1,8 @@
package biz
import (
"github.com/TheTNB/panel/internal/http/request"
"github.com/TheTNB/panel/pkg/types"
"github.com/tnb-labs/panel/internal/http/request"
"github.com/tnb-labs/panel/pkg/types"
)
type ContainerVolumeRepo interface {
+1 -1
View File
@@ -3,7 +3,7 @@ package biz
import (
"time"
"github.com/TheTNB/panel/internal/http/request"
"github.com/tnb-labs/panel/internal/http/request"
)
type Cron struct {
+26 -11
View File
@@ -1,16 +1,31 @@
package biz
import "time"
import (
"github.com/tnb-labs/panel/internal/http/request"
)
type DatabaseType string
const (
DatabaseTypeMysql DatabaseType = "mysql"
DatabaseTypePostgresql DatabaseType = "postgresql"
DatabaseTypeMongoDB DatabaseType = "mongodb"
DatabaseSQLite DatabaseType = "sqlite"
DatabaseTypeRedis DatabaseType = "redis"
)
type Database struct {
ID uint `gorm:"primaryKey" json:"id"`
Name string `gorm:"not null;unique" json:"name"`
Type string `gorm:"not null" json:"type"`
Host string `gorm:"not null" json:"host"`
Port int `gorm:"not null" json:"port"`
Username string `gorm:"not null" json:"username"`
Password string `gorm:"not null" json:"password"`
Remark string `gorm:"not null" json:"remark"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
Type DatabaseType `json:"type"`
Name string `json:"name"`
Server string `json:"server"`
ServerID uint `json:"server_id"`
Encoding string `json:"encoding"`
Comment string `json:"comment"`
}
type DatabaseRepo interface {
List(page, limit uint) ([]*Database, int64, error)
Create(req *request.DatabaseCreate) error
Delete(serverID uint, name string) error
Comment(req *request.DatabaseComment) error
}
+74
View File
@@ -0,0 +1,74 @@
package biz
import (
"time"
"github.com/go-rat/utils/crypt"
"gorm.io/gorm"
"github.com/tnb-labs/panel/internal/app"
"github.com/tnb-labs/panel/internal/http/request"
)
type DatabaseServerStatus string
const (
DatabaseServerStatusValid DatabaseServerStatus = "valid"
DatabaseServerStatusInvalid DatabaseServerStatus = "invalid"
)
type DatabaseServer struct {
ID uint `gorm:"primaryKey" json:"id"`
Name string `gorm:"not null;unique" json:"name"`
Type DatabaseType `gorm:"not null" json:"type"`
Host string `gorm:"not null" json:"host"`
Port uint `gorm:"not null" json:"port"`
Username string `gorm:"not null" json:"username"`
Password string `gorm:"not null" json:"password"`
Status DatabaseServerStatus `gorm:"-:all" json:"status"`
Remark string `gorm:"not null" json:"remark"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
func (r *DatabaseServer) BeforeSave(tx *gorm.DB) error {
crypter, err := crypt.NewXChacha20Poly1305([]byte(app.Key))
if err != nil {
return err
}
r.Password, err = crypter.Encrypt([]byte(r.Password))
if err != nil {
return err
}
return nil
}
func (r *DatabaseServer) AfterFind(tx *gorm.DB) error {
crypter, err := crypt.NewXChacha20Poly1305([]byte(app.Key))
if err != nil {
return err
}
password, err := crypter.Decrypt(r.Password)
if err == nil {
r.Password = string(password)
}
return nil
}
type DatabaseServerRepo interface {
Count() (int64, error)
List(page, limit uint) ([]*DatabaseServer, int64, error)
Get(id uint) (*DatabaseServer, error)
GetByName(name string) (*DatabaseServer, error)
Create(req *request.DatabaseServerCreate) error
Update(req *request.DatabaseServerUpdate) error
UpdateRemark(req *request.DatabaseServerUpdateRemark) error
Delete(id uint) error
ClearUsers(id uint) error
Sync(id uint) error
}
+73
View File
@@ -0,0 +1,73 @@
package biz
import (
"time"
"github.com/go-rat/utils/crypt"
"gorm.io/gorm"
"github.com/tnb-labs/panel/internal/app"
"github.com/tnb-labs/panel/internal/http/request"
)
type DatabaseUserStatus string
const (
DatabaseUserStatusValid DatabaseUserStatus = "valid"
DatabaseUserStatusInvalid DatabaseUserStatus = "invalid"
)
type DatabaseUser struct {
ID uint `gorm:"primaryKey" json:"id"`
ServerID uint `gorm:"not null" json:"server_id"`
Username string `gorm:"not null" json:"username"`
Password string `gorm:"not null" json:"password"`
Host string `gorm:"not null" json:"host"` // 仅 mysql
Status DatabaseUserStatus `gorm:"-:all" json:"status"` // 仅显示
Privileges []string `gorm:"-:all" json:"privileges"` // 仅显示
Remark string `gorm:"not null" json:"remark"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
Server *DatabaseServer `gorm:"foreignKey:ServerID;references:ID" json:"server"`
}
func (r *DatabaseUser) BeforeSave(tx *gorm.DB) error {
crypter, err := crypt.NewXChacha20Poly1305([]byte(app.Key))
if err != nil {
return err
}
r.Password, err = crypter.Encrypt([]byte(r.Password))
if err != nil {
return err
}
return nil
}
func (r *DatabaseUser) AfterFind(tx *gorm.DB) error {
crypter, err := crypt.NewXChacha20Poly1305([]byte(app.Key))
if err != nil {
return err
}
password, err := crypter.Decrypt(r.Password)
if err == nil {
r.Password = string(password)
}
return nil
}
type DatabaseUserRepo interface {
Count() (int64, error)
List(page, limit uint) ([]*DatabaseUser, int64, error)
Get(id uint) (*DatabaseUser, error)
Create(req *request.DatabaseUserCreate) error
Update(req *request.DatabaseUserUpdate) error
UpdateRemark(req *request.DatabaseUserUpdateRemark) error
Delete(id uint) error
DeleteByNames(serverID uint, names []string) error
}
-4
View File
@@ -1,4 +0,0 @@
package biz
type FirewallRepo interface {
}
+2 -2
View File
@@ -3,8 +3,8 @@ package biz
import (
"time"
"github.com/TheTNB/panel/internal/http/request"
"github.com/TheTNB/panel/pkg/types"
"github.com/tnb-labs/panel/internal/http/request"
"github.com/tnb-labs/panel/pkg/types"
)
type Monitor struct {
+2 -3
View File
@@ -4,7 +4,7 @@ import (
"context"
"time"
"github.com/TheTNB/panel/internal/http/request"
"github.com/tnb-labs/panel/internal/http/request"
)
type SettingKey string
@@ -18,6 +18,7 @@ const (
SettingKeyWebsitePath SettingKey = "website_path"
SettingKeyMySQLRootPassword SettingKey = "mysql_root_password"
SettingKeyOfflineMode SettingKey = "offline_mode"
SettingKeyAutoUpdate SettingKey = "auto_update"
)
type Setting struct {
@@ -35,6 +36,4 @@ type SettingRepo interface {
Delete(key SettingKey) error
GetPanelSetting(ctx context.Context) (*request.PanelSetting, error)
UpdatePanelSetting(ctx context.Context, setting *request.PanelSetting) (bool, error)
UpdatePanel(version, url, checksum string) error
FixPanel() error
}
+43 -2
View File
@@ -3,8 +3,12 @@ package biz
import (
"time"
"github.com/TheTNB/panel/internal/http/request"
"github.com/TheTNB/panel/pkg/ssh"
"github.com/go-rat/utils/crypt"
"gorm.io/gorm"
"github.com/tnb-labs/panel/internal/app"
"github.com/tnb-labs/panel/internal/http/request"
"github.com/tnb-labs/panel/pkg/ssh"
)
type SSH struct {
@@ -18,6 +22,43 @@ type SSH struct {
UpdatedAt time.Time `json:"updated_at"`
}
func (r *SSH) BeforeSave(tx *gorm.DB) error {
crypter, err := crypt.NewXChacha20Poly1305([]byte(app.Key))
if err != nil {
return err
}
r.Config.Key, err = crypter.Encrypt([]byte(r.Config.Key))
if err != nil {
return err
}
r.Config.Password, err = crypter.Encrypt([]byte(r.Config.Password))
if err != nil {
return err
}
return nil
}
func (r *SSH) AfterFind(tx *gorm.DB) error {
crypter, err := crypt.NewXChacha20Poly1305([]byte(app.Key))
if err != nil {
return err
}
key, err := crypter.Decrypt(r.Config.Key)
if err == nil {
r.Config.Key = string(key)
}
password, err := crypter.Decrypt(r.Config.Password)
if err == nil {
r.Config.Password = string(password)
}
return nil
}
type SSHRepo interface {
List(page, limit uint) ([]*SSH, int64, error)
Get(id uint) (*SSH, error)

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