UNPKG

lifxlan

Version:

TypeScript library for controlling LIFX products over LAN

80 lines 3.07 kB
import { decodeHeader, getPayload } from './encoding.js'; import { convertTargetToSerialNumber } from './utils/index.js'; import { SourceExhaustionError, ValidationError } from './errors.js'; const MAX_SOURCE = 0xFFFFFFFF; /** 0 and 1 are reserved */ const MAX_SOURCE_VALUES = MAX_SOURCE - 2; /** * Since a client is a source of messages and there may be multiple * clients sending messages at the same time, the router receives * response messages and routes them to the client (a MessageHandler) * that sent the request message. * * It has the added benefit of allowing callers to send messages * messages. With the previous benefit, the router helps associate * received messages with previously sent messages. * * It also decodes the header and converts the target to a serial * number string. This helps avoid calling the relatively expensive * convertTargetToSerialNumber utility function multiple times for * each response message. */ export function Router(options) { const handlers = options.handlers ?? new Map(); let sourceCounter = 2; return { nextSource() { let source = -1; for (let i = 0; i < MAX_SOURCE_VALUES; i++) { if (!handlers.has(sourceCounter)) { source = sourceCounter; break; } sourceCounter = (sourceCounter + 1) % 0x100000000; if (sourceCounter <= 1) { sourceCounter = 2; } } if (source === -1) { throw new SourceExhaustionError(); } return source; }, register(source, handler) { if (source <= 1 || source > MAX_SOURCE) { throw new ValidationError('source', source, 'must be between 2 and 4294967295'); } if (handlers.has(source)) { throw new ValidationError('source', source, 'already registered'); } handlers.set(source, handler); }, deregister(source, handler) { if (handlers.get(source) !== handler) { throw new ValidationError('messageHandler', handler, 'does not match registered handler'); } handlers.delete(source); }, send(message, port, address, serialNumber) { options.onSend(message, port, address, serialNumber); }, receive(message) { const header = decodeHeader(message); const payload = getPayload(message); const serialNumber = convertTargetToSerialNumber(header.target); const handler = handlers.get(header.source); if (handler) { handler(header, payload, serialNumber); } if (options.onMessage) { options.onMessage(header, payload, serialNumber); } return { header, payload, serialNumber, }; }, }; } //# sourceMappingURL=router.js.map