diff options
Diffstat (limited to 'mastodon/streaming.py')
-rw-r--r-- | mastodon/streaming.py | 48 |
1 files changed, 41 insertions, 7 deletions
diff --git a/mastodon/streaming.py b/mastodon/streaming.py index ceb61ea..65acba8 100644 --- a/mastodon/streaming.py +++ b/mastodon/streaming.py | |||
@@ -5,6 +5,11 @@ https://github.com/tootsuite/mastodon/blob/master/docs/Using-the-API/Streaming-A | |||
5 | 5 | ||
6 | import json | 6 | import json |
7 | import six | 7 | import six |
8 | try: | ||
9 | from inspect import signature | ||
10 | except: | ||
11 | pass | ||
12 | |||
8 | from mastodon import Mastodon | 13 | from mastodon import Mastodon |
9 | from mastodon.Mastodon import MastodonMalformedEventError, MastodonNetworkError, MastodonReadTimeout | 14 | from mastodon.Mastodon import MastodonMalformedEventError, MastodonNetworkError, MastodonReadTimeout |
10 | from requests.exceptions import ChunkedEncodingError, ReadTimeout | 15 | from requests.exceptions import ChunkedEncodingError, ReadTimeout |
@@ -16,10 +21,15 @@ class StreamListener(object): | |||
16 | Mastodon.hashtag_stream().""" | 21 | Mastodon.hashtag_stream().""" |
17 | 22 | ||
18 | def on_update(self, status): | 23 | def on_update(self, status): |
19 | """A new status has appeared! 'status' is the parsed JSON dictionary | 24 | """A new status has appeared. 'status' is the parsed JSON dictionary |
20 | describing the status.""" | 25 | describing the status.""" |
21 | pass | 26 | pass |
22 | 27 | ||
28 | def on_status_update(self, status): | ||
29 | """A status has been edited. 'status' is the parsed JSON dictionary | ||
30 | describing the updated status.""" | ||
31 | pass | ||
32 | |||
23 | def on_notification(self, notification): | 33 | def on_notification(self, notification): |
24 | """A new notification. 'notification' is the parsed JSON dictionary | 34 | """A new notification. 'notification' is the parsed JSON dictionary |
25 | describing the notification.""" | 35 | describing the notification.""" |
@@ -55,6 +65,7 @@ class StreamListener(object): | |||
55 | self.on_abort(exception) | 65 | self.on_abort(exception) |
56 | raise exception | 66 | raise exception |
57 | 67 | ||
68 | |||
58 | def handle_heartbeat(self): | 69 | def handle_heartbeat(self): |
59 | """The server has sent us a keep-alive message. This callback may be | 70 | """The server has sent us a keep-alive message. This callback may be |
60 | useful to carry out periodic housekeeping tasks, or just to confirm | 71 | useful to carry out periodic housekeeping tasks, or just to confirm |
@@ -135,6 +146,10 @@ class StreamListener(object): | |||
135 | try: | 146 | try: |
136 | name = event['event'] | 147 | name = event['event'] |
137 | data = event['data'] | 148 | data = event['data'] |
149 | try: | ||
150 | for_stream = json.loads(event['stream']) | ||
151 | except: | ||
152 | for_stream = None | ||
138 | payload = json.loads(data, object_hook = Mastodon._Mastodon__json_hooks) | 153 | payload = json.loads(data, object_hook = Mastodon._Mastodon__json_hooks) |
139 | except KeyError as err: | 154 | except KeyError as err: |
140 | exception = MastodonMalformedEventError('Missing field', err.args[0], event) | 155 | exception = MastodonMalformedEventError('Missing field', err.args[0], event) |
@@ -152,15 +167,29 @@ class StreamListener(object): | |||
152 | exception, | 167 | exception, |
153 | err | 168 | err |
154 | ) | 169 | ) |
155 | # New mastodon API also supports event names with dots: | 170 | # New mastodon API also supports event names with dots, |
171 | # specifically, status_update. | ||
156 | handler_name = 'on_' + name.replace('.', '_') | 172 | handler_name = 'on_' + name.replace('.', '_') |
173 | |||
157 | # A generic way to handle unknown events to make legacy code more stable for future changes | 174 | # A generic way to handle unknown events to make legacy code more stable for future changes |
158 | handler = getattr(self, handler_name, self.on_unknown_event) | 175 | handler = getattr(self, handler_name, self.on_unknown_event) |
159 | if handler != self.on_unknown_event: | 176 | try: |
160 | handler(payload) | 177 | handler_args = list(signature(handler).parameters) |
178 | except: | ||
179 | handler_args = handler.__code__.co_varnames[:handler.__code__.co_argcount] | ||
180 | |||
181 | # The "for_stream" is right now only theoretical - it's only supported on websocket, | ||
182 | # and we do not support websocket based multiplexed streams (yet). | ||
183 | if "for_stream" in handler_args: | ||
184 | if handler != self.on_unknown_event: | ||
185 | handler(payload, for_stream) | ||
186 | else: | ||
187 | handler(name, payload, for_stream) | ||
161 | else: | 188 | else: |
162 | handler(name, payload) | 189 | if handler != self.on_unknown_event: |
163 | 190 | handler(payload) | |
191 | else: | ||
192 | handler(name, payload) | ||
164 | 193 | ||
165 | class CallbackStreamListener(StreamListener): | 194 | class CallbackStreamListener(StreamListener): |
166 | """ | 195 | """ |
@@ -169,7 +198,7 @@ class CallbackStreamListener(StreamListener): | |||
169 | Define an unknown_event_handler for new Mastodon API events. If not, the | 198 | Define an unknown_event_handler for new Mastodon API events. If not, the |
170 | listener will raise an error on new, not handled, events from the API. | 199 | listener will raise an error on new, not handled, events from the API. |
171 | """ | 200 | """ |
172 | def __init__(self, update_handler = None, local_update_handler = None, delete_handler = None, notification_handler = None, conversation_handler = None, unknown_event_handler = None): | 201 | def __init__(self, update_handler = None, local_update_handler = None, delete_handler = None, notification_handler = None, conversation_handler = None, unknown_event_handler = None, status_update_handler = None): |
173 | super(CallbackStreamListener, self).__init__() | 202 | super(CallbackStreamListener, self).__init__() |
174 | self.update_handler = update_handler | 203 | self.update_handler = update_handler |
175 | self.local_update_handler = local_update_handler | 204 | self.local_update_handler = local_update_handler |
@@ -177,6 +206,7 @@ class CallbackStreamListener(StreamListener): | |||
177 | self.notification_handler = notification_handler | 206 | self.notification_handler = notification_handler |
178 | self.conversation_handler = conversation_handler | 207 | self.conversation_handler = conversation_handler |
179 | self.unknown_event_handler = unknown_event_handler | 208 | self.unknown_event_handler = unknown_event_handler |
209 | self.status_update_handler = status_update_handler | ||
180 | 210 | ||
181 | def on_update(self, status): | 211 | def on_update(self, status): |
182 | if self.update_handler != None: | 212 | if self.update_handler != None: |
@@ -210,3 +240,7 @@ class CallbackStreamListener(StreamListener): | |||
210 | exception = MastodonMalformedEventError('Bad event type', name) | 240 | exception = MastodonMalformedEventError('Bad event type', name) |
211 | self.on_abort(exception) | 241 | self.on_abort(exception) |
212 | raise exception | 242 | raise exception |
243 | |||
244 | def on_status_update(self, status): | ||
245 | if self.status_update_handler != None: | ||
246 | self.status_update_handler(status) \ No newline at end of file | ||