text/x-rust
•
2.40 KB
•
81 lines
use std::{
any::Any,
fs,
sync::{
Arc,
atomic::{AtomicBool, Ordering},
},
time::Instant,
};
use anyhow::Result;
use rubhub_auth_store::AuthStore;
use tokio::sync::{OnceCell, broadcast};
use super::{AppConfig, RepoEvent};
/// Type-erased CI job sender (allows main crate to set specific sender type)
type CiJobSender = Box<dyn Any + Send + Sync>;
/// Global application state
#[derive(Debug, Clone)]
pub struct GlobalState {
pub auth: Arc<AuthStore>,
pub config: Arc<AppConfig>,
pub process_start: Instant,
pub event_tx: broadcast::Sender<RepoEvent>,
pub local_podman_ci_available: Arc<AtomicBool>,
ci_job_tx: Arc<OnceCell<CiJobSender>>,
}
impl GlobalState {
/// Build a full URI from a path using the configured base URL
pub fn uri(&self, path: &str) -> String {
format!("{}{}", self.config.base_url, path)
}
/// Check if any CI backend is available and enabled
pub fn ci_available(&self) -> bool {
self.local_podman_ci_available.load(Ordering::Relaxed)
}
/// Create a new GlobalState instance
pub fn new(config: AppConfig, process_start: Instant) -> Result<Self> {
fs::create_dir_all(&config.dir_root)?;
fs::create_dir_all(&config.git_root)?;
fs::create_dir_all(&config.session_root)?;
fs::create_dir_all(&config.ci_root)?;
let auth = AuthStore::new(config.dir_root.clone());
let auth = Arc::new(auth);
// Create broadcast channel for SSE events
// 256 buffer - lagging receivers will drop old events
let (event_tx, _) = broadcast::channel(256);
Ok(Self {
auth,
process_start,
config: Arc::new(config),
event_tx,
local_podman_ci_available: Arc::new(AtomicBool::new(false)),
ci_job_tx: Arc::new(OnceCell::new()),
})
}
/// Emit a repository event to all SSE listeners
pub fn emit_event(&self, event: RepoEvent) {
// Ignore send errors (no receivers is fine)
let _ = self.event_tx.send(event);
}
/// Set the CI job sender (can only be called once)
pub fn set_ci_sender(&self, sender: Box<dyn Any + Send + Sync>) {
let _ = self.ci_job_tx.set(sender);
}
/// Get the CI job sender (returns None if not set)
pub fn ci_sender(&self) -> Option<&(dyn Any + Send + Sync)> {
self.ci_job_tx.get().map(|b| b.as_ref())
}
}