const robots = new Map() const KIND_NAMES = { DEVICE_KIND_AGV: 'agv', DEVICE_KIND_ARM: 'arm', DEVICE_KIND_BATTERY: 'battery', DEVICE_KIND_BIO_HEAD: 'bioHead', DEVICE_KIND_CAMERA: 'camera', DEVICE_KIND_CAN_BUS: 'canBus', DEVICE_KIND_DEX_HAND: 'dexHand', DEVICE_KIND_GRIPPER: 'gripper', DEVICE_KIND_MICROPHONE: 'microphone', DEVICE_KIND_MOTOR: 'motor', DEVICE_KIND_MOTOR_SYSTEM: 'motorSystem', DEVICE_KIND_ROBOT: 'robot', DEVICE_KIND_SPEAKER: 'speaker' } function groupDevices(devices = []) { return devices.reduce((groups, device) => { const kind = KIND_NAMES[device.kind] || 'other' if (!groups[kind]) groups[kind] = [] groups[kind].push({ deviceId: device.device_id, typeName: device.type_name || '', enabled: device.enabled !== false, state: device.manager_state || 'MANAGED_DEVICE_STATE_UNSPECIFIED', health: device.health || 'DEVICE_HEALTH_STATUS_UNSPECIFIED', hasError: Boolean(device.has_error), errorMessage: device.error_message || '' }) return groups }, {}) } function endpoint(peer, grpcEndpoint = {}) { return peer?.ip && grpcEndpoint.port ? `${peer.ip}:${grpcEndpoint.port}` : '' } export function consumeQuicEvent(event) { if (event?.event !== 'control_message') return const payload = event.payload || {} if (event.payload_type === 'node_register_request') { const node = payload.node || {} const robotId = node.robot_id || node.node_id if (!robotId) return const previous = robots.get(robotId) || {} robots.set(robotId, { ...previous, robotId, nodeId: node.node_id || previous.nodeId || '', ip: endpoint(event.peer, node.grpc_endpoint) || previous.ip || '', peerIp: event.peer?.ip || previous.peerIp || '', grpcEndpoint: node.grpc_endpoint || previous.grpcEndpoint || {}, devices: previous.devices || {}, online: true, lastSeenAt: new Date().toISOString() }) } if (event.payload_type === 'node_heartbeat') { const robotId = payload.robot_id || payload.node_id if (!robotId) return const previous = robots.get(robotId) || {} robots.set(robotId, { ...previous, robotId, nodeId: payload.node_id || previous.nodeId || '', ip: endpoint(event.peer, payload.grpc_endpoint) || previous.ip || '', peerIp: event.peer?.ip || previous.peerIp || '', grpcEndpoint: payload.grpc_endpoint || previous.grpcEndpoint || {}, devices: groupDevices(payload.device_manager?.devices), online: true, heartbeatSequence: payload.sequence || '0', lastSeenAt: new Date().toISOString() }) } } export function listRobots() { return [...robots.values()].sort((a, b) => a.robotId.localeCompare(b.robotId)) } export function getRobotAddress(robotId) { if (!robotId) return '' return robots.get(robotId)?.ip || '' } export function getRobotDeviceId(robotId, kind) { const devices = robots.get(robotId)?.devices?.[kind] || [] return (devices.find(device => device.enabled) || devices[0])?.deviceId || '' }