From 87998001f505441e93f2d8799d31ca8fdc443a98 Mon Sep 17 00:00:00 2001 From: Ville Ranki Date: Sun, 29 Mar 2020 23:50:33 +0300 Subject: [PATCH] Added mxma module --- README.md | 32 ++++++++++++++++++++++++++++++++ bot.py | 38 +++++++++++++++++++++++++++++++++++++- modules/mxma.py | 27 +++++++++++++++++++++++++++ 3 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 modules/mxma.py diff --git a/README.md b/README.md index 8d5fd4c..4c28752 100644 --- a/README.md +++ b/README.md @@ -268,6 +268,38 @@ Commands: * !wa [query] - Query wolfram alpha * !wa appid [appid] - Set appid (must be done as bot owner) +### Matrix Messaging API + +This is a simple API to ask bot to send messages in Matrix using JSON file from external service. + +You'll need an API endpoint (webserver) that contains a message queue. It must respond with following JSON to a HTTP GET request: + +```json +{ + "messages":[ + { + "to": "@example:matrix.org", + "title": "Room Title", + "message": "Hello from Hemppa" + }, + { + "to": "@another:matrix.user", + "title": "Room 2 Title", + "message": "Second message" + } + ] +} +``` + +Normally you want to clear the messages when the endpoint is GETted or the messages will repeat +every time bot updates itself. + +These messages are sent to given Matrix users in private message with given room title. +Messages are sent "best effort" - if sending fails, it will be logged to bot output log. + +Then just: +* !mxma add http://url.to.the/endpoint.json + ## Bot setup * Create a Matrix user diff --git a/bot.py b/bot.py index d2f1f2d..aca8b1f 100755 --- a/bot.py +++ b/bot.py @@ -19,7 +19,7 @@ import datetime from importlib import reload import requests -from nio import AsyncClient, InviteEvent, JoinError, RoomMessageText, MatrixRoom, LoginError +from nio import AsyncClient, InviteEvent, JoinError, RoomMessageText, MatrixRoom, LoginError, RoomMemberEvent, RoomVisibility, RoomPreset, RoomCreateError # Couple of custom exceptions @@ -106,6 +106,35 @@ class Bot: } await self.client.room_send(room.room_id, 'm.room.message', msg) + async def send_msg(self, mxid, roomname, message): + # Sends private message to user. Returns true on success. + + # Find if we already have a common room with user: + msg_room = None + for croomid in self.client.rooms: + roomobj = self.client.rooms[croomid] + if len(roomobj.users) == 2: + for user in roomobj.users: + if user == mxid: + msg_room = roomobj + + # Nope, let's create one + if not msg_room: + msg_room = await self.client.room_create(visibility=RoomVisibility.private, + name=roomname, + is_direct=True, + preset=RoomPreset.private_chat, + invite={mxid}, + ) + + if not msg_room or (type(msg_room) is RoomCreateError): + self.logger.error(f'Unable to create room when trying to message {mxid}') + return False + + # Send message to the room + await self.send_text(msg_room, message) + return True + def remove_callback(self, callback): for cb_object in self.client.event_callbacks: if cb_object.func == callback: @@ -233,6 +262,12 @@ class Bot: else: self.logger.warning(f'Received invite event, but not joining as sender is not owner or bot not configured to join on invite. {event}') + async def memberevent_cb(self, room, event): + # Automatically leaves rooms where bot is alone. + if room.member_count == 1 and event.membership=='leave': + self.logger.info(f"membership event in {room.display_name} ({room.room_id}) with {room.member_count} members by '{event.sender}' - leaving room as i don't want to be left alone!") + await self.client.room_leave(room.room_id) + def load_module(self, modulename): try: self.logger.info(f'load module: {modulename}') @@ -361,6 +396,7 @@ class Bot: self.load_settings(self.get_account_data()) self.client.add_event_callback(self.message_cb, RoomMessageText) self.client.add_event_callback(self.invite_cb, (InviteEvent,)) + self.client.add_event_callback(self.memberevent_cb, (RoomMemberEvent,)) if self.join_on_invite: self.logger.info('Note: Bot will join rooms if invited') diff --git a/modules/mxma.py b/modules/mxma.py new file mode 100644 index 0000000..85475eb --- /dev/null +++ b/modules/mxma.py @@ -0,0 +1,27 @@ +from modules.common.module import BotModule +import requests, json +import traceback + +from modules.common.pollingservice import PollingService + +class MatrixModule(PollingService): + def __init__(self, name): + super().__init__(name) + self.service_name = 'MXMA' + self.poll_interval_min = 5 + self.poll_interval_random = 2 + + async def poll_implementation(self, bot, account, roomid, send_messages): + try: + response = requests.get(url=account, timeout=5) + if response.status_code == 200: + if 'messages' in response.json(): + messages = response.json()['messages'] + for message in messages: + success = await bot.send_msg(message['to'], message['title'], message['message']) + except Exception: + self.logger.error('Polling MXMA failed:') + traceback.print_exc(file=sys.stderr) + + def help(self): + return 'Matrix messaging API'