From c47e31c82e21d497a272ac54710178536d1027dd Mon Sep 17 00:00:00 2001 From: Hornwitser Date: Tue, 29 Sep 2015 08:35:26 +0200 Subject: [PATCH] Add new event system Add event system based on a public dispatch method in Client. The new event system bases itself on two types of events, internal event handlers and user defined event handlers. Internal event handlers begin with 'handle_', and user defined events begin with 'on_'. Events are dispatched with dispatch(event_name, *args). The Client class should be subclassed and the on_ handlers defined in it for responding to events. The handle_ handlers can the overridden to override the behaviour of the Client class, though this is not recommended. The subclassing method allows separation of the instance of the client and the code that handles it. (i.e. you don't need the instance of the client object to define event handlers for it). Though, the old method of using the event decorator from the instance will still be supported. --- discord/client.py | 50 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 34 insertions(+), 16 deletions(-) diff --git a/discord/client.py b/discord/client.py index 738d8d764..b33f79abb 100644 --- a/discord/client.py +++ b/discord/client.py @@ -216,6 +216,24 @@ class Client(object): else: return [] + def on_error(self, event_method, *args, **kwargs): + msg = 'Caught exception in {} with args (*{}, **{})' + log.exception(msg.format(event_method, args, kwargs)) + + def dispatch(self, event, *args, **kwargs): + log.debug("Dispatching event {}".format(event)) + handle_method = '_'.join(('handle', event)) + event_method = '_'.join(('on', event)) + getattr(self, handle_method, _null_event)(*args, **kwargs) + try: + getattr(self, event_method, _null_event)(*args, **kwargs) + except Exception as e: + getattr(self, 'on_error')(event_method, *args, **kwargs) + + # Compatibility shim to old event system. + if event_method in self.events: + self._invoke_event(event_method, *args, **kwargs) + def _invoke_event(self, event_name, *args, **kwargs): try: log.info('attempting to invoke event {}'.format(event_name)) @@ -230,7 +248,7 @@ class Client(object): if response.get('op') != 0: return - self._invoke_event('on_response', response) + self.dispatch('response', response) event = response.get('t') data = response.get('d') @@ -250,18 +268,18 @@ class Client(object): self.keep_alive.start() # we're all ready - self._invoke_event('on_ready') + self.dispatch('ready') elif event == 'MESSAGE_CREATE': channel = self.get_channel(data.get('channel_id')) message = Message(channel=channel, **data) - self._invoke_event('on_message', message) + self.dispatch('message', message) self.messages.append(message) elif event == 'MESSAGE_DELETE': channel = self.get_channel(data.get('channel_id')) message_id = data.get('id') found = self._get_message(message_id) if found is not None: - self._invoke_event('on_message_delete', found) + self.dispatch('message_delete', found) self.messages.remove(found) elif event == 'MESSAGE_UPDATE': older_message = self._get_message(data.get('id')) @@ -277,7 +295,7 @@ class Client(object): setattr(message, attr, utils.parse_time(value)) else: setattr(message, attr, value) - self._invoke_event('on_message_edit', older_message, message) + self.dispatch('message_edit', older_message, message) # update the older message older_message = message @@ -295,8 +313,8 @@ class Client(object): member.avatar = user.get('avatar', member.avatar) # call the event now - self._invoke_event('on_status', member) - self._invoke_event('on_member_update', member) + self.dispatch('status', member) + self.dispatch('member_update', member) elif event == 'USER_UPDATE': self.user = User(**data) elif event == 'CHANNEL_DELETE': @@ -305,14 +323,14 @@ class Client(object): channel_id = data.get('id') channel = utils.find(lambda c: c.id == channel_id, server.channels) server.channels.remove(channel) - self._invoke_event('on_channel_delete', channel) + self.dispatch('channel_delete', channel) elif event == 'CHANNEL_UPDATE': server = self._get_server(data.get('guild_id')) if server is not None: channel_id = data.get('id') channel = utils.find(lambda c: c.id == channel_id, server.channels) channel.update(server=server, **data) - self._invoke_event('on_channel_update', channel) + self.dispatch('channel_update', channel) elif event == 'CHANNEL_CREATE': is_private = data.get('is_private', False) channel = None @@ -327,18 +345,18 @@ class Client(object): channel = Channel(server=server, **data) server.channels.append(channel) - self._invoke_event('on_channel_create', channel) + self.dispatch('channel_create', channel) elif event == 'GUILD_MEMBER_ADD': server = self._get_server(data.get('guild_id')) member = Member(server=server, deaf=False, mute=False, **data) server.members.append(member) - self._invoke_event('on_member_join', member) + self.dispatch('member_join', member) elif event == 'GUILD_MEMBER_REMOVE': server = self._get_server(data.get('guild_id')) user_id = data['user']['id'] member = utils.find(lambda m: m.id == user_id, server.members) server.members.remove(member) - self._invoke_event('on_member_remove', member) + self.dispatch('member_remove', member) elif event == 'GUILD_MEMBER_UPDATE': server = self._get_server(data.get('guild_id')) user_id = data['user']['id'] @@ -354,21 +372,21 @@ class Client(object): if role.id in data['roles']: member.roles.append(role) - self._invoke_event('on_member_update', member) + self.dispatch('member_update', member) elif event == 'GUILD_CREATE': self._add_server(data) - self._invoke_event('on_server_create', self.servers[-1]) + self.dispatch('server_create', self.servers[-1]) elif event == 'GUILD_DELETE': server = self._get_server(data.get('id')) self.servers.remove(server) - self._invoke_event('on_server_delete', server) + self.dispatch('server_delete', server) def _opened(self): log.info('Opened at {}'.format(int(time.time()))) def _closed(self, code, reason=None): log.info('Closed with {} ("{}") at {}'.format(code, reason, int(time.time()))) - self._invoke_event('on_disconnect') + self.dispatch('disconnect') def run(self): """Runs the client and allows it to receive messages and events."""