1515
1616class WebSocketDisconnect (Exception ):
1717 """Exception raised when a WebSocket connection is disconnected."""
18-
18+
1919 def __init__ (self , code : int = 1000 , reason : str = "" ):
2020 self .code = code
2121 self .reason = reason
@@ -27,28 +27,28 @@ class WebSocketAdapter:
2727 Adapter class that provides a modern WebSocket interface
2828 wrapping Robyn's WebSocketConnector for compatibility.
2929 """
30-
30+
3131 def __init__ (self , websocket_connector : WebSocketConnector , message : str = None ):
3232 self ._connector = websocket_connector
3333 self ._message = message
3434 self ._accepted = False
35-
35+
3636 async def accept (self ):
3737 """Accept the WebSocket connection (no-op in Robyn as it's auto-accepted)"""
3838 self ._accepted = True
39-
39+
4040 async def close (self , code : int = 1000 ):
4141 """Close the WebSocket connection"""
4242 self ._connector .close ()
43-
43+
4444 async def send_text (self , data : str ):
4545 """Send text data to the WebSocket"""
4646 await self ._connector .async_send_to (self ._connector .id , data )
47-
47+
4848 async def send_bytes (self , data : bytes ):
4949 """Send binary data to the WebSocket"""
50- await self ._connector .async_send_to (self ._connector .id , data .decode (' utf-8' ))
51-
50+ await self ._connector .async_send_to (self ._connector .id , data .decode (" utf-8" ))
51+
5252 async def receive_text (self ) -> str :
5353 """Receive text data from the WebSocket"""
5454 if self ._message is not None :
@@ -58,47 +58,49 @@ async def receive_text(self) -> str:
5858 # Note: In a real implementation, this would need to handle the message queue
5959 # For now, we return the current message if available
6060 return ""
61-
61+
6262 async def receive_bytes (self ) -> bytes :
6363 """Receive binary data from the WebSocket"""
6464 text = await self .receive_text ()
65- return text .encode (' utf-8' )
66-
65+ return text .encode (" utf-8" )
66+
6767 async def send_json (self , data ):
6868 """Send JSON data to the WebSocket"""
6969 import json
70+
7071 await self .send_text (json .dumps (data ))
71-
72+
7273 async def receive_json (self ):
7374 """Receive JSON data from the WebSocket"""
7475 import json
76+
7577 text = await self .receive_text ()
7678 return json .loads (text ) if text else None
77-
79+
7880 async def broadcast (self , data : str ):
7981 """Broadcast data to all connected WebSocket clients"""
8082 await self ._connector .async_broadcast (data )
81-
83+
8284 @property
8385 def query_params (self ):
8486 """Access query parameters"""
8587 return self ._connector .query_params
86-
88+
8789 @property
8890 def path_params (self ):
8991 """Access path parameters"""
90- return getattr (self ._connector , ' path_params' , {})
91-
92+ return getattr (self ._connector , " path_params" , {})
93+
9294 @property
9395 def headers (self ):
9496 """Access request headers"""
95- return getattr (self ._connector , ' headers' , {})
96-
97+ return getattr (self ._connector , " headers" , {})
98+
9799 @property
98100 def client (self ):
99101 """Client information"""
100- return getattr (self ._connector , ' client' , None )
101-
102+ return getattr (self ._connector , " client" , None )
103+
102104 @property
103105 def id (self ):
104106 """WebSocket connection ID"""
@@ -110,32 +112,34 @@ def create_websocket_decorator(app_instance):
110112 Factory function to create a websocket decorator for an app instance.
111113 This allows access to the app's dependencies and web_socket_router.
112114 """
115+
113116 def websocket (endpoint : str ):
114117 """
115118 Modern WebSocket decorator that accepts a single handler function.
116119 The handler function receives a WebSocket object and can optionally have on_connect and on_close callbacks.
117-
120+
118121 Usage:
119122 @app.websocket("/ws")
120123 async def websocket_endpoint(websocket):
121124 await websocket.accept()
122125 while True:
123126 data = await websocket.receive_text()
124127 await websocket.send_text(f"Echo: {data}")
125-
128+
126129 # With optional callbacks:
127130 @websocket_endpoint.on_connect
128131 async def on_connect(websocket):
129132 await websocket.send_text("Connected!")
130-
131- @websocket_endpoint.on_close
133+
134+ @websocket_endpoint.on_close
132135 async def on_close(websocket):
133136 print("Disconnected")
134137 """
138+
135139 def decorator (handler ):
136140 # Dictionary to store handlers for this WebSocket endpoint
137141 handlers = {}
138-
142+
139143 # Create the main message handler
140144 async def message_handler (websocket_connector , msg , * args , ** kwargs ):
141145 # Convert WebSocketConnector to modern WebSocket interface
@@ -152,78 +156,78 @@ async def message_handler(websocket_connector, msg, *args, **kwargs):
152156 if "connection closed" in str (e ).lower () or "websocket" in str (e ).lower ():
153157 return ""
154158 raise e
155-
159+
156160 # Create FunctionInfo for the message handler
157161 params = dict (inspect .signature (message_handler ).parameters )
158162 num_params = len (params )
159163 is_async = asyncio .iscoroutinefunction (message_handler )
160164 injected_dependencies = app_instance .dependencies .get_dependency_map (app_instance )
161-
165+
162166 # Filter dependencies to only include reserved parameters that exist in handler
163167 filtered_dependencies = {}
164168 if "global_dependencies" in params :
165169 filtered_dependencies ["global_dependencies" ] = injected_dependencies .get ("global_dependencies" , {})
166170 if "router_dependencies" in params :
167171 filtered_dependencies ["router_dependencies" ] = injected_dependencies .get ("router_dependencies" , {})
168-
172+
169173 handlers ["message" ] = FunctionInfo (message_handler , is_async , num_params , params , filtered_dependencies )
170-
174+
171175 # Add methods to the handler to allow attaching on_connect and on_close
172176 def add_on_connect (connect_handler ):
173177 def connect_wrapper (websocket_connector , * args , ** kwargs ):
174178 websocket_adapter = WebSocketAdapter (websocket_connector )
175179 if asyncio .iscoroutinefunction (connect_handler ):
176180 return asyncio .create_task (connect_handler (websocket_adapter ))
177181 return connect_handler (websocket_adapter )
178-
182+
179183 # Create FunctionInfo for connect handler
180184 connect_params = dict (inspect .signature (connect_handler ).parameters ) # Use original handler params, not wrapper
181185 connect_num_params = len (connect_params )
182186 connect_is_async = asyncio .iscoroutinefunction (connect_wrapper )
183-
187+
184188 # Filter dependencies for connect handler - only reserved parameters
185189 filtered_connect_deps = {}
186190 if "global_dependencies" in connect_params :
187191 filtered_connect_deps ["global_dependencies" ] = injected_dependencies .get ("global_dependencies" , {})
188192 if "router_dependencies" in connect_params :
189193 filtered_connect_deps ["router_dependencies" ] = injected_dependencies .get ("router_dependencies" , {})
190-
194+
191195 handlers ["connect" ] = FunctionInfo (connect_wrapper , connect_is_async , connect_num_params , connect_params , filtered_connect_deps )
192196 return connect_handler
193-
197+
194198 def add_on_close (close_handler ):
195199 def close_wrapper (websocket_connector , * args , ** kwargs ):
196200 websocket_adapter = WebSocketAdapter (websocket_connector )
197201 if asyncio .iscoroutinefunction (close_handler ):
198202 return asyncio .create_task (close_handler (websocket_adapter ))
199203 return close_handler (websocket_adapter )
200-
204+
201205 # Create FunctionInfo for close handler
202206 close_params = dict (inspect .signature (close_handler ).parameters ) # Use original handler params, not wrapper
203207 close_num_params = len (close_params )
204208 close_is_async = asyncio .iscoroutinefunction (close_wrapper )
205-
209+
206210 # Filter dependencies for close handler - only reserved parameters
207211 filtered_close_deps = {}
208212 if "global_dependencies" in close_params :
209213 filtered_close_deps ["global_dependencies" ] = injected_dependencies .get ("global_dependencies" , {})
210214 if "router_dependencies" in close_params :
211215 filtered_close_deps ["router_dependencies" ] = injected_dependencies .get ("router_dependencies" , {})
212-
216+
213217 handlers ["close" ] = FunctionInfo (close_wrapper , close_is_async , close_num_params , close_params , filtered_close_deps )
214218 return close_handler
215-
219+
216220 # Attach methods to the handler function
217221 handler .on_connect = add_on_connect
218222 handler .on_close = add_on_close
219223 handler ._ws_handlers = handlers # Store reference to handlers dict
220-
224+
221225 # Add the WebSocket to the router
222226 app_instance .add_web_socket (endpoint , handlers )
223227 return handler
224-
228+
225229 return decorator
226-
230+
227231 return websocket
228232
229233
@@ -259,4 +263,4 @@ def inner(handler):
259263
260264 return handler
261265
262- return inner
266+ return inner
0 commit comments