diff --git a/nanobot/channels/matrix.py b/nanobot/channels/matrix.py index 0ea4ae138..f3b84689b 100644 --- a/nanobot/channels/matrix.py +++ b/nanobot/channels/matrix.py @@ -1,10 +1,11 @@ import asyncio from typing import Any -from nio import AsyncClient, MatrixRoom, RoomMessageText +from nio import AsyncClient, AsyncClientConfig, InviteEvent, MatrixRoom, RoomMessageText -from nanobot.channels.base import BaseChannel from nanobot.bus.events import OutboundMessage +from nanobot.channels.base import BaseChannel +from nanobot.config.loader import get_data_dir class MatrixChannel(BaseChannel): @@ -22,18 +23,28 @@ class MatrixChannel(BaseChannel): async def start(self) -> None: self._running = True - self.client = AsyncClient( - homeserver=self.config.homeserver, - user=self.config.user_id, - ) - - self.client.access_token = self.config.access_token + store_path = get_data_dir() / "matrix-store" + store_path.mkdir(parents=True, exist_ok=True) - self.client.add_event_callback( - self._on_message, - RoomMessageText + self.client = AsyncClient( + homeserver=self.config.homeserver, + user=self.config.user_id, + store_path=store_path, # Where tokens are saved + config=AsyncClientConfig( + store_sync_tokens=True, # Auto-persists next_batch tokens + encryption_enabled=True, + ), ) + self.client.user_id = self.config.user_id + self.client.access_token = self.config.access_token + self.client.device_id = self.config.device_id + + self.client.add_event_callback(self._on_message, RoomMessageText) + self.client.add_event_callback(self._on_room_invite, InviteEvent) + + self.client.load_store() + self._sync_task = asyncio.create_task(self._sync_loop()) async def stop(self) -> None: @@ -51,22 +62,23 @@ class MatrixChannel(BaseChannel): room_id=msg.chat_id, message_type="m.room.message", content={"msgtype": "m.text", "body": msg.content}, + ignore_unverified_devices=True, ) async def _sync_loop(self) -> None: while self._running: try: - await self.client.sync(timeout=30000) + await self.client.sync_forever(timeout=30000, full_state=True) except asyncio.CancelledError: break except Exception: await asyncio.sleep(2) - async def _on_message( - self, - room: MatrixRoom, - event: RoomMessageText - ) -> None: + async def _on_room_invite(self, room: MatrixRoom, event: RoomMessageText) -> None: + if event.sender in self.config.allow_from: + await self.client.join(room.room_id) + + async def _on_message(self, room: MatrixRoom, event: RoomMessageText) -> None: # Ignore self messages if event.sender == self.config.user_id: return @@ -76,4 +88,4 @@ class MatrixChannel(BaseChannel): chat_id=room.room_id, content=event.body, metadata={"room": room.display_name}, - ) \ No newline at end of file + ) diff --git a/nanobot/config/schema.py b/nanobot/config/schema.py index aa29403a2..57a7e03ea 100644 --- a/nanobot/config/schema.py +++ b/nanobot/config/schema.py @@ -51,7 +51,8 @@ class MatrixConfig(BaseModel): enabled: bool = False homeserver: str = "https://matrix.org" access_token: str = "" - user_id: str = "" # @bot:matrix.org + user_id: str = "" # @bot:matrix.org + device_id: str = "" allow_from: list[str] = Field(default_factory=list) class ChannelsConfig(BaseModel): diff --git a/pyproject.toml b/pyproject.toml index 20afad6ea..92986b5ac 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -32,7 +32,7 @@ dependencies = [ "python-telegram-bot[socks]>=21.0", "lark-oapi>=1.0.0", "socksio>=1.0.0", - "matrix-nio>=0.25.2" + "matrix-nio[e2e]>=0.25.2", ] [project.optional-dependencies]