| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102 |
- const db = require('../plugin/DataBase/db')
- const Redis = require('../plugin/DataBase/Redis')
- const CONFIG_KEYS = ['pay', 'email', 'unilogin', 'proxyForwardServer']
- const CACHE_TTL_SECONDS = 300
- class RuntimeConfigNotFoundError extends Error {
- constructor(key) {
- super(`未配置或未启用 ${key}`)
- this.name = 'RuntimeConfigNotFoundError'
- this.code = 'RUNTIME_CONFIG_NOT_FOUND'
- this.key = key
- }
- }
- function cacheKey(key) {
- return `runtimeConfig:${key}`
- }
- async function getRuntimeConfig(key, options = {}) {
- const { required = true, defaultValue = undefined } = options
- if (!CONFIG_KEYS.includes(key)) throw new Error('不支持的运行时配置')
- const cached = await Redis.get(cacheKey(key))
- if (cached) return JSON.parse(cached)
- const rows = await db.query(
- `SELECT config_value FROM runtime_configs
- WHERE config_key = ? AND enabled = 1
- ORDER BY is_default DESC, updated_at DESC LIMIT 1`,
- [key]
- )
- if (!rows?.[0]) {
- if (!required) return defaultValue
- throw new RuntimeConfigNotFoundError(key)
- }
- const value = typeof rows[0].config_value === 'object'
- ? rows[0].config_value
- : JSON.parse(rows[0].config_value)
- await Redis.set(cacheKey(key), JSON.stringify(value), { EX: CACHE_TTL_SECONDS })
- return value
- }
- async function getAllRuntimeConfigs() {
- const rows = await db.query(
- `SELECT config_key, config_name, config_value, enabled, is_default, updated_at, updated_by
- FROM runtime_configs ORDER BY config_key, is_default DESC, updated_at DESC`
- ) || []
- return rows.map(row => ({
- ...row,
- config_value: typeof row.config_value === 'object' ? row.config_value : JSON.parse(row.config_value)
- }))
- }
- function validateRuntimeConfig(key, value) {
- if (key === 'email') {
- if (!Array.isArray(value)) throw new Error('邮件配置必须为数组')
- return value.map((item, index) => ({ ...item, priority: Number(item.priority ?? index) }))
- .sort((a, b) => a.priority - b.priority)
- }
- if (!value || typeof value !== 'object' || Array.isArray(value)) throw new Error(`${key} 配置必须为对象`)
- if (key === 'pay' && (!Array.isArray(value.methods) || value.methods.some(item => !item?.type))) {
- throw new Error('付款方式配置无效')
- }
- return value
- }
- async function saveRuntimeConfig({ key, name = 'default', value, enabled = true, isDefault = false, updatedBy }) {
- if (!CONFIG_KEYS.includes(key)) throw new Error('不支持的运行时配置')
- const normalized = validateRuntimeConfig(key, value)
- const result = await db.query(
- `INSERT INTO runtime_configs (config_key, config_name, config_value, enabled, is_default, updated_at, updated_by)
- VALUES (?, ?, ?, ?, ?, ?, ?)
- ON DUPLICATE KEY UPDATE config_value = VALUES(config_value), enabled = VALUES(enabled),
- is_default = VALUES(is_default), updated_at = VALUES(updated_at), updated_by = VALUES(updated_by)`,
- [key, String(name).trim(), JSON.stringify(normalized), enabled ? 1 : 0, isDefault ? 1 : 0, Date.now(), updatedBy || null]
- )
- if (result === undefined) throw new Error('保存运行时配置失败')
- if (isDefault) {
- await db.query('UPDATE runtime_configs SET is_default = IF(config_name = ?, 1, 0) WHERE config_key = ?', [String(name).trim(), key])
- }
- await Redis.del(cacheKey(key))
- return normalized
- }
- async function selectRuntimeConfig({ key, name, updatedBy }) {
- if (!CONFIG_KEYS.includes(key) || !name) throw new Error('配置类型或名称无效')
- const result = await db.query(
- 'UPDATE runtime_configs SET is_default = IF(config_name = ?, 1, 0), updated_at = ?, updated_by = ? WHERE config_key = ?',
- [name, Date.now(), updatedBy || null, key]
- )
- if (result === undefined) throw new Error('切换运行时配置失败')
- await Redis.del(cacheKey(key))
- }
- module.exports = {
- CONFIG_KEYS,
- RuntimeConfigNotFoundError,
- getRuntimeConfig,
- getAllRuntimeConfigs,
- saveRuntimeConfig,
- selectRuntimeConfig
- }
|