aob-lemmy-bot/src/bot.rs

136 lines
4.6 KiB
Rust

use crate::{config::{Config}, HTTP_CLIENT};
use crate::lemmy::{Lemmy};
use crate::post_history::{SeriesHistory};
use chrono::{DateTime, Duration, Utc};
use std::sync::{Arc, RwLock};
use notify::{Event, EventKind, event::{AccessKind, AccessMode}, RecursiveMode, Watcher};
use tokio::time::sleep;
use systemd_journal_logger::connected_to_journal;
macro_rules! debug {
($msg:tt) => {
match connected_to_journal() {
true => log::debug!("[DEBUG] {}", $msg),
false => println!("[DEBUG] {}", $msg),
}
};
}
macro_rules! info {
($msg:tt) => {
match connected_to_journal() {
true => log::info!("[INFO] {}", $msg),
false => println!("[INFO] {}", $msg),
}
};
}
macro_rules! error {
($msg:tt) => {
match connected_to_journal() {
true => log::error!("[ERROR] {}", $msg),
false => eprintln!("[ERROR] {}", $msg),
}
};
}
pub(crate) struct Bot {
shared_config: Arc<RwLock<Config>>,
history: SeriesHistory,
run_start_time: DateTime<Utc>
}
enum Wait {
Absolute,
Buffer
}
impl Bot {
pub(crate) fn new() -> Self {
let config = Config::load();
let shared_config: Arc<RwLock<Config>> = Arc::new(RwLock::new(config));
let shared_config_copy = shared_config.clone();
let mut watcher = notify::recommended_watcher(move |res: Result<Event, notify::Error>| {
match res {
Ok(event) => {
if event.kind == EventKind::Access(AccessKind::Close(AccessMode::Write)) {
let mut write = shared_config_copy.write().expect("Write Lock Failed");
let new_config = Config::load();
write.series = new_config.series;
write.instance = new_config.instance;
write.protected_communities = new_config.protected_communities;
write.status_post_url = new_config.status_post_url;
info!("Reloaded Configuration");
}
},
Err(e) => {
let msg = format!("Error watching files: {e}");
error!(msg);
}
}
}).expect("Watcher Error");
watcher.watch(&Config::get_path(), RecursiveMode::NonRecursive).expect("Error in watcher");
let history: SeriesHistory = SeriesHistory::load_history();
Bot { shared_config, history, run_start_time: Utc::now() }
}
pub(crate) async fn run(&mut self) {
loop {
let mut lemmy = match Lemmy::new(&self.shared_config).await {
Ok(data) => data,
Err(_) => continue,
};
lemmy.get_communities().await;
self.history = SeriesHistory::load_history();
let start: DateTime<Utc> = Utc::now();
while Utc::now() - start <= Duration::minutes(60) {
self.run_start_time = Utc::now();
self.ping_status().await;
let read_copy = self.shared_config.read().expect("Read Lock Failed").clone();
for series in read_copy.series {
series.update(&mut self.history, &lemmy, &self.shared_config).await;
debug!("Done Updating Series");
self.wait(1, Wait::Absolute).await;
}
debug!("Awaiting Timeout");
self.wait(30, Wait::Buffer).await;
debug!("Pinging Server");
self.ping_status().await;
debug!("Awaiting Timeout 2");
self.wait(30, Wait::Absolute).await;
}
lemmy.logout().await;
}
}
async fn ping_status(&self) {
let read_config = &self.shared_config.read().expect("Read Lock Failed").clone();
if let Some(status_url) = &read_config.status_post_url {
match HTTP_CLIENT.get(status_url).send().await {
Ok(_) => {},
Err(e) => {
let err_msg = format!("While pinging status URL: {e}");
error!(err_msg);
}
}
}
}
async fn wait(&self, seconds: i64, start_time: Wait) {
let duration: Duration = Duration::seconds(seconds);
let start_time: DateTime<Utc> = match start_time {
Wait::Absolute => Utc::now(),
Wait::Buffer => self.run_start_time,
};
while Utc::now() - start_time < duration {
sleep(Duration::milliseconds(100).to_std().unwrap()).await
}
}
}