初始化提交:go比特版本精简

This commit is contained in:
2026-09-20 17:02:11 +08:00
commit f41a979462
213 changed files with 58288 additions and 0 deletions
+106
View File
@@ -0,0 +1,106 @@
/**
* @file server.js
* @brief Express 服务器入口
*/
'use strict';
const express = require('express');
const path = require('path');
const Config = require('./src/core/config');
const { initDB } = require('./src/core/database');
// ==================== 初始化 ====================
initDB();
const app = express();
// 中间件
app.use(express.json({ limit: '10mb' }));
app.use(express.urlencoded({ extended: true }));
// 静态文件
app.use(express.static(path.join(__dirname, 'public')));
// 截图静态服务:data/screenshots/ → /screenshots/
app.use('/screenshots', express.static(path.join(Config.DATA_DIR, 'screenshots')));
// ==================== API 路由 ====================
app.use('/api/accounts', require('./src/routes/accounts'));
app.use('/api/settings', require('./src/routes/settings'));
app.use('/api/recharge-credentials', require('./src/routes/recharge_credentials'));
app.use('/api/workspace-refund-credentials', require('./src/routes/workspace_refund_credentials'));
app.use('/api/google-account-credentials', require('./src/routes/google_account_credentials'));
app.use('/api/feishu', require('./src/routes/feishu'));
app.use('/api/quota-monitor', require('./src/routes/quota_monitor'));
app.use('/api/operations', require('./src/routes/operations'));
app.use('/api/diagnostics', require('./src/routes/diagnostics'));
app.use('/api/static-proxies', require('./src/routes/static_proxies'));
app.use('/api/templates', require('./src/routes/templates'));
app.use('/api/backups', require('./src/routes/backups'));
// ==================== 前端路由 (SPA) ====================
app.get('*', (req, res) => {
res.sendFile(path.join(__dirname, 'public', 'index.html'));
});
// ==================== 错误处理 ====================
app.use((err, req, res, next) => {
// body-parser 的解析异常可能携带原始请求体;充值请求中包含 API Secret
// 或卡密,因此全局错误日志和响应都不能输出 err/body/message 原文。
const status = Number.isInteger(err && err.status) && err.status >= 400 && err.status < 600
? err.status
: 500;
const type = String((err && err.type) || 'request_error')
.replace(/[^a-z0-9_.-]/gi, '')
.slice(0, 80) || 'request_error';
console.error(`[Server] Request failed: type=${type} status=${status}`);
res.status(status).json({
success: false,
msg: status >= 400 && status < 500 ? '请求格式无效' : '服务器内部错误',
});
});
// ==================== 启动服务器 ====================
// 端口优先级:环境变量 PORT > src/core/config.js 中的 PORT > 3000
// 注意:启动程序.bat 会读取 config.js 中的 PORT 来打开浏览器,二者需保持一致
const PORT = Number(process.env.PORT) || Config.PORT || 3000;
const HOST = process.env.HOST || '0.0.0.0';
const server = app.listen(PORT, HOST, () => {
require('./src/services/quota_monitor_scheduler').start();
require('./src/services/refund_deadline_scheduler').start();
require('./src/services/recharge_reconciler').start();
const { networkInterfaces } = require('os');
const nets = networkInterfaces();
let localIP = 'localhost';
for (const name of Object.keys(nets)) {
for (const net of nets[name]) {
if (net.family === 'IPv4' && !net.internal) {
localIP = net.address;
break;
}
}
}
console.log(`╔═══════════════════════════════════════╗`);
console.log(`║ Gemini Go Web - Node.js版 ║`);
console.log(`╠═══════════════════════════════════════╣`);
console.log(`║ 服务器已启动 ║`);
console.log(`║ 本机: http://localhost:${PORT} ║`);
console.log(`║ 局域网: http://${localIP}:${PORT} ║`);
console.log(`╚═══════════════════════════════════════╝`);
});
// 监听失败时给出明确提示(否则只会抛出一段堆栈,启动窗口一闪而过难以排查)
server.on('error', (err) => {
const code = err && err.code ? err.code : '';
if (code === 'EADDRINUSE') {
console.error(`[Server] 启动失败:端口 ${PORT} 已被占用。`);
console.error(`[Server] 请关闭仍在运行的旧 "Gemini Go Server" 窗口,或修改 src/core/config.js 中的 PORT 后重试。`);
} else if (code === 'EACCES') {
console.error(`[Server] 启动失败:没有权限监听 ${HOST}:${PORT},请更换端口或以管理员身份运行。`);
} else {
console.error(`[Server] 启动失败:${code} ${err && err.message ? err.message : err}`);
}
process.exit(1);
});
module.exports = app;