remi/
lib.rs

1// ๐Ÿปโ€โ„๏ธ๐Ÿงถ remi-rs: Asynchronous Rust crate to handle communication between applications and object storage providers
2// Copyright (c) 2022-2025 Noelware, LLC. <team@noelware.org>
3//
4// Permission is hereby granted, free of charge, to any person obtaining a copy
5// of this software and associated documentation files (the "Software"), to deal
6// in the Software without restriction, including without limitation the rights
7// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8// copies of the Software, and to permit persons to whom the Software is
9// furnished to do so, subject to the following conditions:
10//
11// The above copyright notice and this permission notice shall be included in all
12// copies or substantial portions of the Software.
13//
14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20// SOFTWARE.
21
22//! **remi-rs** is a Rust edition of Noelware's Java library [remi](https://github.com/Noelware/remi) that was
23//! discontinuted on **December 15th, 2023** and is the primary library that Noelware uses and maintained.
24//!
25//! **remi-rs** is a easy way to communicate with object storage providers like Azure Blob Storage and Amazon S3.
26//! It is an abstraction on common methods (like fetching, creating, listing, etc.) called a "storage service"
27//! where it implements a set of methods that is commonly used in applications.
28//!
29//! **Warning** โ€” All code in the repository is VERY EXPERIMENTAL and things can break at anytime &
30//! be removed without any notice.
31//!
32//! ## Projects using `remi-rs`
33//! - [๐Ÿ“ฆ **charted-server**](https://github.com/charted-dev/charted)
34//! - [๐Ÿชถ **Hazel**](https://github.com/Noelware/hazel)
35//! - [๐Ÿพ **ume**](https://github.com/auguwu/ume)
36//!
37//! ## Official Crates
38//! - [**remi-gridfs**](https://crates.io/crates/remi-gridfs)
39//! - [**remi-azure**](https://crates.io/crates/remi-azure)
40//! - [**remi-s3**](https://crates.io/crates/remi-s3)
41//! - [**remi-fs**](https://crates.io/crates/remi-fs)
42
43#![doc(html_logo_url = "https://cdn.floofy.dev/images/trans.png")]
44#![doc(html_favicon_url = "https://cdn.floofy.dev/images/trans.png")]
45#![cfg_attr(any(noeldoc, docsrs), feature(doc_cfg))]
46
47use std::{borrow::Cow, path::Path};
48
49// re-export (just in case!~)
50#[doc(hidden)]
51pub use async_trait::async_trait;
52
53#[doc(hidden)]
54pub use bytes::Bytes;
55
56mod blob;
57mod options;
58
59pub use blob::*;
60pub use options::*;
61
62/// A storage service is a base primitive of `remi-rs`: it is the way to interact
63/// with the storage providers in ways that you would commonly use files: open, deleting,
64/// listing, etc.
65#[async_trait]
66pub trait StorageService: Send + Sync {
67    /// Represents a generic error to use for errors that could be emitted
68    /// when calling any function.
69    type Error;
70
71    /// Returns the name of the storage service.
72    ///
73    /// * since 0.1.0
74    fn name(&self) -> Cow<'static, str>
75    where
76        Self: Sized;
77
78    /// Optionally initialize this [`StorageService`] if it requires initialization,
79    /// like creating a directory if it doesn't exist.
80    ///
81    /// * since 0.1.0
82    async fn init(&self) -> Result<(), Self::Error>
83    where
84        Self: Sized,
85    {
86        Ok(())
87    }
88
89    /// Opens a file in the specified `path` and returns the contents as [`Bytes`] if it existed, otherwise
90    /// `None` will be returned to indicate that file doesn't exist.
91    ///
92    /// * since 0.1.0
93    async fn open<P: AsRef<Path> + Send>(&self, path: P) -> Result<Option<Bytes>, Self::Error>
94    where
95        Self: Sized;
96
97    /// Open a file in the given `path` and returns a [`Blob`] structure if the path existed, otherwise
98    /// `None` will be returned to indiciate that a file doesn't exist.
99    ///
100    /// * since 0.1.0
101    async fn blob<P: AsRef<Path> + Send>(&self, path: P) -> Result<Option<Blob>, Self::Error>
102    where
103        Self: Sized;
104
105    /// Iterate over a list of files from a storage service and returns a [`Vec`] of [`Blob`]s.
106    ///
107    /// * since 0.1.0
108    async fn blobs<P: AsRef<Path> + Send>(
109        &self,
110        path: Option<P>,
111        options: Option<ListBlobsRequest>,
112    ) -> Result<Vec<Blob>, Self::Error>
113    where
114        Self: Sized;
115
116    /// Deletes a file in a specified `path`. At the moment, `()` is returned but `bool` might be
117    /// returned to indicate if it actually deleted itself or not.
118    ///
119    /// * since 0.1.0
120    async fn delete<P: AsRef<Path> + Send>(&self, path: P) -> Result<(), Self::Error>
121    where
122        Self: Sized;
123
124    /// Checks the existence of the file by the specified path.
125    ///
126    /// * since: 0.1.0
127    async fn exists<P: AsRef<Path> + Send>(&self, path: P) -> Result<bool, Self::Error>
128    where
129        Self: Sized;
130
131    /// Does a file upload where it writes the byte array as one call and does not do chunking.
132    ///
133    /// * since: 0.1.0
134    async fn upload<P: AsRef<Path> + Send>(&self, path: P, options: UploadRequest) -> Result<(), Self::Error>
135    where
136        Self: Sized;
137
138    #[cfg(feature = "unstable")]
139    #[cfg_attr(any(noeldoc, docsrs), doc(cfg(feature = "unstable")))]
140    /// Performs any healthchecks to determine the storage service's health.
141    async fn healthcheck(&self) -> Result<(), Self::Error> {
142        Ok(())
143    }
144}
145
146#[cfg(test)]
147mod tests {
148    use crate::StorageService;
149
150    const _DYN_STORAGE_SERVICE: Option<&dyn StorageService<Error = ()>> = None;
151}