def _process_event(self, event: Event): if event.event == 'connection_open': event.event = 'open' elif not event.event: event.event = 'message' event.type = event.event # https://developer.mozilla.org/en-US/docs/Web/API/Event/type logging.debug('EventSource._process_event: ' + event.type) self.dispatch_event(event)
def test_listen(self): script = "./" node_runner = Mock() formatted = "Zemke via CWT: “Here is a message”" node_runner.format = Mock(return_value=formatted) channel = "1234" endpoint = "http://example.com" client_mock = Mock() guild_mock = Mock() channel_mock = Mock() type(channel_mock).id = PropertyMock(return_value=1234) type(guild_mock).text_channels = PropertyMock( return_value=[channel_mock]) type(client_mock).guilds = PropertyMock(return_value=[guild_mock]) message = { "id": 5000, "category": "SHOUTBOX", "author": { "username": "******" }, "body": "Here is a message", } events = [Event(event="EVENT", data=json.dumps(message))] open_stream = type("SSEClient", (object, ), {"events": lambda x: events}) listener = Listener(client_mock, channel, node_runner, open_stream) cb_mock = Mock() listener.listen(1, cb_mock) cb_mock.assert_called_once_with(int(channel), formatted)
def sse_connect(): while True: try: messages = SSEClient1(self.url) except (requests.exceptions.ConnectionError, requests.exceptions.HTTPError) as e: self._process_event(Event(data=str(e), event='error')) return self.readyState = _OPEN try: for event in messages: if self.readyState == _CLOSED: # TODO: We should close the underlying HTTP request. logging.info('EventSource closing...') return self._process_event(event) except (ConnectionResetError, requests.exceptions.ConnectionError) as e: # TODO: We do not need to handle ConnectionError, SSEClient does it for us. logging.exception(str(e)) pass logging.debug('EventSource reconnect...') self.readyState = _CONNECTING time.sleep(1)
def test_listen_yields_sse_events(mock_iterator, mock_init): mock_init.return_value = None mock_iterator.return_value = iter([Event(id=1234)]) client = RestAdapter(PROCEDURES_URI) result = client.listen() assert next(result).id == 1234
def test_round_trip_parse(): m1 = E(data='hi there\nsexy developer', event='salutation', id='abcdefg', retry=10000) dumped = m1.dump() m2 = E.parse(dumped) assert m1.id == m2.id assert m1.data == m2.data assert m1.retry == m2.retry assert m1.event == m2.event
def messages(self): """ Simulates live event stream by using a dump file of the event stream from: `curl -sN host_ip:9999/events > dump_file` """ for_processing = [] for line in open(self.file_path, 'r'): if line == "\n": if for_processing != [':\n']: yield Event.parse(''.join(for_processing)) for_processing = [] continue for_processing.append(line)
def test_round_trip_parse(): m1 = E( data='hi there\nsexy developer', event='salutation', id='abcdefg', retry=10000 ) dumped = m1.dump() m2 = E.parse(dumped) assert m1.id == m2.id assert m1.data == m2.data assert m1.retry == m2.retry assert m1.event == m2.event
def test_restclientui_handles_listen_event_parse_error(mock_listen_fn, capsys): mock_listen_fn.return_value = [Event(data="")] fire.Fire(RestClientUI, ["listen", "--topics=request.procedure.create"]) captured = capsys.readouterr() assert "" == captured.out mock_listen_fn.return_value = [Event(data="{'invalid json'}")] fire.Fire(RestClientUI, ["listen", "--topics=request.procedure.create"]) captured = capsys.readouterr() assert "- ERROR Could not parse event: {'invalid json'}\n" == captured.out mock_listen_fn.return_value = [ Event(data='{"topic": "this is not correct topic "}') ] fire.Fire(RestClientUI, ["listen", "--topics=request.procedure.create"]) captured = capsys.readouterr() assert "" == captured.out # tests the case where the formatter returns a KeyError mock_listen_fn.return_value = [Event(data='{"topic": "subarray.fault"}')] fire.Fire(RestClientUI, ["listen", "--topics=subarray.fault"]) captured = capsys.readouterr() assert "" == captured.out
def file_message_streamer(server: str, start_from): """ Simulates live event stream by using a dump file of the event stream from: `curl -sN host_ip:9999/events > dump_file` server should be full path to file """ for_processing = [] for line in open(server, 'r'): if line == "\n": if for_processing != [':\n']: msg = Event.parse(''.join(for_processing)) cur_id = int(msg.id) if msg.id is not None else 0 if cur_id >= int(start_from): yield msg for_processing = [] continue for_processing.append(line)
def __next__(self): decoder = codecs.getincrementaldecoder( self.resp.encoding)(errors='replace') pos = 0 while end_of_field.search(self.buf, pos) is None: try: next_chunk = next(self.resp_iterator) if not next_chunk: raise EOFError() pos = max(0, len(self.buf) - 4) self.buf += decoder.decode(next_chunk) except (StopIteration, requests.RequestException, EOFError, http.client.IncompleteRead) as e: time.sleep(self.retry / 1000.0) self._connect() # The SSE spec only supports resuming from a whole message, so # if we have half a message we should throw it out. head, sep, tail = self.buf.rpartition('\n') self.buf = head + sep continue # Split the complete event (up to the end_of_field) into event_string, # and retain anything after the current complete event in self.buf # for next time. (event_string, self.buf) = re.split(end_of_field, self.buf, maxsplit=1) msg = Event.parse(event_string) # If the server requests a specific retry delay, we need to honor it. if msg.retry: self.retry = msg.retry # last_id should only be set if included in the message. It's not # forgotten if a message omits it. if msg.id: self.last_id = msg.id return msg
def test_no_space(): m = E.parse('data:hi') assert m.data == 'hi'
def test_comment(): raw = ":this is a comment\ndata: this is some data" m = E.parse(raw) assert m.data == 'this is some data'
def test_eols(): for eol in ('\r\n', '\r', '\n'): m = E.parse('event: hello%sdata: eol%s' % (eol, eol)) assert m.event == 'hello' assert m.data == 'eol'
def test_default_event(): m = E.parse('data: blah') assert m.event == 'message'
def test_retry_is_integer(): m = E.parse('data: hi\nretry: 4000') assert m.retry == 4000
def test_no_colon(): m = E.parse('data') assert m.data == ''
["RUNNING", 1601303225.8234824], ["READY", 1601303225.8234867], ["RUNNING", 1601303225.8702714], ["COMPLETE", 1601303225.8702714], ], "stacktrace": None, }, state="COMPLETE", ) ] REST_ADAPTER_LISTEN_RESPONSE = [ Event( data='{"topic": "user.script.announce", "msg": "announced"}', event="some event", id=101, ) ] def parse_rest_create_list_response(resp): """Split the response from the REST API lines into columns Args: resp (string): [description] Returns: [rest_response_object]: [description] """