- unit test passing again
This commit is contained in:
parent
e9bd55a563
commit
8c8e009baa
@ -84,7 +84,7 @@ public class RedisListener{
|
||||
String meetingId = map.get("meetingId");
|
||||
String request = map.get("request");
|
||||
if(request != null){
|
||||
if(request.equalsIgnoreCase("end")){
|
||||
if(request.equalsIgnoreCase("endMeeting")){
|
||||
roomsManager.endMeetingRequest(meetingId);
|
||||
}
|
||||
}
|
||||
|
@ -79,39 +79,49 @@ bigbluebutton.web.logoutURL=
|
||||
# successfully joining the meeting.
|
||||
defaultClientUrl=${bigbluebutton.web.serverURL}/client/BigBlueButton.html
|
||||
|
||||
apiVersion=0.7
|
||||
|
||||
# The number of minutes before the system removed the meeting from memory.
|
||||
defaultMeetingExpireDuration=60
|
||||
|
||||
# Salt which is used by 3rd-party apps to authenticate api calls
|
||||
securitySalt=e49e0123e531d0816abaf4bc1b1d7f11
|
||||
|
||||
# Directory where we drop the <meeting-id-recorded>.done file
|
||||
recordStatusDir=/var/bigbluebutton/recording/status/recorded
|
||||
|
||||
redisHost=localhost
|
||||
redisPort=6379
|
||||
|
||||
# The directory where the published/unpublised recordings are located. This is for
|
||||
# the get recording* api calls
|
||||
publishedDir=/var/bigbluebutton/published
|
||||
unpublishedDir=/var/bigbluebutton/unpublished
|
||||
|
||||
# If the API is enabled.
|
||||
serviceEnabled = true
|
||||
|
||||
# Test voiceBridge number
|
||||
testVoiceBridge=99999
|
||||
testConferenceMock=conference-mock-default
|
||||
|
||||
#------------------------------------------------------
|
||||
# These properties are used to test the conversion process.
|
||||
# Conference name folder in ${presentationDir} (see above)
|
||||
beans.presentationService.testConferenceMock=conference-mock-default
|
||||
beans.dynamicConferenceService.testConferenceMock=conference-mock-default
|
||||
beans.presentationService.testConferenceMock=${testConferenceMock}
|
||||
|
||||
# Conference room folder in ${presentationDir}/${testConferenceMock}
|
||||
beans.presentationService.testRoomMock=conference-mock-default
|
||||
# Uploaded presentation name
|
||||
beans.presentationService.testPresentationName=appkonference
|
||||
# Uploaded presentation file
|
||||
beans.presentationService.testUploadedPresentation=appkonference.txt
|
||||
# Test voiceBridge number
|
||||
beans.dynamicConferenceService.testVoiceBridge=99999
|
||||
|
||||
redisHost=localhost
|
||||
redisPort=6379
|
||||
|
||||
# Directory where we drop the <meeting-id-recorded>.done file
|
||||
beans.dynamicConferenceService.recordStatusDir=/var/bigbluebutton/recording/status/recorded
|
||||
|
||||
#----------------------------------------------------
|
||||
# Inject values into grails service beans
|
||||
beans.presentationService.presentationDir=${presentationDir}
|
||||
beans.dynamicConferenceService.recordingDir=${presentationDir}
|
||||
beans.dynamicConferenceService.serviceEnabled=true
|
||||
beans.dynamicConferenceService.apiVersion=0.7
|
||||
beans.dynamicConferenceService.minutesElapsedBeforeMeetingExpiration=60
|
||||
beans.dynamicConferenceService.securitySalt=e49e0123e531d0816abaf4bc1b1d7f11
|
||||
beans.dynamicConferenceService.defaultWelcomeMessage=${defaultWelcomeMessage}
|
||||
beans.dynamicConferenceService.defaultDialAccessNumber=${defaultDialAccessNumber}
|
||||
beans.dynamicConferenceService.defaultMaxUsers=${defaultMaxUsers}
|
||||
beans.dynamicConferenceService.defaultLogoutUrl=${bigbluebutton.web.logoutURL}
|
||||
beans.dynamicConferenceService.defaultServerUrl=${bigbluebutton.web.serverURL}
|
||||
beans.dynamicConferenceService.defaultNumDigitsForTelVoice=${defaultNumDigitsForTelVoice}
|
||||
beans.dynamicConferenceService.defaultClientUrl=${defaultClientUrl}
|
||||
beans.dynamicConferenceService.defaultMeetingDuration=${defaultMeetingDuration}
|
||||
|
||||
|
||||
|
||||
|
||||
|
84
bigbluebutton-web/grails-app/conf/spring/doc-conversion.xml
Executable file
84
bigbluebutton-web/grails-app/conf/spring/doc-conversion.xml
Executable file
@ -0,0 +1,84 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
|
||||
">
|
||||
|
||||
<bean id="documentConversionService" class="org.bigbluebutton.presentation.DocumentConversionServiceImp">
|
||||
<property name="messagingService" ref="messagingService"/>
|
||||
<property name="officeToPdfConversionService" ref="officeToPdfConversionService"/>
|
||||
<property name="pdfToSwfSlidesGenerationService" ref="pdfToSwfSlidesGenerationService"/>
|
||||
<property name="imageToSwfSlidesGenerationService" ref="imageToSwfSlidesGenerationService"/>
|
||||
</bean>
|
||||
|
||||
<bean id="officeToPdfConversionService" class="org.bigbluebutton.presentation.imp.OfficeToPdfConversionService"/>
|
||||
|
||||
<bean id="pageExtractor" class="org.bigbluebutton.presentation.imp.GhostscriptPageExtractor">
|
||||
<property name="ghostscriptExec" value="${ghostScriptExec}"/>
|
||||
<property name="noPdfMarkWorkaround" value="${noPdfMarkWorkaround}"/>
|
||||
</bean>
|
||||
|
||||
<bean id="imageMagickPageConverter" class="org.bigbluebutton.presentation.imp.ImageMagickPageConverter">
|
||||
<property name="imageMagickDir" value="${imageMagickDir}"/>
|
||||
</bean>
|
||||
|
||||
<bean id="png2SwfConverter" class="org.bigbluebutton.presentation.imp.Png2SwfPageConverter">
|
||||
<property name="swfToolsDir" value="${swfToolsDir}"/>
|
||||
</bean>
|
||||
|
||||
<bean id="jpg2SwfConverter" class="org.bigbluebutton.presentation.imp.Jpeg2SwfPageConverter">
|
||||
<property name="swfToolsDir" value="${swfToolsDir}"/>
|
||||
</bean>
|
||||
|
||||
<bean id="pageCounter" class="org.bigbluebutton.presentation.imp.Pdf2SwfPageCounter">
|
||||
<property name="swfToolsDir" value="${swfToolsDir}"/>
|
||||
</bean>
|
||||
|
||||
<bean id="pageCounterService" class="org.bigbluebutton.presentation.imp.PageCounterService">
|
||||
<property name="pageCounter" ref="pageCounter"/>
|
||||
<property name="maxNumPages" value="${maxNumPages}"/>
|
||||
</bean>
|
||||
|
||||
<bean id="pdf2SwfPageConverter" class="org.bigbluebutton.presentation.imp.Pdf2SwfPageConverter">
|
||||
<property name="swfToolsDir" value="${swfToolsDir}"/>
|
||||
<property name="fontsDir" value="${fontsDir}"/>
|
||||
</bean>
|
||||
|
||||
<bean id="imageConvSvc" class="org.bigbluebutton.presentation.imp.PdfPageToImageConversionService">
|
||||
<property name="pageExtractor" ref="pageExtractor"/>
|
||||
<property name="pdfToImageConverter" ref="imageMagickPageConverter"/>
|
||||
<property name="imageToSwfConverter" ref="png2SwfConverter"/>
|
||||
</bean>
|
||||
|
||||
<bean id="thumbCreator" class="org.bigbluebutton.presentation.imp.ThumbnailCreatorImp">
|
||||
<property name="imageMagickDir" value="${imageMagickDir}"/>
|
||||
<property name="blankThumbnail" value="${BLANK_THUMBNAIL}"/>
|
||||
</bean>
|
||||
|
||||
<bean id="generatedSlidesInfoHelper" class="org.bigbluebutton.presentation.GeneratedSlidesInfoHelperImp"/>
|
||||
|
||||
<bean id="pdfToSwfSlidesGenerationService" class="org.bigbluebutton.presentation.imp.PdfToSwfSlidesGenerationService">
|
||||
<property name="counterService" ref="pageCounterService"/>
|
||||
<property name="pageConverter" ref="pdf2SwfPageConverter"/>
|
||||
<property name="pdfPageToImageConversionService" ref="imageConvSvc"/>
|
||||
<property name="thumbnailCreator" ref="thumbCreator"/>
|
||||
<property name="blankSlide" value="${BLANK_SLIDE}"/>
|
||||
<property name="maxConversionTime" value="${maxConversionTime}"/>
|
||||
<property name="swfSlidesGenerationProgressNotifier" ref="swfSlidesGenerationProgressNotifier"/>
|
||||
</bean>
|
||||
|
||||
<bean id="imageToSwfSlidesGenerationService" class="org.bigbluebutton.presentation.imp.ImageToSwfSlidesGenerationService">
|
||||
<property name="pngPageConverter" ref="png2SwfConverter"/>
|
||||
<property name="jpgPageConverter" ref="jpg2SwfConverter"/>
|
||||
<property name="thumbnailCreator" ref="thumbCreator"/>
|
||||
<property name="blankSlide" value="${BLANK_SLIDE}"/>
|
||||
<property name="maxConversionTime" value="${maxConversionTime}"/>
|
||||
<property name="swfSlidesGenerationProgressNotifier" ref="swfSlidesGenerationProgressNotifier"/>
|
||||
</bean>
|
||||
|
||||
<bean id="swfSlidesGenerationProgressNotifier" class="org.bigbluebutton.presentation.imp.SwfSlidesGenerationProgressNotifier">
|
||||
<property name="messagingService" ref="messagingService"/>
|
||||
<property name="generatedSlidesInfoHelper" ref="generatedSlidesInfoHelper"/>
|
||||
</bean>
|
||||
</beans>
|
@ -4,98 +4,48 @@
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
|
||||
">
|
||||
|
||||
<bean id="meetingService" class="org.bigbluebutton.api.MeetingServiceImp" >
|
||||
<property name="messagingService" ref="messagingService"/>
|
||||
|
||||
<bean id="messagingService" class="org.bigbluebutton.api.messaging.RedisMessagingService">
|
||||
<constructor-arg index="0" value="${redisHost}"/>
|
||||
<constructor-arg index="1" value="${redisPort}"/>
|
||||
<property name="redisPool" ref="redisPool"/>
|
||||
</bean>
|
||||
|
||||
<bean id="paramsProcessorUtil" class="org.bigbluebutton.api.ParamsProcessorUtil"/>
|
||||
|
||||
<bean id="messagingService" class="org.bigbluebutton.api.messaging.RedisMessagingService">
|
||||
<constructor-arg index="0" value="${redisHost}"/>
|
||||
<constructor-arg index="1" value="${redisPort}"/>
|
||||
<property name="redisPool" ref="redisPool"/>
|
||||
</bean>
|
||||
|
||||
<bean id="redisPool" class="redis.clients.jedis.JedisPool">
|
||||
<constructor-arg index="0" value="${redisHost}"/>
|
||||
<constructor-arg index="1" value="${redisPort}"/>
|
||||
</bean>
|
||||
|
||||
<bean id="documentConversionService" class="org.bigbluebutton.presentation.DocumentConversionServiceImp">
|
||||
<bean id="redisPool" class="redis.clients.jedis.JedisPool">
|
||||
<constructor-arg index="0" value="${redisHost}"/>
|
||||
<constructor-arg index="1" value="${redisPort}"/>
|
||||
</bean>
|
||||
|
||||
<bean id="meetingService" class="org.bigbluebutton.api.MeetingService">
|
||||
<property name="defaultMeetingExpireDuration" value="${defaultMeetingExpireDuration}"/>
|
||||
<property name="messagingService" ref="messagingService"/>
|
||||
<property name="officeToPdfConversionService" ref="officeToPdfConversionService"/>
|
||||
<property name="pdfToSwfSlidesGenerationService" ref="pdfToSwfSlidesGenerationService"/>
|
||||
<property name="imageToSwfSlidesGenerationService" ref="imageToSwfSlidesGenerationService"/>
|
||||
</bean>
|
||||
|
||||
<bean id="officeToPdfConversionService" class="org.bigbluebutton.presentation.imp.OfficeToPdfConversionService"/>
|
||||
|
||||
<bean id="pageExtractor" class="org.bigbluebutton.presentation.imp.GhostscriptPageExtractor">
|
||||
<property name="ghostscriptExec" value="${ghostScriptExec}"/>
|
||||
<property name="noPdfMarkWorkaround" value="${noPdfMarkWorkaround}"/>
|
||||
</bean>
|
||||
|
||||
<bean id="imageMagickPageConverter" class="org.bigbluebutton.presentation.imp.ImageMagickPageConverter">
|
||||
<property name="imageMagickDir" value="${imageMagickDir}"/>
|
||||
</bean>
|
||||
|
||||
<bean id="png2SwfConverter" class="org.bigbluebutton.presentation.imp.Png2SwfPageConverter">
|
||||
<property name="swfToolsDir" value="${swfToolsDir}"/>
|
||||
</bean>
|
||||
|
||||
<bean id="jpg2SwfConverter" class="org.bigbluebutton.presentation.imp.Jpeg2SwfPageConverter">
|
||||
<property name="swfToolsDir" value="${swfToolsDir}"/>
|
||||
</bean>
|
||||
|
||||
<bean id="pageCounter" class="org.bigbluebutton.presentation.imp.Pdf2SwfPageCounter">
|
||||
<property name="swfToolsDir" value="${swfToolsDir}"/>
|
||||
</bean>
|
||||
|
||||
<bean id="pageCounterService" class="org.bigbluebutton.presentation.imp.PageCounterService">
|
||||
<property name="pageCounter" ref="pageCounter"/>
|
||||
<property name="maxNumPages" value="${maxNumPages}"/>
|
||||
</bean>
|
||||
|
||||
<bean id="pdf2SwfPageConverter" class="org.bigbluebutton.presentation.imp.Pdf2SwfPageConverter">
|
||||
<property name="swfToolsDir" value="${swfToolsDir}"/>
|
||||
<property name="fontsDir" value="${fontsDir}"/>
|
||||
</bean>
|
||||
|
||||
<bean id="imageConvSvc" class="org.bigbluebutton.presentation.imp.PdfPageToImageConversionService">
|
||||
<property name="pageExtractor" ref="pageExtractor"/>
|
||||
<property name="pdfToImageConverter" ref="imageMagickPageConverter"/>
|
||||
<property name="imageToSwfConverter" ref="png2SwfConverter"/>
|
||||
</bean>
|
||||
|
||||
<bean id="thumbCreator" class="org.bigbluebutton.presentation.imp.ThumbnailCreatorImp">
|
||||
<property name="imageMagickDir" value="${imageMagickDir}"/>
|
||||
<property name="blankThumbnail" value="${BLANK_THUMBNAIL}"/>
|
||||
</bean>
|
||||
|
||||
<bean id="generatedSlidesInfoHelper" class="org.bigbluebutton.presentation.GeneratedSlidesInfoHelperImp"/>
|
||||
|
||||
<bean id="pdfToSwfSlidesGenerationService" class="org.bigbluebutton.presentation.imp.PdfToSwfSlidesGenerationService">
|
||||
<property name="counterService" ref="pageCounterService"/>
|
||||
<property name="pageConverter" ref="pdf2SwfPageConverter"/>
|
||||
<property name="pdfPageToImageConversionService" ref="imageConvSvc"/>
|
||||
<property name="thumbnailCreator" ref="thumbCreator"/>
|
||||
<property name="blankSlide" value="${BLANK_SLIDE}"/>
|
||||
<property name="maxConversionTime" value="${maxConversionTime}"/>
|
||||
<property name="swfSlidesGenerationProgressNotifier" ref="swfSlidesGenerationProgressNotifier"/>
|
||||
</bean>
|
||||
|
||||
<bean id="imageToSwfSlidesGenerationService" class="org.bigbluebutton.presentation.imp.ImageToSwfSlidesGenerationService">
|
||||
<property name="pngPageConverter" ref="png2SwfConverter"/>
|
||||
<property name="jpgPageConverter" ref="jpg2SwfConverter"/>
|
||||
<property name="thumbnailCreator" ref="thumbCreator"/>
|
||||
<property name="blankSlide" value="${BLANK_SLIDE}"/>
|
||||
<property name="maxConversionTime" value="${maxConversionTime}"/>
|
||||
<property name="swfSlidesGenerationProgressNotifier" ref="swfSlidesGenerationProgressNotifier"/>
|
||||
</bean>
|
||||
|
||||
<bean id="swfSlidesGenerationProgressNotifier" class="org.bigbluebutton.presentation.imp.SwfSlidesGenerationProgressNotifier">
|
||||
<property name="messagingService" ref="messagingService"/>
|
||||
<property name="generatedSlidesInfoHelper" ref="generatedSlidesInfoHelper"/>
|
||||
</bean>
|
||||
<property name="recordingService" ref="recordingService"/>
|
||||
</bean>
|
||||
|
||||
<bean id="recordingServiceHelper" class="org.bigbluebutton.api.RecordingServiceHelperImp"/>
|
||||
|
||||
<bean id="recordingService" class="org.bigbluebutton.api.RecordingService" >
|
||||
<property name="recordingStatusDir" value="${recordStatusDir}"/>
|
||||
<property name="publishedDir" value="${publishedDir}"/>
|
||||
<property name="unpublishedDir" value="${unpublishedDir}"/>
|
||||
<property name="recordingServiceHelper" ref="recordingServiceHelper"/>
|
||||
</bean>
|
||||
|
||||
<bean id="paramsProcessorUtil" class="org.bigbluebutton.api.ParamsProcessorUtil">
|
||||
<property name="apiVersion" value="${apiVersion}"/>
|
||||
<property name="serviceEnabled" value="${serviceEnabled}"/>
|
||||
<property name="securitySalt" value="${securitySalt}"/>
|
||||
<property name="defaultMaxUsers" value="${defaultMaxUsers}"/>
|
||||
<property name="defaultWelcomeMessage" value="${defaultWelcomeMessage}"/>
|
||||
<property name="defaultDialAccessNumber" value="${defaultDialAccessNumber}"/>
|
||||
<property name="testVoiceBridge" value="${testVoiceBridge}"/>
|
||||
<property name="testConferenceMock" value="${testConferenceMock}"/>
|
||||
<property name="defaultLogoutUrl" value="${bigbluebutton.web.logoutURL}"/>
|
||||
<property name="defaultServerUrl" value="${bigbluebutton.web.serverURL}"/>
|
||||
<property name="defaultNumDigitsForTelVoice" value="${defaultNumDigitsForTelVoice}"/>
|
||||
<property name="defaultClientUrl" value="${defaultClientUrl}"/>
|
||||
<property name="defaultMeetingDuration" value="${defaultMeetingDuration}"/>
|
||||
</bean>
|
||||
|
||||
<import resource="doc-conversion.xml" />
|
||||
</beans>
|
@ -30,6 +30,7 @@ import org.apache.commons.lang.RandomStringUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.bigbluebutton.web.services.DynamicConferenceService;
|
||||
import org.bigbluebutton.api.domain.Meeting;
|
||||
import org.bigbluebutton.api.MeetingService;
|
||||
import org.bigbluebutton.api.domain.Recording;
|
||||
import org.bigbluebutton.web.services.PresentationService
|
||||
import org.bigbluebutton.presentation.UploadedPresentation
|
||||
@ -51,7 +52,7 @@ class ApiController {
|
||||
private static final String ROLE_ATTENDEE = "VIEWER";
|
||||
private static final String SECURITY_SALT = '639259d4-9dd8-4b25-bf01-95f9567eaf4b'
|
||||
|
||||
DynamicConferenceService dynamicConferenceService;
|
||||
MeetingService meetingService;
|
||||
PresentationService presentationService
|
||||
ParamsProcessorUtil paramsProcessorUtil
|
||||
|
||||
@ -64,12 +65,40 @@ class ApiController {
|
||||
render(contentType:"text/xml") {
|
||||
response() {
|
||||
returncode(RESP_CODE_SUCCESS)
|
||||
version(dynamicConferenceService.apiVersion)
|
||||
version(paramsProcessorUtil.getApiVersion())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Substitute keywords from the welcome message.
|
||||
**/
|
||||
private String substituteKeywords(String message, String dialNum, String telVoice, String meetingName) {
|
||||
String welcomeMessage = message
|
||||
|
||||
def DIAL_NUM = /%%DIALNUM%%/
|
||||
def CONF_NUM = /%%CONFNUM%%/
|
||||
def CONF_NAME = /%%CONFNAME%%/
|
||||
def keywordList = [DIAL_NUM, CONF_NUM, CONF_NAME];
|
||||
|
||||
keywordList.each { keyword ->
|
||||
switch(keyword){
|
||||
case DIAL_NUM:
|
||||
welcomeMessage = welcomeMessage.replaceAll(DIAL_NUM, dialNum)
|
||||
break
|
||||
case CONF_NUM:
|
||||
welcomeMessage = welcomeMessage.replaceAll(CONF_NUM, telVoice)
|
||||
break
|
||||
case CONF_NAME:
|
||||
welcomeMessage = welcomeMessage.replaceAll(CONF_NAME, meetingName)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return welcomeMessage;
|
||||
}
|
||||
|
||||
/***********************************
|
||||
* CREATE (API)
|
||||
@ -103,7 +132,7 @@ class ApiController {
|
||||
}
|
||||
|
||||
// Do we agree with the checksum? If not, complain.
|
||||
if (! dynamicConferenceService.isChecksumSame(API_CALL, params.checksum, request.getQueryString())) {
|
||||
if (! paramsProcessorUtil.isChecksumSame(API_CALL, params.checksum, request.getQueryString())) {
|
||||
errors.checksumError()
|
||||
respondWithErrors(errors)
|
||||
return
|
||||
@ -115,7 +144,7 @@ class ApiController {
|
||||
|
||||
// Get the digits for voice conference for users joining through the phone.
|
||||
// If none is provided, generate one.
|
||||
String telVoice = dynamicConferenceService.processTelVoice(params.voiceBridge);
|
||||
String telVoice = paramsProcessorUtil.processTelVoice(params.voiceBridge);
|
||||
|
||||
// Get the voice conference digits/chars for users joing through VOIP on the client.
|
||||
// If none is provided, make it the same as the telVoice. If one has been provided,
|
||||
@ -126,16 +155,17 @@ class ApiController {
|
||||
}
|
||||
|
||||
// Get all the other relevant parameters and generate defaults if none has been provided.
|
||||
String dialNumber = dynamicConferenceService.processDialNumber(params.dialNumber);
|
||||
String logoutUrl = dynamicConferenceService.processLogoutUrl(params.logoutURL);
|
||||
boolean record = dynamicConferenceService.processRecordMeeting(params.record);
|
||||
int maxUsers = dynamicConferenceService.processMaxUser(params.maxParticipants);
|
||||
int meetingDuration = dynamicConferenceService.processMeetingDuration(params.duration);
|
||||
String welcomeMessage = dynamicConferenceService.processWelcomeMessage(params.welcome == null ? "" : params.welcome, dialNumber, telVoice, meetingName);
|
||||
String dialNumber = paramsProcessorUtil.processDialNumber(params.dialNumber);
|
||||
String logoutUrl = paramsProcessorUtil.processLogoutUrl(params.logoutURL);
|
||||
boolean record = paramsProcessorUtil.processRecordMeeting(params.record);
|
||||
int maxUsers = paramsProcessorUtil.processMaxUser(params.maxParticipants);
|
||||
int meetingDuration = paramsProcessorUtil.processMeetingDuration(params.duration);
|
||||
String welcomeMessage = paramsProcessorUtil.processWelcomeMessage(params.welcome);
|
||||
welcomeMessage = substituteKeywords(welcomeMessage, dialNumber, telVoice, meetingName);
|
||||
|
||||
// Translate the external meeting id into an internal meeting id.
|
||||
String internalMeetingId = dynamicConferenceService.convertToInternalMeetingId(externalMeetingId);
|
||||
Meeting existing = dynamicConferenceService.getMeeting(internalMeetingId);
|
||||
String internalMeetingId = paramsProcessorUtil.convertToInternalMeetingId(externalMeetingId);
|
||||
Meeting existing = meetingService.getMeeting(internalMeetingId);
|
||||
if (existing != null) {
|
||||
log.debug "Existing conference found"
|
||||
if (existing.getViewerPassword().equals(viewerPass) && existing.getModeratorPassword().equals(modPass)) {
|
||||
@ -152,8 +182,8 @@ class ApiController {
|
||||
}
|
||||
|
||||
// Check if this is a test meeting. NOTE: This should not belong here. Extract this out.
|
||||
if (dynamicConferenceService.isTestMeeting(telVoice)) {
|
||||
digestMeetingId = dynamicConferenceService.getIntMeetingIdForTestMeeting(telVoice)
|
||||
if (paramsProcessorUtil.isTestMeeting(telVoice)) {
|
||||
internalMeetingId = paramsProcessorUtil.getIntMeetingIdForTestMeeting(telVoice)
|
||||
}
|
||||
|
||||
// Collect metadata for this meeting that the third-party app wants to store if meeting is recorded.
|
||||
@ -179,7 +209,7 @@ class ApiController {
|
||||
.withLogoutUrl(logoutUrl).withTelVoice(telVoice).withWebVoice(webVoice).withDialNumber(dialNumber)
|
||||
.withMetadata(meetingInfo).withWelcomeMessage(welcomeMessage).build()
|
||||
|
||||
dynamicConferenceService.createMeeting(meeting);
|
||||
meetingService.createMeeting(meeting);
|
||||
|
||||
// See if the request came with pre-uploading of presentation.
|
||||
uploadDocuments(meeting);
|
||||
@ -224,7 +254,7 @@ class ApiController {
|
||||
}
|
||||
|
||||
// Do we agree on the checksum? If not, complain.
|
||||
if (! dynamicConferenceService.isChecksumSame(API_CALL, params.checksum, request.getQueryString())) {
|
||||
if (! paramsProcessorUtil.isChecksumSame(API_CALL, params.checksum, request.getQueryString())) {
|
||||
errors.checksumError()
|
||||
respondWithErrors(errors)
|
||||
return
|
||||
@ -237,9 +267,9 @@ class ApiController {
|
||||
|
||||
// Everything is good so far. Translate the external meeting id to an internal meeting id. If
|
||||
// we can't find the meeting, complain.
|
||||
String internalMeetingId = dynamicConferenceService.convertToInternalMeetingId(externalMeetingId);
|
||||
String internalMeetingId = paramsProcessorUtil.convertToInternalMeetingId(externalMeetingId);
|
||||
log.info("Retrieving meeting ${internalMeetingId}")
|
||||
Meeting meeting = dynamicConferenceService.getMeeting(internalMeetingId);
|
||||
Meeting meeting = meetingService.getMeeting(internalMeetingId);
|
||||
if (meeting == null) {
|
||||
errors.invalidMeetingIdError();
|
||||
respondWithErrors(errors)
|
||||
@ -291,8 +321,8 @@ class ApiController {
|
||||
|
||||
session.setMaxInactiveInterval(SESSION_TIMEOUT);
|
||||
|
||||
log.info("Successfully joined. Redirecting to ${dynamicConferenceService.defaultClientUrl}");
|
||||
redirect(url: dynamicConferenceService.defaultClientUrl)
|
||||
log.info("Successfully joined. Redirecting to ${paramsProcessorUtil.getDefaultClientUrl()}");
|
||||
redirect(url: paramsProcessorUtil.getDefaultClientUrl())
|
||||
}
|
||||
|
||||
/*******************************************
|
||||
@ -321,7 +351,7 @@ class ApiController {
|
||||
}
|
||||
|
||||
// Do we agree on the checksum? If not, complain.
|
||||
if (! dynamicConferenceService.isChecksumSame(API_CALL, params.checksum, request.getQueryString())) {
|
||||
if (! paramsProcessorUtil.isChecksumSame(API_CALL, params.checksum, request.getQueryString())) {
|
||||
errors.checksumError()
|
||||
respondWithErrors(errors)
|
||||
return
|
||||
@ -329,9 +359,9 @@ class ApiController {
|
||||
|
||||
// Everything is good so far. Translate the external meeting id to an internal meeting id. If
|
||||
// we can't find the meeting, complain.
|
||||
String internalMeetingId = dynamicConferenceService.convertToInternalMeetingId(externalMeetingId);
|
||||
String internalMeetingId = paramsProcessorUtil.convertToInternalMeetingId(externalMeetingId);
|
||||
log.info("Retrieving meeting ${internalMeetingId}")
|
||||
Meeting meeting = dynamicConferenceService.getMeeting(internalMeetingId);
|
||||
Meeting meeting = meetingService.getMeeting(internalMeetingId);
|
||||
if (meeting == null) {
|
||||
errors.invalidMeetingIdError();
|
||||
respondWithErrors(errors)
|
||||
@ -383,7 +413,7 @@ class ApiController {
|
||||
}
|
||||
|
||||
// Do we agree on the checksum? If not, complain.
|
||||
if (! dynamicConferenceService.isChecksumSame(API_CALL, params.checksum, request.getQueryString())) {
|
||||
if (! paramsProcessorUtil.isChecksumSame(API_CALL, params.checksum, request.getQueryString())) {
|
||||
errors.checksumError()
|
||||
respondWithErrors(errors)
|
||||
return
|
||||
@ -391,9 +421,9 @@ class ApiController {
|
||||
|
||||
// Everything is good so far. Translate the external meeting id to an internal meeting id. If
|
||||
// we can't find the meeting, complain.
|
||||
String internalMeetingId = dynamicConferenceService.convertToInternalMeetingId(externalMeetingId);
|
||||
String internalMeetingId = paramsProcessorUtil.convertToInternalMeetingId(externalMeetingId);
|
||||
log.info("Retrieving meeting ${internalMeetingId}")
|
||||
Meeting meeting = dynamicConferenceService.getMeeting(internalMeetingId);
|
||||
Meeting meeting = meetingService.getMeeting(internalMeetingId);
|
||||
if (meeting == null) {
|
||||
errors.invalidMeetingIdError();
|
||||
respondWithErrors(errors)
|
||||
@ -406,7 +436,7 @@ class ApiController {
|
||||
return;
|
||||
}
|
||||
|
||||
dynamicConferenceService.endMeetingRequest(internalMeetingId);
|
||||
meetingService.endMeeting(internalMeetingId);
|
||||
|
||||
response.addHeader("Cache-Control", "no-cache")
|
||||
withFormat {
|
||||
@ -454,7 +484,7 @@ class ApiController {
|
||||
}
|
||||
|
||||
// Do we agree on the checksum? If not, complain.
|
||||
if (! dynamicConferenceService.isChecksumSame(API_CALL, params.checksum, request.getQueryString())) {
|
||||
if (! paramsProcessorUtil.isChecksumSame(API_CALL, params.checksum, request.getQueryString())) {
|
||||
errors.checksumError()
|
||||
respondWithErrors(errors)
|
||||
return
|
||||
@ -462,9 +492,9 @@ class ApiController {
|
||||
|
||||
// Everything is good so far. Translate the external meeting id to an internal meeting id. If
|
||||
// we can't find the meeting, complain.
|
||||
String internalMeetingId = dynamicConferenceService.convertToInternalMeetingId(externalMeetingId);
|
||||
String internalMeetingId = paramsProcessorUtil.convertToInternalMeetingId(externalMeetingId);
|
||||
log.info("Retrieving meeting ${internalMeetingId}")
|
||||
Meeting meeting = dynamicConferenceService.getMeeting(internalMeetingId);
|
||||
Meeting meeting = meetingService.getMeeting(internalMeetingId);
|
||||
if (meeting == null) {
|
||||
errors.invalidMeetingIdError();
|
||||
respondWithErrors(errors)
|
||||
@ -500,13 +530,13 @@ class ApiController {
|
||||
}
|
||||
|
||||
// Do we agree on the checksum? If not, complain.
|
||||
if (! dynamicConferenceService.isChecksumSame(API_CALL, params.checksum, request.getQueryString())) {
|
||||
if (! paramsProcessorUtil.isChecksumSame(API_CALL, params.checksum, request.getQueryString())) {
|
||||
errors.checksumError()
|
||||
respondWithErrors(errors)
|
||||
return
|
||||
}
|
||||
|
||||
Collection<Meeting> mtgs = dynamicConferenceService.getAllMeetings();
|
||||
Collection<Meeting> mtgs = meetingService.getMeetings();
|
||||
|
||||
if (mtgs == null || mtgs.isEmpty()) {
|
||||
response.addHeader("Cache-Control", "no-cache")
|
||||
@ -610,8 +640,8 @@ class ApiController {
|
||||
*************************************************/
|
||||
def signOut = {
|
||||
String meetingId = session["conference"]
|
||||
Meeting meeting = dynamicConferenceService.getMeeting(meetingId);
|
||||
String logoutUrl = dynamicConferenceService.defaultLogoutUrl
|
||||
Meeting meeting = meetingService.getMeeting(meetingId);
|
||||
String logoutUrl = paramsProcessorUtil.getDefaultLogoutUrl()
|
||||
log.debug("Logging out from [" + meeting.getInternalId() + "]");
|
||||
|
||||
// Log the user out of the application.
|
||||
@ -621,7 +651,7 @@ class ApiController {
|
||||
logoutUrl = meeting.getLogoutUrl();
|
||||
if (meeting.isRecord()) {
|
||||
log.debug("[" + meeting.getInternalId() + "] is recorded. Process it.");
|
||||
dynamicConferenceService.processRecording(meeting.getInternalId())
|
||||
meetingService.processRecording(meeting.getInternalId())
|
||||
}
|
||||
} else {
|
||||
log.warn("Signing out from a non-existing meeting [" + meetingId + "]");
|
||||
@ -632,7 +662,7 @@ class ApiController {
|
||||
}
|
||||
|
||||
def getRecordings = {
|
||||
ArrayList<Recording> r = dynamicConferenceService.getRecordings();
|
||||
ArrayList<Recording> r = meetingService.getRecordings();
|
||||
if (r.isEmpty()) {
|
||||
|
||||
} else {
|
||||
@ -721,7 +751,7 @@ class ApiController {
|
||||
}
|
||||
|
||||
def beforeInterceptor = {
|
||||
if (dynamicConferenceService.serviceEnabled == false) {
|
||||
if (paramsProcessorUtil.isServiceEnabled() == false) {
|
||||
log.info("apiNotEnabled: The API service and/or controller is not enabled on this server. To use it, you must first enable it.")
|
||||
// TODO: this doesn't stop the request - so it generates invalid XML
|
||||
// since the request continues and renders a second response
|
||||
|
@ -1,283 +0,0 @@
|
||||
/* BigBlueButton - http://www.bigbluebutton.org
|
||||
*
|
||||
*
|
||||
* Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
|
||||
*
|
||||
* BigBlueButton 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
|
||||
* Foundation; either version 3 of the License, or (at your option) any later
|
||||
* version.
|
||||
*
|
||||
* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License along
|
||||
* with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @author Jeremy Thomerson <jthomerson@genericconf.com>
|
||||
* @version $Id: $
|
||||
*/
|
||||
package org.bigbluebutton.web.services
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
import org.bigbluebutton.api.domain.Meeting;
|
||||
import org.bigbluebutton.api.domain.Recording;
|
||||
import org.bigbluebutton.api.MeetingService;
|
||||
import org.apache.commons.codec.binary.Hex;
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import org.apache.commons.lang.RandomStringUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
|
||||
|
||||
public class DynamicConferenceService {
|
||||
boolean transactional = false
|
||||
def serviceEnabled = false
|
||||
|
||||
/** See bigbluebutton.properties for default values **/
|
||||
def apiVersion;
|
||||
def securitySalt
|
||||
int minutesElapsedBeforeMeetingExpiration = 60
|
||||
int defaultMaxUsers = 20
|
||||
def defaultWelcomeMessage
|
||||
def defaultDialAccessNumber
|
||||
def testVoiceBridge
|
||||
def testConferenceMock
|
||||
def recordingDir
|
||||
def recordingFile
|
||||
def recordStatusDir
|
||||
def defaultLogoutUrl
|
||||
def defaultServerUrl
|
||||
def defaultNumDigitsForTelVoice
|
||||
def defaultClientUrl
|
||||
def defaultMeetingDuration
|
||||
|
||||
MeetingService meetingService
|
||||
|
||||
public Collection<Meeting> getAllMeetings() {
|
||||
return meetingService.getMeetings()
|
||||
}
|
||||
|
||||
public void createMeeting(Meeting meeting) {
|
||||
meetingService.storeMeeting(meeting);
|
||||
}
|
||||
|
||||
public Meeting getMeeting(String meetingId) {
|
||||
return meetingService.getMeeting(meetingId);
|
||||
}
|
||||
|
||||
public void endMeetingRequest(String meetingId) {
|
||||
meetingService.endMeeting(meetingId);
|
||||
}
|
||||
|
||||
public boolean isMeetingWithVoiceBridgeExist(String voiceBridge) {
|
||||
Collection<Meeting> confs = confsByMtgID.values()
|
||||
for (Meeting c : confs) {
|
||||
if (voiceBridge == c.voiceBridge) {
|
||||
log.debug "Found voice bridge $voiceBridge"
|
||||
return true
|
||||
}
|
||||
}
|
||||
log.debug "could not find voice bridge $voiceBridge"
|
||||
return false
|
||||
}
|
||||
|
||||
public void processRecording(String meetingId) {
|
||||
System.out.println("enter processRecording " + meetingId)
|
||||
Meeting room = meetingService.getMeeting(meetingId)
|
||||
if (room != null) {
|
||||
System.out.println("Number of participants in room " + room.getNumberOfParticipants())
|
||||
if (room.getNumberOfParticipants() == 0) {
|
||||
System.out.println("starting processRecording " + meetingId)
|
||||
// Run conversion on another thread.
|
||||
new Timer().runAfter(1000) {
|
||||
startIngestAndProcessing(meetingId)
|
||||
}
|
||||
} else {
|
||||
System.out.println("Someone still in the room...not processRecording " + meetingId)
|
||||
}
|
||||
} else {
|
||||
System.out.println("Could not find room " + meetingId + " ... Not processing recording")
|
||||
}
|
||||
}
|
||||
|
||||
private void startIngestAndProcessing(meetingId) {
|
||||
String done = recordStatusDir + "/" + meetingId + ".done"
|
||||
|
||||
File doneFile = new File(done)
|
||||
if (!doneFile.exists()) {
|
||||
doneFile.createNewFile()
|
||||
if (!doneFile.exists())
|
||||
log.error("Failed to create " + done + " file.")
|
||||
} else {
|
||||
log.error(done + " file already exists.")
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isValidMeetingId(String name) {
|
||||
return name ==~ /[0-9a-zA-Z_-]+/
|
||||
}
|
||||
|
||||
public String convertToInternalMeetingId(extMeetingId) {
|
||||
return DigestUtils.shaHex(extMeetingId);
|
||||
}
|
||||
|
||||
public boolean hasChecksumAndQueryString(String checksum, String queryString) {
|
||||
return (! StringUtils.isEmpty(checksum) && StringUtils.isEmpty(queryString));
|
||||
}
|
||||
|
||||
public String processPassword(String pass) {
|
||||
return StringUtils.isEmpty(pass) ? RandomStringUtils.randomAlphanumeric(8) : pass;
|
||||
return paramsService.processPassword(pass);
|
||||
}
|
||||
|
||||
public String processTelVoice(String telNum) {
|
||||
return StringUtils.isEmpty(telNum) ? RandomStringUtils.randomNumeric(defaultNumDigitsForTelVoice) : telNum;
|
||||
}
|
||||
|
||||
public String processDialNumber(String dial) {
|
||||
return StringUtils.isEmpty(dial) ? defaultDialAccessNumber : dial;
|
||||
}
|
||||
|
||||
public String processLogoutUrl(String logoutUrl) {
|
||||
if (StringUtils.isEmpty(logoutUrl)) {
|
||||
if (StringUtils.isEmpty(defaultLogoutUrl)) {
|
||||
return defaultServerUrl;
|
||||
} else {
|
||||
return defaultLogoutUrl;
|
||||
}
|
||||
}
|
||||
|
||||
return logoutUrl;
|
||||
}
|
||||
|
||||
public boolean processRecordMeeting(String record) {
|
||||
boolean rec = false
|
||||
if(! StringUtils.isEmpty(record)){
|
||||
try {
|
||||
rec = Boolean.parseBoolean(record)
|
||||
} catch(Exception ex){
|
||||
log.error("Failed to parse record parameter.")
|
||||
rec = false;
|
||||
}
|
||||
}
|
||||
|
||||
return rec;
|
||||
}
|
||||
|
||||
public int processMaxUser(String maxUsers) {
|
||||
int mUsers = -1;
|
||||
|
||||
try {
|
||||
mUsers = Integer.parseInt(maxUsers);
|
||||
} catch(Exception ex) {
|
||||
log.warn("Failed to parse maximum number of participants.");
|
||||
mUsers = defaultMaxUsers;
|
||||
}
|
||||
|
||||
return mUsers;
|
||||
}
|
||||
|
||||
public int processMeetingDuration(String duration) {
|
||||
int mDuration = -1;
|
||||
|
||||
try {
|
||||
mDuration = Integer.parseInt(duration);
|
||||
} catch(Exception ex) {
|
||||
log.warn("Failed to parse meeting duration.");
|
||||
mDuration = Integer.parseInt(defaultMeetingDuration);
|
||||
}
|
||||
|
||||
return mDuration;
|
||||
}
|
||||
|
||||
public boolean isTestMeeting(String telVoice) {
|
||||
return ((! StringUtils.isEmpty(telVoice)) &&
|
||||
(! StringUtils.isEmpty(testVoiceBridge)) &&
|
||||
(telVoice == testVoiceBridge));
|
||||
}
|
||||
|
||||
public String getIntMeetingIdForTestMeeting(String telVoice) {
|
||||
if ((testVoiceBridge != null) && (telVoice == testVoiceBridge)) {
|
||||
if (StringUtils.isEmpty(testConferenceMock))
|
||||
return testConferenceMock
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
public Map<String, String> processMeetingInfo(HashMap<String, String> params) {
|
||||
Map<String, String> meetingInfo = new HashMap<String, String>();
|
||||
|
||||
params.keySet().each { p ->
|
||||
if (p.contains("meta")) {
|
||||
String[] m = metadata.split("_")
|
||||
if (m.length == 2) {
|
||||
meetingInfo.put(m[1], params.get(p))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isChecksumSame(String apiCall, String checksum, String queryString) {
|
||||
log.debug "checksum: " + checksum + "; query string: " + queryString
|
||||
|
||||
if (StringUtils.isEmpty(securitySalt)) {
|
||||
log.warn "Security is disabled in this service. Make sure this is intentional."
|
||||
return true;
|
||||
}
|
||||
|
||||
// handle either checksum as first or middle / end parameter
|
||||
// TODO: this is hackish - should be done better
|
||||
queryString = queryString.replace("&checksum=" + checksum, "")
|
||||
queryString = queryString.replace("checksum=" + checksum + "&", "")
|
||||
log.debug "query string after checksum removed: " + queryString
|
||||
String cs = DigestUtils.shaHex(apiCall + queryString + securitySalt);
|
||||
log.debug "our checksum: " + cs
|
||||
if (cs == null || cs.equals(checksum) == false) {
|
||||
log.info("checksumError: request did not pass the checksum security check")
|
||||
log.info("salt: ${securitySalt} checksum: ${cs} client: ${checksum} query: ${queryString}")
|
||||
return false;
|
||||
}
|
||||
log.debug("checksum ok: request passed the checksum security check")
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the welcome message parameter.
|
||||
**/
|
||||
public String processWelcomeMessage(String message, String dialNum, String telVoice, String meetingName) {
|
||||
String welcomeMessage = message
|
||||
if (StringUtils.isEmpty(message)) {
|
||||
welcomeMessage = defaultWelcomeMessage
|
||||
} else {
|
||||
def DIAL_NUM = /%%DIALNUM%%/
|
||||
def CONF_NUM = /%%CONFNUM%%/
|
||||
def CONF_NAME = /%%CONFNAME%%/
|
||||
def keywordList = [DIAL_NUM, CONF_NUM, CONF_NAME];
|
||||
|
||||
keywordList.each { keyword ->
|
||||
switch(keyword){
|
||||
case DIAL_NUM:
|
||||
welcomeMessage = welcomeMessage.replaceAll(DIAL_NUM, dialNum)
|
||||
break
|
||||
case CONF_NUM:
|
||||
welcomeMessage = welcomeMessage.replaceAll(CONF_NUM, telVoice)
|
||||
break
|
||||
case CONF_NAME:
|
||||
welcomeMessage = welcomeMessage.replaceAll(CONF_NAME, meetingName)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return welcomeMessage;
|
||||
}
|
||||
|
||||
|
||||
public void setMeetingService(MeetingService s) {
|
||||
meetingService = s;
|
||||
}
|
||||
}
|
@ -8,9 +8,53 @@ import java.util.ArrayList;
|
||||
import org.bigbluebutton.api.domain.Recording;
|
||||
|
||||
public class RecordingServiceHelperImp implements RecordingServiceHelper {
|
||||
/*
|
||||
<recording>
|
||||
<id>Demo Meeting-3243244</id>
|
||||
<state>available</state>
|
||||
<published>true</published>
|
||||
<start_time>Thu Mar 04 14:05:56 UTC 2010</start_time>
|
||||
<end_time>Thu Mar 04 15:01:01 UTC 2010</end_time>
|
||||
<playback>
|
||||
<format>simple</format>
|
||||
<link>http://server.com/simple/playback?recordingID=Demo Meeting-3243244</link>
|
||||
</playback>
|
||||
<meta>
|
||||
<title>Test Recording 2</title>
|
||||
<subject>English 232 session</subject>
|
||||
<description>Second test recording</description>
|
||||
<creator>Omar Shammas</creator>
|
||||
<contributor>Blindside</contributor>
|
||||
<language>en_US</language>
|
||||
</meta>
|
||||
</recording>
|
||||
*/
|
||||
|
||||
public void writeRecordingInfo(String path, Recording info) {
|
||||
def writer = new StringWriter()
|
||||
def builder = new groovy.xml.MarkupBuilder(writer)
|
||||
def metadataXml = builder.recording {
|
||||
builder.identity(info.getId())
|
||||
builder.state(info.getState())
|
||||
builder.published(info.isPublished())
|
||||
builder.start_time(info.getStartTime())
|
||||
builder.end_time(info.getEndTime())
|
||||
builder.playback {
|
||||
builder.format(info.getPlaybackFormat())
|
||||
builder.link(info.getPlaybackLink())
|
||||
}
|
||||
Map<String,String> meta = info.getMetadata();
|
||||
meta.keySet().each { key ->
|
||||
builder."$key"(meta.get(key))
|
||||
}
|
||||
}
|
||||
|
||||
public Recording getRecordingInfo(String id, String publishedDir, String playbackFormat) {
|
||||
String path = publishedDir + File.pathSeparator + playbackFormat;
|
||||
xmlEventFile = new File(path + File.pathSeparatorChar + "metadata.xml")
|
||||
xmlEventFile.write writer.toString()
|
||||
}
|
||||
|
||||
public Recording getRecordingInfo(String id, String recordingDir, String playbackFormat) {
|
||||
String path = recordingDir + File.pathSeparator + playbackFormat;
|
||||
File dir = new File(path);
|
||||
if (dir.isDirectory()) {
|
||||
def recording = new XmlSlurper().parse(new File(path + File.pathSeparatorChar + "metadata.xml"));
|
||||
|
@ -1,14 +1,181 @@
|
||||
package org.bigbluebutton.api;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.*;
|
||||
import org.bigbluebutton.api.domain.Meeting;
|
||||
import org.bigbluebutton.api.domain.User;
|
||||
import org.bigbluebutton.api.messaging.MessageListener;
|
||||
import org.bigbluebutton.api.messaging.MessagingService;
|
||||
import org.bigbluebutton.web.services.ExpiredMeetingCleanupTimerTask;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
|
||||
public interface MeetingService {
|
||||
public void removeExpiredMeetings();
|
||||
public Collection<Meeting> getMeetings();
|
||||
public void storeMeeting(Meeting m);
|
||||
public void endMeeting(String meetingId);
|
||||
public Meeting getMeeting(String meetingId);
|
||||
public boolean isMeetingWithVoiceBridgeExist(String voiceBridge);
|
||||
void send(String channel, String message);
|
||||
}
|
||||
public class MeetingService {
|
||||
private static Logger log = LoggerFactory.getLogger(MeetingService.class);
|
||||
|
||||
private final ConcurrentMap<String, Meeting> meetings;
|
||||
private int defaultMeetingExpireDuration = 60;
|
||||
private RecordingService recordingService;
|
||||
private MessagingService messagingService;
|
||||
private ExpiredMeetingCleanupTimerTask cleaner;
|
||||
|
||||
|
||||
public MeetingService() {
|
||||
meetings = new ConcurrentHashMap<String, Meeting>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the meetings that have ended from the list of
|
||||
* running meetings.
|
||||
*/
|
||||
// @Override
|
||||
public void removeExpiredMeetings() {
|
||||
for (Meeting m : meetings.values()) {
|
||||
if (m.hasExpired(defaultMeetingExpireDuration) || m.wasNeverStarted(defaultMeetingExpireDuration)) {
|
||||
log.info("Removing expired meeting [{} - {}]", m.getInternalId(), m.getName());
|
||||
meetings.remove(m.getInternalId());
|
||||
continue;
|
||||
}
|
||||
|
||||
if (m.hasExceededDuration()) {
|
||||
log.info("Ending meeting [{} - {}]", m.getInternalId(), m.getName());
|
||||
m.setForciblyEnded(true);
|
||||
endMeeting(m.getInternalId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Collection<Meeting> getMeetings() {
|
||||
log.debug("The number of meetings are: " + meetings.size());
|
||||
return meetings.isEmpty() ? Collections.<Meeting>emptySet() : Collections.unmodifiableCollection(meetings.values());
|
||||
}
|
||||
|
||||
public void createMeeting(Meeting m) {
|
||||
log.debug("Storing Meeting with internal id:" + m.getInternalId());
|
||||
meetings.put(m.getInternalId(), m);
|
||||
}
|
||||
|
||||
public Meeting getMeeting(String meetingId) {
|
||||
if (StringUtils.isEmpty(meetingId)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (String key : meetings.keySet()) {
|
||||
if (key.startsWith(meetingId))
|
||||
return (Meeting) meetings.get(key);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void processRecording(String meetingId) {
|
||||
log.debug("Checking if we need to process recording for [{}]", meetingId);
|
||||
Meeting m = getMeeting(meetingId);
|
||||
if (m != null) {
|
||||
int numUsers = m.getNumUsers();
|
||||
if (numUsers == 0) {
|
||||
recordingService.startIngestAndProcessing(meetingId);
|
||||
} else {
|
||||
log.debug("Meeting [{}] is not empty with {} users.", meetingId, numUsers);
|
||||
}
|
||||
} else {
|
||||
log.warn("Meeting [{}] does not exist.", meetingId);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isMeetingWithVoiceBridgeExist(String voiceBridge) {
|
||||
/* Collection<Meeting> confs = meetings.values();
|
||||
for (Meeting c : confs) {
|
||||
if (voiceBridge == c.getVoiceBridge()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
*/ return false;
|
||||
}
|
||||
|
||||
public void send(String channel, String message) {
|
||||
messagingService.send(channel, message);
|
||||
}
|
||||
|
||||
public void endMeeting(String meetingId) {
|
||||
messagingService.endMeeting(meetingId);
|
||||
}
|
||||
|
||||
public void setDefaultMeetingExpireDuration(int meetingExpiration) {
|
||||
this.defaultMeetingExpireDuration = meetingExpiration;
|
||||
}
|
||||
|
||||
public void setRecordingService(RecordingService s) {
|
||||
recordingService = s;
|
||||
}
|
||||
|
||||
public void setMessagingService(MessagingService mess) {
|
||||
messagingService = mess;
|
||||
messagingService.addListener(new MeetingMessageListener());
|
||||
messagingService.start();
|
||||
}
|
||||
|
||||
public void setExpiredMeetingCleanupTimerTask(ExpiredMeetingCleanupTimerTask c) {
|
||||
cleaner = c;
|
||||
cleaner.setMeetingService(this);
|
||||
cleaner.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Class that listens for messages from bbb-apps.
|
||||
* @author Richard Alam
|
||||
*
|
||||
*/
|
||||
private class MeetingMessageListener implements MessageListener {
|
||||
@Override
|
||||
public void meetingStarted(String meetingId) {
|
||||
Meeting m = getMeeting(meetingId);
|
||||
if (m != null) {
|
||||
m.setStartTime(System.currentTimeMillis());
|
||||
log.debug("Setting meeting started time");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void meetingEnded(String meetingId) {
|
||||
Meeting m = getMeeting(meetingId);
|
||||
if (m != null) {
|
||||
m.setEndTime(System.currentTimeMillis());
|
||||
log.debug("Setting meeting end time");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void userJoined(String meetingId, String userId, String name, String role) {
|
||||
Meeting m = getMeeting(meetingId);
|
||||
if (m != null) {
|
||||
User user = new User(userId, name, role);
|
||||
m.userJoined(user);
|
||||
log.debug("New user in meeting:"+user.getFullname());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void userLeft(String meetingId, String userId) {
|
||||
Meeting m = getMeeting(meetingId);
|
||||
if (m != null) {
|
||||
User user = m.userLeft(userId);
|
||||
log.debug("User removed from meeting:" + user.getFullname());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updatedStatus(String meetingId, String userId, String status, String value) {
|
||||
Meeting m = getMeeting(meetingId);
|
||||
if (m != null) {
|
||||
User user = m.getUserById(userId);
|
||||
user.setStatus(status, value);
|
||||
log.debug("Setting new status value for participant:"+user.getFullname());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,171 +0,0 @@
|
||||
package org.bigbluebutton.api;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.*;
|
||||
import org.bigbluebutton.api.domain.Meeting;
|
||||
import org.bigbluebutton.api.domain.User;
|
||||
import org.bigbluebutton.api.messaging.MessageListener;
|
||||
import org.bigbluebutton.api.messaging.MessagingService;
|
||||
import org.bigbluebutton.web.services.ExpiredMeetingCleanupTimerTask;
|
||||
import org.bigbluebutton.web.services.IDynamicConferenceService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
|
||||
public class MeetingServiceImp implements MeetingService {
|
||||
private static Logger log = LoggerFactory.getLogger(MeetingServiceImp.class);
|
||||
|
||||
private final ConcurrentMap<String, Meeting> meetings;
|
||||
|
||||
private int minutesElapsedBeforeMeetingExpiration = 60;
|
||||
|
||||
private IDynamicConferenceService dynConfService;
|
||||
private MessagingService messagingService;
|
||||
private ExpiredMeetingCleanupTimerTask cleaner;
|
||||
|
||||
public MeetingServiceImp() {
|
||||
meetings = new ConcurrentHashMap<String, Meeting>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the meetings that have ended from the list of
|
||||
* running meetings.
|
||||
*/
|
||||
@Override
|
||||
public void removeExpiredMeetings() {
|
||||
for (Meeting m : meetings.values()) {
|
||||
if (m.hasExpired(minutesElapsedBeforeMeetingExpiration) || m.wasNeverStarted(minutesElapsedBeforeMeetingExpiration)) {
|
||||
log.info("Removing expired meeting [{} - {}]", m.getInternalId(), m.getName());
|
||||
meetings.remove(m.getInternalId());
|
||||
continue;
|
||||
}
|
||||
|
||||
if (m.hasExceededDuration()) {
|
||||
log.info("Ending meeting [{} - {}]", m.getInternalId(), m.getName());
|
||||
m.setForciblyEnded(true);
|
||||
endMeeting(m.getInternalId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Collection<Meeting> getMeetings() {
|
||||
log.debug("The number of meetings are: " + meetings.size());
|
||||
return meetings.isEmpty() ? Collections.<Meeting>emptySet() : Collections.unmodifiableCollection(meetings.values());
|
||||
}
|
||||
|
||||
public void storeMeeting(Meeting m) {
|
||||
log.debug("Storing Meeting with internal id:" + m.getInternalId());
|
||||
meetings.put(m.getInternalId(), m);
|
||||
}
|
||||
|
||||
public Meeting getMeeting(String meetingId) {
|
||||
if (StringUtils.isEmpty(meetingId)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (String key : meetings.keySet()) {
|
||||
if (key.startsWith(meetingId))
|
||||
return (Meeting) meetings.get(key);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public boolean isMeetingWithVoiceBridgeExist(String voiceBridge) {
|
||||
/* Collection<Meeting> confs = meetings.values();
|
||||
for (Meeting c : confs) {
|
||||
if (voiceBridge == c.getVoiceBridge()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
*/ return false;
|
||||
}
|
||||
|
||||
public void send(String channel, String message) {
|
||||
messagingService.send(channel, message);
|
||||
}
|
||||
|
||||
public void endMeeting(String meetingId) {
|
||||
|
||||
messagingService.endMeeting(meetingId);
|
||||
}
|
||||
|
||||
public void setMinutesElapsedBeforeMeetingExpiration(int minutes) {
|
||||
minutesElapsedBeforeMeetingExpiration = minutes;
|
||||
}
|
||||
|
||||
public void setDynamicConferenceService(IDynamicConferenceService s) {
|
||||
dynConfService = s;
|
||||
s.setMeetingService((MeetingService) this);
|
||||
}
|
||||
|
||||
public void setMessagingService(MessagingService mess) {
|
||||
messagingService = mess;
|
||||
messagingService.addListener(new MeetingMessageListener());
|
||||
messagingService.start();
|
||||
}
|
||||
|
||||
public void setExpiredMeetingCleanupTimerTask(ExpiredMeetingCleanupTimerTask c) {
|
||||
cleaner = c;
|
||||
cleaner.setMeetingService(this);
|
||||
cleaner.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Class that listens for messages from bbb-apps.
|
||||
* @author Richard Alam
|
||||
*
|
||||
*/
|
||||
private class MeetingMessageListener implements MessageListener {
|
||||
@Override
|
||||
public void meetingStarted(String meetingId) {
|
||||
Meeting m = getMeeting(meetingId);
|
||||
if (m != null) {
|
||||
m.setStartTime(System.currentTimeMillis());
|
||||
log.debug("Setting meeting started time");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void meetingEnded(String meetingId) {
|
||||
Meeting m = getMeeting(meetingId);
|
||||
if (m != null) {
|
||||
m.setEndTime(System.currentTimeMillis());
|
||||
log.debug("Setting meeting end time");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void userJoined(String meetingId, String userId, String name, String role) {
|
||||
Meeting m = getMeeting(meetingId);
|
||||
if (m != null) {
|
||||
User user = new User(userId, name, role);
|
||||
m.userJoined(user);
|
||||
log.debug("New user in meeting:"+user.getFullname());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void userLeft(String meetingId, String userId) {
|
||||
Meeting m = getMeeting(meetingId);
|
||||
if (m != null) {
|
||||
User user = m.userLeft(userId);
|
||||
log.debug("User removed from meeting:" + user.getFullname());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updatedStatus(String meetingId, String userId, String status, String value) {
|
||||
Meeting m = getMeeting(meetingId);
|
||||
if (m != null) {
|
||||
User user = m.getUserById(userId);
|
||||
user.setStatus(status, value);
|
||||
log.debug("Setting new status value for participant:"+user.getFullname());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,25 +1,51 @@
|
||||
package org.bigbluebutton.api;
|
||||
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
import org.apache.commons.lang.RandomStringUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class ParamsProcessorUtil {
|
||||
private static Logger log = LoggerFactory.getLogger(ParamsProcessorUtil.class);
|
||||
|
||||
private String apiVersion;
|
||||
private boolean serviceEnabled = false;
|
||||
private String securitySalt;
|
||||
private int minutesElapsedBeforeMeetingExpiration = 60;
|
||||
private int defaultMaxUsers = 20;
|
||||
private String defaultWelcomeMessage;
|
||||
private String defaultDialAccessNumber;
|
||||
private String testVoiceBridge;
|
||||
private String testConferenceMock;
|
||||
private String recordingDir;
|
||||
private String recordingFile;
|
||||
private String recordStatusDir;
|
||||
private String defaultLogoutUrl;
|
||||
private String defaultServerUrl;
|
||||
private String defaultNumDigitsForTelVoice;
|
||||
private int defaultNumDigitsForTelVoice;
|
||||
private String defaultClientUrl;
|
||||
private String defaultMeetingDuration;
|
||||
private int defaultMeetingDuration;
|
||||
|
||||
public String getApiVersion() {
|
||||
return apiVersion;
|
||||
}
|
||||
|
||||
public boolean isServiceEnabled() {
|
||||
return serviceEnabled;
|
||||
}
|
||||
|
||||
public String getDefaultClientUrl() {
|
||||
return defaultClientUrl;
|
||||
}
|
||||
|
||||
public String processWelcomeMessage(String message) {
|
||||
String welcomeMessage = message;
|
||||
if (StringUtils.isEmpty(message)) {
|
||||
welcomeMessage = defaultWelcomeMessage;
|
||||
}
|
||||
return welcomeMessage;
|
||||
}
|
||||
|
||||
public String convertToInternalMeetingId(String extMeetingId) {
|
||||
return DigestUtils.shaHex(extMeetingId);
|
||||
}
|
||||
|
||||
public String processPassword(String pass) {
|
||||
return StringUtils.isEmpty(pass) ? RandomStringUtils.randomAlphanumeric(8) : pass;
|
||||
@ -30,7 +56,7 @@ public class ParamsProcessorUtil {
|
||||
}
|
||||
|
||||
public String processTelVoice(String telNum) {
|
||||
return StringUtils.isEmpty(telNum) ? RandomStringUtils.randomNumeric(Integer.parseInt(defaultNumDigitsForTelVoice)) : telNum;
|
||||
return StringUtils.isEmpty(telNum) ? RandomStringUtils.randomNumeric(defaultNumDigitsForTelVoice) : telNum;
|
||||
}
|
||||
|
||||
public String processDialNumber(String dial) {
|
||||
@ -80,7 +106,7 @@ public class ParamsProcessorUtil {
|
||||
try {
|
||||
mDuration = Integer.parseInt(duration);
|
||||
} catch(Exception ex) {
|
||||
mDuration = Integer.parseInt(defaultMeetingDuration);
|
||||
mDuration = defaultMeetingDuration;
|
||||
}
|
||||
|
||||
return mDuration;
|
||||
@ -101,6 +127,30 @@ public class ParamsProcessorUtil {
|
||||
return "";
|
||||
}
|
||||
|
||||
public boolean isChecksumSame(String apiCall, String checksum, String queryString) {
|
||||
log.debug("checksum: [{}] ; query string: [{}]", checksum, queryString);
|
||||
|
||||
if (StringUtils.isEmpty(securitySalt)) {
|
||||
log.warn("Security is disabled in this service. Make sure this is intentional.");
|
||||
return true;
|
||||
}
|
||||
|
||||
// handle either checksum as first or middle / end parameter
|
||||
// TODO: this is hackish - should be done better
|
||||
queryString = queryString.replace("&checksum=" + checksum, "");
|
||||
queryString = queryString.replace("checksum=" + checksum + "&", "");
|
||||
log.debug("query string after checksum removed: [{}]", queryString);
|
||||
String cs = DigestUtils.shaHex(apiCall + queryString + securitySalt);
|
||||
log.debug("our checksum: [{}], client: [{}]", cs, checksum);
|
||||
if (cs == null || cs.equals(checksum) == false) {
|
||||
log.info("checksumError: request did not pass the checksum security check");
|
||||
return false;
|
||||
}
|
||||
log.debug("checksum ok: request passed the checksum security check");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*************************************************
|
||||
* Setters
|
||||
************************************************/
|
||||
@ -109,15 +159,14 @@ public class ParamsProcessorUtil {
|
||||
this.apiVersion = apiVersion;
|
||||
}
|
||||
|
||||
public void setServiceEnabled(boolean e) {
|
||||
serviceEnabled = e;
|
||||
}
|
||||
|
||||
public void setSecuritySalt(String securitySalt) {
|
||||
this.securitySalt = securitySalt;
|
||||
}
|
||||
|
||||
public void setMinutesElapsedBeforeMeetingExpiration(
|
||||
int minutesElapsedBeforeMeetingExpiration) {
|
||||
this.minutesElapsedBeforeMeetingExpiration = minutesElapsedBeforeMeetingExpiration;
|
||||
}
|
||||
|
||||
public void setDefaultMaxUsers(int defaultMaxUsers) {
|
||||
this.defaultMaxUsers = defaultMaxUsers;
|
||||
}
|
||||
@ -138,18 +187,6 @@ public class ParamsProcessorUtil {
|
||||
this.testConferenceMock = testConferenceMock;
|
||||
}
|
||||
|
||||
public void setRecordingDir(String recordingDir) {
|
||||
this.recordingDir = recordingDir;
|
||||
}
|
||||
|
||||
public void setRecordingFile(String recordingFile) {
|
||||
this.recordingFile = recordingFile;
|
||||
}
|
||||
|
||||
public void setRecordStatusDir(String recordStatusDir) {
|
||||
this.recordStatusDir = recordStatusDir;
|
||||
}
|
||||
|
||||
public void setDefaultLogoutUrl(String defaultLogoutUrl) {
|
||||
this.defaultLogoutUrl = defaultLogoutUrl;
|
||||
}
|
||||
@ -158,7 +195,7 @@ public class ParamsProcessorUtil {
|
||||
this.defaultServerUrl = defaultServerUrl;
|
||||
}
|
||||
|
||||
public void setDefaultNumDigitsForTelVoice(String defaultNumDigitsForTelVoice) {
|
||||
public void setDefaultNumDigitsForTelVoice(int defaultNumDigitsForTelVoice) {
|
||||
this.defaultNumDigitsForTelVoice = defaultNumDigitsForTelVoice;
|
||||
}
|
||||
|
||||
@ -166,7 +203,7 @@ public class ParamsProcessorUtil {
|
||||
this.defaultClientUrl = defaultClientUrl;
|
||||
}
|
||||
|
||||
public void setDefaultMeetingDuration(String defaultMeetingDuration) {
|
||||
public void setDefaultMeetingDuration(int defaultMeetingDuration) {
|
||||
this.defaultMeetingDuration = defaultMeetingDuration;
|
||||
}
|
||||
}
|
||||
|
@ -2,14 +2,37 @@ package org.bigbluebutton.api;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.bigbluebutton.api.domain.Recording;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class RecordingService {
|
||||
private static Logger log = LoggerFactory.getLogger(RecordingService.class);
|
||||
|
||||
private String publishedDir = "/var/bigbluebutton/published";
|
||||
private String unpublishedDir = "/var/bigbluebutton/unpublished";
|
||||
private RecordingServiceHelper recordingServiceHelper;
|
||||
private String recordStatusDir;
|
||||
|
||||
public void startIngestAndProcessing(String meetingId) {
|
||||
String done = recordStatusDir + "/" + meetingId + ".done";
|
||||
|
||||
File doneFile = new File(done);
|
||||
if (!doneFile.exists()) {
|
||||
try {
|
||||
doneFile.createNewFile();
|
||||
if (!doneFile.exists())
|
||||
log.error("Failed to create " + done + " file.");
|
||||
} catch (IOException e) {
|
||||
log.error("Failed to create " + done + " file.");
|
||||
}
|
||||
} else {
|
||||
log.error(done + " file already exists.");
|
||||
}
|
||||
}
|
||||
|
||||
public ArrayList<Recording> getRecordings(String meetingId) {
|
||||
ArrayList<Recording> recs = new ArrayList<Recording>();
|
||||
@ -32,29 +55,89 @@ public class RecordingService {
|
||||
|
||||
String[] format = getPlaybackFormats(path);
|
||||
for (int i = 0; i < format.length; i++) {
|
||||
File[] recordings = getDirectories(publishedDir + File.pathSeparatorChar + format[i]);
|
||||
File[] recordings = getDirectories(path + File.pathSeparatorChar + format[i]);
|
||||
for (int f = 0; f < recordings.length; f++) {
|
||||
if (recordings[f].getName().startsWith(meetingId)) {
|
||||
Recording r = getRecordingInfo(recordings[f].getName(), format[i]);
|
||||
Recording r = getRecordingInfo(path, recordings[f].getName(), format[i]);
|
||||
if (r != null) recs.add(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return recs;
|
||||
}
|
||||
|
||||
public Recording getRecordingInfo(String recordingId, String format) {
|
||||
Recording rec = recordingServiceHelper.getRecordingInfo(recordingId, publishedDir, format);
|
||||
return getRecordingInfo(publishedDir, recordingId, format);
|
||||
}
|
||||
|
||||
private Recording getRecordingInfo(String path, String recordingId, String format) {
|
||||
Recording rec = recordingServiceHelper.getRecordingInfo(recordingId, path, format);
|
||||
return rec;
|
||||
}
|
||||
|
||||
public void publish(String recordingId) {
|
||||
|
||||
public void publish(String recordingId, boolean publish) {
|
||||
publish(publishedDir, recordingId, publish);
|
||||
publish(unpublishedDir, recordingId, publish);
|
||||
}
|
||||
|
||||
public void delete(String recordingId) {
|
||||
private void publish(String path, String recordingId, boolean publish) {
|
||||
String[] format = getPlaybackFormats(path);
|
||||
for (int i = 0; i < format.length; i++) {
|
||||
File[] recordings = getDirectories(path + File.pathSeparatorChar + format[i]);
|
||||
for (int f = 0; f < recordings.length; f++) {
|
||||
if (recordings[f].getName().equals(recordingId)) {
|
||||
Recording r = getRecordingInfo(recordingId, path, format[i]);
|
||||
if (r != null) {
|
||||
File dest;
|
||||
if (publish) {
|
||||
dest = new File(publishedDir);
|
||||
} else {
|
||||
dest = new File(unpublishedDir);
|
||||
}
|
||||
boolean moved = recordings[f].renameTo(new File(dest, recordings[f].getName()));
|
||||
if (moved) {
|
||||
r.setPublished(publish);
|
||||
recordingServiceHelper.writeRecordingInfo(dest.getAbsolutePath() + File.pathSeparatorChar + recordings[f].getName(), r);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void delete(String recordingId) {
|
||||
deleteRecording(recordingId, publishedDir);
|
||||
deleteRecording(recordingId, unpublishedDir);
|
||||
}
|
||||
|
||||
private void deleteRecording(String id, String path) {
|
||||
String[] format = getPlaybackFormats(path);
|
||||
for (int i = 0; i < format.length; i++) {
|
||||
File[] recordings = getDirectories(path + File.pathSeparatorChar + format[i]);
|
||||
for (int f = 0; f < recordings.length; f++) {
|
||||
if (recordings[f].getName().equals(id)) {
|
||||
deleteDirectory(recordings[f]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void deleteDirectory(File directory) {
|
||||
/**
|
||||
* Go through each directory and check if it's not empty.
|
||||
* We need to delete files inside a directory before a
|
||||
* directory can be deleted.
|
||||
**/
|
||||
File[] files = directory.listFiles();
|
||||
for (int i = 0; i < files.length; i++) {
|
||||
if (files[i].isDirectory()) {
|
||||
deleteDirectory(files[i]);
|
||||
} else {
|
||||
files[i].delete();
|
||||
}
|
||||
}
|
||||
// Now that the directory is empty. Delete it.
|
||||
directory.delete();
|
||||
}
|
||||
|
||||
private File[] getDirectories(String path) {
|
||||
@ -77,6 +160,14 @@ public class RecordingService {
|
||||
return formats;
|
||||
}
|
||||
|
||||
public void setRecordingStatusDir(String dir) {
|
||||
recordStatusDir = dir;
|
||||
}
|
||||
|
||||
public void setUnpublishedDir(String dir) {
|
||||
unpublishedDir = dir;
|
||||
}
|
||||
|
||||
public void setPublishedDir(String dir) {
|
||||
publishedDir = dir;
|
||||
}
|
||||
|
@ -4,4 +4,5 @@ import org.bigbluebutton.api.domain.Recording;
|
||||
|
||||
public interface RecordingServiceHelper {
|
||||
public Recording getRecordingInfo(String id, String publishedDir, String playbackFormat);
|
||||
public void writeRecordingInfo(String path, Recording info);
|
||||
}
|
||||
|
@ -62,7 +62,11 @@ public class RedisMessagingService implements MessagingService {
|
||||
}
|
||||
|
||||
public void endMeeting(String meetingId) {
|
||||
log.warn("***Need to implement sending of end meeting request!");
|
||||
HashMap<String,String> map = new HashMap<String, String>();
|
||||
map.put("request", "endMeeting");
|
||||
map.put("meetingId", meetingId);
|
||||
Gson gson = new Gson();
|
||||
send(MessagingConstants.SYSTEM_CHANNEL, gson.toJson(map));
|
||||
}
|
||||
|
||||
public void send(String channel, String message) {
|
||||
|
@ -1,7 +1,9 @@
|
||||
package org.bigbluebutton.web.controllers
|
||||
|
||||
import grails.test.*
|
||||
import org.bigbluebutton.web.services.DynamicConferenceService;
|
||||
|
||||
import org.bigbluebutton.api.ParamsProcessorUtil;
|
||||
import org.bigbluebutton.api.RecordingService;
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
import org.bigbluebutton.api.*;
|
||||
import org.bigbluebutton.api.domain.Meeting;
|
||||
@ -10,31 +12,51 @@ import org.bigbluebutton.api.messaging.NullMessagingService;
|
||||
import org.bigbluebutton.api.messaging.MessagingService;
|
||||
|
||||
class ApiControllerTests extends ControllerUnitTestCase {
|
||||
String API_VERSION = "0.7"
|
||||
String SALT = 'ab56fda9fc1c2bde2d65ff76134b47ad'
|
||||
final String API_VERSION = "0.7"
|
||||
final boolean SERVICE_ENABLED = true;
|
||||
final String SALT = 'ab56fda9fc1c2bde2d65ff76134b47ad'
|
||||
final int DEF_MAX_USERS = 20
|
||||
final String DEF_WELCOME_MSG = "<br>Welcome to this BigBlueButton Demo Server.<br><br>For help using BigBlueButton <a href=\"event:http://www.bigbluebutton.org/content/videos\"><u>check out these videos</u></a>.<br><br>"
|
||||
final String DEF_DIAL_NUMER = "613-555-1234"
|
||||
final String TEST_VOICE_BRIDGE = "9999"
|
||||
final String TEST_CONF_MOCK = "conference-mock-default"
|
||||
final String DEF_LOGOUT_URL = ""
|
||||
final String DEF_SERVER_URL = "http://192.168.0.166"
|
||||
final int DEF_NUM_FOR_VOICE = 5;
|
||||
final String DEF_CLIENT_URL = "http://localhost/client/BigBlueButton.html"
|
||||
final int DEF_MEETING_DURATION = 210;
|
||||
|
||||
String MEETING_ID = "default-meeting-id"
|
||||
String MEETING_NAME = "Default Meeting"
|
||||
String MOD_PASS = "modpass"
|
||||
String VIEW_PASS = "viewpass"
|
||||
String CLIENT_URL = "http://localhost/client/BigBlueButton.html"
|
||||
long CREATE_TIME = 1234567890
|
||||
|
||||
def dynamicConferenceService
|
||||
MeetingServiceImp meetingService
|
||||
RecordingService recordingService
|
||||
MeetingService meetingService
|
||||
ParamsProcessorUtil ppu = new ParamsProcessorUtil();
|
||||
|
||||
protected void setUp() {
|
||||
super.setUp()
|
||||
mockLogging(DynamicConferenceService)
|
||||
dynamicConferenceService = new DynamicConferenceService()
|
||||
meetingService = new MeetingServiceImp()
|
||||
mockLogging(RecordingService)
|
||||
recordingService = new RecordingService()
|
||||
meetingService = new MeetingService()
|
||||
MessagingService ms = new NullMessagingService();
|
||||
meetingService.setMessagingService(ms);
|
||||
dynamicConferenceService.setMeetingService(meetingService)
|
||||
dynamicConferenceService.apiVersion = API_VERSION
|
||||
dynamicConferenceService.securitySalt = SALT
|
||||
dynamicConferenceService.defaultNumDigitsForTelVoice = 5
|
||||
dynamicConferenceService.defaultNumDigitsForTelVoice = 5
|
||||
dynamicConferenceService.defaultClientUrl = CLIENT_URL
|
||||
|
||||
ppu.setApiVersion(API_VERSION)
|
||||
ppu.setSecuritySalt(SALT);
|
||||
ppu.setDefaultNumDigitsForTelVoice(5)
|
||||
ppu.setDefaultClientUrl(DEF_CLIENT_URL)
|
||||
ppu.setDefaultMeetingDuration(DEF_MEETING_DURATION);
|
||||
ppu.setDefaultDialAccessNumber(DEF_DIAL_NUMER);
|
||||
ppu.setDefaultMaxUsers(DEF_MAX_USERS);
|
||||
ppu.setDefaultLogoutUrl(DEF_LOGOUT_URL);
|
||||
ppu.setDefaultWelcomeMessage(DEF_WELCOME_MSG);
|
||||
ppu.setServiceEnabled(SERVICE_ENABLED);
|
||||
ppu.setTestConferenceMock(TEST_CONF_MOCK);
|
||||
ppu.setTestVoiceBridge(VIEW_PASS);
|
||||
|
||||
}
|
||||
|
||||
protected void tearDown() {
|
||||
@ -44,7 +66,8 @@ class ApiControllerTests extends ControllerUnitTestCase {
|
||||
void testIndex() {
|
||||
ApiController controller = new ApiController()
|
||||
mockLogging(ApiController)
|
||||
controller.setDynamicConferenceService(dynamicConferenceService)
|
||||
controller.setMeetingService(meetingService)
|
||||
controller.setParamsProcessorUtil(ppu);
|
||||
controller.index()
|
||||
println "controller response = " + controller.response.contentAsString
|
||||
}
|
||||
@ -52,7 +75,8 @@ class ApiControllerTests extends ControllerUnitTestCase {
|
||||
void testCreateAPI() {
|
||||
ApiController controller = new ApiController()
|
||||
mockLogging(ApiController)
|
||||
controller.setDynamicConferenceService(dynamicConferenceService)
|
||||
controller.setMeetingService(meetingService)
|
||||
controller.setParamsProcessorUtil(ppu);
|
||||
createMeeting(controller)
|
||||
controller.create()
|
||||
|
||||
@ -63,46 +87,46 @@ class ApiControllerTests extends ControllerUnitTestCase {
|
||||
/**
|
||||
* Now that the meeting has been setup. Try to join it.
|
||||
*/
|
||||
ApiController controller2 = new ApiController()
|
||||
ApiController controller = new ApiController()
|
||||
mockLogging(ApiController)
|
||||
controller2.setDynamicConferenceService(dynamicConferenceService)
|
||||
|
||||
controller.setMeetingService(meetingService)
|
||||
controller.setParamsProcessorUtil(ppu);
|
||||
// Create a conference. This prevents us from calling the CREATE API
|
||||
dynamicConferenceService.createMeeting(createDefaultMeeting())
|
||||
meetingService.createMeeting(createDefaultMeeting())
|
||||
|
||||
joinMeeting(controller2)
|
||||
controller2.join()
|
||||
println "controller response = " + controller2.response.contentAsString
|
||||
joinMeeting(controller)
|
||||
controller.join()
|
||||
println "controller response = " + controller.response.contentAsString
|
||||
/**
|
||||
* Need to use controller2.redirectArgs['url'] instead of controller2.response.redirectedUrl as
|
||||
* shown in the grails doc because it is returning null for me.
|
||||
*
|
||||
* see http://kousenit.wordpress.com/2010/11/10/unit-testing-grails-controllers-revisited/
|
||||
*/
|
||||
assertEquals CLIENT_URL, controller2.redirectArgs['url']
|
||||
assertEquals DEF_CLIENT_URL, controller.redirectArgs['url']
|
||||
}
|
||||
|
||||
void testIsMeetingRunningAPI() {
|
||||
ApiController controller3 = new ApiController()
|
||||
ApiController controller = new ApiController()
|
||||
mockLogging(ApiController)
|
||||
controller3.setDynamicConferenceService(dynamicConferenceService)
|
||||
|
||||
controller.setMeetingService(meetingService)
|
||||
controller.setParamsProcessorUtil(ppu);
|
||||
// Create a conference. This prevents us from calling the CREATE API
|
||||
dynamicConferenceService.createMeeting(createDefaultMeeting())
|
||||
meetingService.createMeeting(createDefaultMeeting())
|
||||
|
||||
isMeetingRunning(controller3)
|
||||
controller3.isMeetingRunning()
|
||||
println "controller response = " + controller3.response.contentAsString
|
||||
isMeetingRunning(controller)
|
||||
controller.isMeetingRunning()
|
||||
println "controller response = " + controller.response.contentAsString
|
||||
}
|
||||
|
||||
|
||||
void testEndAPI() {
|
||||
ApiController endCtlr = new ApiController()
|
||||
mockLogging(ApiController)
|
||||
endCtlr.setDynamicConferenceService(dynamicConferenceService)
|
||||
|
||||
endCtlr.setMeetingService(meetingService)
|
||||
endCtlr.setParamsProcessorUtil(ppu);
|
||||
// Create a conference. This prevents us from calling the CREATE API
|
||||
dynamicConferenceService.createMeeting(createDefaultMeeting())
|
||||
meetingService.createMeeting(createDefaultMeeting())
|
||||
|
||||
endMeeting(endCtlr)
|
||||
endCtlr.end()
|
||||
@ -112,14 +136,14 @@ class ApiControllerTests extends ControllerUnitTestCase {
|
||||
void testGetMeetingInfo() {
|
||||
ApiController gmiCtlr = new ApiController()
|
||||
mockLogging(ApiController)
|
||||
gmiCtlr.setDynamicConferenceService(dynamicConferenceService)
|
||||
|
||||
gmiCtlr.setMeetingService(meetingService)
|
||||
gmiCtlr.setParamsProcessorUtil(ppu);
|
||||
// Create a conference. This prevents us from calling the CREATE API
|
||||
Meeting m = createDefaultMeeting()
|
||||
// Add a user.
|
||||
User u = new User("test-user", "Test User", "MODERATOR");
|
||||
m.userJoined(u);
|
||||
dynamicConferenceService.createMeeting(m)
|
||||
meetingService.createMeeting(m)
|
||||
|
||||
getMeetingInfo(gmiCtlr)
|
||||
gmiCtlr.getMeetingInfo()
|
||||
@ -129,17 +153,17 @@ class ApiControllerTests extends ControllerUnitTestCase {
|
||||
void testGetMeetings() {
|
||||
ApiController gmCtlr = new ApiController()
|
||||
mockLogging(ApiController)
|
||||
gmCtlr.setDynamicConferenceService(dynamicConferenceService)
|
||||
|
||||
gmCtlr.setMeetingService(meetingService)
|
||||
gmCtlr.setParamsProcessorUtil(ppu);
|
||||
// Create a conference. This prevents us from calling the CREATE API
|
||||
Meeting m = createDefaultMeeting()
|
||||
// Add a user.
|
||||
User u = new User("test-user", "Test User", "MODERATOR");
|
||||
m.userJoined(u);
|
||||
dynamicConferenceService.createMeeting(m)
|
||||
meetingService.createMeeting(m)
|
||||
|
||||
// Create another meeting
|
||||
dynamicConferenceService.createMeeting(createAnotherMeeting());
|
||||
meetingService.createMeeting(createAnotherMeeting());
|
||||
|
||||
getMeetings(gmCtlr)
|
||||
gmCtlr.getMeetings()
|
||||
@ -153,7 +177,7 @@ class ApiControllerTests extends ControllerUnitTestCase {
|
||||
|
||||
private Meeting createDefaultMeeting() {
|
||||
|
||||
String internalMeetingId = dynamicConferenceService.convertToInternalMeetingId(MEETING_ID)
|
||||
String internalMeetingId = ppu.convertToInternalMeetingId(MEETING_ID)
|
||||
String logoutUrl = "http://localhost"
|
||||
String telVoice = "85115"
|
||||
String webVoice = "bbb-85115"
|
||||
@ -178,7 +202,7 @@ class ApiControllerTests extends ControllerUnitTestCase {
|
||||
|
||||
private Meeting createAnotherMeeting() {
|
||||
String externalMeetingId = "cook-with-omar"
|
||||
String internalMeetingId = dynamicConferenceService.convertToInternalMeetingId(externalMeetingId)
|
||||
String internalMeetingId = ppu.convertToInternalMeetingId(externalMeetingId)
|
||||
String logoutUrl = "http://localhost"
|
||||
String telVoice = "85116"
|
||||
String webVoice = "bbb-85116"
|
||||
|
@ -1,46 +0,0 @@
|
||||
package org.bigbluebutton.web.services;
|
||||
|
||||
import groovy.util.GroovyTestCase;
|
||||
|
||||
|
||||
class DynamicConferenceServiceTests extends GroovyTestCase {
|
||||
|
||||
protected void setUp() {
|
||||
super.setUp()
|
||||
}
|
||||
|
||||
protected void tearDown() {
|
||||
super.tearDown()
|
||||
}
|
||||
|
||||
void testIsValidMeetingId() {
|
||||
DynamicConferenceService service = new DynamicConferenceService()
|
||||
assertTrue(service.isValidMeetingId("test-meeting"))
|
||||
assertFalse(service.isValidMeetingId("test meeting"))
|
||||
assertFalse(service.isValidMeetingId("test.meeting-valid name"))
|
||||
}
|
||||
|
||||
void testProcessMeetingInfo() {
|
||||
Map params = new LinkedHashMap()
|
||||
params.put("ext_sakai_server", "http://192.168.0.60:8080");
|
||||
params.put("oauth_nonce", "2936012982701750");
|
||||
params.put("oauth_consumer_key", "fred");
|
||||
params.put("context_label", "BasicLTI Test");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
DynamicConference conf = new DynamicConference("Test Conf", "abc", "123", "456", 30);
|
||||
service.storeConference(conf);
|
||||
|
||||
assertEquals(conf, service.getConferenceByMeetingID("abc"));
|
||||
|
||||
assertNull(service.getConferenceByMeetingID("abd"));
|
||||
assertNull(service.getConferenceByMeetingID(conf.getMeetingToken()));
|
||||
|
||||
assertNull(service.getConferenceByMeetingID("abcd"));
|
||||
|
||||
assertEquals(conf, service.getConferenceByMeetingID("abc"));
|
||||
*/
|
Loading…
Reference in New Issue
Block a user