aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTrygve Aaberge <trygveaa@gmail.com>2023-10-08 17:35:04 +0200
committerTrygve Aaberge <trygveaa@gmail.com>2024-02-18 11:32:54 +0100
commit01c1a010f9d03f69aab27c40f2773147a0fb6bd5 (patch)
treec3b72159a1872beee149e0fac38bcf8060777f77
parent5041120cc7020baee501c0dd053c0ef552530a0c (diff)
downloadwee-slack-01c1a010f9d03f69aab27c40f2773147a0fb6bd5.tar.gz
Reload conversations on reconnect
-rw-r--r--slack/slack_api.py16
-rw-r--r--slack/slack_buffer.py20
-rw-r--r--slack/slack_conversation.py83
-rw-r--r--slack/slack_thread.py34
-rw-r--r--slack/slack_workspace.py2
5 files changed, 125 insertions, 30 deletions
diff --git a/slack/slack_api.py b/slack/slack_api.py
index 8e0b28a..9f57fdd 100644
--- a/slack/slack_api.py
+++ b/slack/slack_api.py
@@ -142,6 +142,22 @@ class SlackApi(SlackApiCommon):
raise SlackApiError(self.workspace, method, response, params)
return response
+ async def fetch_conversations_history_after(
+ self, conversation: SlackConversation, after: SlackTs
+ ):
+ method = "conversations.history"
+ params: Params = {
+ "channel": conversation.id,
+ "oldest": after,
+ "inclusive": False,
+ }
+ response: SlackConversationsHistoryResponse = await self._fetch_list(
+ method, "messages", params
+ )
+ if response["ok"] is False:
+ raise SlackApiError(self.workspace, method, response, params)
+ return response
+
async def fetch_conversations_replies(
self, conversation: SlackConversation, parent_message_ts: SlackTs
):
diff --git a/slack/slack_buffer.py b/slack/slack_buffer.py
index 881e56d..9554db1 100644
--- a/slack/slack_buffer.py
+++ b/slack/slack_buffer.py
@@ -3,7 +3,7 @@ from __future__ import annotations
import time
from abc import ABC, abstractmethod
from contextlib import contextmanager
-from typing import TYPE_CHECKING, Dict, List, Mapping, Optional, Tuple
+from typing import TYPE_CHECKING, Dict, List, Mapping, Optional, Set, Tuple
import weechat
@@ -127,8 +127,11 @@ class SlackBuffer(ABC):
# TODO: buffer_pointer may be accessed by buffer_switch before it's initialized
self.buffer_pointer: str = ""
self.is_loading = False
- self.history_filled = False
self.history_pending = False
+ self.history_pending_messages: List[SlackMessage] = []
+ self.history_needs_refresh = False
+ self.last_printed_ts: Optional[SlackTs] = None
+ self.hotlist_tss: Set[SlackTs] = set()
self.completion_context: Literal[
"NO_COMPLETION",
@@ -185,9 +188,8 @@ class SlackBuffer(ABC):
async def get_name_and_buffer_props(self) -> Tuple[str, Dict[str, str]]:
raise NotImplementedError()
- @abstractmethod
async def buffer_switched_to(self) -> None:
- raise NotImplementedError()
+ self.hotlist_tss.clear()
def get_full_name(self, name: str) -> str:
return f"{shared.SCRIPT_NAME}.{self.workspace.name}.{name}"
@@ -234,6 +236,10 @@ class SlackBuffer(ABC):
for key, value in buffer_props.items():
weechat.buffer_set(self.buffer_pointer, key, value)
+ @abstractmethod
+ async def set_hotlist(self) -> None:
+ raise NotImplementedError()
+
async def rerender_message(self, message: SlackMessage):
modify_buffer_line(
self.buffer_pointer,
@@ -258,6 +264,9 @@ class SlackBuffer(ABC):
weechat.prnt_date_tags(self.buffer_pointer, message.ts.major, tags, rendered)
if backlog:
weechat.buffer_set(self.buffer_pointer, "unread", "")
+ else:
+ self.hotlist_tss.add(message.ts)
+ self.last_printed_ts = message.ts
def last_read_line_ts(self) -> Optional[SlackTs]:
if self.buffer_pointer:
@@ -287,6 +296,7 @@ class SlackBuffer(ABC):
# TODO: Move unread marker to correct position according to last_read for WeeChat >= 4.0.0
weechat.buffer_set(self.buffer_pointer, "unread", "")
weechat.buffer_set(self.buffer_pointer, "hotlist", "-1")
+ self.hotlist_tss.clear()
def _buffer_input_cb(self, data: str, buffer: str, input_data: str) -> int:
weechat.prnt(buffer, "Text: %s" % input_data)
@@ -296,5 +306,5 @@ class SlackBuffer(ABC):
if self.buffer_pointer in shared.buffers:
del shared.buffers[self.buffer_pointer]
self.buffer_pointer = ""
- self.history_filled = False
+ self.last_printed_ts = None
return weechat.WEECHAT_RC_OK
diff --git a/slack/slack_conversation.py b/slack/slack_conversation.py
index cd0492f..4a33989 100644
--- a/slack/slack_conversation.py
+++ b/slack/slack_conversation.py
@@ -10,7 +10,7 @@ from slack.error import SlackError
from slack.python_compatibility import removeprefix
from slack.shared import shared
from slack.slack_buffer import SlackBuffer
-from slack.slack_message import SlackMessage, SlackTs
+from slack.slack_message import MessagePriority, SlackMessage, SlackTs
from slack.slack_thread import SlackThread
from slack.slack_user import SlackBot, SlackUser, nick_color
from slack.task import gather, run_async
@@ -240,6 +240,7 @@ class SlackConversation(SlackBuffer):
}
async def buffer_switched_to(self):
+ await super().buffer_switched_to()
await gather(self.nicklist_update(), self.fill_history())
async def open_buffer(self, switch: bool = False):
@@ -291,27 +292,68 @@ class SlackConversation(SlackBuffer):
return replies
async def set_hotlist(self):
- history = await self._api.fetch_conversations_history(self)
+ if self.last_printed_ts is not None:
+ self.history_needs_refresh = True
+
+ if self.buffer_pointer and shared.current_buffer_pointer == self.buffer_pointer:
+ await self.fill_history()
+ return
+
+ if self.last_printed_ts is not None:
+ history_after_ts = (
+ next(iter(self._messages))
+ if self.display_thread_replies()
+ else self.last_printed_ts
+ )
+ history = await self._api.fetch_conversations_history_after(
+ self, history_after_ts
+ )
+ else:
+ history = await self._api.fetch_conversations_history(self)
+
if self.buffer_pointer and shared.current_buffer_pointer != self.buffer_pointer:
for message_json in history["messages"]:
message = SlackMessage(self, message_json)
- if message.ts > self.last_read or (
+ if message.ts > self.last_read and message.ts not in self.hotlist_tss:
+ weechat.buffer_set(
+ self.buffer_pointer, "hotlist", message.priority.value
+ )
+ self.hotlist_tss.add(message.ts)
+ if (
self.display_thread_replies()
and message.latest_reply
- and message.latest_reply > message.last_read
+ and message.latest_reply > self.last_read
+ and message.latest_reply not in self.hotlist_tss
):
- weechat.buffer_set(
- self.buffer_pointer, "hotlist", message.priority.value
+ priority = (
+ MessagePriority.PRIVATE
+ if self.buffer_type == "private"
+ else MessagePriority.MESSAGE
)
+ weechat.buffer_set(self.buffer_pointer, "hotlist", priority.value)
+ self.hotlist_tss.add(message.latest_reply)
async def fill_history(self):
- if self.history_filled or self.history_pending:
+ if self.history_pending:
+ return
+
+ if self.last_printed_ts is not None and not self.history_needs_refresh:
return
with self.loading():
self.history_pending = True
- history = await self._api.fetch_conversations_history(self)
+ history_after_ts = (
+ next(iter(self._messages), None)
+ if self.history_needs_refresh
+ else self.last_printed_ts
+ )
+ if history_after_ts:
+ history = await self._api.fetch_conversations_history_after(
+ self, history_after_ts
+ )
+ else:
+ history = await self._api.fetch_conversations_history(self)
conversation_messages = [
SlackMessage(self, message) for message in history["messages"]
@@ -328,11 +370,17 @@ class SlackConversation(SlackBuffer):
)
)
+ if self.history_needs_refresh:
+ await self.rerender_history()
+
self._messages = OrderedDict(sorted(self._messages.items()))
+ self.history_pending_messages.clear()
messages = [
message
for message in self._messages.values()
if self.should_display_message(message)
+ and self.last_printed_ts is None
+ or message.ts > self.last_printed_ts
]
sender_user_ids = [m.sender_user_id for m in messages if m.sender_user_id]
@@ -360,7 +408,11 @@ class SlackConversation(SlackBuffer):
for message in messages:
await self.print_message(message)
- self.history_filled = True
+ while self.history_pending_messages:
+ message = self.history_pending_messages.pop(0)
+ await self.print_message(message)
+
+ self.history_needs_refresh = False
self.history_pending = False
async def nicklist_update(self):
@@ -433,18 +485,25 @@ class SlackConversation(SlackBuffer):
self._messages[message.ts] = message
if self.should_display_message(message):
- if self.history_filled:
+ if self.history_pending:
+ self.history_pending_messages.append(message)
+ elif self.last_printed_ts is not None:
await self.print_message(message)
else:
weechat.buffer_set(
self.buffer_pointer, "hotlist", message.priority.value
)
+ self.hotlist_tss.add(message.ts)
parent_message = message.parent_message
if parent_message:
parent_message.replies[message.ts] = message
- if parent_message.thread_buffer:
- await parent_message.thread_buffer.print_message(message)
+ thread_buffer = parent_message.thread_buffer
+ if thread_buffer:
+ if thread_buffer.history_pending:
+ thread_buffer.history_pending_messages.append(message)
+ else:
+ await thread_buffer.print_message(message)
elif message.thread_ts is not None:
await self.fetch_replies(message.thread_ts)
diff --git a/slack/slack_thread.py b/slack/slack_thread.py
index bc02c26..79ef68c 100644
--- a/slack/slack_thread.py
+++ b/slack/slack_thread.py
@@ -51,32 +51,41 @@ class SlackThread(SlackBuffer):
}
async def buffer_switched_to(self):
+ await super().buffer_switched_to()
await self.fill_history()
- async def print_history(self):
- if self.history_filled:
- return
-
- self.history_filled = True
+ async def set_hotlist(self):
+ self.history_needs_refresh = True
+ await self.fill_history()
- with self.loading():
- messages = chain([self.parent], self.parent.replies.values())
- for message in messages:
+ async def print_history(self):
+ messages = chain([self.parent], self.parent.replies.values())
+ self.history_pending_messages.clear()
+ for message in list(messages):
+ if self.last_printed_ts is None or message.ts > self.last_printed_ts:
await self.print_message(message)
+ while self.history_pending_messages:
+ message = self.history_pending_messages.pop(0)
+ await self.print_message(message)
+
async def fill_history(self):
if self.history_pending:
return
- if self.parent.reply_history_filled:
- await self.print_history()
- return
-
with self.loading():
self.history_pending = True
+ if self.parent.reply_history_filled and not self.history_needs_refresh:
+ await self.print_history()
+ self.history_pending = False
+ return
+
messages = await self.parent.conversation.fetch_replies(self.parent.ts)
+ if self.history_needs_refresh:
+ await self.rerender_history()
+
sender_user_ids = [m.sender_user_id for m in messages if m.sender_user_id]
self.workspace.users.initialize_items(sender_user_ids)
@@ -90,6 +99,7 @@ class SlackThread(SlackBuffer):
await gather(*(message.render(self.context) for message in messages))
await self.print_history()
+ self.history_needs_refresh = False
self.history_pending = False
async def mark_read(self):
diff --git a/slack/slack_workspace.py b/slack/slack_workspace.py
index 3f5d525..992e025 100644
--- a/slack/slack_workspace.py
+++ b/slack/slack_workspace.py
@@ -265,7 +265,7 @@ class SlackWorkspace:
await conversation.open_buffer()
await gather(
- *(conversation[1].set_hotlist() for conversation in conversations_to_open)
+ *(slack_buffer.set_hotlist() for slack_buffer in shared.buffers.values())
)
self.is_connected = True