Skip to content

Commit

Permalink
repo: add debug logs
Browse files Browse the repository at this point in the history
  • Loading branch information
thetayloredman committed Feb 21, 2023
1 parent 747743e commit a3e4f07
Show file tree
Hide file tree
Showing 9 changed files with 117 additions and 7 deletions.
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
"@babel/core": "^7.20.7",
"@babel/preset-env": "^7.20.2",
"@babel/preset-typescript": "^7.18.6",
"@types/debug": "^4.1.7",
"@types/jest": "^29.2.4",
"@typescript-eslint/eslint-plugin": "^5.47.0",
"@typescript-eslint/parser": "^5.47.0",
Expand Down Expand Up @@ -81,6 +82,7 @@
},
"packageManager": "yarn@3.4.1",
"dependencies": {
"debug": "^4.3.4",
"strict-event-emitter": "^0.4.6"
}
}
9 changes: 9 additions & 0 deletions src/DumbClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,15 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

import debug from "debug";

import SafeEventEmitter from "./lib/SafeEventEmitter";
import Packet from "./Packet";
import type Shell from "./shell";
import { ShellEvents } from "./shell";

const log = debug("node-subdata-2:DumbClient");

/** A list of possible events for a {@link DumbClient} */
export enum DumbClientEvents {
/** A new packet is received */
Expand Down Expand Up @@ -48,11 +52,14 @@ export default class DumbClient extends SafeEventEmitter<DumbClientEventArgument
*/
public constructor(shell: Shell) {
super();
log("initializing");
this._shell = shell;
this._shell.on(ShellEvents.Close, () => {
log("forwarding close");
this.emit(DumbClientEvents.Close);
});
this._shell.on(ShellEvents.Packet, (_size, data) => {
log("forwarding packet", data);
this.emit(DumbClientEvents.Packet, new Packet(data));
});
}
Expand All @@ -61,11 +68,13 @@ export default class DumbClient extends SafeEventEmitter<DumbClientEventArgument
* Terminate the TCP level of the connection. This does not send the disconnect packets.
*/
public close() {
log("triggering close");
this._shell.close();
}

/** Send a {@link Packet} over the stream. */
public send(data: Packet) {
log("sending packet", data);
this._shell.send(data.toRaw());
}
}
6 changes: 6 additions & 0 deletions src/shell/algorithms/Raw.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,21 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

import debug from "debug";

import type ShellAlgorithm from "./ShellAlgorithm";

const log = debug("node-subdata-2:shell:algorithms:Raw");

/** The initial {@link ShellAlgorithm} used before any encryption is enabled. */
export default class RawShellAlgorithm implements ShellAlgorithm {
public encode(data: Buffer): Buffer {
log("encoding", data, "to", data);
return data;
}

public decode(packet: Buffer): Buffer {
log("decoding", packet, "to", packet);
return packet;
}
}
9 changes: 9 additions & 0 deletions src/shell/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,15 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

import debug from "debug";

import SafeEventEmitter from "../lib/SafeEventEmitter";
import type Stream from "../stream";
import { StreamEvents } from "../stream";
import type ShellAlgorithm from "./algorithms/ShellAlgorithm";

const log = debug("node-subdata-2:shell");

