Last active
March 19, 2025 11:44
-
-
Save defnull/8231ec8633781f621c59e8945256f028 to your computer and use it in GitHub Desktop.
Admin tool to send chat messags to running BBB meetings
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 | |
import sys, json, subprocess, time, argparse | |
""" | |
Admin tool to send chat messages to running BBB meetings by directly injecting events into the REDIS channel. | |
This can be used for example to broadcast a maintenance warning message before shuttinng down a server. | |
Tested with BBB 2.5 | |
Copyright 2022 Marcel Hellkamp | |
License: MIT | |
""" | |
def main(): | |
parser = argparse.ArgumentParser(description='Send system messages to public chats of existing meetings.') | |
parser.add_argument('--user', default="SYSTEM", help='User name (default: SYSTEM)') | |
parser.add_argument('--meeting', default="ALL", help='Meeting ID (default: all meetings)') | |
parser.add_argument('text', help='Message to send') | |
args = parser.parse_args() | |
if args.meeting == 'ALL': | |
meetings = find_all_meetings() | |
else: | |
meetings = [args.meeting] | |
for meeting in meetings: | |
send_chat(meeting, args.text, args.user) | |
def get_secret(): | |
with open('/etc/bigbluebutton/bbb-web.properties', 'r') as fp: | |
for line in fp: | |
if line.startswith('securitySalt'): | |
return line.partition("=")[2].strip() | |
def find_all_meetings(): | |
import xml.etree.ElementTree as ET | |
import urllib.request | |
import urllib.parse | |
import hashlib | |
secret = get_secret() | |
command = "getMeetings" | |
checksum = hashlib.sha1((command+secret).encode('utf8')).hexdigest() | |
url = f"http://localhost:8090/bigbluebutton/api/{command}?checksum={checksum}" | |
with urllib.request.urlopen(url) as f: | |
xml = f.read().decode('utf8') | |
root = ET.fromstring(xml) | |
for meeting in root.findall('./meetings/meeting/internalMeetingID'): | |
yield meeting.text | |
def send_chat(meeting, text, user): | |
print(meeting) | |
ts = int(time.time() * 1000) | |
event = { | |
"envelope": { | |
"name":"GroupChatMessageBroadcastEvtMsg", | |
"routing": { | |
"msgType": "BROADCAST_TO_MEETING", | |
"meetingId": meeting, | |
"userId": "SYSTEM" | |
}, | |
"timestamp": ts | |
}, | |
"core":{ | |
"header":{ | |
"name": "GroupChatMessageBroadcastEvtMsg", | |
"meetingId": meeting, | |
"userId": "SYSTEM" | |
}, | |
"body":{ | |
"chatId": "MAIN-PUBLIC-GROUP-CHAT", | |
"msg":{ | |
"id": f"{ts}-fake", | |
"timestamp": ts, | |
"correlationId":"SYSTEM", | |
"sender":{ | |
"id": "SYSTEM", | |
"name": user, | |
"role": "MODERATOR" | |
}, | |
"chatEmphasizedText": True, | |
"message": text | |
} | |
} | |
} | |
} | |
subprocess.run(["redis-cli", "PUBLISH", "from-akka-apps-redis-channel", json.dumps(event)], stdout=subprocess.DEVNULL) | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment