From 7bd95a826e79a103d39c0cd027fcdfdf97b35f22816181c441862c500f94d230 Mon Sep 17 00:00:00 2001 From: kira Date: Wed, 26 Aug 2026 11:12:06 +0200 Subject: [PATCH] Saving more work. --- Cargo.lock | 144 ++++++++++++++++++++++++++++++++++++ Cargo.toml | 5 +- src/daemon.rs | 165 ++++++++++++++++++++++++++++++++--------- src/hive_config.rs | 12 +-- src/hive_db.rs | 25 ++++--- src/hive_intercom.rs | 172 +++++++++++++++++++++++++++++++++++++++++++ src/hive_system.rs | 8 +- src/main.rs | 38 ++++------ 8 files changed, 494 insertions(+), 75 deletions(-) create mode 100644 src/hive_intercom.rs diff --git a/Cargo.lock b/Cargo.lock index 2299a68..a6a0c03 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -61,12 +61,27 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "atomic-polyfill" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cf2bce30dfe09ef0bfaef228b9d414faaf7e563035494d7fe092dba54b300f4" +dependencies = [ + "critical-section", +] + [[package]] name = "bitflags" version = "2.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b588b76d00fde79687d7646a9b5bdf3cc0f655e0bbd080335a95d7e96f3587da" +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + [[package]] name = "cfg-if" version = "1.0.4" @@ -119,12 +134,39 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" +[[package]] +name = "cobs" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1" +dependencies = [ + "thiserror", +] + [[package]] name = "colorchoice" version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" +[[package]] +name = "critical-section" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" + +[[package]] +name = "embedded-io" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced" + +[[package]] +name = "embedded-io" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" + [[package]] name = "equivalent" version = "1.0.2" @@ -141,12 +183,35 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "hash32" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67" +dependencies = [ + "byteorder", +] + [[package]] name = "hashbrown" version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" +[[package]] +name = "heapless" +version = "0.7.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdc6457c0eb62c71aac4bc17216026d8410337c4126773b9c5daba343f17964f" +dependencies = [ + "atomic-polyfill", + "hash32", + "rustc_version", + "serde", + "spin", + "stable_deref_trait", +] + [[package]] name = "heck" version = "0.5.0" @@ -159,6 +224,7 @@ version = "0.1.0" dependencies = [ "clap", "nix", + "postcard", "regex", "serde", "serde_json", @@ -195,6 +261,15 @@ version = "0.2.189" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2" +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + [[package]] name = "memchr" version = "2.8.3" @@ -219,6 +294,19 @@ version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" +[[package]] +name = "postcard" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6764c3b5dd454e283a30e6dfe78e9b31096d9e32036b5d1eaac7a6119ccb9a24" +dependencies = [ + "cobs", + "embedded-io 0.4.0", + "embedded-io 0.6.1", + "heapless", + "serde", +] + [[package]] name = "proc-macro2" version = "1.0.107" @@ -266,6 +354,27 @@ version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "semver" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" + [[package]] name = "serde" version = "1.0.229" @@ -338,6 +447,21 @@ dependencies = [ "libc", ] +[[package]] +name = "spin" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3763264f6b73151db08c50ff20d7d8a0b8796e021cdea7ceedad07b80155fa0e" +dependencies = [ + "lock_api", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + [[package]] name = "strsim" version = "0.11.1" @@ -355,6 +479,26 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "thiserror" +version = "2.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec86235f5fcc2a73650310756d2ac5b138a5780bbbdfae3eeccec992c435ba4f" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc04cd3e1236dd4a98afca4569f2deb3f120e5422a4023be2cb683f8486292af" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "time-format" version = "1.2.2" diff --git a/Cargo.toml b/Cargo.toml index fc6ec49..ca5393f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,9 +6,10 @@ edition = "2024" [dependencies] clap = { version = "4.6", features = ["derive"] } nix = { version = "0", features = ["user"] } +postcard = { version = "1.1", features = ["use-std"] } regex = "1" serde = { version = "1", features = ["derive"] } -serde_json = "1.0.151" +serde_json = "1.0" signal-hook = "0.4" time-format = "1.2" -toml = "1.1.4" +toml = "1.1" diff --git a/src/daemon.rs b/src/daemon.rs index 0b6c7d2..a52efae 100644 --- a/src/daemon.rs +++ b/src/daemon.rs @@ -18,22 +18,23 @@ hive-up daemon logic */ -use std::fs; -use std::process::Command; use std::sync::Arc; use std::sync::atomic::{AtomicBool, Ordering}; use std::thread; -use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH}; -use time_format; +use std::time::{Duration, SystemTime, UNIX_EPOCH}; +use std::os::unix::net::UnixDatagram; use crate::hive_config::HiveConfig; -use crate::hive_db; +use crate::hive_db::{self, HiveDb}; +use crate::hive_config; use crate::hive_system; +use crate::hive_intercom::{self, IntercomError, BzzReq, BzzResp}; #[derive(Debug)] pub enum DaemonError { IoError(std::io::Error), DBError(hive_db::DBError), + ConfigError(hive_config::ConfigError), ExecCommandError(hive_system::ExecCommandError), TimestampError, } @@ -51,6 +52,13 @@ impl From for DaemonError { } } +impl From for DaemonError { + fn from(err: hive_config::ConfigError) -> Self { + DaemonError::ConfigError(err) + } +} + + impl From for DaemonError { fn from(err: hive_system::ExecCommandError) -> Self { DaemonError::ExecCommandError(err) @@ -61,12 +69,9 @@ impl std::fmt::Display for DaemonError { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { match self { DaemonError::IoError(e) => write!(f, "IO Error: {}", e), - DaemonError::DBError(e) => { - write!(f, "Database error: {}", e) - }, - DaemonError::ExecCommandError(e) => { - write!(f, "Exec Command Error: {}", e) - }, + DaemonError::DBError(e) => write!(f, "Database error: {}", e), + DaemonError::ConfigError(e) => write!(f, "Config Error: {}", e), + DaemonError::ExecCommandError(e) => write!(f, "Exec Command Error: {}", e), DaemonError::TimestampError => write!(f, "Timestamp Error"), } } @@ -82,41 +87,133 @@ fn get_timestamp_sec() -> u64 { .as_secs() } +/// bloking function. Bloaks for configured socker recv timeout +fn process_remoute(bzz_db: &mut HiveDb, listening_socket: &UnixDatagram, recv_buf: &mut [u8]) -> Result<(), DaemonError> { + // waiting on socket recv_from untill timeout (also using this as a timer) + match hive_intercom::socket_recv(&listening_socket, recv_buf) { + // we get some request to process + Ok((bzz_req, client_addr)) => { + match bzz_req { + // return awailable updates number + BzzReq::UpdatesAvailable => { + let resp = BzzResp::UpdatesAvailable(bzz_db.updates_available); + if let Err(ex) = hive_intercom::socket_send(&listening_socket,&client_addr, resp) { + println!("Error while ansvering cli request: {}", ex); + } + }, + // we should apply updates if any on reboot + BzzReq::ScheduleUpdate => { + // but only if we have actually any updates + if bzz_db.updates_available > 0 { + bzz_db.update_on_reboot = true; + // keep it simple Kira + // lets just return err from the loop if something wrong with db + hive_db::write_db(&bzz_db)?; + // signal remoute that evertyhing go OK + if let Err(ex) = hive_intercom::socket_send(&listening_socket,&client_addr, BzzResp::Finish) { + println!("Error while ansvering cli request: {}", ex); + } + } + } + } + Ok(()) + } + // if time out - do nothing + Err(IntercomError::Timeout) => { + Ok(()) + } + // if some actual IO error then return it + Err(IntercomError::IoError(ex)) => Err(ex.into()), + // if other kinds of errors - log and continue + Err(ex) => { + println!("Got error while listenin to unix socket: {}", ex); + print!("Sleeping for 1 secong and continue..."); + thread::sleep(Duration::from_secs(1)); + Ok(()) + } + } +} + +// doing what daemons usually beezz +fn do_local_work(config: &HiveConfig, bzz_db: &mut HiveDb)-> Result<(), DaemonError> { + // if updates check is turned on + if config.update.updates_check_interval != 0 { + let timestamp = get_timestamp_sec(); + + // calculate how many hours passed sinse last update + let hours_since_update_check = timestamp + .checked_sub(bzz_db.update_check_timestamp) + .ok_or(DaemonError::TimestampError)? + / 3600; + + // if more than updates_check_interval specifiyed in config - check for updates + if hours_since_update_check > config.update.updates_check_interval { + // perform update check + println!("Cheking for updates..."); + // now that may fail because of bad internet and idealy we + // want to just log error and retry in other time + bzz_db.updates_available = match hive_system::check_updates() { + Ok(updates_num) => updates_num, + Err(ex) => { + println!("Error while shecking for updates: {}", ex); + 0u32 + } + }; + hive_db::write_db(&bzz_db)?; + println!("Found {} packages that needs to be updated.", bzz_db.updates_available); + + // if auto download for updates is enabled and there is some updates - download them + if config.update.download_updates && bzz_db.updates_available != 0 { + println!("Downloadin updates..."); + match hive_system::download_updates() { + Ok(()) => {println!("Updates downloaded...");}, + Err(ex) => {println!("Error downloading updates: {}", ex);} + } + } + + // updating las tcheck for updates timestamp in db + bzz_db.update_check_timestamp = get_timestamp_sec(); + hive_db::write_db(&bzz_db)?; + } + } + Ok(()) +} + pub fn run( - config: HiveConfig, + mut bzz_config: HiveConfig, term_flag: Arc, reload_flag: Arc, ) -> Result<(), DaemonError> { - let duration = SystemTime::now() - .duration_since(UNIX_EPOCH) - .expect("Time went backwards"); + // reading db from disk let mut bzz_db = hive_db::read_db()?; - //duration.as_secs() - let keep_going = true; + // stop flag + let mut keep_going = true; - //last_check. + // init udp unix socket for communication with cli and such + let listening_socket = hive_intercom::socket_bind(1)?; + let mut recv_buf: Vec = Vec::with_capacity(1024); + + // main loop (I love loops) (No please just do recursion properly) while keep_going { - thread::sleep(Duration::from_secs(1)); + process_remoute(&mut bzz_db, &listening_socket, recv_buf.as_mut_slice())?; + do_local_work(&bzz_config, &mut bzz_db)?; + // check termination flags + if term_flag.load(Ordering::Relaxed) { + println!("SIGTERM recieved - wrapping things up."); + keep_going = false; + } - // if updates check is turned on - if config.update.updates_check_interval != 0 { - let timestamp = get_timestamp_sec(); - let hours_since_update_check = timestamp - .checked_sub(bzz_db.last_update_check) - .ok_or(DaemonError::TimestampError)? - / 3600; - - if hours_since_update_check > config.update.updates_check_interval { - // perform update check - let packages_num = hive_system::check_updates()?; - // updating las tupdate timestamp in db - bzz_db.last_update_check = get_timestamp_sec(); - hive_db::write_db(&bzz_db)?; - } + // checking reload signal flag + if reload_flag.load(Ordering::Relaxed) { + println!("SIGHUP recieved - reloading config and DB."); + bzz_config = hive_config::read_config()?; + bzz_db = hive_db::read_db()?; + println!("Reloaded!"); } } + println!("Exiting..."); Ok(()) } diff --git a/src/hive_config.rs b/src/hive_config.rs index b332d63..1d47dbd 100644 --- a/src/hive_config.rs +++ b/src/hive_config.rs @@ -23,6 +23,8 @@ use serde::{Serialize, Deserialize}; use std::{fs, io}; use toml; +const CONFIG_PATH: &str = "/etc/hive_up.toml"; + #[derive(Debug, Serialize, Deserialize)] pub struct HiveConfig { // Matches [kernel] in TOML @@ -91,18 +93,18 @@ impl std::fmt::Display for ConfigError { // Implement std::error::Error impl std::error::Error for ConfigError {} -pub fn read_config(conf_file: &str) -> Result { - let file_content = fs::read_to_string(conf_file)?; +pub fn read_config() -> Result { + let file_content = fs::read_to_string(CONFIG_PATH)?; let config:HiveConfig = toml::from_str(&file_content)?; Ok(config) } -pub fn change_updates_check_interval(conf_file: &str, new_interval: u64) -> Result { - let mut config: HiveConfig = read_config(conf_file)?; +pub fn change_updates_check_interval(new_interval: u64) -> Result { + let mut config: HiveConfig = read_config()?; config.update.updates_check_interval = new_interval; let conf_str = toml::to_string_pretty(&config)?; - fs::write(conf_file, conf_str)?; + fs::write(CONFIG_PATH, conf_str)?; Ok(config) diff --git a/src/hive_db.rs b/src/hive_db.rs index 54ab8d6..fdc6b87 100644 --- a/src/hive_db.rs +++ b/src/hive_db.rs @@ -58,9 +58,16 @@ impl std::error::Error for DBError {} #[derive(Serialize, Deserialize, Debug)] pub struct HiveDb { - pub last_update_check: u64, - pub update_sucess_status: bool, - pub last_update_timestamp: String, + /// Timestamp of last check for updates in seconds from UNIX_EPOCH + pub update_check_timestamp: u64, + /// non zero if there is updates that can bee applied, showing numbers of packages that can be updated + pub updates_available: u32, + /// true if last update fas successful + pub update_status: bool, + /// datetime of last snapshot in format "%Y-%m-%dT%H:%M:%S" + pub last_snapshot_time: String, + /// set to true if we want to apply available updates on reboot + pub update_on_reboot: bool, } pub fn read_db() -> Result { @@ -81,8 +88,8 @@ pub fn write_db(db: &HiveDb) -> Result<(), DBError> { /// pub fn update_last_check_update_time(new_timestamp: u64) -> Result { let mut db = read_db()?; - let old_value = db.last_update_check; - db.last_update_check = new_timestamp; + let old_value = db.update_check_timestamp; + db.update_check_timestamp = new_timestamp; write_db(&db)?; Ok(old_value) } @@ -93,8 +100,8 @@ pub fn update_last_check_update_time(new_timestamp: u64) -> Result /// pub fn update_update_status(sucess_status: bool) -> Result { let mut db = read_db()?; - let old_value = db.update_sucess_status; - db.update_sucess_status = sucess_status; + let old_value = db.update_status; + db.update_status = sucess_status; write_db(&db)?; Ok(old_value) } @@ -105,8 +112,8 @@ pub fn update_update_status(sucess_status: bool) -> Result { /// pub fn update_last_update_timestamp(new_timestamp: String) -> Result { let mut db = read_db()?; - let old_value = db.last_update_timestamp; - db.last_update_timestamp = new_timestamp; + let old_value = db.last_snapshot_time; + db.last_snapshot_time = new_timestamp; write_db(&db)?; Ok(old_value) } diff --git a/src/hive_intercom.rs b/src/hive_intercom.rs new file mode 100644 index 0000000..a8d2e5f --- /dev/null +++ b/src/hive_intercom.rs @@ -0,0 +1,172 @@ +// +// Copyright (C) <2026> + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +/* + hive-up unix socket communication +*/ + +use postcard; +use serde::{Deserialize, Serialize}; +use std::fs; +use std::os::unix::net::{SocketAddr, UnixDatagram}; +use std::time::Duration; + +pub const SOCKET_DIR: &str = "/run/hive-up"; +pub const SOCKET_PATH: &str = "/run/hive-up/hive-intercom.soc"; +pub const CLINET_READ_TIMEOUT: u64 = 5; + +#[derive(Debug)] +pub enum IntercomError { + IoError(std::io::Error), + PostcardError(postcard::Error), + ConnectionClosed, + Timeout, + UnexpectedResponse, + ServerError(String), +} + +// Wrapping IO errors but separating time out error +impl From for IntercomError { + fn from(err: std::io::Error) -> Self { + if err.kind() == std::io::ErrorKind::TimedOut + || err.kind() == std::io::ErrorKind::WouldBlock + { + IntercomError::Timeout + } else { + IntercomError::IoError(err) + } + } +} + +impl From for IntercomError { + fn from(err: postcard::Error) -> Self { + IntercomError::PostcardError(err) + } +} + +impl From for IntercomError { + fn from(err: String) -> Self { + IntercomError::ServerError(err) + } +} + +impl std::fmt::Display for IntercomError { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match self { + IntercomError::IoError(e) => write!(f, "IO Error: {}", e), + IntercomError::PostcardError(e) => { + write!(f, "Data parsing (postcard) error: {}", e) + } + IntercomError::Timeout => write!(f, "Operation Timeout"), + IntercomError::ConnectionClosed => write!(f, "Connection closed"), + IntercomError::UnexpectedResponse => write!(f, "Unexpected response"), + IntercomError::ServerError(err) => write!(f, "Server side error: {}", err), + } + } +} + +// Implement std::error::Error +impl std::error::Error for IntercomError {} + +#[derive(Debug, PartialEq, Serialize, Deserialize)] +pub enum BzzResp { + Working, + Finish, + UpdatesAvailable(u32), + Error(String), +} + +#[derive(Debug, PartialEq, Serialize, Deserialize)] +#[repr(u8)] +pub enum BzzReq { + UpdatesAvailable, + ScheduleUpdate, +} + +pub fn socket_bind(read_timeout_sec: u64) -> Result { + // create socket directory if it is does not exist + if let Ok(path_exist) = fs::exists(SOCKET_DIR) + && path_exist == false + { + fs::create_dir(SOCKET_DIR)?; + } + // remove socket file if any present + let _ = fs::remove_file(SOCKET_PATH); + + // bind datagram unix socket + let socket = UnixDatagram::bind(SOCKET_PATH)?; + socket.set_read_timeout(Some(Duration::from_secs(read_timeout_sec)))?; + Ok(socket) +} + +// for daemon side +pub fn socket_send(socket: &UnixDatagram, client_addr: &SocketAddr, resp: BzzResp) -> Result<(), IntercomError> { + let resp_buff = postcard::to_stdvec(&resp)?; + socket.send_to_addr(resp_buff.as_slice(), client_addr)?; + Ok(()) +} + +// for daemon side +pub fn socket_recv( + socket: &UnixDatagram, + recv_buf: &mut [u8], +) -> Result<(BzzReq, SocketAddr), IntercomError> { + match socket.recv_from(recv_buf) { + Ok((rec_count, client_addr)) => { + if rec_count != 0 { + println!("DEBUG: Total bytes recieved {}", rec_count); + let decoded_req: BzzReq = postcard::from_bytes(&recv_buf)?; + Ok((decoded_req, client_addr)) + } else { + Err(IntercomError::ConnectionClosed) + } + } + Err(ex) => Err(ex.into()), + } +} + +fn send_and_recv(request: BzzReq) -> Result { + let socket = UnixDatagram::unbound()?; + socket.connect(SOCKET_PATH)?; + socket.set_read_timeout(Some(Duration::from_secs(CLINET_READ_TIMEOUT)))?; + + let encoded_buf = postcard::to_stdvec(&request)?; + + socket.send(encoded_buf.as_slice())?; + + let mut recv_buf: Vec = Vec::with_capacity(1024); + match socket.recv(recv_buf.as_mut_slice()) { + Ok(rec_count) => { + if rec_count != 0 { + println!("DEBUG: Total bytes recieved {}", rec_count); + let decoded_resp: BzzResp = postcard::from_bytes(&recv_buf)?; + Ok(decoded_resp) + } else { + Err(IntercomError::ConnectionClosed) + } + } + Err(e) => Err(e.into()), + } +} + +fn updates_available() -> Result { + let resp = send_and_recv(BzzReq::UpdatesAvailable)?; + match resp { + BzzResp::UpdatesAvailable(updates_count) => Ok(updates_count), + BzzResp::Error(ex) => Err(IntercomError::ServerError(ex)), + _ => Err(IntercomError::UnexpectedResponse), + } +} diff --git a/src/hive_system.rs b/src/hive_system.rs index e114e00..e82673e 100644 --- a/src/hive_system.rs +++ b/src/hive_system.rs @@ -134,11 +134,13 @@ pub fn exec_command_out(cmd: &str, args: &Vec<&str>) -> Result Result { +pub fn check_updates() -> Result { + // Synchronize pacman DB exec_command("pacman", &vec!["-Sy"])?; + // Check for updates let out = Command::new("pacman").arg("-Qu").output()?; if out.status.success() { - Ok(String::from_utf8(out.stdout)?.lines().count()) + Ok(String::from_utf8(out.stdout)?.lines().count().try_into().unwrap()) } else { if let Some(code) = out.status.code() && code == 1 { Ok(0) } else { @@ -149,7 +151,7 @@ pub fn check_updates() -> Result { /// /// sudo pacman -Suw --noconfirm --noprogressbar -/// Dopwnload updates (need to check for updates first) +/// Download updates (need to check for updates first) /// pub fn download_updates() -> Result<(), ExecCommandError> { exec_command("pacman", &vec!["-Suw", "--noconfirm", "--noprogressbar"]) diff --git a/src/main.rs b/src/main.rs index c0324bb..61b76da 100644 --- a/src/main.rs +++ b/src/main.rs @@ -16,9 +16,9 @@ use clap::{Args, Parser}; use signal_hook::{consts::SIGINT, iterator::Signals}; -use std::{error::Error, thread, time::Duration}; use std::sync::Arc; use std::sync::atomic::{AtomicBool, Ordering}; +use std::{error::Error, thread, time::Duration}; mod hive_system; use hive_system::ExecCommandError; @@ -26,11 +26,9 @@ use hive_system::ExecCommandError; mod hive_config; use hive_config::{HiveConfig, KernelConfig}; -mod hive_db; - mod daemon; - -const CONFIG_PATH_STR: &str = "/etc/hive_up.toml"; +mod hive_db; +mod hive_intercom; // Define the mutually exclusive group #[derive(Args, Debug)] @@ -62,7 +60,7 @@ struct Cli { mode: HiveUpMode, } -fn main() { +fn main() -> Result<(), String> { // registering signals handling let term_flag: Arc = Arc::new(AtomicBool::new(false)); let reload_flag = Arc::new(AtomicBool::new(false)); @@ -73,18 +71,15 @@ fn main() { let args = Cli::parse(); if !hive_system::check_if_run_as_root() { - eprintln!("Error: This program requires root privileges."); - std::process::exit(1); + return Err("Error: This program requires root privileges.".to_string()); } // read config - let hive_config = match hive_config::read_config(CONFIG_PATH_STR) { + let bzz_config = match hive_config::read_config() { Ok(conf) => conf, Err(ex) => { - println!("Error reading \"{}\" hive-up config file: {}", CONFIG_PATH_STR, ex); - std::process::exit(2); + return Err(format!("Error reading hive-up config file: {}", ex)); } - }; // Logic to check which one was set @@ -99,17 +94,16 @@ fn main() { } else if args.mode.update { println!("update mode"); } else if args.mode.daemon { - let snaps = hive_system::list_bzzpss_snaps().unwrap(); - println!("Snaps num: {}", snaps.len()); - for sn in snaps { - println!("Snap: {}", sn); + if let Err(ex) = daemon::run(bzz_config, term_flag.clone(), reload_flag.clone()) { + return Err(format!("Hive-Up daemon error: {}", ex)); } + + // let snaps = hive_system::list_bzzpss_snaps().unwrap(); + // println!("Snaps num: {}", snaps.len()); + // for sn in snaps { + // println!("Snap: {}", sn); + // } } - while !term_flag.load(Ordering::Relaxed) { - // Do some time-limited stuff here - // (if this could block forever, then there's no guarantee the signal will have any - // effect). - } - + Ok(()) }