forked from FluffyLabs/jam-testing
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsocket.ts
More file actions
100 lines (81 loc) · 2.68 KB
/
Copy pathsocket.ts
File metadata and controls
100 lines (81 loc) · 2.68 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import * as net from "node:net";
const LEN_PREFIX_BYTES = 4;
function decodeLength(buffer: Buffer): number {
return buffer.readUInt32LE(0);
}
function encodeLength(length: number): Buffer {
const buffer = Buffer.allocUnsafe(LEN_PREFIX_BYTES);
buffer.writeUInt32LE(length, 0);
return buffer;
}
export class Socket {
static async connect(socketPath: string) {
const client = net.createConnection(socketPath);
await new Promise<void>((resolve, reject) => {
client.once("connect", () => {
resolve();
});
client.once("error", () => {
reject();
});
});
return new Socket(socketPath, client);
}
private constructor(
private readonly socketPath: string,
private socket: net.Socket,
) {}
async reconnect() {
this.socket.end();
const client = net.createConnection(this.socketPath);
await new Promise<void>((resolve, reject) => {
client.once("connect", () => {
resolve();
});
client.once("error", () => {
reject();
});
});
this.socket = client;
}
async send(data: Buffer | Uint8Array): Promise<Buffer> {
// prepare to read response.
let responseBuffer = Buffer.alloc(0);
let expectedLength: number | null = null;
const response = new Promise<Buffer>((resolve, reject) => {
const socket = this.socket;
socket.on("data", readResponse);
socket.once("error", reject);
socket.once("close", closeHandler);
function readResponse(chunk: Buffer) {
responseBuffer = Buffer.concat([responseBuffer, chunk]);
if (expectedLength === null && responseBuffer.length >= LEN_PREFIX_BYTES) {
expectedLength = decodeLength(responseBuffer.subarray(0, LEN_PREFIX_BYTES));
}
if (expectedLength === null || responseBuffer.length < expectedLength + LEN_PREFIX_BYTES) {
// wait for more data
return;
}
// we now have everything, we can resolve the promise.
const responseData = responseBuffer.subarray(LEN_PREFIX_BYTES, expectedLength + LEN_PREFIX_BYTES);
socket.off("data", readResponse);
socket.off("error", reject);
socket.off("close", closeHandler);
resolve(responseData);
}
function closeHandler() {
if (expectedLength === null || responseBuffer.length < expectedLength + 4) {
reject(new Error("Connection closed before receiving complete response"));
}
}
});
// and send the request now
const lengthPrefix = encodeLength(data.length);
const message = Buffer.concat([lengthPrefix, data]);
this.socket.write(message);
return await response;
}
close() {
this.socket.end();
}
}