@whyour/qinglong 2.19.2-2 → 2.20.0-1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (107) hide show
  1. package/.env.example +1 -2
  2. package/README-en.md +4 -2
  3. package/README.md +4 -2
  4. package/back/protos/api.proto +17 -0
  5. package/docker/310.Dockerfile +23 -6
  6. package/docker/Dockerfile +22 -6
  7. package/docker/docker-entrypoint.sh +27 -14
  8. package/package.json +8 -9
  9. package/sample/notify.js +18 -2
  10. package/sample/notify.py +15 -0
  11. package/sample/ql_sample.js +28 -0
  12. package/shell/api.sh +8 -48
  13. package/shell/check.sh +5 -22
  14. package/shell/preload/client.js +6 -1
  15. package/shell/pub.sh +4 -4
  16. package/shell/share.sh +32 -55
  17. package/shell/task.sh +19 -10
  18. package/shell/update.sh +1 -0
  19. package/static/build/api/dependence.js +7 -1
  20. package/static/build/api/env.js +30 -4
  21. package/static/build/api/script.js +47 -8
  22. package/static/build/api/subscription.js +3 -3
  23. package/static/build/api/system.js +19 -26
  24. package/static/build/api/user.js +2 -1
  25. package/static/build/app.js +96 -18
  26. package/static/build/config/index.js +2 -2
  27. package/static/build/config/util.js +24 -1
  28. package/static/build/data/cron.js +4 -0
  29. package/static/build/data/env.js +3 -1
  30. package/static/build/data/notify.js +1 -0
  31. package/static/build/loaders/db.js +29 -35
  32. package/static/build/loaders/deps.js +22 -5
  33. package/static/build/loaders/express.js +19 -10
  34. package/static/build/loaders/initData.js +25 -1
  35. package/static/build/loaders/initTask.js +6 -0
  36. package/static/build/loaders/sock.js +10 -12
  37. package/static/build/protos/api.js +336 -1
  38. package/static/build/schedule/addCron.js +2 -2
  39. package/static/build/schedule/api.js +100 -1
  40. package/static/build/schedule/delCron.js +1 -1
  41. package/static/build/schedule/health.js +2 -3
  42. package/static/build/services/cron.js +54 -20
  43. package/static/build/services/dependence.js +6 -5
  44. package/static/build/services/env.js +9 -2
  45. package/static/build/services/notify.js +17 -5
  46. package/static/build/services/schedule.js +4 -4
  47. package/static/build/services/sshKey.js +24 -4
  48. package/static/build/services/subscription.js +11 -8
  49. package/static/build/services/system.js +15 -0
  50. package/static/build/services/user.js +83 -4
  51. package/static/build/shared/auth.js +40 -0
  52. package/static/build/shared/logStreamManager.js +104 -0
  53. package/static/build/shared/runCron.js +23 -0
  54. package/static/build/validation/schedule.js +39 -2
  55. package/static/dist/1147.856bb861.async.js +1 -0
  56. package/static/dist/1379.f91563a1.async.js +1 -0
  57. package/static/dist/{2208.3bc521b1.async.js → 2208.7bf7e296.async.js} +1 -1
  58. package/static/dist/3191.da7f3e07.async.js +1 -0
  59. package/static/dist/5691.931f59c5.async.js +1 -0
  60. package/static/dist/7571.4f6240b1.async.js +1 -0
  61. package/static/dist/{8826.3ab4ad84.async.js → 8826.5f289c4d.async.js} +1 -1
  62. package/static/dist/index.html +2 -2
  63. package/static/dist/preload_helper.17d7028f.js +1 -0
  64. package/static/dist/{src__pages__crontab__detail.ee431270.async.js → src__pages__crontab__detail.b07f0c0a.async.js} +1 -1
  65. package/static/dist/src__pages__crontab__index.6b90d8c5.async.js +1 -0
  66. package/static/dist/{src__pages__crontab__logModal.57501983.async.js → src__pages__crontab__logModal.5e6a4bf2.async.js} +1 -1
  67. package/static/dist/src__pages__crontab__modal.2d3d4953.async.js +1 -0
  68. package/static/dist/src__pages__dependence__modal.86604072.async.js +1 -0
  69. package/static/dist/{src__pages__env__editNameModal.665393cd.async.js → src__pages__env__editNameModal.79b7cf83.async.js} +1 -1
  70. package/static/dist/src__pages__env__index.a0a2fece.async.js +1 -0
  71. package/static/dist/{src__pages__env__modal.168498f9.async.js → src__pages__env__modal.b84c1173.async.js} +1 -1
  72. package/static/dist/{src__pages__error__index.d9beeda3.async.js → src__pages__error__index.01fac00e.async.js} +1 -1
  73. package/static/dist/{src__pages__initialization__index.2403c031.async.js → src__pages__initialization__index.2e49cf43.async.js} +1 -1
  74. package/static/dist/{src__pages__script__editNameModal.e36cd111.async.js → src__pages__script__editNameModal.05441c89.async.js} +1 -1
  75. package/static/dist/{src__pages__script__index.82b42e11.async.js → src__pages__script__index.6a23d7b5.async.js} +1 -1
  76. package/static/dist/{src__pages__script__renameModal.f9756f26.async.js → src__pages__script__renameModal.3bb00014.async.js} +1 -1
  77. package/static/dist/{src__pages__script__saveModal.e885e133.async.js → src__pages__script__saveModal.03cc698b.async.js} +1 -1
  78. package/static/dist/{src__pages__script__setting.8c2727b4.async.js → src__pages__script__setting.5a2a2a2c.async.js} +1 -1
  79. package/static/dist/{src__pages__setting__appModal.5a39121e.async.js → src__pages__setting__appModal.7f763fa7.async.js} +1 -1
  80. package/static/dist/src__pages__setting__dependence.e64c4554.async.js +1 -0
  81. package/static/dist/src__pages__setting__index.3a220288.async.js +1 -0
  82. package/static/dist/src__pages__setting__notification.49003b2f.async.js +1 -0
  83. package/static/dist/src__pages__setting__other.0d931d6f.async.js +1 -0
  84. package/static/dist/src__pages__setting__security.a916e056.async.js +1 -0
  85. package/static/dist/{src__pages__setting__systemLog.fc5bdc78.async.js → src__pages__setting__systemLog.cbb0a3bb.async.js} +1 -1
  86. package/static/dist/src__pages__subscription__modal.ade477c1.async.js +1 -0
  87. package/static/dist/umi.ba9d6227.js +1 -0
  88. package/version.yaml +46 -9
  89. package/docker/front.conf +0 -61
  90. package/docker/nginx.conf +0 -45
  91. package/static/dist/2995.2eb218b3.async.js +0 -1
  92. package/static/dist/3191.cc1e31cd.async.js +0 -1
  93. package/static/dist/4046.7fbcfa02.async.js +0 -1
  94. package/static/dist/5713.8519f547.async.js +0 -1
  95. package/static/dist/8851.503b1e64.async.js +0 -1
  96. package/static/dist/preload_helper.9c086410.js +0 -1
  97. package/static/dist/src__pages__crontab__index.af4cb04a.async.js +0 -1
  98. package/static/dist/src__pages__crontab__modal.21258e08.async.js +0 -1
  99. package/static/dist/src__pages__dependence__modal.6639424a.async.js +0 -1
  100. package/static/dist/src__pages__env__index.70340ba7.async.js +0 -1
  101. package/static/dist/src__pages__setting__dependence.a46e873d.async.js +0 -1
  102. package/static/dist/src__pages__setting__index.9be4775c.async.js +0 -1
  103. package/static/dist/src__pages__setting__notification.299f6b96.async.js +0 -1
  104. package/static/dist/src__pages__setting__other.60924a56.async.js +0 -1
  105. package/static/dist/src__pages__setting__security.e7371daa.async.js +0 -1
  106. package/static/dist/src__pages__subscription__modal.a7fd6a3c.async.js +0 -1
  107. package/static/dist/umi.5b8ae363.js +0 -1
package/.env.example CHANGED
@@ -1,6 +1,5 @@
1
1
  GRPC_PORT=5500
2
- BACK_PORT=5600
3
- PORT=5700
2
+ BACK_PORT=5700
4
3
 
5
4
  LOG_LEVEL='info'
6
5
 
package/README-en.md CHANGED
@@ -18,9 +18,9 @@ Timed task management platform supporting Python3, JavaScript, Shell, Typescript
18
18
  [docker-image-size-image]: https://img.shields.io/docker/image-size/whyour/qinglong?style=flat
19
19
  [docker-image-size-url]: https://hub.docker.com/r/whyour/qinglong
20
20
 
21
- [Demo](http://demo.ninesix.cc:4433/) / [Issues](https://github.com/whyour/qinglong/issues) / [Telegram Channel](https://t.me/jiao_long) / [Buy Me a Coffee](https://www.buymeacoffee.com/qinglong)
21
+ [Demo](http://demo.qinglong.online:4433/) / [Issues](https://github.com/whyour/qinglong/issues) / [Telegram Channel](https://t.me/jiao_long) / [Buy Me a Coffee](https://www.buymeacoffee.com/qinglong)
22
22
 
23
- [演示](http://demo.ninesix.cc:4433/) / [反馈](https://github.com/whyour/qinglong/issues) / [Telegram 频道](https://t.me/jiao_long) / [打赏开发者](https://user-images.githubusercontent.com/22700758/244744295-29cd0cd1-c8bb-4ea1-adf6-29bd390ad4dd.jpg)
23
+ [演示](http://demo.qinglong.online:4433/) / [反馈](https://github.com/whyour/qinglong/issues) / [Telegram 频道](https://t.me/jiao_long) / [打赏开发者](https://user-images.githubusercontent.com/22700758/244744295-29cd0cd1-c8bb-4ea1-adf6-29bd390ad4dd.jpg)
24
24
  </div>
25
25
 
26
26
  ![cover](https://user-images.githubusercontent.com/22700758/244847235-8dc1ca21-e03f-4606-9458-0541fab60413.png)
@@ -41,6 +41,8 @@ Timed task management platform supporting Python3, JavaScript, Shell, Typescript
41
41
 
42
42
  The `latest` image is built on `alpine` and the `debian` image is built on `debian-slim`. If you need to use a dependency that is not supported by `alpine`, it is recommended that you use the `debian` image.
43
43
 
44
+ **⚠️ Important**: If you need to run Docker as a **non-root user**, please use the `debian` image. Alpine's `crond` requires root privileges.
45
+
44
46
  ```bash
45
47
  docker pull whyour/qinglong:latest
46
48
  docker pull whyour/qinglong:debian
package/README.md CHANGED
@@ -20,9 +20,9 @@ Timed task management platform supporting Python3, JavaScript, Shell, Typescript
20
20
  [docker-image-size-image]: https://img.shields.io/docker/image-size/whyour/qinglong?style=flat
21
21
  [docker-image-size-url]: https://hub.docker.com/r/whyour/qinglong
22
22
 
23
- [Demo](http://demo.ninesix.cc:4433/) / [Issues](https://github.com/whyour/qinglong/issues) / [Telegram Channel](https://t.me/jiao_long) / [Buy Me a Coffee](https://www.buymeacoffee.com/qinglong)
23
+ [Demo](http://demo.qinglong.online:4433/) / [Issues](https://github.com/whyour/qinglong/issues) / [Telegram Channel](https://t.me/jiao_long) / [Buy Me a Coffee](https://www.buymeacoffee.com/qinglong)
24
24
 
25
- [演示](http://demo.ninesix.cc:4433/) / [反馈](https://github.com/whyour/qinglong/issues) / [Telegram 频道](https://t.me/jiao_long) / [打赏开发者](https://user-images.githubusercontent.com/22700758/244744295-29cd0cd1-c8bb-4ea1-adf6-29bd390ad4dd.jpg)
25
+ [演示](http://demo.qinglong.online:4433/) / [反馈](https://github.com/whyour/qinglong/issues) / [Telegram 频道](https://t.me/jiao_long) / [打赏开发者](https://user-images.githubusercontent.com/22700758/244744295-29cd0cd1-c8bb-4ea1-adf6-29bd390ad4dd.jpg)
26
26
  </div>
27
27
 
28
28
  ![cover](https://user-images.githubusercontent.com/22700758/244847235-8dc1ca21-e03f-4606-9458-0541fab60413.png)
@@ -43,6 +43,8 @@ Timed task management platform supporting Python3, JavaScript, Shell, Typescript
43
43
 
44
44
  `latest` 镜像是基于 `alpine` 构建,`debian` 镜像是基于 `debian-slim` 构建。如果需要使用 `alpine` 不支持的依赖,建议使用 `debian` 镜像
45
45
 
46
+ **⚠️ 重要提示**: 如果您需要以**非 root 用户**运行 Docker,请使用 `debian` 镜像。Alpine 的 `crond` 需要 root 权限。
47
+
46
48
  ```bash
47
49
  docker pull whyour/qinglong:latest
48
50
  docker pull whyour/qinglong:debian
@@ -97,6 +97,18 @@ message UpdateCronRequest {
97
97
 
98
98
  message DeleteCronsRequest { repeated int32 ids = 1; }
99
99
 
100
+ message GetCronsRequest {
101
+ optional string searchValue = 1;
102
+ }
103
+
104
+ message GetCronByIdRequest { int32 id = 1; }
105
+
106
+ message EnableCronsRequest { repeated int32 ids = 1; }
107
+
108
+ message DisableCronsRequest { repeated int32 ids = 1; }
109
+
110
+ message RunCronsRequest { repeated int32 ids = 1; }
111
+
100
112
  message CronsResponse {
101
113
  int32 code = 1;
102
114
  repeated CronItem data = 2;
@@ -254,4 +266,9 @@ service Api {
254
266
  rpc CreateCron(CreateCronRequest) returns (CronResponse) {}
255
267
  rpc UpdateCron(UpdateCronRequest) returns (CronResponse) {}
256
268
  rpc DeleteCrons(DeleteCronsRequest) returns (Response) {}
269
+ rpc GetCrons(GetCronsRequest) returns (CronsResponse) {}
270
+ rpc GetCronById(GetCronByIdRequest) returns (CronResponse) {}
271
+ rpc EnableCrons(EnableCronsRequest) returns (Response) {}
272
+ rpc DisableCrons(DisableCronsRequest) returns (Response) {}
273
+ rpc RunCrons(RunCronsRequest) returns (Response) {}
257
274
  }
@@ -26,6 +26,17 @@ ENV QL_DIR=/ql \
26
26
  SHELL=/bin/bash \
27
27
  PS1="\u@\h:\w \$ "
28
28
 
29
+ ARG QL_UID=5432
30
+ ARG QL_GID=5432
31
+ RUN groupadd -g ${QL_GID} qinglong && \
32
+ useradd -m -u ${QL_UID} -g ${QL_GID} -s /bin/bash qinglong && \
33
+ mkdir -p /home/qinglong/bin /home/qinglong/.ssh && \
34
+ chmod 700 /home/qinglong/.ssh && \
35
+ chown -R ${QL_UID}:${QL_GID} /home/qinglong
36
+
37
+ ENV QL_USER=qinglong
38
+ ENV QL_HOME=/home/$QL_USER
39
+
29
40
  COPY --from=nodebuilder /usr/local/bin/node /usr/local/bin/
30
41
  COPY --from=nodebuilder /usr/local/lib/node_modules/. /usr/local/lib/node_modules/
31
42
 
@@ -40,7 +51,6 @@ RUN set -x && \
40
51
  perl \
41
52
  openssl \
42
53
  openssh-client \
43
- nginx \
44
54
  jq \
45
55
  procps \
46
56
  netcat-openbsd \
@@ -58,16 +68,21 @@ RUN set -x && \
58
68
  rm -rf /etc/apt/apt.conf.d/docker-clean && \
59
69
  ulimit -c 0
60
70
 
71
+ RUN mkdir -p ${QL_DIR} && \
72
+ chown -R ${QL_UID}:${QL_GID} ${QL_DIR}
73
+
74
+ USER qinglong
75
+
61
76
  ARG SOURCE_COMMIT
62
77
  RUN git clone --depth=1 -b ${QL_BRANCH} ${QL_URL} ${QL_DIR} && \
63
78
  cd ${QL_DIR} && \
64
79
  cp -f .env.example .env && \
65
80
  chmod 777 ${QL_DIR}/shell/*.sh && \
66
81
  chmod 777 ${QL_DIR}/docker/*.sh && \
67
- git clone --depth=1 -b ${QL_BRANCH} https://github.com/${QL_MAINTAINER}/qinglong-static.git /static && \
82
+ git clone --depth=1 -b ${QL_BRANCH} https://github.com/${QL_MAINTAINER}/qinglong-static.git /tmp/static && \
68
83
  mkdir -p ${QL_DIR}/static && \
69
- cp -rf /static/* ${QL_DIR}/static && \
70
- rm -rf /static
84
+ cp -rf /tmp/static/* ${QL_DIR}/static && \
85
+ rm -rf /tmp/static
71
86
 
72
87
  ENV PNPM_HOME=${QL_DIR}/data/dep_cache/node \
73
88
  PYTHON_HOME=${QL_DIR}/data/dep_cache/python3 \
@@ -80,12 +95,14 @@ ENV PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:${PNPM_HOM
80
95
 
81
96
  RUN pip3 install --prefix ${PYTHON_HOME} requests
82
97
 
83
- COPY --from=builder /tmp/build/node_modules/. /ql/node_modules/
98
+ COPY --chown=qinglong:qinglong --from=builder /tmp/build/node_modules/. /ql/node_modules/
99
+
100
+ USER root
84
101
 
85
102
  WORKDIR ${QL_DIR}
86
103
 
87
104
  HEALTHCHECK --interval=5s --timeout=2s --retries=20 \
88
- CMD curl -sf --noproxy '*' http://127.0.0.1:5600/api/health || exit 1
105
+ CMD curl -sf --noproxy '*' http://127.0.0.1:5700/api/health || exit 1
89
106
 
90
107
  ENTRYPOINT ["./docker/docker-entrypoint.sh"]
91
108
 
package/docker/Dockerfile CHANGED
@@ -26,6 +26,17 @@ ENV QL_DIR=/ql \
26
26
  SHELL=/bin/bash \
27
27
  PS1="\u@\h:\w \$ "
28
28
 
29
+ ARG QL_UID=5432
30
+ ARG QL_GID=5432
31
+ RUN groupadd -g ${QL_GID} qinglong && \
32
+ useradd -m -u ${QL_UID} -g ${QL_GID} -s /bin/bash qinglong && \
33
+ mkdir -p /home/qinglong/bin /home/qinglong/.ssh && \
34
+ chmod 700 /home/qinglong/.ssh && \
35
+ chown -R ${QL_UID}:${QL_GID} /home/qinglong
36
+
37
+ ENV QL_USER=qinglong
38
+ ENV QL_HOME=/home/$QL_USER
39
+
29
40
  COPY --from=nodebuilder /usr/local/bin/node /usr/local/bin/
30
41
  COPY --from=nodebuilder /usr/local/lib/node_modules/. /usr/local/lib/node_modules/
31
42
 
@@ -41,7 +52,6 @@ RUN set -x && \
41
52
  perl \
42
53
  openssl \
43
54
  openssh-client \
44
- nginx \
45
55
  jq \
46
56
  procps \
47
57
  netcat-openbsd \
@@ -59,16 +69,20 @@ RUN set -x && \
59
69
  rm -rf /etc/apt/apt.conf.d/docker-clean && \
60
70
  ulimit -c 0
61
71
 
72
+ RUN mkdir -p ${QL_DIR} && \
73
+ chown -R ${QL_UID}:${QL_GID} ${QL_DIR}
74
+
75
+ USER qinglong
62
76
  ARG SOURCE_COMMIT
63
77
  RUN git clone --depth=1 -b ${QL_BRANCH} ${QL_URL} ${QL_DIR} && \
64
78
  cd ${QL_DIR} && \
65
79
  cp -f .env.example .env && \
66
80
  chmod 777 ${QL_DIR}/shell/*.sh && \
67
81
  chmod 777 ${QL_DIR}/docker/*.sh && \
68
- git clone --depth=1 -b ${QL_BRANCH} https://github.com/${QL_MAINTAINER}/qinglong-static.git /static && \
82
+ git clone --depth=1 -b ${QL_BRANCH} https://github.com/${QL_MAINTAINER}/qinglong-static.git /tmp/static && \
69
83
  mkdir -p ${QL_DIR}/static && \
70
- cp -rf /static/* ${QL_DIR}/static && \
71
- rm -rf /static
84
+ cp -rf /tmp/static/* ${QL_DIR}/static && \
85
+ rm -rf /tmp/static
72
86
 
73
87
  ENV PNPM_HOME=${QL_DIR}/data/dep_cache/node \
74
88
  PYTHON_HOME=${QL_DIR}/data/dep_cache/python3 \
@@ -81,12 +95,14 @@ ENV PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:${PNPM_HOM
81
95
 
82
96
  RUN pip3 install --prefix ${PYTHON_HOME} requests
83
97
 
84
- COPY --from=builder /tmp/build/node_modules/. /ql/node_modules/
98
+ COPY --chown=qinglong:qinglong --from=builder /tmp/build/node_modules/. /ql/node_modules/
99
+
100
+ USER root
85
101
 
86
102
  WORKDIR ${QL_DIR}
87
103
 
88
104
  HEALTHCHECK --interval=5s --timeout=2s --retries=20 \
89
- CMD curl -sf --noproxy '*' http://127.0.0.1:5600/api/health || exit 1
105
+ CMD curl -sf --noproxy '*' http://127.0.0.1:5700/api/health || exit 1
90
106
 
91
107
  ENTRYPOINT ["./docker/docker-entrypoint.sh"]
92
108
 
@@ -1,43 +1,56 @@
1
1
  #!/bin/bash
2
2
 
3
+ export PATH="$HOME/bin:$PATH"
4
+
3
5
  dir_shell=/ql/shell
4
6
  . $dir_shell/share.sh
5
- . $dir_shell/env.sh
7
+
8
+ export_ql_envs() {
9
+ export BACK_PORT="${ql_port}"
10
+ export GRPC_PORT="${ql_grpc_port}"
11
+ }
6
12
 
7
13
  log_with_style() {
8
14
  local level="$1"
9
15
  local message="$2"
10
16
  local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
11
-
12
17
  printf "\n[%s] [%7s] %s\n" "${timestamp}" "${level}" "${message}"
13
18
  }
14
19
 
15
- log_with_style "INFO" "🚀 1. 检测配置文件..."
20
+ # Fix DNS resolution issues in Alpine Linux
21
+ # Alpine uses musl libc which has known DNS resolver issues with certain domains
22
+ # Adding ndots:0 prevents unnecessary search domain appending
23
+ if [ -f /etc/alpine-release ]; then
24
+ if ! grep -q "^options ndots:0" /etc/resolv.conf 2>/dev/null; then
25
+ echo "options ndots:0" >> /etc/resolv.conf
26
+ log_with_style "INFO" "🔧 0. 已配置 DNS 解析优化 (ndots:0)"
27
+ fi
28
+ fi
29
+
30
+ log_with_style "INFO" "🚀 1. 检测配置文件..."
31
+ load_ql_envs
32
+ export_ql_envs
33
+ . $dir_shell/env.sh
16
34
  import_config "$@"
17
- make_dir /etc/nginx/conf.d
18
- make_dir /run/nginx
19
- init_nginx
20
35
  fix_config
21
36
 
22
- pm2 l &>/dev/null
23
-
24
- log_with_style "INFO" "🔄 2. 启动 nginx..."
25
- nginx -s reload 2>/dev/null || nginx -c /etc/nginx/nginx.conf
37
+ # Try to initialize PM2, but don't fail if it doesn't work
38
+ pm2 l &>/dev/null || log_with_style "WARN" "PM2 初始化可能失败,将在启动时尝试使用备用方案"
26
39
 
27
- log_with_style "INFO" "⚙️ 3. 启动 pm2 服务..."
40
+ log_with_style "INFO" "⚙️ 2. 启动 pm2 服务..."
28
41
  reload_pm2
29
42
 
30
43
  if [[ $AutoStartBot == true ]]; then
31
- log_with_style "INFO" "🤖 4. 启动 bot..."
44
+ log_with_style "INFO" "🤖 3. 启动 bot..."
32
45
  nohup ql bot >$dir_log/bot.log 2>&1 &
33
46
  fi
34
47
 
35
48
  if [[ $EnableExtraShell == true ]]; then
36
- log_with_style "INFO" "🛠️ 5. 执行自定义脚本..."
49
+ log_with_style "INFO" "🛠️ 4. 执行自定义脚本..."
37
50
  nohup ql extra >$dir_log/extra.log 2>&1 &
38
51
  fi
39
52
 
40
- log_with_style "SUCCESS" "🎉 容器启动成功!"
53
+ log_with_style "SUCCESS" "🎉 容器启动成功!"
41
54
 
42
55
  tail -f /dev/null
43
56
 
package/package.json CHANGED
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "name": "@whyour/qinglong",
3
- "version": "2.19.2-2",
3
+ "packageManager": "pnpm@8.3.1",
4
+ "version": "2.20.0-1",
4
5
  "description": "Timed task management platform supporting Python3, JavaScript, Shell, Typescript",
5
6
  "repository": {
6
7
  "type": "git",
@@ -13,13 +14,12 @@
13
14
  },
14
15
  "scripts": {
15
16
  "start": "concurrently -n w: npm:start:*",
16
- "start:back": "nodemon",
17
+ "start:back": "nodemon ./back/app.ts",
17
18
  "start:front": "max dev",
18
19
  "build:front": "max build",
19
20
  "build:back": "tsc -p back/tsconfig.json",
20
21
  "panel": "npm run build:back && node static/build/app.js",
21
22
  "gen:proto": "protoc --experimental_allow_proto3_optional --plugin=./node_modules/.bin/protoc-gen-ts_proto ./back/protos/*.proto --ts_proto_out=./ --ts_proto_opt=outputServices=grpc-js,env=node,esModuleInterop=true,snakeToCamel=false",
22
- "gen:api": "python3 -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. ./back/protos/api.proto",
23
23
  "prettier": "prettier --write '**/*.{js,jsx,tsx,ts,less,md,json}'",
24
24
  "postinstall": "max setup 2>/dev/null || true",
25
25
  "test": "umi-test",
@@ -71,14 +71,14 @@
71
71
  }
72
72
  },
73
73
  "dependencies": {
74
- "@grpc/grpc-js": "^1.12.3",
75
- "@grpc/proto-loader": "^0.7.13",
74
+ "@grpc/grpc-js": "^1.14.0",
75
+ "@grpc/proto-loader": "^0.8.0",
76
76
  "@otplib/preset-default": "^12.0.1",
77
77
  "body-parser": "^1.20.3",
78
78
  "celebrate": "^15.0.3",
79
79
  "chokidar": "^4.0.1",
80
80
  "cors": "^2.8.5",
81
- "cron-parser": "^4.9.0",
81
+ "cron-parser": "^5.4.0",
82
82
  "cross-spawn": "^7.0.6",
83
83
  "dayjs": "^1.11.13",
84
84
  "dotenv": "^16.4.6",
@@ -97,11 +97,10 @@
97
97
  "node-schedule": "^2.1.0",
98
98
  "nodemailer": "^6.9.16",
99
99
  "p-queue-cjs": "7.3.4",
100
- "@bufbuild/protobuf": "^2.2.3",
100
+ "@bufbuild/protobuf": "^2.10.0",
101
101
  "ps-tree": "^1.2.0",
102
102
  "reflect-metadata": "^0.2.2",
103
103
  "sequelize": "^6.37.5",
104
- "serve-handler": "^6.1.6",
105
104
  "sockjs": "^0.3.24",
106
105
  "sqlite3": "git+https://github.com/whyour/node-sqlite3.git#v1.0.3",
107
106
  "toad-scheduler": "^3.0.1",
@@ -115,7 +114,7 @@
115
114
  "@keyv/sqlite": "^4.0.1",
116
115
  "proper-lockfile": "^4.1.2",
117
116
  "compression": "^1.7.4",
118
- "helmet": "^6.0.1"
117
+ "helmet": "^8.1.0"
119
118
  },
120
119
  "devDependencies": {
121
120
  "moment": "2.30.1",
package/sample/notify.js CHANGED
@@ -52,6 +52,7 @@ const push_config = {
52
52
  DD_BOT_TOKEN: '', // 钉钉机器人的 DD_BOT_TOKEN
53
53
 
54
54
  FSKEY: '', // 飞书机器人的 FSKEY
55
+ FSSECRET: '', // 飞书机器人的 FSSECRET,对应安全设置里的签名校验密钥
55
56
 
56
57
  // 推送到个人QQ:http://127.0.0.1/send_private_msg
57
58
  // 群:http://127.0.0.1/send_group_msg
@@ -989,11 +990,26 @@ function aibotkNotify(text, desp) {
989
990
 
990
991
  function fsBotNotify(text, desp) {
991
992
  return new Promise((resolve) => {
992
- const { FSKEY } = push_config;
993
+ const { FSKEY, FSSECRET } = push_config;
993
994
  if (FSKEY) {
995
+ const body = { msg_type: 'text', content: { text: `${text}\n\n${desp}` } };
996
+
997
+ // Add signature if secret is provided
998
+ // Note: Feishu's signature algorithm uses timestamp+"\n"+secret as the HMAC key
999
+ // and signs an empty message, which differs from typical HMAC usage
1000
+ if (FSSECRET) {
1001
+ const crypto = require('crypto');
1002
+ const timestamp = Math.floor(Date.now() / 1000).toString();
1003
+ const stringToSign = `${timestamp}\n${FSSECRET}`;
1004
+ const hmac = crypto.createHmac('sha256', stringToSign);
1005
+ const sign = hmac.digest('base64');
1006
+ body.timestamp = timestamp;
1007
+ body.sign = sign;
1008
+ }
1009
+
994
1010
  const options = {
995
1011
  url: `https://open.feishu.cn/open-apis/bot/v2/hook/${FSKEY}`,
996
- json: { msg_type: 'text', content: { text: `${text}\n\n${desp}` } },
1012
+ json: body,
997
1013
  headers: {
998
1014
  'Content-Type': 'application/json',
999
1015
  },
package/sample/notify.py CHANGED
@@ -49,6 +49,7 @@ push_config = {
49
49
  'DD_BOT_TOKEN': '', # 钉钉机器人的 DD_BOT_TOKEN
50
50
 
51
51
  'FSKEY': '', # 飞书机器人的 FSKEY
52
+ 'FSSECRET': '', # 飞书机器人的 FSSECRET,对应安全设置里的签名校验密钥
52
53
 
53
54
  'GOBOT_URL': '', # go-cqhttp
54
55
  # 推送到个人QQ:http://127.0.0.1/send_private_msg
@@ -233,6 +234,20 @@ def feishu_bot(title: str, content: str) -> None:
233
234
 
234
235
  url = f'https://open.feishu.cn/open-apis/bot/v2/hook/{push_config.get("FSKEY")}'
235
236
  data = {"msg_type": "text", "content": {"text": f"{title}\n\n{content}"}}
237
+
238
+ # Add signature if secret is provided
239
+ # Note: Feishu's signature algorithm uses timestamp+"\n"+secret as the HMAC key
240
+ # and signs an empty message, which differs from typical HMAC usage
241
+ if push_config.get("FSSECRET"):
242
+ timestamp = str(int(time.time()))
243
+ string_to_sign = f'{timestamp}\n{push_config.get("FSSECRET")}'
244
+ hmac_code = hmac.new(
245
+ string_to_sign.encode("utf-8"), digestmod=hashlib.sha256
246
+ ).digest()
247
+ sign = base64.b64encode(hmac_code).decode("utf-8")
248
+ data["timestamp"] = timestamp
249
+ data["sign"] = sign
250
+
236
251
  response = requests.post(url, data=json.dumps(data)).json()
237
252
 
238
253
  if response.get("StatusCode") == 0 or response.get("code") == 0:
@@ -12,4 +12,32 @@ QLAPI.getEnvs({ searchValue: 'dddd' }).then((x) => {
12
12
  QLAPI.systemNotify({ title: '123', content: '231' }).then((x) => {
13
13
  console.log('systemNotify', x);
14
14
  });
15
+
16
+ // 查询定时任务 (Query cron tasks)
17
+ QLAPI.getCrons({ searchValue: 'test' }).then((x) => {
18
+ console.log('getCrons', x);
19
+ });
20
+
21
+ // 通过ID查询定时任务 (Get cron by ID)
22
+ QLAPI.getCronById({ id: 1 }).then((x) => {
23
+ console.log('getCronById', x);
24
+ }).catch((err) => {
25
+ console.log('getCronById error', err);
26
+ });
27
+
28
+ // 启用定时任务 (Enable cron tasks)
29
+ QLAPI.enableCrons({ ids: [1, 2] }).then((x) => {
30
+ console.log('enableCrons', x);
31
+ });
32
+
33
+ // 禁用定时任务 (Disable cron tasks)
34
+ QLAPI.disableCrons({ ids: [1, 2] }).then((x) => {
35
+ console.log('disableCrons', x);
36
+ });
37
+
38
+ // 手动执行定时任务 (Run cron tasks manually)
39
+ QLAPI.runCrons({ ids: [1] }).then((x) => {
40
+ console.log('runCrons', x);
41
+ });
42
+
15
43
  console.log('test desc');
package/shell/api.sh CHANGED
@@ -41,14 +41,9 @@ add_cron_api() {
41
41
  fi
42
42
 
43
43
  local api=$(
44
- curl -s --noproxy "*" "http://0.0.0.0:5600/open/crons?t=$currentTimeStamp" \
45
- -H "Accept: application/json" \
44
+ curl -s --noproxy "*" "http://0.0.0.0:${ql_port}/open/crons?t=$currentTimeStamp" \
46
45
  -H "Authorization: Bearer ${__ql_token__}" \
47
- -H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 11_2_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36" \
48
46
  -H "Content-Type: application/json;charset=UTF-8" \
49
- -H "Origin: http://0.0.0.0:5700" \
50
- -H "Referer: http://0.0.0.0:5700/crontab" \
51
- -H "Accept-Language: en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7" \
52
47
  --data-raw "{\"name\":\"${name//\"/\\\"}\",\"command\":\"${command//\"/\\\"}\",\"schedule\":\"$schedule\",\"sub_id\":$sub_id}" \
53
48
  --compressed
54
49
  )
@@ -76,15 +71,10 @@ update_cron_api() {
76
71
  fi
77
72
 
78
73
  local api=$(
79
- curl -s --noproxy "*" "http://0.0.0.0:5600/open/crons?t=$currentTimeStamp" \
74
+ curl -s --noproxy "*" "http://0.0.0.0:${ql_port}/open/crons?t=$currentTimeStamp" \
80
75
  -X 'PUT' \
81
- -H "Accept: application/json" \
82
76
  -H "Authorization: Bearer ${__ql_token__}" \
83
- -H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 11_2_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36" \
84
77
  -H "Content-Type: application/json;charset=UTF-8" \
85
- -H "Origin: http://0.0.0.0:5700" \
86
- -H "Referer: http://0.0.0.0:5700/crontab" \
87
- -H "Accept-Language: en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7" \
88
78
  --data-raw "{\"name\":\"${name//\"/\\\"}\",\"command\":\"${command//\"/\\\"}\",\"schedule\":\"$schedule\",\"id\":\"$id\"}" \
89
79
  --compressed
90
80
  )
@@ -108,15 +98,10 @@ update_cron_command_api() {
108
98
  fi
109
99
 
110
100
  local api=$(
111
- curl -s --noproxy "*" "http://0.0.0.0:5600/open/crons?t=$currentTimeStamp" \
101
+ curl -s --noproxy "*" "http://0.0.0.0:${ql_port}/open/crons?t=$currentTimeStamp" \
112
102
  -X 'PUT' \
113
- -H "Accept: application/json" \
114
103
  -H "Authorization: Bearer ${__ql_token__}" \
115
- -H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 11_2_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36" \
116
104
  -H "Content-Type: application/json;charset=UTF-8" \
117
- -H "Origin: http://0.0.0.0:5700" \
118
- -H "Referer: http://0.0.0.0:5700/crontab" \
119
- -H "Accept-Language: en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7" \
120
105
  --data-raw "{\"command\":\"${command//\"/\\\"}\",\"id\":\"$id\"}" \
121
106
  --compressed
122
107
  )
@@ -133,15 +118,10 @@ del_cron_api() {
133
118
  local ids="$1"
134
119
  local currentTimeStamp=$(date +%s)
135
120
  local api=$(
136
- curl -s --noproxy "*" "http://0.0.0.0:5600/open/crons?t=$currentTimeStamp" \
121
+ curl -s --noproxy "*" "http://0.0.0.0:${ql_port}/open/crons?t=$currentTimeStamp" \
137
122
  -X 'DELETE' \
138
- -H "Accept: application/json" \
139
123
  -H "Authorization: Bearer ${__ql_token__}" \
140
- -H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 11_2_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36" \
141
124
  -H "Content-Type: application/json;charset=UTF-8" \
142
- -H "Origin: http://0.0.0.0:5700" \
143
- -H "Referer: http://0.0.0.0:5700/crontab" \
144
- -H "Accept-Language: en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7" \
145
125
  --data-raw "[$ids]" \
146
126
  --compressed
147
127
  )
@@ -163,15 +143,10 @@ update_cron() {
163
143
  local runningTime="${6:-0}"
164
144
  local currentTimeStamp=$(date +%s)
165
145
  local api=$(
166
- curl -s --noproxy "*" "http://0.0.0.0:5600/open/crons/status?t=$currentTimeStamp" \
146
+ curl -s --noproxy "*" "http://0.0.0.0:${ql_port}/open/crons/status?t=$currentTimeStamp" \
167
147
  -X 'PUT' \
168
- -H "Accept: application/json" \
169
148
  -H "Authorization: Bearer ${__ql_token__}" \
170
- -H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 11_2_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36" \
171
149
  -H "Content-Type: application/json;charset=UTF-8" \
172
- -H "Origin: http://0.0.0.0:5700" \
173
- -H "Referer: http://0.0.0.0:5700/crontab" \
174
- -H "Accept-Language: en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7" \
175
150
  --data-raw "{\"ids\":[$ids],\"status\":\"$status\",\"pid\":\"$pid\",\"log_path\":\"$logPath\",\"last_execution_time\":$lastExecutingTime,\"last_running_time\":$runningTime}" \
176
151
  --compressed
177
152
  )
@@ -190,15 +165,10 @@ notify_api() {
190
165
  local content="$2"
191
166
  local currentTimeStamp=$(date +%s)
192
167
  local api=$(
193
- curl -s --noproxy "*" "http://0.0.0.0:5600/open/system/notify?t=$currentTimeStamp" \
168
+ curl -s --noproxy "*" "http://0.0.0.0:${ql_port}/open/system/notify?t=$currentTimeStamp" \
194
169
  -X 'PUT' \
195
- -H "Accept: application/json" \
196
170
  -H "Authorization: Bearer ${__ql_token__}" \
197
- -H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 11_2_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36" \
198
171
  -H "Content-Type: application/json;charset=UTF-8" \
199
- -H "Origin: http://0.0.0.0:5700" \
200
- -H "Referer: http://0.0.0.0:5700/crontab" \
201
- -H "Accept-Language: en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7" \
202
172
  --data-raw "{\"title\":\"${title//\"/\\\"}\",\"content\":\"${content//\"/\\\"}\"}" \
203
173
  --compressed
204
174
  )
@@ -215,14 +185,9 @@ find_cron_api() {
215
185
  local params="$1"
216
186
  local currentTimeStamp=$(date +%s)
217
187
  local api=$(
218
- curl -s --noproxy "*" "http://0.0.0.0:5600/open/crons/detail?$params&t=$currentTimeStamp" \
219
- -H "Accept: application/json" \
188
+ curl -s --noproxy "*" "http://0.0.0.0:${ql_port}/open/crons/detail?$params&t=$currentTimeStamp" \
220
189
  -H "Authorization: Bearer ${__ql_token__}" \
221
- -H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 11_2_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36" \
222
190
  -H "Content-Type: application/json;charset=UTF-8" \
223
- -H "Origin: http://0.0.0.0:5700" \
224
- -H "Referer: http://0.0.0.0:5700/crontab" \
225
- -H "Accept-Language: en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7" \
226
191
  --compressed
227
192
  )
228
193
  data=$(echo "$api" | jq -r .data)
@@ -239,15 +204,10 @@ update_auth_config() {
239
204
  local tip="$2"
240
205
  local currentTimeStamp=$(date +%s)
241
206
  local api=$(
242
- curl -s --noproxy "*" "http://0.0.0.0:5600/open/system/auth/reset?t=$currentTimeStamp" \
207
+ curl -s --noproxy "*" "http://0.0.0.0:${ql_port}/open/system/auth/reset?t=$currentTimeStamp" \
243
208
  -X 'PUT' \
244
- -H "Accept: application/json" \
245
209
  -H "Authorization: Bearer ${__ql_token__}" \
246
- -H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 11_2_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36" \
247
210
  -H "Content-Type: application/json;charset=UTF-8" \
248
- -H "Origin: http://0.0.0.0:5700" \
249
- -H "Referer: http://0.0.0.0:5700/crontab" \
250
- -H "Accept-Language: en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7" \
251
211
  --data-raw "{$body}" \
252
212
  --compressed
253
213
  )
package/shell/check.sh CHANGED
@@ -20,34 +20,18 @@ copy_dep() {
20
20
  echo -e "---> 复制一份 $file_notify_js_sample 为 $file_notify_js\n"
21
21
  cp -fv $file_notify_js_sample $file_notify_js
22
22
  echo -e "---> 通知文件复制完成\n"
23
-
24
- echo -e "---> 2. 复制nginx配置文件\n"
25
- init_nginx
26
- echo -e "---> 配置文件复制完成\n"
27
23
  }
28
24
 
29
25
  pm2_log() {
30
26
  echo -e "---> pm2日志"
31
- local panelOut="/root/.pm2/logs/panel-out.log"
32
- local panelError="/root/.pm2/logs/panel-error.log"
27
+ local panelOut="/root/.pm2/logs/qinglong-out.log"
28
+ local panelError="/root/.pm2/logs/qinglong-error.log"
33
29
  tail -n 300 "$panelOut"
34
30
  tail -n 300 "$panelError"
35
31
  }
36
32
 
37
- check_nginx() {
38
- local nginxPid=$(ps -eo pid,command | grep nginx | grep -v grep)
39
- echo -e "=====> 检测nginx服务\n$nginxPid"
40
- if [[ $nginxPid ]]; then
41
- echo -e "\n=====> nginx服务正常\n"
42
- nginx -s reload
43
- else
44
- echo -e "\n=====> nginx服务异常,重新启动nginx\n"
45
- nginx -c /etc/nginx/nginx.conf
46
- fi
47
- }
48
-
49
33
  check_ql() {
50
- local api=$(curl -s --noproxy "*" "http://0.0.0.0:5700")
34
+ local api=$(curl -s --noproxy "*" "http://0.0.0.0:${ql_port}")
51
35
  echo -e "\n=====> 检测面板\n\n$api\n"
52
36
  if [[ $api =~ "<div id=\"root\"></div>" ]]; then
53
37
  echo -e "=====> 面板服务启动正常\n"
@@ -58,10 +42,10 @@ check_pm2() {
58
42
  pm2_log
59
43
  local currentTimeStamp=$(date +%s)
60
44
  local api=$(
61
- curl -s --noproxy "*" "http://0.0.0.0:5600/api/system?t=$currentTimeStamp" \
45
+ curl -s --noproxy "*" "http://0.0.0.0:${ql_port}/api/system?t=$currentTimeStamp" \
62
46
  -H 'Accept: */*' \
63
47
  -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36' \
64
- -H 'Referer: http://0.0.0.0:5700/crontab' \
48
+ -H "Referer: http://0.0.0.0:${ql_port}/crontab" \
65
49
  -H 'Accept-Language: en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7' \
66
50
  --compressed
67
51
  )
@@ -78,7 +62,6 @@ main() {
78
62
  reset_env
79
63
  copy_dep
80
64
  check_ql
81
- check_nginx
82
65
  check_pm2
83
66
  reload_pm2
84
67
  echo -e "\n=====> 检测结束\n"