From 9d3b624733b49202dc48d9b18bfebc35dd4534a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Mon, 3 Dec 2018 22:28:49 +0100 Subject: [PATCH] server: Add support for sending out read markers. --- main.py | 19 +++++++++++++------ matrix/buffer.py | 45 +++++++++++++++++++++++++++++++++++++++++++++ matrix/commands.py | 22 ++++++++++++++++++++-- matrix/config.py | 13 +++++++++++++ matrix/server.py | 20 ++++++++++++++++++++ 5 files changed, 111 insertions(+), 8 deletions(-) diff --git a/main.py b/main.py index 2cd7bd3..69f420d 100644 --- a/main.py +++ b/main.py @@ -463,12 +463,16 @@ class WeechatHandler(StreamHandler): W.prnt(buf, item) -def lazy_fetch_members_signal(_, _signal, buffer_ptr): - """ Fetch room members on a buffer switch signal. +def buffer_switch_cb(_, _signal, buffer_ptr): + """Do some buffer operations when we switch buffers. + This function is called every time we switch a buffer. The pointer of - the new buffer is given to us by weechat. If it is one of our room buffers - we check if the members for the room aren't fetched and fetch them now if - they aren't. + the new buffer is given to us by weechat. + + If it is one of our room buffers we check if the members for the room + aren't fetched and fetch them now if they aren't. + + Read receipts are send out from here as well. """ for server in SERVERS.values(): if buffer_ptr == server.server_buffer: @@ -481,6 +485,9 @@ def lazy_fetch_members_signal(_, _signal, buffer_ptr): if not room_buffer: continue + if room_buffer.should_send_read_marker: + server.room_send_read_marker(room_buffer) + if room_buffer.members_fetched: return W.WEECHAT_RC_OK @@ -533,7 +540,7 @@ if __name__ == "__main__": init_bar_items() init_completion() - W.hook_signal("buffer_switch", "lazy_fetch_members_signal", "") + W.hook_signal("buffer_switch", "buffer_switch_cb", "") W.hook_signal("input_text_changed", "typing_notification_cb", "") if not SERVERS: diff --git a/matrix/buffer.py b/matrix/buffer.py index c70a875..78b1c9f 100644 --- a/matrix/buffer.py +++ b/matrix/buffer.py @@ -829,6 +829,9 @@ class RoomBuffer(object): self._typing = False self.typing_enabled = True + self.last_read_event = None + self._read_markers_enabled = True + buffer_name = "{}.{}".format(server_name, room.room_id) # This dict remembers the connection from a user_id to the name we @@ -899,6 +902,48 @@ class RoomBuffer(object): return True return False + @property + def should_send_read_marker(self): + # type () -> bool + """Check if we need to send out a read receipt.""" + if not self.read_markers_enabled: + return False + + if not self.last_read_event: + return True + + if self.last_read_event == self.last_event_id: + return False + + return True + + @property + def last_event_id(self): + # type () -> str + """Get the event id of the last shown matrix event.""" + for line in self.weechat_buffer.lines: + for tag in line.tags: + if tag.startswith("matrix_id"): + event_id = tag[10:] + return event_id + + return "" + + @property + def read_markers_enabled(self): + # type: () -> bool + """Check if read receipts are enabled for this room.""" + return bool(int(W.string_eval_expression( + G.CONFIG.network.read_markers_conditions, + {}, + {"markers_enabled": str(int(self._read_markers_enabled))}, + {"type": "condition"} + ))) + + @read_markers_enabled.setter + def read_markers_enabled(self, value): + self._read_markers_enabled = value + def find_nick(self, user_id): # type: (str) -> str """Find a suitable nick from a user_id.""" diff --git a/matrix/commands.py b/matrix/commands.py index 9350b67..14f2b5b 100644 --- a/matrix/commands.py +++ b/matrix/commands.py @@ -151,6 +151,12 @@ class WeechatCommandParser(object): choices=["enable", "disable", "toggle"] ) + read_markers = subparsers.add_parser("read-markers") + read_markers.add_argument( + "state", + choices=["enable", "disable", "toggle"] + ) + return WeechatCommandParser._run_parser(parser, args) @@ -376,12 +382,15 @@ def hook_commands(): "room", "change room state", # Synopsis - ("typing-notifications " + ("typing-notifications ||" + "read-markers " ), # Description ("state: one of enable, disable or toggle\n"), # Completions - ("typing-notifications enable|disable|toggle"), + ("typing-notifications enable|disable|toggle||" + "read-markers enable|disable|toggle" + ), # Callback "matrix_room_command_cb", "", @@ -915,6 +924,15 @@ def matrix_room_command_cb(data, buffer, args): room.typing_enabled = not room.typing_enabled break + elif parsed_args.subcommand == "read-markers": + if parsed_args.state == "enable": + room.read_markers_enabled = True + elif parsed_args.state == "disable": + room.read_markers_enabled = False + elif parsed_args.state == "toggle": + room.read_markers_enabled = not room.read_markers_enabled + break + return W.WEECHAT_RC_OK diff --git a/matrix/config.py b/matrix/config.py index 8f80bb9..8914938 100644 --- a/matrix/config.py +++ b/matrix/config.py @@ -625,6 +625,19 @@ class MatrixConfig(WeechatConfig): "the typing_enabled variable can be manipulated with the " "/room command, see /help room"), ), + Option( + "read_markers_conditions", + "string", + "", + 0, + 0, + "${markers_enabled}", + ("conditions to send read markers (note: content is " + "evaluated, see /help eval); besides the buffer and window " + "variables the markers_enabled variable is also expanded; " + "the markers_enabled variable can be manipulated with the " + "/room command, see /help room"), + ), ] color_options = [ diff --git a/matrix/server.py b/matrix/server.py index 657a94b..ab49e61 100644 --- a/matrix/server.py +++ b/matrix/server.py @@ -673,6 +673,26 @@ class MatrixServer(object): self.backlog_queue[uuid] = room_id self.send_or_queue(request) + def room_send_read_marker(self, room_buffer): + """Send read markers for the provided room. + + Args: + room_buffer(RoomBuffer): the room for which the read markers should + be sent. + """ + if not self.connected: + return + + event_id = room_buffer.last_event_id + + _, request = self.client.room_read_markers( + room_buffer.room.room_id, + fully_read_event=event_id, + read_event=event_id) + self.send(request) + + room_buffer.last_read_event = event_id + def room_send_typing_notice(self, room_buffer): """Send a typing notice for the provided room.