def test_continuation_with_close_empty(out, parser): parser.parse_frame = mock.Mock() parser.parse_frame.return_value = [ (0, WSMsgType.TEXT, b'line1'), (0, WSMsgType.CLOSE, b''), (1, WSMsgType.CONTINUATION, b'line2'), ] parser.feed_data(b'') res = out._buffer[0] assert res, (WSMessage(WSMsgType.CLOSE, 0, ''), 0) res = out._buffer[1] assert res == (WSMessage(WSMsgType.TEXT, 'line1line2', ''), 10)
async def test_cloud_messages_invalid_format(hass_platform_cloud_connection, config, aioclient_mock): hass = hass_platform_cloud_connection requests = ['foo'] session = MockSession(aioclient_mock, msg=[ WSMessage(type=WSMsgType.TEXT, extra={}, data=r) for r in requests ]) manager = CloudManager(hass, config, session) with patch.object(manager, '_try_reconnect', return_value=None) as mock_reconnect: await manager.connect() mock_reconnect.assert_called_once() requests = [json.dumps({'request_id': 'req', '_action': 'foo'})] session = MockSession(aioclient_mock, msg=[ WSMessage(type=WSMsgType.TEXT, extra={}, data=r) for r in requests ]) manager = CloudManager(hass, config, session) mock_reconnect.reset_mock() with patch.object(manager, '_try_reconnect', return_value=None) as mock_reconnect: await manager.connect() mock_reconnect.assert_called_once() requests = [ json.dumps({ 'request_id': 'req', 'action': 'foo', 'message': 'not_{_json' }) ] session = MockSession(aioclient_mock, msg=[ WSMessage(type=WSMsgType.TEXT, extra={}, data=r) for r in requests ]) manager = CloudManager(hass, config, session) mock_reconnect.reset_mock() with patch.object(manager, '_try_reconnect', return_value=None) as mock_reconnect: await manager.connect() mock_reconnect.assert_called_once()
async def handle_message(self, message: aiohttp.WSMessage): if message.type == aiohttp.WSMsgType.TEXT: data = message.json() self.logger.debug(f"handling:{repr(hide_secret(data))}") if "method" in data: await self.handle_method_message(data) else: if "id" in data: if "error" in data: if self.on_response_error: await self.on_response_error() else: self.logger.error(f"Receive error {repr(data)}") else: request_id = data["id"] request = self.requests.get(request_id) if request: await self.handle_response(request=request, response=data) del self.requests[request_id] else: if self.on_handle_response: await self.on_handle_response(data) else: self.logger.warning( f"Unknown id:{request_id}, the on_handle_response event must be defined." f" Unhandled message {data}") else: self.logger.warning(f"Unsupported message {message.data}") else: self.logger.warning(f"Unknown type of message {repr(message)}")
def test_close_frame_info(out, parser): parser.parse_frame = mock.Mock() parser.parse_frame.return_value = [(1, WSMsgType.CLOSE, b'0112345')] parser.feed_data(b'') res = out._buffer[0] assert res == (WSMessage(WSMsgType.CLOSE, 12337, '12345'), 0)
def _build_resp(msg: aiohttp.WSMessage) -> WSResponse: if msg.type == aiohttp.WSMsgType.BINARY: data = msg.data else: data = msg.json() response = WSResponse(data) return response
def test_listen_for_user_stream_sends_ping_message_before_ping_interval_finishes( self, ws_connect_mock): successful_login_response = {"event": "login", "code": "0", "msg": ""} ws_connect_mock.return_value = self.mocking_assistant.create_websocket_mock( ) ws_connect_mock.return_value.receive.side_effect = [ WSMessage(type=WSMsgType.TEXT, data=json.dumps(successful_login_response), extra=None), asyncio.TimeoutError("Test timeiout"), asyncio.CancelledError ] msg_queue = asyncio.Queue() self.listening_task = self.ev_loop.create_task( self.data_source.listen_for_user_stream(msg_queue)) try: self.async_run_with_timeout(self.listening_task) except asyncio.CancelledError: pass sent_messages = self.mocking_assistant.text_messages_sent_through_websocket( websocket_mock=ws_connect_mock.return_value) expected_ping_message = "ping" self.assertEqual(expected_ping_message, sent_messages[0])
async def on_message(self, route: str, ws: web.WebSocketResponse, ws_msg_from_client: aiohttp.WSMessage): if ws_msg_from_client.type == WSMsgType.TEXT: msg = ws_msg_from_client.json() self.parent.tk(self.parent.detail_var.set, msg.get("detail")) # Schedule on gui thread elif ws_msg_from_client.type == WSMsgType.CLOSE: # Two ways two detect a closing txt = self.parent.detail_var.get() + "\nDisconnected." self.parent.tk(self.parent.detail_var.set, txt)
async def on_message(self, message: aiohttp.WSMessage): # deserialize message data = message.json(loads=json.loads) serial = data.get('serial', -1) msg_type = data.get('type', 'call') assert serial >= 0 log.debug("Acquiring lock for %s serial %s", self, serial) async with self._locks[serial]: try: if msg_type == 'call': args, kwargs = self._prepare_args( data.get('arguments', None)) callback = data.get('call', None) if callback is None: raise ValueError( 'Require argument "call" does\'t exist.') callee = self.resolver(callback) calee_is_route = hasattr( callee, '__self__') and isinstance( callee.__self__, WebSocketRoute) if not calee_is_route: a = [self] a.extend(args) args = a result = await self._executor( partial(callee, *args, **kwargs)) self._send(data=result, serial=serial, type='callback') elif msg_type == 'callback': cb = self._futures.pop(serial, None) cb.set_result(data.get('data', None)) elif msg_type == 'error': self._reject(data.get('serial', -1), data.get('data', None)) log.error('Client return error: \n\t{0}'.format( data.get('data', None))) except Exception as e: log.exception(e) self._send(data=self._format_error(e), serial=serial, type='error') finally: def clean_lock(): log.debug("Release and delete lock for %s serial %s", self, serial) if serial in self._locks: self._locks.pop(serial) self._call_later(self._CLEAN_LOCK_TIMEOUT, clean_lock)
async def test_cloud_req_user_devices_query(hass_platform_cloud_connection, config, aioclient_mock): hass = hass_platform_cloud_connection requests = [{ 'request_id': 'req_user_devices_query_1', 'action': '/user/devices/query', 'message': json.dumps({'devices': [{ 'id': 'sensor.outside_temp' }]}) }, { 'request_id': 'req_user_devices_query_2', 'action': '/user/devices/query', 'message': json.dumps({'devices': [{ 'id': 'sensor.not_existed' }]}) }] session = MockSession(aioclient_mock, msg=[ WSMessage(type=WSMsgType.TEXT, extra={}, data=json.dumps(r)) for r in requests ]) # noinspection PyTypeChecker manager = CloudManager(hass, config, session) await manager.connect() assert json.loads(session.ws.send_queue[0]) == { 'request_id': 'req_user_devices_query_1', 'payload': { 'devices': [{ 'id': 'sensor.outside_temp', 'capabilities': [], 'properties': [{ 'type': 'devices.properties.float', 'state': { 'instance': 'temperature', 'value': 15.6 } }] }] } } assert json.loads(session.ws.send_queue[1]) == { 'request_id': 'req_user_devices_query_2', 'payload': { 'devices': [{ 'id': 'sensor.not_existed', 'error_code': 'DEVICE_UNREACHABLE' }] } }
def test_continuation(out, parser): parser.parse_frame = mock.Mock() parser.parse_frame.return_value = [(0, WSMsgType.TEXT, b'line1'), (1, WSMsgType.CONTINUATION, b'line2')] parser._feed_data(b'') res = out._buffer[0] assert res == (WSMessage(WSMsgType.TEXT, 'line1line2', ''), 10)
def _build_resp(msg: aiohttp.WSMessage) -> WSResponse: if msg.type == aiohttp.WSMsgType.BINARY: data = msg.data else: try: data = msg.json() except JSONDecodeError: data = msg.data response = WSResponse(data) return response
async def test_ticks_pong(make_transport, make_fut): transp = make_transport() pong = WSMessage(type=WSMsgType.PONG, data=b'', extra='') close = WSMessage(type=WSMsgType.closing, data=b'', extra='') future = Future() future.set_result(pong) future2 = Future() future2.set_result(close) ws = mock.Mock() ws.receive.side_effect = [future, future2] session = transp.session await transp.client(ws, session) assert session._tick.called
async def __handle_text_message( _websocket: ClientWebSocketResponse, msg: WSMessage, event_handler: Callable[[MessageDTO], None]) -> None: _LOG.debug('%s: Server sent "%s"', datetime.now(), msg.data) json_response = msg.json() if 'access_id' not in json_response: message = MessageDTO(**json_response) event_handler(message) elif isinstance(json_response, dict): _LOG.info(f'Got id {json_response.get("access_id")}')
def test_close_frame_info(out, parser): def parse_frame(buf): yield return (1, WSMsgType.CLOSE, b'0112345') with mock.patch('aiohttp._ws_impl.parse_frame') as m_parse_frame: m_parse_frame.side_effect = parse_frame next(parser) parser.send(b'') res = out._buffer[0] assert res == (WSMessage(WSMsgType.CLOSE, 12337, '12345'), 0)
def test_continuation_with_close(out, parser): frames = [ (0, WSMsgType.TEXT, b'line1'), (0, WSMsgType.CLOSE, build_close_frame(1002, b'test', noheader=True)), (1, WSMsgType.CONTINUATION, b'line2'), ] def parse_frame(buf, cont=False): yield return frames.pop(0) with mock.patch('aiohttp._ws_impl.parse_frame') as m_parse_frame: m_parse_frame.side_effect = parse_frame next(parser) parser.send(b'') parser.send(b'') parser.send(b'') res = out._buffer[0] assert res, (WSMessage(WSMsgType.CLOSE, 1002, 'test'), 0) res = out._buffer[1] assert res == (WSMessage(WSMsgType.TEXT, 'line1line2', ''), 10)
def test_continuation_with_ping(out, parser): frames = [ (0, WSMsgType.text, b'line1'), (0, WSMsgType.ping, b''), (1, WSMsgType.continuation, b'line2'), ] def parse_frame(buf, cont=False): yield return frames.pop(0) with mock.patch('aiohttp._ws_impl.parse_frame') as m_parse_frame: m_parse_frame.side_effect = parse_frame next(parser) parser.send(b'') parser.send(b'') parser.send(b'') res = out._buffer[0] assert res == (WSMessage(WSMsgType.ping, b'', ''), 0) res = out._buffer[1] assert res == (WSMessage(WSMsgType.text, 'line1line2', ''), 10)
async def handle_message(self, message: aiohttp.WSMessage): # noinspection PyTypeChecker, PyNoneFunctionAssignment data = message.json(loads=loads) # type: dict log.debug("Got message: %r", data) serial = data.get("id") if serial is None: return await self.handle_event(data) call_item = self._parse_message(data) await self._call_method(call_item)
async def test_get_message_loop(opsdroid): connector = ConnectorTwitch(connector_config, opsdroid=opsdroid) connector.websocket = amock.MagicMock() connector.websocket.__aiter__.return_value = [ WSMessage(WSMsgType.TEXT, "PING", b""), WSMessage(WSMsgType.TEXT, ":[email protected]! JOIN #channel", b""), WSMessage(WSMsgType.CLOSED, "CLOSE", ""), ] connector.websocket.send_str = amock.CoroutineMock() connector.websocket.close = amock.CoroutineMock() connector._handle_message = amock.CoroutineMock() with pytest.raises(ConnectionError): await connector.get_messages_loop() assert connector.is_live assert connector.send_str.called assert connector.websocket.close.called assert connector._handle_message.called
async def test_frames(make_transport, make_handler): result = [] handler = make_handler(result) transp = make_transport(handler=handler) empty_message = Future() empty_message.set_result(WSMessage(type=WSMsgType.text, data="", extra="")) empty_frame = Future() empty_frame.set_result(WSMessage(type=WSMsgType.text, data="[]", extra="")) single_msg_frame = Future() single_msg_frame.set_result( WSMessage(type=WSMsgType.text, data='"single_msg"', extra="")) multi_msg_frame = Future() multi_msg_frame.set_result( WSMessage(type=WSMsgType.text, data='["msg1", "msg2"]', extra="")) close_frame = Future() close_frame.set_result(WSMessage(type=WSMsgType.closed, data="", extra="")) ws = mock.Mock() ws.receive.side_effect = [ empty_message, empty_frame, single_msg_frame, multi_msg_frame, close_frame, ] session = transp.session await transp.client(ws, session) assert result[0][0].data == "single_msg" assert result[1][0].data == "msg1" assert result[2][0].data == "msg2"
async def on_message(self, route: str, ws: web.WebSocketResponse, ws_msg_from_client: aiohttp.WSMessage): if ws_msg_from_client.type == WSMsgType.TEXT: try: msg = ws_msg_from_client.json() except Exception as ex: print("Error trying to make json", ex, ws_msg_from_client) else: if OAUTH2_TOKEN_KEY in msg: token = msg.get(OAUTH2_TOKEN_KEY) await self.queue.put(token) else: err = msg.get("error") await self.queue.put(PushbulletError(err)) await self.queue.put(ws)
def test_continuation(out, parser): cur = 0 def parse_frame(buf, cont=False): nonlocal cur yield if cur == 0: cur = 1 return (0, WSMsgType.TEXT, b'line1') else: return (1, WSMsgType.CONTINUATION, b'line2') with mock.patch('aiohttp._ws_impl.parse_frame') as m_parse_frame: m_parse_frame.side_effect = parse_frame next(parser) parser.send(b'') parser.send(b'') res = out._buffer[0] assert res == (WSMessage(WSMsgType.TEXT, 'line1line2', ''), 10)
def process_ws_response(response: aiohttp.WSMessage) -> Union[dict, list]: """A utility function to process the response from the Synse Server WebSocket API. Args: response: The WebSocket response message. Returns: The JSON response edata marshaled into its Python type (e.g., dict or list). Raises: errors.SynseError: An instance of a SynseError, wrapping any other error which may have occurred. """ if response.type == aiohttp.WSMsgType.text: msg = response.json() if msg['event'] == 'response/error': log.debug(f'error response from Synse Server: {msg}') status = msg['data']['http_code'] desc = msg['data'].get('description', '') ctx = msg['data'].get('context', 'no context available') err = f'{desc} [{status}]: {ctx}' if status == 404: raise errors.NotFound(err) elif status == 400: raise errors.InvalidInput(err) else: raise errors.SynseError(err) else: return msg elif response.type == aiohttp.WSMsgType.closed: raise errors.SynseError('WebSocket connection closed: {}'.format( response.extra)) elif response.type == aiohttp.WSMsgType.error: raise errors.SynseError('WebSocket error: {} : {}'.format( response.data, response.extra)) else: raise errors.SynseError(f'Unexpected WebSocket response: {response}')
async def handle_message(self, message: aiohttp.WSMessage): if message.type == aiohttp.WSMsgType.TEXT: data = message.json() if isinstance(data, list): channel_id = data[0] handler = self.channel_handlers.get(channel_id) if handler: await handler(data, self) else: self.logger.warning( f"Can't find handler for channel_id{channel_id}, {data}" ) elif isinstance(data, dict): if "event" in data: await self.handle_event(data) else: self.logger.warning(f"Unknown message {message.data}") else: self.logger.warning(f"Unknown message {message.data}") else: self.logger.warning(f"Unknown type of message {repr(message)}")
def test_write_to_customer(self): """ Простой тест для отправки сообщений клиенту(кастомеру). В этом случае все происходит довольно просто и тупо: приходит сообщение в веб-сокет и оно уже отправляется через шлюз непосредственно в сервис, который работает с этими сообщениями. при этом сообщение будет сохранено в бд """ dialog = Dialog(id=123, channel=Channel.TEST) dialog.customer = Customer(id=1, name="Example customer") user = User(id=123) message_to_send = Message(text="example text", dialog=dialog, created_at=datetime.today()) self.ws_mock.iter = iter([ WSMessage(WSMsgType.TEXT, json.dumps(message_to_send, cls=MessageEncoder), extra={}) ]) gateway_mock = mock.MagicMock() gateways_repository = Repository() gateways_repository.register_gateway(dialog.channel, gateway_mock) handler = ChatHandler(ws=self.ws_mock, dialog=dialog, user=user, queues_repository=self.queues_repository, gateways_repository=gateways_repository, messages_repository=self.messages_repository) self.loop.run_until_complete(handler.write_to_customer()) # Проверяем, сохранилось ли сообщение в бд self.messages_repository.save.assert_called() gateway_mock.send_message.assert_called() self.assertEqual(dialog, message_to_send.dialog)
async def handle_message(self, message: aiohttp.WSMessage): # deserialize message # noinspection PyNoneFunctionAssignment, PyTypeChecker data = message.json(loads=loads) # type: dict log.debug("Response: %r", data) serial = data.get('id') if serial is None: return await self.handle_event(data) method = data.get('method') result = data.get('result') error = data.get('error') log.debug("Acquiring lock for %s serial %s", self, serial) async with self._locks[serial]: try: if 'method' in data: args, kwargs = self.prepare_args(data.get('params', None)) return await self.handle_method(method, serial, *args, **kwargs) elif 'result' in data: return await self.handle_result(serial, result) elif 'error' in data: return await self.handle_error(serial, error) else: return await self.handle_result(serial, None) except Exception as e: log.exception(e) if serial: await self._send(error=self._format_error(e), id=serial) finally: self._call_later(self._CLEAN_LOCK_TIMEOUT, self.__clean_lock, serial)
async def receive(): return WSMessage(WSMsgType.TEXT, 'data', b'')
async def receive(): return WSMessage(WSMsgType.BINARY, b'data', b'')
def as_websocket(self): return WSMessage(type=WSMsgType.TEXT, data=json.dumps(asdict(self)), extra=None)
def function1900(): return WSMessage(WSMsgType.BINARY, b'data', b'')
async def on_message(ws, message: aiohttp.WSMessage): """ { "message": { "data": "hello", "extended_data": [], "captions": [], "type": "PLAIN" }, "topic": "global", "type": "MESSAGE" } """ from main import bot hub_log.info(message) msg = message.json() type = msg['type'] if type == 'MESSAGE': topic = msg['topic'] if topic: # ignore topic global if topic == 'global': return # render message innter_type = msg['message']['type'] innter_data = msg['message']['data'] extended_data = msg['message']['extended_data'] or [] caption = msg['message']['caption'] preview = msg['message']['preview'] group = False body = '' parse_mode = None disable_preview = not preview disable_notification = False # parse message type if innter_type == MESSAGE_TYPE.PLAIN.name: body = innter_data elif innter_type == MESSAGE_TYPE.MARKDOWN.name: body = innter_data parse_mode = "Markdown" elif innter_type == MESSAGE_TYPE.HTML.name: body = innter_data parse_mode = "HTML" elif innter_type == MESSAGE_TYPE.JSON.name: body = innter_data elif is_media(innter_type) or extended_data: body = [{ 'type': innter_type, 'data': innter_data, 'caption': caption }] + extended_data # type: list print(body) # check: all types must be photo or video if not all(is_media(x['type']) for x in body): hub_log.warning(f"not all types are media") return else: hub_log.warning(f"unprocessed type {innter_type}") if body: all_topics = DB.get_key_topics_map() for key, topics in all_topics.items(): user_id, username, chat_id = Event.parse_key(key) if topic in topics: try: if is_media(innter_type) or extended_data: # string in hub message maybe a base64 encoded bytes # or http url of a image media_group = [{ 'type': x['type'].lower(), 'media': x['data'] if x['data'].startswith('http') else BytesIO(base64.b64decode(x['data'])), 'caption': x['caption'], } for x in body] if len(media_group) > 1: await bot.send_media_group( chat_id, media_group, disable_notification= disable_notification, ) else: if user_id != chat_id: caption_default = f"# {topic} by {username}" else: caption_default = f'# {topic}' if caption: caption_default = ( f'{caption.rstrip()}\n\n{caption_default}' ) x = media_group[0] if x['type'] == 'photo': await bot.send_photo( chat_id, x['media'], caption=caption_default, parse_mode=parse_mode, disable_notification= disable_notification, ) else: await bot.send_video( chat_id, x['media'], caption=caption_default, parse_mode=parse_mode, disable_notification= disable_notification, ) else: body_with_topic = f"{body.rstrip()}\n\n# {topic}" # reply in group or private chat if user_id != chat_id: real_body = ( f"{body_with_topic} by {username}") disable_notification = True else: real_body = body_with_topic await bot.send_message( chat_id, real_body, parse_mode=parse_mode, disable_web_page_preview=disable_preview, disable_notification=disable_notification, ) except Exception as e: traceback.print_exc()