config.js 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. /**
  2. * 配置路由模块
  3. */
  4. const express = require('express');
  5. const router = express.Router();
  6. const fs = require('fs').promises;
  7. const path = require('path');
  8. const logger = require('../logger');
  9. const { requireLogin } = require('../middleware/auth');
  10. const configService = require('../services/configService');
  11. // 修改配置文件路径,使用独立的配置文件
  12. const configFilePath = path.join(__dirname, '../data/config.json');
  13. // 默认配置
  14. const DEFAULT_CONFIG = {
  15. proxyDomain: 'registry-1.docker.io',
  16. logo: '',
  17. theme: 'light'
  18. };
  19. // 确保配置文件存在
  20. async function ensureConfigFile() {
  21. try {
  22. // 确保目录存在
  23. const dir = path.dirname(configFilePath);
  24. try {
  25. await fs.access(dir);
  26. } catch (error) {
  27. await fs.mkdir(dir, { recursive: true });
  28. logger.info(`创建目录: ${dir}`);
  29. }
  30. // 检查文件是否存在
  31. try {
  32. await fs.access(configFilePath);
  33. const data = await fs.readFile(configFilePath, 'utf8');
  34. return JSON.parse(data);
  35. } catch (error) {
  36. // 文件不存在或JSON解析错误,创建默认配置
  37. await fs.writeFile(configFilePath, JSON.stringify(DEFAULT_CONFIG, null, 2));
  38. logger.info(`创建默认配置文件: ${configFilePath}`);
  39. return DEFAULT_CONFIG;
  40. }
  41. } catch (error) {
  42. logger.error(`配置文件操作失败: ${error.message}`);
  43. // 出错时返回默认配置以确保API不会失败
  44. return DEFAULT_CONFIG;
  45. }
  46. }
  47. // 获取配置
  48. router.get('/config', async (req, res) => {
  49. try {
  50. const config = await ensureConfigFile();
  51. res.json(config);
  52. } catch (error) {
  53. logger.error('获取配置失败:', error);
  54. // 即使失败也返回默认配置
  55. res.json(DEFAULT_CONFIG);
  56. }
  57. });
  58. // 保存配置
  59. router.post('/config', async (req, res) => {
  60. try {
  61. const newConfig = req.body;
  62. // 验证请求数据
  63. if (!newConfig || typeof newConfig !== 'object') {
  64. return res.status(400).json({
  65. error: '无效的配置数据',
  66. details: '配置必须是一个对象'
  67. });
  68. }
  69. // 读取现有配置
  70. let existingConfig;
  71. try {
  72. existingConfig = await ensureConfigFile();
  73. } catch (error) {
  74. existingConfig = DEFAULT_CONFIG;
  75. }
  76. // 合并配置
  77. const mergedConfig = { ...existingConfig, ...newConfig };
  78. // 保存到文件
  79. await fs.writeFile(configFilePath, JSON.stringify(mergedConfig, null, 2));
  80. res.json({ success: true, message: '配置已保存' });
  81. } catch (error) {
  82. logger.error('保存配置失败:', error);
  83. res.status(500).json({
  84. error: '保存配置失败',
  85. details: error.message
  86. });
  87. }
  88. });
  89. // 获取监控配置
  90. router.get('/monitoring-config', async (req, res) => {
  91. logger.info('收到监控配置请求');
  92. try {
  93. logger.info('读取监控配置...');
  94. const config = await configService.getConfig();
  95. if (!config.monitoringConfig) {
  96. logger.info('监控配置不存在,创建默认配置');
  97. config.monitoringConfig = {
  98. notificationType: 'wechat',
  99. webhookUrl: '',
  100. telegramToken: '',
  101. telegramChatId: '',
  102. monitorInterval: 60,
  103. isEnabled: false
  104. };
  105. await configService.saveConfig(config);
  106. }
  107. logger.info('返回监控配置');
  108. res.json({
  109. notificationType: config.monitoringConfig.notificationType || 'wechat',
  110. webhookUrl: config.monitoringConfig.webhookUrl || '',
  111. telegramToken: config.monitoringConfig.telegramToken || '',
  112. telegramChatId: config.monitoringConfig.telegramChatId || '',
  113. monitorInterval: config.monitoringConfig.monitorInterval || 60,
  114. isEnabled: config.monitoringConfig.isEnabled || false
  115. });
  116. } catch (error) {
  117. logger.error('获取监控配置失败:', error);
  118. res.status(500).json({ error: '获取监控配置失败', details: error.message });
  119. }
  120. });
  121. // 保存监控配置
  122. router.post('/monitoring-config', requireLogin, async (req, res) => {
  123. try {
  124. const {
  125. notificationType,
  126. webhookUrl,
  127. telegramToken,
  128. telegramChatId,
  129. monitorInterval,
  130. isEnabled
  131. } = req.body;
  132. // 验证必填字段
  133. if (!notificationType) {
  134. return res.status(400).json({ error: '通知类型不能为空' });
  135. }
  136. // 根据通知类型验证对应的字段
  137. if (notificationType === 'wechat' && !webhookUrl) {
  138. return res.status(400).json({ error: '企业微信 Webhook URL 不能为空' });
  139. }
  140. if (notificationType === 'telegram' && (!telegramToken || !telegramChatId)) {
  141. return res.status(400).json({ error: 'Telegram Token 和 Chat ID 不能为空' });
  142. }
  143. // 保存配置
  144. const config = await configService.getConfig();
  145. config.monitoringConfig = {
  146. notificationType,
  147. webhookUrl: webhookUrl || '',
  148. telegramToken: telegramToken || '',
  149. telegramChatId: telegramChatId || '',
  150. monitorInterval: parseInt(monitorInterval) || 60,
  151. isEnabled: !!isEnabled
  152. };
  153. await configService.saveConfig(config);
  154. logger.info('监控配置已更新');
  155. res.json({ success: true, message: '监控配置已保存' });
  156. } catch (error) {
  157. logger.error('保存监控配置失败:', error);
  158. res.status(500).json({ error: '保存监控配置失败', details: error.message });
  159. }
  160. });
  161. // 测试通知
  162. router.post('/test-notification', requireLogin, async (req, res) => {
  163. try {
  164. const { notificationType, webhookUrl, telegramToken, telegramChatId } = req.body;
  165. // 验证参数
  166. if (!notificationType) {
  167. return res.status(400).json({ error: '通知类型不能为空' });
  168. }
  169. if (notificationType === 'wechat' && !webhookUrl) {
  170. return res.status(400).json({ error: '企业微信 Webhook URL 不能为空' });
  171. }
  172. if (notificationType === 'telegram' && (!telegramToken || !telegramChatId)) {
  173. return res.status(400).json({ error: 'Telegram Token 和 Chat ID 不能为空' });
  174. }
  175. // 构造测试消息
  176. const testMessage = {
  177. title: '测试通知',
  178. content: `这是一条测试通知消息,发送时间: ${new Date().toLocaleString('zh-CN')}`,
  179. type: 'info'
  180. };
  181. // 模拟发送通知
  182. logger.info('发送测试通知:', testMessage);
  183. // TODO: 实际发送通知的逻辑
  184. // 这里仅做模拟,实际应用中需要实现真正的通知发送逻辑
  185. // 返回成功
  186. res.json({ success: true, message: '测试通知已发送' });
  187. } catch (error) {
  188. logger.error('发送测试通知失败:', error);
  189. res.status(500).json({ error: '发送测试通知失败', details: error.message });
  190. }
  191. });
  192. // 导出路由
  193. module.exports = router;