MISC: Refactor implementation of ports (#2396)

This moves the implementation entirely into the PortHandle class, which
makes the code a bit more streamlined and will allow for other port
implementations in the future.
This commit is contained in:
David Walker
2025-11-22 17:52:25 -08:00
committed by GitHub
parent 67119e6c9c
commit 50b0cc2808
3 changed files with 74 additions and 80 deletions

View File

@@ -26,7 +26,7 @@ import { convertTimeMsToTimeElapsedString } from "../utils/StringHelperFunctions
import { currentNodeMults } from "../BitNode/BitNodeMultipliers";
import { CONSTANTS } from "../Constants";
import { influenceStockThroughServerHack } from "../StockMarket/PlayerInfluencing";
import { PortNumber } from "../NetscriptPort";
import { type PortNumber, PortHandle } from "../NetscriptPort";
import { FormulaGang } from "../Gang/formulas/formulas";
import { GangMember } from "../Gang/GangMember";
import { GangMemberTask } from "../Gang/GangMemberTask";
@@ -88,7 +88,7 @@ export const helpers = {
getServer,
scriptIdentifier,
hack,
portNumber,
portHandle,
person,
server,
gang,
@@ -611,7 +611,7 @@ function hack(ctx: NetscriptContext, hostname: string, manual: boolean, opts: un
});
}
function portNumber(ctx: NetscriptContext, _n: unknown): PortNumber {
function portHandle(ctx: NetscriptContext, _n: unknown): PortHandle {
const n = positiveInteger(ctx, "portNumber", _n);
if (n > CONSTANTS.NumNetscriptPorts) {
throw errorMessage(
@@ -619,7 +619,7 @@ function portNumber(ctx: NetscriptContext, _n: unknown): PortNumber {
`Trying to use an invalid port: ${n}. Must be less or equal to ${CONSTANTS.NumNetscriptPorts}.`,
);
}
return n as PortNumber;
return new PortHandle(n as PortNumber);
}
function person(ctx: NetscriptContext, p: unknown): IPerson {

View File

@@ -91,7 +91,6 @@ import { ScriptDeath } from "./Netscript/ScriptDeath";
import { getBitNodeMultipliers } from "./BitNode/BitNode";
import { assert, assertArray, assertString, assertObject } from "./utils/TypeAssertion";
import { escapeRegExp } from "lodash";
import { clearPort, peekPort, portHandle, readPort, tryWritePort, writePort, nextPortWrite } from "./NetscriptPort";
import { FilePath, resolveFilePath } from "./Paths/FilePath";
import { hasScriptExtension } from "./Paths/ScriptFilePath";
import { hasTextExtension } from "./Paths/TextFilePath";
@@ -1039,8 +1038,8 @@ export const ns: InternalAPI<NSFull> = {
return helpers.getRunningScript(ctx, ident) !== null;
},
writePort: (ctx) => (_portNumber, data) => {
const portNumber = helpers.portNumber(ctx, _portNumber);
return writePort(portNumber, data);
const portHandle = helpers.portHandle(ctx, _portNumber);
return portHandle.write(data);
},
write: (ctx) => (_filename, _data, _mode) => {
const filepath = helpers.filePath(ctx, "filename", _filename);
@@ -1071,16 +1070,16 @@ export const ns: InternalAPI<NSFull> = {
server.writeToTextFile(filepath, mode === "w" ? data : existingText + data);
},
tryWritePort: (ctx) => (_portNumber, data) => {
const portNumber = helpers.portNumber(ctx, _portNumber);
return tryWritePort(portNumber, data);
const portHandle = helpers.portHandle(ctx, _portNumber);
return portHandle.tryWrite(data);
},
nextPortWrite: (ctx) => (_portNumber) => {
const portNumber = helpers.portNumber(ctx, _portNumber);
return nextPortWrite(portNumber);
const portHandle = helpers.portHandle(ctx, _portNumber);
return portHandle.nextWrite();
},
readPort: (ctx) => (_portNumber) => {
const portNumber = helpers.portNumber(ctx, _portNumber);
return readPort(portNumber);
const portHandle = helpers.portHandle(ctx, _portNumber);
return portHandle.read();
},
read: (ctx) => (_filename) => {
const path = helpers.filePath(ctx, "filename", _filename);
@@ -1101,8 +1100,8 @@ export const ns: InternalAPI<NSFull> = {
return contentFile.metadata.plain();
},
peek: (ctx) => (_portNumber) => {
const portNumber = helpers.portNumber(ctx, _portNumber);
return peekPort(portNumber);
const portHandle = helpers.portHandle(ctx, _portNumber);
return portHandle.peek();
},
clear: (ctx) => (_file) => {
const path = helpers.filePath(ctx, "file", _file);
@@ -1116,12 +1115,12 @@ export const ns: InternalAPI<NSFull> = {
file.content = "";
},
clearPort: (ctx) => (_portNumber) => {
const portNumber = helpers.portNumber(ctx, _portNumber);
return clearPort(portNumber);
const portHandle = helpers.portHandle(ctx, _portNumber);
return portHandle.clear();
},
getPortHandle: (ctx) => (_portNumber) => {
const portNumber = helpers.portNumber(ctx, _portNumber);
return portHandle(portNumber);
const portHandle = helpers.portHandle(ctx, _portNumber);
return portHandle;
},
rm: (ctx) => (_fn, _host) => {
const filepath = helpers.filePath(ctx, "fn", _fn);

View File

@@ -23,10 +23,10 @@ export function getPort(n: PortNumber) {
}
export class Port {
data: any[] = [];
data: unknown[] = [];
resolver: Resolver | null = null;
promise: Promise<void> | null = null;
add(data: any) {
add(data: unknown) {
this.data.push(data);
if (!this.resolver) return;
this.resolver();
@@ -35,71 +35,66 @@ export class Port {
}
}
export function portHandle(n: PortNumber): NetscriptPort {
return {
write: (value: unknown) => writePort(n, value),
tryWrite: (value: unknown) => tryWritePort(n, value),
read: () => readPort(n),
peek: () => peekPort(n),
nextWrite: () => nextPortWrite(n),
full: () => isFullPort(n),
empty: () => isEmptyPort(n),
clear: () => clearPort(n),
};
}
export class PortHandle implements NetscriptPort {
n: PortNumber;
export function writePort(n: PortNumber, value: unknown): unknown {
const port = getPort(n);
// Primitives don't need to be cloned.
port.add(isObjectLike(value) ? structuredClone(value) : value);
if (port.data.length > Settings.MaxPortCapacity) return port.data.shift();
return null;
}
constructor(n: PortNumber) {
this.n = n;
}
export function tryWritePort(n: PortNumber, value: unknown): boolean {
const port = getPort(n);
if (port.data.length >= Settings.MaxPortCapacity) return false;
// Primitives don't need to be cloned.
port.add(isObjectLike(value) ? structuredClone(value) : value);
return true;
}
write(value: unknown): unknown {
const port = getPort(this.n);
// Primitives don't need to be cloned.
port.add(isObjectLike(value) ? structuredClone(value) : value);
if (port.data.length > Settings.MaxPortCapacity) return port.data.shift();
return null;
}
export function readPort(n: PortNumber): unknown {
const port = NetscriptPorts.get(n);
if (!port || !port.data.length) return emptyPortData;
const returnVal: unknown = port.data.shift();
if (!port.data.length && !port.resolver) NetscriptPorts.delete(n);
return returnVal;
}
tryWrite(value: unknown): boolean {
const port = getPort(this.n);
if (port.data.length >= Settings.MaxPortCapacity) return false;
// Primitives don't need to be cloned.
port.add(isObjectLike(value) ? structuredClone(value) : value);
return true;
}
export function peekPort(n: PortNumber): unknown {
const port = NetscriptPorts.get(n);
if (!port || !port.data.length) return emptyPortData;
// Needed to avoid exposing internal objects.
return isObjectLike(port.data[0]) ? structuredClone(port.data[0]) : port.data[0];
}
read(): unknown {
const port = NetscriptPorts.get(this.n);
if (!port || !port.data.length) return emptyPortData;
const returnVal: unknown = port.data.shift();
if (!port.data.length && !port.resolver) NetscriptPorts.delete(this.n);
return returnVal;
}
export function nextPortWrite(n: PortNumber) {
const port = getPort(n);
if (!port.promise) port.promise = new Promise<void>((res) => (port.resolver = res));
return port.promise;
}
peek(): unknown {
const port = NetscriptPorts.get(this.n);
if (!port || !port.data.length) return emptyPortData;
// Needed to avoid exposing internal objects.
return isObjectLike(port.data[0]) ? structuredClone(port.data[0]) : port.data[0];
}
function isFullPort(n: PortNumber) {
const port = NetscriptPorts.get(n);
if (!port) return false;
return port.data.length >= Settings.MaxPortCapacity;
}
nextWrite(): Promise<void> {
const port = getPort(this.n);
if (!port.promise) port.promise = new Promise<void>((res) => (port.resolver = res));
return port.promise;
}
function isEmptyPort(n: PortNumber) {
const port = NetscriptPorts.get(n);
if (!port) return true;
return port.data.length === 0;
}
full(): boolean {
const port = NetscriptPorts.get(this.n);
if (!port) return false;
return port.data.length >= Settings.MaxPortCapacity;
}
export function clearPort(n: PortNumber) {
const port = NetscriptPorts.get(n);
if (!port) return;
if (!port.resolver) NetscriptPorts.delete(n);
port.data.length = 0;
empty(): boolean {
const port = NetscriptPorts.get(this.n);
if (!port) return true;
return port.data.length === 0;
}
clear(): void {
const port = NetscriptPorts.get(this.n);
if (!port) return;
if (!port.resolver) NetscriptPorts.delete(this.n);
port.data.length = 0;
}
}