diff options
| -rwxr-xr-x | bin/dbolla | 7 | ||||
| -rw-r--r-- | warmachine/addons/base.py | 2 | ||||
| -rw-r--r-- | warmachine/addons/standup.py | 81 | ||||
| -rw-r--r-- | warmachine/connections/slack.py | 8 |
4 files changed, 66 insertions, 32 deletions
| @@ -4,6 +4,8 @@ import asyncio | |||
| 4 | import datetime | 4 | import datetime |
| 5 | import functools | 5 | import functools |
| 6 | import logging.config | 6 | import logging.config |
| 7 | import os | ||
| 8 | |||
| 7 | 9 | ||
| 8 | from warmachine.config import Config | 10 | from warmachine.config import Config |
| 9 | from warmachine.connections.irc import AioIRC | 11 | from warmachine.connections.irc import AioIRC |
| @@ -53,6 +55,8 @@ class Bot(object): | |||
| 53 | self.load_plugin('warmachine.addons.giphy.GiphySearch') | 55 | self.load_plugin('warmachine.addons.giphy.GiphySearch') |
| 54 | self.load_plugin('warmachine.addons.standup.StandUpPlugin') | 56 | self.load_plugin('warmachine.addons.standup.StandUpPlugin') |
| 55 | 57 | ||
| 58 | # TODO: Ensure the config directory has been created | ||
| 59 | |||
| 56 | def start(self): | 60 | def start(self): |
| 57 | for connection in self.connections: | 61 | for connection in self.connections: |
| 58 | t = asyncio.ensure_future(connection.connect()) | 62 | t = asyncio.ensure_future(connection.connect()) |
| @@ -64,6 +68,9 @@ class Bot(object): | |||
| 64 | self.connections[connection] = {} | 68 | self.connections[connection] = {} |
| 65 | 69 | ||
| 66 | def on_connect(self, connection, task): | 70 | def on_connect(self, connection, task): |
| 71 | for p in self.loaded_plugins: | ||
| 72 | if hasattr(p, 'on_connect'): | ||
| 73 | p.on_connect(connection) | ||
| 67 | asyncio.ensure_future(self.process_message(connection)) | 74 | asyncio.ensure_future(self.process_message(connection)) |
| 68 | 75 | ||
| 69 | async def process_message(self, connection): | 76 | async def process_message(self, connection): |
diff --git a/warmachine/addons/base.py b/warmachine/addons/base.py index aa23c78..e605c2c 100644 --- a/warmachine/addons/base.py +++ b/warmachine/addons/base.py | |||
| @@ -1,6 +1,8 @@ | |||
| 1 | import asyncio | ||
| 1 | import logging | 2 | import logging |
| 2 | 3 | ||
| 3 | 4 | ||
| 4 | class WarMachinePlugin(object): | 5 | class WarMachinePlugin(object): |
| 5 | def __init__(self): | 6 | def __init__(self): |
| 7 | self._loop = asyncio.get_event_loop() | ||
| 6 | self.log = logging.getLogger(self.__class__.__name__) | 8 | self.log = logging.getLogger(self.__class__.__name__) |
diff --git a/warmachine/addons/standup.py b/warmachine/addons/standup.py index dc5f70a..99094d5 100644 --- a/warmachine/addons/standup.py +++ b/warmachine/addons/standup.py | |||
| @@ -30,6 +30,9 @@ class StandUpPlugin(WarMachinePlugin): | |||
| 30 | # } | 30 | # } |
| 31 | self.users_awaiting_reply = {} | 31 | self.users_awaiting_reply = {} |
| 32 | 32 | ||
| 33 | def on_connect(self, connection): | ||
| 34 | self.load_schedule(connection) | ||
| 35 | |||
| 33 | async def recv_msg(self, connection, message): | 36 | async def recv_msg(self, connection, message): |
| 34 | """ | 37 | """ |
| 35 | When the connection receives a message this method is called. We parse | 38 | When the connection receives a message this method is called. We parse |
| @@ -73,39 +76,12 @@ class StandUpPlugin(WarMachinePlugin): | |||
| 73 | cmd = message['message'].split(' ')[0] | 76 | cmd = message['message'].split(' ')[0] |
| 74 | parts = message['message'].split(' ')[1:] | 77 | parts = message['message'].split(' ')[1:] |
| 75 | 78 | ||
| 76 | self._loop = asyncio.get_event_loop() | ||
| 77 | |||
| 78 | ################ | 79 | ################ |
| 79 | # !standup-add # | 80 | # !standup-add # |
| 80 | ################ | 81 | ################ |
| 81 | if cmd == '!standup-add': | 82 | if cmd == '!standup-add': |
| 82 | next_standup = self.get_next_standup_secs(parts[0]) | 83 | self.schedule_standup(connection, message['channel'], parts[0]) |
| 83 | 84 | self.save_schedule(connection) | |
| 84 | standup_td = next_standup - datetime.now() | ||
| 85 | next_standup_secs = standup_td.seconds | ||
| 86 | |||
| 87 | f = self._loop.call_later( | ||
| 88 | next_standup_secs, functools.partial( | ||
| 89 | self.standup_schedule_func, connection, message['channel'])) | ||
| 90 | |||
| 91 | self.standup_schedules[message['channel']] = { | ||
| 92 | 'future': f, | ||
| 93 | 'datetime': next_standup, | ||
| 94 | 'time24h': parts[0], | ||
| 95 | } | ||
| 96 | |||
| 97 | self.log.info('New schedule added to channel {} for {}'.format( | ||
| 98 | connection.channel_map[message['channel']]['name'], | ||
| 99 | parts[0] | ||
| 100 | )) | ||
| 101 | |||
| 102 | await connection.say('Next standup at {} ({}s)'.format( | ||
| 103 | next_standup.ctime(), next_standup_secs), message['channel']) | ||
| 104 | |||
| 105 | # d = json.dumps(self.standup_schedules) | ||
| 106 | # with open('~/.warmachine/standup_schedules.json', 'w') as f: | ||
| 107 | # f.write(d) | ||
| 108 | |||
| 109 | 85 | ||
| 110 | ###################### | 86 | ###################### |
| 111 | # !standup-schedules # | 87 | # !standup-schedules # |
| @@ -122,6 +98,7 @@ class StandUpPlugin(WarMachinePlugin): | |||
| 122 | 'Current Time: {}'.format(datetime.now()), message['channel']) | 98 | 'Current Time: {}'.format(datetime.now()), message['channel']) |
| 123 | await connection.say( | 99 | await connection.say( |
| 124 | pformat(self.standup_schedules), message['channel']) | 100 | pformat(self.standup_schedules), message['channel']) |
| 101 | |||
| 125 | ############################ | 102 | ############################ |
| 126 | # !standup-waiting_replies # | 103 | # !standup-waiting_replies # |
| 127 | ############################ | 104 | ############################ |
| @@ -134,6 +111,30 @@ class StandUpPlugin(WarMachinePlugin): | |||
| 134 | await connection.say( | 111 | await connection.say( |
| 135 | pformat(self.users_awaiting_reply), message['channel']) | 112 | pformat(self.users_awaiting_reply), message['channel']) |
| 136 | 113 | ||
| 114 | def schedule_standup(self, connection, channel, time24h): | ||
| 115 | """ | ||
| 116 | Schedules a standup | ||
| 117 | """ | ||
| 118 | next_standup = self.get_next_standup_secs(time24h) | ||
| 119 | |||
| 120 | standup_td = next_standup - datetime.now() | ||
| 121 | next_standup_secs = standup_td.seconds | ||
| 122 | |||
| 123 | f = self._loop.call_later( | ||
| 124 | next_standup_secs, functools.partial( | ||
| 125 | self.standup_schedule_func, connection, channel)) | ||
| 126 | |||
| 127 | self.standup_schedules[channel] = { | ||
| 128 | 'future': f, | ||
| 129 | 'datetime': next_standup, | ||
| 130 | 'time24h': time24h, | ||
| 131 | } | ||
| 132 | |||
| 133 | self.log.info('New schedule added to channel {} for {}'.format( | ||
| 134 | connection.channel_map[channel]['name'], | ||
| 135 | time24h | ||
| 136 | )) | ||
| 137 | |||
| 137 | def standup_schedule_func(self, connection, channel): | 138 | def standup_schedule_func(self, connection, channel): |
| 138 | """ | 139 | """ |
| 139 | Non-async function used to schedule the standup for a channel. | 140 | Non-async function used to schedule the standup for a channel. |
| @@ -249,12 +250,30 @@ class StandUpPlugin(WarMachinePlugin): | |||
| 249 | 250 | ||
| 250 | return next_standup | 251 | return next_standup |
| 251 | 252 | ||
| 252 | def save_schedule(self): | 253 | def save_schedule(self, connection): |
| 253 | """ | 254 | """ |
| 254 | Save all channel schedules to a file. | 255 | Save all channel schedules to a file. |
| 255 | """ | 256 | """ |
| 257 | keys_to_save = ['time24h', ] | ||
| 258 | data = {} | ||
| 259 | for channel in self.standup_schedules: | ||
| 260 | data[channel] = {} | ||
| 261 | for key in keys_to_save: | ||
| 262 | data[channel][key] = self.standup_schedules[channel][key] | ||
| 263 | |||
| 264 | data = {connection.id: data} | ||
| 265 | with open('/home/jason/.warmachine/standup_schedules.json', 'w') as f: | ||
| 266 | f.write(json.dumps(data)) | ||
| 256 | 267 | ||
| 257 | def load_schedule(self): | 268 | self.log.info('Schedules saved to disk') |
| 269 | |||
| 270 | def load_schedule(self, connection): | ||
| 258 | """ | 271 | """ |
| 259 | Load the channel schedules from a file. | 272 | Load the channel schedules from a file. |
| 260 | """ | 273 | """ |
| 274 | with open('/home/jason/.warmachine/standup_schedules.json', 'r') as f: | ||
| 275 | data = json.loads(f.read()) | ||
| 276 | |||
| 277 | for channel in data[connection.id]: | ||
| 278 | self.schedule_standup( | ||
| 279 | connection, channel, data[connection.id][channel]['time24h']) | ||
diff --git a/warmachine/connections/slack.py b/warmachine/connections/slack.py index 0cc69d4..8ae52da 100644 --- a/warmachine/connections/slack.py +++ b/warmachine/connections/slack.py | |||
| @@ -8,7 +8,7 @@ import urllib.request | |||
| 8 | import websockets | 8 | import websockets |
| 9 | 9 | ||
| 10 | from .base import Connection, INITALIZED, CONNECTED | 10 | from .base import Connection, INITALIZED, CONNECTED |
| 11 | 11 | from ..utils.decorators import memoize | |
| 12 | 12 | ||
| 13 | #: Define slack as a config section prefix | 13 | #: Define slack as a config section prefix |
| 14 | __config_prefix__ = 'slack' | 14 | __config_prefix__ = 'slack' |
| @@ -36,6 +36,12 @@ class SlackWS(Connection): | |||
| 36 | 36 | ||
| 37 | self.status = INITALIZED | 37 | self.status = INITALIZED |
| 38 | 38 | ||
| 39 | @property | ||
| 40 | @memoize | ||
| 41 | def id(self): | ||
| 42 | from hashlib import md5 | ||
| 43 | return md5(self.token.encode()).hexdigest() | ||
| 44 | |||
| 39 | async def connect(self): | 45 | async def connect(self): |
| 40 | self.host = self.authenticate() | 46 | self.host = self.authenticate() |
| 41 | self.log.info('Connecting to {}'.format(self.host)) | 47 | self.log.info('Connecting to {}'.format(self.host)) |