Skip to content

Commit ee74e17

Browse files
committed
Add support for receiving EDUs directly (MSC2409)
1 parent 59b90d7 commit ee74e17

File tree

5 files changed

+54
-23
lines changed

5 files changed

+54
-23
lines changed

mautrix/appservice/appservice.py

+5-3
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import logging
1212

1313
from mautrix.types import JSON, UserID, RoomAlias
14+
from mautrix.util.logging import TraceLogger
1415

1516
from .api import AppServiceAPI, IntentAPI
1617
from .state_store import ASStateStore, FileASStateStore
@@ -47,7 +48,7 @@ class AppService(AppServiceServerMixin):
4748
live: bool
4849

4950
loop: asyncio.AbstractEventLoop
50-
log: logging.Logger
51+
log: TraceLogger
5152
app: web.Application
5253
runner: web.AppRunner
5354

@@ -57,8 +58,9 @@ def __init__(self, server: str, domain: str, as_token: str, hs_token: str, bot_l
5758
tls_cert: Optional[str] = None, tls_key: Optional[str] = None,
5859
query_user: QueryFunc = None, query_alias: QueryFunc = None,
5960
real_user_content_key: Optional[str] = "net.maunium.appservice.puppet",
60-
state_store: ASStateStore = None, aiohttp_params: Dict = None) -> None:
61-
super().__init__()
61+
state_store: ASStateStore = None, aiohttp_params: Dict = None,
62+
ephemeral_events: bool = False) -> None:
63+
super().__init__(ephemeral_events=ephemeral_events)
6264
self.server = server
6365
self.domain = domain
6466
self.id = id

mautrix/appservice/as_handler.py

+36-15
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
import asyncio
1111
import logging
1212

13-
from mautrix.types import JSON, UserID, RoomAlias, Event, SerializerError
13+
from mautrix.types import JSON, UserID, RoomAlias, Event, EphemeralEvent, SerializerError
1414

1515
QueryFunc = Callable[[web.Request], Awaitable[Optional[web.Response]]]
1616
HandlerFunc = Callable[[Event], Awaitable]
@@ -21,16 +21,18 @@ class AppServiceServerMixin:
2121
log: logging.Logger
2222

2323
hs_token: str
24+
ephemeral_events: bool
2425

2526
query_user: Callable[[UserID], JSON]
2627
query_alias: Callable[[RoomAlias], JSON]
2728

2829
transactions: Set[str]
2930
event_handlers: List[HandlerFunc]
3031

31-
def __init__(self) -> None:
32+
def __init__(self, ephemeral_events: bool = False) -> None:
3233
self.transactions = set()
3334
self.event_handlers = []
35+
self.ephemeral_events = ephemeral_events
3436

3537
async def default_query_handler(_):
3638
return None
@@ -64,45 +66,45 @@ def _check_token(self, request: web.Request) -> bool:
6466

6567
async def _http_query_user(self, request: web.Request) -> web.Response:
6668
if not self._check_token(request):
67-
return web.Response(status=401)
69+
return web.json_response({"error": "Invalid auth token"}, status=401)
6870

6971
try:
7072
user_id = request.match_info["user_id"]
7173
except KeyError:
72-
return web.Response(status=400)
74+
return web.json_response({"error": "Missing user_id parameter"}, status=400)
7375

7476
try:
7577
response = await self.query_user(user_id)
7678
except Exception:
7779
self.log.exception("Exception in user query handler")
78-
return web.Response(status=500)
80+
return web.json_response({"error": "Internal appservice error"}, status=500)
7981

8082
if not response:
81-
return web.Response(status=404)
83+
return web.json_response({}, status=404)
8284
return web.json_response(response)
8385

8486
async def _http_query_alias(self, request: web.Request) -> web.Response:
8587
if not self._check_token(request):
86-
return web.Response(status=401)
88+
return web.json_response({"error": "Invalid auth token"}, status=401)
8789

8890
try:
8991
alias = request.match_info["alias"]
9092
except KeyError:
91-
return web.Response(status=400)
93+
return web.json_response({"error": "Missing alias parameter"}, status=400)
9294

9395
try:
9496
response = await self.query_alias(alias)
9597
except Exception:
9698
self.log.exception("Exception in alias query handler")
97-
return web.Response(status=500)
99+
return web.json_response({"error": "Internal appservice error"}, status=500)
98100

99101
if not response:
100-
return web.Response(status=404)
102+
return web.json_response({}, status=404)
101103
return web.json_response(response)
102104

103105
async def _http_handle_transaction(self, request: web.Request) -> web.Response:
104106
if not self._check_token(request):
105-
return web.Response(status=401)
107+
return web.json_response({"error": "Invalid auth token"}, status=401)
106108

