From b0f96911c30d6f3a38ce1be93d14a1c10f69b702 Mon Sep 17 00:00:00 2001 From: gammafn Date: Mon, 2 Aug 2021 14:33:50 -0500 Subject: [PATCH] Add !mumble --- README.md | 10 +++++ modules/mumble.py | 96 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 106 insertions(+) create mode 100644 modules/mumble.py diff --git a/README.md b/README.md index 7ad3e62..c373785 100644 --- a/README.md +++ b/README.md @@ -628,6 +628,16 @@ Currently only Finnish RASP supported. Uses data from http://ennuste.ilmailuliit Day and hour can be omitted - fetches today's forecast if not set. PR welcome for supporting other data sources. +### Mumble + +Show information about a configured mumble server, +including version, how many users are connected, and ping time. + +#### Usage + +* !mumble - Show info about the configured mumble server +- !mumble (set|setserver) [host] ([port]) - Set the configured mumble server + ## Bot setup * Create a Matrix user diff --git a/modules/mumble.py b/modules/mumble.py new file mode 100644 index 0000000..cd54051 --- /dev/null +++ b/modules/mumble.py @@ -0,0 +1,96 @@ +from modules.common.module import BotModule +import random +import socket +from struct import pack, unpack +import time + +# Modified from https://gist.github.com/azlux/315c924af4800ffbc2c91db3ab8a59bc + +class MatrixModule(BotModule): + def __init__(self, name): + super().__init__(name) + self.host = None + self.port = 64738 + + def set_settings(self, data): + super().set_settings(data) + if data.get('host'): + self.host = data['host'] + if data.get('port'): + self.port = data['port'] + + def get_settings(self): + data = super().get_settings() + data['host'] = self.host + data['port'] = self.port + return data + + async def matrix_message(self, bot, room, event): + args = event.body.split() + + if len(args) > 1 and args[1] in ['set', 'setserver']: + bot.must_be_owner(event) + self.logger.info(f"room: {room.name} sender: {event.sender} is setting the server settings") + if len(args) < 3: + self.host = None + return await bot.send_text(room, f'Usage: !{args[0]} {args[1]} [host] ([port])') + self.host = args[2] + if len(args) > 3: + self.port = int(args[3]) + if not self.port: + self.port = 64738 + bot.save_settings() + return await bot.send_text(room, f'Set server settings: host: {self.host} port: {self.port}') + + self.logger.info(f"room: {room.name} sender: {event.sender} wants mumble info") + if not self.host: + return await bot.send_text(room, f'No mumble host info set!') + + try: + ret = self.mumble_ping() + # https://wiki.mumble.info/wiki/Protocol + # [0,1,2,3] = version + version = '.'.join(map(str, ret[1:4])) + # [4] = identifier passed to the server (used here to get ping time) + ping = int(time.time() * 1000) - ret[4] + # [7] = bandwidth + # [5] = users + # [6] = max users + await bot.send_text(room, f'{self.host}:{self.port} (v{version}): {ret[5]} / {ret[6]} (ping: {ping}ms)') + except socket.gaierror as e: + self.logger.error(f"room: {room.name}: mumble_ping failed: {e}") + await bot.send_text(room, f'Could not get get mumble server info: {e}') + + def mumble_ping(self): + addrinfo = socket.getaddrinfo(self.host, self.port, 0, 0, socket.SOL_UDP) + + for (family, socktype, proto, canonname, sockaddr) in addrinfo: + s = socket.socket(family, socktype, proto=proto) + s.settimeout(2) + + buf = pack(">iQ", 0, int(time.time() * 1000)) + try: + s.sendto(buf, sockaddr) + except (socket.gaierror, socket.timeout) as e: + continue + + try: + data, addr = s.recvfrom(1024) + except socket.timeout: + continue + + return unpack(">bbbbQiii", data) + + def help(self): + return 'Show info about a mumble server' + + def long_help(self): + text = self.help() + ( + '\n- "!mumble": Get the status of the configured mumble server') + + if bot and event and bot.is_owner(event): + text += ( + '\nOwner commands:' + '\n- "!mumble set [host] ([port])": Set use the following host and port' + '\n- If no port is given, defaults to 64738') + return text