app.ts 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. // Auto-deploy test comment
  2. import Koa from 'koa';
  3. import cors from '@koa/cors';
  4. import Router from '@koa/router';
  5. import bodyParser from '@koa/bodyparser';
  6. import koaBody from 'koa-body';
  7. import serve from 'koa-static';
  8. import mount from 'koa-mount';
  9. import path from 'path';
  10. import http from 'http';
  11. import { config } from './config';
  12. import { connectDatabase } from './models';
  13. import { errorHandler } from './middleware/errorHandler';
  14. import { requestLogger } from './services/requestLogger';
  15. import { httpLogger } from './services/logger.service';
  16. import { redisService } from './services/redis.service';
  17. import { ossService } from './services/oss.service';
  18. import { storageService } from './services/storage.service';
  19. import { queueService } from './services/queue.service';
  20. import { initBookGenerationQueue, resumeInterruptedTasks } from './modules/book-generator/book-queue.processor';
  21. import { websocketService } from './services/websocket.service';
  22. import { initSentry, sentryErrorHandler } from './services/sentry.service';
  23. import { xssProtection, sqlInjectionProtection } from './middleware/security';
  24. import { performanceMonitor, getMetrics } from './middleware/performance';
  25. import { apiRateLimiter } from './middleware/rate-limiter';
  26. import logRoutes from './services/log.controller';
  27. import authRoutes from './modules/auth/auth.controller';
  28. import ttsRoutes from './modules/tts/tts.controller';
  29. import memberRoutes from './modules/member/member.controller';
  30. import shareRoutes from './modules/share/share.controller';
  31. import playerRoutes from './modules/player/player.controller';
  32. import favoritesRoutes from './modules/favorites/favorites.controller';
  33. import preferencesRoutes from './modules/preferences/preferences.controller';
  34. import searchRoutes from './modules/search/search.controller';
  35. import categoriesRoutes from './modules/categories/categories.controller';
  36. import commentsRoutes from './modules/comments/comments.controller';
  37. import notificationsRoutes from './modules/notifications/notifications.controller';
  38. import bgmRoutes from './modules/bgm/bgm.controller';
  39. import audioEditRoutes from './modules/audioedit/audioedit.controller';
  40. import langGraphRoutes from './modules/book-generator/langgraph-controller';
  41. import aiGenerateRoutes from './modules/book-generator/ai-generate-controller';
  42. import albumRoutes from './modules/book-generator/album-controller';
  43. import albumManagementRoutes from './modules/book-generator/album-management.controller';
  44. import playlistRoutes from './modules/player/playlist.controller';
  45. import draftsRoutes from './modules/drafts/drafts.controller';
  46. import videoGeneratorRoutes from './modules/video-generator/video-generator.controller';
  47. import publishRoutes from './modules/publish/publish.controller';
  48. import signRoutes from './modules/sign/sign.controller';
  49. import subscriptionRoutes from './modules/subscription/subscription.controller';
  50. import paymentRoutes from './modules/payment/payment.controller';
  51. import historyRoutes from './modules/history/history.controller';
  52. import historyBatchRoutes from './modules/history/history-batch.controller';
  53. import { initializePlans } from './modules/subscription/subscription.service';
  54. const app = new Koa();
  55. const router = new Router();
  56. // 创建 HTTP 服务器
  57. const server = http.createServer(app.callback());
  58. // 中间件
  59. app.use(errorHandler);
  60. app.use(sentryErrorHandler()); // Sentry 错误监控
  61. app.use(performanceMonitor()); // 性能监控
  62. app.use(httpLogger); // Winston 日志
  63. app.use(xssProtection()); // XSS 防护
  64. app.use(sqlInjectionProtection()); // SQL 注入防护
  65. app.use(cors({
  66. origin: '*',
  67. allowMethods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
  68. allowHeaders: ['Content-Type', 'Authorization'],
  69. }));
  70. // app.use(apiRateLimiter); // 全局限流 - 已关闭
  71. app.use(koaBody({
  72. multipart: true,
  73. formidable: {
  74. uploadDir: path.join(process.cwd(), 'uploads', 'materials'),
  75. keepExtensions: true,
  76. maxFileSize: 100 * 1024 * 1024, // 100MB
  77. },
  78. }));
  79. // 静态文件服务 - 音频文件
  80. app.use(mount('/uploads', serve(config.upload.dir)));
  81. // 静态文件服务 - 视频文件
  82. app.use(mount('/videos', serve(path.join(process.cwd(), 'public', 'videos'))));
  83. // 健康检查
  84. router.get('/health', (ctx) => {
  85. ctx.body = { code: 0, message: 'ok', data: { status: 'healthy' } };
  86. });
  87. // 性能指标
  88. router.get('/api/metrics', getMetrics);
  89. // 注册路由
  90. router.use('/api/auth', authRoutes.routes());
  91. router.use('/api/tts', ttsRoutes.routes());
  92. router.use('/api/member', memberRoutes.routes());
  93. router.use('/api/share', shareRoutes.routes());
  94. router.use('/api/player', playerRoutes.routes());
  95. router.use('/api/favorites', favoritesRoutes.routes());
  96. router.use('/api/user/preferences', preferencesRoutes.routes());
  97. router.use('/api/search', searchRoutes.routes());
  98. router.use('/api/categories', categoriesRoutes.routes());
  99. router.use('/api/comments', commentsRoutes.routes());
  100. router.use('/api/notifications', notificationsRoutes.routes());
  101. router.use('/api/bgm', bgmRoutes.routes());
  102. router.use('/api/audio', audioEditRoutes.routes());
  103. router.use('/api/book-generator/langgraph', langGraphRoutes.routes());
  104. router.use('/api/book-generator', aiGenerateRoutes.routes());
  105. router.use('/api/book-generator', albumRoutes.routes());
  106. router.use('/api/book-generator/album', albumManagementRoutes.routes());
  107. router.use('/api/playlists', playlistRoutes.routes());
  108. router.use('/api/drafts', draftsRoutes.routes());
  109. router.use('/api/history', historyRoutes.routes());
  110. router.use('/api/history', historyBatchRoutes.routes());
  111. router.use('/api/video', videoGeneratorRoutes.routes());
  112. router.use('/api/sign', signRoutes.routes());
  113. router.use('/api/subscription', subscriptionRoutes.routes());
  114. router.use('/api/payment', paymentRoutes.routes());
  115. router.use('/api/publish', publishRoutes.routes());
  116. router.use('/api', logRoutes.routes());
  117. app.use(router.routes()).use(router.allowedMethods());
  118. // 启动服务
  119. async function start() {
  120. try {
  121. // 0. 初始化 Sentry
  122. initSentry();
  123. // 1. 连接数据库
  124. await connectDatabase();
  125. console.log('✅ MySQL 连接成功');
  126. // 2. 测试 Redis 连接
  127. const redisOk = await redisService.testConnection();
  128. console.log(redisOk ? '✅ Redis 连接成功' : '⚠️ Redis 连接失败(缓存功能将不可用)');
  129. // 3. 测试存储连接
  130. const storageOk = await storageService.testConnection();
  131. const storageType = storageService.getStorageType();
  132. console.log(storageOk
  133. ? `✅ 存储连接成功 (${storageType === 'oss' ? '阿里云 OSS' : '本地存储'})`
  134. : '⚠️ 存储连接失败');
  135. // 4. 初始化订阅套餐数据
  136. await initializePlans();
  137. // 5. 初始化 WebSocket
  138. websocketService.initialize(server);
  139. // 6. 启动服务
  140. server.listen(config.port, () => {
  141. console.log(`🚀 服务启动成功: http://localhost:${config.port}`);
  142. console.log(`📁 上传目录: ${config.upload.dir}`);
  143. console.log(`💾 存储模式: ${storageType === 'oss' ? '阿里云 OSS' : '本地存储'}`);
  144. console.log(`⚡ 缓存模式: ${redisOk ? 'Redis' : '内存'}`);
  145. console.log(`🔌 WebSocket: ws://localhost:${config.port}/ws`);
  146. console.log(`\n💡 提示: 修改 .env 中的 STORAGE_TYPE 可切换存储模式`);
  147. });
  148. // 7. 初始化书籍生成队列处理器
  149. initBookGenerationQueue();
  150. // 自动恢复中断的任务
  151. resumeInterruptedTasks();
  152. // 7. 优雅关闭
  153. process.on('SIGTERM', async () => {
  154. console.log('收到 SIGTERM 信号,正在关闭服务...');
  155. websocketService.close();
  156. await queueService.closeAll();
  157. await redisService.disconnect();
  158. process.exit(0);
  159. });
  160. process.on('SIGINT', async () => {
  161. console.log('收到 SIGINT 信号,正在关闭服务...');
  162. websocketService.close();
  163. await queueService.closeAll();
  164. await redisService.disconnect();
  165. process.exit(0);
  166. });
  167. } catch (error) {
  168. console.error('❌ 服务启动失败:', error);
  169. process.exit(1);
  170. }
  171. }
  172. start();