77 lines
2.3 KiB
TypeScript
77 lines
2.3 KiB
TypeScript
export class WSClient {
|
|
private is_connected: boolean;
|
|
private is_closed: boolean;
|
|
private sock: WebSocket;
|
|
|
|
private messages_received: Blob[];
|
|
|
|
// callbacks
|
|
private callbacks_connected: (() => void)[];
|
|
private callbacks_receive: ((data: Blob | null) => void)[];
|
|
|
|
public constructor(addr: string) {
|
|
this.is_connected = false;
|
|
this.is_closed = false;
|
|
this.messages_received = [];
|
|
this.callbacks_connected = [];
|
|
this.callbacks_receive = [];
|
|
|
|
this.sock = new WebSocket(addr);
|
|
this.sock.binaryType = "blob";
|
|
this.sock.addEventListener("open", (_) => {
|
|
this.is_connected = true;
|
|
for (const callback of this.callbacks_connected) { callback(); }
|
|
this.callbacks_connected = [];
|
|
});
|
|
this.sock.addEventListener("message", (e) => {
|
|
const callback = this.callbacks_receive.shift();
|
|
if (callback === undefined) { this.messages_received.push(e.data); return; }
|
|
callback(e.data);
|
|
});
|
|
this.sock.addEventListener("error", (_) => { this.end(); });
|
|
this.sock.addEventListener("close", (_) => { this.end(); });
|
|
}
|
|
|
|
public async wait_for_connection(): Promise<void> {
|
|
if (this.is_closed) { throw new Error("connetion was already closed"); }
|
|
if (this.is_connected) { return; }
|
|
await new Promise<void>((resolver) => {
|
|
this.callbacks_connected.push(resolver);
|
|
});
|
|
}
|
|
|
|
private end(): void {
|
|
this.is_connected = false;
|
|
this.is_closed = true;
|
|
for (const callback of this.callbacks_connected) { callback(); }
|
|
this.callbacks_connected = [];
|
|
for (const callback of this.callbacks_receive) { callback(null); }
|
|
this.callbacks_receive = [];
|
|
}
|
|
|
|
/**
|
|
* @returns `true` if the send call was placed successfully, `false` if the client is not
|
|
* active anymore
|
|
*/
|
|
public send(message: string | ArrayBufferLike | Blob | ArrayBufferView): boolean {
|
|
if (!this.is_connected) { return false; }
|
|
this.sock.send(message);
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Waits for a new incoming message or connection close.
|
|
*
|
|
* @returns a `Blob` if there was an incoming message, `null` if the connection closed before
|
|
* a message could be received
|
|
*/
|
|
public receive(): Promise<Blob | null> {
|
|
const queued = this.messages_received.shift();
|
|
if (queued !== undefined) { return Promise.resolve(queued); }
|
|
if (this.is_closed) { return Promise.resolve(null); }
|
|
return new Promise<Blob | null>((resolver) => {
|
|
this.callbacks_receive.push(resolver);
|
|
});
|
|
}
|
|
}
|