355 lines
10 KiB
JavaScript
355 lines
10 KiB
JavaScript
const express = require('express');
|
|
const cors = require('cors');
|
|
const path = require('path');
|
|
const fs = require('fs');
|
|
|
|
// 导入logger
|
|
const { defaultLogger } = require('./utils/logger');
|
|
|
|
// 导入中间件
|
|
const { errorHandler } = require('./middleware/errorHandler');
|
|
const { loggerMiddleware } = require('./middleware/logger');
|
|
const { corsMiddleware } = require('./middleware/cors');
|
|
const { bodyParserMiddleware } = require('./middleware/bodyParser');
|
|
const { staticFilesMiddleware } = require('./middleware/staticFiles');
|
|
const { backendInjector } = require('./middleware/backendInjector');
|
|
|
|
// 导入路由配置
|
|
const { setupRoutes } = require('./routes');
|
|
|
|
// 导入核心模块
|
|
const PixivBackend = require('./core');
|
|
const proxyConfig = require('./config');
|
|
|
|
// 创建logger实例
|
|
const logger = defaultLogger.child('Server');
|
|
|
|
class PixivServer {
|
|
constructor() {
|
|
this.server = null;
|
|
this.backend = null;
|
|
}
|
|
|
|
/**
|
|
* 加载配置文件
|
|
*/
|
|
loadConfig() {
|
|
// 检测是否在pkg打包环境中运行
|
|
const isPackaged = process.pkg !== undefined;
|
|
|
|
// 在打包环境中,配置文件在当前工作目录;在开发环境中,配置文件在上级目录
|
|
const configPath = isPackaged
|
|
? path.join(process.cwd(), 'config.json') // 打包环境:当前工作目录
|
|
: path.join(__dirname, '..', 'config.json'); // 开发环境:上级目录
|
|
let config = {
|
|
server: {
|
|
port: 3000,
|
|
autoOpenBrowser: true
|
|
},
|
|
proxy: {
|
|
port: null,
|
|
enabled: false
|
|
},
|
|
logging: {
|
|
level: "INFO"
|
|
},
|
|
system: {
|
|
threadPoolSize: 16
|
|
}
|
|
};
|
|
|
|
try {
|
|
logger.info(`检测环境: ${isPackaged ? '打包环境' : '开发环境'}`);
|
|
logger.info(`配置文件路径: ${configPath}`);
|
|
|
|
if (fs.existsSync(configPath)) {
|
|
const configData = fs.readFileSync(configPath, 'utf8');
|
|
const userConfig = JSON.parse(configData);
|
|
|
|
// 合并配置,用户配置覆盖默认配置
|
|
config = {
|
|
...config,
|
|
server: { ...config.server, ...userConfig.server },
|
|
proxy: { ...config.proxy, ...userConfig.proxy },
|
|
logging: { ...config.logging, ...userConfig.logging },
|
|
system: { ...config.system, ...userConfig.system }
|
|
};
|
|
logger.info('已加载配置文件');
|
|
} else {
|
|
// 如果配置文件不存在,创建默认配置文件
|
|
fs.writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf8');
|
|
logger.info('已创建默认配置文件:', configPath);
|
|
}
|
|
} catch (error) {
|
|
logger.error('读取配置文件失败,使用默认配置:', error.message);
|
|
}
|
|
|
|
return config;
|
|
}
|
|
|
|
/**
|
|
* 应用配置到环境变量
|
|
*/
|
|
applyConfig(config) {
|
|
// 设置线程池大小
|
|
if (!process.env.UV_THREADPOOL_SIZE) {
|
|
process.env.UV_THREADPOOL_SIZE = config.system.threadPoolSize.toString();
|
|
}
|
|
|
|
// 设置环境变量
|
|
process.env.NODE_ENV = process.env.NODE_ENV || 'development';
|
|
|
|
// 设置日志级别环境变量
|
|
if (config.logging.level) {
|
|
process.env.LOG_LEVEL = config.logging.level.toLowerCase();
|
|
}
|
|
|
|
// 如果配置了代理,设置环境变量
|
|
if (config.proxy.enabled === true || (config.proxy.enabled === "auto" && config.proxy.port)) {
|
|
// 显式配置代理端口
|
|
if (config.proxy.port) {
|
|
process.env.PROXY_PORT = config.proxy.port.toString();
|
|
logger.info(`代理端口已设置为: ${config.proxy.port}`);
|
|
}
|
|
} else if (config.proxy.enabled === "auto") {
|
|
// 自动检测系统代理
|
|
const systemProxy = process.env.HTTP_PROXY || process.env.HTTPS_PROXY || process.env.http_proxy || process.env.https_proxy;
|
|
if (systemProxy) {
|
|
logger.info(`检测到系统代理: ${systemProxy}`);
|
|
// 从系统代理URL中提取端口
|
|
const match = systemProxy.match(/http:\/\/127\.0\.0\.1:(\d+)/);
|
|
if (match) {
|
|
process.env.PROXY_PORT = match[1];
|
|
logger.info(`自动设置代理端口为: ${match[1]}`);
|
|
}
|
|
} else {
|
|
logger.info('未检测到系统代理,将尝试使用系统代理环境变量');
|
|
}
|
|
}
|
|
|
|
// 设置服务器端口
|
|
if (config.server.port) {
|
|
process.env.PORT = config.server.port.toString();
|
|
logger.info(`服务器端口已设置为: ${config.server.port}`);
|
|
}
|
|
|
|
// 设置自动打开浏览器选项
|
|
if (config.server.autoOpenBrowser !== undefined) {
|
|
process.env.AUTO_OPEN_BROWSER = config.server.autoOpenBrowser.toString();
|
|
logger.info(`自动打开浏览器: ${config.server.autoOpenBrowser ? '启用' : '禁用'}`);
|
|
}
|
|
|
|
logger.info(`日志级别: ${config.logging.level}`);
|
|
}
|
|
|
|
/**
|
|
* 初始化服务器
|
|
*/
|
|
async init() {
|
|
this.app = express();
|
|
this.port = parseInt(process.env.PORT) || 3000;
|
|
this.logLevel = process.env.LOG_LEVEL || 'info';
|
|
this.isVerboseMode = ['debug', 'trace'].includes(this.logLevel.toLowerCase());
|
|
|
|
logger.info('初始化 Pixiv 服务器...');
|
|
logger.info(`服务器端口: ${this.port}`);
|
|
logger.info(`日志级别: ${this.logLevel}`);
|
|
|
|
// 初始化后端核心
|
|
this.backend = new PixivBackend();
|
|
await this.backend.init();
|
|
|
|
// 设置中间件
|
|
this.setupMiddleware();
|
|
|
|
// 设置路由
|
|
this.setupRoutes();
|
|
|
|
logger.info('服务器初始化完成');
|
|
}
|
|
|
|
/**
|
|
* 配置中间件
|
|
*/
|
|
setupMiddleware() {
|
|
// 自定义日志中间件
|
|
this.app.use(loggerMiddleware);
|
|
|
|
// CORS 中间件
|
|
this.app.use(corsMiddleware());
|
|
|
|
// Body Parser 中间件
|
|
this.app.use(bodyParserMiddleware());
|
|
|
|
// 静态文件服务中间件
|
|
const staticMiddlewares = staticFilesMiddleware();
|
|
this.app.use('/downloads', staticMiddlewares[0]); // 下载文件静态服务
|
|
this.app.use(staticMiddlewares[1]); // 前端静态文件服务
|
|
|
|
// 后端实例注入中间件
|
|
this.app.use(backendInjector(this.backend));
|
|
|
|
// 将服务器实例保存到app.locals中,供路由使用
|
|
this.app.locals.serverInstance = this;
|
|
}
|
|
|
|
/**
|
|
* 配置路由
|
|
*/
|
|
setupRoutes() {
|
|
setupRoutes(this.app, this.backend);
|
|
}
|
|
|
|
/**
|
|
* 配置错误处理
|
|
*/
|
|
setupErrorHandling() {
|
|
this.app.use(errorHandler);
|
|
}
|
|
|
|
/**
|
|
* 启动服务器
|
|
*/
|
|
start() {
|
|
this.server = this.app.listen(this.port, () => {
|
|
logger.info('Pixiv 后端服务器已启动');
|
|
logger.info(`服务地址: http://localhost:${this.port}`);
|
|
logger.info(`健康检查: http://localhost:${this.port}/health`);
|
|
logger.info(`登录状态: ${this.backend.isLoggedIn ? '已登录' : '未登录'}`);
|
|
if (this.backend.isLoggedIn) {
|
|
logger.info(`用户: ${this.backend.config.user?.account}`);
|
|
}
|
|
if (this.isVerboseMode) {
|
|
logger.info(`日志级别: ${this.logLevel.toUpperCase()}`);
|
|
logger.debug(`服务器端口: ${this.port}`);
|
|
logger.debug(`代理端口: ${process.env.PROXY_PORT || '未设置'}`);
|
|
}
|
|
logger.info('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
|
|
// 自动打开浏览器
|
|
if (process.env.AUTO_OPEN_BROWSER === 'true') {
|
|
this.openBrowser();
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* 打开浏览器
|
|
*/
|
|
openBrowser() {
|
|
const url = `http://localhost:${this.port}`;
|
|
logger.info(`正在打开浏览器: ${url}`);
|
|
|
|
const { spawn } = require('child_process');
|
|
const os = require('os');
|
|
const fs = require('fs');
|
|
const platform = os.platform();
|
|
|
|
// 在服务器环境中直接跳过打开浏览器
|
|
if (platform === 'linux') {
|
|
// 直接跳过 Linux 服务器环境的浏览器打开
|
|
logger.info('在 Linux 服务器环境中,跳过打开浏览器');
|
|
return;
|
|
}
|
|
|
|
let command;
|
|
let args = [url];
|
|
|
|
switch (platform) {
|
|
case 'win32':
|
|
command = 'cmd';
|
|
args = ['/c', 'start', '""', url];
|
|
break;
|
|
case 'darwin':
|
|
command = 'open';
|
|
break;
|
|
default:
|
|
logger.warn('不支持的操作系统,无法自动打开浏览器');
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const child = spawn(command, args, {
|
|
detached: true,
|
|
stdio: 'ignore',
|
|
});
|
|
|
|
// 添加错误处理
|
|
child.on('error', (err) => {
|
|
logger.warn('打开浏览器失败:', err.message);
|
|
});
|
|
|
|
child.unref();
|
|
logger.info('浏览器打开命令已执行');
|
|
} catch (error) {
|
|
logger.warn('打开浏览器失败:', error.message);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 重启服务器
|
|
*/
|
|
async restart() {
|
|
logger.info('正在重启服务器...');
|
|
|
|
try {
|
|
// 关闭当前服务器
|
|
if (this.server) {
|
|
await new Promise((resolve) => {
|
|
this.server.close(() => {
|
|
logger.info('HTTP服务器已关闭');
|
|
resolve();
|
|
});
|
|
});
|
|
}
|
|
|
|
// 清理后端实例
|
|
if (this.backend) {
|
|
await this.backend.cleanup?.();
|
|
}
|
|
|
|
// 重新加载配置文件
|
|
const config = this.loadConfig();
|
|
|
|
// 重新应用配置到环境变量
|
|
this.applyConfig(config);
|
|
|
|
// 重新初始化并启动
|
|
await this.init();
|
|
await this.start();
|
|
|
|
logger.info('服务器重启成功');
|
|
return { success: true, message: '服务器重启成功' };
|
|
|
|
} catch (error) {
|
|
logger.error('服务器重启失败:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 优雅关闭
|
|
*/
|
|
async shutdown() {
|
|
logger.info('正在关闭服务器...');
|
|
logger.info('服务器已关闭');
|
|
process.exit(0);
|
|
}
|
|
}
|
|
|
|
// 如果直接运行此文件
|
|
if (require.main === module) {
|
|
const server = new PixivServer();
|
|
|
|
// 处理进程信号
|
|
process.on('SIGINT', () => server.shutdown());
|
|
process.on('SIGTERM', () => server.shutdown());
|
|
|
|
// 启动服务器
|
|
server
|
|
.init()
|
|
.then(() => server.start())
|
|
.catch((error) => logger.error('服务器启动失败', error));
|
|
}
|
|
|
|
module.exports = PixivServer; |