From d6ad49eb6e7e7aff1caeb910642187ae0e9608d9 Mon Sep 17 00:00:00 2001 From: fwcd Date: Sun, 6 Feb 2022 06:07:03 +0100 Subject: [PATCH 1/9] Name types more consistently and parameterize over payload --- src/Lighthouse/LighthouseWebsocket.ts | 22 +++++++++++----------- src/Lighthouse/types.ts | 12 ++++++------ 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/Lighthouse/LighthouseWebsocket.ts b/src/Lighthouse/LighthouseWebsocket.ts index 67bbf98..8dd179c 100644 --- a/src/Lighthouse/LighthouseWebsocket.ts +++ b/src/Lighthouse/LighthouseWebsocket.ts @@ -1,26 +1,26 @@ import { decode, encode } from "@msgpack/msgpack"; import { v4 as uuid } from "uuid"; import { WebSocket } from "ws"; -import { LighthouseAuth, RequestPayload, ResponsePayload } from "./types"; +import { LighthouseAuth, LighthouseRequest, LighthouseEvent } from "./types"; -type ResponseHandler = (data: ResponsePayload) => void; +type LighthouseEventHandler

= (data: LighthouseEvent

) => void; export class LighthouseWebsocket { private static readonly serverAddress = "wss://lighthouse.uni-kiel.de/websocket"; private ws?: WebSocket; - private responseHandlers: Map; + private responseHandlers: Map>; constructor(private readonly auth: LighthouseAuth) { - this.responseHandlers = new Map(); + this.responseHandlers = new Map>(); } public async open(address = LighthouseWebsocket.serverAddress): Promise { this.ws = new WebSocket(address); this.ws.on("message", (data) => { - const response: ResponsePayload = decode(new Uint8Array(data as Buffer)) as ResponsePayload; + const response = decode(new Uint8Array(data as Buffer)) as LighthouseEvent; const handler = this.responseHandlers.get(response.REID); if (handler && typeof handler === "function") { handler(response); @@ -34,18 +34,18 @@ export class LighthouseWebsocket { }); } - public async send(payload: number[]): Promise { + public async send

(payload: P): Promise> { const id = uuid(); - const data: RequestPayload = { + const data: LighthouseRequest = { AUTH: this.auth, META: {}, PATH: ["user", this.auth.USER, "model"], - PAYL: new Uint8Array(payload), + PAYL: payload, REID: id, VERB: "PUT", }; if (this.ws?.readyState === WebSocket.OPEN) { - const prom = new Promise((res) => { + const prom = new Promise>((res) => { this.registerResponseHandler(id, res); }); this.ws?.send(encode(data)); @@ -54,8 +54,8 @@ export class LighthouseWebsocket { throw new Error("Websocket is currently not open!"); } - private registerResponseHandler(id: string, cb: ResponseHandler) { - this.responseHandlers.set(id, cb); + private registerResponseHandler

(id: string, cb: LighthouseEventHandler

) { + this.responseHandlers.set(id, cb as LighthouseEventHandler); } public close(): void { diff --git a/src/Lighthouse/types.ts b/src/Lighthouse/types.ts index 1c65652..65b7fe6 100644 --- a/src/Lighthouse/types.ts +++ b/src/Lighthouse/types.ts @@ -1,24 +1,24 @@ -type Verb = "POST" | "CREATE" | "MKDIR" | "DELETE" | "LIST" | "GET" | "PUT" | "STREAM" | "STOP" | "LINK" | "UNLINK"; +export type LighthouseVerb = "POST" | "CREATE" | "MKDIR" | "DELETE" | "LIST" | "GET" | "PUT" | "STREAM" | "STOP" | "LINK" | "UNLINK"; export interface LighthouseAuth { USER: U; TOKEN: string; } -export interface RequestPayload { +export interface LighthouseRequest { REID: string; AUTH: LighthouseAuth; - VERB: Verb; + VERB: LighthouseVerb; PATH: ["user", U, "model"]; META: object; - PAYL: unknown; + PAYL: P; } -export interface ResponsePayload { +export interface LighthouseEvent

{ REID: string; RNUM: number; RESPONSE: string; META: object; - PAYL: unknown; + PAYL: P; WARNINGS: string[]; } From 0ae60889cb810bba305de06af253543b38a65ad5 Mon Sep 17 00:00:00 2001 From: fwcd Date: Sun, 6 Feb 2022 06:12:56 +0100 Subject: [PATCH 2/9] Add support for non-response event handlers --- src/Lighthouse/LighthouseWebsocket.ts | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/Lighthouse/LighthouseWebsocket.ts b/src/Lighthouse/LighthouseWebsocket.ts index 8dd179c..9b3f6f7 100644 --- a/src/Lighthouse/LighthouseWebsocket.ts +++ b/src/Lighthouse/LighthouseWebsocket.ts @@ -3,18 +3,17 @@ import { v4 as uuid } from "uuid"; import { WebSocket } from "ws"; import { LighthouseAuth, LighthouseRequest, LighthouseEvent } from "./types"; -type LighthouseEventHandler

= (data: LighthouseEvent

) => void; +type LighthouseEventHandler

= (event: LighthouseEvent

) => void; export class LighthouseWebsocket { private static readonly serverAddress = "wss://lighthouse.uni-kiel.de/websocket"; private ws?: WebSocket; - private responseHandlers: Map>; + private responseHandlers: Map> = new Map(); + private eventHandlers: LighthouseEventHandler[] = []; - constructor(private readonly auth: LighthouseAuth) { - this.responseHandlers = new Map>(); - } + constructor(private readonly auth: LighthouseAuth) {} public async open(address = LighthouseWebsocket.serverAddress): Promise { this.ws = new WebSocket(address); @@ -25,6 +24,10 @@ export class LighthouseWebsocket { if (handler && typeof handler === "function") { handler(response); this.responseHandlers.delete(response.REID); + } else { + for (const handler of this.eventHandlers) { + handler(response); + } } }); return new Promise((res) => { @@ -58,6 +61,10 @@ export class LighthouseWebsocket { this.responseHandlers.set(id, cb as LighthouseEventHandler); } + private registerEventHandler

(cb: LighthouseEventHandler

) { + this.eventHandlers.push(cb as LighthouseEventHandler); + } + public close(): void { this.ws?.close(); } From bac7451ace1547d37f57b05ccf83e4c903720cfc Mon Sep 17 00:00:00 2001 From: fwcd Date: Sun, 6 Feb 2022 06:25:54 +0100 Subject: [PATCH 3/9] Split 'send' and 'sendDisplay' --- examples/disco/src/index.ts | 2 +- src/Lighthouse/LighthouseWebsocket.ts | 18 +++++++++++------- src/Lighthouse/types.ts | 3 ++- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/examples/disco/src/index.ts b/examples/disco/src/index.ts index 26af3b9..e254e9b 100644 --- a/examples/disco/src/index.ts +++ b/examples/disco/src/index.ts @@ -25,7 +25,7 @@ async function sleep(time: number) { while (true) { // eslint-disable-next-line no-loop-func const data = new Array(28 * 14 * 3).fill(0).map((_, j) => (j % 3 === i ? 255 : 0)); - const msg = await lh.send(data); + const msg = await lh.sendDisplay(data); // eslint-disable-next-line no-console console.log(msg); diff --git a/src/Lighthouse/LighthouseWebsocket.ts b/src/Lighthouse/LighthouseWebsocket.ts index 9b3f6f7..f12e8a8 100644 --- a/src/Lighthouse/LighthouseWebsocket.ts +++ b/src/Lighthouse/LighthouseWebsocket.ts @@ -1,7 +1,7 @@ import { decode, encode } from "@msgpack/msgpack"; import { v4 as uuid } from "uuid"; import { WebSocket } from "ws"; -import { LighthouseAuth, LighthouseRequest, LighthouseEvent } from "./types"; +import { LighthouseAuth, LighthousePath, LighthouseRequest, LighthouseEvent, LighthouseVerb } from "./types"; type LighthouseEventHandler

= (event: LighthouseEvent

) => void; @@ -37,18 +37,22 @@ export class LighthouseWebsocket { }); } - public async send

(payload: P): Promise> { + public async sendDisplay(rgbValues: number[]): Promise> { + return await this.send("PUT", ["user", this.auth.USER, "model"], new Uint8Array(rgbValues)); + } + + private async send

(verb: LighthouseVerb, path: LighthousePath, payload: P) { const id = uuid(); const data: LighthouseRequest = { AUTH: this.auth, META: {}, - PATH: ["user", this.auth.USER, "model"], + PATH: path, PAYL: payload, REID: id, - VERB: "PUT", + VERB: verb, }; if (this.ws?.readyState === WebSocket.OPEN) { - const prom = new Promise>((res) => { + const prom = new Promise>((res) => { this.registerResponseHandler(id, res); }); this.ws?.send(encode(data)); @@ -57,11 +61,11 @@ export class LighthouseWebsocket { throw new Error("Websocket is currently not open!"); } - private registerResponseHandler

(id: string, cb: LighthouseEventHandler

) { + private registerResponseHandler

(id: string, cb: LighthouseEventHandler

): void { this.responseHandlers.set(id, cb as LighthouseEventHandler); } - private registerEventHandler

(cb: LighthouseEventHandler

) { + private registerEventHandler

(cb: LighthouseEventHandler

): void { this.eventHandlers.push(cb as LighthouseEventHandler); } diff --git a/src/Lighthouse/types.ts b/src/Lighthouse/types.ts index 65b7fe6..1e53d2d 100644 --- a/src/Lighthouse/types.ts +++ b/src/Lighthouse/types.ts @@ -1,4 +1,5 @@ export type LighthouseVerb = "POST" | "CREATE" | "MKDIR" | "DELETE" | "LIST" | "GET" | "PUT" | "STREAM" | "STOP" | "LINK" | "UNLINK"; +export type LighthousePath = ["user", U, "model"]; export interface LighthouseAuth { USER: U; @@ -9,7 +10,7 @@ export interface LighthouseRequest { REID: string; AUTH: LighthouseAuth; VERB: LighthouseVerb; - PATH: ["user", U, "model"]; + PATH: LighthousePath; META: object; PAYL: P; } From f697d26fed98472ffb264fb997138d192a70dbf1 Mon Sep 17 00:00:00 2001 From: fwcd Date: Sun, 6 Feb 2022 17:53:14 +0100 Subject: [PATCH 4/9] Add requestStream and pass uint8array to sendDisplay --- examples/disco/src/index.ts | 2 +- src/Lighthouse/LighthouseWebsocket.ts | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/examples/disco/src/index.ts b/examples/disco/src/index.ts index e254e9b..dedfc3b 100644 --- a/examples/disco/src/index.ts +++ b/examples/disco/src/index.ts @@ -24,7 +24,7 @@ async function sleep(time: number) { // eslint-disable-next-line no-constant-condition while (true) { // eslint-disable-next-line no-loop-func - const data = new Array(28 * 14 * 3).fill(0).map((_, j) => (j % 3 === i ? 255 : 0)); + const data = new Uint8Array(28 * 14 * 3).fill(0).map((_, j) => (j % 3 === i ? 255 : 0)); const msg = await lh.sendDisplay(data); // eslint-disable-next-line no-console diff --git a/src/Lighthouse/LighthouseWebsocket.ts b/src/Lighthouse/LighthouseWebsocket.ts index f12e8a8..ebe690d 100644 --- a/src/Lighthouse/LighthouseWebsocket.ts +++ b/src/Lighthouse/LighthouseWebsocket.ts @@ -37,8 +37,12 @@ export class LighthouseWebsocket { }); } - public async sendDisplay(rgbValues: number[]): Promise> { - return await this.send("PUT", ["user", this.auth.USER, "model"], new Uint8Array(rgbValues)); + public async sendDisplay(rgbValues: Uint8Array): Promise> { + return await this.send("PUT", ["user", this.auth.USER, "model"], rgbValues); + } + + public async requestStream(): Promise> { + return await this.send("STREAM", ["user", this.auth.USER, "model"], undefined); } private async send

(verb: LighthouseVerb, path: LighthousePath, payload: P) { From f4a53016b54f0c8f73417c839eb28130df6acfc5 Mon Sep 17 00:00:00 2001 From: fwcd Date: Sun, 6 Feb 2022 17:54:37 +0100 Subject: [PATCH 5/9] Add 'dev' script for watch-mode compilation to example --- examples/disco/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/disco/package.json b/examples/disco/package.json index 9f98d2a..681f6e4 100644 --- a/examples/disco/package.json +++ b/examples/disco/package.json @@ -4,6 +4,7 @@ "description": "", "main": "build/index.js", "scripts": { + "dev": "tsc -w", "build": "tsc", "start": "node .", "build:start": "npm run build && npm run start" From 1f85dcc099b9230c829c2c5e89ae200d7a00caf2 Mon Sep 17 00:00:00 2001 From: fwcd Date: Sun, 6 Feb 2022 18:03:37 +0100 Subject: [PATCH 6/9] Throw error if credential env var is not defined --- examples/disco/src/index.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/examples/disco/src/index.ts b/examples/disco/src/index.ts index dedfc3b..97f9d7a 100644 --- a/examples/disco/src/index.ts +++ b/examples/disco/src/index.ts @@ -4,11 +4,17 @@ import { LighthouseAuth, LighthouseWebsocket } from "lighthouse.js"; config(); -const user = process.env.LIGHTHOUSE_USER ?? ""; +function getEnv(name: string): string { + const value = process.env[name]; + if (!value) throw Error(`Environment variable ${name} is not defined!`); + return value; +} + +const user = getEnv("LIGHTHOUSE_USER"); const auth: LighthouseAuth = { USER: user, - TOKEN: process.env.LIGHTHOUSE_TOKEN ?? "", + TOKEN: getEnv("LIGHTHOUSE_TOKEN"), }; async function sleep(time: number) { From 834d77bf468a3363d720da30e0264875f16888a2 Mon Sep 17 00:00:00 2001 From: fwcd Date: Sun, 6 Feb 2022 18:07:30 +0100 Subject: [PATCH 7/9] Type send result --- src/Lighthouse/LighthouseWebsocket.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Lighthouse/LighthouseWebsocket.ts b/src/Lighthouse/LighthouseWebsocket.ts index ebe690d..c334558 100644 --- a/src/Lighthouse/LighthouseWebsocket.ts +++ b/src/Lighthouse/LighthouseWebsocket.ts @@ -45,7 +45,7 @@ export class LighthouseWebsocket { return await this.send("STREAM", ["user", this.auth.USER, "model"], undefined); } - private async send

(verb: LighthouseVerb, path: LighthousePath, payload: P) { + private async send

(verb: LighthouseVerb, path: LighthousePath, payload: P): Promise> { const id = uuid(); const data: LighthouseRequest = { AUTH: this.auth, From bf49d8551aed06685236275255cd7f70f40947bc Mon Sep 17 00:00:00 2001 From: fwcd Date: Sun, 6 Feb 2022 18:19:59 +0100 Subject: [PATCH 8/9] Reject promise if request fails --- src/Lighthouse/LighthouseWebsocket.ts | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/Lighthouse/LighthouseWebsocket.ts b/src/Lighthouse/LighthouseWebsocket.ts index c334558..a6e5154 100644 --- a/src/Lighthouse/LighthouseWebsocket.ts +++ b/src/Lighthouse/LighthouseWebsocket.ts @@ -47,7 +47,7 @@ export class LighthouseWebsocket { private async send

(verb: LighthouseVerb, path: LighthousePath, payload: P): Promise> { const id = uuid(); - const data: LighthouseRequest = { + const request: LighthouseRequest = { AUTH: this.auth, META: {}, PATH: path, @@ -56,10 +56,16 @@ export class LighthouseWebsocket { VERB: verb, }; if (this.ws?.readyState === WebSocket.OPEN) { - const prom = new Promise>((res) => { - this.registerResponseHandler(id, res); + const prom = new Promise>((resolve, reject) => { + this.registerResponseHandler(id, response => { + if (response.RNUM === 200) { + resolve(response); + } else { + reject(`${response.RNUM} ${response.RESPONSE}`); + } + }); }); - this.ws?.send(encode(data)); + this.ws?.send(encode(request)); return prom; } throw new Error("Websocket is currently not open!"); From fa7579679a7656dc1538e0168394a1426325e906 Mon Sep 17 00:00:00 2001 From: fwcd Date: Sun, 6 Feb 2022 18:34:38 +0100 Subject: [PATCH 9/9] Expose LIGHTHOUSE_WIDTH and LIGHTHOUSE_HEIGHT as constants --- examples/disco/src/index.ts | 4 ++-- src/Lighthouse/constants.ts | 2 ++ src/index.ts | 1 + 3 files changed, 5 insertions(+), 2 deletions(-) create mode 100644 src/Lighthouse/constants.ts diff --git a/examples/disco/src/index.ts b/examples/disco/src/index.ts index 97f9d7a..1cccaff 100644 --- a/examples/disco/src/index.ts +++ b/examples/disco/src/index.ts @@ -1,6 +1,6 @@ /* eslint-disable no-await-in-loop */ import { config } from "dotenv"; -import { LighthouseAuth, LighthouseWebsocket } from "lighthouse.js"; +import { LighthouseAuth, LighthouseWebsocket, LIGHTHOUSE_WIDTH, LIGHTHOUSE_HEIGHT } from "lighthouse.js"; config(); @@ -30,7 +30,7 @@ async function sleep(time: number) { // eslint-disable-next-line no-constant-condition while (true) { // eslint-disable-next-line no-loop-func - const data = new Uint8Array(28 * 14 * 3).fill(0).map((_, j) => (j % 3 === i ? 255 : 0)); + const data = new Uint8Array(LIGHTHOUSE_WIDTH * LIGHTHOUSE_HEIGHT * 3).map((_, j) => (j % 3 === i ? 255 : 0)); const msg = await lh.sendDisplay(data); // eslint-disable-next-line no-console diff --git a/src/Lighthouse/constants.ts b/src/Lighthouse/constants.ts new file mode 100644 index 0000000..433c7ba --- /dev/null +++ b/src/Lighthouse/constants.ts @@ -0,0 +1,2 @@ +export const LIGHTHOUSE_WIDTH: number = 28; +export const LIGHTHOUSE_HEIGHT: number = 14; diff --git a/src/index.ts b/src/index.ts index 2ea1cdf..a7cb57f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,2 +1,3 @@ export * from "./Lighthouse/LighthouseWebsocket"; +export * from "./Lighthouse/constants"; export * from "./Lighthouse/types";