From b6f088e77bff4fb34e6059f53aaf4136073e21c7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 25 Apr 2026 06:48:14 +0000 Subject: [PATCH] Add OpeniLink notification channel support Agent-Logs-Url: https://github.com/whyour/qinglong/sessions/c80b4882-1bd7-4ffe-9180-cd3220da5986 Co-authored-by: whyour <22700758+whyour@users.noreply.github.com> --- back/data/notify.ts | 8 +++++++- back/services/notify.ts | 26 ++++++++++++++++++++++++ sample/config.sample.sh | 5 +++++ sample/notify.js | 44 +++++++++++++++++++++++++++++++++++++++++ sample/notify.py | 33 +++++++++++++++++++++++++++++++ src/utils/config.ts | 10 ++++++++++ 6 files changed, 125 insertions(+), 1 deletion(-) diff --git a/back/data/notify.ts b/back/data/notify.ts index b0899500..ce5c9aea 100644 --- a/back/data/notify.ts +++ b/back/data/notify.ts @@ -20,6 +20,7 @@ export enum NotificationMode { 'chronocat' = 'Chronocat', 'ntfy' = 'ntfy', 'wxPusherBot' = 'wxPusherBot', + 'openiLink' = 'openiLink', } abstract class NotificationBaseInfo { @@ -161,6 +162,10 @@ export class WxPusherBotNotification extends NotificationBaseInfo { public wxPusherBotUids = ''; } +export class OpeniLinkNotification extends NotificationBaseInfo { + public openiLinkAppToken = ''; +} + export interface NotificationInfo extends GoCqHttpBotNotification, GotifyNotification, @@ -182,4 +187,5 @@ export interface NotificationInfo ChronocatNotification, LarkNotification, NtfyNotification, - WxPusherBotNotification {} + WxPusherBotNotification, + OpeniLinkNotification {} diff --git a/back/services/notify.ts b/back/services/notify.ts index 22609748..55f44fc3 100644 --- a/back/services/notify.ts +++ b/back/services/notify.ts @@ -34,6 +34,7 @@ export default class NotificationService { ['chronocat', this.chronocat], ['ntfy', this.ntfy], ['wxPusherBot', this.wxPusherBot], + ['openiLink', this.openiLink], ]); private title = ''; @@ -858,4 +859,29 @@ export default class NotificationService { } return {}; } + + private async openiLink() { + const { openiLinkAppToken } = this.params; + const url = 'https://hub.openilink.com/bot/v1/message/send'; + try { + const res = await httpClient.post(url, { + ...this.gotOption, + json: { + type: 'text', + content: `${this.title}\n\n${this.content}`, + }, + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${openiLinkAppToken}`, + }, + }); + if (res.ok) { + return true; + } else { + throw new Error(JSON.stringify(res)); + } + } catch (error: any) { + throw new Error(error.response ? error.response.body : error); + } + } } diff --git a/sample/config.sample.sh b/sample/config.sample.sh index 734f4ae5..caa083f7 100644 --- a/sample/config.sample.sh +++ b/sample/config.sample.sh @@ -259,4 +259,9 @@ export WEBHOOK_METHOD="" ## 支持 text/plain、application/json、multipart/form-data、application/x-www-form-urlencoded export WEBHOOK_CONTENT_TYPE="" +## 23. OpeniLink +## 官方文档: https://openilink.com/docs/hub/apps +## 在 OpeniLink Hub 后台安装 App 后获取 app_token +export OPENILINK_APP_TOKEN="" + ## 其他需要的变量,脚本中需要的变量使用 export 变量名= 声明即可 diff --git a/sample/notify.js b/sample/notify.js index f935e8ce..741182d7 100644 --- a/sample/notify.js +++ b/sample/notify.js @@ -151,6 +151,9 @@ const push_config = { WXPUSHER_APP_TOKEN: '', // wxpusher 的 appToken WXPUSHER_TOPIC_IDS: '', // wxpusher 的 主题ID,多个用英文分号;分隔 topic_ids 与 uids 至少配置一个才行 WXPUSHER_UIDS: '', // wxpusher 的 用户ID,多个用英文分号;分隔 topic_ids 与 uids 至少配置一个才行 + + // 官方文档: https://openilink.com/docs/hub/apps + OPENILINK_APP_TOKEN: '', // OpeniLink 的 app_token,在 OpeniLink Hub 后台安装 App 后获取 }; for (const key in push_config) { @@ -1408,6 +1411,46 @@ function wxPusherNotify(text, desp) { }); } +function openiLinkNotify(text, desp) { + return new Promise((resolve) => { + const { OPENILINK_APP_TOKEN } = push_config; + if (OPENILINK_APP_TOKEN) { + const options = { + url: 'https://hub.openilink.com/bot/v1/message/send', + body: JSON.stringify({ + type: 'text', + content: `${text}\n\n${desp}`, + }), + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${OPENILINK_APP_TOKEN}`, + }, + timeout, + }; + + $.post(options, (err, resp, data) => { + try { + if (err) { + console.log('OpeniLink 发送通知消息失败!\n', err); + } else { + if (data.ok) { + console.log('OpeniLink 发送通知消息成功!'); + } else { + console.log(`OpeniLink 发送通知消息异常:${data.error}`); + } + } + } catch (e) { + $.logErr(e, resp); + } finally { + resolve(data); + } + }); + } else { + resolve(); + } + }); +} + function parseString(input, valueFormatFn) { const regex = /(\w+):\s*((?:(?!\n\w+:).)*)/g; const matches = {}; @@ -1538,6 +1581,7 @@ async function sendNotify(text, desp, params = {}) { qmsgNotify(text, desp), // 自定义通知 ntfyNotify(text, desp), // Ntfy wxPusherNotify(text, desp), // wxpusher + openiLinkNotify(text, desp), // OpeniLink ]); } diff --git a/sample/notify.py b/sample/notify.py index 8dd885ca..e153bff3 100644 --- a/sample/notify.py +++ b/sample/notify.py @@ -135,6 +135,8 @@ push_config = { 'WXPUSHER_APP_TOKEN': '', # wxpusher 的 appToken 官方文档: https://wxpusher.zjiecode.com/docs/ 管理后台: https://wxpusher.zjiecode.com/admin/ 'WXPUSHER_TOPIC_IDS': '', # wxpusher 的 主题ID,多个用英文分号;分隔 topic_ids 与 uids 至少配置一个才行 'WXPUSHER_UIDS': '', # wxpusher 的 用户ID,多个用英文分号;分隔 topic_ids 与 uids 至少配置一个才行 + + 'OPENILINK_APP_TOKEN': '', # OpeniLink 的 app_token,在 OpeniLink Hub 后台安装 App 后获取 官方文档: https://openilink.com/docs/hub/apps } # fmt: on @@ -898,6 +900,35 @@ def wxpusher_bot(title: str, content: str) -> None: print(f"wxpusher 推送失败!错误信息:{response.get('msg')}") +def openilink(title: str, content: str) -> None: + """ + 通过 OpeniLink 推送消息。 + 支持的环境变量: + - OPENILINK_APP_TOKEN: 在 OpeniLink Hub 后台安装 App 后获取的 app_token + """ + if not push_config.get("OPENILINK_APP_TOKEN"): + return + + print("OpeniLink 服务启动") + + url = "https://hub.openilink.com/bot/v1/message/send" + headers = { + "Content-Type": "application/json", + "Authorization": f'Bearer {push_config.get("OPENILINK_APP_TOKEN")}', + } + data = { + "type": "text", + "content": f"{title}\n\n{content}", + } + + response = requests.post(url=url, json=data, headers=headers).json() + + if response.get("ok"): + print("OpeniLink 推送成功!") + else: + print(f'OpeniLink 推送失败!错误信息:{response.get("error")}') + + def parse_headers(headers): if not headers: return {} @@ -1063,6 +1094,8 @@ def add_notify_function(): push_config.get("WXPUSHER_TOPIC_IDS") or push_config.get("WXPUSHER_UIDS") ): notify_function.append(wxpusher_bot) + if push_config.get("OPENILINK_APP_TOKEN"): + notify_function.append(openilink) if not notify_function: print(f"无推送渠道,请检查通知变量是否正确") return notify_function diff --git a/src/utils/config.ts b/src/utils/config.ts index b529a7d0..3aead8e5 100644 --- a/src/utils/config.ts +++ b/src/utils/config.ts @@ -98,6 +98,7 @@ export default { { value: 'pushPlus', label: 'PushPlus' }, { value: 'wePlusBot', label: intl.get('微加机器人') }, { value: 'wxPusherBot', label: 'wxPusher' }, + { value: 'openiLink', label: 'OpeniLink' }, { value: 'chat', label: intl.get('群晖chat') }, { value: 'email', label: intl.get('邮箱') }, { value: 'lark', label: intl.get('飞书机器人') }, @@ -387,6 +388,15 @@ export default { required: false, }, ], + openiLink: [ + { + label: 'openiLinkAppToken', + tip: intl.get( + 'OpeniLink的app_token,在OpeniLink Hub后台安装App后获取,参考 https://openilink.com/docs/hub/apps', + ), + required: true, + }, + ], lark: [ { label: 'larkKey',