2023-08-30 18:37:51 +00:00
|
|
|
import { Logger, Peer } from "../types.js";
|
|
|
|
import NodeId from "../nodeId.js";
|
|
|
|
import * as net from "net";
|
|
|
|
import { URL } from "url";
|
|
|
|
import { decodeEndian } from "../util.js";
|
2023-08-31 09:04:33 +00:00
|
|
|
import * as console from "console";
|
2023-08-30 18:37:51 +00:00
|
|
|
|
|
|
|
export class TcpPeer implements Peer {
|
|
|
|
connectionUris: Array<URL>;
|
|
|
|
isConnected: boolean = false;
|
|
|
|
challenge: Uint8Array;
|
|
|
|
private _socket: net.Socket;
|
|
|
|
|
|
|
|
constructor(_socket: net.Socket, connectionUris: URL[]) {
|
|
|
|
this.connectionUris = connectionUris.map((uri) => new URL(uri.toString()));
|
|
|
|
this.challenge = new Uint8Array();
|
|
|
|
this._socket = _socket;
|
|
|
|
}
|
|
|
|
|
|
|
|
private _id?: NodeId;
|
|
|
|
|
2023-08-31 06:25:27 +00:00
|
|
|
get id(): NodeId {
|
|
|
|
return this._id as NodeId;
|
|
|
|
}
|
|
|
|
|
2023-08-30 18:37:51 +00:00
|
|
|
set id(value: NodeId) {
|
|
|
|
this._id = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
sendMessage(message: Uint8Array): void {
|
|
|
|
this._socket.write(message);
|
|
|
|
}
|
|
|
|
|
|
|
|
renderLocationUri(): string {
|
|
|
|
return this.connectionUris.length === 0
|
|
|
|
? (this._socket.remoteAddress as string)
|
|
|
|
: this.connectionUris[0].toString();
|
|
|
|
}
|
|
|
|
|
|
|
|
listenForMessages(
|
|
|
|
callback: (event: any) => Promise<void>,
|
|
|
|
{
|
|
|
|
onDone,
|
|
|
|
onError,
|
|
|
|
logger,
|
|
|
|
}: { onDone?: any; onError?: (...args: any[]) => void; logger: Logger },
|
|
|
|
): void {
|
|
|
|
const listener = (data: Uint8Array) => {
|
|
|
|
let pos = 0;
|
|
|
|
|
|
|
|
while (pos < data.length) {
|
|
|
|
const lengthBuffer = data.slice(pos, pos + 4);
|
|
|
|
const length = decodeEndian(lengthBuffer);
|
|
|
|
|
|
|
|
if (data.length < pos + 4 + length) {
|
|
|
|
console.log(`Ignore message, invalid length (from ${this.id})`);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
const message = data.slice(pos + 4, pos + 4 + length);
|
|
|
|
callback(message).catch((e) => {
|
|
|
|
logger.catched(`Error in callback: ${e}`, this.id.toBase58());
|
|
|
|
});
|
|
|
|
} catch (e) {
|
|
|
|
logger.catched(`Caught an exception: ${e}`, this.id.toBase58());
|
|
|
|
}
|
|
|
|
|
|
|
|
pos += length + 4;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
this._socket.on("data", listener);
|
|
|
|
|
|
|
|
if (onDone) {
|
|
|
|
this._socket.on("end", onDone);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (onError) {
|
|
|
|
this._socket.on("error", onError);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-31 09:04:33 +00:00
|
|
|
public static async connect(uri: URL): Promise<net.Socket> {
|
|
|
|
const host = uri.hostname;
|
|
|
|
const port = parseInt(uri.port);
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
const socket = net.connect(port, host, () => {
|
|
|
|
resolve(socket);
|
|
|
|
});
|
|
|
|
socket.on("error", (err) => {
|
|
|
|
reject(err);
|
|
|
|
});
|
2023-08-30 18:37:51 +00:00
|
|
|
});
|
2023-08-31 09:04:33 +00:00
|
|
|
}
|
2023-08-30 18:37:51 +00:00
|
|
|
}
|