mirror of
https://github.com/bourquep/mysa-js-sdk.git
synced 2026-02-04 09:41:07 +00:00
feat: Initial commit
This commit is contained in:
106
src/lib/EventEmitter.ts
Normal file
106
src/lib/EventEmitter.ts
Normal file
@@ -0,0 +1,106 @@
|
||||
import { EventEmitter as NodeEventEmitter } from 'node:events';
|
||||
|
||||
/**
|
||||
* Typed wrapper around Node's `EventEmitter` class.
|
||||
*
|
||||
* @remarks
|
||||
* Source: {@link https://blog.makerx.com.au/a-type-safe-event-emitter-in-node-js}
|
||||
*/
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
export class EventEmitter<TEvents extends Record<string, any>> implements NodeJS.EventEmitter {
|
||||
private _emitter = new NodeEventEmitter();
|
||||
|
||||
emit<TEventName extends keyof TEvents & string>(eventName: TEventName, ...eventArg: TEvents[TEventName]) {
|
||||
return this._emitter.emit(eventName, ...(eventArg as []));
|
||||
}
|
||||
|
||||
on<TEventName extends keyof TEvents & string>(
|
||||
eventName: TEventName,
|
||||
handler: (...eventArg: TEvents[TEventName]) => void
|
||||
) {
|
||||
this._emitter.on(eventName, handler as any);
|
||||
return this;
|
||||
}
|
||||
|
||||
once<TEventName extends keyof TEvents & string>(
|
||||
eventName: TEventName,
|
||||
handler: (...eventArg: TEvents[TEventName]) => void
|
||||
) {
|
||||
this._emitter.once(eventName, handler as any);
|
||||
return this;
|
||||
}
|
||||
|
||||
off<TEventName extends keyof TEvents & string>(
|
||||
eventName: TEventName,
|
||||
handler: (...eventArg: TEvents[TEventName]) => void
|
||||
) {
|
||||
this._emitter.off(eventName, handler as any);
|
||||
return this;
|
||||
}
|
||||
|
||||
addListener<TEventName extends keyof TEvents & string>(
|
||||
eventName: TEventName,
|
||||
listener: (...args: TEvents[TEventName]) => void
|
||||
) {
|
||||
this._emitter.addListener(eventName, listener);
|
||||
return this;
|
||||
}
|
||||
|
||||
removeListener<TEventName extends keyof TEvents & string>(
|
||||
eventName: TEventName,
|
||||
listener: (...args: TEvents[TEventName]) => void
|
||||
) {
|
||||
this._emitter.removeListener(eventName, listener);
|
||||
return this;
|
||||
}
|
||||
|
||||
removeAllListeners<TEventName extends keyof TEvents & string>(eventName?: TEventName | undefined) {
|
||||
this._emitter.removeAllListeners(eventName);
|
||||
return this;
|
||||
}
|
||||
|
||||
setMaxListeners(n: number) {
|
||||
this._emitter.setMaxListeners(n);
|
||||
return this;
|
||||
}
|
||||
|
||||
getMaxListeners(): number {
|
||||
return this._emitter.getMaxListeners();
|
||||
}
|
||||
|
||||
listeners<TEventName extends keyof TEvents & string>(eventName: TEventName) {
|
||||
return this._emitter.listeners(eventName);
|
||||
}
|
||||
|
||||
rawListeners<TEventName extends keyof TEvents & string>(eventName: TEventName) {
|
||||
return this._emitter.rawListeners(eventName);
|
||||
}
|
||||
|
||||
listenerCount<TEventName extends keyof TEvents & string>(
|
||||
eventName: TEventName,
|
||||
listener?: (...args: TEvents[TEventName]) => void
|
||||
) {
|
||||
return this._emitter.listenerCount(eventName, listener);
|
||||
}
|
||||
|
||||
prependListener<TEventName extends keyof TEvents & string>(
|
||||
eventName: TEventName,
|
||||
listener: (...args: TEvents[TEventName]) => void
|
||||
) {
|
||||
this._emitter.prependListener(eventName, listener);
|
||||
return this;
|
||||
}
|
||||
|
||||
prependOnceListener<TEventName extends keyof TEvents & string>(
|
||||
eventName: TEventName,
|
||||
listener: (...args: TEvents[TEventName]) => void
|
||||
) {
|
||||
this._emitter.prependOnceListener(eventName, listener);
|
||||
return this;
|
||||
}
|
||||
|
||||
eventNames() {
|
||||
return this._emitter.eventNames();
|
||||
}
|
||||
}
|
||||
/* eslint-enable @typescript-eslint/no-explicit-any */
|
||||
39
src/lib/PayloadParser.ts
Normal file
39
src/lib/PayloadParser.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
import { InPayload } from '@/types/mqtt/InPayload';
|
||||
import { OutPayload } from '@/types/mqtt/OutPayload';
|
||||
|
||||
/**
|
||||
* Parses an MQTT payload from binary data into a typed OutPayload object.
|
||||
*
|
||||
* Converts the raw ArrayBuffer received from MQTT messages into a structured TypeScript object representing device
|
||||
* status, state changes, or other outgoing message types from Mysa devices.
|
||||
*
|
||||
* @param payload - The raw binary MQTT message payload as ArrayBuffer
|
||||
* @returns The parsed payload as a typed OutPayload object
|
||||
* @throws Error if the payload cannot be decoded or parsed as valid JSON
|
||||
*/
|
||||
export function parseMqttPayload(payload: ArrayBuffer): OutPayload {
|
||||
try {
|
||||
const decoder = new TextDecoder('utf-8');
|
||||
const jsonString = decoder.decode(payload);
|
||||
return JSON.parse(jsonString);
|
||||
} catch (error) {
|
||||
console.error('Error parsing MQTT payload:', error);
|
||||
throw new Error('Failed to parse MQTT payload');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes an InPayload object into binary data for MQTT transmission.
|
||||
*
|
||||
* Converts a typed TypeScript payload object into the binary ArrayBuffer format required for sending commands and
|
||||
* requests to Mysa devices via MQTT.
|
||||
*
|
||||
* @typeParam T - The specific InPayload type being serialized
|
||||
* @param payload - The typed payload object to serialize
|
||||
* @returns The serialized payload as ArrayBuffer ready for MQTT transmission
|
||||
*/
|
||||
export function serializeMqttPayload<T extends InPayload>(payload: T): ArrayBuffer {
|
||||
const jsonString = JSON.stringify(payload);
|
||||
const encoder = new TextEncoder();
|
||||
return encoder.encode(jsonString);
|
||||
}
|
||||
29
src/lib/PayloadTypeGuards.ts
Normal file
29
src/lib/PayloadTypeGuards.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import { MsgOutPayload } from '@/types/mqtt/MsgOutPayload';
|
||||
import { MsgTypeOutPayload } from '@/types/mqtt/MsgTypeOutPayload';
|
||||
import { OutPayload } from '@/types/mqtt/OutPayload';
|
||||
|
||||
/**
|
||||
* Type guard function to determine if an OutPayload is a MsgType-based payload.
|
||||
*
|
||||
* Checks whether the payload uses the legacy MsgType field format for message type identification. This is used to
|
||||
* differentiate between different payload structures and ensure proper type narrowing in TypeScript.
|
||||
*
|
||||
* @param payload - The OutPayload to check
|
||||
* @returns True if the payload is a MsgTypeOutPayload, false otherwise
|
||||
*/
|
||||
export function isMsgTypeOutPayload(payload: OutPayload): payload is MsgTypeOutPayload {
|
||||
return 'MsgType' in payload;
|
||||
}
|
||||
|
||||
/**
|
||||
* Type guard function to determine if an OutPayload is a message-based payload.
|
||||
*
|
||||
* Checks whether the payload uses the newer msg field format for message type identification. This is used to
|
||||
* differentiate between different payload structures and ensure proper type narrowing in TypeScript.
|
||||
*
|
||||
* @param payload - The OutPayload to check
|
||||
* @returns True if the payload is a MsgOutPayload, false otherwise
|
||||
*/
|
||||
export function isMsgOutPayload(payload: OutPayload): payload is MsgOutPayload {
|
||||
return 'msg' in payload;
|
||||
}
|
||||
Reference in New Issue
Block a user