wasmer_wasix/runners/dcgi/
handler.rs

1use std::{ops::Deref, pin::Pin, sync::Arc};
2
3use anyhow::Error;
4use futures::{Future, FutureExt};
5use http::{Request, Response};
6
7use crate::runners::wcgi;
8
9use super::DcgiInstanceFactory;
10
11use super::super::Body;
12
13/// The shared object that manages the instantiaion of WASI executables and
14/// communicating with them via the CGI protocol.
15#[derive(Clone, Debug)]
16pub(crate) struct Handler {
17    state: Arc<SharedState>,
18    inner: wcgi::Handler,
19}
20
21impl Handler {
22    pub(crate) fn new(handler: wcgi::Handler) -> Self {
23        Handler {
24            state: Arc::new(SharedState {
25                inner: handler.deref().clone(),
26                factory: DcgiInstanceFactory::new(),
27                master_lock: Default::default(),
28            }),
29            inner: handler,
30        }
31    }
32
33    #[tracing::instrument(level = "debug", skip_all, err)]
34    pub(crate) async fn handle(
35        &self,
36        req: Request<hyper::body::Incoming>,
37    ) -> Result<Response<Body>, Error> {
38        // we acquire a guard token so that only one request at a time can be processed
39        // which effectively means that DCGI is single-threaded. This is a limitation
40        // of the MVP which should be rectified in future releases.
41        let guard_token = self.state.master_lock.clone().lock_owned().await;
42
43        // Process the request as a normal WCGI request
44        self.inner.handle(req, guard_token).await
45    }
46}
47
48impl Deref for Handler {
49    type Target = Arc<SharedState>;
50
51    fn deref(&self) -> &Self::Target {
52        &self.state
53    }
54}
55
56#[derive(Debug, Clone)]
57#[allow(dead_code)]
58pub(crate) struct SharedState {
59    #[allow(dead_code)]
60    pub(crate) inner: Arc<wcgi::SharedState>,
61    factory: DcgiInstanceFactory,
62    master_lock: Arc<tokio::sync::Mutex<()>>,
63}
64
65impl tower::Service<Request<hyper::body::Incoming>> for Handler {
66    type Response = Response<Body>;
67    type Error = Error;
68    type Future = Pin<Box<dyn Future<Output = Result<Response<Body>, Error>> + Send>>;
69
70    fn poll_ready(
71        &mut self,
72        _cx: &mut std::task::Context<'_>,
73    ) -> std::task::Poll<Result<(), Self::Error>> {
74        std::task::Poll::Ready(Ok(()))
75    }
76
77    fn call(&mut self, request: Request<hyper::body::Incoming>) -> Self::Future {
78        // Note: all fields are reference-counted so cloning is pretty cheap
79        let handler = self.clone();
80        let fut = async move { handler.handle(request).await };
81        fut.boxed()
82    }
83}