use crate::actions::action::ProcessedMagnets; use crate::config::Config; use crate::db::Database; use crate::reddit_client::RedditPost; use crate::services::action::ActionService; use crate::services::database::DatabaseService; use crate::services::notification::NotificationService; use crate::services::post_processor::PostProcessorService; use crate::services::reddit::RedditService; use crate::services::report::ReportService; use color_eyre::eyre::Result; use multimap::MultiMap; use std::cell::RefCell; use std::collections::{HashMap, HashSet}; use std::rc::Rc; /// Trait for configurations that can be enabled or disabled pub trait Enableable { /// Returns whether the configuration is enabled fn is_enabled(&self) -> bool; } /// Application state and behavior pub struct App { config: Config, action_service: ActionService, notification_service: NotificationService, reddit_service: RedditService, post_processor: PostProcessorService, report_service: ReportService, } impl App { /// Create a new App instance pub fn new(db: Database, config: Config) -> Self { let db_service = Rc::new(RefCell::new(DatabaseService::new(db))); Self { config, action_service: ActionService::new(Rc::clone(&db_service)), notification_service: NotificationService::new(), reddit_service: RedditService::new(), post_processor: PostProcessorService::new(Rc::clone(&db_service)), report_service: ReportService::new(), } } /// Initialize actions based on configuration pub fn init_actions(&mut self) -> Result<()> { self.action_service.init_actions(&self.config) } /// Initialize notifications based on configuration pub fn init_notifications(&mut self) -> Result<()> { self.notification_service.init_notifications(&self.config) } /// Fetch posts from Reddit pub async fn fetch_posts(&self, post_count: u32) -> Result> { let mut unique_usernames = HashSet::new(); for source_config in self.config.sources.values() { unique_usernames.insert(source_config.username.clone()); } let user_posts = self .reddit_service .fetch_posts_from_users(unique_usernames, post_count) .await?; Ok(user_posts) } /// Process sources and extract magnet links pub async fn process_sources( &mut self, user_posts: &MultiMap, ) -> Result { self.post_processor .process_sources(user_posts, &self.config.sources) } /// Process magnet links with actions pub async fn process_actions(&mut self) -> Result> { self.action_service.process_actions().await } /// Send notifications pub async fn send_notifications( &self, action_results: &HashMap, total_new_links: usize, ) -> Result<()> { self.notification_service .send_notifications(action_results, total_new_links) .await } /// Generate and display report pub fn generate_report( &self, action_results: &HashMap, total_new_links: usize, ) { self.report_service .generate_report(action_results, total_new_links); } pub async fn run(&mut self, post_count: u32) -> Result<()> { self.init_actions()?; self.init_notifications()?; // Fetch posts from Reddit let user_posts = self.fetch_posts(post_count).await?; // Process sources and extract magnet links let total_new_links = self.process_sources(&user_posts).await?; // Process magnet links with actions let action_results = self.process_actions().await?; // Send notifications self.send_notifications(&action_results, total_new_links) .await?; // Generate and display report self.generate_report(&action_results, total_new_links); Ok(()) } }