veilid/veilid-cli/src/main.rs

177 lines
5.9 KiB
Rust
Raw Normal View History

2021-12-07 22:09:45 -05:00
#![deny(clippy::all)]
2021-12-09 16:11:52 -05:00
#![deny(unused_must_use)]
2021-11-27 21:34:08 -05:00
use veilid_core::xx::*;
2021-11-22 11:28:30 -05:00
use async_std::prelude::*;
2022-03-11 07:35:41 -05:00
use clap::{Arg, ColorChoice, Command};
2021-11-22 11:28:30 -05:00
use flexi_logger::*;
use std::ffi::OsStr;
use std::net::ToSocketAddrs;
mod client_api_connection;
mod command_processor;
mod settings;
mod ui;
2021-11-28 20:08:50 -05:00
#[allow(clippy::all)]
2021-11-22 11:28:30 -05:00
pub mod veilid_client_capnp {
include!(concat!(env!("OUT_DIR"), "/proto/veilid_client_capnp.rs"));
}
fn parse_command_line(default_config_path: &OsStr) -> Result<clap::ArgMatches, String> {
2022-03-11 07:35:41 -05:00
let matches = Command::new("veilid-cli")
2021-11-22 11:28:30 -05:00
.version("0.1")
.color(ColorChoice::Auto)
2021-11-22 11:28:30 -05:00
.about("Veilid Console Client")
.arg(
Arg::new("address")
2021-11-22 11:28:30 -05:00
.required(false)
.help("Address to connect to"),
)
.arg(
Arg::new("debug")
2021-11-22 11:28:30 -05:00
.long("debug")
.help("Turn on debug logging"),
)
.arg(
Arg::new("wait-for-debug")
2021-11-22 11:28:30 -05:00
.long("wait-for-debug")
.help("Wait for debugger to attach"),
)
.arg(
Arg::new("trace")
2021-11-22 11:28:30 -05:00
.long("trace")
.conflicts_with("debug")
.help("Turn on trace logging"),
)
.arg(
Arg::new("config-file")
.short('c')
2021-11-22 11:28:30 -05:00
.takes_value(true)
.value_name("FILE")
.default_value_os(default_config_path)
.help("Specify a configuration file to use"),
)
.get_matches();
Ok(matches)
}
#[async_std::main]
async fn main() -> Result<(), String> {
2021-11-22 11:28:30 -05:00
// Get command line options
let default_config_path = settings::Settings::get_default_config_path();
let matches = parse_command_line(default_config_path.as_os_str())?;
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
let mut settings = settings::Settings::new(
matches.occurrences_of("config-file") == 0,
matches.value_of_os("config-file").unwrap(),
)
.map_err(map_to_string)?;
2021-11-22 11:28:30 -05:00
// Set config from command line
if matches.occurrences_of("debug") != 0 {
settings.logging.level = settings::LogLevel::Debug;
settings.logging.terminal.enabled = true;
}
if matches.occurrences_of("trace") != 0 {
settings.logging.level = settings::LogLevel::Trace;
settings.logging.terminal.enabled = true;
}
// Create UI object
let mut sivui = ui::UI::new(settings.interface.node_log.scrollback, &settings);
// Set up loggers
{
let mut specbuilder = LogSpecBuilder::new();
specbuilder.default(settings::convert_loglevel(settings.logging.level));
specbuilder.module("cursive_core", LevelFilter::Off);
specbuilder.module("cursive_buffered_backend", LevelFilter::Off);
specbuilder.module("mio", LevelFilter::Off);
specbuilder.module("async_std", LevelFilter::Off);
specbuilder.module("async_io", LevelFilter::Off);
specbuilder.module("polling", LevelFilter::Off);
let logger = Logger::with(specbuilder.build());
if settings.logging.terminal.enabled {
let flv = sivui.cursive_flexi_logger();
if settings.logging.file.enabled {
std::fs::create_dir_all(settings.logging.file.directory.clone())
.map_err(map_to_string)?;
2021-11-22 11:28:30 -05:00
logger
.log_target(LogTarget::FileAndWriter(flv))
.suppress_timestamp()
// .format(flexi_logger::colored_default_format)
.directory(settings.logging.file.directory.clone())
.start()
.expect("failed to initialize logger!");
} else {
logger
.log_target(LogTarget::Writer(flv))
.suppress_timestamp()
.format(flexi_logger::colored_default_format)
.start()
.expect("failed to initialize logger!");
}
} else if settings.logging.file.enabled {
std::fs::create_dir_all(settings.logging.file.directory.clone())
.map_err(map_to_string)?;
2021-11-22 11:28:30 -05:00
logger
.log_target(LogTarget::File)
.suppress_timestamp()
.directory(settings.logging.file.directory.clone())
.start()
.expect("failed to initialize logger!");
}
}
// Get client address
let server_addrs;
if let Some(address_arg) = matches.value_of("address") {
server_addrs = address_arg
.to_socket_addrs()
.map_err(|e| format!("Invalid server address '{}'", e))?
2021-11-22 11:28:30 -05:00
.collect()
} else {
server_addrs = settings.address.addrs.clone();
}
let server_addr = server_addrs.first().cloned();
// Create command processor
debug!("Creating Command Processor ");
let mut comproc = command_processor::CommandProcessor::new(sivui.clone(), &settings);
sivui.set_command_processor(comproc.clone());
// Create client api client side
info!("Starting API connection");
let mut capi = client_api_connection::ClientApiConnection::new(comproc.clone());
// Save client api in command processor
comproc.set_client_api_connection(capi.clone());
// Keep a connection to the server
comproc.set_server_address(server_addr);
let mut comproc2 = comproc.clone();
let connection_future = comproc.connection_manager();
// Start UI
let ui_future = async_std::task::spawn_local(async move {
sivui.run_async().await;
// When UI quits, close connection and command processor cleanly
comproc2.quit();
capi.disconnect().await;
});
// Wait for ui and connection to complete
ui_future.join(connection_future).await;
Ok(())
}