feat(ctrl): report gateway presence in welcome

ServerWelcome now carries an initial gateway_connected flag with serde defaulting
for older welcome payloads. The relay sets it from room admission state so a
gateway sees itself as connected, clients joining behind an existing gateway see
yes, and clients that arrive first see no.

The Windows client prints that handshake fact at startup. This does not replace
the later peer-event stream; it gives phase-1 diagnostics an immediate answer
for whether the relay already has a LAN gateway in the room.

Test Plan:
- cargo fmt --check
- cargo test -p lanparty-ctrl -p lanparty-relay -p lanparty-client-core \
  -p lanparty-client-win
- cargo clippy -p lanparty-ctrl -p lanparty-relay -p lanparty-client-core \
  -p lanparty-client-win --all-targets -- -D warnings
- cargo test --workspace
- cargo clippy --workspace --all-targets -- -D warnings
- git diff --check

Refs: PLAN.md
This commit is contained in:
2026-05-21 20:24:14 +02:00
parent c6dbb78cfc
commit 0824f60548
5 changed files with 44 additions and 4 deletions
+15 -2
View File
@@ -327,8 +327,10 @@ impl Room {
format!("invalid peer: {error}"),
)
})?;
let welcome =
ServerWelcome::new(self.room_id, peer_id, effective_tap_mtu).map_err(|error| {
let gateway_connected = matches!(peer.role(), Role::Gateway) || self.gateway.is_some();
let welcome = ServerWelcome::new(self.room_id, peer_id, effective_tap_mtu)
.map(|welcome| welcome.with_gateway_connected(gateway_connected))
.map_err(|error| {
Reject::new(
RejectReason::InternalError,
format!("welcome failed: {error}"),
@@ -817,13 +819,24 @@ mod tests {
assert_eq!(registry.room_count(), 1);
assert_eq!(gateway.peer().role(), Role::Gateway);
assert_eq!(gateway.welcome().peer_id(), 1);
assert!(gateway.welcome().gateway_connected());
assert_eq!(client.peer().role(), Role::Client);
assert_eq!(client.welcome().peer_id(), 2);
assert!(client.welcome().gateway_connected());
assert_eq!(snapshot.gateway().unwrap().peer_id(), 1);
assert_eq!(snapshot.clients().len(), 1);
assert_eq!(snapshot.effective_tap_mtu(), 1200);
}
#[test]
fn reports_missing_gateway_to_client_joining_first() {
let mut registry = RoomRegistry::default();
let client = registry.join(client_hello(1)).unwrap();
assert!(!client.welcome().gateway_connected());
}
#[test]
fn rejects_second_gateway() {
let mut registry = RoomRegistry::default();