opencloudmesh 0.2.1

Implementation of the OpenCloudMesh protocol
Documentation
// SPDX-FileCopyrightText: 2026 Matthias Kraus <info@opengeomesh.org>
//
// SPDX-License-Identifier: LGPL-3.0-or-later

use ocm_types::{common::OcmAddress, share::NewShare};
use std::sync::Mutex;
use std::{collections::HashMap, fmt::Debug, sync::Arc};

use crate::drivers::resources::Resource;

use super::ShareRepoError;

/// Store Shares sent by this OCM Server
pub trait SentShareRepo: Debug + Clone + Send + Sync {
    /// Type of resources which are shared by Shares in this repo.
    type ResourceType: Resource;

    /// Store a new share and the resource shared by this share.
    fn insert(
        &self,
        share: NewShare,
        resource: Self::ResourceType,
    ) -> impl std::future::Future<
        Output = Result<Option<(NewShare, Self::ResourceType)>, ShareRepoError>,
    > + std::marker::Send
    + std::marker::Sized;
    /// Get a share by provider_id
    fn get(
        &self,
        provider_id: &str,
    ) -> impl std::future::Future<Output = Result<(NewShare, Self::ResourceType), ShareRepoError>>
    + std::marker::Send
    + std::marker::Sized;
    /// Get all shares sent by the given sender.
    fn get_by_sender(
        &self,
        sender: &OcmAddress,
    ) -> impl std::future::Future<Output = Result<Vec<(NewShare, Self::ResourceType)>, ShareRepoError>>
    + std::marker::Send
    + std::marker::Sized;
    /// Get all shares sent to the given recipient.
    fn get_by_recipient(
        &self,
        recipient: &OcmAddress,
    ) -> impl std::future::Future<Output = Result<Vec<(NewShare, Self::ResourceType)>, ShareRepoError>>
    + std::marker::Send
    + std::marker::Sized;
    /// Delete a share.
    fn remove(
        &self,
        provider_id: &str,
    ) -> impl std::future::Future<Output = Result<(NewShare, Self::ResourceType), ShareRepoError>>
    + std::marker::Send
    + std::marker::Sized;
}

/// Store sent shares in memory. This is intended for testing only.
#[derive(Debug, Clone)]
pub struct InMemorySentShareRepo<R: Resource> {
    map: Arc<Mutex<HashMap<String, (NewShare, R)>>>,
}

impl<R: Resource> Default for InMemorySentShareRepo<R> {
    fn default() -> Self {
        Self { map: Default::default() }
    }
}

impl<R> InMemorySentShareRepo<R> where R: Resource {
    pub fn new() -> Self {
        Self { map: Arc::new(Mutex::new(HashMap::new())) }
    }
}

impl<R: Resource> SentShareRepo for InMemorySentShareRepo<R> {
    type ResourceType = R;

    async fn insert(
        &self,
        share: NewShare,
        resource: R,
    ) -> Result<Option<(NewShare, R)>, ShareRepoError> {
        Ok(self
            .map
            .lock()
            .unwrap()
            .insert(share.provider_id.clone(), (share, resource)))
    }

    async fn get(&self, provider_id: &str) -> Result<(NewShare, R), ShareRepoError> {
        Ok(self
            .map
            .lock()
            .unwrap()
            .get(provider_id)
            .cloned()
            .ok_or(ShareRepoError::NotFound))?
    }

    async fn get_by_sender(
        &self,
        sender: &OcmAddress,
    ) -> Result<Vec<(NewShare, R)>, ShareRepoError> {
        Ok(self
            .map
            .lock()
            .unwrap()
            .values()
            .filter(|share| &share.0.sender == sender)
            .cloned()
            .collect())
    }

    async fn get_by_recipient(
        &self,
        recipient: &OcmAddress,
    ) -> Result<Vec<(NewShare, R)>, ShareRepoError> {
        Ok(self
            .map
            .lock()
            .unwrap()
            .values()
            .filter(|share| &share.0.share_with == recipient)
            .cloned()
            .collect())
    }

    async fn remove(
        &self,
        provider_id: &str,
    ) -> Result<(NewShare, R), ShareRepoError> {
        Ok(self
            .map
            .lock()
            .unwrap()
            .remove(provider_id)
            .ok_or(ShareRepoError::NotFound))?
    }
}