feat(call-to-play)!: coordinate game sessions across peers

Implement the launcher design as a production peer-to-peer feature. Call to
Play actions are immutable, validated events broadcast over the existing QUIC
control channel, deduplicated in a bounded in-memory history, and exchanged in
Hello/HelloAck so late joiners reconstruct current calls.

Add the Tauri bridge and modular launcher surfaces for play-now and scheduled
calls, check-in, readiness buffers, role-aware controls, chat, tickers, and
actual caller launch. A deterministic frontend reducer derives presentation
state from replicated history. Extend the JSONL peer harness with publish/list
commands and a three-peer live-delivery and late-join scenario.

This intentionally raises the only supported wire protocol from version 5 to
version 6; older builds are not supported. Document the transport architecture
and exclude generated peer-test state from Docker build contexts.

Test Plan:
- `just fmt` -- passed
- `just clippy` -- passed
- `just test` -- passed
- `just frontend-test` -- passed, 20 tests
- `just build` -- passed
- `just peer-cli-tests S2 S48` -- passed
- `git diff --cached --check` -- passed
This commit is contained in:
2026-07-21 22:30:11 +02:00
parent 8f151e38b4
commit 0f53bc4b78
31 changed files with 3032 additions and 21 deletions
+39 -1
View File
@@ -4,7 +4,7 @@ use bytes::Bytes;
use lanspread_db::db::{Game, GameFileDescription};
use serde::{Deserialize, Serialize};
pub const PROTOCOL_VERSION: u32 = 5;
pub const PROTOCOL_VERSION: u32 = 6;
pub use lanspread_db::db::Availability;
@@ -27,6 +27,7 @@ pub struct Hello {
pub listen_addr: SocketAddr,
pub library: LibrarySnapshot,
pub features: Vec<String>,
pub call_to_play_events: Vec<CallToPlayEvent>,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
@@ -36,6 +37,40 @@ pub struct HelloAck {
pub listen_addr: SocketAddr,
pub library: LibrarySnapshot,
pub features: Vec<String>,
pub call_to_play_events: Vec<CallToPlayEvent>,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
pub struct CallToPlayEvent {
pub id: String,
pub call_id: String,
pub actor: String,
pub at: i64,
pub action: CallToPlayAction,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
pub enum CallToPlayAction {
Create {
game_id: String,
max_players: u16,
scheduled_for: Option<i64>,
deadline: i64,
},
Respond {
ready_at: Option<i64>,
},
Rsvp,
SendMessage {
message_id: String,
text: String,
},
Leave,
Cancel,
Start,
AddTime {
deadline: i64,
},
}
#[derive(Clone, Debug, Serialize, Deserialize)]
@@ -75,6 +110,9 @@ pub enum Request {
peer_id: String,
delta: LibraryDelta,
},
CallToPlayEvents {
events: Vec<CallToPlayEvent>,
},
Goodbye {
peer_id: String,
},