1#![cfg_attr(docsrs, feature(doc_cfg))]
2#![doc = include_str!("../README.md")]
3
4#[macro_use]
5mod macros;
6
7pub mod resources;
8use resources::Resources;
9
10pub mod state;
11
12pub mod routes;
13use routes::{Catcher, ParamsNames, RawRoute, Route, Routes};
14
15#[macro_use]
16pub mod util;
17
18pub mod into;
19use into::IntoRoute;
20
21pub mod error;
22pub use error::{Error, Result};
23
24pub mod extractor;
25pub use extractor::Res;
26
27mod server;
28use server::Server;
29
30mod fire;
31use fire::{RequestConfigs, Wood};
32use tracing::info;
33
34#[cfg(feature = "fs")]
35#[cfg_attr(docsrs, doc(cfg(feature = "fs")))]
36pub mod fs;
37
38#[cfg(feature = "json")]
39#[cfg_attr(docsrs, doc(cfg(feature = "json")))]
40pub mod json;
41
42#[cfg(feature = "ws")]
43#[cfg_attr(docsrs, doc(cfg(feature = "ws")))]
44pub mod ws;
45
46#[cfg(feature = "graphql")]
47#[cfg_attr(docsrs, doc(cfg(feature = "graphql")))]
48pub mod graphql;
49
50pub mod service {
51 pub use crate::server::FireService;
52}
53
54use std::any::Any;
55use std::net::SocketAddr;
56use std::sync::Arc;
57use std::time::Duration;
58
59use tokio::net::ToSocketAddrs;
60use tokio::task::JoinHandle;
61
62pub use types;
63pub use types::{body, header, Body, Request, Response};
64
65pub use codegen::*;
66
67pub async fn build(addr: impl ToSocketAddrs) -> Result<FireBuilder> {
69 FireBuilder::new(addr).await
70}
71
72pub struct FireBuilder {
74 addr: SocketAddr,
75 resources: Resources,
76 routes: Routes,
77 configs: RequestConfigs,
78}
79
80impl FireBuilder {
81 pub(crate) async fn new<A>(addr: A) -> Result<Self>
82 where
83 A: ToSocketAddrs,
84 {
85 let addr = tokio::net::lookup_host(addr)
86 .await
87 .map_err(Error::from_server_error)?
88 .next()
89 .unwrap();
90 Ok(Self {
91 addr,
92 resources: Resources::new(),
93 routes: Routes::new(),
94 configs: RequestConfigs::new(),
95 })
96 }
97
98 pub fn data(&self) -> &Resources {
100 &self.resources
101 }
102
103 pub fn add_data<D>(&mut self, data: D)
104 where
105 D: Any + Send + Sync,
106 {
107 self.resources.insert(data);
108 }
109
110 pub fn add_raw_route<R>(&mut self, route: R)
112 where
113 R: RawRoute + 'static,
114 {
115 let path = route.path();
116 let names = ParamsNames::parse(&path.path);
117 route.validate_requirements(&names, &self.resources);
118 self.routes.push_raw(path, route)
119 }
120
121 pub fn add_route<R>(&mut self, route: R)
123 where
124 R: IntoRoute + 'static,
125 {
126 let route = route.into_route();
127 let path = route.path();
128 let names = ParamsNames::parse(&path.path);
129 route.validate_requirements(&names, &self.resources);
130 self.routes.push(path, route)
131 }
132
133 pub fn add_catcher<C>(&mut self, catcher: C)
135 where
136 C: Catcher + 'static,
137 {
138 catcher.validate_data(&self.resources);
139 self.routes.push_catcher(catcher)
140 }
141
142 pub fn request_size_limit(&mut self, size_limit: usize) {
149 self.configs.size_limit(size_limit)
150 }
151
152 pub fn request_timeout(&mut self, timeout: Duration) {
156 self.configs.timeout(timeout)
157 }
158
159 pub async fn build(self) -> Result<Fire> {
164 let wood =
165 Arc::new(Wood::new(self.resources, self.routes, self.configs));
166
167 let server = Server::bind(self.addr, wood.clone()).await?;
168
169 Ok(Fire { wood, server })
170 }
171
172 pub async fn ignite(self) -> Result<()> {
177 let fire = self.build().await?;
178 fire.ignite().await
179 }
180
181 pub fn ignite_task(self) -> JoinHandle<()> {
186 tokio::spawn(async move { self.ignite().await.unwrap() })
187 }
188
189 pub fn into_pit(self) -> FirePit {
196 let wood =
197 Arc::new(Wood::new(self.resources, self.routes, self.configs));
198
199 FirePit { wood }
200 }
201}
202
203pub struct Fire {
205 wood: Arc<Wood>,
206 server: Server,
207}
208
209impl Fire {
210 pub fn local_addr(&self) -> Option<SocketAddr> {
211 self.server.local_addr().ok()
212 }
213
214 pub fn pit(&self) -> FirePit {
215 FirePit {
216 wood: self.wood.clone(),
217 }
218 }
219
220 pub async fn ignite(self) -> Result<()> {
221 info!("Running server on addr: {}", self.local_addr().unwrap());
222
223 self.server.serve().await
224 }
225}
226
227#[derive(Clone)]
228pub struct FirePit {
229 wood: Arc<Wood>,
230}
231
232impl FirePit {
233 pub fn data(&self) -> &Resources {
234 self.wood.data()
235 }
236
237 pub async fn route(&self, req: &mut Request) -> Option<Result<Response>> {
243 fire::route(&self.wood, req).await
244 }
245}