Adding ability to download log files from within the game to the local filesystem.

This commit is contained in:
aef123 2023-05-06 15:04:06 -07:00
parent 7ff71ffbd9
commit 41127abee8
7 changed files with 114 additions and 4 deletions

1
.gitignore vendored
View file

@ -5,6 +5,7 @@ npm-debug.log*
yarn-debug.log* yarn-debug.log*
yarn-error.log* yarn-error.log*
lerna-debug.log* lerna-debug.log*
NetScriptDefinitions.d.ts
# Diagnostic reports (https://nodejs.org/api/report.html) # Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json

21
filesync.json Normal file
View file

@ -0,0 +1,21 @@
{
"allowedFiletypes": [
".js"
],
"allowDeletingFiles": true,
"port": 12525,
"scriptsFolder": "c:\\git\\bitburner\\out",
"quiet": false,
"dry": false,
"definitionFile": {
"update": true,
"location": "NetScriptDefinitions.d.ts"
},
"logFiles": {
"update": true,
"interval": 1,
"remoteLocation": "/logs/",
"localLocation": "D:\\bitburner_game_logs"
},
"pushAllOnConnection": true
}

View file

@ -42,6 +42,32 @@ export const config = convict({
default: false, default: false,
arg: "dry", arg: "dry",
}, },
logFiles: {
update: {
doc: "Automatically pull the log files from the game.",
format: "Boolean",
env: "BB_UPDATE_LOG",
default: false
},
interval: {
doc: "Interval in seconds to pull log files from the game.",
format: "Number",
env: "BB_UPDATE_LOG_INTERVAL",
default: 5
},
remoteLocation: {
doc: "Folder where log files are stored in the game.",
format: "String",
env: "BB_LOCATION_LOG",
default: "/logs"
},
localLocation: {
doc: "Folder where log files are stored locally.",
format: "String",
env: "BB_LOCATION_LOG_LOCAL",
default: "./logs"
}
},
definitionFile: { definitionFile: {
update: { update: {
doc: "Automatically pull the definition file from the game.", doc: "Automatically pull the definition file from the game.",

View file

@ -12,6 +12,17 @@ function fileFilter(file: File) {
return false; return false;
} }
export async function setupLogsFolder() {
try {
await mkdir(resolve(config.get("logFiles").localLocation));
} catch (err) {
if (isError(err) && err.code !== "EEXIST") {
console.log(`Failed to create folder '${config.get("logFiles").localLocation}' (${err.code})`);
process.exit();
}
}
}
function isError(err: unknown): err is NodeJS.ErrnoException { function isError(err: unknown): err is NodeJS.ErrnoException {
return (err as NodeJS.ErrnoException).code !== undefined; return (err as NodeJS.ErrnoException).code !== undefined;
} }

View file

@ -1,4 +1,4 @@
import { setupWatch } from "./fileWatch"; import { setupWatch, setupLogsFolder } from "./fileWatch";
import { config, loadConfig } from "./config"; import { config, loadConfig } from "./config";
import { setupSocket } from "./networking/webSocket"; import { setupSocket } from "./networking/webSocket";
import signal from "signal-js"; import signal from "signal-js";
@ -8,21 +8,26 @@ import {
fileRemovalEventToMsg, fileRemovalEventToMsg,
requestFilenames, requestFilenames,
requestDefinitionFile, requestDefinitionFile,
getAllFiles
} from "./networking/messageGenerators"; } from "./networking/messageGenerators";
import { EventType } from "./eventTypes"; import { EventType } from "./eventTypes";
import { messageHandler } from "./networking/messageHandler"; import { messageHandler } from "./networking/messageHandler";
import { FileEvent } from "./interfaces"; import { FileEvent } from "./interfaces";
import { TIMEOUT } from "dns";
export async function start() { export async function start() {
loadConfig(); loadConfig();
const watch = await setupWatch(signal); const watch = await setupWatch(signal);
const socket = setupSocket(signal); const socket = setupSocket(signal);
let isConnected: boolean = false;
await setupLogsFolder();
// Add a handler for received messages. // Add a handler for received messages.
signal.on(EventType.MessageReceived, (msg: RawData) => messageHandler(signal, msg, watch.paths)); signal.on(EventType.MessageReceived, (msg: RawData) => messageHandler(signal, msg, watch.paths, config.get("logFiles").update, config.get("logFiles").remoteLocation, config.get("logFiles").localLocation));
// Add a handler for when a connection to a game is made. // Add a handler for when a connection to a game is made.
signal.on(EventType.ConnectionMade, () => { signal.on(EventType.ConnectionMade, () => {
isConnected = true;
console.log("Connection made!"); console.log("Connection made!");
if (config.get("definitionFile").update) { if (config.get("definitionFile").update) {
@ -62,4 +67,14 @@ export async function start() {
socket.close(); socket.close();
process.exit(); process.exit();
}); });
if (config.get("logFiles").update) {
while(true) {
if ((isConnected as boolean) === true) {
signal.emit(EventType.MessageSend, getAllFiles());
}
await new Promise((resolve) => setTimeout(resolve, config.get("logFiles").interval * 1000));
}
}
} }

View file

@ -49,6 +49,17 @@ export function requestFilenames(): Message {
}; };
} }
export function getAllFiles(): Message {
return {
jsonrpc: "2.0",
method: "getAllFiles",
params: {
server: "home",
},
id: messageCounter++,
};
}
function addLeadingSlash(path: string): string { function addLeadingSlash(path: string): string {
const slashes = path.match("/"); const slashes = path.match("/");
if (slashes) return `/${path}`; if (slashes) return `/${path}`;

View file

@ -5,7 +5,7 @@ import { config } from "../config";
import { EventType } from "../eventTypes"; import { EventType } from "../eventTypes";
import { fileChangeEventToMsg } from "./messageGenerators"; import { fileChangeEventToMsg } from "./messageGenerators";
import type { Signal } from "signal-js"; import type { Signal } from "signal-js";
import { Message } from "../interfaces"; import { Message, FileContent } from "../interfaces";
function deserialize(data: RawData): Message { function deserialize(data: RawData): Message {
const msg = JSON.parse(data.toString()); const msg = JSON.parse(data.toString());
@ -32,7 +32,12 @@ export function isStringArray(s: Array<unknown>): s is string[] {
return s.every((s) => typeof s === "string"); return s.every((s) => typeof s === "string");
} }
export function messageHandler(signaller: Signal, data: RawData, paths: Map<string, Stats>) { export function messageHandler(signaller: Signal,
data: RawData,
paths: Map<string, Stats>,
updateLogs: boolean,
remoteLogFolder: string,
localLogFolder: string) {
let incoming; let incoming;
try { try {
@ -62,6 +67,26 @@ export function messageHandler(signaller: Signal, data: RawData, paths: Map<stri
signaller.emit(EventType.MessageSend, fileChangeEventToMsg({ path: fileName })); signaller.emit(EventType.MessageSend, fileChangeEventToMsg({ path: fileName }));
}); });
} }
break;
case "getAllFiles":
if (!Array.isArray(incoming.result))
return console.log("Malformed data received.");
if (updateLogs) {
let results: FileContent[] = (incoming.result as FileContent[])
for (let result of results) {
if (result.filename.startsWith(remoteLogFolder)) {
let localFileName = result.filename.replace(remoteLogFolder, "").replace("/", "_");
writeFile(localLogFolder + "\\" + localFileName, result.content, (err) => {
if (err) return console.log(err);
});
}
}
}
break;
} }
} }