22
33import asyncio
44import logging
5- import time
65from collections import deque
76from itertools import zip_longest
87from typing import TYPE_CHECKING
1615from ably .types .connectionstate import ConnectionEvent , ConnectionState , ConnectionStateChange
1716from ably .types .operations import PublishResult
1817from ably .types .tokendetails import TokenDetails
18+ from ably .util .clock import Clock , select_clock
1919from ably .util .eventemitter import EventEmitter
2020from ably .util .exceptions import AblyException , IncompatibleClientIdException
2121from ably .util .helper import Timer , get_random_id , is_token_error
@@ -123,23 +123,25 @@ def clear(self) -> None:
123123class PendingPing :
124124 """Represents a ping awaiting its heartbeat echo from the server"""
125125
126- def __init__ (self , id : str ):
126+ def __init__ (self , id : str , clock : Clock ):
127127 self .id = id
128+ self .clock = clock
128129 self .future : asyncio .Future [None ] = asyncio .get_running_loop ().create_future ()
129- self .start_time : float = time . monotonic ()
130+ self .start_time : float = clock . monotonic_ms ()
130131
131132 @property
132133 def message (self ) -> dict :
133134 return {"action" : ProtocolMessageAction .HEARTBEAT , "id" : self .id }
134135
135136 @property
136137 def response_time_ms (self ) -> float :
137- return round (( time . monotonic () - self .start_time ) * 1000 , 2 )
138+ return round (self . clock . monotonic_ms () - self .start_time , 2 )
138139
139140
140141class ConnectionManager (EventEmitter ):
141142 def __init__ (self , realtime : AblyRealtime , initial_state ):
142143 self .options = realtime .options
144+ self .clock = select_clock (self .options )
143145 self .__ably = realtime
144146 self .__state : ConnectionState = initial_state
145147 self .__pending_pings : dict [str , PendingPing ] = {}
@@ -364,7 +366,7 @@ async def ping(self) -> float:
364366 raise AblyException ("Cannot send ping request. Calling ping in invalid state" , 400 , 40000 )
365367
366368 # RTN13e: the id tells this ping's echo apart from server heartbeats and other pings
367- pending_ping = PendingPing (get_random_id ())
369+ pending_ping = PendingPing (get_random_id (), self . clock )
368370 self .__pending_pings [pending_ping .id ] = pending_ping
369371 try :
370372 # RTN13d: while connecting, the heartbeat goes out once the connection is established
@@ -379,7 +381,7 @@ async def ping(self) -> float:
379381 return pending_ping .response_time_ms
380382
381383 async def __send_heartbeat (self , pending_ping : PendingPing ) -> None :
382- pending_ping .start_time = time . monotonic ()
384+ pending_ping .start_time = self . clock . monotonic_ms ()
383385 try :
384386 await self .send_protocol_message (pending_ping .message )
385387 except Exception as error :
@@ -718,7 +720,7 @@ def on_transition_timer_expire():
718720
719721 log .debug (f'ConnectionManager.start_transition_timer(): setting timer for { timeout } ms' )
720722
721- self .transition_timer = Timer (timeout , on_transition_timer_expire )
723+ self .transition_timer = self . clock . timer (timeout , on_transition_timer_expire )
722724
723725 def cancel_transition_timer (self ):
724726 log .debug ('ConnectionManager.cancel_transition_timer()' )
@@ -741,7 +743,7 @@ def on_suspend_timer_expire() -> None:
741743 )
742744 self .__fail_state = ConnectionState .SUSPENDED
743745
744- self .suspend_timer = Timer (Defaults .connection_state_ttl , on_suspend_timer_expire )
746+ self .suspend_timer = self . clock . timer (Defaults .connection_state_ttl , on_suspend_timer_expire )
745747
746748 def check_suspend_timer (self , state : ConnectionState ) -> None :
747749 if state not in (
@@ -764,7 +766,7 @@ def on_retry_timeout():
764766 self .retry_timer = None
765767 self .request_state (ConnectionState .CONNECTING )
766768
767- self .retry_timer = Timer (interval , on_retry_timeout )
769+ self .retry_timer = self . clock . timer (interval , on_retry_timeout )
768770
769771 def cancel_retry_timer (self ) -> None :
770772 if self .retry_timer :
0 commit comments