BUGFIX: Memory Leak in NetscriptPorts (#399)

Co-authored-by: Snarling <84951833+Snarling@users.noreply.github.com>
This commit is contained in:
T.J. Eckman 2023-02-27 19:54:04 -05:00 committed by GitHub
parent 9d504b0dfb
commit 33f0150d25
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 169 additions and 190 deletions

@ -15,9 +15,7 @@ the element that is read is removed from the port.
The :js:func:`read`, :js:func:`write`, :js:func:`tryWrite`, :js:func:`clear`, and :js:func:`peek` The :js:func:`read`, :js:func:`write`, :js:func:`tryWrite`, :js:func:`clear`, and :js:func:`peek`
Netscript functions can be used to interact with ports. Netscript functions can be used to interact with ports.
Right now, there are only 20 ports for Netscript, denoted by the number 1 When using the functions above, the ports are specified by passing the number as the first argument and the value as the second.
through 20. When using the functions above, the ports are specified
by passing the number as the first argument and the value as the second.
The default maximum capacity of a port is 50, but this can be changed in Options > System. Setting this too high can cause the game to use a lot of memory. The default maximum capacity of a port is 50, but this can be changed in Options > System. Setting this too high can cause the game to use a lot of memory.
.. important:: The data inside ports are not saved! This means if you close and re-open the game, or reload the page then you will lose all of the data in the ports! .. important:: The data inside ports are not saved! This means if you close and re-open the game, or reload the page then you will lose all of the data in the ports!

@ -9,7 +9,7 @@ Object representing a port. A port is a serialized queue.
**Signature:** **Signature:**
```typescript ```typescript
interface NetscriptPort export interface NetscriptPort
``` ```
## Methods ## Methods

@ -9,14 +9,14 @@ Get all data on a port.
**Signature:** **Signature:**
```typescript ```typescript
getPortHandle(port: number): NetscriptPort; getPortHandle(portNumber: number): NetscriptPort;
``` ```
## Parameters ## Parameters
| Parameter | Type | Description | | Parameter | Type | Description |
| --- | --- | --- | | --- | --- | --- |
| port | number | Port number. Must be an integer between 1 and 20. | | portNumber | number | Port number. Must be an integer between 1 and 20. |
**Returns:** **Returns:**

@ -90,7 +90,7 @@ export async function main(ns) {
| [getHostname()](./bitburner.ns.gethostname.md) | Returns a string with the hostname of the server that the script is running on. | | [getHostname()](./bitburner.ns.gethostname.md) | Returns a string with the hostname of the server that the script is running on. |
| [getMoneySources()](./bitburner.ns.getmoneysources.md) | Get information about the sources of income for this run. | | [getMoneySources()](./bitburner.ns.getmoneysources.md) | Get information about the sources of income for this run. |
| [getPlayer()](./bitburner.ns.getplayer.md) | Get information about the player. | | [getPlayer()](./bitburner.ns.getplayer.md) | Get information about the player. |
| [getPortHandle(port)](./bitburner.ns.getporthandle.md) | Get all data on a port. | | [getPortHandle(portNumber)](./bitburner.ns.getporthandle.md) | Get all data on a port. |
| [getPurchasedServerCost(ram)](./bitburner.ns.getpurchasedservercost.md) | Get cost of purchasing a server. | | [getPurchasedServerCost(ram)](./bitburner.ns.getpurchasedservercost.md) | Get cost of purchasing a server. |
| [getPurchasedServerLimit()](./bitburner.ns.getpurchasedserverlimit.md) | Returns the maximum number of servers you can purchase. | | [getPurchasedServerLimit()](./bitburner.ns.getpurchasedserverlimit.md) | Returns the maximum number of servers you can purchase. |
| [getPurchasedServerMaxRam()](./bitburner.ns.getpurchasedservermaxram.md) | Returns the maximum RAM that a purchased server can have. | | [getPurchasedServerMaxRam()](./bitburner.ns.getpurchasedservermaxram.md) | Returns the maximum RAM that a purchased server can have. |
@ -140,14 +140,14 @@ export async function main(ns) {
| [mv(host, source, destination)](./bitburner.ns.mv.md) | Move a file on the target server. | | [mv(host, source, destination)](./bitburner.ns.mv.md) | Move a file on the target server. |
| [nFormat(n, format)](./bitburner.ns.nformat.md) | Format a number using the numeral library. This function is deprecated and will be removed in 2.3. | | [nFormat(n, format)](./bitburner.ns.nformat.md) | Format a number using the numeral library. This function is deprecated and will be removed in 2.3. |
| [nuke(host)](./bitburner.ns.nuke.md) | Runs NUKE.exe on a server. | | [nuke(host)](./bitburner.ns.nuke.md) | Runs NUKE.exe on a server. |
| [peek(port)](./bitburner.ns.peek.md) | Get a copy of the data from a port without popping it. | | [peek(portNumber)](./bitburner.ns.peek.md) | Get a copy of the data from a port without popping it. |
| [print(args)](./bitburner.ns.print.md) | Prints one or more values or variables to the scripts logs. | | [print(args)](./bitburner.ns.print.md) | Prints one or more values or variables to the scripts logs. |
| [printf(format, args)](./bitburner.ns.printf.md) | Prints a formatted string to the scripts logs. | | [printf(format, args)](./bitburner.ns.printf.md) | Prints a formatted string to the scripts logs. |
| [prompt(txt, options)](./bitburner.ns.prompt.md) | Prompt the player with an input modal. | | [prompt(txt, options)](./bitburner.ns.prompt.md) | Prompt the player with an input modal. |
| [ps(host)](./bitburner.ns.ps.md) | List running scripts on a server. | | [ps(host)](./bitburner.ns.ps.md) | List running scripts on a server. |
| [purchaseServer(hostname, ram)](./bitburner.ns.purchaseserver.md) | Purchase a server. | | [purchaseServer(hostname, ram)](./bitburner.ns.purchaseserver.md) | Purchase a server. |
| [read(filename)](./bitburner.ns.read.md) | Read content of a file. | | [read(filename)](./bitburner.ns.read.md) | Read content of a file. |
| [readPort(port)](./bitburner.ns.readport.md) | Read data from a port. | | [readPort(portNumber)](./bitburner.ns.readport.md) | Read data from a port. |
| [relaysmtp(host)](./bitburner.ns.relaysmtp.md) | Runs relaySMTP.exe on a server. | | [relaysmtp(host)](./bitburner.ns.relaysmtp.md) | Runs relaySMTP.exe on a server. |
| [renamePurchasedServer(hostname, newName)](./bitburner.ns.renamepurchasedserver.md) | Rename a purchased server. | | [renamePurchasedServer(hostname, newName)](./bitburner.ns.renamepurchasedserver.md) | Rename a purchased server. |
| [resizeTail(width, height, pid)](./bitburner.ns.resizetail.md) | Resize a tail window. | | [resizeTail(width, height, pid)](./bitburner.ns.resizetail.md) | Resize a tail window. |
@ -168,12 +168,12 @@ export async function main(ns) {
| [toast(msg, variant, duration)](./bitburner.ns.toast.md) | Queue a toast (bottom-right notification). | | [toast(msg, variant, duration)](./bitburner.ns.toast.md) | Queue a toast (bottom-right notification). |
| [tprint(args)](./bitburner.ns.tprint.md) | Prints one or more values or variables to the Terminal. | | [tprint(args)](./bitburner.ns.tprint.md) | Prints one or more values or variables to the Terminal. |
| [tprintf(format, values)](./bitburner.ns.tprintf.md) | Prints a raw value or a variable to the Terminal. | | [tprintf(format, values)](./bitburner.ns.tprintf.md) | Prints a raw value or a variable to the Terminal. |
| [tryWritePort(port, data)](./bitburner.ns.trywriteport.md) | Attempt to write to a port. | | [tryWritePort(portNumber, data)](./bitburner.ns.trywriteport.md) | Attempt to write to a port. |
| [upgradePurchasedServer(hostname, ram)](./bitburner.ns.upgradepurchasedserver.md) | Upgrade a purchased server's RAM. | | [upgradePurchasedServer(hostname, ram)](./bitburner.ns.upgradepurchasedserver.md) | Upgrade a purchased server's RAM. |
| [vsprintf(format, args)](./bitburner.ns.vsprintf.md) | Format a string with an array of arguments. | | [vsprintf(format, args)](./bitburner.ns.vsprintf.md) | Format a string with an array of arguments. |
| [weaken(host, opts)](./bitburner.ns.weaken.md) | Reduce a server's security level. | | [weaken(host, opts)](./bitburner.ns.weaken.md) | Reduce a server's security level. |
| [weakenAnalyze(threads, cores)](./bitburner.ns.weakenanalyze.md) | Predict the effect of weaken. | | [weakenAnalyze(threads, cores)](./bitburner.ns.weakenanalyze.md) | Predict the effect of weaken. |
| [wget(url, target, host)](./bitburner.ns.wget.md) | Download a file from the internet. | | [wget(url, target, host)](./bitburner.ns.wget.md) | Download a file from the internet. |
| [write(filename, data, mode)](./bitburner.ns.write.md) | Write data to a file. | | [write(filename, data, mode)](./bitburner.ns.write.md) | Write data to a file. |
| [writePort(port, data)](./bitburner.ns.writeport.md) | Write data to a port. | | [writePort(portNumber, data)](./bitburner.ns.writeport.md) | Write data to a port. |

@ -9,14 +9,14 @@ Get a copy of the data from a port without popping it.
**Signature:** **Signature:**
```typescript ```typescript
peek(port: number): PortData; peek(portNumber: number): PortData;
``` ```
## Parameters ## Parameters
| Parameter | Type | Description | | Parameter | Type | Description |
| --- | --- | --- | | --- | --- | --- |
| port | number | Port to peek. Must be an integer between 1 and 20. | | portNumber | number | Port to peek. Must be an integer between 1 and 20. |
**Returns:** **Returns:**

@ -9,14 +9,14 @@ Read data from a port.
**Signature:** **Signature:**
```typescript ```typescript
readPort(port: number): PortData; readPort(portNumber: number): PortData;
``` ```
## Parameters ## Parameters
| Parameter | Type | Description | | Parameter | Type | Description |
| --- | --- | --- | | --- | --- | --- |
| port | number | | | portNumber | number | |
**Returns:** **Returns:**

@ -9,14 +9,14 @@ Attempt to write to a port.
**Signature:** **Signature:**
```typescript ```typescript
tryWritePort(port: number, data: string | number): boolean; tryWritePort(portNumber: number, data: string | number): boolean;
``` ```
## Parameters ## Parameters
| Parameter | Type | Description | | Parameter | Type | Description |
| --- | --- | --- | | --- | --- | --- |
| port | number | Port or text file that will be written to. | | portNumber | number | Port or text file that will be written to. |
| data | string \| number | Data to write. | | data | string \| number | Data to write. |
**Returns:** **Returns:**

@ -9,14 +9,14 @@ Write data to a port.
**Signature:** **Signature:**
```typescript ```typescript
writePort(port: number, data: string | number): PortData | null; writePort(portNumber: number, data: string | number): PortData | null;
``` ```
## Parameters ## Parameters
| Parameter | Type | Description | | Parameter | Type | Description |
| --- | --- | --- | | --- | --- | --- |
| port | number | | | portNumber | number | |
| data | string \| number | | | data | string \| number | |
**Returns:** **Returns:**

@ -28,7 +28,7 @@ Array of four elements that represents the players position in a stock.
RAM cost: 2 GB Returns an array of four elements that represents the players position in a stock. RAM cost: 2 GB Returns an array of four elements that represents the players position in a stock.
The first element is the returned array is the number of shares the player owns of the stock in the Long position. The second element in the array is the average price of the players shares in the Long position. The first element in the returned array is the number of shares the player owns of the stock in the Long position. The second element in the array is the average price of the players shares in the Long position.
The third element in the array is the number of shares the player owns of the stock in the Short position. The fourth element in the array is the average price of the players Short position. The third element in the array is the number of shares the player owns of the stock in the Short position. The fourth element in the array is the average price of the players Short position.

@ -19,8 +19,7 @@ import { convertTimeMsToTimeElapsedString } from "../utils/StringHelperFunctions
import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers"; import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers";
import { CONSTANTS } from "../Constants"; import { CONSTANTS } from "../Constants";
import { influenceStockThroughServerHack } from "../StockMarket/PlayerInfluencing"; import { influenceStockThroughServerHack } from "../StockMarket/PlayerInfluencing";
import { IPort, NetscriptPort } from "../NetscriptPort"; import { PortNumber } from "../NetscriptPort";
import { NetscriptPorts } from "../NetscriptWorker";
import { FormulaGang } from "../Gang/formulas/formulas"; import { FormulaGang } from "../Gang/formulas/formulas";
import { GangMember } from "../Gang/GangMember"; import { GangMember } from "../Gang/GangMember";
import { GangMemberTask } from "../Gang/GangMemberTask"; import { GangMemberTask } from "../Gang/GangMemberTask";
@ -52,7 +51,7 @@ export const helpers = {
getServer, getServer,
scriptIdentifier, scriptIdentifier,
hack, hack,
getValidPort, portNumber,
person, person,
server, server,
gang, gang,
@ -538,26 +537,15 @@ function hack(
}); });
} }
function getValidPort(ctx: NetscriptContext, port: number): IPort { function portNumber(ctx: NetscriptContext, _n: unknown): PortNumber {
if (isNaN(port)) { const n = positiveInteger(ctx, "portNumber", _n);
if (n > CONSTANTS.NumNetscriptPorts) {
throw makeRuntimeErrorMsg( throw makeRuntimeErrorMsg(
ctx, ctx,
`Invalid argument. Must be a port number between 1 and ${CONSTANTS.NumNetscriptPorts}, is ${port}`, `Trying to use an invalid port: ${n}. Must be less or equal to ${CONSTANTS.NumNetscriptPorts}.`,
); );
} }
port = Math.round(port); return n as PortNumber;
if (port < 1 || port > CONSTANTS.NumNetscriptPorts) {
throw makeRuntimeErrorMsg(
ctx,
`Trying to use an invalid port: ${port}. Only ports 1-${CONSTANTS.NumNetscriptPorts} are valid.`,
);
}
let iport = NetscriptPorts.get(port);
if (!iport) {
iport = NetscriptPort();
NetscriptPorts.set(port, iport);
}
return iport;
} }
function person(ctx: NetscriptContext, p: unknown): IPerson { function person(ctx: NetscriptContext, p: unknown): IPerson {

@ -90,6 +90,7 @@ import { CityName, JobName, CrimeType, GymType, LocationName, UniversityClassTyp
import { cloneDeep } from "lodash"; import { cloneDeep } from "lodash";
import { FactionWorkType } from "./Enums"; import { FactionWorkType } from "./Enums";
import numeral from "numeral"; import numeral from "numeral";
import { clearPort, peekPort, portHandle, readPort, tryWritePort, writePort } from "./NetscriptPort";
export const enums: NSEnums = { export const enums: NSEnums = {
CityName, CityName,
@ -1399,19 +1400,16 @@ export const ns: InternalAPI<NSFull> = {
}); });
return res; return res;
}, },
writePort: writePort: (ctx) => (_portNumber, data) => {
(ctx) => const portNumber = helpers.portNumber(ctx, _portNumber);
(_port, data): string | number | null => { if (typeof data !== "string" && typeof data !== "number") {
const port = helpers.number(ctx, "port", _port); throw helpers.makeRuntimeErrorMsg(
if (typeof data !== "string" && typeof data !== "number") { ctx,
throw helpers.makeRuntimeErrorMsg( `Trying to write invalid data to a port: only strings and numbers are valid.`,
ctx, );
`Trying to write invalid data to a port: only strings and numbers are valid.`, }
); return writePort(portNumber, data);
} },
const iport = helpers.getValidPort(ctx, port);
return iport.write(data);
},
write: write:
(ctx) => (ctx) =>
(_filename, _data = "", _mode = "a") => { (_filename, _data = "", _mode = "a") => {
@ -1451,25 +1449,19 @@ export const ns: InternalAPI<NSFull> = {
} }
return; return;
}, },
tryWritePort: tryWritePort: (ctx) => (_portNumber, data) => {
(ctx) => const portNumber = helpers.portNumber(ctx, _portNumber);
(_port, data = "") => { if (typeof data !== "string" && typeof data !== "number") {
const port = helpers.number(ctx, "port", _port); throw helpers.makeRuntimeErrorMsg(
if (typeof data !== "string" && typeof data !== "number") { ctx,
throw helpers.makeRuntimeErrorMsg( `Trying to write invalid data to a port: only strings and numbers are valid.`,
ctx, );
`Trying to write invalid data to a port: only strings and numbers are valid.`, }
); return tryWritePort(portNumber, data);
} },
const iport = helpers.getValidPort(ctx, port); readPort: (ctx) => (_portNumber) => {
return iport.tryWrite(data); const portNumber = helpers.portNumber(ctx, _portNumber);
}, return readPort(portNumber);
readPort: (ctx) => (_port) => {
const port = helpers.number(ctx, "port", _port);
// Read from port
const iport = helpers.getValidPort(ctx, port);
const x = iport.read();
return x;
}, },
read: (ctx) => (_filename) => { read: (ctx) => (_filename) => {
const fn = helpers.string(ctx, "filename", _filename); const fn = helpers.string(ctx, "filename", _filename);
@ -1494,11 +1486,9 @@ export const ns: InternalAPI<NSFull> = {
} }
} }
}, },
peek: (ctx) => (_port) => { peek: (ctx) => (_portNumber) => {
const port = helpers.number(ctx, "port", _port); const portNumber = helpers.portNumber(ctx, _portNumber);
const iport = helpers.getValidPort(ctx, port); return peekPort(portNumber);
const x = iport.peek();
return x;
}, },
clear: (ctx) => (_file) => { clear: (ctx) => (_file) => {
const file = helpers.string(ctx, "file", _file); const file = helpers.string(ctx, "file", _file);
@ -1517,16 +1507,13 @@ export const ns: InternalAPI<NSFull> = {
throw helpers.makeRuntimeErrorMsg(ctx, `Invalid argument: ${file}`); throw helpers.makeRuntimeErrorMsg(ctx, `Invalid argument: ${file}`);
} }
}, },
clearPort: (ctx) => (_port) => { clearPort: (ctx) => (_portNumber) => {
const port = helpers.number(ctx, "port", _port); const portNumber = helpers.portNumber(ctx, _portNumber);
// Clear port return clearPort(portNumber);
const iport = helpers.getValidPort(ctx, port);
iport.clear();
}, },
getPortHandle: (ctx) => (_port) => { getPortHandle: (ctx) => (_portNumber) => {
const port = helpers.number(ctx, "port", _port); const portNumber = helpers.portNumber(ctx, _portNumber);
const iport = helpers.getValidPort(ctx, port); return portHandle(portNumber);
return iport;
}, },
rm: rm:
(ctx) => (ctx) =>

