diff --git a/chatexchange/browser.py b/chatexchange/browser.py index c412825..8be2945 100644 --- a/chatexchange/browser.py +++ b/chatexchange/browser.py @@ -239,6 +239,7 @@ def watch_room_socket(self, room_id, on_activity): socket_watcher = RoomSocketWatcher(self, room_id, on_activity) self.sockets[room_id] = socket_watcher socket_watcher.start() + return socket_watcher def watch_room_http(self, room_id, on_activity, interval): """ @@ -249,6 +250,7 @@ def watch_room_http(self, room_id, on_activity, interval): http_watcher = RoomPollingWatcher(self, room_id, on_activity, interval) self.polls[room_id] = http_watcher http_watcher.start() + return http_watcher def toggle_starring(self, message_id): return self.post_fkeyed( @@ -566,6 +568,9 @@ def __init__(self, browser, room_id, on_activity): self.on_activity = on_activity self.killed = False + def close(self): + self.killed = True + def start(self): last_event_time = self.browser.rooms[self.room_id]['eventtime'] @@ -607,6 +612,9 @@ def start(self): self.thread.setDaemon(True) self.thread.start() + def close(self): + self.killed = True + def _runner(self): while not self.killed: last_event_time = self.browser.rooms[self.room_id]['eventtime'] diff --git a/chatexchange/client.py b/chatexchange/client.py index 302fbc9..5d16262 100644 --- a/chatexchange/client.py +++ b/chatexchange/client.py @@ -38,7 +38,7 @@ def __init__(self, host='stackexchange.com', email=None, password=None): If email and password are provided, the client will L{login}. """ - self.logger = logger.getChild('SEChatWraper') + self.logger = logger.getChild('Client') if email or password: assert email and password, ( @@ -254,30 +254,3 @@ def _do_action_despite_throttling(self, action): def _join_room(self, room_id): self._br.join_room(room_id) - - def _room_events(self, activity, room_id): - """ - Returns a list of Events associated with a particular room, - given an activity message from the server. - """ - room_activity = activity.get('r%s' % (room_id,), {}) - room_events_data = room_activity.get('e', []) - for room_event_data in room_events_data: - if room_event_data: - event = events.make(room_event_data, self) - self._recently_gotten_objects.appendleft(event) - yield event - - def _watch_room_polling(self, room_id, event_callback, interval): - def on_activity(activity): - for event in self._room_events(activity, room_id): - event_callback(event, self) - - self._br.watch_room_http(room_id, on_activity, interval) - - def _watch_room_socket(self, room_id, event_callback): - def on_activity(activity): - for event in self._room_events(activity, room_id): - event_callback(event, self) - - self._br.watch_room_socket(room_id, on_activity) diff --git a/chatexchange/rooms.py b/chatexchange/rooms.py index 6561f87..96e51f2 100644 --- a/chatexchange/rooms.py +++ b/chatexchange/rooms.py @@ -1,6 +1,9 @@ +import Queue +import contextlib import logging from . import _utils, events +import collections logger = logging.getLogger(__name__) @@ -52,26 +55,75 @@ def watch(self, event_callback): return self.watch_polling(event_callback, 3) def watch_polling(self, event_callback, interval): - return self._client._watch_room_polling(self.id, event_callback, interval) + def on_activity(activity): + for event in self._events_from_activity(activity, self.id): + event_callback(event, self._client) + + return self._client._br.watch_room_http(self.id, on_activity, interval) def watch_socket(self, event_callback): - return self._client._watch_room_socket(self.id, event_callback) + def on_activity(activity): + for event in self._events_from_activity(activity, self.id): + event_callback(event, self._client) + + return self._client._br.watch_room_socket(self.id, on_activity) + + def _events_from_activity(self, activity, room_id): + """ + Returns a list of Events associated with a particular room, + given an activity message from the server. + """ + room_activity = activity.get('r%s' % (room_id,), {}) + room_events_data = room_activity.get('e', []) + for room_event_data in room_events_data: + if room_event_data: + event = events.make(room_event_data, self._client) + self._client._recently_gotten_objects.appendleft(event) + yield event def new_events(self, types=events.Event): - raise NotImplementedError() - events = FilteredEventIterator() - - self.watch_socket() - - return events + return FilteredEventIterator(self, types) def new_messages(self): - raise NotImplementedError() + return MessageIterator(self) class FilteredEventIterator(object): - pass + def __init__(self, room, types): + self.types = types + self._queue = Queue.Queue() + + room.join() + self._watcher = room.watch(self._on_event) + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, tracback): + self._watcher.close() + + def __iter__(self): + while True: + yield self._queue.get() + + def _on_event(self, event, client): + if isinstance(event, self.types): + self._queue.put(event) class MessageIterator(object): - pass + def __init__(self, room): + self._event_iter = FilteredEventIterator(room, events.MessagePosted) + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, tracback): + self._event_iter._watcher.close() + + def __iter__(self): + for event in self._event_iter: + yield event.message + + def _on_event(self, event, client): + return self._event_iter._on_event(event) diff --git a/examples/chat.py b/examples/chat.py index 490f7ea..f93935a 100755 --- a/examples/chat.py +++ b/examples/chat.py @@ -24,9 +24,7 @@ def main(): if 'ChatExchangeU' in os.environ: email = os.environ['ChatExchangeU'] else: - sys.stderr.write("Username: ") - sys.stderr.flush() - email = raw_input() + email = raw_input("Email: ") if 'ChatExchangeP' in os.environ: password = os.environ['ChatExchangeP'] else: diff --git a/examples/hello_world.py b/examples/hello_world.py index 1295480..2b2ee5f 100755 --- a/examples/hello_world.py +++ b/examples/hello_world.py @@ -1,6 +1,7 @@ #!/usr/bin/env python -from getpass import getpass +import getpass import logging +import os import chatexchange from chatexchange.events import MessageEdited @@ -8,16 +9,22 @@ logging.basicConfig(level=logging.DEBUG) -email = raw_input('Email: ') -password = getpass() +if 'ChatExchangeU' in os.environ: + email = os.environ['ChatExchangeU'] +else: + email = raw_input("Email: ") +if 'ChatExchangeP' in os.environ: + password = os.environ['ChatExchangeP'] +else: + password = getpass.getpass("Password: ") client = chatexchange.Client('stackexchange.com', email, password) me = client.get_me() -sandbox = client.get_room(11540) +sandbox = client.get_room(14219) my_message = None -with sandbox.messages() as messages: - sandbox._send_message("hello worl") +with sandbox.new_messages() as messages: + sandbox.send_message("hello worl") for message in messages: if message.owner is me: @@ -26,7 +33,7 @@ print "message sent successfully" break -with sandbox.events(MessageEdited) as edits: +with sandbox.new_events(MessageEdited) as edits: my_message.edit("hello world") for edit in edits: diff --git a/examples/web_viewer.py b/examples/web_viewer.py index d3e9715..df6c5c5 100755 --- a/examples/web_viewer.py +++ b/examples/web_viewer.py @@ -71,7 +71,7 @@ def get_state(self): 'name': self.room.name }, 'recent_events': - map(str, self.client.recent_events), + map(str, self.client._recently_gotten_objects), 'messages': [{ 'id': message.id, 'owner_user_id': message.owner.id, diff --git a/test/test_rooms.py b/test/test_rooms.py index 974e5b4..ae20105 100644 --- a/test/test_rooms.py +++ b/test/test_rooms.py @@ -1,4 +1,4 @@ -import pytest +import logging import chatexchange from chatexchange.events import MessageEdited @@ -6,6 +6,9 @@ import live_testing +logger = logging.getLogger(__name__) + + if live_testing.enabled: def test_room_info(): client = chatexchange.Client('stackexchange.com') @@ -25,8 +28,6 @@ def test_room_info(): sandbox.text_description sandbox.parent_site_name + sandbox.name - @pytest.mark.timeout(60) - @pytest.mark.xfail(reason="event iterators not yet implemented") def test_room_iterators(): client = chatexchange.Client( 'stackexchange.com', live_testing.email, live_testing.password) @@ -37,13 +38,15 @@ def test_room_iterators(): my_message = None with sandbox.new_messages() as messages: - sandbox._send_message("hello worl") + sandbox.send_message("hello worl") for message in messages: if message.owner is me: my_message = message assert my_message.content == "hello worl" break + else: + logger.info("ignoring message: %r", message) with sandbox.new_events(MessageEdited) as edits: my_message.edit("hello world")