traq_bot_http/handler/
future.rs

1use std::future::Future;
2use std::marker::PhantomData;
3use std::pin::Pin;
4use std::task::{Context, Poll};
5
6use futures_core::ready;
7use http::{Response, StatusCode};
8use http_body::Body;
9use pin_project_lite::pin_project;
10use tower_service::Service;
11
12use crate::error::{Error, Result};
13use crate::events::Event;
14use crate::parser::ParseRequest;
15
16pin_project! {
17    /// <code>impl [Future]<Output = Result<(), [Error]>></code>
18    ///
19    /// `F: Future<Output = Result<(), E>>`を受け取り、エラー型`E`を[`Error`]に変換した[`Future`]を返します。
20    /// 以下のコードと同様です。
21    ///
22    /// ```ignore
23    /// use futures::TryFutureExt;
24    ///
25    /// async fn f() -> Result<(), E> { ... }
26    ///
27    /// let wrap_error = f().map_err(|e| -> traq_bot_http::Error { ... });
28    /// ```
29    ///
30    /// [Future]: std::future::Future
31    /// [Error]: crate::error::Error
32    /// [`Future`]: std::future::Future
33    /// [`Error`]: crate::error::Error
34    #[must_use]
35    #[project = WrapErrorFutureProject]
36    #[derive(Debug)]
37    pub struct WrapErrorFuture<F, E> {
38        _error: PhantomData<E>,
39        #[pin]
40        inner: F,
41    }
42}
43
44impl<F, E> WrapErrorFuture<F, E> {
45    pub(crate) fn new(inner: F) -> Self {
46        Self {
47            _error: PhantomData,
48            inner,
49        }
50    }
51}
52
53impl<F, E> Future for WrapErrorFuture<F, E>
54where
55    F: Future<Output = Result<(), E>>,
56    E: Into<Box<dyn std::error::Error + Send + Sync + 'static>>,
57{
58    type Output = Result<()>;
59
60    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
61        let s = self.project();
62        let res = ready!(s.inner.poll(cx));
63        Poll::Ready(res.map_err(Error::handler))
64    }
65}
66
67pin_project! {
68    #[must_use]
69    #[project = HandlerCallParseRequestProject]
70    struct HandlerCallParseRequest<B, S>
71    where
72        B: Body,
73    {
74        #[pin]
75        parse_request: ParseRequest<B>,
76        service: S,
77    }
78}
79
80impl<B, S> Future for HandlerCallParseRequest<B, S>
81where
82    B: Body,
83    B::Error: Into<Box<dyn std::error::Error + Send + Sync + 'static>>,
84    S: Service<Event>,
85{
86    type Output = Result<S::Future>;
87
88    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
89        let s = self.project();
90        let event = match ready!(s.parse_request.poll(cx)) {
91            Ok(e) => e,
92            Err(e) => return Poll::Ready(Err(e)),
93        };
94        let call = s.service.call(event);
95        Poll::Ready(Ok(call))
96    }
97}
98
99pin_project! {
100    #[must_use]
101    #[project = HandlerCallServiceCallProject]
102    struct HandlerCallServiceCall<F> {
103        #[pin]
104        inner: F,
105    }
106}
107
108impl<F> Future for HandlerCallServiceCall<F>
109where
110    F: Future<Output = Result<(), Error>>,
111{
112    type Output = Result<Response<String>>;
113
114    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
115        let s = self.project();
116        if let Err(e) = ready!(s.inner.poll(cx)) {
117            return Poll::Ready(Err(e));
118        }
119        let res = Response::builder()
120            .status(StatusCode::NO_CONTENT)
121            .body(String::new())
122            .map_err(Error::handler);
123        Poll::Ready(res)
124    }
125}
126
127pin_project! {
128    #[must_use]
129    #[project = HandlerCallInnerProject]
130    #[project_replace = HandlerCallInnerProjectReplace]
131    enum HandlerCallInner<B, S>
132    where
133        B: Body,
134        S: Service<Event>,
135    {
136        ParseRequest {
137            #[pin]
138            inner: HandlerCallParseRequest<B, S>,
139        },
140        ServiceCall {
141            #[pin]
142            inner: HandlerCallServiceCall<S::Future>,
143        },
144    }
145}
146
147impl<B, S> Future for HandlerCallInner<B, S>
148where
149    B: Body,
150    B::Error: Into<Box<dyn std::error::Error + Send + Sync + 'static>>,
151    S: Service<Event, Response = (), Error = Error>,
152{
153    type Output = Result<Response<String>>;
154
155    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
156        let s = self.as_mut().project();
157        let service_call = match s {
158            HandlerCallInnerProject::ParseRequest { inner } => match ready!(inner.poll(cx)) {
159                Ok(c) => c,
160                Err(e) => return Poll::Ready(Err(e)),
161            },
162            HandlerCallInnerProject::ServiceCall { inner } => return inner.poll(cx),
163        };
164        self.project_replace(HandlerCallInner::ServiceCall {
165            inner: HandlerCallServiceCall {
166                inner: service_call,
167            },
168        });
169        cx.waker().wake_by_ref();
170        Poll::Pending
171    }
172}
173
174pin_project! {
175    /// <code><[Handler] as [Service]<[Request]<[B]>>>::[Future]</code>
176    ///
177    /// [Handler]: crate::Handler
178    /// [Service]: tower::Service
179    /// [Request]: http::Request
180    /// [B]: http_body::Body
181    /// [Future]: crate::Handler::Future
182    #[must_use]
183    #[project = HandlerCallProject]
184    pub struct HandlerCall<B, S>
185    where
186        B: Body,
187        S: Service<Event>,
188    {
189        #[pin]
190        inner: HandlerCallInner<B, S>,
191    }
192}
193
194impl<B, S> HandlerCall<B, S>
195where
196    B: Body,
197    S: Service<Event>,
198{
199    pub(super) fn new(parse_request: ParseRequest<B>, service: S) -> Self {
200        Self {
201            inner: HandlerCallInner::ParseRequest {
202                inner: HandlerCallParseRequest {
203                    parse_request,
204                    service,
205                },
206            },
207        }
208    }
209}
210
211impl<B, S> Future for HandlerCall<B, S>
212where
213    B: Body,
214    B::Error: Into<Box<dyn std::error::Error + Send + Sync + 'static>>,
215    S: Service<Event, Response = (), Error = Error>,
216{
217    type Output = Result<Response<String>>;
218
219    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
220        let s = self.project();
221        s.inner.poll(cx)
222    }
223}