app.js 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. const express = require('express');
  2. const cors = require('cors');
  3. const routes = require('./routes');
  4. const webhookRouter = require('./webhook/webhook');
  5. const logger = require('./logger'); // 引入日志记录器
  6. const fs = require('fs');
  7. const path = require('path');
  8. // 主应用服务器
  9. const app = express();
  10. // 记录应用启动信息
  11. logger.info('正在初始化应用服务器...');
  12. // 启用 CORS
  13. app.use(cors());
  14. logger.info('CORS 中间件已启用');
  15. // 解析 JSON 请求体
  16. app.use(express.json());
  17. logger.info('JSON 解析中间件已启用');
  18. // 解析 URL 编码的请求体
  19. app.use(express.urlencoded({ extended: true }));
  20. logger.info('URL 编码解析中间件已启用');
  21. // 请求日志中间件
  22. app.use((req, res, next) => {
  23. const start = Date.now();
  24. res.on('finish', () => {
  25. const duration = Date.now() - start;
  26. logger.info(`${req.method} ${req.originalUrl} - ${res.statusCode} - ${duration}ms`);
  27. });
  28. next();
  29. });
  30. // 加载路由
  31. app.use('/', routes); // 将主路由挂载到 /api 路径
  32. app.use('/', webhookRouter); // 将 Webhook 路由挂载到 /webhook 路径
  33. logger.info('路由模块已加载');
  34. // 404 处理
  35. app.use((req, res, next) => {
  36. logger.warn(`404 Not Found: ${req.method} ${req.originalUrl}`);
  37. res.status(404).json({
  38. success: false,
  39. message: '请求的资源不存在'
  40. });
  41. });
  42. // 错误处理中间件
  43. app.use((err, req, res, next) => {
  44. logger.error('应用错误:', err);
  45. logger.error('错误堆栈:', err.stack);
  46. res.status(500).json({
  47. success: false,
  48. message: '服务器内部错误'
  49. });
  50. });
  51. // 主服务器配置
  52. const MAIN_PORT = 3000;
  53. const MAIN_HOST = '0.0.0.0';
  54. // 启动主服务器
  55. app.listen(MAIN_PORT, MAIN_HOST, () => {
  56. logger.info(`主服务器已启动: http://${MAIN_HOST}:${MAIN_PORT}`);
  57. logger.info('主服务器配置信息:');
  58. logger.info(`- 监听端口: ${MAIN_PORT}`);
  59. logger.info(`- 监听地址: ${MAIN_HOST}`);
  60. logger.info(`- 环境: ${process.env.NODE_ENV || 'development'}`);
  61. });
  62. // OTA 服务器
  63. const otaApp = express();
  64. // 添加 JSON 解析中间件
  65. otaApp.use(express.json());
  66. otaApp.use(express.urlencoded({ extended: true }));
  67. // 固件文件路径
  68. const FIRMWARE_PATH = path.join(__dirname, '../sketch_feb24a.ino.bin'); // 确保固件文件与服务器代码在同一目录下
  69. // 最新固件版本
  70. const LATEST_FIRMWARE_VERSION = "1.0.4"; // 服务器上的最新固件版本
  71. // 需要更新的设备ID列表
  72. const TARGET_DEVICES = ["54:32:04:0C:ED:C8", ""]; // 替换为实际的设备ID
  73. // 修改检查更新路由
  74. otaApp.post('/check-update', (req, res) => {
  75. logger.debug('收到请求体:', req.body);
  76. if (!req.body || !req.body.device_id || !req.body.version) {
  77. logger.error('无效的请求体:', req.body);
  78. return res.status(400).json({
  79. success: false,
  80. message: '请求体必须包含 device_id 和 version 字段'
  81. });
  82. }
  83. // 获取设备ID和当前固件版本
  84. const { device_id, version } = req.body;
  85. logger.info(`收到设备ID: ${device_id}, 当前固件版本: ${version}`);
  86. // 检查设备是否需要更新
  87. if (TARGET_DEVICES.includes(device_id) && version !== LATEST_FIRMWARE_VERSION) {
  88. logger.info(`设备 ${device_id} 需要更新。`);
  89. res.send("update"); // 返回"update"表示需要更新
  90. } else {
  91. logger.info(`设备 ${device_id} 无需更新。`);
  92. res.send("no_update"); // 返回"no_update"表示无需更新
  93. }
  94. });
  95. // 固件下载路由
  96. otaApp.get('/firmware', (req, res) => {
  97. // 返回固件文件
  98. logger.info("正在下发固件...");
  99. if (fs.existsSync(FIRMWARE_PATH)) {
  100. res.download(FIRMWARE_PATH, (err) => {
  101. if (err) {
  102. logger.error("固件下发失败:", err);
  103. res.status(500).send("固件下发失败");
  104. }
  105. });
  106. } else {
  107. logger.error("固件文件未找到");
  108. res.status(404).send("固件文件未找到");
  109. }
  110. });
  111. // OTA 服务器配置
  112. const OTA_PORT = 2999;
  113. const OTA_HOST = '0.0.0.0';
  114. // 启动 OTA 服务器
  115. otaApp.listen(OTA_PORT, OTA_HOST, () => {
  116. logger.info(`OTA 服务器已启动: http://${OTA_HOST}:${OTA_PORT}`);
  117. logger.info('OTA 服务器配置信息:');
  118. logger.info(`- 监听端口: ${OTA_PORT}`);
  119. logger.info(`- 监听地址: ${OTA_HOST}`);
  120. });
  121. // 捕获未处理的异常
  122. process.on('uncaughtException', (err) => {
  123. logger.error('未捕获的异常:', err);
  124. logger.error('错误堆栈:', err.stack);
  125. // 给进程一点时间来记录日志
  126. setTimeout(() => {
  127. process.exit(1);
  128. }, 1000);
  129. });
  130. // 捕获未处理的 Promise 拒绝
  131. process.on('unhandledRejection', (reason, promise) => {
  132. logger.error('未处理的 Promise 拒绝:', reason);
  133. logger.error('Promise:', promise);
  134. });
  135. // 优雅关闭
  136. process.on('SIGTERM', () => {
  137. logger.info('收到 SIGTERM 信号,准备关闭服务器...');
  138. // 在这里可以添加清理代码
  139. process.exit(0);
  140. });
  141. process.on('SIGINT', () => {
  142. logger.info('收到 SIGINT 信号,准备关闭服务器...');
  143. // 在这里可以添加清理代码
  144. process.exit(0);
  145. });
  146. // app.use('/', otaRouter); // 修改
  147. // app.use('/', otaRouter);
  148. module.exports = app;