Merge branch 'meteor-rebuild-server' of https://github.com/antobinary/bigbluebutton into prototype-metor-client
This commit is contained in:
commit
eab639e134
@ -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";
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
||||
|
@ -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))
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -39,5 +39,8 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||
<bean id="chat.service" class="org.bigbluebutton.conference.service.chat.ChatService">
|
||||
<property name="chatApplication"> <ref local="chatApplication"/></property>
|
||||
</bean>
|
||||
|
||||
|
||||
<bean id="chatMessageListener" class="org.bigbluebutton.conference.service.chat.ChatMessageListener">
|
||||
<property name="bigBlueButtonInGW" ref="bbbInGW" />
|
||||
</bean>
|
||||
</beans>
|
||||
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
<bean id="presentationMessageListener" class="org.bigbluebutton.conference.service.presentation.PresentationMessageListener">
|
||||
<property name="conversionUpdatesProcessor" ref="conversionUpdatesProcessor" />
|
||||
</bean>
|
||||
|
||||
<bean id="chatMessageListener" class="org.bigbluebutton.conference.service.chat.ChatMessageListener">
|
||||
<property name="bigBlueButtonInGW" ref="bbbInGW" />
|
||||
</bean>
|
||||
|
||||
<bean id="participantsListener" class="org.bigbluebutton.conference.service.participants.ParticipantsListener">
|
||||
<property name="bigBlueButtonInGW" ref="bbbInGW" />
|
||||
</bean>
|
||||
</beans>
|
||||
|
@ -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.gnu.org/licenses/>.
|
||||
http://www.springframework.org/schema/util
|
||||
http://www.springframework.org/schema/util/spring-util-2.0.xsd
|
||||
">
|
||||
|
||||
|
||||
<bean id="participantsHandler" class="org.bigbluebutton.conference.service.participants.ParticipantsHandler">
|
||||
<property name="participantsApplication"> <ref local="participantsApplication"/></property>
|
||||
</bean>
|
||||
@ -38,5 +38,8 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||
<bean id="participants.service" class="org.bigbluebutton.conference.service.participants.ParticipantsService">
|
||||
<property name="participantsApplication"> <ref local="participantsApplication"/></property>
|
||||
</bean>
|
||||
|
||||
|
||||
<bean id="participantsListener" class="org.bigbluebutton.conference.service.participants.ParticipantsListener">
|
||||
<property name="bigBlueButtonInGW" ref="bbbInGW" />
|
||||
</bean>
|
||||
</beans>
|
||||
|
@ -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.gnu.org/licenses/>.
|
||||
http://www.springframework.org/schema/util
|
||||
http://www.springframework.org/schema/util/spring-util-2.0.xsd
|
||||
">
|
||||
|
||||
|
||||
<bean id="whiteboardApplication" class="org.bigbluebutton.conference.service.whiteboard.WhiteboardApplication">
|
||||
<property name="bigBlueButtonInGW"> <ref bean="bbbInGW"/></property>
|
||||
<property name="bigBlueButtonInGW"> <ref bean="bbbInGW"/></property>
|
||||
</bean>
|
||||
|
||||
|
||||
<bean id="whiteboard.service" class="org.bigbluebutton.conference.service.whiteboard.WhiteboardService">
|
||||
<property name="whiteboardApplication"> <ref local="whiteboardApplication"/></property>
|
||||
</bean>
|
||||
|
||||
|
||||
<bean id="whiteboardListener" class="org.bigbluebutton.conference.service.whiteboard.WhiteboardListener">
|
||||
<property name="bigBlueButtonInGW"> <ref bean="bbbInGW"/></property>
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
|
@ -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.gnu.org/licenses/>.
|
||||
http://www.springframework.org/schema/util
|
||||
http://www.springframework.org/schema/util/spring-util-2.0.xsd
|
||||
">
|
||||
|
||||
|
||||
|
||||
<bean id="redisMessageSender" class="org.bigbluebutton.conference.service.messaging.redis.MessageSender"
|
||||
init-method="start" destroy-method="stop">
|
||||
<property name="redisPool"> <ref bean="redisPool"/></property>
|
||||
</bean>
|
||||
<property name="redisPool"> <ref bean="redisPool"/></property>
|
||||
</bean>
|
||||
|
||||
<bean id="redisMessageReceiver" class="org.bigbluebutton.conference.service.messaging.redis.MessageReceiver"
|
||||
init-method="start" destroy-method="stop">
|
||||
<property name="redisPool"> <ref bean="redisPool"/></property>
|
||||
<property name="messageHandler"> <ref local="redisMessageHandler"/> </property>
|
||||
</bean>
|
||||
<property name="redisPool"> <ref bean="redisPool"/></property>
|
||||
<property name="messageHandler"> <ref local="redisMessageHandler"/> </property>
|
||||
</bean>
|
||||
|
||||
<bean id="redisMessageHandler" class="org.bigbluebutton.conference.service.messaging.redis.ReceivedMessageHandler"
|
||||
init-method="start" destroy-method="stop">
|
||||
<property name="messageDistributor"><ref bean="redisMessageDistributor" /></property>
|
||||
</bean>
|
||||
|
||||
<bean id="redisMessageDistributor" class="org.bigbluebutton.conference.service.messaging.redis.MessageDistributor">
|
||||
<property name="messageHandler"> <ref local="redisMessageHandler"/> </property>
|
||||
<property name="messageListeners">
|
||||
<set>
|
||||
<ref bean="presentationMessageListener" />
|
||||
<ref bean="chatMessageListener" />
|
||||
<ref bean="meetingMessageHandler" />
|
||||
<ref bean="pollMessageHandler" />
|
||||
<ref bean="participantsListener" />
|
||||
</set>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
|
||||
<bean id="redisMessageDistributor" class="org.bigbluebutton.conference.service.messaging.redis.MessageDistributor">
|
||||
<property name="messageHandler"> <ref local="redisMessageHandler"/> </property>
|
||||
<property name="messageListeners">
|
||||
<set>
|
||||
<ref bean="presentationMessageListener" />
|
||||
<ref bean="chatMessageListener" />
|
||||
<ref bean="meetingMessageHandler" />
|
||||
<ref bean="pollMessageHandler" />
|
||||
<ref bean="participantsListener" />
|
||||
<ref bean="whiteboardListener" />
|
||||
</set>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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: ->
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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) ->
|
||||
|
@ -1,10 +1,10 @@
|
||||
<li class="user-wrapper">
|
||||
<div class="row">
|
||||
<div class="user-role col-md-1" id="user-<%= userID %>"><i class="icon fa fa-user"></i></div>
|
||||
<div class="user-name col-md-5"><%= username %></div>
|
||||
<div class="user-video col-md-1"><i class="icon fa fa-video-camera"></i></div>
|
||||
<div class="user-audio col-md-1"><i class="icon fa fa-microphone"></i></div>
|
||||
<div class="user-kick col-md-1"><i class="icon fa fa-sign-out"></i></div>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
</li>
|
||||
<li class="user-wrapper" id="user-<%= userID %>">
|
||||
<div class="row">
|
||||
<div class="user-role col-md-1"><i class="icon fa fa-user"></i></div>
|
||||
<div class="user-name col-md-5"><%= username %></div>
|
||||
<div class="user-video col-md-1"><i class="icon fa fa-video-camera"></i></div>
|
||||
<div class="user-audio col-md-1"><i class="icon fa fa-microphone"></i></div>
|
||||
<div class="user-kick col-md-1"><i class="icon fa fa-sign-out"></i></div>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
</li>
|
@ -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).
|
||||
|
1
labs/demos/.gitignore
vendored
Normal file
1
labs/demos/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
node_modules
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"settings": {
|
||||
"IP": "http://192.168.0.203",
|
||||
"IP": "http://192.168.0.232",
|
||||
"PORT": "4000",
|
||||
"salt": "74a91f30f165423067bf3039722e33e0"
|
||||
"salt": "c7faeb82a786bd71134b61833b0ec4af"
|
||||
}
|
||||
}
|
||||
}
|
@ -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 =
|
||||
|
@ -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}
|
||||
|
1
labs/meteor-client/.gitignore
vendored
Normal file
1
labs/meteor-client/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
packages
|
@ -6,8 +6,11 @@
|
||||
standard-app-packages
|
||||
autopublish
|
||||
insecure
|
||||
bootstrap
|
||||
less
|
||||
coffeescript
|
||||
redis
|
||||
npm
|
||||
less
|
||||
bootstrap-3
|
||||
iron-router
|
||||
router
|
||||
bootstrap
|
||||
|
@ -1,8 +0,0 @@
|
||||
Meteor.navigateTo = (path) ->
|
||||
Router.go path
|
||||
|
||||
Router.configure layoutTemplate: 'layout'
|
||||
|
||||
Router.map ->
|
||||
@route 'main',
|
||||
path: '/'
|
@ -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));
|
||||
}
|
||||
});
|
54
labs/meteor-client/config.coffee
Normal file
54
labs/meteor-client/config.coffee
Normal file
@ -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
|
34
labs/meteor-client/lib/router.coffee
Normal file
34
labs/meteor-client/lib/router.coffee
Normal file
@ -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"
|
||||
}
|
11
labs/meteor-client/packages.json
Normal file
11
labs/meteor-client/packages.json
Normal file
@ -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"
|
||||
}
|
30
labs/meteor-client/server/app.coffee
Normal file
30
labs/meteor-client/server/app.coffee
Normal file
@ -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)
|
||||
|
||||
###
|
17
labs/meteor-client/server/bbblogger.coffee
Executable file
17
labs/meteor-client/server/bbblogger.coffee
Executable file
@ -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
|
||||
}
|
||||
]
|
||||
})
|
||||
###
|
93
labs/meteor-client/server/clientproxy.coffee
Normal file
93
labs/meteor-client/server/clientproxy.coffee
Normal file
@ -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)
|
39
labs/meteor-client/server/controller.coffee
Executable file
39
labs/meteor-client/server/controller.coffee
Executable file
@ -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)
|
40
labs/meteor-client/server/messagebus.coffee
Executable file
40
labs/meteor-client/server/messagebus.coffee
Executable file
@ -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)
|
79
labs/meteor-client/server/modules.coffee
Normal file
79
labs/meteor-client/server/modules.coffee
Normal file
@ -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)
|
55
labs/meteor-client/server/redispubsub.coffee
Normal file
55
labs/meteor-client/server/redispubsub.coffee
Normal file
@ -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);
|
@ -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();
|
||||
|
||||
});
|
||||
});
|
||||
*/
|
||||
|
@ -1,6 +1,9 @@
|
||||
{
|
||||
"packages": {
|
||||
"redis": {},
|
||||
"npm": {},
|
||||
"bootstrap-3": {},
|
||||
"iron-router": {}
|
||||
"iron-router": {},
|
||||
"router": {}
|
||||
}
|
||||
}
|
||||
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user