surrender to the async devil and use blackmagic to initialize asyncronously an object

This commit is contained in:
histausse 2021-10-03 16:36:36 +02:00
parent ee81cf93af
commit e368d661ac
Signed by: histausse
GPG key ID: 67486F107F62E9E9
3 changed files with 62 additions and 9 deletions

View file

@ -0,0 +1,17 @@
"""
Some utilities to help with async stuff.
"""
class Aobject(object):
"""
Inheriting this class allows you to define an async __init__.
So you can create objects by doing something like `await MyClass(params)`
Copied from https://newbedev.com/how-to-set-class-attribute-with-await-in-init
"""
async def __new__(cls, *a, **kw):
instance = super().__new__(cls)
await instance.__init__(*a, **kw)
return instance
async def __init__(self):
pass

View file

@ -10,13 +10,14 @@ from typing import (
NoReturn,
Union
)
from .async_utils import Aobject
from .utils import (
Room,
RoomAlias,
RoomId
)
class Client:
class Client(Aobject):
"""
Connect to the matrix server and handle interactions with the
server.
@ -24,6 +25,8 @@ class Client:
allowed_rooms: dict of the rooms where the bot is allowed to connect, indexed
by id (the name starting with '!'). If set to None, the bot connect to
all room where it is invited.
/!\ The client is initialized asyncronously: `client = await Client(...)`
"""
__client: nio.AsyncClient
@ -31,7 +34,7 @@ class Client:
__rooms_by_id: dict[RoomId, Room]
allowed_rooms: Optional[dict[RoomId, Room]]
def __init__(
async def __init__(
self,
username: str,
homeserver: str,
@ -47,23 +50,22 @@ class Client:
(given by room id (expl: '!xxx:matrix.org') of room alias (expl:
'#xxx:matrix.org'))
"""
loop = asyncio.get_event_loop()
self.__client = nio.AsyncClient(
homeserver,
username
)
self.__rooms_by_aliases = {}
self.__rooms_by_id = {}
resp = loop.run_until_complete(self.__client.login(password))
resp = await self.__client.login(password)
if isinstance(resp, nio.responses.LoginError):
raise RuntimeError(f"Fail to connect: {resp.message}")
# Where is the async map when you need it?
# TODO: Where is the async map when you need it?
self.allowed_rooms = None
if allowed_rooms_names:
self.allowed_rooms = {}
for room_name in allowed_rooms_names:
room = loop.run_until_complete(self.resolve_room(room_name))
room = await self.resolve_room(room_name)
self.allowed_rooms[room.id] = room # room uniqueness is handled by self.resolve_room
@ -107,3 +109,30 @@ class Client:
self.__rooms_by_aliases[room_name] = room
return room
async def sync(
self,
sync_delta:int=30
)->NoReturn:
"""
Sync with the server every sync_delta seconds.
sync_delta: the time in sec between each sync.
"""
while True:
sync_resp = await self.__client.sync(sync_delta*1000)
if isinstance(sync_resp, nio.responses.SyncError):
print(f"Error while syncronizing: {sync_resp.message}") # TODO: use proper logging
continue
print(sync_resp)
async def run(
self,
sync_delta:int=30
)->NoReturn:
"""
Run the bot: sync with the server and execute callbacks.
"""
await asyncio.gather(
self.sync(sync_delta=sync_delta)
)

View file

@ -2,18 +2,25 @@
Not really tests, because I don't know how to testt without a whole matrix server.
"""
import asyncio
import os
from dotenv import load_dotenv
from matrix_bot.client import Client
from getpass import getpass
if __name__ == "__main__":
async def main():
load_dotenv()
client = Client(
client = await Client(
os.environ["MUSER"],
os.environ["HOMESERVER"],
os.environ["PASSWD"],
os.environ["ROOMS"].split(",")
)
print(client.allowed_rooms)
# print(client.allowed_rooms)
await client.run()
if __name__ == "__main__":
asyncio.run(main())