add a wrapper for message callbacks

This commit is contained in:
histausse 2021-10-05 19:05:21 +02:00
parent 66cbd31f82
commit 139b9e138b
Signed by: histausse
GPG key ID: 67486F107F62E9E9
4 changed files with 52 additions and 10 deletions

View file

@ -3,3 +3,9 @@
A package implementing a reusable class to make matrix bots A package implementing a reusable class to make matrix bots
This is inventing the wheel once again, but who care? It's fun :) 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)

View file

@ -1,3 +1,4 @@
from __future__ import annotations
""" """
The Client class. The Client class.
Connect to the matrix server and handle interactions with the server. Connect to the matrix server and handle interactions with the server.
@ -9,6 +10,8 @@ import nio
from aiopath import AsyncPath from aiopath import AsyncPath
from typing import ( from typing import (
Any, Any,
Awaitable,
Callable,
Optional, Optional,
NoReturn, NoReturn,
Union Union
@ -32,6 +35,8 @@ class Client(Aobject):
Connect to the matrix server and handle interactions with the Connect to the matrix server and handle interactions with the
server. server.
user: the user id of the client (exp: @bot:matrix.org)
/!\ The client is initialized asyncronously: `client = await Client(...)` /!\ The client is initialized asyncronously: `client = await Client(...)`
""" """
@ -43,6 +48,7 @@ class Client(Aobject):
__sync_token_queue: asyncio.Queue[str] __sync_token_queue: asyncio.Queue[str]
__invite_queue: asyncio.Queue[tuple[RoomId, nio.responses.InviteInfo]] __invite_queue: asyncio.Queue[tuple[RoomId, nio.responses.InviteInfo]]
__invite_policy: InvitePolicy __invite_policy: InvitePolicy
user: str
async def __init__( async def __init__(
self, self,
@ -81,6 +87,7 @@ class Client(Aobject):
if isinstance(resp, nio.responses.LoginError): if isinstance(resp, nio.responses.LoginError):
raise RuntimeError(f"Fail to connect: {resp.message}") raise RuntimeError(f"Fail to connect: {resp.message}")
log.info("logged in") log.info("logged in")
self.user_id = self.__client.user_id
async def resolve_room( async def resolve_room(
self, self,
@ -283,6 +290,18 @@ class Client(Aobject):
for room_id in invites: for room_id in invites:
await self.__invite_queue.put((room_id, invites[room_id])) 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( async def run(
self, self,
sync_timeout:int=30 sync_timeout:int=30

View file

@ -1,11 +1,15 @@
from __future__ import annotations
""" """
Utilities for the bot. Utilities for the bot.
""" """
from typing import TYPE_CHECKING
from dataclasses import ( from dataclasses import (
dataclass, dataclass,
field field
) )
if TYPE_CHECKING:
from .client import Client
RoomAlias = str RoomAlias = str
RoomId = str RoomId = str
@ -17,3 +21,18 @@ class Room:
id: RoomId id: RoomId
aliases: set[RoomAlias] = field(default_factory=set) 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

View file

@ -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 import asyncio
@ -12,10 +12,15 @@ from matrix_bot.invite_policy import (
DeclineAll, DeclineAll,
WhiteList WhiteList
) )
from matrix_bot.utils import ignore_client_message
from getpass import getpass from getpass import getpass
logging.basicConfig(format="%(levelname)s: %(message)s", level=logging.DEBUG) 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(): async def main():
load_dotenv() load_dotenv()
client = await Client( client = await Client(
@ -23,25 +28,18 @@ async def main():
os.environ["HOMESERVER"], os.environ["HOMESERVER"],
os.environ["PASSWD"], os.environ["PASSWD"],
) )
client.add_message_callback(callback)
withelisted_room_names = os.environ["ROOMS"].split(",") withelisted_room_names = os.environ["ROOMS"].split(",")
whitelist_policy = await WhiteList(client, withelisted_room_names) whitelist_policy = await WhiteList(client, withelisted_room_names)
room_name = withelisted_room_names[0] room_name = withelisted_room_names[0]
client.set_invite_policy(whitelist_policy) client.set_invite_policy(whitelist_policy)
await client.send_message(room_name, "Beware of Greeks bearing gifts") await client.send_message(room_name, "Beware of Greeks bearing gifts")
await asyncio.sleep(5) await asyncio.sleep(1)
await client.send_formated_message( await client.send_formated_message(
room_name, room_name,
"<b><font color='red'>Beware of Greeks bearing gifts</font></b>", "<b><font color='red'>Beware of Greeks bearing gifts</font></b>",
"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() await client.run()