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 login https://my.instance/ me@email.invalid r00tm3
|
||||||
* !md roomlogin #myroom:matrix.org 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
|
## Bot setup
|
||||||
|
|
||||||
* Create a Matrix user
|
* Create a Matrix user
|
||||||
|
|
7
bot.py
7
bot.py
|
@ -142,7 +142,10 @@ class Bot:
|
||||||
self.client.event_callbacks.remove(cb_object)
|
self.client.event_callbacks.remove(cb_object)
|
||||||
|
|
||||||
def get_room_by_id(self, room_id):
|
def get_room_by_id(self, room_id):
|
||||||
|
try:
|
||||||
return self.client.rooms[room_id]
|
return self.client.rooms[room_id]
|
||||||
|
except KeyError:
|
||||||
|
return None
|
||||||
|
|
||||||
async def get_room_by_alias(self, alias):
|
async def get_room_by_alias(self, alias):
|
||||||
rar = await self.client.room_resolve_alias(alias)
|
rar = await self.client.room_resolve_alias(alias)
|
||||||
|
@ -205,7 +208,7 @@ class Bot:
|
||||||
# Ignore if asked to ignore
|
# Ignore if asked to ignore
|
||||||
if self.should_ignore_event(event):
|
if self.should_ignore_event(event):
|
||||||
if self.debug:
|
if self.debug:
|
||||||
print('Ignoring event!')
|
self.logger.debug('Ignoring event!')
|
||||||
return
|
return
|
||||||
|
|
||||||
body = event.body
|
body = event.body
|
||||||
|
@ -450,4 +453,4 @@ async def main():
|
||||||
try:
|
try:
|
||||||
asyncio.run(main())
|
asyncio.run(main())
|
||||||
except Exception as e:
|
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
|
from functools import lru_cache
|
||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
|
import sys
|
||||||
|
import traceback
|
||||||
from bs4 import BeautifulSoup
|
from bs4 import BeautifulSoup
|
||||||
from nio import RoomMessageText
|
from nio import RoomMessageText
|
||||||
|
|
||||||
|
@ -90,6 +92,7 @@ class MatrixModule(BotModule):
|
||||||
title, description = self.get_content_from_url(url)
|
title, description = self.get_content_from_url(url)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.logger.warning(f"could not fetch url: {e}")
|
self.logger.warning(f"could not fetch url: {e}")
|
||||||
|
traceback.print_exc(file=sys.stderr)
|
||||||
# failed fetching, give up
|
# failed fetching, give up
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue