server: Add a maximum value for the number of nicklist users.
This commit is contained in:
parent
d896962b19
commit
74efe8ef9b
5 changed files with 122 additions and 35 deletions
11
main.py
11
main.py
|
@ -34,9 +34,14 @@ from logbook import Logger, StreamHandler
|
|||
from nio import RemoteProtocolError, RemoteTransportError, TransportType
|
||||
|
||||
from matrix import globals as G
|
||||
from matrix.bar_items import (init_bar_items, matrix_bar_item_buffer_modes,
|
||||
matrix_bar_item_lag, matrix_bar_item_name,
|
||||
matrix_bar_item_plugin)
|
||||
from matrix.bar_items import (
|
||||
init_bar_items,
|
||||
matrix_bar_item_buffer_modes,
|
||||
matrix_bar_item_lag,
|
||||
matrix_bar_item_name,
|
||||
matrix_bar_item_plugin,
|
||||
matrix_bar_nicklist_count
|
||||
)
|
||||
from matrix.buffer import room_buffer_close_cb, room_buffer_input_cb
|
||||
# Weechat searches for the registered callbacks in the scope of the main script
|
||||
# file, import the callbacks here so weechat can find them.
|
||||
|
|
|
@ -117,9 +117,26 @@ def matrix_bar_item_buffer_modes(data, item, window, buffer, extra_info):
|
|||
return ""
|
||||
|
||||
|
||||
@utf8_decode
|
||||
def matrix_bar_nicklist_count(data, item, window, buffer, extra_info):
|
||||
# pylint: disable=unused-argument
|
||||
for server in SERVERS.values():
|
||||
if buffer in server.buffers.values():
|
||||
room_buffer = server.find_room_from_ptr(buffer)
|
||||
room = room_buffer.room
|
||||
return str(len(room.users))
|
||||
|
||||
return ""
|
||||
|
||||
|
||||
def init_bar_items():
|
||||
W.bar_item_new("(extra)buffer_plugin", "matrix_bar_item_plugin", "")
|
||||
W.bar_item_new("(extra)buffer_name", "matrix_bar_item_name", "")
|
||||
W.bar_item_new("(extra)lag", "matrix_bar_item_lag", "")
|
||||
W.bar_item_new(
|
||||
"(extra)buffer_nicklist_count",
|
||||
"matrix_bar_nicklist_count",
|
||||
""
|
||||
)
|
||||
W.bar_item_new("(extra)buffer_modes", "matrix_bar_item_buffer_modes", "")
|
||||
W.bar_item_new("(extra)matrix_modes", "matrix_bar_item_buffer_modes", "")
|
||||
|
|
|
@ -692,7 +692,7 @@ class WeechatChannelBuffer(object):
|
|||
message = self._membership_message(user, "invite")
|
||||
self.print_date_tags(message, date, tags + (extra_tags or []))
|
||||
|
||||
def _remove_user_from_nicklist(self, user):
|
||||
def remove_user_from_nicklist(self, user):
|
||||
# type: (WeechatUser) -> None
|
||||
nick_pointer = W.nicklist_search_nick(self._ptr, "", user.nick)
|
||||
|
||||
|
@ -702,7 +702,7 @@ class WeechatChannelBuffer(object):
|
|||
def _leave(self, nick, date, message, leave_type, extra_tags=None):
|
||||
# type: (str, int, bool, str, List[str]) -> None
|
||||
user = self._get_user(nick)
|
||||
self._remove_user_from_nicklist(user)
|
||||
self.remove_user_from_nicklist(user)
|
||||
|
||||
if len(self.users) <= 2:
|
||||
W.buffer_set(self._ptr, "localvar_set_type", "private")
|
||||
|
@ -807,6 +807,7 @@ class RoomBuffer(object):
|
|||
self.leave_event_id = None # type: Optional[str]
|
||||
self.members_fetched = False
|
||||
self.unhandled_users = [] # type: List[str]
|
||||
self.inactive_users = []
|
||||
|
||||
buffer_name = "{}.{}".format(server_name, room.room_id)
|
||||
|
||||
|
@ -840,7 +841,11 @@ class RoomBuffer(object):
|
|||
|
||||
return user_id
|
||||
|
||||
def add_user(self, user_id, date, is_state):
|
||||
def add_user(self, user_id, date, is_state, force_add=False):
|
||||
# User is already added don't add him again.
|
||||
if user_id in self.displayed_nicks:
|
||||
return
|
||||
|
||||
try:
|
||||
user = self.room.users[user_id]
|
||||
except KeyError:
|
||||
|
@ -848,9 +853,24 @@ class RoomBuffer(object):
|
|||
# yet to come, so do nothing
|
||||
return
|
||||
|
||||
# User is already added don't add him again.
|
||||
if user_id in self.displayed_nicks:
|
||||
return
|
||||
# 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 stop adding inactive users, they will be lazily added if
|
||||
# they become active.
|
||||
if is_state and not force_add and user.power_level <= 0:
|
||||
if (len(self.displayed_nicks) >=
|
||||
G.CONFIG.network.max_nicklist_users):
|
||||
self.inactive_users.append(user_id)
|
||||
return
|
||||
|
||||
try:
|
||||
self.inactive_users.remove(user_id)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
short_name = shorten_sender(user.user_id)
|
||||
|
||||
|
@ -882,28 +902,13 @@ class RoomBuffer(object):
|
|||
date = server_ts_to_weechat(event.server_timestamp)
|
||||
|
||||
if event.content["membership"] == "join":
|
||||
if event.state_key not in self.displayed_nicks:
|
||||
# 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.displayed_nicks) > 100
|
||||
and is_state):
|
||||
# Always add users with a high power level
|
||||
try:
|
||||
user = self.room.users[event.state_key]
|
||||
except KeyError:
|
||||
self.unhandled_users.append(event.state_key)
|
||||
else:
|
||||
if user.power_level > 0:
|
||||
self.add_user(event.state_key, date, is_state)
|
||||
else:
|
||||
self.unhandled_users.append(event.state_key)
|
||||
else:
|
||||
self.add_user(event.state_key, date, is_state)
|
||||
if (event.state_key not in self.displayed_nicks
|
||||
and event.state_key not in self.inactive_users):
|
||||
if len(self.room.users) > 100:
|
||||
self.unhandled_users.append(event.state_key)
|
||||
return
|
||||
|
||||
self.add_user(event.state_key, date, is_state)
|
||||
else:
|
||||
# TODO print out profile changes
|
||||
return
|
||||
|
@ -1062,7 +1067,7 @@ class RoomBuffer(object):
|
|||
|
||||
# There is no way to change the group of a user without
|
||||
# removing him from the nicklist
|
||||
self.weechat_buffer._remove_user_from_nicklist(user)
|
||||
self.weechat_buffer.remove_user_from_nicklist(user)
|
||||
self.weechat_buffer._add_user_to_nicklist(user)
|
||||
|
||||
def handle_state_event(self, event):
|
||||
|
@ -1087,7 +1092,7 @@ class RoomBuffer(object):
|
|||
except ValueError:
|
||||
pass
|
||||
|
||||
self.add_user(event.sender, 0, True)
|
||||
self.add_user(event.sender, 0, True, True)
|
||||
|
||||
if isinstance(event, RoomMemberEvent):
|
||||
self.handle_membership_events(event, False)
|
||||
|
|
|
@ -396,6 +396,18 @@ class MatrixConfig(WeechatConfig):
|
|||
"they will be loaded when the buffer becomes active. This "
|
||||
"only affects non encrypted rooms."),
|
||||
),
|
||||
Option(
|
||||
"max_nicklist_users",
|
||||
"integer",
|
||||
"",
|
||||
100,
|
||||
20000,
|
||||
"5000",
|
||||
("Limit the number of users that are added to the nicklist. "
|
||||
"Active users and users with a higher power level are always."
|
||||
" Inactive users will be removed from the nicklist after a "
|
||||
"day of inactivity."),
|
||||
),
|
||||
]
|
||||
|
||||
color_options = [
|
||||
|
|
|
@ -252,6 +252,7 @@ class MatrixServer(object):
|
|||
# type: DefaultDict[str, Deque[EncrytpionQueueItem]]
|
||||
self.backlog_queue = dict() # type: Dict[str, str]
|
||||
|
||||
self.user_gc_time = time.time() # type: float
|
||||
self.member_request_list = [] # type: List[str]
|
||||
self.rooms_with_missing_members = [] # type: List[str]
|
||||
self.lazy_load_hook = None # type: Optional[str]
|
||||
|
@ -1101,6 +1102,53 @@ class MatrixServer(object):
|
|||
room_buffer = self.room_buffers[room_id]
|
||||
return room_buffer
|
||||
|
||||
def garbage_collect_users(self):
|
||||
""" Remove inactive users.
|
||||
This tries to keep the number of users added to the nicklist less than
|
||||
the configuration option matrix.network.max_nicklist_users. It
|
||||
removes users that have not been active for a day until there are
|
||||
less than max_nicklist_users or no users are left for removal.
|
||||
It never removes users that have a bigger power level than the
|
||||
default one.
|
||||
This function is run every hour by the server timer callback"""
|
||||
|
||||
now = time.time()
|
||||
self.user_gc_time = now
|
||||
|
||||
def day_passed(t1, t2):
|
||||
return (t2 - t1) > 86400
|
||||
|
||||
for room_buffer in self.room_buffers.values():
|
||||
to_remove = max(
|
||||
(len(room_buffer.displayed_nicks) -
|
||||
G.CONFIG.network.max_nicklist_users),
|
||||
0
|
||||
)
|
||||
|
||||
if not to_remove:
|
||||
continue
|
||||
|
||||
removed = 0
|
||||
removed_user_ids = []
|
||||
|
||||
for user_id, nick in room_buffer.displayed_nicks.items():
|
||||
user = room_buffer.weechat_buffer.users[nick]
|
||||
|
||||
if (not user.speaking_time or
|
||||
day_passed(user.speaking_time, now)):
|
||||
room_buffer.weechat_buffer.part(nick, 0, False)
|
||||
removed_user_ids.append(user_id)
|
||||
removed += 1
|
||||
|
||||
if removed >= to_remove:
|
||||
break
|
||||
|
||||
for user_id in removed_user_ids:
|
||||
W.prnt("", "Garbage collected {}".format(user_id))
|
||||
del room_buffer.displayed_nicks[user_id]
|
||||
|
||||
pass
|
||||
|
||||
def buffer_merge(self):
|
||||
if not self.server_buffer:
|
||||
return
|
||||
|
@ -1267,8 +1315,8 @@ def matrix_timer_cb(server_name, remaining_calls):
|
|||
}
|
||||
server.sync(timeout, sync_filter)
|
||||
|
||||
if not server.next_batch:
|
||||
return W.WEECHAT_RC_OK
|
||||
if current_time > (server.user_gc_time + 3600):
|
||||
server.garbage_collect_users()
|
||||
|
||||
return W.WEECHAT_RC_OK
|
||||
|
||||
|
|
Loading…
Reference in a new issue