diff options
author | Trygve Aaberge <trygveaa@gmail.com> | 2023-10-08 17:35:04 +0200 |
---|---|---|
committer | Trygve Aaberge <trygveaa@gmail.com> | 2024-02-18 11:32:54 +0100 |
commit | 01c1a010f9d03f69aab27c40f2773147a0fb6bd5 (patch) | |
tree | c3b72159a1872beee149e0fac38bcf8060777f77 | |
parent | 5041120cc7020baee501c0dd053c0ef552530a0c (diff) | |
download | wee-slack-01c1a010f9d03f69aab27c40f2773147a0fb6bd5.tar.gz |
Reload conversations on reconnect
-rw-r--r-- | slack/slack_api.py | 16 | ||||
-rw-r--r-- | slack/slack_buffer.py | 20 | ||||
-rw-r--r-- | slack/slack_conversation.py | 83 | ||||
-rw-r--r-- | slack/slack_thread.py | 34 | ||||
-rw-r--r-- | slack/slack_workspace.py | 2 |
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 |