use crate::db; use anyhow::{Context, Result}; use chrono::Utc; use rusqlite::Connection; use std::path::Path; use std::sync::Arc; use std::time::Duration; use tokio::sync::{mpsc, Mutex}; use tokio::time; use tracing::{debug, error, info, warn}; pub struct ChatPollerService { chat_db_path: String, us_db: Arc>, tx: mpsc::Sender, poll_interval: Duration, } impl ChatPollerService { pub fn new( chat_db_path: String, us_db: Arc>, tx: mpsc::Sender, poll_interval_ms: u64, ) -> Self { Self { chat_db_path, us_db, tx, poll_interval: Duration::from_millis(poll_interval_ms), } } pub async fn run(&self) -> Result<()> { info!("Starting chat poller service"); info!("Polling {} every {:?}", self.chat_db_path, self.poll_interval); // Get last processed rowid from database let us_db = self.us_db.lock().await; let mut last_rowid = db::get_last_processed_rowid(&us_db) .context("Failed to get last processed rowid")?; drop(us_db); info!("Starting from rowid: {}", last_rowid); let mut interval = time::interval(self.poll_interval); loop { interval.tick().await; match self.poll_messages(last_rowid).await { Ok(new_messages) => { if !new_messages.is_empty() { info!("Found {} new messages", new_messages.len()); for msg in new_messages { // Update last_rowid if msg.rowid > last_rowid { last_rowid = msg.rowid; } // Send message to processing pipeline if let Err(e) = self.tx.send(msg).await { error!("Failed to send message to processing pipeline: {}", e); } } // Save state to database let us_db = self.us_db.lock().await; if let Err(e) = db::save_last_processed_rowid(&us_db, last_rowid) { warn!("Failed to save last processed rowid: {}", e); } drop(us_db); } else { debug!("No new messages"); } } Err(e) => { error!("Error polling messages: {}", e); } } } } async fn poll_messages(&self, last_rowid: i64) -> Result> { // Check if chat.db exists if !Path::new(&self.chat_db_path).exists() { return Err(anyhow::anyhow!("chat.db not found at {}", self.chat_db_path)); } // Open chat.db (read-only) let chat_db = lib::ChatDb::open(&self.chat_db_path) .context("Failed to open chat.db")?; // Get messages with rowid > last_rowid // We'll use the existing get_our_messages but need to filter by rowid // For now, let's get recent messages and filter in-memory let start_date = Some(Utc::now() - chrono::Duration::days(7)); let end_date = Some(Utc::now()); let messages = chat_db .get_our_messages(start_date, end_date) .context("Failed to get messages from chat.db")?; // Filter messages with rowid > last_rowid and ensure they're not duplicates let new_messages: Vec = messages .into_iter() .filter(|msg| msg.rowid > last_rowid) .collect(); // Insert new messages into our database let us_db = self.us_db.lock().await; for msg in &new_messages { if let Err(e) = db::insert_message(&us_db, msg) { warn!("Failed to insert message {}: {}", msg.rowid, e); } } Ok(new_messages) } }