about summary refs log tree commit diff
path: root/kittybox-rs/src/media/storage/mod.rs
diff options
context:
space:
mode:
authorVika <vika@fireburn.ru>2022-07-07 00:32:33 +0300
committerVika <vika@fireburn.ru>2022-07-07 00:36:39 +0300
commit7f23ec84bc05c236c1bf40c2f0d72412af711516 (patch)
treef0ba64804fffce29a8f04e5b6c76f9863de81dd2 /kittybox-rs/src/media/storage/mod.rs
parent5cfac54aa4fb3c207ea2cbbeccd4571fa204a09b (diff)
treewide: rewrite using Axum
Axum has streaming bodies and allows to write simpler code. It also
helps enforce stronger types and looks much more neat.

This allows me to progress on the media endpoint and add streaming
reads and writes to the MediaStore trait.

Metrics are temporarily not implemented. Everything else was
preserved, and the tests still pass, after adjusting for new calling
conventions.

TODO: create method routers for protocol endpoints
Diffstat (limited to 'kittybox-rs/src/media/storage/mod.rs')
-rw-r--r--kittybox-rs/src/media/storage/mod.rs53
1 files changed, 53 insertions, 0 deletions
diff --git a/kittybox-rs/src/media/storage/mod.rs b/kittybox-rs/src/media/storage/mod.rs
new file mode 100644
index 0000000..e9b01f9
--- /dev/null
+++ b/kittybox-rs/src/media/storage/mod.rs
@@ -0,0 +1,53 @@
+use async_trait::async_trait;
+
+pub mod file;
+
+#[derive(Debug, Clone, Copy)]
+pub enum ErrorKind {
+    Backend,
+    Permission,
+    Conflict,
+    Other,
+}
+
+#[derive(Debug)]
+pub struct MediaStoreError {
+    kind: ErrorKind,
+    source: Option<Box<dyn std::error::Error + Send + Sync>>,
+    msg: String,
+}
+
+impl std::error::Error for MediaStoreError {
+    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
+        self.source
+            .as_ref()
+            .map(|i| i.as_ref() as &dyn std::error::Error)
+    }
+}
+
+impl std::fmt::Display for MediaStoreError {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(
+            f,
+            "{}: {}",
+            match self.kind {
+                ErrorKind::Backend => "media storage backend error",
+                ErrorKind::Permission => "permission denied",
+                ErrorKind::Conflict => "conflict with existing data",
+                ErrorKind::Other => "unknown media storage error",
+            },
+            self.msg
+        )
+    }
+}
+
+pub type Result<T> = std::result::Result<T, MediaStoreError>;
+
+#[async_trait]
+pub trait MediaStore: 'static + Send + Sync + Clone {
+    async fn write_streaming(&self, domain: url::Host, filename: &str, content: axum::extract::multipart::Field<'_>) -> Result<()>;
+    async fn write(&self, domain: url::Host, filename: &str, content: &[u8]) -> Result<()>;
+    async fn read_streaming(&self, domain: url::Host, filename: &str) -> Result<tokio_util::io::ReaderStream<Box<dyn tokio::io::AsyncRead>>>;
+    async fn read(&self, domain: url::Host, filename: &str) -> Result<Vec<u8>>;
+    async fn delete(&self, domain: url::Host, filename: &str) -> Result<()>;
+}