94 lines
3.0 KiB
JavaScript
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 || ''
|
|
}
|