Skip to content

Commit be4ddbd

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

File tree

12 files changed

+257
-164
lines changed

12 files changed

+257
-164
lines changed

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
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: 47 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import logging
2-
import random
32
from abc import ABC, abstractmethod
43

54
from ably.transport.defaults import Defaults
@@ -29,17 +28,21 @@ def __init__(self, client_id=None, log_level=0, tls=True, rest_host=None, realti
2928
tls_port=0, use_binary_protocol=True, queue_messages=True, recover=False, endpoint=None,
3029
environment=None, http_open_timeout=None, http_request_timeout=None,
3130
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,
31+
fallback_hosts=None, fallback_hosts_use_default=None, fallback_retry_timeout=None,
32+
disconnected_retry_timeout=None, idempotent_rest_publishing=None, loop=None, auto_connect=True,
3433
suspended_retry_timeout=None, connectivity_check_url=None,
3534
channel_retry_timeout=Defaults.channel_retry_timeout, add_request_ids=False,
3635
vcdiff_decoder: VCDiffDecoder = None, transport_params=None, **kwargs):
3736

3837
super().__init__(**kwargs)
3938

39+
# REC1b1: endpoint is incompatible with deprecated options
4040
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')
41+
if (environment is not None or rest_host is not None or
42+
realtime_host is not None or fallback_hosts_use_default is not None):
43+
raise ValueError(
44+
'endpoint is incompatible with any of environment, rest_host, '
45+
'realtime_host or fallback_hosts_use_default')
4346

4447
# TODO check these defaults
4548
if fallback_retry_timeout is None:
@@ -65,21 +68,34 @@ def __init__(self, client_id=None, log_level=0, tls=True, rest_host=None, realti
6568
if environment is not None and realtime_host is not None:
6669
raise ValueError('specify realtime_host or environment, not both')
6770

71+
# REC2a1: fallback_hosts is incompatible with fallback_hosts_use_default
72+
if fallback_hosts is not None and fallback_hosts_use_default is not None:
73+
raise ValueError('fallback_hosts is incompatible with fallback_hosts_use_default')
74+
6875
if idempotent_rest_publishing is None:
6976
from ably import api_version
7077
idempotent_rest_publishing = api_version >= '1.2'
7178

7279
if environment is not None and endpoint is None:
80+
log.warning("environment client option is deprecated, please use endpoint instead")
7381
endpoint = environment
7482

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

7896
self.__client_id = client_id
7997
self.__log_level = log_level
8098
self.__tls = tls
81-
self.__rest_host = rest_host
82-
self.__realtime_host = realtime_host
8399
self.__port = port
84100
self.__tls_port = tls_port
85101
self.__use_binary_protocol = use_binary_protocol
@@ -92,6 +108,7 @@ def __init__(self, client_id=None, log_level=0, tls=True, rest_host=None, realti
92108
self.__http_max_retry_count = http_max_retry_count
93109
self.__http_max_retry_duration = http_max_retry_duration
94110
self.__fallback_hosts = fallback_hosts
111+
self.__fallback_hosts_use_default = fallback_hosts_use_default
95112
self.__fallback_retry_timeout = fallback_retry_timeout
96113
self.__disconnected_retry_timeout = disconnected_retry_timeout
97114
self.__channel_retry_timeout = channel_retry_timeout
@@ -101,13 +118,10 @@ def __init__(self, client_id=None, log_level=0, tls=True, rest_host=None, realti
101118
self.__connection_state_ttl = connection_state_ttl
102119
self.__suspended_retry_timeout = suspended_retry_timeout
103120
self.__connectivity_check_url = connectivity_check_url
104-
self.__fallback_realtime_host = None
105121
self.__add_request_ids = add_request_ids
106122
self.__vcdiff_decoder = vcdiff_decoder
107123
self.__transport_params = transport_params or {}
108-
109-
self.__rest_hosts = self.__get_rest_hosts()
110-
self.__realtime_hosts = self.__get_realtime_hosts()
124+
self.__hosts = self.__get_hosts()
111125

112126
@property
113127
def client_id(self):
@@ -133,23 +147,6 @@ def tls(self):
133147
def tls(self, value):
134148
self.__tls = value
135149

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-
153150
@property
154151
def port(self):
155152
return self.__port
@@ -275,14 +272,6 @@ def suspended_retry_timeout(self):
275272
def connectivity_check_url(self):
276273
return self.__connectivity_check_url
277274

278-
@property
279-
def fallback_realtime_host(self):
280-
return self.__fallback_realtime_host
281-
282-
@fallback_realtime_host.setter
283-
def fallback_realtime_host(self, value):
284-
self.__fallback_realtime_host = value
285-
286275
@property
287276
def add_request_ids(self):
288277
return self.__add_request_ids
@@ -295,61 +284,33 @@ def vcdiff_decoder(self):
295284
def transport_params(self):
296285
return self.__transport_params
297286

298-
def __get_rest_hosts(self):
299-
"""
300-
Return the list of hosts as they should be tried. First comes the main
301-
host. Then the fallback hosts in random order.
302-
The returned list will have a length of up to http_max_retry_count.
303-
"""
304-
# Defaults
305-
host = self.rest_host
306-
if host is None:
307-
host = Defaults.get_hostname(self.endpoint)
308-
309-
http_max_retry_count = self.http_max_retry_count
310-
if http_max_retry_count is None:
311-
http_max_retry_count = Defaults.http_max_retry_count
312-
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-
321-
# Shuffle
322-
fallback_hosts = list(fallback_hosts)
323-
random.shuffle(fallback_hosts)
324-
self.__fallback_hosts = fallback_hosts
325-
326-
# First main host
327-
hosts = [host] + fallback_hosts
328-
hosts = hosts[:http_max_retry_count]
329-
return hosts
330-
331-
def __get_realtime_hosts(self):
332-
if self.realtime_host is not None:
333-
host = self.realtime_host
334-
return [host]
335-
287+
def __get_hosts(self):
336288
host = Defaults.get_hostname(self.endpoint)
337-
return [host] + self.__fallback_hosts
289+
# REC2: Determine fallback hosts
290+
fallback_hosts = self.get_fallback_hosts()
291+
return [host] + fallback_hosts
338292

339-
def get_rest_hosts(self):
340-
return self.__rest_hosts
293+
def get_hosts(self):
294+
return self.__hosts
341295

342-
def get_rest_host(self):
343-
return self.__rest_hosts[0]
296+
def get_host(self):
297+
return self.__hosts[0]
344298

345-
def get_realtime_hosts(self):
346-
return self.__realtime_hosts
299+
# REC2: Various client options collectively determine a set of fallback domains
300+
def get_fallback_hosts(self):
301+
# REC2a: If the fallbackHosts client option is specified
302+
if self.__fallback_hosts is not None:
303+
# REC2a2: the set of fallback domains is given by the value of the fallbackHosts option
304+
return self.__fallback_hosts
347305

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

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

354315
def get_fallback_realtime_hosts(self):
355-
return self.__realtime_hosts[1:]
316+
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)