Things are less hacky now. WIP

This commit is contained in:
Jacob Henry 2019-02-20 20:46:58 -05:00
parent b35593b89d
commit fe33a5a0e4
9 changed files with 115 additions and 54 deletions

View File

@ -27,5 +27,5 @@ async def channel_check_callback(slack: SlackClient, msg: dict, match: Match) ->
slack_util.reply(slack, msg, response)
channel_check_hook = slack_util.Hook(channel_check_callback,
patterns=r"channel id\s*(.*)")
channel_check_hook = slack_util.ChannelHook(channel_check_callback,
patterns=r"channel id\s*(.*)")

View File

@ -123,5 +123,5 @@ class ClientWrapper(object):
_singleton = ClientWrapper()
def get_client_wrapper() -> ClientWrapper:
def grab() -> ClientWrapper:
return _singleton

View File

@ -138,7 +138,7 @@ def lookup_brother_userids(brother: scroll_util.Brother) -> List[str]:
return result
identify_hook = slack_util.Hook(identify_callback, patterns=r"my scroll is (.*)")
identify_other_hook = slack_util.Hook(identify_other_callback, patterns=r"<@(.*)>\s+has scroll\s+(.*)")
check_hook = slack_util.Hook(check_callback, patterns=r"what is my scroll")
name_hook = slack_util.Hook(name_callback, patterns=r"what is my name")
identify_hook = slack_util.ChannelHook(identify_callback, patterns=r"my scroll is (.*)")
identify_other_hook = slack_util.ChannelHook(identify_other_callback, patterns=r"<@(.*)>\s+has scroll\s+(.*)")
check_hook = slack_util.ChannelHook(check_callback, patterns=r"what is my scroll")
name_hook = slack_util.ChannelHook(name_callback, patterns=r"what is my name")

View File

