mod config;
mod client;
pub mod request;
mod base64;
pub mod response;
mod encoding;
#[cfg(feature = "ws")]
pub mod websocket;
use std::{io, thread};
use std::io::{Error, ErrorKind};
use std::net::{IpAddr, SocketAddr, TcpListener};
use std::path::PathBuf;
use std::sync::Arc;
use std::time::{Duration, Instant};
use log::{error, info, warn};
use openssl::ssl::{SslAcceptor, SslFiletype, SslMethod};
use crate::client::{Client, Scheme};
use crate::config::Config;
use crate::request::Request;
use crate::response::Response;
#[cfg(feature = "ws")]
use crate::websocket::{CloseCode, ErrorCode, Message, Websocket};
#[derive(Clone, Debug)]
pub struct WebServer;
impl WebServer {
#[cfg(feature = "http")]
pub fn new_service(config_file: PathBuf, factory: fn() -> Box<dyn Handler>) {
loop {
match WebServer::service(Config::new(config_file.clone()), factory) {
Ok(_) => {}
Err(e) => error!("{}[{}]: {}",file!(), line!(),e)
};
warn!("服务器 2秒后重启");
thread::sleep(Duration::from_secs(2));
}
}
#[cfg(feature = "web")]
pub fn new_webpage(config_file: PathBuf, factory: fn() -> Box<dyn Handler>) {
loop {
match WebServer::webpage(Config::new(config_file.clone()), factory) {
Ok(_) => {}
Err(e) => error!("{}[{}]: {}",file!(), line!(),e)
};
warn!("网页服务器 2秒后重启");
thread::sleep(Duration::from_secs(2));
}
}
#[cfg(feature = "http")]
fn service(config: Config, factory: fn() -> Box<dyn Handler>) -> io::Result<()> {
info!("==================== 网络服务 服务信息 ====================");
info!("日志记录: {}",if config.is_save_log {"开启"}else{"关闭"});
info!("调试模式: {}",if config.is_debug {"开启"}else{"关闭"});
info!("服务地址: {}",format!("{}", config.address));
info!("根 目 录: {}",format!("{}", config.root_path));
info!("访问目录: {}",format!("{}",config.public));
info!("运行目录: {}",format!("{}", config.runtime));
info!("SSL/TLS: {}",format!("{}", if config.https{"开启"}else{"关闭"}));
if config.https {
info!("证书目录KEY: {}",format!("{:?}", config.tls.key));
info!("证书目录PEM: {}",format!("{:?}", config.tls.certs));
}
let addrs = [
SocketAddr::from((IpAddr::V4(config.host.parse().unwrap()), config.port))
];
let listener = TcpListener::bind(&addrs[..])?;
info!("==================== 网络服务 启动成功 ====================");
let acceptor = if config.https {
let mut acceptor = SslAcceptor::mozilla_intermediate(SslMethod::tls())?;
if !config.tls.key.is_file() {
return Err(Error::new(ErrorKind::Other, format!("private.key 不存在: {:?}", config.tls.key).as_str()));
}
if !config.tls.certs.is_file() {
return Err(Error::new(ErrorKind::Other, format!("certificate.pem 不存在: {:?}", config.tls.certs).as_str()));
}
acceptor.set_private_key_file(config.tls.key.clone(), SslFiletype::PEM)?;
acceptor.set_certificate_file(config.tls.certs.clone(), SslFiletype::PEM)?;
Arc::new(acceptor.build())
} else {
Arc::new(SslAcceptor::mozilla_intermediate(SslMethod::tls())?.build())
};
for stream in listener.incoming() {
match stream {
Ok(stream) => {
let config_new = config.clone();
let acceptor = acceptor.clone();
thread::spawn(move || {
if config_new.write_timeout > 0 {
stream.set_write_timeout(Some(Duration::from_secs(config_new.write_timeout))).unwrap_or_default();
}
if config_new.read_timeout > 0 {
stream.set_read_timeout(Some(Duration::from_secs(config_new.read_timeout))).unwrap_or_default();
}
let client_ip = stream.peer_addr().unwrap().to_string();
let server_ip = stream.local_addr().unwrap().to_string();
let scheme = match config_new.https {
true => {
match acceptor.accept(stream.try_clone().unwrap()) {
Ok(e) => Scheme::Https(e),
Err(_) => return
}
}
false => Scheme::Http(stream.try_clone().unwrap())
};
let mut client = Client {
config: config_new.clone(),
request: Request::default(),
response: Response::new(config_new),
handle_time: Instant::now(),
factory,
};
match client.handle_service(scheme, server_ip.leak(), client_ip.leak()) {
Ok(_) => {}
Err(e) => error!("{}",e)
};
});
}
Err(e) => return Err(e)
}
}
Ok(())
}
#[cfg(feature = "web")]
fn webpage(config: Config, factory: fn() -> Box<dyn Handler>) -> io::Result<()> {
info!("==================== 网页服务 服务信息 ====================");
info!("日志记录: {}",if config.is_save_log {"开启"}else{"关闭"});
info!("调试模式: {}",if config.is_debug {"开启"}else{"关闭"});
info!("服务地址: {}",format!("{}", config.address));
info!("根 目 录: {}",format!("{}", config.root_path));
info!("网页目录: {}",format!("{}", config.webpage));
info!("SSL/TLS: {}",format!("{}", if config.https{"开启"}else{"关闭"}));
if config.https {
info!("证书目录KEY: {}",format!("{:?}", config.tls.key));
info!("证书目录PEM: {}",format!("{:?}", config.tls.certs));
}
let addrs = [
SocketAddr::from((IpAddr::V4(config.host.parse().unwrap()), config.port))
];
let listener = TcpListener::bind(&addrs[..])?;
info!("==================== 网页服务 启动成功 ====================");
let acceptor = if config.https {
let mut acceptor = SslAcceptor::mozilla_intermediate(SslMethod::tls())?;
if !config.tls.key.is_file() {
return Err(Error::new(ErrorKind::Other, format!("private.key 不存在: {:?}", config.tls.key).as_str()));
}
if !config.tls.certs.is_file() {
return Err(Error::new(ErrorKind::Other, format!("certificate.pem 不存在: {:?}", config.tls.certs).as_str()));
}
acceptor.set_private_key_file(config.tls.key.clone(), SslFiletype::PEM)?;
acceptor.set_certificate_file(config.tls.certs.clone(), SslFiletype::PEM)?;
Arc::new(acceptor.build())
} else {
Arc::new(SslAcceptor::mozilla_intermediate(SslMethod::tls())?.build())
};
for stream in listener.incoming() {
match stream {
Ok(stream) => {
let config_new = config.clone();
let acceptor = acceptor.clone();
thread::spawn(move || {
if config_new.write_timeout > 0 {
stream.set_write_timeout(Some(Duration::from_secs(config_new.write_timeout))).unwrap_or_default();
}
if config_new.read_timeout > 0 {
stream.set_read_timeout(Some(Duration::from_secs(config_new.read_timeout))).unwrap_or_default();
}
let client_ip = stream.peer_addr().unwrap().to_string();
let server_ip = stream.local_addr().unwrap().to_string();
let scheme = match config_new.https {
true => {
match acceptor.accept(stream.try_clone().unwrap()) {
Ok(e) => Scheme::Https(e),
Err(_) => return
}
}
false => Scheme::Http(stream.try_clone().unwrap())
};
let mut client = Client {
config: config_new.clone(),
request: Request::default(),
response: Response::new(config_new),
handle_time: Instant::now(),
factory,
};
match client.handle_webpage(scheme, server_ip.as_str(), client_ip.as_str()) {
Ok(_) => {}
Err(e) => error!("{}",e)
};
});
}
Err(e) => return Err(e)
}
}
Ok(())
}
}
pub trait Handler {
#[cfg(any(feature = "web", feature = "http"))]
fn on_request(&mut self, request: Request, response: Response) -> Response;
#[cfg(any(feature = "web", feature = "http"))]
fn on_options(&mut self, _request: Request, mut response: Response) -> Response {
response.header("Access-Control-Allow-Origin", "*");
response.header("Access-Control-Allow-Methods", "*");
response.header("Access-Control-Allow-Headers", "*");
response.header("Access-Control-Allow-Credentials", "true");
response.header("Access-Control-Expose-Headers", "content-disposition");
response.header("Access-Control-Max-Age", "0");
response
}
#[cfg(any(feature = "web", feature = "http"))]
fn on_response(&mut self, request: Request, mut response: Response) -> Response {
if !response.config.origin.is_empty() {
let origin = request.header.get("origin").unwrap_or(&"".into()).clone();
if !origin.is_empty() && response.config.origin.contains(&origin.to_string().clone()) {
response.header("Access-Control-Allow-Origin", origin.as_str().unwrap_or(""));
}
} else {
response.header("Access-Control-Allow-Origin", "*");
}
response
}
#[cfg(feature = "ws")]
fn on_open(&mut self, _websocket: Websocket) -> io::Result<()> { Ok(()) }
#[cfg(feature = "ws")]
fn on_message(&mut self, _msg: Message) -> io::Result<()> { Ok(()) }
#[cfg(feature = "ws")]
fn on_close(&mut self, _code: CloseCode, _reason: &str) {}
#[cfg(feature = "ws")]
fn on_error(&mut self, _err: ErrorCode) {}
#[cfg(feature = "ws")]
fn on_shutdown(&mut self) {}
#[cfg(feature = "ws")]
fn on_ping(&mut self, _msg: Message) {}
#[cfg(feature = "ws")]
fn on_pong(&mut self, _msg: Message) {}
}