Last active
January 2, 2022 11:34
-
-
Save krisek/5683335b2ed81d62f0dd63c17094da18 to your computer and use it in GitHub Desktop.
Matrix webhook
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
""" | |
Matrix Webhook. | |
Post a message to a matrix room with a simple HTTP POST | |
""" | |
import asyncio | |
import json | |
import os | |
from http import HTTPStatus | |
from signal import SIGINT, SIGTERM | |
from aiohttp import web | |
from markdown import markdown | |
from nio import AsyncClient,AsyncClientConfig | |
from nio.exceptions import LocalProtocolError | |
SERVER_ADDRESS = ('', int(os.environ.get('PORT', 4785))) | |
MATRIX_URL = os.environ.get('MATRIX_URL', 'https://matrix.org') | |
MATRIX_ID = os.environ.get('MATRIX_ID', '@wwm:matrix.org') | |
MATRIX_PW = os.environ['MATRIX_PW'] | |
API_KEY = os.environ['API_KEY'] | |
DEVICE_ID = os.environ['DEVICE_ID'] | |
STORE_PATH = os.environ['STORE_PATH'] | |
client_config = AsyncClientConfig(encryption_enabled=True) | |
CLIENT = AsyncClient(MATRIX_URL, MATRIX_ID, config=client_config, store_path=STORE_PATH, device_id=DEVICE_ID) | |
async def handler(request): | |
""" | |
Coroutine given to the server, st. it knows what to do with an HTTP request. | |
This one handles a POST, checks its content, and forwards it to the matrix room. | |
""" | |
data = await request.read() | |
try: | |
data = json.loads(data.decode()) | |
except json.decoder.JSONDecodeError: | |
return create_json_response(HTTPStatus.BAD_REQUEST, 'Invalid JSON') | |
if not all(key in data for key in ['text', 'key']): | |
return create_json_response(HTTPStatus.BAD_REQUEST, | |
'Missing text and/or API key property') | |
if data['key'] != API_KEY: | |
return create_json_response(HTTPStatus.UNAUTHORIZED, 'Invalid API key') | |
room_id = data.get('room_id', str(request.rel_url)[1:]) | |
#room_id = str(request.rel_url)[1:] | |
content = { | |
'msgtype': 'm.text', | |
'body': data['text'], | |
'format': 'org.matrix.custom.html', | |
'formatted_body': markdown(data['text'], extensions=['extra']), | |
} | |
try: | |
# await send_room_message(room_id, content) | |
await CLIENT.room_send(room_id=room_id, message_type='m.room.message', content=content) | |
except LocalProtocolError: # Connection lost, try another login | |
await CLIENT.login(MATRIX_PW, device_name='matrix-webhook') | |
# await send_room_message(room_id, content) | |
await CLIENT.room_send(room_id=room_id, message_type='m.room.message', content=content) | |
return create_json_response(HTTPStatus.OK, 'OK') | |
def create_json_response(status, ret): | |
"""Create a JSON response.""" | |
response_data = {'status': status, 'ret': ret} | |
return web.json_response(response_data, status=status) | |
async def send_room_message(room_id, content): | |
"""Send a message to a room.""" | |
return await CLIENT.room_send(room_id=room_id, message_type='m.room.message', content=content) | |
async def main(event): | |
""" | |
Launch main coroutine. | |
matrix client login & start web server | |
""" | |
await CLIENT.login(MATRIX_PW, device_name='matrix-commander') | |
server = web.Server(handler) | |
runner = web.ServerRunner(server) | |
await runner.setup() | |
site = web.TCPSite(runner, *SERVER_ADDRESS) | |
await site.start() | |
sync_forever_task = asyncio.create_task(CLIENT.sync_forever(30000, full_state=True)) | |
# Run until we get a shutdown request | |
await event.wait() | |
# Cleanup | |
await runner.cleanup() | |
await CLIENT.close() | |
def terminate(event, signal): | |
"""Close handling stuff.""" | |
event.set() | |
asyncio.get_event_loop().remove_signal_handler(signal) | |
def run(): | |
"""Launch everything.""" | |
loop = asyncio.get_event_loop() | |
event = asyncio.Event() | |
for sig in (SIGINT, SIGTERM): | |
loop.add_signal_handler(sig, terminate, event, sig) | |
loop.run_until_complete(main(event)) | |
loop.close() | |
if __name__ == '__main__': | |
run() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment