diff --git a/README.md b/README.md index e4c8077..aa81add 100644 --- a/README.md +++ b/README.md @@ -3,3 +3,9 @@ A package implementing a reusable class to make matrix bots This is inventing the wheel once again, but who care? It's fun :) + +## TODO: + +- Use more of nio features and less custom hacks (like, use callback for the +invite policy stuff, and nio.Room is way better than my custom type) + diff --git a/src/matrix_bot/client.py b/src/matrix_bot/client.py index 44997a2..2c22337 100644 --- a/src/matrix_bot/client.py +++ b/src/matrix_bot/client.py @@ -1,3 +1,4 @@ +from __future__ import annotations """ The Client class. Connect to the matrix server and handle interactions with the server. @@ -9,6 +10,8 @@ import nio from aiopath import AsyncPath from typing import ( Any, + Awaitable, + Callable, Optional, NoReturn, Union @@ -32,6 +35,8 @@ class Client(Aobject): Connect to the matrix server and handle interactions with the server. + user: the user id of the client (exp: @bot:matrix.org) + /!\ The client is initialized asyncronously: `client = await Client(...)` """ @@ -43,6 +48,7 @@ class Client(Aobject): __sync_token_queue: asyncio.Queue[str] __invite_queue: asyncio.Queue[tuple[RoomId, nio.responses.InviteInfo]] __invite_policy: InvitePolicy + user: str async def __init__( self, @@ -81,6 +87,7 @@ class Client(Aobject): if isinstance(resp, nio.responses.LoginError): raise RuntimeError(f"Fail to connect: {resp.message}") log.info("logged in") + self.user_id = self.__client.user_id async def resolve_room( self, @@ -283,6 +290,18 @@ class Client(Aobject): for room_id in invites: await self.__invite_queue.put((room_id, invites[room_id])) + def add_message_callback( + self, + callback: Callable[[Client, nio.rooms.Room, nio.events.room_events.RoomMessageText], Awaitable[None]] + ): + """ + Add a callback called when a message is received. + The callback is an async function that take the client, the room and the event message in arg. + """ + async def new_callback(room: nio.rooms.Room, msg: nio.events.room_events.RoomMessageText): + await callback(self, room, msg) + self.__client.add_event_callback(new_callback, nio.RoomMessageText) + async def run( self, sync_timeout:int=30 diff --git a/src/matrix_bot/utils.py b/src/matrix_bot/utils.py index 15e7a4e..0c00d95 100644 --- a/src/matrix_bot/utils.py +++ b/src/matrix_bot/utils.py @@ -1,11 +1,15 @@ +from __future__ import annotations """ Utilities for the bot. """ +from typing import TYPE_CHECKING from dataclasses import ( dataclass, field ) +if TYPE_CHECKING: + from .client import Client RoomAlias = str RoomId = str @@ -17,3 +21,18 @@ class Room: id: RoomId aliases: set[RoomAlias] = field(default_factory=set) +def ignore_client_message( + callback: Callable[[Client, nio.rooms.Room, nio.events.room_events.RoomMessageText], Awaitable[None]] +)->Callable[[Client, nio.rooms.Room, nio.events.room_events.RoomMessageText], Awaitable[None]]: + """ + Decorator for message callback. + The decorated callback will ignore message sent by the client. + """ + async def new_callback( + client: Client, + room: nio.rooms.Room, + message: nio.events.room_events.RoomMessageText + ): + if client.user_id != message.sender: + await callback(client, room, message) + return new_callback diff --git a/tests/test.py b/tests/test.py index eaa3676..92133df 100644 --- a/tests/test.py +++ b/tests/test.py @@ -1,5 +1,5 @@ """ -Not really tests, because I don't know how to testt without a whole matrix server. +Not really tests, because I don't know how to test without a whole matrix server. """ import asyncio @@ -12,10 +12,15 @@ from matrix_bot.invite_policy import ( DeclineAll, WhiteList ) +from matrix_bot.utils import ignore_client_message from getpass import getpass logging.basicConfig(format="%(levelname)s: %(message)s", level=logging.DEBUG) +@ignore_client_message +async def callback(client, room, event): + await client.send_message(room.room_id, "Hello!") + async def main(): load_dotenv() client = await Client( @@ -23,25 +28,18 @@ async def main(): os.environ["HOMESERVER"], os.environ["PASSWD"], ) + client.add_message_callback(callback) withelisted_room_names = os.environ["ROOMS"].split(",") whitelist_policy = await WhiteList(client, withelisted_room_names) room_name = withelisted_room_names[0] client.set_invite_policy(whitelist_policy) await client.send_message(room_name, "Beware of Greeks bearing gifts") - await asyncio.sleep(5) + await asyncio.sleep(1) await client.send_formated_message( room_name, "Beware of Greeks bearing gifts", "Beware of Greeks bearing gifts" ) - await asyncio.sleep(5) - await client.send_firework_message(room_name, "fire") - await asyncio.sleep(5) - await client.send_confetti_message(room_name, "confetti") - await asyncio.sleep(5) - await client.send_snow_message(room_name, "snow") - await asyncio.sleep(5) - await client.send_space_invader_message(room_name, "space") await client.run()