lifxlan
Version:
TypeScript library for controlling LIFX products over LAN
83 lines • 3.22 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.Router = Router;
const encoding_js_1 = require("./encoding.js");
const index_js_1 = require("./utils/index.js");
const errors_js_1 = require("./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.
*/
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 errors_js_1.SourceExhaustionError();
}
return source;
},
register(source, handler) {
if (source <= 1 || source > MAX_SOURCE) {
throw new errors_js_1.ValidationError('source', source, 'must be between 2 and 4294967295');
}
if (handlers.has(source)) {
throw new errors_js_1.ValidationError('source', source, 'already registered');
}
handlers.set(source, handler);
},
deregister(source, handler) {
if (handlers.get(source) !== handler) {
throw new errors_js_1.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 = (0, encoding_js_1.decodeHeader)(message);
const payload = (0, encoding_js_1.getPayload)(message);
const serialNumber = (0, index_js_1.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