veilid/veilid-cli/src/main.rs

178 lines
5.8 KiB
Rust
Raw Normal View History

2021-12-08 03:09:45 +00:00
#![deny(clippy::all)]
2021-12-09 21:11:52 +00:00
#![deny(unused_must_use)]
#![recursion_limit = "256"]
2021-11-28 02:34:08 +00:00
2022-12-02 00:59:19 +00:00
use crate::tools::*;
use clap::{Parser, ValueEnum};
2021-11-22 16:28:30 +00:00
use flexi_logger::*;
use std::{net::ToSocketAddrs, path::PathBuf};
2021-11-22 16:28:30 +00:00
mod client_api_connection;
mod command_processor;
2022-09-06 20:49:43 +00:00
mod peers_table_view;
2021-11-22 16:28:30 +00:00
mod settings;
2022-06-28 03:46:29 +00:00
mod tools;
2021-11-22 16:28:30 +00:00
mod ui;
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum, Debug)]
enum LogLevel {
/// Turn on debug logging
Debug,
/// Turn on trace logging
Trace,
}
#[derive(Parser, Debug)]
#[command(author, version, about = "Veilid Console Client")]
struct CmdlineArgs {
/// Address to connect to
#[arg(long)]
address: Option<String>,
/// Wait for debugger to attach
#[arg(long)]
wait_for_debug: bool,
/// Specify a configuration file to use
2023-08-13 21:42:27 +00:00
#[arg(short, long, value_name = "FILE")]
config_file: Option<PathBuf>,
/// log level
#[arg(value_enum)]
log_level: Option<LogLevel>,
2021-11-22 16:28:30 +00:00
}
2022-06-28 03:46:29 +00:00
fn main() -> Result<(), String> {
2021-11-22 16:28:30 +00:00
// Get command line options
let default_config_path = settings::Settings::get_default_config_path();
let args = CmdlineArgs::parse();
if args.wait_for_debug {
2021-11-22 16:28:30 +00:00
use bugsalot::debugger;
debugger::wait_until_attached(None).expect("state() not implemented on this platform");
}
// Attempt to load configuration
let settings_path = args.config_file.unwrap_or(default_config_path);
let settings_path = if settings_path.exists() {
Some(settings_path.into_os_string())
2022-06-26 21:00:05 +00:00
} else {
None
};
let mut settings = settings::Settings::new(settings_path)
.map_err(|e| format!("configuration is invalid: {}", e))?;
2021-11-22 16:28:30 +00:00
// Set config from command line
if let Some(LogLevel::Debug) = args.log_level {
2021-11-22 16:28:30 +00:00
settings.logging.level = settings::LogLevel::Debug;
settings.logging.terminal.enabled = true;
}
if let Some(LogLevel::Trace) = args.log_level {
2021-11-22 16:28:30 +00:00
settings.logging.level = settings::LogLevel::Trace;
settings.logging.terminal.enabled = true;
}
// Create UI object
2023-06-08 18:07:09 +00:00
let (mut sivui, uisender) = ui::UI::new(settings.interface.node_log.scrollback, &settings);
2021-11-22 16:28:30 +00:00
// Set up loggers
{
let mut specbuilder = LogSpecBuilder::new();
specbuilder.default(settings::convert_loglevel(settings.logging.level));
2022-07-01 20:20:43 +00:00
specbuilder.module("cursive", LevelFilter::Off);
2021-11-22 16:28:30 +00:00
specbuilder.module("cursive_core", LevelFilter::Off);
specbuilder.module("cursive_buffered_backend", LevelFilter::Off);
2022-07-02 15:41:25 +00:00
specbuilder.module("tokio_util", LevelFilter::Off);
2021-11-22 16:28:30 +00:00
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 16:28:30 +00:00
logger
2022-06-26 21:00:05 +00:00
.log_to_file_and_writer(
FileSpec::default()
.directory(settings.logging.file.directory.clone())
.suppress_timestamp(),
flv,
)
2021-11-22 16:28:30 +00:00
.start()
.expect("failed to initialize logger!");
} else {
logger
2022-06-26 21:00:05 +00:00
.log_to_writer(flv)
2021-11-22 16:28:30 +00:00
.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 16:28:30 +00:00
logger
2022-06-26 21:00:05 +00:00
.log_to_file(
FileSpec::default()
.directory(settings.logging.file.directory.clone())
.suppress_timestamp(),
)
2021-11-22 16:28:30 +00:00
.start()
.expect("failed to initialize logger!");
}
}
// Get client address
let server_addrs = if let Some(address_arg) = args.address {
2022-03-13 16:45:36 +00:00
address_arg
2021-11-22 16:28:30 +00:00
.to_socket_addrs()
.map_err(|e| format!("Invalid server address '{}'", e))?
2021-11-22 16:28:30 +00:00
.collect()
} else {
2022-03-13 16:45:36 +00:00
settings.address.addrs.clone()
};
2021-11-22 16:28:30 +00:00
let server_addr = server_addrs.first().cloned();
// Create command processor
debug!("Creating Command Processor ");
2023-06-08 18:07:09 +00:00
let comproc = command_processor::CommandProcessor::new(uisender, &settings);
2021-11-22 16:28:30 +00:00
sivui.set_command_processor(comproc.clone());
// Create client api client side
info!("Starting API connection");
2023-06-08 18:07:09 +00:00
let capi = client_api_connection::ClientApiConnection::new(comproc.clone());
2021-11-22 16:28:30 +00:00
// 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);
2023-06-08 18:07:09 +00:00
let comproc2 = comproc.clone();
2021-11-22 16:28:30 +00:00
let connection_future = comproc.connection_manager();
2022-06-28 03:46:29 +00:00
// Start async
block_on(async move {
// Start UI
let ui_future = async move {
sivui.run_async().await;
// When UI quits, close connection and command processor cleanly
comproc2.quit();
capi.disconnect().await;
};
cfg_if! {
if #[cfg(feature="rt-async-std")] {
use async_std::prelude::*;
// Wait for ui and connection to complete
let _ = ui_future.join(connection_future).await;
} else if #[cfg(feature="rt-tokio")] {
// Wait for ui and connection to complete
let _ = tokio::join!(ui_future, connection_future);
}
}
2021-11-22 16:28:30 +00:00
});
Ok(())
}