use std::path::PathBuf;
use serde::{Deserialize, Serialize};
use super::error::ZebFsError;
use super::local::LocalZebFs;
use super::s3::{S3Config, S3ZebFs};
use super::store::ZebFs;
pub const BACKEND_ZEBFS: &str = "zebfs";
pub const BACKEND_S3: &str = "s3";
pub const FILE_BACKENDS: &[&str] = &[BACKEND_ZEBFS, BACKEND_S3];
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum FileBackend {
#[default]
Zebfs,
S3,
}
impl FileBackend {
pub fn as_str(self) -> &'static str {
match self {
Self::Zebfs => BACKEND_ZEBFS,
Self::S3 => BACKEND_S3,
}
}
pub fn label(self) -> &'static str {
match self {
Self::Zebfs => "Local disk",
Self::S3 => "Object store (S3)",
}
}
pub fn parse(value: &str) -> Result<Self, ZebFsError> {
match value {
BACKEND_ZEBFS => Ok(Self::Zebfs),
BACKEND_S3 => Ok(Self::S3),
other => Err(ZebFsError::new(
"ZEBFS_UNKNOWN_BACKEND",
unknown_backend_message(other),
)),
}
}
pub fn resolve(declared: Option<&str>) -> Result<Self, ZebFsError> {
match declared {
Some(value) => Self::parse(value),
None => Ok(Self::default()),
}
}
}
pub fn unknown_backend_message(value: &str) -> String {
format!(
"'{value}' is not a file storage backend this build provides; accepted: {}",
FILE_BACKENDS.join(", ")
)
}
#[derive(Debug, Clone)]
pub enum FileStore {
Local(PathBuf),
S3(S3Config),
}
impl FileStore {
pub fn backend(&self) -> FileBackend {
match self {
Self::Local(_) => FileBackend::Zebfs,
Self::S3(_) => FileBackend::S3,
}
}
}
pub const LOCAL_STORE_ID: &str = "local";
pub fn open(store: &FileStore) -> ZebFs {
match store {
FileStore::Local(files_dir) => ZebFs::Local(LocalZebFs::new(files_dir.clone())),
FileStore::S3(config) => ZebFs::S3(S3ZebFs::new(config.clone())),
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn the_declared_word_is_the_word_a_file_ref_carries() {
assert_eq!(
FileBackend::default().as_str(),
crate::pipeline::nodes::shared::file_ref::BACKEND_ZEBFS
);
}
#[test]
fn an_absent_declaration_resolves_to_the_local_backend() {
assert_eq!(FileBackend::resolve(None).unwrap(), FileBackend::Zebfs);
assert_eq!(FileBackend::default().as_str(), "zebfs");
assert_eq!(FileBackend::resolve(Some("s3")).unwrap(), FileBackend::S3);
}
#[test]
fn a_resolved_local_store_opens_on_its_directory() {
let files_dir = PathBuf::from("/tmp/zebflow-backend-test/files");
let store = open(&FileStore::Local(files_dir.clone()));
assert_eq!(store.backend(), FileBackend::Zebfs);
assert_eq!(store.local_root(), Some(files_dir.as_path()));
}
#[test]
fn an_unknown_backend_is_refused_by_name_with_the_accepted_list() {
let err = FileBackend::parse("ftp").unwrap_err();
assert_eq!(err.code, "ZEBFS_UNKNOWN_BACKEND");
assert!(err.message.contains("'ftp'"), "{}", err.message);
assert!(err.message.contains("accepted: zebfs, s3"), "{}", err.message);
}
}