use std::time::Duration;
use awa_metrics::AwaMetrics;
use serde::Serialize;
use sqlx::PgPool;
use crate::cache::DashboardCache;
use crate::error::ApiError;
#[derive(Clone)]
pub struct AppState {
pub pool: PgPool,
pub read_only: bool,
pub cache: DashboardCache,
pub callback_hmac_secret: Option<[u8; 32]>,
pub poll_interval_ms: u64,
pub metrics: AwaMetrics,
}
impl AppState {
pub fn new(
pool: PgPool,
read_only: bool,
cache_ttl: Duration,
callback_hmac_secret: Option<[u8; 32]>,
) -> Self {
let poll_interval_ms = cache_ttl.as_millis().max(5_000) as u64;
Self {
pool,
read_only,
cache: DashboardCache::new(cache_ttl),
callback_hmac_secret,
poll_interval_ms,
metrics: AwaMetrics::from_global(),
}
}
pub fn require_writable(&self) -> Result<(), ApiError> {
if self.read_only {
return Err(ApiError::read_only());
}
Ok(())
}
pub fn invalidate_dashboard_caches(&self) {
self.cache.stats.invalidate_all();
self.cache.queues.invalidate_all();
self.cache.runtime.invalidate_all();
self.cache.queue_runtime.invalidate_all();
self.cache.storage.invalidate_all();
}
}
pub async fn detect_read_only(pool: &PgPool) -> Result<bool, sqlx::Error> {
let read_only =
sqlx::query_scalar::<_, bool>("SELECT current_setting('transaction_read_only') = 'on'")
.fetch_one(pool)
.await?;
Ok(read_only)
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub enum ReadOnlyMode {
#[default]
Auto,
ReadOnly,
Writable,
}
impl ReadOnlyMode {
pub async fn resolve(self, pool: &PgPool) -> Result<bool, sqlx::Error> {
match self {
Self::Auto => detect_read_only(pool).await,
Self::ReadOnly => Ok(true),
Self::Writable => Ok(false),
}
}
}
#[derive(Debug, Serialize)]
pub struct Capabilities {
pub read_only: bool,
pub poll_interval_ms: u64,
}