mirror of
https://github.com/whyour/qinglong.git
synced 2026-04-29 00:45:11 +08:00
Add OpeniLink notification channel (#2988)
* Initial plan * 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> * Add context_token and hub_url to OpeniLink notification channel Agent-Logs-Url: https://github.com/whyour/qinglong/sessions/a5e66f5a-dab8-4a65-96ca-960d35fa9d50 Co-authored-by: whyour <22700758+whyour@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: whyour <22700758+whyour@users.noreply.github.com>
This commit is contained in:
parent
07bf0c705b
commit
66700ebe1a
|
|
@ -20,6 +20,7 @@ export enum NotificationMode {
|
||||||
'chronocat' = 'Chronocat',
|
'chronocat' = 'Chronocat',
|
||||||
'ntfy' = 'ntfy',
|
'ntfy' = 'ntfy',
|
||||||
'wxPusherBot' = 'wxPusherBot',
|
'wxPusherBot' = 'wxPusherBot',
|
||||||
|
'openiLink' = 'openiLink',
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class NotificationBaseInfo {
|
abstract class NotificationBaseInfo {
|
||||||
|
|
@ -161,6 +162,12 @@ export class WxPusherBotNotification extends NotificationBaseInfo {
|
||||||
public wxPusherBotUids = '';
|
public wxPusherBotUids = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class OpeniLinkNotification extends NotificationBaseInfo {
|
||||||
|
public openiLinkAppToken = '';
|
||||||
|
public openiLinkHubUrl = '';
|
||||||
|
public openiLinkContextToken = '';
|
||||||
|
}
|
||||||
|
|
||||||
export interface NotificationInfo
|
export interface NotificationInfo
|
||||||
extends GoCqHttpBotNotification,
|
extends GoCqHttpBotNotification,
|
||||||
GotifyNotification,
|
GotifyNotification,
|
||||||
|
|
@ -182,4 +189,5 @@ export interface NotificationInfo
|
||||||
ChronocatNotification,
|
ChronocatNotification,
|
||||||
LarkNotification,
|
LarkNotification,
|
||||||
NtfyNotification,
|
NtfyNotification,
|
||||||
WxPusherBotNotification {}
|
WxPusherBotNotification,
|
||||||
|
OpeniLinkNotification {}
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@ export default class NotificationService {
|
||||||
['chronocat', this.chronocat],
|
['chronocat', this.chronocat],
|
||||||
['ntfy', this.ntfy],
|
['ntfy', this.ntfy],
|
||||||
['wxPusherBot', this.wxPusherBot],
|
['wxPusherBot', this.wxPusherBot],
|
||||||
|
['openiLink', this.openiLink],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
private title = '';
|
private title = '';
|
||||||
|
|
@ -858,4 +859,35 @@ export default class NotificationService {
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async openiLink() {
|
||||||
|
const { openiLinkAppToken, openiLinkHubUrl, openiLinkContextToken } =
|
||||||
|
this.params;
|
||||||
|
const baseUrl = openiLinkHubUrl?.replace(/\/$/, '') || 'https://hub.openilink.com';
|
||||||
|
const url = `${baseUrl}/bot/v1/message/send`;
|
||||||
|
const body: Record<string, string> = {
|
||||||
|
type: 'text',
|
||||||
|
content: `${this.title}\n\n${this.content}`,
|
||||||
|
};
|
||||||
|
if (openiLinkContextToken) {
|
||||||
|
body.context_token = openiLinkContextToken;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const res = await httpClient.post(url, {
|
||||||
|
...this.gotOption,
|
||||||
|
json: body,
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -259,4 +259,13 @@ export WEBHOOK_METHOD=""
|
||||||
## 支持 text/plain、application/json、multipart/form-data、application/x-www-form-urlencoded
|
## 支持 text/plain、application/json、multipart/form-data、application/x-www-form-urlencoded
|
||||||
export WEBHOOK_CONTENT_TYPE=""
|
export WEBHOOK_CONTENT_TYPE=""
|
||||||
|
|
||||||
|
## 23. OpeniLink
|
||||||
|
## 官方文档: https://openilink.com/docs/hub/apps
|
||||||
|
## 在 OpeniLink Hub 后台安装 App 后获取 app_token
|
||||||
|
export OPENILINK_APP_TOKEN=""
|
||||||
|
## OpeniLink Hub 地址,默认为 https://hub.openilink.com,自建 Hub 时填写自己的地址
|
||||||
|
export OPENILINK_HUB_URL=""
|
||||||
|
## OpeniLink 的 context_token,用于标识消息会话上下文,可从消息事件中获取
|
||||||
|
export OPENILINK_CONTEXT_TOKEN=""
|
||||||
|
|
||||||
## 其他需要的变量,脚本中需要的变量使用 export 变量名= 声明即可
|
## 其他需要的变量,脚本中需要的变量使用 export 变量名= 声明即可
|
||||||
|
|
|
||||||
|
|
@ -151,6 +151,11 @@ const push_config = {
|
||||||
WXPUSHER_APP_TOKEN: '', // wxpusher 的 appToken
|
WXPUSHER_APP_TOKEN: '', // wxpusher 的 appToken
|
||||||
WXPUSHER_TOPIC_IDS: '', // wxpusher 的 主题ID,多个用英文分号;分隔 topic_ids 与 uids 至少配置一个才行
|
WXPUSHER_TOPIC_IDS: '', // wxpusher 的 主题ID,多个用英文分号;分隔 topic_ids 与 uids 至少配置一个才行
|
||||||
WXPUSHER_UIDS: '', // 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 后获取
|
||||||
|
OPENILINK_HUB_URL: '', // OpeniLink Hub 地址,默认为 https://hub.openilink.com,自建 Hub 时填写自己的地址
|
||||||
|
OPENILINK_CONTEXT_TOKEN: '', // OpeniLink 的 context_token,用于标识消息会话上下文,可从消息事件中获取
|
||||||
};
|
};
|
||||||
|
|
||||||
for (const key in push_config) {
|
for (const key in push_config) {
|
||||||
|
|
@ -1408,6 +1413,54 @@ function wxPusherNotify(text, desp) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function openiLinkNotify(text, desp) {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
const { OPENILINK_APP_TOKEN, OPENILINK_HUB_URL, OPENILINK_CONTEXT_TOKEN } =
|
||||||
|
push_config;
|
||||||
|
if (OPENILINK_APP_TOKEN) {
|
||||||
|
const baseUrl = OPENILINK_HUB_URL
|
||||||
|
? OPENILINK_HUB_URL.replace(/\/$/, '')
|
||||||
|
: 'https://hub.openilink.com';
|
||||||
|
const body = {
|
||||||
|
type: 'text',
|
||||||
|
content: `${text}\n\n${desp}`,
|
||||||
|
};
|
||||||
|
if (OPENILINK_CONTEXT_TOKEN) {
|
||||||
|
body.context_token = OPENILINK_CONTEXT_TOKEN;
|
||||||
|
}
|
||||||
|
const options = {
|
||||||
|
url: `${baseUrl}/bot/v1/message/send`,
|
||||||
|
body: JSON.stringify(body),
|
||||||
|
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) {
|
function parseString(input, valueFormatFn) {
|
||||||
const regex = /(\w+):\s*((?:(?!\n\w+:).)*)/g;
|
const regex = /(\w+):\s*((?:(?!\n\w+:).)*)/g;
|
||||||
const matches = {};
|
const matches = {};
|
||||||
|
|
@ -1538,6 +1591,7 @@ async function sendNotify(text, desp, params = {}) {
|
||||||
qmsgNotify(text, desp), // 自定义通知
|
qmsgNotify(text, desp), // 自定义通知
|
||||||
ntfyNotify(text, desp), // Ntfy
|
ntfyNotify(text, desp), // Ntfy
|
||||||
wxPusherNotify(text, desp), // wxpusher
|
wxPusherNotify(text, desp), // wxpusher
|
||||||
|
openiLinkNotify(text, desp), // OpeniLink
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -135,6 +135,10 @@ push_config = {
|
||||||
'WXPUSHER_APP_TOKEN': '', # wxpusher 的 appToken 官方文档: https://wxpusher.zjiecode.com/docs/ 管理后台: https://wxpusher.zjiecode.com/admin/
|
'WXPUSHER_APP_TOKEN': '', # wxpusher 的 appToken 官方文档: https://wxpusher.zjiecode.com/docs/ 管理后台: https://wxpusher.zjiecode.com/admin/
|
||||||
'WXPUSHER_TOPIC_IDS': '', # wxpusher 的 主题ID,多个用英文分号;分隔 topic_ids 与 uids 至少配置一个才行
|
'WXPUSHER_TOPIC_IDS': '', # wxpusher 的 主题ID,多个用英文分号;分隔 topic_ids 与 uids 至少配置一个才行
|
||||||
'WXPUSHER_UIDS': '', # 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
|
||||||
|
'OPENILINK_HUB_URL': '', # OpeniLink Hub 地址,默认为 https://hub.openilink.com,自建 Hub 时填写自己的地址
|
||||||
|
'OPENILINK_CONTEXT_TOKEN': '', # OpeniLink 的 context_token,用于标识消息会话上下文,可从消息事件中获取
|
||||||
}
|
}
|
||||||
# fmt: on
|
# fmt: on
|
||||||
|
|
||||||
|
|
@ -898,6 +902,43 @@ def wxpusher_bot(title: str, content: str) -> None:
|
||||||
print(f"wxpusher 推送失败!错误信息:{response.get('msg')}")
|
print(f"wxpusher 推送失败!错误信息:{response.get('msg')}")
|
||||||
|
|
||||||
|
|
||||||
|
def openilink(title: str, content: str) -> None:
|
||||||
|
"""
|
||||||
|
通过 OpeniLink 推送消息。
|
||||||
|
支持的环境变量:
|
||||||
|
- OPENILINK_APP_TOKEN: 在 OpeniLink Hub 后台安装 App 后获取的 app_token
|
||||||
|
- OPENILINK_HUB_URL: OpeniLink Hub 地址,默认为 https://hub.openilink.com
|
||||||
|
- OPENILINK_CONTEXT_TOKEN: 消息会话上下文 token,可从消息事件中获取
|
||||||
|
"""
|
||||||
|
if not push_config.get("OPENILINK_APP_TOKEN"):
|
||||||
|
return
|
||||||
|
|
||||||
|
print("OpeniLink 服务启动")
|
||||||
|
|
||||||
|
base_url = (
|
||||||
|
push_config.get("OPENILINK_HUB_URL", "").rstrip("/")
|
||||||
|
or "https://hub.openilink.com"
|
||||||
|
)
|
||||||
|
url = f"{base_url}/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}",
|
||||||
|
}
|
||||||
|
if push_config.get("OPENILINK_CONTEXT_TOKEN"):
|
||||||
|
data["context_token"] = push_config.get("OPENILINK_CONTEXT_TOKEN")
|
||||||
|
|
||||||
|
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):
|
def parse_headers(headers):
|
||||||
if not headers:
|
if not headers:
|
||||||
return {}
|
return {}
|
||||||
|
|
@ -1063,6 +1104,8 @@ def add_notify_function():
|
||||||
push_config.get("WXPUSHER_TOPIC_IDS") or push_config.get("WXPUSHER_UIDS")
|
push_config.get("WXPUSHER_TOPIC_IDS") or push_config.get("WXPUSHER_UIDS")
|
||||||
):
|
):
|
||||||
notify_function.append(wxpusher_bot)
|
notify_function.append(wxpusher_bot)
|
||||||
|
if push_config.get("OPENILINK_APP_TOKEN"):
|
||||||
|
notify_function.append(openilink)
|
||||||
if not notify_function:
|
if not notify_function:
|
||||||
print(f"无推送渠道,请检查通知变量是否正确")
|
print(f"无推送渠道,请检查通知变量是否正确")
|
||||||
return notify_function
|
return notify_function
|
||||||
|
|
|
||||||
|
|
@ -98,6 +98,7 @@ export default {
|
||||||
{ value: 'pushPlus', label: 'PushPlus' },
|
{ value: 'pushPlus', label: 'PushPlus' },
|
||||||
{ value: 'wePlusBot', label: intl.get('微加机器人') },
|
{ value: 'wePlusBot', label: intl.get('微加机器人') },
|
||||||
{ value: 'wxPusherBot', label: 'wxPusher' },
|
{ value: 'wxPusherBot', label: 'wxPusher' },
|
||||||
|
{ value: 'openiLink', label: 'OpeniLink' },
|
||||||
{ value: 'chat', label: intl.get('群晖chat') },
|
{ value: 'chat', label: intl.get('群晖chat') },
|
||||||
{ value: 'email', label: intl.get('邮箱') },
|
{ value: 'email', label: intl.get('邮箱') },
|
||||||
{ value: 'lark', label: intl.get('飞书机器人') },
|
{ value: 'lark', label: intl.get('飞书机器人') },
|
||||||
|
|
@ -387,6 +388,27 @@ export default {
|
||||||
required: false,
|
required: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
openiLink: [
|
||||||
|
{
|
||||||
|
label: 'openiLinkAppToken',
|
||||||
|
tip: intl.get(
|
||||||
|
'OpeniLink的app_token,在OpeniLink Hub后台安装App后获取,参考 https://openilink.com/docs/hub/apps',
|
||||||
|
),
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'openiLinkHubUrl',
|
||||||
|
tip: intl.get(
|
||||||
|
'OpeniLink Hub地址,默认为 https://hub.openilink.com,自建Hub时填写自己的地址',
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'openiLinkContextToken',
|
||||||
|
tip: intl.get(
|
||||||
|
'OpeniLink的context_token,用于标识消息会话上下文,可从消息事件中获取',
|
||||||
|
),
|
||||||
|
},
|
||||||
|
],
|
||||||
lark: [
|
lark: [
|
||||||
{
|
{
|
||||||
label: 'larkKey',
|
label: 'larkKey',
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user