Cleanup + lint/format

This commit is contained in:
Zoë Hoekstra
2022-08-10 23:22:03 +02:00
parent 2628dc1ae8
commit 88d8f13847
7 changed files with 235 additions and 237 deletions

View File

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

View File

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

View File

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

View File

@ -3,127 +3,138 @@ import { isScriptFilename } from "../Script/isScriptFilename";
import { GetServer } from "../Server/AllServers"; import { GetServer } from "../Server/AllServers";
import { isValidFilePath } from "../Terminal/DirectoryHelpers"; import { isValidFilePath } from "../Terminal/DirectoryHelpers";
import { TextFile } from "../TextFile"; 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 //@ts-ignore: Complaint of import ending with .d.ts
import libSource from "!!raw-loader!../ScriptEditor/NetscriptDefinitions.d.ts"; import libSource from "!!raw-loader!../ScriptEditor/NetscriptDefinitions.d.ts";
import { RFALogger } from "./RFALogger";
function error(errorMsg: string, { id }: RFAMessage): RFAMessage { function error(errorMsg: string, { id }: RFAMessage): RFAMessage {
console.error("[RFA-ERROR]" + (typeof (id) === "undefined" ? "" : `Request ${id}: `) + errorMsg); RFALogger.error((typeof id === "undefined" ? "" : `Request ${id}: `) + errorMsg);
return new RFAMessage({ error: errorMsg, id: id }); return new RFAMessage({ error: errorMsg, id: id });
} }
export const RFARequestHandler: Record<string, (message: RFAMessage) => void | RFAMessage> = { 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 { const fileData: FileData = msg.params;
if (!isFileData(msg.params)) return error("pushFile message misses parameters", msg); if (!isValidFilePath(fileData.filename)) return error("Invalid filename", msg);
const fileData: FileData = msg.params; const server = GetServer(fileData.server);
if (!isValidFilePath(fileData.filename)) return error("pushFile with an invalid filename", msg); if (!server) return error("Server hostname invalid", msg);
const server = GetServer(fileData.server); if (isScriptFilename(fileData.filename)) server.writeToScriptFile(Player, fileData.filename, fileData.content);
if (server == null) return error("Server hostname invalid", msg); // Assume it's a text file
else server.writeToTextFile(fileData.filename, fileData.content);
if (isScriptFilename(fileData.filename)) // If and only if the content is actually changed correctly, send back an OK.
server.writeToScriptFile(Player, fileData.filename, fileData.content); const savedCorrectly =
else // Assume it's a text file server.getScript(fileData.filename)?.code === fileData.content ||
server.writeToTextFile(fileData.filename, 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. if (!savedCorrectly) return error("File wasn't saved correctly", msg);
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); 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 { const fileData: FileLocation = msg.params;
if (!isFileLocation(msg.params)) return error("getFile message misses parameters", msg); if (!isValidFilePath(fileData.filename)) return error("Invalid filename", msg);
const fileData: FileLocation = msg.params; const server = GetServer(fileData.server);
if (!isValidFilePath(fileData.filename)) return error("getFile with an invalid filename", msg); if (!server) return error("Server hostname invalid", msg);
const server = GetServer(fileData.server); if (isScriptFilename(fileData.filename)) {
if (server == null) return error("Server hostname invalid", msg); const scriptContent = server.getScript(fileData.filename);
if (!scriptContent) return error("File doesn't exist", msg);
if (isScriptFilename(fileData.filename)) { return new RFAMessage({ result: scriptContent.code, id: msg.id });
const scriptContent = server.getScript(fileData.filename); } else {
if (!scriptContent) return error("Requested script doesn't exist", msg); // Assume it's a text file
return new RFAMessage({ result: scriptContent.code, id: msg.id }); const file = server.textFiles.filter((t: TextFile) => t.filename == fileData.filename).at(0);
} if (!file) return error("File doesn't exist", msg);
else { // Assume it's a text file return new RFAMessage({ result: file.text, id: msg.id });
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});
} }
} },
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 });
},
};

View File

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

View File

@ -1,47 +1,49 @@
import { RFALogger } from "./RFALogger"; import { RFALogger } from "./RFALogger";
import { RFAMessage } from "./MessageDefinitions" import { RFAMessage } from "./MessageDefinitions";
import { RFARequestHandler } from "./MessageHandlers"; import { RFARequestHandler } from "./MessageHandlers";
export class Remote { export class Remote {
connection? : WebSocket; connection?: WebSocket;
protocol = "ws"; protocol = "ws";
ipaddr: string; ipaddr: string;
port: number; port: number;
constructor(ip : string, port : number) { constructor(ip: string, port: number) {
this.ipaddr = ip; this.ipaddr = ip;
this.port = port; this.port = port;
} }
public stopConnection() : void { public stopConnection(): void {
this.connection?.close(); this.connection?.close();
} }
public startConnection() : void { public startConnection(): void {
RFALogger.log("Trying to connect."); RFALogger.log("Trying to connect.");
this.connection = new WebSocket(this.protocol + "://" + this.ipaddr + ":" + this.port); this.connection = new WebSocket(this.protocol + "://" + this.ipaddr + ":" + this.port);
this.connection.addEventListener("error", (e:Event) => RFALogger.error(e)); this.connection.addEventListener("error", (e: Event) => RFALogger.error(e));
this.connection.addEventListener("message", handleMessageEvent); this.connection.addEventListener("message", handleMessageEvent);
this.connection.addEventListener("open", () => RFALogger.log("Connection established: ", this.ipaddr, ":", this.port)); this.connection.addEventListener("open", () =>
this.connection.addEventListener("close", () => RFALogger.log("Connection closed")); RFALogger.log("Connection established: ", this.ipaddr, ":", this.port),
} );
this.connection.addEventListener("close", () => RFALogger.log("Connection closed"));
}
} }
function handleMessageEvent(e: MessageEvent):void { function handleMessageEvent(this: WebSocket, e: MessageEvent): void {
const msg : RFAMessage = JSON.parse(e.data); const msg: RFAMessage = JSON.parse(e.data);
RFALogger.log("Message received:", msg); 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) {
if (!RFARequestHandler[msg.method]) {
if (msg.method) const response = new RFAMessage({ error: "Unknown message received", id: msg.id });
{ this.send(JSON.stringify(response));
const response = RFARequestHandler[msg.method](msg); return;
RFALogger.log("Sending response: ", response); }
if(response) this.send(JSON.stringify(response)); 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.result) RFALogger.log("Somehow retrieved a result message.");
else if (msg.error) RFALogger.error("Received an error from server", msg); else if (msg.error) RFALogger.error("Received an error from server", msg);
else RFALogger.error("Incorrect Message", msg); else RFALogger.error("Incorrect Message", msg);
} }

View File

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