feat: initial async appservice rewrite
This commit is contained in:
parent
266a0d558b
commit
b6c92790d6
2 changed files with 134 additions and 17 deletions
99
src/aioappsrv/app.py
Normal file
99
src/aioappsrv/app.py
Normal file
|
@ -0,0 +1,99 @@
|
|||
import asyncio
|
||||
import logging
|
||||
|
||||
from typing import Callable, Awaitable
|
||||
|
||||
from aiohttp import ClientSession, web
|
||||
|
||||
from .matrix import Event, EventType
|
||||
|
||||
class AppService:
|
||||
_rx: web.Application
|
||||
_tx: ClientSession
|
||||
_callbacks: dict[EventType, dict[str, Callable]]
|
||||
|
||||
as_token: str
|
||||
hs_token: str
|
||||
base_url: str
|
||||
user_id: str
|
||||
server_name: str
|
||||
|
||||
logger: logging.Logger
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
as_token: str,
|
||||
hs_token: str,
|
||||
base_url: str,
|
||||
user_id: str,
|
||||
server_name: str,
|
||||
logger: logging.Logger | None = None,
|
||||
):
|
||||
self._rx = web.Application()
|
||||
|
||||
self.as_token = as_token
|
||||
self.hs_token = hs_token
|
||||
self.base_url = base_url
|
||||
self.user_id = user_id
|
||||
self.server_name = server_name
|
||||
|
||||
self.logger = logger if logger is not None else logging.getLogger(__file__)
|
||||
|
||||
self._rx.add_routes([
|
||||
web.put('/transactions/{transaction}', lambda req: self.handler(req))
|
||||
])
|
||||
|
||||
async def handler(self, request: web.Request) -> web.Response:
|
||||
self.logger.debug("handling webhook callback %s", request)
|
||||
hs_token = request.query.getone("access_token")
|
||||
if not hs_token:
|
||||
return web.Response(status=401)
|
||||
if hs_token != self.hs_token:
|
||||
return web.Response(status=403)
|
||||
body = await request.json()
|
||||
for doc in body["events"]:
|
||||
event = Event(**doc)
|
||||
if event.type not in EventType:
|
||||
self.logger.warn("unhandled event of type %s, ignoring", event["type"])
|
||||
continue
|
||||
self.logger.debug("dispatching event %s for %s", event.type)
|
||||
asyncio.get_event_loop().create_task(
|
||||
self._callbacks[event.type][event.room_id](event)
|
||||
)
|
||||
|
||||
return web.Response()
|
||||
|
||||
def callback(self, room: str, event: EventType | str = EventType.MESSAGE) -> Callable:
|
||||
def wrapper(func: Callable[[Event], Awaitable[None]]):
|
||||
if isinstance(event, str):
|
||||
key = EventType[event]
|
||||
else:
|
||||
key = event
|
||||
self._callbacks[key][room] = func
|
||||
return func
|
||||
return wrapper
|
||||
|
||||
async def join_room(self):
|
||||
pass
|
||||
|
||||
async def leave_room(self):
|
||||
pass
|
||||
|
||||
async def send_message(self):
|
||||
pass
|
||||
|
||||
async def redact_message(self):
|
||||
pass
|
||||
|
||||
async def start(self, host: str = "localhost", port: int = 25511):
|
||||
runner = web.AppRunner(self._rx)
|
||||
await runner.setup()
|
||||
site = web.TCPSite(runner, host, port)
|
||||
await site.start()
|
||||
|
||||
|
||||
|
||||
# utility function in case we need to block forever
|
||||
async def idle():
|
||||
while True:
|
||||
await asyncio.sleep(3600)
|
|
@ -1,28 +1,46 @@
|
|||
from typing import Any
|
||||
from enum import Enum
|
||||
from dataclasses import dataclass
|
||||
|
||||
|
||||
@dataclass
|
||||
class User:
|
||||
avatar_url: str = ""
|
||||
display_name: str = ""
|
||||
|
||||
class EventType(Enum):
|
||||
MESSAGE = "m.room.message"
|
||||
MEMBER = "m.room.member"
|
||||
REDACTION = "m.room.redaction"
|
||||
|
||||
@dataclass
|
||||
class Event:
|
||||
def __init__(self, event: dict):
|
||||
content = event.get("content", {})
|
||||
content: dict[str, Any]
|
||||
type: EventType
|
||||
event_id: str
|
||||
origin_server_ts: int
|
||||
room_id: str
|
||||
sender: str
|
||||
state_key: str | None = None
|
||||
redacts: str | None = None
|
||||
unsigned: dict | None = None
|
||||
|
||||
self.attachment = content.get("url")
|
||||
self.body = content.get("body", "").strip()
|
||||
self.formatted_body = content.get("formatted_body", "")
|
||||
self.id = event["event_id"]
|
||||
self.is_direct = content.get("is_direct", False)
|
||||
self.redacts = event.get("redacts", "")
|
||||
self.room_id = event["room_id"]
|
||||
self.sender = event["sender"]
|
||||
self.state_key = event.get("state_key", "")
|
||||
|
||||
rel = content.get("m.relates_to", {})
|
||||
|
||||
self.relates_to = rel.get("event_id")
|
||||
self.reltype = rel.get("rel_type")
|
||||
self.new_body = content.get("m.new_content", {}).get("body", "")
|
||||
# class Event:
|
||||
# def __init__(self, event: dict):
|
||||
# content = event.get("content", {})
|
||||
#
|
||||
# self.attachment = content.get("url")
|
||||
# self.body = content.get("body", "").strip()
|
||||
# self.formatted_body = content.get("formatted_body", "")
|
||||
# self.id = event["event_id"]
|
||||
# self.is_direct = content.get("is_direct", False)
|
||||
# self.redacts = event.get("redacts", "")
|
||||
# self.room_id = event["room_id"]
|
||||
# self.sender = event["sender"]
|
||||
# self.state_key = event.get("state_key", "")
|
||||
#
|
||||
# rel = content.get("m.relates_to", {})
|
||||
#
|
||||
# self.relates_to = rel.get("event_id")
|
||||
# self.reltype = rel.get("rel_type")
|
||||
# self.new_body = content.get("m.new_content", {}).get("body", "")
|
||||
|
|
Loading…
Reference in a new issue