@ -23,17 +23,10 @@ export type INetscriptExtra = {
export function NetscriptExtra(): InternalAPI<INetscriptExtra> { export function NetscriptExtra(): InternalAPI<INetscriptExtra> {
return { return {
heart: { heart: {
// Easter egg function break: () => () => Player.karma,
break: () => () => {
return Player.karma;
},
},
openDevMenu: () => () => {
devMenu.emit();
},
exploit: () => () => {
Player.giveExploit(Exploit.UndocumentedFunctionCall);
}, },
openDevMenu: () => () => devMenu.emit(),
exploit: () => () => Player.giveExploit(Exploit.UndocumentedFunctionCall),
bypass: (ctx) => (doc) => { bypass: (ctx) => (doc) => {
// reset both fields first // reset both fields first
type temporary = { completely_unused_field: unknown }; type temporary = { completely_unused_field: unknown };
@ -64,20 +57,12 @@ export function NetscriptExtra(): InternalAPI<INetscriptExtra> {
Player.giveExploit(Exploit.RealityAlteration); Player.giveExploit(Exploit.RealityAlteration);
} }
}, },
rainbow: (ctx) => (guess) => { rainbow: (ctx) => (_guess) => {
function tryGuess(): boolean { const guess = helpers.string(ctx, "guess", _guess);
// eslint-disable-next-line no-sync const verified = bcrypt.compareSync(guess, "$2a$10$aertxDEkgor8baVtQDZsLuMwwGYmkRM/ohcA6FjmmzIHQeTCsrCcO");
const verified = bcrypt.compareSync( if (!verified) return false;
helpers.string(ctx, "guess", guess), Player.giveExploit(Exploit.INeedARainbow);
"$2a$10$aertxDEkgor8baVtQDZsLuMwwGYmkRM/ohcA6FjmmzIHQeTCsrCcO", return true;
);
if (verified) {
Player.giveExploit(Exploit.INeedARainbow);
return true;
}
return false;
}
return tryGuess();
}, },
iKnowWhatImDoing: (ctx) => () => { iKnowWhatImDoing: (ctx) => () => {
helpers.log(ctx, () => "Unlocking unsupported feature: window.tprintRaw"); helpers.log(ctx, () => "Unlocking unsupported feature: window.tprintRaw");

@ -1,79 +1,100 @@
import { Settings } from "./Settings/Settings"; import { Settings } from "./Settings/Settings";
import { NetscriptPort } from "@nsdefs";
import { NetscriptPorts } from "./NetscriptWorker";
type PortData = string | number; type PortData = string | number;
type Resolver = () => void; type Resolver = () => void;
export interface IPort { const emptyPortData = "NULL PORT DATA";
write: (value: unknown) => PortData | null; /** The object property is for typechecking and is not present at runtime */
tryWrite: (value: unknown) => boolean; export type PortNumber = number & { __PortNumber: true };
read: () => PortData;
peek: () => PortData; /** Gets the numbered port, initializing it if it doesn't already exist.
nextWrite: () => Promise<void>; * Only using for functions that write data/resolvers. Use NetscriptPorts.get(n) for */
full: () => boolean; export function getPort(n: PortNumber) {
empty: () => boolean; let port = NetscriptPorts.get(n);
clear: () => void; if (port) return port;
port = new Port();
NetscriptPorts.set(n, port);
return port;
} }
export function NetscriptPort(): IPort { export class Port {
const data: PortData[] = []; data: PortData[] = [];
const resolvers: Resolver[] = []; resolvers: Resolver[] = [];
}
export function portHandle(n: PortNumber): NetscriptPort {
return { return {
write: (value) => { write: (value: unknown) => writePort(n, value),
if (typeof value !== "number" && typeof value !== "string") { tryWrite: (value: unknown) => tryWritePort(n, value),
throw new Error( read: () => readPort(n),
`port.write: Tried to write type ${typeof value}. Only string and number types may be written to ports.`, peek: () => peekPort(n),
); nextWrite: () => nextWritePort(n),
} full: () => isFullPort(n),
data.push(value); empty: () => isEmptyPort(n),
while (resolvers.length > 0) { clear: () => clearPort(n),
(resolvers.pop() as Resolver)();
}
if (data.length > Settings.MaxPortCapacity) {
return data.shift() as PortData;
}
return null;
},
tryWrite: (value) => {
if (typeof value != "number" && typeof value != "string") {
throw new Error(
`port.write: Tried to write type ${typeof value}. Only string and number types may be written to ports.`,
);
}
if (data.length >= Settings.MaxPortCapacity) {
return false;
}
data.push(value);
while (resolvers.length > 0) {
(resolvers.pop() as Resolver)();
}
return true;
},
read: () => {
if (data.length === 0) return "NULL PORT DATA";
return data.shift() as PortData;
},
peek: () => {
if (data.length === 0) return "NULL PORT DATA";
return data[0];
},
nextWrite: () => {
return new Promise((res) => resolvers.push(res));
},
full: () => {
return data.length == Settings.MaxPortCapacity;
},
empty: () => {
return data.length === 0;
},
clear: () => {
data.length = 0;
},
}; };
} }
export function writePort(n: PortNumber, value: unknown): PortData | null {
if (typeof value !== "number" && typeof value !== "string") {
throw new Error(
`port.write: Tried to write type ${typeof value}. Only string and number types may be written to ports.`,
);
}
const { data, resolvers } = getPort(n);
data.push(value);
while (resolvers.length > 0) (resolvers.pop() as Resolver)();
if (data.length > Settings.MaxPortCapacity) return data.shift() as PortData;
return null;
}
export function tryWritePort(n: PortNumber, value: unknown): boolean {
if (typeof value != "number" && typeof value != "string") {
throw new Error(
`port.write: Tried to write type ${typeof value}. Only string and number types may be written to ports.`,
);
}
const { data, resolvers } = getPort(n);
if (data.length >= Settings.MaxPortCapacity) return false;
data.push(value);
while (resolvers.length > 0) (resolvers.pop() as Resolver)();
return true;
}
export function readPort(n: PortNumber): PortData {
const port = NetscriptPorts.get(n);
if (!port || !port.data.length) return emptyPortData;
const returnVal = port.data.shift() as PortData;
if (!port.data.length && !port.resolvers.length) NetscriptPorts.delete(n);
return returnVal;
}
export function peekPort(n: PortNumber): PortData {
const port = NetscriptPorts.get(n);
if (!port || !port.data.length) return emptyPortData;
return port.data[0];
}
function nextWritePort(n: PortNumber) {
const { resolvers } = getPort(n);
return new Promise<void>((res) => resolvers.push(res as Resolver));
}
function isFullPort(n: PortNumber) {
const port = NetscriptPorts.get(n);
if (!port) return false;
return port.data.length >= Settings.MaxPortCapacity;
}
function isEmptyPort(n: PortNumber) {
const port = NetscriptPorts.get(n);
if (!port) return true;
return port.data.length === 0;
}
export function clearPort(n: PortNumber) {
const port = NetscriptPorts.get(n);
if (!port) return;
if (!port.resolvers.length) NetscriptPorts.delete(n);
port.data.length = 0;
}

@ -13,7 +13,7 @@ import { CONSTANTS } from "./Constants";
import { Interpreter } from "./ThirdParty/JSInterpreter"; import { Interpreter } from "./ThirdParty/JSInterpreter";
import { NetscriptFunctions } from "./NetscriptFunctions"; import { NetscriptFunctions } from "./NetscriptFunctions";
import { compile, Node } from "./NetscriptJSEvaluator"; import { compile, Node } from "./NetscriptJSEvaluator";
import { IPort } from "./NetscriptPort"; import { Port, PortNumber } from "./NetscriptPort";
import { RunningScript } from "./Script/RunningScript"; import { RunningScript } from "./Script/RunningScript";
import { getRamUsageFromRunningScript } from "./Script/RunningScriptHelpers"; import { getRamUsageFromRunningScript } from "./Script/RunningScriptHelpers";
import { scriptCalculateOfflineProduction } from "./Script/ScriptHelpers"; import { scriptCalculateOfflineProduction } from "./Script/ScriptHelpers";
@ -35,7 +35,7 @@ import { Terminal } from "./Terminal";
import { ScriptArg } from "./Netscript/ScriptArg"; import { ScriptArg } from "./Netscript/ScriptArg";
import { handleUnknownError } from "./Netscript/NetscriptHelpers"; import { handleUnknownError } from "./Netscript/NetscriptHelpers";
export const NetscriptPorts: Map<number, IPort> = new Map(); export const NetscriptPorts: Map<PortNumber, Port> = new Map();
export function prestigeWorkerScripts(): void { export function prestigeWorkerScripts(): void {
for (const ws of workerScripts.values()) { for (const ws of workerScripts.values()) {

@ -927,7 +927,7 @@ export type SleeveTask =
/** Object representing a port. A port is a serialized queue. /** Object representing a port. A port is a serialized queue.
* @public */ * @public */
interface NetscriptPort { export interface NetscriptPort {
/** Write data to a port. /** Write data to a port.
* @remarks * @remarks
* RAM cost: 0 GB * RAM cost: 0 GB
@ -6117,11 +6117,11 @@ export interface NS {
* If the port is full, the data will not be written. * If the port is full, the data will not be written.
* Otherwise, the data will be written normally. * Otherwise, the data will be written normally.
* *
* @param port - Port or text file that will be written to. * @param portNumber - Port or text file that will be written to.
* @param data - Data to write. * @param data - Data to write.
* @returns True if the data is successfully written to the port, and false otherwise. * @returns True if the data is successfully written to the port, and false otherwise.
*/ */
tryWritePort(port: number, data: string | number): boolean; tryWritePort(portNumber: number, data: string | number): boolean;
/** /**
* Read content of a file. * Read content of a file.
@ -6147,10 +6147,10 @@ export interface NS {
* first element in the specified port without removing that element. If * first element in the specified port without removing that element. If
* the port is empty, the string NULL PORT DATA will be returned. * the port is empty, the string NULL PORT DATA will be returned.
* *
* @param port - Port to peek. Must be an integer between 1 and 20. * @param portNumber - Port to peek. Must be an integer between 1 and 20.
* @returns Data in the specified port. * @returns Data in the specified port.
*/ */
peek(port: number): PortData; peek(portNumber: number): PortData;
/** /**
* Clear data from a file. * Clear data from a file.
@ -6182,7 +6182,7 @@ export interface NS {
* Write data to the given Netscript port. * Write data to the given Netscript port.
* @returns The data popped off the queue if it was full, or null if it was not full. * @returns The data popped off the queue if it was full, or null if it was not full.
*/ */
writePort(port: number, data: string | number): PortData | null; writePort(portNumber: number, data: string | number): PortData | null;
/** /**
* Read data from a port. * Read data from a port.
* @remarks * @remarks
@ -6193,7 +6193,7 @@ export interface NS {
* If the queue is empty, then the string NULL PORT DATA will be returned. * If the queue is empty, then the string NULL PORT DATA will be returned.
* @returns The data read. * @returns The data read.
*/ */
readPort(port: number): PortData; readPort(portNumber: number): PortData;
/** /**
* Get all data on a port. * Get all data on a port.
@ -6205,9 +6205,9 @@ export interface NS {
* WARNING: Port Handles only work in NetscriptJS (Netscript 2.0). They will not work in Netscript 1.0. * WARNING: Port Handles only work in NetscriptJS (Netscript 2.0). They will not work in Netscript 1.0.
* *
* @see https://bitburner-official.readthedocs.io/en/latest/netscript/netscriptmisc.html#netscript-ports * @see https://bitburner-official.readthedocs.io/en/latest/netscript/netscriptmisc.html#netscript-ports
* @param port - Port number. Must be an integer between 1 and 20. * @param portNumber - Port number. Must be an integer between 1 and 20.
*/ */
getPortHandle(port: number): NetscriptPort; getPortHandle(portNumber: number): NetscriptPort;
/** /**
* Delete a file. * Delete a file.