bitburner-src/src/Server/BaseServer.ts

306 lines
8.6 KiB
TypeScript
Raw Normal View History

2019-03-25 04:03:24 +01:00
/**
* Abstract Base Class for any Server object
*/
import { CodingContract } from "../CodingContracts";
import { RunningScript } from "../Script/RunningScript";
import { Script } from "../Script/Script";
import { isValidFilePath } from "../Terminal/DirectoryHelpers";
2019-03-25 04:03:24 +01:00
import { TextFile } from "../TextFile";
import { IReturnStatus } from "../types";
2019-03-25 04:03:24 +01:00
2021-09-24 22:34:21 +02:00
import { isScriptFilename } from "../Script/isScriptFilename";
2019-03-25 04:03:24 +01:00
2021-09-25 20:42:57 +02:00
import { createRandomIp } from "../utils/IPAddress";
import { compareArrays } from "../utils/helpers/compareArrays";
2021-11-16 05:49:33 +01:00
import { IPlayer } from "../PersonObjects/IPlayer";
2019-03-25 04:03:24 +01:00
interface IConstructorParams {
2021-09-05 01:09:30 +02:00
adminRights?: boolean;
hostname: string;
ip?: string;
isConnectedTo?: boolean;
maxRam?: number;
organizationName?: string;
2019-03-25 04:03:24 +01:00
}
2021-05-01 09:17:31 +02:00
interface writeResult {
2021-09-05 01:09:30 +02:00
success: boolean;
overwritten: boolean;
2021-05-01 09:17:31 +02:00
}
export class BaseServer {
2021-09-05 01:09:30 +02:00
// Coding Contract files on this server
contracts: CodingContract[] = [];
2019-03-25 04:03:24 +01:00
2021-09-05 01:09:30 +02:00
// How many CPU cores this server has. Maximum of 8.
// Currently, this only affects hacking missions
cpuCores = 1;
2019-03-25 04:03:24 +01:00
2021-09-05 01:09:30 +02:00
// Flag indicating whether the FTP port is open
ftpPortOpen = false;
2019-03-25 04:03:24 +01:00
2021-09-05 01:09:30 +02:00
// Flag indicating whether player has admin/root access to this server
hasAdminRights = false;
2019-03-25 04:03:24 +01:00
2021-09-05 01:09:30 +02:00
// Hostname. Must be unique
hostname = "";
2019-03-25 04:03:24 +01:00
2021-09-05 01:09:30 +02:00
// Flag indicating whether HTTP Port is open
httpPortOpen = false;
2019-03-25 04:03:24 +01:00
2021-09-05 01:09:30 +02:00
// IP Address. Must be unique
ip = "";
2019-03-25 04:03:24 +01:00
2021-09-05 01:09:30 +02:00
// Flag indicating whether player is curently connected to this server
isConnectedTo = false;
2019-03-25 04:03:24 +01:00
2021-09-05 01:09:30 +02:00
// RAM (GB) available on this server
maxRam = 0;
2019-03-25 04:03:24 +01:00
2021-09-05 01:09:30 +02:00
// Message files AND Literature files on this Server
2021-10-14 08:07:05 +02:00
messages: string[] = [];
2019-03-25 04:03:24 +01:00
2021-09-05 01:09:30 +02:00
// Name of company/faction/etc. that this server belongs to.
// Optional, not applicable to all Servers
organizationName = "";
2019-03-25 04:03:24 +01:00
2021-09-05 01:09:30 +02:00
// Programs on this servers. Contains only the names of the programs
programs: string[] = [];
2019-03-25 04:03:24 +01:00
2021-09-05 01:09:30 +02:00
// RAM (GB) used. i.e. unavailable RAM
ramUsed = 0;
2019-03-25 04:03:24 +01:00
2021-09-05 01:09:30 +02:00
// RunningScript files on this server
runningScripts: RunningScript[] = [];
2019-03-25 04:03:24 +01:00
2021-09-05 01:09:30 +02:00
// Script files on this Server
scripts: Script[] = [];
2019-03-25 04:03:24 +01:00
2022-03-17 14:50:23 +01:00
// Contains the hostnames of all servers that are immediately
2021-09-05 01:09:30 +02:00
// reachable from this one
serversOnNetwork: string[] = [];
2019-03-25 04:03:24 +01:00
2021-09-05 01:09:30 +02:00
// Flag indicating whether SMTP Port is open
smtpPortOpen = false;
2019-03-25 04:03:24 +01:00
2021-09-05 01:09:30 +02:00
// Flag indicating whether SQL Port is open
sqlPortOpen = false;
2019-03-25 04:03:24 +01:00
2021-09-05 01:09:30 +02:00
// Flag indicating whether the SSH Port is open
sshPortOpen = false;
2019-03-25 04:03:24 +01:00
2021-09-05 01:09:30 +02:00
// Text files on this server
textFiles: TextFile[] = [];
2019-03-25 04:03:24 +01:00
2021-11-11 23:00:36 +01:00
// Flag indicating wehther this is a purchased server
purchasedByPlayer = false;
2021-09-09 05:47:34 +02:00
constructor(params: IConstructorParams = { hostname: "", ip: createRandomIp() }) {
2021-09-05 01:09:30 +02:00
this.ip = params.ip ? params.ip : createRandomIp();
2019-03-25 04:03:24 +01:00
2021-09-05 01:09:30 +02:00
this.hostname = params.hostname;
2021-09-09 05:47:34 +02:00
this.organizationName = params.organizationName != null ? params.organizationName : "";
this.isConnectedTo = params.isConnectedTo != null ? params.isConnectedTo : false;
2019-03-25 04:03:24 +01:00
2021-09-05 01:09:30 +02:00
//Access information
2021-09-09 05:47:34 +02:00
this.hasAdminRights = params.adminRights != null ? params.adminRights : false;
2021-09-05 01:09:30 +02:00
}
2019-03-25 04:03:24 +01:00
2021-09-05 01:09:30 +02:00
addContract(contract: CodingContract): void {
this.contracts.push(contract);
}
2019-03-25 04:03:24 +01:00
2021-09-05 01:09:30 +02:00
getContract(contractName: string): CodingContract | null {
for (const contract of this.contracts) {
if (contract.fn === contractName) {
return contract;
}
2019-03-25 04:03:24 +01:00
}
2021-09-05 01:09:30 +02:00
return null;
}
/**
* Find an actively running script on this server
* @param scriptName - Filename of script to search for
* @param scriptArgs - Arguments that script is being run with
* @returns RunningScript for the specified active script
* Returns null if no such script can be found
*/
2021-09-09 05:47:34 +02:00
getRunningScript(scriptName: string, scriptArgs: any[]): RunningScript | null {
2021-09-05 01:09:30 +02:00
for (const rs of this.runningScripts) {
if (rs.filename === scriptName && compareArrays(rs.args, scriptArgs)) {
return rs;
}
}
2021-09-05 01:09:30 +02:00
return null;
}
/**
* Given the name of the script, returns the corresponding
* Script object on the server (if it exists)
*/
getScript(scriptName: string): Script | null {
for (let i = 0; i < this.scripts.length; i++) {
if (this.scripts[i].filename === scriptName) {
return this.scripts[i];
}
2019-03-25 04:03:24 +01:00
}
2021-09-05 01:09:30 +02:00
return null;
}
/**
* Returns boolean indicating whether the given script is running on this server
*/
isRunning(fn: string): boolean {
for (const runningScriptObj of this.runningScripts) {
if (runningScriptObj.filename === fn) {
return true;
}
}
2021-09-05 01:09:30 +02:00
return false;
}
removeContract(contract: CodingContract): void {
if (contract instanceof CodingContract) {
this.contracts = this.contracts.filter((c) => {
return c.fn !== contract.fn;
});
} else {
this.contracts = this.contracts.filter((c) => {
return c.fn !== contract;
});
2019-03-25 04:03:24 +01:00
}
2021-09-05 01:09:30 +02:00
}
/**
* Remove a file from the server
* @param fn {string} Name of file to be deleted
* @returns {IReturnStatus} Return status object indicating whether or not file was deleted
*/
removeFile(fn: string): IReturnStatus {
2021-09-09 05:47:34 +02:00
if (fn.endsWith(".exe") || fn.match(/^.+\.exe-\d+(?:\.\d*)?%-INC$/) != null) {
2021-09-05 01:09:30 +02:00
for (let i = 0; i < this.programs.length; ++i) {
if (this.programs[i] === fn) {
this.programs.splice(i, 1);
return { res: true };
}
2021-09-05 01:09:30 +02:00
}
} else if (isScriptFilename(fn)) {
for (let i = 0; i < this.scripts.length; ++i) {
if (this.scripts[i].filename === fn) {
if (this.isRunning(fn)) {
return {
res: false,
msg: "Cannot delete a script that is currently running!",
};
}
this.scripts.splice(i, 1);
return { res: true };
}
}
} else if (fn.endsWith(".lit")) {
for (let i = 0; i < this.messages.length; ++i) {
const f = this.messages[i];
if (typeof f === "string" && f === fn) {
this.messages.splice(i, 1);
return { res: true };
}
}
} else if (fn.endsWith(".txt")) {
for (let i = 0; i < this.textFiles.length; ++i) {
if (this.textFiles[i].fn === fn) {
this.textFiles.splice(i, 1);
return { res: true };
}
}
} else if (fn.endsWith(".cct")) {
for (let i = 0; i < this.contracts.length; ++i) {
if (this.contracts[i].fn === fn) {
this.contracts.splice(i, 1);
return { res: true };
}
}
2019-03-25 04:03:24 +01:00
}
2021-09-05 01:09:30 +02:00
return { res: false, msg: "No such file exists" };
}
/**
* Called when a script is run on this server.
* All this function does is add a RunningScript object to the
* `runningScripts` array. It does NOT check whether the script actually can
* be run.
*/
runScript(script: RunningScript): void {
this.runningScripts.push(script);
}
setMaxRam(ram: number): void {
this.maxRam = ram;
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
2021-11-16 05:49:33 +01:00
updateRamUsed(ram: number, player: IPlayer): void {
this.ramUsed = ram;
}
2021-09-05 01:09:30 +02:00
/**
* Write to a script file
* Overwrites existing files. Creates new files if the script does not eixst
*/
2022-01-05 01:09:34 +01:00
writeToScriptFile(player: IPlayer, fn: string, code: string): writeResult {
2021-09-05 01:09:30 +02:00
const ret = { success: false, overwritten: false };
if (!isValidFilePath(fn) || !isScriptFilename(fn)) {
return ret;
2019-03-25 04:03:24 +01:00
}
2021-09-05 01:09:30 +02:00
// Check if the script already exists, and overwrite it if it does
for (let i = 0; i < this.scripts.length; ++i) {
if (fn === this.scripts[i].filename) {
const script = this.scripts[i];
script.code = code;
2022-01-05 01:09:34 +01:00
script.updateRamUsage(player, this.scripts);
2021-09-05 01:09:30 +02:00
script.markUpdated();
ret.overwritten = true;
2019-03-25 04:03:24 +01:00
ret.success = true;
return ret;
2021-09-05 01:09:30 +02:00
}
2019-03-25 04:03:24 +01:00
}
2021-09-05 01:09:30 +02:00
// Otherwise, create a new script
2022-01-05 01:09:34 +01:00
const newScript = new Script(player, fn, code, this.hostname, this.scripts);
2021-09-05 01:09:30 +02:00
this.scripts.push(newScript);
ret.success = true;
return ret;
}
// Write to a text file
// Overwrites existing files. Creates new files if the text file does not exist
writeToTextFile(fn: string, txt: string): writeResult {
const ret = { success: false, overwritten: false };
if (!isValidFilePath(fn) || !fn.endsWith("txt")) {
return ret;
}
2019-03-25 04:03:24 +01:00
2021-09-05 01:09:30 +02:00
// Check if the text file already exists, and overwrite if it does
for (let i = 0; i < this.textFiles.length; ++i) {
if (this.textFiles[i].fn === fn) {
ret.overwritten = true;
this.textFiles[i].text = txt;
2019-03-25 04:03:24 +01:00
ret.success = true;
return ret;
2021-09-05 01:09:30 +02:00
}
2019-03-25 04:03:24 +01:00
}
2021-09-05 01:09:30 +02:00
// Otherwise create a new text file
const newFile = new TextFile(fn, txt);
this.textFiles.push(newFile);
ret.success = true;
return ret;
}
2019-03-25 04:03:24 +01:00
}