From d3fc36c85d4b58bfb852c86ad09f95f8e24e4db3 Mon Sep 17 00:00:00 2001 From: jason Date: Thu, 18 Aug 2016 18:18:33 -0600 Subject: misc updates - updates slack.py to use 'unique' message ids - updates standup to clear out channels waiting for a reply after 8 hours --- warmachine/addons/standup.py | 47 ++++++++++++++++++++++++++++++++++++++--- warmachine/connections/slack.py | 19 ++++++++++++----- 2 files changed, 58 insertions(+), 8 deletions(-) diff --git a/warmachine/addons/standup.py b/warmachine/addons/standup.py index fd75473..6ee6378 100644 --- a/warmachine/addons/standup.py +++ b/warmachine/addons/standup.py @@ -257,7 +257,7 @@ class StandUpPlugin(WarMachinePlugin): def clear_old_standup_message_schedule_func(self, user): """ This function is scheduled to remove old standup messages so that the - user is asked about standup the following day. + user is asked for updates on the next standup. """ self.log.info('Clearing old standup message for {}'.format(user)) del self.users_awaiting_reply[user]['clear_standup_msg_f'] @@ -287,6 +287,17 @@ class StandUpPlugin(WarMachinePlugin): else: await self.standup_priv_msg(connection, u, channel) + # schedule a function to run in 12 hours to clear out this channel from + # self.users_awaiting_reply for all `users`. + # This is assuming that after 12 hours, nobody cares about the report + # from people who never reported earlier. It will prevent flooding + # "tomorrow's" response to channels whose standup is scheduled for + # later. + self._loop.call_later(8*(60*60), # 8 hours + self.clean_channel_from_waiting_replies, channel, + users) + + async def standup_priv_msg(self, connection, user, channel, pester=600, pester_count=0): """ @@ -314,11 +325,13 @@ class StandUpPlugin(WarMachinePlugin): 'for_channels': [channel, ], } + for_channels = self.users_awaiting_reply[user]['for_channels'] await connection.say('What did you do yesterday? What will you ' 'do today? do you have any blockers? ' - '(standup for:{})'.format(channel), user) + '(standup for:{})'.format( + ', '.join(for_channels)), user) - if pester > 0 and pester_count <= 6: + if pester > 0 and pester_count <= 5: self.log.info('Scheduling pester for {} {}m from now'.format( user, pester/60)) f = self._loop.call_later( @@ -366,6 +379,31 @@ class StandUpPlugin(WarMachinePlugin): return next_standup + def clean_channel_from_waiting_replies(self, channel, users): + """ + This clears ``channel`` from the list of interested channels for a + user's stand up, so that when the next stand up comes and they answer, + the other channels won't recieve information they are most likely not + interested in anymore + + Args: + channel (str): The channel to clear out + users (list): List of users to check for + """ + for u in users: + if u in self.users_awaiting_reply: + self.log.info('Clearing channel {} from list of waiting ' + 'channels for user {}'.format(channel, u)) + self.users_awaiting_reply[u]['for_channels'].remove(channel) + + # if that was the last channel, kill any pester tasks + if not self.users_awaiting_reply[u]['for_channels'] and \ + self.users_awaiting_reply[u]['pester_task']: + self.log.info('No more interested channels for {}. ' + 'Cancelling pester.'.format(u)) + self.users_awaiting_reply[u]['pester_task'].cancel() + del self.users_awaiting_reply[u]['pester_task'] + def save_schedule(self, connection): """ Save all channel schedules to a file. @@ -394,6 +432,9 @@ class StandUpPlugin(WarMachinePlugin): self.log.debug('Error loading standup schedules: {}'.format(e)) return + if connection.id not in data: + return + for channel in data[connection.id]: self.schedule_standup( connection, channel, data[connection.id][channel]['time24h']) diff --git a/warmachine/connections/slack.py b/warmachine/connections/slack.py index 79c80a2..07e026c 100644 --- a/warmachine/connections/slack.py +++ b/warmachine/connections/slack.py @@ -34,6 +34,8 @@ class SlackWS(Connection): self.my_id = '000' self.ws = None + # used to give messages an id. slack requirement + self._internal_msgid = 0 self.status = INITALIZED @@ -53,7 +55,14 @@ class SlackWS(Connection): async def read(self): if self.ws: - message = json.loads(await self.ws.recv()) + try: + message = json.loads(await self.ws.recv()) + except websockets.ConnectionClosed as e: + self.log.error('Connection Closed: {}'.format(e)) + while not self.connect(): + self.error('Trying to reconnect...') + await asyncio.sleep(300) + return # Slack is acknowledging a message was sent. Do nothing if 'reply_to' in message: # {'ok': True, @@ -61,10 +70,10 @@ class SlackWS(Connection): # 'text': "['!whois', 'synic']", # 'ts': '1469743355.000150'} self.log.debug('Ignoring reply_to message: {}'.format( - pformat(message))) + message)) return - self.log.debug('new slack message: {}'.format(pformat(message))) + self.log.debug('new slack message: {}'.format(message)) if message['type'] == 'message' and 'subtype' not in message: # Handle text messages from users return await self.process_message(message) @@ -104,8 +113,9 @@ class SlackWS(Connection): destination = self.get_dm_id_by_user(_user) + self._internal_msgid += 1 message = { - 'id': 1, # TODO: this should be a get_msgid call or something + 'id': self._internal_msgid, 'type': 'message', 'channel': destination, 'text': str(message) @@ -301,7 +311,6 @@ class SlackWS(Connection): for u_id in r[key]['members']: users.append(self.user_map[u_id]['name']) - self.log.debug(pformat(users)) return users async def on_group_join(self, channel): -- cgit v1.2.1