[code][fix] improvements for LAN 202503
- 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)
This commit is contained in:
@@ -3,12 +3,7 @@ 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::{ReceiveStream, SendStream},
|
||||
};
|
||||
use tokio::io::AsyncWriteExt as _;
|
||||
use s2n_quic::{Connection, Server, provider::limits::Limits, stream::BidirectionalStream};
|
||||
|
||||
use crate::req::{RequestHandler, send_game_file_data};
|
||||
|
||||
@@ -21,92 +16,65 @@ struct ServerCtx {
|
||||
games_folder: PathBuf,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
struct ConnectionCtx {
|
||||
server_ctx: Arc<ServerCtx>,
|
||||
}
|
||||
async fn handle_bidi_stream(stream: BidirectionalStream, ctx: Arc<ServerCtx>) -> eyre::Result<()> {
|
||||
let (mut rx, mut tx) = stream.split();
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
struct StreamCtx {
|
||||
conn_ctx: Arc<ConnectionCtx>,
|
||||
}
|
||||
|
||||
async fn handle_bidi_stream(
|
||||
mut rx: ReceiveStream,
|
||||
mut tx: SendStream,
|
||||
ctx: Arc<StreamCtx>,
|
||||
) -> eyre::Result<()> {
|
||||
let remote_addr = maybe_addr!(rx.connection().remote_addr());
|
||||
tracing::trace!("{remote_addr} stream opened");
|
||||
|
||||
// handle streams
|
||||
while let Ok(Some(data)) = rx.receive().await {
|
||||
tracing::trace!(
|
||||
"{remote_addr} msg: (raw): {}",
|
||||
String::from_utf8_lossy(&data)
|
||||
);
|
||||
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:?}");
|
||||
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.conn_ctx.server_ctx.games_folder,
|
||||
)
|
||||
.await;
|
||||
continue;
|
||||
}
|
||||
// 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;
|
||||
}
|
||||
|
||||
let response = ctx
|
||||
.conn_ctx
|
||||
.server_ctx
|
||||
.handler
|
||||
.handle_request(request, &ctx.conn_ctx.server_ctx.games_folder)
|
||||
.await;
|
||||
|
||||
tracing::trace!("{remote_addr} server response: {response:?}");
|
||||
let raw_response = response.encode();
|
||||
tracing::trace!(
|
||||
"{remote_addr} server response (raw): {}",
|
||||
String::from_utf8_lossy(&raw_response)
|
||||
);
|
||||
|
||||
// write response back to client
|
||||
if let Err(e) = tx.write_all(&raw_response).await {
|
||||
tracing::error!(?e);
|
||||
}
|
||||
|
||||
// close the stream
|
||||
if let Err(e) = tx.close().await {
|
||||
tracing::error!(?e);
|
||||
// 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<ConnectionCtx>,
|
||||
) -> eyre::Result<()> {
|
||||
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();
|
||||
let (rx, tx) = stream.split();
|
||||
|
||||
let ctx = Arc::new(StreamCtx {
|
||||
conn_ctx: ctx.clone(),
|
||||
});
|
||||
|
||||
// spawn a new task for the stream
|
||||
tokio::spawn(async move {
|
||||
if let Err(e) = handle_bidi_stream(rx, tx, ctx).await {
|
||||
if let Err(e) = handle_bidi_stream(stream, ctx).await {
|
||||
tracing::error!("{remote_addr} stream error: {e}");
|
||||
}
|
||||
});
|
||||
@@ -121,8 +89,8 @@ pub(crate) async fn run_server(
|
||||
games_folder: PathBuf,
|
||||
) -> eyre::Result<()> {
|
||||
let limits = Limits::default()
|
||||
.with_max_idle_timeout(Duration::ZERO)?
|
||||
.with_max_handshake_duration(Duration::from_secs(3))?;
|
||||
.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))?
|
||||
@@ -130,23 +98,22 @@ pub(crate) async fn run_server(
|
||||
.with_limits(limits)?
|
||||
.start()?;
|
||||
|
||||
let server_ctx = Arc::new(ServerCtx {
|
||||
let ctx = Arc::new(ServerCtx {
|
||||
handler: RequestHandler::new(db),
|
||||
games_folder,
|
||||
});
|
||||
|
||||
while let Some(connection) = server.accept().await {
|
||||
let conn_ctx = Arc::new(ConnectionCtx {
|
||||
server_ctx: server_ctx.clone(),
|
||||
});
|
||||
|
||||
let ctx = ctx.clone();
|
||||
// spawn a new task for the connection
|
||||
tokio::spawn(async move {
|
||||
if let Err(e) = handle_connection(connection, conn_ctx).await {
|
||||
if let Err(e) = handle_connection(connection, ctx).await {
|
||||
tracing::error!("Connection error: {}", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
tracing::info!("Server shutting down");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user