11use std:: sync:: Arc ;
22use std:: time:: Duration ;
33
4+ use bytes:: Bytes ;
45use dashmap:: DashMap ;
56use tokio:: io:: BufWriter ;
67use tokio:: net:: { TcpListener , TcpStream } ;
@@ -52,7 +53,7 @@ pub struct Server {
5253/// Handle to a running server.
5354///
5455/// Provides runtime control: shutdown and room management.
55- /// Rooms can be created and deleted at any time — new clients will see the
56+ /// Rooms can be created and deleted at any time, new clients will see the
5657/// updated room list, and existing clients in deleted rooms get errors on
5758/// their next broadcast or join attempt.
5859pub struct ServerHandle {
@@ -102,18 +103,13 @@ impl Server {
102103 }
103104
104105 /// Create a room. Call this before [`Server::run`].
105- ///
106106 /// Clients can only join rooms that have been explicitly created.
107- ///
108- /// # Errors
109- ///
110107 /// Returns [`SyncError::RoomAlreadyExists`] if a room with this ID exists.
111108 pub fn create_room ( & self , id : & str ) -> Result < ( ) > {
112109 self . rooms . create ( id)
113110 }
114111
115112 /// Delete a room. Call this before [`Server::run`].
116- ///
117113 /// Returns `true` if the room existed.
118114 pub fn delete_room ( & self , id : & str ) -> bool {
119115 self . rooms . delete ( id)
@@ -122,7 +118,7 @@ impl Server {
122118 /// Start accepting connections.
123119 ///
124120 /// Binds the TCP listener synchronously. If the bind fails, the error is
125- /// returned immediately — nothing is spawned on failure.
121+ /// returned immediately
126122 ///
127123 /// On success, spawns the accept loop on the current runtime and returns
128124 /// a [`ServerHandle`] for shutdown and runtime action
@@ -188,14 +184,14 @@ impl Server {
188184 Ok ( handle)
189185 }
190186
191- #[ inline( always ) ]
187+ #[ inline]
192188 async fn handle_connection ( self : & Arc < Self > , stream : TcpStream ) -> Result < ( ) > {
193189 let client_id = Uuid :: new_v4 ( ) ;
194190 let ( read_half, write_half) = stream. into_split ( ) ;
195191 let mut reader = tokio:: io:: BufReader :: new ( read_half) ;
196192 let mut writer = BufWriter :: new ( write_half) ;
197193
198- let ( write_tx, mut write_rx) = mpsc:: channel :: < Vec < u8 > > ( 64 ) ;
194+ let ( write_tx, mut write_rx) = mpsc:: channel :: < Bytes > ( self . config . channel_capacity ) ;
199195
200196 // Spawn writer task
201197 let writer_handle = tokio:: spawn ( async move {
@@ -222,11 +218,12 @@ impl Server {
222218 result
223219 }
224220
221+ #[ inline( always) ]
225222 async fn client_loop (
226223 self : & Arc < Self > ,
227224 client_id : Uuid ,
228225 reader : & mut tokio:: io:: BufReader < tokio:: net:: tcp:: OwnedReadHalf > ,
229- write_tx : & mpsc:: Sender < Vec < u8 > > ,
226+ write_tx : & mpsc:: Sender < Bytes > ,
230227 ) -> Result < ( ) > {
231228 let mut shutdown_rx = self . shutdown_tx . subscribe ( ) ;
232229 let mut ping_interval = tokio:: time:: interval ( self . config . ping_interval ) ;
@@ -289,7 +286,7 @@ impl Server {
289286 self : & Arc < Self > ,
290287 client_id : Uuid ,
291288 msg : ClientWire ,
292- write_tx : & mpsc:: Sender < Vec < u8 > > ,
289+ write_tx : & mpsc:: Sender < Bytes > ,
293290 ) -> Result < ( ) > {
294291 match msg {
295292 ClientWire :: JoinRoom { room_id } => {
@@ -375,9 +372,10 @@ impl Server {
375372 } ;
376373 let payload = wincode:: serialize ( & broadcast)
377374 . map_err ( |e| SyncError :: Protocol ( format ! ( "serialize failed: {:?}" , e) ) ) ?;
375+ let payload = Bytes :: from ( payload) ;
378376
379377 if let Some ( room) = self . rooms . get ( & room_id) {
380- let dropped = room. broadcast_raw ( client_id, & payload) . await ;
378+ let dropped = room. broadcast_raw ( client_id, payload) . await ;
381379 for id in dropped {
382380 self . handler . on_backpressure ( id, & room_id) ;
383381 }
@@ -392,6 +390,7 @@ impl Server {
392390 Ok ( ( ) )
393391 }
394392
393+ #[ inline]
395394 async fn cleanup_client ( self : & Arc < Self > , client_id : Uuid , room_id : & str ) {
396395 let notify = ServerWire :: PlayerLeft { client_id } ;
397396 if let Some ( room) = self . rooms . get ( room_id) {
@@ -407,9 +406,9 @@ impl Server {
407406 }
408407
409408 #[ inline( always) ]
410- async fn send_to_client ( & self , client_id : Uuid , tx : & mpsc:: Sender < Vec < u8 > > , msg : & ServerWire ) {
409+ async fn send_to_client ( & self , client_id : Uuid , tx : & mpsc:: Sender < Bytes > , msg : & ServerWire ) {
411410 if let Ok ( payload) = wincode:: serialize ( msg) {
412- if tx. try_send ( payload) . is_err ( ) {
411+ if tx. try_send ( Bytes :: from ( payload) ) . is_err ( ) {
413412 if let Some ( state) = self . clients . get ( & client_id) {
414413 if let Some ( ref room_id) = state. room_id {
415414 self . handler . on_backpressure ( client_id, room_id) ;
@@ -484,6 +483,14 @@ impl ServerBuilder {
484483 self
485484 }
486485
486+ /// Per-client write channel capacity. Frames are dropped when full
487+ /// (with `on_backpressure` hook). Higher values buffer more for bursty
488+ /// games; lower values keep latency tight. Default: 64.
489+ pub fn channel_capacity ( mut self , n : usize ) -> Self {
490+ self . config . channel_capacity = n;
491+ self
492+ }
493+
487494 /// Set a custom event handler for lifecycle hooks.
488495 pub fn handler ( mut self , h : impl ServerHandler ) -> Self {
489496 self . handler = Arc :: new ( h) ;
0 commit comments