Semi-stable? Pingme works. Stability of websockets under asyncio uncertain

This commit is contained in:
Jacob Henry 2018-11-08 02:11:58 -05:00
parent 418a7029bd
commit 42f2a64967
2 changed files with 41 additions and 25 deletions

46
main.py
View File

@ -1,17 +1,16 @@
import typing import asyncio
from typing import List from typing import List, Any, Match, AsyncGenerator
from slackclient import SlackClient # Obvious from slackclient import SlackClient # Obvious
import channel_util import channel_util
import identifier import identifier
import job_nagger import job_nagger
import job_signoff
import management_commands import management_commands
import scroll_util import scroll_util
import slack_util import slack_util
import slavestothemachine import slavestothemachine
import job_signoff
import asyncio
from dummy import FakeClient from dummy import FakeClient
# Read api token from file # Read api token from file
@ -58,7 +57,7 @@ def main() -> None:
wrap.add_hook(slack_util.Hook(help_callback, pattern=management_commands.bot_help_pattern)) wrap.add_hook(slack_util.Hook(help_callback, pattern=management_commands.bot_help_pattern))
# Schedule? # Schedule?
async def do_later(slk: SlackClient, msg: dict, match: typing.Match): async def do_later(slk: SlackClient, msg: dict, match: Match):
time = int(match.group(1)) time = int(match.group(1))
await asyncio.sleep(time) await asyncio.sleep(time)
slack_util.reply(slk, msg, "hello!") slack_util.reply(slk, msg, "hello!")
@ -92,11 +91,13 @@ class ClientWrapper(object):
def add_hook(self, hook: slack_util.Hook) -> None: def add_hook(self, hook: slack_util.Hook) -> None:
self.hooks.append(hook) self.hooks.append(hook)
async def listen(self) -> None: async def listen(self):
feed = self.async_message_feed() async for _ in self.spool_tasks():
async for msg in feed: print("Handling a message...!")
print(msg)
async def spool_tasks(self) -> AsyncGenerator[asyncio.Task, Any]:
async for msg in self.async_message_feed():
# Preprocess msg
# We only care about standard messages, not subtypes, as those usually just channel activity # We only care about standard messages, not subtypes, as those usually just channel activity
if msg.get("subtype") is not None: if msg.get("subtype") is not None:
continue continue
@ -105,10 +106,10 @@ class ClientWrapper(object):
if msg.get("channel") == channel_util.GENERAL: if msg.get("channel") == channel_util.GENERAL:
continue continue
# Handle Message # Strip garbage
msg['text'] = msg['text'].strip() msg['text'] = msg['text'].strip()
# If first few letters DEBUG, use debug slack # Handle debug
if msg['text'][:6] == "DEBUG ": if msg['text'][:6] == "DEBUG ":
slack_to_use = self.debug_slack slack_to_use = self.debug_slack
msg['text'] = msg['text'][6:] msg['text'] = msg['text'][6:]
@ -116,16 +117,27 @@ class ClientWrapper(object):
else: else:
slack_to_use = self.slack slack_to_use = self.slack
success = False # Msg is good
# Find which hook, if any, satisfies
sat_hook = None
sat_match = None
for hook in self.hooks: for hook in self.hooks:
if await hook.check(slack_to_use, msg): match = hook.check(msg)
success = True if match is not None:
sat_match = match
sat_hook = hook
break break
if not success: # If no hooks, continue
print("No hit on {}".format(msg['text'])) if not sat_hook:
continue
async def async_message_feed(self) -> typing.AsyncGenerator[dict, None]: # Throw up as a task, otherwise
coro = sat_hook.invoke(slack_to_use, msg, sat_match)
task = asyncio.create_task(coro)
yield task
async def async_message_feed(self) -> AsyncGenerator[dict, None]:
""" """
Async wrapper around the message feed. Async wrapper around the message feed.
Yields messages awaitably forever. Yields messages awaitably forever.

View File

@ -1,3 +1,4 @@
import asyncio
import re import re
from time import sleep from time import sleep
from typing import Any, Optional, Generator, Match, Callable, List, Coroutine from typing import Any, Optional, Generator, Match, Callable, List, Coroutine
@ -110,24 +111,27 @@ class Hook(object):
else: else:
raise Exception("Cannot whitelist and blacklist") raise Exception("Cannot whitelist and blacklist")
async def check(self, slack: SlackClient, msg: dict) -> bool: def check(self, msg: dict) -> Optional[Match]:
"""
Returns whether a message should be handled by this dict, returning a Match if so, or None
"""
# Fail if pattern invalid # Fail if pattern invalid
match = re.match(self.pattern, msg['text'], flags=re.IGNORECASE) match = re.match(self.pattern, msg['text'], flags=re.IGNORECASE)
if match is None: if match is None:
# print("Missed pattern") # print("Missed pattern")
return False return None
# Fail if whitelist defined, and we aren't there # Fail if whitelist defined, and we aren't there
if self.channel_whitelist is not None and msg["channel"] not in self.channel_whitelist: if self.channel_whitelist is not None and msg["channel"] not in self.channel_whitelist:
# print("Missed whitelist") # print("Missed whitelist")
return False return None
# Fail if blacklist defined, and we are there # Fail if blacklist defined, and we are there
if self.channel_blacklist is not None and msg["channel"] in self.channel_blacklist: if self.channel_blacklist is not None and msg["channel"] in self.channel_blacklist:
# print("Hit blacklist") # print("Hit blacklist")
return False return None
# Otherwise do callback and return success return match
print("Matched on pattern {} callback {}".format(self.pattern, self.callback))
await self.callback(slack, msg, match) def invoke(self, slack: SlackClient, msg: dict, match: Match):
return True return self.callback(slack, msg, match)