Skip to content

Commit a52e5b7

Browse files
committed
Prevent repeated WebSocket subscription creation (#109)
Make WebSocketClient retain and reuse one private subscription object. Require explicit non-empty events for create_subscription; reject pending or active duplicate creation via the existing createSubscriptionError path while routing retries after failure and creation after removal through the retained object's existing registration flow with the newly supplied events.
1 parent 95b7bce commit a52e5b7

2 files changed

Lines changed: 335 additions & 8 deletions

File tree

‎ringcentral/websocket/web_socket_client.py‎

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ def __init__(self, platform):
1717
self._is_ready = False
1818
self._heartbeat_task = None
1919
self._send_attempt_counter = 0
20+
self._subscription = None
2021

2122
async def create_new_connection(self):
2223
"""
@@ -249,26 +250,41 @@ async def send_message(self, message):
249250
self.trigger(WebSocketEvents.sendMessageError, e)
250251
raise
251252

252-
async def create_subscription(self, events=None):
253+
async def create_subscription(self, events):
253254
"""
254255
Creates a subscription to WebSocket events.
255256
256257
Args:
257-
events (list, optional): A list of events to subscribe to. Default is None.
258+
events (list): A required, non-empty list of events to subscribe to.
258259
259260
Raises:
260-
Exception: If any error occurs during the process or if the connection is not ready after multiple attempts.
261+
Exception: If any error occurs during the process, if events are omitted, None, or empty, if a subscription creation is already in progress, or if a subscription already exists.
261262
262263
Note:
263-
- If the WebSocket connection is ready (`_is_ready` flag), resets the send attempt counter and creates a WebSocketSubscription instance.
264-
- Registers the subscription with the specified events.
264+
- Events are required: an omitted argument is rejected by ordinary Python argument checking, and None or empty events raise "Events are undefined" before any request is sent or any receive listener is attached.
265+
- The client retains and reuses a single subscription object; a retry after a failed creation and a creation after removal reuse the retained object's existing registration flow with the newly supplied events.
266+
- Rejects a call while a subscription creation is already in progress with "WebSocket subscription creation is already in progress; wait for subscriptionCreated or createSubscriptionError before retrying".
267+
- Rejects a call after a subscription has been created with "A WebSocket subscription already exists; use update_subscription() to change its events or remove_subscription() before creating another".
268+
- Rejections are delivered through the createSubscriptionError event and raised to the caller.
269+
- If the WebSocket connection is ready (`_is_ready` flag), resets the send attempt counter and registers the retained subscription with the specified events.
265270
- If the connection is not ready, retries after a delay and increments the send attempt counter.
266271
- If the send attempt counter exceeds a threshold, triggers the connectionNotReady event and raises an exception.
267272
"""
268273
try:
274+
if not events or len(events) == 0:
275+
raise Exception("Events are undefined")
276+
277+
if self._subscription is None:
278+
self._subscription = WebSocketSubscription(self)
279+
subscription = self._subscription
280+
281+
if subscription._pending_creation_message_id is not None:
282+
raise Exception("WebSocket subscription creation is already in progress; wait for subscriptionCreated or createSubscriptionError before retrying")
283+
if subscription.get_subscription_info() is not None:
284+
raise Exception("A WebSocket subscription already exists; use update_subscription() to change its events or remove_subscription() before creating another")
285+
269286
if self._is_ready:
270287
self._send_attempt_counter = 0
271-
subscription = WebSocketSubscription(self)
272288
await subscription.register(events)
273289
else:
274290
await asyncio.sleep(1)

0 commit comments

Comments
 (0)