-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathbridge.py
More file actions
172 lines (145 loc) · 6.07 KB
/
bridge.py
File metadata and controls
172 lines (145 loc) · 6.07 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
import base64
import logging
import uuid
from typing import Callable, List, Tuple
import requests
from matrix.appservice import Appservice
from msghandlers import MsgHandlers
from murmur.murmur import MurmurICE
from utils import ensure_image_size
# This class connects the two interfaces and does the actual bridging.
# It provides the interfaces with callback functions and transforms
# from the format of the sender interface to the format of the receiver interface.
# Also it applies the message handlers.
class Bridge:
def __init__(
self,
matrix: Appservice,
bridge_room: str,
user_prefix: str,
murmur: MurmurICE,
msg_handlers: List[Callable[[str, str], Tuple[bool, str]]],
message_on_connected: bool = False,
):
self._matrix = matrix
self._bridge_room = bridge_room
self._bridge_room_id = None
self._user_prefix = user_prefix
# Saves matrix users that already exist.
self._matrix_registrated_users = []
self._murmur = murmur
self._enabled_msg_handlers = msg_handlers
self._matrix.on_img_cb = self._on_matrix_img
self._matrix.on_msg_cb = self._on_matrix_msg
self._murmur.on_connection_cb = self._on_murmur_connection
self._murmur.on_msg_cb = self._on_murmur_msg
self._message_on_connected = message_on_connected
self._msg_handlers = MsgHandlers()
self.no_resize = False
def initialize(self) -> bool:
if not self._matrix_ensure_bridge_room():
return False
return True
def _matrix_ensure_bridge_room(self) -> bool:
id = self._matrix.resolve_room_alias(self._bridge_room)
if id is None:
logging.info("could not find matrix bridge room, creating")
id = self._matrix.create_room(self._bridge_room, "MandM-bridge")
if id is None:
logging.critical("could not create bridge room")
return False
if self._matrix.set_room_default_power(id, 50) is None:
logging.critical("could set default powerlevel for bridge room")
return False
else:
logging.info("found bridge room %s", id)
self._bridge_room_id = id
return True
def _matrix_ensure_user(self, name: str, has_to_be_joined: bool = False) -> bool:
exists = self._matrix.user_exist(self._user_prefix + name)
if not exists:
logging.info("user %s does not exist, registering", name)
if not self._matrix.register_user(self._user_prefix + name):
logging.error("could not create user")
return False
if has_to_be_joined:
return self._matrix_user_join_bridge_room(name)
return True
def _matrix_user_join_bridge_room(self, name: str) -> bool:
joined = self._matrix.user_join_room(
self._user_prefix + name, self._bridge_room_id, "connected"
)
if not joined:
logging.error("user could not join the bridge room")
return False
return True
def _matrix_user_leave_bridge_room(self, name: str) -> bool:
joined = self._matrix.user_leave_room(
self._user_prefix + name, self._bridge_room_id, "disconnected"
)
if not joined:
logging.error("user could not join the bridge room")
return False
return True
def _on_matrix_img(self, _, sender: str, image_url: str, image_name: str):
try:
img = requests.get(image_url).content
except requests.exceptions.RequestException:
logging.exception("error while getting media")
return
extension = "png" if ".png" in image_name else "jpeg"
if not self.no_resize:
img = ensure_image_size(img, extension)
else:
self.no_resize = False
encoded = base64.b64encode(img).decode("utf-8")
self._murmur.send_msg(
f'{sender} [matrix]: <img src="data:image/{extension};base64,{encoded}">'
)
def _on_matrix_msg(self, _, sender: str, msg: str):
for handler in self._enabled_msg_handlers:
if not handler.startswith("matrix"):
continue
send, msg = getattr(self._msg_handlers, handler)(sender, msg)
if not send:
return
if msg == "!noresize":
self.no_resize = True
self._murmur.send_msg(f"{sender} [matrix]: {msg}")
def _on_murmur_connection(self, sender: str, connection_event: str):
if sender not in self._matrix_registrated_users:
if not self._matrix_ensure_user(sender):
return
self._matrix_registrated_users.append(sender)
if connection_event == "connected":
self._matrix_user_join_bridge_room(sender)
if self._message_on_connected:
sent = self._matrix.user_send_msg(
self._user_prefix + sender,
"connected!",
self._bridge_room_id,
str(uuid.uuid4()),
)
if not sent:
logging.error("could not send matrix message")
else:
self._matrix_user_leave_bridge_room(sender)
def _on_murmur_msg(self, sender: str, msg: str):
for handler in self._enabled_msg_handlers:
if not handler.startswith("murmur"):
continue
send, msg = getattr(self._msg_handlers, handler)(sender, msg)
if not send:
return
if sender not in self._matrix_registrated_users:
if not self._matrix_ensure_user(sender, has_to_be_joined=True):
return
self._matrix_registrated_users.append(sender)
if len(msg) > 1000:
logging.info("murmur message too big, wont bridge")
return
sent = self._matrix.user_send_msg(
self._user_prefix + sender, msg, self._bridge_room_id, str(uuid.uuid4())
)
if not sent:
logging.error("could not send matrix message")