documentation

This commit is contained in:
MeexReay 2024-07-01 21:12:31 +03:00
parent b7cd187c0e
commit 3e51e91630
2 changed files with 81 additions and 26 deletions

View File

@ -18,6 +18,7 @@ use std::{
sync::{mpsc, Mutex}, sync::{mpsc, Mutex},
}; };
/// Http headers
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Headers { pub struct Headers {
entries: Vec<(String, String)>, entries: Vec<(String, String)>,
@ -51,18 +52,9 @@ impl Headers {
} }
} }
pub fn contains_value(self, value: impl ToString) -> bool { pub fn contains(self, header: impl ToString) -> bool {
for (_, v) in self.entries {
if v == value.to_string() {
return true;
}
}
return false;
}
pub fn contains_key(self, key: impl ToString) -> bool {
for (k, _) in self.entries { for (k, _) in self.entries {
if k.to_lowercase() == key.to_string().to_lowercase() { if k.to_lowercase() == header.to_string().to_lowercase() {
return true; return true;
} }
} }
@ -124,6 +116,7 @@ impl Display for Headers {
} }
} }
/// Http request
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct HttpRequest { pub struct HttpRequest {
pub page: String, pub page: String,
@ -140,6 +133,7 @@ impl Display for HttpRequest {
} }
} }
/// Http response
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct HttpResponse { pub struct HttpResponse {
pub headers: Headers, pub headers: Headers,
@ -241,17 +235,19 @@ fn split(text: String, delimiter: &str, times: usize) -> Vec<String> {
} }
impl HttpRequest { impl HttpRequest {
/// Create new http request
pub fn new(page: &str, method: &str, params: Value, headers: Headers, data: Vec<u8>) -> Self { pub fn new(page: &str, method: &str, params: Value, headers: Headers, data: Vec<u8>) -> Self {
HttpRequest { HttpRequest {
page: page.to_string(), page: page.to_string(),
method: method.to_string(), method: method.to_string(),
addr: String::new(), addr: String::new(),
params: params, params,
headers: headers, headers,
data: data, data,
} }
} }
/// Read http request from stream
pub fn read(data: &mut impl Read, addr: &SocketAddr) -> Result<HttpRequest, HttpError> { pub fn read(data: &mut impl Read, addr: &SocketAddr) -> Result<HttpRequest, HttpError> {
let octets = match addr.ip() { let octets = match addr.ip() {
IpAddr::V4(ip) => ip.octets(), IpAddr::V4(ip) => ip.octets(),
@ -406,15 +402,16 @@ impl HttpRequest {
} }
Ok(HttpRequest { Ok(HttpRequest {
page: page, page,
method: method, method,
addr: ip_str.to_string(), addr: ip_str.to_string(),
params: Value::Object(params), params: Value::Object(params),
headers: headers, headers,
data: reqdata.clone(), data: reqdata.clone(),
}) })
} }
/// Read http request with http_rrs support
pub fn read_with_rrs(data: &mut impl Read) -> Result<HttpRequest, HttpError> { pub fn read_with_rrs(data: &mut impl Read) -> Result<HttpRequest, HttpError> {
let addr = match read_line_lf(data) { let addr = match read_line_lf(data) {
Ok(i) => i, Ok(i) => i,
@ -428,6 +425,7 @@ impl HttpRequest {
HttpRequest::read(data, &addr) HttpRequest::read(data, &addr)
} }
/// Set params to query in url
pub fn params_to_page(&mut self) { pub fn params_to_page(&mut self) {
let mut query = String::new(); let mut query = String::new();
@ -450,6 +448,14 @@ impl HttpRequest {
self.page += query.as_str(); self.page += query.as_str();
} }
/// Set params to json data
pub fn params_to_json(&mut self) {
self.data = Vec::from(self.params.to_string().as_bytes());
}
/// Write http request to stream
///
/// [`params`](Self::params) is not written to the stream, you need to use [`params_to_json`](Self::params_to_json) or [`params_to_page`](Self::params_to_page)
pub fn write(self, data: &mut impl Write) -> Result<(), HttpError> { pub fn write(self, data: &mut impl Write) -> Result<(), HttpError> {
let mut head: String = String::new(); let mut head: String = String::new();
head.push_str(&self.method); head.push_str(&self.method);
@ -484,26 +490,30 @@ impl HttpRequest {
} }
impl HttpResponse { impl HttpResponse {
/// Create new http response with empty headers and data and a 200 OK status code
pub fn new() -> Self { pub fn new() -> Self {
Self::from_bytes(Headers::new(), "200 OK", Vec::new()) Self::from_bytes(Headers::new(), "200 OK", Vec::new())
} }
/// Create new http response from headers, bytes data, and status code
pub fn from_bytes(headers: Headers, status_code: impl ToString, data: Vec<u8>) -> Self { pub fn from_bytes(headers: Headers, status_code: impl ToString, data: Vec<u8>) -> Self {
HttpResponse { HttpResponse {
headers: headers, headers,
data: data, data,
status_code: status_code.to_string(), status_code: status_code.to_string(),
} }
} }
/// Create new http response from headers, string data, and status code
pub fn from_string(headers: Headers, status_code: impl ToString, data: impl ToString) -> Self { pub fn from_string(headers: Headers, status_code: impl ToString, data: impl ToString) -> Self {
HttpResponse { HttpResponse {
headers: headers, headers,
data: data.to_string().into_bytes(), data: data.to_string().into_bytes(),
status_code: status_code.to_string(), status_code: status_code.to_string(),
} }
} }
/// Get data in UTF-8
pub fn get_text(self) -> String { pub fn get_text(self) -> String {
match String::from_utf8(self.data) { match String::from_utf8(self.data) {
Ok(i) => i, Ok(i) => i,
@ -511,6 +521,7 @@ impl HttpResponse {
} }
} }
/// Get json [`Value`](Value) from data
pub fn get_json(self) -> Value { pub fn get_json(self) -> Value {
match serde_json::from_str(self.get_text().as_str()) { match serde_json::from_str(self.get_text().as_str()) {
Ok(i) => i, Ok(i) => i,
@ -518,6 +529,7 @@ impl HttpResponse {
} }
} }
/// Read http response from stream
pub fn read(data: &mut impl Read) -> Result<HttpResponse, HttpError> { pub fn read(data: &mut impl Read) -> Result<HttpResponse, HttpError> {
let status = match read_line_crlf(data) { let status = match read_line_crlf(data) {
Ok(i) => i, Ok(i) => i,
@ -591,13 +603,10 @@ impl HttpResponse {
} }
} }
Ok(HttpResponse { Ok(HttpResponse::from_bytes(headers, status_code, reqdata))
headers: headers,
status_code: status_code.to_string(),
data: reqdata,
})
} }
/// Write http response to stream
pub fn write(self, data: &mut impl Write) -> Result<(), &str> { pub fn write(self, data: &mut impl Write) -> Result<(), &str> {
let mut head: String = String::new(); let mut head: String = String::new();
head.push_str("HTTP/1.1 "); head.push_str("HTTP/1.1 ");
@ -627,6 +636,7 @@ impl HttpResponse {
} }
} }
/// Async http server trait
pub trait HttpServer { pub trait HttpServer {
fn on_start(&mut self, host: &str) -> impl Future<Output = ()> + Send; fn on_start(&mut self, host: &str) -> impl Future<Output = ()> + Send;
fn on_close(&mut self) -> impl Future<Output = ()> + Send; fn on_close(&mut self) -> impl Future<Output = ()> + Send;
@ -636,6 +646,7 @@ pub trait HttpServer {
) -> impl Future<Output = Option<HttpResponse>> + Send; ) -> impl Future<Output = Option<HttpResponse>> + Send;
} }
/// Http server start builder
pub struct HttpServerStarter<T: HttpServer + Send + 'static> { pub struct HttpServerStarter<T: HttpServer + Send + 'static> {
http_server: T, http_server: T,
support_http_rrs: bool, support_http_rrs: bool,
@ -644,6 +655,7 @@ pub struct HttpServerStarter<T: HttpServer + Send + 'static> {
threads: usize, threads: usize,
} }
/// Running http server
pub struct RunningHttpServer { pub struct RunningHttpServer {
thread: thread::JoinHandle<()>, thread: thread::JoinHandle<()>,
running: Arc<AtomicBool>, running: Arc<AtomicBool>,
@ -654,6 +666,7 @@ impl RunningHttpServer {
RunningHttpServer { thread, running } RunningHttpServer { thread, running }
} }
/// Stop http server
pub fn close(self) { pub fn close(self) {
self.running.store(false, Ordering::Release); self.running.store(false, Ordering::Release);
self.thread.join().unwrap(); self.thread.join().unwrap();
@ -661,6 +674,7 @@ impl RunningHttpServer {
} }
impl<T: HttpServer + Send + 'static> HttpServerStarter<T> { impl<T: HttpServer + Send + 'static> HttpServerStarter<T> {
/// Create new HttpServerStarter
pub fn new(http_server: T, host: &str) -> Self { pub fn new(http_server: T, host: &str) -> Self {
HttpServerStarter { HttpServerStarter {
http_server, http_server,
@ -671,31 +685,68 @@ impl<T: HttpServer + Send + 'static> HttpServerStarter<T> {
} }
} }
/// Set http server
pub fn http_server(mut self, http_server: T) -> Self { pub fn http_server(mut self, http_server: T) -> Self {
self.http_server = http_server; self.http_server = http_server;
return self; return self;
} }
/// Set if http_rrs is supported
pub fn support_http_rrs(mut self, support_http_rrs: bool) -> Self { pub fn support_http_rrs(mut self, support_http_rrs: bool) -> Self {
self.support_http_rrs = support_http_rrs; self.support_http_rrs = support_http_rrs;
return self; return self;
} }
/// Set timeout for read & write
pub fn timeout(mut self, timeout: Option<Duration>) -> Self { pub fn timeout(mut self, timeout: Option<Duration>) -> Self {
self.timeout = timeout; self.timeout = timeout;
return self; return self;
} }
/// Set host
pub fn host(mut self, host: String) -> Self { pub fn host(mut self, host: String) -> Self {
self.host = host; self.host = host;
return self; return self;
} }
/// Set threads in threadpool and return builder
///
/// 0 threads means that a new thread is created for each connection
/// 1 thread means that all connections are processed in the main thread
pub fn threads(mut self, threads: usize) -> Self { pub fn threads(mut self, threads: usize) -> Self {
self.threads = threads; self.threads = threads;
return self; return self;
} }
/// Get http server
pub fn get_http_server(self) -> T {
self.http_server
}
/// Get if http_rrs is supported
pub fn get_support_http_rrs(&self) -> bool {
self.support_http_rrs
}
/// Get timeout for read & write
pub fn get_timeout(&self) -> Option<Duration> {
self.timeout
}
/// Get host
pub fn get_host(&self) -> &str {
&self.host
}
/// Get threads in threadpool
///
/// 0 threads means that a new thread is created for each connection
/// 1 thread means that all connections are processed in the main thread
pub fn get_threads(&self) -> usize {
self.threads
}
/// Start http server forever with options
pub fn start_forever(self) -> Result<(), Box<dyn Error>> { pub fn start_forever(self) -> Result<(), Box<dyn Error>> {
let handler = if self.support_http_rrs { let handler = if self.support_http_rrs {
move |server, sock| { move |server, sock| {
@ -725,6 +776,7 @@ impl<T: HttpServer + Send + 'static> HttpServerStarter<T> {
} }
} }
/// Start http server with options in new thread
pub fn start(self) -> RunningHttpServer { pub fn start(self) -> RunningHttpServer {
let handler = if self.support_http_rrs { let handler = if self.support_http_rrs {
move |server, sock| { move |server, sock| {
@ -999,6 +1051,9 @@ impl Worker {
} }
} }
/// Start [`HttpServer`](HttpServer) on some host
///
/// Use [`HttpServerStarter`](HttpServerStarter) to set more options
pub fn start_server<S: HttpServer + Send + 'static>(server: S, host: &str) { pub fn start_server<S: HttpServer + Send + 'static>(server: S, host: &str) {
start_server_new_thread( start_server_new_thread(
server, server,

View File

@ -1,5 +1,5 @@
use ezhttp::{Headers, HttpRequest, HttpResponse, HttpServer, HttpServerStarter}; use ezhttp::{Headers, HttpRequest, HttpResponse, HttpServer, HttpServerStarter};
use std::{collections::HashMap, time::Duration}; use std::time::Duration;
struct EzSite { struct EzSite {
index_page: String, index_page: String,