"use strict";
|
|
const path = require("path");
|
const fs = require("fs");
|
const { createLogger } = require("./lib/logger");
|
const { DataCache } = require("./lib/data-cache");
|
const { DeviceManager } = require("./lib/device-manager");
|
const { UploadManager } = require("./lib/upload");
|
const { createDashboard } = require("./dashboard/server");
|
|
// 配置读取:优先从工作目录(CWD),便于打包后用户编辑;开发时回退到 __dirname
|
let configPath = path.resolve(process.cwd(), "config.json");
|
if (!fs.existsSync(configPath)) {
|
configPath = path.join(__dirname, "config.json");
|
}
|
if (!fs.existsSync(configPath)) {
|
console.error("缺少 config.json,请先创建配置文件(放置于当前工作目录或程序目录)");
|
process.exit(1);
|
}
|
|
let config;
|
try {
|
config = JSON.parse(fs.readFileSync(configPath, "utf-8"));
|
} catch (err) {
|
console.error("config.json 解析失败:", err.message);
|
process.exit(1);
|
}
|
|
// 启动配置校验
|
if (!Array.isArray(config.devices) || config.devices.length === 0) {
|
console.error("config.json 缺少有效的 devices 数组");
|
process.exit(1);
|
}
|
for (let i = 0; i < config.devices.length; i++) {
|
const d = config.devices[i];
|
if (!d.ip || !d.port || !d.serialNumber) {
|
console.error(`config.json devices[${i}] 缺少必填字段 ip/port/serialNumber`);
|
process.exit(1);
|
}
|
}
|
const activeDevices = config.devices.filter((d) => d.enabled !== false);
|
console.log(`配置校验通过: ${activeDevices.length}/${config.devices.length} 台设备启用`);
|
|
const logDir = path.resolve(process.cwd(), config.logDir || "./logs");
|
const logger = createLogger({
|
logDir,
|
retentionDays: config.logRetentionDays || 30,
|
});
|
|
logger.sys("联机服务启动");
|
logger.sys(`日志目录: ${logDir} 保留: ${config.logRetentionDays} 天`);
|
logger.sys(`轮询间隔: ${config.pollIntervalMs / 1000}s 重连退避: ${config.reconnectBaseMs / 1000}s~${config.reconnectMaxMs / 1000}s`);
|
|
const dataCache = new DataCache();
|
|
// 上传模块
|
const uploadManager = new UploadManager({
|
mqttConfig: config.mqtt || {},
|
aliyunConfig: config.aliyun || {},
|
logger,
|
});
|
uploadManager.start();
|
|
const deviceManager = new DeviceManager({
|
config,
|
dataCache,
|
logger,
|
uploadManager,
|
});
|
|
const dashboard = createDashboard({
|
port: config.dashboardPort || 3100,
|
dataCache,
|
deviceManager,
|
logger,
|
config,
|
uploadManager,
|
});
|
|
deviceManager.startAll();
|
dashboard.start();
|
|
process.on("SIGINT", () => {
|
logger.sys("收到 SIGINT,正在关闭...");
|
deviceManager.stopAll();
|
uploadManager.stop();
|
dashboard.stop();
|
logger.close();
|
process.exit(0);
|
});
|
|
process.on("SIGTERM", () => {
|
logger.sys("收到 SIGTERM,正在关闭...");
|
deviceManager.stopAll();
|
uploadManager.stop();
|
dashboard.stop();
|
logger.close();
|
process.exit(0);
|
});
|
|
process.on("uncaughtException", (err) => {
|
logger.error("system", `未捕获异常: ${err.message}`, { stack: err.stack });
|
});
|
|
process.on("unhandledRejection", (reason) => {
|
const msg = reason instanceof Error ? reason.message : String(reason);
|
const stack = reason instanceof Error ? reason.stack : undefined;
|
logger.error("system", `未处理的 Promise 拒绝: ${msg}`, stack ? { stack } : undefined);
|
});
|
|
console.log(`\n联机服务已启动 → Dashboard: http://localhost:${config.dashboardPort || 3100}\n`);
|