From afcaf38813051897fde1c5d4de3fc6da835d1490 Mon Sep 17 00:00:00 2001 From: 0xLogN Date: Tue, 21 Feb 2023 09:47:13 -0800 Subject: [PATCH] feat: initial DumbClient impl --- src/DumbClient.ts | 71 ++++++++++++++++++++++++++++++++++++++++++++++ src/Packet.ts | 44 ++++++++++++++++++++++++++++ src/index.ts | 4 +++ src/shell/index.ts | 5 ++++ 4 files changed, 124 insertions(+) create mode 100644 src/DumbClient.ts create mode 100644 src/Packet.ts diff --git a/src/DumbClient.ts b/src/DumbClient.ts new file mode 100644 index 0000000..4b905b6 --- /dev/null +++ b/src/DumbClient.ts @@ -0,0 +1,71 @@ +/* + * node-subdata-2 - SubData 2 wrapper for Node.js + * Copyright (C) 2022 LogN + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +import SafeEventEmitter from "./lib/SafeEventEmitter"; +import Packet from "./Packet"; +import type Shell from "./shell"; +import { ShellEvents } from "./shell"; + +/** A list of possible events for a {@link DumbClient} */ +export enum DumbClientEvents { + /** A new packet is received */ + Packet = "packet", + /** The connection is closing */ + Close = "close" +} + +export type DumbClientEventArguments = { + [DumbClientEvents.Packet]: [Packet]; + [DumbClientEvents.Close]: []; +}; + +/** + * Represents a SubData 2 client that does not perform any protocol + * handshake or states, and leaves it up to the user. You probably + * don't want to use this. + */ +export default class DumbClient extends SafeEventEmitter { + private _shell: Shell; + + /** + * Create a new DumbClient. + * @param shell The {@link Shell} to use + */ + public constructor(shell: Shell) { + super(); + this._shell = shell; + this._shell.on(ShellEvents.Close, () => { + this.emit(DumbClientEvents.Close); + }); + this._shell.on(ShellEvents.Packet, (_size, data) => { + this.emit(DumbClientEvents.Packet, new Packet(data)); + }); + } + + /** + * Terminate the TCP level of the connection. This does not send the disconnect packets. + */ + public close() { + this._shell.close(); + } + + /** Send a {@link Packet} over the stream. */ + public send(data: Packet) { + this._shell.send(data.toRaw()); + } +} diff --git a/src/Packet.ts b/src/Packet.ts new file mode 100644 index 0000000..d4544e2 --- /dev/null +++ b/src/Packet.ts @@ -0,0 +1,44 @@ +/* + * node-subdata-2 - SubData 2 wrapper for Node.js + * Copyright (C) 2022 LogN + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** Describes a SubData 2 packet. */ +export default class Packet { + /** This packet's identification number */ + public id: number; + /** The rest of the packet's InputStream */ + public data: Buffer; + + /** + * Create a new Packet. + * @param raw The raw packet data including the ID as the first two bytes + */ + public constructor(raw: Buffer) { + this.id = parseInt(raw.subarray(0, 2).toString("hex"), 16); + this.data = raw.subarray(2); + } + + /** Convert this Packet to raw network data */ + public toRaw() { + return Buffer.concat([Buffer.from([this.id >> 8, this.id & 0xff]), this.data]); + } + + /** Make a new Packet given an ID and data. */ + public static fromID(id: number, data: Buffer) { + return new Packet(Buffer.concat([Buffer.from([id >> 8, id & 0xff]), data])); + } +} diff --git a/src/index.ts b/src/index.ts index 69022c1..8ea2344 100644 --- a/src/index.ts +++ b/src/index.ts @@ -16,6 +16,7 @@ * along with this program. If not, see . */ +import DumbClient, { DumbClientEventArguments, DumbClientEvents } from "./DumbClient"; import SafeEventEmitter from "./lib/SafeEventEmitter.js"; import { bytes, kb, mb } from "./lib/sizeHelpers.js"; import Shell, { ShellEventArguments, ShellEvents } from "./shell/"; @@ -34,6 +35,9 @@ export { DirectStream, DirectStreamEventArguments, DirectStreamEvents, + DumbClient, + DumbClientEventArguments, + DumbClientEvents, IOProvider, IOProviderEventArguments, IOProviderEvents, diff --git a/src/shell/index.ts b/src/shell/index.ts index ba2c65c..103eecf 100644 --- a/src/shell/index.ts +++ b/src/shell/index.ts @@ -62,4 +62,9 @@ export default class Shell extends SafeEventEmitter { public send(data: Buffer): void { this._stream.writePacket(this._algorithm.encode(data)); } + + /** Close the underlying connection. */ + public close(): void { + this._stream.close(); + } }