summaryrefslogtreecommitdiff
path: root/rola-bucket/src/bucket/bind.rs
diff options
context:
space:
mode:
author魏曹先生 <1992414357@qq.com>2026-06-19 01:40:38 +0800
committer魏曹先生 <1992414357@qq.com>2026-06-19 01:40:38 +0800
commit1e9c97c21f8a4e55420712b054895ff8b4f9a849 (patch)
treec6bd37889deb54c024f974f368a9a7d654cad822 /rola-bucket/src/bucket/bind.rs
parente078163c7cdbbf226c18d3e3afa7268a2878e18b (diff)
feat(rola-bucket): add bucket bind managementHEADmaster
Implement bucket bind CRUD operations and config loading, along with CLI integration for listing, setting, and removing bucket bindings.
Diffstat (limited to 'rola-bucket/src/bucket/bind.rs')
-rw-r--r--rola-bucket/src/bucket/bind.rs210
1 files changed, 210 insertions, 0 deletions
diff --git a/rola-bucket/src/bucket/bind.rs b/rola-bucket/src/bucket/bind.rs
new file mode 100644
index 0000000..87f3382
--- /dev/null
+++ b/rola-bucket/src/bucket/bind.rs
@@ -0,0 +1,210 @@
+use serde::{Deserialize, Serialize};
+use shared_constants::bucket::PREFIX_BUCKET_BIND;
+use space_system::{Space, SpaceError};
+use std::borrow::Borrow;
+use std::cmp::Ordering;
+use std::fmt;
+use std::fs::ReadDir;
+use std::io::ErrorKind::NotFound;
+use std::ops::{Deref, DerefMut};
+
+use crate::{AsyncBucketTransferProtocol, Bucket};
+
+#[cfg(test)]
+mod test;
+
+/// Represents a binding between a bucket and a URL.
+///
+/// `BucketBind` is a newtype wrapper around a `String` that stores a URL
+/// associated with a bucket. It provides convenient access to the underlying
+/// URL string through `Deref`, `DerefMut`, `Borrow`, and `Display` trait
+/// implementations.
+#[derive(Debug, Serialize, Deserialize, Default, PartialEq, Eq, Clone)]
+pub struct BucketBind {
+ /// The index of the bucket bind
+ index: u8,
+
+ /// The URL associated with the bucket bind.
+ url: String,
+}
+
+impl BucketBind {
+ /// Creates a new `BucketBind` with the given URL.
+ fn new(index: u8, url: impl Into<String>) -> Self {
+ Self {
+ index,
+ url: url.into(),
+ }
+ }
+
+ /// Returns the index of the bucket bind.
+ pub fn get_index(&self) -> u8 {
+ self.index
+ }
+
+ /// Returns a reference to the URL of the bucket bind.
+ pub fn get_url(&self) -> &str {
+ &self.url
+ }
+}
+
+/// Reads all bucket bind records from the space.
+///
+/// This function traverses the root directory of the specified space, filters files
+/// that start with a specific prefix (`PREFIX_BUCKET_BIND`), parses the index and URL
+/// from each binding record, and returns them as `BucketBind` objects.
+pub fn read_bucket_binds<Protocol: AsyncBucketTransferProtocol + Send + Sync>(
+ space: &Space<Bucket<Protocol>>,
+) -> Result<Vec<BucketBind>, SpaceError> {
+ // Fixed prefix for bucket bind filenames
+ const PREFIX: &str = PREFIX_BUCKET_BIND;
+
+ // Open a read stream for the space root directory
+ let reader: ReadDir = space.read_dir(".")?;
+ let mut binds = Vec::new();
+
+ // Loop through each entry in the directory
+ for entry in reader {
+ let entry = entry?;
+ let file_name = entry.file_name();
+ let name = file_name.to_string_lossy().to_string();
+
+ // Only process files starting with the bind prefix
+ if let Some(suffix) = name.strip_prefix(PREFIX) {
+ // Extract the part after the prefix as the index string
+ // Attempt to parse the suffix as a u8 index value
+ if let Ok(index) = suffix.parse::<u8>() {
+ // Read the file content as the URL
+ let content = space.read_to_string(&name)?;
+ let url = content.trim().to_string();
+
+ // Add the parsed binding record to the list
+ binds.push(BucketBind::new(index, url));
+ }
+ }
+ }
+
+ // Sort by index before returning
+ binds.sort();
+ Ok(binds)
+}
+
+/// Writes a bucket bind record to the space.
+///
+/// This function creates or updates a binding between a bucket and a URL
+/// at the specified index. It writes the URL content to a file named
+/// with the prefix `PREFIX_BUCKET_BIND` followed by the zero-padded index.
+pub fn write_bucket_bind<Protocol: AsyncBucketTransferProtocol + Send + Sync>(
+ space: &Space<Bucket<Protocol>>,
+ idx: u8,
+ url: &str,
+) -> Result<(), SpaceError> {
+ const PREFIX: &str = PREFIX_BUCKET_BIND;
+ let file_name = format!("{}{:03}", PREFIX, idx);
+ space.write(&file_name, url.trim())
+}
+
+/// Reads a single bucket bind record from the space by index.
+///
+/// This function looks for a file named with the prefix `PREFIX_BUCKET_BIND`
+/// followed by the zero-padded index, reads its content as a URL, and returns
+/// the corresponding `BucketBind`. Returns `None` if the file does not exist.
+pub fn read_bucket_bind<Protocol: AsyncBucketTransferProtocol + Send + Sync>(
+ space: &Space<Bucket<Protocol>>,
+ idx: u8,
+) -> Result<Option<BucketBind>, SpaceError> {
+ const PREFIX: &str = PREFIX_BUCKET_BIND;
+ let file_name = format!("{}{:03}", PREFIX, idx);
+
+ match space.read_to_string(&file_name) {
+ Ok(content) => {
+ let url = content.trim().to_string();
+ Ok(Some(BucketBind::new(idx, url)))
+ }
+ Err(SpaceError::Io(err)) => {
+ if err.kind() == NotFound {
+ Ok(None)
+ } else {
+ Err(SpaceError::Io(err))
+ }
+ }
+ Err(e) => Err(e),
+ }
+}
+
+/// Checks whether a bucket bind record exists at the given index.
+///
+/// Returns `true` if a file named with the prefix `PREFIX_BUCKET_BIND` followed
+/// by the zero-padded index exists in the space, `false` otherwise.
+pub fn check_bucket_bind_exists<Protocol: AsyncBucketTransferProtocol + Send + Sync>(
+ space: &Space<Bucket<Protocol>>,
+ idx: u8,
+) -> Result<bool, SpaceError> {
+ const PREFIX: &str = PREFIX_BUCKET_BIND;
+ let file_name = format!("{}{:03}", PREFIX, idx);
+
+ match space.read_to_string(&file_name) {
+ Ok(_) => Ok(true),
+ Err(SpaceError::Io(err)) => {
+ if err.kind() == NotFound {
+ Ok(false)
+ } else {
+ Err(SpaceError::Io(err))
+ }
+ }
+ Err(e) => Err(e),
+ }
+}
+
+/// Removes a bucket bind record from the space by index.
+///
+/// This function deletes the file named with the prefix `PREFIX_BUCKET_BIND`
+/// followed by the zero-padded index from the space. Returns `Ok(())` if the
+/// deletion succeeds, or an error if the operation fails (including if the
+/// file does not exist).
+pub fn remove_bucket_bind<Protocol: AsyncBucketTransferProtocol + Send + Sync>(
+ space: &Space<Bucket<Protocol>>,
+ idx: u8,
+) -> Result<(), SpaceError> {
+ const PREFIX: &str = PREFIX_BUCKET_BIND;
+ let file_name = format!("{}{:03}", PREFIX, idx);
+ space.remove_file(&file_name)
+}
+
+impl Ord for BucketBind {
+ fn cmp(&self, other: &Self) -> Ordering {
+ self.index.cmp(&other.index)
+ }
+}
+
+impl PartialOrd for BucketBind {
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ Some(self.cmp(other))
+ }
+}
+
+impl Deref for BucketBind {
+ type Target = String;
+
+ fn deref(&self) -> &Self::Target {
+ &self.url
+ }
+}
+
+impl DerefMut for BucketBind {
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ &mut self.url
+ }
+}
+
+impl Borrow<String> for BucketBind {
+ fn borrow(&self) -> &String {
+ &self.url
+ }
+}
+
+impl fmt::Display for BucketBind {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "{}", self.url)
+ }
+}