ghost_sync/handler.rs
1use std::net::SocketAddr;
2use uuid::Uuid;
3
4/// Optional hook trait for server lifecycle events.
5/// All methods have no-op defaults — implement only what you need.
6///
7/// # Composability
8///
9/// These hooks are the extension point for game logic. The library never
10/// interprets room metadata or makes game-specific decisions. Use the hooks
11/// to implement private rooms, max player limits, matchmaking, bans, etc.
12///
13/// # Security
14///
15/// Use [`on_connect`](ServerHandler::on_connect) to filter connections by address
16/// before they're fully accepted.
17///
18/// # Backpressure
19///
20/// When a client's write channel is full, the frame is dropped and
21/// [`on_backpressure`](ServerHandler::on_backpressure) is called. This is
22/// intentional for real-time game relay — a slow client shouldn't stall the server.
23pub trait ServerHandler: Send + Sync + 'static {
24 /// Called when a new TCP connection arrives. Return `false` to reject it.
25 /// Called before any resources are allocated for the connection.
26 fn on_connect(&self, _addr: SocketAddr) -> bool {
27 true
28 }
29
30 /// Called when a client requests to join a room.
31 ///
32 /// Return `(true, _)` to allow the join.
33 /// Return `(false, Some(reason))` to reject with a custom error message.
34 /// Return `(false, None)` to reject with the default "join rejected" message.
35 ///
36 /// Use this to implement private rooms (check password), max player limits (check client count)
37 /// or use payload_data field to validate any sort of tokens,
38 /// bans (check addr), add room_limit or any custom join logic you wish
39 fn on_join(
40 &self,
41 _client_id: Uuid,
42 _room_id: &str,
43 _addr: SocketAddr,
44 _data: &[u8],
45 ) -> (bool, Option<String>) {
46 (true, None)
47 }
48
49 /// Called when a client leaves a room (or disconnects).
50 fn on_leave(&self, _client_id: Uuid, _room_id: &str) {}
51
52 /// Called after a room is created (including via [`ServerHandle::create_room_runtime`](crate::ServerHandle::create_room)).
53 fn on_room_create(&self, _room_id: &str) {}
54
55 /// Called after a room is deleted.
56 fn on_room_delete(&self, _room_id: &str) {}
57
58 /// Called when a broadcast message is relayed.
59 /// client_id is the sender, and the message has already been relayed to all peers.
60 #[inline]
61 fn on_broadcast(&self, _client_id: Uuid, _room_id: &str, _data: &[u8]) {}
62
63 /// Called when a frame is dropped because a client's write channel is full.
64 /// The affected clients are identified by their UUIDs.
65 ///
66 /// NOTE: For auto-kicking or pausing slow clients, you need to monitor channel length via [`ServerHandle::get_client_channel_len`](crate::ServerHandle::get_client_channel_len)
67 /// or [`ServerHandle::get_room_channel_lens`](crate::ServerHandle::get_room_channel_lens) and implement your own logic in this hook.
68 /// The library does not auto-kick or pause clients on backpressure, as some games may prefer to drop frames silently.
69 #[inline]
70 fn on_backpressure(&self, _client_id: Uuid, _room_id: &str) {}
71
72 /// Called when server is shutdown via ctrl-c (shutdown signals)
73 /// Can be used as a graceful shutdown signal for any background tasks or post-shutdown cleanup or jobs
74 fn on_shutdown(&self) {}
75}
76
77/// Default no-op handler. Accepts all connections, ignores all events.
78pub struct NoopHandler;
79
80impl ServerHandler for NoopHandler {}