2026-08-21 20:58:06 +02:00
|
|
|
// <hive-up - update program fot Kira Linux.>
|
|
|
|
|
// Copyright (C) <2026> <Kira Foundation>
|
|
|
|
|
|
|
|
|
|
// 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 <https://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
hive-up daemon logic
|
|
|
|
|
*/
|
|
|
|
|
|
2026-08-27 16:53:56 +02:00
|
|
|
use std::os::unix::net::UnixDatagram;
|
2026-08-21 20:58:06 +02:00
|
|
|
use std::sync::Arc;
|
|
|
|
|
use std::sync::atomic::{AtomicBool, Ordering};
|
|
|
|
|
use std::thread;
|
2026-08-26 11:12:06 +02:00
|
|
|
use std::time::{Duration, SystemTime, UNIX_EPOCH};
|
2026-08-21 20:58:06 +02:00
|
|
|
|
2026-08-27 16:53:56 +02:00
|
|
|
use crate::hive_config;
|
2026-08-21 20:58:06 +02:00
|
|
|
use crate::hive_config::HiveConfig;
|
2026-08-26 11:12:06 +02:00
|
|
|
use crate::hive_db::{self, HiveDb};
|
2026-08-27 16:53:56 +02:00
|
|
|
use crate::hive_intercom::{self, BzzReq, BzzResp, IntercomError};
|
2026-08-21 20:58:06 +02:00
|
|
|
use crate::hive_system;
|
|
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
|
pub enum DaemonError {
|
|
|
|
|
IoError(std::io::Error),
|
|
|
|
|
DBError(hive_db::DBError),
|
2026-08-26 11:12:06 +02:00
|
|
|
ConfigError(hive_config::ConfigError),
|
2026-08-21 20:58:06 +02:00
|
|
|
ExecCommandError(hive_system::ExecCommandError),
|
|
|
|
|
TimestampError,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 2. Implement From for each wrapped error type
|
|
|
|
|
impl From<std::io::Error> for DaemonError {
|
|
|
|
|
fn from(err: std::io::Error) -> Self {
|
|
|
|
|
DaemonError::IoError(err)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl From<hive_db::DBError> for DaemonError {
|
|
|
|
|
fn from(err: hive_db::DBError) -> Self {
|
|
|
|
|
DaemonError::DBError(err)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-26 11:12:06 +02:00
|
|
|
impl From<hive_config::ConfigError> for DaemonError {
|
|
|
|
|
fn from(err: hive_config::ConfigError) -> Self {
|
|
|
|
|
DaemonError::ConfigError(err)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-21 20:58:06 +02:00
|
|
|
impl From<hive_system::ExecCommandError> for DaemonError {
|
|
|
|
|
fn from(err: hive_system::ExecCommandError) -> Self {
|
|
|
|
|
DaemonError::ExecCommandError(err)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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),
|
2026-08-26 11:12:06 +02:00
|
|
|
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),
|
2026-08-21 20:58:06 +02:00
|
|
|
DaemonError::TimestampError => write!(f, "Timestamp Error"),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Implement std::error::Error
|
|
|
|
|
impl std::error::Error for DaemonError {}
|
|
|
|
|
|
|
|
|
|
fn get_timestamp_sec() -> u64 {
|
|
|
|
|
SystemTime::now()
|
|
|
|
|
.duration_since(UNIX_EPOCH)
|
|
|
|
|
.expect("Time went backwards")
|
|
|
|
|
.as_secs()
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-26 11:12:06 +02:00
|
|
|
/// bloking function. Bloaks for configured socker recv timeout
|
2026-08-27 16:53:56 +02:00
|
|
|
fn process_remoute(
|
|
|
|
|
bzz_db: &mut HiveDb,
|
|
|
|
|
listening_socket: &UnixDatagram,
|
|
|
|
|
recv_buf: &mut [u8],
|
|
|
|
|
) -> Result<(), DaemonError> {
|
2026-08-26 11:12:06 +02:00
|
|
|
// waiting on socket recv_from untill timeout (also using this as a timer)
|
2026-08-27 16:53:56 +02:00
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
BzzReq::CheckForUpdates => {
|
|
|
|
|
let resp = BzzResp::Working(1);
|
|
|
|
|
if let Err(ex) =
|
|
|
|
|
hive_intercom::socket_send(&listening_socket, &client_addr, resp)
|
|
|
|
|
{
|
|
|
|
|
println!("Error while ansvering cli request: {}", ex);
|
|
|
|
|
} else {
|
|
|
|
|
// 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
|
|
|
|
|
);
|
|
|
|
|
// send evailable updates numbet to client
|
2026-08-26 11:12:06 +02:00
|
|
|
let resp = BzzResp::UpdatesAvailable(bzz_db.updates_available);
|
2026-08-27 16:53:56 +02:00
|
|
|
if let Err(ex) =
|
|
|
|
|
hive_intercom::socket_send(&listening_socket, &client_addr, resp)
|
|
|
|
|
{
|
2026-08-26 11:12:06 +02:00
|
|
|
println!("Error while ansvering cli request: {}", ex);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-08-27 16:53:56 +02:00
|
|
|
Ok(())
|
2026-08-26 11:12:06 +02:00
|
|
|
}
|
2026-08-27 16:53:56 +02:00
|
|
|
// 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(())
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-08-26 11:12:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// doing what daemons usually beezz
|
2026-08-27 16:53:56 +02:00
|
|
|
fn do_local_work(config: &HiveConfig, bzz_db: &mut HiveDb) -> Result<(), DaemonError> {
|
2026-08-26 11:12:06 +02:00
|
|
|
// if updates check is turned on
|
2026-09-05 23:24:08 +02:00
|
|
|
if config.update.check_interval != 0 {
|
2026-08-26 11:12:06 +02:00
|
|
|
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
|
2026-09-05 23:24:08 +02:00
|
|
|
if hours_since_update_check > config.update.check_interval {
|
2026-08-26 11:12:06 +02:00
|
|
|
// perform update check
|
|
|
|
|
println!("Cheking for updates...");
|
2026-08-27 16:53:56 +02:00
|
|
|
// now that may fail because of bad internet and idealy we
|
2026-08-26 11:12:06 +02:00
|
|
|
// 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)?;
|
2026-08-27 16:53:56 +02:00
|
|
|
println!(
|
|
|
|
|
"Found {} packages that needs to be updated.",
|
|
|
|
|
bzz_db.updates_available
|
|
|
|
|
);
|
2026-08-26 11:12:06 +02:00
|
|
|
|
|
|
|
|
// 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() {
|
2026-08-27 16:53:56 +02:00
|
|
|
Ok(()) => {
|
|
|
|
|
println!("Updates downloaded...");
|
|
|
|
|
}
|
|
|
|
|
Err(ex) => {
|
|
|
|
|
println!("Error downloading updates: {}", ex);
|
|
|
|
|
}
|
2026-08-26 11:12:06 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// updating las tcheck for updates timestamp in db
|
|
|
|
|
bzz_db.update_check_timestamp = get_timestamp_sec();
|
|
|
|
|
hive_db::write_db(&bzz_db)?;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-21 20:58:06 +02:00
|
|
|
pub fn run(
|
2026-08-26 11:12:06 +02:00
|
|
|
mut bzz_config: HiveConfig,
|
2026-08-21 20:58:06 +02:00
|
|
|
term_flag: Arc<AtomicBool>,
|
|
|
|
|
reload_flag: Arc<AtomicBool>,
|
|
|
|
|
) -> Result<(), DaemonError> {
|
2026-08-26 11:12:06 +02:00
|
|
|
// reading db from disk
|
2026-08-21 20:58:06 +02:00
|
|
|
let mut bzz_db = hive_db::read_db()?;
|
|
|
|
|
|
2026-08-26 11:12:06 +02:00
|
|
|
// stop flag
|
|
|
|
|
let mut keep_going = true;
|
2026-08-21 20:58:06 +02:00
|
|
|
|
2026-08-26 11:12:06 +02:00
|
|
|
// init udp unix socket for communication with cli and such
|
|
|
|
|
let listening_socket = hive_intercom::socket_bind(1)?;
|
|
|
|
|
let mut recv_buf: Vec<u8> = Vec::with_capacity(1024);
|
2026-08-27 16:53:56 +02:00
|
|
|
|
2026-08-26 11:12:06 +02:00
|
|
|
// main loop (I love loops) (No please just do recursion properly)
|
2026-08-21 20:58:06 +02:00
|
|
|
while keep_going {
|
2026-08-26 11:12:06 +02:00
|
|
|
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;
|
|
|
|
|
}
|
2026-08-21 20:58:06 +02:00
|
|
|
|
2026-08-26 11:12:06 +02:00
|
|
|
// 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!");
|
2026-08-21 20:58:06 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-26 11:12:06 +02:00
|
|
|
println!("Exiting...");
|
2026-08-21 20:58:06 +02:00
|
|
|
Ok(())
|
|
|
|
|
}
|