buffer: Lazily add users to the nicklist.

This commit is contained in:
Damir Jelić 2018-09-19 12:47:53 +02:00
parent 97d3a59e33
commit ac5d1b823e
3 changed files with 135 additions and 37 deletions

View file

@ -61,7 +61,7 @@ from matrix.server import (MatrixServer, create_default_server,
matrix_config_server_change_cb,
matrix_config_server_read_cb,
matrix_config_server_write_cb, matrix_timer_cb,
send_cb)
send_cb, matrix_load_users_cb)
from matrix.utf import utf8_decode
from matrix.utils import server_buffer_prnt, server_buffer_set_title

View file

@ -30,6 +30,7 @@ from nio import (
RoomAliasEvent,
RoomEncryptionEvent,
RoomMemberEvent,
RoomMessage,
RoomMessageEmote,
RoomMessageMedia,
RoomMessageNotice,
@ -785,6 +786,7 @@ class RoomBuffer(object):
self.prev_batch = prev_batch
self.joined = True
self.leave_event_id = None # type: Optional[str]
self.unhandled_users = [] # type: List[str]
buffer_name = "{}.{}".format(server_name, room.room_id)
@ -813,13 +815,13 @@ class RoomBuffer(object):
return user_id
def handle_membership_events(self, event, is_state):
def join(event, date, is_state):
def add_user(self, user_id, date, is_state):
try:
user = self.room.users[event.state_key]
user = self.room.users[user_id]
except KeyError:
# No user found, he must have left already in an event that is
# yet to come, so do nothing
# W.prnt("", "NOT ADDING USER {}".format(user_id))
return
short_name = shorten_sender(user.user_id)
@ -835,29 +837,45 @@ class RoomBuffer(object):
# TODO make this configurable
if not short_name or short_name in self.displayed_nicks.values():
# Use the full user id, but don't include the @
nick = event.sender[1:]
nick = user_id[1:]
else:
nick = short_name
buffer_user = RoomUser(nick, event.sender, user.power_level, date)
self.displayed_nicks[event.sender] = nick
buffer_user = RoomUser(nick, user_id, user.power_level, date)
self.displayed_nicks[user_id] = nick
if self.room.own_user_id == event.sender:
if self.room.own_user_id == user_id:
buffer_user.color = "weechat.color.chat_nick_self"
user.nick_color = "weechat.color.chat_nick_self"
self.weechat_buffer.join(buffer_user, date, not is_state)
def handle_membership_events(self, event, is_state):
date = server_ts_to_weechat(event.server_timestamp)
if event.content["membership"] == "join":
if event.state_key not in self.displayed_nicks:
join(event, date, is_state)
# Adding users to the nicklist is a O(1) + search time
# operation (the nicks are added to a linked list sorted).
# The search time is O(N * min(a,b)) where N is the number
# of nicks already added and a/b are the length of
# the strings that are compared at every itteration.
# Because the search time get's increasingly longer we're
# going to add nicks later in a timer hook.
if ((len(self.room.users) - len(self.displayed_nicks)) > 500
and is_state):
self.unhandled_users.append(event.state_key)
else:
self.add_user(event.state_key, date, is_state)
else:
# TODO print out profile changes
return
elif event.content["membership"] == "leave":
if event.state_key in self.unhandled_users:
self.unhandled_users.remove(event.state_key)
return
nick = self.find_nick(event.state_key)
if event.sender == event.state_key:
self.weechat_buffer.part(nick, date, not is_state)
@ -1021,6 +1039,19 @@ class RoomBuffer(object):
self.weechat_buffer.error(message)
def handle_timeline_event(self, event):
# TODO this should be done for every messagetype that gets printed in
# the buffer
if isinstance(event, (RoomMessage, MegolmEvent)):
if (event.sender not in self.displayed_nicks and
event.sender in self.room.users):
try:
self.unhandled_users.remove(event.sender)
except ValueError:
pass
self.add_user(event.sender, 0, True)
if isinstance(event, RoomMemberEvent):
self.handle_membership_events(event, False)
@ -1274,6 +1305,12 @@ class RoomBuffer(object):
for event in timeline_events:
self.handle_timeline_event(event)
# We didn't handle all joined users, the room display name might still
# be outdated because of that, update it now.
if self.unhandled_users:
room_name = self.room.display_name()
self.weechat_buffer.short_name = room_name
def handle_left_room(self, info):
self.joined = False

View file

@ -222,6 +222,9 @@ class MatrixServer(object):
self.own_message_queue = dict() # type: Dict[str, OwnMessage]
self.backlog_queue = dict() # type: Dict[str, str]
self.unhandled_users = dict() # type: Dict[str, List[str]]
self.lazy_load_hook = None # type: str
self.config = ServerConfig(self.name, config_ptr)
self._create_session_dir()
# yapf: enable
@ -736,6 +739,8 @@ class MatrixServer(object):
room_buffer = self.find_room_from_id(room_id)
room_buffer.handle_left_room(info)
should_lazy_hook = False
for room_id, info in response.rooms.join.items():
if room_id not in self.buffers:
self.create_room_buffer(room_id, info.timeline.prev_batch)
@ -743,6 +748,42 @@ class MatrixServer(object):
room_buffer = self.find_room_from_id(room_id)
room_buffer.handle_joined_room(info)
if room_buffer.unhandled_users:
should_lazy_hook = True
if should_lazy_hook:
hook = W.hook_timer(1 * 100, 0, 0, "matrix_load_users_cb",
self.name)
self.lazy_load_hook = hook
def add_unhandled_users(self, rooms, n):
# type: (List[RoomBuffer], int) -> bool
total_users = 0
while total_users <= n:
try:
room_buffer = rooms.pop()
except IndexError:
return False
handled_users = 0
users = room_buffer.unhandled_users
for user_id in users:
room_buffer.add_user(user_id, 0, True)
handled_users += 1
total_users += 1
if total_users >= n:
room_buffer.unhandled_users = users[handled_users:]
rooms.append(room_buffer)
return True
room_buffer.unhandled_users = []
return False
def _handle_sync(self, response):
# we got the same batch again, nothing to do
if self.next_batch == response.next_batch:
@ -901,6 +942,26 @@ def matrix_config_server_change_cb(server_name, option):
return 1
@utf8_decode
def matrix_load_users_cb(server_name, remaining_calls):
server = SERVERS[server_name]
start = time.time()
rooms = [x for x in server.room_buffers.values() if x.unhandled_users]
while server.add_unhandled_users(rooms, 100):
current = time.time()
if current - start >= 0.1:
return W.WEECHAT_RC_OK
# We are done adding users, we can unhook now.
W.unhook(server.lazy_load_hook)
server.lazy_load_hook = None
return W.WEECHAT_RC_OK
@utf8_decode
def matrix_timer_cb(server_name, remaining_calls):
server = SERVERS[server_name]