Spaces:
Sleeping
Sleeping
| /** | |
| * Consumer client for receiving robot commands in RobotHub TransportServer | |
| */ | |
| import { RoboticsClientCore } from './core.js'; | |
| import type { | |
| WebSocketMessage, | |
| JointUpdateMessage, | |
| StateSyncMessage, | |
| ClientOptions, | |
| JointUpdateCallback, | |
| StateSyncCallback, | |
| } from './types.js'; | |
| export class RoboticsConsumer extends RoboticsClientCore { | |
| // Event callbacks | |
| private onStateSyncCallback: StateSyncCallback | null = null; | |
| private onJointUpdateCallback: JointUpdateCallback | null = null; | |
| constructor(baseUrl: string, options: ClientOptions = {}) { | |
| super(baseUrl, options); | |
| } | |
| // ============= CONSUMER CONNECTION ============= | |
| async connect(workspaceId: string, roomId: string, participantId?: string): Promise<boolean> { | |
| return this.connectToRoom(workspaceId, roomId, 'consumer', participantId); | |
| } | |
| // ============= CONSUMER METHODS ============= | |
| async getStateSyncAsync(): Promise<Record<string, number>> { | |
| if (!this.workspaceId || !this.roomId) { | |
| throw new Error('Must be connected to a room'); | |
| } | |
| const state = await this.getRoomState(this.workspaceId, this.roomId); | |
| return state.joints; | |
| } | |
| // ============= EVENT CALLBACKS ============= | |
| onStateSync(callback: StateSyncCallback): void { | |
| this.onStateSyncCallback = callback; | |
| } | |
| onJointUpdate(callback: JointUpdateCallback): void { | |
| this.onJointUpdateCallback = callback; | |
| } | |
| // ============= MESSAGE HANDLING ============= | |
| protected override handleRoleSpecificMessage(message: WebSocketMessage): void { | |
| switch (message.type) { | |
| case 'state_sync': | |
| this.handleStateSync(message as StateSyncMessage); | |
| break; | |
| case 'joint_update': | |
| this.handleJointUpdate(message as JointUpdateMessage); | |
| break; | |
| case 'emergency_stop': | |
| console.warn(`🚨 Emergency stop: ${message.reason || 'Unknown reason'}`); | |
| this.handleError(`Emergency stop: ${message.reason || 'Unknown reason'}`); | |
| break; | |
| case 'error': | |
| console.error(`Server error: ${message.message}`); | |
| this.handleError(message.message); | |
| break; | |
| default: | |
| console.warn(`Unknown message type for consumer: ${message.type}`); | |
| } | |
| } | |
| private handleStateSync(message: StateSyncMessage): void { | |
| if (this.onStateSyncCallback) { | |
| this.onStateSyncCallback(message.data); | |
| } | |
| this.emit('stateSync', message.data); | |
| } | |
| private handleJointUpdate(message: JointUpdateMessage): void { | |
| if (this.onJointUpdateCallback) { | |
| this.onJointUpdateCallback(message.data); | |
| } | |
| this.emit('jointUpdate', message.data); | |
| } | |
| // ============= UTILITY METHODS ============= | |
| /** | |
| * Create a consumer and automatically connect to a room | |
| */ | |
| static async createAndConnect( | |
| workspaceId: string, | |
| roomId: string, | |
| baseUrl: string, | |
| participantId?: string | |
| ): Promise<RoboticsConsumer> { | |
| const consumer = new RoboticsConsumer(baseUrl); | |
| const connected = await consumer.connect(workspaceId, roomId, participantId); | |
| if (!connected) { | |
| throw new Error('Failed to connect as consumer'); | |
| } | |
| return consumer; | |
| } | |
| } |