Compare commits

...

2 commits

Author SHA1 Message Date
ebbfdcea63
Split Memory Log into Log Levels, support different lenght limits (hardcoded for now)
All checks were successful
Run Tests on Code / run-tests (push) Successful in 17s
2024-07-21 14:10:52 +02:00
ff0360ac07
Implement Settings Updating inside Bot thread, Improve Status Ping behaviour 2024-07-21 14:10:21 +02:00
5 changed files with 123 additions and 51 deletions

View file

@ -12,9 +12,10 @@ use crate::settings::{BotSettings, SeriesSettings};
pub(crate) struct Bot {
settings: BotSettings,
settings_id: u16,
health_signal: Arc<AtomicHealthSignal>,
history: SeriesHistory,
login_time: Option<DateTime<Utc>>
login_time: Option<DateTime<Utc>>,
}
enum Wait {
@ -23,16 +24,26 @@ enum Wait {
}
impl Bot {
pub(crate) fn new(health_signal: Arc<AtomicHealthSignal>, settings: BotSettings) -> Self {
pub(crate) fn new(health_signal: Arc<AtomicHealthSignal>, settings_id: u16, settings: BotSettings) -> Self {
let history: SeriesHistory = SeriesHistory::load_history();
Bot { health_signal, settings, history, login_time: None }
Bot { health_signal, settings_id, settings, history, login_time: None }
}
pub(crate) fn run(&mut self, series_settings: Arc<RwLock<HashMap<u16, SeriesSettings>>>, update_pending: Arc<AtomicBool>) {
pub(crate) fn run(
&mut self,
series_settings: Arc<RwLock<HashMap<u16, SeriesSettings>>>,
bot_settings: Arc<RwLock<HashMap<u16, BotSettings>>>,
update_pending: Arc<AtomicBool>
) {
let mut last_ping = Utc::now();
if let Some(interval) = self.settings.status_post_interval() {
last_ping -= interval
}
loop {
match self.health_signal.load(Ordering::SeqCst) {
HealthSignal::RequestAlive => {
//self.health_signal.store(HealthSignal::ConfirmAlive, Ordering::SeqCst);
self.health_signal.store(HealthSignal::ConfirmAlive, Ordering::SeqCst);
}
HealthSignal::RequestStop => {
break;
@ -40,53 +51,64 @@ impl Bot {
_ => {}
}
while update_pending.load(Ordering::SeqCst) {
if update_pending.load(Ordering::SeqCst) {
Logging::debug("Awaiting Config Update");
sleep(Duration::milliseconds(100).to_std().unwrap());
continue
}
self.settings = bot_settings.read().get(&self.settings_id).unwrap().clone();
// perform status ping
if let Some(interval) = self.settings.status_post_interval() {
if Utc::now() + Duration::seconds(1) >= last_ping + interval {
if self.ping_status() {
last_ping = Utc::now();
}
else {
continue
}
}
}
if let Some(login_time) = self.login_time {
if Utc::now() - login_time >= Duration::minutes(60) {
self.logout();
//self.logout();
continue
}
}
else {
self.login();
//self.login();
}
self.history = SeriesHistory::load_history();
let run_start_time = Utc::now();
self.ping_status();
series_settings.read().iter().for_each(|(id, series)| {
let new_entries = series.check();
//let new_entries = series.check();
});
for series in series_settings.read().iter() {
//series.update(&mut self.history, &lemmy, &self.settings).await;
Logging::debug("Done Updating Series");
self.wait(1, Wait::Absolute);
}
Logging::debug("Awaiting Timeout");
self.wait(30, Wait::Buffer(run_start_time));
Logging::debug("Pinging Server");
self.ping_status();
Logging::debug("Awaiting Timeout 2");
self.wait(30, Wait::Absolute);
}
self.health_signal.store(HealthSignal::ConfirmStop, Ordering::SeqCst);
}
fn ping_status(&self) {
fn ping_status(&self) -> bool {
if let Some(status_url) = &self.settings.status_post_url() {
match HTTP_CLIENT.get(status_url).send() {
Ok(_) => {},
return match HTTP_CLIENT.get(status_url).send() {
Ok(_) => {
true
},
Err(e) => {
let err_msg = format!("While pinging status URL: {e}");
Logging::error(err_msg.as_str());
false
}
}
}
false
}
fn wait(&self, seconds: i64, start_time: Wait) {
@ -99,15 +121,14 @@ impl Bot {
sleep(Duration::milliseconds(100).to_std().unwrap());
}
}
fn login(&mut self) {
//
todo!();
self.login_time = Some(Utc::now());
todo!()
}
fn logout(&mut self) {
self.login_time = None;
todo!()
todo!();
}
}

View file

@ -1,22 +1,52 @@
use std::collections::VecDeque;
use chrono::{DateTime, Utc};
use log::Level;
use parking_lot::Mutex;
use systemd_journal_logger::connected_to_journal;
fn mem_log(msg: Option<String>) -> VecDeque<LogEvent> {
static MEM_LOG: Mutex<VecDeque<LogEvent>> = Mutex::new(VecDeque::new());
fn mem_log(level: Level, msg: Option<String>) -> VecDeque<LogEvent> {
static MEM_LOG_DEBUG: Mutex<VecDeque<LogEvent>> = Mutex::new(VecDeque::new());
static MEM_LOG_INFO: Mutex<VecDeque<LogEvent>> = Mutex::new(VecDeque::new());
static MEM_LOG_WARN: Mutex<VecDeque<LogEvent>> = Mutex::new(VecDeque::new());
static MEM_LOG_ERROR: Mutex<VecDeque<LogEvent>> = Mutex::new(VecDeque::new());
let max_len: i8;
let mut list = match level {
Level::Debug => {
max_len = 10;
MEM_LOG_DEBUG.lock()
},
Level::Info => {
max_len = 20;
MEM_LOG_INFO.lock()
},
Level::Warn => {
max_len = 40;
MEM_LOG_WARN.lock()
},
Level::Error => {
max_len = -1;
MEM_LOG_ERROR.lock()
},
Level::Trace => {
max_len = 10;
MEM_LOG_DEBUG.lock()
}
};
if let Some(msg) = msg {
let now = Utc::now();
let log_event = LogEvent::new(now, msg);
let mut lock = MEM_LOG.lock();
lock.push_back(log_event);
while lock.len() > 10 {
lock.pop_front();
list.push_back(log_event);
if max_len != -1 {
while list.len() > max_len as usize {
list.pop_front();
}
}
}
return MEM_LOG.lock().clone();
list.clone()
}
pub struct Logging {
@ -29,7 +59,7 @@ impl Logging {
true => log::debug!("{msg}"),
false => println!("{msg}"),
}
mem_log(Some(msg));
mem_log(Level::Debug, Some(msg));
}
pub fn info(msg: &str) {
@ -38,7 +68,7 @@ impl Logging {
true => log::info!("{msg}"),
false => println!("{msg}"),
}
mem_log(Some(msg));
mem_log(Level::Info, Some(msg));
}
pub fn warn(msg: &str) {
@ -47,7 +77,7 @@ impl Logging {
true => log::warn!("{msg}"),
false => println!("{msg}"),
}
mem_log(Some(msg));
mem_log(Level::Warn, Some(msg));
}
pub fn error(msg: &str) {
@ -56,11 +86,11 @@ impl Logging {
true => log::error!("{msg}"),
false => eprintln!("{msg}"),
}
mem_log(Some(msg));
mem_log(Level::Error, Some(msg));
}
pub fn get_mem_log() -> VecDeque<LogEvent> {
mem_log(None)
pub fn get_mem_log(level: Level) -> VecDeque<LogEvent> {
mem_log(level, None)
}
}

View file

@ -59,18 +59,19 @@ fn main() {
let mut health_signals: Vec<Arc<AtomicHealthSignal>> = vec![];
let mut update_pending: Arc<AtomicBool> = Arc::new(AtomicBool::new(false));
let series_settings = settings.read().series_settings().clone();
settings.read().bot_settings().read().iter().for_each(|(id, bot_settings)| {
let health_signal = Arc::new(AtomicHealthSignal::new(HealthSignal::RequestAlive));
health_signals.push(health_signal.clone());
let bot_settings = bot_settings.clone();
let series_settings = series_settings.clone();
let bot_id = *id;
let series_settings = settings.read().series_settings().clone();
let bot_settings_map = settings.read().bot_settings().clone();
let update_pending = update_pending.clone();
spawn(move || {
let mut bot = Bot::new(health_signal, bot_settings);
bot.run(series_settings, update_pending);
let mut bot = Bot::new(health_signal, bot_id, bot_settings);
bot.run(series_settings, bot_settings_map, update_pending);
});
});

View file

@ -69,6 +69,12 @@ impl ApplicationSettings {
}
}
#[derive(Clone)]
pub struct StatusPostSettings {
url: String,
interval: Duration,
}
#[derive(Clone)]
pub struct BotSettings {
id: u16,
@ -76,7 +82,7 @@ pub struct BotSettings {
instance: String,
username: SensitiveString,
password: SensitiveString,
status_post_url: Option<String>,
status_post_settings: Option<StatusPostSettings>,
}
impl BotSettings {
pub fn instance(&self) -> String {
@ -90,7 +96,17 @@ impl BotSettings {
}
pub fn status_post_url(&self) -> Option<String> {
self.status_post_url.clone()
match &self.status_post_settings {
Some(settings) => Some(settings.url.clone()),
None => None
}
}
pub fn status_post_interval(&self) -> Option<Duration> {
match &self.status_post_settings {
Some(settings) => Some(settings.interval),
None => None
}
}
}

View file

@ -7,7 +7,7 @@ use crate::config::SeriesConfig;
use crate::fetchers::{Fetcher, FetcherTrait};
use crate::fetchers::jnovel::JNovelFetcher;
use crate::lemmy::PostType;
use crate::settings::{BotSettings, PostSettings, SeriesSettings, SettingsSource};
use crate::settings::{BotSettings, PostSettings, SeriesSettings, SettingsSource, StatusPostSettings};
use crate::settings::toml::TomlSettings;
#[derive(Serialize, Deserialize, Clone, Debug)]
@ -16,9 +16,10 @@ pub struct SingleBotTomlSettings {
username: SensitiveString,
password: SensitiveString,
status_post_url: Option<String>,
status_post_interval: Option<u32>,
pub protected_communities: Vec<String>,
series: Vec<SeriesConfig>,
fetch_interval: usize,
fetch_interval: u32,
}
impl SettingsSource for SingleBotTomlSettings {
@ -41,7 +42,10 @@ impl SettingsSource for SingleBotTomlSettings {
instance: self.instance.clone(),
username: self.username.clone(),
password: self.password.clone(),
status_post_url: self.status_post_url.clone(),
status_post_settings: Some(StatusPostSettings {
url: self.status_post_url.clone().unwrap(),
interval: Duration::from_secs(self.status_post_interval.clone().unwrap() as u64)
}),
});
map
}