use std::sync::Arc;
use crate::Result;
use crate::policy::{Decision, Permission, Policy, ProvidesPolicy};
use crate::store::{ProvidesResourceStore, ResourceStore};
use unitycatalog_common::models::ResourceIdent;
use unitycatalog_delta_api::coordinator::{
CommitCoordinator, InMemoryCommitCoordinator, ProvidesCommitCoordinator,
};
pub mod credential_vending;
mod delta_backend;
pub mod location;
pub mod location_policy;
pub(crate) mod object_store;
pub use location_policy::LocalStoragePolicy;
pub trait ProvidesLocalStoragePolicy {
fn local_storage_policy(&self) -> &LocalStoragePolicy;
}
pub trait ProvidesManagedStorageRoot {
fn managed_storage_root(&self) -> Option<&str>;
}
#[derive(Clone)]
pub struct ServerHandler<Cx> {
handler: Arc<ServerHandlerInner<Cx>>,
}
impl<Cx: Send + Sync + 'static> ServerHandler<Cx> {
pub fn try_new_tokio(
policy: Arc<dyn Policy<Cx>>,
store: Arc<dyn ResourceStore>,
) -> Result<Self> {
Self::try_new_tokio_with_coordinator(
policy,
store,
Arc::new(InMemoryCommitCoordinator::default()),
)
}
pub fn try_new_tokio_with_coordinator(
policy: Arc<dyn Policy<Cx>>,
store: Arc<dyn ResourceStore>,
commit_coordinator: Arc<dyn CommitCoordinator>,
) -> Result<Self> {
let handler = Arc::new(
ServerHandlerInner::new(policy.clone(), store.clone())
.with_commit_coordinator(commit_coordinator),
);
Ok(Self { handler })
}
}
impl<Cx: Send + Sync + 'static> ServerHandler<Cx> {
pub fn with_local_storage_policy(mut self, policy: impl Into<Arc<LocalStoragePolicy>>) -> Self {
let prev = &self.handler;
let inner = ServerHandlerInner {
policy: prev.policy.clone(),
store: prev.store.clone(),
commit_coordinator: prev.commit_coordinator.clone(),
local_storage_policy: policy.into(),
managed_storage_root: prev.managed_storage_root.clone(),
};
self.handler = Arc::new(inner);
self
}
pub fn with_managed_storage_root(mut self, root: Option<impl Into<Arc<str>>>) -> Self {
let prev = &self.handler;
let inner = ServerHandlerInner {
policy: prev.policy.clone(),
store: prev.store.clone(),
commit_coordinator: prev.commit_coordinator.clone(),
local_storage_policy: prev.local_storage_policy.clone(),
managed_storage_root: root.map(Into::into),
};
self.handler = Arc::new(inner);
self
}
}
#[derive(Clone)]
pub struct ServerHandlerInner<Cx> {
policy: Arc<dyn Policy<Cx>>,
store: Arc<dyn ResourceStore>,
commit_coordinator: Arc<dyn CommitCoordinator>,
local_storage_policy: Arc<LocalStoragePolicy>,
managed_storage_root: Option<Arc<str>>,
}
impl<Cx: Send + Sync + 'static> ServerHandlerInner<Cx> {
pub fn new(policy: Arc<dyn Policy<Cx>>, store: Arc<dyn ResourceStore>) -> Self {
Self {
policy,
store,
commit_coordinator: Arc::new(InMemoryCommitCoordinator::default()),
local_storage_policy: Arc::new(LocalStoragePolicy::deny_all()),
managed_storage_root: None,
}
}
pub fn with_local_storage_policy(mut self, policy: impl Into<Arc<LocalStoragePolicy>>) -> Self {
self.local_storage_policy = policy.into();
self
}
pub fn with_managed_storage_root(mut self, root: Option<impl Into<Arc<str>>>) -> Self {
self.managed_storage_root = root.map(Into::into);
self
}
pub fn with_commit_coordinator(mut self, coordinator: Arc<dyn CommitCoordinator>) -> Self {
self.commit_coordinator = coordinator;
self
}
}
impl<Cx: Send + Sync + 'static> ProvidesPolicy<Cx> for ServerHandlerInner<Cx> {
fn policy(&self) -> &Arc<dyn Policy<Cx>> {
&self.policy
}
}
impl<Cx: Send + Sync + 'static> ProvidesPolicy<Cx> for ServerHandler<Cx> {
fn policy(&self) -> &Arc<dyn Policy<Cx>> {
&self.handler.policy
}
}
#[async_trait::async_trait]
impl<Cx: Send + Sync + 'static> Policy<Cx> for ServerHandlerInner<Cx> {
async fn authorize(
&self,
resource: &ResourceIdent,
permission: &Permission,
context: &Cx,
) -> Result<Decision> {
self.policy().authorize(resource, permission, context).await
}
async fn authorize_many(
&self,
resources: &[ResourceIdent],
permission: &Permission,
context: &Cx,
) -> Result<Vec<Decision>> {
self.policy()
.authorize_many(resources, permission, context)
.await
}
}
#[async_trait::async_trait]
impl<Cx: Send + Sync + 'static> Policy<Cx> for ServerHandler<Cx> {
async fn authorize(
&self,
resource: &ResourceIdent,
permission: &Permission,
context: &Cx,
) -> Result<Decision> {
self.handler
.policy
.authorize(resource, permission, context)
.await
}
async fn authorize_many(
&self,
resources: &[ResourceIdent],
permission: &Permission,
context: &Cx,
) -> Result<Vec<Decision>> {
self.handler
.policy
.authorize_many(resources, permission, context)
.await
}
}
impl<Cx: Send + Sync + 'static> ProvidesResourceStore for ServerHandlerInner<Cx> {
fn store(&self) -> &dyn ResourceStore {
self.store.as_ref()
}
}
impl<Cx: Send + Sync + 'static> ProvidesResourceStore for ServerHandler<Cx> {
fn store(&self) -> &dyn ResourceStore {
self.handler.store.as_ref()
}
}
impl<Cx: Send + Sync + 'static> ProvidesCommitCoordinator for ServerHandlerInner<Cx> {
fn commit_coordinator(&self) -> &dyn CommitCoordinator {
self.commit_coordinator.as_ref()
}
}
impl<Cx: Send + Sync + 'static> ProvidesCommitCoordinator for ServerHandler<Cx> {
fn commit_coordinator(&self) -> &dyn CommitCoordinator {
self.handler.commit_coordinator.as_ref()
}
}
impl<Cx: Send + Sync + 'static> ProvidesLocalStoragePolicy for ServerHandlerInner<Cx> {
fn local_storage_policy(&self) -> &LocalStoragePolicy {
self.local_storage_policy.as_ref()
}
}
impl<Cx: Send + Sync + 'static> ProvidesLocalStoragePolicy for ServerHandler<Cx> {
fn local_storage_policy(&self) -> &LocalStoragePolicy {
self.handler.local_storage_policy.as_ref()
}
}
impl<Cx: Send + Sync + 'static> ProvidesManagedStorageRoot for ServerHandlerInner<Cx> {
fn managed_storage_root(&self) -> Option<&str> {
self.managed_storage_root.as_deref()
}
}
impl<Cx: Send + Sync + 'static> ProvidesManagedStorageRoot for ServerHandler<Cx> {
fn managed_storage_root(&self) -> Option<&str> {
self.handler.managed_storage_root.as_deref()
}
}