2022-01-15 23:24:37 +00:00
use crate ::settings ::* ;
2022-07-07 03:15:51 +00:00
use crate ::* ;
2022-03-10 16:10:11 +00:00
use clap ::{ Arg , ArgMatches , Command } ;
2022-01-19 02:21:11 +00:00
use std ::ffi ::OsStr ;
2022-05-17 20:55:53 +00:00
use std ::path ::Path ;
2022-01-15 23:24:37 +00:00
use std ::str ::FromStr ;
2022-05-16 15:52:48 +00:00
use veilid_core ::{ DHTKey , DHTKeySecret } ;
2022-01-15 23:24:37 +00:00
fn do_clap_matches ( default_config_path : & OsStr ) -> Result < clap ::ArgMatches , clap ::Error > {
2022-03-10 16:10:11 +00:00
let matches = Command ::new ( " veilid-server " )
2022-01-15 23:24:37 +00:00
. version ( " 0.1 " )
. about ( " Veilid Server " )
. color ( clap ::ColorChoice ::Auto )
. arg (
Arg ::new ( " daemon " )
. long ( " daemon " )
. short ( 'd' )
. help ( " Run in daemon mode in the background " ) ,
)
2022-05-18 14:17:04 +00:00
. arg (
Arg ::new ( " foreground " )
. long ( " foreground " )
. short ( 'f' )
. conflicts_with ( " daemon " )
. help ( " Run in the foreground " ) ,
)
2022-01-15 23:24:37 +00:00
. arg (
Arg ::new ( " config-file " )
. short ( 'c' )
. long ( " config-file " )
. takes_value ( true )
. value_name ( " FILE " )
. default_value_os ( default_config_path )
2022-01-19 02:21:11 +00:00
. allow_invalid_utf8 ( true )
2022-01-15 23:24:37 +00:00
. help ( " Specify a configuration file to use " ) ,
2022-06-08 15:18:17 +00:00
)
. arg (
Arg ::new ( " set-config " )
. short ( 's' )
. long ( " set-config " )
. takes_value ( true )
. multiple_occurrences ( true )
. help ( " Specify configuration value to set (key in dot format, value in json format), eg: logging.api.enabled=true " )
)
. arg (
2022-01-15 23:24:37 +00:00
Arg ::new ( " attach " )
. long ( " attach " )
. takes_value ( true )
. value_name ( " BOOL " )
. possible_values ( & [ " false " , " true " ] )
. help ( " Automatically attach the server to the Veilid network " ) ,
)
// Dev options
. arg (
Arg ::new ( " debug " )
. long ( " debug " )
. help ( " Turn on debug logging on the terminal " ) ,
)
. arg (
Arg ::new ( " trace " )
. long ( " trace " )
. conflicts_with ( " debug " )
. help ( " Turn on trace logging on the terminal " ) ,
)
2022-06-11 22:47:58 +00:00
. arg (
Arg ::new ( " otlp " )
. long ( " otlp " )
. takes_value ( true )
. value_name ( " endpoint " )
2022-06-15 19:03:13 +00:00
. default_missing_value ( " localhost:4317 " )
2022-06-26 17:51:55 +00:00
. help ( " Turn on OpenTelemetry tracing " )
. long_help ( " This option uses the GRPC OpenTelemetry protocol, not HTTP. The format for the endpoint is host:port, like 'localhost:4317' " ) ,
2022-06-11 22:47:58 +00:00
)
2022-01-15 23:24:37 +00:00
. arg (
2022-05-16 15:52:48 +00:00
Arg ::new ( " subnode-index " )
. long ( " subnode-index " )
2022-01-15 23:24:37 +00:00
. takes_value ( true )
. help ( " Run as an extra daemon on the same machine for testing purposes, specify a number greater than zero to offset the listening ports " ) ,
)
. arg (
Arg ::new ( " generate-dht-key " )
. long ( " generate-dht-key " )
. help ( " Only generate a new dht key and print it " ) ,
)
2022-05-16 15:52:48 +00:00
. arg (
Arg ::new ( " set-node-id " )
. long ( " set-node-id " )
. takes_value ( true )
. value_name ( " ID " )
. help ( " Set the node id and secret key " )
. long_help ( " To specify both node id and secret key on the command line, use a ID:SECRET syntax with a colon, like: \n zsVXz5aTU98vZxwTcDmvpcnO5g1B2jRO3wpdNiDrRgw:gJzQLmzuBvA-dFvEmLcYvLoO5bh7hzCWFzfpJHapZKg \n If no colon is used, the node id is specified, and a prompt appears to enter the secret key interactively. " )
)
2022-01-19 02:21:11 +00:00
. arg (
Arg ::new ( " delete-protected-store " )
. long ( " delete-protected-store " )
. help ( " Delete the entire contents of the protected store (DANGER, NO UNDO!) " ) ,
)
. arg (
Arg ::new ( " delete-table-store " )
. long ( " delete-table-store " )
. help ( " Delete the entire contents of the table store (DANGER, NO UNDO!) " ) ,
)
. arg (
Arg ::new ( " delete-block-store " )
. long ( " delete-block-store " )
. help ( " Delete the entire contents of the block store (DANGER, NO UNDO!) " ) ,
)
2022-01-15 23:24:37 +00:00
. arg (
Arg ::new ( " dump-config " )
. long ( " dump-config " )
. help ( " Instead of running the server, print the configuration it would use to the console " ) ,
)
2022-05-16 15:52:48 +00:00
. arg (
Arg ::new ( " dump-txt-record " )
. long ( " dump-txt-record " )
. help ( " Prints the bootstrap TXT record for this node and then quits " )
)
2022-01-15 23:24:37 +00:00
. arg (
Arg ::new ( " bootstrap " )
. long ( " bootstrap " )
. takes_value ( true )
. value_name ( " BOOTSTRAP_LIST " )
2022-05-16 15:52:48 +00:00
. help ( " Specify a list of bootstrap hostnames to use " )
)
. arg (
Arg ::new ( " bootstrap-nodes " )
. conflicts_with ( " bootstrap " )
. long ( " bootstrap-nodes " )
. takes_value ( true )
. value_name ( " BOOTSTRAP_NODE_LIST " )
. help ( " Specify a list of bootstrap node dialinfos to use " ) ,
2022-01-15 23:24:37 +00:00
)
. arg (
Arg ::new ( " local " )
. long ( " local " )
. help ( " Enable local peer scope " )
) ;
2022-01-19 02:21:11 +00:00
#[ cfg(debug_assertions) ]
let matches = matches . arg (
Arg ::new ( " wait-for-debug " )
. long ( " wait-for-debug " )
. help ( " Wait for debugger to attach " ) ,
) ;
2022-01-15 23:24:37 +00:00
Ok ( matches . get_matches ( ) )
}
2022-07-07 03:15:51 +00:00
pub fn process_command_line ( ) -> EyreResult < ( Settings , ArgMatches ) > {
2022-01-15 23:24:37 +00:00
// Get command line options
let default_config_path = Settings ::get_default_config_path ( ) ;
let matches = do_clap_matches ( default_config_path . as_os_str ( ) )
2022-07-07 03:15:51 +00:00
. wrap_err ( " failed to parse command line: {} " ) ? ;
2022-01-15 23:24:37 +00:00
// Check for one-off commands
#[ cfg(debug_assertions) ]
if matches . occurrences_of ( " wait-for-debug " ) ! = 0 {
use bugsalot ::debugger ;
debugger ::wait_until_attached ( None ) . expect ( " state() not implemented on this platform " ) ;
}
// Attempt to load configuration
2022-05-17 20:55:53 +00:00
let settings_path = if let Some ( config_file ) = matches . value_of_os ( " config-file " ) {
if Path ::new ( config_file ) . exists ( ) {
Some ( config_file )
} else {
None
}
2022-03-10 16:10:11 +00:00
} else {
2022-05-17 20:55:53 +00:00
None
} ;
2022-07-07 03:15:51 +00:00
let settings = Settings ::new ( settings_path ) . wrap_err ( " configuration is invalid " ) ? ;
2022-01-15 23:24:37 +00:00
// write lock the settings
let mut settingsrw = settings . write ( ) ;
// Set config from command line
if matches . occurrences_of ( " daemon " ) ! = 0 {
2022-05-16 15:52:48 +00:00
settingsrw . daemon . enabled = true ;
2022-01-15 23:24:37 +00:00
settingsrw . logging . terminal . enabled = false ;
}
2022-05-18 14:17:04 +00:00
if matches . occurrences_of ( " foreground " ) ! = 0 {
settingsrw . daemon . enabled = false ;
}
2022-05-16 15:52:48 +00:00
if matches . occurrences_of ( " subnode-index " ) ! = 0 {
let subnode_index = match matches . value_of ( " subnode-index " ) {
2022-07-07 03:15:51 +00:00
Some ( x ) = > x . parse ( ) . wrap_err ( " couldn't parse subnode index " ) ? ,
2022-01-15 23:24:37 +00:00
None = > {
2022-07-07 03:15:51 +00:00
bail! ( " value not specified for subnode-index " ) ;
2022-01-15 23:24:37 +00:00
}
} ;
if subnode_index = = 0 {
2022-07-07 03:15:51 +00:00
bail! ( " value of subnode_index should be between 1 and 65535 " ) ;
2022-01-15 23:24:37 +00:00
}
settingsrw . testing . subnode_index = subnode_index ;
}
2022-01-19 02:21:11 +00:00
2022-01-15 23:24:37 +00:00
if matches . occurrences_of ( " debug " ) ! = 0 {
settingsrw . logging . terminal . enabled = true ;
settingsrw . logging . terminal . level = LogLevel ::Debug ;
}
if matches . occurrences_of ( " trace " ) ! = 0 {
settingsrw . logging . terminal . enabled = true ;
settingsrw . logging . terminal . level = LogLevel ::Trace ;
}
2022-06-11 22:47:58 +00:00
if matches . occurrences_of ( " otlp " ) ! = 0 {
settingsrw . logging . otlp . enabled = true ;
2022-06-15 19:03:13 +00:00
settingsrw . logging . otlp . grpc_endpoint = NamedSocketAddrs ::from_str (
& matches
. value_of ( " otlp " )
. expect ( " should not be null because of default missing value " )
. to_string ( ) ,
)
2022-07-07 03:15:51 +00:00
. wrap_err ( " failed to parse OTLP address " ) ? ;
2022-06-11 22:47:58 +00:00
settingsrw . logging . otlp . level = LogLevel ::Trace ;
}
2022-01-15 23:24:37 +00:00
if matches . is_present ( " attach " ) {
settingsrw . auto_attach = ! matches! ( matches . value_of ( " attach " ) , Some ( " true " ) ) ;
}
if matches . is_present ( " local " ) {
settingsrw . core . network . enable_local_peer_scope = true ;
}
2022-01-19 02:21:11 +00:00
if matches . occurrences_of ( " delete-protected-store " ) ! = 0 {
settingsrw . core . protected_store . delete = true ;
}
if matches . occurrences_of ( " delete-block-store " ) ! = 0 {
settingsrw . core . block_store . delete = true ;
}
if matches . occurrences_of ( " delete-table-store " ) ! = 0 {
settingsrw . core . table_store . delete = true ;
}
2022-05-16 15:52:48 +00:00
if matches . occurrences_of ( " dump-txt-record " ) ! = 0 {
// Turn off terminal logging so we can be interactive
settingsrw . logging . terminal . enabled = false ;
}
if let Some ( v ) = matches . value_of ( " set-node-id " ) {
// Turn off terminal logging so we can be interactive
settingsrw . logging . terminal . enabled = false ;
// Split or get secret
let ( k , s ) = if let Some ( ( k , s ) ) = v . split_once ( ':' ) {
2022-07-07 03:15:51 +00:00
let k = DHTKey ::try_decode ( k ) . wrap_err ( " failed to decode node id from command line " ) ? ;
2022-05-16 15:52:48 +00:00
let s = DHTKeySecret ::try_decode ( s ) ? ;
( k , s )
} else {
let k = DHTKey ::try_decode ( v ) ? ;
let buffer = rpassword ::prompt_password ( " Enter secret key (will not echo): " )
2022-07-07 03:15:51 +00:00
. wrap_err ( " invalid secret key " ) ? ;
2022-05-16 15:52:48 +00:00
let buffer = buffer . trim ( ) . to_string ( ) ;
let s = DHTKeySecret ::try_decode ( & buffer ) ? ;
( k , s )
} ;
settingsrw . core . network . node_id = k ;
settingsrw . core . network . node_id_secret = s ;
}
2022-01-15 23:24:37 +00:00
if matches . occurrences_of ( " bootstrap " ) ! = 0 {
2022-05-18 14:17:04 +00:00
let bootstrap_list = match matches . value_of ( " bootstrap " ) {
2022-05-16 15:52:48 +00:00
Some ( x ) = > {
println! ( " Overriding bootstrap list with: " ) ;
let mut out : Vec < String > = Vec ::new ( ) ;
for x in x . split ( ',' ) {
let x = x . trim ( ) . to_string ( ) ;
println! ( " {} " , x ) ;
out . push ( x ) ;
}
out
}
None = > {
2022-07-07 03:15:51 +00:00
bail! ( " value not specified for bootstrap " ) ;
2022-05-16 15:52:48 +00:00
}
} ;
settingsrw . core . network . bootstrap = bootstrap_list ;
}
if matches . occurrences_of ( " bootstrap-nodes " ) ! = 0 {
2022-05-18 14:17:04 +00:00
let bootstrap_list = match matches . value_of ( " bootstrap-nodes " ) {
2022-01-15 23:24:37 +00:00
Some ( x ) = > {
2022-05-16 15:52:48 +00:00
println! ( " Overriding bootstrap node list with: " ) ;
2022-01-15 23:24:37 +00:00
let mut out : Vec < ParsedNodeDialInfo > = Vec ::new ( ) ;
for x in x . split ( ',' ) {
2022-05-16 15:52:48 +00:00
let x = x . trim ( ) ;
2022-01-15 23:24:37 +00:00
println! ( " {} " , x ) ;
2022-07-07 03:15:51 +00:00
out . push (
ParsedNodeDialInfo ::from_str ( x )
. wrap_err ( " unable to parse dial info in bootstrap node list " ) ? ,
) ;
2022-01-15 23:24:37 +00:00
}
out
}
None = > {
2022-07-07 03:15:51 +00:00
bail! ( " value not specified for bootstrap node list " ) ;
2022-01-15 23:24:37 +00:00
}
} ;
2022-05-16 15:52:48 +00:00
settingsrw . core . network . bootstrap_nodes = bootstrap_list ;
2022-01-15 23:24:37 +00:00
}
2022-06-08 15:18:17 +00:00
drop ( settingsrw ) ;
// Set specific config settings
if let Some ( set_configs ) = matches . values_of ( " set-config " ) {
for set_config in set_configs {
if let Some ( ( k , v ) ) = set_config . split_once ( '=' ) {
let k = k . trim ( ) ;
let v = v . trim ( ) ;
settings . set ( k , v ) ? ;
}
}
}
2022-01-15 23:24:37 +00:00
// Apply subnode index if we're testing
settings
. apply_subnode_index ( )
2022-07-07 03:15:51 +00:00
. wrap_err ( " failed to apply subnode index " ) ? ;
2022-01-15 23:24:37 +00:00
Ok ( ( settings , matches ) )
2022-01-19 02:21:11 +00:00
}