workbuddy.xpcool.com/.workbuddy/tmp/bark.js

195 lines
8.1 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// bark.js —— xpcool 定制版(基于 Uptime Kuma 2.5.3 官方实现)
//
// 为什么要定制:官方 Bark provider 只支持 endpoint / group / sound 三个参数,
// 且图标写死成 GitHub 上的 Uptime Kuma 图标。本项目需要:
// 1. 自定义推送图标(自托管 PNG手机端直接拉取
// 2. 推送消息分组(可选 config.barkGroup 覆盖)
// 3. 重要警告 level=critical穿透静音 / 专注模式(仅 DOWN
// 4. 图片推送通知 image按状态区分「异常图 / 恢复图」
// 5. 设置角标 badgeDOWN 自增、UP 清零)
// 6. 附带call=1 持续响铃、isArchive=1 自动保存(仅 DOWN
//
// 部署方式:宿主文件 /data/uptime-kuma-patch/bark.js 只读挂载覆盖本路径。
// ⚠️ 升级 uptime-kuma 镜像后需重新核对此文件与新版官方实现的差异。
//
const NotificationProvider = require("./notification-provider");
const { DOWN, UP } = require("../../src/util");
const { default: axios } = require("axios");
// ===== xpcool 定制:素材地址与默认值 =====
const barkNotificationAvatar = "https://status.xpcool.com/bark-assets/icon.png"; // 自定义推送图标
const IMAGE_DOWN = "https://status.xpcool.com/bark-assets/down.png"; // 服务异常配图
const IMAGE_UP = "https://status.xpcool.com/bark-assets/up.png"; // 服务恢复配图
const DEFAULT_GROUP = "Uptime-Kuma"; // 默认推送分组
const successMessage = "Successes!";
class Bark extends NotificationProvider {
name = "Bark";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let barkEndpoint = notification.barkEndpoint;
// check if the endpoint has a "/" suffix, if so, delete it first
if (barkEndpoint.endsWith("/")) {
barkEndpoint = barkEndpoint.substring(0, barkEndpoint.length - 1);
}
// xpcool 定制:按 UP / DOWN 状态生成附加参数(重要警告、角标、配图等)
const status = heartbeatJSON != null ? heartbeatJSON["status"] : null;
const extra = this.statusParams(notification, status);
if (msg != null && heartbeatJSON != null && status === UP) {
let title = "UptimeKuma Monitor Up";
return await this.postNotification(notification, title, msg, barkEndpoint, extra);
}
if (msg != null && heartbeatJSON != null && status === DOWN) {
let title = "UptimeKuma Monitor Down";
return await this.postNotification(notification, title, msg, barkEndpoint, extra);
}
if (msg != null) {
let title = "UptimeKuma Message";
return await this.postNotification(notification, title, msg, barkEndpoint, extra);
}
}
/**
* xpcool 定制:按告警状态生成 Bark 附加参数
* 所有项都可用通知 config 里的同名字段覆盖barkLevel / barkVolume / barkCall /
* barkBadge / barkImageDown / barkImageUp / barkBadgeReset无需改代码。
* @param {BeanModel} notification 通知配置
* @param {number|null} status 心跳状态0=DOWN 1=UP
* @returns {object} 追加到 Bark 请求上的参数
*/
statusParams(notification, status) {
const p = {};
if (status === DOWN) {
// 重要警告:无视静音与专注模式(手机上需在 Bark App 里允许「重要警告」)
p.level = notification.barkLevel || "critical";
p.volume = notification.barkVolume != null ? notification.barkVolume : 5;
// 持续响铃约 30 秒:默认关闭(避免半夜长时间吵闹),
// 想开启就在通知 config 里加 "barkCall": true
if (notification.barkCall === true) {
p.call = 1;
}
// 角标auto = 自动累加未处理告警数,也可填具体数字
p.badge = notification.barkBadge != null ? notification.barkBadge : "auto";
// 自动保存到通知中心,便于事后回看
p.isArchive = 1;
// 异常配图
p.image = notification.barkImageDown || IMAGE_DOWN;
} else if (status === UP) {
// 恢复配图
p.image = notification.barkImageUp || IMAGE_UP;
// 恢复时清掉角标(设 barkBadgeReset=false 可保留)
if (notification.barkBadgeReset !== false) {
p.badge = 0;
}
}
return p;
}
/**
* Add additional parameter for Bark v1 endpoints.
* Leads to better on device styles (iOS 15 optimized)
* @param {BeanModel} notification Notification to be sent
* @param {object} extra xpcool 定制:状态相关附加参数
* @returns {string} Additional URL parameters
*/
additionalParameters(notification, extra = {}) {
// xpcool 定制:图标改为自托管 PNG可被 config.barkIcon 覆盖)
let params = "?icon=" + encodeURIComponent(notification.barkIcon || barkNotificationAvatar);
// 推送消息分组
params += "&group=" + encodeURIComponent(notification.barkGroup || DEFAULT_GROUP);
// picked a sound, this should follow system's mute status when arrival
params += "&sound=" + encodeURIComponent(notification.barkSound || "telegraph");
// xpcool 定制追加状态相关参数level / volume / call / badge / image / isArchive
for (const key of Object.keys(extra)) {
const value = extra[key];
if (value === undefined || value === null || value === "") {
continue;
}
params += "&" + key + "=" + encodeURIComponent(value);
}
return params;
}
/**
* Check if result is successful
* @param {object} result Axios response object
* @returns {void}
* @throws {Error} The status code is not in range 2xx
*/
checkResult(result) {
if (result.status == null) {
throw new Error("Bark notification failed with invalid response!");
}
if (result.status < 200 || result.status >= 300) {
throw new Error("Bark notification failed with status code " + result.status);
}
}
/**
* Send the message
* @param {BeanModel} notification Notification to be sent
* @param {string} title Message title
* @param {string} subtitle Message
* @param {string} endpoint Endpoint to send request to
* @param {object} extra xpcool 定制:状态相关附加参数
* @returns {Promise<string>} Success message
*/
async postNotification(notification, title, subtitle, endpoint, extra = {}) {
let result;
let config = this.getAxiosConfigWithProxy({});
if (notification.apiVersion === "v1" || notification.apiVersion == null) {
// url encode title and subtitle
title = encodeURIComponent(title);
subtitle = encodeURIComponent(subtitle);
const params = this.additionalParameters(notification, extra);
result = await axios.get(`${endpoint}/${title}/${subtitle}${params}`, config);
} else {
// xpcool 定制v2(POST) 分支同样带上附加参数
const body = {
title,
body: subtitle,
icon: notification.barkIcon || barkNotificationAvatar,
sound: notification.barkSound || "telegraph",
group: notification.barkGroup || DEFAULT_GROUP,
};
for (const key of Object.keys(extra)) {
if (extra[key] !== undefined && extra[key] !== null) {
body[key] = extra[key];
}
}
result = await axios.post(endpoint, body, config);
}
this.checkResult(result);
if (result.statusText != null) {
return "Bark notification succeed: " + result.statusText;
}
// because returned in range 200 ..< 300
return successMessage;
}
}
module.exports = Bark;