Skip to main content

ranvier_http/
service.rs

1//! # RanvierService - Hyper Service Adapter
2//!
3//! Adapts Ranvier Axon execution to Hyper's Service trait.
4//! This allows Ranvier circuits to be used with any Hyper-compatible infrastructure.
5//!
6//! ## Design (Discussion 190)
7//!
8//! > "ranvier-http is an adapter that converts Ranvier Axon into hyper::service::Service"
9
10use bytes::Bytes;
11use http::{Request, Response};
12use http_body_util::Full;
13use ranvier_core::prelude::*;
14use ranvier_runtime::Axon;
15use std::convert::Infallible;
16use std::future::Future;
17use std::pin::Pin;
18use std::sync::Arc;
19
20/// The foundational logic engine service.
21/// Adapts HTTP requests to Axon executions.
22#[derive(Clone)]
23pub struct RanvierService<In, Out, E, F, Res = ()> {
24    axon: Axon<In, Out, E, Res>,
25    /// Converts a Request into the Axon's input state and potentially populates the Bus.
26    converter: F,
27    /// Resources used by the axon
28    resources: Arc<Res>,
29}
30
31impl<In, Out, E, F, Res> RanvierService<In, Out, E, F, Res> {
32    pub fn new(axon: Axon<In, Out, E, Res>, converter: F, resources: Res) -> Self {
33        Self {
34            axon,
35            converter,
36            resources: Arc::new(resources),
37        }
38    }
39}
40
41impl<B, In, Out, E, F, Res> hyper::service::Service<Request<B>> for RanvierService<In, Out, E, F, Res>
42where
43    B: Send + 'static,
44    In: Send + Sync + serde::Serialize + serde::de::DeserializeOwned + 'static,
45    Out: Send + Sync + serde::Serialize + serde::de::DeserializeOwned + 'static,
46    E: Send + Sync + serde::Serialize + serde::de::DeserializeOwned + std::fmt::Debug + 'static,
47    F: Fn(Request<B>, &mut Bus) -> In + Clone + Send + Sync + 'static,
48    Res: ranvier_core::transition::ResourceRequirement + Send + Sync + 'static,
49{
50    type Response = Response<Full<Bytes>>;
51    type Error = Infallible;
52    type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send>>;
53
54    fn call(&self, req: Request<B>) -> Self::Future {
55        let axon = self.axon.clone();
56        let converter = self.converter.clone();
57        let resources = self.resources.clone();
58
59        Box::pin(async move {
60            let mut bus = Bus::new();
61
62            // 1. Ingress Adapter: Request -> In + Bus
63            let input = converter(req, &mut bus);
64
65            // 2. Run Axon
66            let _result = axon.execute(input, &resources, &mut bus).await;
67
68            // 3. Egress Adapter: Outcome -> Response
69            // TODO: Properly map Outcome to Response based on application needs
70            let body_str = format!(
71                "Ranvier Execution Result: {:?}",
72                "result (Debug missing on Outcome?)"
73            );
74
75            let response = Response::new(Full::new(Bytes::from(body_str)));
76            Ok(response)
77        })
78    }
79}