bitburner-src/src/Netscript/APIWrapper.ts

108 lines
3.2 KiB
TypeScript
Raw Normal View History

import { getRamCost } from "./RamCostGenerator";
import type { WorkerScript } from "./WorkerScript";
2022-08-08 19:43:41 +02:00
import { helpers } from "./NetscriptHelpers";
2022-08-09 21:41:47 +02:00
import { ScriptArg } from "./ScriptArg";
import { NSEnums } from "src/ScriptEditor/NetscriptDefinitions";
2022-08-10 01:02:33 +02:00
import { NSFull } from "src/NetscriptFunctions";
2022-07-15 07:51:30 +02:00
type ExternalFunction = (...args: unknown[]) => unknown;
2022-08-10 16:02:41 +02:00
export type ExternalAPILayer = {
[key: string]: ExternalAPILayer | ExternalFunction | ScriptArg[];
2022-04-07 02:00:54 +02:00
};
2022-03-30 01:11:13 +02:00
type InternalFunction<F extends (...args: unknown[]) => unknown> = (ctx: NetscriptContext) => F;
2022-05-24 23:51:48 +02:00
2022-03-30 01:11:13 +02:00
export type InternalAPI<API> = {
2022-04-07 02:00:54 +02:00
[Property in keyof API]: API[Property] extends ExternalFunction
? InternalFunction<API[Property]>
2022-08-09 21:41:47 +02:00
: API[Property] extends NSEnums
? NSEnums
: API[Property] extends ScriptArg[]
? ScriptArg[]
: API[Property] extends object
2022-04-07 02:00:54 +02:00
? InternalAPI<API[Property]>
: never;
};
2022-03-30 01:11:13 +02:00
export type NetscriptContext = {
workerScript: WorkerScript;
function: string;
2022-08-08 21:51:50 +02:00
functionPath: string;
};
function wrapFunction(
2022-08-10 16:02:41 +02:00
wrappedAPI: ExternalAPILayer,
2022-04-07 02:00:54 +02:00
workerScript: WorkerScript,
func: (_ctx: NetscriptContext) => (...args: unknown[]) => unknown,
2022-04-07 02:00:54 +02:00
...tree: string[]
): void {
2022-04-08 02:02:59 +02:00
const functionPath = tree.join(".");
const functionName = tree.pop();
2022-04-07 02:00:54 +02:00
if (typeof functionName !== "string") {
2022-09-05 14:56:39 +02:00
throw helpers.makeBasicErrorMsg(workerScript, "Failure occured while wrapping netscript api", "INITIALIZATION");
}
const ctx = {
workerScript,
function: functionName,
2022-08-08 21:51:50 +02:00
functionPath,
};
function wrappedFunction(...args: unknown[]): unknown {
2022-08-08 19:43:41 +02:00
helpers.checkEnvFlags(ctx);
2022-08-29 08:41:17 +02:00
helpers.updateDynamicRam(ctx, getRamCost(...tree, ctx.function));
return func(ctx)(...args);
}
const parent = getNestedProperty(wrappedAPI, tree);
Object.defineProperty(parent, functionName, {
value: wrappedFunction,
2022-04-07 02:00:54 +02:00
writable: true,
2022-04-08 02:02:59 +02:00
enumerable: true,
});
}
2022-08-10 01:04:05 +02:00
export function wrapAPI(workerScript: WorkerScript, namespace: object, args: ScriptArg[]): NSFull {
const wrappedAPI = wrapAPILayer({}, workerScript, namespace);
wrappedAPI.args = args;
2022-08-10 01:02:33 +02:00
return wrappedAPI as unknown as NSFull;
}
2022-08-10 01:04:05 +02:00
export function wrapAPILayer(
2022-08-10 16:02:41 +02:00
wrappedAPI: ExternalAPILayer,
2022-08-10 01:04:05 +02:00
workerScript: WorkerScript,
namespace: object,
...tree: string[]
) {
2022-07-20 07:37:41 +02:00
for (const [key, value] of Object.entries(namespace)) {
2022-07-20 17:34:49 +02:00
if (typeof value === "function") {
2022-08-08 19:43:41 +02:00
wrapFunction(wrappedAPI, workerScript, value, ...tree, key);
2022-07-20 17:34:49 +02:00
} else if (Array.isArray(value)) {
setNestedProperty(wrappedAPI, value.slice(), key);
2022-07-20 17:34:49 +02:00
} else if (typeof value === "object") {
2022-08-10 01:02:33 +02:00
wrapAPILayer(wrappedAPI, workerScript, value, ...tree, key);
2022-07-20 17:34:49 +02:00
} else {
setNestedProperty(wrappedAPI, value, ...tree, key);
}
}
return wrappedAPI;
}
function setNestedProperty(root: any, value: unknown, ...tree: string[]): void {
let target = root;
const key = tree.pop();
if (!key) throw new Error("Failure occured while wrapping netscript api (setNestedProperty)");
for (const branch of tree) {
target[branch] ??= {};
target = target[branch];
}
target[key] = value;
}
function getNestedProperty(root: any, tree: string[]): unknown {
let target = root;
for (const branch of tree) {
target[branch] ??= {};
target = target[branch];
}
return target;
}