libvault 0.2.2

the libvault is modified from RustyVault
Documentation
use std::{any::Any, sync::Arc};

use super::{Storage, StorageEntry, barrier::SecurityBarrier};
use crate::errors::RvError;

pub struct BarrierView {
    barrier: Arc<dyn SecurityBarrier>,
    prefix: String,
}

#[async_trait::async_trait]
impl Storage for BarrierView {
    async fn list(&self, prefix: &str) -> Result<Vec<String>, RvError> {
        self.sanity_check(prefix)?;
        self.barrier.list(self.expand_key(prefix).as_str()).await
    }

    async fn get(&self, key: &str) -> Result<Option<StorageEntry>, RvError> {
        self.sanity_check(key)?;
        let storage_entry = self.barrier.get(self.expand_key(key).as_str()).await?;
        if let Some(entry) = storage_entry {
            Ok(Some(StorageEntry {
                key: self.truncate_key(entry.key.as_str()),
                value: entry.value,
            }))
        } else {
            Ok(None)
        }
    }

    async fn put(&self, entry: &StorageEntry) -> Result<(), RvError> {
        self.sanity_check(entry.key.as_str())?;
        let nested = StorageEntry {
            key: self.expand_key(entry.key.as_str()),
            value: entry.value.clone(),
        };
        self.barrier.put(&nested).await
    }

    async fn delete(&self, key: &str) -> Result<(), RvError> {
        self.sanity_check(key)?;
        self.barrier.delete(self.expand_key(key).as_str()).await
    }

    async fn lock(&self, lock_name: &str) -> Result<Box<dyn Any>, RvError> {
        self.barrier.lock(lock_name).await
    }
}

impl BarrierView {
    pub fn new(barrier: Arc<dyn SecurityBarrier>, prefix: &str) -> Self {
        Self {
            barrier,
            prefix: prefix.to_string(),
        }
    }

    pub fn new_sub_view(&self, prefix: &str) -> Self {
        Self {
            barrier: self.barrier.clone(),
            prefix: self.expand_key(prefix),
        }
    }

    pub async fn get_keys(&self) -> Result<Vec<String>, RvError> {
        let mut paths = vec!["".to_string()];
        let mut keys = Vec::new();
        while !paths.is_empty() {
            let n = paths.len();
            let curr = paths[n - 1].to_owned();
            paths.pop();

            let items = self.list(curr.as_str()).await?;
            for p in items {
                let path = format!("{curr}{p}");
                if p.ends_with('/') {
                    paths.push(path);
                } else {
                    keys.push(path.to_owned());
                }
            }
        }
        keys.sort();
        Ok(keys)
    }

    pub async fn clear(&self) -> Result<(), RvError> {
        let keys = self.get_keys().await?;
        for key in keys {
            self.delete(key.as_str()).await?
        }
        Ok(())
    }

    pub fn as_storage(&self) -> &dyn Storage {
        self
    }

    fn sanity_check(&self, key: &str) -> Result<(), RvError> {
        if key.contains("..") || key.starts_with('/') {
            Err(RvError::ErrBarrierKeySanityCheckFailed)
        } else {
            Ok(())
        }
    }

    fn expand_key(&self, suffix: &str) -> String {
        format!("{}{}", self.prefix, suffix)
    }

    fn truncate_key(&self, full: &str) -> String {
        if let Some(result) = full.strip_prefix(self.prefix.as_str()) {
            result.to_string()
        } else {
            full.to_string()
        }
    }
}