Add initial backlog event.
The backlog event currently only supports non redacted messages.
This commit is contained in:
parent
afd595b780
commit
3b77689c7d
4 changed files with 280 additions and 30 deletions
|
@ -421,6 +421,23 @@ class MatrixBacklogMessage(MatrixMessage):
|
||||||
data
|
data
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def decode_body(self, server):
|
||||||
|
try:
|
||||||
|
parsed_dict = json.loads(
|
||||||
|
self.response.body,
|
||||||
|
encoding='utf-8',
|
||||||
|
)
|
||||||
|
self.event = MatrixEvents.MatrixBacklogEvent.from_dict(
|
||||||
|
server,
|
||||||
|
self.room_id,
|
||||||
|
parsed_dict
|
||||||
|
)
|
||||||
|
|
||||||
|
return (True, None)
|
||||||
|
|
||||||
|
except json.decoder.JSONDecodeError as error:
|
||||||
|
return (False, error)
|
||||||
|
|
||||||
|
|
||||||
class MatrixJoinMessage(MatrixMessage):
|
class MatrixJoinMessage(MatrixMessage):
|
||||||
def __init__(self, client, room_id):
|
def __init__(self, client, room_id):
|
||||||
|
|
203
matrix/events.py
203
matrix/events.py
|
@ -18,9 +18,18 @@ from __future__ import unicode_literals
|
||||||
from builtins import str
|
from builtins import str
|
||||||
|
|
||||||
import time
|
import time
|
||||||
|
import math
|
||||||
|
from functools import partial
|
||||||
|
|
||||||
from matrix.globals import W, OPTIONS
|
from matrix.globals import W, OPTIONS
|
||||||
from matrix.utils import color_for_tags
|
from matrix.utils import (
|
||||||
|
color_for_tags,
|
||||||
|
date_from_age,
|
||||||
|
sender_to_nick_and_color,
|
||||||
|
tags_for_message,
|
||||||
|
add_event_tags
|
||||||
|
)
|
||||||
|
from matrix.colors import Formatted
|
||||||
|
|
||||||
def sanitize_id(string):
|
def sanitize_id(string):
|
||||||
# type: (unicode) -> unicode
|
# type: (unicode) -> unicode
|
||||||
|
@ -40,6 +49,38 @@ def sanitize_id(string):
|
||||||
return string.translate(remap)
|
return string.translate(remap)
|
||||||
|
|
||||||
|
|
||||||
|
def sanitize_age(age):
|
||||||
|
# type: (int) -> int
|
||||||
|
if not isinstance(age, int):
|
||||||
|
raise TypeError
|
||||||
|
|
||||||
|
if math.isnan(age):
|
||||||
|
raise ValueError
|
||||||
|
|
||||||
|
if math.isinf(age):
|
||||||
|
raise ValueError
|
||||||
|
|
||||||
|
if age < 0:
|
||||||
|
raise ValueError
|
||||||
|
|
||||||
|
return age
|
||||||
|
|
||||||
|
|
||||||
|
def sanitize_text(string):
|
||||||
|
# type: (str) -> str
|
||||||
|
if not isinstance(string, str):
|
||||||
|
raise TypeError
|
||||||
|
|
||||||
|
remap = {
|
||||||
|
ord('\b'): None,
|
||||||
|
ord('\f'): None,
|
||||||
|
ord('\r'): None,
|
||||||
|
ord('\0'): None
|
||||||
|
}
|
||||||
|
|
||||||
|
return string.translate(remap)
|
||||||
|
|
||||||
|
|
||||||
class MatrixEvent():
|
class MatrixEvent():
|
||||||
def __init__(self, server):
|
def __init__(self, server):
|
||||||
self.server = server
|
self.server = server
|
||||||
|
@ -104,7 +145,7 @@ class MatrixLoginEvent(MatrixEvent):
|
||||||
sanitize_id(parsed_dict["user_id"]),
|
sanitize_id(parsed_dict["user_id"]),
|
||||||
sanitize_id(parsed_dict["access_token"])
|
sanitize_id(parsed_dict["access_token"])
|
||||||
)
|
)
|
||||||
except (KeyError, TypeError):
|
except (KeyError, TypeError, ValueError):
|
||||||
return MatrixErrorEvent.from_dict(
|
return MatrixErrorEvent.from_dict(
|
||||||
server,
|
server,
|
||||||
"Error logging in",
|
"Error logging in",
|
||||||
|
@ -153,7 +194,7 @@ class MatrixSendEvent(MatrixEvent):
|
||||||
sanitize_id(parsed_dict["event_id"]),
|
sanitize_id(parsed_dict["event_id"]),
|
||||||
message
|
message
|
||||||
)
|
)
|
||||||
except (KeyError, TypeError):
|
except (KeyError, TypeError, ValueError):
|
||||||
return MatrixErrorEvent.from_dict(
|
return MatrixErrorEvent.from_dict(
|
||||||
server,
|
server,
|
||||||
"Error sending message",
|
"Error sending message",
|
||||||
|
@ -178,7 +219,7 @@ class MatrixTopicEvent(MatrixEvent):
|
||||||
sanitize_id(parsed_dict["event_id"]),
|
sanitize_id(parsed_dict["event_id"]),
|
||||||
topic
|
topic
|
||||||
)
|
)
|
||||||
except (KeyError, TypeError):
|
except (KeyError, TypeError, ValueError):
|
||||||
return MatrixErrorEvent.from_dict(
|
return MatrixErrorEvent.from_dict(
|
||||||
server,
|
server,
|
||||||
"Error setting topic",
|
"Error setting topic",
|
||||||
|
@ -203,7 +244,7 @@ class MatrixRedactEvent(MatrixEvent):
|
||||||
sanitize_id(parsed_dict["event_id"]),
|
sanitize_id(parsed_dict["event_id"]),
|
||||||
reason
|
reason
|
||||||
)
|
)
|
||||||
except (KeyError, TypeError):
|
except (KeyError, TypeError, ValueError):
|
||||||
return MatrixErrorEvent.from_dict(
|
return MatrixErrorEvent.from_dict(
|
||||||
server,
|
server,
|
||||||
"Error redacting message",
|
"Error redacting message",
|
||||||
|
@ -226,7 +267,7 @@ class MatrixJoinEvent(MatrixEvent):
|
||||||
room_id,
|
room_id,
|
||||||
sanitize_id(parsed_dict["room_id"]),
|
sanitize_id(parsed_dict["room_id"]),
|
||||||
)
|
)
|
||||||
except (KeyError, TypeError):
|
except (KeyError, TypeError, ValueError):
|
||||||
return MatrixErrorEvent.from_dict(
|
return MatrixErrorEvent.from_dict(
|
||||||
server,
|
server,
|
||||||
"Error joining room",
|
"Error joining room",
|
||||||
|
@ -281,3 +322,153 @@ class MatrixInviteEvent(MatrixEvent):
|
||||||
False,
|
False,
|
||||||
parsed_dict
|
parsed_dict
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class MatrixBacklogEvent(MatrixEvent):
|
||||||
|
def __init__(self, server, room_id, end_token, messages):
|
||||||
|
self.room_id = room_id
|
||||||
|
self.end_token = end_token
|
||||||
|
self.messages = messages
|
||||||
|
MatrixEvent.__init__(self, server)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _message_from_event(room_id, event):
|
||||||
|
if room_id != event["room_id"]:
|
||||||
|
raise ValueError
|
||||||
|
|
||||||
|
if "redacted_by" in event["unsigned"]:
|
||||||
|
return RedactedMessage.from_dict(event)
|
||||||
|
|
||||||
|
return Message.from_dict(event)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_dict(cls, server, room_id, parsed_dict):
|
||||||
|
try:
|
||||||
|
if not parsed_dict["chunk"]:
|
||||||
|
return cls(server, room_id, None, [])
|
||||||
|
|
||||||
|
end_token = sanitize_id(parsed_dict["end"])
|
||||||
|
|
||||||
|
message_func = partial(
|
||||||
|
MatrixBacklogEvent._message_from_event,
|
||||||
|
room_id
|
||||||
|
)
|
||||||
|
|
||||||
|
message_events = list(filter(
|
||||||
|
lambda event: event["type"] == "m.room.message",
|
||||||
|
parsed_dict["chunk"]
|
||||||
|
))
|
||||||
|
|
||||||
|
messages = [message_func(m) for m in message_events]
|
||||||
|
|
||||||
|
return cls(
|
||||||
|
server,
|
||||||
|
room_id,
|
||||||
|
end_token,
|
||||||
|
messages)
|
||||||
|
except (KeyError, ValueError, TypeError):
|
||||||
|
return MatrixErrorEvent.from_dict(
|
||||||
|
server,
|
||||||
|
"Error fetching backlog",
|
||||||
|
False,
|
||||||
|
parsed_dict
|
||||||
|
)
|
||||||
|
|
||||||
|
def execute(self):
|
||||||
|
room = self.server.rooms[self.room_id]
|
||||||
|
buf = self.server.buffers[self.room_id]
|
||||||
|
tags = tags_for_message("backlog")
|
||||||
|
|
||||||
|
for message in self.messages:
|
||||||
|
message.prnt(room, buf, tags)
|
||||||
|
|
||||||
|
room.prev_batch = self.end_token
|
||||||
|
|
||||||
|
|
||||||
|
class AbstractMessage():
|
||||||
|
def __init__(self, event_id, sender, age):
|
||||||
|
self.event_id = event_id
|
||||||
|
self.sender = sender
|
||||||
|
self.age = age
|
||||||
|
|
||||||
|
|
||||||
|
class RedactedMessage(AbstractMessage):
|
||||||
|
def __init__(self, event_id, sender, age, censor, reason=None):
|
||||||
|
self.censor = censor
|
||||||
|
self.reason = reason
|
||||||
|
AbstractMessage.__init__(self, event_id, sender, age)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_dict(cls, event):
|
||||||
|
event_id = sanitize_id(event["event_id"])
|
||||||
|
sender = sanitize_id(event["sender"])
|
||||||
|
age = event["unsigned"]["age"]
|
||||||
|
|
||||||
|
censor = sanitize_id(
|
||||||
|
event['unsigned']['redacted_because']['sender'])
|
||||||
|
reason = None
|
||||||
|
|
||||||
|
if 'reason' in event['unsigned']['redacted_because']['content']:
|
||||||
|
reason = sanitize_text(
|
||||||
|
event['unsigned']['redacted_because']['content']['reason'])
|
||||||
|
|
||||||
|
return cls(event_id, sender, age, censor, reason)
|
||||||
|
|
||||||
|
def prnt(self, room, buff, tags):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class Message(AbstractMessage):
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
event_id,
|
||||||
|
sender,
|
||||||
|
age,
|
||||||
|
message,
|
||||||
|
formatted_message=None
|
||||||
|
):
|
||||||
|
self.message = message
|
||||||
|
self.formatted_message = formatted_message
|
||||||
|
AbstractMessage.__init__(self, event_id, sender, age)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_dict(cls, event):
|
||||||
|
event_id = sanitize_id(event["event_id"])
|
||||||
|
sender = sanitize_id(event["sender"])
|
||||||
|
age = sanitize_age(event["unsigned"]["age"])
|
||||||
|
|
||||||
|
msg = ""
|
||||||
|
formatted_msg = None
|
||||||
|
|
||||||
|
if event['content']['msgtype'] == 'm.text':
|
||||||
|
msg = sanitize_text(event['content']['body'])
|
||||||
|
|
||||||
|
if ('format' in event['content'] and
|
||||||
|
'formatted_body' in event['content']):
|
||||||
|
if event['content']['format'] == "org.matrix.custom.html":
|
||||||
|
formatted_msg = Formatted.from_html(
|
||||||
|
sanitize_text(event['content']['formatted_body']))
|
||||||
|
|
||||||
|
return cls(event_id, sender, age, msg, formatted_msg)
|
||||||
|
|
||||||
|
def prnt(self, room, buff, tags):
|
||||||
|
msg = (self.formatted_message.to_weechat() if
|
||||||
|
self.formatted_message
|
||||||
|
else self.message)
|
||||||
|
|
||||||
|
nick, color_name = sender_to_nick_and_color(room, self.sender)
|
||||||
|
color = color_for_tags(color_name)
|
||||||
|
|
||||||
|
event_tags = add_event_tags(
|
||||||
|
self.event_id,
|
||||||
|
nick,
|
||||||
|
color,
|
||||||
|
tags
|
||||||
|
)
|
||||||
|
|
||||||
|
tags_string = ",".join(event_tags)
|
||||||
|
|
||||||
|
data = "{author}\t{msg}".format(author=nick, msg=msg)
|
||||||
|
|
||||||
|
date = date_from_age(self.age)
|
||||||
|
W.prnt_date_tags(buff, date, tags_string, data)
|
||||||
|
|
|
@ -660,17 +660,6 @@ def matrix_update_buffer_lines(new_lines, own_lines):
|
||||||
line = W.hdata_move(hdata_line, line, 1)
|
line = W.hdata_move(hdata_line, line, 1)
|
||||||
|
|
||||||
|
|
||||||
def matrix_handle_old_messages(server, room_id, events):
|
|
||||||
for event in events:
|
|
||||||
if event['type'] == 'm.room.message':
|
|
||||||
matrix_handle_room_messages(server, room_id, event, old=True)
|
|
||||||
# TODO do we wan't to handle topics joins/quits here?
|
|
||||||
else:
|
|
||||||
pass
|
|
||||||
|
|
||||||
matrix_sort_old_messages(server, room_id)
|
|
||||||
|
|
||||||
|
|
||||||
def matrix_handle_message(
|
def matrix_handle_message(
|
||||||
server, # type: MatrixServer
|
server, # type: MatrixServer
|
||||||
message, # type: MatrixMessage
|
message, # type: MatrixMessage
|
||||||
|
@ -707,6 +696,11 @@ def matrix_handle_message(
|
||||||
event = message.event
|
event = message.event
|
||||||
event.execute()
|
event.execute()
|
||||||
|
|
||||||
|
elif message_type == MessageType.ROOM_MSG:
|
||||||
|
event = message.event
|
||||||
|
event.execute()
|
||||||
|
matrix_sort_old_messages(server, message.room_id)
|
||||||
|
|
||||||
elif message_type is MessageType.SYNC:
|
elif message_type is MessageType.SYNC:
|
||||||
next_batch = response['next_batch']
|
next_batch = response['next_batch']
|
||||||
|
|
||||||
|
@ -723,19 +717,6 @@ def matrix_handle_message(
|
||||||
# TODO add a delay to this
|
# TODO add a delay to this
|
||||||
server.sync()
|
server.sync()
|
||||||
|
|
||||||
elif message_type == MessageType.ROOM_MSG:
|
|
||||||
# Response has no messages, that is we already got the oldest message
|
|
||||||
# in a previous request, nothing to do
|
|
||||||
if not response['chunk']:
|
|
||||||
return
|
|
||||||
|
|
||||||
room_id = response['chunk'][0]['room_id']
|
|
||||||
room = server.rooms[room_id]
|
|
||||||
|
|
||||||
matrix_handle_old_messages(server, room_id, response['chunk'])
|
|
||||||
|
|
||||||
room.prev_batch = response['end']
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
server_buffer_prnt(
|
server_buffer_prnt(
|
||||||
server,
|
server,
|
||||||
|
|
|
@ -119,3 +119,64 @@ def color_for_tags(color):
|
||||||
option = W.config_get(color)
|
option = W.config_get(color)
|
||||||
return W.config_string(option)
|
return W.config_string(option)
|
||||||
return color
|
return color
|
||||||
|
|
||||||
|
|
||||||
|
def date_from_age(age):
|
||||||
|
# type: (float) -> int
|
||||||
|
now = time.time()
|
||||||
|
date = int(now - (age / 1000))
|
||||||
|
return date
|
||||||
|
|
||||||
|
|
||||||
|
def strip_matrix_server(string):
|
||||||
|
# type: (str) -> str
|
||||||
|
return string.rsplit(":", 1)[0]
|
||||||
|
|
||||||
|
|
||||||
|
def shorten_sender(sender):
|
||||||
|
# type: (str) -> str
|
||||||
|
return strip_matrix_server(sender)[1:]
|
||||||
|
|
||||||
|
|
||||||
|
def sender_to_nick_and_color(room, sender):
|
||||||
|
nick = sender
|
||||||
|
nick_color_name = "default"
|
||||||
|
|
||||||
|
if sender in room.users:
|
||||||
|
user = room.users[sender]
|
||||||
|
nick = user.display_name
|
||||||
|
nick_color_name = user.nick_color
|
||||||
|
else:
|
||||||
|
nick = shorten_sender(sender)
|
||||||
|
nick_color_name = W.info_get("nick_color_name", nick)
|
||||||
|
|
||||||
|
return (nick, nick_color_name)
|
||||||
|
|
||||||
|
|
||||||
|
def tags_for_message(message_type):
|
||||||
|
default_tags = {
|
||||||
|
"message": [
|
||||||
|
"matrix_message",
|
||||||
|
"notify_message",
|
||||||
|
"log1"
|
||||||
|
],
|
||||||
|
"backlog": [
|
||||||
|
"matrix_message",
|
||||||
|
"notify_message",
|
||||||
|
"no_log",
|
||||||
|
"no_highlight"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
return default_tags[message_type]
|
||||||
|
|
||||||
|
|
||||||
|
def add_event_tags(event_id, nick, color, tags):
|
||||||
|
if not tags:
|
||||||
|
tags = tags_for_message("message")
|
||||||
|
|
||||||
|
tags.append("nick_{nick}".format(nick=nick))
|
||||||
|
tags.append("perfix_nick_{color}".format(color=color_for_tags(color)))
|
||||||
|
tags.append("matrix_id_{event_id}".format(event_id=event_id))
|
||||||
|
|
||||||
|
return tags
|
||||||
|
|
Loading…
Add table
Reference in a new issue