From fc8740fe91e24c4d0bd0bc94e7ef66ff2a2c0560 Mon Sep 17 00:00:00 2001 From: Dastan-glitch Date: Mon, 21 Aug 2023 05:05:17 +0300 Subject: [PATCH] bin/darkirc: implement removing events older than one week, and save/load tree state --- bin/darkirc/darkirc_config.toml | 14 ++++++-- bin/darkirc/src/main.rs | 61 +++++++++++++++++++++++++-------- bin/darkirc/src/settings.rs | 4 +++ 3 files changed, 62 insertions(+), 17 deletions(-) diff --git a/bin/darkirc/darkirc_config.toml b/bin/darkirc/darkirc_config.toml index 775b6c791..c5a779c4c 100644 --- a/bin/darkirc/darkirc_config.toml +++ b/bin/darkirc/darkirc_config.toml @@ -13,8 +13,18 @@ ## TLS secret key path if IRC acceptor uses TLS (optional) #irc_tls_secret = "/etc/letsencrypt/ircd/privkey.pem" +## Sets Datastore Path +#datastore = "~/.darkirc" + ## List of channels to autojoin for new client connections -autojoin = ["#dev", "#memes", "#philosophy", "#markets", "#math", "#random"] +autojoin = [ + "#dev", + "#memes", + "#philosophy", + "#markets", + "#math", + "#random", +] ## Daemon specific password (optional, but once you configure it, ## it is required from the client side) @@ -26,7 +36,7 @@ autojoin = ["#dev", "#memes", "#philosophy", "#markets", "#math", "#random"] #inbound = ["tcp+tls://0.0.0.0:26661", "tcp+tls://[::]:26661"] ## Connection slots -outbound_connections=8 +outbound_connections = 8 ## Addresses we want to advertise to peers (optional) ## These should be reachable externally diff --git a/bin/darkirc/src/main.rs b/bin/darkirc/src/main.rs index 2e745aa7e..d01b4ff31 100644 --- a/bin/darkirc/src/main.rs +++ b/bin/darkirc/src/main.rs @@ -16,13 +16,14 @@ * along with this program. If not, see . */ -use std::collections::HashMap; +use std::{collections::HashMap, fs::create_dir_all}; use async_std::{ stream::StreamExt, sync::{Arc, Mutex}, task, }; + use chrono::{Duration, Utc}; use irc::ClientSubMsg; use log::{debug, info}; @@ -72,7 +73,8 @@ async fn parse_signals( } } -async fn reset_root(model: ModelPtr) { +// Removes events older than one week ,then sleeps untill next midnight +async fn remove_old_events(model: ModelPtr) -> Result<()> { loop { let now = Utc::now(); @@ -81,21 +83,24 @@ async fn reset_root(model: ModelPtr) { let duration = next_midnight.signed_duration_since(now.naive_utc()).to_std().unwrap(); - // make sure the root is the same as everyone else's at - // startup by passing today's date 00:00 AM UTC as - // timestamp to root_event - let now_datetime = now.date_naive().and_hms_opt(0, 0, 0).unwrap(); - let timestamp = now_datetime.timestamp() as u64; + let week_old_datetime = + (now - Duration::weeks(1)).date_naive().and_hms_opt(0, 0, 0).unwrap(); + let timestamp = week_old_datetime.timestamp() as u64; - model.lock().await.reset_root(Timestamp(timestamp)); + model.lock().await.remove_old_events(Timestamp(timestamp))?; + info!("Removing old events"); - sleep(duration.as_secs()).await; - info!("Resetting root"); + sleep(duration.as_secs() + 1).await; } } async_daemonize!(realmain); async fn realmain(settings: Args, executor: Arc>) -> Result<()> { + let datastore_path = expand_path(&settings.datastore)?; + + // mkdir datastore_path if not exists + create_dir_all(datastore_path.clone())?; + // Signal handling for config reload and graceful termination. let (signals_handler, signals_task) = SignalHandler::new()?; let client_sub = Subscriber::new(); @@ -155,10 +160,29 @@ async fn realmain(settings: Args, executor: Arc>) -> Result<( //////////////////// let events_queue = EventsQueue::::new(); let model = Arc::new(Mutex::new(Model::new(events_queue.clone()))); - let view = Arc::new(Mutex::new(View::new(events_queue))); + let view = Arc::new(Mutex::new(View::new(events_queue.clone()))); let model_clone = model.clone(); let model_clone2 = model.clone(); + { + // Temporarly load model and check if the loaded head is not + // older than one week (already removed from other node's tree) + let now = Utc::now(); + + let now_datetime = (now - Duration::weeks(1)).date_naive().and_hms_opt(0, 0, 0).unwrap(); + let timestamp = Timestamp(now_datetime.timestamp() as u64); + + let mut loaded_model = Model::new(events_queue.clone()); + loaded_model.load_tree(&datastore_path)?; + + if loaded_model + .get_event(&loaded_model.get_head_hash()) + .is_some_and(|event| event.timestamp >= timestamp) + { + model.lock().await.load_tree(&datastore_path)?; + } + } + //////////////////// // P2p setup //////////////////// @@ -207,21 +231,28 @@ async fn realmain(settings: Args, executor: Arc>) -> Result<( //////////////////// // New irc server - let irc_server = - IrcServer::new(settings.clone(), p2p.clone(), model_clone, view.clone(), client_sub) - .await?; + let irc_server = IrcServer::new( + settings.clone(), + p2p.clone(), + model_clone.clone(), + view.clone(), + client_sub, + ) + .await?; // Start the irc server and detach it let executor_cloned = executor.clone(); executor.spawn(async move { irc_server.start(executor_cloned).await }).detach(); // Reset root task - executor.spawn(async move { reset_root(model_clone2).await }).detach(); + executor.spawn(async move { remove_old_events(model_clone2).await }).detach(); // Wait for termination signal signals_handler.wait_termination(signals_task).await?; info!("Caught termination signal, cleaning up and exiting..."); + model_clone.lock().await.save_tree(&datastore_path)?; + // stop p2p p2p2.stop().await; Ok(()) diff --git a/bin/darkirc/src/settings.rs b/bin/darkirc/src/settings.rs index 3baeb59ca..dfb6525e0 100644 --- a/bin/darkirc/src/settings.rs +++ b/bin/darkirc/src/settings.rs @@ -53,6 +53,10 @@ pub struct Args { #[structopt(long)] pub config: Option, + /// Sets Datastore Path + #[structopt(long, default_value = "~/.darkirc")] + pub datastore: String, + /// JSON-RPC listen URL #[structopt(long = "rpc", default_value = "tcp://127.0.0.1:26660")] pub rpc_listen: Url,