This re-enables stdout/stderr logging for release binaries for DTMM. As a GUI application, it usually won't be started from a CLI, and there should be no negative impact from that. But since stdout logging is synchronous and much faster than the async action that writes to the log file, it might get to log more when the application panics.
102 lines
3.1 KiB
Rust
102 lines
3.1 KiB
Rust
#![recursion_limit = "256"]
|
|
#![feature(let_chains)]
|
|
#![feature(arc_unwrap_or_clone)]
|
|
#![windows_subsystem = "windows"]
|
|
|
|
use std::path::PathBuf;
|
|
use std::sync::Arc;
|
|
|
|
use clap::parser::ValueSource;
|
|
use clap::{command, value_parser, Arg};
|
|
use color_eyre::eyre::{self, Context};
|
|
use color_eyre::{Report, Result};
|
|
use druid::AppLauncher;
|
|
use tokio::sync::RwLock;
|
|
|
|
use crate::controller::worker::work_thread;
|
|
use crate::state::AsyncAction;
|
|
use crate::state::{Delegate, State};
|
|
use crate::ui::theme;
|
|
use crate::util::log::LogLevel;
|
|
|
|
mod controller;
|
|
mod state;
|
|
mod util {
|
|
pub mod ansi;
|
|
pub mod config;
|
|
pub mod log;
|
|
}
|
|
mod ui;
|
|
|
|
#[tracing::instrument]
|
|
fn main() -> Result<()> {
|
|
color_eyre::install()?;
|
|
|
|
let default_config_path = util::config::get_default_config_path();
|
|
|
|
tracing::trace!(default_config_path = %default_config_path.display());
|
|
|
|
let matches = command!()
|
|
.arg(
|
|
Arg::new("config")
|
|
.long("config")
|
|
.short('c')
|
|
.help("Path to the config file")
|
|
.value_parser(value_parser!(PathBuf))
|
|
.default_value(default_config_path.to_string_lossy().to_string()),
|
|
)
|
|
.arg(
|
|
Arg::new("log-level")
|
|
.long("log-level")
|
|
.help("The maximum level of log events to print")
|
|
.value_parser(value_parser!(LogLevel))
|
|
.default_value("info"),
|
|
)
|
|
.get_matches();
|
|
|
|
let (log_tx, log_rx) = tokio::sync::mpsc::unbounded_channel();
|
|
let level = if matches.value_source("log-level") == Some(ValueSource::DefaultValue) {
|
|
None
|
|
} else {
|
|
matches.get_one::<LogLevel>("log-level").cloned()
|
|
};
|
|
util::log::create_tracing_subscriber(log_tx, level);
|
|
|
|
let (action_tx, action_rx) = tokio::sync::mpsc::unbounded_channel();
|
|
|
|
let config_path = matches
|
|
.get_one::<PathBuf>("config")
|
|
.cloned()
|
|
.expect("argument has default value");
|
|
let is_config_default = matches.value_source("config") == Some(ValueSource::DefaultValue);
|
|
if action_tx
|
|
.send(AsyncAction::LoadInitial((config_path, is_config_default)))
|
|
.is_err()
|
|
{
|
|
let err = eyre::eyre!("Failed to send action");
|
|
return Err(err);
|
|
}
|
|
|
|
let launcher = AppLauncher::with_window(ui::window::main::new())
|
|
.delegate(Delegate::new(action_tx))
|
|
.configure_env(theme::set_theme_env);
|
|
|
|
let event_sink = launcher.get_external_handle();
|
|
|
|
std::thread::Builder::new()
|
|
.name("work-thread".into())
|
|
.spawn(move || {
|
|
let event_sink = Arc::new(RwLock::new(event_sink));
|
|
let action_rx = Arc::new(RwLock::new(action_rx));
|
|
let log_rx = Arc::new(RwLock::new(log_rx));
|
|
loop {
|
|
if let Err(err) = work_thread(event_sink.clone(), action_rx.clone(), log_rx.clone())
|
|
{
|
|
tracing::error!("Work thread failed, restarting: {:?}", err);
|
|
}
|
|
}
|
|
})
|
|
.wrap_err("Work thread panicked")?;
|
|
|
|
launcher.launch(State::new()).map_err(Report::new)
|
|
}
|