Skip to content
This repository has been archived by the owner on Sep 16, 2021. It is now read-only.

Commit

Permalink
migrate event handling completely to handlers.EventHandler
Browse files Browse the repository at this point in the history
also refactor the event handling as it uses asyncio.async and a lot of redundant code

performace: do not rebuild the permamem entry on each event, instead only update on events that could change conv meta
  • Loading branch information
das7pad committed Jun 4, 2017
1 parent e9da7a3 commit 649b6ca
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 103 deletions.
97 changes: 67 additions & 30 deletions hangupsbot/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

import plugins
from commands import command
from event import (TypingEvent, WatermarkEvent, ConversationEvent)
from exceptions import HangupsBotExceptions


Expand Down Expand Up @@ -278,36 +279,6 @@ def handle_command(self, event):
for id in event.acknowledge:
yield from self.run_reprocessor(id, event, results)

@asyncio.coroutine
def handle_chat_membership(self, event):
"""handle conversation membership change"""
yield from self.run_pluggable_omnibus("membership", self.bot, event, command)

@asyncio.coroutine
def handle_chat_rename(self, event):
"""handle conversation name change"""
yield from self.run_pluggable_omnibus("rename", self.bot, event, command)

@asyncio.coroutine
def handle_chat_history(self, event):
"""handle conversation OTR status change"""
yield from self.run_pluggable_omnibus("history", self.bot, event, command)

@asyncio.coroutine
def handle_call(self, event):
"""handle incoming calls (voice/video)"""
yield from self.run_pluggable_omnibus("call", self.bot, event, command)

@asyncio.coroutine
def handle_typing_notification(self, event):
"""handle changes in typing state"""
yield from self.run_pluggable_omnibus("typing", self.bot, event, command)

@asyncio.coroutine
def handle_watermark_notification(self, event):
"""handle watermark updates"""
yield from self.run_pluggable_omnibus("watermark", self.bot, event, command)

async def run_pluggable_omnibus(self, name, *args, **kwargs):
"""forward args to a group of handler which were registered for the name
Expand Down Expand Up @@ -362,6 +333,72 @@ async def run_pluggable_omnibus(self, name, *args, **kwargs):
# handler and do not continue with event handling in the parent
raise

async def handle_event(self, conv_event):
"""Handle conversation events
Args:
conv_event: hangups.conversation_event.ConversationEvent instance
"""
event = ConversationEvent(self.bot, conv_event)

if isinstance(conv_event, hangups.ChatMessageEvent):
pluggable = None

elif isinstance(conv_event, hangups.MembershipChangeEvent):
pluggable = "membership"

elif isinstance(conv_event, hangups.RenameEvent):
pluggable = "rename"

elif isinstance(conv_event, hangups.OTREvent):
pluggable = "history"

elif isinstance(conv_event, hangups.HangoutEvent):
pluggable = "call"

else:
# Unsupported Events:
# * GroupLinkSharingModificationEvent
# https://github.com/tdryer/hangups/blob/master/hangups/conversation_event.py
logger.warning("unrecognised event type: %s", type(conv_event))
return

if pluggable is not None or event.conv_id not in self.bot.conversations:
# rebuild permamem for a conv including conv-name, participants, otr
# if the event is not a message or the conv is missing in permamem
await self.bot.conversations.update(event.conv, source="event")

if pluggable is None:
asyncio.ensure_future(self.handle_chat_message(event))
return

asyncio.ensure_future(self.run_pluggable_omnibus(
pluggable, self.bot, event, command))

async def handle_status_change(self, state_update):
"""run notification handler for a given state_update
Args:
state_update: hangups.hangouts_pb2.StateUpdate instance
"""
notification_type = state_update.WhichOneof("state_update")

if notification_type == "typing_notification":
pluggable = "typing"
event = TypingEvent(self.bot, state_update.typing_notification)

elif notification_type == "watermark_notification":
pluggable = "watermark"
event = WatermarkEvent(self.bot,
state_update.watermark_notification)
else:
# Unsupported State Updates (state_update):
# https://github.com/tdryer/hangups/blob/9a27ecd0cbfd94acf8959e89c52ac3250c920a1f/hangups/hangouts.proto#L1034
return

asyncio.ensure_future(self.run_pluggable_omnibus(
pluggable, self.bot, event, command))


class HandlerBridge:
"""shim for xmikosbot handler decorator"""
Expand Down
76 changes: 3 additions & 73 deletions hangupsbot/hangupsbot.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@

import sinks
import plugins

from event import (TypingEvent, WatermarkEvent, ConversationEvent)
from hangups_conversation import (HangupsConversation, FakeConversation)

from commands import command
Expand Down Expand Up @@ -474,80 +472,12 @@ def _on_connect(self):
plugins.load(self, "commands.loggertochat")
plugins.load_user_plugins(self)

self._conv_list.on_event.add_observer(self._on_event)
self._client.on_state_update.add_observer(self._on_status_changes)
self._conv_list.on_event.add_observer(self._handlers.handle_event)
self._client.on_state_update.add_observer(
self._handlers.handle_status_change)

logger.info("bot initialised")


def _on_status_changes(self, state_update):
notification_type = state_update.WhichOneof('state_update')
if notification_type == 'typing_notification':
asyncio.async(
self._handlers.handle_typing_notification(
TypingEvent(self, state_update.typing_notification)
)
).add_done_callback(lambda future: future.result())
elif notification_type == 'watermark_notification':
asyncio.async(
self._handlers.handle_watermark_notification(
WatermarkEvent(self, state_update.watermark_notification)
)
).add_done_callback(lambda future: future.result())
elif notification_type == 'event_notification':
"""
XXX: Unsupported State Updates (state_update):
re: https://github.com/tdryer/hangups/blob/9a27ecd0cbfd94acf8959e89c52ac3250c920a1f/hangups/hangouts.proto#L1034
"""
pass


@asyncio.coroutine
def _on_event(self, conv_event):
"""Handle conversation events"""

event = ConversationEvent(self, conv_event)

yield from self.conversations.update(self._conv_list.get(conv_event.conversation_id),
source="event")

if isinstance(conv_event, hangups.ChatMessageEvent):
self._execute_hook("on_chat_message", event)
asyncio.async(
self._handlers.handle_chat_message(event)
).add_done_callback(lambda future: future.result())

elif isinstance(conv_event, hangups.MembershipChangeEvent):
self._execute_hook("on_membership_change", event)
asyncio.async(
self._handlers.handle_chat_membership(event)
).add_done_callback(lambda future: future.result())

elif isinstance(conv_event, hangups.RenameEvent):
self._execute_hook("on_rename", event)
asyncio.async(
self._handlers.handle_chat_rename(event)
).add_done_callback(lambda future: future.result())

elif isinstance(conv_event, hangups.OTREvent):
asyncio.async(
self._handlers.handle_chat_history(event)
).add_done_callback(lambda future: future.result())

elif type(conv_event) is hangups.conversation_event.HangoutEvent:
asyncio.async(
self._handlers.handle_call(event)
).add_done_callback(lambda future: future.result())

else:
"""
XXX: Unsupported Events:
* GroupLinkSharingModificationEvent
re: https://github.com/tdryer/hangups/blob/master/hangups/conversation_event.py
"""

logger.warning("_on_event(): unrecognised event type: {}".format(type(conv_event)))

def _on_disconnect(self):
"""Handle disconnecting"""
logger.info('Connection lost!')
Expand Down

0 comments on commit 649b6ca

Please sign in to comment.