2022-03-15 20:41:23 -04:00
import { ArgError , ArgParser } from '/scripts/lib/arg-parser' ;
2022-03-22 14:18:56 -04:00
import { copyWithDependencies , scanNetwork } from '/scripts/lib/utils' ;
2022-03-15 20:41:23 -04:00
/ * *
* BitBurner autocomplete
* @ param data { server : string [ ] , txts : string [ ] , scripts : string [ ] , flags : string [ ] } - Contextual information
* @ returns { string [ ] } - Pool of autocomplete options
* /
export function autocomplete ( data ) {
return [ ... data . scripts , '{{TARGET}}' ] ;
}
2022-02-11 01:08:32 -05:00
2022-03-09 14:06:14 -05:00
/ * *
* Search the network for targets to execute a script against .
* @ param ns { NS } - BitBurner API
* /
export async function main ( ns ) {
2022-03-15 20:41:23 -04:00
// Setup
2022-03-09 14:06:14 -05:00
ns . disableLog ( 'ALL' ) ;
const argParser = new ArgParser ( 'crawler.js' , 'Search the network for targets to execute a script against.' , null , [
{ name : 'script' , desc : 'Script to copy & execute' , type : 'string' } ,
{ name : 'args' , desc : 'Arguments for script. Forward the current target with: {{TARGET}}' , optional : true , extras : true , type : 'string' } ,
2022-03-22 14:18:56 -04:00
{ name : 'cpu' , desc : 'Number of CPU threads to use with script' , flags : [ '-c' , '--cpu' ] , type : 'num' } ,
2022-03-09 14:06:14 -05:00
{ name : 'depth' , desc : 'Depth to scan to, defaults to 3' , flags : [ '-d' , '--depth' ] , default : Infinity , type : 'num' } ,
2022-03-22 14:18:56 -04:00
{ name : 'kill' , desc : 'Kill all scripts running on device' , flags : [ '-k' , '--kill' ] , type : 'bool' } ,
{ name : 'level' , desc : 'Exclude targets with higher hack level, defaults to current hack level' , flags : [ '--level' ] , default : ns . getHackingLevel ( ) , type : 'num' } ,
{ name : 'remoteExec' , desc : 'Copy script to remote device & run there' , flags : [ '-e' , '--remote-exec' ] , type : 'bool' } ,
2022-03-20 13:42:49 -04:00
{ name : 'rooted' , desc : 'Filter to devices that have been rooted' , flags : [ '-r' , '--rooted' ] , type : 'bool' } ,
{ name : 'notRooted' , desc : 'Filter to devices that have not been rooted' , flags : [ '-n' , '--not-rooted' ] , type : 'bool' } ,
{ name : 'ports' , desc : 'Exclude targets with too many closed ports' , flags : [ '-p' , '--ports' ] , default : Infinity , type : 'num' } ,
2022-03-22 14:18:56 -04:00
{ name : 'silent' , desc : 'Suppress program output' , flags : [ '-s' , '--silent' ] , type : 'bool' } ,
{ name : 'verbose' , desc : 'Display the device names in the final report' , flags : [ '-v' , '--verbose' ] , type : 'bool' } ,
2022-03-13 21:44:47 -04:00
] , true ) ;
2022-02-04 11:49:05 -05:00
2022-03-15 20:41:23 -04:00
try {
// Run
2022-03-22 14:18:56 -04:00
const localhost = ns . getHostname ( ) ;
2022-03-15 20:41:23 -04:00
const args = argParser . parse ( ns . args ) ;
const [ devices , network ] = scanNetwork ( ns ) ;
2022-03-22 14:18:56 -04:00
let complete = [ ] , failed = [ ] , skipped = [ ] ;
2022-03-15 20:41:23 -04:00
for ( let device of devices ) {
2022-03-20 13:42:49 -04:00
// Check root status if needed
const rooted = ns . hasRootAccess ( device ) ;
if ( args [ 'rooted' ] && ! rooted ) continue ;
if ( args [ 'notRooted' ] && rooted ) continue ;
2022-03-15 20:41:23 -04:00
// Skip invalid devices
if ( device == 'home' || args [ 'level' ] < ns . getServerRequiredHackingLevel ( device ) || args [ 'ports' ] < ns . getServerNumPortsRequired ( device ) ) {
2022-03-22 14:18:56 -04:00
skipped . push ( device ) ;
2022-03-15 20:41:23 -04:00
continue ;
}
2022-02-11 01:08:32 -05:00
2022-03-15 20:41:23 -04:00
// Start script
2022-03-22 14:18:56 -04:00
if ( args [ 'kill' ] ) ns . killall ( device ) ;
2022-03-15 20:41:23 -04:00
const scriptArgs = args [ 'args' ] . map ( arg => arg . toUpperCase ( ) == '{{TARGET}}' ? device : arg ) ;
2022-03-22 14:18:56 -04:00
const [ totalRam , usedRam ] = ns . getServerRam ( args [ 'remoteExec' ] ? device : localhost ) ;
const threads = args [ 'cpu' ] || ~ ~ ( ( totalRam - usedRam ) / ns . getScriptRam ( args [ 'script' ] , localhost ) ) || 1 ;
if ( args [ 'remoteExec' ] ) await copyWithDependencies ( ns , args [ 'script' ] , device ) ;
const pid = ns . exec ( args [ 'script' ] , args [ 'remoteExec' ] ? device : localhost , threads , ... scriptArgs ) ;
2022-03-15 20:41:23 -04:00
if ( pid == 0 ) {
2022-03-22 14:18:56 -04:00
failed . push ( device ) ;
2022-03-15 20:41:23 -04:00
continue ;
}
2022-02-11 01:08:32 -05:00
2022-03-22 14:18:56 -04:00
// Wait for script to finish if local
if ( ! args [ 'remoteExec' ] )
while ( ns . scriptRunning ( args [ 'script' ] , localhost ) ) await ns . sleep ( 1000 ) ;
complete . push ( device ) ;
2022-03-09 14:06:14 -05:00
}
2022-02-11 01:08:32 -05:00
2022-03-15 20:41:23 -04:00
// Output report
if ( ! args [ 'silent' ] ) {
ns . tprint ( '===================================================' ) ;
2022-03-22 14:18:56 -04:00
ns . tprint ( ` Crawler Report: ${ complete . length + failed . length + skipped . length } Devices ` ) ;
2022-03-15 20:41:23 -04:00
ns . tprint ( '===================================================' ) ;
2022-03-22 14:18:56 -04:00
if ( args [ 'verbose' ] ) {
ns . tprint ( ` Complete ( ${ complete . length } ): ` ) ;
if ( complete . length ) ns . tprint ( complete . join ( ', ' ) ) ;
ns . tprint ( '' ) ;
ns . tprint ( ` Failed ( ${ failed . length } ): ` ) ;
if ( failed . length ) ns . tprint ( failed . join ( ', ' ) ) ;
ns . tprint ( '' ) ;
ns . tprint ( ` Skipped ( ${ skipped . length } ): ` ) ;
if ( skipped . length ) ns . tprint ( skipped . join ( ', ' ) ) ;
ns . tprint ( '' ) ;
} else {
ns . tprint ( ` Complete: ${ complete . length } \t Failed: ${ failed . length } \t Skipped: ${ skipped . length } ` ) ;
ns . tprint ( '' ) ;
}
2022-03-09 14:06:14 -05:00
}
2022-03-15 20:41:23 -04:00
} catch ( err ) {
if ( err instanceof ArgError ) return ns . tprint ( argParser . help ( err . message ) ) ;
throw err ;
2022-02-11 01:08:32 -05:00
}
2022-02-04 11:49:05 -05:00
}