#![doc(html_logo_url = "https://cdn.floofy.dev/images/trans.png")]
#![cfg_attr(any(noeldoc, docsrs), feature(doc_cfg))]
#![allow(non_camel_case_types)]
use remi::{ListBlobsRequest, UploadRequest};
use std::{borrow::Cow, path::Path};
pub use remi as core;
#[cfg(feature = "gridfs")]
#[cfg_attr(any(docsrs, noeldoc), doc(cfg(feature = "gridfs")))]
pub use remi_gridfs as gridfs;
#[cfg(feature = "azure")]
#[cfg_attr(any(docsrs, noeldoc), doc(cfg(feature = "azure")))]
pub use remi_azure as azure;
#[cfg(feature = "s3")]
#[cfg_attr(any(docsrs, noeldoc), doc(cfg(feature = "s3")))]
pub use remi_s3 as s3;
#[cfg(feature = "fs")]
#[cfg_attr(any(docsrs, noeldoc), doc(cfg(feature = "fs")))]
pub use remi_fs as fs;
macro_rules! mk_storage_service_impl {
(
$(#[$meta:meta])*
$($feat:literal => $field:ident as $ty:ty {
$(#[$error_meta:meta])*
Error: $error:ty;
$(#[$config_meta:meta])*
Config: $config:ty;
Display: |$f:ident, $error_name:ident| $display:expr;
})*
) => {
$(#[$meta])*
pub enum StorageService {
$(
#[cfg(feature = $feat)]
#[cfg_attr(any(noeldoc, docsrs), doc(cfg(feature = $feat)))]
$field($ty),
)*
__non_exhaustive
}
#[derive(Debug)]
#[allow(non_camel_case_types)]
pub enum Error {
$(
#[cfg(feature = $feat)]
#[cfg_attr(any(noeldoc, docsrs), doc(cfg(feature = $feat)))]
$(#[$error_meta])*
$field($error),
)*
__non_exhaustive,
}
impl ::std::fmt::Display for Error {
#[allow(unused)]
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match self {
$(
#[cfg(feature = $feat)]
Error::$field(err) => {
let $error_name = err;
let $f = f;
$display
},
)*
_ => unreachable!()
}
}
}
impl ::std::error::Error for Error {
fn source(&self) -> Option<&(dyn ::std::error::Error + 'static)> {
match self {
$(
#[cfg(feature = $feat)]
Error::$field(err) => Some(err),
)*
_ => None
}
}
}
$(
#[cfg(feature = $feat)]
#[cfg_attr(any(noeldoc, docsrs), doc(cfg(feature = $feat)))]
impl ::core::convert::From<$error> for Error {
fn from(value: $error) -> Self {
Error::$field(value)
}
}
)*
#[derive(Debug, Clone, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "lowercase"))]
#[non_exhaustive]
pub enum Config {
$(
#[cfg(feature = $feat)]
#[cfg_attr(any(noeldoc, docsrs), doc(cfg(feature = $feat)))]
#[doc = concat!("Configuration variant that can be used to configure the [`StorageService::", stringify!($field), "`] variant.")]
$(#[$config_meta])*
$field($config),
)*
#[default]
Unknown,
}
};
}
mk_storage_service_impl! {
#[cfg_attr(feature = "gridfs", doc = "* [`remi_gridfs::StorageService`]")]
#[cfg_attr(feature = "azure", doc = "* [`remi_azure::StorageService`]")]
#[cfg_attr(feature = "fs", doc = "* [`remi_fs::StorageService`]")]
#[cfg_attr(feature = "s3", doc = "* [`remi_s3::StorageService`]")]
#[allow(non_camel_case_types)]
#[derive(Clone)]
"gridfs" => Gridfs as ::remi_gridfs::StorageService {
Error: ::remi_gridfs::mongodb::error::Error;
Config: ::remi_gridfs::StorageConfig;
Display: |f, err| match &*err.kind {
::remi_gridfs::mongodb::error::ErrorKind::Custom(msg) => {
if let Some(msg) = msg.downcast_ref::<&str>() {
f.write_str(msg)
} else if let Some(msg) = msg.downcast_ref::<String>() {
f.write_str(msg)
} else {
::std::fmt::Display::fmt(err, f)
}
},
_ => ::std::fmt::Display::fmt(err, f),
};
}
"azure" => Azure as ::remi_azure::StorageService {
Error: ::remi_azure::core::storage::Error;
Config: ::remi_azure::StorageConfig;
Display: |f, err| ::std::fmt::Display::fmt(err, f);
}
"fs" => Filesystem as ::remi_fs::StorageService {
Error: ::std::io::Error;
Config: ::remi_fs::StorageConfig;
Display: |f, err| ::std::fmt::Display::fmt(err, f);
}
"s3" => S3 as ::remi_s3::StorageService {
Error: ::remi_s3::Error;
Config: ::remi_s3::StorageConfig;
Display: |f, err| ::std::fmt::Display::fmt(err, f);
}
}
impl StorageService {
#[cfg(feature = "fs")]
#[cfg_attr(any(noeldoc, docsrs), doc(cfg(feature = "fs")))]
pub fn as_filesystem(&self) -> Option<&remi_fs::StorageService> {
match *self {
Self::Filesystem(ref fs) => Some(fs),
_ => None,
}
}
#[cfg(feature = "s3")]
#[cfg_attr(any(noeldoc, docsrs), doc(cfg(feature = "s3")))]
pub fn as_s3(&self) -> Option<&remi_s3::StorageService> {
match *self {
Self::S3(ref s3) => Some(s3),
_ => None,
}
}
#[cfg(feature = "azure")]
#[cfg_attr(any(noeldoc, docsrs), doc(cfg(feature = "azure")))]
pub fn as_azure(&self) -> Option<&remi_azure::StorageService> {
match *self {
Self::Azure(ref azure) => Some(azure),
_ => None,
}
}
#[cfg(feature = "gridfs")]
#[cfg_attr(any(noeldoc, docsrs), doc(cfg(feature = "gridfs")))]
pub fn as_gridfs(&self) -> Option<&remi_gridfs::StorageService> {
match *self {
Self::Gridfs(ref gridfs) => Some(gridfs),
_ => None,
}
}
}
#[remi::async_trait]
#[allow(unused)]
impl remi::StorageService for StorageService {
type Error = Error;
fn name(&self) -> Cow<'static, str> {
let name = match self {
#[cfg(feature = "fs")]
StorageService::Filesystem(service) => service.name(),
#[cfg(feature = "s3")]
StorageService::S3(service) => service.name(),
#[cfg(feature = "azure")]
StorageService::Azure(service) => service.name(),
#[cfg(feature = "gridfs")]
StorageService::Gridfs(service) => service.name(),
_ => Cow::Borrowed("<unknown>"),
};
Cow::Owned(format!("azalia:remi[{name}]"))
}
async fn init(&self) -> Result<(), Self::Error> {
match self {
#[cfg(feature = "fs")]
StorageService::Filesystem(service) => service.init().await.map_err(From::from),
#[cfg(feature = "s3")]
StorageService::S3(service) => service.init().await.map_err(From::from),
#[cfg(feature = "azure")]
StorageService::Azure(service) => service.init().await.map_err(From::from),
#[cfg(feature = "gridfs")]
StorageService::Gridfs(service) => service.init().await.map_err(From::from),
_ => unreachable!(),
}
}
async fn open<P: AsRef<Path> + Send>(&self, path: P) -> Result<Option<remi::Bytes>, Self::Error> {
match self {
#[cfg(feature = "fs")]
StorageService::Filesystem(service) => service.open(path).await.map_err(From::from),
#[cfg(feature = "s3")]
StorageService::S3(service) => service.open(path).await.map_err(From::from),
#[cfg(feature = "azure")]
StorageService::Azure(service) => service.open(path).await.map_err(From::from),
#[cfg(feature = "gridfs")]
StorageService::Gridfs(service) => service.open(path).await.map_err(From::from),
_ => unreachable!(),
}
}
async fn blob<P: AsRef<Path> + Send>(&self, path: P) -> Result<Option<remi::Blob>, Self::Error> {
match self {
#[cfg(feature = "fs")]
StorageService::Filesystem(service) => service.blob(path).await.map_err(From::from),
#[cfg(feature = "s3")]
StorageService::S3(service) => service.blob(path).await.map_err(From::from),
#[cfg(feature = "azure")]
StorageService::Azure(service) => service.blob(path).await.map_err(From::from),
#[cfg(feature = "gridfs")]
StorageService::Gridfs(service) => service.blob(path).await.map_err(From::from),
_ => unreachable!(),
}
}
async fn blobs<P: AsRef<Path> + Send>(
&self,
path: Option<P>,
options: Option<ListBlobsRequest>,
) -> Result<Vec<remi::Blob>, Self::Error> {
match self {
#[cfg(feature = "fs")]
StorageService::Filesystem(service) => service.blobs(path, options).await.map_err(From::from),
#[cfg(feature = "s3")]
StorageService::S3(service) => service.blobs(path, options).await.map_err(From::from),
#[cfg(feature = "azure")]
StorageService::Azure(service) => service.blobs(path, options).await.map_err(From::from),
#[cfg(feature = "gridfs")]
StorageService::Gridfs(service) => service.blobs(path, options).await.map_err(From::from),
_ => unreachable!(),
}
}
async fn delete<P: AsRef<Path> + Send>(&self, path: P) -> Result<(), Self::Error> {
match self {
#[cfg(feature = "fs")]
StorageService::Filesystem(service) => service.delete(path).await.map_err(From::from),
#[cfg(feature = "s3")]
StorageService::S3(service) => service.delete(path).await.map_err(From::from),
#[cfg(feature = "azure")]
StorageService::Azure(service) => service.delete(path).await.map_err(From::from),
#[cfg(feature = "gridfs")]
StorageService::Gridfs(service) => service.delete(path).await.map_err(From::from),
_ => unreachable!(),
}
}
async fn exists<P: AsRef<Path> + Send>(&self, path: P) -> Result<bool, Self::Error> {
match self {
#[cfg(feature = "fs")]
StorageService::Filesystem(service) => service.exists(path).await.map_err(From::from),
#[cfg(feature = "s3")]
StorageService::S3(service) => service.exists(path).await.map_err(From::from),
#[cfg(feature = "azure")]
StorageService::Azure(service) => service.exists(path).await.map_err(From::from),
#[cfg(feature = "gridfs")]
StorageService::Gridfs(service) => service.exists(path).await.map_err(From::from),
_ => unreachable!(),
}
}
async fn upload<P: AsRef<Path> + Send>(&self, path: P, request: UploadRequest) -> Result<(), Self::Error> {
match self {
#[cfg(feature = "fs")]
StorageService::Filesystem(service) => service.upload(path, request).await.map_err(From::from),
#[cfg(feature = "s3")]
StorageService::S3(service) => service.upload(path, request).await.map_err(From::from),
#[cfg(feature = "azure")]
StorageService::Azure(service) => service.upload(path, request).await.map_err(From::from),
#[cfg(feature = "gridfs")]
StorageService::Gridfs(service) => service.upload(path, request).await.map_err(From::from),
_ => unreachable!(),
}
}
#[cfg(feature = "unstable")]
#[cfg_attr(any(noeldoc, docsrs), doc(cfg(feature = "unstable")))]
async fn healthcheck(&self) -> Result<(), Self::Error> {
match self {
#[cfg(feature = "fs")]
StorageService::Filesystem(service) => service.healthcheck().await.map_err(From::from),
#[cfg(feature = "s3")]
StorageService::S3(service) => service.healthcheck().await.map_err(From::from),
#[cfg(feature = "azure")]
StorageService::Azure(service) => service.healthcheck().await.map_err(From::from),
#[cfg(feature = "gridfs")]
StorageService::Gridfs(service) => service.healthcheck().await.map_err(From::from),
_ => unreachable!(),
}
}
}