初始化模版工程
This commit is contained in:
109
app/api/remote-control/config/route.ts
Normal file
109
app/api/remote-control/config/route.ts
Normal file
@@ -0,0 +1,109 @@
|
||||
import { NextRequest, NextResponse } from 'next/server'
|
||||
import { ConfigManager, reconnectAllPlatforms } from '@/remote-control/config/manager'
|
||||
|
||||
export async function GET() {
|
||||
const configManager = ConfigManager.getInstance()
|
||||
await configManager.ensureLoaded()
|
||||
const config = configManager.getMasked()
|
||||
return NextResponse.json(config)
|
||||
}
|
||||
|
||||
export async function PUT(request: NextRequest) {
|
||||
try {
|
||||
const body = await request.json()
|
||||
const configManager = ConfigManager.getInstance()
|
||||
await configManager.ensureLoaded()
|
||||
|
||||
// Replace masked values with existing real values so we don't overwrite secrets
|
||||
const merged = stripMaskedValues(body, configManager.get())
|
||||
|
||||
const validationError = validateConfig(merged)
|
||||
if (validationError) {
|
||||
return NextResponse.json(
|
||||
{ success: false, error: validationError },
|
||||
{ status: 400 }
|
||||
)
|
||||
}
|
||||
|
||||
// skipEmit: lifecycle is managed explicitly below, avoid double-triggering
|
||||
await configManager.update(merged, { skipEmit: true })
|
||||
|
||||
// After saving, explicitly manage bot lifecycle:
|
||||
// - Stop all disabled bots
|
||||
// - Reconnect (stop + start) all enabled bots
|
||||
const config = configManager.get()
|
||||
const errors: string[] = []
|
||||
|
||||
await reconnectAllPlatforms(config, errors)
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
message: errors.length > 0
|
||||
? `配置已保存,部分渠道连接异常: ${errors.join('; ')}`
|
||||
: '配置已保存并生效',
|
||||
})
|
||||
} catch (error) {
|
||||
return NextResponse.json(
|
||||
{ success: false, error: '保存配置失败' },
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const MASK_PREFIX = '••••'
|
||||
|
||||
/**
|
||||
* If the frontend sends back a masked value (e.g. "••••pbYI"), replace it
|
||||
* with the real value from the current config so we never overwrite secrets.
|
||||
*/
|
||||
function stripMaskedValues(
|
||||
incoming: Record<string, Record<string, unknown>>,
|
||||
current: Record<string, Record<string, unknown>>,
|
||||
): Record<string, Record<string, unknown>> {
|
||||
const result: Record<string, Record<string, unknown>> = {}
|
||||
for (const platform of Object.keys(incoming)) {
|
||||
const incomingPlatform = incoming[platform]
|
||||
const currentPlatform = current[platform] ?? {}
|
||||
const merged: Record<string, unknown> = {}
|
||||
for (const key of Object.keys(incomingPlatform)) {
|
||||
const val = incomingPlatform[key]
|
||||
if (typeof val === 'string' && val.startsWith(MASK_PREFIX)) {
|
||||
// Keep the real value
|
||||
merged[key] = currentPlatform[key] ?? ''
|
||||
} else {
|
||||
merged[key] = val
|
||||
}
|
||||
}
|
||||
result[platform] = merged
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
function validateConfig(config: Record<string, unknown>): string | null {
|
||||
const discord = config.discord as Record<string, unknown> | undefined
|
||||
const dingtalk = config.dingtalk as Record<string, unknown> | undefined
|
||||
const lark = config.lark as Record<string, unknown> | undefined
|
||||
|
||||
if (discord?.enabled && !discord?.botToken) {
|
||||
return 'Discord Bot Token 不能为空'
|
||||
}
|
||||
if (dingtalk?.enabled && (!dingtalk?.clientId || !dingtalk?.clientSecret)) {
|
||||
return '钉钉 Client ID 和 Client Secret 不能为空'
|
||||
}
|
||||
if (lark?.enabled) {
|
||||
if (!lark?.appId || !lark?.appSecret) {
|
||||
return '飞书 App ID 和 App Secret 不能为空'
|
||||
}
|
||||
}
|
||||
|
||||
const telegram = config.telegram as Record<string, unknown> | undefined
|
||||
const slack = config.slack as Record<string, unknown> | undefined
|
||||
|
||||
if (telegram?.enabled && !telegram?.botToken) {
|
||||
return 'Telegram Bot Token 不能为空'
|
||||
}
|
||||
if (slack?.enabled && (!slack?.botToken || !slack?.appToken)) {
|
||||
return 'Slack Bot Token 和 App Token 不能为空'
|
||||
}
|
||||
return null
|
||||
}
|
||||
Reference in New Issue
Block a user