1use std::fmt::Debug;
2use std::io;
3use std::path::Path;
4use std::sync::Arc;
5
6use crate::endpoint::MiddlewareEndpoint;
7use crate::fs::{ServeDir, ServeFile};
8use crate::log;
9use crate::{router::Router, Endpoint, Middleware};
10
11#[allow(missing_debug_implementations)]
20pub struct Route<'a, State> {
21 router: &'a mut Router<State>,
22 path: String,
23 middleware: Vec<Arc<dyn Middleware<State>>>,
24 prefix: bool,
29}
30
31impl<'a, State: Clone + Send + Sync + 'static> Route<'a, State> {
32 pub(crate) fn new(router: &'a mut Router<State>, path: String) -> Route<'a, State> {
33 Route {
34 router,
35 path,
36 middleware: Vec::new(),
37 prefix: false,
38 }
39 }
40
41 pub fn at<'b>(&'b mut self, path: &str) -> Route<'b, State> {
43 let mut p = self.path.clone();
44
45 if !p.ends_with('/') && !path.starts_with('/') {
46 p.push('/');
47 }
48
49 if path != "/" {
50 p.push_str(path);
51 }
52
53 Route {
54 router: &mut self.router,
55 path: p,
56 middleware: self.middleware.clone(),
57 prefix: false,
58 }
59 }
60
61 #[must_use]
63 pub fn path(&self) -> &str {
64 &self.path
65 }
66
67 #[cfg(any(feature = "unstable", feature = "docs"))]
73 #[cfg_attr(feature = "docs", doc(cfg(unstable)))]
74 pub fn strip_prefix(&mut self) -> &mut Self {
75 self.prefix = true;
76 self
77 }
78
79 pub fn with<M>(&mut self, middleware: M) -> &mut Self
81 where
82 M: Middleware<State>,
83 {
84 log::trace!(
85 "Adding middleware {} to route {:?}",
86 middleware.name(),
87 self.path
88 );
89 self.middleware.push(Arc::new(middleware));
90 self
91 }
92
93 pub fn reset_middleware(&mut self) -> &mut Self {
95 self.middleware.clear();
96 self
97 }
98
99 pub fn nest<InnerState>(&mut self, service: crate::Server<InnerState>) -> &mut Self
103 where
104 State: Clone + Send + Sync + 'static,
105 InnerState: Clone + Send + Sync + 'static,
106 {
107 let prefix = self.prefix;
108
109 self.prefix = true;
110 self.all(service);
111 self.prefix = prefix;
112
113 self
114 }
115
116 pub fn serve_dir(&mut self, dir: impl AsRef<Path>) -> io::Result<()> {
136 let dir = dir.as_ref().to_owned().canonicalize()?;
138 let prefix = self.path().to_string();
139 self.at("*").get(ServeDir::new(prefix, dir));
140 Ok(())
141 }
142
143 pub fn serve_file(&mut self, file: impl AsRef<Path>) -> io::Result<()> {
148 self.get(ServeFile::init(file)?);
149 Ok(())
150 }
151
152 pub fn method(&mut self, method: http_types::Method, ep: impl Endpoint<State>) -> &mut Self {
154 if self.prefix {
155 let ep = StripPrefixEndpoint::new(ep);
156
157 self.router.add(
158 &self.path,
159 method,
160 MiddlewareEndpoint::wrap_with_middleware(ep.clone(), &self.middleware),
161 );
162 let wildcard = self.at("*--tide-path-rest");
163 wildcard.router.add(
164 &wildcard.path,
165 method,
166 MiddlewareEndpoint::wrap_with_middleware(ep, &wildcard.middleware),
167 );
168 } else {
169 self.router.add(
170 &self.path,
171 method,
172 MiddlewareEndpoint::wrap_with_middleware(ep, &self.middleware),
173 );
174 }
175 self
176 }
177
178 pub fn all(&mut self, ep: impl Endpoint<State>) -> &mut Self {
182 if self.prefix {
183 let ep = StripPrefixEndpoint::new(ep);
184
185 self.router.add_all(
186 &self.path,
187 MiddlewareEndpoint::wrap_with_middleware(ep.clone(), &self.middleware),
188 );
189 let wildcard = self.at("*--tide-path-rest");
190 wildcard.router.add_all(
191 &wildcard.path,
192 MiddlewareEndpoint::wrap_with_middleware(ep, &wildcard.middleware),
193 );
194 } else {
195 self.router.add_all(
196 &self.path,
197 MiddlewareEndpoint::wrap_with_middleware(ep, &self.middleware),
198 );
199 }
200 self
201 }
202
203 pub fn get(&mut self, ep: impl Endpoint<State>) -> &mut Self {
205 self.method(http_types::Method::Get, ep);
206 self
207 }
208
209 pub fn head(&mut self, ep: impl Endpoint<State>) -> &mut Self {
211 self.method(http_types::Method::Head, ep);
212 self
213 }
214
215 pub fn put(&mut self, ep: impl Endpoint<State>) -> &mut Self {
217 self.method(http_types::Method::Put, ep);
218 self
219 }
220
221 pub fn post(&mut self, ep: impl Endpoint<State>) -> &mut Self {
223 self.method(http_types::Method::Post, ep);
224 self
225 }
226
227 pub fn delete(&mut self, ep: impl Endpoint<State>) -> &mut Self {
229 self.method(http_types::Method::Delete, ep);
230 self
231 }
232
233 pub fn options(&mut self, ep: impl Endpoint<State>) -> &mut Self {
235 self.method(http_types::Method::Options, ep);
236 self
237 }
238
239 pub fn connect(&mut self, ep: impl Endpoint<State>) -> &mut Self {
241 self.method(http_types::Method::Connect, ep);
242 self
243 }
244
245 pub fn patch(&mut self, ep: impl Endpoint<State>) -> &mut Self {
247 self.method(http_types::Method::Patch, ep);
248 self
249 }
250
251 pub fn trace(&mut self, ep: impl Endpoint<State>) -> &mut Self {
253 self.method(http_types::Method::Trace, ep);
254 self
255 }
256}
257
258#[derive(Debug)]
259struct StripPrefixEndpoint<E>(std::sync::Arc<E>);
260
261impl<E> StripPrefixEndpoint<E> {
262 fn new(ep: E) -> Self {
263 Self(std::sync::Arc::new(ep))
264 }
265}
266
267impl<E> Clone for StripPrefixEndpoint<E> {
268 fn clone(&self) -> Self {
269 Self(self.0.clone())
270 }
271}
272
273#[async_trait::async_trait]
274impl<State, E> Endpoint<State> for StripPrefixEndpoint<E>
275where
276 State: Clone + Send + Sync + 'static,
277 E: Endpoint<State>,
278{
279 async fn call(&self, req: crate::Request<State>) -> crate::Result {
280 let crate::Request {
281 state,
282 mut req,
283 route_params,
284 } = req;
285
286 let rest = crate::request::rest(&route_params).unwrap_or("");
287 req.url_mut().set_path(&rest);
288
289 self.0
290 .call(crate::Request {
291 state,
292 req,
293 route_params,
294 })
295 .await
296 }
297}