/** Start up script on all local and remote servers.
* @remarks
* Runs prefedined script on purchased and hackable servers with a
* specified target.
*
* @param {NS} ns - Netscript namespace
* @param {string} target - Server to hack
* @return {Promise<void>}
*/
import * as getServers from "getServers.js";
import { calcMaxThreads } from "upgradeServers.js";
import * as bestServers from "listBestServers.js";
// Logging
/** @ constant
* @ default
*/
const logFile = "/logs/startup.txt";
/** @ constant
* @ default
*/
const logMode = "w";
// Functions
/** Copy and run script
* @remarks
* Copy `_script` to `_server` and hack `_target` with `_threads` number of threads.
*
* @param {string} _script - script to copy and run
* @param {string} _server - server to copy script to and run on
* @param {number} _threads - number of threads of _script to run on _server
* @param {string} _target - server for _script to target
* @return {Promise<void>}
*/
export async function copyAndRun(ns, _script, _server, _threads, _target) {
await ns.scp(_script, _server);
if (!ns.hasRootAccess(_server)) {
// If no root access, use nuke() to get it.
ns.nuke(_server);
}
ns.exec(_script, _server, _threads, _target);
}
export function hackWithTool(ns, _server, _toolNum) {
/* Use tool specified by `_toolNum` to hack `_server`.
*
* Tools specified by listBestServers.tools
*/
switch (_toolNum) {
case 0:
ns.brutessh(_server);
break;
case 1:
ns.ftpcrack(_server);
break;
case 2:
ns.relaysmtp(_server);
break;
case 3:
ns.httpworm(_server);
break;
case 4:
ns.sqlinject(_server);
break;
default:
throw RangeError(`Unexpected value for _toolNum: ${_toolNum}`);
}
}
export async function startServers(ns, _script, _serverList, _target, _toolNum = null) {
/* For each server in `_serverList`:
* 1) Hack with `_toolNum` (if specified)
* 2) Copy and run `_script` specifying `_target` as a target
*/
for (let serv of _serverList) {
if (_toolNum) {
// If a tool is specified, use tools to gain access
if (!ns.hasRootAccess(serv)) {
// If no access, then use a tool to open it.
let i = _toolNum;
while (i >= 0) {
// Use all tools to open required number of ports
hackWithTool(ns, serv, i);
i--;
}
}
}
// Copy and run script on each server
let serverRam = ns.getServerMaxRam(serv);
if (serverRam === 0) {
continue; // Skip servers without RAM
}
let maxThreads = calcMaxThreads(ns, serv, _script, serverRam);
if (serv !== _target) {
// Only run if current server doesn't match the target server.
await copyAndRun(ns, _script, serv, maxThreads, _target);
} else {
await ns.write(logFile, `Server skipped: ${serv}\n`, "a");
}
}
}
export async function waitForTool(ns, _tool) {
await ns.write(logFile, `Waiting for ${_tool}\n`, "a");
while (!ns.fileExists(_tool)) {
// Wait until we acquire the `_tool` program
await ns.sleep(60000);
}
}
export async function main(ns) {
await ns.write(logFile, "Start startup.js\n", logMode);
// No args
if (ns.args.length === 0) {
throw TypeError("Empty args");
}
// Disable logging on these functions so it doesn't spam the logs
ns.disableLog("sleep");
// Constants and variables
let script = "earlyHackTemplate.js"; // Script to start
const servers = await getServers.main(ns); // Map of servers
const hackable = Array.from(Array(6), () => new Array()); // Hackable servers
let purchasedServers = ns.getPurchasedServers(); // Purchased servers
// Which server is being targeted
let target = ns.args[0];
// Determine hackable servers
bestServers.getHackable(ns, servers, hackable);
await ns.write(logFile, `Hackable servers: ${hackable.join(",\n")}\n`, "a");
// Start purchased servers
await startServers(ns, script, purchasedServers, target);
await ns.write(logFile, "Finished local servers.\n", "a");
// Start servers by port requirements
/* NOTE: Because there is an await inside the for loop, hackable.forEach(function(){})
* acts the same as a for-await-of loop outside an async function.
*
* hackable.forEach(async function(){}) also didn't resolve the syntax issue.
*
* More info:
* - https://github.com/nodejs/node/issues/21617
*/
let numPorts = 0; // Iterator for below loop
for (let serverList of hackable) {
await ns.write(logFile, `Server list: ${serverList}\n`, "a");
if (serverList.length === 0) {
continue; // Skip if there are no servers
}
let toolNum = numPorts;
if (numPorts > 0) {
toolNum = numPorts - 1; // Tools are zero indexed
}
let tool = bestServers.tools[toolNum];
switch (numPorts) {
case 0:
// No tools required
await startServers(ns, script, serverList, target);
await ns.write(logFile,
`Finished ${numPorts} port servers.\n`, "a");
break;
case 1:
await waitForTool(ns, tool);
await startServers(ns, script, serverList, target, toolNum);
await ns.write(logFile,
`Finished ${numPorts} port servers.\n`, "a");
break;
case 2:
await waitForTool(ns, tool);
await startServers(ns, script, serverList, target, toolNum);
await ns.write(logFile,
`Finished ${numPorts} port servers.\n`, "a");
break;
case 3:
await waitForTool(ns, tool);
await startServers(ns, script, serverList, target, toolNum);
await ns.write(logFile, `Finished ${numPorts} port servers.\n`, "a");
break;
case 4:
await waitForTool(ns, tool);
await startServers(ns, script, serverList, target, toolNum);
await ns.write(logFile, `Finished ${numPorts} port servers.\n`, "a");
break;
case 5:
await waitForTool(ns, tool);
await startServers(ns, script, serverList, target, toolNum);
await ns.write(logFile, `Finished ${numPorts} port servers.\n`, "a");
break;
default:
throw RangeError(`Unexpected value for numPorts: ${numPorts}`);
}
numPorts++;
}
await ns.write(logFile, "End startup.js\n", "a");
ns.tprint("startup.js Done.");
}