1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 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
//! # micro_http_async
//!
//! ## What is it for?
//! 
//! A small, lightweight crate using async to serve web pages or webapis with high performance and low overhead.
//! 
//! ## How do I use it?
//! 
//! Firstly, install the crate and dependencies:
//! 
//! ```
//! [dependencies]
//! micro_http_async = "0.0.2"
//! tokio = "1.1"
//! ```
//! This crate is designed to abstract away many of the low level code required to run a safe, asynchrynous web server
//! 
//! Here is a small example which shows how to route, use asynchrynous callbacks and load webpage templates from HTML files.
//! 
//! Please note this is probably not the final API
//! 
//! **Example**
//! ```
//! use micro_http_async::HttpServer;
//! use micro_http_async::Request;
//! use micro_http_async::HtmlConstructor;
//! use micro_http_async::Vars;
//! use micro_http_async::Variable;
//! 
//! /// # main handler
//! /// 
//! /// main handler is a test to test our route and function callbacks work
//! /// 
//! /// And it does!
//! /// 
//! /// The way it works is that we run test_handler when we recieve a connection. 
//! /// 
//! /// Then, this handler manipulates the request (for post info, or other info etc)
//! /// 
//! /// after, we return the response as a string. It is then served to the user.
//! /// 
//! /// The syntax is a bit weird but if it works it works. I'll try fix it :')
//! /// 
//! /// It should return a pinned box future result that implements send
//! fn main_handler(_request: Request) -> std::pin::Pin<Box<dyn std::future::Future<Output = Result<String, String>> + Send>>{
//!     // We wrap the return_str as a future, so we can return it for our routing system to call await on
//!     // This works better than making the whole function a future, since doing that causes race errors.
//!     // By returning a Pinned Boxed future, we define it as a future so it works. Just looks a bit odd
//!     let return_future = async move { 
//!         let mut vars = Vars::new();
//!         let test_string = "This string will be outputted dynamically to the web page!".to_string();
//! 
//!         vars.insert("test_var".to_string(), Variable::String(test_string));
//! 
//!        let header = "HTTP/1.1 200 OK\r\n\r\n";
//!         let body = HtmlConstructor::construct_page("./templates/index.html", vars).await;
//!         let page = format!("{}{}", header , body);
//!         Ok(page) 
//!    };
//! 
//!     return Box::pin(return_future);
//! }
//! 
//! /// We have to define a custom error handler, which defines what to do when we have a 404
//! /// 
//! /// Not doing this WILL result in an unrecoverable panic.
//! fn error_handler(request: Request) -> std::pin::Pin<Box<dyn std::future::Future<Output = Result<String, String>> + Send>>{
//! 
//!     let return_future = async move {      
//!         let mut vars = Vars::new();
//!         let test_string = format!("Could not load webpage at <code>127.0.0.1:8080{}</code>", request.uri);
//!         vars.insert("uri".to_string(), Variable::String(test_string));
//! 
//!         let header = "HTTP/1.1 404 ERR\r\n\r\n";
//!         let body = HtmlConstructor::construct_page("./templates/err.html", vars).await;
//!         let page = format!("{}{}", header , body);
//!         Ok(page) 
//!     };
//! 
//!     return Box::pin(return_future);
//! }
//! 
//! /// # main
//! /// 
//! /// Does what it says, just sets up the server and routes
//! /// 
//! /// then listens for incoming connections
//! #[tokio::main]
//! pub async fn main() {
//!     let mut http_server = HttpServer::new("127.0.0.1", "8080").await.expect("Error binding to IP/Port");
//!     
//!     // must be placed on heap so it can be allocated at runtime (alternative is static)
//!     http_server.routes.add_route("/".to_string(), Box::pin(main_handler)).await;
//!     http_server.routes.add_route("err".to_string(), Box::pin(error_handler)).await;
//! 
//!     http_server.listen().await;
//! }
//! 
//! ```
//! 
//! This crate aims only to simplify webapi or lightweight web creation - not intended to run full scale web apps like chatrooms
//! or other high intensity applications. It implements a simple asynchrynous routing system (Made using hashmaps for speed and efficiency)
//! as well as asynchrynous file loading and more. 
//! 
//! The demo above uses 0% CPU under no load, and less than 10mb of memory under usage
#![doc(test(attr(deny(warnings))))]
#![doc(test(no_crate_inject))]

mod server;
mod connection;
mod routes;
mod request;
mod html_loader;

pub use server::HttpServer;
pub use connection::Connection;
pub use routes::Routes;
pub use request::{Request, HttpMethod};
pub use html_loader::{Variable, HtmlConstructor, FileLoader, Vars};