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 http::StatusCode;
use ocm_types::error::Error;
use serde::Serialize;

/// Represents a pool of shareable resources. 
///
/// This could be a filesystem or folder from which a user is allowed to share subfolders or files
/// or a REST API provided by another service.
pub trait ResourceRepo: Clone + std::fmt::Debug + Send + Sync {
    /// Type of Resources available in this ResourceRepo.
    type Item: Resource + Send;

    /// Get a resource by an identifier specific to this ResourceRepo. This might be a path
    /// within a filesystem or an arbitrary identifier in a REST API. 
    fn get_resource(
        &self,
        resource_id: &str,
    ) -> impl Future<Output = Result<Self::Item, ResourceError>> + Send;

    /// Type of Resources available in this ResourceRepo.
    fn resource_types(&self) -> &'static [&'static str] {
        &[Self::Item::RESOURCE_TYPE]
    }
}

/// the piece of data or interaction to which access is being granted, including but not
/// limited to: a file or folder, a video call, a contact, a printer queue, etc.
pub trait Resource: Clone + std::fmt::Debug + Send + Sync + Serialize {
    /// Identifier for this resource type.
    ///
    /// Examples: `file`, `folder`, `calendar`, ...
    const RESOURCE_TYPE: &str;

    /// Locates the shareable resource to the SendingServer. This can be used by
    /// [Protocol](super::protocols::Protocol) implementations.
    fn uri(&self) -> &str;
    /// Display Name of this resource e.g. "Examplefolder"
    fn name(&self) -> &str;
    /// Identifier for this resource type.
    ///
    /// Examples: `file`, `folder`, `calendar`, ...
    fn resource_type(&self) -> &str {
        Self::RESOURCE_TYPE
    }
}

/// Anything that can go wrong when accessing a resource backing a share.
#[derive(Debug)]
pub enum ResourceError {
    /// Provided resource id is not valid for this resource repo.
    // FIXME cleanup .0 is source error as string
    InvalidResourceId(String),
    /// Requested resource not valid for this resource repo.
    // FIXME cleanup .0 is source error as string
    InvalidResource(String),
    /// Resource could not be found
    NotFound,
    /// Resource was found but couldn't be accessed.
    Io(std::io::Error),
}

impl From<ResourceError> for Error {
    fn from(value: ResourceError) -> Self {
        match value {
            ResourceError::InvalidResourceId(id_error) => Error {
                message: format!("Id is invalid: {id_error}"),
                validation_errors: vec![],
            },
            ResourceError::InvalidResource(resource_error) => Error {
                message: format!("Resource was found but is invalid: {resource_error}"),
                validation_errors: vec![],
            },
            ResourceError::NotFound => Error {
                message: "Resource was not found".to_string(),
                validation_errors: vec![],
            },
            ResourceError::Io(error) => Error {
                message: format!("Resource could not be accessed: {error}"),
                validation_errors: vec![],
            },
        }
    }
}

impl ResourceError {
    pub fn status_code(&self) -> StatusCode {
        match self {
            ResourceError::InvalidResourceId(_) => StatusCode::NOT_ACCEPTABLE,
            ResourceError::InvalidResource(_) => StatusCode::BAD_GATEWAY,
            ResourceError::NotFound => StatusCode::NOT_FOUND,
            ResourceError::Io(_) => StatusCode::BAD_GATEWAY,
        }
    }
}

impl From<std::io::Error> for ResourceError {
    fn from(value: std::io::Error) -> Self {
        Self::Io(value)
    }
}