matrix: Change the way responses and events are executed.

This commit is contained in:
poljar (Damir Jelić) 2018-07-05 15:13:19 +02:00
parent e7208ded62
commit 38d6a14a33
6 changed files with 218 additions and 132 deletions

View file

@ -46,6 +46,7 @@ from matrix.commands import (hook_commands, hook_page_up, matrix_command_cb,
matrix_command_pgup_cb, matrix_redact_command_cb, matrix_command_pgup_cb, matrix_redact_command_cb,
matrix_command_buf_clear_cb, matrix_me_command_cb, matrix_command_buf_clear_cb, matrix_me_command_cb,
matrix_command_kick_cb) matrix_command_kick_cb)
from matrix.buffer import room_buffer_input_cb, room_buffer_close_cb
from matrix.server import ( from matrix.server import (
MatrixServer, MatrixServer,

View file

@ -28,7 +28,7 @@ from builtins import super
@utf8_decode @utf8_decode
def room_buffer_input_cb(server_name, buffer, input_data): def room_buffer_input_cb(server_name, buffer, input_data):
server = SERVERS[server_name] server = SERVERS[server_name]
room, room_buffer = server.find_room(buffer) room, room_buffer = server.find_room_from_ptr(buffer)
if not room_buffer: if not room_buffer:
# TODO log error # TODO log error
@ -40,9 +40,7 @@ def room_buffer_input_cb(server_name, buffer, input_data):
formatted_data = Formatted.from_input_line(input_data) formatted_data = Formatted.from_input_line(input_data)
if room.encrypted: server.send_room_message(room, formatted_data)
server.send_room_message(room.id, formatted_data)
return W.WEECHAT_RC_OK
return W.WEECHAT_RC_OK return W.WEECHAT_RC_OK
@ -86,6 +84,13 @@ class WeechatChannelBuffer(object):
"notify_message", "notify_message",
"log1" "log1"
], ],
"self_message": [
SCRIPT_NAME + "_message",
"notify_none",
"no_highlight",
"self_msg",
"log1"
],
"old_message": [ "old_message": [
SCRIPT_NAME + "_message", SCRIPT_NAME + "_message",
"notify_message", "notify_message",
@ -107,6 +112,10 @@ class WeechatChannelBuffer(object):
"invite": [ "invite": [
SCRIPT_NAME + "_invite", SCRIPT_NAME + "_invite",
"log4" "log4"
],
"topic": [
SCRIPT_NAME + "_topic",
"log3",
] ]
} }
@ -123,13 +132,17 @@ class WeechatChannelBuffer(object):
name, name,
"room_buffer_input_cb", "room_buffer_input_cb",
server_name, server_name,
"room_buffer_input_cb", "room_buffer_close_cb",
server_name, server_name,
) )
self.name = "" self.name = ""
self.users = {} # type: Dict[str, RoomUser] self.users = {} # type: Dict[str, RoomUser]
self.topic = ""
self.topic_author = ""
self.topic_date = None
W.buffer_set(self._ptr, "localvar_set_type", 'channel') W.buffer_set(self._ptr, "localvar_set_type", 'channel')
W.buffer_set(self._ptr, "type", 'formatted') W.buffer_set(self._ptr, "type", 'formatted')
@ -216,7 +229,7 @@ class WeechatChannelBuffer(object):
def _message_tags(self, user, message_type): def _message_tags(self, user, message_type):
# type: (str, RoomUser, str) -> List[str] # type: (str, RoomUser, str) -> List[str]
tags = self.tags[message_type].copy() tags = list(self.tags[message_type])
tags.append("nick_{nick}".format(nick=user.nick)) tags.append("nick_{nick}".format(nick=user.nick))
@ -235,10 +248,10 @@ class WeechatChannelBuffer(object):
# A message from a non joined user # A message from a non joined user
return RoomUser(nick) return RoomUser(nick)
def message(self, nick, message, date): def message(self, nick, message, date, tags=[]):
# type: (str, str, int, str) -> None # type: (str, str, int, str) -> None
user = self._get_user(nick) user = self._get_user(nick)
tags = self._message_tags(user, "message") tags = tags or self._message_tags(user, "message")
prefix_string = ("" if not user.prefix else "{}{}{}".format( prefix_string = ("" if not user.prefix else "{}{}{}".format(
W.color(self._get_prefix_color(user.prefix)), W.color(self._get_prefix_color(user.prefix)),
@ -264,10 +277,10 @@ class WeechatChannelBuffer(object):
self.message(nick, data, date) self.message(nick, data, date)
def action(self, nick, message, date): def action(self, nick, message, date, tags=[]):
# type: (str, str, int) -> None # type: (str, str, int) -> None
user = self._get_user(nick) user = self._get_user(nick)
tags = self._message_tags(user, "action") tags = tags or self._message_tags(user, "action")
nick_prefix = ("" if not user.prefix else "{}{}{}".format( nick_prefix = ("" if not user.prefix else "{}{}{}".format(
W.color(self._get_prefix_color(user.prefix)), W.color(self._get_prefix_color(user.prefix)),
@ -282,7 +295,7 @@ class WeechatChannelBuffer(object):
nick_color=W.color(user.color), nick_color=W.color(user.color),
author=nick, author=nick,
ncolor=W.color("reset"), ncolor=W.color("reset"),
msg=self.message) msg=message)
self.print_date_tags(data, date, tags) self.print_date_tags(data, date, tags)
@ -293,9 +306,9 @@ class WeechatChannelBuffer(object):
if user.prefix == "&": if user.prefix == "&":
group_name = "000|o" group_name = "000|o"
elif user.power_level == "@": elif user.prefix == "@":
group_name = "001|h" group_name = "001|h"
elif user.power_level > "+": elif user.prefix > "+":
group_name = "002|v" group_name = "002|v"
return group_name return group_name
@ -400,3 +413,41 @@ class WeechatChannelBuffer(object):
def kick(self, user, date, message=True, extra_tags=[]): def kick(self, user, date, message=True, extra_tags=[]):
# type: (WeechatUser, int, Optional[bool], Optional[List[str]]) -> None # type: (WeechatUser, int, Optional[bool], Optional[List[str]]) -> None
self._leave(user, date, message, "kick", extra_tags=[]) self._leave(user, date, message, "kick", extra_tags=[])
def _print_topic(self, nick, topic, date):
user = self._get_user(nick)
tags = self._message_tags(user, "topic")
data = ("{prefix}{nick} has changed "
"the topic for {chan_color}{room}{ncolor} "
"to \"{topic}\"").format(
prefix=W.prefix("network"),
nick=user.nick,
chan_color=W.color("chat_channel"),
ncolor=W.color("reset"),
room=self.name,
topic=topic
)
self.print_date_tags(data, date, tags)
def topic(self, nick, topic, date, message=True):
W.buffer_set(self._ptr, "title", topic)
if message:
self._print_topic(nick, topic, date)
self.topic = topic
self.topic_author = nick
self.topic_date = date
def self_message(self, nick, message, date):
user = self._get_user(nick)
tags = self._message_tags(user, "self_message")
self.message(nick, message, date, tags)
def self_action(self, nick, message, date):
user = self._get_user(nick)
tags = self._message_tags(user, "self_message")
tags.append(SCRIPT_NAME + "_action")
self.action(nick, message, date, tags)

View file

@ -73,8 +73,9 @@ class WeechatArgParse(argparse.ArgumentParser):
def error(self, message): def error(self, message):
m = ("{prefix}Error: {message} for command {command} " m = ("{prefix}Error: {message} for command {command} "
"(see /help {command})").format(prefix=W.prefix("error"), "(see /help {command})").format(prefix=W.prefix("error"),
message=message, command=self.prog) message=message,
command=self.prog)
W.prnt("", m) W.prnt("", m)
raise ParseError raise ParseError

View file

@ -27,11 +27,12 @@ from operator import itemgetter
from matrix.globals import W from matrix.globals import W
from matrix.utils import (tags_for_message, sanitize_id, sanitize_token, from matrix.utils import (tags_for_message, sanitize_id, sanitize_token,
sanitize_text, tags_from_line_data) sanitize_text, tags_from_line_data)
from matrix.rooms import (matrix_create_room_buffer, RoomInfo, RoomMessageText, from matrix.rooms import (RoomInfo, RoomMessageText,
RoomMessageEvent, RoomRedactedMessageEvent, RoomMessageEvent, RoomRedactedMessageEvent,
RoomMessageEmote) RoomMessageEmote)
from matrix.encryption import OlmDeviceKey, OneTimeKey from matrix.encryption import OlmDeviceKey, OneTimeKey
from .buffer import RoomUser
try: try:
from olm.session import OlmMessage, OlmPreKeyMessage from olm.session import OlmMessage, OlmPreKeyMessage
@ -657,7 +658,7 @@ class MatrixSyncEvent(MatrixEvent):
info = self.joined_room_infos.pop() info = self.joined_room_infos.pop()
if info.room_id not in server.buffers: if info.room_id not in server.buffers:
matrix_create_room_buffer(server, info.room_id) server.create_room_buffer(info.room_id)
room = server.rooms[info.room_id] room = server.rooms[info.room_id]

View file

@ -156,45 +156,15 @@ class MatrixUser:
# yapf: enable # yapf: enable
def matrix_create_room_buffer(server, room_id):
# type: (MatrixServer, str) -> None
buf = W.buffer_new(room_id, "room_input_cb", server.name, "room_close_cb",
server.name)
W.buffer_set(buf, "localvar_set_type", 'channel')
W.buffer_set(buf, "type", 'formatted')
W.buffer_set(buf, "localvar_set_channel", room_id)
W.buffer_set(buf, "localvar_set_nick", server.user)
W.buffer_set(buf, "localvar_set_server", server.name)
short_name = strip_matrix_server(room_id)
W.buffer_set(buf, "short_name", short_name)
W.nicklist_add_group(buf, '', "000|o", "weechat.color.nicklist_group", 1)
W.nicklist_add_group(buf, '', "001|h", "weechat.color.nicklist_group", 1)
W.nicklist_add_group(buf, '', "002|v", "weechat.color.nicklist_group", 1)
W.nicklist_add_group(buf, '', "999|...", "weechat.color.nicklist_group", 1)
W.buffer_set(buf, "nicklist", "1")
W.buffer_set(buf, "nicklist_display_groups", "0")
# TODO make this configurable
W.buffer_set(buf, "highlight_tags_restrict", "matrix_message")
server.buffers[room_id] = buf
server.rooms[room_id] = MatrixRoom(room_id)
class RoomInfo(): class RoomInfo():
def __init__(self, room_id, prev_batch, events): def __init__(self, room_id, prev_batch, state, timeline):
# type: (str, str, List[Any], List[Any]) -> None # type: (str, str, List[Any], List[Any]) -> None
self.room_id = room_id self.room_id = room_id
self.prev_batch = prev_batch self.prev_batch = prev_batch
self.events = deque(events)
self.state = deque(state)
self.timeline = deque(timeline)
@staticmethod @staticmethod
def _message_from_event(event): def _message_from_event(event):
@ -219,66 +189,40 @@ class RoomInfo():
raise ValueError raise ValueError
if event_dict["content"]["membership"] == "join": if event_dict["content"]["membership"] == "join":
event = RoomMemberJoin.from_dict(event_dict) return RoomMemberJoin.from_dict(event_dict)
try:
message = RoomMembershipMessage(
event.event_id, event.sender, event.timestamp,
"has joined", "join")
return event, message
except AttributeError:
return event, None
elif event_dict["content"]["membership"] == "leave": elif event_dict["content"]["membership"] == "leave":
event = RoomMemberLeave.from_dict(event_dict) return RoomMemberLeave.from_dict(event_dict)
try: return None
msg = ("has left" if event.sender == event.leaving_user else
"has been kicked")
message = RoomMembershipMessage(
event.event_id, event.leaving_user, event.timestamp, msg, "quit")
return event, message
except AttributeError:
return event, None
return None, None
@staticmethod @staticmethod
def parse_event(olm, room_id, event_dict): def parse_event(olm, room_id, event_dict):
# type: (Dict[Any, Any]) -> (RoomEvent, RoomEvent) # type: (Dict[Any, Any]) -> (RoomEvent, RoomEvent)
state_event = None event = None
message_event = None
if "redacted_by" in event_dict["unsigned"]: if "redacted_by" in event_dict["unsigned"]:
message_event = RoomRedactedMessageEvent.from_dict(event_dict) event = RoomRedactedMessageEvent.from_dict(event_dict)
elif event_dict["type"] == "m.room.message": elif event_dict["type"] == "m.room.message":
message_event = RoomInfo._message_from_event(event_dict) event = RoomInfo._message_from_event(event_dict)
elif event_dict["type"] == "m.room.member": elif event_dict["type"] == "m.room.member":
state_event, message_event = ( event = RoomInfo._membership_from_dict(event_dict)
RoomInfo._membership_from_dict(event_dict))
elif event_dict["type"] == "m.room.power_levels": elif event_dict["type"] == "m.room.power_levels":
state_event = RoomPowerLevels.from_dict(event_dict) event = RoomPowerLevels.from_dict(event_dict)
elif event_dict["type"] == "m.room.topic": elif event_dict["type"] == "m.room.topic":
state_event = RoomTopicEvent.from_dict(event_dict) event = RoomTopicEvent.from_dict(event_dict)
message_event = RoomTopiceMessage(
state_event.event_id,
state_event.sender,
state_event.timestamp,
state_event.topic)
elif event_dict["type"] == "m.room.redaction": elif event_dict["type"] == "m.room.redaction":
message_event = RoomRedactionEvent.from_dict(event_dict) event = RoomRedactionEvent.from_dict(event_dict)
elif event_dict["type"] == "m.room.name": elif event_dict["type"] == "m.room.name":
state_event = RoomNameEvent.from_dict(event_dict) event = RoomNameEvent.from_dict(event_dict)
elif event_dict["type"] == "m.room.canonical_alias": elif event_dict["type"] == "m.room.canonical_alias":
state_event = RoomAliasEvent.from_dict(event_dict) event = RoomAliasEvent.from_dict(event_dict)
elif event_dict["type"] == "m.room.encryption": elif event_dict["type"] == "m.room.encryption":
state_event = RoomEncryptionEvent.from_dict(event_dict) event = RoomEncryptionEvent.from_dict(event_dict)
elif event_dict["type"] == "m.room.encrypted": elif event_dict["type"] == "m.room.encrypted":
state_event, message_event = RoomInfo._decrypt_event(olm, room_id, event = RoomInfo._decrypt_event(olm, room_id, event_dict)
event_dict)
return state_event, message_event return event
@staticmethod @staticmethod
def _decrypt_event(olm, room_id, event_dict): def _decrypt_event(olm, room_id, event_dict):
@ -287,7 +231,7 @@ class RoomInfo():
plaintext = olm.group_decrypt(room_id, session_id, ciphertext) plaintext = olm.group_decrypt(room_id, session_id, ciphertext)
if not plaintext: if not plaintext:
return None, None return None
parsed_plaintext = json.loads(plaintext, encoding="utf-8") parsed_plaintext = json.loads(plaintext, encoding="utf-8")
@ -297,18 +241,13 @@ class RoomInfo():
return RoomInfo.parse_event(olm, room_id, event_dict) return RoomInfo.parse_event(olm, room_id, event_dict)
@staticmethod @staticmethod
def _parse_events(olm, room_id, parsed_dict, messages=True, state=True): def _parse_events(olm, room_id, parsed_dict):
state_events = [] events = []
message_events = []
if not messages and not state:
return []
try: try:
for event in parsed_dict: for event in parsed_dict:
m_event, s_event = RoomInfo.parse_event(olm, room_id, event) e = RoomInfo.parse_event(olm, room_id, event)
state_events.append(m_event) events.append(e)
message_events.append(s_event)
except (ValueError, TypeError, KeyError) as error: except (ValueError, TypeError, KeyError) as error:
message = ("{prefix}matrix: Error parsing " message = ("{prefix}matrix: Error parsing "
"room event of type {type}: {error}\n{event}").format( "room event of type {type}: {error}\n{event}").format(
@ -319,14 +258,6 @@ class RoomInfo():
W.prnt("", message) W.prnt("", message)
raise raise
events = []
if state:
events = events + state_events
if messages:
events = events + message_events
return events return events
@classmethod @classmethod
@ -336,12 +267,23 @@ class RoomInfo():
state_dict = parsed_dict['state']['events'] state_dict = parsed_dict['state']['events']
timeline_dict = parsed_dict['timeline']['events'] timeline_dict = parsed_dict['timeline']['events']
state_events = RoomInfo._parse_events(olm, room_id, state_dict, messages=False) state_events = RoomInfo._parse_events(
timeline_events = RoomInfo._parse_events(olm, room_id, timeline_dict) olm,
room_id,
state_dict
)
timeline_events = RoomInfo._parse_events(
olm,
room_id,
timeline_dict
)
events = state_events + timeline_events return cls(
room_id,
return cls(room_id, prev_batch, list(filter(None, events))) prev_batch,
list(filter(None, state_events)),
list(filter(None, timeline_events))
)
class RoomEvent(): class RoomEvent():

View file

@ -29,10 +29,19 @@ from http_parser.pyparser import HttpParser
from matrix.plugin_options import Option, DebugType from matrix.plugin_options import Option, DebugType
from matrix.utils import (key_from_value, prnt_debug, server_buffer_prnt, from matrix.utils import (key_from_value, prnt_debug, server_buffer_prnt,
create_server_buffer, tags_for_message) create_server_buffer, tags_for_message,
server_ts_to_weechat, shorten_sender)
from matrix.utf import utf8_decode from matrix.utf import utf8_decode
from matrix.globals import W, SERVERS, OPTIONS from matrix.globals import W, SERVERS, OPTIONS
import matrix.api as API import matrix.api as API
from .buffer import WeechatChannelBuffer, RoomUser
from .rooms import (
MatrixRoom,
RoomMessageText,
RoomMessageEmote,
MatrixUser,
RoomMemberJoin
)
from matrix.api import ( from matrix.api import (
MatrixClient, MatrixClient,
MatrixSyncMessage, MatrixSyncMessage,
@ -40,10 +49,13 @@ from matrix.api import (
MatrixKeyUploadMessage, MatrixKeyUploadMessage,
MatrixKeyQueryMessage, MatrixKeyQueryMessage,
MatrixToDeviceMessage, MatrixToDeviceMessage,
MatrixSendMessage,
MatrixEncryptedMessage, MatrixEncryptedMessage,
MatrixKeyClaimMessage MatrixKeyClaimMessage
) )
from .events import MatrixSendEvent
from matrix.encryption import ( from matrix.encryption import (
Olm, Olm,
EncryptionError, EncryptionError,
@ -77,6 +89,7 @@ class MatrixServer:
self.password = "" # type: str self.password = "" # type: str
self.rooms = dict() # type: Dict[str, MatrixRoom] self.rooms = dict() # type: Dict[str, MatrixRoom]
self.room_buffers = dict() # type: Dict[str, WeechatChannelBuffer]
self.buffers = dict() # type: Dict[str, weechat.buffer] self.buffers = dict() # type: Dict[str, weechat.buffer]
self.server_buffer = None # type: weechat.buffer self.server_buffer = None # type: weechat.buffer
self.fd_hook = None # type: weechat.hook self.fd_hook = None # type: weechat.hook
@ -433,7 +446,7 @@ class MatrixServer:
if self.server_buffer: if self.server_buffer:
message = ("{prefix}matrix: disconnected from server" message = ("{prefix}matrix: disconnected from server"
).format(prefix=W.prefix("network")) ).format(prefix=W.prefix("network"))
server_buffer_prnt(self, message) server_buffer_prnt(self, message)
if reconnect: if reconnect:
@ -486,16 +499,20 @@ class MatrixServer:
message = MatrixSyncMessage(self.client, self.next_batch, limit) message = MatrixSyncMessage(self.client, self.next_batch, limit)
self.send_queue.append(message) self.send_queue.append(message)
def _send_unencrypted_message(self, room_id, formatted_data):
message = MatrixSendMessage(
self.client, room_id=room_id, formatted_message=formatted_data)
self.send_or_queue(message)
def send_room_message( def send_room_message(
self, self,
room_id, room,
formatted_data, formatted_data,
already_claimed=False already_claimed=False
): ):
# type: (str, Formatted) -> None # type: (str, Formatted) -> None
room = self.rooms[room_id]
if not room.encrypted: if not room.encrypted:
self._send_unencrypted_message(room.room_id, formatted_data)
return return
# TODO don't send messages unless all the devices are verified # TODO don't send messages unless all the devices are verified
@ -505,8 +522,8 @@ class MatrixServer:
W.prnt("", "{prefix}matrix: Olm session missing for room, can't" W.prnt("", "{prefix}matrix: Olm session missing for room, can't"
" encrypt message.") " encrypt message.")
W.prnt("", pprint.pformat(missing)) W.prnt("", pprint.pformat(missing))
self.encryption_queue[room_id].append(formatted_data) self.encryption_queue[room.room_id].append(formatted_data)
message = MatrixKeyClaimMessage(self.client, room_id, missing) message = MatrixKeyClaimMessage(self.client, room.room_id, missing)
self.send_or_queue(message) self.send_or_queue(message)
return return
@ -525,7 +542,7 @@ class MatrixServer:
try: try:
payload_dict, to_device_dict = self.olm.group_encrypt( payload_dict, to_device_dict = self.olm.group_encrypt(
room_id, room.room_id,
plaintext_dict, plaintext_dict,
self.user_id, self.user_id,
room.users.keys() room.users.keys()
@ -538,7 +555,7 @@ class MatrixServer:
message = MatrixEncryptedMessage( message = MatrixEncryptedMessage(
self.client, self.client,
room_id, room.room_id,
formatted_data, formatted_data,
payload_dict payload_dict
) )
@ -612,19 +629,46 @@ class MatrixServer:
server_buffer_prnt(self, pprint.pformat(message.request.payload)) server_buffer_prnt(self, pprint.pformat(message.request.payload))
server_buffer_prnt(self, pprint.pformat(message.response.body)) server_buffer_prnt(self, pprint.pformat(message.response.body))
def handle_room_event(self, room, room_buffer, event, is_state_event):
if isinstance(event, RoomMemberJoin):
if event.sender in room.users:
user = room.users[event.sender]
if event.display_name:
user.display_name = event.display_name
else:
short_name = shorten_sender(event.sender)
user = MatrixUser(short_name, event.display_name)
buffer_user = RoomUser(user.name, event.sender)
room.users[event.sender] = user
if self.user_id == event.sender:
buffer_user.color = "weechat.color.chat_nick_self"
user.nick_color = "weechat.color.chat_nick_self"
room_buffer.join(
buffer_user,
server_ts_to_weechat(event.timestamp),
not is_state_event
)
else:
tags = tags_for_message("message")
event.execute(self, room, room_buffer._ptr, tags)
def _loop_events(self, info, n): def _loop_events(self, info, n):
for i in range(n+1): for i in range(n+1):
is_state = False
try: try:
event = info.events.popleft() event = info.state.popleft()
is_state = True
except IndexError: except IndexError:
return i try:
event = info.timeline.popleft()
except IndexError:
return i
room = self.rooms[info.room_id] room, room_buffer = self.find_room_from_id(info.room_id)
buf = self.buffers[info.room_id] self.handle_room_event(room, room_buffer, event, is_state)
tags = tags_for_message("message")
event.execute(self, room, buf, tags)
self.event_queue.appendleft(info) self.event_queue.appendleft(info)
return i return i
@ -657,6 +701,32 @@ class MatrixServer:
return return
def handle_own_messages(self, room_buffer, message):
if isinstance(message, RoomMessageText):
msg = (message.formatted_message.to_weechat()
if message.formatted_message
else message.message)
date = server_ts_to_weechat(message.timestamp)
room_buffer.self_message(self.user, msg, date)
return
elif isinstance(message, RoomMessageEmote):
date = server_ts_to_weechat(message.timestamp)
room_buffer.self_action(self.user, message.message, date)
return
raise NotImplementedError("Unsupported message of type {}".format(
type(message)))
def handle_matrix_response(self, response):
if isinstance(response, MatrixSendEvent):
_, room_buffer = self.find_room_from_id(response.room_id)
self.handle_own_messages(room_buffer, response.message)
else:
response.execute()
def handle_response(self, message): def handle_response(self, message):
# type: (MatrixMessage) -> None # type: (MatrixMessage) -> None
@ -674,7 +744,7 @@ class MatrixServer:
return return
event = message.event event = message.event
event.execute() self.handle_matrix_response(event)
else: else:
status_code = message.response.status status_code = message.response.status
if status_code == 504: if status_code == 504:
@ -705,6 +775,26 @@ class MatrixServer:
return return
def create_room_buffer(self, room_id):
buf = WeechatChannelBuffer(room_id, self.name, self.user)
# TODO this should turned into a propper class
self.room_buffers[room_id] = buf
self.buffers[room_id] = buf._ptr
self.rooms[room_id] = MatrixRoom(room_id)
pass
def find_room_from_ptr(self, pointer):
room_id = key_from_value(self.buffers, pointer)
room = self.rooms[room_id]
room_buffer = self.room_buffers[room_id]
return room, room_buffer
def find_room_from_id(self, room_id):
room = self.rooms[room_id]
room_buffer = self.room_buffers[room_id]
return room, room_buffer
@utf8_decode @utf8_decode
def matrix_config_server_read_cb(data, config_file, section, option_name, def matrix_config_server_read_cb(data, config_file, section, option_name,