async def wait_until(model, *conditions, log_time=5, timeout=None, wait_period=0.5, loop=None): """Return only after all conditions are true. """ log_count = 0 def _disconnected(): return not (model.is_connected() and model.connection().is_open) async def _block(log_count): while not _disconnected() and not all(c() for c in conditions): await asyncio.sleep(wait_period, loop=loop) log_count += 0.5 if log_count % log_time == 0: log.info('[RUNNING] Machines: {} {} Apps: {}'.format( len(model.machines), ', '.join(model.machines.keys()), len(model.applications))) await asyncio.wait_for(_block(log_count), timeout, loop=loop) if _disconnected(): raise websockets.ConnectionClosed(1006, 'no reason') log.info('[DONE] Machines: {} Apps: {}'.format(len(model.machines), len(model.applications)))
async def ping(self): try: last_ts = max(self._last_ping_ts, self.last_recv_ts) except TypeError: last_ts = next( (x for x in (self._last_ping_ts, self.last_recv_ts) if x), 0) if self.ping_after is None or time.time() > last_ts + self.ping_after: if self.ping_as_message: message = self.ping_func() self.log2('sending ping: {}'.format(message)) # message will be json encoded await self.send(message, dump=(self.ping_as_message == 'dump'), log=False) else: args = [self.ping_func()] if self.ping_func is not None else [] self.log2( 'sending ping{}'.format(': ' + str(args[0]) if args else '')) # message will be converted into bytes (must be str or bytes) try: await asyncio.wait_for(self.socket.ping(*args), self.ping_timeout) except asyncio.TimeoutError: await self._socket_recv_queue.put( websockets.ConnectionClosed(-3, 'Ping timeout occurred')) finally: self._last_ping_ts = time.time()
async def get_trades(queue): symbol_dict = deepcopy(SUB_MESG_TRADES) async with websockets.connect( 'wss://api.bitfinex.com/ws/2') as websocket_get_trades: await websocket_get_trades.send(json.dumps(symbol_dict)) while True: try: res = await asyncio.wait_for(websocket_get_trades.recv(), timeout=websocket_timeout) except asyncio.TimeoutError: print( '{0} -> In get_trades() Waited {1}s, still to wait {2}s before disconnect' .format(symbol, websocket_timeout, websocket_timeout)) try: pong_waiter = await websocket_get_trades.ping() await asyncio.wait_for(pong_waiter, timeout=websocket_timeout) except asyncio.TimeoutError: print( '{0} -> CONNECTION CLOSED raised exception in get_trades() -> TRYING TO RECONNECT !!!' .format(symbol)) raise websockets.ConnectionClosed( 'ConnectionClosed ---> in get_trades()') Exception break else: await build_trades_bids_asks(res, queue) await asyncio.sleep(asyncio_sleep)
async def test_listen_reconnect(ds: IdexDatastream): class BreakExc(Exception): pass exc = websockets.ConnectionClosed(code=999, reason='some reason') exit_exc = BreakExc('to break the infinite loop') ds._check_connection = CoroutineMock() ds._ws = MagicMock() ds._ws.__aiter__.side_effect = exc ds.init = CoroutineMock() ds.sub_manager.resubscribe = CoroutineMock() ds.sub_manager.resubscribe.side_effect = exit_exc ds._logger.error = Mock() with pytest.raises(BreakExc): async for m in ds.listen(): break ds._check_connection.assert_awaited_once() ds._logger.error.assert_called_once_with(exc) ds.init.assert_awaited_once() ds.sub_manager.resubscribe.assert_awaited_once()
def _verify_recv_timeout(self): if self.connected_url and self.recv_timeout is not None and not self._ignore_recv_ts and \ self.last_recv_ts is not None and time.time() - self.last_recv_ts > self.recv_timeout: self.log('recv timeout occurred. Reconnecting.', 'ERROR') asyncio.ensure_future(self._exit_conn(self.conn)) #To force the current recv to complete itself (if not already done) self._socket_recv_queue.put_nowait(_heartbeat) raise websockets.ConnectionClosed(-2, 'recv timeout occurred')
async def _listen(self): backoff = ExponentialBackoff(base=7) if not self.is_connected and self._last_exc: __log__.error(f'WEBSOCKET | Connection failure:: {self._last_exc}') raise websockets.ConnectionClosed( reason=f'Websocket connection failure:\n\n{self._last_exc}', code=1006) while True: try: data = json.loads(await self._websocket.recv()) __log__.debug(f'WEBSOCKET | Received Payload:: <{data}>') except websockets.ConnectionClosed as e: self._last_exc = e if e.code == 4001: print(f'\nAuthorization Failed for Node:: {self._node}\n', file=sys.stderr) break self._closed = True retry = backoff.delay() __log__.warning( f'WEBSOCKET | Connection closed:: Retrying connection in <{retry}> seconds' ) await self._connect() await asyncio.sleep(retry) continue op = data.get('op', None) if not op: continue if op == 'stats': self._node.stats = Stats(self._node, data) if op == 'event': try: data['player'] = self._node.players[int(data['guildId'])] except KeyError: return await self._send(op='destroy', guildId=str(data['guildId'])) event = self._get_event(data['type'], data) __log__.debug(f'WEBSOCKET | op: event:: {data}') await self._node.on_event(event) elif op == 'playerUpdate': __log__.debug(f'WEBSOCKET | op: playerUpdate:: {data}') try: await self._node.players[int(data['guildId']) ].update_state(data) except KeyError: pass
async def wait_on_signalr_future(): try: await signalr_fut except websockets.ConnectionClosed as e: self.log('signalr socket has crashed') await q.put(e) else: self.log('signalr socket has been closed') await q.put( websockets.ConnectionClosed(-1, 'signalr ws closed'))
def test_socket_closed(self): server = Mock() server.game.max_nb_ticks = 500 socket = AsyncMock() socket.recv.side_effect = websockets.ConnectionClosed(0, "") gs, player = get_player(server, socket) player.logger = Mock() next_move = asyncio.run(player.request_next_move(123, gs)) socket.send.assert_called_once() self.assertEqual((None, Action.FORWARD), next_move) player.logger.warning.assert_called_once() player.server.game.unregister_player.assert_called_once()
def test_send_tick_socket_closed(self): server = Mock() server.game.max_nb_ticks = 500 socket = AsyncMock() socket.send.side_effect = websockets.ConnectionClosed(0, "") viewer = SocketViewer(server, socket) viewer.logger = Mock() gs = GameState(GameMap(3)) asyncio.run(viewer.send_tick(123, gs)) viewer.logger.warning.assert_called_once() server.game.unregister_viewer.assert_called_once()
def test_send_winner_socket_closed(self): server = Mock() socket = AsyncMock() socket.send.side_effect = websockets.ConnectionClosed(0, "") viewer = SocketViewer(server, socket) viewer.logger = Mock() gs = GameState(GameMap(3)) ps = PlayerState(1, "p1", gs.game_map, Position(1, 1)) asyncio.run(viewer.send_winner(123, ps)) viewer.logger.warning.assert_called_once() server.game.unregister_viewer.assert_called_once()
def run(self): """ Handle incoming level 3 data on a separate thread :return: """ while True: msg = self.queue.get() if self.book.new_tick(msg) is False: self.retry_counter += 1 self.book.clear_book() print('\n[Bitfinex - %s] ...going to try and reload the order book\n' % self.sym) raise websockets.ConnectionClosed(1006, 'BitfinexClient: no explanation')
async def get_ticker(symbol): SUB_MESG_TICKER = { 'event': 'subscribe', 'channel': 'ticker', 'symbol': symbol['symbol'] } async with websockets.connect( 'wss://api.bitfinex.com/ws/2') as websocket_get_ticker: await websocket_get_ticker.send(json.dumps(SUB_MESG_TICKER)) while True: try: res = await asyncio.wait_for(websocket_get_ticker.recv(), timeout=websocket_timeout) except asyncio.TimeoutError: print( '{0} -> in get_ticker() Waited {1}s, still to wait {2}s before disconnect' .format(symbol['symbol'], websocket_timeout, websocket_timeout)) # No data in websocket_timeout seconds, check the connection. try: pong_waiter = await websocket_get_ticker.ping() await asyncio.wait_for(pong_waiter, timeout=websocket_timeout) except asyncio.TimeoutError: # No response to ping in X seconds, disconnect. print( '{0} -> CONNECTION CLOSED raised exception in get_ticker() -> TRYING TO RECONNECT !!!' .format(symbol['symbol'])) raise websockets.ConnectionClosed( 'ConnectionClosed ---> in get_ticker()') break else: ticker = json.loads(res) if ticker: if isinstance(ticker, list): if isinstance(ticker[1], list): symbol['ticker_bid'] = ticker[1][0] symbol['ticker_ask'] = ticker[1][2] await asyncio.sleep(loop_timer_ticker)
async def _exit_conn(self, conn=None): conn = conn if conn is not None else self.conn if conn is None: pass elif self.signalr: safeTry(conn.close) #self.hub = None elif self.socketio: await safeAsyncTry(conn.disconnect) # this must be done here as socketio has not callback on user initiated disconnect await self._socket_recv_queue.put( websockets.ConnectionClosed(-1, 'socketio ws closed')) else: if hasattr(conn, 'ws_client'): try: await conn.__aexit__(*sys.exc_info()) except Exception as e: logger.exception(e)
async def listen(self): await self._check_connection() asyncio.create_task(self._ping_ws_task()) while True: try: # 1000 and 1001 exit codes reconnect support if self._ws.closed: raise websockets.ConnectionClosed(self._ws.close_code, 'Connection is closed') async for msg in self._ws: self._logger.debug('New message: %s', msg) message = self._process_message(msg) if message: yield message except (websockets.ConnectionClosed, IdexResponseSidError) as e: self._logger.error(e) self._logger.warning('Reconnecting...') await self.init() await self.sub_manager.resubscribe()
def run(self) -> None: """ Handle incoming level 3 data on a separate thread or process. Returns ------- """ super(BitfinexClient, self).run() while True: msg = self.queue.get() if self.book.new_tick(msg) is False: self.retry_counter += 1 self.book.clear_book() LOGGER.info( '\n[%s - %s] ...going to try and reload the order book\n' % (self.exchange.upper(), self.sym)) raise websockets.ConnectionClosed( 10001, '%s: no explanation' % self.exchange.upper())
async def disconnect(): self.log('socketio connection has crashed') await q.put(websockets.ConnectionClosed(-1, 'socketio ws crashed'))
async def connect_error(*args): self.log('socketio encountered connect error') await q.put( websockets.ConnectionClosed(-1, 'socketio connect error'))
def raise_closed(): raise websockets.ConnectionClosed(4000, "")
async def reconn_handler(self, _packet): """Handle OP Reconnect packets.""" await self.ws.close() await self.reconnect( websockets.ConnectionClosed(code=Disconnect.UNKNOWN, reason='forced reconnect'))