765447e6d1
- more robust client <-> server connection - new client event: DownloadGameFilesFailed - 3 seconds to reconnect - retry forever if server is gone and never lose a UI request - code cleanup here and there (mostly server)
120 lines
3.7 KiB
Rust
120 lines
3.7 KiB
Rust
use std::{net::SocketAddr, path::PathBuf, sync::Arc, time::Duration};
|
|
|
|
use lanspread_db::db::GameDB;
|
|
use lanspread_proto::{Message as _, Request};
|
|
use lanspread_utils::maybe_addr;
|
|
use s2n_quic::{Connection, Server, provider::limits::Limits, stream::BidirectionalStream};
|
|
|
|
use crate::req::{RequestHandler, send_game_file_data};
|
|
|
|
static KEY_PEM: &str = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/../../key.pem"));
|
|
static CERT_PEM: &str = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/../../cert.pem"));
|
|
|
|
#[derive(Clone, Debug)]
|
|
struct ServerCtx {
|
|
handler: RequestHandler,
|
|
games_folder: PathBuf,
|
|
}
|
|
|
|
async fn handle_bidi_stream(stream: BidirectionalStream, ctx: Arc<ServerCtx>) -> eyre::Result<()> {
|
|
let (mut rx, mut tx) = stream.split();
|
|
|
|
let remote_addr = maybe_addr!(rx.connection().remote_addr());
|
|
tracing::trace!("{remote_addr} stream opened");
|
|
|
|
// handle streams
|
|
loop {
|
|
match rx.receive().await {
|
|
Ok(Some(data)) => {
|
|
tracing::trace!(
|
|
"{remote_addr} msg: (raw): {}",
|
|
String::from_utf8_lossy(&data)
|
|
);
|
|
|
|
let request = Request::decode(data);
|
|
tracing::debug!("{remote_addr} msg: {request:?}");
|
|
|
|
// special case for now (send game file data to client)
|
|
if let Request::GetGameFileData(game_file_desc) = &request {
|
|
send_game_file_data(game_file_desc, &mut tx, &ctx.games_folder).await;
|
|
continue;
|
|
}
|
|
|
|
// normal case (handle request)
|
|
if let Err(e) = ctx
|
|
.handler
|
|
.handle_request(request, &ctx.games_folder, &mut tx)
|
|
.await
|
|
{
|
|
tracing::error!(?e, "{remote_addr} error handling request");
|
|
}
|
|
}
|
|
Ok(None) => {
|
|
tracing::trace!("{remote_addr} stream closed");
|
|
break;
|
|
}
|
|
Err(e) => {
|
|
tracing::error!("{remote_addr} stream error: {e}");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
async fn handle_connection(mut connection: Connection, ctx: Arc<ServerCtx>) -> eyre::Result<()> {
|
|
let remote_addr = maybe_addr!(connection.remote_addr());
|
|
tracing::info!("{remote_addr} connected");
|
|
|
|
// handle streams
|
|
while let Ok(Some(stream)) = connection.accept_bidirectional_stream().await {
|
|
let ctx = ctx.clone();
|
|
let remote_addr = remote_addr.clone();
|
|
|
|
// spawn a new task for the stream
|
|
tokio::spawn(async move {
|
|
if let Err(e) = handle_bidi_stream(stream, ctx).await {
|
|
tracing::error!("{remote_addr} stream error: {e}");
|
|
}
|
|
});
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
pub(crate) async fn run_server(
|
|
addr: SocketAddr,
|
|
db: GameDB,
|
|
games_folder: PathBuf,
|
|
) -> eyre::Result<()> {
|
|
let limits = Limits::default()
|
|
.with_max_handshake_duration(Duration::from_secs(3))?
|
|
.with_max_idle_timeout(Duration::from_secs(3))?;
|
|
|
|
let mut server = Server::builder()
|
|
.with_tls((CERT_PEM, KEY_PEM))?
|
|
.with_io(addr)?
|
|
.with_limits(limits)?
|
|
.start()?;
|
|
|
|
let ctx = Arc::new(ServerCtx {
|
|
handler: RequestHandler::new(db),
|
|
games_folder,
|
|
});
|
|
|
|
while let Some(connection) = server.accept().await {
|
|
let ctx = ctx.clone();
|
|
// spawn a new task for the connection
|
|
tokio::spawn(async move {
|
|
if let Err(e) = handle_connection(connection, ctx).await {
|
|
tracing::error!("Connection error: {}", e);
|
|
}
|
|
});
|
|
}
|
|
|
|
tracing::info!("Server shutting down");
|
|
|
|
Ok(())
|
|
}
|