add client receiving base
This commit is contained in:
80
client/pythagoras_client.ts
Normal file
80
client/pythagoras_client.ts
Normal file
@@ -0,0 +1,80 @@
|
||||
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);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user