81 lines
2.1 KiB
TypeScript
81 lines
2.1 KiB
TypeScript
import { uint_bytes_to_num, utf8_decode } from "./tools";
|
|
import { WSClient } from "./ws";
|
|
|
|
enum PythagorasIncomingMessageType {
|
|
SubUpdateCur,
|
|
SubFinishCur,
|
|
SelectedMessage,
|
|
};
|
|
|
|
type PythagorasIncomingMessage = (
|
|
|
|
{
|
|
type: PythagorasIncomingMessageType.SubFinishCur | PythagorasIncomingMessageType.SubUpdateCur,
|
|
text: string,
|
|
} |
|
|
|
|
{
|
|
type: PythagorasIncomingMessageType.SelectedMessage,
|
|
message: string,
|
|
}
|
|
|
|
);
|
|
|
|
export class PythagorasClient {
|
|
private sock: WSClient | null;
|
|
private addr: string;
|
|
|
|
private buf: Uint8Array;
|
|
|
|
private static max_recv_retry: number = 10;
|
|
|
|
public constructor(addr: string) {
|
|
this.sock = null;
|
|
this.addr = addr;
|
|
this.buf = new Uint8Array(0);
|
|
}
|
|
|
|
private async reconnect(): Promise<void> {
|
|
this.sock = new WSClient(this.addr);
|
|
await this.sock.wait_for_connection();
|
|
}
|
|
|
|
/**
|
|
* Force receive from the underlying `WSClient`.
|
|
* This will try to receive (or reconnect) up to `PythagorasClient.max_recv_retry` times.
|
|
*/
|
|
private async recv_inner(): Promise<Blob> {
|
|
if (this.sock === null) { await this.reconnect(); }
|
|
for (let i = 0; i < PythagorasClient.max_recv_retry; ++i) {
|
|
const received = await this.sock!.receive();
|
|
if (received !== null) { return received; }
|
|
await this.reconnect();
|
|
}
|
|
throw new Error("max reconnection attempts reached");
|
|
}
|
|
|
|
/**
|
|
* Receive `target` bytes from the underlying stream (or leftovers from previous reads).
|
|
*/
|
|
private async recv_length(target: number): Promise<Uint8Array> {
|
|
if (target == 0) { return new Uint8Array(0); }
|
|
while (this.buf.length < target) {
|
|
const received = await (await this.recv_inner()).bytes();
|
|
const merged = new Uint8Array(this.buf.length + received.length);
|
|
merged.set(this.buf);
|
|
merged.set(received, this.buf.length);
|
|
this.buf = merged;
|
|
}
|
|
const total = this.buf;
|
|
this.buf = new Uint8Array(total.length - target);
|
|
this.buf.set(total.slice(target));
|
|
return total.slice(0, target);
|
|
}
|
|
|
|
public async recv(): Promise<PythagorasIncomingMessage> {
|
|
const advertised_length = uint_bytes_to_num(await this.recv_length(4));
|
|
const payload = utf8_decode(await this.recv_length(advertised_length));
|
|
return JSON.parse(payload);
|
|
}
|
|
}
|