1use crate::RequestContext;
4use crate::Response;
5use crate::TiiResult;
6use crate::{ConnectionStream, MimeType, RequestBody, ResponseContext, TiiError, UserError};
7use crate::{WebsocketReceiver, WebsocketSender};
8use std::any::Any;
9use std::fmt::{Debug, Formatter};
10use std::marker::PhantomData;
11use std::sync::Mutex;
12use std::thread;
13use std::thread::JoinHandle;
14
15pub struct ThreadAdapterJoinHandle(Box<dyn FnOnce() -> thread::Result<()> + Send>);
17
18impl ThreadAdapterJoinHandle {
19 pub fn new(inner: Box<dyn FnOnce() -> thread::Result<()> + Send>) -> Self {
21 ThreadAdapterJoinHandle(inner)
22 }
23
24 pub fn join(self) -> thread::Result<()> {
26 self.0()
27 }
28}
29
30impl Debug for ThreadAdapterJoinHandle {
31 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
32 f.write_str("ThreadAdapterJoinHandle")
33 }
34}
35
36impl Default for ThreadAdapterJoinHandle {
37 fn default() -> Self {
38 Self(Box::new(|| Ok(())))
39 }
40}
41
42pub trait ThreadAdapter: Send + Sync + Debug {
44 fn spawn(&self, task: Box<dyn FnOnce() + Send>) -> TiiResult<ThreadAdapterJoinHandle>;
46}
47
48#[allow(dead_code)] #[derive(Debug)]
50pub(crate) struct DefaultThreadAdapter;
51impl ThreadAdapter for DefaultThreadAdapter {
52 fn spawn(&self, task: Box<dyn FnOnce() + Send>) -> TiiResult<ThreadAdapterJoinHandle> {
53 let hdl: JoinHandle<()> = thread::Builder::new().spawn(task)?;
54 Ok(ThreadAdapterJoinHandle::new(Box::new(move || hdl.join())))
55 }
56}
57
58pub trait WebsocketEndpoint: Send + Sync {
60 fn serve(
62 &self,
63 request: &RequestContext,
64 receiver: WebsocketReceiver,
65 sender: WebsocketSender,
66 ) -> TiiResult<()>;
67}
68
69trait IntoWebsocketEndpointResponse {
70 fn into(self) -> TiiResult<()>;
71}
72
73impl IntoWebsocketEndpointResponse for TiiResult<()> {
74 fn into(self) -> TiiResult<()> {
75 self
76 }
77}
78
79impl IntoWebsocketEndpointResponse for () {
80 fn into(self) -> TiiResult<()> {
81 Ok(())
82 }
83}
84
85impl<F, R> WebsocketEndpoint for F
86where
87 R: IntoWebsocketEndpointResponse,
88 F: Fn(&RequestContext, WebsocketReceiver, WebsocketSender) -> R + Send + Sync,
89{
90 fn serve(
91 &self,
92 request: &RequestContext,
93 receiver: WebsocketReceiver,
94 sender: WebsocketSender,
95 ) -> TiiResult<()> {
96 self(request, receiver, sender).into()
97 }
98}
99
100pub trait HttpEndpoint: Send + Sync {
113 fn serve(&self, request: &RequestContext) -> TiiResult<Response>;
115
116 fn parse_entity(
119 &self,
120 mime: &MimeType,
121 request: &RequestBody,
122 ) -> TiiResult<Option<Box<dyn Any + Send + Sync>>>;
123}
124
125impl<F, R> HttpEndpoint for F
126where
127 R: Into<TiiResult<Response>>,
128 F: Fn(&RequestContext) -> R + Send + Sync,
129{
130 fn serve(&self, request: &RequestContext) -> TiiResult<Response> {
131 if request.get_request_entity().is_some() {
132 return Err(TiiError::UserError(UserError::BadFilterOrBadEndpointCausedEntityTypeMismatch));
133 }
134
135 self(request).into()
136 }
137 fn parse_entity(
138 &self,
139 _: &MimeType,
140 _: &RequestBody,
141 ) -> TiiResult<Option<Box<dyn Any + Send + Sync>>> {
142 Ok(None)
144 }
145}
146
147pub trait EntityDeserializer<T: Any + Send + Sync> {
149 fn deserialize(&self, mime: &MimeType, body: &RequestBody) -> TiiResult<T>;
152}
153
154impl<F, T> EntityDeserializer<T> for F
155where
156 T: Any + Send + Sync,
157 F: Fn(&MimeType, &RequestBody) -> TiiResult<T>,
158{
159 fn deserialize(&self, mime: &MimeType, body: &RequestBody) -> TiiResult<T> {
160 self(mime, body)
161 }
162}
163
164pub(crate) struct EntityHttpEndpoint<T, F, R, D>
165where
166 T: Any + Send + Sync,
167 R: Into<TiiResult<Response>> + Send,
168 F: Fn(&RequestContext, &T) -> R + Send + Sync,
169 D: EntityDeserializer<T> + Send + Sync,
170{
171 pub(crate) endpoint: F,
172 pub(crate) deserializer: D,
173 pub(crate) _p1: PhantomData<T>,
174 pub(crate) _p2: Mutex<PhantomData<R>>,
181}
182
183impl<T, F, R, D> HttpEndpoint for EntityHttpEndpoint<T, F, R, D>
184where
185 T: Any + Send + Sync,
186 R: Into<TiiResult<Response>> + Send,
187 F: Fn(&RequestContext, &T) -> R + Send + Sync,
188 D: EntityDeserializer<T> + Send + Sync,
189{
190 fn serve(&self, request: &RequestContext) -> TiiResult<Response> {
191 let Some(entity) = request.get_request_entity() else {
192 return Err(TiiError::UserError(UserError::BadFilterOrBadEndpointCausedEntityTypeMismatch));
193 };
194
195 let Some(entity) = entity.downcast_ref::<T>() else {
196 return Err(TiiError::UserError(UserError::BadFilterOrBadEndpointCausedEntityTypeMismatch));
197 };
198
199 (self.endpoint)(request, entity).into()
200 }
201
202 fn parse_entity(
203 &self,
204 mime: &MimeType,
205 request: &RequestBody,
206 ) -> TiiResult<Option<Box<dyn Any + Send + Sync>>> {
207 let result: T = self.deserializer.deserialize(mime, request)?;
208 Ok(Some(Box::new(result) as Box<dyn Any + Send + Sync>))
209 }
210}
211
212pub trait RouterFilter: Send + Sync {
216 fn filter(&self, request: &RequestContext) -> TiiResult<bool>;
220}
221
222impl<F: Fn(&RequestContext) -> TiiResult<bool> + Send + Sync> RouterFilter for F {
223 fn filter(&self, request: &RequestContext) -> TiiResult<bool> {
224 self(request)
225 }
226}
227
228trait IntoRequestFilterResult {
229 fn into(self) -> TiiResult<Option<Response>>;
230}
231
232impl IntoRequestFilterResult for Option<Response> {
233 fn into(self) -> TiiResult<Option<Response>> {
234 Ok(self)
235 }
236}
237
238impl IntoRequestFilterResult for TiiResult<Option<Response>> {
239 fn into(self) -> TiiResult<Option<Response>> {
240 self
241 }
242}
243impl IntoRequestFilterResult for () {
244 fn into(self) -> TiiResult<Option<Response>> {
245 Ok(None)
246 }
247}
248
249impl IntoRequestFilterResult for TiiResult<()> {
250 fn into(self) -> TiiResult<Option<Response>> {
251 self.map(|_| None)
252 }
253}
254
255pub trait RequestFilter: Send + Sync {
263 fn filter(&self, request: &mut RequestContext) -> TiiResult<Option<Response>>;
268}
269
270impl<F, R> RequestFilter for F
271where
272 R: IntoRequestFilterResult,
273 F: Fn(&mut RequestContext) -> R + Send + Sync,
274{
275 fn filter(&self, request: &mut RequestContext) -> TiiResult<Option<Response>> {
276 self(request).into()
277 }
278}
279
280pub trait ResponseFilter: Send + Sync {
287 fn filter(&self, request: &mut ResponseContext<'_>) -> TiiResult<()>;
291}
292
293impl<F, R> ResponseFilter for F
294where
295 R: Into<TiiResult<()>>,
296 F: Fn(&mut ResponseContext<'_>) -> R + Send + Sync,
297{
298 fn filter(&self, request: &mut ResponseContext<'_>) -> TiiResult<()> {
299 self(request).into()
300 }
301}
302
303#[derive(Debug)]
307pub enum RouterWebSocketServingResponse {
308 HandledWithProtocolSwitch,
310 HandledWithoutProtocolSwitch(Response),
312 NotHandled,
314}
315
316pub trait Router: Debug + Send + Sync {
318 fn serve(&self, request: &mut RequestContext) -> TiiResult<Option<Response>>;
325
326 fn serve_websocket(
333 &self,
334 stream: &dyn ConnectionStream,
335 request: &mut RequestContext,
336 ) -> TiiResult<RouterWebSocketServingResponse>;
337}