diff options
author | Lorenz Diener <[email protected]> | 2017-12-19 13:49:00 +0100 |
---|---|---|
committer | Lorenz Diener <[email protected]> | 2017-12-19 13:49:00 +0100 |
commit | 9f9a7826d7bdb30eb394c6fd9f4fdafb06e9bfae (patch) | |
tree | cf7fe9a4e2467a4a6c7f9d9fce7a34798ad0512e /mastodon/streaming.py | |
parent | e5c50ea80d86449b5f95a32cf3a01d7bf8e9d2f4 (diff) | |
download | mastodon.py-9f9a7826d7bdb30eb394c6fd9f4fdafb06e9bfae.tar.gz |
Fix streaming API to be more stable (closes #117)
Diffstat (limited to 'mastodon/streaming.py')
-rw-r--r-- | mastodon/streaming.py | 58 |
1 files changed, 33 insertions, 25 deletions
diff --git a/mastodon/streaming.py b/mastodon/streaming.py index 92a02dc..3df3298 100644 --- a/mastodon/streaming.py +++ b/mastodon/streaming.py | |||
@@ -34,38 +34,46 @@ class StreamListener(object): | |||
34 | that the connection is still open.""" | 34 | that the connection is still open.""" |
35 | pass | 35 | pass |
36 | 36 | ||
37 | def handle_stream(self, lines): | 37 | def handle_stream(self, response): |
38 | """ | 38 | """ |
39 | Handles a stream of events from the Mastodon server. When each event | 39 | Handles a stream of events from the Mastodon server. When each event |
40 | is received, the corresponding .on_[name]() method is called. | 40 | is received, the corresponding .on_[name]() method is called. |
41 | 41 | ||
42 | lines: an iterable of lines of bytes sent by the Mastodon server, as | 42 | response; a requests response object with the open stream for reading. |
43 | returned by requests.Response.iter_lines(). | ||
44 | """ | 43 | """ |
45 | event = {} | 44 | self.event = {} |
46 | for raw_line in lines: | 45 | line_buffer = bytearray() |
47 | try: | 46 | for chunk in response.iter_content(chunk_size = 1): |
48 | line = raw_line.decode('utf-8') | 47 | if chunk: |
49 | except UnicodeDecodeError as err: | 48 | if chunk == b'\n': |
50 | six.raise_from( | 49 | self.handle_line(line_buffer) |
51 | MastodonMalformedEventError("Malformed UTF-8", line), | 50 | line_buffer = bytearray() |
52 | err | 51 | else: |
53 | ) | 52 | line_buffer.extend(chunk) |
53 | |||
54 | def handle_line(self, raw_line): | ||
55 | try: | ||
56 | line = raw_line.decode('utf-8') | ||
57 | except UnicodeDecodeError as err: | ||
58 | six.raise_from( | ||
59 | MastodonMalformedEventError("Malformed UTF-8", line), | ||
60 | err | ||
61 | ) | ||
54 | 62 | ||
55 | if line.startswith(':'): | 63 | if line.startswith(':'): |
56 | self.handle_heartbeat() | 64 | self.handle_heartbeat() |
57 | elif line == '': | 65 | elif line == '': |
58 | # end of event | 66 | # end of event |
59 | self._dispatch(event) | 67 | self._dispatch(self.event) |
60 | event = {} | 68 | self.event = {} |
69 | else: | ||
70 | key, value = line.split(': ', 1) | ||
71 | # According to the MDN spec, repeating the 'data' key | ||
72 | # represents a newline(!) | ||
73 | if key in self.event: | ||
74 | self.event[key] += '\n' + value | ||
61 | else: | 75 | else: |
62 | key, value = line.split(': ', 1) | 76 | self.event[key] = value |
63 | # According to the MDN spec, repeating the 'data' key | ||
64 | # represents a newline(!) | ||
65 | if key in event: | ||
66 | event[key] += '\n' + value | ||
67 | else: | ||
68 | event[key] = value | ||
69 | 77 | ||
70 | def _dispatch(self, event): | 78 | def _dispatch(self, event): |
71 | try: | 79 | try: |