Added relay module for relaybot functionality
This commit is contained in:
parent
ea8fd74a85
commit
39c1b98f88
20
README.md
20
README.md
|
@ -411,6 +411,26 @@ Example commands:
|
|||
* !md login https://my.instance/ me@email.invalid r00tm3
|
||||
* !md roomlogin #myroom:matrix.org https://my.instance/ me@email.invalid r00tm3
|
||||
|
||||
### Relay bridge
|
||||
|
||||
Bridges two or more Matrix rooms together via relaybot.
|
||||
|
||||
Note: Room ID is not same as room alias! Rooms can exist without aliases so ID's are more flexible. Room id is usually in format !123LotOfRandomChars:server.org
|
||||
|
||||
To get room ID, it's in Element Web room settings | Advanced | Internal room ID
|
||||
|
||||
Before bridging the bot must be present on both rooms.
|
||||
|
||||
Commands:
|
||||
|
||||
* !relay bridge [roomid] - Bridge room with given ID to this room (must be done as bot owner)
|
||||
* !relay list - List bridged rooms (and their index numbers) (must be done as bot owner)
|
||||
* !relay unbridge [number] - Remove the given bridge number (must be done as bot owner)
|
||||
|
||||
File uploads, joins, leaves or other special events are not (yet) handled. Contributions welcome.
|
||||
|
||||
Relaybots are stupid. Please prefer real Matrix bridges to this. Sometimes there's no alternative.
|
||||
|
||||
## Bot setup
|
||||
|
||||
* Create a Matrix user
|
||||
|
|
7
bot.py
7
bot.py
|
@ -142,7 +142,10 @@ class Bot:
|
|||
self.client.event_callbacks.remove(cb_object)
|
||||
|
||||
def get_room_by_id(self, room_id):
|
||||
try:
|
||||
return self.client.rooms[room_id]
|
||||
except KeyError:
|
||||
return None
|
||||
|
||||
async def get_room_by_alias(self, alias):
|
||||
rar = await self.client.room_resolve_alias(alias)
|
||||
|
@ -205,7 +208,7 @@ class Bot:
|
|||
# Ignore if asked to ignore
|
||||
if self.should_ignore_event(event):
|
||||
if self.debug:
|
||||
print('Ignoring event!')
|
||||
self.logger.debug('Ignoring event!')
|
||||
return
|
||||
|
||||
body = event.body
|
||||
|
@ -450,4 +453,4 @@ async def main():
|
|||
try:
|
||||
asyncio.run(main())
|
||||
except Exception as e:
|
||||
print(e)
|
||||
traceback.print_exc(file=sys.stderr)
|
||||
|
|
|
@ -0,0 +1,108 @@
|
|||
from modules.common.module import BotModule
|
||||
from nio import RoomMessageText
|
||||
|
||||
class MatrixModule(BotModule):
|
||||
def __init__(self, name):
|
||||
super().__init__(name)
|
||||
self.bridges = dict()
|
||||
self.bot = None
|
||||
|
||||
async def message_cb(self, room, event):
|
||||
if self.bot.should_ignore_event(event):
|
||||
return
|
||||
|
||||
if event.body.startswith('!'):
|
||||
return
|
||||
|
||||
source_id = None
|
||||
target_id = None
|
||||
|
||||
for src_id, tgt_id in self.bridges.items():
|
||||
if room.room_id == src_id:
|
||||
source_id = src_id
|
||||
target_id = tgt_id
|
||||
elif room.room_id == tgt_id:
|
||||
source_id = tgt_id
|
||||
target_id = src_id
|
||||
|
||||
if not source_id or not target_id:
|
||||
return
|
||||
|
||||
target_room = self.bot.get_room_by_id(target_id)
|
||||
if(target_room):
|
||||
sendernick = target_room.user_name(event.sender)
|
||||
if not sendernick:
|
||||
sendernick = event.sender
|
||||
await self.bot.send_text(target_room, f'<{sendernick}> {event.body}', msgtype="m.text", bot_ignore=True)
|
||||
else:
|
||||
self.logger.warning(f"Bot doesn't seem to be in bridged room {target_id}")
|
||||
|
||||
def matrix_start(self, bot):
|
||||
super().matrix_start(bot)
|
||||
bot.client.add_event_callback(self.message_cb, RoomMessageText)
|
||||
self.bot = bot
|
||||
|
||||
def matrix_stop(self, bot):
|
||||
super().matrix_stop(bot)
|
||||
bot.remove_callback(self.message_cb)
|
||||
self.bot = None
|
||||
|
||||
async def matrix_message(self, bot, room, event):
|
||||
bot.must_be_admin(room, event)
|
||||
args = event.body.split()
|
||||
args.pop(0)
|
||||
if len(args) == 1:
|
||||
if args[0] == 'list':
|
||||
i = 1
|
||||
msg = f"Active relay bridges ({len(self.bridges)}):\n"
|
||||
for src_id, tgt_id in self.bridges.items():
|
||||
srcroom = self.bot.get_room_by_id(src_id)
|
||||
tgtroom = self.bot.get_room_by_id(tgt_id)
|
||||
|
||||
if srcroom:
|
||||
srcroom = srcroom.display_name
|
||||
else:
|
||||
srcroom = f'??? {src_id}'
|
||||
|
||||
if tgtroom:
|
||||
tgtroom = tgtroom.display_name
|
||||
else:
|
||||
tgtroom = f'??? {tgt_id}'
|
||||
|
||||
msg += f'{i}: {srcroom} <-> {tgtroom}'
|
||||
i = i + 1
|
||||
await bot.send_text(room, msg)
|
||||
|
||||
if len(args) == 2:
|
||||
if args[0] == 'bridge':
|
||||
roomid = args[1]
|
||||
room_to_bridge = bot.get_room_by_id(roomid)
|
||||
if room_to_bridge:
|
||||
await bot.send_text(room, f'Bridging {room_to_bridge.display_name} here.')
|
||||
self.bridges[room.room_id] = roomid
|
||||
bot.save_settings()
|
||||
else:
|
||||
await bot.send_text(room, f'I am not on room with id {roomid} (note: use id, not alias)!')
|
||||
elif args[0] == 'unbridge':
|
||||
idx = int(args[1]) - 1
|
||||
i = 0
|
||||
for src_id, tgt_id in self.bridges.items():
|
||||
if i == idx:
|
||||
del self.bridges[src_id]
|
||||
await bot.send_text(room, f'Unbridged {src_id} and {tgt_id}.')
|
||||
bot.save_settings()
|
||||
return
|
||||
i = i + 1
|
||||
|
||||
def help(self):
|
||||
return 'Simple relaybot between two Matrix rooms'
|
||||
|
||||
def get_settings(self):
|
||||
data = super().get_settings()
|
||||
data["bridges"] = self.bridges
|
||||
return data
|
||||
|
||||
def set_settings(self, data):
|
||||
super().set_settings(data)
|
||||
if data.get("bridges"):
|
||||
self.bridges = data["bridges"]
|
|
@ -3,6 +3,8 @@ import shlex
|
|||
from functools import lru_cache
|
||||
|
||||
import httpx
|
||||
import sys
|
||||
import traceback
|
||||
from bs4 import BeautifulSoup
|
||||
from nio import RoomMessageText
|
||||
|
||||
|
@ -90,6 +92,7 @@ class MatrixModule(BotModule):
|
|||
title, description = self.get_content_from_url(url)
|
||||
except Exception as e:
|
||||
self.logger.warning(f"could not fetch url: {e}")
|
||||
traceback.print_exc(file=sys.stderr)
|
||||
# failed fetching, give up
|
||||
continue
|
||||
|
||||
|
|
Loading…
Reference in New Issue