mirror of
https://github.com/turt2live/matrix-dimension.git
synced 2024-09-29 20:25:58 +00:00
Fix communication with BBB, fix widget query parameters etc.
This commit is contained in:
parent
5c28ec1d94
commit
32d0bd3aec
@ -91,6 +91,27 @@ dimension:
|
|||||||
# to your own Dimension instance.
|
# to your own Dimension instance.
|
||||||
publicUrl: "https://dimension.example.org"
|
publicUrl: "https://dimension.example.org"
|
||||||
|
|
||||||
|
bigbluebutton:
|
||||||
|
# The full base URL of the API of your BigBlueButton instance. The API is
|
||||||
|
# used to create and join meetings.
|
||||||
|
apiBaseUrl: "https://bbb.example.org/bigbluebutton/api"
|
||||||
|
|
||||||
|
# The "shared secret" of your BigBlueButton instance. This is used to
|
||||||
|
# authenticate to the API above.
|
||||||
|
sharedSecret: "YourSharedSecretHere"
|
||||||
|
|
||||||
|
# The title for BigBlueButton widgets that are generated by Dimension.
|
||||||
|
widgetName: "BigBlueButton Conference"
|
||||||
|
|
||||||
|
# The subtitle for BigBlueButton widgets that are generated by Dimension.
|
||||||
|
widgetTitle: "Join the conference"
|
||||||
|
|
||||||
|
# The avatar for BigBlueButton widgets that are generated by Dimension.
|
||||||
|
# Usually this doen't need to be changed, however if your homeserver
|
||||||
|
# is not able to reach t2bot.io then you should specify your own here.
|
||||||
|
# TODO: Need a t2bot.io MXC URL.
|
||||||
|
widgetAvatarUrl: "mxc://t2bot.io/ineedamxcurlplstravis"
|
||||||
|
|
||||||
# Settings for controlling how logging works
|
# Settings for controlling how logging works
|
||||||
logging:
|
logging:
|
||||||
file: logs/dimension.log
|
file: logs/dimension.log
|
||||||
|
@ -30,7 +30,6 @@
|
|||||||
"@types/body-parser": "^1.17.0",
|
"@types/body-parser": "^1.17.0",
|
||||||
"@types/node": "^12.0.10",
|
"@types/node": "^12.0.10",
|
||||||
"@types/validator": "^10.11.1",
|
"@types/validator": "^10.11.1",
|
||||||
"bigbluebutton-api-js": "^2.2.1",
|
|
||||||
"body-parser": "^1.19.0",
|
"body-parser": "^1.19.0",
|
||||||
"config": "^3.1.0",
|
"config": "^3.1.0",
|
||||||
"dns-then": "^0.1.0",
|
"dns-then": "^0.1.0",
|
||||||
|
@ -2,7 +2,7 @@ import { GET, Path, QueryParam } from "typescript-rest";
|
|||||||
import * as request from "request";
|
import * as request from "request";
|
||||||
import { LogService } from "matrix-js-snippets";
|
import { LogService } from "matrix-js-snippets";
|
||||||
import { URL } from "url";
|
import { URL } from "url";
|
||||||
import { BigBlueButtonJoinRequest, BigBlueButtonCreateAndJoinMeetingRequest } from "../../models/Widget";
|
import { BigBlueButtonJoinRequest } from "../../models/Widget";
|
||||||
import { BigBlueButtonJoinResponse, BigBlueButtonCreateAndJoinMeetingResponse, BigBlueButtonWidgetResponse } from "../../models/WidgetResponses";
|
import { BigBlueButtonJoinResponse, BigBlueButtonCreateAndJoinMeetingResponse, BigBlueButtonWidgetResponse } from "../../models/WidgetResponses";
|
||||||
import { AutoWired } from "typescript-ioc/es6";
|
import { AutoWired } from "typescript-ioc/es6";
|
||||||
import { ApiError } from "../ApiError";
|
import { ApiError } from "../ApiError";
|
||||||
@ -173,7 +173,6 @@ export class DimensionBigBlueButtonService {
|
|||||||
* @param {string} qs The query parameters to use with the request.
|
* @param {string} qs The query parameters to use with the request.
|
||||||
* @param {string} body The JSON body of the request
|
* @param {string} body The JSON body of the request
|
||||||
* @param {boolean} followRedirect Whether to follow redirect responses automatically.
|
* @param {boolean} followRedirect Whether to follow redirect responses automatically.
|
||||||
* @private
|
|
||||||
*/
|
*/
|
||||||
private async doRequest(
|
private async doRequest(
|
||||||
method: string,
|
method: string,
|
||||||
@ -225,19 +224,17 @@ export class DimensionBigBlueButtonService {
|
|||||||
// Hash the room ID in order to generate a unique widget ID
|
// Hash the room ID in order to generate a unique widget ID
|
||||||
const widgetId = sha256(roomId + "bigbluebutton");
|
const widgetId = sha256(roomId + "bigbluebutton");
|
||||||
|
|
||||||
// TODO: Make configurable
|
const widgetName = config.bigbluebutton.widgetName;
|
||||||
const widgetTitle = "BigBlueButton Video Conference";
|
const widgetTitle = config.bigbluebutton.widgetTitle;
|
||||||
const widgetSubTitle = "Join the conference";
|
const widgetAvatarUrl = config.bigbluebutton.widgetAvatarUrl;
|
||||||
const widgetAvatarUrl = "mxc://fosdem.org/0eea5cb67fbe964399060b10b09a22e45e2226ee";
|
|
||||||
|
|
||||||
// TODO: What should we put for the creatorUserId? Also make it configurable?
|
// TODO: What should we put for the creatorUserId? Also make it configurable?
|
||||||
const widgetCreatorUserId = "@bobbb:localhost";
|
const widgetCreatorUserId = "@bbb:localhost";
|
||||||
|
|
||||||
// TODO: Set to configured Dimension publicUrl
|
|
||||||
let widgetUrl = "http://localhost:8082/widgets/bigbluebutton";
|
|
||||||
|
|
||||||
// Add all necessary client variables to the url when loading the widget
|
// Add all necessary client variables to the url when loading the widget
|
||||||
widgetUrl += "?widgetId=$matrix_widget_id&roomId=$matrix_room_id#displayName=$matrix_display_name&avatarUrl=$matrix_avatar_url&userId=$matrix_user_id&roomId=$matrix_room_id&auth=openidtoken-jwt";
|
const widgetUrl = config.dimension.publicUrl +
|
||||||
|
"/widgets/bigbluebutton" +
|
||||||
|
"?widgetId=$matrix_widget_id&roomId=$matrix_room_id&createMeeting=true&displayName=$matrix_display_name&avatarUrl=$matrix_avatar_url&userId=$matrix_user_id&auth=openidtoken-jwt";
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"widget_id": widgetId,
|
"widget_id": widgetId,
|
||||||
@ -246,12 +243,11 @@ export class DimensionBigBlueButtonService {
|
|||||||
"id": widgetId,
|
"id": widgetId,
|
||||||
"type": "m.custom",
|
"type": "m.custom",
|
||||||
"waitForIframeLoad": true,
|
"waitForIframeLoad": true,
|
||||||
"name": widgetTitle,
|
"name": widgetName,
|
||||||
"avatar_url": widgetAvatarUrl,
|
"avatar_url": widgetAvatarUrl,
|
||||||
"url": widgetUrl,
|
"url": widgetUrl,
|
||||||
"data": {
|
"data": {
|
||||||
"title": widgetSubTitle,
|
"title": widgetTitle,
|
||||||
"widgetVersion": 2,
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"layout": {
|
"layout": {
|
||||||
@ -264,9 +260,10 @@ export class DimensionBigBlueButtonService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@GET
|
@GET
|
||||||
@Path("createAndJoinMeeting")
|
@Path("create")
|
||||||
public async createAndJoinMeeting(
|
public async createAndJoinMeeting(
|
||||||
@QueryParam("room_id") roomId: string,
|
@QueryParam("roomId") roomId: string,
|
||||||
|
@QueryParam("fullName") fullName: string,
|
||||||
): Promise<BigBlueButtonCreateAndJoinMeetingResponse|ApiError> {
|
): Promise<BigBlueButtonCreateAndJoinMeetingResponse|ApiError> {
|
||||||
// Check if a meeting already exists for this room...
|
// Check if a meeting already exists for this room...
|
||||||
LogService.info("BigBlueButton", "Got a meeting create and join request for room: " + roomId);
|
LogService.info("BigBlueButton", "Got a meeting create and join request for room: " + roomId);
|
||||||
@ -275,15 +272,36 @@ export class DimensionBigBlueButtonService {
|
|||||||
LogService.info("BigBlueButton", "Using secret: " + config.bigbluebutton.sharedSecret);
|
LogService.info("BigBlueButton", "Using secret: " + config.bigbluebutton.sharedSecret);
|
||||||
|
|
||||||
// NOTE: BBB meetings will by default end a minute or two after the last person leaves.
|
// NOTE: BBB meetings will by default end a minute or two after the last person leaves.
|
||||||
const queryParameters = {
|
const createQueryParameters = {
|
||||||
meetingID: roomId + "bigbluebuttondimension",
|
meetingID: roomId + "bigbluebuttondimension",
|
||||||
|
attendeePW: "a",
|
||||||
|
moderatorPW: "b",
|
||||||
};
|
};
|
||||||
const response = await this.makeBBBApiCall("GET", "create", queryParameters, null);
|
|
||||||
LogService.info("BigBlueButton", response);
|
// TODO: Contrary to the documentation, one needs to provide a meeting ID, attendee and moderator password in order
|
||||||
|
// for creating meeting to be idempotent. For now we use dummy passwords, though we may want to consider generating
|
||||||
|
// some once we actually start authenticating meetings.
|
||||||
|
const createResponse = await this.makeBBBApiCall("GET", "create", createQueryParameters, null);
|
||||||
|
LogService.info("BigBlueButton", createResponse);
|
||||||
|
|
||||||
|
// Grab the meeting ID and password from the create response
|
||||||
|
const returnedMeetingId = createResponse.meetingID[0];
|
||||||
|
const returnedAttendeePassword = createResponse.attendeePW[0];
|
||||||
|
const joinQueryParameters = {
|
||||||
|
meetingID: returnedMeetingId,
|
||||||
|
password: returnedAttendeePassword,
|
||||||
|
fullName: fullName,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate the checksum for the join URL. We need to do so as a browser would as we're passing this back to a browser
|
||||||
|
const checksum = this.bbbChecksumFromCallNameAndQueryParamaters("join", joinQueryParameters, true);
|
||||||
|
|
||||||
|
// Construct the join URL, which we'll give back to the client, who can then add additional parameters to (or we just do it)
|
||||||
|
const url = `${config.bigbluebutton.apiBaseUrl}/join?${this.queryStringFromObject(joinQueryParameters, true)}&checksum=${checksum}`;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
url: "https://bla.com",
|
url: url,
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -292,7 +310,6 @@ export class DimensionBigBlueButtonService {
|
|||||||
* @param {string} apiCallName The name of the API (the last bit of the endpoint) to call. e.g 'create', 'join'.
|
* @param {string} apiCallName The name of the API (the last bit of the endpoint) to call. e.g 'create', 'join'.
|
||||||
* @param {any} queryParameters The query parameters to use in the request.
|
* @param {any} queryParameters The query parameters to use in the request.
|
||||||
* @param {any} body The body of the request.
|
* @param {any} body The body of the request.
|
||||||
* @private
|
|
||||||
* @returns {BigBlueButtonApiResponse} The response to the call.
|
* @returns {BigBlueButtonApiResponse} The response to the call.
|
||||||
*/
|
*/
|
||||||
private async makeBBBApiCall(
|
private async makeBBBApiCall(
|
||||||
@ -301,42 +318,69 @@ export class DimensionBigBlueButtonService {
|
|||||||
queryParameters: any,
|
queryParameters: any,
|
||||||
body: any,
|
body: any,
|
||||||
): Promise<any> {
|
): Promise<any> {
|
||||||
// Build the URL path from the api name, query parameter string, shared secret and checksum
|
// Compute the checksum needed to authenticate the request (as derived from the configured shared secret)
|
||||||
// Docs: https://docs.bigbluebutton.org/dev/api.html#usage
|
queryParameters.checksum = this.bbbChecksumFromCallNameAndQueryParamaters(apiCallName, queryParameters, false);
|
||||||
|
|
||||||
LogService.info("BigBlueButton", "given query params: " + queryParameters.meetingID);
|
|
||||||
// Convert the query parameters map into a string
|
|
||||||
// We URL encode each value, as doRequest does so as well. If we don't, our resulting checksum will not match
|
|
||||||
const widgetQueryString = Object.keys(queryParameters).map(k => k + "=" + this.encodeForUrl(queryParameters[k])).join("&");
|
|
||||||
LogService.info("BigBlueButton", "queryString: " + widgetQueryString);
|
|
||||||
|
|
||||||
// SHA1 hash the api name and query parameters to get the checksum, and add it to the set of query parameters
|
|
||||||
queryParameters.checksum = sha1(apiCallName + widgetQueryString + config.bigbluebutton.sharedSecret);
|
|
||||||
LogService.info("BigBlueButton", "hashing: " + apiCallName + widgetQueryString + config.bigbluebutton.sharedSecret);
|
|
||||||
|
|
||||||
// Get the URL host and path using the configured api base and the API call name
|
// Get the URL host and path using the configured api base and the API call name
|
||||||
const url = `${config.bigbluebutton.apiBaseUrl}/${apiCallName}`;
|
const url = `${config.bigbluebutton.apiBaseUrl}/${apiCallName}`;
|
||||||
const qsWithChecksum = Object.keys(queryParameters).map(k => k + "=" + this.encodeForUrl(queryParameters[k])).join("&");
|
|
||||||
LogService.info("BigBlueButton", "final url: " + url + "?" + qsWithChecksum);
|
|
||||||
|
|
||||||
// Now make the request!
|
// Now make the request!
|
||||||
// TODO: Unfortunately doRequest is URLencoding the query parameters which the checksum stuff doesn't take into account.
|
|
||||||
// So we need to disable URL encoding here, or do it when calculating the checksum
|
|
||||||
const response = await this.doRequest(method, url, queryParameters, body);
|
const response = await this.doRequest(method, url, queryParameters, body);
|
||||||
|
|
||||||
// Parse and return the XML from the response
|
// Parse and return the XML from the response
|
||||||
LogService.info("BigBlueButton", response.body);
|
// TODO: XML parsing error handling
|
||||||
return await parseStringPromise(response.body);
|
const parsedResponse = await parseStringPromise(response.body);
|
||||||
|
|
||||||
|
// Extract the "response" object
|
||||||
|
return parsedResponse.response;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encodes a string in the same fashion browsers do (encoding ! and other characters)
|
* Converts an object representing a query string into a checksum suitable for appending to a BBB API call.
|
||||||
* @param {string} text The text to encode
|
* Docs: https://docs.bigbluebutton.org/dev/api.html#usage
|
||||||
|
* @param {string} apiCallName The name of the API to call, e.g "create", "join".
|
||||||
|
* @param {any} queryParameters An object representing a set of query parameters represented by keys and values.
|
||||||
|
* @param {boolean} encodeAsBrowser Whether to encode the query string as a browser would.
|
||||||
|
* @returns {string} The checksum for the request.
|
||||||
*/
|
*/
|
||||||
encodeForUrl(text: string) {
|
private bbbChecksumFromCallNameAndQueryParamaters(apiCallName: string, queryParameters: any, encodeAsBrowser: boolean): string {
|
||||||
// use + instead of %20 for space to match what the Java tools do.
|
// Convert the query parameters object into a string
|
||||||
// encodeURIComponent doesn't escape !'()* but browsers do, so manually escape them.
|
// We URL encode each value as a browser would. If we don't, our resulting checksum will not match.
|
||||||
return encodeURIComponent(text).replace(/%20/g, '+').replace(/[!'()]/g, escape).replace(/\*/g, "%2A");
|
const widgetQueryString = this.queryStringFromObject(queryParameters, encodeAsBrowser);
|
||||||
|
|
||||||
|
LogService.info("BigBlueButton", "Built widget string:" + widgetQueryString);
|
||||||
|
LogService.info("BigBlueButton", "Hashing:" + apiCallName + widgetQueryString + config.bigbluebutton.sharedSecret);
|
||||||
|
|
||||||
|
// SHA1 hash the api name and query parameters to get the checksum, and add it to the set of query parameters
|
||||||
|
// TODO: Try Sha256
|
||||||
|
return sha1(apiCallName + widgetQueryString + config.bigbluebutton.sharedSecret);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A
|
||||||
|
* @param queryParameters
|
||||||
|
* @param encodeAsBrowser
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
private queryStringFromObject(queryParameters: any, encodeAsBrowser: boolean): string {
|
||||||
|
return Object.keys(queryParameters).map(k => k + "=" + this.encodeForUrl(queryParameters[k], encodeAsBrowser)).join("&");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encodes a string in the same fashion browsers do (encoding ! and other characters).
|
||||||
|
* @param {string} text The text to encode.
|
||||||
|
* @param {boolean} encodeAsBrowser Whether to encode the query string as a browser would.
|
||||||
|
* @returns {string} The encoded text.
|
||||||
|
*/
|
||||||
|
private encodeForUrl(text: string, encodeAsBrowser: boolean): string {
|
||||||
|
let encodedText = encodeURIComponent(text);
|
||||||
|
if (!encodeAsBrowser) {
|
||||||
|
// use + instead of %20 for space to match what the 'request' JavaScript library does do.
|
||||||
|
// encodeURIComponent doesn't escape !'()*, so manually escape them.
|
||||||
|
encodedText = encodedText.replace(/%20/g, '+').replace(/[!'()]/g, escape).replace(/\*/g, "%2A");
|
||||||
|
}
|
||||||
|
|
||||||
|
return encodedText;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -31,6 +31,9 @@ export interface DimensionConfig {
|
|||||||
bigbluebutton: {
|
bigbluebutton: {
|
||||||
apiBaseUrl: string;
|
apiBaseUrl: string;
|
||||||
sharedSecret: string;
|
sharedSecret: string;
|
||||||
|
widgetName: string;
|
||||||
|
widgetTitle: string;
|
||||||
|
widgetAvatarUrl: string;
|
||||||
};
|
};
|
||||||
stickers: {
|
stickers: {
|
||||||
enabled: boolean;
|
enabled: boolean;
|
||||||
|
@ -20,7 +20,6 @@ export interface BigBlueButtonWidgetResponse {
|
|||||||
url: string;
|
url: string;
|
||||||
data: {
|
data: {
|
||||||
title: string;
|
title: string;
|
||||||
widgetVersion: number;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
layout: {
|
layout: {
|
||||||
|
@ -27,7 +27,7 @@ export class BigBlueButtonConfigComponent extends WidgetComponent {
|
|||||||
|
|
||||||
protected OnNewWidgetPrepared(widget: EditableWidget): void {
|
protected OnNewWidgetPrepared(widget: EditableWidget): void {
|
||||||
widget.dimension.newData["conferenceUrl"] = this.bigBlueButtonWidget.options.conferenceUrl;
|
widget.dimension.newData["conferenceUrl"] = this.bigBlueButtonWidget.options.conferenceUrl;
|
||||||
widget.dimension.newData["widgetVersion"] = this.bigBlueButtonWidget.options.widgetVersion;
|
widget.dimension.newData["createMeeting"] = this.bigBlueButtonWidget.options.createMeeting;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected OnWidgetBeforeAdd(widget: EditableWidget) {
|
protected OnWidgetBeforeAdd(widget: EditableWidget) {
|
||||||
@ -44,6 +44,7 @@ export class BigBlueButtonConfigComponent extends WidgetComponent {
|
|||||||
let widgetQueryString = url.format({
|
let widgetQueryString = url.format({
|
||||||
query: {
|
query: {
|
||||||
"conferenceUrl": "$conferenceUrl",
|
"conferenceUrl": "$conferenceUrl",
|
||||||
|
"createMeeting": "$createMeeting",
|
||||||
"displayName": "$matrix_display_name",
|
"displayName": "$matrix_display_name",
|
||||||
"avatarUrl": "$matrix_avatar_url",
|
"avatarUrl": "$matrix_avatar_url",
|
||||||
"userId": "$matrix_user_id",
|
"userId": "$matrix_user_id",
|
||||||
|
@ -101,7 +101,7 @@ export interface FE_JitsiWidget extends FE_Widget {
|
|||||||
export interface FE_BigBlueButtonWidget extends FE_Widget {
|
export interface FE_BigBlueButtonWidget extends FE_Widget {
|
||||||
options: {
|
options: {
|
||||||
conferenceUrl: string;
|
conferenceUrl: string;
|
||||||
widgetVersion: number;
|
createMeeting: boolean;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,12 +10,12 @@ export class BigBlueButtonApiService extends AuthedApi {
|
|||||||
super(http);
|
super(http);
|
||||||
}
|
}
|
||||||
|
|
||||||
public joinMeeting(url: string, name: string): Promise<FE_BigBlueButtonJoin|ApiError> {
|
public joinMeetingWithGreenlightUrl(url: string, name: string): Promise<FE_BigBlueButtonJoin|ApiError> {
|
||||||
return this.authedGet<FE_BigBlueButtonJoin|ApiError>("/api/v1/dimension/bigbluebutton/join", {greenlightUrl: url, fullName: name}).toPromise();
|
return this.authedGet<FE_BigBlueButtonJoin|ApiError>("/api/v1/dimension/bigbluebutton/join", {greenlightUrl: url, fullName: name}).toPromise();
|
||||||
}
|
}
|
||||||
|
|
||||||
public createAndJoinMeeting(roomId: string): Promise<FE_BigBlueButtonCreateAndJoinMeeting|ApiError> {
|
public createAndJoinMeeting(roomId: string, name: string): Promise<FE_BigBlueButtonCreateAndJoinMeeting|ApiError> {
|
||||||
return this.authedGet<FE_BigBlueButtonCreateAndJoinMeeting|ApiError>("/api/v1/dimension/bigbluebutton/join_meeting", {roomId: roomId}).toPromise();
|
return this.authedGet<FE_BigBlueButtonCreateAndJoinMeeting|ApiError>("/api/v1/dimension/bigbluebutton/create", {roomId: roomId, fullName: name}).toPromise();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -25,6 +25,12 @@ export class BigBlueButtonWidgetWrapperComponent extends CapableWidget implement
|
|||||||
private displayName: string;
|
private displayName: string;
|
||||||
private userId: string;
|
private userId: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* The name to join the BigBlueButton meeting with. Made up of metadata the client passes to us.
|
||||||
|
*/
|
||||||
|
private joinName: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether we expect the meeting to be created on command.
|
* Whether we expect the meeting to be created on command.
|
||||||
*
|
*
|
||||||
@ -79,7 +85,14 @@ export class BigBlueButtonWidgetWrapperComponent extends CapableWidget implement
|
|||||||
this.displayName = params.displayName;
|
this.displayName = params.displayName;
|
||||||
this.userId = params.userId || params.email; // Element uses `email` when placing a conference call
|
this.userId = params.userId || params.email; // Element uses `email` when placing a conference call
|
||||||
|
|
||||||
|
// Create a nick to display in the meeting
|
||||||
|
this.joinName = `${this.displayName} (${this.userId})`;
|
||||||
|
|
||||||
|
// TODO: As of BigBlueButton 2.3, Avatar URLs are supported in /join, which would allow us to set the
|
||||||
|
// user's avatar in BigBlueButton to that of their Matrix ID.
|
||||||
|
|
||||||
console.log("BigBlueButton: should create meeting: " + this.createMeeting);
|
console.log("BigBlueButton: should create meeting: " + this.createMeeting);
|
||||||
|
console.log("BigBlueButton: will join as: " + this.joinName);
|
||||||
console.log("BigBlueButton: got room ID: " + this.roomId);
|
console.log("BigBlueButton: got room ID: " + this.roomId);
|
||||||
|
|
||||||
// Set the widget ID if we have it
|
// Set the widget ID if we have it
|
||||||
@ -117,25 +130,22 @@ export class BigBlueButtonWidgetWrapperComponent extends CapableWidget implement
|
|||||||
this.statusMessage = "Joining conference...";
|
this.statusMessage = "Joining conference...";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate a nick to display in the meeting
|
|
||||||
const joinName = `${this.displayName} (${this.userId})`;
|
|
||||||
|
|
||||||
// Make a request to Dimension requesting the join URL
|
// Make a request to Dimension requesting the join URL
|
||||||
if (this.createMeeting === true) {
|
if (this.createMeeting) {
|
||||||
// Ask Dimension to create the meeting for us and return the URL
|
// Ask Dimension to create the meeting for us and return the URL
|
||||||
this.createAndJoinMeeting(joinName);
|
this.createAndJoinMeeting();
|
||||||
} else {
|
} else {
|
||||||
// Provide Dimension with a Greenlight URL, which it will transform into
|
// Provide Dimension with a Greenlight URL, which it will transform into
|
||||||
// a BBB meeting URL
|
// a BBB meeting URL
|
||||||
this.joinThroughGreenlightUrl(joinName);
|
this.joinThroughGreenlightUrl();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ask Dimension to create a meeting (or use an existing one) for this room and return the embeddable meeting URL
|
// Ask Dimension to create a meeting (or use an existing one) for this room and return the embeddable meeting URL
|
||||||
private createAndJoinMeeting(joinName: string) {
|
private createAndJoinMeeting() {
|
||||||
console.log("BigBlueButton: joining and creating meeting if it doesn't already exist, with fullname:", joinName);
|
console.log("BigBlueButton: joining and creating meeting if it doesn't already exist, with fullname:", this.joinName);
|
||||||
|
|
||||||
this.bigBlueButtonApi.createAndJoinMeeting(this.roomId).then((response) => {
|
this.bigBlueButtonApi.createAndJoinMeeting(this.roomId, this.joinName).then((response) => {
|
||||||
if ("errorCode" in response) {
|
if ("errorCode" in response) {
|
||||||
// This is an instance of ApiError
|
// This is an instance of ApiError
|
||||||
// if (response.errorCode === "WAITING_FOR_MEETING_START") {
|
// if (response.errorCode === "WAITING_FOR_MEETING_START") {
|
||||||
@ -158,9 +168,9 @@ export class BigBlueButtonWidgetWrapperComponent extends CapableWidget implement
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Hand Dimension a Greenlight URL and receive a translated, embeddable meeting URL in response
|
// Hand Dimension a Greenlight URL and receive a translated, embeddable meeting URL in response
|
||||||
private joinThroughGreenlightUrl(joinName: string) {
|
private joinThroughGreenlightUrl() {
|
||||||
console.log("BigBlueButton: joining via greenlight url:", this.conferenceUrl);
|
console.log("BigBlueButton: joining via greenlight url:", this.conferenceUrl);
|
||||||
this.bigBlueButtonApi.joinMeeting(this.conferenceUrl, joinName).then((response) => {
|
this.bigBlueButtonApi.joinMeetingWithGreenlightUrl(this.conferenceUrl, this.joinName).then((response) => {
|
||||||
if ("errorCode" in response) {
|
if ("errorCode" in response) {
|
||||||
// This is an instance of ApiError
|
// This is an instance of ApiError
|
||||||
if (response.errorCode === "WAITING_FOR_MEETING_START") {
|
if (response.errorCode === "WAITING_FOR_MEETING_START") {
|
||||||
@ -183,6 +193,10 @@ export class BigBlueButtonWidgetWrapperComponent extends CapableWidget implement
|
|||||||
}
|
}
|
||||||
|
|
||||||
private embedMeetingWithUrl(url: string) {
|
private embedMeetingWithUrl(url: string) {
|
||||||
|
this.canEmbed = true;
|
||||||
|
this.statusMessage = null;
|
||||||
|
this.embedUrl = this.sanitizer.bypassSecurityTrustResourceUrl(url);
|
||||||
|
return
|
||||||
// Check if the given URL is embeddable
|
// Check if the given URL is embeddable
|
||||||
this.widgetApi.isEmbeddable(url).then(result => {
|
this.widgetApi.isEmbeddable(url).then(result => {
|
||||||
this.canEmbed = result.canEmbed;
|
this.canEmbed = result.canEmbed;
|
||||||
|
Loading…
Reference in New Issue
Block a user