actrpc-orchestrator 0.1.0

Configuration and orchestration utilities for ActRPC.
Documentation
use crate::{
    error::MethodCallError,
    method::{MethodInfo, MethodName, ProviderName},
};
use actrpc_core::json_rpc::{JsonRpcMessage, JsonRpcParams};
use std::{future::Future, pin::Pin};

pub type MethodProviderFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;

pub trait MethodProvider: Send + Sync {
    fn name(&self) -> &ProviderName;

    fn description(&self) -> Option<&str>;

    fn info(&self) -> &serde_json::Value;

    fn methods(&self) -> &[MethodInfo];

    fn method(&self, name: &MethodName) -> Option<&MethodInfo> {
        self.methods().iter().find(|method| &method.name == name)
    }

    fn request_message(
        &self,
        method: &MethodName,
        params: Option<JsonRpcParams>,
    ) -> Result<JsonRpcMessage, MethodCallError>;

    fn send_message<'a>(
        &'a self,
        method: &'a MethodName,
        message: JsonRpcMessage,
    ) -> MethodProviderFuture<'a, Result<JsonRpcMessage, MethodCallError>>;

    fn call<'a>(
        &'a self,
        method: &'a MethodName,
        params: Option<JsonRpcParams>,
    ) -> MethodProviderFuture<'a, Result<serde_json::Value, MethodCallError>> {
        Box::pin(async move {
            let request = self.request_message(method, params)?;
            let response = self.send_message(method, request).await?;
            decode_success_value(self.name().clone(), method.clone(), response)
        })
    }
}

pub fn decode_success_value(
    provider: ProviderName,
    method: MethodName,
    message: JsonRpcMessage,
) -> Result<serde_json::Value, MethodCallError> {
    use actrpc_core::json_rpc::{JsonRpcResponse, JsonRpcSingleMessage};

    let JsonRpcMessage::Single(JsonRpcSingleMessage::Response(response)) = message else {
        return Err(MethodCallError::InvalidResponse {
            provider,
            method,
            message: "provider returned a non-response JSON-RPC message".to_owned(),
        });
    };

    match response {
        JsonRpcResponse::Success(success) => Ok(success.result),

        JsonRpcResponse::Error(error) => Err(MethodCallError::RemoteError {
            provider,
            method,
            error: error.error,
        }),
    }
}