pub struct Server<State: 'static + Send + Sync = ()> {
pub port: u16,
pub ip: Ipv4Addr,
pub routes: Vec<Route<State>>,
pub middleware: Vec<Box<dyn Middleware + Send + Sync>>,
pub state: Option<Arc<State>>,
pub error_handler: Box<dyn Fn(Option<Arc<State>>, &Box<Result<Rc<Request>>>, String) -> Response + Send + Sync>,
pub default_headers: Vec<Header>,
pub keep_alive: bool,
pub socket_timeout: Option<Duration>,
}Expand description
Defines a server.
Fieldsยง
ยงport: u16Port to listen on.
ip: Ipv4AddrIp address to listen on.
routes: Vec<Route<State>>Routes to handle.
middleware: Vec<Box<dyn Middleware + Send + Sync>>Middleware
state: Option<Arc<State>>Server wide App State
error_handler: Box<dyn Fn(Option<Arc<State>>, &Box<Result<Rc<Request>>>, String) -> Response + Send + Sync>Default response for internal server errors
default_headers: Vec<Header>Headers automatically added to every response.
keep_alive: boolWeather to allow keep-alive connections. If this is set to false, the server will close the connection after every request. This is enabled by default.
socket_timeout: Option<Duration>Socket Timeout
Implementationsยง
sourceยงimpl<State: Send + Sync> Server<State>
impl<State: Send + Sync> Server<State>
Implementations for Server
sourcepub fn new(raw_ip: impl ToHostAddress, port: u16) -> Self
pub fn new(raw_ip: impl ToHostAddress, port: u16) -> Self
Creates a new server on the specified address and port.
raw_ip can be either an IP address or โlocalhostโ, which expands to 127.0.0.1.
Example
// Create a server for localhost on port 8080
// Note: The server has not been started yet
let mut server = Server::<()>::new("localhost", 8080);Examples found in repository?
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
fn main() {
// Create Server
let mut server = Server::new("localhost", 8080).state(RwLock::new(Vec::new()));
// New paste interface
server.route(Method::GET, "/", |_req| {
Response::new().content(Content::HTML).text(
r#"
<form action="/new-form" method="post">
<input type="text" name="name" id="name" placeholder="Title">
<br />
<textarea id="body" name="body" rows="5" cols="33"></textarea>
<input type="submit" value="Submit" />
</form>
"#,
)
});
// New paste API handler
server.stateful_route(Method::POST, "/new", move |app, req| {
// Make sure paste data isn't too long
if req.body.len() > DATA_LIMIT {
return Response::new()
.status(Status::NotFound)
.text("Data too big!");
}
// Get the data as string
let body_str = String::from_utf8_lossy(&req.body).to_string();
// Get the name from the Name header
let name = req.headers.get("Name").unwrap_or("Untitled");
let paste = Paste {
name: name.to_owned(),
body: body_str,
time: Instant::now(),
};
// Push this paste to the pastes vector
let mut pastes = app.write().unwrap();
let id = pastes.len();
pastes.push(paste);
// Send Redirect response
Response::new()
.status(Status::MovedPermanently)
.header(HeaderType::Location, format!("/p/{id}"))
.text(format!("Redirecting to /p/{id}."))
});
// New paste form handler
server.stateful_route(Method::POST, "/new-form", |app, req| {
// Get data from response
let query = Query::from_body(String::from_utf8_lossy(&req.body).borrow());
let name = decode_url(query.get("name").unwrap_or("Untitled")).expect("Invalid name");
let body = decode_url(query.get("body").expect("No body supplied")).expect("Invalid body");
// Make sure paste data isn't too long
if body.len() > DATA_LIMIT {
return Response::new()
.status(Status::NotFound)
.text("Data too big!");
}
let paste = Paste {
name,
body,
time: Instant::now(),
};
// Push this paste to the pastes vector
let mut pastes = app.write().unwrap();
let id = pastes.len();
pastes.push(paste);
// Send Redirect response
Response::new()
.status(Status::MovedPermanently)
.text("Ok")
.header(HeaderType::Location, format!("/p/{}", id))
});
// Get pate handler
server.stateful_route(Method::GET, "/p/{id}", move |app, req| {
// Get is from path param
let id = req.param("id").unwrap().parse::<usize>().unwrap();
// Get the paste by id
let paste = &app.read().unwrap()[id];
// Send paste
Response::new().text(&paste.body)
});
// View all pastes
server.stateful_route(Method::GET, "/pastes", move |app, _req| {
// Starter HTML
let mut out = String::from(
r#"<a href="/">New Paste</a><meta charset="UTF-8"><table><tr><th>Name</th><th>Date</th><th>Link</th></tr>"#,
);
// Add a table row for each paste
for (i, e) in app.read().unwrap().iter().enumerate() {
out.push_str(&format!(
"<tr><td>{}</td><td>{}</td><td><a href=\"/p/{}\">๐</a></td></tr>",
e.name,
fmt_relative_time(e.time.elapsed().as_secs()),
i
));
}
// Send HTML
Response::new()
.text(format!("{}</table>", out))
.content(Content::HTML)
});
server.start().unwrap();
}sourcepub fn start(&self) -> Result<()>
pub fn start(&self) -> Result<()>
Starts the server without a threadpool.
This is blocking.
Will return an error if the server cant bind to the specified address, or of you are using stateful routes and have not set the state. (See Server::state)
Example
// Creates a server on localhost (127.0.0.1) port 8080
let mut server = Server::<()>::new("localhost", 8080);
/* Define Routes, Attach Middleware, etc. */
// Starts the server
// This is blocking
server.start().unwrap();Examples found in repository?
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
fn main() {
// Create Server
let mut server = Server::new("localhost", 8080).state(RwLock::new(Vec::new()));
// New paste interface
server.route(Method::GET, "/", |_req| {
Response::new().content(Content::HTML).text(
r#"
<form action="/new-form" method="post">
<input type="text" name="name" id="name" placeholder="Title">
<br />
<textarea id="body" name="body" rows="5" cols="33"></textarea>
<input type="submit" value="Submit" />
</form>
"#,
)
});
// New paste API handler
server.stateful_route(Method::POST, "/new", move |app, req| {
// Make sure paste data isn't too long
if req.body.len() > DATA_LIMIT {
return Response::new()
.status(Status::NotFound)
.text("Data too big!");
}
// Get the data as string
let body_str = String::from_utf8_lossy(&req.body).to_string();
// Get the name from the Name header
let name = req.headers.get("Name").unwrap_or("Untitled");
let paste = Paste {
name: name.to_owned(),
body: body_str,
time: Instant::now(),
};
// Push this paste to the pastes vector
let mut pastes = app.write().unwrap();
let id = pastes.len();
pastes.push(paste);
// Send Redirect response
Response::new()
.status(Status::MovedPermanently)
.header(HeaderType::Location, format!("/p/{id}"))
.text(format!("Redirecting to /p/{id}."))
});
// New paste form handler
server.stateful_route(Method::POST, "/new-form", |app, req| {
// Get data from response
let query = Query::from_body(String::from_utf8_lossy(&req.body).borrow());
let name = decode_url(query.get("name").unwrap_or("Untitled")).expect("Invalid name");
let body = decode_url(query.get("body").expect("No body supplied")).expect("Invalid body");
// Make sure paste data isn't too long
if body.len() > DATA_LIMIT {
return Response::new()
.status(Status::NotFound)
.text("Data too big!");
}
let paste = Paste {
name,
body,
time: Instant::now(),
};
// Push this paste to the pastes vector
let mut pastes = app.write().unwrap();
let id = pastes.len();
pastes.push(paste);
// Send Redirect response
Response::new()
.status(Status::MovedPermanently)
.text("Ok")
.header(HeaderType::Location, format!("/p/{}", id))
});
// Get pate handler
server.stateful_route(Method::GET, "/p/{id}", move |app, req| {
// Get is from path param
let id = req.param("id").unwrap().parse::<usize>().unwrap();
// Get the paste by id
let paste = &app.read().unwrap()[id];
// Send paste
Response::new().text(&paste.body)
});
// View all pastes
server.stateful_route(Method::GET, "/pastes", move |app, _req| {
// Starter HTML
let mut out = String::from(
r#"<a href="/">New Paste</a><meta charset="UTF-8"><table><tr><th>Name</th><th>Date</th><th>Link</th></tr>"#,
);
// Add a table row for each paste
for (i, e) in app.read().unwrap().iter().enumerate() {
out.push_str(&format!(
"<tr><td>{}</td><td>{}</td><td><a href=\"/p/{}\">๐</a></td></tr>",
e.name,
fmt_relative_time(e.time.elapsed().as_secs()),
i
));
}
// Send HTML
Response::new()
.text(format!("{}</table>", out))
.content(Content::HTML)
});
server.start().unwrap();
}sourcepub fn start_threaded(self, threads: usize) -> Result<()>
pub fn start_threaded(self, threads: usize) -> Result<()>
Start the server with a threadpool of threads threads.
Just like Server::start, this is blocking.
Will return an error if the server cant bind to the specified address, or of you are using stateful routes and have not set the state. (See Server::state)
Example
// Import Library
use afire::{Server, Response, Header, Method};
// Creates a server on localhost (127.0.0.1) port 8080
let mut server = Server::<()>::new("localhost", 8080);
/* Define Routes, Attach Middleware, etc. */
// Starts the server with 4 threads
// This is blocking
server.start_threaded(4).unwrap();sourcepub fn default_header(
self,
key: impl Into<HeaderType>,
value: impl AsRef<str>
) -> Self
pub fn default_header( self, key: impl Into<HeaderType>, value: impl AsRef<str> ) -> Self
Add a new default header to the server. This will be added to every response if it is not already present.
This will be added to every response
Example
// Create a server for localhost on port 8080
let mut server = Server::<()>::new("localhost", 8080)
// Add a default header to the response
.default_header("X-Server", "afire");sourcepub fn socket_timeout(self, socket_timeout: Duration) -> Self
pub fn socket_timeout(self, socket_timeout: Duration) -> Self
Set the timeout for the socket. This will ensure that the server will not hang on a request for too long. By default there is no timeout.
Example
// Create a server for localhost on port 8080
let mut server = Server::<()>::new("localhost", 8080)
// Set socket timeout
.socket_timeout(Duration::from_secs(5));sourcepub fn keep_alive(self, keep_alive: bool) -> Self
pub fn keep_alive(self, keep_alive: bool) -> Self
Set the keep alive state of the server. This will determine if the server will keep the connection alive after a request. By default this is true. If you arenโt using a threadpool, you may want to set this to false.
Example
// Create a server for localhost on port 8080
let mut server = Server::<()>::new("localhost", 8080)
// Disable Keep Alive
.keep_alive(false);sourcepub fn state(self, state: State) -> Self
pub fn state(self, state: State) -> Self
Set the state of a server.
The state will be available to stateful routes (Server::stateful_route) and middleware.
It is not mutable, so you will need to use an atomic or sync type to mutate it.
Example
// Create a server for localhost on port 8080
// Note: We can omit the type parameter here because we are setting the state
let mut server = Server::new("localhost", 8080)
// Set server wide state
.state(AtomicU32::new(0));
// Add a stateful route to increment the state
server.stateful_route(Method::GET, "/", |state, _req| {
Response::new().text(state.fetch_add(1, Ordering::Relaxed))
});Examples found in repository?
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
fn main() {
// Create Server
let mut server = Server::new("localhost", 8080).state(RwLock::new(Vec::new()));
// New paste interface
server.route(Method::GET, "/", |_req| {
Response::new().content(Content::HTML).text(
r#"
<form action="/new-form" method="post">
<input type="text" name="name" id="name" placeholder="Title">
<br />
<textarea id="body" name="body" rows="5" cols="33"></textarea>
<input type="submit" value="Submit" />
</form>
"#,
)
});
// New paste API handler
server.stateful_route(Method::POST, "/new", move |app, req| {
// Make sure paste data isn't too long
if req.body.len() > DATA_LIMIT {
return Response::new()
.status(Status::NotFound)
.text("Data too big!");
}
// Get the data as string
let body_str = String::from_utf8_lossy(&req.body).to_string();
// Get the name from the Name header
let name = req.headers.get("Name").unwrap_or("Untitled");
let paste = Paste {
name: name.to_owned(),
body: body_str,
time: Instant::now(),
};
// Push this paste to the pastes vector
let mut pastes = app.write().unwrap();
let id = pastes.len();
pastes.push(paste);
// Send Redirect response
Response::new()
.status(Status::MovedPermanently)
.header(HeaderType::Location, format!("/p/{id}"))
.text(format!("Redirecting to /p/{id}."))
});
// New paste form handler
server.stateful_route(Method::POST, "/new-form", |app, req| {
// Get data from response
let query = Query::from_body(String::from_utf8_lossy(&req.body).borrow());
let name = decode_url(query.get("name").unwrap_or("Untitled")).expect("Invalid name");
let body = decode_url(query.get("body").expect("No body supplied")).expect("Invalid body");
// Make sure paste data isn't too long
if body.len() > DATA_LIMIT {
return Response::new()
.status(Status::NotFound)
.text("Data too big!");
}
let paste = Paste {
name,
body,
time: Instant::now(),
};
// Push this paste to the pastes vector
let mut pastes = app.write().unwrap();
let id = pastes.len();
pastes.push(paste);
// Send Redirect response
Response::new()
.status(Status::MovedPermanently)
.text("Ok")
.header(HeaderType::Location, format!("/p/{}", id))
});
// Get pate handler
server.stateful_route(Method::GET, "/p/{id}", move |app, req| {
// Get is from path param
let id = req.param("id").unwrap().parse::<usize>().unwrap();
// Get the paste by id
let paste = &app.read().unwrap()[id];
// Send paste
Response::new().text(&paste.body)
});
// View all pastes
server.stateful_route(Method::GET, "/pastes", move |app, _req| {
// Starter HTML
let mut out = String::from(
r#"<a href="/">New Paste</a><meta charset="UTF-8"><table><tr><th>Name</th><th>Date</th><th>Link</th></tr>"#,
);
// Add a table row for each paste
for (i, e) in app.read().unwrap().iter().enumerate() {
out.push_str(&format!(
"<tr><td>{}</td><td>{}</td><td><a href=\"/p/{}\">๐</a></td></tr>",
e.name,
fmt_relative_time(e.time.elapsed().as_secs()),
i
));
}
// Send HTML
Response::new()
.text(format!("{}</table>", out))
.content(Content::HTML)
});
server.start().unwrap();
}sourcepub fn error_handler(
&mut self,
res: impl Fn(Option<Arc<State>>, &Box<Result<Rc<Request>>>, String) -> Response + Send + Sync + 'static
)
pub fn error_handler( &mut self, res: impl Fn(Option<Arc<State>>, &Box<Result<Rc<Request>>>, String) -> Response + Send + Sync + 'static )
Set the panic handler, which is called if a route or middleware panics.
This is only available if the panic_handler feature is enabled.
If you donโt set it, the default response is 500 โInternal Server Error :/โ.
Be sure that your panic handler wont panic, because that will just panic the whole application.
Example
// Set the panic handler response
server.error_handler(|_state, _req, err| {
Response::new()
.status(Status::InternalServerError)
.text(format!("Internal Server Error: {}", err))
});sourcepub fn route(
&mut self,
method: Method,
path: impl AsRef<str>,
handler: impl Fn(&Request) -> Response + Send + Sync + 'static
) -> &mut Self
pub fn route( &mut self, method: Method, path: impl AsRef<str>, handler: impl Fn(&Request) -> Response + Send + Sync + 'static ) -> &mut Self
Create a new route.
The path can contain parameters, which are defined with {...}, as well as wildcards, which are defined with *.
(** lets you math anything after the wildcard, including /)
Example
// Define a route
server.route(Method::GET, "/greet/{name}", |req| {
let name = req.param("name").unwrap();
Response::new()
.text(format!("Hello, {}!", name))
.content(Content::TXT)
});Examples found in repository?
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
fn main() {
// Create Server
let mut server = Server::new("localhost", 8080).state(RwLock::new(Vec::new()));
// New paste interface
server.route(Method::GET, "/", |_req| {
Response::new().content(Content::HTML).text(
r#"
<form action="/new-form" method="post">
<input type="text" name="name" id="name" placeholder="Title">
<br />
<textarea id="body" name="body" rows="5" cols="33"></textarea>
<input type="submit" value="Submit" />
</form>
"#,
)
});
// New paste API handler
server.stateful_route(Method::POST, "/new", move |app, req| {
// Make sure paste data isn't too long
if req.body.len() > DATA_LIMIT {
return Response::new()
.status(Status::NotFound)
.text("Data too big!");
}
// Get the data as string
let body_str = String::from_utf8_lossy(&req.body).to_string();
// Get the name from the Name header
let name = req.headers.get("Name").unwrap_or("Untitled");
let paste = Paste {
name: name.to_owned(),
body: body_str,
time: Instant::now(),
};
// Push this paste to the pastes vector
let mut pastes = app.write().unwrap();
let id = pastes.len();
pastes.push(paste);
// Send Redirect response
Response::new()
.status(Status::MovedPermanently)
.header(HeaderType::Location, format!("/p/{id}"))
.text(format!("Redirecting to /p/{id}."))
});
// New paste form handler
server.stateful_route(Method::POST, "/new-form", |app, req| {
// Get data from response
let query = Query::from_body(String::from_utf8_lossy(&req.body).borrow());
let name = decode_url(query.get("name").unwrap_or("Untitled")).expect("Invalid name");
let body = decode_url(query.get("body").expect("No body supplied")).expect("Invalid body");
// Make sure paste data isn't too long
if body.len() > DATA_LIMIT {
return Response::new()
.status(Status::NotFound)
.text("Data too big!");
}
let paste = Paste {
name,
body,
time: Instant::now(),
};
// Push this paste to the pastes vector
let mut pastes = app.write().unwrap();
let id = pastes.len();
pastes.push(paste);
// Send Redirect response
Response::new()
.status(Status::MovedPermanently)
.text("Ok")
.header(HeaderType::Location, format!("/p/{}", id))
});
// Get pate handler
server.stateful_route(Method::GET, "/p/{id}", move |app, req| {
// Get is from path param
let id = req.param("id").unwrap().parse::<usize>().unwrap();
// Get the paste by id
let paste = &app.read().unwrap()[id];
// Send paste
Response::new().text(&paste.body)
});
// View all pastes
server.stateful_route(Method::GET, "/pastes", move |app, _req| {
// Starter HTML
let mut out = String::from(
r#"<a href="/">New Paste</a><meta charset="UTF-8"><table><tr><th>Name</th><th>Date</th><th>Link</th></tr>"#,
);
// Add a table row for each paste
for (i, e) in app.read().unwrap().iter().enumerate() {
out.push_str(&format!(
"<tr><td>{}</td><td>{}</td><td><a href=\"/p/{}\">๐</a></td></tr>",
e.name,
fmt_relative_time(e.time.elapsed().as_secs()),
i
));
}
// Send HTML
Response::new()
.text(format!("{}</table>", out))
.content(Content::HTML)
});
server.start().unwrap();
}sourcepub fn stateful_route(
&mut self,
method: Method,
path: impl AsRef<str>,
handler: impl Fn(Arc<State>, &Request) -> Response + Send + Sync + 'static
) -> &mut Self
pub fn stateful_route( &mut self, method: Method, path: impl AsRef<str>, handler: impl Fn(Arc<State>, &Request) -> Response + Send + Sync + 'static ) -> &mut Self
Create a new stateful route.
Is the same as Server::route, but the state is passed as the first parameter.
(See Server::state)
Note: If you add a stateful route, you must also set the state or starting the sever will return an error.
Example
// Create a server for localhost on port 8080
let mut server = Server::<u32>::new("localhost", 8080)
.state(101);
// Define a route
server.stateful_route(Method::GET, "/nose", |sta, req| {
Response::new().text(sta.to_string())
});Examples found in repository?
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
fn main() {
// Create Server
let mut server = Server::new("localhost", 8080).state(RwLock::new(Vec::new()));
// New paste interface
server.route(Method::GET, "/", |_req| {
Response::new().content(Content::HTML).text(
r#"
<form action="/new-form" method="post">
<input type="text" name="name" id="name" placeholder="Title">
<br />
<textarea id="body" name="body" rows="5" cols="33"></textarea>
<input type="submit" value="Submit" />
</form>
"#,
)
});
// New paste API handler
server.stateful_route(Method::POST, "/new", move |app, req| {
// Make sure paste data isn't too long
if req.body.len() > DATA_LIMIT {
return Response::new()
.status(Status::NotFound)
.text("Data too big!");
}
// Get the data as string
let body_str = String::from_utf8_lossy(&req.body).to_string();
// Get the name from the Name header
let name = req.headers.get("Name").unwrap_or("Untitled");
let paste = Paste {
name: name.to_owned(),
body: body_str,
time: Instant::now(),
};
// Push this paste to the pastes vector
let mut pastes = app.write().unwrap();
let id = pastes.len();
pastes.push(paste);
// Send Redirect response
Response::new()
.status(Status::MovedPermanently)
.header(HeaderType::Location, format!("/p/{id}"))
.text(format!("Redirecting to /p/{id}."))
});
// New paste form handler
server.stateful_route(Method::POST, "/new-form", |app, req| {
// Get data from response
let query = Query::from_body(String::from_utf8_lossy(&req.body).borrow());
let name = decode_url(query.get("name").unwrap_or("Untitled")).expect("Invalid name");
let body = decode_url(query.get("body").expect("No body supplied")).expect("Invalid body");
// Make sure paste data isn't too long
if body.len() > DATA_LIMIT {
return Response::new()
.status(Status::NotFound)
.text("Data too big!");
}
let paste = Paste {
name,
body,
time: Instant::now(),
};
// Push this paste to the pastes vector
let mut pastes = app.write().unwrap();
let id = pastes.len();
pastes.push(paste);
// Send Redirect response
Response::new()
.status(Status::MovedPermanently)
.text("Ok")
.header(HeaderType::Location, format!("/p/{}", id))
});
// Get pate handler
server.stateful_route(Method::GET, "/p/{id}", move |app, req| {
// Get is from path param
let id = req.param("id").unwrap().parse::<usize>().unwrap();
// Get the paste by id
let paste = &app.read().unwrap()[id];
// Send paste
Response::new().text(&paste.body)
});
// View all pastes
server.stateful_route(Method::GET, "/pastes", move |app, _req| {
// Starter HTML
let mut out = String::from(
r#"<a href="/">New Paste</a><meta charset="UTF-8"><table><tr><th>Name</th><th>Date</th><th>Link</th></tr>"#,
);
// Add a table row for each paste
for (i, e) in app.read().unwrap().iter().enumerate() {
out.push_str(&format!(
"<tr><td>{}</td><td>{}</td><td><a href=\"/p/{}\">๐</a></td></tr>",
e.name,
fmt_relative_time(e.time.elapsed().as_secs()),
i
));
}
// Send HTML
Response::new()
.text(format!("{}</table>", out))
.content(Content::HTML)
});
server.start().unwrap();
}