use std::sync::{Arc, RwLock};
use std::time::Duration;
use corium_db::Db;
pub const DEFAULT_POLL_INTERVAL: Duration = Duration::from_secs(2);
#[derive(Clone, Debug, thiserror::Error)]
pub enum SourceError {
#[error("authorization database {0:?} is not available")]
Unavailable(String),
#[error("cannot read authorization database {db:?}: {reason}")]
Failed {
db: String,
reason: String,
},
}
#[tonic::async_trait]
pub trait PolicySource: Send + Sync + 'static {
fn name(&self) -> &str;
async fn snapshot(&self) -> Result<Db, SourceError>;
async fn changed(&self, basis_t: u64) {
let _ = basis_t;
tokio::time::sleep(DEFAULT_POLL_INTERVAL).await;
}
}
pub struct MemoryPolicySource {
name: String,
db: RwLock<Db>,
}
impl MemoryPolicySource {
pub fn new(name: impl Into<String>, db: Db) -> Self {
Self {
name: name.into(),
db: RwLock::new(db),
}
}
pub fn set(&self, db: Db) {
*self
.db
.write()
.unwrap_or_else(std::sync::PoisonError::into_inner) = db;
}
#[must_use]
pub fn shared(self) -> Arc<dyn PolicySource> {
Arc::new(self)
}
}
#[tonic::async_trait]
impl PolicySource for MemoryPolicySource {
fn name(&self) -> &str {
&self.name
}
async fn snapshot(&self) -> Result<Db, SourceError> {
Ok(self
.db
.read()
.unwrap_or_else(std::sync::PoisonError::into_inner)
.clone())
}
}