bitburner-src/src/Netscript/killWorkerScript.ts

148 lines
4.8 KiB
TypeScript
Raw Normal View History

/**
* Stops an actively-running script (represented by a WorkerScript object)
* and removes it from the global pool of active scripts.
*/
import { WorkerScript } from "./WorkerScript";
import { workerScripts } from "./WorkerScripts";
import { WorkerScriptStartStopEventEmitter } from "./WorkerScriptStartStopEventEmitter";
import { RunningScript } from "../Script/RunningScript";
2021-10-07 22:56:01 +02:00
import { GetServer } from "../Server/AllServers";
2021-09-25 20:42:57 +02:00
import { compareArrays } from "../utils/helpers/compareArrays";
2021-10-15 02:13:26 +02:00
import { dialogBoxCreate } from "../ui/React/DialogBox";
2021-10-07 23:55:49 +02:00
export function killWorkerScript(runningScriptObj: RunningScript, hostname: string, rerenderUi?: boolean): boolean;
export function killWorkerScript(workerScript: WorkerScript): boolean;
export function killWorkerScript(pid: number): boolean;
2021-09-05 01:09:30 +02:00
export function killWorkerScript(
script: RunningScript | WorkerScript | number,
2021-10-07 23:55:49 +02:00
hostname?: string,
2021-09-05 01:09:30 +02:00
rerenderUi?: boolean,
): boolean {
if (rerenderUi == null || typeof rerenderUi !== "boolean") {
rerenderUi = true;
}
if (script instanceof WorkerScript) {
stopAndCleanUpWorkerScript(script);
return true;
2021-10-07 23:55:49 +02:00
} else if (script instanceof RunningScript && typeof hostname === "string") {
2021-09-05 01:09:30 +02:00
// Try to kill by PID
const res = killWorkerScriptByPid(script.pid, rerenderUi);
if (res) {
return res;
}
2021-09-05 01:09:30 +02:00
// If for some reason that doesn't work, we'll try the old way
for (const ws of workerScripts.values()) {
2021-10-07 23:55:49 +02:00
if (ws.name == script.filename && ws.hostname == hostname && compareArrays(ws.args, script.args)) {
2021-09-05 01:09:30 +02:00
stopAndCleanUpWorkerScript(ws, rerenderUi);
return true;
2021-09-05 01:09:30 +02:00
}
}
2021-09-05 01:09:30 +02:00
return false;
} else if (typeof script === "number") {
return killWorkerScriptByPid(script, rerenderUi);
} else {
console.error(`killWorkerScript() called with invalid argument:`);
console.error(script);
return false;
}
}
2021-09-05 01:09:30 +02:00
function killWorkerScriptByPid(pid: number, rerenderUi = true): boolean {
const ws = workerScripts.get(pid);
if (ws instanceof WorkerScript) {
stopAndCleanUpWorkerScript(ws, rerenderUi);
2021-09-05 01:09:30 +02:00
return true;
}
2021-09-05 01:09:30 +02:00
return false;
}
2021-09-09 05:47:34 +02:00
function stopAndCleanUpWorkerScript(workerScript: WorkerScript, rerenderUi = true): void {
2021-09-05 01:09:30 +02:00
workerScript.env.stopFlag = true;
killNetscriptDelay(workerScript);
2021-10-15 02:13:26 +02:00
if (typeof workerScript.atExit === "function") {
try {
workerScript.atExit();
} catch (e: any) {
dialogBoxCreate(
`Error trying to call atExit for script ${workerScript.name} on ${workerScript.hostname} ${workerScript.scriptRef.args} ${e}`,
);
}
workerScript.atExit = undefined;
}
2021-09-05 01:09:30 +02:00
removeWorkerScript(workerScript, rerenderUi);
}
/**
* Helper function that removes the script being killed from the global pool.
* Also handles other cleanup-time operations
*
* @param {WorkerScript | number} - Identifier for WorkerScript. Either the object itself, or
* its index in the global workerScripts array
*/
2021-09-09 05:47:34 +02:00
function removeWorkerScript(workerScript: WorkerScript, rerenderUi = true): void {
2021-09-05 01:09:30 +02:00
if (workerScript instanceof WorkerScript) {
2021-10-07 23:55:49 +02:00
const ip = workerScript.hostname;
2021-09-05 01:09:30 +02:00
const name = workerScript.name;
// Get the server on which the script runs
2021-10-07 22:56:01 +02:00
const server = GetServer(ip);
2021-09-05 01:09:30 +02:00
if (server == null) {
2021-09-09 05:47:34 +02:00
console.error(`Could not find server on which this script is running: ${ip}`);
2021-09-05 01:09:30 +02:00
return;
}
// Delete the RunningScript object from that server
for (let i = 0; i < server.runningScripts.length; ++i) {
const runningScript = server.runningScripts[i];
2021-09-09 05:47:34 +02:00
if (runningScript.filename === name && compareArrays(runningScript.args, workerScript.args)) {
2021-09-05 01:09:30 +02:00
server.runningScripts.splice(i, 1);
break;
}
}
2021-10-09 05:45:54 +02:00
// Recalculate ram used on that server
server.ramUsed = 0;
2021-10-09 21:07:42 +02:00
for (const rs of server.runningScripts) server.ramUsed += rs.ramUsage * rs.threads;
2021-10-09 05:45:54 +02:00
2021-09-05 01:09:30 +02:00
// Delete script from global pool (workerScripts)
const res = workerScripts.delete(workerScript.pid);
if (!res) {
2021-09-09 05:47:34 +02:00
console.warn(`removeWorkerScript() called with WorkerScript that wasn't in the global map:`);
2021-09-05 01:09:30 +02:00
console.warn(workerScript);
}
if (rerenderUi) {
2021-09-18 21:44:39 +02:00
WorkerScriptStartStopEventEmitter.emit();
}
2021-09-05 01:09:30 +02:00
} else {
console.error(`Invalid argument passed into removeWorkerScript():`);
console.error(workerScript);
return;
}
}
/**
* Helper function that interrupts a script's delay if it is in the middle of a
* timed, blocked operation (like hack(), sleep(), etc.). This allows scripts to
* be killed immediately even if they're in the middle of one of those long operations
*/
2021-05-01 09:17:31 +02:00
function killNetscriptDelay(workerScript: WorkerScript): void {
2021-09-05 01:09:30 +02:00
if (workerScript instanceof WorkerScript) {
if (workerScript.delay) {
clearTimeout(workerScript.delay);
if (workerScript.delayResolve) {
workerScript.delayResolve();
}
}
2021-09-05 01:09:30 +02:00
}
}