From acf22177ae0be58fd270f7444df14e7668912b8a Mon Sep 17 00:00:00 2001
From: Felipe Cecagno <fcecagno@gmail.com>
Date: Wed, 24 Oct 2018 23:49:56 -0300
Subject: [PATCH] add compatibility with old messaging format

---
 bbb-webhooks/config.js         |   5 +-
 bbb-webhooks/messageMapping.js | 129 ++++++++++++++++++++++++++++++++-
 bbb-webhooks/userMapping.js    |  14 +++-
 bbb-webhooks/web_hooks.js      |   2 +-
 4 files changed, 143 insertions(+), 7 deletions(-)

diff --git a/bbb-webhooks/config.js b/bbb-webhooks/config.js
index cfc7ccda07..4c06a78fbb 100644
--- a/bbb-webhooks/config.js
+++ b/bbb-webhooks/config.js
@@ -21,7 +21,10 @@ if (!config.hooks.channels) {
   config.hooks.channels = {
     mainChannel: 'from-akka-apps-redis-channel',
     rapChannel: 'bigbluebutton:from-rap',
-    chatChannel: 'from-akka-apps-chat-redis-channel'
+    chatChannel: 'from-akka-apps-chat-redis-channel',
+    compMeetingChannel: 'bigbluebutton:from-bbb-apps:meeting',
+    compUserChannel: 'bigbluebutton:from-bbb-apps:users',
+    compChatChannel: 'bigbluebutton:from-bbb-apps:chat'
   }
  }
 // IP where permanent hook will post data (more than 1 URL means more than 1 permanent hook)
diff --git a/bbb-webhooks/messageMapping.js b/bbb-webhooks/messageMapping.js
index 7ea2062c8a..8bd3edef19 100644
--- a/bbb-webhooks/messageMapping.js
+++ b/bbb-webhooks/messageMapping.js
@@ -11,6 +11,9 @@ module.exports = class MessageMapping {
     this.userEvents = ["UserJoinedMeetingEvtMsg","UserLeftMeetingEvtMsg","UserJoinedVoiceConfToClientEvtMsg","UserLeftVoiceConfToClientEvtMsg","PresenterAssignedEvtMsg", "PresenterUnassignedEvtMsg", "UserBroadcastCamStartedEvtMsg", "UserBroadcastCamStoppedEvtMsg", "UserEmojiChangedEvtMsg"];
     this.chatEvents = ["SendPublicMessageEvtMsg","SendPrivateMessageEvtMsg"];
     this.rapEvents = ["archive_started","archive_ended","sanity_started","sanity_ended","post_archive_started","post_archive_ended","process_started","process_ended","post_process_started","post_process_ended","publish_started","publish_ended","post_publish_started","post_publish_ended"];
+
+    this.compMeetingEvents = ["meeting_created_message","meeting_destroyed_event"];
+    this.compUserEvents = ["user_joined_message","user_left_message","user_listening_only","user_joined_voice_message","user_left_voice_message","user_shared_webcam_message","user_unshared_webcam_message","user_status_changed_message"];
   }
 
   // Map internal message based on it's type
@@ -23,6 +26,10 @@ module.exports = class MessageMapping {
       this.chatTemplate(messageObj);
     } else if (this.mappedEvent(messageObj,this.rapEvents)) {
       this.rapTemplate(messageObj);
+    } else if (this.mappedEvent(messageObj,this.compMeetingEvents)) {
+      this.compMeetingTemplate(messageObj);
+    } else if (this.mappedEvent(messageObj,this.compUserEvents)) {
+      this.compUserTemplate(messageObj);
     }
   }
 
@@ -79,6 +86,46 @@ module.exports = class MessageMapping {
     Logger.info("[MessageMapping] Mapped message:", this.mappedMessage);
   }
 