107109
transaction_id = request.match_info["transaction_id"]
108110
if transaction_id in self.transactions:
@@ -111,15 +113,26 @@ async def _http_handle_transaction(self, request: web.Request) -> web.Response:
111113
try:
112114
json = await request.json()
113115
except JSONDecodeError:
114-
return web.Response(status=400)
116+
return web.json_response({"error": "Body is not JSON"}, status=400)
115117

116118
try:
117119
events = json["events"]
118120
except KeyError:
119-
return web.Response(status=400)
121+
return web.json_response({"error": "Missing events object in body"}, status=400)
122+
123+
if self.ephemeral_events:
124+
try:
125+
ephemeral = json["ephemeral"]
126+
except KeyError:
127+
try:
128+
ephemeral = json["de.sorunome.msc2409.ephemeral"]
129+
except KeyError:
130+
ephemeral = None
131+
else:
132+
ephemeral = None
120133

121134
try:
122-
await self.handle_transaction(transaction_id, events)
135+
await self.handle_transaction(transaction_id, events=events, ephemeral=ephemeral)
123136
except Exception:
124137
self.log.exception("Exception in transaction handler")
125138

@@ -137,7 +150,15 @@ def _fix_prev_content(raw_event: JSON) -> None:
137150
except KeyError:
138151
pass
139152

140-
async def handle_transaction(self, txn_id: str, events: List[JSON]) -> None:
153+
async def handle_transaction(self, txn_id: str, events: List[JSON],
154+
ephemeral: Optional[List[JSON]] = None) -> None:
155+
for raw_edu in ephemeral:
156+
try:
157+
edu = EphemeralEvent.deserialize(raw_edu)
158+
except SerializerError:
159+
self.log.exception("Failed to deserialize ephemeral event %s", raw_edu)
160+
else:
161+
self.handle_matrix_event(edu)
141162
for raw_event in events:
142163
try:
143164
self._fix_prev_content(raw_event)

mautrix/bridge/commands/meta.py

+4-5
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
SECTION_GENERAL)
1212

1313

14-
@command_handler(help_section=SECTION_GENERAL,
14+
@command_handler(needs_auth=False, help_section=SECTION_GENERAL,
1515
help_text="Cancel an ongoing action.")
1616
async def cancel(evt: CommandEvent) -> EventID:
1717
if evt.sender.command_status:
@@ -22,7 +22,7 @@ async def cancel(evt: CommandEvent) -> EventID:
2222
return await evt.reply("No ongoing command.")
2323

2424

25-
@command_handler(help_section=SECTION_GENERAL,
25+
@command_handler(needs_auth=False, help_section=SECTION_GENERAL,
2626
help_text="Get the bridge version.")
2727
async def version(evt: CommandEvent) -> None:
2828
if not evt.processor.bridge:
@@ -32,7 +32,7 @@ async def version(evt: CommandEvent) -> None:
3232
f"{evt.processor.bridge.markdown_version or evt.processor.bridge.version}")
3333

3434

35-
@command_handler()
35+
@command_handler(needs_auth=False)
3636
async def unknown_command(evt: CommandEvent) -> EventID:
3737
return await evt.reply("Unknown command. Try `$cmdprefix+sp help` for help.")
3838

@@ -63,8 +63,7 @@ def _get_management_status(evt: CommandEvent) -> str:
6363
return "**This is not a management room**: you must prefix commands with `$cmdprefix`."
6464

6565

66-
@command_handler(name="help",
67-
help_section=SECTION_GENERAL,
66+
@command_handler(name="help", needs_auth=False, help_section=SECTION_GENERAL,
6867
help_text="Show this help message.")
6968
async def help_cmd(evt: CommandEvent) -> EventID:
7069
return await evt.reply(_get_management_status(evt) + "\n" + await _get_help_text(evt))

mautrix/bridge/config.py

+6
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ def do_update(self, helper: ConfigUpdateHelper) -> None:
7474
copy("appservice.as_token")
7575
copy("appservice.hs_token")
7676

77+
copy("appservice.ephemeral_events")
78+
7779
copy("logging")
7880

7981
@property
@@ -123,3 +125,7 @@ def generate_registration(self) -> None:
123125
"sender_localpart": self._new_token(),
124126
"rate_limited": False
125127
}
128+
129+
if self["appservice.ephemeral_events"]:
130+
self._registration["de.sorunome.msc2409.push_ephemeral"] = True
131+
self._registration["push_ephemeral"] = True

mautrix/bridge/matrix.py

+3
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,9 @@ async def int_handle_event(self, evt: Event) -> None:
426426
else:
427427
if evt.type.is_state and isinstance(evt, StateEvent):
428428
await self.handle_state_event(evt)
429+
elif evt.type.is_ephemeral and isinstance(evt, (PresenceEvent, TypingEvent,
430+
ReceiptEvent)):
431+
await self.handle_ephemeral_event(evt)
429432
else:
430433
await self.handle_event(evt)
431434

0 commit comments

Comments
 (0)