diff options
author | evuez <julien@mulga.net> | 2024-04-03 22:43:16 +0200 |
---|---|---|
committer | evuez <julien@mulga.net> | 2024-04-03 22:43:16 +0200 |
commit | 43e1a12b5bce11b4a28a53acca243e35c2be6d3e (patch) | |
tree | 07d64823718bfee063ab7b3d5721ac1e950ae17c /src/server/storage | |
download | carton-43e1a12b5bce11b4a28a53acca243e35c2be6d3e.tar.gz |
Initial commit
Diffstat (limited to 'src/server/storage')
-rw-r--r-- | src/server/storage/backend.rs | 26 | ||||
-rw-r--r-- | src/server/storage/backend/disk.rs | 65 | ||||
-rw-r--r-- | src/server/storage/record.rs | 56 |
3 files changed, 147 insertions, 0 deletions
diff --git a/src/server/storage/backend.rs b/src/server/storage/backend.rs new file mode 100644 index 0000000..8ae62b4 --- /dev/null +++ b/src/server/storage/backend.rs @@ -0,0 +1,26 @@ +pub mod disk; + +use super::Result; +use crate::server::blobref::BlobRef; + +pub fn factory<'a, T: StorageBackend>(config: &T::Config) -> impl Fn(&'a str) -> T + '_ { + |bucket: &str| T::new(bucket, config) +} + +pub trait StorageBackend: Iterator { + type Config; + + fn new(bucket: &str, config: &Self::Config) -> Self; + + fn put(&self, data: &[u8]) -> Result<BlobRef>; + + fn get(&self, blobref: &BlobRef) -> Result<Option<Vec<u8>>>; + + fn exists(&self, blobref: &BlobRef) -> bool { + if let Ok(Some(_)) = self.get(blobref) { + return true; + } + + false + } +} diff --git a/src/server/storage/backend/disk.rs b/src/server/storage/backend/disk.rs new file mode 100644 index 0000000..3137376 --- /dev/null +++ b/src/server/storage/backend/disk.rs @@ -0,0 +1,65 @@ +use super::StorageBackend; +use crate::server::blobref::BlobRef; +use crate::server::storage::{Error, Result}; +use log::debug; +use serde::{Deserialize, Serialize}; +use std::{fs, io::ErrorKind, path::PathBuf}; + +pub struct Disk { + bucket: String, + pub root: PathBuf, +} + +#[derive(Serialize, Deserialize)] +pub struct Config { + pub root: PathBuf, +} + +impl StorageBackend for Disk { + type Config = Config; + + fn new(bucket: &str, config: &Self::Config) -> Self { + Self { + bucket: bucket.to_string(), + root: config.root.clone().join(bucket), + } + } + + fn put(&self, data: &[u8]) -> Result<BlobRef> { + let blobref = BlobRef::for_bytes(data); + debug!("Preparing {blobref}"); + + if !self.exists(&blobref) { + let blobpath = self.root.join(blobref.path()); + let blobdir = blobpath.parent().expect("blobpath should have a parent"); + debug!("Writing blob to {blobpath:?}"); + + fs::create_dir_all(blobdir).map_err(|_| Error::Io)?; + fs::write(blobpath, data).map_err(|_| Error::Io)?; + } + + Ok(blobref) + } + + fn get(&self, blobref: &BlobRef) -> Result<Option<Vec<u8>>> { + let blobpath = self.root.join(blobref.path()); + + match fs::read(blobpath) { + Ok(contents) => Ok(Some(contents)), + Err(e) if e.kind() == ErrorKind::NotFound => Ok(None), + Err(e) => Err(Error::Io), + } + } + + fn exists(&self, blobref: &BlobRef) -> bool { + self.root.join(blobref.path()).exists() + } +} + +impl Iterator for Disk { + type Item = BlobRef; + + fn next(&mut self) -> Option<Self::Item> { + todo!() + } +} diff --git a/src/server/storage/record.rs b/src/server/storage/record.rs new file mode 100644 index 0000000..ab5c977 --- /dev/null +++ b/src/server/storage/record.rs @@ -0,0 +1,56 @@ +use crate::server::{attrs::Attr, blobref::BlobRef}; +use rand::{thread_rng, Rng}; +use serde::{Deserialize, Serialize}; +use time::OffsetDateTime; + +#[derive(Serialize, Deserialize)] +#[serde(rename_all = "kebab-case")] +pub(super) struct Anchor { + rand: u64, + #[serde(with = "time::serde::rfc3339")] + created_at: OffsetDateTime, +} + +#[derive(Debug, Serialize, Deserialize)] +#[serde(rename_all = "kebab-case")] +pub(super) struct Patch { + pub anchor: BlobRef, + pub changes: Vec<Change>, + #[serde(with = "time::serde::rfc3339")] + created_at: OffsetDateTime, +} + +#[derive(Debug, Serialize, Deserialize)] +#[serde(rename_all = "kebab-case")] +// #[allow(clippy::enum_variant_names)] +pub(super) enum Change { + AddChunk { + blobref: BlobRef, + offset: u64, + size: usize, + }, + SetAttr(Attr), +} + +impl Anchor { + pub(super) fn new() -> Self { + Self { + rand: thread_rng().gen(), + created_at: OffsetDateTime::now_utc(), + } + } +} + +impl Patch { + pub(super) fn new(anchor: BlobRef) -> Self { + Self { + anchor, + changes: Vec::new(), + created_at: OffsetDateTime::now_utc(), + } + } + + pub(super) fn add_change(&mut self, change: Change) { + self.changes.push(change); + } +} |