Skip to content

Commit f8244d7

Browse files
committed
feat: get rid of rest_host, realtime_host internally unified everything under host
1 parent 761c421 commit f8244d7

13 files changed

Lines changed: 284 additions & 154 deletions

ably/http/http.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -140,9 +140,9 @@ def dump_body(self, body):
140140
else:
141141
return json.dumps(body, separators=(',', ':'))
142142

143-
def get_rest_hosts(self):
144-
hosts = self.options.get_rest_hosts()
145-
host = self.__host or self.options.fallback_realtime_host
143+
def get_hosts(self):
144+
hosts = self.options.get_hosts()
145+
host = self.__host or self.options.fallback_host
146146
if host is None:
147147
return hosts
148148

@@ -186,7 +186,7 @@ async def make_request(self, method, path, version=None, headers=None, body=None
186186
http_max_retry_duration = self.http_max_retry_duration
187187
requested_at = time.time()
188188

189-
hosts = self.get_rest_hosts()
189+
hosts = self.get_hosts()
190190
for retry_count, host in enumerate(hosts):
191191
def should_stop_retrying(retry_count=retry_count):
192192
time_passed = time.time() - requested_at
@@ -229,7 +229,7 @@ def should_stop_retrying(retry_count=retry_count):
229229
continue
230230

231231
# Keep fallback host for later (RSC15f)
232-
if retry_count > 0 and host != self.options.get_rest_host():
232+
if retry_count > 0 and host != self.options.get_host():
233233
self.__host = host
234234
self.__host_expires = time.time() + (self.options.fallback_retry_timeout / 1000.0)
235235

@@ -277,7 +277,7 @@ def options(self):
277277

278278
@property
279279
def preferred_host(self):
280-
return self.options.get_rest_host()
280+
return self.options.get_host()
281281

282282
@property
283283
def preferred_port(self):

ably/realtime/connectionmanager.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ def __init__(self, realtime: AblyRealtime, initial_state):
122122
self.retry_timer: Timer | None = None
123123
self.connect_base_task: asyncio.Task | None = None
124124
self.disconnect_transport_task: asyncio.Task | None = None
125-
self.__fallback_hosts: list[str] = self.options.get_fallback_realtime_hosts()
125+
self.__fallback_hosts: list[str] = self.options.get_fallback_hosts()
126126
self.queued_messages: deque[PendingMessage] = deque()
127127
self.__error_reason: AblyException | None = None
128128
self.msg_serial: int = 0
@@ -532,7 +532,7 @@ async def connect_with_fallback_hosts(self, fallback_hosts: list) -> Exception |
532532

533533
async def connect_base(self) -> None:
534534
fallback_hosts = self.__fallback_hosts
535-
primary_host = self.options.get_realtime_host()
535+
primary_host = self.options.get_host()
536536
try:
537537
await self.try_host(primary_host)
538538
return

ably/transport/websockettransport.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -142,8 +142,8 @@ async def on_protocol_message(self, msg):
142142
self.max_idle_interval = max_idle_interval + self.options.realtime_request_timeout
143143
self.on_activity()
144144
self.is_connected = True
145-
if self.host != self.options.get_realtime_host(): # RTN17e
146-
self.options.fallback_realtime_host = self.host
145+
if self.host != self.options.get_host(): # RTN17e
146+
self.options.fallback_host = self.host
147147
self.connection_manager.on_connected(connection_details, connection_id, reason=exception)
148148
elif action == ProtocolMessageAction.DISCONNECTED:
149149
error = msg.get('error')

ably/types/options.py

Lines changed: 60 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -29,17 +29,21 @@ def __init__(self, client_id=None, log_level=0, tls=True, rest_host=None, realti
2929
tls_port=0, use_binary_protocol=True, queue_messages=True, recover=False, endpoint=None,
3030
environment=None, http_open_timeout=None, http_request_timeout=None,
3131
realtime_request_timeout=None, http_max_retry_count=None, http_max_retry_duration=None,
32-
fallback_hosts=None, fallback_retry_timeout=None, disconnected_retry_timeout=None,
33-
idempotent_rest_publishing=None, loop=None, auto_connect=True,
32+
fallback_hosts=None, fallback_hosts_use_default=None, fallback_retry_timeout=None,
33+
disconnected_retry_timeout=None, idempotent_rest_publishing=None, loop=None, auto_connect=True,
3434
suspended_retry_timeout=None, connectivity_check_url=None,
3535
channel_retry_timeout=Defaults.channel_retry_timeout, add_request_ids=False,
3636
vcdiff_decoder: VCDiffDecoder = None, transport_params=None, **kwargs):
3737

3838
super().__init__(**kwargs)
3939

40+
# REC1b1: endpoint is incompatible with deprecated options
4041
if endpoint is not None:
41-
if environment is not None or rest_host is not None or realtime_host is not None:
42-
raise ValueError('endpoint is incompatible with any of environment, rest_host or realtime_host')
42+
if (environment is not None or rest_host is not None or
43+
realtime_host is not None or fallback_hosts_use_default is not None):
44+
raise ValueError(
45+
'endpoint is incompatible with any of environment, rest_host, '
46+
'realtime_host or fallback_hosts_use_default')
4347

4448
# TODO check these defaults
4549
if fallback_retry_timeout is None:
@@ -65,21 +69,34 @@ def __init__(self, client_id=None, log_level=0, tls=True, rest_host=None, realti
6569
if environment is not None and realtime_host is not None:
6670
raise ValueError('specify realtime_host or environment, not both')
6771

72+
# REC2a1: fallback_hosts is incompatible with fallback_hosts_use_default
73+
if fallback_hosts is not None and fallback_hosts_use_default is not None:
74+
raise ValueError('fallback_hosts is incompatible with fallback_hosts_use_default')
75+
6876
if idempotent_rest_publishing is None:
6977
from ably import api_version
7078
idempotent_rest_publishing = api_version >= '1.2'
7179

7280
if environment is not None and endpoint is None:
81+
log.warning("environment client option is deprecated, please use endpoint instead")
7382
endpoint = environment
7483

84+
# REC1d: restHost or realtimeHost option
85+
# REC1d1: restHost takes precedence over realtimeHost
86+
if rest_host is not None and endpoint is None:
87+
log.warning("rest_host client option is deprecated, please use endpoint instead")
88+
endpoint = rest_host
89+
elif realtime_host is not None and endpoint is None:
90+
# REC1d2: realtimeHost if restHost not specified
91+
log.warning("realtime_host client option is deprecated, please use endpoint instead")
92+
endpoint = realtime_host
93+
7594
if endpoint is None:
7695
endpoint = Defaults.endpoint
7796

7897
self.__client_id = client_id
7998
self.__log_level = log_level
8099
self.__tls = tls
81-
self.__rest_host = rest_host
82-
self.__realtime_host = realtime_host
83100
self.__port = port
84101
self.__tls_port = tls_port
85102
self.__use_binary_protocol = use_binary_protocol
@@ -91,7 +108,10 @@ def __init__(self, client_id=None, log_level=0, tls=True, rest_host=None, realti
91108
self.__realtime_request_timeout = realtime_request_timeout
92109
self.__http_max_retry_count = http_max_retry_count
93110
self.__http_max_retry_duration = http_max_retry_duration
111+
# Field for internal use only
112+
self.__fallback_host = None
94113
self.__fallback_hosts = fallback_hosts
114+
self.__fallback_hosts_use_default = fallback_hosts_use_default
95115
self.__fallback_retry_timeout = fallback_retry_timeout
96116
self.__disconnected_retry_timeout = disconnected_retry_timeout
97117
self.__channel_retry_timeout = channel_retry_timeout
@@ -101,13 +121,10 @@ def __init__(self, client_id=None, log_level=0, tls=True, rest_host=None, realti
101121
self.__connection_state_ttl = connection_state_ttl
102122
self.__suspended_retry_timeout = suspended_retry_timeout
103123
self.__connectivity_check_url = connectivity_check_url
104-
self.__fallback_realtime_host = None
105124
self.__add_request_ids = add_request_ids
106125
self.__vcdiff_decoder = vcdiff_decoder
107126
self.__transport_params = transport_params or {}
108-
109-
self.__rest_hosts = self.__get_rest_hosts()
110-
self.__realtime_hosts = self.__get_realtime_hosts()
127+
self.__hosts = self.__get_hosts()
111128

112129
@property
113130
def client_id(self):
@@ -133,23 +150,6 @@ def tls(self):
133150
def tls(self, value):
134151
self.__tls = value
135152

136-
@property
137-
def rest_host(self):
138-
return self.__rest_host
139-
140-
@rest_host.setter
141-
def rest_host(self, value):
142-
self.__rest_host = value
143-
144-
# RTC1d
145-
@property
146-
def realtime_host(self):
147-
return self.__realtime_host
148-
149-
@realtime_host.setter
150-
def realtime_host(self, value):
151-
self.__realtime_host = value
152-
153153
@property
154154
def port(self):
155155
return self.__port
@@ -276,12 +276,18 @@ def connectivity_check_url(self):
276276
return self.__connectivity_check_url
277277

278278
@property
279-
def fallback_realtime_host(self):
280-
return self.__fallback_realtime_host
279+
def fallback_host(self):
280+
"""
281+
For internal use only, can be deleted in future
282+
"""
283+
return self.__fallback_host
281284

282-
@fallback_realtime_host.setter
283-
def fallback_realtime_host(self, value):
284-
self.__fallback_realtime_host = value
285+
@fallback_host.setter
286+
def fallback_host(self, value):
287+
"""
288+
For internal use only, can be deleted in future
289+
"""
290+
self.__fallback_host = value
285291

286292
@property
287293
def add_request_ids(self):
@@ -295,29 +301,20 @@ def vcdiff_decoder(self):
295301
def transport_params(self):
296302
return self.__transport_params
297303

298-
def __get_rest_hosts(self):
304+
def __get_hosts(self):
299305
"""
300306
Return the list of hosts as they should be tried. First comes the main
301307
host. Then the fallback hosts in random order.
302308
The returned list will have a length of up to http_max_retry_count.
303309
"""
304-
# Defaults
305-
host = self.rest_host
306-
if host is None:
307-
host = Defaults.get_hostname(self.endpoint)
310+
host = Defaults.get_hostname(self.endpoint)
311+
# REC2: Determine fallback hosts
312+
fallback_hosts = self.get_fallback_hosts()
308313

309314
http_max_retry_count = self.http_max_retry_count
310315
if http_max_retry_count is None:
311316
http_max_retry_count = Defaults.http_max_retry_count
312317

313-
# Fallback hosts
314-
fallback_hosts = self.fallback_hosts
315-
if fallback_hosts is None:
316-
if self.rest_host is not None:
317-
fallback_hosts = []
318-
else:
319-
fallback_hosts = Defaults.get_fallback_hosts(self.endpoint)
320-
321318
# Shuffle
322319
fallback_hosts = list(fallback_hosts)
323320
random.shuffle(fallback_hosts)
@@ -328,28 +325,27 @@ def __get_rest_hosts(self):
328325
hosts = hosts[:http_max_retry_count]
329326
return hosts
330327

331-
def __get_realtime_hosts(self):
332-
if self.realtime_host is not None:
333-
host = self.realtime_host
334-
return [host]
335-
336-
host = Defaults.get_hostname(self.endpoint)
337-
return [host] + self.__fallback_hosts
338-
339-
def get_rest_hosts(self):
340-
return self.__rest_hosts
328+
def get_hosts(self):
329+
return self.__hosts
341330

342-
def get_rest_host(self):
343-
return self.__rest_hosts[0]
331+
def get_host(self):
332+
return self.__hosts[0]
344333

345-
def get_realtime_hosts(self):
346-
return self.__realtime_hosts
334+
# REC2: Various client options collectively determine a set of fallback domains
335+
def get_fallback_hosts(self):
336+
# REC2a: If the fallbackHosts client option is specified
337+
if self.__fallback_hosts is not None:
338+
# REC2a2: the set of fallback domains is given by the value of the fallbackHosts option
339+
return self.__fallback_hosts
347340

348-
def get_realtime_host(self):
349-
return self.__realtime_hosts[0]
341+
# REC2b: Otherwise, if the deprecated fallbackHostsUseDefault option is specified
342+
if self.__fallback_hosts_use_default is not None and self.__fallback_hosts_use_default:
343+
# REC2b: then the set of fallback domains is the default set defined in (REC2c1)
344+
return Defaults.get_fallback_hosts("main")
350345

351-
def get_fallback_rest_hosts(self):
352-
return self.__rest_hosts[1:]
346+
# REC2c: Otherwise, the set of fallback domains is defined implicitly by the options
347+
# used to define the primary domain as specified in (REC1)
348+
return Defaults.get_fallback_hosts(self.endpoint)
353349

354350
def get_fallback_realtime_hosts(self):
355-
return self.__realtime_hosts[1:]
351+
return self.get_fallback_hosts()

test/ably/realtime/realtimeconnection_test.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ async def test_connectivity_check_bad_status(self):
187187
assert ably.connection.connection_manager.check_connection() is False
188188

189189
async def test_unroutable_host(self):
190-
ably = await TestApp.get_ably_realtime(realtime_host="10.255.255.1", realtime_request_timeout=3000)
190+
ably = await TestApp.get_ably_realtime(endpoint="10.255.255.1", realtime_request_timeout=3000)
191191
state_change = await ably.connection.once_async()
192192
assert state_change.reason
193193
assert state_change.reason.code == 50003
@@ -197,7 +197,7 @@ async def test_unroutable_host(self):
197197
await ably.close()
198198

199199
async def test_invalid_host(self):
200-
ably = await TestApp.get_ably_realtime(realtime_host="iamnotahost")
200+
ably = await TestApp.get_ably_realtime(endpoint="iamnotahost")
201201
state_change = await ably.connection.once_async()
202202
assert state_change.reason
203203
assert state_change.reason.code == 40000
@@ -299,8 +299,8 @@ async def test_fallback_host(self):
299299

300300
await asyncio.wait_for(ably.connection.once_async(ConnectionState.CONNECTED), timeout=5)
301301

302-
assert ably.connection.connection_manager.transport.host != self.test_vars["realtime_host"]
303-
assert ably.options.fallback_realtime_host != self.test_vars["realtime_host"]
302+
assert ably.connection.connection_manager.transport.host != self.test_vars["endpoint"]
303+
assert ably.options.fallback_host != self.test_vars["endpoint"]
304304
await ably.close()
305305

306306
async def test_fallback_host_no_connection(self):
@@ -325,7 +325,7 @@ def check_connection():
325325

326326
await ably.connection.once_async(ConnectionState.DISCONNECTED)
327327

328-
assert ably.options.fallback_realtime_host is None
328+
assert ably.options.fallback_host is None
329329
await ably.close()
330330

331331
async def test_fallback_host_disconnected_protocol_msg(self):
@@ -344,8 +344,8 @@ async def test_fallback_host_disconnected_protocol_msg(self):
344344

345345
await asyncio.wait_for(ably.connection.once_async(ConnectionState.CONNECTED), timeout=5)
346346

347-
assert ably.connection.connection_manager.transport.host != self.test_vars["realtime_host"]
348-
assert ably.options.fallback_realtime_host != self.test_vars["realtime_host"]
347+
assert ably.connection.connection_manager.transport.host != self.test_vars["endpoint"]
348+
assert ably.options.fallback_host != self.test_vars["endpoint"]
349349
await ably.close()
350350

351351
# RTN2d

test/ably/rest/restauth_test.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -486,7 +486,7 @@ class TestRenewToken(BaseAsyncTestCase):
486486
async def setup(self):
487487
self.test_vars = await TestApp.get_test_vars()
488488
self.host = 'fake-host.ably.io'
489-
self.ably = await TestApp.get_ably_rest(use_binary_protocol=False, rest_host=self.host)
489+
self.ably = await TestApp.get_ably_rest(use_binary_protocol=False, endpoint=self.host)
490490
# with headers
491491
self.publish_attempts = 0
492492
self.channel = uuid.uuid4().hex
@@ -549,7 +549,7 @@ async def test_when_not_renewable(self):
549549

550550
self.ably = await TestApp.get_ably_rest(
551551
key=None,
552-
rest_host=self.host,
552+
endpoint=self.host,
553553
token='token ID cannot be used to create a new token',
554554
use_binary_protocol=False)
555555
await self.ably.channels[self.channel].publish('evt', 'msg')
@@ -568,7 +568,7 @@ async def test_when_not_renewable_with_token_details(self):
568568
token_details = TokenDetails(token='a_dummy_token')
569569
self.ably = await TestApp.get_ably_rest(
570570
key=None,
571-
rest_host=self.host,
571+
endpoint=self.host,
572572
token_details=token_details,
573573
use_binary_protocol=False)
574574
await self.ably.channels[self.channel].publish('evt', 'msg')
@@ -638,7 +638,7 @@ def cb_publish(request):
638638

639639
# RSA4b1
640640
async def test_query_time_false(self):
641-
ably = await TestApp.get_ably_rest(rest_host=self.host)
641+
ably = await TestApp.get_ably_rest(endpoint=self.host)
642642
await ably.auth.authorize()
643643
self.publish_fail = True
644644
await ably.channels[self.channel].publish('evt', 'msg')
@@ -647,7 +647,7 @@ async def test_query_time_false(self):
647647

648648
# RSA4b1
649649
async def test_query_time_true(self):
650-
ably = await TestApp.get_ably_rest(query_time=True, rest_host=self.host)
650+
ably = await TestApp.get_ably_rest(query_time=True, endpoint=self.host)
651651
await ably.auth.authorize()
652652
self.publish_fail = False
653653
await ably.channels[self.channel].publish('evt', 'msg')

0 commit comments

Comments
 (0)