diff --git a/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/service/messaging/MessagingConstants.java b/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/service/messaging/MessagingConstants.java
index 3dfb3a9e69..5d5e57aa1f 100644
--- a/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/service/messaging/MessagingConstants.java
+++ b/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/service/messaging/MessagingConstants.java
@@ -37,8 +37,8 @@ public class MessagingConstants {
public static final String TO_PRESENTATION_CHANNEL = TO_BBB_APPS_CHANNEL + ":presentation";
public static final String TO_POLLING_CHANNEL = TO_BBB_APPS_CHANNEL + ":polling";
public static final String TO_USERS_CHANNEL = TO_BBB_APPS_CHANNEL + ":users";
- public static final String TO_CHAT_CHANNEL = TO_BBB_APPS_CHANNEL + ":chat";
-
+ public static final String TO_CHAT_CHANNEL = TO_BBB_APPS_CHANNEL + ":chat";
+ public static final String TO_WHITEBOARD_CHANNEL = TO_BBB_APPS_CHANNEL + ":whiteboard";
public static final String DESTROY_MEETING_REQUEST_EVENT = "DestroyMeetingRequestEvent";
public static final String CREATE_MEETING_REQUEST_EVENT = "CreateMeetingRequestEvent";
diff --git a/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/service/whiteboard/WhiteboardListener.java b/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/service/whiteboard/WhiteboardListener.java
new file mode 100644
index 0000000000..47bc7b68c6
--- /dev/null
+++ b/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/service/whiteboard/WhiteboardListener.java
@@ -0,0 +1,52 @@
+
+package org.bigbluebutton.conference.service.whiteboard;
+
+
+import org.bigbluebutton.conference.service.messaging.MessagingConstants;
+import org.bigbluebutton.conference.service.messaging.redis.MessageHandler;
+
+import org.bigbluebutton.core.api.IBigBlueButtonInGW;
+import com.google.gson.JsonParser;
+import com.google.gson.JsonObject;
+
+public class WhiteboardListener implements MessageHandler{
+
+ private IBigBlueButtonInGW bbbInGW;
+
+ public void setBigBlueButtonInGW(IBigBlueButtonInGW bbbInGW) {
+ this.bbbInGW = bbbInGW;
+ }
+
+ @Override
+ public void handleMessage(String pattern, String channel, String message) {
+ if (channel.equalsIgnoreCase(MessagingConstants.TO_WHITEBOARD_CHANNEL)) {
+ System.out.println("AntonChannel=(whiteboard)" + channel);
+
+ JsonParser parser = new JsonParser();
+ JsonObject obj = (JsonObject) parser.parse(message);
+ JsonObject headerObject = (JsonObject) obj.get("header");
+ JsonObject payloadObject = (JsonObject) obj.get("payload");
+
+ String eventName = headerObject.get("name").toString().replace("\"", "");
+
+ if(eventName.equalsIgnoreCase("get_whiteboard_shapes_request")){
+ //more cases to follow
+
+ String roomName = payloadObject.get("meeting_id").toString().replace("\"", "");
+
+ if(eventName.equalsIgnoreCase("get_whiteboard_shapes_request")){
+ String requesterID = payloadObject.get("requester_id").toString().replace("\"", "");
+ if(payloadObject.get("whiteboard_id") != null){
+ String whiteboardID = payloadObject.get("whiteboard_id").toString().replace("\"", "");
+ System.out.println("\n FOUND A whiteboardID:" + whiteboardID + "\n");
+ bbbInGW.requestWhiteboardAnnotationHistory(roomName, requesterID, whiteboardID, requesterID);
+ }
+ else {
+ System.out.println("\n DID NOT FIND A whiteboardID \n");
+ }
+ System.out.println("\n\n\n user<" + requesterID + "> requested the shapes.\n\n");
+ }
+ }
+ }
+ }
+}
diff --git a/bigbluebutton-apps/src/main/scala/org/bigbluebutton/core/MeetingActor.scala b/bigbluebutton-apps/src/main/scala/org/bigbluebutton/core/MeetingActor.scala
index 29390b0bac..151d490524 100644
--- a/bigbluebutton-apps/src/main/scala/org/bigbluebutton/core/MeetingActor.scala
+++ b/bigbluebutton-apps/src/main/scala/org/bigbluebutton/core/MeetingActor.scala
@@ -36,60 +36,59 @@ class MeetingActor(val meetingID: String, meetingName: String, val recorded: Boo
}
def act() = {
- loop {
- react {
- case "StartTimer" => handleStartTimer
- case "Hello" => handleHello
- case msg: ValidateAuthToken => handleValidateAuthToken(msg)
- case msg: RegisterUser => handleRegisterUser(msg)
- case msg: VoiceUserJoined => handleVoiceUserJoined(msg)
- case msg: VoiceUserLeft => handleVoiceUserLeft(msg)
- case msg: VoiceUserMuted => handleVoiceUserMuted(msg)
- case msg: VoiceUserTalking => handleVoiceUserTalking(msg)
- case msg: UserJoining => handleUserJoin(msg)
- case msg: UserLeaving => handleUserLeft(msg)
- case msg: AssignPresenter => handleAssignPresenter(msg)
- case msg: GetUsers => handleGetUsers(msg)
- case msg: ChangeUserStatus => handleChangeUserStatus(msg)
- case msg: UserRaiseHand => handleUserRaiseHand(msg)
- case msg: UserLowerHand => handleUserLowerHand(msg)
- case msg: UserShareWebcam => handleUserShareWebcam(msg)
- case msg: UserUnshareWebcam => handleUserunshareWebcam(msg)
- case msg: MuteMeetingRequest => handleMuteMeetingRequest(msg)
- case msg: IsMeetingMutedRequest => handleIsMeetingMutedRequest(msg)
- case msg: MuteUserRequest => handleMuteUserRequest(msg)
- case msg: LockUserRequest => handleLockUserRequest(msg)
- case msg: EjectUserRequest => handleEjectUserRequest(msg)
- case msg: SetLockSettings => handleSetLockSettings(msg)
- case msg: InitLockSettings => handleInitLockSettings(msg)
- case msg: LockUser => handleLockUser(msg)
- case msg: LockAllUsers => handleLockAllUsers(msg)
- case msg: GetLockSettings => handleGetLockSettings(msg)
- case msg: IsMeetingLocked => handleIsMeetingLocked(msg)
- case msg: GetChatHistoryRequest => handleGetChatHistoryRequest(msg)
- case msg: SendPublicMessageRequest => handleSendPublicMessageRequest(msg)
- case msg: SendPrivateMessageRequest => handleSendPrivateMessageRequest(msg)
- case msg: UserConnectedToGlobalAudio => handleUserConnectedToGlobalAudio(msg)
- case msg: UserDisconnectedFromGlobalAudio => handleUserDisconnectedFromGlobalAudio(msg)
- case msg: GetCurrentLayoutRequest => handleGetCurrentLayoutRequest(msg)
- case msg: LayoutLockSettings => handleLayoutLockSettings(msg)
- case msg: SetLayoutRequest => handleSetLayoutRequest(msg)
- case msg: LockLayoutRequest => handleLockLayoutRequest(msg)
- case msg: UnlockLayoutRequest => handleUnlockLayoutRequest(msg)
- case msg: InitializeMeeting => handleInitializeMeeting(msg)
- case msg: ClearPresentation => handleClearPresentation(msg)
- case msg: PresentationConversionUpdate => handlePresentationConversionUpdate(msg)
- case msg: PresentationPageCountError => handlePresentationPageCountError(msg)
- case msg: PresentationSlideGenerated => handlePresentationSlideGenerated(msg)
- case msg: PresentationConversionCompleted => handlePresentationConversionCompleted(msg)
- case msg: RemovePresentation => handleRemovePresentation(msg)
- case msg: GetPresentationInfo => handleGetPresentationInfo(msg)
- case msg: SendCursorUpdate => handleSendCursorUpdate(msg)
- case msg: ResizeAndMoveSlide => handleResizeAndMoveSlide(msg)
- case msg: GotoSlide => handleGotoSlide(msg)
- case msg: SharePresentation => handleSharePresentation(msg)
- case msg: GetSlideInfo => handleGetSlideInfo(msg)
- case msg: PreuploadedPresentations => handlePreuploadedPresentations(msg)
+ loop {
+ react {
+ case "StartTimer" => handleStartTimer
+ case "Hello" => handleHello
+ case msg: ValidateAuthToken => handleValidateAuthToken(msg)
+ case msg: RegisterUser => handleRegisterUser(msg)
+ case msg: VoiceUserJoined => handleVoiceUserJoined(msg)
+ case msg: VoiceUserLeft => handleVoiceUserLeft(msg)
+ case msg: VoiceUserMuted => handleVoiceUserMuted(msg)
+ case msg: VoiceUserTalking => handleVoiceUserTalking(msg)
+ case msg: UserJoining => handleUserJoin(msg)
+ case msg: UserLeaving => handleUserLeft(msg)
+ case msg: AssignPresenter => handleAssignPresenter(msg)
+ case msg: GetUsers => handleGetUsers(msg)
+ case msg: ChangeUserStatus => handleChangeUserStatus(msg)
+ case msg: UserRaiseHand => handleUserRaiseHand(msg)
+ case msg: UserLowerHand => handleUserLowerHand(msg)
+ case msg: UserShareWebcam => handleUserShareWebcam(msg)
+ case msg: UserUnshareWebcam => handleUserunshareWebcam(msg)
+ case msg: MuteMeetingRequest => handleMuteMeetingRequest(msg)
+ case msg: IsMeetingMutedRequest => handleIsMeetingMutedRequest(msg)
+ case msg: MuteUserRequest => handleMuteUserRequest(msg)
+ case msg: LockUserRequest => handleLockUserRequest(msg)
+ case msg: EjectUserRequest => handleEjectUserRequest(msg)
+ case msg: SetLockSettings => handleSetLockSettings(msg)
+ case msg: InitLockSettings => handleInitLockSettings(msg)
+ case msg: LockUser => handleLockUser(msg)
+ case msg: LockAllUsers => handleLockAllUsers(msg)
+ case msg: GetLockSettings => handleGetLockSettings(msg)
+ case msg: IsMeetingLocked => handleIsMeetingLocked(msg)
+ case msg: GetChatHistoryRequest => handleGetChatHistoryRequest(msg)
+ case msg: SendPublicMessageRequest => handleSendPublicMessageRequest(msg)
+ case msg: SendPrivateMessageRequest => handleSendPrivateMessageRequest(msg)
+ case msg: UserConnectedToGlobalAudio => handleUserConnectedToGlobalAudio(msg)
+ case msg: UserDisconnectedFromGlobalAudio => handleUserDisconnectedFromGlobalAudio(msg)
+ case msg: GetCurrentLayoutRequest => handleGetCurrentLayoutRequest(msg)
+ case msg: SetLayoutRequest => handleSetLayoutRequest(msg)
+ case msg: LockLayoutRequest => handleLockLayoutRequest(msg)
+ case msg: UnlockLayoutRequest => handleUnlockLayoutRequest(msg)
+ case msg: InitializeMeeting => handleInitializeMeeting(msg)
+ case msg: ClearPresentation => handleClearPresentation(msg)
+ case msg: PresentationConversionUpdate => handlePresentationConversionUpdate(msg)
+ case msg: PresentationPageCountError => handlePresentationPageCountError(msg)
+ case msg: PresentationSlideGenerated => handlePresentationSlideGenerated(msg)
+ case msg: PresentationConversionCompleted => handlePresentationConversionCompleted(msg)
+ case msg: RemovePresentation => handleRemovePresentation(msg)
+ case msg: GetPresentationInfo => handleGetPresentationInfo(msg)
+ case msg: SendCursorUpdate => handleSendCursorUpdate(msg)
+ case msg: ResizeAndMoveSlide => handleResizeAndMoveSlide(msg)
+ case msg: GotoSlide => handleGotoSlide(msg)
+ case msg: SharePresentation => handleSharePresentation(msg)
+ case msg: GetSlideInfo => handleGetSlideInfo(msg)
+ case msg: PreuploadedPresentations => handlePreuploadedPresentations(msg)
case msg: PreCreatedPoll => handlePreCreatedPoll(msg)
case msg: CreatePoll => handleCreatePoll(msg)
case msg: UpdatePoll => handleUpdatePoll(msg)
@@ -103,22 +102,22 @@ class MeetingActor(val meetingID: String, meetingName: String, val recorded: Boo
case msg: RespondToPoll => handleRespondToPoll(msg)
case msg: HidePollResult => handleHidePollResult(msg)
case msg: ShowPollResult => handleShowPollResult(msg)
- case msg: SendWhiteboardAnnotationRequest => handleSendWhiteboardAnnotationRequest(msg)
- case msg: GetWhiteboardShapesRequest => handleGetWhiteboardShapesRequest(msg)
- case msg: ClearWhiteboardRequest => handleClearWhiteboardRequest(msg)
- case msg: UndoWhiteboardRequest => handleUndoWhiteboardRequest(msg)
- case msg: EnableWhiteboardRequest => handleEnableWhiteboardRequest(msg)
- case msg: IsWhiteboardEnabledRequest => handleIsWhiteboardEnabledRequest(msg)
- case msg: SetRecordingStatus => handleSetRecordingStatus(msg)
- case msg: GetRecordingStatus => handleGetRecordingStatus(msg)
- case msg: VoiceRecording => handleVoiceRecording(msg)
-
- case msg: EndMeeting => handleEndMeeting(msg)
- case StopMeetingActor => exit
- case _ => // do nothing
- }
- }
- }
+ case msg: SendWhiteboardAnnotationRequest => handleSendWhiteboardAnnotationRequest(msg)
+ case msg: GetWhiteboardShapesRequest => handleGetWhiteboardShapesRequest(msg)
+ case msg: ClearWhiteboardRequest => handleClearWhiteboardRequest(msg)
+ case msg: UndoWhiteboardRequest => handleUndoWhiteboardRequest(msg)
+ case msg: EnableWhiteboardRequest => handleEnableWhiteboardRequest(msg)
+ case msg: IsWhiteboardEnabledRequest => handleIsWhiteboardEnabledRequest(msg)
+ case msg: SetRecordingStatus => handleSetRecordingStatus(msg)
+ case msg: GetRecordingStatus => handleGetRecordingStatus(msg)
+ case msg: VoiceRecording => handleVoiceRecording(msg)
+
+ case msg: EndMeeting => handleEndMeeting(msg)
+ case StopMeetingActor => exit
+ case _ => // do nothing
+ }
+ }
+ }
def hasMeetingEnded():Boolean = {
meetingEnded
diff --git a/bigbluebutton-apps/src/main/scala/org/bigbluebutton/core/apps/users/UsersApp.scala b/bigbluebutton-apps/src/main/scala/org/bigbluebutton/core/apps/users/UsersApp.scala
index 8fc46abe55..d2dd418892 100644
--- a/bigbluebutton-apps/src/main/scala/org/bigbluebutton/core/apps/users/UsersApp.scala
+++ b/bigbluebutton-apps/src/main/scala/org/bigbluebutton/core/apps/users/UsersApp.scala
@@ -80,9 +80,6 @@ trait UsersApp {
//send the presentation
this ! (new GetPresentationInfo(meetingID, msg.userId, replyTo))
-
- //send the whiteboard
- //this ! (new GetWhiteboardShapesNoIdRequest(meetingID, msg.userId, replyTo))
}
case None => outGW.send(new ValidateAuthTokenReply(meetingID, msg.userId, msg.token, false, msg.correlationId))
}
diff --git a/bigbluebutton-apps/src/main/scala/org/bigbluebutton/core/apps/whiteboard/WhiteboardApp.scala b/bigbluebutton-apps/src/main/scala/org/bigbluebutton/core/apps/whiteboard/WhiteboardApp.scala
index 7de004116e..30f461e8f9 100755
--- a/bigbluebutton-apps/src/main/scala/org/bigbluebutton/core/apps/whiteboard/WhiteboardApp.scala
+++ b/bigbluebutton-apps/src/main/scala/org/bigbluebutton/core/apps/whiteboard/WhiteboardApp.scala
@@ -28,20 +28,20 @@ trait WhiteboardApp {
} else if ((WhiteboardKeyUtil.PENCIL_TYPE == shapeType)
&& (WhiteboardKeyUtil.DRAW_START_STATUS == status)) {
println("Received pencil draw start status")
- wbModel.addAnnotation(wbId, shape)
+ wbModel.addAnnotation(wbId, shape)
} else if ((WhiteboardKeyUtil.DRAW_END_STATUS == status)
&& ((WhiteboardKeyUtil.RECTANGLE_TYPE == shapeType)
|| (WhiteboardKeyUtil.ELLIPSE_TYPE == shapeType)
- || (WhiteboardKeyUtil.TRIANGLE_TYPE == shapeType)
- || (WhiteboardKeyUtil.LINE_TYPE == shapeType))) {
+ || (WhiteboardKeyUtil.TRIANGLE_TYPE == shapeType)
+ || (WhiteboardKeyUtil.LINE_TYPE == shapeType))) {
println("Received [" + shapeType +"] draw end status")
- wbModel.addAnnotation(wbId, shape)
+ wbModel.addAnnotation(wbId, shape)
} else if (WhiteboardKeyUtil.TEXT_TYPE == shapeType) {
- println("Received [" + shapeType +"] modify text status")
- wbModel.modifyText(wbId, shape)
- } else {
- println("Received UNKNOWN whiteboard shape!!!!. status=[" + status + "], shapeType=[" + shapeType + "]")
- }
+ println("Received [" + shapeType +"] modify text status")
+ wbModel.modifyText(wbId, shape)
+ } else {
+ println("Received UNKNOWN whiteboard shape!!!!. status=[" + status + "], shapeType=[" + shapeType + "]")
+ }
wbModel.getWhiteboard(wbId) foreach {wb =>
println("WhiteboardApp::handleSendWhiteboardAnnotationRequest - num shapes [" + wb.shapes.length + "]")
@@ -52,20 +52,20 @@ trait WhiteboardApp {
}
def handleGetWhiteboardShapesRequest(msg: GetWhiteboardShapesRequest) {
- println("WB: Received page history [" + msg.whiteboardId + "]")
+ println("WB: Received page history [" + msg.whiteboardId + "]")
wbModel.history(msg.whiteboardId) foreach {wb =>
outGW.send(new GetWhiteboardShapesReply(meetingID, recorded,
- msg.requesterID, wb.id, wb.shapes.toArray, msg.replyTo))
+ msg.requesterID, wb.id, wb.shapes.toArray, msg.replyTo))
}
- }
-
+ }
+
def handleClearWhiteboardRequest(msg: ClearWhiteboardRequest) {
- println("WB: Received clear whiteboard")
+ println("WB: Received clear whiteboard")
wbModel.clearWhiteboard(msg.whiteboardId)
wbModel.getWhiteboard(msg.whiteboardId) foreach {wb =>
outGW.send(new ClearWhiteboardEvent(meetingID, recorded,
- msg.requesterID, wb.id))
- }
+ msg.requesterID, wb.id))
+ }
}
def handleUndoWhiteboardRequest(msg: UndoWhiteboardRequest) {
diff --git a/bigbluebutton-apps/src/main/webapp/WEB-INF/bbb-app-chat.xml b/bigbluebutton-apps/src/main/webapp/WEB-INF/bbb-app-chat.xml
index f0658c476e..ef1d82c2d6 100755
--- a/bigbluebutton-apps/src/main/webapp/WEB-INF/bbb-app-chat.xml
+++ b/bigbluebutton-apps/src/main/webapp/WEB-INF/bbb-app-chat.xml
@@ -39,5 +39,8 @@ with BigBlueButton; if not, see .
-
+
+
+
+
diff --git a/bigbluebutton-apps/src/main/webapp/WEB-INF/bbb-app-presentation.xml b/bigbluebutton-apps/src/main/webapp/WEB-INF/bbb-app-presentation.xml
index aad204ed66..112a4a2da5 100755
--- a/bigbluebutton-apps/src/main/webapp/WEB-INF/bbb-app-presentation.xml
+++ b/bigbluebutton-apps/src/main/webapp/WEB-INF/bbb-app-presentation.xml
@@ -3,7 +3,7 @@
BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
-Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+Copyright (c) 2014 BigBlueButton Inc. and by respective authors (see below).
This program is free software; you can redistribute it and/or modify it under the
terms of the GNU Lesser General Public License as published by the Free Software
@@ -51,12 +51,4 @@ with BigBlueButton; if not, see .
-
-
-
-
-
-
-
-
diff --git a/bigbluebutton-apps/src/main/webapp/WEB-INF/bbb-app-users.xml b/bigbluebutton-apps/src/main/webapp/WEB-INF/bbb-app-users.xml
index 0e8e62847c..a3eb650373 100755
--- a/bigbluebutton-apps/src/main/webapp/WEB-INF/bbb-app-users.xml
+++ b/bigbluebutton-apps/src/main/webapp/WEB-INF/bbb-app-users.xml
@@ -3,7 +3,7 @@
BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
-Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+Copyright (c) 2014 BigBlueButton Inc. and by respective authors (see below).
This program is free software; you can redistribute it and/or modify it under the
terms of the GNU Lesser General Public License as published by the Free Software
@@ -26,7 +26,7 @@ with BigBlueButton; if not, see .
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-2.0.xsd
">
-
+
@@ -38,5 +38,8 @@ with BigBlueButton; if not, see .
-
+
+
+
+
diff --git a/bigbluebutton-apps/src/main/webapp/WEB-INF/bbb-app-whiteboard.xml b/bigbluebutton-apps/src/main/webapp/WEB-INF/bbb-app-whiteboard.xml
index 8c426036f8..adcfb71c3a 100755
--- a/bigbluebutton-apps/src/main/webapp/WEB-INF/bbb-app-whiteboard.xml
+++ b/bigbluebutton-apps/src/main/webapp/WEB-INF/bbb-app-whiteboard.xml
@@ -3,7 +3,7 @@
BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
-Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+Copyright (c) 2014 BigBlueButton Inc. and by respective authors (see below).
This program is free software; you can redistribute it and/or modify it under the
terms of the GNU Lesser General Public License as published by the Free Software
@@ -26,13 +26,17 @@ with BigBlueButton; if not, see .
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-2.0.xsd
">
-
+
-
+
-
+
-
+
+
+
+
+
diff --git a/bigbluebutton-apps/src/main/webapp/WEB-INF/bbb-redis-messaging.xml b/bigbluebutton-apps/src/main/webapp/WEB-INF/bbb-redis-messaging.xml
index 47504b0d9f..36432b3644 100755
--- a/bigbluebutton-apps/src/main/webapp/WEB-INF/bbb-redis-messaging.xml
+++ b/bigbluebutton-apps/src/main/webapp/WEB-INF/bbb-redis-messaging.xml
@@ -3,7 +3,7 @@
BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
-Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+Copyright (c) 2014 BigBlueButton Inc. and by respective authors (see below).
This program is free software; you can redistribute it and/or modify it under the
terms of the GNU Lesser General Public License as published by the Free Software
@@ -26,35 +26,35 @@ with BigBlueButton; if not, see .
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-2.0.xsd
">
-
-
+
-
-
+
+
-
-
-
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/client/bbb-html5-client/config.coffee b/client/bbb-html5-client/config.coffee
index 416d181cfc..210cdfbec6 100755
--- a/client/bbb-html5-client/config.coffee
+++ b/client/bbb-html5-client/config.coffee
@@ -33,6 +33,7 @@ config.redis.channels.toBBBApps.pattern = "bigbluebutton:to-bbb-apps:*"
config.redis.channels.toBBBApps.chat = "bigbluebutton:to-bbb-apps:chat"
config.redis.channels.toBBBApps.meeting = "bigbluebutton:to-bbb-apps:meeting"
config.redis.channels.toBBBApps.users = "bigbluebutton:to-bbb-apps:users"
+config.redis.channels.toBBBApps.whiteboard = "bigbluebutton:to-bbb-apps:whiteboard"
config.redis.internalChannels = {}
config.redis.internalChannels.receive = "html5-receive"
config.redis.internalChannels.reply = "html5-reply"
diff --git a/client/bbb-html5-client/lib/redispubsub.coffee b/client/bbb-html5-client/lib/redispubsub.coffee
index 1c969805b8..c8e007f391 100644
--- a/client/bbb-html5-client/lib/redispubsub.coffee
+++ b/client/bbb-html5-client/lib/redispubsub.coffee
@@ -97,6 +97,7 @@ module.exports = class RedisPubSub
if message.header?.name is 'get_presentation_info_reply'
#filter for the current=true page on the server-side
currentPage = null
+ numCurrentPage = null
presentations = message.payload?.presentations
for presentation in presentations
@@ -105,6 +106,23 @@ module.exports = class RedisPubSub
for page in pages
if page.current is true
currentPage = page
+ numCurrentPage = page.num
+
+ console.log "\n\n\n\n the message is: " + JSON.stringify message
+ console.log "\n" + message.payload?.presentations[0]?.id + "/" + numCurrentPage + "\n\n"
+ #request the whiteboard information
+ requestMessage = {
+ "payload": {
+ "meeting_id": message.payload?.meeting_id
+ "requester_id": message.payload?.requester_id
+ "whiteboard_id": message.payload?.presentations[0]?.id + "/" + numCurrentPage #not sure if always [0]
+ },
+ "header": {
+ "timestamp": new Date().getTime()
+ "name": "get_whiteboard_shapes_request"
+ }
+ }
+ @publishing(config.redis.channels.toBBBApps.whiteboard, requestMessage)
#strip off excess data, leaving only the current slide information
message.payload.currentPage = currentPage
diff --git a/client/bbb-html5-client/public/js/collections/users.coffee b/client/bbb-html5-client/public/js/collections/users.coffee
index e7f9a22016..9716ade8bd 100755
--- a/client/bbb-html5-client/public/js/collections/users.coffee
+++ b/client/bbb-html5-client/public/js/collections/users.coffee
@@ -5,7 +5,6 @@ define [
'cs!models/user'
], (_, Backbone, globals, UserModel) ->
- # TODO: this class should actually store UserModel's, for now it is only trigerring events
UsersCollection = Backbone.Collection.extend
model: UserModel
diff --git a/client/bbb-html5-client/public/js/models/connection.coffee b/client/bbb-html5-client/public/js/models/connection.coffee
index e6279d276e..165deecbb2 100755
--- a/client/bbb-html5-client/public/js/models/connection.coffee
+++ b/client/bbb-html5-client/public/js/models/connection.coffee
@@ -19,12 +19,8 @@ define [
@username = @getUrlVars()["username"]
globals.meetingName = decodeURI(@getUrlVars()["meetingName"])
- disconnect: =>
- alert( " i go through disconnect")
- if @socket?
- #@socket.disconnect()
- else
- console.log "tried to disconnect but it's not connected"
+ disconnect: ->
+ alert( " i go through disconnect") # not used right now
connect: ->
console.log("user_id=" + @userId + " auth_token=" + @authToken + " meeting_id=" + @meetingId)
@@ -58,12 +54,10 @@ define [
console.log "socket.io received: data"
globals.events.trigger("message", data)
-
# Immediately say we are connected
@socket.on "connect", =>
console.log "socket on: connect"
globals.events.trigger("connection:connected")
- #@socket.emit "user connect" # tell the server we have a new user
message = {
"payload": {
@@ -81,9 +75,11 @@ define [
if @authToken? and @userId? and @meetingId?
@socket.emit "message", message
+ # Received a list of users from bbb-apps
+ # param {object} message object
@socket.on "get_users_reply", (message) =>
requesterId = message.payload?.requester_id
-
+
if(requesterId is @userId)
users = []
for user in message.payload?.users
@@ -91,6 +87,8 @@ define [
globals.events.trigger("connection:load_users", users)
+ # Received a the chat history for a meeting
+ # @param {object} message object
@socket.on "get_chat_history_reply", (message) =>
requesterId = message.payload?.requester_id
if(requesterId is @userId)
@@ -111,83 +109,91 @@ define [
globals.events.trigger("connection:disconnected")
@socket = null
- @socket.on "reconnect", ->
- console.log "socket on: reconnect"
- globals.events.trigger("connection:reconnect")
+ #@socket.on "reconnect", ->
+ # console.log "socket on: reconnect"
+ # globals.events.trigger("connection:reconnect")
- @socket.on "reconnecting", ->
- console.log "socket on: reconnecting"
- globals.events.trigger("connection:reconnecting")
+ #@socket.on "reconnecting", ->
+ # console.log "socket on: reconnecting"
+ # globals.events.trigger("connection:reconnecting")
- @socket.on "reconnect_failed", ->
- console.log "socket on: reconnect_failed"
- globals.events.trigger("connection:reconnect_failed")
+ #@socket.on "reconnect_failed", ->
+ # console.log "socket on: reconnect_failed"
+ # globals.events.trigger("connection:reconnect_failed")
# If an error occurs while not connected
# @param {string} reason Reason for the error.
- @socket.on "error", (reason) ->
- console.error "unable to connect socket.io", reason
+ #@socket.on "error", (reason) -> #TODO
+ # console.error "unable to connect socket.io", reason
# Received event to update all the slide images
# @param {Array} urls list of URLs to be added to the paper (after old images are removed)
- @socket.on "all_slides", (allSlidesEventObject) =>
- console.log "socket on: all_slides"
- console.log "allSlidesEventObject: " + allSlidesEventObject
- globals.events.trigger("connection:all_slides", allSlidesEventObject);
+ #@socket.on "all_slides", (allSlidesEventObject) =>
+ # console.log "socket on: all_slides"
+ # console.log "allSlidesEventObject: " + allSlidesEventObject
+ # globals.events.trigger("connection:all_slides", allSlidesEventObject);
# Received event to clear the whiteboard shapes
- @socket.on "clrPaper",=>
- console.log "socket on: clrPaper"
- globals.events.trigger("connection:clrPaper")
+ #@socket.on "clrPaper",=>
+ # console.log "socket on: clrPaper"
+ # globals.events.trigger("connection:clrPaper")
# Received event to update all the shapes in the whiteboard
# @param {Array} shapes Array of shapes to be drawn
- @socket.on "allShapes", (allShapesEventObject) =>
- console.log "socket on: all_shapes" + allShapesEventObject
- globals.events.trigger("connection:all_shapes", allShapesEventObject)
+ #@socket.on "allShapes", (allShapesEventObject) =>
+ # # check for the requester_id
+ # console.log "socket on: all_shapes" + allShapesEventObject
+ # globals.events.trigger("connection:all_shapes", allShapesEventObject)
+
+ # Received event to update all the shapes in the whiteboard
+ # @param {Array} shapes Array of shapes to be drawn
+ #@socket.on "get_whiteboard_shapes_reply", (object) =>
+ # if @userId is object.payload?.requester_id
+ # #alert("I am getting some shapes reply" + JSON.stringify object)
+ # for shape in object.payload?.shapes
+ # #alert("for a shape:")
+ # shape_type = shape.shape_type
+ # globals.events.trigger("connection:whiteboard_draw_event", shape_type, shape.shape) # TODO to change the name
+
+ # globals.events.trigger("connection:updShape", shape_type, shape.shape)
# Received event to update a shape being created
# @param {string} shape type of shape being updated
# @param {Array} data all information to update the shape
- @socket.on "whiteboard_update_event", (data) =>
- console.log "socket on: whiteboard_update_event"
- shape = data.payload.shape_type
+ @socket.on "send_whiteboard_shape_message", (data) =>
+ alert "send_whiteboard_shape_message" + JSON.stringify data
+ shape = data.payload.shape.shape_type
+ for point in data.payload.shape.shape.points
+ point = point/100 #early attempt to scale down
+ globals.events.trigger("connection:whiteboard_draw_event", shape, data)
globals.events.trigger("connection:updShape", shape, data)
- # Received event to create a shape on the whiteboard
- # @param {string} shape type of shape being made
- # @param {Array} data all information to make the shape
- @socket.on "whiteboard_draw_event", (data) =>
- console.log "socket on: whiteboard_draw_event"
- shape = data.payload.shape_type
- globals.events.trigger("connection:whiteboard_draw_event", shape, data)
-
# Pencil drawings are received as points from the server and painted as lines.
- @socket.on "whiteboardDrawPen", (data) =>
- console.log "socket on: whiteboardDrawPen"+ data
- globals.events.trigger("connection:whiteboardDrawPen", data)
+ #@socket.on "whiteboardDrawPen", (data) =>
+ # console.log "socket on: whiteboardDrawPen"+ data
+ # globals.events.trigger("connection:whiteboardDrawPen", data)
# Received event to update the cursor coordinates
# @param {number} x x-coord of the cursor as a percentage of page width
# @param {number} y y-coord of the cursor as a percentage of page height
- @socket.on "mvCur", (data) =>
- x = data.cursor.x #TODO change to new json structure
- y = data.cursor.y #TODO change to new json structure
- console.log "socket on: mvCur"
- globals.events.trigger("connection:mvCur", x, y)
+ #@socket.on "mvCur", (data) =>
+ # x = data.cursor.x #TODO change to new json structure
+ # y = data.cursor.y #TODO change to new json structure
+ # console.log "socket on: mvCur"
+ # globals.events.trigger("connection:mvCur", x, y)
# Received event to update the zoom or move the slide
# @param {number} x x-coord of the cursor as a percentage of page width
# @param {number} y y-coord of the cursor as a percentage of page height
- @socket.on "move_and_zoom", (xOffset, yOffset, widthRatio, heightRatio) =>
- console.log "socket on: move_and_zoom"
- globals.events.trigger("connection:move_and_zoom", xOffset, yOffset, widthRatio, heightRatio)
+ #@socket.on "move_and_zoom", (xOffset, yOffset, widthRatio, heightRatio) =>
+ # console.log "socket on: move_and_zoom"
+ # globals.events.trigger("connection:move_and_zoom", xOffset, yOffset, widthRatio, heightRatio)
# Received event to update the slide image
# @param {string} url URL of image to show
- @socket.on "changeslide", (url) =>
- console.log "socket on: changeslide"
- globals.events.trigger("connection:changeslide", url)
+ #@socket.on "changeslide", (url) =>
+ # console.log "socket on: changeslide"
+ # globals.events.trigger("connection:changeslide", url)
# Received event to update the viewBox value
# @param {string} xperc Percentage of x-offset from top left corner
@@ -195,50 +201,50 @@ define [
# @param {string} wperc Percentage of full width of image to be displayed
# @param {string} hperc Percentage of full height of image to be displayed
# TODO: not tested yet
- @socket.on "viewBox", (xperc, yperc, wperc, hperc) =>
- console.log "socket on: viewBox"
- globals.events.trigger("connection:viewBox", xperc, yperc, wperc, hperc)
+ #@socket.on "viewBox", (xperc, yperc, wperc, hperc) =>
+ # console.log "socket on: viewBox"
+ # globals.events.trigger("connection:viewBox", xperc, yperc, wperc, hperc)
# Received event to update the zoom level of the whiteboard.
# @param {number} delta amount of change in scroll wheel
- @socket.on "zoom", (delta) ->
- console.log "socket on: zoom"
- globals.events.trigger("connection:zoom", delta)
+ #@socket.on "zoom", (delta) ->
+ # console.log "socket on: zoom"
+ # globals.events.trigger("connection:zoom", delta)
# Received event to update the whiteboard size and position
# @param {number} cx x-offset from top left corner as percentage of original width of paper
# @param {number} cy y-offset from top left corner as percentage of original height of paper
# @param {number} sw slide width as percentage of original width of paper
# @param {number} sh slide height as a percentage of original height of paper
- @socket.on "paper", (cx, cy, sw, sh) ->
- console.log "socket on: paper"
- globals.events.trigger("connection:paper", cx, cy, sw, sh)
+ #@socket.on "paper", (cx, cy, sw, sh) ->
+ # console.log "socket on: paper"
+ # globals.events.trigger("connection:paper", cx, cy, sw, sh)
# Received event when the panning action finishes
- @socket.on "panStop", ->
- console.log "socket on: panStop"
- globals.events.trigger("connection:panStop")
+ #@socket.on "panStop", ->
+ # console.log "socket on: panStop"
+ # globals.events.trigger("connection:panStop")
# Received event to denote when the text has been created
- @socket.on "textDone", ->
- console.log "socket on: textDone"
- globals.events.trigger("connection:textDone")
+ #@socket.on "textDone", ->
+ # console.log "socket on: textDone"
+ # globals.events.trigger("connection:textDone")
# Received event to update the status of the upload progress
# @param {string} message update message of status of upload progress
# @param {boolean} fade true if you wish the message to automatically disappear after 3 seconds
- @socket.on "uploadStatus", (message, fade) =>
- console.log "socket on: uploadStatus"
- globals.events.trigger("connection:uploadStatus", message, fade)
+ #@socket.on "uploadStatus", (message, fade) =>
+ # console.log "socket on: uploadStatus"
+ # globals.events.trigger("connection:uploadStatus", message, fade)
# Received event for a user list change
# @param {Array} users Array of names and publicIDs of connected users
# TODO: event name with spaces is bad
- @socket.on "user list change", (users) =>
- console.log "socket on: user list change"
- globals.events.trigger("connection:user_list_change", users)
+ #@socket.on "user list change", (users) =>
+ # console.log "socket on: user list change"
+ # globals.events.trigger("connection:user_list_change", users)
# Received event for a new user
@socket.on "user_joined_message", (message) =>
@@ -253,9 +259,9 @@ define [
# Received event to set the presenter to a user
# @param {string} userID publicID of the user that is being set as the current presenter
- @socket.on "setPresenter", (userid) =>
- console.log "socket on: setPresenter"
- globals.events.trigger("connection:setPresenter", userid)
+ #@socket.on "setPresenter", (userid) =>
+ # console.log "socket on: setPresenter"
+ # globals.events.trigger("connection:setPresenter", userid)
# Received event to update all the messages in the chat box
# @param {Array} messages Array of messages in public chat box
@@ -276,16 +282,12 @@ define [
@socket.emit "mvCur", x, y
# Requests the shapes from the server.
- emitAllShapes: ->
- @socket.emit "all_shapes"
+ #emitAllShapes: ->
+ # @socket.emit "all_shapes"
-
- # Emit a message to the server
- # @param {string} the message
+ # Emit a chat message to the server
+ # @param {string} the chat message
emitMsg: (msg) ->
-
- console.log "emitting message: " + msg
-
object = {
"header": {
"name": "send_public_chat_message"
@@ -312,28 +314,28 @@ define [
@socket.emit "message", object
# Emit the finish of a text shape
- emitTextDone: ->
- @socket.emit "textDone"
+ #emitTextDone: ->
+ # @socket.emit "textDone"
# Emit the creation of a shape
# @param {string} shape type of shape
# @param {Array} data all the data required to draw the shape on the client whiteboard
- emitMakeShape: (shape, data) ->
- @socket.emit "makeShape", shape, data
+ #emitMakeShape: (shape, data) ->
+ # @socket.emit "makeShape", shape, data
# Emit the update of a shape
# @param {string} shape type of shape
# @param {Array} data all the data required to update the shape on the client whiteboard
- emitUpdateShape: (shape, data) ->
- @socket.emit "updShape", shape, data
+ #emitUpdateShape: (shape, data) ->
+ # @socket.emit "updShape", shape, data
# Emit an update in the whiteboard position/size values
# @param {number} cx x-offset from top left corner as percentage of original width of paper
# @param {number} cy y-offset from top left corner as percentage of original height of paper
# @param {number} sw slide width as percentage of original width of paper
# @param {number} sh slide height as a percentage of original height of paper
- emitPaperUpdate: (cx, cy, sw, sh) ->
- @socket.emit "paper", cx, cy, sw, sh
+ #emitPaperUpdate: (cx, cy, sw, sh) ->
+ # @socket.emit "paper", cx, cy, sw, sh
# Update the zoom level for the clients
# @param {number} delta amount of change in scroll wheel
@@ -341,12 +343,12 @@ define [
@socket.emit "zoom", delta
# Request the next slide
- emitNextSlide: ->
- @socket.emit "nextslide"
+ #emitNextSlide: ->
+ # @socket.emit "nextslide"
# Request the previous slide
- emitPreviousSlide: ->
- @socket.emit "prevslide"
+ #emitPreviousSlide: ->
+ # @socket.emit "prevslide"
# Logout of the meeting
emitLogout: ->
@@ -363,37 +365,36 @@ define [
}
@socket.emit "message", message
@socket.disconnect()
- #@disconnect()
-
+
#Utils.postToUrl "logout"
#window.location.replace "./"
# Emit panning has stopped
- emitPanStop: ->
- @socket.emit "panStop"
+ #emitPanStop: ->
+ # @socket.emit "panStop"
# Publish a shape to the server to be saved
# @param {string} shape type of shape to be saved
# @param {Array} data information about shape so that it can be recreated later
- emitPublishShape: (shape, data) ->
- @socket.emit "saveShape", shape, JSON.stringify(data)
+ #emitPublishShape: (shape, data) ->
+ # @socket.emit "saveShape", shape, JSON.stringify(data)
# Emit a change in the current tool
# @param {string} tool [description]
- emitChangeTool: (tool) ->
- @socket.emit "changeTool", tool
+ #emitChangeTool: (tool) ->
+ # @socket.emit "changeTool", tool
# Tell the server to undo the last shape
- emitUndo: ->
- @socket.emit "undo"
+ #emitUndo: ->
+ # @socket.emit "undo"
# Emit a change in the presenter
- emitSetPresenter: (id) ->
- @socket.emit "setPresenter", id
+ #emitSetPresenter: (id) ->
+ # @socket.emit "setPresenter", id
# Emit signal to clear the canvas
- emitClearCanvas: (id) ->
- @socket.emit "clrPaper", id
+ #emitClearCanvas: (id) ->
+ # @socket.emit "clrPaper", id
# Helper method to get the meeting_id, user_id and auth_token from the url
getUrlVars: ->
diff --git a/client/bbb-html5-client/public/js/models/whiteboard_paper.coffee b/client/bbb-html5-client/public/js/models/whiteboard_paper.coffee
index 16a1c36f76..ecbf2255e6 100755
--- a/client/bbb-html5-client/public/js/models/whiteboard_paper.coffee
+++ b/client/bbb-html5-client/public/js/models/whiteboard_paper.coffee
@@ -23,6 +23,7 @@ define [
# Container must be a DOM element
initialize: (@container) ->
+ alert("initializing the paper model")
# a WhiteboardCursorModel
@cursor = null
@@ -278,7 +279,7 @@ define [
@cursor.undrag()
@currentLine = @_createTool(tool)
@cursor.drag(@currentLine.dragOnMove, @currentLine.dragOnStart, @currentLine.dragOnEnd)
- when "rect"
+ when "rectangle"
@cursor.undrag()
@currentRect = @_createTool(tool)
@cursor.drag(@currentRect.dragOnMove, @currentRect.dragOnStart, @currentRect.dragOnEnd)
@@ -351,6 +352,7 @@ define [
# Draws an array of shapes to the paper.
# @param {array} shapes the array of shapes to draw
drawListOfShapes: (shapes) ->
+ alert("drawListOfShapes" + shapes.length)
@currentShapesDefinitions = shapes
@currentShapes = @raphaelObj.set()
for shape in shapes
@@ -392,6 +394,7 @@ define [
# Make a shape `shape` with the data in `data`.
makeShape: (shape, data) ->
+ console.log("shape=" + shape + " data=" + JSON.stringify data)
tool = null
switch shape
when "path", "line"
@@ -409,6 +412,7 @@ define [
when "triangle"
@currentTriangle = @_createTool(shape)
toolModel = @currentTriangle
+ toolModel.draw(tool, data)
tool = @currentTriangle.make(data)
when "text"
@currentText = @_createTool(shape)
@@ -417,7 +421,12 @@ define [
else
console.log "shape not recognized at makeShape", shape
if tool?
- @currentShapes.push(tool)
+ alert("in currentShapes")
+ if @currentShapes? #rewrite TODO
+ @currentShapes.push(tool)
+ else
+ @currentShapes = []
+ @currentShapes.push(tool)
@currentShapesDefinitions.push(toolModel.getDefinition())
# Update the cursor position on screen
@@ -515,6 +524,7 @@ define [
globals.events.on "connection:allShapes", (allShapesEventObject) =>
# TODO: a hackish trick for making compatible the shapes from redis with the node.js
+ alert("on connection:allShapes:" + JSON.stringify allShapesEventObject)
shapes = allShapesEventObject.shapes
for shape in shapes
properties = JSON.parse(shape.data)
diff --git a/client/bbb-html5-client/public/js/models/whiteboard_rect.coffee b/client/bbb-html5-client/public/js/models/whiteboard_rect.coffee
index bc27f797da..d66cc99ea6 100644
--- a/client/bbb-html5-client/public/js/models/whiteboard_rect.coffee
+++ b/client/bbb-html5-client/public/js/models/whiteboard_rect.coffee
@@ -24,16 +24,16 @@ define [
# @param {string} colour the colour of the object
# @param {number} thickness the thickness of the object's line(s)
make: (startingData) ->
- console.log "make startingData"+ startingData
- x = startingData.payload.data.coordinate.first_x
- y = startingData.payload.data.coordinate.first_y
- color = startingData.payload.data.line.color
- thickness = startingData.payload.data.line.weight
+ console.log "make startingData"#+ JSON.stringify startingData
+ x = startingData.payload.shape.shape.points[0]
+ y = startingData.payload.shape.shape.points[1]
+ color = startingData.payload.shape.shape.color
+ thickness = startingData.payload.shape.shape.thickness
@obj = @paper.rect(x * @gw + @xOffset, y * @gh + @yOffset, 0, 0, 1)
@obj.attr Utils.strokeAndThickness(color, thickness)
@definition =
- shape: "rect"
+ shape: "rectangle"
data: [x, y, 0, 0, @obj.attrs["stroke"], @obj.attrs["stroke-width"]]
@obj
@@ -44,11 +44,11 @@ define [
# @param {number} y2 the y value of the bottom right corner
# @param {boolean} square (draw a square or not)
update: (startingData) ->
- x1 = startingData.payload.data.coordinate.first_x
- y1 = startingData.payload.data.coordinate.first_y
- x2 = startingData.payload.data.coordinate.last_x
- y2 = startingData.payload.data.coordinate.last_y
- square = startingData.payload.data.square
+ x1 = startingData.payload.shape.shape.points[0]
+ y1 = startingData.payload.shape.shape.points[1]
+ x2 = startingData.payload.shape.shape.points[2]
+ y2 = startingData.payload.shape.shape.points[3]
+ square = startingData.payload.shape.shape.square
if @obj?
[x1, x2] = [x2, x1] if x2 < x1
[x1, x2] = [x2, x1] if x2 < x1
diff --git a/client/bbb-html5-client/public/js/views/session_users.coffee b/client/bbb-html5-client/public/js/views/session_users.coffee
index f6b245e194..7209b2993d 100755
--- a/client/bbb-html5-client/public/js/views/session_users.coffee
+++ b/client/bbb-html5-client/public/js/views/session_users.coffee
@@ -72,8 +72,6 @@ define [
# Removes all a user from the list #TODO - for now it does not remove but moves to the left hand side
_removeUserByID: (userID)->
@$("#user-"+userID).remove()
- #@$("#user-"+userID).parent().context.hidden = "true"
- #console.log @$el.children("ul")
# Marks a user as selected when clicked.
_userClicked: (e) ->
diff --git a/client/bbb-html5-client/public/templates/user.html b/client/bbb-html5-client/public/templates/user.html
index 796c1bf1c6..816a12d461 100644
--- a/client/bbb-html5-client/public/templates/user.html
+++ b/client/bbb-html5-client/public/templates/user.html
@@ -1,10 +1,10 @@
-
-
-
-
<%= username %>
-
-
-
-
-
-
+
+
+
+
<%= username %>
+
+
+
+
+
+
\ No newline at end of file
diff --git a/labs/bbb-api-php/includes/bbb-api.php b/labs/bbb-api-php/includes/bbb-api.php
index 53b791ec23..311a7e7201 100644
--- a/labs/bbb-api-php/includes/bbb-api.php
+++ b/labs/bbb-api-php/includes/bbb-api.php
@@ -36,6 +36,8 @@ Versions:
- Now using Zend coding, naming and style conventions
- Refactored methods to accept standardized parameters & match BBB API structure
-- See included samples for usage examples
+ 1.4 -- Updated by xaker1
+ (email : admin [a t ] xaker1 DOT ru)
*/
/* _______________________________________________________________________*/
@@ -60,7 +62,7 @@ class BigBlueButton {
$this->_bbbServerBaseUrl = CONFIG_SERVER_BASE_URL;
}
- private function _processXmlResponse($url){
+ private function _processXmlResponse($url, $xml = ''){
/*
A private utility method used by other public methods to process XML responses.
*/
@@ -71,6 +73,16 @@ class BigBlueButton {
curl_setopt( $ch, CURLOPT_URL, $url );
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 );
curl_setopt( $ch, CURLOPT_CONNECTTIMEOUT, $timeout);
+ if(!empty($xml)){
+ curl_setopt($ch, CURLOPT_HEADER, 0);
+ curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
+ curl_setopt($ch, CURLOPT_POST, 1);
+ curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
+ curl_setopt($ch, CURLOPT_HTTPHEADER, array(
+ 'Content-type: application/xml',
+ 'Content-length: ' . strlen($xml)
+ ));
+ }
$data = curl_exec( $ch );
curl_close( $ch );
@@ -79,10 +91,13 @@ class BigBlueButton {
else
return false;
}
+ if(!empty($xml))
+ throw new Exception('Set xml, but curl does not installed.');
+
return (simplexml_load_file($url));
}
- private function _requiredParam($param) {
+ private function _requiredParam($param, $name = '') {
/* Process required params and throw errors if we don't get values */
if ((isset($param)) && ($param != '')) {
return $param;
@@ -91,7 +106,7 @@ class BigBlueButton {
throw new Exception('Missing parameter.');
}
else {
- throw new Exception(''.$param.' is required.');
+ throw new Exception(''.$name.' is required.');
}
}
@@ -119,8 +134,8 @@ class BigBlueButton {
USAGE:
(see $creationParams array in createMeetingArray method.)
*/
- $this->_meetingId = $this->_requiredParam($creationParams['meetingId']);
- $this->_meetingName = $this->_requiredParam($creationParams['meetingName']);
+ $this->_meetingId = $this->_requiredParam($creationParams['meetingId'], 'meetingId');
+ $this->_meetingName = $this->_requiredParam($creationParams['meetingName'], 'meetingName');
// Set up the basic creation URL:
$creationUrl = $this->_bbbServerBaseUrl."api/create?";
// Add params:
@@ -144,7 +159,7 @@ class BigBlueButton {
return ( $creationUrl.$params.'&checksum='.sha1("create".$params.$this->_securitySalt) );
}
- public function createMeetingWithXmlResponseArray($creationParams) {
+ public function createMeetingWithXmlResponseArray($creationParams, $xml = '') {
/*
USAGE:
$creationParams = array(
@@ -162,8 +177,9 @@ class BigBlueButton {
'duration' => '0', -- Default = 0 which means no set duration in minutes. [number]
'meta_category' => '', -- Use to pass additional info to BBB server. See API docs to enable.
);
+ $xml = ''; -- Use to pass additional xml to BBB server. Example, use to Preupload Slides. See API docs.
*/
- $xml = $this->_processXmlResponse($this->getCreateMeetingURL($creationParams));
+ $xml = $this->_processXmlResponse($this->getCreateMeetingURL($creationParams), $xml);
if($xml) {
if($xml->meetingID)
@@ -204,9 +220,9 @@ class BigBlueButton {
'webVoiceConf' => '' -- OPTIONAL - string
);
*/
- $this->_meetingId = $this->_requiredParam($joinParams['meetingId']);
- $this->_username = $this->_requiredParam($joinParams['username']);
- $this->_password = $this->_requiredParam($joinParams['password']);
+ $this->_meetingId = $this->_requiredParam($joinParams['meetingId'], 'meetingId');
+ $this->_username = $this->_requiredParam($joinParams['username'], 'username');
+ $this->_password = $this->_requiredParam($joinParams['password'], 'password');
// Establish the basic join URL:
$joinUrl = $this->_bbbServerBaseUrl."api/join?";
// Add parameters to the URL:
@@ -231,8 +247,8 @@ class BigBlueButton {
'password' => 'mp' -- REQUIRED - The moderator password for the meeting
);
*/
- $this->_meetingId = $this->_requiredParam($endParams['meetingId']);
- $this->_password = $this->_requiredParam($endParams['password']);
+ $this->_meetingId = $this->_requiredParam($endParams['meetingId'], 'meetingId');
+ $this->_password = $this->_requiredParam($endParams['password'], 'password');
$endUrl = $this->_bbbServerBaseUrl."api/end?";
$params =
'meetingID='.urlencode($this->_meetingId).
@@ -272,7 +288,7 @@ class BigBlueButton {
/* USAGE:
$meetingId = '1234' -- REQUIRED - The unique id for the meeting
*/
- $this->_meetingId = $this->_requiredParam($meetingId);
+ $this->_meetingId = $this->_requiredParam($meetingId, 'meetingId');
$runningUrl = $this->_bbbServerBaseUrl."api/isMeetingRunning?";
$params =
'meetingID='.urlencode($this->_meetingId);
@@ -363,8 +379,8 @@ class BigBlueButton {
'password' => 'mp' -- REQUIRED - The moderator password for the meeting
);
*/
- $this->_meetingId = $this->_requiredParam($infoParams['meetingId']);
- $this->_password = $this->_requiredParam($infoParams['password']);
+ $this->_meetingId = $this->_requiredParam($infoParams['meetingId'], 'meetingId');
+ $this->_password = $this->_requiredParam($infoParams['password'], 'password');
$infoUrl = $this->_bbbServerBaseUrl."api/getMeetingInfo?";
$params =
'meetingID='.urlencode($this->_meetingId).
diff --git a/labs/demos/.gitignore b/labs/demos/.gitignore
new file mode 100644
index 0000000000..3c3629e647
--- /dev/null
+++ b/labs/demos/.gitignore
@@ -0,0 +1 @@
+node_modules
diff --git a/labs/demos/config.json b/labs/demos/config.json
index 1ffa20f1fa..fc20efda85 100644
--- a/labs/demos/config.json
+++ b/labs/demos/config.json
@@ -1,7 +1,7 @@
{
"settings": {
- "IP": "http://192.168.0.203",
+ "IP": "http://192.168.0.232",
"PORT": "4000",
- "salt": "74a91f30f165423067bf3039722e33e0"
+ "salt": "c7faeb82a786bd71134b61833b0ec4af"
}
-}
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/labs/demos/lib/handlers.coffee b/labs/demos/lib/handlers.coffee
index 7616127ab4..11c204d3d9 100755
--- a/labs/demos/lib/handlers.coffee
+++ b/labs/demos/lib/handlers.coffee
@@ -20,6 +20,8 @@ login = (req, resp) ->
#calling createapi
bbbapi.create(createParams, serverAndSecret, {}, (errorOuter, responseOuter, bodyOuter) ->
#console.log JSON.stringify(response)
+ console.log "\n\nouterXML=" + responseOuter.body
+ console.log "\nerrorOuter=" + JSON.stringify errorOuter
bbbapi.join(joinParams, serverAndSecret, {}, (error, response, body) ->
if error
console.log error
@@ -39,7 +41,7 @@ login = (req, resp) ->
"\nuser_id = " + user_id +
"\nauth_token = " + auth_token
- url = "#{configJson.settings.IP}:3000/html5.client?meeting_id=" + meeting_id + "&user_id=" +
+ url = "#{configJson.settings.IP}:3000/meeting_id=" + meeting_id + "&user_id=" +
user_id + "&auth_token=" + auth_token + "&username=" + joinParams.fullName + "&meetingName=" + joinParams.meetingID
json =
diff --git a/labs/demos/lib/testapi.coffee b/labs/demos/lib/testapi.coffee
index 664f9223df..7e5b0cff1a 100644
--- a/labs/demos/lib/testapi.coffee
+++ b/labs/demos/lib/testapi.coffee
@@ -17,13 +17,13 @@ createParams.attendeePW = "ap"
createParams.moderatorPW = "mp"
createParams.record = false
createParams.voiceBridge = 70827
-createParams.name = "Demo Meeting"
-createParams.meetingID = "Demo Meeting"
+createParams.name = "Demo Meeting9"
+createParams.meetingID = "Demo Meeting9"
joinParams = {}
joinParams.password = "mp"
joinParams.fullName = "Richard"
-joinParams.meetingID = "Demo Meeting"
+joinParams.meetingID = "Demo Meeting9"
joinParams.redirect = false
serverAndSecret = {server: bbbServer, secret: sharedSecret}
diff --git a/labs/meteor-client/.gitignore b/labs/meteor-client/.gitignore
new file mode 100644
index 0000000000..f9ced93c2f
--- /dev/null
+++ b/labs/meteor-client/.gitignore
@@ -0,0 +1 @@
+packages
diff --git a/labs/meteor-client/.meteor/packages b/labs/meteor-client/.meteor/packages
index 6026737d9e..5a8dc1445f 100644
--- a/labs/meteor-client/.meteor/packages
+++ b/labs/meteor-client/.meteor/packages
@@ -6,8 +6,11 @@
standard-app-packages
autopublish
insecure
-bootstrap
-less
coffeescript
+redis
+npm
+less
bootstrap-3
iron-router
+router
+bootstrap
diff --git a/labs/meteor-client/client/routing.coffee b/labs/meteor-client/client/routing.coffee
deleted file mode 100755
index 842ef9a0ef..0000000000
--- a/labs/meteor-client/client/routing.coffee
+++ /dev/null
@@ -1,8 +0,0 @@
-Meteor.navigateTo = (path) ->
- Router.go path
-
-Router.configure layoutTemplate: 'layout'
-
-Router.map ->
- @route 'main',
- path: '/'
\ No newline at end of file
diff --git a/labs/meteor-client/collections/users.js b/labs/meteor-client/collections/users.js
index 5ce37294d9..02af2f7c5f 100755
--- a/labs/meteor-client/collections/users.js
+++ b/labs/meteor-client/collections/users.js
@@ -23,5 +23,10 @@ Meteor.methods({
},
showUserId: function() {
throw new Meteor.Error(422, this.userId);
+ },
+ addToCollection: function(userid, meeting_id) {
+ var user = {userId: userid, meetingId: meeting_id};
+ var userId = Meteor.users.insert(user);
+ console.log("added user id=[" + userId + "] :" + JSON.stringify(user));
}
});
\ No newline at end of file
diff --git a/labs/meteor-client/config.coffee b/labs/meteor-client/config.coffee
new file mode 100644
index 0000000000..314e8d88b5
--- /dev/null
+++ b/labs/meteor-client/config.coffee
@@ -0,0 +1,54 @@
+# # Global configurations file
+
+config = {}
+
+# Default global variables
+config.appName = 'BigBlueButton HTML5 Client'
+config.maxUsernameLength = 30
+config.maxChatLength = 140
+
+# the path in which an image of a presentation is stored
+config.presentationImagePath = (meetingID, presentationID, filename) ->
+ "bigbluebutton/presentation/#{meetingID}/#{meetingID}/#{presentationID}/png/#{filename}"
+
+## Application configurations
+config.app = {}
+
+# Generate a new secret with:
+# $ npm install crypto
+# $ coffee
+# coffee> crypto = require 'crypto'
+# coffee> crypto.randomBytes(32).toString('base64')
+config.app.sessionSecret = "J7XSu96KC/B/UPyeGub3J6w6QFXWoUNABVgi9Q1LskE="
+
+# Configs for redis
+config.redis = {}
+config.redis.host = "127.0.0.1"
+config.redis.post = "6379"
+config.redis.timeout = 5000
+config.redis.channels = {}
+config.redis.channels.fromBBBApps = "bigbluebutton:from-bbb-apps:*"
+config.redis.channels.toBBBApps = {}
+config.redis.channels.toBBBApps.pattern = "bigbluebutton:to-bbb-apps:*"
+config.redis.channels.toBBBApps.chat = "bigbluebutton:to-bbb-apps:chat"
+config.redis.channels.toBBBApps.meeting = "bigbluebutton:to-bbb-apps:meeting"
+config.redis.channels.toBBBApps.users = "bigbluebutton:to-bbb-apps:users"
+config.redis.channels.toBBBApps.whiteboard = "bigbluebutton:to-bbb-apps:whiteboard"
+config.redis.internalChannels = {}
+config.redis.internalChannels.receive = "html5-receive"
+config.redis.internalChannels.reply = "html5-reply"
+config.redis.internalChannels.publish = "html5-publish"
+
+# Logging
+config.log = {}
+
+config.log.path = if process.env.NODE_ENV == "production"
+ "/var/log/bigbluebutton/bbbnode.log"
+else
+ "./log/development.log"
+
+# Global instance of Modules, created by `app.coffee`
+config.modules = null
+
+
+Meteor.config = config
\ No newline at end of file
diff --git a/labs/meteor-client/lib/router.coffee b/labs/meteor-client/lib/router.coffee
new file mode 100644
index 0000000000..9c0b82a8a9
--- /dev/null
+++ b/labs/meteor-client/lib/router.coffee
@@ -0,0 +1,34 @@
+Meteor.Router.configure layoutTemplate: 'layout'
+
+Meteor.Router.add {
+ '/': 'main',
+
+ '*': (url)->
+
+ # Here we want to extract the meeting_id, user_id, auth_token, etc
+ # from the uri
+
+ if url.indexOf("meeting_id") > -1 # if the URL is /meeting_id=...&...
+ urlParts = url.split("&");
+
+ meetingId = urlParts[0]?.split("=")[1];
+ console.log "meetingId=" + meetingId
+
+ userId = urlParts[1]?.split("=")[1];
+ console.log "userId=" + userId
+
+ authToken = urlParts[2]?.split("=")[1];
+ console.log "authToken=" + authToken
+
+ userName = urlParts[3]?.split("=")[1];
+ console.log "userName=" + userName
+ if meetingId? and userId? and authToken? and userName?
+ redisPubSub = new Meteor.RedisPubSub
+ redisPubSub.sendValidateToken(meetingId, userId, authToken)
+ 'main'
+
+ else
+ console.log "unable to extract from the URL some of {meetingId, userName, userId, authToken}"
+ else
+ console.log "unable to extract the required information for the meeting from the URL"
+}
diff --git a/labs/meteor-client/packages.json b/labs/meteor-client/packages.json
new file mode 100644
index 0000000000..10cfd8126c
--- /dev/null
+++ b/labs/meteor-client/packages.json
@@ -0,0 +1,11 @@
+{
+ "request": "2.34.0",
+ "require": "0.5.0",
+ "bunyan": "0.22.2",
+ "socket.io": "1.0.4",
+ "crypto-js": "3.1.2-3",
+ "lodash": "1.3.1",
+ "postal": "0.10.0",
+ "events": "1.0.1",
+ "redis": "0.10.3"
+}
\ No newline at end of file
diff --git a/labs/meteor-client/server/app.coffee b/labs/meteor-client/server/app.coffee
new file mode 100644
index 0000000000..eca0751db2
--- /dev/null
+++ b/labs/meteor-client/server/app.coffee
@@ -0,0 +1,30 @@
+###
+if Meteor.isServer
+ console.log " I am in the server"
+ Meteor.startup ->
+ console.log "On startup in the server"
+ console.log Meteor.config.appName
+
+
+
+ #a = new Meteor.ClientProxy()
+
+ #b = new Meteor.RedisPubSub()
+
+
+
+ # Module to store the modules registered in the application
+ Meteor.config.modules = modules = new Meteor.Modules()
+ # Router
+ #config.modules.register "MainRouter", new MainRouter()
+
+ # Application modules
+ Meteor.config.modules.register "RedisPubSub", new Meteor.RedisPubSub()
+ #Meteor.config.modules.register "MessageBus", new Meteor.MessageBus()
+ #Meteor.config.modules.register "Controller", new Controller()
+
+ clientProxy = new Meteor.ClientProxy()
+ Meteor.config.modules.register "ClientProxy", clientProxy
+ ###############clientProxy.listen(app)
+
+###
\ No newline at end of file
diff --git a/labs/meteor-client/server/bbblogger.coffee b/labs/meteor-client/server/bbblogger.coffee
new file mode 100755
index 0000000000..cf1b793aca
--- /dev/null
+++ b/labs/meteor-client/server/bbblogger.coffee
@@ -0,0 +1,17 @@
+###
+bunyan = Meteor.require 'bunyan'
+
+logger = bunyan.createLogger({
+ name: 'bbbnode',
+ streams: [
+ {
+ level: 'debug',
+ stream: process.stdout,
+ },
+ {
+ level: 'info',
+ path: Meteor.config.log.path
+ }
+ ]
+})
+###
\ No newline at end of file
diff --git a/labs/meteor-client/server/clientproxy.coffee b/labs/meteor-client/server/clientproxy.coffee
new file mode 100644
index 0000000000..085b5f42db
--- /dev/null
+++ b/labs/meteor-client/server/clientproxy.coffee
@@ -0,0 +1,93 @@
+
+socketio = Meteor.require('socket.io')
+
+MESSAGE = "message"
+
+moduleDeps = ["Controller"]
+
+class Meteor.ClientProxy
+
+ constructor: ->
+ Meteor.config.modules.wait moduleDeps, =>
+ @controller = Meteor.config.modules.get("Controller")
+
+ # Listens for events on the websocket and does something when they are triggered.
+ listen: (app) ->
+ @io = socketio.listen(app)
+ @io.set('log level', 1)
+ @io.sockets.on 'connection', (socket) =>
+ log.debug({ client: socket.id }, "Client has connected.")
+ socket.on 'message', (jsonMsg) =>
+ log.debug({ message: jsonMsg }, "Received message")
+ @_handleMessage(socket, jsonMsg)
+ socket.on 'disconnect', =>
+ @_handleClientDisconnected socket
+
+ # Sends a message in `data` to all the clients that should receive it.
+ sendToClients: (data, callback) ->
+ #log.debug({ data: data }, "Sending to client")
+
+ # the channel can be the user_id (send to one user only) or the meeting_id
+ # (send to everyone in the meeting)
+ channel = data?.payload?.user_id or data?.payload?.meeting_id
+
+ # if the data has "header":{"name":"some_event_name"} use that name
+ # otherwise look for "name":"some_event_name" in the top level of the data
+ eventName = data?.header?.name or data?.name
+
+ # clients = @io.sockets.clients(channel)
+ # console.log "Found", clients?.length, "clients for the channel", channel
+
+ #log.debug({ channel: channel, eventName: eventName, message: data, clientCount: clients?.length },
+ # "Sending message to websocket clients")
+
+ # TODO: if `channel` is undefined, it should not send the message,
+ # instead if is sending to all users
+ @io.sockets.in(channel).emit(eventName, data)
+ callback?()
+
+ _handleClientDisconnected: (socket) ->
+ console.log "\ntrying to disconnect"
+
+ #if socket.userId?
+ # log.info("User [#{socket.userId}] has disconnected.")
+
+ _handleMessage: (socket, message) ->
+ if message.header?.name?
+ @_handleValidMessage(socket, message)
+ else
+ log.error({ message: message }, "Invalid message.")
+
+ _handleValidMessage: (socket, message) =>
+ switch message.header.name
+ when 'validate_auth_token'
+ @_handleLoginMessage socket, message
+ when 'send_public_chat_message'
+ @controller.sendingChat message
+ when 'user_leaving_request'
+ @controller.sendingUsersMessage message
+ else
+ log.error({ message: message }, 'Unknown message name.')
+
+ _handleLoginMessage: (socket, data) ->
+ @controller.processAuthMessage(data, (err, result) ->
+ if err?
+ log.debug({ message: result }, "Sending authentication not OK to user and disconnecting socket")
+ sendMessageToClient(socket, result)
+ socket.disconnect()
+ else
+ log.debug({ userChannel: result.payload.user_id, meetingChannel: result.payload.meeting_id },
+ "Subscribing a user to his channels")
+ socket.join(result.payload.user_id)
+ socket.join(result.payload.meeting_id)
+
+ # assign the userId to this socket. This way we can
+ # locate this socket using the userId.
+ socket.userId = result?.payload?.user_id
+
+ log.debug({ message: result }, "Sending authentication OK reply to user")
+ sendMessageToClient(socket, result)
+ )
+
+sendMessageToClient = (socket, message) ->
+ socket.emit(MESSAGE, message)
diff --git a/labs/meteor-client/server/controller.coffee b/labs/meteor-client/server/controller.coffee
new file mode 100755
index 0000000000..e0e6ba94f0
--- /dev/null
+++ b/labs/meteor-client/server/controller.coffee
@@ -0,0 +1,39 @@
+moduleDeps = ["MessageBus", "ClientProxy"]
+
+class Meteor.Controller
+
+ constructor: ->
+ config.modules.wait moduleDeps, =>
+ @messageBus = config.modules.get("MessageBus")
+ @clientProxy = config.modules.get("ClientProxy")
+
+ @messageBus.receiveMessages (data) =>
+ @processReceivedMessage(data)
+
+ processReceivedMessage: (data, callback) ->
+ @clientProxy.sendToClients(data, callback)
+
+ # Processes a message requesting authentication
+ processAuthMessage: (data, callback) ->
+ log.info({ data: data }, "Sending an authentication request and waiting for reply")
+ @messageBus.sendAndWaitForReply data, (err, result) ->
+ if err?
+ log.error({ reason: err, result: result, original: data }, "Authentication failure")
+ callback(err, null)
+ else
+ if result.payload?.valid
+ log.info({ result: result }, "Authentication successful")
+ callback(null, result)
+ else
+ log.info({ result: result }, "Authentication failure")
+ callback(new Error("Authentication failure"), null)
+
+ # processEndMessage: (data, callback) ->
+ # @clientProxy.endMeeting()
+
+ sendingChat: (data) =>
+ @messageBus.sendingToRedis(config.redis.channels.toBBBApps.chat, data)
+
+
+ sendingUsersMessage: (data) =>
+ @messageBus.sendingToRedis(config.redis.channels.toBBBApps.users, data)
diff --git a/labs/meteor-client/server/messagebus.coffee b/labs/meteor-client/server/messagebus.coffee
new file mode 100755
index 0000000000..0a79b8c044
--- /dev/null
+++ b/labs/meteor-client/server/messagebus.coffee
@@ -0,0 +1,40 @@
+crypto = Meteor.require 'crypto'
+postal = Meteor.require 'postal'
+
+moduleDeps = ["RedisPubSub"]
+
+class Meteor.MessageBus
+
+ constructor: ->
+ Meteor.config.modules.wait moduleDeps, =>
+ @pubSub = Meteor.config.modules.get("RedisPubSub")
+
+ receiveMessages: (callback) ->
+ postal.subscribe
+ channel: Meteor.config.redis.internalChannels.receive
+ topic: "broadcast"
+ callback: (msg, envelope) ->
+ callback(msg)
+
+ sendAndWaitForReply: (data, callback) ->
+ replyTo =
+ channel: Meteor.config.redis.internalChannels.reply
+ topic: 'get.' + crypto.randomBytes(16).toString('hex')
+
+ postal.subscribe(
+ channel: replyTo.channel
+ topic: replyTo.topic
+ callback: (msg, envelope) ->
+ callback(null, msg)
+ ).once()
+
+ log.info({ message: data, replyTo: replyTo }, "Sending a message and waiting for reply")
+
+ postal.publish
+ channel: Meteor.config.redis.internalChannels.publish
+ topic: 'broadcast'
+ replyTo: replyTo
+ data: data
+
+ sendingToRedis: (channel, message) =>
+ @pubSub.publishing(channel, message)
diff --git a/labs/meteor-client/server/modules.coffee b/labs/meteor-client/server/modules.coffee
new file mode 100644
index 0000000000..a05564f554
--- /dev/null
+++ b/labs/meteor-client/server/modules.coffee
@@ -0,0 +1,79 @@
+
+_ = Meteor.require('lodash')
+EventEmitter = Meteor.require('events').EventEmitter
+
+
+
+# Helper class to register and store modules.
+# It stores a list of objects in an object literal indexed by the name of the module.
+# Includes methods for a class to ask for a module and wait until it is ready.
+#
+# This class is used to prevent errors when modules are required in an order that
+# would generate a circular dependency. In these cases, the objects might not be loaded
+# entirely.
+# @see http://nodejs.org/api/modules.html#modules_cycles
+#
+# With this class, the class requiring a module can wait until the module is properly
+# loaded. More than that, it will return an instanced object, not only a reference to
+# a class (as usually done when using `require`).
+#
+# @example How to use it
+# modules = new Modules()
+# modules.wait ["db"], ->
+# # this callback will only be called when the module "db" is registered
+# db = config.modules.get("db")
+# ...
+# # calls to register a module can be made anywhere in the application
+# modules.register "db", new Database()
+#
+class Meteor.Modules extends EventEmitter
+
+ constructor: ->
+ # the list of modules registered:
+ @modules = {}
+ # list of callbacks waiting for a module to be registered:
+ @callbacks = []
+
+ # Registers a new module with the name in `name` and the content in `object`.
+ # @param name [string] the name of the module
+ # @param object [string] the instance of the module
+ # @return [object] the same object in the parameter `object`
+ register: (name, object) ->
+ @modules[name] = object
+ @_checkCallbacks()
+ object
+
+ # Blocks until a list of modules is registered.
+ # @param names [Array] an array of strings with the names of all modules that should be waited for
+ # @param callback [Function] will be called when *all* modules in `names` are registered
+ wait: (names, callback) ->
+ names = [names] unless _.isArray(names)
+ @callbacks.push {modules: names, fn: callback}
+ @_checkCallbacks()
+
+ # Returns the module with the name in `name`.
+ # @param name [string] the name of the module to be returned
+ # @return [object] the module asked for
+ get: (name) ->
+ @modules[name]
+
+ # Returns the list of all modules registered.
+ # @return [Array] all modules registered
+ all: ->
+ @modules
+
+ # Run through the list of registered callbacks in `@callbacks` to see if any of
+ # them are ready to be called (if all modules waited for are available).
+ # @private
+ _checkCallbacks: () ->
+ toRemove = []
+ for cb in @callbacks
+ done = true
+ for name in cb.modules
+ unless @modules[name]?
+ done = false
+ break
+ if done
+ cb.fn()
+ toRemove.push cb
+ @callbacks = _.filter(@callbacks, (i) -> i not in toRemove)
diff --git a/labs/meteor-client/server/redispubsub.coffee b/labs/meteor-client/server/redispubsub.coffee
new file mode 100644
index 0000000000..044bc4ceaf
--- /dev/null
+++ b/labs/meteor-client/server/redispubsub.coffee
@@ -0,0 +1,55 @@
+class Meteor.RedisPubSub
+ constructor: () ->
+ console.log "constructor RedisPubSub"
+
+ @pubClient = redis.createClient()
+ @subClient = redis.createClient()
+
+ @subClient.on "psubscribe", Meteor.bindEnvironment(@_onSubscribe )
+ @subClient.on "pmessage", Meteor.bindEnvironment(@_onMessage)
+
+ #log.info
+ console.log("RPC: Subscribing message on channel: #{Meteor.config.redis.channels.fromBBBApps}")
+ @subClient.psubscribe(Meteor.config.redis.channels.fromBBBApps)
+
+ # Construct and send a message to bbb-web to validate the user
+ sendValidateToken: (meetingId, userId, authToken) ->
+ console.log "\n\n i am sending a validate_auth_token with " + userId + "" + meetingId
+
+ message = {
+ "payload": {
+ "auth_token": authToken
+ "userid": userId
+ "meeting_id": meetingId
+ },
+ "header": {
+ "timestamp": new Date().getTime()
+ "reply_to": meetingId + "/" + userId
+ "name": "validate_auth_token"
+ }
+ }
+ if authToken? and userId? and meetingId?
+ @pubClient.publish(Meteor.config.redis.channels.toBBBApps.meeting, JSON.stringify(message))
+ else
+ console.log "did not have enough information to send a validate_auth_token message"
+
+ _onSubscribe: (channel, count) ->
+ #Meteor.call("addToCollection");
+ console.log "Subscribed to #{channel}"
+
+ _onMessage: (pattern, channel, jsonMsg) =>
+ # TODO: this has to be in a try/catch block, otherwise the server will
+ # crash if the message has a bad format
+
+ message = JSON.parse(jsonMsg)
+ correlationId = message.payload?.reply_to or message.header?.reply_to
+
+ unless message.header?.name is "keep_alive_reply"
+ console.log "\nchannel=" + channel
+ console.log "correlationId=" + correlationId if correlationId?
+ console.log "eventType=" + message.header?.name + "\n"
+ #log.debug({ pattern: pattern, channel: channel, message: message}, "Received a message from redis")
+ console.log jsonMsg
+
+ if message.header?.name is "user_joined_message"
+ Meteor.call("addToCollection", message.payload.user.userid, message.payload.meeting_id);
diff --git a/labs/meteor-client/server/server.js b/labs/meteor-client/server/server.js
index ef9c76404e..95821f3dc7 100755
--- a/labs/meteor-client/server/server.js
+++ b/labs/meteor-client/server/server.js
@@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////
// Startup
//
-
+/*
Meteor.startup(function () {
console.log('server start');
// cleanup collections
@@ -22,4 +22,5 @@ Meteor.startup(function () {
// Set collection permissions
SetCollectionPermissions();
-});
\ No newline at end of file
+});
+*/
diff --git a/labs/meteor-client/smart.json b/labs/meteor-client/smart.json
index fe196844c7..048f255ba1 100644
--- a/labs/meteor-client/smart.json
+++ b/labs/meteor-client/smart.json
@@ -1,6 +1,9 @@
{
"packages": {
+ "redis": {},
+ "npm": {},
"bootstrap-3": {},
- "iron-router": {}
+ "iron-router": {},
+ "router": {}
}
}
diff --git a/labs/meteor-client/smart.lock b/labs/meteor-client/smart.lock
index a617c0cb06..704bd73f54 100644
--- a/labs/meteor-client/smart.lock
+++ b/labs/meteor-client/smart.lock
@@ -2,10 +2,23 @@
"meteor": {},
"dependencies": {
"basePackages": {
+ "redis": {},
+ "npm": {},
"bootstrap-3": {},
- "iron-router": {}
+ "iron-router": {},
+ "router": {}
},
"packages": {
+ "redis": {
+ "git": "https://github.com/stevemanuel/meteor-redis.git",
+ "tag": "v0.1.3",
+ "commit": "8af9aaab84f4a87358ccb4616592a373661f712b"
+ },
+ "npm": {
+ "git": "https://github.com/arunoda/meteor-npm.git",
+ "tag": "v0.2.6",
+ "commit": "177ab6118de5bf8cffb19481343d5762ff7a2aaf"
+ },
"bootstrap-3": {
"git": "https://github.com/mangasocial/meteor-bootstrap-3.git",
"tag": "v3.1.1-1",
@@ -16,10 +29,25 @@
"tag": "v0.7.1",
"commit": "d1ffb3f06ea4c112132b030f2eb1a70b81675ecb"
},
+ "router": {
+ "git": "https://github.com/tmeasday/meteor-router.git",
+ "tag": "v0.6.1",
+ "commit": "8ec75fec7affdefc787d19f23b36fd6d1d44ef04"
+ },
"blaze-layout": {
"git": "https://github.com/EventedMind/blaze-layout.git",
"tag": "v0.2.4",
"commit": "b40e9b0612329288d75cf52ad14a7da64bb8618f"
+ },
+ "page-js-ie-support": {
+ "git": "https://github.com/tmeasday/meteor-page-js-ie-support.git",
+ "tag": "v1.3.5",
+ "commit": "b99ed8380aefd10b2afc8f18d9eed4dd0d8ea9cb"
+ },
+ "HTML5-History-API": {
+ "git": "https://github.com/tmeasday/meteor-HTML5-History-API.git",
+ "tag": "v4.1.2",
+ "commit": "b5fca79f9ae8936e5f748a04f475295f4fa1cc7a"
}
}
}