mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2026-04-16 06:18:42 +02:00
CODEBASE: Refactor message handler of Remote API (#2211)
This commit is contained in:
@@ -4,110 +4,170 @@ import { hasScriptExtension } from "../Paths/ScriptFilePath";
|
||||
import { GetServer, GetAllServers } from "../Server/AllServers";
|
||||
import {
|
||||
RFAMessage,
|
||||
type FileData,
|
||||
type FileContent,
|
||||
isFileServer,
|
||||
isFileLocation,
|
||||
type FileLocation,
|
||||
isFileData,
|
||||
type FileMetadata,
|
||||
type FileData,
|
||||
type FileLocation,
|
||||
type FileServer,
|
||||
} from "./MessageDefinitions";
|
||||
|
||||
import libSource from "../ScriptEditor/NetscriptDefinitions.d.ts?raw";
|
||||
import { saveObject } from "../SaveObject";
|
||||
import { Player } from "@player";
|
||||
import type { BaseServer } from "../Server/BaseServer";
|
||||
import type { ContentFilePath } from "../Paths/ContentFile";
|
||||
|
||||
function error(errorMsg: string, { id }: RFAMessage): RFAMessage {
|
||||
return new RFAMessage({ error: errorMsg, id: id });
|
||||
type SuccessResult<T> = { success: true; params: T };
|
||||
type FailureResult = { success: false; errorResponse: RFAMessage };
|
||||
export type ValidationResult<T> = SuccessResult<T> | FailureResult;
|
||||
|
||||
function getErrorResponse(errorMsg: string, { id }: RFAMessage): RFAMessage {
|
||||
return new RFAMessage({ error: errorMsg, id });
|
||||
}
|
||||
|
||||
function validateParams<T>(validationFunction: (p: unknown) => p is T, request: RFAMessage): ValidationResult<T> {
|
||||
if (!request.params) {
|
||||
return { success: false, errorResponse: getErrorResponse("Missing params", request) };
|
||||
}
|
||||
if (!validationFunction(request.params)) {
|
||||
return {
|
||||
success: false,
|
||||
errorResponse: getErrorResponse(`Invalid params: ${JSON.stringify(request.params)}`, request),
|
||||
};
|
||||
}
|
||||
return { success: true, params: request.params };
|
||||
}
|
||||
|
||||
function validateFilePathAndServerParams<T extends FileData | FileLocation>(
|
||||
validationFunction: (p: unknown) => p is T,
|
||||
request: RFAMessage,
|
||||
): { success: true; data: { filePath: ContentFilePath; server: BaseServer; params: T } } | FailureResult {
|
||||
const validationResult = validateParams(validationFunction, request);
|
||||
if (!validationResult.success) {
|
||||
return validationResult;
|
||||
}
|
||||
const params = validationResult.params;
|
||||
const filePath = resolveFilePath(params.filename);
|
||||
if (!filePath) {
|
||||
return { success: false, errorResponse: getErrorResponse(`Invalid file path: ${params.filename}`, request) };
|
||||
}
|
||||
|
||||
if (!hasTextExtension(filePath) && !hasScriptExtension(filePath)) {
|
||||
return {
|
||||
success: false,
|
||||
errorResponse: getErrorResponse(`Invalid file extension. Filename: ${params.filename}`, request),
|
||||
};
|
||||
}
|
||||
|
||||
const server = GetServer(params.server);
|
||||
if (!server) {
|
||||
return { success: false, errorResponse: getErrorResponse(`Invalid hostname: ${params.server}`, request) };
|
||||
}
|
||||
|
||||
return { success: true, data: { filePath, server, params } };
|
||||
}
|
||||
|
||||
function validateServerParams(
|
||||
request: RFAMessage,
|
||||
): { success: true; data: { server: BaseServer; params: FileServer } } | FailureResult {
|
||||
const validationResult = validateParams(isFileServer, request);
|
||||
if (!validationResult.success) {
|
||||
return validationResult;
|
||||
}
|
||||
const fileServer = validationResult.params;
|
||||
|
||||
const server = GetServer(fileServer.server);
|
||||
if (!server) {
|
||||
return { success: false, errorResponse: getErrorResponse(`Invalid hostname: ${fileServer.server}`, request) };
|
||||
}
|
||||
|
||||
return { success: true, data: { server, params: fileServer } };
|
||||
}
|
||||
|
||||
export const RFARequestHandler: Record<string, (message: RFAMessage) => RFAMessage | Promise<RFAMessage>> = {
|
||||
pushFile: function (msg: RFAMessage): RFAMessage {
|
||||
if (!isFileData(msg.params)) return error("Misses parameters", msg);
|
||||
|
||||
const fileData: FileData = msg.params;
|
||||
const filePath = resolveFilePath(fileData.filename);
|
||||
if (!filePath) return error("Invalid file path", msg);
|
||||
|
||||
const server = GetServer(fileData.server);
|
||||
if (!server) return error("Server hostname invalid", msg);
|
||||
|
||||
if (hasTextExtension(filePath) || hasScriptExtension(filePath)) {
|
||||
server.writeToContentFile(filePath, fileData.content);
|
||||
return new RFAMessage({ result: "OK", id: msg.id });
|
||||
const validationResult = validateFilePathAndServerParams(isFileData, msg);
|
||||
if (!validationResult.success) {
|
||||
return validationResult.errorResponse;
|
||||
}
|
||||
return error("Invalid file extension", msg);
|
||||
const validationData = validationResult.data;
|
||||
|
||||
validationData.server.writeToContentFile(validationData.filePath, validationData.params.content);
|
||||
return new RFAMessage({ result: "OK", id: msg.id });
|
||||
},
|
||||
|
||||
getFile: function (msg: RFAMessage): RFAMessage {
|
||||
if (!isFileLocation(msg.params)) return error("Message misses parameters", msg);
|
||||
const validationResult = validateFilePathAndServerParams(isFileLocation, msg);
|
||||
if (!validationResult.success) {
|
||||
return validationResult.errorResponse;
|
||||
}
|
||||
const validationData = validationResult.data;
|
||||
|
||||
const fileData: FileLocation = msg.params;
|
||||
const filePath = resolveFilePath(fileData.filename);
|
||||
if (!filePath) return error("Invalid file path", msg);
|
||||
const file = validationData.server.getContentFile(validationData.filePath);
|
||||
if (!file) {
|
||||
return getErrorResponse(`File does not exist. Filename: ${validationData.params.filename}`, msg);
|
||||
}
|
||||
|
||||
const server = GetServer(fileData.server);
|
||||
if (!server) return error("Server hostname invalid", msg);
|
||||
|
||||
if (!hasTextExtension(filePath) && !hasScriptExtension(filePath)) return error("Invalid file extension", msg);
|
||||
const file = server.getContentFile(filePath);
|
||||
if (!file) return error("File doesn't exist", msg);
|
||||
return new RFAMessage({ result: file.content, id: msg.id });
|
||||
},
|
||||
|
||||
getFileMetadata: function (msg: RFAMessage): RFAMessage {
|
||||
if (!isFileLocation(msg.params)) return error("Message misses parameters", msg);
|
||||
const validationResult = validateFilePathAndServerParams(isFileLocation, msg);
|
||||
if (!validationResult.success) {
|
||||
return validationResult.errorResponse;
|
||||
}
|
||||
const validationData = validationResult.data;
|
||||
|
||||
const fileData: FileLocation = msg.params;
|
||||
const filePath = resolveFilePath(fileData.filename);
|
||||
if (!filePath) return error("Invalid file path", msg);
|
||||
const file = validationData.server.getContentFile(validationData.filePath);
|
||||
if (!file) {
|
||||
return getErrorResponse(`File does not exist. Filename: ${validationData.params.filename}`, msg);
|
||||
}
|
||||
|
||||
const server = GetServer(fileData.server);
|
||||
if (!server) return error("Server hostname invalid", msg);
|
||||
|
||||
if (!hasTextExtension(filePath) && !hasScriptExtension(filePath)) return error("Invalid file extension", msg);
|
||||
const file = server.getContentFile(filePath);
|
||||
if (!file) return error("File doesn't exist", msg);
|
||||
|
||||
const result: FileMetadata = {
|
||||
filename: file.filename,
|
||||
...file.metadata.plain(),
|
||||
};
|
||||
return new RFAMessage({ result: result, id: msg.id });
|
||||
return new RFAMessage({
|
||||
result: {
|
||||
filename: file.filename,
|
||||
...file.metadata.plain(),
|
||||
},
|
||||
id: msg.id,
|
||||
});
|
||||
},
|
||||
|
||||
deleteFile: function (msg: RFAMessage): RFAMessage {
|
||||
if (!isFileLocation(msg.params)) return error("Message misses parameters", msg);
|
||||
const validationResult = validateFilePathAndServerParams(isFileLocation, msg);
|
||||
if (!validationResult.success) {
|
||||
return validationResult.errorResponse;
|
||||
}
|
||||
const validationData = validationResult.data;
|
||||
|
||||
const fileData: FileLocation = msg.params;
|
||||
const filePath = resolveFilePath(fileData.filename);
|
||||
if (!filePath) return error("Invalid filename", msg);
|
||||
const resultOfRemovingFile = validationData.server.removeFile(validationData.filePath);
|
||||
if (!resultOfRemovingFile.res) {
|
||||
return getErrorResponse(resultOfRemovingFile.msg ?? "Failed", msg);
|
||||
}
|
||||
|
||||
const server = GetServer(fileData.server);
|
||||
if (!server) return error("Server hostname invalid", msg);
|
||||
|
||||
const result = server.removeFile(filePath);
|
||||
if (result.res) return new RFAMessage({ result: "OK", id: msg.id });
|
||||
return error(result.msg ?? "Failed", msg);
|
||||
return new RFAMessage({ result: "OK", id: msg.id });
|
||||
},
|
||||
|
||||
getFileNames: function (msg: RFAMessage): RFAMessage {
|
||||
if (!isFileServer(msg.params)) return error("Message misses parameters", msg);
|
||||
const validationResult = validateServerParams(msg);
|
||||
if (!validationResult.success) {
|
||||
return validationResult.errorResponse;
|
||||
}
|
||||
const validationData = validationResult.data;
|
||||
|
||||
const server = GetServer(msg.params.server);
|
||||
if (!server) return error("Server hostname invalid", msg);
|
||||
|
||||
const fileNameList: string[] = [...server.textFiles.keys(), ...server.scripts.keys()];
|
||||
const fileNameList = [...validationData.server.textFiles.keys(), ...validationData.server.scripts.keys()];
|
||||
|
||||
return new RFAMessage({ result: fileNameList, id: msg.id });
|
||||
},
|
||||
|
||||
getAllFiles: function (msg: RFAMessage): RFAMessage {
|
||||
if (!isFileServer(msg.params)) return error("Message misses parameters", msg);
|
||||
const validationResult = validateServerParams(msg);
|
||||
if (!validationResult.success) {
|
||||
return validationResult.errorResponse;
|
||||
}
|
||||
const validationData = validationResult.data;
|
||||
|
||||
const server = GetServer(msg.params.server);
|
||||
if (!server) return error("Server hostname invalid", msg);
|
||||
|
||||
const fileList: FileContent[] = [...server.scripts, ...server.textFiles].map(([filename, file]) => ({
|
||||
const fileList = [...validationData.server.scripts, ...validationData.server.textFiles].map(([filename, file]) => ({
|
||||
filename,
|
||||
content: file.content,
|
||||
}));
|
||||
@@ -115,12 +175,13 @@ export const RFARequestHandler: Record<string, (message: RFAMessage) => RFAMessa
|
||||
},
|
||||
|
||||
getAllFileMetadata: function (msg: RFAMessage): RFAMessage {
|
||||
if (!isFileServer(msg.params)) return error("Message misses parameters", msg);
|
||||
const validationResult = validateServerParams(msg);
|
||||
if (!validationResult.success) {
|
||||
return validationResult.errorResponse;
|
||||
}
|
||||
const validationData = validationResult.data;
|
||||
|
||||
const server = GetServer(msg.params.server);
|
||||
if (!server) return error("Server hostname invalid", msg);
|
||||
|
||||
const fileList: FileMetadata[] = [...server.scripts, ...server.textFiles].map(([filename, file]) => ({
|
||||
const fileList = [...validationData.server.scripts, ...validationData.server.textFiles].map(([filename, file]) => ({
|
||||
filename: filename,
|
||||
...file.metadata.plain(),
|
||||
}));
|
||||
@@ -128,19 +189,30 @@ export const RFARequestHandler: Record<string, (message: RFAMessage) => RFAMessa
|
||||
},
|
||||
|
||||
calculateRam: function (msg: RFAMessage): RFAMessage {
|
||||
if (!isFileLocation(msg.params)) return error("Message misses parameters", msg);
|
||||
const fileData: FileLocation = msg.params;
|
||||
const filePath = resolveFilePath(fileData.filename);
|
||||
if (!filePath) return error("Invalid filename", msg);
|
||||
const validationResult = validateFilePathAndServerParams(isFileLocation, msg);
|
||||
if (!validationResult.success) {
|
||||
return validationResult.errorResponse;
|
||||
}
|
||||
const validationData = validationResult.data;
|
||||
|
||||
const server = GetServer(fileData.server);
|
||||
if (!server) return error("Server hostname invalid", msg);
|
||||
// Validate filePath again. validateFilePathAndServerParams only checks if filePath is a text file or a script.
|
||||
if (!hasScriptExtension(validationData.filePath)) {
|
||||
return getErrorResponse(`File is not a script. Filename: ${validationData.params.filename}`, msg);
|
||||
}
|
||||
|
||||
const script = validationData.server.scripts.get(validationData.filePath);
|
||||
if (!script) {
|
||||
return getErrorResponse(`File does not exist. Filename: ${validationData.params.filename}`, msg);
|
||||
}
|
||||
|
||||
const ramUsage = script.getRamUsage(validationData.server.scripts);
|
||||
if (!ramUsage) {
|
||||
return getErrorResponse(
|
||||
`Cannot calculate RAM usage of an invalid script. Filename: ${validationData.params.filename}`,
|
||||
msg,
|
||||
);
|
||||
}
|
||||
|
||||
if (!hasScriptExtension(filePath)) return error("Filename isn't a script filename", msg);
|
||||
const script = server.scripts.get(filePath);
|
||||
if (!script) return error("File doesn't exist", msg);
|
||||
const ramUsage = script.getRamUsage(server.scripts);
|
||||
if (!ramUsage) return error("Ram cost could not be calculated", msg);
|
||||
return new RFAMessage({ result: ramUsage, id: msg.id });
|
||||
},
|
||||
|
||||
|
||||
Reference in New Issue
Block a user