traq_bot_http/
handler.rs

1//! [`Handler`]の実装で使われるヘルパー群です。
2//!
3//! # Note
4//! このモジュール内のアイテムは全て**unstable**です。
5//!
6//! [`Handler`]: crate::Handler
7
8use std::marker::PhantomData;
9use std::sync::Arc;
10use std::task::{Context, Poll};
11
12use http::{Request, Response};
13use paste::paste;
14use tower_service::Service;
15
16use super::Handler;
17use crate::macros::all_events;
18use crate::{Error, Event, RequestParser};
19
20mod future;
21
22#[allow(clippy::module_name_repetitions)]
23pub use future::{HandlerCall, WrapErrorFuture};
24
25/// handleされなかった[`Event`]の受け皿となる[`Service`]です。
26///
27/// [`Event`]: crate::Event
28/// [`Service`]: tower::Service
29#[must_use]
30#[derive(Debug, Clone, Copy)]
31pub struct Sink {
32    // ユーザーが直接構築できないように
33    _priv: PhantomData<()>,
34}
35
36impl Sink {
37    fn new() -> Self {
38        Self { _priv: PhantomData }
39    }
40}
41
42impl<T> Service<T> for Sink {
43    type Response = ();
44    type Error = Error;
45    type Future = futures_util::future::Ready<Result<(), Error>>;
46
47    fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
48        Poll::Ready(Ok(()))
49    }
50
51    #[inline]
52    fn call(&mut self, _request: T) -> Self::Future {
53        futures_util::future::ready(Ok(()))
54    }
55}
56
57/// 内部の`Service`に`State`を渡す[`Service`]です。
58///
59/// `WithState::call`の度に`State`がcloneされるため、`State`は[`Clone`]を実装する必要があります。
60///
61/// [`Service`]: tower::Service
62/// [`Clone`]: std::clone::Clone
63#[must_use]
64#[derive(Debug, Clone)]
65pub struct WithState<State, Service> {
66    state: Arc<State>,
67    service: Service,
68}
69
70impl<State, Srv> WithState<State, Srv> {
71    fn new(state: State, service: Srv) -> Self {
72        let state = Arc::new(state);
73        Self { state, service }
74    }
75
76    fn clone_state(&self) -> State
77    where
78        State: Clone,
79    {
80        State::clone(&*self.state)
81    }
82}
83
84impl<State, Srv> Service<Event> for WithState<State, Srv>
85where
86    Srv: Service<(State, Event)>,
87    State: Clone,
88{
89    type Response = Srv::Response;
90    type Error = Srv::Error;
91    type Future = Srv::Future;
92
93    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
94        self.service.poll_ready(cx)
95    }
96
97    #[inline]
98    fn call(&mut self, request: Event) -> Self::Future {
99        self.service.call((self.clone_state(), request))
100    }
101}
102
103impl<OState, State, Srv> Service<(OState, Event)> for WithState<State, Srv>
104where
105    Srv: Service<(State, Event)>,
106    State: Clone,
107{
108    type Response = Srv::Response;
109    type Error = Srv::Error;
110    type Future = Srv::Future;
111
112    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
113        self.service.poll_ready(cx)
114    }
115
116    #[inline]
117    fn call(&mut self, (_, request): (OState, Event)) -> Self::Future {
118        self.service.call((self.clone_state(), request))
119    }
120}
121
122macro_rules! all_event_service {
123    (
124        $( $e:ident ),*
125    ) => {
126        $( $crate::macros::event_service! {
127            #[doc = paste! { concat!(
128                "[`", stringify!([< $e:camel Payload >]), "`]をhandleする[`Service`]です。\n\n",
129                "[`Service`]: tower::Service\n",
130                "[`", stringify!([< $e:camel Payload >]), "`]: ",
131                "crate::payloads::", stringify!([< $e:camel Payload >]),
132            )}]
133            #[must_use]
134            #[derive(Debug, Clone)]
135            pub $e
136        } )*
137    };
138}
139
140all_events! {all_event_service}
141
142impl<Service> Handler<Service> {
143    // TODO: これpubにしたい
144    /// 新しくイベントハンドラを作成します。`service`は以下の条件を満たす必要があります。
145    ///
146    /// - <code>[Service]<[Event]></code>, [`Clone`]を実装している
147    /// - `Service::Response`が`()`と等しい
148    /// - `Service::Error`が<code>Into<Box<dyn [Error] + [Send] + [Sync] + &#39;static>></code>を実装している
149    ///
150    /// [Service]: tower::Service
151    /// [Event]: crate::Event
152    /// [`Clone`]: std::clone::Clone
153    /// [Error]: std::error::Error
154    /// [Send]: std::marker::Send
155    /// [Sync]: std::marker::Sync
156    fn new(parser: crate::RequestParser, service: Service) -> Self {
157        Self { service, parser }
158    }
159
160    /// イベントハンドラに`State`を追加します。`State`は以下の条件を満たす必要があります。
161    ///
162    /// - [`Clone`]を実装している
163    ///
164    /// # Example
165    ///
166    /// ```
167    /// use std::convert::Infallible;
168    ///
169    /// use tower::service_fn;
170    /// use traq_bot_http::{payloads, RequestParser};
171    ///
172    /// async fn on_ping(state: i32, payload: payloads::PingPayload) -> Result<(), Infallible> {
173    ///     println!("state: {state}, payload: {payload:?}");
174    ///     Ok(())
175    /// }
176    ///
177    /// let parser = RequestParser::new("verification_token");
178    /// let handler = parser
179    ///     .into_handler()
180    ///     // これはinvalidです; with_stateはstateを使用するハンドラより後に置く必要があります
181    ///     // .with_state(0)
182    ///     .on_ping(service_fn(|(state, payload)| on_ping(state, payload)))
183    ///     .with_state(0);
184    /// # let _ = handler;
185    /// ```
186    ///
187    /// [`Clone`]: std::clone::Clone
188    // TODO: State: Clone
189    pub fn with_state<State>(self, state: State) -> Handler<WithState<State, Service>> {
190        let Self { service, parser } = self;
191        Handler {
192            service: WithState::new(state, service),
193            parser,
194        }
195    }
196}
197
198impl RequestParser {
199    /// [イベントハンドラ](crate::Handler)に変換します。
200    ///
201    /// **Note**: この関数は`tower`featureが有効になっている時のみ提供されます。
202    pub fn into_handler(self) -> Handler<Sink> {
203        Handler::new(self, Sink::new())
204    }
205}
206
207macro_rules! all_handler_on_events {
208    (
209        $( $e:ident ),*
210    ) => {
211        $crate::macros::handler_on_events! { $(
212            #[doc = paste! { concat!(
213                "[`", stringify!([< $e:camel Payload >]), "`]をhandleする[`Service`]を登録します。\n\n",
214                "引数の型`Service2`は`Service<Req>` traitを実装し、さらに以下の条件を満たす必要があります。\n\n",
215                "- [`Clone`]を実装している\n",
216                "- `Req`が次のうちいずれかと等しい\n",
217                "  - [`", stringify!([< $e:camel Payload >]), "`]\n",
218                "  - `(State, ", stringify!([< $e:camel Payload >]), ")` ",
219                "(`State`に関しては[`Handler::with_state`]を参照してください)\n",
220                "- `Service2::Response`が`()`と等しい\n",
221                "- `Service2::Error`が<code>Into<Box<dyn [Error] + [Send] + [Sync] + &#39;static>></code>を実装している\n\n",
222                "[`Service`]: tower::Service\n",
223                "[`", stringify!([< $e:camel Payload >]), "`]: ",
224                "crate::payloads::", stringify!([< $e:camel Payload >]), "\n",
225                "[`Clone`]: std::clone::Clone\n",
226                "[`Handler::with_state`]: crate::Handler::with_state\n",
227                "[Error]: std::error::Error\n",
228                "[Send]: std::marker::Send\n",
229                "[Sync]: std::marker::Sync\n",
230            ) } ]
231            pub $e;
232        )* }
233    };
234}
235
236all_events! {all_handler_on_events}
237
238impl<Srv, Body> Service<Request<Body>> for Handler<Srv>
239where
240    Srv: Service<Event, Response = (), Error = Error>,
241    Srv: Clone,
242    Body: http_body::Body,
243    Body::Error: Into<Box<dyn std::error::Error + Send + Sync + 'static>>,
244{
245    type Response = Response<String>;
246    type Error = Error;
247    type Future = HandlerCall<Body, Srv>;
248
249    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
250        self.service.poll_ready(cx).map_err(Error::handler)
251    }
252
253    fn call(&mut self, req: Request<Body>) -> Self::Future {
254        let parse_request = self.parser.parse_request(req);
255        let mut s = self.service.clone();
256        // https://docs.rs/tower/latest/tower/trait.Service.html#be-careful-when-cloning-inner-services
257        std::mem::swap(&mut self.service, &mut s);
258        HandlerCall::new(parse_request, s)
259    }
260}