- refactor how default presentation is downloaded

This commit is contained in:
Richard Alam 2015-10-21 20:51:58 +00:00
parent 9c527be4f0
commit c47272fd2c
9 changed files with 153 additions and 83 deletions

View File

@ -13,7 +13,7 @@ public class CreateBreakoutRoomRequest implements IBigBlueButtonMessage {
this.payload = payload;
}
static class CreateBreakoutRoomRequestPayload {
public static class CreateBreakoutRoomRequestPayload {
public final String meetingId; // The main meeting internal id
public final String name; // The name of the breakout room
public final String voiceConfId; // The voice conference id

View File

@ -186,11 +186,12 @@ beans.presentationService.testUploadedPresentation=appkonference.txt
# Default Uploaded presentation file
beans.presentationService.defaultUploadedPresentation=${bigbluebutton.web.serverURL}/default.pdf
presentationBaseURL=${bigbluebutton.web.serverURL}/bigbluebutton/presentation
#----------------------------------------------------
# The URL where the presentations will be loaded from.
#----------------------------------------------------
beans.presentationService.presentationBaseUrl=${bigbluebutton.web.serverURL}/bigbluebutton/presentation
beans.presentationService.presentationBaseUrl=${presentationBaseURL}
#----------------------------------------------------
# Inject values into grails service beans
beans.presentationService.presentationDir=${presentationDir}

View File

@ -19,39 +19,42 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
-->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-2.0.xsd
">
<bean id="messagingService" class="org.bigbluebutton.api.messaging.RedisMessagingService">
<property name="messageSender" ref="messageSender"/>
<property name="redisStorageService" ref="redisStorageService"/>
</bean>
<bean id="expiredMeetingCleanupTimerTask" class="org.bigbluebutton.web.services.ExpiredMeetingCleanupTimerTask"/>
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-2.0.xsd">
<bean id="messagingService" class="org.bigbluebutton.api.messaging.RedisMessagingService">
<property name="messageSender" ref="messageSender"/>
<property name="redisStorageService" ref="redisStorageService"/>
</bean>
<bean id="expiredMeetingCleanupTimerTask" class="org.bigbluebutton.web.services.ExpiredMeetingCleanupTimerTask"/>
<bean id="keepAliveService" class="org.bigbluebutton.web.services.KeepAliveService"
init-method="start" destroy-method="stop">
<property name="runEvery" value="${checkBBBServerEvery}"/>
<property name="messagingService" ref="messagingService" />
</bean>
<bean id="meetingService" class="org.bigbluebutton.api.MeetingService" init-method="start" destroy-method="stop">
<property name="defaultMeetingExpireDuration" value="${defaultMeetingExpireDuration}"/>
<property name="defaultMeetingCreateJoinDuration" value="${defaultMeetingCreateJoinDuration}"/>
<property name="removeMeetingWhenEnded" value="${removeMeetingWhenEnded}"/>
<property name="expiredMeetingCleanupTimerTask" ref="expiredMeetingCleanupTimerTask"/>
<property name="messagingService" ref="messagingService"/>
<property name="recordingService" ref="recordingService"/>
<bean id="meetingService" class="org.bigbluebutton.api.MeetingService" init-method="start" destroy-method="stop">
<property name="defaultMeetingExpireDuration" value="${defaultMeetingExpireDuration}"/>
<property name="defaultMeetingCreateJoinDuration" value="${defaultMeetingCreateJoinDuration}"/>
<property name="removeMeetingWhenEnded" value="${removeMeetingWhenEnded}"/>
<property name="expiredMeetingCleanupTimerTask" ref="expiredMeetingCleanupTimerTask"/>
<property name="messagingService" ref="messagingService"/>
<property name="recordingService" ref="recordingService"/>
</bean>
<bean id="recordingServiceHelper" class="org.bigbluebutton.api.RecordingServiceHelperImp"/>
<bean id="presDownloadService" class="org.bigbluebutton.presentation.PresentationUrlDownloadService"/>
<bean id="presDownloadService" class="org.bigbluebutton.presentation.PresentationUrlDownloadService">
<property name="presentationDir" value="${presentationDir}"/>
<property name="presentationBaseURL" value="${presentationBaseURL}"/>
<property name="documentConversionService" ref="documentConversionService"/>
</bean>
<bean id="recordingService" class="org.bigbluebutton.api.RecordingService" >
<property name="recordingStatusDir" value="${recordStatusDir}"/>

View File

@ -171,11 +171,7 @@ class ApiController {
}
Meeting newMeeting = paramsProcessorUtil.processCreateParams(params);
if (! StringUtils.isEmpty(params.moderatorOnlyMessage)) {
newMeeting.setModeratorOnlyMessage(params.moderatorOnlyMessage);
}
meetingService.createMeeting(newMeeting);
// See if the request came with pre-uploading of presentation.
@ -1949,7 +1945,7 @@ class ApiController {
requestBody = StringUtils.isEmpty(requestBody) ? null : requestBody;
if (requestBody == null) {
downloadAndProcessDocument(presentationService.defaultUploadedPresentation, conf.getInternalId());
presDownloadService.downloadAndProcessDocument(presentationService.defaultUploadedPresentation, conf.getInternalId());
} else {
log.debug "Request body: \n" + requestBody;
def xml = new XmlSlurper().parseText(requestBody);
@ -1960,7 +1956,7 @@ class ApiController {
// need to iterate over presentation files and process them
module.children().each { document ->
if (!StringUtils.isEmpty(document.@url.toString())) {
downloadAndProcessDocument(document.@url.toString(), conf.getInternalId());
presDownloadService.downloadAndProcessDocument(document.@url.toString(), conf.getInternalId());
} else if (!StringUtils.isEmpty(document.@name.toString())) {
def b64 = new Base64()
def decodedBytes = b64.decode(document.text().getBytes())
@ -1989,40 +1985,11 @@ class ApiController {
fos.flush()
fos.close()
processUploadedFile(meetingId, presId, presFilename, pres);
presDownloadService.processUploadedFile(meetingId, presId, presFilename, pres);
}
}
def downloadAndProcessDocument(address, meetingId) {
log.debug("ApiController#downloadAndProcessDocument(${address}, ${meetingId})");
String presFilename = address.tokenize("/")[-1];
def filenameExt = presDownloadService.getFilenameExt(presFilename);
String presentationDir = presentationService.getPresentationDir()
def presId = presDownloadService.generatePresentationId(presFilename)
File uploadDir = presDownloadService.createPresentationDirectory(meetingId, presentationDir, presId)
if (uploadDir != null) {
def newFilename = presDownloadService.createNewFilename(presId, filenameExt)
def newFilePath = uploadDir.absolutePath + File.separatorChar + newFilename
if (presDownloadService.savePresentation(meetingId, newFilePath, address)) {
def pres = new File(newFilePath)
processUploadedFile(meetingId, presId, presFilename, pres);
} else {
log.error("Failed to download presentation=[${address}], meeting=[${meetingId}]")
}
}
}
def processUploadedFile(meetingId, presId, filename, presFile) {
def presentationBaseUrl = presentationService.presentationBaseUrl
UploadedPresentation uploadedPres = new UploadedPresentation(meetingId, presId, filename, presentationBaseUrl);
uploadedPres.setUploadedFile(presFile);
presentationService.processUploadedPresentation(uploadedPres);
}
def beforeInterceptor = {
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.")

View File

@ -44,6 +44,7 @@ import org.bigbluebutton.api.domain.User;
import org.bigbluebutton.api.domain.UserSession;
import org.bigbluebutton.api.messaging.MessageListener;
import org.bigbluebutton.api.messaging.MessagingService;
import org.bigbluebutton.api.messaging.messages.CreateBreakoutRoom;
import org.bigbluebutton.api.messaging.messages.CreateMeeting;
import org.bigbluebutton.api.messaging.messages.EndMeeting;
import org.bigbluebutton.api.messaging.messages.IMessage;
@ -63,30 +64,31 @@ import org.bigbluebutton.api.messaging.messages.UserUnsharedWebcam;
import org.bigbluebutton.web.services.ExpiredMeetingCleanupTimerTask;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.Gson;
public class MeetingService implements MessageListener {
private static Logger log = LoggerFactory.getLogger(MeetingService.class);
private static Logger log = LoggerFactory.getLogger(MeetingService.class);
private BlockingQueue<IMessage> receivedMessages = new LinkedBlockingQueue<IMessage>();
private volatile boolean processMessage = false;
private final Executor msgProcessorExec = Executors.newSingleThreadExecutor();
private final Executor runExec = Executors.newSingleThreadExecutor();
/**
* http://ria101.wordpress.com/2011/12/12/concurrenthashmap-avoid-a-common-misuse/
*/
private final ConcurrentMap<String, Meeting> meetings;
private final ConcurrentMap<String, UserSession> sessions;
private int defaultMeetingExpireDuration = 1;
private int defaultMeetingCreateJoinDuration = 5;
private RecordingService recordingService;
private MessagingService messagingService;
private ExpiredMeetingCleanupTimerTask cleaner;
private boolean removeMeetingWhenEnded = false;
private BlockingQueue<IMessage> receivedMessages = new LinkedBlockingQueue<IMessage>();
private volatile boolean processMessage = false;
private final Executor msgProcessorExec = Executors.newSingleThreadExecutor();
private final Executor runExec = Executors.newSingleThreadExecutor();
/**
* http://ria101.wordpress.com/2011/12/12/concurrenthashmap-avoid-a-common-misuse/
*/
private final ConcurrentMap<String, Meeting> meetings;
private final ConcurrentMap<String, UserSession> sessions;
private int defaultMeetingExpireDuration = 1;
private int defaultMeetingCreateJoinDuration = 5;
private RecordingService recordingService;
private MessagingService messagingService;
private ExpiredMeetingCleanupTimerTask cleaner;
private boolean removeMeetingWhenEnded = false;
private ParamsProcessorUtil paramsProcessorUtil;
public MeetingService() {
meetings = new ConcurrentHashMap<String, Meeting>(8, 0.9f, 1);
sessions = new ConcurrentHashMap<String, UserSession>(8, 0.9f, 1);
@ -437,6 +439,10 @@ public class MeetingService implements MessageListener {
handle(new EndMeeting(meetingId));
}
private void processCreateBreakoutRoom(CreateBreakoutRoom message) {
}
private void processEndMeeting(EndMeeting message) {
messagingService.endMeeting(message.meetingId);
@ -682,7 +688,9 @@ public class MeetingService implements MessageListener {
processEndMeeting((EndMeeting)message);
} else if (message instanceof RegisterUser) {
processRegisterUser((RegisterUser) message);
}
} else if (message instanceof CreateBreakoutRoom) {
processCreateBreakoutRoom((CreateBreakoutRoom) message);
}
}
};
@ -750,4 +758,8 @@ public class MeetingService implements MessageListener {
public void setRemoveMeetingWhenEnded(boolean s) {
removeMeetingWhenEnded = s;
}
public void setParamsProcessorUtil(ParamsProcessorUtil util) {
this.paramsProcessorUtil = util;
}
}

View File

@ -362,6 +362,11 @@ public class ParamsProcessorUtil {
String configXML = getDefaultConfigXML();
meeting.storeConfig(true, configXML);
if (! StringUtils.isEmpty(params.get("moderatorOnlyMessage"))) {
String moderatorOnlyMessage = params.get("moderatorOnlyMessage");
meeting.setModeratorOnlyMessage(moderatorOnlyMessage);
}
return meeting;
}

View File

@ -2,6 +2,7 @@ package org.bigbluebutton.api.messaging;
import java.util.Set;
import org.bigbluebutton.api.messaging.messages.CreateBreakoutRoom;
import org.bigbluebutton.api.messaging.messages.IMessage;
import org.bigbluebutton.api.messaging.messages.KeepAliveReply;
import org.bigbluebutton.api.messaging.messages.MeetingDestroyed;
@ -67,6 +68,11 @@ public class MeetingMessageHandler implements MessageHandler {
} else if (CreateBreakoutRoomRequest.NAME.equals(messageName)) {
Gson gson = new Gson();
CreateBreakoutRoomRequest msg = gson.fromJson(message, CreateBreakoutRoomRequest.class);
for (MessageListener listener : listeners) {
listener.handle(new CreateBreakoutRoom(msg.payload.meetingId,
msg.payload.name, msg.payload.voiceConfId, msg.payload.viewerPassword,
msg.payload.moderatorPassword, msg.payload.durationInMinutes, msg.payload.defaultPresentationURL));
}
}
}
}

View File

@ -0,0 +1,25 @@
package org.bigbluebutton.api.messaging.messages;
public class CreateBreakoutRoom implements IMessage {
public final String meetingId; // The main meeting internal id
public final String name; // The name of the breakout room
public final String voiceConfId; // The voice conference id
public final String viewerPassword;
public final String moderatorPassword;
public final Integer durationInMinutes; // The duration of the breakout room
public final String defaultPresentationURL;
public CreateBreakoutRoom(String meetingId, String name,
String voiceConfId, String viewerPassword, String moderatorPassword,
Integer duration, String defaultPresentationURL) {
this.meetingId = meetingId;
this.name = name;
this.voiceConfId = voiceConfId;
this.viewerPassword = viewerPassword;
this.moderatorPassword = moderatorPassword;
this.durationInMinutes = duration;
this.defaultPresentationURL = defaultPresentationURL;
}
}

View File

@ -5,6 +5,8 @@ import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Timer;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
@ -18,7 +20,42 @@ public class PresentationUrlDownloadService {
private static Logger log = LoggerFactory.getLogger(PresentationUrlDownloadService.class);
private final int maxRedirects = 5;
private DocumentConversionService documentConversionService;
private String presentationBaseURL;
private String presentationDir;
public void processUploadedPresentation(UploadedPresentation uploadedPres) {
documentConversionService.processDocument(uploadedPres);
}
public void processUploadedFile(String meetingId, String presId, String filename, File presFile) {
UploadedPresentation uploadedPres = new UploadedPresentation(meetingId, presId, filename, presentationBaseURL);
uploadedPres.setUploadedFile(presFile);
processUploadedPresentation(uploadedPres);
}
public void downloadAndProcessDocument(String address, String meetingId) {
log.debug("downloadAndProcessDocument [pres=" + address + ", meeting=" + meetingId + "]");
String presFilename = address.substring(address.lastIndexOf('/') + 1);
log.debug("downloadAndProcessDocument [filename=" + presFilename + "]");
String filenameExt = getFilenameExt(presFilename);
String presId = generatePresentationId(presFilename);
File uploadDir = createPresentationDirectory(meetingId, presentationDir, presId);
if (uploadDir != null) {
String newFilename = createNewFilename(presId, filenameExt);
String newFilePath = uploadDir.getAbsolutePath() + File.separatorChar + newFilename;
if (savePresentation(meetingId, newFilePath, address)) {
File pres = new File(newFilePath);
processUploadedFile(meetingId, presId, presFilename, pres);
} else {
log.error("Failed to download presentation=[" + address + "], meeting=[" + meetingId + "]");
}
}
}
public String generatePresentationId(String name) {
long timestamp = System.currentTimeMillis();
return DigestUtils.shaHex(name) + "-" + timestamp;
@ -115,4 +152,18 @@ public class PresentationUrlDownloadService {
return success;
}
public void setPresentationDir(String presDir) {
presentationDir = presDir;
}
public void setPresentationBaseURL(String presentationBaseUrl) {
presentationBaseURL = presentationBaseUrl;
}
public void setDocumentConversionService(DocumentConversionService documentConversionService) {
this.documentConversionService = documentConversionService;
}
}