refactor: prune unconsumed peer lifecycle events
An emit-vs-listen audit of the event surface showed the GUI is state-as-source-of-truth: useGames renders the complete `games-list` snapshot (full library + active_operations) and reconstructs status from it, not from a stream of granular events. Several PeerEvents were emitted but had no consumer at all -- no frontend `listen()` and no peer-cli scenario assertion -- so they were pure dead weight that made the backend look event-driven when it no longer is. This prunes that dead surface in two parts. 1. Remove three PeerEvent variants with no consumer: InstallGameBegin, UninstallGameBegin, and RemoveDownloadedGameBegin. The operation-start transition is still observable via ActiveOperationsChanged (the snapshot already carries the Installing/Updating/Uninstalling/ RemovingDownload kind), so nothing is lost. This drops their emit sites in handlers.rs, the begin-event assertions in the peer's lifecycle unit tests (the asserted sequence is now ActiveOperationsChanged(kind) -> LocalLibraryChanged -> ActiveOperationsChanged([]) -> *Finished), the peer-cli JSONL mappings (install-begin/uninstall-begin/remove-download-begin) plus the now-orphaned install_operation_name helper and InstallOperation import, and the matching Tauri handler arms. 2. Drop Tauri webview emits that no frontend listener consumed: peer-local-ready, game-download-begin, game-download-pre, game-download-finished, game-uninstall-finished, and peer-connected/-disconnected/-discovered/-lost. The log lines and all real side effects are kept (handle_got_game_files still forwards PeerCommand::DownloadGameFiles). The orphaned emit_peer_addr_event and handle_download_finished helpers and the now-unused SocketAddr import are removed. peer-runtime-failed is kept pending a decision on surfacing runtime failures in the GUI. Why not re-wire instead: under state-as-source-of-truth, per-event UI state is exactly the pattern this project abandoned. Live progress already flows via game-download-progress, and the peer-cli's chunk, timing-trigger, and transition assertions read events that are retained (download-begin, download-chunk-finished, the *-finished/*-failed terminals), so test coverage is unchanged. Behavior change: none functional. The Tauri backend no longer emits events nothing listened to; the GUI is unchanged. The peer-cli no longer emits the three *-begin JSONL events. PeerEvent is a workspace-internal UI-reporting type, not a wire-protocol type, so there is no protocol or version impact and all consumers are updated in this commit. Docs: PEER_CLI_SCENARIOS.md S39 no longer lists install-begin (with a note that the start transition is visible via active-operations-changed), and a dated Run Log entry records the removal. The historical 2026-05-18 run-log note is left intact as a dated observation. Test Plan: - just test: pass (incl. peer lifecycle event-sequence tests). - just clippy: pass (-D warnings, all targets). - just frontend-test: pass (11/11, incl. streamed-install gating/labels). - just build: pass (release, no bundle). - Not run: the Docker S39-S47 matrix (run_extended_scenarios.py); those scenarios never asserted the removed *-begin events, so coverage is unaffected. just fmt's tombi step needs network and was skipped; no TOML changed. Refs: peer event-surface emit-vs-listen audit; no external consumers of the removed events.
This commit was merged in pull request #28.
This commit is contained in:
@@ -17,7 +17,6 @@ use lanspread_peer::{
|
||||
ActiveOperation,
|
||||
ActiveOperationKind,
|
||||
ExternalUnrarStreamProvider,
|
||||
InstallOperation,
|
||||
NoopStreamInstallProvider,
|
||||
OutboundTransfers,
|
||||
PeerCommand,
|
||||
@@ -541,16 +540,10 @@ async fn update_state_from_event(shared: &SharedState, event: PeerEvent) -> (&'s
|
||||
download_terminal_event(shared, "download-failed", id).await
|
||||
}
|
||||
PeerEvent::DownloadGameFilesAllPeersGone { id } => game_id_event("download-peers-gone", id),
|
||||
PeerEvent::InstallGameBegin { id, operation } => (
|
||||
"install-begin",
|
||||
json!({"game_id": id, "operation": install_operation_name(operation)}),
|
||||
),
|
||||
PeerEvent::InstallGameFinished { id } => game_id_event("install-finished", id),
|
||||
PeerEvent::InstallGameFailed { id } => game_id_event("install-failed", id),
|
||||
PeerEvent::UninstallGameBegin { id } => game_id_event("uninstall-begin", id),
|
||||
PeerEvent::UninstallGameFinished { id } => game_id_event("uninstall-finished", id),
|
||||
PeerEvent::UninstallGameFailed { id } => game_id_event("uninstall-failed", id),
|
||||
PeerEvent::RemoveDownloadedGameBegin { id } => game_id_event("remove-download-begin", id),
|
||||
PeerEvent::RemoveDownloadedGameFinished { id } => {
|
||||
game_id_event("remove-download-finished", id)
|
||||
}
|
||||
@@ -686,10 +679,6 @@ fn active_operation_name(operation: ActiveOperationKind) -> &'static str {
|
||||
(&operation).into()
|
||||
}
|
||||
|
||||
fn install_operation_name(operation: InstallOperation) -> &'static str {
|
||||
(&operation).into()
|
||||
}
|
||||
|
||||
fn runtime_component_name(component: PeerRuntimeComponent) -> &'static str {
|
||||
(&component).into()
|
||||
}
|
||||
|
||||
@@ -784,13 +784,6 @@ async fn commit_streamed_install(
|
||||
ctx.active_operations.clone(),
|
||||
tx_notify_ui.clone(),
|
||||
);
|
||||
events::send(
|
||||
tx_notify_ui,
|
||||
PeerEvent::InstallGameBegin {
|
||||
id: id.clone(),
|
||||
operation: InstallOperation::Installing,
|
||||
},
|
||||
);
|
||||
|
||||
match transaction.commit().await {
|
||||
Ok(()) => {
|
||||
@@ -918,14 +911,6 @@ async fn run_started_install_operation(
|
||||
tx_notify_ui.clone(),
|
||||
);
|
||||
let result = {
|
||||
events::send(
|
||||
tx_notify_ui,
|
||||
PeerEvent::InstallGameBegin {
|
||||
id: id.clone(),
|
||||
operation,
|
||||
},
|
||||
);
|
||||
|
||||
let state_dir = ctx.state_dir.as_ref();
|
||||
match operation {
|
||||
InstallOperation::Installing => {
|
||||
@@ -995,14 +980,7 @@ async fn run_uninstall_operation(ctx: &Ctx, tx_notify_ui: &UnboundedSender<PeerE
|
||||
ctx.active_operations.clone(),
|
||||
tx_notify_ui.clone(),
|
||||
);
|
||||
let result = {
|
||||
events::send(
|
||||
tx_notify_ui,
|
||||
PeerEvent::UninstallGameBegin { id: id.clone() },
|
||||
);
|
||||
|
||||
install::uninstall(&game_root, ctx.state_dir.as_ref(), &id).await
|
||||
};
|
||||
let result = install::uninstall(&game_root, ctx.state_dir.as_ref(), &id).await;
|
||||
|
||||
match result {
|
||||
Ok(()) => {
|
||||
@@ -1068,14 +1046,7 @@ async fn run_remove_downloaded_operation(
|
||||
ctx.active_operations.clone(),
|
||||
tx_notify_ui.clone(),
|
||||
);
|
||||
let result = {
|
||||
events::send(
|
||||
tx_notify_ui,
|
||||
PeerEvent::RemoveDownloadedGameBegin { id: id.clone() },
|
||||
);
|
||||
|
||||
install::remove_downloaded(&game_dir, &id).await
|
||||
};
|
||||
let result = install::remove_downloaded(&game_dir, &id).await;
|
||||
|
||||
match result {
|
||||
Ok(()) => {
|
||||
@@ -2032,13 +2003,6 @@ mod tests {
|
||||
recv_event(&mut rx).await,
|
||||
&active_update("game", ActiveOperationKind::Updating),
|
||||
);
|
||||
assert!(matches!(
|
||||
recv_event(&mut rx).await,
|
||||
PeerEvent::InstallGameBegin {
|
||||
id,
|
||||
operation: InstallOperation::Updating
|
||||
} if id == "game"
|
||||
));
|
||||
assert_active_update(recv_event(&mut rx).await, &[]);
|
||||
assert!(matches!(
|
||||
recv_event(&mut rx).await,
|
||||
@@ -2063,13 +2027,6 @@ mod tests {
|
||||
recv_event(&mut rx).await,
|
||||
&active_update("game", ActiveOperationKind::Installing),
|
||||
);
|
||||
match recv_event(&mut rx).await {
|
||||
PeerEvent::InstallGameBegin { id, operation } => {
|
||||
assert_eq!(id, "game");
|
||||
assert_eq!(operation, InstallOperation::Installing);
|
||||
}
|
||||
_ => panic!("expected InstallGameBegin"),
|
||||
}
|
||||
assert_local_update(recv_event(&mut rx).await, true, true);
|
||||
assert_active_update(recv_event(&mut rx).await, &[]);
|
||||
assert!(matches!(
|
||||
@@ -2124,13 +2081,6 @@ mod tests {
|
||||
recv_event(&mut rx).await,
|
||||
&active_update("game", ActiveOperationKind::Installing),
|
||||
);
|
||||
match recv_event(&mut rx).await {
|
||||
PeerEvent::InstallGameBegin { id, operation } => {
|
||||
assert_eq!(id, "game");
|
||||
assert_eq!(operation, InstallOperation::Installing);
|
||||
}
|
||||
_ => panic!("expected InstallGameBegin"),
|
||||
}
|
||||
assert_local_update(recv_event(&mut rx).await, true, true);
|
||||
assert_active_update(recv_event(&mut rx).await, &[]);
|
||||
assert!(matches!(
|
||||
@@ -2184,13 +2134,6 @@ mod tests {
|
||||
recv_event(&mut rx).await,
|
||||
&active_update("game", ActiveOperationKind::Updating),
|
||||
);
|
||||
match recv_event(&mut rx).await {
|
||||
PeerEvent::InstallGameBegin { id, operation } => {
|
||||
assert_eq!(id, "game");
|
||||
assert_eq!(operation, InstallOperation::Updating);
|
||||
}
|
||||
_ => panic!("expected InstallGameBegin"),
|
||||
}
|
||||
assert_local_update(recv_event(&mut rx).await, true, true);
|
||||
assert_active_update(recv_event(&mut rx).await, &[]);
|
||||
assert!(matches!(
|
||||
@@ -2215,13 +2158,6 @@ mod tests {
|
||||
recv_event(&mut rx).await,
|
||||
&active_update("game", ActiveOperationKind::Installing),
|
||||
);
|
||||
assert!(matches!(
|
||||
recv_event(&mut rx).await,
|
||||
PeerEvent::InstallGameBegin {
|
||||
id,
|
||||
operation: InstallOperation::Installing
|
||||
} if id == "game"
|
||||
));
|
||||
let game = local_update_game(recv_event(&mut rx).await, true, true);
|
||||
assert_eq!(game.local_version.as_deref(), Some("20240101"));
|
||||
assert_active_update(recv_event(&mut rx).await, &[]);
|
||||
@@ -2238,13 +2174,6 @@ mod tests {
|
||||
recv_event(&mut rx).await,
|
||||
&active_update("game", ActiveOperationKind::Updating),
|
||||
);
|
||||
assert!(matches!(
|
||||
recv_event(&mut rx).await,
|
||||
PeerEvent::InstallGameBegin {
|
||||
id,
|
||||
operation: InstallOperation::Updating
|
||||
} if id == "game"
|
||||
));
|
||||
let game = local_update_game(recv_event(&mut rx).await, true, true);
|
||||
assert_eq!(game.local_version.as_deref(), Some("20250101"));
|
||||
assert_active_update(recv_event(&mut rx).await, &[]);
|
||||
@@ -2258,10 +2187,6 @@ mod tests {
|
||||
recv_event(&mut rx).await,
|
||||
&active_update("game", ActiveOperationKind::Uninstalling),
|
||||
);
|
||||
assert!(matches!(
|
||||
recv_event(&mut rx).await,
|
||||
PeerEvent::UninstallGameBegin { id } if id == "game"
|
||||
));
|
||||
let game = local_update_game(recv_event(&mut rx).await, false, true);
|
||||
assert_eq!(game.local_version.as_deref(), Some("20250101"));
|
||||
assert_active_update(recv_event(&mut rx).await, &[]);
|
||||
@@ -2289,10 +2214,6 @@ mod tests {
|
||||
recv_event(&mut rx).await,
|
||||
&active_update("game", ActiveOperationKind::Uninstalling),
|
||||
);
|
||||
assert!(matches!(
|
||||
recv_event(&mut rx).await,
|
||||
PeerEvent::UninstallGameBegin { id } if id == "game"
|
||||
));
|
||||
assert_local_update(recv_event(&mut rx).await, false, true);
|
||||
assert_active_update(recv_event(&mut rx).await, &[]);
|
||||
assert!(matches!(
|
||||
@@ -2324,10 +2245,6 @@ mod tests {
|
||||
recv_event(&mut rx).await,
|
||||
&active_update("game", ActiveOperationKind::RemovingDownload),
|
||||
);
|
||||
assert!(matches!(
|
||||
recv_event(&mut rx).await,
|
||||
PeerEvent::RemoveDownloadedGameBegin { id } if id == "game"
|
||||
));
|
||||
let PeerEvent::LocalLibraryChanged { games } = recv_event(&mut rx).await else {
|
||||
panic!("expected LocalLibraryChanged");
|
||||
};
|
||||
|
||||
@@ -127,23 +127,14 @@ pub enum PeerEvent {
|
||||
DownloadGameFilesFailed { id: String },
|
||||
/// All peers with the game have disconnected during download.
|
||||
DownloadGameFilesAllPeersGone { id: String },
|
||||
/// Install or update transaction has started for a game.
|
||||
InstallGameBegin {
|
||||
id: String,
|
||||
operation: InstallOperation,
|
||||
},
|
||||
/// Install or update transaction has completed successfully.
|
||||
InstallGameFinished { id: String },
|
||||
/// Install or update transaction has failed after rollback.
|
||||
InstallGameFailed { id: String },
|
||||
/// Uninstall transaction has started for a game.
|
||||
UninstallGameBegin { id: String },
|
||||
/// Uninstall transaction has completed successfully.
|
||||
UninstallGameFinished { id: String },
|
||||
/// Uninstall transaction has failed after rollback.
|
||||
UninstallGameFailed { id: String },
|
||||
/// Downloaded archive removal has started for an uninstalled game.
|
||||
RemoveDownloadedGameBegin { id: String },
|
||||
/// Downloaded archive removal has completed successfully.
|
||||
RemoveDownloadedGameFinished { id: String },
|
||||
/// Downloaded archive removal has failed before deleting the game root.
|
||||
|
||||
@@ -2,7 +2,6 @@ use std::{
|
||||
collections::{HashMap, HashSet},
|
||||
fs::{self, OpenOptions},
|
||||
io::{self, Read as _, Seek as _, SeekFrom, Write as _},
|
||||
net::SocketAddr,
|
||||
path::{Component, Path, PathBuf},
|
||||
sync::{Arc, Mutex, OnceLock},
|
||||
time::{Duration, SystemTime, UNIX_EPOCH},
|
||||
@@ -1970,12 +1969,6 @@ fn emit_game_id_event(app_handle: &AppHandle, event: &str, id: &str, label: &str
|
||||
}
|
||||
}
|
||||
|
||||
fn emit_peer_addr_event(app_handle: &AppHandle, event: &str, addr: SocketAddr) {
|
||||
if let Err(e) = app_handle.emit(event, Some(addr.to_string())) {
|
||||
log::error!("Failed to emit {event} event: {e}");
|
||||
}
|
||||
}
|
||||
|
||||
fn spawn_peer_event_loop(app_handle: AppHandle, mut rx_peer_event: UnboundedReceiver<PeerEvent>) {
|
||||
tauri::async_runtime::spawn(async move {
|
||||
while let Some(event) = rx_peer_event.recv().await {
|
||||
@@ -2027,9 +2020,6 @@ async fn handle_peer_event(app_handle: &AppHandle, event: PeerEvent) {
|
||||
match event {
|
||||
PeerEvent::LocalPeerReady { peer_id, addr } => {
|
||||
log::info!("Local peer ready: {peer_id} at {addr}");
|
||||
if let Err(e) = app_handle.emit("peer-local-ready", Some((peer_id, addr.to_string()))) {
|
||||
log::error!("Failed to emit peer-local-ready event: {e}");
|
||||
}
|
||||
}
|
||||
PeerEvent::ListGames(games) => {
|
||||
log::info!("PeerEvent::ListGames received");
|
||||
@@ -2068,13 +2058,7 @@ async fn handle_peer_event(app_handle: &AppHandle, event: PeerEvent) {
|
||||
);
|
||||
}
|
||||
PeerEvent::DownloadGameFilesBegin { id } => {
|
||||
log::info!("PeerEvent::DownloadGameFilesBegin received");
|
||||
emit_game_id_event(
|
||||
app_handle,
|
||||
"game-download-begin",
|
||||
&id,
|
||||
"PeerEvent::DownloadGameFilesBegin",
|
||||
);
|
||||
log::info!("PeerEvent::DownloadGameFilesBegin received for {id}");
|
||||
}
|
||||
PeerEvent::DownloadGameFileChunkFinished {
|
||||
id,
|
||||
@@ -2094,7 +2078,7 @@ async fn handle_peer_event(app_handle: &AppHandle, event: PeerEvent) {
|
||||
}
|
||||
}
|
||||
PeerEvent::DownloadGameFilesFinished { id } => {
|
||||
handle_download_finished(app_handle, id);
|
||||
log::info!("PeerEvent::DownloadGameFilesFinished received for {id}");
|
||||
}
|
||||
PeerEvent::DownloadGameFilesFailed { id } => {
|
||||
log::warn!("PeerEvent::DownloadGameFilesFailed received");
|
||||
@@ -2114,16 +2098,6 @@ async fn handle_peer_event(app_handle: &AppHandle, event: PeerEvent) {
|
||||
"PeerEvent::DownloadGameFilesAllPeersGone",
|
||||
);
|
||||
}
|
||||
PeerEvent::InstallGameBegin { id, operation } => {
|
||||
let operation_name: &'static str = (&operation).into();
|
||||
log::info!("PeerEvent::InstallGameBegin received for {id}: {operation_name}");
|
||||
emit_game_id_event(
|
||||
app_handle,
|
||||
"game-install-begin",
|
||||
&id,
|
||||
"PeerEvent::InstallGameBegin",
|
||||
);
|
||||
}
|
||||
PeerEvent::InstallGameFinished { id } => {
|
||||
log::info!("PeerEvent::InstallGameFinished received for {id}");
|
||||
emit_game_id_event(
|
||||
@@ -2142,23 +2116,8 @@ async fn handle_peer_event(app_handle: &AppHandle, event: PeerEvent) {
|
||||
"PeerEvent::InstallGameFailed",
|
||||
);
|
||||
}
|
||||
PeerEvent::UninstallGameBegin { id } => {
|
||||
log::info!("PeerEvent::UninstallGameBegin received for {id}");
|
||||
emit_game_id_event(
|
||||
app_handle,
|
||||
"game-uninstall-begin",
|
||||
&id,
|
||||
"PeerEvent::UninstallGameBegin",
|
||||
);
|
||||
}
|
||||
PeerEvent::UninstallGameFinished { id } => {
|
||||
log::info!("PeerEvent::UninstallGameFinished received for {id}");
|
||||
emit_game_id_event(
|
||||
app_handle,
|
||||
"game-uninstall-finished",
|
||||
&id,
|
||||
"PeerEvent::UninstallGameFinished",
|
||||
);
|
||||
}
|
||||
PeerEvent::UninstallGameFailed { id } => {
|
||||
log::warn!("PeerEvent::UninstallGameFailed received for {id}");
|
||||
@@ -2169,15 +2128,6 @@ async fn handle_peer_event(app_handle: &AppHandle, event: PeerEvent) {
|
||||
"PeerEvent::UninstallGameFailed",
|
||||
);
|
||||
}
|
||||
PeerEvent::RemoveDownloadedGameBegin { id } => {
|
||||
log::info!("PeerEvent::RemoveDownloadedGameBegin received for {id}");
|
||||
emit_game_id_event(
|
||||
app_handle,
|
||||
"game-remove-download-begin",
|
||||
&id,
|
||||
"PeerEvent::RemoveDownloadedGameBegin",
|
||||
);
|
||||
}
|
||||
PeerEvent::RemoveDownloadedGameFinished { id } => {
|
||||
log::info!("PeerEvent::RemoveDownloadedGameFinished received for {id}");
|
||||
emit_game_id_event(
|
||||
@@ -2198,19 +2148,15 @@ async fn handle_peer_event(app_handle: &AppHandle, event: PeerEvent) {
|
||||
}
|
||||
PeerEvent::PeerConnected(addr) => {
|
||||
log::info!("Peer connected: {addr}");
|
||||
emit_peer_addr_event(app_handle, "peer-connected", addr);
|
||||
}
|
||||
PeerEvent::PeerDisconnected(addr) => {
|
||||
log::info!("Peer disconnected: {addr}");
|
||||
emit_peer_addr_event(app_handle, "peer-disconnected", addr);
|
||||
}
|
||||
PeerEvent::PeerDiscovered(addr) => {
|
||||
log::info!("Peer discovered: {addr}");
|
||||
emit_peer_addr_event(app_handle, "peer-discovered", addr);
|
||||
}
|
||||
PeerEvent::PeerLost(addr) => {
|
||||
log::info!("Peer lost: {addr}");
|
||||
emit_peer_addr_event(app_handle, "peer-lost", addr);
|
||||
}
|
||||
PeerEvent::PeerCountUpdated(count) => {
|
||||
log::info!("Peer count updated: {count}");
|
||||
@@ -2237,12 +2183,6 @@ async fn handle_got_game_files(
|
||||
file_descriptions: Vec<GameFileDescription>,
|
||||
) {
|
||||
log::info!("PeerEvent::GotGameFiles received");
|
||||
emit_game_id_event(
|
||||
app_handle,
|
||||
"game-download-pre",
|
||||
&id,
|
||||
"PeerEvent::GotGameFiles",
|
||||
);
|
||||
|
||||
let state = app_handle.state::<LanSpreadState>();
|
||||
let peer_ctrl = state.peer_ctrl.read().await.clone();
|
||||
@@ -2256,16 +2196,6 @@ async fn handle_got_game_files(
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_download_finished(app_handle: &AppHandle, id: String) {
|
||||
log::info!("PeerEvent::DownloadGameFilesFinished received");
|
||||
emit_game_id_event(
|
||||
app_handle,
|
||||
"game-download-finished",
|
||||
&id,
|
||||
"PeerEvent::DownloadGameFilesFinished",
|
||||
);
|
||||
}
|
||||
|
||||
#[allow(clippy::missing_panics_doc)]
|
||||
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
||||
pub fn run() {
|
||||
|
||||
Reference in New Issue
Block a user