Cleanup + lint/format

This commit is contained in:
Zoë Hoekstra 2022-08-10 23:22:03 +02:00
parent 2628dc1ae8
commit 88d8f13847
No known key found for this signature in database
GPG Key ID: F9B7B7D8130F3323
7 changed files with 235 additions and 237 deletions

@ -17,30 +17,25 @@ export class ConnectionBauble extends React.Component<baubleProps> {
super(props);
this.state = {
connection: props.callback(),
callback: props.callback
callback: props.callback,
};
}
componentDidMount() : void {
this.timerID = setInterval(
() => this.tick(),
1000
);
componentDidMount(): void {
this.timerID = setInterval(() => this.tick(), 1000);
}
componentWillUnmount() : void {
componentWillUnmount(): void {
clearInterval(this.timerID);
}
tick() : void {
tick(): void {
this.setState({
connection: this.state.callback()
connection: this.state.callback(),
});
}
render() : string {
return (
this.state.connection? "Connected" : "Disconnected"
);
render(): string {
return this.state.connection ? "Connected" : "Disconnected";
}
}

@ -370,27 +370,26 @@ export const CurrentOptionsPage = (props: IProps): React.ReactElement => {
</>
}
/>
<Tooltip title={
<Typography>
This port number is used to connect to a Remote File API port,
please ensure that it matches with the port the Remote File API server is publishing on (12525 by default).
Click the reconnect button to try and re-establish connection.
The little colored bauble shows whether the connection is live or not.
</Typography>
}>
<TextField
<Tooltip
title={
<Typography>
This port number is used to connect to a Remote File API port, please ensure that it matches with the port
the Remote File API server is publishing on (12525 by default). Click the reconnect button to try and
re-establish connection. The little colored bauble shows whether the connection is live or not.
</Typography>
}
>
<TextField
InputProps={{
startAdornment: (
<Typography
color={remoteFileApiPort > 0 && remoteFileApiPort <= 65535? "success" : "error"}
>
<Typography color={remoteFileApiPort > 0 && remoteFileApiPort <= 65535 ? "success" : "error"}>
Remote File API port:
</Typography>
),
endAdornment: (
<Box>
<Button onClick={newRemoteFileApiConnection}>Reconnect</Button>
<ConnectionBauble callback={isRemoteFileApiConnectionLive}/>
<ConnectionBauble callback={isRemoteFileApiConnectionLive} />
</Box>
),
}}
@ -398,7 +397,7 @@ export const CurrentOptionsPage = (props: IProps): React.ReactElement => {
onChange={handleRemoteFileApiPortChange}
placeholder="12525"
/>
</Tooltip>
</Tooltip>
</GameOptionsPage>
),
};

@ -1,65 +1,58 @@
export class RFAMessage {
jsonrpc = "2.0"; // Transmits version of JSON-RPC. Compliance maybe allows some funky interaction with external tools?
public method?:string; // Is defined when it's a request/notification, otherwise undefined
public result?:string; // Is defined when it's a response, otherwise undefined
public params?:FileMetadata; // Optional parameters to method
public error? :string; // Only defined on error
public id? :number; // ID to keep track of request -> response interaction, undefined with notifications, defined with request/response
jsonrpc = "2.0"; // Transmits version of JSON-RPC. Compliance maybe allows some funky interaction with external tools?
public method?: string; // Is defined when it's a request/notification, otherwise undefined
public result?: string; // Is defined when it's a response, otherwise undefined
public params?: FileMetadata; // Optional parameters to method
public error?: string; // Only defined on error
public id?: number; // ID to keep track of request -> response interaction, undefined with notifications, defined with request/response
constructor(obj: { method?: string; result?: string; params?: FileMetadata; error?: string; id?: number } = {}){
this.method = obj.method;
this.result = obj.result;
this.params = obj.params;
this.error = obj.error;
this.id = obj.id;
}
constructor(obj: { method?: string; result?: string; params?: FileMetadata; error?: string; id?: number } = {}) {
this.method = obj.method;
this.result = obj.result;
this.params = obj.params;
this.error = obj.error;
this.id = obj.id;
}
}
type FileMetadata = FileData
| FileContent
| FileLocation
| FileServer;
type FileMetadata = FileData | FileContent | FileLocation | FileServer;
export interface FileData {
filename: string;
content: string;
server: string;
filename: string;
content: string;
server: string;
}
export interface FileContent {
filename: string;
content: string;
filename: string;
content: string;
}
export interface FileLocation {
filename: string;
server: string;
filename: string;
server: string;
}
export interface FileServer {
server: string;
server: string;
}
export function isFileData(p: unknown): p is FileData {
const pf = p as FileData
return typeof pf.server === 'string' &&
typeof pf.filename === 'string' &&
typeof pf.content === 'string'
const pf = p as FileData;
return typeof pf.server === "string" && typeof pf.filename === "string" && typeof pf.content === "string";
}
export function isFileLocation(p: unknown): p is FileLocation {
const pf = p as FileLocation
return typeof pf.server === 'string' &&
typeof pf.filename === 'string'
const pf = p as FileLocation;
return typeof pf.server === "string" && typeof pf.filename === "string";
}
export function isFileContent(p: unknown): p is FileContent {
const pf = p as FileContent
return typeof pf.filename === 'string' &&
typeof pf.content === 'string'
const pf = p as FileContent;
return typeof pf.filename === "string" && typeof pf.content === "string";
}
export function isFileServer(p: unknown): p is FileServer {
const pf = p as FileServer
return typeof pf.server === 'string'
const pf = p as FileServer;
return typeof pf.server === "string";
}

@ -3,127 +3,138 @@ import { isScriptFilename } from "../Script/isScriptFilename";
import { GetServer } from "../Server/AllServers";
import { isValidFilePath } from "../Terminal/DirectoryHelpers";
import { TextFile } from "../TextFile";
import { RFAMessage, FileData, FileContent, isFileServer, isFileLocation, FileLocation, isFileData } from "./MessageDefinitions";
import {
RFAMessage,
FileData,
FileContent,
isFileServer,
isFileLocation,
FileLocation,
isFileData,
} from "./MessageDefinitions";
//@ts-ignore: Complaint of import ending with .d.ts
import libSource from "!!raw-loader!../ScriptEditor/NetscriptDefinitions.d.ts";
import { RFALogger } from "./RFALogger";
function error(errorMsg: string, { id }: RFAMessage): RFAMessage {
console.error("[RFA-ERROR]" + (typeof (id) === "undefined" ? "" : `Request ${id}: `) + errorMsg);
return new RFAMessage({ error: errorMsg, id: id });
RFALogger.error((typeof id === "undefined" ? "" : `Request ${id}: `) + errorMsg);
return new RFAMessage({ error: errorMsg, id: id });
}
export const RFARequestHandler: Record<string, (message: RFAMessage) => void | RFAMessage> = {
pushFile: function (msg: RFAMessage): RFAMessage {
if (!isFileData(msg.params)) return error("Misses parameters", msg);
pushFile: function (msg: RFAMessage): RFAMessage {
if (!isFileData(msg.params)) return error("pushFile message misses parameters", msg);
const fileData: FileData = msg.params;
if (!isValidFilePath(fileData.filename)) return error("Invalid filename", msg);
const fileData: FileData = msg.params;
if (!isValidFilePath(fileData.filename)) return error("pushFile with an invalid filename", msg);
const server = GetServer(fileData.server);
if (!server) return error("Server hostname invalid", msg);
const server = GetServer(fileData.server);
if (server == null) return error("Server hostname invalid", msg);
if (isScriptFilename(fileData.filename)) server.writeToScriptFile(Player, fileData.filename, fileData.content);
// Assume it's a text file
else server.writeToTextFile(fileData.filename, fileData.content);
if (isScriptFilename(fileData.filename))
server.writeToScriptFile(Player, fileData.filename, fileData.content);
else // Assume it's a text file
server.writeToTextFile(fileData.filename, fileData.content);
// If and only if the content is actually changed correctly, send back an OK.
const savedCorrectly =
server.getScript(fileData.filename)?.code === fileData.content ||
server.textFiles.filter((t: TextFile) => t.filename == fileData.filename).at(0)?.text === fileData.content;
// If and only if the content is actually changed correctly, send back an OK.
const savedCorrectly = server.getScript(fileData.filename)?.code === fileData.content
|| server.textFiles.filter((t: TextFile) => t.filename == fileData.filename).at(0)?.text === fileData.content;
if (!savedCorrectly) return error("File wasn't saved correctly", msg);
if (!savedCorrectly) return error("File wasn't saved correctly", msg);
return new RFAMessage({ result: "OK", id: msg.id });
},
return new RFAMessage({ result: "OK", id: msg.id });
},
getFile: function (msg: RFAMessage): RFAMessage {
if (!isFileLocation(msg.params)) return error("Message misses parameters", msg);
getFile: function (msg: RFAMessage): RFAMessage {
if (!isFileLocation(msg.params)) return error("getFile message misses parameters", msg);
const fileData: FileLocation = msg.params;
if (!isValidFilePath(fileData.filename)) return error("Invalid filename", msg);
const fileData: FileLocation = msg.params;
if (!isValidFilePath(fileData.filename)) return error("getFile with an invalid filename", msg);
const server = GetServer(fileData.server);
if (!server) return error("Server hostname invalid", msg);
const server = GetServer(fileData.server);
if (server == null) return error("Server hostname invalid", msg);
if (isScriptFilename(fileData.filename)) {
const scriptContent = server.getScript(fileData.filename);
if (!scriptContent) return error("Requested script doesn't exist", msg);
return new RFAMessage({ result: scriptContent.code, id: msg.id });
}
else { // Assume it's a text file
const file = server.textFiles.filter((t: TextFile) => t.filename == fileData.filename).at(0);
if (file === undefined) return error("Requested textfile doesn't exist", msg);
return new RFAMessage({ result: file.text, id: msg.id });
}
},
deleteFile: function (msg: RFAMessage): RFAMessage {
if (!isFileLocation(msg.params)) return error("deleteFile message misses parameters", msg);
const fileData: FileLocation = msg.params;
if (!isValidFilePath(fileData.filename)) return error("deleteFile with an invalid filename", msg);
const server = GetServer(fileData.server);
if (server == null) return error("Server hostname invalid", msg);
const fileExists = (): boolean => !!server.getScript(fileData.filename)
|| server.textFiles.some((t: TextFile) => t.filename === fileData.filename);
if (!fileExists()) return error("deleteFile file doesn't exist", msg);
server.removeFile(fileData.filename);
if (fileExists()) return error("deleteFile failed to delete the file", msg);
return new RFAMessage({ result: "OK", id: msg.id });
},
getFileNames: function (msg: RFAMessage): RFAMessage {
if (!isFileServer(msg.params)) return error("getFileNames message misses parameters", msg);
const server = GetServer(msg.params.server);
if (server == null) return error("Server hostname invalid", msg);
const fileNameList: string[] = [
...server.textFiles.map((txt): string => txt.filename),
...server.scripts.map((scr): string => scr.filename)
];
return new RFAMessage({ result: JSON.stringify(fileNameList), id: msg.id });
},
getAllFiles: function (msg: RFAMessage): RFAMessage {
if (!isFileServer(msg.params)) return error("getAllFiles message misses parameters", msg);
const server = GetServer(msg.params.server);
if (server == null) return error("Server hostname invalid", msg);
const fileList: FileContent[] = [
...server.textFiles.map((txt): FileContent => { return { filename: txt.filename, content: txt.text } }),
...server.scripts.map((scr): FileContent => { return { filename: scr.filename, content: scr.code } })
];
return new RFAMessage({ result: JSON.stringify(fileList), id: msg.id });
},
calculateRam: function (msg: RFAMessage): RFAMessage {
if (!isFileLocation(msg.params)) return error("calculateRam message misses parameters", msg);
const fileData: FileLocation = msg.params;
if (!isValidFilePath(fileData.filename)) return error("deleteFile with an invalid filename", msg);
const server = GetServer(fileData.server);
if (server == null) return error("Server hostname invalid", msg);
if (!isScriptFilename(fileData.filename)) return error("Filename isn't a script filename", msg);
const script = server.getScript(fileData.filename);
if (!script) return error("File doesn't exist", msg);
const ramUsage = script.ramUsage;
return new RFAMessage({result: String(ramUsage), id: msg.id});
},
getDefinitionFile: function (msg: RFAMessage): RFAMessage {
const source = (libSource + "").replace(/export /g, "");
console.log(source);
return new RFAMessage({result: source, id: msg.id});
if (isScriptFilename(fileData.filename)) {
const scriptContent = server.getScript(fileData.filename);
if (!scriptContent) return error("File doesn't exist", msg);
return new RFAMessage({ result: scriptContent.code, id: msg.id });
} else {
// Assume it's a text file
const file = server.textFiles.filter((t: TextFile) => t.filename == fileData.filename).at(0);
if (!file) return error("File doesn't exist", msg);
return new RFAMessage({ result: file.text, id: msg.id });
}
}
},
deleteFile: function (msg: RFAMessage): RFAMessage {
if (!isFileLocation(msg.params)) return error("Message misses parameters", msg);
const fileData: FileLocation = msg.params;
if (!isValidFilePath(fileData.filename)) return error("Invalid filename", msg);
const server = GetServer(fileData.server);
if (!server) return error("Server hostname invalid", msg);
const fileExists = (): boolean =>
!!server.getScript(fileData.filename) || server.textFiles.some((t: TextFile) => t.filename === fileData.filename);
if (!fileExists()) return error("File doesn't exist", msg);
server.removeFile(fileData.filename);
if (fileExists()) return error("Failed to delete the file", 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 server = GetServer(msg.params.server);
if (!server) return error("Server hostname invalid", msg);
const fileNameList: string[] = [
...server.textFiles.map((txt): string => txt.filename),
...server.scripts.map((scr): string => scr.filename),
];
return new RFAMessage({ result: JSON.stringify(fileNameList), id: msg.id });
},
getAllFiles: function (msg: RFAMessage): RFAMessage {
if (!isFileServer(msg.params)) return error("Message misses parameters", msg);
const server = GetServer(msg.params.server);
if (!server) return error("Server hostname invalid", msg);
const fileList: FileContent[] = [
...server.textFiles.map((txt): FileContent => {
return { filename: txt.filename, content: txt.text };
}),
...server.scripts.map((scr): FileContent => {
return { filename: scr.filename, content: scr.code };
}),
];
return new RFAMessage({ result: JSON.stringify(fileList), id: msg.id });
},
calculateRam: function (msg: RFAMessage): RFAMessage {
if (!isFileLocation(msg.params)) return error("Message misses parameters", msg);
const fileData: FileLocation = msg.params;
if (!isValidFilePath(fileData.filename)) return error("Invalid filename", msg);
const server = GetServer(fileData.server);
if (!server) return error("Server hostname invalid", msg);
if (!isScriptFilename(fileData.filename)) return error("Filename isn't a script filename", msg);
const script = server.getScript(fileData.filename);
if (!script) return error("File doesn't exist", msg);
const ramUsage = script.ramUsage;
return new RFAMessage({ result: String(ramUsage), id: msg.id });
},
getDefinitionFile: function (msg: RFAMessage): RFAMessage {
const source = (libSource + "").replace(/export /g, "");
console.log(source);
return new RFAMessage({ result: source, id: msg.id });
},
};

@ -1,27 +1,27 @@
class RemoteFileAPILogger {
_enabled = true;
_prefix = "[RFA]";
_error_prefix = "[RFA-ERROR]";
_enabled = true;
_prefix = "[RFA]";
_error_prefix = "[RFA-ERROR]";
constructor(enabled: boolean){
this._enabled = enabled;
}
constructor(enabled: boolean) {
this._enabled = enabled;
}
public error(...message: any[]) : void {
if (this._enabled) console.error(this._error_prefix, ...message);
}
public error(...message: any[]): void {
if (this._enabled) console.error(this._error_prefix, ...message);
}
public log(...message: any[]) : void {
if (this._enabled) console.log(this._prefix, ...message);
}
public log(...message: any[]): void {
if (this._enabled) console.log(this._prefix, ...message);
}
public disable() : void {
this._enabled = false;
}
public disable(): void {
this._enabled = false;
}
public enable() : void {
this._enabled = true;
}
public enable(): void {
this._enabled = true;
}
}
export const RFALogger = new RemoteFileAPILogger(true);

@ -1,47 +1,49 @@
import { RFALogger } from "./RFALogger";
import { RFAMessage } from "./MessageDefinitions"
import { RFAMessage } from "./MessageDefinitions";
import { RFARequestHandler } from "./MessageHandlers";
export class Remote {
connection? : WebSocket;
protocol = "ws";
ipaddr: string;
port: number;
connection?: WebSocket;
protocol = "ws";
ipaddr: string;
port: number;
constructor(ip : string, port : number) {
this.ipaddr = ip;
this.port = port;
}
constructor(ip: string, port: number) {
this.ipaddr = ip;
this.port = port;
}
public stopConnection() : void {
this.connection?.close();
}
public stopConnection(): void {
this.connection?.close();
}
public startConnection() : void {
RFALogger.log("Trying to connect.");
this.connection = new WebSocket(this.protocol + "://" + this.ipaddr + ":" + this.port);
public startConnection(): void {
RFALogger.log("Trying to connect.");
this.connection = new WebSocket(this.protocol + "://" + this.ipaddr + ":" + this.port);
this.connection.addEventListener("error", (e:Event) => RFALogger.error(e));
this.connection.addEventListener("message", handleMessageEvent);
this.connection.addEventListener("open", () => RFALogger.log("Connection established: ", this.ipaddr, ":", this.port));
this.connection.addEventListener("close", () => RFALogger.log("Connection closed"));
}
this.connection.addEventListener("error", (e: Event) => RFALogger.error(e));
this.connection.addEventListener("message", handleMessageEvent);
this.connection.addEventListener("open", () =>
RFALogger.log("Connection established: ", this.ipaddr, ":", this.port),
);
this.connection.addEventListener("close", () => RFALogger.log("Connection closed"));
}
}
function handleMessageEvent(e: MessageEvent):void {
const msg : RFAMessage = JSON.parse(e.data);
RFALogger.log("Message received:", msg);
function handleMessageEvent(this: WebSocket, e: MessageEvent): void {
const msg: RFAMessage = JSON.parse(e.data);
RFALogger.log("Message received:", msg);
//TODO: Needs more safety, send error on invalid input, send error when msg.method isn´t in handlers, ...
if (msg.method)
{
const response = RFARequestHandler[msg.method](msg);
RFALogger.log("Sending response: ", response);
if(response) this.send(JSON.stringify(response));
}
else if (msg.result) RFALogger.error("Result handling not implemented yet.");
else if (msg.error) RFALogger.error("Received an error from server", msg);
else RFALogger.error("Incorrect Message", msg);
if (msg.method) {
if (!RFARequestHandler[msg.method]) {
const response = new RFAMessage({ error: "Unknown message received", id: msg.id });
this.send(JSON.stringify(response));
return;
}
const response = RFARequestHandler[msg.method](msg);
RFALogger.log("Sending response: ", response);
if (response) this.send(JSON.stringify(response));
} else if (msg.result) RFALogger.log("Somehow retrieved a result message.");
else if (msg.error) RFALogger.error("Received an error from server", msg);
else RFALogger.error("Incorrect Message", msg);
}

@ -1,21 +1,19 @@
import { Settings } from "../Settings/Settings";
import { Remote } from "./Remote";
import { Remote } from "./Remote";
let server: Remote;
export function newRemoteFileApiConnection() : void {
if(server == undefined) {
server = new Remote("localhost", Settings.RemoteFileApiPort);
server.startConnection();
}
else {
server.stopConnection();
server = new Remote("localhost", Settings.RemoteFileApiPort);
server.startConnection();
}
export function newRemoteFileApiConnection(): void {
if (server == undefined) {
server = new Remote("localhost", Settings.RemoteFileApiPort);
server.startConnection();
} else {
server.stopConnection();
server = new Remote("localhost", Settings.RemoteFileApiPort);
server.startConnection();
}
}
export function isRemoteFileApiConnectionLive() : boolean {
return server.connection != undefined && server.connection.readyState == 1;
export function isRemoteFileApiConnectionLive(): boolean {
return server.connection != undefined && server.connection.readyState == 1;
}