mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-11-22 23:53:48 +01:00
unified errors
This commit is contained in:
parent
8d0347577d
commit
7d37736058
@ -33,6 +33,7 @@ import { RunningScript as IRunningScript } from "../ScriptEditor/NetscriptDefini
|
|||||||
import { arrayToString } from "../utils/helpers/arrayToString";
|
import { arrayToString } from "../utils/helpers/arrayToString";
|
||||||
import { HacknetServer } from "../Hacknet/HacknetServer";
|
import { HacknetServer } from "../Hacknet/HacknetServer";
|
||||||
import { BaseServer } from "../Server/BaseServer";
|
import { BaseServer } from "../Server/BaseServer";
|
||||||
|
import { dialogBoxCreate } from "../ui/React/DialogBox";
|
||||||
|
|
||||||
export const helpers = {
|
export const helpers = {
|
||||||
string,
|
string,
|
||||||
@ -131,11 +132,13 @@ function argsToString(args: unknown[]): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Creates an error message string containing hostname, scriptname, and the error message msg */
|
/** Creates an error message string containing hostname, scriptname, and the error message msg */
|
||||||
function makeBasicErrorMsg(workerScript: WorkerScript, msg: string, type = "RUNTIME"): string {
|
function makeBasicErrorMsg(ws: WorkerScript | ScriptDeath, msg: string, type = "RUNTIME"): string {
|
||||||
for (const scriptUrl of workerScript.scriptRef.dependencies) {
|
if (ws instanceof WorkerScript) {
|
||||||
|
for (const scriptUrl of ws.scriptRef.dependencies) {
|
||||||
msg = msg.replace(new RegExp(scriptUrl.url, "g"), scriptUrl.filename);
|
msg = msg.replace(new RegExp(scriptUrl.url, "g"), scriptUrl.filename);
|
||||||
}
|
}
|
||||||
return `${type} ERROR\n${workerScript.name}@${workerScript.hostname} (PID - ${workerScript.pid})\n\n${msg}`;
|
}
|
||||||
|
return `${type} ERROR\n${ws.name}@${ws.hostname} (PID - ${ws.pid})\n\n${msg}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Creates an error message string with a stack trace. */
|
/** Creates an error message string with a stack trace. */
|
||||||
@ -250,8 +253,7 @@ function checkEnvFlags(ctx: NetscriptContext): void {
|
|||||||
throw new ScriptDeath(ws);
|
throw new ScriptDeath(ws);
|
||||||
}
|
}
|
||||||
if (ws.env.runningFn && ctx.function !== "asleep") {
|
if (ws.env.runningFn && ctx.function !== "asleep") {
|
||||||
//This one has no error message so it will not create a dialog
|
ws.delayReject?.(new ScriptDeath(ws));
|
||||||
if (ws.delayReject) ws.delayReject(new ScriptDeath(ws));
|
|
||||||
ws.env.stopFlag = true;
|
ws.env.stopFlag = true;
|
||||||
log(ctx, () => "Failed to run due to failed concurrency check.");
|
log(ctx, () => "Failed to run due to failed concurrency check.");
|
||||||
throw makeRuntimeErrorMsg(
|
throw makeRuntimeErrorMsg(
|
||||||
@ -692,3 +694,30 @@ function failOnHacknetServer(ctx: NetscriptContext, server: BaseServer, callingF
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Generate an error dialog when workerscript is known */
|
||||||
|
export function handleUnknownError(e: unknown, ws: WorkerScript | ScriptDeath | null = null, initialText = "") {
|
||||||
|
if (e instanceof ScriptDeath) {
|
||||||
|
//No dialog for an empty ScriptDeath
|
||||||
|
if (e.errorMessage === "") return;
|
||||||
|
if (!ws) {
|
||||||
|
ws = e;
|
||||||
|
e = ws.errorMessage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ws && typeof e === "string") {
|
||||||
|
const headerText = makeBasicErrorMsg(ws, "", "");
|
||||||
|
if (!e.includes(headerText)) e = makeBasicErrorMsg(ws, e);
|
||||||
|
} else if (e instanceof SyntaxError) {
|
||||||
|
const msg = `${e.message} (sorry we can't be more helpful)`;
|
||||||
|
e = ws ? makeBasicErrorMsg(ws, msg, "SYNTAX") : `SYNTAX ERROR:\n\n${msg}`;
|
||||||
|
} else if (e instanceof Error) {
|
||||||
|
const msg = `${e.message}${e.stack ? `\nstack:\n${e.stack.toString()}` : ""}`;
|
||||||
|
e = ws ? makeBasicErrorMsg(ws, msg) : `RUNTIME ERROR:\n\n${msg}`;
|
||||||
|
}
|
||||||
|
if (typeof e !== "string") {
|
||||||
|
console.error("Unexpected error type:", e);
|
||||||
|
e = "Unexpected type of error thrown. See console output.";
|
||||||
|
}
|
||||||
|
dialogBoxCreate(initialText + e);
|
||||||
|
}
|
||||||
|
@ -10,10 +10,10 @@ import { WorkerScriptStartStopEventEmitter } from "./WorkerScriptStartStopEventE
|
|||||||
import { RunningScript } from "../Script/RunningScript";
|
import { RunningScript } from "../Script/RunningScript";
|
||||||
import { GetServer } from "../Server/AllServers";
|
import { GetServer } from "../Server/AllServers";
|
||||||
|
|
||||||
import { errorDialog } from "../ui/React/DialogBox";
|
|
||||||
import { AddRecentScript } from "./RecentScripts";
|
import { AddRecentScript } from "./RecentScripts";
|
||||||
import { ITutorial } from "../InteractiveTutorial";
|
import { ITutorial } from "../InteractiveTutorial";
|
||||||
import { AlertEvents } from "../ui/React/AlertManager";
|
import { AlertEvents } from "../ui/React/AlertManager";
|
||||||
|
import { handleUnknownError } from "./NetscriptHelpers";
|
||||||
|
|
||||||
export type killScriptParams = WorkerScript | number | { runningScript: RunningScript; hostname: string };
|
export type killScriptParams = WorkerScript | number | { runningScript: RunningScript; hostname: string };
|
||||||
|
|
||||||
@ -59,13 +59,16 @@ function killWorkerScriptByPid(pid: number): boolean {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function stopAndCleanUpWorkerScript(ws: WorkerScript): void {
|
function stopAndCleanUpWorkerScript(ws: WorkerScript): void {
|
||||||
killNetscriptDelay(ws);
|
//Clean up any ongoing netscriptDelay
|
||||||
|
if (ws.delay) clearTimeout(ws.delay);
|
||||||
|
ws.delayReject?.(new ScriptDeath(ws));
|
||||||
|
|
||||||
if (typeof ws.atExit === "function") {
|
if (typeof ws.atExit === "function") {
|
||||||
try {
|
try {
|
||||||
ws.env.stopFlag = false;
|
ws.env.stopFlag = false;
|
||||||
ws.atExit();
|
ws.atExit();
|
||||||
} catch (e: unknown) {
|
} catch (e: unknown) {
|
||||||
errorDialog(e, `Error during atExit ${ws.name}@${ws.hostname} (PID - ${ws.pid}\n\n`);
|
handleUnknownError(e, ws, "Error running atExit function.\n\n");
|
||||||
}
|
}
|
||||||
ws.atExit = undefined;
|
ws.atExit = undefined;
|
||||||
}
|
}
|
||||||
@ -115,19 +118,3 @@ function removeWorkerScript(workerScript: WorkerScript): void {
|
|||||||
|
|
||||||
WorkerScriptStartStopEventEmitter.emit();
|
WorkerScriptStartStopEventEmitter.emit();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 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
|
|
||||||
*/
|
|
||||||
function killNetscriptDelay(workerScript: WorkerScript): void {
|
|
||||||
if (workerScript instanceof WorkerScript) {
|
|
||||||
if (workerScript.delay) {
|
|
||||||
clearTimeout(workerScript.delay);
|
|
||||||
if (workerScript.delayReject) {
|
|
||||||
workerScript.delayReject(new ScriptDeath(workerScript));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -24,7 +24,7 @@ import { Settings } from "./Settings/Settings";
|
|||||||
|
|
||||||
import { generate } from "escodegen";
|
import { generate } from "escodegen";
|
||||||
|
|
||||||
import { dialogBoxCreate, errorDialog } from "./ui/React/DialogBox";
|
import { dialogBoxCreate } from "./ui/React/DialogBox";
|
||||||
import { arrayToString } from "./utils/helpers/arrayToString";
|
import { arrayToString } from "./utils/helpers/arrayToString";
|
||||||
import { roundToTwo } from "./utils/helpers/roundToTwo";
|
import { roundToTwo } from "./utils/helpers/roundToTwo";
|
||||||
|
|
||||||
@ -33,7 +33,7 @@ import { simple as walksimple } from "acorn-walk";
|
|||||||
import { areFilesEqual } from "./Terminal/DirectoryHelpers";
|
import { areFilesEqual } from "./Terminal/DirectoryHelpers";
|
||||||
import { Terminal } from "./Terminal";
|
import { Terminal } from "./Terminal";
|
||||||
import { ScriptArg } from "./Netscript/ScriptArg";
|
import { ScriptArg } from "./Netscript/ScriptArg";
|
||||||
import { helpers } from "./Netscript/NetscriptHelpers";
|
import { handleUnknownError } from "./Netscript/NetscriptHelpers";
|
||||||
|
|
||||||
export const NetscriptPorts: Map<number, IPort> = new Map();
|
export const NetscriptPorts: Map<number, IPort> = new Map();
|
||||||
|
|
||||||
@ -347,16 +347,7 @@ function createAndAddWorkerScript(runningScriptObj: RunningScript, server: BaseS
|
|||||||
workerScript.log("", () => "Script finished running");
|
workerScript.log("", () => "Script finished running");
|
||||||
})
|
})
|
||||||
.catch(function (e) {
|
.catch(function (e) {
|
||||||
if (typeof e === "string") {
|
handleUnknownError(e, workerScript);
|
||||||
const headerText = helpers.makeBasicErrorMsg(workerScript, "", "");
|
|
||||||
//Add header info if it is not present;
|
|
||||||
if (!e.includes(headerText)) e = helpers.makeBasicErrorMsg(workerScript, e);
|
|
||||||
} else if (e instanceof SyntaxError) {
|
|
||||||
e = helpers.makeBasicErrorMsg(workerScript, `${e.message} (sorry we can't be more helpful)`, "SYNTAX");
|
|
||||||
} else if (e instanceof Error) {
|
|
||||||
e = helpers.makeBasicErrorMsg(workerScript, `${e.message}${e.stack ? `\nstack:\n${e.stack.toString()}` : ""}`);
|
|
||||||
}
|
|
||||||
errorDialog(e);
|
|
||||||
workerScript.log("", () => (e instanceof ScriptDeath ? "Script killed." : "Script crashed due to an error."));
|
workerScript.log("", () => (e instanceof ScriptDeath ? "Script killed." : "Script crashed due to an error."));
|
||||||
killWorkerScript(workerScript);
|
killWorkerScript(workerScript);
|
||||||
});
|
});
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
import { errorDialog } from "./ui/React/DialogBox";
|
import { handleUnknownError } from "./Netscript/NetscriptHelpers";
|
||||||
|
|
||||||
export function setupUncaughtPromiseHandler(): void {
|
export function setupUncaughtPromiseHandler(): void {
|
||||||
window.addEventListener("unhandledrejection", (e) =>
|
window.addEventListener("unhandledrejection", (e) => {
|
||||||
errorDialog(e.reason, "UNCAUGHT PROMISE ERROR\nYou forgot to await a promise\nmaybe hack / grow / weaken ?\n"),
|
handleUnknownError(
|
||||||
|
e.reason,
|
||||||
|
null,
|
||||||
|
"UNCAUGHT PROMISE ERROR\nYou forgot to await a promise\nmaybe hack / grow / weaken ?\n\n",
|
||||||
);
|
);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
@ -2,25 +2,7 @@ import { AlertEvents } from "./AlertManager";
|
|||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { Typography } from "@mui/material";
|
import { Typography } from "@mui/material";
|
||||||
import { ScriptDeath } from "../../Netscript/ScriptDeath";
|
|
||||||
|
|
||||||
export function dialogBoxCreate(txt: string | JSX.Element): void {
|
export function dialogBoxCreate(txt: string | JSX.Element): void {
|
||||||
AlertEvents.emit(typeof txt === "string" ? <Typography component="span">{txt}</Typography> : txt);
|
AlertEvents.emit(typeof txt === "string" ? <Typography component="span">{txt}</Typography> : txt);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function errorDialog(e: unknown, initialText = "") {
|
|
||||||
let errorText = "";
|
|
||||||
if (typeof e === "string") errorText = e;
|
|
||||||
else if (e instanceof ScriptDeath) {
|
|
||||||
if (!e.errorMessage) return; //No need for a dialog for an empty ScriptDeath
|
|
||||||
errorText = e.errorMessage;
|
|
||||||
if (!e.errorMessage.includes(`${e.name}@${e.hostname}`)) {
|
|
||||||
initialText += `${e.name}@${e.hostname} (PID - ${e.pid})\n\n`;
|
|
||||||
}
|
|
||||||
} else if (e instanceof Error) errorText = "Original error message:\n" + e.message;
|
|
||||||
else {
|
|
||||||
errorText = "An unknown error was thrown, see console.";
|
|
||||||
console.error(e);
|
|
||||||
}
|
|
||||||
dialogBoxCreate(initialText + errorText);
|
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user