traq_bot_http/parser/
http.rs1use std::future::Future;
4use std::pin::Pin;
5use std::task::{Context, Poll};
6
7use bytes::Bytes;
8use futures_core::ready;
9use futures_util::future::Ready;
10use http_body::Body;
11use http_body_util::{combinators::Collect, Collected};
12use pin_project_lite::pin_project;
13
14use crate::error::{Error, Result};
15use crate::events::{Event, EventKind};
16use crate::parser::RequestParser;
17
18pin_project! {
19 #[must_use]
20 #[project = CollectBodyProject]
21 struct CollectBody<B>
22 where
23 B: Body,
24 B: ?Sized,
25 {
26 #[pin]
27 collect: Collect<B>,
28 }
29}
30
31impl<B> Future for CollectBody<B>
32where
33 B: Body + ?Sized,
34 B::Error: Into<Box<dyn std::error::Error + Send + Sync + 'static>>,
35{
36 type Output = Result<Bytes>;
37
38 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
39 let s = self.project();
40 let collected = ready!(s.collect.poll(cx));
41 let res = collected
42 .map(Collected::to_bytes)
43 .map_err(Error::read_body_failed);
44 Poll::Ready(res)
45 }
46}
47
48pin_project! {
49 #[must_use]
50 #[project = ParseEventKindProject]
51 struct ParseEventKind<K, B> {
52 #[pin]
53 inner: K,
54 body: Option<B>
55 }
56}
57
58impl<K, B> Future for ParseEventKind<K, B>
59where
60 K: Future<Output = Result<EventKind>>,
61{
62 type Output = ParseRequestInner<K, B>;
63
64 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
65 let s = self.project();
66 let res = ready!(s.inner.poll(cx));
67 let next = match res {
68 Ok(kind) => {
69 let body = s.body.take().expect("polled after ready");
70 ParseRequestInner::ParseBody {
71 inner: ParseBody { kind, inner: body },
72 }
73 }
74 Err(e) => ParseRequestInner::ParseEventKindFailed {
75 inner: futures_util::future::ready(Err(e)),
76 },
77 };
78 Poll::Ready(next)
79 }
80}
81
82type ParseEventKindFailed = Ready<Result<Event>>;
83
84pin_project! {
85 #[must_use]
86 #[project = ParseBodyProject]
87 struct ParseBody<B> {
88 kind: EventKind,
89 #[pin]
90 inner: B,
91 }
92}
93
94impl<B> Future for ParseBody<B>
95where
96 B: Future<Output = Result<Bytes>>,
97{
98 type Output = Result<Event>;
99
100 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
101 let s = self.project();
102 let body = ready!(s.inner.poll(cx));
103 let res: Result<Event> = {
104 let body = body?;
105 let body = std::str::from_utf8(&body).map_err(Error::read_body_failed)?;
106 super::parse_body(*s.kind, body)
107 };
108 Poll::Ready(res)
109 }
110}
111
112pin_project! {
113 #[must_use]
114 #[project = ParseRequestInnerProject]
115 #[project_replace = ParseRequestInnerProjectReplace]
116 enum ParseRequestInner<K, B> {
117 ParseEventKind {
118 #[pin]
119 inner: ParseEventKind<K, B>,
120 },
121 ParseEventKindFailed {
122 #[pin]
123 inner: ParseEventKindFailed,
124 },
125 ParseBody {
126 #[pin]
127 inner: ParseBody<B>,
128 }
129 }
130}
131
132impl<K, B> ParseRequestInner<K, B>
133where
134 K: Future<Output = Result<EventKind>>,
135 B: Future<Output = Result<Bytes>>,
136{
137 fn new(kind: K, body: B) -> Self {
138 Self::ParseEventKind {
139 inner: ParseEventKind {
140 inner: kind,
141 body: Some(body),
142 },
143 }
144 }
145}
146
147impl<K, B> Future for ParseRequestInner<K, B>
148where
149 K: Future<Output = Result<EventKind>>,
150 B: Future<Output = Result<Bytes>>,
151{
152 type Output = Result<Event>;
153
154 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
155 use ParseRequestInnerProject::{ParseBody, ParseEventKind, ParseEventKindFailed};
156 let s = self.as_mut().project();
157 let next = match s {
158 ParseEventKind { inner } => ready!(inner.poll(cx)),
159 ParseEventKindFailed { inner } => return inner.poll(cx),
160 ParseBody { inner } => return inner.poll(cx),
161 };
162 self.project_replace(next);
163 cx.waker().wake_by_ref();
164 Poll::Pending
165 }
166}
167
168pin_project! {
169 #[must_use]
175 #[project = ParseRequestProject]
176 pub struct ParseRequest<B>
177 where
178 B: Body,
179 {
180 #[pin]
181 inner: ParseRequestInner<Ready<Result<EventKind>>, CollectBody<B>>
182 }
183}
184
185impl<B> ParseRequest<B>
186where
187 B: Body,
188 B::Error: Into<Box<dyn std::error::Error + Send + Sync + 'static>>,
189{
190 fn new(kind: Result<EventKind>, body: B) -> Self {
191 use http_body_util::BodyExt;
192
193 let kind = futures_util::future::ready(kind);
194 let body = CollectBody {
195 collect: body.collect(),
196 };
197 let inner = ParseRequestInner::new(kind, body);
198 Self { inner }
199 }
200}
201
202impl<B> Future for ParseRequest<B>
203where
204 B: Body,
205 B::Error: Into<Box<dyn std::error::Error + Send + Sync + 'static>>,
206{
207 type Output = Result<Event>;
208
209 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
210 let s = self.project();
211 s.inner.poll(cx)
212 }
213}
214
215impl RequestParser {
216 pub fn parse_request<B>(&self, request: http::Request<B>) -> ParseRequest<B>
260 where
261 B: Body,
262 B::Error: Into<Box<dyn std::error::Error + Send + Sync + 'static>>,
263 {
264 let (parts, body) = request.into_parts();
265 let kind = self.parse_headers(&parts.headers);
266 ParseRequest::new(kind, body)
267 }
268}
269
270#[cfg(test)]
271mod tests {
272 use futures::executor::block_on;
273 use http_body_util::BodyExt;
274
275 use super::{CollectBody, ParseRequest};
276 use crate::{Error, ErrorKind, Event, EventKind};
277
278 #[test]
279 fn collect_body() {
280 let body_content = "some content";
281 let fut = CollectBody {
282 collect: body_content.to_string().collect(),
283 };
284 let collected = block_on(fut).unwrap();
285 assert_eq!(collected, body_content.as_bytes());
286 }
287
288 #[test]
289 fn parse_request_future() {
290 let kind = EventKind::Ping;
291 let payload = r#"{"eventTime": "2019-05-07T04:50:48.582586882Z"}"#;
292 let body = payload.to_string();
293 let fut = ParseRequest::new(Ok(kind), body);
294 let event = block_on(fut).unwrap();
295 assert!(matches!(event, Event::Ping(_)));
296 }
297
298 #[test]
299 fn parse_event_failed() {
300 let err: Error = ErrorKind::BotTokenMismatch.into();
301 let body = String::new();
302 let fut = ParseRequest::new(Err(err), body);
303 let err = block_on(fut).unwrap_err();
304 assert_eq!(err.kind(), ErrorKind::BotTokenMismatch);
305 }
306}