Files
plezy/server/relay_protocol_gen.go
edde746 89d54d8f1d feat(watch-together): let the host hand the room to another participant
close #2183

Reusing a room means whoever enters first becomes the host, and moving the
session to someone else's library meant everyone leaving and re-entering in
the right order. The host can now promote any connected guest from the
participant list (Watch Together screen and the in-player session sheet),
with playback, control mode, and reconnect identities carried across.

The relay owns the swap: a new `transferHost` message validates the sender
is the live host and the target a connected modern-protocol guest, then
swaps `HostPeerID` and the reconnect verifiers (each peer keeps its own
token), persists the room, and broadcasts `hostChanged` to every peer.

Clients flip roles in place: the controller swaps its role engine while
keeping the session, message queue, and player attachment. A promoted guest
seeds the coordinator with the room's last known intent (a paused room
stays paused) and the known-peer roster so the fresh epoch re-gates
instead of solo-starting; a demoted host falls back to a reconciler with a
fresh clock sync and asks the new authority for state. Guests re-pin the
host identity, reset their sequence, and re-converge their clocks.

A rejected transfer (`not_host` / `peer_not_found`) surfaces as a toast
instead of tearing the session down. Pre-transfer app builds in the room
ignore `hostChanged` and stop following the room at the next transfer;
targets on an old sync protocol are not offered the action.
2026-08-31 08:55:45 +02:00

57 lines
1.8 KiB
Go

// Code generated by scripts/codegen/generate_relay_protocol.py. DO NOT EDIT.
package main
const (
relayProtocolVersion = 2
legacyRelayProtocolVersion = 0
relayTypeCreate = "create"
relayTypeJoin = "join"
relayTypeBroadcast = "broadcast"
relayTypeSendTo = "sendTo"
relayTypePing = "ping"
relayTypeLeave = "leave"
relayTypeEndSession = "endSession"
relayTypeTransferHost = "transferHost"
relayTypeCreated = "created"
relayTypeJoined = "joined"
relayTypePeerJoined = "peerJoined"
relayTypePeerLeft = "peerLeft"
relayTypeMessage = "message"
relayTypeError = "error"
relayTypePong = "pong"
relayTypeLeft = "left"
relayTypeEnded = "ended"
relayTypeHostChanged = "hostChanged"
relayErrorRateLimited = "rate_limited"
relayErrorInvalidMessage = "invalid_message"
relayErrorRoomExists = "room_exists"
relayErrorRoomNotFound = "room_not_found"
relayErrorRoomFull = "room_full"
relayErrorNotInRoom = "not_in_room"
relayErrorAlreadyInRoom = "already_in_room"
relayErrorPeerIdUnavailable = "peer_id_unavailable"
relayErrorProtocolMismatch = "protocol_mismatch"
relayErrorNotHost = "not_host"
relayErrorPeerNotFound = "peer_not_found"
maxRoomSize = 8
maxMessageSize = 65536
maxSessionIDLength = 64
maxPeerIDLength = 128
)
func validRelayID(value string, maxLength int) bool {
if len(value) == 0 || len(value) > maxLength {
return false
}
for _, ch := range value {
if (ch < 'a' || ch > 'z') && (ch < 'A' || ch > 'Z') &&
(ch < '0' || ch > '9') && ch != '_' && ch != '-' {
return false
}
}
return true
}