use anyhow::Result;
use serde::Deserialize;
use std::future::Future;
pub mod local;
pub use local::LocalRawStore;
#[cfg(feature = "source")]
pub mod s3;
#[cfg(feature = "source")]
pub use s3::S3RawStore;
pub trait RawStore: Send + Sync {
fn put(
&self,
doc_id: &str,
data: &[u8],
content_type: &str,
meta: Option<&serde_json::Value>,
) -> impl Future<Output = Result<String>> + Send;
fn get(&self, ref_: &str) -> impl Future<Output = Result<Vec<u8>>> + Send;
fn exists(
&self,
doc_id: &str,
fingerprint: Option<&str>,
) -> impl Future<Output = Result<bool>> + Send;
fn delete(&self, doc_id: &str) -> impl Future<Output = Result<()>> + Send;
}
#[derive(Debug, Clone, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum RawStoreConfig {
Local(LocalRawStoreConfig),
#[cfg(feature = "source")]
S3(S3RawStoreConfig),
}
#[derive(Debug, Clone, Deserialize)]
pub struct LocalRawStoreConfig {
pub root: String,
}
#[cfg(feature = "source")]
#[derive(Debug, Clone, Deserialize)]
pub struct S3RawStoreConfig {
pub bucket: String,
#[serde(default)]
pub prefix: String,
#[serde(default)]
pub endpoint_url: Option<String>,
}
pub enum AnyRawStore {
Local(LocalRawStore),
#[cfg(feature = "source")]
S3(S3RawStore),
}
impl AnyRawStore {
pub async fn put(
&self,
doc_id: &str,
data: &[u8],
content_type: &str,
meta: Option<&serde_json::Value>,
) -> Result<String> {
match self {
AnyRawStore::Local(s) => s.put(doc_id, data, content_type, meta).await,
#[cfg(feature = "source")]
AnyRawStore::S3(s) => s.put(doc_id, data, content_type, meta).await,
}
}
pub async fn get(&self, ref_: &str) -> Result<Vec<u8>> {
match self {
AnyRawStore::Local(s) => s.get(ref_).await,
#[cfg(feature = "source")]
AnyRawStore::S3(s) => s.get(ref_).await,
}
}
pub async fn exists(&self, doc_id: &str, fingerprint: Option<&str>) -> Result<bool> {
match self {
AnyRawStore::Local(s) => s.exists(doc_id, fingerprint).await,
#[cfg(feature = "source")]
AnyRawStore::S3(s) => s.exists(doc_id, fingerprint).await,
}
}
pub async fn delete(&self, doc_id: &str) -> Result<()> {
match self {
AnyRawStore::Local(s) => s.delete(doc_id).await,
#[cfg(feature = "source")]
AnyRawStore::S3(s) => s.delete(doc_id).await,
}
}
}
pub fn load_raw_store(cfg: &RawStoreConfig) -> Result<AnyRawStore> {
match cfg {
RawStoreConfig::Local(c) => Ok(AnyRawStore::Local(LocalRawStore::new(&c.root)?)),
#[cfg(feature = "source")]
RawStoreConfig::S3(c) => Ok(AnyRawStore::S3(S3RawStore::new(c.clone())?)),
}
}
pub(crate) fn doc_id_hash(doc_id: &str) -> String {
use sha2::{Digest, Sha256};
let mut h = Sha256::new();
h.update(doc_id.as_bytes());
format!("{:x}", h.finalize())
}