mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2026-04-16 22:38:34 +02:00
MISC: Remove API server (#2084)
This commit is contained in:
@@ -1,199 +0,0 @@
|
||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
||||
const http = require("http");
|
||||
const crypto = require("crypto");
|
||||
const log = require("electron-log");
|
||||
const Store = require("electron-store");
|
||||
const store = new Store();
|
||||
|
||||
let server;
|
||||
let window;
|
||||
|
||||
async function initialize(win) {
|
||||
window = win;
|
||||
server = http.createServer(async function (req, res) {
|
||||
let body = "";
|
||||
res.setHeader("Content-Type", "application/json");
|
||||
|
||||
req.on("data", (chunk) => {
|
||||
body += chunk.toString(); // convert Buffer to string
|
||||
});
|
||||
|
||||
req.on("end", async () => {
|
||||
const providedToken = req.headers?.authorization?.replace("Bearer ", "") ?? "";
|
||||
const isValid = providedToken === getAuthenticationToken();
|
||||
if (isValid) {
|
||||
log.debug("Valid authentication token");
|
||||
} else {
|
||||
log.log("Invalid authentication token");
|
||||
res.writeHead(401);
|
||||
|
||||
res.end(
|
||||
JSON.stringify({
|
||||
success: false,
|
||||
msg: "Invalid authentication token",
|
||||
}),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
let data;
|
||||
try {
|
||||
data = JSON.parse(body);
|
||||
} catch (error) {
|
||||
log.warn(`Invalid body data`);
|
||||
res.writeHead(400);
|
||||
res.end(
|
||||
JSON.stringify({
|
||||
success: false,
|
||||
msg: "Invalid body data",
|
||||
}),
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
let result;
|
||||
switch (req.method) {
|
||||
// Request files
|
||||
case "GET":
|
||||
result = await window.webContents.executeJavaScript(`document.getFiles()`);
|
||||
break;
|
||||
|
||||
// Create or update files
|
||||
// Support POST for VScode implementation
|
||||
case "POST":
|
||||
case "PUT":
|
||||
if (!data) {
|
||||
log.warn(`Invalid script update request - No data`);
|
||||
res.writeHead(400);
|
||||
res.end(
|
||||
JSON.stringify({
|
||||
success: false,
|
||||
msg: "Invalid script update request - No data",
|
||||
}),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
result = await window.webContents.executeJavaScript(`document.saveFile("${data.filename}", "${data.code}")`);
|
||||
break;
|
||||
|
||||
// Delete files
|
||||
case "DELETE":
|
||||
result = await window.webContents.executeJavaScript(`document.deleteFile("${data.filename}")`);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!result.res) {
|
||||
//We've encountered an error
|
||||
res.writeHead(400);
|
||||
log.warn(`Api Server Error`, result.msg);
|
||||
}
|
||||
|
||||
res.end(
|
||||
JSON.stringify({
|
||||
success: result.res,
|
||||
msg: result.msg,
|
||||
data: result.data,
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
const autostart = store.get("autostart", false);
|
||||
if (autostart) {
|
||||
try {
|
||||
await enable();
|
||||
} catch (error) {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
}
|
||||
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
function enable() {
|
||||
if (isListening()) {
|
||||
log.warn("API server already listening");
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
const port = store.get("port", 9990);
|
||||
const host = store.get("host", "127.0.0.1");
|
||||
log.log(`Starting http server on port ${port} - listening on ${host}`);
|
||||
|
||||
// https://stackoverflow.com/a/62289870
|
||||
let startFinished = false;
|
||||
return new Promise((resolve, reject) => {
|
||||
server.listen(port, host, () => {
|
||||
if (!startFinished) {
|
||||
startFinished = true;
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
server.once("error", (err) => {
|
||||
if (!startFinished) {
|
||||
startFinished = true;
|
||||
console.log("There was an error starting the server in the error listener:", err);
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function disable() {
|
||||
if (!isListening()) {
|
||||
log.warn("API server not listening");
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
log.log("Stopping http server");
|
||||
return server.close();
|
||||
}
|
||||
|
||||
function toggleServer() {
|
||||
if (isListening()) {
|
||||
return disable();
|
||||
} else {
|
||||
return enable();
|
||||
}
|
||||
}
|
||||
|
||||
function isListening() {
|
||||
return server?.listening ?? false;
|
||||
}
|
||||
|
||||
function toggleAutostart() {
|
||||
const newValue = !isAutostart();
|
||||
store.set("autostart", newValue);
|
||||
log.log(`New autostart value is '${newValue}'`);
|
||||
}
|
||||
|
||||
function isAutostart() {
|
||||
return store.get("autostart");
|
||||
}
|
||||
|
||||
function getAuthenticationToken() {
|
||||
const token = store.get("token");
|
||||
if (token) return token;
|
||||
|
||||
const newToken = generateToken();
|
||||
store.set("token", newToken);
|
||||
return newToken;
|
||||
}
|
||||
|
||||
function generateToken() {
|
||||
const buffer = crypto.randomBytes(48);
|
||||
return buffer.toString("base64");
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
initialize,
|
||||
enable,
|
||||
disable,
|
||||
toggleServer,
|
||||
toggleAutostart,
|
||||
isAutostart,
|
||||
getAuthenticationToken,
|
||||
isListening,
|
||||
};
|
||||
@@ -1,10 +1,8 @@
|
||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
||||
const { app, shell, BrowserWindow } = require("electron");
|
||||
const log = require("electron-log");
|
||||
const utils = require("./utils");
|
||||
const achievements = require("./achievements");
|
||||
const menu = require("./menu");
|
||||
const api = require("./api-server");
|
||||
const path = require("path");
|
||||
const { windowTracker } = require("./windowTracker");
|
||||
|
||||
@@ -64,13 +62,6 @@ async function createWindow(killall) {
|
||||
achievements.enableAchievementsInterval(window);
|
||||
utils.attachUnresponsiveAppHandler(window);
|
||||
|
||||
try {
|
||||
await api.initialize(window);
|
||||
} catch (error) {
|
||||
log.error(error);
|
||||
utils.showErrorBox("Error starting http server", error);
|
||||
}
|
||||
|
||||
menu.refreshMenu(window);
|
||||
setStopProcessHandler(app, window);
|
||||
|
||||
|
||||
@@ -20,7 +20,6 @@ app.on("window-all-closed", () => {
|
||||
});
|
||||
|
||||
const greenworks = require("./greenworks");
|
||||
const api = require("./api-server");
|
||||
const gameWindow = require("./gameWindow");
|
||||
const achievements = require("./achievements");
|
||||
const utils = require("./utils");
|
||||
@@ -61,9 +60,6 @@ function setStopProcessHandler(app, window) {
|
||||
// First we clear the achievement timer
|
||||
achievements.disableAchievementsInterval(window);
|
||||
|
||||
// Shutdown the http server
|
||||
api.disable();
|
||||
|
||||
// Trigger debounced saves right now before closing
|
||||
try {
|
||||
await saveToDisk.flush();
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
||||
const { app, Menu, clipboard, dialog, shell } = require("electron");
|
||||
const { app, Menu, dialog, shell } = require("electron");
|
||||
const log = require("electron-log");
|
||||
const Store = require("electron-store");
|
||||
const api = require("./api-server");
|
||||
const utils = require("./utils");
|
||||
const storage = require("./storage");
|
||||
const store = new Store();
|
||||
@@ -233,83 +232,6 @@ function getMenu(window) {
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "API Server",
|
||||
submenu: [
|
||||
{
|
||||
label: api.isListening() ? "Disable Server" : "Enable Server",
|
||||
click: async () => {
|
||||
let success = false;
|
||||
try {
|
||||
await api.toggleServer();
|
||||
success = true;
|
||||
} catch (error) {
|
||||
log.error(error);
|
||||
utils.showErrorBox("Error Toggling Server", error);
|
||||
}
|
||||
if (success && api.isListening()) {
|
||||
utils.writeToast(window, "Started API Server", "success");
|
||||
} else if (success && !api.isListening()) {
|
||||
utils.writeToast(window, "Stopped API Server", "success");
|
||||
} else {
|
||||
utils.writeToast(window, "Error Toggling Server", "error");
|
||||
}
|
||||
refreshMenu(window);
|
||||
},
|
||||
},
|
||||
{
|
||||
label: api.isAutostart() ? "Disable Autostart" : "Enable Autostart",
|
||||
click: async () => {
|
||||
api.toggleAutostart();
|
||||
if (api.isAutostart()) {
|
||||
utils.writeToast(window, "Enabled API Server Autostart", "success");
|
||||
} else {
|
||||
utils.writeToast(window, "Disabled API Server Autostart", "success");
|
||||
}
|
||||
refreshMenu(window);
|
||||
},
|
||||
},
|
||||
{
|
||||
label: "Copy Auth Token",
|
||||
click: async () => {
|
||||
const token = api.getAuthenticationToken();
|
||||
log.log("Wrote authentication token to clipboard");
|
||||
clipboard.writeText(token);
|
||||
utils.writeToast(window, "Copied Authentication Token to Clipboard", "info");
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "separator",
|
||||
},
|
||||
{
|
||||
label: "Information",
|
||||
click: () => {
|
||||
dialog
|
||||
.showMessageBox({
|
||||
type: "warning",
|
||||
title: "Bitburner > API Server Information",
|
||||
message: "The API Server is used to write script files to your in-game home.",
|
||||
detail:
|
||||
`WARNING: This feature is deprecated. It may be removed in future versions.\n\n` +
|
||||
`You should use external tools that support our Remote API feature. For details, please check the "Remote API" page in the in-game documentation. You can also check the "external-editors" channel in our Discord server for more information and support.\n\n` +
|
||||
"--------------------------------------------------------------------------------\n\n" +
|
||||
"There is an official Visual Studio Code extension that makes use of the API Server feature.\n\n" +
|
||||
"It allows you to write your script file in an external IDE and have them pushed over to the game automatically.\n" +
|
||||
"If you want more information, head over to: https://github.com/bitburner-official/bitburner-vscode.",
|
||||
buttons: ["Dismiss", "Open Extension Link (GitHub)"],
|
||||
defaultId: 0,
|
||||
cancelId: 0,
|
||||
noLink: true,
|
||||
})
|
||||
.then(({ response }) => {
|
||||
if (response === 1) {
|
||||
shell.openExternal("https://github.com/bitburner-official/bitburner-vscode");
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "Zoom",
|
||||
submenu: [
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
||||
const { app, ipcMain } = require("electron");
|
||||
const zlib = require("zlib");
|
||||
const path = require("path");
|
||||
const fs = require("fs/promises");
|
||||
const { promisify } = require("util");
|
||||
const gzip = promisify(zlib.gzip);
|
||||
const gunzip = promisify(zlib.gunzip);
|
||||
|
||||
const greenworks = require("./greenworks");
|
||||
const log = require("electron-log");
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
||||
const { dialog, shell } = require("electron");
|
||||
const { dialog } = require("electron");
|
||||
const log = require("electron-log");
|
||||
|
||||
const Store = require("electron-store");
|
||||
|
||||
@@ -5,13 +5,10 @@ import { Terminal } from "./Terminal";
|
||||
import { SnackbarEvents } from "./ui/React/Snackbar";
|
||||
import { ToastVariant } from "@enums";
|
||||
import { IReturnStatus, SaveData } from "./types";
|
||||
import { GetServer } from "./Server/AllServers";
|
||||
import { ImportPlayerData, ElectronGameData, saveObject } from "./SaveObject";
|
||||
import { exportScripts } from "./Terminal/commands/download";
|
||||
import { CONSTANTS } from "./Constants";
|
||||
import { commitHash } from "./utils/helpers/commitHash";
|
||||
import { resolveFilePath } from "./Paths/FilePath";
|
||||
import { hasScriptExtension } from "./Paths/ScriptFilePath";
|
||||
import { handleGetSaveDataInfoError } from "./utils/ErrorHandler";
|
||||
|
||||
interface IReturnWebStatus extends IReturnStatus {
|
||||
@@ -49,55 +46,12 @@ export function initElectron(): void {
|
||||
if (userAgent.includes(" electron/")) {
|
||||
// Electron-specific code
|
||||
document.achievements = [];
|
||||
initWebserver();
|
||||
initAppNotifier();
|
||||
initSaveFunctions();
|
||||
initElectronBridge();
|
||||
}
|
||||
}
|
||||
|
||||
function initWebserver(): void {
|
||||
document.getFiles = function (): IReturnWebStatus {
|
||||
const home = GetServer("home");
|
||||
if (home === null) return { res: false, msg: "Home server does not exist." };
|
||||
return {
|
||||
res: true,
|
||||
data: {
|
||||
files: [...home.scripts.values()].map((script) => ({
|
||||
filename: script.filename,
|
||||
code: script.code,
|
||||
ramUsage: script.ramUsage,
|
||||
})),
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
document.deleteFile = function (filename: string): IReturnWebStatus {
|
||||
const path = resolveFilePath(filename);
|
||||
if (!path) return { res: false, msg: "Invalid file path." };
|
||||
const home = GetServer("home");
|
||||
if (!home) return { res: false, msg: "Home server does not exist." };
|
||||
return home.removeFile(path);
|
||||
};
|
||||
|
||||
document.saveFile = function (filename: string, code: string): IReturnWebStatus {
|
||||
const path = resolveFilePath(filename);
|
||||
if (!path) return { res: false, msg: "Invalid file path." };
|
||||
if (!hasScriptExtension(path)) return { res: false, msg: "Invalid file extension: must be a script" };
|
||||
|
||||
code = decodeURIComponent(escape(atob(code)));
|
||||
const home = GetServer("home");
|
||||
if (!home) return { res: false, msg: "Home server does not exist." };
|
||||
|
||||
const { overwritten } = home.writeToScriptFile(path, code);
|
||||
const script = home.scripts.get(path);
|
||||
if (!script) return { res: false, msg: "Somehow failed to get script after writing it. This is a bug." };
|
||||
|
||||
const ramUsage = script.getRamUsage(home.scripts);
|
||||
return { res: true, data: { overwritten, ramUsage } };
|
||||
};
|
||||
}
|
||||
|
||||
// Expose certain alert functions to allow the wrapper to sends message to the game
|
||||
function initAppNotifier(): void {
|
||||
const funcs = {
|
||||
|
||||
Reference in New Issue
Block a user