|
|
@ -290,6 +290,7 @@ class Network(Logger): |
|
|
|
self.nodes_retry_time = time.time() |
|
|
|
# the main server we are currently communicating with |
|
|
|
self.interface = None # type: Interface |
|
|
|
self.default_server_changed_event = asyncio.Event() |
|
|
|
# set of servers we have an ongoing connection with |
|
|
|
self.interfaces = {} # type: Dict[str, Interface] |
|
|
|
self.auto_connect = self.config.get('auto_connect', True) |
|
|
@ -730,10 +731,13 @@ class Network(Logger): |
|
|
|
i = self.interfaces[server] |
|
|
|
if old_interface != i: |
|
|
|
self.logger.info(f"switching to {server}") |
|
|
|
assert i.ready.done(), "interface we are switching to is not ready yet" |
|
|
|
blockchain_updated = i.blockchain != self.blockchain() |
|
|
|
self.interface = i |
|
|
|
await i.group.spawn(self._request_server_info(i)) |
|
|
|
self.trigger_callback('default_server_changed') |
|
|
|
self.default_server_changed_event.set() |
|
|
|
self.default_server_changed_event.clear() |
|
|
|
self._set_status('connected') |
|
|
|
self.trigger_callback('network_updated') |
|
|
|
if blockchain_updated: self.trigger_callback('blockchain_updated') |
|
|
@ -840,30 +844,27 @@ class Network(Logger): |
|
|
|
b.update_size() |
|
|
|
|
|
|
|
def best_effort_reliable(func): |
|
|
|
async def make_reliable_wrapper(self, *args, **kwargs): |
|
|
|
async def make_reliable_wrapper(self: 'Network', *args, **kwargs): |
|
|
|
for i in range(10): |
|
|
|
iface = self.interface |
|
|
|
# retry until there is a main interface |
|
|
|
if not iface: |
|
|
|
await asyncio.sleep(0.1) |
|
|
|
continue # try again |
|
|
|
# wait for it to be usable |
|
|
|
iface_ready = iface.ready |
|
|
|
iface_disconnected = iface.got_disconnected |
|
|
|
await asyncio.wait([iface_ready, iface_disconnected], return_when=asyncio.FIRST_COMPLETED) |
|
|
|
if not iface_ready.done() or iface_ready.cancelled(): |
|
|
|
await asyncio.sleep(0.1) |
|
|
|
try: |
|
|
|
await asyncio.wait_for(self.default_server_changed_event.wait(), 1) |
|
|
|
except asyncio.TimeoutError: |
|
|
|
pass |
|
|
|
continue # try again |
|
|
|
assert iface.ready.done(), "interface not ready yet" |
|
|
|
# try actual request |
|
|
|
success_fut = asyncio.ensure_future(func(self, *args, **kwargs)) |
|
|
|
await asyncio.wait([success_fut, iface_disconnected], return_when=asyncio.FIRST_COMPLETED) |
|
|
|
await asyncio.wait([success_fut, iface.got_disconnected], return_when=asyncio.FIRST_COMPLETED) |
|
|
|
if success_fut.done() and not success_fut.cancelled(): |
|
|
|
if success_fut.exception(): |
|
|
|
try: |
|
|
|
raise success_fut.exception() |
|
|
|
except RequestTimedOut: |
|
|
|
await iface.close() |
|
|
|
await iface_disconnected |
|
|
|
await iface.got_disconnected |
|
|
|
continue # try again |
|
|
|
return success_fut.result() |
|
|
|
# otherwise; try again |
|
|
|