@ -149,7 +149,7 @@ async def _mod_jobs(slack: SlackClient,
new_hook = slack_util.ReplyWaiter(foc, pattern, msg["ts"], 120)
# Register it
client_wrapper.get_client_wrapper().add_hook(new_hook)
client_wrapper.grab().add_hook(new_hook)
async def signoff_callback(slack: SlackClient, msg: dict, match: Match) -> None:
@ -351,50 +351,50 @@ async def nag_callback(slack, msg, match):
slack_util.reply(slack, msg, response, in_thread=False, to_channel=channel_util.GENERAL)
signoff_hook = slack_util.Hook(signoff_callback,
patterns=[
signoff_hook = slack_util.ChannelHook(signoff_callback,
patterns=[
r"signoff\s+(.*)",
r"sign off\s+(.*)",
],
channel_whitelist=[channel_util.HOUSEJOBS])
channel_whitelist=[channel_util.HOUSEJOBS])
undo_hook = slack_util.Hook(undo_callback,
patterns=[
undo_hook = slack_util.ChannelHook(undo_callback,
patterns=[
r"unsignoff\s+(.*)",
r"undosignoff\s+(.*)",
r"undo signoff\s+(.*)",
],
channel_whitelist=[channel_util.HOUSEJOBS])
channel_whitelist=[channel_util.HOUSEJOBS])
late_hook = slack_util.Hook(late_callback,
patterns=[
late_hook = slack_util.ChannelHook(late_callback,
patterns=[
r"marklate\s+(.*)",
r"mark late\s+(.*)",
],
channel_whitelist=[channel_util.HOUSEJOBS])
channel_whitelist=[channel_util.HOUSEJOBS])
reset_hook = slack_util.Hook(reset_callback,
patterns=[
reset_hook = slack_util.ChannelHook(reset_callback,
patterns=[
r"reset signoffs",
r"reset sign offs",
],
channel_whitelist=[channel_util.COMMAND_CENTER_ID])
channel_whitelist=[channel_util.COMMAND_CENTER_ID])
nag_hook = slack_util.Hook(nag_callback,
patterns=[
nag_hook = slack_util.ChannelHook(nag_callback,
patterns=[
r"nagjobs\s+(.*)",
r"nag jobs\s+(.*)"
],
channel_whitelist=[channel_util.COMMAND_CENTER_ID])
channel_whitelist=[channel_util.COMMAND_CENTER_ID])
reassign_hook = slack_util.Hook(reassign_callback,
patterns=r"reassign\s+(.*?)-&gt;\s+(.+)",
channel_whitelist=[channel_util.HOUSEJOBS])
reassign_hook = slack_util.ChannelHook(reassign_callback,
patterns=r"reassign\s+(.*?)-&gt;\s+(.+)",
channel_whitelist=[channel_util.HOUSEJOBS])
refresh_hook = slack_util.Hook(refresh_callback,
patterns=[
refresh_hook = slack_util.ChannelHook(refresh_callback,
patterns=[
"refresh points",
"update points"
],
channel_whitelist=[channel_util.COMMAND_CENTER_ID]
)
channel_whitelist=[channel_util.COMMAND_CENTER_ID]
)

View File

@ -16,7 +16,7 @@ import slavestothemachine
def main() -> None:
wrap = client_wrapper.get_client_wrapper()
wrap = client_wrapper.grab()
# Add scroll handling
wrap.add_hook(scroll_util.scroll_hook)
@ -46,7 +46,7 @@ def main() -> None:
wrap.add_hook(job_commands.refresh_hook)
# Add help
wrap.add_hook(slack_util.Hook(help_callback, patterns=[r"help", r"bot\s+help"]))
wrap.add_hook(slack_util.ChannelHook(help_callback, patterns=[r"help", r"bot\s+help"]))
# Add boozebot
# wrap.add_passive(periodicals.ItsTenPM())

View File

@ -6,7 +6,7 @@ import channel_util
import slack_util
def list_hooks_callback_gen(hooks: List[slack_util.Hook]) -> slack_util.Callback:
def list_hooks_callback_gen(hooks: List[slack_util.ChannelHook]) -> slack_util.Callback:
# noinspection PyUnusedLocal
async def callback(slack, msg, match):
slack_util.reply(slack, msg, "\n".join(hook.patterns for hook in hooks))
@ -23,6 +23,6 @@ async def reboot_callback(slack: SlackClient, msg: dict, match: Match) -> None:
# Make hooks
reboot_hook = slack_util.Hook(reboot_callback,
patterns=r"reboot",
channel_whitelist=[channel_util.COMMAND_CENTER_ID])
reboot_hook = slack_util.ChannelHook(reboot_callback,
patterns=r"reboot",
channel_whitelist=[channel_util.COMMAND_CENTER_ID])

View File

@ -105,4 +105,4 @@ async def find_by_name(name: str, threshold: Optional[float] = None) -> Brother:
raise BrotherNotFound(msg)
scroll_hook = slack_util.Hook(scroll_callback, patterns=r"scroll\s+(.*)")
scroll_hook = slack_util.ChannelHook(scroll_callback, patterns=r"scroll\s+(.*)")

View File

@ -1,4 +1,6 @@
from __future__ import annotations
import re
from dataclasses import dataclass
from time import sleep, time
from typing import Any, Optional, Generator, Match, Callable, List, Coroutine, Union, TypeVar, Awaitable
@ -10,9 +12,10 @@ Slack helpers. Separated for compartmentalization
"""
def reply(slack: SlackClient, msg: dict, text: str, in_thread: bool = True, to_channel: str = None) -> dict:
def reply(msg: dict, text: str, in_thread: bool = True, to_channel: str = None) -> dict:
"""
Sends message with "text" as its content to the channel that message came from
Sends message with "text" as its content to the channel that message came from.
Returns the JSON response.
"""
# If no channel specified, just do same as msg
if to_channel is None:
@ -27,9 +30,10 @@ def reply(slack: SlackClient, msg: dict, text: str, in_thread: bool = True, to_c
return send_message(slack, text, to_channel)
def send_message(slack: SlackClient, text: str, channel: str, thread: str = None, broadcast: bool = False) -> dict:
def send_message(text: str, channel: str, thread: str = None, broadcast: bool = False) -> dict:
"""
Copy of the internal send message function of slack
Copy of the internal send message function of slack, with some helpful options.
Returns the JSON response.
"""
kwargs = {"channel": channel, "text": text}
if thread:
@ -40,7 +44,58 @@ def send_message(slack: SlackClient, text: str, channel: str, thread: str = None
return slack.api_call("chat.postMessage", **kwargs)
def message_stream(slack: SlackClient) -> Generator[dict, None, None]:
"""
Objects to represent things
"""
class User:
pass
class Channel:
@property
def channel_name(self) -> str:
raise NotImplementedError()
"""
Below we have a modular system that represents possible event contents.
"""
@dataclass
class Event:
channel: Optional[ChannelContext]
user: Optional[UserContext]
message: Optional[Message]
# If this was posted in a specific channel or conversation
@dataclass
class ChannelContext:
channel_id: str
# If there is a specific user associated with this event
@dataclass
class UserContext:
user_id: str
def as_user(self) -> User:
raise NotImplementedError()
# Whether or not this is a threadable text message
@dataclass
class Message:
ts: str
text: str
@dataclass
class File:
pass
def message_stream(slack: SlackClient) -> Generator[Event, None, None]:
"""
Generator that yields messages from slack.
Messages are in standard api format, look it up.
@ -83,35 +138,41 @@ class VerboseWrapper(Callable):
try:
return await awt
except Exception as e:
reply(self.slack, self.command_msg, "Error: {}".format(str(e)), True)
reply(self.command_msg, "Error: {}".format(str(e)), True)
raise e
# The result of a message
MsgAction = Coroutine[Any, Any, None]
Callback = Callable[[SlackClient, dict, Match], MsgAction]
# The function called on a message
Callback = Callable[[SlackClient, Message, Match], MsgAction]
class DeadHook(Exception):
pass
# Abstract hook parent class
class AbsHook(object):
def __init__(self, consumes_applicable: bool):
# Whether or not messages that yield a coroutine should not be checked further
self.consumes = consumes_applicable
def try_apply(self, slack: SlackClient, msg: dict) -> Optional[Coroutine[None, None, None]]:
def try_apply(self, event: Event) -> Optional[MsgAction]:
raise NotImplementedError()
class Hook(AbsHook):
class ChannelHook(AbsHook):
"""
Hook that handles messages in a variety of channels
"""
def __init__(self,
callback: Callback,
patterns: Union[str, List[str]],
channel_whitelist: Optional[List[str]] = None,
channel_blacklist: Optional[List[str]] = None,
consumer: bool = True):
super(Hook, self).__init__(consumer)
super(ChannelHook, self).__init__(consumer)
# Save all
if not isinstance(patterns, list):
@ -131,7 +192,7 @@ class Hook(AbsHook):
else:
raise ValueError("Cannot whitelist and blacklist")
def try_apply(self, slack: SlackClient, msg: dict) -> Optional[Coroutine[None, None, None]]:
def try_apply(self, event: Event) -> Optional[MsgAction]:
"""
Returns whether a message should be handled by this dict, returning a Match if so, or None
"""
@ -170,7 +231,7 @@ class ReplyWaiter(AbsHook):
self.start_time = time()
self.dead = False
def try_apply(self, slack: SlackClient, msg: dict) -> Optional[Coroutine[None, None, None]]:
def try_apply(self, event: Event) -> Optional[MsgAction]:
# First check: are we dead of age yet?
time_alive = time() - self.start_time
should_expire = time_alive > self.lifetime
@ -199,6 +260,6 @@ class Passive(object):
Base class for Periodical tasks, such as reminders and stuff
"""
async def run(self, slack: SlackClient) -> None:
async def run(self) -> None:
# Run this passive routed through the specified slack client.
raise NotImplementedError()

View File

@ -89,7 +89,7 @@ async def record_towel_contribution(for_brother: Brother, contribution_count: in
# Make dem HOOKs
count_work_hook = slack_util.Hook(count_work_callback,
patterns=".*",
channel_whitelist=[channel_util.SLAVES_TO_THE_MACHINE_ID],
consumer=False)
count_work_hook = slack_util.ChannelHook(count_work_callback,
patterns=".*",
channel_whitelist=[channel_util.SLAVES_TO_THE_MACHINE_ID],
consumer=False)