inspection-host-computer/server/robotRegistry.js

94 lines
3.0 KiB
JavaScript

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 || ''
}