This commit is contained in:
114
server/config/bbb.js
Normal file
114
server/config/bbb.js
Normal file
@@ -0,0 +1,114 @@
|
||||
import crypto from 'crypto';
|
||||
import xml2js from 'xml2js';
|
||||
|
||||
const BBB_URL = process.env.BBB_URL || 'https://your-bbb-server.com/bigbluebutton/api/';
|
||||
const BBB_SECRET = process.env.BBB_SECRET || '';
|
||||
|
||||
function getChecksum(apiCall, params) {
|
||||
const queryString = new URLSearchParams(params).toString();
|
||||
const raw = apiCall + queryString + BBB_SECRET;
|
||||
return crypto.createHash('sha256').update(raw).digest('hex');
|
||||
}
|
||||
|
||||
function buildUrl(apiCall, params = {}) {
|
||||
const checksum = getChecksum(apiCall, params);
|
||||
const queryString = new URLSearchParams({ ...params, checksum }).toString();
|
||||
return `${BBB_URL}${apiCall}?${queryString}`;
|
||||
}
|
||||
|
||||
async function apiCall(apiCallName, params = {}) {
|
||||
const url = buildUrl(apiCallName, params);
|
||||
try {
|
||||
const response = await fetch(url);
|
||||
const xml = await response.text();
|
||||
const result = await xml2js.parseStringPromise(xml, {
|
||||
explicitArray: false,
|
||||
trim: true,
|
||||
});
|
||||
return result.response;
|
||||
} catch (error) {
|
||||
console.error(`BBB API error (${apiCallName}):`, error.message);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// Generate deterministic passwords from room UID
|
||||
function getRoomPasswords(uid) {
|
||||
const modPw = crypto.createHash('sha256').update(uid + '_mod_' + BBB_SECRET).digest('hex').substring(0, 16);
|
||||
const attPw = crypto.createHash('sha256').update(uid + '_att_' + BBB_SECRET).digest('hex').substring(0, 16);
|
||||
return { moderatorPW: modPw, attendeePW: attPw };
|
||||
}
|
||||
|
||||
export async function createMeeting(room) {
|
||||
const { moderatorPW, attendeePW } = getRoomPasswords(room.uid);
|
||||
const params = {
|
||||
meetingID: room.uid,
|
||||
name: room.name,
|
||||
attendeePW,
|
||||
moderatorPW,
|
||||
welcome: room.welcome_message || 'Willkommen!',
|
||||
record: room.record_meeting ? 'true' : 'false',
|
||||
autoStartRecording: 'false',
|
||||
allowStartStopRecording: 'true',
|
||||
muteOnStart: room.mute_on_join ? 'true' : 'false',
|
||||
'meta_bbb-origin': 'Redlight',
|
||||
'meta_bbb-origin-server-name': 'Redlight',
|
||||
};
|
||||
if (room.max_participants > 0) {
|
||||
params.maxParticipants = room.max_participants.toString();
|
||||
}
|
||||
if (room.access_code) {
|
||||
params.lockSettingsLockOnJoin = 'true';
|
||||
}
|
||||
return apiCall('create', params);
|
||||
}
|
||||
|
||||
export async function joinMeeting(uid, name, isModerator = false) {
|
||||
const { moderatorPW, attendeePW } = getRoomPasswords(uid);
|
||||
const params = {
|
||||
meetingID: uid,
|
||||
fullName: name,
|
||||
password: isModerator ? moderatorPW : attendeePW,
|
||||
redirect: 'true',
|
||||
};
|
||||
return buildUrl('join', params);
|
||||
}
|
||||
|
||||
export async function endMeeting(uid) {
|
||||
const { moderatorPW } = getRoomPasswords(uid);
|
||||
return apiCall('end', { meetingID: uid, password: moderatorPW });
|
||||
}
|
||||
|
||||
export async function getMeetingInfo(uid) {
|
||||
return apiCall('getMeetingInfo', { meetingID: uid });
|
||||
}
|
||||
|
||||
export async function isMeetingRunning(uid) {
|
||||
const result = await apiCall('isMeetingRunning', { meetingID: uid });
|
||||
return result.running === 'true';
|
||||
}
|
||||
|
||||
export async function getMeetings() {
|
||||
return apiCall('getMeetings', {});
|
||||
}
|
||||
|
||||
export async function getRecordings(meetingID) {
|
||||
const params = meetingID ? { meetingID } : {};
|
||||
const result = await apiCall('getRecordings', params);
|
||||
if (result.returncode !== 'SUCCESS' || !result.recordings) {
|
||||
return [];
|
||||
}
|
||||
const recordings = result.recordings.recording;
|
||||
if (!recordings) return [];
|
||||
return Array.isArray(recordings) ? recordings : [recordings];
|
||||
}
|
||||
|
||||
export async function deleteRecording(recordID) {
|
||||
return apiCall('deleteRecordings', { recordID });
|
||||
}
|
||||
|
||||
export async function publishRecording(recordID, publish) {
|
||||
return apiCall('publishRecordings', { recordID, publish: publish ? 'true' : 'false' });
|
||||
}
|
||||
|
||||
export { getRoomPasswords };
|
||||
Reference in New Issue
Block a user