export enum ShellEvents {
/** Fired when a new packet is received */
Packet = "packet",
Expand All @@ -45,23 +49,28 @@ export default class Shell extends SafeEventEmitter<ShellEventArguments> {

public constructor(algorithm: ShellAlgorithm, stream: Stream) {
super();
log("initializing");
this._algorithm = algorithm;
this._stream = stream;
this._stream.on(StreamEvents.Close, () => {
log("forwarding close");
this.emit(ShellEvents.Close);
});
this._stream.on(StreamEvents.Packet, (size, packet) => {
log("forwarding+decoding packet", packet);
this.emit(ShellEvents.Packet, size, this._algorithm.decode(packet));
});
}

/** Send a packet. */
public send(data: Buffer): void {
log("encoding+sending packet", data);
this._stream.writePacket(this._algorithm.encode(data));
}

/** Close the underlying connection. */
public close(): void {
log("closing");
this._stream.close();
}
}
48 changes: 41 additions & 7 deletions src/stream/DirectStream.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,14 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

import debug from "debug";

import SafeEventEmitter from "../lib/SafeEventEmitter";
import { bytes, kb, mb } from "../lib/sizeHelpers";
import { type SizedControlCharacters, ControlCharacters } from "./controlCharacters";

const log = debug("node-subdata-2:stream:DirectStream");

export enum DirectStreamEvents {
ReadReset = "reset",
Read = "read",
Expand Down Expand Up @@ -64,6 +68,7 @@ export default class DirectStream extends SafeEventEmitter<DirectStreamEventArgu

public constructor() {
super();
log("initializing");
this._buffer = Buffer.alloc(0);
this._bufferSize = 0;
this._packet = Buffer.alloc(0);
Expand All @@ -75,15 +80,18 @@ export default class DirectStream extends SafeEventEmitter<DirectStreamEventArgu
* @param data The data to feed
*/
public feed(data: Buffer): void {
log("feeding data", data, "size", data.length);
this._buffer = Buffer.concat([this._buffer, data]);
this._bufferSize += data.length;
log("new data", this._buffer, "size", this._bufferSize);
this._handleNewData();
}

/**
* Invalidates all previous data. Called internally when a {@link ControlCharacters.ReadReset} is encountered.
*/
private _readReset(): void {
log("triggering read reset");
this._buffer = Buffer.alloc(0);
this._bufferSize = 0;
this._packet = Buffer.alloc(0);
Expand All @@ -101,11 +109,15 @@ export default class DirectStream extends SafeEventEmitter<DirectStreamEventArgu
if (!(char.toString() in ControlCharacters))
throw new Error(`I don't know what I am looking at! Encountered unknown control character 0x${this._buffer[0].toString(16)} in stream.`);

log("handling control character", ControlCharacters[char]);

switch (this._buffer[0]) {
case ControlCharacters.ReadReset:
const postReset = this._buffer.subarray(1);
log("triggering read reset, following data", postReset);
this._readReset();
// Re-insert all data that follows the reset
log("re-feeding data");
this.feed(postReset);
break;
case ControlCharacters.ReadByte:
Expand Down Expand Up @@ -186,6 +198,7 @@ export default class DirectStream extends SafeEventEmitter<DirectStreamEventArgu
}: { controlCharacter: SizedControlCharacters | ControlCharacters.ReadByte; bytes: number; numberOfType: number },
data: Buffer | number
): void {
log("triggering read event of type", ControlCharacters[controlCharacter], "with data", data, "and size", bytes, "bytes");
this._packet = Buffer.concat([this._packet, data instanceof Buffer ? data : Buffer.from([data])]);
this._packetSize += bytes;
/* istanbul ignore if: this should never reasonably happen & is untestable without a LOT of work */
Expand All @@ -203,6 +216,7 @@ export default class DirectStream extends SafeEventEmitter<DirectStreamEventArgu

/** Called internally to clear and emit a packet. */
private _emitPacket(): void {
debug("triggering packet");
this.emit(DirectStreamEvents.Packet, this._packetSize, this._packet);
this._packet = Buffer.alloc(0);
this._packetSize = 0;
Expand All @@ -213,6 +227,7 @@ export default class DirectStream extends SafeEventEmitter<DirectStreamEventArgu
* @param count The amount to shift the buffer by
*/
private _shiftBuffer(count: number): void {
log("shifting internal buffer by", count);
this._buffer = this._buffer.subarray(count);
this._bufferSize -= count;
}
Expand All @@ -229,11 +244,20 @@ export default class DirectStream extends SafeEventEmitter<DirectStreamEventArgu
size: number,
sizeFn: (s: number) => number
): { controlCharacter: SizedControlCharacters; number: number; remainder: number } {
return {
const result = {
controlCharacter,
number: Math.min(255, Math.floor(size / sizeFn(4)) - 1),
remainder: size - sizeFn(4) * (Math.min(255, Math.floor(size / sizeFn(4)) - 1) + 1)
};
log(
"calculated control character data for size",
size,
"(using arbitrary units) and control character",
ControlCharacters[controlCharacter],
"as",
result
);
return result;
}

/**
Expand All @@ -247,18 +271,25 @@ export default class DirectStream extends SafeEventEmitter<DirectStreamEventArgu
| { controlCharacter: ControlCharacters.ReadByte; number: -1; remainder: number }
| { controlCharacter: SizedControlCharacters; number: number; remainder: number }
| false {
if (size < 1) return false;
if (size < 4) return { controlCharacter: ControlCharacters.ReadByte, number: -1, remainder: size - 1 };
if (size < kb(4)) return this._calculateControlCharacterRemainder(ControlCharacters.ReadBytes, size, bytes);
if (size < mb(4)) return this._calculateControlCharacterRemainder(ControlCharacters.ReadKB, size, kb);
return this._calculateControlCharacterRemainder(ControlCharacters.ReadMB, size, mb);
let result:
| { controlCharacter: ControlCharacters.ReadByte; number: -1; remainder: number }
| { controlCharacter: SizedControlCharacters; number: number; remainder: number }
| false;
if (size < 1) result = false;
else if (size < 4) result = { controlCharacter: ControlCharacters.ReadByte, number: -1, remainder: size - 1 };
else if (size < kb(4)) result = this._calculateControlCharacterRemainder(ControlCharacters.ReadBytes, size, bytes);
else if (size < mb(4)) result = this._calculateControlCharacterRemainder(ControlCharacters.ReadKB, size, kb);
else result = this._calculateControlCharacterRemainder(ControlCharacters.ReadMB, size, mb);
log("best control character for size", size, "is", result);
return result;
}

/**
* Encode a Buffer into Layer 1 stream data.
* @param data The data to encode
*/
public encode(input: Buffer): Buffer {
log("encoding data", input);
const size = input.length;
let remaining = size;
// TODO: Change this when GB/TB/PB support is added.
Expand All @@ -269,6 +300,7 @@ export default class DirectStream extends SafeEventEmitter<DirectStreamEventArgu
// and convert it to a Buffer.
const results = [];
while (remaining > 0) {
log("remaining size", remaining);
const data = this._bestControlCharacter(remaining);
/* istanbul ignore next: this should never happen */
if (data === false) throw new Error("This should never happen");
Expand Down Expand Up @@ -305,6 +337,8 @@ export default class DirectStream extends SafeEventEmitter<DirectStreamEventArgu
/* istanbul ignore next */
throw new Error(`Unrecognized control character returned by _bestControlCharacter for size ${remainder}`);
}
return Buffer.from(results.flat().flatMap((x) => (x instanceof Buffer ? Array.from(x.values()) : x)));
const result = Buffer.from(results.flat().flatMap((x) => (x instanceof Buffer ? Array.from(x.values()) : x)));
log("final result", result);
return result;
}
}
15 changes: 15 additions & 0 deletions src/stream/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,16 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

import debug from "debug";

import SafeEventEmitter from "../lib/SafeEventEmitter";
import { ControlCharacters } from "./controlCharacters";
import DirectStream, { DirectStreamEvents } from "./DirectStream";
import type IOProvider from "./providers/IOProvider";
import { IOProviderEvents } from "./providers/IOProvider";

const log = debug("node-subdata-2:stream");

export enum StreamEvents {
Read = "read",
Packet = "packet",
Expand Down Expand Up @@ -67,21 +71,27 @@ export default class Stream extends SafeEventEmitter<StreamEventArguments> {
*/
public constructor(provider: IOProvider) {
super();
log("initializing");
this._provider = provider;
this._stream = new DirectStream();
this._provider.on(IOProviderEvents.Data, (data) => {
log("feeding data", data);
this._stream.feed(data);
});
this._stream.on(DirectStreamEvents.ReadReset, () => {
log("forwarding reset");
this.emit(StreamEvents.Reset);
});
this._stream.on(DirectStreamEvents.Read, (_size, _count, data) => {
log("forwarding read", data);
this.emit(StreamEvents.Read, data instanceof Buffer ? data : Buffer.from([data]));
});
this._stream.on(DirectStreamEvents.Packet, (size, data) => {
log("forwarding packet", data);
this.emit(StreamEvents.Packet, size, data);
});
this._provider.on(IOProviderEvents.Close, () => {
log("forwarding close");
this.emit(StreamEvents.Close);
});
}
Expand All @@ -92,6 +102,7 @@ export default class Stream extends SafeEventEmitter<StreamEventArguments> {
* @param data The data to write
*/
public write(data: Buffer): void {
log("writing", data);
this._provider.write(this._stream.encode(data));
}

Expand All @@ -100,6 +111,7 @@ export default class Stream extends SafeEventEmitter<StreamEventArguments> {
* Note: This is often easier performed in one write via {@link Stream.writePacket}.
*/
public endPacket(): void {
log("ending packet");
this._provider.write(Buffer.from([ControlCharacters.EndOfPacket]));
}

Expand All @@ -108,20 +120,23 @@ export default class Stream extends SafeEventEmitter<StreamEventArguments> {
* however, this will send both in one single transmission, which is probably marginally more efficient.
*/
public writePacket(data: Buffer): void {
log("writing packet of", data);
this._provider.write(Buffer.concat([this._stream.encode(data), Buffer.from([ControlCharacters.EndOfPacket])]));
}

/**
* Trigger a read reset and tell the remote server to discard all data.
*/
public readReset(): void {
log("triggering read reset");
this._provider.write(Buffer.from([ControlCharacters.ReadReset]));
}

/**
* Close the connection
*/
public close(): void {
log("triggering close");
this._provider.close();
}
}
Loading

0 comments on commit a3e4f07

Please sign in to comment.