后端迁移通知服务
This commit is contained in:
@@ -0,0 +1,107 @@
|
||||
import fs from 'node:fs'
|
||||
import path from 'node:path'
|
||||
|
||||
import { PROJECT_ROOT } from '../../config/runtime.js'
|
||||
|
||||
const NOTIFICATION_CONFIG_FILE_PATH = path.join(PROJECT_ROOT, 'data', 'notification-config.json')
|
||||
const DEFAULT_BARK_SERVER_URL = 'https://api.day.app'
|
||||
|
||||
type JsonObject = Record<string, any>
|
||||
|
||||
export function getNotificationConfigFilePath() {
|
||||
return NOTIFICATION_CONFIG_FILE_PATH
|
||||
}
|
||||
|
||||
export function getNotificationConfig() {
|
||||
return loadNotificationConfigFromFile()
|
||||
}
|
||||
|
||||
export function saveNotificationConfig(rawValue: unknown) {
|
||||
const normalized = normalizeNotificationConfig(rawValue)
|
||||
fs.mkdirSync(path.dirname(NOTIFICATION_CONFIG_FILE_PATH), { recursive: true })
|
||||
fs.writeFileSync(NOTIFICATION_CONFIG_FILE_PATH, `${JSON.stringify(normalized, null, 2)}\n`, 'utf8')
|
||||
return normalized
|
||||
}
|
||||
|
||||
export function listEnabledBarkRecipients(config: JsonObject = getNotificationConfig()) {
|
||||
if (config.enabled === false || config.channels?.bark?.enabled === false) {
|
||||
return []
|
||||
}
|
||||
|
||||
return (Array.isArray(config.channels?.bark?.recipients) ? config.channels.bark.recipients : [])
|
||||
.filter((item) => item.enabled !== false && String(item.deviceKey || '').trim())
|
||||
}
|
||||
|
||||
function loadNotificationConfigFromFile() {
|
||||
if (!fs.existsSync(NOTIFICATION_CONFIG_FILE_PATH)) {
|
||||
return createDefaultNotificationConfig()
|
||||
}
|
||||
|
||||
try {
|
||||
const rawText = fs.readFileSync(NOTIFICATION_CONFIG_FILE_PATH, 'utf8')
|
||||
return normalizeNotificationConfig(JSON.parse(rawText))
|
||||
} catch {
|
||||
return createDefaultNotificationConfig()
|
||||
}
|
||||
}
|
||||
|
||||
function normalizeNotificationConfig(rawValue: unknown) {
|
||||
const source = isPlainObject(rawValue) ? rawValue : {}
|
||||
const bark = isPlainObject(source.channels?.bark) ? source.channels.bark : {}
|
||||
|
||||
return {
|
||||
enabled: typeof source.enabled === 'boolean' ? source.enabled : true,
|
||||
channels: {
|
||||
bark: {
|
||||
enabled: typeof bark.enabled === 'boolean' ? bark.enabled : true,
|
||||
serverUrl: normalizeBarkServerUrl(bark.serverUrl),
|
||||
recipients: (Array.isArray(bark.recipients) ? bark.recipients : [])
|
||||
.map((item) => normalizeBarkRecipient(item))
|
||||
.filter(Boolean),
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
function normalizeBarkRecipient(rawValue: unknown) {
|
||||
if (!isPlainObject(rawValue)) {
|
||||
return null
|
||||
}
|
||||
|
||||
const name = String(rawValue.name || '').trim()
|
||||
const deviceKey = String(rawValue.deviceKey || '').trim()
|
||||
const id = String(rawValue.id || deviceKey || name || '').trim()
|
||||
|
||||
if (!name && !deviceKey) {
|
||||
return null
|
||||
}
|
||||
|
||||
return {
|
||||
id,
|
||||
name,
|
||||
deviceKey,
|
||||
enabled: typeof rawValue.enabled === 'boolean' ? rawValue.enabled : true,
|
||||
}
|
||||
}
|
||||
|
||||
function normalizeBarkServerUrl(value: unknown) {
|
||||
const normalized = String(value || DEFAULT_BARK_SERVER_URL).trim() || DEFAULT_BARK_SERVER_URL
|
||||
return normalized.replace(/\/+$/, '')
|
||||
}
|
||||
|
||||
function createDefaultNotificationConfig() {
|
||||
return {
|
||||
enabled: true,
|
||||
channels: {
|
||||
bark: {
|
||||
enabled: true,
|
||||
serverUrl: DEFAULT_BARK_SERVER_URL,
|
||||
recipients: [],
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
function isPlainObject(value: unknown): value is JsonObject {
|
||||
return Object.prototype.toString.call(value) === '[object Object]'
|
||||
}
|
||||
Reference in New Issue
Block a user