+  compMeetingTemplate(messageObj) {
+    const props = messageObj.payload;
+    const meetingId = props.meeting_id;
+    this.mappedObject.data = {
+      "type": "event",
+      "id": this.mapInternalMessage(messageObj),
+      "attributes":{
+        "meeting":{
+          "internal-meeting-id": meetingId,
+          "external-meeting-id": IDMapping.getExternalMeetingID(meetingId)
+        }
+      },
+      "event":{
+        "ts": Date.now()
+      }
+    };
+    if (messageObj.header.name === "meeting_created_message") {
+      this.mappedObject.data.attributes = {
+        "meeting":{
+          "internal-meeting-id": meetingId,
+          "external-meeting-id": props.external_meeting_id,
+          "name": props.name,
+          "is-breakout": props.is_breakout,
+          "duration": props.duration,
+          "create-time": props.create_time,
+          "create-date": props.create_date,
+          "moderator-pass": props.moderator_pass,
+          "viewer-pass": props.viewer_pass,
+          "record": props.recorded,
+          "voice-conf": props.voice_conf,
+          "dial-number": props.dial_number,
+          "max-users": props.max_users,
+          "metadata": props.metadata
+        }
+      };
+    }
+    this.mappedMessage = JSON.stringify(this.mappedObject);
+    Logger.info("[MessageMapping] Mapped message:", this.mappedMessage);
+  }
+
   // Map internal to external message for user information
   userTemplate(messageObj) {
     const msgBody = messageObj.core.body;
@@ -111,6 +158,68 @@ module.exports = class MessageMapping {
     Logger.info("[MessageMapping] Mapped message:", this.mappedMessage);
   }
 
+  // Map internal to external message for user information
+  compUserTemplate(messageObj) {
+    const msgBody = messageObj.payload;
+    const msgHeader = messageObj.header;
+
+    let user;
+    if (msgHeader.name === "user_joined_message") {
+      user = {
+        "internal-user-id": msgBody.user.userid,
+        "external-user-id": msgBody.user.extern_userid,
+        "sharing-mic": msgBody.user.voiceUser.joined,
+        "name": msgBody.user.name,
+        "role": msgBody.user.role,
+        "presenter": msgBody.user.presenter,
+        "stream": msgBody.user.webcam_stream,
+        "listening-only": msgBody.user.listenOnly
+      }
+    }
+    else {
+      user = UserMapping.getUser(msgBody.userid) || { "internal-user-id": msgBody.userid || msgBody.user.userid };
+      if (msgHeader.name === "user_status_changed_message") {
+        if (msgBody.status === "presenter") {
+          user["presenter"] = msgBody.value;
+        }
+      }
+      else if (msgHeader.name === "user_listening_only") {
+        user["listening-only"] = msgBody.listen_only;
+      }
+      else if (msgHeader.name === "user_joined_voice_message" || msgHeader.name === "user_left_voice_message") {
+        user["sharing-mic"] = msgBody.user.voiceUser.joined;
+      }
+      else if (msgHeader.name === "user_shared_webcam_message") {
+        user["stream"].push(msgBody.stream);
+      }
+      else if (msgHeader.name === "user_unshared_webcam_message") {
+        let streams = user["stream"];
+        let index = streams.indexOf(msgBody.stream);
+        if (index != -1) {
+          streams.splice(index,1);
+        }
+        user["stream"] = streams;
+      }
+    }
+
+    this.mappedObject.data = {
+      "type": "event",
+      "id": this.mapInternalMessage(messageObj),
+      "attributes":{
+        "meeting":{
+          "internal-meeting-id": msgBody.meeting_id,
+          "external-meeting-id": IDMapping.getExternalMeetingID(msgBody.meeting_id)
+        },
+        "user": user
+      },
+      "event":{
+        "ts": Date.now()
+      }
+    };
+    this.mappedMessage = JSON.stringify(this.mappedObject);
+    Logger.info("[MessageMapping] Mapped message:", this.mappedMessage);
+  }
+
   // Map internal to external message for chat information
   chatTemplate(messageObj) {
     const message = messageObj.core.body.message;
@@ -183,13 +292,14 @@ module.exports = class MessageMapping {
 
 
   mapInternalMessage(message) {
+    let name;
     if (message.envelope) {
-      message = message.envelope.name
+      name = message.envelope.name
     }
     else if (message.header) {
-      message = message.header.name
+      name = message.header.name
     }
-    const mappedMsg = (() => { switch (message) {
+    const mappedMsg = (() => { switch (name) {
       case "MeetingCreatedEvtMsg": return "meeting-created";
       case "MeetingDestroyedEvtMsg": return "meeting-ended";
       case "RecordingStatusChangedEvtMsg": return "meeting-recording-changed";
@@ -221,6 +331,19 @@ module.exports = class MessageMapping {
       case "publish_ended": return "rap-publish-ended";
       case "post_publish_started": return "rap-post-publish-started";
       case "post_publish_ended": return "rap-post-publish-ended";
+      case "meeting_created_message": return "meeting-created";
+      case "meeting_destroyed_event": return "meeting-ended";
+      case "user_joined_message": return "user-joined";
+      case "user_left_message": return "user-left";
+      case "user_listening_only": return (message.payload.listen_only === "true" ? "user-audio-listen-only-enabled" : "user-audio-listen-only-disabled");
+      case "user_joined_voice_message": return "user-audio-voice-enabled";
+      case "user_left_voice_message": return "user-audio-voice-disabled";
+      case "user_shared_webcam_message": return "user-cam-broadcast-start";
+      case "video_stream_unpublished": return "user-cam-broadcast-end";
+      case "user_status_changed_message":
+        if (message.payload.status === "presenter") {
+          return (message.payload.value === "true" ? "user-presenter-assigned" : "user-presenter-unassigned" );
+        }
     } })();
     return mappedMsg;
   }
diff --git a/bbb-webhooks/userMapping.js b/bbb-webhooks/userMapping.js
index 185e2fc9a4..1177071904 100644
--- a/bbb-webhooks/userMapping.js
+++ b/bbb-webhooks/userMapping.js
@@ -32,6 +32,7 @@ module.exports = class UserMapping {
     this.externalUserID = null;
     this.internalUserID = null;
     this.meetingId = null;
+    this.user = null;
     this.redisClient = config.redis.client;
   }
 
@@ -68,7 +69,8 @@ module.exports = class UserMapping {
       "id": this.id,
       "internalUserID": this.internalUserID,
       "externalUserID": this.externalUserID,
-      "meetingId": this.meetingId
+      "meetingId": this.meetingId,
+      "user": this.user
     };
     return r;
   }
@@ -78,18 +80,20 @@ module.exports = class UserMapping {
     this.externalUserID = redisData.externalUserID;
     this.internalUserID = redisData.internalUserID;
     this.meetingId = redisData.meetingId;
+    this.user = redisData.user;
   }
 
   print() {
     return JSON.stringify(this.toRedis());
   }
 
-  static addMapping(internalUserID, externalUserID, meetingId, callback) {
+  static addOrUpdateMapping(internalUserID, externalUserID, meetingId, user, callback) {
     let mapping = new UserMapping();
     mapping.id = nextID++;
     mapping.internalUserID = internalUserID;
     mapping.externalUserID = externalUserID;
     mapping.meetingId = meetingId;
+    mapping.user = user;
     mapping.save(function(error, result) {
       Logger.info(`[UserMapping] added user mapping to the list ${internalUserID}:`, mapping.print());
       (typeof callback === 'function' ? callback(error, result) : undefined);
@@ -131,6 +135,12 @@ module.exports = class UserMapping {
     })();
   }
 
+  static getUser(internalUserID) {
+    if (db[internalUserID]){
+      return db[internalUserID].user;
+    }
+  }
+
   static getExternalUserID(internalUserID) {
     if (db[internalUserID]){
       return db[internalUserID].externalUserID;
diff --git a/bbb-webhooks/web_hooks.js b/bbb-webhooks/web_hooks.js
index c00a2cf0b1..787027787a 100644
--- a/bbb-webhooks/web_hooks.js
+++ b/bbb-webhooks/web_hooks.js
@@ -54,7 +54,7 @@ module.exports = class WebHooks {
               });
               break;
             case "user-joined":
-              UserMapping.addMapping(message.data.attributes.user["internal-user-id"],message.data.attributes.user["external-user-id"], intId, () => {
+              UserMapping.addOrUpdateMapping(message.data.attributes.user["internal-user-id"],message.data.attributes.user["external-user-id"], intId, message.data.attributes.user, () => {
                 processMessage();
               });
               break;
-- 
GitLab