app.js 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. const express = require('express');
  2. const cors = require('cors');
  3. const helmet = require('helmet');
  4. const compression = require('compression');
  5. require('dotenv').config();
  6. const logger = require('./utils/logger');
  7. const sequelize = require('./config/database');
  8. const routes = require('./api/routes');
  9. const Scheduler = require('./core/scheduler');
  10. const MultiSubscriptionManager = require('./core/multiSubscriptionManager');
  11. const BotManager = require('./core/botManager');
  12. const app = express();
  13. const PORT = process.env.PORT || 3000;
  14. // 中间件
  15. app.use(helmet({
  16. contentSecurityPolicy: {
  17. directives: {
  18. defaultSrc: ["'self'"],
  19. styleSrc: ["'self'", "'unsafe-inline'", "https://cdn.jsdelivr.net"],
  20. scriptSrc: ["'self'", "'unsafe-inline'", "https://cdn.jsdelivr.net"],
  21. scriptSrcAttr: ["'unsafe-inline'"],
  22. fontSrc: ["'self'", "https://cdn.jsdelivr.net", "data:"],
  23. imgSrc: ["'self'", "data:", "https:"],
  24. mediaSrc: ["'self'", "data:"],
  25. connectSrc: ["'self'"],
  26. frameSrc: ["'none'"],
  27. objectSrc: ["'none'"],
  28. upgradeInsecureRequests: []
  29. }
  30. }
  31. }));
  32. app.use(compression());
  33. app.use(cors());
  34. app.use(express.json({ limit: '10mb' }));
  35. app.use(express.urlencoded({ extended: true, limit: '10mb' }));
  36. // 静态文件服务
  37. app.use(express.static('public'));
  38. // 请求日志中间件 - 只记录重要请求
  39. app.use((req, res, next) => {
  40. // 只记录重要的API请求,不记录频繁的自动刷新请求
  41. if (req.path.startsWith('/api/') &&
  42. !req.path.includes('/favicon') &&
  43. !req.path.includes('/sw.js') &&
  44. !req.path.includes('/stats') &&
  45. !req.path.includes('/test/results')) {
  46. logger.info(`${req.method} ${req.path}`);
  47. }
  48. next();
  49. });
  50. // API路由
  51. app.use('/api', routes);
  52. // 健康检查
  53. app.get('/health', (req, res) => {
  54. res.json({
  55. status: 'ok',
  56. timestamp: new Date().toISOString(),
  57. uptime: process.uptime()
  58. });
  59. });
  60. // 根路径
  61. app.get('/', (req, res) => {
  62. res.json({
  63. name: 'Clash Speed Test',
  64. version: '1.0.0',
  65. description: 'Clash节点测速工具,支持定时监控和Telegram通知',
  66. endpoints: {
  67. health: '/health',
  68. api: '/api'
  69. }
  70. });
  71. });
  72. // 错误处理中间件
  73. app.use((err, req, res, next) => {
  74. logger.error('未处理的错误', {
  75. error: err.message,
  76. stack: err.stack,
  77. path: req.path,
  78. method: req.method
  79. });
  80. res.status(500).json({
  81. success: false,
  82. error: process.env.NODE_ENV === 'production' ? '服务器内部错误' : err.message
  83. });
  84. });
  85. // 404处理
  86. app.use('*', (req, res) => {
  87. res.status(404).json({
  88. success: false,
  89. error: '接口不存在'
  90. });
  91. });
  92. // 处理未捕获的Promise拒绝
  93. process.on('unhandledRejection', (reason, promise) => {
  94. logger.error('未处理的Promise拒绝', {
  95. reason: {
  96. code: reason.code,
  97. message: reason.message
  98. },
  99. promise: {
  100. isFulfilled: promise.isFulfilled,
  101. isRejected: promise.isRejected,
  102. rejectionReason: promise.rejectionReason
  103. }
  104. });
  105. });
  106. // 启动应用
  107. async function startApp() {
  108. try {
  109. // 测试数据库连接
  110. await sequelize.authenticate();
  111. logger.info('数据库连接成功');
  112. // 同步数据库模型
  113. await sequelize.sync({ alter: true });
  114. logger.info('数据库模型同步完成');
  115. // 启动调度器
  116. const scheduler = new Scheduler();
  117. scheduler.start();
  118. app.set('scheduler', scheduler);
  119. // 启动多订阅管理器
  120. const subscriptionManager = new MultiSubscriptionManager();
  121. subscriptionManager.startAutoUpdate();
  122. // 设置测速触发器
  123. subscriptionManager.setSpeedTestTrigger(() => {
  124. scheduler.runSpeedTest().catch(error => {
  125. logger.error('订阅更新后自动测速失败', { error: error.message });
  126. });
  127. });
  128. app.set('subscriptionManager', subscriptionManager);
  129. // 启动Telegram机器人管理器
  130. const botManager = new BotManager();
  131. app.set('botManager', botManager);
  132. // 检查是否启用启动时立即测速
  133. const enableStartupSpeedTest = process.env.ENABLE_SCHEDULED_SPEED_TEST !== 'false';
  134. if (enableStartupSpeedTest) {
  135. // 立即开始测速
  136. setTimeout(async () => {
  137. try {
  138. logger.info('应用启动后立即开始测速');
  139. await scheduler.runSpeedTest();
  140. } catch (error) {
  141. logger.error('启动测速失败', { error: error.message });
  142. }
  143. }, 3000); // 延迟3秒开始,确保应用完全启动
  144. } else {
  145. logger.info('启动时立即测速功能已禁用');
  146. }
  147. // 启动服务器
  148. app.listen(PORT, () => {
  149. logger.info(`服务器启动成功,端口: ${PORT}`);
  150. logger.info(`前端界面: http://localhost:${PORT}`);
  151. });
  152. } catch (error) {
  153. logger.error('应用启动失败', { error: error.message });
  154. process.exit(1);
  155. }
  156. }
  157. // 优雅关闭
  158. process.on('SIGTERM', async () => {
  159. logger.info('收到SIGTERM信号,开始优雅关闭');
  160. const scheduler = app.get('scheduler');
  161. if (scheduler) {
  162. scheduler.stop();
  163. }
  164. const subscriptionManager = app.get('subscriptionManager');
  165. if (subscriptionManager) {
  166. subscriptionManager.stopAutoUpdate();
  167. }
  168. const botManager = app.get('botManager');
  169. if (botManager) {
  170. botManager.stop();
  171. }
  172. await sequelize.close();
  173. logger.info('应用已关闭');
  174. process.exit(0);
  175. });
  176. process.on('SIGINT', async () => {
  177. logger.info('收到SIGINT信号,开始优雅关闭');
  178. const scheduler = app.get('scheduler');
  179. if (scheduler) {
  180. scheduler.stop();
  181. }
  182. const subscriptionManager = app.get('subscriptionManager');
  183. if (subscriptionManager) {
  184. subscriptionManager.stopAutoUpdate();
  185. }
  186. const botManager = app.get('botManager');
  187. if (botManager) {
  188. botManager.stop();
  189. }
  190. await sequelize.close();
  191. logger.info('应用已关闭');
  192. process.exit(0);
  193. });
  194. // 未捕获的异常处理
  195. process.on('uncaughtException', (error) => {
  196. logger.error('未捕获的异常', { error: error.message, stack: error.stack });
  197. process.exit(1);
  198. });
  199. process.on('unhandledRejection', (reason, promise) => {
  200. logger.error('未处理的Promise拒绝', { reason, promise });
  201. process.exit(1);
  202. });
  203. // 启动应用
  204. startApp();