Adding ability to download log files from within the game to the local filesystem.
This commit is contained in:
parent
7ff71ffbd9
commit
41127abee8
7 changed files with 114 additions and 4 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -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
21
filesync.json
Normal 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
|
||||||
|
}
|
|
@ -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.",
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
19
src/index.ts
19
src/index.ts
|
@ -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));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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}`;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue