use deadpool_redis::cluster::Pool; use serde::Serialize; use std::sync::Arc; #[derive(Debug, Clone, Serialize)] pub struct TaskLog { pub task_id: String, pub repo_id: String, pub worker_id: String, pub level: String, pub message: String, pub timestamp: chrono::DateTime, } pub struct LogStream { channel: String, worker_id: String, pool: Arc, } impl Clone for LogStream { fn clone(&self) -> Self { Self { channel: self.channel.clone(), worker_id: self.worker_id.clone(), pool: self.pool.clone(), } } } impl LogStream { pub fn new(channel: String, worker_id: String, pool: Arc) -> Self { Self { channel, worker_id, pool, } } async fn publish_log(&self, log: TaskLog) { let data = match serde_json::to_vec(&log) { Ok(d) => d, Err(e) => { eprintln!("failed to serialize log: {}", e); return; } }; let redis = match self.pool.get().await { Ok(c) => c, Err(e) => { eprintln!("redis pool get failed: {}", e); return; } }; let mut conn: deadpool_redis::cluster::Connection = redis; if let Err(e) = redis::cmd("PUBLISH") .arg(&self.channel) .arg(&data) .query_async::<()>(&mut conn) .await { eprintln!("Redis PUBLISH failed: {}", e); } } pub async fn info(&self, task_id: &str, repo_id: &str, message: &str) { self.publish_log(TaskLog { task_id: task_id.to_string(), repo_id: repo_id.to_string(), worker_id: self.worker_id.clone(), level: "info".to_string(), message: message.to_string(), timestamp: chrono::Utc::now(), }) .await; } pub async fn error(&self, task_id: &str, repo_id: &str, message: &str) { self.publish_log(TaskLog { task_id: task_id.to_string(), repo_id: repo_id.to_string(), worker_id: self.worker_id.clone(), level: "error".to_string(), message: message.to_string(), timestamp: chrono::Utc::now(), }) .await; } pub async fn warn(&self, task_id: &str, repo_id: &str, message: &str) { self.publish_log(TaskLog { task_id: task_id.to_string(), repo_id: repo_id.to_string(), worker_id: self.worker_id.clone(), level: "warn".to_string(), message: message.to_string(), timestamp: chrono::Utc::now(), }) .await; } }