1pub mod http;
2pub mod modules;
3
4use crate::http::cookie::{CookieJar, CookieReq};
5use crate::http::method::Method;
6use crate::http::request::{Request, RequestBuilder};
7use crate::http::response::ResponseBuilder;
8use crate::http::status::StatusCode;
9use crate::modules::displayable::DisplayableVec;
10use crate::modules::router::route::Route;
11use crate::modules::router::Router;
12use crate::modules::session::cookie_session::CookieSession;
13use crate::modules::session::{Session, SessionType};
14use crate::modules::state::State;
15use crate::modules::stream_reader::StreamReader;
16use serde::Deserialize;
17use std::any::Any;
18use std::collections::HashMap;
19use std::error::Error;
20use std::sync::{Arc, RwLock};
21use tracing_log::log::{log, Level};
22
23pub struct NuttServer {
24 address_dev: Option<(String, u16)>,
25 address_release: Option<(String, u16)>,
26 router: Router,
27 states: Arc<RwLock<HashMap<String, Box<dyn Any + Send + Sync>>>>,
28 session: Option<Session>,
29}
30
31impl Default for NuttServer {
32 fn default() -> Self {
33 Self::new()
34 }
35}
36
37impl NuttServer {
38 pub fn new() -> Self {
39 Self {
40 address_dev: None,
41 address_release: None,
42 router: Router::new(),
43 states: Arc::new(RwLock::new(HashMap::new())),
44 session: None,
45 }
46 }
47
48 pub fn routes(mut self, routes: Vec<Route>) -> Self {
49 for route in routes {
50 self.router.insert(route.get(), route)
51 }
52 self
53 }
54
55 pub fn bind_dev(mut self, address: (&str, u16)) -> Self {
56 self.address_dev = Some((address.0.to_string(), address.1));
57 self
58 }
59
60 pub fn bind_release(mut self, address: (&str, u16)) -> Self {
61 self.address_release = Some((address.0.to_string(), address.1));
62 self
63 }
64
65 pub fn state<T: Sync + Send + 'static + for<'a> Deserialize<'a>>(
66 self,
67 state: (String, State<T>),
68 ) -> Self {
69 self.states
70 .try_write()
71 .unwrap()
72 .insert(state.0, Box::new(state.1));
73 self
74 }
75
76 pub fn session(mut self, session_type: SessionType) -> Self {
77 match session_type {
78 SessionType::Cookie => self.session = Some(Session::Cookie(CookieSession::new())),
79 }
80 self
81 }
82
83 pub async fn run(self) {
84 tracing_subscriber::fmt::init();
85 let address = if cfg!(not(debug_assertions)) && self.address_release.is_some() {
86 self.address_release
87 } else {
88 self.address_dev
89 };
90 if let Some(address) = address {
91 let listener = tokio::net::TcpListener::bind(format!("{}:{}", address.0, address.1))
92 .await
93 .unwrap();
94 log!(Level::Info, "Server started on {}:{}", address.0, address.1);
95 let router = Arc::new(self.router);
96 let states = self.states.clone();
97 let session = Arc::new(self.session);
98 loop {
99 let router_arc = router.clone();
100 let states_arc = states.clone();
101 let session_arc = session.clone();
102 match listener.accept().await {
103 Ok((stream, _)) => {
104 tokio::task::spawn(async move {
105 match Self::handle_stream(stream).await {
106 Ok((method, path, stream, mut req)) => {
107 if let Some(route) = router_arc.get((method, path)) {
108 req.set_states(states_arc.clone());
109 req.set_session(session_arc.clone());
110 route.run_fabric(stream, req)
111 } else {
112 stream
113 .try_write(not_found!().to_string().as_bytes())
114 .unwrap();
115 }
116 }
117 Err(e) => log!(Level::Error, "Error handling stream: {}", e),
118 }
119 });
120 }
121 Err(e) => {
122 log!(Level::Error, "Failed to accept connection: {}", e);
123 }
124 }
125 }
126 } else {
127 panic!("Server don't have address")
128 }
129 }
130
131 async fn handle_stream(
132 mut stream: tokio::net::TcpStream,
133 ) -> Result<(Method, String, tokio::net::TcpStream, Request), Box<dyn Error>> {
134 let request = StreamReader::new(&mut stream).read_req().await;
135 let tokens: Vec<&str> = request.lines().nth(0).unwrap().split_whitespace().collect();
136 if tokens.len() != 3 {
137 return Err("Invalid HTTP request line".into());
138 }
139
140 let method = match tokens[0] {
141 "GET" => Method::GET,
142 "POST" => Method::POST,
143 "PUT" => Method::PUT,
144 "DELETE" => Method::DELETE,
145 _ => return Err("Unsupported HTTP method".into()),
146 };
147
148 let path = tokens[1].to_string();
149
150 let mut headers = DisplayableVec(vec![]);
151 let mut i = 1;
152 let mut is_header = true;
153 let mut body = String::new();
154 while let Some(line) = request.lines().nth(i) {
155 if line.is_empty() {
156 is_header = false
157 }
158 if is_header {
159 headers.0.push(line.to_string());
160 } else {
161 body.push_str(line.trim())
162 }
163 i += 1;
164 }
165
166 let mut cookies = CookieJar::new();
167
168 for header in &headers.0 {
169 if header.starts_with("Cookie: ") {
170 for cookie in header[8..].split(";") {
171 let eq_pos = cookie.find("=").unwrap();
172 cookies.push_cookie(
173 &cookie[..eq_pos],
174 CookieReq::new(cookie[eq_pos + 1..].to_string()),
175 )
176 }
177 }
178 }
179
180 log!(
181 Level::Info,
182 "Request Method: {}, Path: {}, Headers: {}, Body: {}",
183 method,
184 path,
185 headers,
186 body
187 );
188
189 Ok((
190 method.clone(),
191 path,
192 stream,
193 RequestBuilder::new(method, serde_json::to_value(body).unwrap())
194 .set_cookie_jar(cookies)
195 .build(),
196 ))
197 }
198}