use std::sync::Arc;
use object_store::DynObjectStore;
use object_store::memory::InMemory;
use object_store::prefix::PrefixStore;
use crate::backend::{
ProxyCapabilities, ProxyReq, Securable, StorageProxyBackend, reject_key_traversal,
};
use crate::error::{ProxyError, ProxyResult};
#[derive(Clone)]
pub struct InMemoryStorageProxyBackend {
store: Arc<InMemory>,
allowed: Securable,
prefix: String,
allow_write: bool,
}
impl InMemoryStorageProxyBackend {
pub fn table(full_name: impl Into<String>) -> Self {
Self {
store: Arc::new(InMemory::new()),
allowed: Securable::Table {
full_name: full_name.into(),
},
prefix: String::new(),
allow_write: true,
}
}
pub fn volume(full_name: impl Into<String>) -> Self {
Self {
store: Arc::new(InMemory::new()),
allowed: Securable::Volume {
full_name: full_name.into(),
},
prefix: String::new(),
allow_write: true,
}
}
pub fn with_prefix(mut self, prefix: impl Into<String>) -> Self {
self.prefix = prefix.into();
self
}
pub fn read_only(mut self) -> Self {
self.allow_write = false;
self
}
pub fn store(&self) -> Arc<InMemory> {
self.store.clone()
}
}
#[async_trait::async_trait]
impl<Cx: Send + Sync + 'static> StorageProxyBackend<Cx> for InMemoryStorageProxyBackend {
fn capabilities(&self) -> ProxyCapabilities {
ProxyCapabilities { enabled: true }
}
async fn authorize(&self, req: &ProxyReq, _cx: &Cx) -> ProxyResult<()> {
reject_key_traversal(&req.key)?;
if req.securable != self.allowed {
return Err(ProxyError::PermissionDenied(format!(
"securable {:?} is not authorized",
req.securable
)));
}
if !self.prefix.is_empty() && !req.key.starts_with(&self.prefix) {
return Err(ProxyError::OutOfScope(format!(
"key `{}` is outside the authorized prefix `{}`",
req.key, self.prefix
)));
}
if req.verb.is_write() && !self.allow_write {
return Err(ProxyError::PermissionDenied(
"write not permitted for this scope".into(),
));
}
Ok(())
}
async fn open(&self, _req: &ProxyReq, _cx: &Cx) -> ProxyResult<Arc<DynObjectStore>> {
Ok(self.store.clone())
}
}
pub fn prefixed(store: Arc<InMemory>, prefix: &str) -> Arc<DynObjectStore> {
Arc::new(PrefixStore::new(store, prefix))
}