surrender to the async devil and use blackmagic to initialize asyncronously an object
This commit is contained in:
parent
ee81cf93af
commit
e368d661ac
3 changed files with 62 additions and 9 deletions
17
src/matrix_bot/async_utils.py
Normal file
17
src/matrix_bot/async_utils.py
Normal 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
|
|
@ -10,13 +10,14 @@ from typing import (
|
||||||
NoReturn,
|
NoReturn,
|
||||||
Union
|
Union
|
||||||
)
|
)
|
||||||
|
from .async_utils import Aobject
|
||||||
from .utils import (
|
from .utils import (
|
||||||
Room,
|
Room,
|
||||||
RoomAlias,
|
RoomAlias,
|
||||||
RoomId
|
RoomId
|
||||||
)
|
)
|
||||||
|
|
||||||
class Client:
|
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.
|
||||||
|
@ -24,6 +25,8 @@ class Client:
|
||||||
allowed_rooms: dict of the rooms where the bot is allowed to connect, indexed
|
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
|
by id (the name starting with '!'). If set to None, the bot connect to
|
||||||
all room where it is invited.
|
all room where it is invited.
|
||||||
|
|
||||||
|
/!\ The client is initialized asyncronously: `client = await Client(...)`
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__client: nio.AsyncClient
|
__client: nio.AsyncClient
|
||||||
|
@ -31,7 +34,7 @@ class Client:
|
||||||
__rooms_by_id: dict[RoomId, Room]
|
__rooms_by_id: dict[RoomId, Room]
|
||||||
allowed_rooms: Optional[dict[RoomId, Room]]
|
allowed_rooms: Optional[dict[RoomId, Room]]
|
||||||
|
|
||||||
def __init__(
|
async def __init__(
|
||||||
self,
|
self,
|
||||||
username: str,
|
username: str,
|
||||||
homeserver: str,
|
homeserver: str,
|
||||||
|
@ -47,23 +50,22 @@ class Client:
|
||||||
(given by room id (expl: '!xxx:matrix.org') of room alias (expl:
|
(given by room id (expl: '!xxx:matrix.org') of room alias (expl:
|
||||||
'#xxx:matrix.org'))
|
'#xxx:matrix.org'))
|
||||||
"""
|
"""
|
||||||
loop = asyncio.get_event_loop()
|
|
||||||
self.__client = nio.AsyncClient(
|
self.__client = nio.AsyncClient(
|
||||||
homeserver,
|
homeserver,
|
||||||
username
|
username
|
||||||
)
|
)
|
||||||
self.__rooms_by_aliases = {}
|
self.__rooms_by_aliases = {}
|
||||||
self.__rooms_by_id = {}
|
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):
|
if isinstance(resp, nio.responses.LoginError):
|
||||||
raise RuntimeError(f"Fail to connect: {resp.message}")
|
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
|
self.allowed_rooms = None
|
||||||
if allowed_rooms_names:
|
if allowed_rooms_names:
|
||||||
self.allowed_rooms = {}
|
self.allowed_rooms = {}
|
||||||
for room_name in allowed_rooms_names:
|
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
|
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
|
self.__rooms_by_aliases[room_name] = room
|
||||||
return 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)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -2,18 +2,25 @@
|
||||||
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 testt without a whole matrix server.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import asyncio
|
||||||
import os
|
import os
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
from matrix_bot.client import Client
|
from matrix_bot.client import Client
|
||||||
from getpass import getpass
|
from getpass import getpass
|
||||||
|
|
||||||
if __name__ == "__main__":
|
async def main():
|
||||||
load_dotenv()
|
load_dotenv()
|
||||||
client = Client(
|
client = await Client(
|
||||||
os.environ["MUSER"],
|
os.environ["MUSER"],
|
||||||
os.environ["HOMESERVER"],
|
os.environ["HOMESERVER"],
|
||||||
os.environ["PASSWD"],
|
os.environ["PASSWD"],
|
||||||
os.environ["ROOMS"].split(",")
|
os.environ["ROOMS"].split(",")
|
||||||
)
|
)
|
||||||
print(client.allowed_rooms)
|
# print(client.allowed_rooms)
|
||||||
|
await client.run()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
asyncio.run(main())
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue