From 373b8c97d78f3b7891e1471b29d3b1de587cdd72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9B=A8=E6=80=9D?= Date: Thu, 20 Jul 2023 13:19:39 +0800 Subject: [PATCH 1/6] =?UTF-8?q?=E5=A2=9E=E5=8A=A0PushMe=E6=B6=88=E6=81=AF?= =?UTF-8?q?=E9=80=9A=E9=81=93=20(#2018)=EF=BC=8C=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E7=B3=BB=E7=BB=9F=E8=AE=BE=E7=BD=AE=E4=BF=9D=E5=AD=98=E9=80=9A?= =?UTF-8?q?=E7=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- back/data/notify.ts | 6 ++++ back/services/notify.ts | 23 ++++++++++++++++ sample/notify.js | 44 ++++++++++++++++++++++++++++++ sample/notify.py | 25 +++++++++++++++++ src/pages/initialization/index.tsx | 4 +-- src/pages/setting/notification.tsx | 4 +-- src/utils/config.ts | 8 ++++++ 7 files changed, 108 insertions(+), 6 deletions(-) diff --git a/back/data/notify.ts b/back/data/notify.ts index d744f01a..0bbe9c82 100644 --- a/back/data/notify.ts +++ b/back/data/notify.ts @@ -15,6 +15,7 @@ export enum NotificationMode { 'iGot' = 'iGot', 'pushPlus' = 'pushPlus', 'email' = 'email', + 'pushMe' = 'pushMe', 'feishu' = 'feishu', 'webhook' = 'webhook', } @@ -101,6 +102,10 @@ export class EmailNotification extends NotificationBaseInfo { public emailPass: string = ''; } +export class PushMeNotification extends NotificationBaseInfo { + public pushMeKey: string = ''; +} + export class WebhookNotification extends NotificationBaseInfo { public webhookHeaders: string = ''; public webhookBody: string = ''; @@ -131,5 +136,6 @@ export interface NotificationInfo IGotNotification, PushPlusNotification, EmailNotification, + PushMeNotification, WebhookNotification, LarkNotification {} diff --git a/back/services/notify.ts b/back/services/notify.ts index 54e036c0..01d13329 100644 --- a/back/services/notify.ts +++ b/back/services/notify.ts @@ -28,6 +28,7 @@ export default class NotificationService { ['iGot', this.iGot], ['pushPlus', this.pushPlus], ['email', this.email], + ['pushMe', this.pushMe], ['webhook', this.webhook], ['lark', this.lark], ]); @@ -561,6 +562,28 @@ export default class NotificationService { } } + private async pushMe() { + const { pushMeKey } = this.params; + try { + const res: any = await got + .post(`https://push.i-i.me/?push_key=${pushMeKey}`, { + ...this.gotOption, + json: { + title: this.title, + content: this.content + }, + headers: { 'Content-Type': 'application/json' }, + }); + if (res.body === 'success') { + return true; + } else { + throw new Error(res.body); + } + } catch (error: any) { + throw new Error(error.response ? error.response.body : error); + } + } + private async webhook() { const { webhookUrl, diff --git a/sample/notify.js b/sample/notify.js index c4307640..247faabf 100644 --- a/sample/notify.js +++ b/sample/notify.js @@ -141,6 +141,11 @@ let SMTP_EMAIL = ''; let SMTP_PASSWORD = ''; let SMTP_NAME = ''; +// =======================================PushMe通知设置区域=========================================== +//官方文档:https://push.i-i.me/ +//此处填你的PushMe KEY. +let PUSHME_KEY = ''; + //==========================云端环境变量的判断与接收========================= if (process.env.GOTIFY_URL) { GOTIFY_URL = process.env.GOTIFY_URL; @@ -288,6 +293,9 @@ if (process.env.SMTP_PASSWORD) { if (process.env.SMTP_NAME) { SMTP_NAME = process.env.SMTP_NAME; } +if (process.env.PUSHME_KEY) { + PUSHME_KEY = process.env.PUSHME_KEY; +} //==========================云端环境变量的判断与接收========================= /** @@ -336,6 +344,7 @@ async function sendNotify( aibotkNotify(text, desp), //智能微秘书 fsBotNotify(text, desp), //飞书机器人 smtpNotify(text, desp), //SMTP 邮件 + PushMeNotify(text, desp), //PushMe ]); } @@ -1117,6 +1126,41 @@ function smtpNotify(text, desp) { }); } +function PushMeNotify(text, desp) { + return new Promise((resolve) => { + if (PUSHME_KEY) { + const options = { + url: `https://push.i-i.me?push_key=${PUSHME_KEY}`, + json: { title: text, content: desp }, + headers: { + 'Content-Type': 'application/json', + }, + timeout, + }; + $.post(options, (err, resp, data) => { + try { + if (err) { + console.log('PushMeNotify发送通知调用API失败!!\n'); + console.log(err); + } else { + if (data === 'success') { + console.log('PushMe发送通知消息成功🎉\n'); + } else { + console.log(`${data}\n`); + } + } + } catch (e) { + $.logErr(e, resp); + } finally { + resolve(data); + } + }); + } else { + resolve(); + } + }); +} + module.exports = { sendNotify, BARK_PUSH, diff --git a/sample/notify.py b/sample/notify.py index b550e9a6..4a044402 100644 --- a/sample/notify.py +++ b/sample/notify.py @@ -98,6 +98,8 @@ push_config = { 'SMTP_EMAIL': '', # SMTP 收发件邮箱,通知将会由自己发给自己 'SMTP_PASSWORD': '', # SMTP 登录密码,也可能为特殊口令,视具体邮件服务商说明而定 'SMTP_NAME': '', # SMTP 收发件人姓名,可随意填写 + + 'PUSHME_KEY': '', # PushMe 酱的 PUSHME_KEY } notify_function = [] # fmt: on @@ -637,6 +639,27 @@ def smtp(title: str, content: str) -> None: except Exception as e: print(f"SMTP 邮件 推送失败!{e}") +def pushme(title: str, content: str) -> None: + """ + 使用 PushMe 推送消息。 + """ + if not push_config.get("PUSHME_KEY"): + print("PushMe 服务的 PUSHME_KEY 未设置!!\n取消推送") + return + print("PushMe 服务启动") + + url = f'https://push.i-i.me/?push_key={push_config.get("PUSHME_KEY")}' + data = { + "title": title, + "content": content, + } + response = requests.post(url, data=data) + + if response == 'success': + print("PushMe 推送成功!") + else: + print("PushMe 推送失败!{response}") + def one() -> str: """ @@ -692,6 +715,8 @@ if ( and push_config.get("SMTP_NAME") ): notify_function.append(smtp) +if push_config.get("PUSHME_KEY"): + notify_function.append(pushme) def send(title: str, content: str) -> None: diff --git a/src/pages/initialization/index.tsx b/src/pages/initialization/index.tsx index 276991a3..16962174 100644 --- a/src/pages/initialization/index.tsx +++ b/src/pages/initialization/index.tsx @@ -50,9 +50,7 @@ const Initialization = () => { const submitNotification = (values: any) => { setLoading(true); request - .put(`${config.apiPrefix}user/notification/init`, { - values, - }) + .put(`${config.apiPrefix}user/notification/init`, values) .then(({ code, data }) => { if (code === 200) { next(); diff --git a/src/pages/setting/notification.tsx b/src/pages/setting/notification.tsx index ceb0a159..09a583ba 100644 --- a/src/pages/setting/notification.tsx +++ b/src/pages/setting/notification.tsx @@ -19,9 +19,7 @@ const NotificationSetting = ({ data }: any) => { } request - .put(`${config.apiPrefix}user/notification`, { - values, - }) + .put(`${config.apiPrefix}user/notification`, values) .then(({ code, data }) => { if (code === 200) { message.success(values.type ? '通知发送成功' : '通知关闭成功'); diff --git a/src/utils/config.ts b/src/utils/config.ts index 640026c4..afa99905 100644 --- a/src/utils/config.ts +++ b/src/utils/config.ts @@ -96,6 +96,7 @@ export default { { value: 'chat', label: '群晖chat' }, { value: 'email', label: '邮箱' }, { value: 'lark', label: '飞书机器人' }, + { value: 'pushMe', label: 'PushMe' }, { value: 'webhook', label: '自定义通知' }, { value: 'closed', label: '已关闭' }, ], @@ -268,6 +269,13 @@ export default { { label: 'emailUser', tip: '邮箱地址', required: true }, { label: 'emailPass', tip: '邮箱SMTP授权码', required: true }, ], + pushMe: [ + { + label: 'pushMeKey', + tip: 'PushMe的Key,https://push.i-i.me/', + required: true, + }, + ], webhook: [ { label: 'webhookMethod', From 665c344ae48b570a6465f4fbe02d6d08857501dd Mon Sep 17 00:00:00 2001 From: whyour Date: Thu, 20 Jul 2023 22:54:11 +0800 Subject: [PATCH 2/6] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=BE=9D=E8=B5=96?= =?UTF-8?q?=E6=98=AF=E5=90=A6=E5=B7=B2=E7=BB=8F=E5=AE=89=E8=A3=85=E5=88=A4?= =?UTF-8?q?=E6=96=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- back/data/dependence.ts | 2 +- back/services/dependence.ts | 23 +++++++++++++++++------ 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/back/data/dependence.ts b/back/data/dependence.ts index 5db9c297..296452fb 100644 --- a/back/data/dependence.ts +++ b/back/data/dependence.ts @@ -48,7 +48,7 @@ export enum InstallDependenceCommandTypes { export enum GetDependenceCommandTypes { 'pnpm ls -g ', - 'pip3 list --disable-pip-version-check', + 'pip3 show --disable-pip-version-check', 'apk info', } diff --git a/back/services/dependence.ts b/back/services/dependence.ts index 2e440ec3..af70bb0b 100644 --- a/back/services/dependence.ts +++ b/back/services/dependence.ts @@ -23,7 +23,7 @@ export default class DependenceService { constructor( @Inject('logger') private logger: winston.Logger, private sockService: SockService, - ) {} + ) { } public async create(payloads: Dependence[]): Promise { const tabs = payloads.map((x) => { @@ -191,16 +191,27 @@ export default class DependenceService { if (isInstall) { const getCommandPrefix = GetDependenceCommandTypes[dependency.type]; const depVersionStr = versionDependenceCommandTypes[dependency.type]; - const [_depName] = dependency.name.trim().split(depVersionStr); + const [_depName, _depVersion] = dependency.name + .trim() + .split(depVersionStr); + const isNodeDependence = dependency.type === DependenceTypes.nodejs; + const isLinuxDependence = dependency.type === DependenceTypes.linux; + const isPythonDependence = dependency.type === DependenceTypes.python3; const depInfo = ( await promiseExecSuccess( - dependency.type === DependenceTypes.linux - ? `${getCommandPrefix} ${_depName}` - : `${getCommandPrefix} | grep "${_depName}"`, + isNodeDependence + ? `${getCommandPrefix} | grep "${_depName}" | head -1` + : `${getCommandPrefix} ${_depName}`, ) ).replace(/\s{2,}/, ' '); - if (depInfo) { + if ( + depInfo && + ((isNodeDependence && depInfo.split(' ')?.[0] === _depName) || + (isLinuxDependence && depInfo.toLocaleLowerCase().includes('installed')) || + isPythonDependence) && + (!_depVersion || depInfo.includes(_depVersion)) + ) { const endTime = dayjs(); const _message = `检测到已经安装 ${_depName}\n\n${depInfo}\n跳过安装\n\n依赖${actionText}成功,结束时间 ${endTime.format( 'YYYY-MM-DD HH:mm:ss', From 6131fe01109d098fe3b21b513437a8d590a9a744 Mon Sep 17 00:00:00 2001 From: whyour Date: Thu, 20 Jul 2023 23:14:16 +0800 Subject: [PATCH 3/6] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E7=89=88=E6=9C=AC=20v2.1?= =?UTF-8?q?5.19?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- version.yaml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/version.yaml b/version.yaml index f01e57db..a00f2a28 100644 --- a/version.yaml +++ b/version.yaml @@ -1,7 +1,7 @@ -version: 2.15.18 -changeLogLink: https://t.me/jiao_long/384 -publishTime: 2023-07-19 21:21 +version: 2.15.19 +changeLogLink: https://t.me/jiao_long/385 +publishTime: 2023-07-20 23:59 changeLog: | - 1. 增加备份恢复功能 - 2. 重构系统检查更新逻辑 - 3. 修复系统设置自动删除日志启动时失效 + 1. 通知支持 pushMe + 2. 修复系统通知设置保存失败 + 3. 修复判断依赖已安装逻辑 From 04edd97967f135d8f92b3efd8894e8e23907908f Mon Sep 17 00:00:00 2001 From: whyour Date: Fri, 21 Jul 2023 21:22:48 +0800 Subject: [PATCH 4/6] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=20node=20=E4=BE=9D?= =?UTF-8?q?=E8=B5=96=E5=8C=B9=E9=85=8D=E5=88=A4=E6=96=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- back/public.ts | 2 +- back/services/dependence.ts | 24 +++++++++++++++--------- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/back/public.ts b/back/public.ts index d9eb1cc7..094c99ea 100644 --- a/back/public.ts +++ b/back/public.ts @@ -13,7 +13,7 @@ const client = new HealthClient( app.get('/api/health', (req, res) => { client.check({ service: 'cron' }, (err, response) => { if (err) { - return res.status(500).send({ code: 500, error: err }); + return res.status(200).send({ code: 500, error: err }); } return res.status(200).send({ code: 200, data: response }); }); diff --git a/back/services/dependence.ts b/back/services/dependence.ts index af70bb0b..70bf920b 100644 --- a/back/services/dependence.ts +++ b/back/services/dependence.ts @@ -168,7 +168,7 @@ export default class DependenceService { const socketMessageType = isInstall ? 'installDependence' : 'uninstallDependence'; - const depName = dependency.name.trim(); + let depName = dependency.name.trim(); const depRunCommand = ( isInstall ? InstallDependenceCommandTypes @@ -191,29 +191,35 @@ export default class DependenceService { if (isInstall) { const getCommandPrefix = GetDependenceCommandTypes[dependency.type]; const depVersionStr = versionDependenceCommandTypes[dependency.type]; - const [_depName, _depVersion] = dependency.name - .trim() - .split(depVersionStr); + let depVersion = ''; + if (depName.includes(depVersionStr)) { + const symbolRegx = new RegExp(`(.*)${depVersionStr}([0-9\\.\\-\\+a-zA-Z]*)`); + const [, _depName, _depVersion] = depName.match(symbolRegx) || []; + if (_depVersion && _depName) { + depName = _depName; + depVersion = _depVersion; + } + } const isNodeDependence = dependency.type === DependenceTypes.nodejs; const isLinuxDependence = dependency.type === DependenceTypes.linux; const isPythonDependence = dependency.type === DependenceTypes.python3; const depInfo = ( await promiseExecSuccess( isNodeDependence - ? `${getCommandPrefix} | grep "${_depName}" | head -1` - : `${getCommandPrefix} ${_depName}`, + ? `${getCommandPrefix} | grep "${depName}" | head -1` + : `${getCommandPrefix} ${depName}`, ) ).replace(/\s{2,}/, ' '); if ( depInfo && - ((isNodeDependence && depInfo.split(' ')?.[0] === _depName) || + ((isNodeDependence && depInfo.split(' ')?.[0] === depName) || (isLinuxDependence && depInfo.toLocaleLowerCase().includes('installed')) || isPythonDependence) && - (!_depVersion || depInfo.includes(_depVersion)) + (!depVersion || depInfo.includes(depVersion)) ) { const endTime = dayjs(); - const _message = `检测到已经安装 ${_depName}\n\n${depInfo}\n跳过安装\n\n依赖${actionText}成功,结束时间 ${endTime.format( + const _message = `检测到已经安装 ${depName}\n\n${depInfo}\n跳过安装\n\n依赖${actionText}成功,结束时间 ${endTime.format( 'YYYY-MM-DD HH:mm:ss', )},耗时 ${endTime.diff(startTime, 'second')} 秒`; this.sockService.sendMessage({ From 043b7adc24944af685efc629be46f7b6aa80ba51 Mon Sep 17 00:00:00 2001 From: whyour Date: Sun, 23 Jul 2023 22:11:50 +0800 Subject: [PATCH 5/6] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=20linux=20=E4=BE=9D?= =?UTF-8?q?=E8=B5=96=E6=98=AF=E5=90=A6=E5=AD=98=E5=9C=A8=E5=88=A4=E6=96=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- back/config/index.ts | 3 +++ back/data/dependence.ts | 4 ++-- back/loaders/initData.ts | 2 +- back/services/dependence.ts | 6 +++--- docker/Dockerfile | 1 - shell/check.sh | 2 -- shell/share.sh | 1 - src/pages/dependence/index.tsx | 2 +- src/utils/http.ts | 1 + 9 files changed, 11 insertions(+), 11 deletions(-) diff --git a/back/config/index.ts b/back/config/index.ts index ffdbb3e6..3c7ac0d8 100644 --- a/back/config/index.ts +++ b/back/config/index.ts @@ -20,6 +20,7 @@ const rootPath = process.env.QL_DIR as string; const envFound = dotenv.config({ path: path.join(rootPath, '.env') }); const dataPath = path.join(rootPath, 'data/'); +const shellPath = path.join(rootPath, 'shell/'); const tmpPath = path.join(rootPath, '.tmp/'); const samplePath = path.join(rootPath, 'sample/'); const configPath = path.join(dataPath, 'config/'); @@ -44,6 +45,7 @@ const loginFaild = '请先登录!'; const configString = 'config sample crontab shareCode diy'; const versionFile = path.join(rootPath, 'version.yaml'); const dataTgzFile = path.join(tmpPath, 'data.tgz'); +const shareShellFile = path.join(shellPath, 'share.sh'); if (envFound.error) { throw new Error("⚠️ Couldn't find .env file ⚠️"); @@ -64,6 +66,7 @@ export default { tmpPath, dataPath, dataTgzFile, + shareShellFile, configString, loginFaild, authError, diff --git a/back/data/dependence.ts b/back/data/dependence.ts index 296452fb..c8d7eb60 100644 --- a/back/data/dependence.ts +++ b/back/data/dependence.ts @@ -43,13 +43,13 @@ export enum DependenceTypes { export enum InstallDependenceCommandTypes { 'pnpm add -g', 'pip3 install --disable-pip-version-check --root-user-action=ignore', - 'apk add', + 'apk add --no-check-certificate', } export enum GetDependenceCommandTypes { 'pnpm ls -g ', 'pip3 show --disable-pip-version-check', - 'apk info', + 'apk info -es', } export enum versionDependenceCommandTypes { diff --git a/back/loaders/initData.ts b/back/loaders/initData.ts index e680d58e..678625d4 100644 --- a/back/loaders/initData.ts +++ b/back/loaders/initData.ts @@ -38,7 +38,7 @@ export default async () => { // 初始化时安装所有处于安装中,安装成功,安装失败的依赖 DependenceModel.findAll({ where: {}, - order: [['type', 'DESC']], + order: [['type', 'DESC'], ['createdAt', 'DESC']], raw: true, }).then(async (docs) => { await DependenceModel.update( diff --git a/back/services/dependence.ts b/back/services/dependence.ts index 70bf920b..d35c3747 100644 --- a/back/services/dependence.ts +++ b/back/services/dependence.ts @@ -209,7 +209,7 @@ export default class DependenceService { ? `${getCommandPrefix} | grep "${depName}" | head -1` : `${getCommandPrefix} ${depName}`, ) - ).replace(/\s{2,}/, ' '); + ).replace(/\s{2,}/, ' ').replace(/\s+$/, ''); if ( depInfo && @@ -219,7 +219,7 @@ export default class DependenceService { (!depVersion || depInfo.includes(depVersion)) ) { const endTime = dayjs(); - const _message = `检测到已经安装 ${depName}\n\n${depInfo}\n跳过安装\n\n依赖${actionText}成功,结束时间 ${endTime.format( + const _message = `检测到已经安装 ${depName}\n\n${depInfo}\n\n跳过安装\n\n依赖${actionText}成功,结束时间 ${endTime.format( 'YYYY-MM-DD HH:mm:ss', )},耗时 ${endTime.diff(startTime, 'second')} 秒`; this.sockService.sendMessage({ @@ -236,7 +236,7 @@ export default class DependenceService { } } - const cp = spawn(`${depRunCommand} ${depName}`, { + const cp = spawn(`source ${config.shareShellFile} && set_proxy && ${depRunCommand} ${dependency.name.trim()}`, { shell: '/bin/bash', }); diff --git a/docker/Dockerfile b/docker/Dockerfile index 1e5307fc..539ea40e 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -24,7 +24,6 @@ ENV PNPM_HOME=/root/.local/share/pnpm \ QL_BRANCH=${QL_BRANCH} RUN set -x \ - && sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories \ && apk update -f \ && apk upgrade \ && apk --no-cache add -f bash \ diff --git a/shell/check.sh b/shell/check.sh index 33c7db8b..3886c73f 100755 --- a/shell/check.sh +++ b/shell/check.sh @@ -79,8 +79,6 @@ main() { npm i -g pnpm@8.3.1 patch_version - apk add procps netcat-openbsd - if [[ $PipMirror ]]; then pip3 config set global.index-url $PipMirror fi diff --git a/shell/share.sh b/shell/share.sh index 9cbc7955..52b4cab6 100755 --- a/shell/share.sh +++ b/shell/share.sh @@ -314,7 +314,6 @@ reload_pm2() { unset_proxy pm2 flush &>/dev/null pm2 startOrGracefulReload $file_ecosystem_js --update-env - pm2 sendSignal SIGKILL panel &>/dev/null } diff_time() { diff --git a/src/pages/dependence/index.tsx b/src/pages/dependence/index.tsx index 04308444..ec3cbbd6 100644 --- a/src/pages/dependence/index.tsx +++ b/src/pages/dependence/index.tsx @@ -290,7 +290,7 @@ const Dependence = () => { const handleDependence = (dependence: any) => { const result = [...value]; if (Array.isArray(dependence)) { - result.push(...dependence); + result.unshift(...dependence); } else { const index = value.findIndex((x) => x.id === dependence.id); if (index !== -1) { diff --git a/src/utils/http.ts b/src/utils/http.ts index 150ac8b6..5dc1d20a 100644 --- a/src/utils/http.ts +++ b/src/utils/http.ts @@ -11,6 +11,7 @@ interface IResponseData { code?: number; data?: any; message?: string; + error?: any; } type Override< From c6a5a061f8ad9f0b00474dc367b6248b9ccde8ee Mon Sep 17 00:00:00 2001 From: whyour Date: Sun, 23 Jul 2023 22:11:57 +0800 Subject: [PATCH 6/6] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E7=89=88=E6=9C=AC=20v2.1?= =?UTF-8?q?5.20?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- version.yaml | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/version.yaml b/version.yaml index a00f2a28..b07b1eca 100644 --- a/version.yaml +++ b/version.yaml @@ -1,7 +1,6 @@ -version: 2.15.19 -changeLogLink: https://t.me/jiao_long/385 -publishTime: 2023-07-20 23:59 +version: 2.15.20 +changeLogLink: https://t.me/jiao_long/386 +publishTime: 2023-07-22 16:00 changeLog: | - 1. 通知支持 pushMe - 2. 修复系统通知设置保存失败 - 3. 修复判断依赖已安装逻辑 + 1. 修复判断 linux 依赖已安装逻辑 + 2. 修复未启动完成时,页面提示 500