Better error handling
This commit is contained in:
parent
21e0df60a8
commit
dd8cd03036
6 changed files with 207 additions and 68 deletions
123
burrow-gtk/Cargo.lock
generated
123
burrow-gtk/Cargo.lock
generated
|
|
@ -26,6 +26,55 @@ dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstream"
|
||||||
|
version = "0.6.15"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526"
|
||||||
|
dependencies = [
|
||||||
|
"anstyle",
|
||||||
|
"anstyle-parse",
|
||||||
|
"anstyle-query",
|
||||||
|
"anstyle-wincon",
|
||||||
|
"colorchoice",
|
||||||
|
"is_terminal_polyfill",
|
||||||
|
"utf8parse",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle"
|
||||||
|
version = "1.0.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle-parse"
|
||||||
|
version = "0.2.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb"
|
||||||
|
dependencies = [
|
||||||
|
"utf8parse",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle-query"
|
||||||
|
version = "1.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a"
|
||||||
|
dependencies = [
|
||||||
|
"windows-sys 0.52.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle-wincon"
|
||||||
|
version = "3.0.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8"
|
||||||
|
dependencies = [
|
||||||
|
"anstyle",
|
||||||
|
"windows-sys 0.52.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anyhow"
|
name = "anyhow"
|
||||||
version = "1.0.79"
|
version = "1.0.79"
|
||||||
|
|
@ -174,9 +223,11 @@ name = "burrow-gtk"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
|
"colog",
|
||||||
"gettext-rs",
|
"gettext-rs",
|
||||||
"glib-build-tools",
|
"glib-build-tools",
|
||||||
"hyper-util",
|
"hyper-util",
|
||||||
|
"log",
|
||||||
"prost",
|
"prost",
|
||||||
"prost-types",
|
"prost-types",
|
||||||
"relm4",
|
"relm4",
|
||||||
|
|
@ -242,12 +293,62 @@ version = "1.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "colog"
|
||||||
|
version = "1.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2c426b7af8d5e0ad79de6713996632ce31f0d68ba84068fb0d654b396e519df0"
|
||||||
|
dependencies = [
|
||||||
|
"colored",
|
||||||
|
"env_logger",
|
||||||
|
"log",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "colorchoice"
|
||||||
|
version = "1.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "colored"
|
||||||
|
version = "2.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8"
|
||||||
|
dependencies = [
|
||||||
|
"lazy_static",
|
||||||
|
"windows-sys 0.48.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "either"
|
name = "either"
|
||||||
version = "1.9.0"
|
version = "1.9.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
|
checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "env_filter"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab"
|
||||||
|
dependencies = [
|
||||||
|
"log",
|
||||||
|
"regex",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "env_logger"
|
||||||
|
version = "0.11.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d"
|
||||||
|
dependencies = [
|
||||||
|
"anstream",
|
||||||
|
"anstyle",
|
||||||
|
"env_filter",
|
||||||
|
"humantime",
|
||||||
|
"log",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "equivalent"
|
name = "equivalent"
|
||||||
version = "1.0.1"
|
version = "1.0.1"
|
||||||
|
|
@ -797,6 +898,12 @@ version = "1.0.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
|
checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "humantime"
|
||||||
|
version = "2.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hyper"
|
name = "hyper"
|
||||||
version = "1.4.1"
|
version = "1.4.1"
|
||||||
|
|
@ -871,6 +978,12 @@ dependencies = [
|
||||||
"hashbrown 0.14.3",
|
"hashbrown 0.14.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "is_terminal_polyfill"
|
||||||
|
version = "1.70.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itertools"
|
name = "itertools"
|
||||||
version = "0.13.0"
|
version = "0.13.0"
|
||||||
|
|
@ -971,9 +1084,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "log"
|
name = "log"
|
||||||
version = "0.4.20"
|
version = "0.4.22"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
|
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "malloc_buf"
|
name = "malloc_buf"
|
||||||
|
|
@ -1816,6 +1929,12 @@ version = "1.0.12"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "utf8parse"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "version-compare"
|
name = "version-compare"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,8 @@ prost = "0.13"
|
||||||
prost-types = "0.13"
|
prost-types = "0.13"
|
||||||
hyper-util = "0.1.6"
|
hyper-util = "0.1.6"
|
||||||
tower = "0.4.13"
|
tower = "0.4.13"
|
||||||
|
log = "0.4.22"
|
||||||
|
colog = "1.3.0"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
anyhow = "1.0"
|
anyhow = "1.0"
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,6 @@ impl AsyncComponent for DaemonGroup {
|
||||||
root: Self::Root,
|
root: Self::Root,
|
||||||
sender: AsyncComponentSender<Self>,
|
sender: AsyncComponentSender<Self>,
|
||||||
) -> AsyncComponentParts<Self> {
|
) -> AsyncComponentParts<Self> {
|
||||||
// Should be impossible to panic here
|
|
||||||
let model = DaemonGroup {
|
let model = DaemonGroup {
|
||||||
system_setup: init.system_setup,
|
system_setup: init.system_setup,
|
||||||
daemon_client: init.daemon_client.clone(),
|
daemon_client: init.daemon_client.clone(),
|
||||||
|
|
@ -68,45 +67,9 @@ impl AsyncComponent for DaemonGroup {
|
||||||
) {
|
) {
|
||||||
match msg {
|
match msg {
|
||||||
DaemonGroupMsg::LaunchLocal => {
|
DaemonGroupMsg::LaunchLocal => {
|
||||||
// TODO: Handle error condition
|
if let Err(e) = launch_local() {
|
||||||
|
error!("Failed to launch local daemon at: {}", e);
|
||||||
const BURROW_LOCAL_DAEMON_PATH: &str = "/tmp/burrow-detached-daemon";
|
};
|
||||||
|
|
||||||
let burrow_original_bin = std::env::vars()
|
|
||||||
.find(|(k, _)| k == "APPDIR")
|
|
||||||
.map(|(_, v)| v + "/usr/bin/burrow")
|
|
||||||
.unwrap_or("/usr/bin/burrow".to_owned());
|
|
||||||
|
|
||||||
Command::new("cp")
|
|
||||||
.arg(&burrow_original_bin)
|
|
||||||
.arg(BURROW_LOCAL_DAEMON_PATH)
|
|
||||||
.output()
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let mut burrow_bin =
|
|
||||||
String::from_utf8(Command::new("mktemp").output().unwrap().stdout).unwrap();
|
|
||||||
burrow_bin.pop();
|
|
||||||
|
|
||||||
let privileged_spawn_script = format!(
|
|
||||||
r#"chmod +x {}
|
|
||||||
setcap CAP_NET_BIND_SERVICE,CAP_NET_ADMIN+eip {}"#,
|
|
||||||
BURROW_LOCAL_DAEMON_PATH, BURROW_LOCAL_DAEMON_PATH
|
|
||||||
)
|
|
||||||
.replace('\n', "&&");
|
|
||||||
|
|
||||||
Command::new("pkexec")
|
|
||||||
.arg("sh")
|
|
||||||
.arg("-c")
|
|
||||||
.arg(privileged_spawn_script)
|
|
||||||
.arg(&burrow_bin)
|
|
||||||
.output()
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
Command::new(BURROW_LOCAL_DAEMON_PATH)
|
|
||||||
.env("RUST_LOG", "debug")
|
|
||||||
.arg("daemon")
|
|
||||||
.spawn()
|
|
||||||
.unwrap();
|
|
||||||
}
|
}
|
||||||
DaemonGroupMsg::DaemonStateChange => {
|
DaemonGroupMsg::DaemonStateChange => {
|
||||||
self.already_running = self.daemon_client.lock().await.is_some();
|
self.already_running = self.daemon_client.lock().await.is_some();
|
||||||
|
|
@ -114,3 +77,49 @@ setcap CAP_NET_BIND_SERVICE,CAP_NET_ADMIN+eip {}"#,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn launch_local() -> Result<()> {
|
||||||
|
const BURROW_LOCAL_DAEMON_PATH: &str = "/tmp/burrow-detached-daemon";
|
||||||
|
|
||||||
|
let burrow_original_bin = std::env::vars()
|
||||||
|
.find(|(k, _)| k == "APPDIR")
|
||||||
|
.map(|(_, v)| v + "/usr/bin/burrow")
|
||||||
|
.unwrap_or("/usr/bin/burrow".to_owned());
|
||||||
|
|
||||||
|
Command::new("cp")
|
||||||
|
.arg(&burrow_original_bin)
|
||||||
|
.arg(BURROW_LOCAL_DAEMON_PATH)
|
||||||
|
.output()
|
||||||
|
.with_context(|| {
|
||||||
|
format!(
|
||||||
|
"Copying {} to {}",
|
||||||
|
burrow_original_bin, BURROW_LOCAL_DAEMON_PATH
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let mut burrow_bin = String::from_utf8(Command::new("mktemp").output()?.stdout)?;
|
||||||
|
burrow_bin.pop();
|
||||||
|
|
||||||
|
let privileged_spawn_script = format!(
|
||||||
|
r#"chmod +x {}
|
||||||
|
setcap CAP_NET_BIND_SERVICE,CAP_NET_ADMIN+eip {}"#,
|
||||||
|
BURROW_LOCAL_DAEMON_PATH, BURROW_LOCAL_DAEMON_PATH
|
||||||
|
)
|
||||||
|
.replace('\n', "&&");
|
||||||
|
|
||||||
|
// Need to be more careful here.
|
||||||
|
Command::new("pkexec")
|
||||||
|
.arg("sh")
|
||||||
|
.arg("-c")
|
||||||
|
.arg(privileged_spawn_script)
|
||||||
|
.arg(&burrow_bin)
|
||||||
|
.output()
|
||||||
|
.with_context(|| format!("Priviledged call to {}", burrow_bin))?;
|
||||||
|
|
||||||
|
Command::new(BURROW_LOCAL_DAEMON_PATH)
|
||||||
|
.env("RUST_LOG", "debug")
|
||||||
|
.arg("daemon")
|
||||||
|
.spawn()?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,18 +17,18 @@ pub struct DiagGroupInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DiagGroup {
|
impl DiagGroup {
|
||||||
async fn new(daemon_client: Arc<Mutex<Option<Channel>>>) -> Result<Self> {
|
async fn new(daemon_client: Arc<Mutex<Option<Channel>>>) -> Self {
|
||||||
let system_setup = SystemSetup::new();
|
let system_setup = SystemSetup::new();
|
||||||
let daemon_running = daemon_client.lock().await.is_some();
|
let daemon_running = daemon_client.lock().await.is_some();
|
||||||
|
|
||||||
Ok(Self {
|
Self {
|
||||||
service_installed: system_setup.is_service_installed()?,
|
service_installed: system_setup.is_service_installed(),
|
||||||
socket_installed: system_setup.is_socket_installed()?,
|
socket_installed: system_setup.is_socket_installed(),
|
||||||
socket_enabled: system_setup.is_socket_enabled()?,
|
socket_enabled: system_setup.is_socket_enabled(),
|
||||||
daemon_running,
|
daemon_running,
|
||||||
system_setup,
|
system_setup,
|
||||||
daemon_client,
|
daemon_client,
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -95,7 +95,7 @@ impl AsyncComponent for DiagGroup {
|
||||||
sender: AsyncComponentSender<Self>,
|
sender: AsyncComponentSender<Self>,
|
||||||
) -> AsyncComponentParts<Self> {
|
) -> AsyncComponentParts<Self> {
|
||||||
// Should be impossible to panic here
|
// Should be impossible to panic here
|
||||||
let model = DiagGroup::new(init.daemon_client).await.unwrap();
|
let model = DiagGroup::new(init.daemon_client).await;
|
||||||
|
|
||||||
let widgets = view_output!();
|
let widgets = view_output!();
|
||||||
|
|
||||||
|
|
@ -111,7 +111,7 @@ impl AsyncComponent for DiagGroup {
|
||||||
match msg {
|
match msg {
|
||||||
DiagGroupMsg::Refresh => {
|
DiagGroupMsg::Refresh => {
|
||||||
// Should be impossible to panic here
|
// Should be impossible to panic here
|
||||||
*self = Self::new(Arc::clone(&self.daemon_client)).await.unwrap();
|
*self = Self::new(Arc::clone(&self.daemon_client)).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@ use std::{fmt::Display, fs, process::Command};
|
||||||
const SYSTEMD_SOCKET_LOC: &str = "/etc/systemd/system/burrow.socket";
|
const SYSTEMD_SOCKET_LOC: &str = "/etc/systemd/system/burrow.socket";
|
||||||
const SYSTEMD_SERVICE_LOC: &str = "/etc/systemd/system/burrow.service";
|
const SYSTEMD_SERVICE_LOC: &str = "/etc/systemd/system/burrow.service";
|
||||||
|
|
||||||
// I don't like this type very much.
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub enum StatusTernary {
|
pub enum StatusTernary {
|
||||||
True,
|
True,
|
||||||
|
|
@ -33,35 +32,41 @@ impl SystemSetup {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_service_installed(&self) -> Result<StatusTernary> {
|
pub fn is_service_installed(&self) -> StatusTernary {
|
||||||
match self {
|
match self {
|
||||||
SystemSetup::Systemd => Ok(fs::metadata(SYSTEMD_SERVICE_LOC).is_ok().into()),
|
SystemSetup::Systemd => fs::metadata(SYSTEMD_SERVICE_LOC).is_ok().into(),
|
||||||
SystemSetup::AppImage => Ok(StatusTernary::NA),
|
SystemSetup::AppImage => StatusTernary::NA,
|
||||||
SystemSetup::Other => Ok(StatusTernary::NA),
|
SystemSetup::Other => StatusTernary::NA,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_socket_installed(&self) -> Result<StatusTernary> {
|
pub fn is_socket_installed(&self) -> StatusTernary {
|
||||||
match self {
|
match self {
|
||||||
SystemSetup::Systemd => Ok(fs::metadata(SYSTEMD_SOCKET_LOC).is_ok().into()),
|
SystemSetup::Systemd => fs::metadata(SYSTEMD_SOCKET_LOC).is_ok().into(),
|
||||||
SystemSetup::AppImage => Ok(StatusTernary::NA),
|
SystemSetup::AppImage => StatusTernary::NA,
|
||||||
SystemSetup::Other => Ok(StatusTernary::NA),
|
SystemSetup::Other => StatusTernary::NA,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_socket_enabled(&self) -> Result<StatusTernary> {
|
pub fn is_socket_enabled(&self) -> StatusTernary {
|
||||||
match self {
|
match self {
|
||||||
SystemSetup::Systemd => {
|
SystemSetup::Systemd => {
|
||||||
let output = Command::new("systemctl")
|
let Ok(output) = Command::new("systemctl")
|
||||||
.arg("is-enabled")
|
.arg("is-enabled")
|
||||||
.arg("burrow.socket")
|
.arg("burrow.socket")
|
||||||
.output()?
|
.output()
|
||||||
.stdout;
|
.map(|o| o.stdout)
|
||||||
let output = String::from_utf8(output)?;
|
.inspect_err(|e| {
|
||||||
Ok((output == "enabled\n").into())
|
error!("Failed to run `systemctl is-enabled burrow.socket` {}", e)
|
||||||
|
})
|
||||||
|
else {
|
||||||
|
return StatusTernary::NA;
|
||||||
|
};
|
||||||
|
let output = String::from_utf8(output).unwrap();
|
||||||
|
(output == "enabled\n").into()
|
||||||
}
|
}
|
||||||
SystemSetup::AppImage => Ok(StatusTernary::NA),
|
SystemSetup::AppImage => StatusTernary::NA,
|
||||||
SystemSetup::Other => Ok(StatusTernary::NA),
|
SystemSetup::Other => StatusTernary::NA,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
use anyhow::Result;
|
use anyhow::{Context, Result};
|
||||||
|
use log::error;
|
||||||
|
|
||||||
pub mod components;
|
pub mod components;
|
||||||
mod daemon;
|
mod daemon;
|
||||||
|
|
@ -8,5 +9,8 @@ mod diag;
|
||||||
mod config;
|
mod config;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
colog::default_builder()
|
||||||
|
.filter(None, log::LevelFilter::Error)
|
||||||
|
.init();
|
||||||
components::App::run();
|
components::App::run();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue