156 lines
4.5 KiB
Rust
156 lines
4.5 KiB
Rust
use std::net::SocketAddr;
|
|
|
|
use bus::Bus;
|
|
|
|
mod util;
|
|
mod app;
|
|
mod system;
|
|
mod protocol;
|
|
mod manager;
|
|
|
|
use app::App;
|
|
use hyper::body::Bytes;
|
|
use hyper_util::rt::TokioIo;
|
|
use system::{cache::WebCache, net::Stream};
|
|
|
|
#[derive(Clone)]
|
|
struct HttpServiceArgs {
|
|
bus:Bus<protocol::QRPacket>,
|
|
cache:WebCache,
|
|
}
|
|
|
|
async fn service_http(mut request:hyper::Request<hyper::body::Incoming>, args:HttpServiceArgs) -> Result<hyper::Response<http_body_util::Full<Bytes>>, std::convert::Infallible>
|
|
// Serve cached files and upgrade websocket connections.
|
|
//
|
|
{
|
|
use hyper::{Response, body::Bytes, header::{CONTENT_TYPE, CACHE_CONTROL}};
|
|
use http_body_util::Full;
|
|
|
|
println!("Serving: {}", request.uri().path());
|
|
|
|
match request.uri().path() {
|
|
"/.css" => Ok(Response::builder()
|
|
.header(CONTENT_TYPE, "text/css")
|
|
.header(CACHE_CONTROL, "no-cache")
|
|
.body(Full::new(Bytes::from(args.cache.css()))).unwrap()),
|
|
|
|
"/.js" => Ok(Response::builder()
|
|
.header(CONTENT_TYPE, "text/javascript")
|
|
.header(CACHE_CONTROL, "no-cache")
|
|
.body(Full::new(Bytes::from(args.cache.js()))).unwrap()),
|
|
|
|
"/favicon.png" => Ok(Response::builder()
|
|
.header(CONTENT_TYPE, "image/png")
|
|
.body(Full::new(Bytes::from(args.cache.favicon()))).unwrap()),
|
|
|
|
_ => {
|
|
if hyper_tungstenite::is_upgrade_request(&request) {
|
|
if let Ok((response, websocket)) = hyper_tungstenite::upgrade(&mut request, None) {
|
|
tokio::task::spawn(async move {
|
|
match websocket.await {
|
|
Ok(websocket) => manager::handle_ws(websocket, args).await,
|
|
Err(_) => Err(()),
|
|
}.ok()
|
|
});
|
|
|
|
Ok(response)
|
|
} else {
|
|
Ok(Response::builder()
|
|
.status(401)
|
|
.body(Full::new(Bytes::new()))
|
|
.unwrap())
|
|
}
|
|
} else {
|
|
Ok(Response::builder()
|
|
.header(CONTENT_TYPE, "text/html")
|
|
.header(CACHE_CONTROL, "no-cache")
|
|
.body(Full::new(Bytes::from(args.cache.html()))).unwrap())
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
async fn handle_http(stream:system::net::tls::TlsStream, addr:SocketAddr, args:HttpServiceArgs) -> Result<(),()>
|
|
// Hand off socket connection to Hyper server.
|
|
//
|
|
{
|
|
use hyper::server::conn::http1;
|
|
use hyper::service::service_fn;
|
|
|
|
println!("Connection from {}", addr.to_string());
|
|
|
|
let io = TokioIo::new(stream.to_stream());
|
|
|
|
let conn = http1::Builder::new()
|
|
.serve_connection(io, service_fn(move |req| {
|
|
service_http(req, args.clone())
|
|
}));
|
|
|
|
conn.with_upgrades().await.ok();
|
|
Ok(())
|
|
}
|
|
|
|
|
|
#[tokio::main]
|
|
async fn main()
|
|
{
|
|
use system::net::{
|
|
Server,
|
|
tls::*,
|
|
};
|
|
|
|
// Initialize application data.
|
|
let mut app = App::new();
|
|
if app.init().is_err() {
|
|
println!("fatal: failed to initialize server.");
|
|
return;
|
|
}
|
|
|
|
|
|
// Initialize central bus and data serivce.
|
|
let b_main :Bus<protocol::QRPacket> = Bus::new_as(bus::Mode::Transmitter);
|
|
match b_main.connect() {
|
|
Ok(bus) => {
|
|
tokio::spawn(async move {
|
|
manager::thread_system(app, bus).await;
|
|
});
|
|
}
|
|
Err(_) => {
|
|
println!("fatal: failed to initialize bus.");
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
// Initialize HTTPS service.
|
|
match b_main.connect() {
|
|
Ok(bus) => {
|
|
let cache = WebCache::init();
|
|
|
|
let mut server = TlsServer::new();
|
|
if server.add_cert("omen.kirisame.com", "cert/fullchain.pem", "cert/privkey.pem").await.is_ok() {
|
|
println!("Loaded cert file.");
|
|
}
|
|
match server.bind("0.0.0.0:38612").await {
|
|
Ok(_) => {
|
|
println!("Listener bind successful.");
|
|
tokio::spawn(async move {
|
|
while server.accept(handle_http, HttpServiceArgs {
|
|
bus:bus.connect().unwrap(),
|
|
cache:cache.clone(),
|
|
}).await.is_ok() { }
|
|
});
|
|
}
|
|
Err(_) => {
|
|
println!("error: failed to bind port 38612.");
|
|
}
|
|
}
|
|
}
|
|
Err(_) => {
|
|
println!("error: failed to initialize HTTPS service.");
|
|
}
|
|
}
|
|
|
|
std::thread::park();
|
|
}
|