2021-03-14 07:08:24 +01:00
|
|
|
import { Settings } from "./Settings/Settings";
|
2023-02-28 01:54:04 +01:00
|
|
|
import { NetscriptPort } from "@nsdefs";
|
|
|
|
import { NetscriptPorts } from "./NetscriptWorker";
|
2023-03-06 04:39:42 +01:00
|
|
|
import { PositiveInteger } from "./types";
|
2021-03-14 07:08:24 +01:00
|
|
|
|
2022-10-12 14:49:27 +02:00
|
|
|
type PortData = string | number;
|
2022-11-03 11:17:29 +01:00
|
|
|
type Resolver = () => void;
|
2023-02-28 01:54:04 +01:00
|
|
|
const emptyPortData = "NULL PORT DATA";
|
|
|
|
/** The object property is for typechecking and is not present at runtime */
|
2023-03-06 04:39:42 +01:00
|
|
|
export type PortNumber = PositiveInteger & { __PortNumber: true };
|
2021-09-22 02:39:25 +02:00
|
|
|
|
2023-02-28 01:54:04 +01:00
|
|
|
/** Gets the numbered port, initializing it if it doesn't already exist.
|
|
|
|
* Only using for functions that write data/resolvers. Use NetscriptPorts.get(n) for */
|
|
|
|
export function getPort(n: PortNumber) {
|
|
|
|
let port = NetscriptPorts.get(n);
|
|
|
|
if (port) return port;
|
|
|
|
port = new Port();
|
|
|
|
NetscriptPorts.set(n, port);
|
|
|
|
return port;
|
|
|
|
}
|
2021-09-22 02:39:25 +02:00
|
|
|
|
2023-02-28 01:54:04 +01:00
|
|
|
export class Port {
|
|
|
|
data: PortData[] = [];
|
2024-01-14 22:05:57 +01:00
|
|
|
resolver: Resolver | null = null;
|
|
|
|
promise: Promise<void> | null = null;
|
|
|
|
resolve() {
|
|
|
|
if (!this.resolver) return;
|
|
|
|
this.resolver();
|
|
|
|
this.resolver = null;
|
|
|
|
this.promise = null;
|
|
|
|
}
|
2023-02-28 01:54:04 +01:00
|
|
|
}
|
|
|
|
export function portHandle(n: PortNumber): NetscriptPort {
|
2021-09-22 02:39:25 +02:00
|
|
|
return {
|
2023-02-28 01:54:04 +01:00
|
|
|
write: (value: unknown) => writePort(n, value),
|
|
|
|
tryWrite: (value: unknown) => tryWritePort(n, value),
|
|
|
|
read: () => readPort(n),
|
|
|
|
peek: () => peekPort(n),
|
2024-01-15 12:10:39 +01:00
|
|
|
nextWrite: () => nextPortWrite(n),
|
2023-02-28 01:54:04 +01:00
|
|
|
full: () => isFullPort(n),
|
|
|
|
empty: () => isEmptyPort(n),
|
|
|
|
clear: () => clearPort(n),
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
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.`,
|
|
|
|
);
|
|
|
|
}
|
2024-01-15 12:14:13 +01:00
|
|
|
const port = getPort(n);
|
|
|
|
port.data.push(value);
|
|
|
|
port.resolve();
|
|
|
|
if (port.data.length > Settings.MaxPortCapacity) return port.data.shift() as PortData;
|
2023-02-28 01:54:04 +01:00
|
|
|
return null;
|
|
|
|
}
|
2021-09-22 02:39:25 +02:00
|
|
|
|
2023-02-28 01:54:04 +01:00
|
|
|
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.`,
|
|
|
|
);
|
|
|
|
}
|
2024-01-15 12:14:13 +01:00
|
|
|
const port = getPort(n);
|
|
|
|
if (port.data.length >= Settings.MaxPortCapacity) return false;
|
|
|
|
port.data.push(value);
|
|
|
|
port.resolve();
|
2023-02-28 01:54:04 +01:00
|
|
|
return true;
|
|
|
|
}
|
2021-09-22 02:39:25 +02:00
|
|
|
|
2023-02-28 01:54:04 +01:00
|
|
|
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;
|
2024-01-14 22:05:57 +01:00
|
|
|
if (!port.data.length && !port.resolver) NetscriptPorts.delete(n);
|
2023-02-28 01:54:04 +01:00
|
|
|
return returnVal;
|
|
|
|
}
|
2021-09-22 02:39:25 +02:00
|
|
|
|
2023-02-28 01:54:04 +01:00
|
|
|
export function peekPort(n: PortNumber): PortData {
|
|
|
|
const port = NetscriptPorts.get(n);
|
|
|
|
if (!port || !port.data.length) return emptyPortData;
|
|
|
|
return port.data[0];
|
|
|
|
}
|
2021-09-22 02:39:25 +02:00
|
|
|
|
2024-01-15 12:10:39 +01:00
|
|
|
export function nextPortWrite(n: PortNumber) {
|
2024-01-14 22:05:57 +01:00
|
|
|
const port = getPort(n);
|
2024-01-15 12:10:39 +01:00
|
|
|
if (!port.promise) port.promise = new Promise<void>((res) => (port.resolver = res));
|
2024-01-14 22:05:57 +01:00
|
|
|
return port.promise;
|
2023-02-28 01:54:04 +01:00
|
|
|
}
|
2022-11-03 11:17:29 +01:00
|
|
|
|
2023-02-28 01:54:04 +01:00
|
|
|
function isFullPort(n: PortNumber) {
|
|
|
|
const port = NetscriptPorts.get(n);
|
|
|
|
if (!port) return false;
|
|
|
|
return port.data.length >= Settings.MaxPortCapacity;
|
|
|
|
}
|
2021-09-22 02:39:25 +02:00
|
|
|
|
2023-02-28 01:54:04 +01:00
|
|
|
function isEmptyPort(n: PortNumber) {
|
|
|
|
const port = NetscriptPorts.get(n);
|
|
|
|
if (!port) return true;
|
|
|
|
return port.data.length === 0;
|
|
|
|
}
|
2021-09-22 02:39:25 +02:00
|
|
|
|
2023-02-28 01:54:04 +01:00
|
|
|
export function clearPort(n: PortNumber) {
|
|
|
|
const port = NetscriptPorts.get(n);
|
|
|
|
if (!port) return;
|
2024-01-14 22:05:57 +01:00
|
|
|
if (!port.resolver) NetscriptPorts.delete(n);
|
2023-02-28 01:54:04 +01:00
|
|
|
port.data.length = 0;
|
2021-03-14 07:08:24 +01:00
|
|
|
}
|