143 lines
4.5 KiB
Rust
143 lines
4.5 KiB
Rust
use std::{any::type_name_of_val, collections::HashMap, error::Error, sync::Arc};
|
|
|
|
use http_body_util::{Either, Full};
|
|
use hyper::{
|
|
Request, Response, StatusCode,
|
|
body::{Body, Bytes, Incoming},
|
|
rt::{Read, Write},
|
|
server::conn::http1,
|
|
service::{HttpService, Service},
|
|
};
|
|
use hyper_util::rt::TokioIo;
|
|
use json::JsonValue;
|
|
use log::{error, info};
|
|
use rustls::server::Acceptor;
|
|
use tokio::net::{TcpListener, TcpStream};
|
|
use tokio_rustls::{LazyConfigAcceptor, StartHandshake};
|
|
|
|
use crate::tls::TlsOption;
|
|
|
|
pub type GeneralResponse = Response<GeneralBody>;
|
|
pub type GeneralBody = Either<Incoming, Full<Bytes>>;
|
|
|
|
pub fn to_general_response(res: Response<Incoming>) -> GeneralResponse {
|
|
let (parts, body) = res.into_parts();
|
|
Response::from_parts(parts, GeneralBody::Left(body))
|
|
}
|
|
|
|
pub struct Server<S> {
|
|
listener: TcpListener,
|
|
service: S,
|
|
tls: TlsOption,
|
|
}
|
|
|
|
pub trait TcpIntercept {
|
|
fn stream(&mut self, stream: &TcpStream);
|
|
}
|
|
|
|
pub async fn default_response() -> GeneralResponse {
|
|
Response::builder()
|
|
.status(404)
|
|
.body(GeneralBody::Right(Full::from(Bytes::from(
|
|
"That route doesn't exist.",
|
|
))))
|
|
.unwrap()
|
|
}
|
|
|
|
pub async fn custom_resp(e: StatusCode, m: String) -> GeneralResponse {
|
|
Response::builder()
|
|
.status(e)
|
|
.body(GeneralBody::Right(Full::from(Bytes::from(m))))
|
|
.unwrap()
|
|
}
|
|
|
|
pub async fn json_to_vec(v: JsonValue) -> Option<Vec<String>> {
|
|
if let JsonValue::Array(arr) = v {
|
|
Some(
|
|
arr.into_iter()
|
|
.map(|val| val.as_str().unwrap().to_string())
|
|
.collect(),
|
|
)
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
|
|
impl<S> Server<S>
|
|
where
|
|
S: TcpIntercept + Sync,
|
|
S: Service<Request<Incoming>> + Clone + Send + 'static,
|
|
S: HttpService<Incoming> + Clone + Send,
|
|
<S::ResBody as Body>::Error: Into<Box<dyn Error + Send + Sync>>,
|
|
<S::ResBody as Body>::Data: Send,
|
|
S::ResBody: Send,
|
|
<S as HttpService<Incoming>>::Future: Send,
|
|
{
|
|
pub async fn handle(&self) {
|
|
info!(
|
|
"Server started at http://{} for service: {}",
|
|
self.listener.local_addr().unwrap(),
|
|
type_name_of_val(&self.service)
|
|
);
|
|
|
|
loop {
|
|
let (tcp_stream, _) = self.listener.accept().await.unwrap();
|
|
|
|
let mut svc_clone = self.service.clone();
|
|
let tls = self.tls.clone();
|
|
tokio::task::spawn(async move {
|
|
svc_clone.stream(&tcp_stream);
|
|
|
|
match tls {
|
|
TlsOption::NoTls => {
|
|
if let Err(err) = http1::Builder::new()
|
|
.writev(false)
|
|
.serve_connection(TokioIo::new(tcp_stream), svc_clone)
|
|
.await
|
|
{
|
|
error!("Error while trying to serve connection: {err}")
|
|
};
|
|
}
|
|
TlsOption::Tls(x) => {
|
|
let acceptor = LazyConfigAcceptor::new(Acceptor::default(), tcp_stream);
|
|
|
|
match acceptor.await {
|
|
Ok(y) => {
|
|
let hello = y.client_hello();
|
|
let hostname = hello.server_name().clone().unwrap();
|
|
let config = Arc::new(x.matcher(hostname).unwrap());
|
|
let stream = y
|
|
.into_stream(config)
|
|
.await
|
|
.unwrap();
|
|
|
|
if let Err(err) = http1::Builder::new()
|
|
.writev(false)
|
|
.serve_connection(TokioIo::new(stream), svc_clone)
|
|
.await
|
|
{
|
|
error!("Error while trying to serve connection: {err}")
|
|
}
|
|
}
|
|
Err(e) => {
|
|
error!("Error while initiating handshake: {e}");
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
});
|
|
}
|
|
}
|
|
|
|
pub async fn new(service: S, a: (String, u16), tls: TlsOption) -> Result<Self, Box<dyn Error>> {
|
|
Ok(Self {
|
|
listener: TcpListener::bind(&a).await?,
|
|
service,
|
|
tls,
|
|
})
|
|
}
|
|
}
|
|
|
|
/*
|
|
*/
|