import 'dart:async'; import 'dart:convert'; import 'dart:io'; import 'package:shelf/shelf.dart'; import 'package:shelf/shelf_io.dart' as io; import 'package:shelf_web_socket/shelf_web_socket.dart'; import 'package:web_socket_channel/web_socket_channel.dart'; // 用户连接信息 class UserConnection { final String uuid; final String deviceModel; final WebSocketChannel channel; final DateTime connectedAt; String? currentDeviceId; UserConnection({ required this.uuid, required this.deviceModel, required this.channel, required this.connectedAt, this.currentDeviceId, }); } // WebSocket 管理器 class WebSocketManager { final Map _devices = {}; final Map _webClients = {}; // 存储每个连接的注册信息 final Map _channelToClientId = {}; final Map _channelToDeviceUuid = {}; // 获取设备连接 UserConnection? getDevice(String uuid) { return _devices[uuid]; } // 获取所有设备列表 List> getDeviceList() { return _devices.entries.map((entry) { return { 'uuid': entry.key, 'deviceModel': entry.value.deviceModel, 'connectedAt': entry.value.connectedAt.toIso8601String(), 'isConnected': true, }; }).toList(); } // 注册设备 void registerDevice(String uuid, String deviceModel, WebSocketChannel channel) { _devices[uuid] = UserConnection( uuid: uuid, deviceModel: deviceModel, channel: channel, connectedAt: DateTime.now(), ); _channelToDeviceUuid[channel] = uuid; print('✅ 调试设备注册: $deviceModel ($uuid)'); _broadcastUserList(); } // 注册网页客户端 void registerWebClient(String clientId, WebSocketChannel channel) { _webClients[clientId] = channel; _channelToClientId[channel] = clientId; print('🌐 网页客户端注册: $clientId'); // 发送设备列表 _sendUserListToClient(channel); } // 处理网页消息 void handleWebMessage(WebSocketChannel channel, Map data) { final clientId = _channelToClientId[channel]; if (clientId == null) { print('未找到对应的网页客户端'); return; } print('💻 收到网页指令: ${data['type']} from client: $clientId'); final commandType = data['type'] as String; final targetUuid = data['targetUuid'] as String?; switch (commandType) { case 'select_device': if (targetUuid != null) { final device = _devices[targetUuid]; if (device != null) { print(' -> 网页选择控制设备: $targetUuid (${device.deviceModel})'); channel.sink.add(jsonEncode({ 'type': 'device_selected', 'targetUuid': targetUuid, 'deviceModel': device.deviceModel, 'timestamp': DateTime.now().toIso8601String(), })); } else { print(' -> 设备不存在: $targetUuid'); } } break; case 'scan': if (targetUuid != null) { final device = _devices[targetUuid]; if (device != null) { print(' -> 发送扫描命令到设备: $targetUuid'); device.channel.sink.add(jsonEncode({ 'type': 'scan', 'timestamp': DateTime.now().toIso8601String(), })); } else { print(' -> 设备不存在: $targetUuid'); } } break; case 'stop_scan': if (targetUuid != null) { final device = _devices[targetUuid]; if (device != null) { device.channel.sink.add(jsonEncode({ 'type': 'stop_scan', 'timestamp': DateTime.now().toIso8601String(), })); print(' -> 发送停止扫描命令到设备: $targetUuid'); } } break; case 'connect': if (targetUuid != null) { final device = _devices[targetUuid]; final deviceId = data['deviceId'] as String?; if (device != null && deviceId != null) { device.currentDeviceId = deviceId; device.channel.sink.add(jsonEncode({ 'type': 'connect', 'deviceId': deviceId, 'timestamp': DateTime.now().toIso8601String(), })); print(' -> 发送连接设备命令到: $targetUuid, 设备ID: $deviceId'); } } break; case 'disconnect': if (targetUuid != null) { final device = _devices[targetUuid]; if (device != null) { device.currentDeviceId = null; device.channel.sink.add(jsonEncode({ 'type': 'disconnect', 'timestamp': DateTime.now().toIso8601String(), })); print(' -> 发送断开连接命令到设备: $targetUuid'); } } break; case 'send_data': if (targetUuid != null) { final device = _devices[targetUuid]; final sendData = data['data']; if (device != null && sendData != null) { device.channel.sink.add(jsonEncode({ 'type': 'send_data', 'data': sendData, 'timestamp': DateTime.now().toIso8601String(), })); print(' -> 发送数据到设备: $targetUuid, 数据: $sendData'); } } break; default: print('未知命令: $commandType'); } } // 处理设备消息 void handleDeviceMessage(WebSocketChannel channel, Map data) { final uuid = _channelToDeviceUuid[channel]; if (uuid == null) { print('未找到对应的设备'); return; } print('📱 收到设备 $uuid 消息: ${data['type']}'); // 转发给所有网页客户端 for (var entry in _webClients.entries) { entry.value.sink.add(jsonEncode({ 'type': 'device_message', 'fromUser': uuid, 'data': data, 'timestamp': DateTime.now().toIso8601String(), })); } } // 移除设备 void removeDevice(WebSocketChannel channel) { final uuid = _channelToDeviceUuid[channel]; if (uuid != null) { _devices.remove(uuid); _channelToDeviceUuid.remove(channel); print('🗑️ 移除调试设备: $uuid'); _broadcastUserList(); } } // 移除网页客户端 void removeWebClient(WebSocketChannel channel) { final clientId = _channelToClientId[channel]; if (clientId != null) { _webClients.remove(clientId); _channelToClientId.remove(channel); print('网页客户端断开: $clientId'); } } void _sendUserListToClient(WebSocketChannel client) { final deviceList = getDeviceList(); client.sink.add(jsonEncode({ 'type': 'user_list', 'users': deviceList, 'timestamp': DateTime.now().toIso8601String(), })); print('📡 发送设备列表到网页客户端: ${deviceList.length} 个设备'); } void _broadcastUserList() { final deviceList = getDeviceList(); final message = jsonEncode({ 'type': 'user_list', 'users': deviceList, 'timestamp': DateTime.now().toIso8601String(), }); for (var client in _webClients.values) { client.sink.add(message); } print('📡 广播设备列表: ${deviceList.length} 个设备'); } } // WebSocket 处理函数 - 所有消息都在这里统一处理 Future handleWebSocket(Request request, WebSocketManager manager) async { final handler = webSocketHandler((WebSocketChannel channel, String? protocol) { print('🔌 WebSocket 连接建立'); // 标识是否已经注册 bool isRegistered = false; String? connectionType; channel.stream.listen((message) { try { final data = jsonDecode(message); final type = data['type'] as String?; print('收到消息,类型: $type, 已注册: $isRegistered'); if (!isRegistered) { // 处理注册消息 if (type == 'device_register') { final uuid = data['uuid'] as String?; final deviceModel = data['deviceModel'] as String?; if (uuid != null && deviceModel != null) { isRegistered = true; connectionType = 'device'; manager.registerDevice(uuid, deviceModel, channel); } else { print('设备注册信息不完整'); channel.sink.close(); } } else if (type == 'web_register') { final clientId = data['clientId'] as String? ?? 'web_${DateTime.now().millisecondsSinceEpoch}'; isRegistered = true; connectionType = 'web'; manager.registerWebClient(clientId, channel); } else { print('等待注册消息,收到: $type'); channel.sink.close(); } } else { // 已注册,根据连接类型处理后续消息 if (connectionType == 'web') { manager.handleWebMessage(channel, data); } else if (connectionType == 'device') { manager.handleDeviceMessage(channel, data); } else { print('未知连接类型: $connectionType'); } } } catch (e) { print('解析消息失败: $e'); } }, onDone: () { // 连接关闭时的清理 if (connectionType == 'device') { manager.removeDevice(channel); } else if (connectionType == 'web') { manager.removeWebClient(channel); } print('🔌 连接关闭'); }, onError: (error) { print('连接错误: $error'); if (connectionType == 'device') { manager.removeDevice(channel); } else if (connectionType == 'web') { manager.removeWebClient(channel); } }); }); return handler(request); } // CORS 中间件 Middleware createCorsMiddleware() { return (Handler innerHandler) { return (Request request) async { if (request.method == 'OPTIONS') { return Response.ok('', headers: { 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS', 'Access-Control-Allow-Headers': 'Origin, Content-Type, X-Requested-With', 'Access-Control-Allow-Credentials': 'true', }); } final response = await innerHandler(request); return response.change(headers: { 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS', 'Access-Control-Allow-Headers': 'Origin, Content-Type, X-Requested-With', 'Access-Control-Allow-Credentials': 'true', }); }; }; } void main() async { final manager = WebSocketManager(); Future router(Request request) async { final path = request.url.path; print('📨 请求: ${request.method} $path'); if (path == 'ws') { return await handleWebSocket(request, manager); } if (path == 'users') { return Response.ok( jsonEncode(manager.getDeviceList()), headers: {'Content-Type': 'application/json'}, ); } return Response.notFound('Not Found'); } final handler = const Pipeline() .addMiddleware(logRequests()) .addMiddleware(createCorsMiddleware()) .addHandler(router); //端口 final server = await io.serve(handler, '0.0.0.0', 8089); print('\n🚀 ========================================'); print('✅ 服务器启动成功!'); print('🌐 HTTP 地址: http://${server.address.host}:${server.port}'); print('🔌 WebSocket 地址: ws://${server.address.host}:${server.port}/ws'); print('📋 用户列表 API: http://${server.address.host}:${server.port}/users'); print('========================================\n'); }