Add async parameter to streaming API calls. If true, calls the streaming API on a separate thread and returns the Response object to the user so they can close it at their discretion.
This commit is contained in:
pare
fccc4e1986
commit
a6a1ddbed1
S'han modificat 1 arxius amb 64 adicions i 26 eliminacions
|
@ -16,6 +16,7 @@ import dateutil
|
||||||
import dateutil.parser
|
import dateutil.parser
|
||||||
import re
|
import re
|
||||||
import copy
|
import copy
|
||||||
|
import threading
|
||||||
|
|
||||||
class Mastodon:
|
class Mastodon:
|
||||||
"""
|
"""
|
||||||
|
@ -818,46 +819,63 @@ class Mastodon:
|
||||||
###
|
###
|
||||||
# Streaming
|
# Streaming
|
||||||
###
|
###
|
||||||
def user_stream(self, listener):
|
def user_stream(self, listener, async=False):
|
||||||
"""
|
"""
|
||||||
Streams events that are relevant to the authorized user, i.e. home
|
Streams events that are relevant to the authorized user, i.e. home
|
||||||
timeline and notifications. 'listener' should be a subclass of
|
timeline and notifications. 'listener' should be a subclass of
|
||||||
StreamListener.
|
StreamListener which will receive callbacks for incoming events.
|
||||||
|
|
||||||
This method blocks forever, calling callbacks on 'listener' for
|
If async is False, this method blocks forever.
|
||||||
incoming events.
|
|
||||||
|
If async is True, 'listener' will listen on another thread and this method
|
||||||
|
will return a requests.Response instance corresponding to the open
|
||||||
|
connection. The connection may be closed at any time by calling its
|
||||||
|
close() method.
|
||||||
"""
|
"""
|
||||||
return self.__stream('/api/v1/streaming/user', listener)
|
return self.__stream('/api/v1/streaming/user', listener, async=async)
|
||||||
|
|
||||||
def public_stream(self, listener):
|
def public_stream(self, listener, async=False):
|
||||||
"""
|
"""
|
||||||
Streams public events. 'listener' should be a subclass of
|
Streams public events. 'listener' should be a subclass of StreamListener
|
||||||
StreamListener.
|
which will receive callbacks for incoming events.
|
||||||
|
|
||||||
This method blocks forever, calling callbacks on 'listener' for
|
If async is False, this method blocks forever.
|
||||||
incoming events.
|
|
||||||
|
If async is True, 'listener' will listen on another thread and this method
|
||||||
|
will return a requests.Response instance corresponding to the open
|
||||||
|
connection. The connection may be closed at any time by calling its
|
||||||
|
close() method.
|
||||||
"""
|
"""
|
||||||
return self.__stream('/api/v1/streaming/public', listener)
|
return self.__stream('/api/v1/streaming/public', listener, async=async)
|
||||||
|
|
||||||
def local_stream(self, listener):
|
def local_stream(self, listener, async=False):
|
||||||
"""
|
"""
|
||||||
Streams local events. 'listener' should be a subclass of
|
Streams local events. 'listener' should be a subclass of StreamListener
|
||||||
StreamListener.
|
which will receive callbacks for incoming events.
|
||||||
|
|
||||||
This method blocks forever, calling callbacks on 'listener' for
|
If async is False, this method blocks forever.
|
||||||
incoming events.
|
|
||||||
|
If async is True, 'listener' will listen on another thread and this method
|
||||||
|
will return a requests.Response instance corresponding to the open
|
||||||
|
connection. The connection may be closed at any time by calling its
|
||||||
|
close() method.
|
||||||
"""
|
"""
|
||||||
return self.__stream('/api/v1/streaming/public/local', listener)
|
return self.__stream('/api/v1/streaming/public/local', listener, async=async)
|
||||||
|
|
||||||
def hashtag_stream(self, tag, listener):
|
def hashtag_stream(self, tag, listener, async=False):
|
||||||
"""
|
"""
|
||||||
Returns all public statuses for the hashtag 'tag'. 'listener' should be
|
Returns all public statuses for the hashtag 'tag'. 'listener' should be
|
||||||
a subclass of StreamListener.
|
a subclass of StreamListener which will receive callbacks for incoming
|
||||||
|
events.
|
||||||
|
|
||||||
This method blocks forever, calling callbacks on 'listener' for
|
If async is False, this method blocks forever.
|
||||||
incoming events.
|
|
||||||
|
If async is True, 'listener' will listen on another thread and this method
|
||||||
|
will return a requests.Response instance corresponding to the open
|
||||||
|
connection. The connection may be closed at any time by calling its
|
||||||
|
close() method.
|
||||||
"""
|
"""
|
||||||
return self.__stream('/api/v1/streaming/hashtag', listener, params={'tag': tag})
|
return self.__stream('/api/v1/streaming/hashtag', listener, params={'tag': tag}, async=async)
|
||||||
|
|
||||||
###
|
###
|
||||||
# Internal helpers, dragons probably
|
# Internal helpers, dragons probably
|
||||||
|
@ -1017,19 +1035,39 @@ class Mastodon:
|
||||||
|
|
||||||
return response
|
return response
|
||||||
|
|
||||||
def __stream(self, endpoint, listener, params = {}):
|
|
||||||
|
def __stream(self, endpoint, listener, params = {}, async=False):
|
||||||
"""
|
"""
|
||||||
Internal streaming API helper.
|
Internal streaming API helper.
|
||||||
|
|
||||||
|
Returns the requests.Response instance corresponding to the open websocket
|
||||||
|
connection.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
headers = {}
|
headers = {}
|
||||||
if self.access_token != None:
|
if self.access_token != None:
|
||||||
headers = {'Authorization': 'Bearer ' + self.access_token}
|
headers = {'Authorization': 'Bearer ' + self.access_token}
|
||||||
|
|
||||||
url = self.api_base_url + endpoint
|
url = self.api_base_url + endpoint
|
||||||
with closing(requests.get(url, headers = headers, data = params, stream = True)) as r:
|
|
||||||
listener.handle_stream(r.iter_lines())
|
|
||||||
|
|
||||||
|
connection = requests.get(url, headers = headers, data = params, stream = True)
|
||||||
|
|
||||||
|
def __stream_threadproc():
|
||||||
|
with closing(connection) as r:
|
||||||
|
try:
|
||||||
|
listener.handle_stream(r.iter_lines())
|
||||||
|
except AttributeError as e:
|
||||||
|
# TODO If the user closes the connection early, requests gets
|
||||||
|
# confused and throws an AttributeError
|
||||||
|
pass
|
||||||
|
return 0
|
||||||
|
|
||||||
|
if async:
|
||||||
|
t = threading.Thread(args=(), target=__stream_threadproc)
|
||||||
|
t.start()
|
||||||
|
return connection
|
||||||
|
else:
|
||||||
|
# Blocking, never returns (can only leave via exception)
|
||||||
|
return __stream_threadproc()
|
||||||
|
|
||||||
def __generate_params(self, params, exclude = []):
|
def __generate_params(self, params, exclude = []):
|
||||||
"""
|
"""
|
||||||
|
|
Loading…
Referencia en una nova incidència