@@ -74,7 +74,7 @@ def __init__(
74
74
self .access_token = token
75
75
self .send_buffer : List [Callable ] = []
76
76
self .hb_interval = hb_interval
77
- self .ws_connection : Optional [ClientProtocol ] = None
77
+ self ._ws_connection : Optional [ClientProtocol ] = None
78
78
self .ref = 0
79
79
self .auto_reconnect = auto_reconnect
80
80
self .channels : Dict [str , AsyncRealtimeChannel ] = {}
@@ -86,39 +86,31 @@ def __init__(
86
86
87
87
@property
88
88
def is_connected (self ) -> bool :
89
- return self .ws_connection is not None
89
+ return self ._ws_connection is not None
90
90
91
91
async def _listen (self ) -> None :
92
92
"""
93
93
An infinite loop that keeps listening.
94
94
:return: None
95
95
"""
96
96
97
- if not self .ws_connection :
97
+ if not self ._ws_connection :
98
98
raise Exception ("WebSocket connection not established" )
99
99
100
100
try :
101
- async for msg in self .ws_connection :
101
+ async for msg in self ._ws_connection :
102
102
logger .info (f"receive: { msg } " )
103
103
104
104
msg = Message (** json .loads (msg ))
105
105
channel = self .channels .get (msg .topic )
106
106
107
107
if channel :
108
108
channel ._trigger (msg .event , msg .payload , msg .ref )
109
- except websockets .exceptions .ConnectionClosedError as e :
110
- logger .error (
111
- f"WebSocket connection closed with code: { e .code } , reason: { e .reason } "
112
- )
113
- if self .auto_reconnect :
114
- logger .info ("Initiating auto-reconnect sequence..." )
115
-
116
- await self ._reconnect ()
117
- else :
118
- logger .error ("Auto-reconnect disabled, terminating connection" )
109
+ except Exception as e :
110
+ await self ._on_connect_error (e )
119
111
120
112
async def _reconnect (self ) -> None :
121
- self .ws_connection = None
113
+ self ._ws_connection = None
122
114
await self .connect ()
123
115
124
116
if self .is_connected :
@@ -156,7 +148,7 @@ async def connect(self) -> None:
156
148
while retries < self .max_retries :
157
149
try :
158
150
ws = await connect (self .url )
159
- self .ws_connection = ws
151
+ self ._ws_connection = ws
160
152
logger .info ("WebSocket connection established successfully" )
161
153
return await self ._on_connect ()
162
154
except Exception as e :
@@ -197,6 +189,20 @@ async def _on_connect(self) -> None:
197
189
self ._heartbeat_task = asyncio .create_task (self ._heartbeat ())
198
190
await self ._flush_send_buffer ()
199
191
192
+ async def _on_connect_error (self , e : Exception ) -> None :
193
+ if isinstance (e , websockets .exceptions .ConnectionClosedError ):
194
+ logger .error (
195
+ f"WebSocket connection closed with code: { e .code } , reason: { e .reason } "
196
+ )
197
+
198
+ if self .auto_reconnect :
199
+ logger .info ("Initiating auto-reconnect sequence..." )
200
+ await self ._reconnect ()
201
+ else :
202
+ logger .error ("Auto-reconnect disabled, terminating connection" )
203
+ else :
204
+ logger .error (f"Error on connect: { e } " )
205
+
200
206
async def _flush_send_buffer (self ):
201
207
if self .is_connected and len (self .send_buffer ) > 0 :
202
208
for callback in self .send_buffer :
@@ -214,10 +220,10 @@ async def close(self) -> None:
214
220
NotConnectedError: If the connection is not established when this method is called.
215
221
"""
216
222
217
- if self .ws_connection :
218
- await self .ws_connection .close ()
223
+ if self ._ws_connection :
224
+ await self ._ws_connection .close ()
219
225
220
- self .ws_connection = None
226
+ self ._ws_connection = None
221
227
222
228
if self ._listen_task :
223
229
self ._listen_task .cancel ()
@@ -228,7 +234,7 @@ async def close(self) -> None:
228
234
self ._heartbeat_task = None
229
235
230
236
async def _heartbeat (self ) -> None :
231
- if not self .ws_connection :
237
+ if not self ._ws_connection :
232
238
raise Exception ("WebSocket connection not established" )
233
239
234
240
while self .is_connected :
@@ -242,17 +248,8 @@ async def _heartbeat(self) -> None:
242
248
await self .send (data )
243
249
await asyncio .sleep (max (self .hb_interval , 15 ))
244
250
245
- except websockets .exceptions .ConnectionClosed as e :
246
- logger .error (
247
- f"Connection closed during heartbeat. Code: { e .code } , reason: { e .reason } "
248
- )
249
-
250
- if self .auto_reconnect :
251
- logger .info ("Heartbeat failed - initiating reconnection sequence" )
252
- await self ._reconnect ()
253
- else :
254
- logger .error ("Heartbeat failed - auto-reconnect disabled" )
255
- break
251
+ except Exception as e :
252
+ await self ._on_connect_error (e )
256
253
257
254
def channel (
258
255
self , topic : str , params : Optional [RealtimeChannelOptions ] = None
@@ -373,7 +370,15 @@ async def send(self, message: Dict[str, Any]) -> None:
373
370
logger .info (f"send: { message } " )
374
371
375
372
async def send_message ():
376
- await self .ws_connection .send (message )
373
+ if not self ._ws_connection :
374
+ raise Exception (
375
+ "WebSocket connection not established, a connection is expected to be established before sending a message"
376
+ )
377
+
378
+ try :
379
+ await self ._ws_connection .send (message )
380
+ except Exception as e :
381
+ await self ._on_connect_error (e )
377
382
378
383
if self .is_connected :
379
384
await send_message ()
0 commit comments