mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-11-23 08:03:48 +01:00
Add setting UI for port/reconnect, swap wrong API handlers
This commit is contained in:
parent
d20f621b47
commit
5fc67c328b
46
src/GameOptions/ui/ConnectionBauble.tsx
Normal file
46
src/GameOptions/ui/ConnectionBauble.tsx
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
import React from "react";
|
||||||
|
|
||||||
|
interface baubleState {
|
||||||
|
connection: boolean;
|
||||||
|
callback: () => boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface baubleProps {
|
||||||
|
callback: () => boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ConnectionBauble extends React.Component<baubleProps> {
|
||||||
|
timerID: NodeJS.Timer;
|
||||||
|
state: baubleState;
|
||||||
|
|
||||||
|
constructor(props: baubleProps) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
connection: false,
|
||||||
|
callback: props.callback
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() : void {
|
||||||
|
this.timerID = setInterval(
|
||||||
|
() => this.tick(),
|
||||||
|
1000
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() : void {
|
||||||
|
clearInterval(this.timerID);
|
||||||
|
}
|
||||||
|
|
||||||
|
tick() : void {
|
||||||
|
this.setState({
|
||||||
|
connection: this.state.callback()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
render() : string {
|
||||||
|
return (
|
||||||
|
this.state.connection? "Connected" : "Disconnected"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -1,12 +1,15 @@
|
|||||||
import { MenuItem, Select, SelectChangeEvent, TextField, Tooltip, Typography } from "@mui/material";
|
import { MenuItem, Select, SelectChangeEvent, TextField, Tooltip, Typography, Box } from "@mui/material";
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||||
|
import { isRemoteFileApiConnectionLive, newRemoteFileApiConnection } from "../../RemoteFileAPI/RemoteFileAPI";
|
||||||
import { Settings } from "../../Settings/Settings";
|
import { Settings } from "../../Settings/Settings";
|
||||||
import { OptionSwitch } from "../../ui/React/OptionSwitch";
|
import { OptionSwitch } from "../../ui/React/OptionSwitch";
|
||||||
import { formatTime } from "../../utils/helpers/formatTime";
|
import { formatTime } from "../../utils/helpers/formatTime";
|
||||||
import { GameOptionsTab } from "../GameOptionsTab";
|
import { GameOptionsTab } from "../GameOptionsTab";
|
||||||
import { GameOptionsPage } from "./GameOptionsPage";
|
import { GameOptionsPage } from "./GameOptionsPage";
|
||||||
import { OptionsSlider } from "./OptionsSlider";
|
import { OptionsSlider } from "./OptionsSlider";
|
||||||
|
import Button from "@mui/material/Button";
|
||||||
|
import { ConnectionBauble } from "./ConnectionBauble";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
currentTab: GameOptionsTab;
|
currentTab: GameOptionsTab;
|
||||||
@ -21,6 +24,7 @@ export const CurrentOptionsPage = (props: IProps): React.ReactElement => {
|
|||||||
const [terminalSize, setTerminalSize] = useState(Settings.MaxTerminalCapacity);
|
const [terminalSize, setTerminalSize] = useState(Settings.MaxTerminalCapacity);
|
||||||
const [autosaveInterval, setAutosaveInterval] = useState(Settings.AutosaveInterval);
|
const [autosaveInterval, setAutosaveInterval] = useState(Settings.AutosaveInterval);
|
||||||
const [timestampFormat, setTimestampFormat] = useState(Settings.TimestampsFormat);
|
const [timestampFormat, setTimestampFormat] = useState(Settings.TimestampsFormat);
|
||||||
|
const [remoteFileApiPort, setRemoteFileApiPort] = useState(Settings.RemoteFileApiPort);
|
||||||
const [locale, setLocale] = useState(Settings.Locale);
|
const [locale, setLocale] = useState(Settings.Locale);
|
||||||
|
|
||||||
function handleExecTimeChange(
|
function handleExecTimeChange(
|
||||||
@ -81,6 +85,11 @@ export const CurrentOptionsPage = (props: IProps): React.ReactElement => {
|
|||||||
Settings.TimestampsFormat = event.target.value;
|
Settings.TimestampsFormat = event.target.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleRemoteFileApiPortChange(event: React.ChangeEvent<HTMLInputElement>): void {
|
||||||
|
setRemoteFileApiPort(Number(event.target.value) as number);
|
||||||
|
Settings.RemoteFileApiPort = Number(event.target.value);
|
||||||
|
}
|
||||||
|
|
||||||
const pages = {
|
const pages = {
|
||||||
[GameOptionsTab.SYSTEM]: (
|
[GameOptionsTab.SYSTEM]: (
|
||||||
<GameOptionsPage title="System">
|
<GameOptionsPage title="System">
|
||||||
@ -361,6 +370,35 @@ 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
|
||||||
|
InputProps={{
|
||||||
|
startAdornment: (
|
||||||
|
<Typography
|
||||||
|
color={remoteFileApiPort > 0 && remoteFileApiPort <= 65535? "success" : "error"}
|
||||||
|
>
|
||||||
|
Remote File API port:
|
||||||
|
</Typography>
|
||||||
|
),
|
||||||
|
endAdornment: (
|
||||||
|
<Box>
|
||||||
|
<Button onClick={newRemoteFileApiConnection}>Reconnect</Button>
|
||||||
|
<ConnectionBauble callback={isRemoteFileApiConnectionLive}/>
|
||||||
|
</Box>
|
||||||
|
),
|
||||||
|
}}
|
||||||
|
value={remoteFileApiPort}
|
||||||
|
onChange={handleRemoteFileApiPortChange}
|
||||||
|
placeholder="12525"
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
</GameOptionsPage>
|
</GameOptionsPage>
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
@ -77,26 +77,12 @@ export const RFARequestHandler: Record<string, (message: RFAMessage) => void | R
|
|||||||
return new RFAMessage({ result: "OK", id: msg.id });
|
return new RFAMessage({ result: "OK", id: msg.id });
|
||||||
},
|
},
|
||||||
|
|
||||||
getFileNames: function (msg: RFAMessage): RFAMessage {
|
getFileNames: function (msg: RFAMessage): RFAMessage {
|
||||||
if (!isFileServer(msg.params)) return error("getFileNames message misses parameters", msg);
|
if (!isFileServer(msg.params)) return error("getFileNames message misses parameters", msg);
|
||||||
|
|
||||||
const server = GetServer(msg.params.server);
|
const server = GetServer(msg.params.server);
|
||||||
if (server == null) return error("Server hostname invalid", msg);
|
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 });
|
|
||||||
},
|
|
||||||
|
|
||||||
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 fileNameList: string[] = [
|
const fileNameList: string[] = [
|
||||||
...server.textFiles.map((txt): string => txt.filename),
|
...server.textFiles.map((txt): string => txt.filename),
|
||||||
...server.scripts.map((scr): string => scr.filename)
|
...server.scripts.map((scr): string => scr.filename)
|
||||||
@ -105,6 +91,20 @@ export const RFARequestHandler: Record<string, (message: RFAMessage) => void | R
|
|||||||
return new RFAMessage({ result: JSON.stringify(fileNameList), id: msg.id });
|
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 {
|
calculateRam: function (msg: RFAMessage): RFAMessage {
|
||||||
if (!isFileLocation(msg.params)) return error("calculateRam message misses parameters", msg);
|
if (!isFileLocation(msg.params)) return error("calculateRam message misses parameters", msg);
|
||||||
const fileData: FileLocation = msg.params;
|
const fileData: FileLocation = msg.params;
|
||||||
|
@ -13,36 +13,18 @@ export class Remote {
|
|||||||
this.port = port;
|
this.port = port;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public stopConnection() : void {
|
||||||
|
this.connection?.close();
|
||||||
|
}
|
||||||
|
|
||||||
public startConnection() : void {
|
public startConnection() : void {
|
||||||
this.startConnectionRecurse(1, 5);
|
|
||||||
}
|
|
||||||
|
|
||||||
handleCloseEvent():void {
|
|
||||||
delete this.connection;
|
|
||||||
RFALogger.log("Connection closed.");
|
|
||||||
}
|
|
||||||
|
|
||||||
startConnectionRecurse(retryN : number, retryMax : number) : 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) => {
|
this.connection.addEventListener("error", (e:Event) => RFALogger.error(e));
|
||||||
if(!this.connection) return;
|
|
||||||
|
|
||||||
// When having trouble connecting, try again.
|
|
||||||
if (this.connection.readyState === 3) {
|
|
||||||
RFALogger.log(`Connection lost, retrying (try #${retryN}).`);
|
|
||||||
if (retryN <= retryMax) this.startConnectionRecurse(retryN + 1, retryMax);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Else handle the error normally
|
|
||||||
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", () => RFALogger.log("Connection established: ", this.ipaddr, ":", this.port));
|
||||||
this.connection.addEventListener("close", this.handleCloseEvent);
|
this.connection.addEventListener("close", () => RFALogger.log("Connection closed"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,16 +1,19 @@
|
|||||||
|
import { Settings } from "../Settings/Settings";
|
||||||
import { Remote } from "./Remote";
|
import { Remote } from "./Remote";
|
||||||
|
|
||||||
class RemoteFileAPI {
|
|
||||||
server : Remote;
|
|
||||||
|
|
||||||
constructor(){
|
let server: Remote;
|
||||||
this.server = new Remote("localhost", 12525);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
enable() : void {
|
export function newRemoteFileApiConnection() : void {
|
||||||
this.server.startConnection();
|
if(server == undefined)
|
||||||
|
server = new Remote("localhost", Settings.RemoteFileApiPort);
|
||||||
|
else {
|
||||||
|
server.stopConnection();
|
||||||
|
server = new Remote("localhost", Settings.RemoteFileApiPort);
|
||||||
|
server.startConnection();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const RFA = new RemoteFileAPI;
|
export function isRemoteFileApiConnectionLive() : boolean {
|
||||||
|
return server.connection != undefined && server.connection.readyState == 1;
|
||||||
|
}
|
||||||
|
@ -84,6 +84,11 @@ interface IDefaultSettings {
|
|||||||
*/
|
*/
|
||||||
MaxTerminalCapacity: number;
|
MaxTerminalCapacity: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Port the Remote File API client will try to connect to.
|
||||||
|
*/
|
||||||
|
RemoteFileApiPort: number;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Save the game when you save any file.
|
* Save the game when you save any file.
|
||||||
*/
|
*/
|
||||||
@ -206,6 +211,7 @@ export const defaultSettings: IDefaultSettings = {
|
|||||||
MaxLogCapacity: 50,
|
MaxLogCapacity: 50,
|
||||||
MaxPortCapacity: 50,
|
MaxPortCapacity: 50,
|
||||||
MaxTerminalCapacity: 500,
|
MaxTerminalCapacity: 500,
|
||||||
|
RemoteFileApiPort: 12525,
|
||||||
SaveGameOnFileSave: true,
|
SaveGameOnFileSave: true,
|
||||||
SuppressBuyAugmentationConfirmation: false,
|
SuppressBuyAugmentationConfirmation: false,
|
||||||
SuppressFactionInvites: false,
|
SuppressFactionInvites: false,
|
||||||
@ -248,6 +254,7 @@ export const Settings: ISettings & ISelfInitializer & ISelfLoading = {
|
|||||||
MaxTerminalCapacity: defaultSettings.MaxTerminalCapacity,
|
MaxTerminalCapacity: defaultSettings.MaxTerminalCapacity,
|
||||||
OwnedAugmentationsOrder: OwnedAugmentationsOrderSetting.AcquirementTime,
|
OwnedAugmentationsOrder: OwnedAugmentationsOrderSetting.AcquirementTime,
|
||||||
PurchaseAugmentationsOrder: PurchaseAugmentationsOrderSetting.Default,
|
PurchaseAugmentationsOrder: PurchaseAugmentationsOrderSetting.Default,
|
||||||
|
RemoteFileApiPort: defaultSettings.RemoteFileApiPort,
|
||||||
SaveGameOnFileSave: defaultSettings.SaveGameOnFileSave,
|
SaveGameOnFileSave: defaultSettings.SaveGameOnFileSave,
|
||||||
SuppressBuyAugmentationConfirmation: defaultSettings.SuppressBuyAugmentationConfirmation,
|
SuppressBuyAugmentationConfirmation: defaultSettings.SuppressBuyAugmentationConfirmation,
|
||||||
SuppressFactionInvites: defaultSettings.SuppressFactionInvites,
|
SuppressFactionInvites: defaultSettings.SuppressFactionInvites,
|
||||||
|
@ -5,7 +5,7 @@ import { TTheme as Theme, ThemeEvents, refreshTheme } from "./Themes/ui/Theme";
|
|||||||
import { LoadingScreen } from "./ui/LoadingScreen";
|
import { LoadingScreen } from "./ui/LoadingScreen";
|
||||||
import { initElectron } from "./Electron";
|
import { initElectron } from "./Electron";
|
||||||
|
|
||||||
import { RFA } from "./RemoteFileAPI/RemoteFileAPI";
|
import { newRemoteFileApiConnection } from "./RemoteFileAPI/RemoteFileAPI";
|
||||||
|
|
||||||
initElectron();
|
initElectron();
|
||||||
globalThis["React"] = React;
|
globalThis["React"] = React;
|
||||||
@ -17,8 +17,7 @@ ReactDOM.render(
|
|||||||
document.getElementById("root"),
|
document.getElementById("root"),
|
||||||
);
|
);
|
||||||
|
|
||||||
console.log("[RFA] Fix this hack ASAP");
|
newRemoteFileApiConnection();
|
||||||
RFA.enable();
|
|
||||||
|
|
||||||
function rerender(): void {
|
function rerender(): void {
|
||||||
refreshTheme();
|
refreshTheme();
|
||||||
|
Loading…
Reference in New Issue
Block a user