Files
polylan-submitter/polylan_submitter/place/wire.py
T
2026-09-17 01:33:54 +02:00

40 lines
1.7 KiB
Python

"""Compact wire format for the place websocket.
Same convention as clock/wire.py (kept separate on purpose - the two games
don't share code, mirroring how the clock and place apps don't share code
either). Each message is a short string: a one-letter type tag followed by
'|'-separated fields, in a fixed order the client already knows from this
table:
s|<next>|<width>|<height> initial personal state, once per connection
(next = epoch ms cooldown ends, or empty if free now)
p|<x>|<y>|<c> a pixel was placed - broadcast to everyone,
including the placer (no separate ack needed)
k|<next> your own placement was accepted; carries your
new cooldown end
r|c|<next> rejected: still on cooldown
r|a rejected: not logged in
r|i rejected: invalid x/y/color
e|<width>|<height> an admin resized the grid for this event -
broadcast to everyone. A client that sees this
should re-fetch /api/.../place/canvas rather than
try to remap its local pixels.
Client -> server has exactly one message shape, the same as the broadcast:
p|<x>|<y>|<c>
Whether the game is enabled at all for this event (EventGame.enabled) is
checked once, at connect time - a connection is refused outright rather than
accepted-but-disabled, so there's no "disabled" case in this wire format.
"""
DELIMITER = "|"
def encode(*parts) -> str:
return DELIMITER.join("" if p is None else str(p) for p in parts)
def to_epoch_ms(dt) -> int:
return int(dt.timestamp() * 1000)