durable-actors 0.7.10

Standalone regional durable-actors control plane, host, and durability runtime
use super::*;
use crate::bucket::{GcsBucket, gcs::GcsClients};

pub(super) struct GcsSnapshots(GcsBucket);

impl GcsSnapshots {
    pub fn new(bucket: &str, clients: GcsClients) -> Result<Self> {
        Ok(Self(GcsBucket::with_clients(bucket, clients)?))
    }
}

#[async_trait]
impl SnapshotStore for GcsSnapshots {
    async fn put(&self, object: &str, bytes: Bytes) -> Result<()> {
        ensure!(
            replace(&self.0, &object_name(object)?, None, bytes).await?,
            "conflicting immutable checkpoint"
        );
        Ok(())
    }
    async fn get(&self, object: &str) -> Result<Option<Bytes>> {
        Ok(self
            .0
            .get(&object_name(object)?)
            .await?
            .map(|copy| copy.bytes.into()))
    }
    async fn list(&self, prefix: &str) -> Result<Vec<String>> {
        let physical = object_name(prefix)?;
        self.0
            .list(&physical)
            .await?
            .into_iter()
            .map(|key| {
                let suffix = key
                    .strip_prefix(&physical)
                    .context("snapshot list escaped its prefix")?;
                Ok(format!("{prefix}{}", suffix.replace('~', "/")))
            })
            .collect()
    }
    async fn latest(&self, prefix: &str) -> Result<Option<(String, Bytes)>> {
        let key = self
            .list(prefix)
            .await?
            .into_iter()
            .filter_map(|key| super::super::snapshots::version(&key).map(|v| (v, key)))
            .max_by_key(|(v, _)| *v);
        match key {
            Some((_, key)) => Ok(self.get(&key).await?.map(|bytes| (key, bytes))),
            None => Ok(None),
        }
    }
}