From 7ad074083492e78c66e705b97699c92e5d38541a Mon Sep 17 00:00:00 2001 From: Trygve Aaberge Date: Sun, 20 Nov 2022 19:35:28 +0100 Subject: Create buffers on connect --- slack/api.py | 111 ++++++++++++++++++++++++++++++++++++++++++++++-------- slack/commands.py | 19 ++++++++++ slack/init.py | 44 ++++++++++++++-------- slack/task.py | 7 +++- 4 files changed, 148 insertions(+), 33 deletions(-) (limited to 'slack') diff --git a/slack/api.py b/slack/api.py index 52479ae..3b7feb9 100644 --- a/slack/api.py +++ b/slack/api.py @@ -1,14 +1,21 @@ from __future__ import annotations import json -from typing import TYPE_CHECKING, Dict, Union +from typing import TYPE_CHECKING, Dict, Optional, Union from urllib.parse import urlencode +import weechat + from slack.http import http_request from slack.shared import shared +from slack.task import await_all_concurrent, create_task if TYPE_CHECKING: - from slack_api import SlackConversation, SlackConversationIm, SlackConversationNotIm + from slack_api import ( + SlackConversationIm, + SlackConversationInfo, + SlackConversationNotIm, + ) class SlackApi: @@ -55,27 +62,99 @@ class SlackWorkspace: self.api = SlackApi(self) self.connected = False self.nick = "TODO" + # Maybe make private, so you have to use get_user? Maybe make get_user a getter, though don't know if that's a problem since it's async + self.users: Dict[str, SlackUser] = {} + self.conversations: Dict[str, SlackConversation] = {} + + async def connect(self): + # rtm_connect = await self.api.fetch("rtm.connect") + user_channels_response = await self.api.fetch_list( + "users.conversations", + "channels", + { + "exclude_archived": True, + # "types": "public_channel,private_channel,im", + "types": "public_channel", + "limit": 1000, + }, + -1, + ) + user_channels = user_channels_response["channels"] + + for channel in user_channels: + conversation = SlackConversation(self, channel["id"]) + self.conversations[channel["id"]] = conversation + create_task(conversation.init()) + + # print(rtm_connect) + # print([c["name"] for c in user_channels]) + + async def get_user(self, id: str) -> SlackUser: + if id in self.users: + return self.users[id] + user = SlackUser(self, id) + await user.init() + self.users[id] = user + return user + + def get_conversation_from_buffer_pointer( + self, buffer_pointer: str + ) -> Optional[SlackConversation]: + for conversation in self.conversations.values(): + if conversation.buffer_pointer == buffer_pointer: + return conversation + + +class SlackUser: + def __init__(self, workspace: SlackWorkspace, id: str): + self.workspace = workspace + self.api = workspace.api + self.id = id + self.name: str + async def init(self): + info = await self.api.fetch("users.info", {"user": self.id}) + self.name = info["user"]["name"] -class SlackChannelCommonNew: - def __init__(self, workspace: SlackWorkspace, slack_info: SlackConversation): + +class SlackConversation: + def __init__(self, workspace: SlackWorkspace, id: str): self.workspace = workspace self.api = workspace.api - self.id = slack_info["id"] - # self.fetch_info() + self.id = id + self.buffer_pointer: str + self.name: str + self.history_filled = False + self.history_pending = False + + async def init(self): + info = await self.fetch_info() + self.name = info["channel"]["name"] + self.buffer_pointer = weechat.buffer_new(self.name, "", "", "", "") async def fetch_info(self): - response = await self.api.fetch("conversations.info", {"channel": self.id}) - print(len(response)) + return await self.api.fetch("conversations.info", {"channel": self.id}) + async def fill_history(self): + if self.history_filled or self.history_pending: + return + self.history_pending = True -class SlackChannelNew(SlackChannelCommonNew): - def __init__(self, workspace: SlackWorkspace, slack_info: SlackConversationNotIm): - super().__init__(workspace, slack_info) - self.name = slack_info["name"] + history = await self.api.fetch("conversations.history", {"channel": self.id}) + + messages = history["messages"] + user_ids = [message["user"] for message in messages if "user" in message] + await await_all_concurrent( + [self.workspace.get_user(user_id) for user_id in user_ids] + ) + for message in reversed(messages): + if "user" in message: + user = await self.workspace.get_user(message["user"]) + username = user.name + else: + username = "bot" + weechat.prnt(self.buffer_pointer, f'{username}\t{message["text"]}') -class SlackIm(SlackChannelCommonNew): - def __init__(self, workspace: SlackWorkspace, slack_info: SlackConversationIm): - super().__init__(workspace, slack_info) - self.user = slack_info["user"] + self.history_filled = True + self.history_pending = False diff --git a/slack/commands.py b/slack/commands.py index bf48dda..1acf545 100644 --- a/slack/commands.py +++ b/slack/commands.py @@ -11,6 +11,7 @@ from slack.api import SlackWorkspace from slack.config import WeeChatOption from slack.log import print_error from slack.shared import shared +from slack.task import create_task from slack.util import get_callback_name, with_color commands: Dict[str, Command] = {} @@ -99,6 +100,24 @@ def command_slack(buffer: str, args: List[str], options: Dict[str, Optional[str] print("ran slack") +@weechat_command("%(slack_workspaces)") +def command_slack_connect( + buffer: str, args: List[str], options: Dict[str, Optional[str]] +): + async def connect(): + if args and args[0]: + workspace = shared.workspaces.get(args[0]) + if workspace: + await workspace.connect() + else: + print_error(f'workspace "{args[0]}" not found') + else: + for workspace in shared.workspaces.values(): + await workspace.connect() + + create_task(connect(), final=True) + + @weechat_command() def command_slack_workspace( buffer: str, args: List[str], options: Dict[str, Optional[str]] diff --git a/slack/init.py b/slack/init.py index ff95f57..3964a51 100644 --- a/slack/init.py +++ b/slack/init.py @@ -1,9 +1,9 @@ import weechat from slack.commands import register_commands -from slack.config import SlackConfig, SlackWorkspace +from slack.config import SlackConfig from slack.shared import shared -from slack.task import create_task +from slack.task import create_task, sleep from slack.util import get_callback_name SCRIPT_AUTHOR = "Trygve Aaberge " @@ -17,21 +17,25 @@ def shutdown_cb(): return weechat.WEECHAT_RC_OK +def signal_buffer_switch_cb(data: str, signal: str, signal_data: str) -> int: + current_conversation = None + for workspace in shared.workspaces.values(): + conversation = workspace.get_conversation_from_buffer_pointer(signal_data) + if conversation: + current_conversation = conversation + + if current_conversation: + create_task(current_conversation.fill_history()) + return weechat.WEECHAT_RC_OK + + async def init(): - pass - # print(shared.workspaces) - # if "wee-slack-test" not in shared.workspaces: - # shared.workspaces["wee-slack-test"] = SlackWorkspace("wee-slack-test") - # shared.workspaces[ - # "wee-slack-test" - # ].config.api_token.value = weechat.config_get_plugin("api_token") - # shared.workspaces[ - # "wee-slack-test" - # ].config.api_cookies.value = weechat.config_get_plugin("api_cookie") - # workspace = shared.workspaces["wee-slack-test"] - # print(workspace) - # print(workspace.config.slack_timeout.value) - # print(shared.config.color.reaction_suffix.value) + auto_connect = weechat.info_get("auto_connect", "") == "1" + if auto_connect: + await sleep(1) # Defer auto connect to ensure the logger plugin is loaded + for workspace in shared.workspaces.values(): + if workspace.config.autoconnect.value: + await workspace.connect() def main(): @@ -49,4 +53,12 @@ def main(): shared.config = SlackConfig() shared.config.config_read() register_commands() + + weechat.hook_signal( + "buffer_switch", get_callback_name(signal_buffer_switch_cb), "" + ) + weechat.hook_signal( + "window_switch", get_callback_name(signal_buffer_switch_cb), "" + ) + create_task(init(), final=True) diff --git a/slack/task.py b/slack/task.py index 2caf264..27abd48 100644 --- a/slack/task.py +++ b/slack/task.py @@ -1,6 +1,6 @@ from __future__ import annotations -from typing import Any, Awaitable, Coroutine, Generator, Tuple, TypeVar +from typing import Any, Awaitable, Coroutine, Generator, List, Tuple, TypeVar from uuid import uuid4 import weechat @@ -75,6 +75,11 @@ def create_task( return task +async def await_all_concurrent(requests: List[Coroutine[Any, Any, T]]) -> List[T]: + tasks = [create_task(request) for request in requests] + return [await task for task in tasks] + + async def sleep(milliseconds: int): future = FutureTimer() weechat.hook_timer( -- cgit