mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2025-03-11 04:42:34 +01:00
Did some changes of the remote api and added documentation
This commit is contained in:
@ -24,6 +24,7 @@ secrets that you've been searching for.
|
||||
Basic documentation <netscript>
|
||||
Basic Gameplay <basicgameplay>
|
||||
Advanced Gameplay <advancedgameplay>
|
||||
Remote API <remoteapi.rst>
|
||||
Keyboard Shortcuts <shortcuts>
|
||||
Game Frozen or Stuck? <gamefrozen>
|
||||
Guides & Tips <guidesandtips>
|
||||
|
203
doc/source/remoteapi.rst
Normal file
203
doc/source/remoteapi.rst
Normal file
@ -0,0 +1,203 @@
|
||||
|
||||
Remote API
|
||||
==========
|
||||
|
||||
All versions of Bitburner can use websockets to connect to a server.
|
||||
That server can then perform a number of actions.
|
||||
Most commonly this is used in conjunction with an external text editor or API
|
||||
in order to make writing scripts easier, or even use typescript.
|
||||
|
||||
This API uses the JSON RCP 2.0 protocol. Inputs are in the following form:
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": number,
|
||||
"method": string,
|
||||
"params": any
|
||||
}
|
||||
|
||||
Outputs:
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": number,
|
||||
"result": any,
|
||||
"error": any
|
||||
}
|
||||
|
||||
|
||||
Methods
|
||||
-------
|
||||
|
||||
`pushFile`
|
||||
^^^^^^^^^^
|
||||
Create or update a file.
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": number,
|
||||
"method": "pushFile",
|
||||
"params": {
|
||||
filename: string;
|
||||
content: string;
|
||||
server: string;
|
||||
}
|
||||
}
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": number,
|
||||
"result": "OK"
|
||||
}
|
||||
|
||||
`getFile`
|
||||
^^^^^^^^^
|
||||
Read a file and it's content.
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": number,
|
||||
"method": "getFile",
|
||||
"params": {
|
||||
filename: string;
|
||||
server: string;
|
||||
}
|
||||
}
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": number,
|
||||
"result": string
|
||||
}
|
||||
|
||||
`deleteFile`
|
||||
^^^^^^^^^^^^
|
||||
Delete a file.
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": number,
|
||||
"method": "deleteFile",
|
||||
"params": {
|
||||
filename: string;
|
||||
server: string;
|
||||
}
|
||||
}
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": number,
|
||||
"result": "OK"
|
||||
}
|
||||
|
||||
`getFileNames`
|
||||
^^^^^^^^^^^^^^
|
||||
List all file names on a server.
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": number,
|
||||
"method": "getFileNames",
|
||||
"params": {
|
||||
server: string;
|
||||
}
|
||||
}
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": number,
|
||||
"result": string[]
|
||||
}
|
||||
|
||||
`getAllFiles`
|
||||
^^^^^^^^^^^^^
|
||||
Get the content of all files on a server.
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": number,
|
||||
"method": "getAllFiles",
|
||||
"params": {
|
||||
server: string;
|
||||
}
|
||||
}
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": number,
|
||||
"result": {
|
||||
filename: string,
|
||||
content: string
|
||||
}[]
|
||||
}
|
||||
|
||||
`calculateRam`
|
||||
^^^^^^^^^^^^^^
|
||||
Calculate the in-game ram cost of a script.
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": number,
|
||||
"method": "calculateRam",
|
||||
"params": {
|
||||
filename: string;
|
||||
server: string;
|
||||
}
|
||||
}
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": number,
|
||||
"result": number
|
||||
}
|
||||
|
||||
|
||||
`getDefinitionFile`
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
Get the definition file of the API.
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": number,
|
||||
"method": "getDefinitionFile"
|
||||
}
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": number,
|
||||
"result": string
|
||||
}
|
||||
|
||||
|
@ -3,4 +3,5 @@ export enum GameOptionsTab {
|
||||
INTERFACE,
|
||||
GAMEPLAY,
|
||||
MISC,
|
||||
REMOTE_API,
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
import { Typography } from "@mui/material";
|
||||
import React, { useState, useEffect } from "react";
|
||||
import WifiIcon from "@mui/icons-material/Wifi";
|
||||
import WifiOffIcon from "@mui/icons-material/WifiOff";
|
||||
|
||||
interface baubleProps {
|
||||
isConnected: () => boolean;
|
||||
@ -15,5 +17,24 @@ export const ConnectionBauble = (props: baubleProps): React.ReactElement => {
|
||||
return () => clearInterval(timer);
|
||||
});
|
||||
|
||||
return <Typography>{connection ? "Connected" : "Disconnected"}</Typography>;
|
||||
return (
|
||||
<>
|
||||
<Typography>
|
||||
Status:
|
||||
<Typography component="span" color={connection ? "primary" : "error"}>
|
||||
{connection ? (
|
||||
<>
|
||||
Online
|
||||
<WifiIcon />
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
Offline
|
||||
<WifiOffIcon />
|
||||
</>
|
||||
)}
|
||||
</Typography>
|
||||
</Typography>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { MenuItem, Select, SelectChangeEvent, TextField, Tooltip, Typography, Box } from "@mui/material";
|
||||
import { MenuItem, Select, SelectChangeEvent, TextField, Tooltip, Typography, Link } from "@mui/material";
|
||||
import React, { useState } from "react";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { isRemoteFileApiConnectionLive, newRemoteFileApiConnection } from "../../RemoteFileAPI/RemoteFileAPI";
|
||||
@ -370,12 +370,25 @@ export const CurrentOptionsPage = (props: IProps): React.ReactElement => {
|
||||
</>
|
||||
}
|
||||
/>
|
||||
</GameOptionsPage>
|
||||
),
|
||||
[GameOptionsTab.REMOTE_API]: (
|
||||
<GameOptionsPage title="Remote API">
|
||||
<Typography>
|
||||
These settings control the Remote API for bitburner. This is typically used to write scripts using an external
|
||||
text editor and then upload files to the home server.
|
||||
</Typography>
|
||||
<Typography>
|
||||
<Link href="#" target="_blank">
|
||||
Documentation
|
||||
</Link>
|
||||
</Typography>
|
||||
<ConnectionBauble isConnected={isRemoteFileApiConnectionLive} />
|
||||
<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.
|
||||
This port number is used to connect to a Remote API port, please ensure that it matches with your Remote
|
||||
API server port. Set to 0 to disable the feature.
|
||||
</Typography>
|
||||
}
|
||||
>
|
||||
@ -383,15 +396,10 @@ export const CurrentOptionsPage = (props: IProps): React.ReactElement => {
|
||||
InputProps={{
|
||||
startAdornment: (
|
||||
<Typography color={remoteFileApiPort > 0 && remoteFileApiPort <= 65535 ? "success" : "error"}>
|
||||
Remote File API port:
|
||||
Port:
|
||||
</Typography>
|
||||
),
|
||||
endAdornment: (
|
||||
<Box>
|
||||
<Button onClick={newRemoteFileApiConnection}>Reconnect</Button>
|
||||
<ConnectionBauble isConnected={isRemoteFileApiConnectionLive} />
|
||||
</Box>
|
||||
),
|
||||
endAdornment: <Button onClick={newRemoteFileApiConnection}>Connect</Button>,
|
||||
}}
|
||||
value={remoteFileApiPort}
|
||||
onChange={handleRemoteFileApiPortChange}
|
||||
|
@ -107,6 +107,7 @@ export const GameOptionsSidebar = (props: IProps): React.ReactElement => {
|
||||
<SideBarTab sideBarProps={props} tab={GameOptionsTab.GAMEPLAY} tabName="Gameplay" />
|
||||
<SideBarTab sideBarProps={props} tab={GameOptionsTab.INTERFACE} tabName="Interface" />
|
||||
<SideBarTab sideBarProps={props} tab={GameOptionsTab.MISC} tabName="Misc" />
|
||||
<SideBarTab sideBarProps={props} tab={GameOptionsTab.REMOTE_API} tabName="Remote API" />
|
||||
</List>
|
||||
</Paper>
|
||||
<Box
|
||||
|
@ -1,12 +1,14 @@
|
||||
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 result?: string | number; // 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 } = {}) {
|
||||
constructor(
|
||||
obj: { method?: string; result?: string | number; params?: FileMetadata; error?: string; id?: number } = {},
|
||||
) {
|
||||
this.method = obj.method;
|
||||
this.result = obj.result;
|
||||
this.params = obj.params;
|
||||
|
@ -12,12 +12,10 @@ import {
|
||||
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 {
|
||||
RFALogger.error((typeof id === "undefined" ? "" : `Request ${id}: `) + errorMsg);
|
||||
return new RFAMessage({ error: errorMsg, id: id });
|
||||
}
|
||||
|
||||
@ -129,12 +127,11 @@ export const RFARequestHandler: Record<string, (message: RFAMessage) => void | R
|
||||
if (!script) return error("File doesn't exist", msg);
|
||||
const ramUsage = script.ramUsage;
|
||||
|
||||
return new RFAMessage({ result: String(ramUsage), id: msg.id });
|
||||
return new RFAMessage({ result: 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 +0,0 @@
|
||||
class RemoteFileAPILogger {
|
||||
_enabled = true;
|
||||
_prefix = "[RFA]";
|
||||
_error_prefix = "[RFA-ERROR]";
|
||||
|
||||
constructor(enabled: boolean) {
|
||||
this._enabled = enabled;
|
||||
}
|
||||
|
||||
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 disable(): void {
|
||||
this._enabled = false;
|
||||
}
|
||||
|
||||
public enable(): void {
|
||||
this._enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
export const RFALogger = new RemoteFileAPILogger(true);
|
@ -1,10 +1,10 @@
|
||||
import { RFALogger } from "./RFALogger";
|
||||
import { RFAMessage } from "./MessageDefinitions";
|
||||
import { RFARequestHandler } from "./MessageHandlers";
|
||||
import { SnackbarEvents, ToastVariant } from "../ui/React/Snackbar";
|
||||
|
||||
export class Remote {
|
||||
connection?: WebSocket;
|
||||
protocol = "ws";
|
||||
static protocol = "ws";
|
||||
ipaddr: string;
|
||||
port: number;
|
||||
|
||||
@ -18,32 +18,35 @@ export class Remote {
|
||||
}
|
||||
|
||||
public startConnection(): void {
|
||||
RFALogger.log("Trying to connect.");
|
||||
this.connection = new WebSocket(this.protocol + "://" + this.ipaddr + ":" + this.port);
|
||||
const address = Remote.protocol + "://" + this.ipaddr + ":" + this.port;
|
||||
this.connection = new WebSocket(address);
|
||||
|
||||
this.connection.addEventListener("error", (e: Event) => RFALogger.error(e));
|
||||
this.connection.addEventListener("error", (e: Event) =>
|
||||
SnackbarEvents.emit(`Error with websocket ${address}, details: ${JSON.stringify(e)}`, ToastVariant.ERROR, 5000),
|
||||
);
|
||||
this.connection.addEventListener("message", handleMessageEvent);
|
||||
this.connection.addEventListener("open", () =>
|
||||
RFALogger.log("Connection established: ", this.ipaddr, ":", this.port),
|
||||
SnackbarEvents.emit(
|
||||
`Remote API connection established on ${this.ipaddr}:${this.port}`,
|
||||
ToastVariant.SUCCESS,
|
||||
2000,
|
||||
),
|
||||
);
|
||||
this.connection.addEventListener("close", () =>
|
||||
SnackbarEvents.emit("Remote API connection closed", ToastVariant.WARNING, 2000),
|
||||
);
|
||||
this.connection.addEventListener("close", () => RFALogger.log("Connection closed"));
|
||||
}
|
||||
}
|
||||
|
||||
function handleMessageEvent(this: WebSocket, e: MessageEvent): void {
|
||||
const msg: RFAMessage = JSON.parse(e.data);
|
||||
RFALogger.log("Message received:", 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);
|
||||
if (!msg.method || !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);
|
||||
if (!response) return;
|
||||
this.send(JSON.stringify(response));
|
||||
}
|
||||
|
@ -4,14 +4,9 @@ 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();
|
||||
}
|
||||
if (server) server.stopConnection();
|
||||
server = new Remote("localhost", Settings.RemoteFileApiPort);
|
||||
server.startConnection();
|
||||
}
|
||||
|
||||
export function isRemoteFileApiConnectionLive(): boolean {
|
||||
|
@ -211,7 +211,7 @@ export const defaultSettings: IDefaultSettings = {
|
||||
MaxLogCapacity: 50,
|
||||
MaxPortCapacity: 50,
|
||||
MaxTerminalCapacity: 500,
|
||||
RemoteFileApiPort: 12525,
|
||||
RemoteFileApiPort: 0,
|
||||
SaveGameOnFileSave: true,
|
||||
SuppressBuyAugmentationConfirmation: false,
|
||||
SuppressFactionInvites: false,
|
||||
|
@ -17,7 +17,7 @@ ReactDOM.render(
|
||||
document.getElementById("root"),
|
||||
);
|
||||
|
||||
newRemoteFileApiConnection();
|
||||
setTimeout(newRemoteFileApiConnection, 2000);
|
||||
|
||||
function rerender(): void {
|
||||
refreshTheme();
|
||||
|
Reference in New Issue
Block a user