Exemplo n.º 1
0
 def _dispatch(self, event):
     try:
         name = event['event']
         data = event['data']
         payload = json.loads(data, object_hook = Mastodon._Mastodon__json_hooks)
     except KeyError as err:
         exception = MastodonMalformedEventError('Missing field', err.args[0], event)
         self.on_abort(exception)
         six.raise_from(
             exception,
             err
         )
     except ValueError as err:
         # py2: plain ValueError
         # py3: json.JSONDecodeError, a subclass of ValueError
         exception = MastodonMalformedEventError('Bad JSON', data)
         self.on_abort(exception)
         six.raise_from(
             exception,
             err
         )
        
     handler_name = 'on_' + name
     try:
         handler = getattr(self, handler_name)
     except AttributeError as err:
         exception = MastodonMalformedEventError('Bad event type', name)
         self.on_abort(exception)
         six.raise_from(
            exception,
            err
         )
     else:
         handler(payload)
Exemplo n.º 2
0
    def handle_stream(self, lines):
        """
        Handles a stream of events from the Mastodon server. When each event
        is received, the corresponding .on_[name]() method is called.

        lines: an iterable of lines of bytes sent by the Mastodon server, as
        returned by requests.Response.iter_lines().
        """
        event = {}
        for raw_line in lines:
            try:
                line = raw_line.decode('utf-8')
            except UnicodeDecodeError as err:
                six.raise_from(
                    MastodonMalformedEventError("Malformed UTF-8", line), err)

            if line.startswith(':'):
                self.handle_heartbeat()
            elif line == '':
                # end of event
                self._dispatch(event)
                event = {}
            else:
                key, value = line.split(': ', 1)
                # According to the MDN spec, repeating the 'data' key
                # represents a newline(!)
                if key in event:
                    event[key] += '\n' + value
                else:
                    event[key] = value
Exemplo n.º 3
0
    def handle_stream(self, response):
        """
        Handles a stream of events from the Mastodon server. When each event
        is received, the corresponding .on_[name]() method is called.

        response; a requests response object with the open stream for reading.
        """
        event = {}
        line_buffer = bytearray()
        for chunk in response.iter_content(chunk_size=1):
            if chunk:
                if chunk == b'\n':
                    try:
                        line = line_buffer.decode('utf-8')
                    except UnicodeDecodeError as err:
                        six.raise_from(
                            MastodonMalformedEventError("Malformed UTF-8"),
                            err)
                    if line == '':
                        self._dispatch(event)
                        event = {}
                    else:
                        event = self._parse_line(line, event)
                    line_buffer = bytearray()
                else:
                    line_buffer.extend(chunk)
Exemplo n.º 4
0
    def handle_stream(self, response):
        """
        Handles a stream of events from the Mastodon server. When each event
        is received, the corresponding .on_[name]() method is called.

        response; a requests response object with the open stream for reading.
        """
        event = {}
        line_buffer = bytearray()
        try:
            for chunk in response.iter_content(chunk_size=1):
                if chunk:
                    if chunk == b'\n':
                        try:
                            line = line_buffer.decode('utf-8')
                        except UnicodeDecodeError as err:
                            six.raise_from(
                                MastodonMalformedEventError("Malformed UTF-8"),
                                err)
                        if line == '':
                            self._dispatch(event)
                            event = {}
                        else:
                            event = self._parse_line(line, event)
                        line_buffer = bytearray()
                    else:
                        line_buffer.extend(chunk)
        except requests.exceptions.ChunkedEncodingError as e:
            # Empirically, we get this exception when the server sends an empty
            # message (incomplete read) after several hours of running.
            # This is tantamount to the connection terminating, so call on_close
            # to allow clients to handle this case.
            self.on_close()
Exemplo n.º 5
0
 def on_update(self, status):
     if self.update_handler != None:
         self.update_handler(status)
     
     try:
         if self.local_update_handler != None and not "@" in status["account"]["acct"]:
             self.local_update_handler(status)
     except Exception as err:
         six.raise_from(
            MastodonMalformedEventError('received bad update', status),
            err
         )
Exemplo n.º 6
0
    def _dispatch(self, event):
        try:
            name = event['event']
            data = event['data']
            payload = json.loads(data,
                                 object_hook=Mastodon._Mastodon__json_hooks)
        except KeyError as err:
            six.raise_from(
                MastodonMalformedEventError('Missing field', err.args[0],
                                            event), err)
        except ValueError as err:
            # py2: plain ValueError
            # py3: json.JSONDecodeError, a subclass of ValueError
            six.raise_from(MastodonMalformedEventError('Bad JSON', data), err)

        handler_name = 'on_' + name
        try:
            handler = getattr(self, handler_name)
        except AttributeError as err:
            six.raise_from(MastodonMalformedEventError('Bad event type', name),
                           err)
        else:
            # TODO: allow handlers to return/raise to stop streaming cleanly
            handler(payload)
Exemplo n.º 7
0
    def handle_stream(self, response):
        """
        Handles a stream of events from the Mastodon server. When each event
        is received, the corresponding .on_[name]() method is called.

        response; a requests response object with the open stream for reading.
        """
        event = {}
        line_buffer = bytearray()
        try:
            for chunk in response.iter_content(chunk_size = 1):
                if chunk:
                    for chunk_part in chunk:
                        chunk_part = bytearray([chunk_part])
                        if chunk_part == b'\n':
                            try:
                                line = line_buffer.decode('utf-8')
                            except UnicodeDecodeError as err:
                                exception = MastodonMalformedEventError("Malformed UTF-8")
                                self.on_abort(exception)
                                six.raise_from(
                                    exception,
                                    err
                                )
                            if line == '':
                                self._dispatch(event)
                                event = {}
                            else:
                                event = self._parse_line(line, event)
                            line_buffer = bytearray()
                        else:
                            line_buffer.extend(chunk_part)
        except ChunkedEncodingError as err:
            exception = MastodonNetworkError("Server ceased communication.")
            self.on_abort(exception)
            six.raise_from(
                exception,
                err
            )
        except MastodonReadTimeout as err:
            exception = MastodonReadTimeout("Timed out while reading from server."),
            self.on_abort(exception)
            six.raise_from(
                exception,
                err
            )
Exemplo n.º 8
0
 def _parse_line(self, line, event):
     if line.startswith(':'):
         self.handle_heartbeat()
     else:
         try:
             key, value = line.split(': ', 1)
         except:
             exception = MastodonMalformedEventError("Malformed event.")
             self.on_abort(exception)
             raise exception
         # According to the MDN spec, repeating the 'data' key
         # represents a newline(!)
         if key in event:
             event[key] += '\n' + value
         else:
             event[key] = value
     return event