UNPKG

controly

Version:

SDK for the Controly real-time communication system.

119 lines (118 loc) 4.1 kB
/** * @file Implements the Display client for the Controly SDK. */ import { Client } from './Client.js'; /** * The Display client for Controly. * This class is used for devices that need to be controlled remotely. * It connects to the server, registers its commands, and listens for incoming command messages. * * @example * ```javascript * const display = new controly.Display({ * serverUrl: 'ws://localhost:8080/ws', * id: 'my-unique-display-01', * commandUrl: 'https://example.com/commands.json', * token: 'your-secret-token', // Optional * }); * * display.command('play_pause', (args, fromControllerId) => { * console.log(`Received 'play_pause' from ${fromControllerId}`); * // ... implement logic * display.updateStatus({ playback: 'playing' }); * }); * * display.on('open', (id) => { * console.log(`Display connected with ID: ${id}`); * }); * * display.connect(); * ``` */ export class Display extends Client { /** * Creates an instance of a Display client. * @param options The configuration options for the Display. */ constructor(options) { super(options, { type: 'display', id: options.id || '', token: options.token || '', }); this.commandHandlers = new Map(); this._subscriberCount = 0; } /** * Registers a handler function for a specific command. * When a Controller sends a command with a matching name, this handler is executed. * * @template T - The expected type of the arguments for this command. * @param commandName The name of the command to handle (e.g., 'play_pause'). * @param callback The function to execute when the command is received. * It receives the command arguments and the ID of the originating Controller. */ command(commandName, callback) { this.commandHandlers.set(commandName, callback); } /** * Sends a status update to all subscribed Controllers. * This should be called whenever the state of the Display changes. * * @param payload An object representing the current status of the Display. * This can be any object that is serializable to JSON. * @throws {Error} if the WebSocket is not connected. */ updateStatus(payload) { this.sendMessage({ type: 'status', payload, }); } setCommandList(commandList) { this.sendMessage({ type: 'set_command', payload: commandList, }); } /** * Returns the current number of controllers subscribed to this Display. * @returns The number of subscribed controllers. */ subscribers() { return this._subscriberCount; } /** * Processes incoming messages from the server, specific to the Display client. * @param message The parsed message from the server. * @internal */ processMessage(message) { if (message.type === 'command' && message.from) { const command = message.payload; const handler = this.commandHandlers.get(command.name); if (handler) { try { handler(command.args || {}, message.from); } catch (error) { console.error(`Error executing handler for command "${command.name}":`, error); } } else { // It's not mandatory to handle all commands, so we just log a warning. console.warn(`Received unhandled command: "${command.name}"`); } } else if (message.type === 'subscribed') { const payload = message.payload; this._subscriberCount = payload.count; this.emitter.emit('subscribed', payload, message.from); } else if (message.type === 'unsubscribed') { const payload = message.payload; this._subscriberCount = payload.count; this.emitter.emit('unsubscribed', payload, message.from); } } }