Skip to main content

ranvier_http/
service.rs

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