File size: 5,264 Bytes
146bdba
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
import express from 'express';
import { fileURLToPath } from 'url';
import { dirname, join } from 'path';
import { createLogger } from './utils/logger.js';
import { config, validateConfig } from './config/index.js';
import { notionClient } from './services/NotionClient.js';
import { streamManager } from './services/StreamManager.js';
import { proxyPool } from './ProxyPool.js';
import { proxyServer } from './ProxyServer.js';
import { requestLogger, errorHandler, requestLimits } from './middleware/auth.js';
import apiRouter from './routes/api.js';

// 获取当前目录
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

const logger = createLogger('App');

/**

 * 应用程序类

 * 负责初始化和管理整个应用

 */
class Application {
  constructor() {
    this.app = express();
    this.server = null;
  }
  
  /**

   * 配置Express中间件

   */
  configureMiddleware() {
    // 请求体解析
    this.app.use(express.json(requestLimits.json));
    this.app.use(express.urlencoded(requestLimits.urlencoded));
    
    // 静态文件服务
    const publicPath = join(dirname(__dirname), 'public');
    this.app.use(express.static(publicPath));
    
    // 管理界面路由
    this.app.get('/admin', (req, res) => {
      res.sendFile(join(publicPath, 'admin.html'));
    });
    
    // 请求日志
    this.app.use(requestLogger);
    
    // API路由
    this.app.use(apiRouter);
    
    // 错误处理(必须放在最后)
    this.app.use(errorHandler);
  }
  
  /**

   * 初始化服务

   */
  async initializeServices() {
    // 验证配置
    const configErrors = validateConfig();
    if (configErrors.length > 0) {
      throw new Error(`配置错误:\n${configErrors.join('\n')}`);
    }
    
    // 初始化代理服务器
    if (config.proxy.enableServer) {
      try {
        await proxyServer.start();
        logger.success('代理服务器启动成功');
      } catch (error) {
        logger.error(`启动代理服务器失败: ${error.message}`);
        // 代理服务器启动失败不应该阻止应用启动
      }
    }
    
    // 初始化Notion客户端
    await notionClient.initialize();
    
    // 初始化代理池
    if (config.proxy.useNativePool) {
      logger.info('正在初始化本地代理池...');
      proxyPool.logLevel = 'info';
      proxyPool.showProgressBar = true;
      proxyPool.setCountry(config.proxy.country);
      await proxyPool.initialize();
      logger.success(`代理池初始化完成,当前代理国家: ${proxyPool.proxyCountry}`);
    }
  }
  
  /**

   * 启动应用

   */
  async start() {
    try {
      // 初始化服务
      await this.initializeServices();
      
      // 配置中间件
      this.configureMiddleware();
      
      // 启动服务器
      this.server = this.app.listen(config.server.port, () => {
        logger.info(`服务已启动 - 端口: ${config.server.port}`);
        logger.info(`访问地址: http://localhost:${config.server.port}`);
        logger.info(`管理界面: http://localhost:${config.server.port}/admin`);
        
        const status = notionClient.getStatus();
        if (status.initialized) {
          logger.success('系统初始化状态: ✅');
          logger.success(`可用cookie数量: ${status.validCookies}`);
        } else {
          logger.warning('系统初始化状态: ❌');
          logger.warning('警告: 系统未成功初始化,API调用将无法正常工作');
          logger.warning('请检查NOTION_COOKIE配置是否有效');
        }
      });
      
    } catch (error) {
      logger.error(`应用启动失败: ${error.message}`, error);
      process.exit(1);
    }
  }
  
  /**

   * 优雅关闭应用

   */
  async shutdown() {
    logger.info('正在关闭应用...');
    
    // 关闭所有活跃流
    streamManager.closeAll();
    
    // 关闭代理服务器
    if (proxyServer) {
      try {
        proxyServer.stop();
        logger.info('代理服务器已关闭');
      } catch (error) {
        logger.error(`关闭代理服务器时出错: ${error.message}`);
      }
    }
    
    // 关闭Express服务器
    if (this.server) {
      await new Promise((resolve) => {
        this.server.close(resolve);
      });
      logger.info('HTTP服务器已关闭');
    }
    
    logger.success('应用已优雅关闭');
  }
}

// 创建应用实例
const application = new Application();

// 注册进程信号处理
process.on('SIGINT', handleShutdown);
process.on('SIGTERM', handleShutdown);
process.on('SIGQUIT', handleShutdown);

async function handleShutdown(signal) {
  logger.info(`收到${signal}信号,正在关闭应用...`);
  await application.shutdown();
  process.exit(0);
}

// 处理未捕获的异常
process.on('uncaughtException', (error) => {
  logger.error('未捕获的异常:', error);
  process.exit(1);
});

process.on('unhandledRejection', (reason, promise) => {
  logger.error('未处理的Promise拒绝:', reason);
  process.exit(1);
});

application.start();

export { application };