Daniel Brötzmann pushed to branch master at gajim / gajim
Commits: dfa950f3 by Philipp Hörist at 2022-11-11T19:07:12+01:00 perf: Control: Request history more efficiently
- Limit how many events are requested - Merge events and messages and add them afterwards
- - - - -
3 changed files:
- gajim/common/storage/events.py - gajim/gtk/control.py - gajim/gtk/conversation/view.py
Changes:
===================================== gajim/common/storage/events.py ===================================== @@ -13,12 +13,12 @@ # along with Gajim. If not, see http://www.gnu.org/licenses/.
from __future__ import annotations -import dataclasses
from typing import Any -from typing import Iterator from typing import NamedTuple
+import dataclasses + import json import sqlite3 import logging @@ -116,18 +116,26 @@ def store(self, def load(self, contact: ChatContactT, before: bool, - timestamp: float - ) -> Iterator[EventRow]: + timestamp: float, + n_lines: int, + ) -> list[events.ApplicationEvent]:
- time_operator = '<' if before else '>' + if before: + time_order = 'AND timestamp < ? ORDER BY timestamp DESC' + else: + time_order = 'AND timestamp > ? ORDER BY timestamp ASC'
insert_sql = ''' SELECT account, jid, event, timestamp, data as "data [JSON]" - FROM events WHERE account=? AND jid=? AND timestamp %s ? - ''' % time_operator + FROM events WHERE account=? AND jid=? {time_order} + LIMIT ?'''.format(time_order=time_order)
+ event_list: list[events.ApplicationEvent] = [] for row in self._con.execute(insert_sql, (contact.account, contact.jid, - timestamp)).fetchall(): + timestamp, + n_lines)).fetchall(): event_class = EVENT_CLASSES[row.event] - yield event_class(**row.data, timestamp=row.timestamp) + event_list.append(event_class(**row.data, + timestamp=row.timestamp)) + return event_list
===================================== gajim/gtk/control.py ===================================== @@ -56,18 +56,18 @@ from gajim.gui.groupchat_roster import GroupchatRoster from gajim.gui.groupchat_state import GroupchatState
-log = logging.getLogger('gajim.gui.control') - +HistoryRowT = Union[events.ApplicationEvent, ConversationRow]
REQUEST_LINES_COUNT = 20
+log = logging.getLogger('gajim.gui.control') +
class ChatControl(EventHelper): def __init__(self) -> None: EventHelper.__init__(self)
self.handlers: dict[int, Any] = {} - self._contact = None self._client = None
@@ -600,13 +600,7 @@ def scroll_to_message(self, log_line_id: int, timestamp: float) -> None: log_line_id) GLib.idle_add(self._scrolled_view.block_signals, False)
- def _request_history(self, - _scrolled: Gtk.ScrolledWindow, - before: bool - ) -> None: - - self._scrolled_view.block_signals(True) - + def _request_messages(self, before: bool) -> list[ConversationRow]: if before: row = self._scrolled_view.get_first_message_row() else: @@ -617,62 +611,104 @@ def _request_history(self, else: timestamp = row.db_timestamp
+ return app.storage.archive.get_conversation_before_after( + self.contact.account, + self.contact.jid, + before, + timestamp, + REQUEST_LINES_COUNT) + + def _request_events(self, before: bool) -> list[events.ApplicationEvent]: + if before: + row = self._scrolled_view.get_first_event_row() + else: + row = self._scrolled_view.get_last_event_row() + + if row is None: + timestamp = time.time() + else: + timestamp = row.db_timestamp + assert self._contact is not None - for event in app.storage.events.load(self._contact, before, timestamp): - if isinstance(event, events.MUCUserJoined): - self._process_muc_user_joined(event) + return app.storage.events.load(self._contact, + before, + timestamp, + REQUEST_LINES_COUNT)
- elif isinstance(event, events.MUCUserLeft): - self._process_muc_user_left(event) + def _request_history(self, + _scrolled: Gtk.ScrolledWindow, + before: bool + ) -> None:
- elif isinstance(event, events.MUCNicknameChanged): - self._process_muc_nickname_changed(event) + self._scrolled_view.block_signals(True)
- elif isinstance(event, events.MUCRoomKicked): - self._process_muc_room_kicked(event) + rows: list[HistoryRowT] = []
- elif isinstance(event, events.MUCUserAffiliationChanged): - self._process_muc_user_affiliation_changed(event) + messages = self._request_messages(before) + event_rows = self._request_events(before) + rows = self._sort_request_rows(messages, event_rows, before)
- elif isinstance(event, events.MUCUserRoleChanged): - self._process_muc_user_role_changed(event) + assert self._contact is not None + for row in rows: + if not isinstance(row, events.ApplicationEvent): + self.add_messages([row])
- elif isinstance(event, events.MUCUserStatusShowChanged): - self._process_muc_user_status_show_changed(event) + elif isinstance(row, events.MUCUserJoined): + self._process_muc_user_joined(row)
- elif isinstance(event, events.MUCRoomConfigChanged): - self._process_muc_room_config_changed(event) + elif isinstance(row, events.MUCUserLeft): + self._process_muc_user_left(row)
- elif isinstance(event, events.MUCRoomConfigFinished): - self._process_muc_room_config_finished(event) + elif isinstance(row, events.MUCNicknameChanged): + self._process_muc_nickname_changed(row)
- elif isinstance(event, events.MUCRoomPresenceError): - self._process_muc_room_presence_error(event) + elif isinstance(row, events.MUCRoomKicked): + self._process_muc_room_kicked(row)
- elif isinstance(event, events.MUCRoomDestroyed): - self._process_muc_room_destroyed(event) - else: - raise ValueError('Unknown event: %s' % event) + elif isinstance(row, events.MUCUserAffiliationChanged): + self._process_muc_user_affiliation_changed(row)
- messages = app.storage.archive.get_conversation_before_after( - self.contact.account, - self.contact.jid, - before, - timestamp, - REQUEST_LINES_COUNT) + elif isinstance(row, events.MUCUserRoleChanged): + self._process_muc_user_role_changed(row)
- if not messages: - self._scrolled_view.set_history_complete(before, True) - self._scrolled_view.block_signals(False) - return + elif isinstance(row, events.MUCUserStatusShowChanged): + self._process_muc_user_status_show_changed(row) + + elif isinstance(row, events.MUCRoomConfigChanged): + self._process_muc_room_config_changed(row) + + elif isinstance(row, events.MUCRoomConfigFinished): + self._process_muc_room_config_finished(row)
- self.add_messages(messages) + elif isinstance(row, events.MUCRoomPresenceError): + self._process_muc_room_presence_error(row)
- if len(messages) < REQUEST_LINES_COUNT: + elif isinstance(row, events.MUCRoomDestroyed): + self._process_muc_room_destroyed(row) + + else: + raise ValueError('Unknown event: %s' % type(row)) + + if len(rows) < REQUEST_LINES_COUNT: self._scrolled_view.set_history_complete(before, True)
self._scrolled_view.block_signals(False)
+ @staticmethod + def _sort_request_rows(messages: list[ConversationRow], + event_rows: list[events.ApplicationEvent], + before: bool + ) -> list[HistoryRowT]: + + def sort_func(obj: HistoryRowT) -> float: + if isinstance(obj, events.ApplicationEvent): + return obj.timestamp # pyright: ignore + return obj.time + + rows = messages + event_rows + rows.sort(key=sort_func, reverse=before) + return rows + def add_messages(self, messages: list[ConversationRow]): for msg in messages: if msg.kind in (KindConstant.FILE_TRANSFER_INCOMING,
===================================== gajim/gtk/conversation/view.py ===================================== @@ -390,6 +390,20 @@ def get_last_message_row(self) -> Optional[MessageRow]: return row return None
+ def get_first_event_row(self) -> Optional[Union[InfoMessage, MUCJoinLeft]]: + for row in self._list_box.get_children(): + if isinstance(row, (InfoMessage, MUCJoinLeft)): + return row + return None + + def get_last_event_row(self) -> Optional[Union[InfoMessage, MUCJoinLeft]]: + children = self._list_box.get_children() + children.reverse() + for row in children: + if isinstance(row, (InfoMessage, MUCJoinLeft)): + return row + return None + @staticmethod def _sort_func(row1: BaseRow, row2: BaseRow) -> int: if row1.timestamp == row2.timestamp:
View it on GitLab: https://dev.gajim.org/gajim/gajim/-/commit/dfa950f359bde8e4771027ac4e7c6cf2c...