aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTrygve Aaberge <trygveaa@gmail.com>2023-01-14 06:48:11 +0100
committerTrygve Aaberge <trygveaa@gmail.com>2024-02-18 11:32:53 +0100
commit78e551804dfd1784f10c627dd4c8d019214b66a1 (patch)
treee41a030098c6a3d786c6a5160a94b9b2957769d7
parenteed3b0a919e3790c4383548e3d30c83070465e7d (diff)
downloadwee-slack-78e551804dfd1784f10c627dd4c8d019214b66a1.tar.gz
Split slack classes into multiple files
-rw-r--r--slack/api.py246
-rw-r--r--slack/commands.py2
-rw-r--r--slack/config.py2
-rw-r--r--slack/http.py2
-rw-r--r--slack/init.py4
-rw-r--r--slack/log.py2
-rw-r--r--slack/shared.py2
-rw-r--r--slack/slack_conversation.py107
-rw-r--r--slack/slack_message.py48
-rw-r--r--slack/slack_user.py21
-rw-r--r--slack/slack_workspace.py98
-rw-r--r--slack/util.py2
12 files changed, 286 insertions, 250 deletions
diff --git a/slack/api.py b/slack/api.py
deleted file mode 100644
index 2f4b738..0000000
--- a/slack/api.py
+++ /dev/null
@@ -1,246 +0,0 @@
-from __future__ import annotations
-
-import json
-import re
-import time
-from contextlib import contextmanager
-from typing import TYPE_CHECKING, Any, Dict, List, Optional, Union
-from urllib.parse import urlencode
-
-import weechat
-
-from slack.http import http_request
-from slack.shared import shared
-from slack.task import Future, create_task, gather
-from slack.util import get_callback_name
-
-if TYPE_CHECKING:
- from slack_api import SlackConversationInfoResponse
-
-
-def get_conversation_from_buffer_pointer(
- buffer_pointer: str,
-) -> Optional[SlackConversation]:
- for workspace in shared.workspaces.values():
- for conversation in workspace.conversations.values():
- if conversation.buffer_pointer == buffer_pointer:
- return conversation
- return None
-
-
-class SlackApi:
- def __init__(self, workspace: SlackWorkspace):
- self.workspace = workspace
-
- def get_request_options(self):
- return {
- "useragent": f"wee_slack {shared.SCRIPT_VERSION}",
- "httpheader": f"Authorization: Bearer {self.workspace.config.api_token.value}",
- "cookie": self.workspace.config.api_cookies.value,
- }
-
- async def fetch(self, method: str, params: Dict[str, Union[str, int]] = {}):
- url = f"https://api.slack.com/api/{method}?{urlencode(params)}"
- response = await http_request(
- url,
- self.get_request_options(),
- self.workspace.config.slack_timeout.value * 1000,
- )
- return json.loads(response)
-
- async def fetch_list(
- self,
- method: str,
- list_key: str,
- params: Dict[str, Union[str, int]] = {},
- pages: int = 1, # negative or 0 means all pages
- ):
- response = await self.fetch(method, params)
- next_cursor = response.get("response_metadata", {}).get("next_cursor")
- if pages != 1 and next_cursor and response["ok"]:
- params["cursor"] = next_cursor
- next_pages = await self.fetch_list(method, list_key, params, pages - 1)
- response[list_key].extend(next_pages[list_key])
- return response
- return response
-
-
-class SlackWorkspace:
- def __init__(self, name: str):
- self.name = name
- self.config = shared.config.create_workspace_config(self.name)
- self.api = SlackApi(self)
- self.is_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, Future[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])
- self.is_connected = True
- weechat.bar_item_update("input_text")
-
- async def create_user(self, id: str) -> SlackUser:
- user = SlackUser(self, id)
- await user.init()
- return user
-
- async def get_user(self, id: str) -> SlackUser:
- if id in self.users:
- return await self.users[id]
- self.users[id] = create_task(self.create_user(id))
- return await self.users[id]
-
-
-class SlackUser:
- def __init__(self, workspace: SlackWorkspace, id: str):
- self.workspace = workspace
- self.id = id
- self.name: str
-
- @property
- def api(self) -> SlackApi:
- return self.workspace.api
-
- async def init(self):
- info = await self.api.fetch("users.info", {"user": self.id})
- self.name = info["user"]["name"]
-
-
-def buffer_input_cb(data: str, buffer: str, input_data: str) -> int:
- weechat.prnt(buffer, "Text: %s" % input_data)
- return weechat.WEECHAT_RC_OK
-
-
-class SlackConversation:
- def __init__(self, workspace: SlackWorkspace, id: str):
- self.workspace = workspace
- self.id = id
- # TODO: buffer_pointer may be accessed by buffer_switch before it's initialized
- self.buffer_pointer: str = ""
- self.name: str
- self.is_loading = False
- self.history_filled = False
- self.history_pending = False
-
- @property
- def api(self) -> SlackApi:
- return self.workspace.api
-
- @contextmanager
- def loading(self):
- self.is_loading = True
- weechat.bar_item_update("input_text")
- try:
- yield
- finally:
- self.is_loading = False
- weechat.bar_item_update("input_text")
-
- async def init(self):
- with self.loading():
- info = await self.fetch_info()
- if info["ok"] != True:
- # TODO: Handle error
- return
-
- info_channel = info["channel"]
- if info_channel["is_im"] == True:
- self.name = "IM" # TODO
- elif info_channel["is_mpim"] == True:
- self.name = "MPIM" # TODO
- else:
- self.name = info_channel["name"]
-
- self.buffer_pointer = weechat.buffer_new(
- self.name, get_callback_name(buffer_input_cb), "", "", ""
- )
- weechat.buffer_set(self.buffer_pointer, "localvar_set_nick", "nick")
-
- async def fetch_info(self) -> SlackConversationInfoResponse:
- with self.loading():
- info = await self.api.fetch("conversations.info", {"channel": self.id})
- return info
-
- async def fill_history(self):
- if self.history_filled or self.history_pending:
- return
-
- with self.loading():
- self.history_pending = True
-
- history = await self.api.fetch(
- "conversations.history", {"channel": self.id}
- )
- start = time.time()
-
- messages = [SlackMessage(self, message) for message in history["messages"]]
- messages_rendered = await gather(
- *(message.render_message() for message in messages)
- )
-
- for rendered in reversed(messages_rendered):
- weechat.prnt(self.buffer_pointer, rendered)
-
- print(f"history w/o fetch took: {time.time() - start}")
- self.history_filled = True
- self.history_pending = False
-
-
-class SlackMessage:
- def __init__(self, conversation: SlackConversation, message_json: Any):
- self.conversation = conversation
- self.ts = message_json["ts"]
- self.message_json = message_json
-
- @property
- def workspace(self) -> SlackWorkspace:
- return self.conversation.workspace
-
- @property
- def api(self) -> SlackApi:
- return self.workspace.api
-
- async def render_message(self):
- message = await self.unfurl_refs(self.message_json["text"])
- if "user" in self.message_json:
- user = await self.workspace.get_user(self.message_json["user"])
- prefix = user.name
- else:
- prefix = "bot"
-
- return f"{prefix}\t{message}"
-
- async def unfurl_refs(self, message: str):
- re_user = re.compile("<@([^>]+)>")
- user_ids: List[str] = re_user.findall(message)
- users_list = await gather(
- *(self.workspace.get_user(user_id) for user_id in user_ids)
- )
- users = dict(zip(user_ids, users_list))
-
- def unfurl_user(user_id: str):
- return "@" + users[user_id].name
-
- return re_user.sub(lambda match: unfurl_user(match.group(1)), message)
diff --git a/slack/commands.py b/slack/commands.py
index 24ee99f..44d1d13 100644
--- a/slack/commands.py
+++ b/slack/commands.py
@@ -7,9 +7,9 @@ from typing import Any, Callable, Dict, List, Optional, Tuple
import weechat
-from slack.api import SlackWorkspace
from slack.log import print_error
from slack.shared import shared
+from slack.slack_workspace import SlackWorkspace
from slack.task import create_task
from slack.util import get_callback_name, with_color
from slack.weechat_config import WeeChatOption
diff --git a/slack/config.py b/slack/config.py
index b2e2c07..7228ed8 100644
--- a/slack/config.py
+++ b/slack/config.py
@@ -4,9 +4,9 @@ from typing import Union
import weechat
-from slack.api import SlackWorkspace
from slack.log import print_error
from slack.shared import shared
+from slack.slack_workspace import SlackWorkspace
from slack.util import get_callback_name
from slack.weechat_config import (
WeeChatColor,
diff --git a/slack/http.py b/slack/http.py
index ca99526..7ec661e 100644
--- a/slack/http.py
+++ b/slack/http.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import os
import resource
from io import StringIO
diff --git a/slack/init.py b/slack/init.py
index b126a24..e039d9c 100644
--- a/slack/init.py
+++ b/slack/init.py
@@ -1,9 +1,11 @@
+from __future__ import annotations
+
import weechat
-from slack.api import get_conversation_from_buffer_pointer
from slack.commands import register_commands
from slack.config import SlackConfig
from slack.shared import shared
+from slack.slack_conversation import get_conversation_from_buffer_pointer
from slack.task import create_task, sleep
from slack.util import get_callback_name, with_color
diff --git a/slack/log.py b/slack/log.py
index 2c8a679..552727d 100644
--- a/slack/log.py
+++ b/slack/log.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
from enum import IntEnum
import weechat
diff --git a/slack/shared.py b/slack/shared.py
index eab2c92..1e9b2aa 100644
--- a/slack/shared.py
+++ b/slack/shared.py
@@ -4,8 +4,8 @@ from collections import defaultdict
from typing import TYPE_CHECKING, Any, Dict, List
if TYPE_CHECKING:
- from slack.api import SlackWorkspace
from slack.config import SlackConfig
+ from slack.slack_workspace import SlackWorkspace
from slack.task import Future, Task
diff --git a/slack/slack_conversation.py b/slack/slack_conversation.py
new file mode 100644
index 0000000..16dc8ec
--- /dev/null
+++ b/slack/slack_conversation.py
@@ -0,0 +1,107 @@
+from __future__ import annotations
+
+import time
+from contextlib import contextmanager
+from typing import TYPE_CHECKING, Optional
+
+import weechat
+
+from slack.shared import shared
+from slack.slack_message import SlackMessage
+from slack.task import gather
+from slack.util import get_callback_name
+
+if TYPE_CHECKING:
+ from slack_api import SlackConversationInfoResponse
+
+ from slack.slack_workspace import SlackApi, SlackWorkspace
+
+
+def get_conversation_from_buffer_pointer(
+ buffer_pointer: str,
+) -> Optional[SlackConversation]:
+ for workspace in shared.workspaces.values():
+ for conversation in workspace.conversations.values():
+ if conversation.buffer_pointer == buffer_pointer:
+ return conversation
+ return None
+
+
+def buffer_input_cb(data: str, buffer: str, input_data: str) -> int:
+ weechat.prnt(buffer, "Text: %s" % input_data)
+ return weechat.WEECHAT_RC_OK
+
+
+class SlackConversation:
+ def __init__(self, workspace: SlackWorkspace, id: str):
+ self.workspace = workspace
+ self.id = id
+ # TODO: buffer_pointer may be accessed by buffer_switch before it's initialized
+ self.buffer_pointer: str = ""
+ self.name: str
+ self.is_loading = False
+ self.history_filled = False
+ self.history_pending = False
+
+ @property
+ def api(self) -> SlackApi:
+ return self.workspace.api
+
+ @contextmanager
+ def loading(self):
+ self.is_loading = True
+ weechat.bar_item_update("input_text")
+ try:
+ yield
+ finally:
+ self.is_loading = False
+ weechat.bar_item_update("input_text")
+
+ async def init(self):
+ with self.loading():
+ info = await self.fetch_info()
+ if info["ok"] != True:
+ # TODO: Handle error
+ return
+
+ info_channel = info["channel"]
+ if info_channel["is_im"] == True:
+ self.name = "IM" # TODO
+ elif info_channel["is_mpim"] == True:
+ self.name = "MPIM" # TODO
+ else:
+ self.name = info_channel["name"]
+
+ self.buffer_pointer = weechat.buffer_new(
+ self.name, get_callback_name(buffer_input_cb), "", "", ""
+ )
+ weechat.buffer_set(self.buffer_pointer, "localvar_set_nick", "nick")
+
+ async def fetch_info(self) -> SlackConversationInfoResponse:
+ with self.loading():
+ info = await self.api.fetch("conversations.info", {"channel": self.id})
+ return info
+
+ async def fill_history(self):
+ if self.history_filled or self.history_pending:
+ return
+
+ with self.loading():
+ self.history_pending = True
+
+ history = await self.api.fetch(
+ "conversations.history", {"channel": self.id}
+ )
+ start = time.time()
+
+ messages = [SlackMessage(self, message) for message in history["messages"]]
+ messages_rendered = await gather(
+ *(message.render_message() for message in messages)
+ )
+
+ for rendered in reversed(messages_rendered):
+ weechat.prnt(self.buffer_pointer, rendered)
+
+ print(f"history w/o fetch took: {time.time() - start}")
+ self.history_filled = True
+ self.history_pending = False
diff --git a/slack/slack_message.py b/slack/slack_message.py
new file mode 100644
index 0000000..d90ddb8
--- /dev/null
+++ b/slack/slack_message.py
@@ -0,0 +1,48 @@
+from __future__ import annotations
+
+import re
+from typing import TYPE_CHECKING, Any, List
+
+from slack.task import gather
+
+if TYPE_CHECKING:
+ from slack.slack_conversation import SlackConversation
+ from slack.slack_workspace import SlackApi, SlackWorkspace
+
+
+class SlackMessage:
+ def __init__(self, conversation: SlackConversation, message_json: Any):
+ self.conversation = conversation
+ self.ts = message_json["ts"]
+ self.message_json = message_json
+
+ @property
+ def workspace(self) -> SlackWorkspace:
+ return self.conversation.workspace
+
+ @property
+ def api(self) -> SlackApi:
+ return self.workspace.api
+
+ async def render_message(self):
+ message = await self.unfurl_refs(self.message_json["text"])
+ if "user" in self.message_json:
+ user = await self.workspace.get_user(self.message_json["user"])
+ prefix = user.name
+ else:
+ prefix = "bot"
+
+ return f"{prefix}\t{message}"
+
+ async def unfurl_refs(self, message: str):
+ re_user = re.compile("<@([^>]+)>")
+ user_ids: List[str] = re_user.findall(message)
+ users_list = await gather(
+ *(self.workspace.get_user(user_id) for user_id in user_ids)
+ )
+ users = dict(zip(user_ids, users_list))
+
+ def unfurl_user(user_id: str):
+ return "@" + users[user_id].name
+
+ return re_user.sub(lambda match: unfurl_user(match.group(1)), message)
diff --git a/slack/slack_user.py b/slack/slack_user.py
new file mode 100644
index 0000000..50540f8
--- /dev/null
+++ b/slack/slack_user.py
@@ -0,0 +1,21 @@
+from __future__ import annotations
+
+from typing import TYPE_CHECKING
+
+if TYPE_CHECKING:
+ from slack.slack_workspace import SlackApi, SlackWorkspace
+
+
+class SlackUser:
+ def __init__(self, workspace: SlackWorkspace, id: str):
+ self.workspace = workspace
+ self.id = id
+ self.name: str
+
+ @property
+ def api(self) -> SlackApi:
+ return self.workspace.api
+
+ async def init(self):
+ info = await self.api.fetch("users.info", {"user": self.id})
+ self.name = info["user"]["name"]
diff --git a/slack/slack_workspace.py b/slack/slack_workspace.py
new file mode 100644
index 0000000..df99f94
--- /dev/null
+++ b/slack/slack_workspace.py
@@ -0,0 +1,98 @@
+from __future__ import annotations
+
+import json
+from typing import Dict, Union
+from urllib.parse import urlencode
+
+import weechat
+
+from slack.http import http_request
+from slack.shared import shared
+from slack.slack_conversation import SlackConversation
+from slack.slack_user import SlackUser
+from slack.task import Future, create_task
+
+
+class SlackApi:
+ def __init__(self, workspace: SlackWorkspace):
+ self.workspace = workspace
+
+ def get_request_options(self):
+ return {
+ "useragent": f"wee_slack {shared.SCRIPT_VERSION}",
+ "httpheader": f"Authorization: Bearer {self.workspace.config.api_token.value}",
+ "cookie": self.workspace.config.api_cookies.value,
+ }
+
+ async def fetch(self, method: str, params: Dict[str, Union[str, int]] = {}):
+ url = f"https://api.slack.com/api/{method}?{urlencode(params)}"
+ response = await http_request(
+ url,
+ self.get_request_options(),
+ self.workspace.config.slack_timeout.value * 1000,
+ )
+ return json.loads(response)
+
+ async def fetch_list(
+ self,
+ method: str,
+ list_key: str,
+ params: Dict[str, Union[str, int]] = {},
+ pages: int = 1, # negative or 0 means all pages
+ ):
+ response = await self.fetch(method, params)
+ next_cursor = response.get("response_metadata", {}).get("next_cursor")
+ if pages != 1 and next_cursor and response["ok"]:
+ params["cursor"] = next_cursor
+ next_pages = await self.fetch_list(method, list_key, params, pages - 1)
+ response[list_key].extend(next_pages[list_key])
+ return response
+ return response
+
+
+class SlackWorkspace:
+ def __init__(self, name: str):
+ self.name = name
+ self.config = shared.config.create_workspace_config(self.name)
+ self.api = SlackApi(self)
+ self.is_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, Future[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])
+ self.is_connected = True
+ weechat.bar_item_update("input_text")
+
+ async def create_user(self, id: str) -> SlackUser:
+ user = SlackUser(self, id)
+ await user.init()
+ return user
+
+ async def get_user(self, id: str) -> SlackUser:
+ if id in self.users:
+ return await self.users[id]
+ self.users[id] = create_task(self.create_user(id))
+ return await self.users[id]
diff --git a/slack/util.py b/slack/util.py
index 112f060..b5b5bb2 100644
--- a/slack/util.py
+++ b/slack/util.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
from typing import Callable, Dict, Union
import weechat