Merge pull request #15855 from GuiLeme/backport-pdf-100
This commit is contained in:
commit
195beda6cb
@ -24,7 +24,8 @@ class PresentationPodHdlrs(implicit val context: ActorContext)
|
||||
with RemovePresentationPodPubMsgHdlr
|
||||
with PresentationPageConvertedSysMsgHdlr
|
||||
with PresentationPageConversionStartedSysMsgHdlr
|
||||
with PresentationConversionEndedSysMsgHdlr {
|
||||
with PresentationConversionEndedSysMsgHdlr
|
||||
with PresentationUploadedFileTimeoutErrorPubMsgHdlr {
|
||||
|
||||
val log = Logging(context.system, getClass)
|
||||
}
|
||||
|
@ -0,0 +1,38 @@
|
||||
package org.bigbluebutton.core.apps.presentationpod
|
||||
|
||||
import org.bigbluebutton.common2.msgs._
|
||||
import org.bigbluebutton.core.bus.MessageBus
|
||||
import org.bigbluebutton.core.domain.MeetingState2x
|
||||
import org.bigbluebutton.core.running.LiveMeeting
|
||||
|
||||
trait PresentationUploadedFileTimeoutErrorPubMsgHdlr {
|
||||
this: PresentationPodHdlrs =>
|
||||
|
||||
def handle(
|
||||
msg: PresentationUploadedFileTimeoutErrorSysPubMsg, state: MeetingState2x,
|
||||
liveMeeting: LiveMeeting, bus: MessageBus
|
||||
): MeetingState2x = {
|
||||
|
||||
def broadcastEvent(msg: PresentationUploadedFileTimeoutErrorSysPubMsg): Unit = {
|
||||
val routing = Routing.addMsgToClientRouting(
|
||||
MessageTypes.BROADCAST_TO_MEETING,
|
||||
liveMeeting.props.meetingProp.intId, msg.header.userId
|
||||
)
|
||||
val envelope = BbbCoreEnvelope(PresentationUploadedFileTooLargeErrorEvtMsg.NAME, routing)
|
||||
val header = BbbClientMsgHeader(
|
||||
PresentationUploadedFileTooLargeErrorEvtMsg.NAME,
|
||||
liveMeeting.props.meetingProp.intId, msg.header.userId
|
||||
)
|
||||
|
||||
val body = PresentationUploadedFileTimeoutErrorEvtMsgBody(msg.body.podId, msg.body.meetingId,
|
||||
msg.body.presentationName, msg.body.page, msg.body.messageKey, msg.body.temporaryPresentationId,
|
||||
msg.body.presentationId, msg.body.maxNumberOfAttempts)
|
||||
val event = PresentationUploadedFileTimeoutErrorEvtMsg(header, body)
|
||||
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
|
||||
bus.outGW.send(msgEvent)
|
||||
}
|
||||
|
||||
broadcastEvent(msg)
|
||||
state
|
||||
}
|
||||
}
|
@ -280,6 +280,8 @@ class ReceivedJsonMsgHandlerActor(
|
||||
routeGenericMsg[PreuploadedPresentationsSysPubMsg](envelope, jsonNode)
|
||||
case PresentationUploadedFileTooLargeErrorSysPubMsg.NAME =>
|
||||
routeGenericMsg[PresentationUploadedFileTooLargeErrorSysPubMsg](envelope, jsonNode)
|
||||
case PresentationUploadedFileTimeoutErrorSysPubMsg.NAME =>
|
||||
routeGenericMsg[PresentationUploadedFileTimeoutErrorSysPubMsg](envelope, jsonNode)
|
||||
case PresentationConversionUpdateSysPubMsg.NAME =>
|
||||
routeGenericMsg[PresentationConversionUpdateSysPubMsg](envelope, jsonNode)
|
||||
case PresentationPageCountErrorSysPubMsg.NAME =>
|
||||
|
@ -509,6 +509,7 @@ class MeetingActor(
|
||||
case m: SetPresentationDownloadablePubMsg => state = presentationPodsApp.handle(m, state, liveMeeting, msgBus)
|
||||
case m: PresentationConversionUpdateSysPubMsg => state = presentationPodsApp.handle(m, state, liveMeeting, msgBus)
|
||||
case m: PresentationUploadedFileTooLargeErrorSysPubMsg => state = presentationPodsApp.handle(m, state, liveMeeting, msgBus)
|
||||
case m: PresentationUploadedFileTimeoutErrorSysPubMsg => state = presentationPodsApp.handle(m, state, liveMeeting, msgBus)
|
||||
case m: PresentationPageGeneratedSysPubMsg => state = presentationPodsApp.handle(m, state, liveMeeting, msgBus)
|
||||
case m: PresentationPageCountErrorSysPubMsg => state = presentationPodsApp.handle(m, state, liveMeeting, msgBus)
|
||||
case m: PresentationUploadTokenReqMsg => state = presentationPodsApp.handle(m, state, liveMeeting, msgBus)
|
||||
|
@ -165,6 +165,22 @@ case class PresentationUploadedFileTooLargeErrorSysPubMsgBody(
|
||||
maxFileSize: Int
|
||||
)
|
||||
|
||||
object PresentationUploadedFileTimeoutErrorSysPubMsg { val NAME = "PresentationUploadedFileTimeoutErrorSysPubMsg" }
|
||||
case class PresentationUploadedFileTimeoutErrorSysPubMsg(
|
||||
header: BbbClientMsgHeader,
|
||||
body: PresentationUploadedFileTimeoutErrorSysPubMsgBody
|
||||
) extends StandardMsg
|
||||
case class PresentationUploadedFileTimeoutErrorSysPubMsgBody(
|
||||
podId: String,
|
||||
meetingId: String,
|
||||
presentationName: String,
|
||||
page: Int,
|
||||
messageKey: String,
|
||||
temporaryPresentationId: String,
|
||||
presentationId: String,
|
||||
maxNumberOfAttempts: Int,
|
||||
)
|
||||
|
||||
// ------------ bbb-common-web to akka-apps ------------
|
||||
|
||||
// ------------ akka-apps to client ------------
|
||||
@ -220,6 +236,13 @@ object PresentationUploadedFileTooLargeErrorEvtMsg { val NAME = "PresentationUpl
|
||||
case class PresentationUploadedFileTooLargeErrorEvtMsg(header: BbbClientMsgHeader, body: PresentationUploadedFileTooLargeErrorEvtMsgBody) extends BbbCoreMsg
|
||||
case class PresentationUploadedFileTooLargeErrorEvtMsgBody(podId: String, messageKey: String, code: String, presentationName: String, presentationToken: String, fileSize: Int, maxFileSize: Int)
|
||||
|
||||
object PresentationUploadedFileTimeoutErrorEvtMsg { val NAME = "PresentationUploadedFileTimeoutErrorEvtMsg" }
|
||||
case class PresentationUploadedFileTimeoutErrorEvtMsg(header: BbbClientMsgHeader, body: PresentationUploadedFileTimeoutErrorEvtMsgBody) extends BbbCoreMsg
|
||||
case class PresentationUploadedFileTimeoutErrorEvtMsgBody(podId: String, meetingId: String, presentationName: String,
|
||||
page: Int, messageKey: String,
|
||||
temporaryPresentationId: String, presentationId: String,
|
||||
maxNumberOfAttempts: Int)
|
||||
|
||||
object PresentationConversionRequestReceivedEventMsg { val NAME = "PresentationConversionRequestReceivedEventMsg" }
|
||||
case class PresentationConversionRequestReceivedEventMsg(
|
||||
header: BbbClientMsgHeader,
|
||||
|
@ -38,6 +38,7 @@ public class ConversionMessageConstants {
|
||||
public static final String GENERATED_SVGIMAGES_KEY = "GENERATED_SVGIMAGES";
|
||||
public static final String CONVERSION_STARTED_KEY = "CONVERSION_STARTED_KEY";
|
||||
public static final String CONVERSION_COMPLETED_KEY = "CONVERSION_COMPLETED";
|
||||
public static final String CONVERSION_TIMEOUT_KEY = "CONVERSION_TIMEOUT";
|
||||
|
||||
private ConversionMessageConstants() {
|
||||
throw new IllegalStateException("ConversionMessageConstants is a utility class. Instanciation is forbidden.");
|
||||
|
@ -21,7 +21,8 @@
|
||||
* @version $Id: $
|
||||
*/
|
||||
package org.bigbluebutton.presentation;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
public interface SvgImageCreator {
|
||||
public boolean createSvgImage(UploadedPresentation pres, int page);
|
||||
public boolean createSvgImage(UploadedPresentation pres, int page) throws TimeoutException;
|
||||
}
|
||||
|
@ -83,7 +83,13 @@ public class ImageToSwfSlidesGenerationService {
|
||||
createThumbnails(pres, page);
|
||||
|
||||
if (svgImagesRequired) {
|
||||
createSvgImages(pres, page);
|
||||
try {
|
||||
createSvgImages(pres, page);
|
||||
} catch (TimeoutException e) {
|
||||
log.error("Slide {} was not converted due to TimeoutException, ending process.", page, e);
|
||||
notifier.sendUploadFileTimedout(pres, page);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (generatePngs) {
|
||||
@ -119,7 +125,7 @@ public class ImageToSwfSlidesGenerationService {
|
||||
thumbnailCreator.createThumbnail(pres, page, pres.getUploadedFile());
|
||||
}
|
||||
|
||||
private void createSvgImages(UploadedPresentation pres, int page) {
|
||||
private void createSvgImages(UploadedPresentation pres, int page) throws TimeoutException{
|
||||
log.debug("Creating SVG images.");
|
||||
notifier.sendCreatingSvgImagesUpdateMessage(pres);
|
||||
svgImageCreator.createSvgImage(pres, page);
|
||||
@ -243,7 +249,7 @@ public class ImageToSwfSlidesGenerationService {
|
||||
public void setMaxConversionTime(int minutes) {
|
||||
MAX_CONVERSION_TIME = minutes * 60 * 1000L;
|
||||
}
|
||||
|
||||
|
||||
public void setSwfSlidesGenerationProgressNotifier(SwfSlidesGenerationProgressNotifier notifier) {
|
||||
this.notifier = notifier;
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package org.bigbluebutton.presentation.imp;
|
||||
|
||||
import org.bigbluebutton.presentation.*;
|
||||
import java.io.File;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
public class PageToConvert {
|
||||
|
||||
@ -24,6 +25,7 @@ public class PageToConvert {
|
||||
private PageConverter pdfToSwfConverter;
|
||||
private SwfSlidesGenerationProgressNotifier notifier;
|
||||
private File pageFile;
|
||||
private String messageErrorInConversion;
|
||||
|
||||
public PageToConvert(UploadedPresentation pres,
|
||||
int page,
|
||||
@ -71,6 +73,14 @@ public class PageToConvert {
|
||||
return pres.getMeetingId();
|
||||
}
|
||||
|
||||
public String getMessageErrorInConversion() {
|
||||
return messageErrorInConversion;
|
||||
}
|
||||
|
||||
public void setMessageErrorInConversion(String messageErrorInConversion) {
|
||||
this.messageErrorInConversion = messageErrorInConversion;
|
||||
}
|
||||
|
||||
public PageToConvert convert() {
|
||||
|
||||
// Only create SWF files if the configuration requires it
|
||||
@ -85,7 +95,11 @@ public class PageToConvert {
|
||||
|
||||
// only create SVG images if the configuration requires it
|
||||
if (svgImagesRequired) {
|
||||
createSvgImages(pres, page);
|
||||
try{
|
||||
createSvgImages(pres, page);
|
||||
} catch (TimeoutException e) {
|
||||
messageErrorInConversion = e.getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
// only create PNG images if the configuration requires it
|
||||
@ -106,7 +120,7 @@ public class PageToConvert {
|
||||
textFileCreator.createTextFile(pres, page);
|
||||
}
|
||||
|
||||
private void createSvgImages(UploadedPresentation pres, int page) {
|
||||
private void createSvgImages(UploadedPresentation pres, int page) throws TimeoutException{
|
||||
//notifier.sendCreatingSvgImagesUpdateMessage(pres);
|
||||
svgImageCreator.createSvgImage(pres, page);
|
||||
}
|
||||
|
@ -12,7 +12,9 @@ import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
@ -91,6 +93,7 @@ public class PresentationFileProcessor {
|
||||
}
|
||||
|
||||
private void extractIntoPages(UploadedPresentation pres) {
|
||||
List<PageToConvert> listOfPagesConverted = new ArrayList<>();
|
||||
for (int page = 1; page <= pres.getNumberOfPages(); page++) {
|
||||
String presDir = pres.getUploadedFile().getParent();
|
||||
File pageFile = new File(presDir + "/page" + "-" + page + ".pdf");
|
||||
@ -123,6 +126,18 @@ public class PresentationFileProcessor {
|
||||
);
|
||||
|
||||
pdfToSwfSlidesGenerationService.process(pageToConvert);
|
||||
|
||||
listOfPagesConverted.add(pageToConvert);
|
||||
PageToConvert timeoutErrorMessage =
|
||||
listOfPagesConverted.stream().filter(item -> {
|
||||
return item.getMessageErrorInConversion() != null;
|
||||
}).findAny().orElse(null);
|
||||
|
||||
if (timeoutErrorMessage != null) {
|
||||
log.error(timeoutErrorMessage.getMessageErrorInConversion());
|
||||
notifier.sendUploadFileTimedout(pres, timeoutErrorMessage.getPageNumber());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,7 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.bigbluebutton.presentation.SupportedFileTypes;
|
||||
@ -31,13 +32,15 @@ public class SvgImageCreatorImp implements SvgImageCreator {
|
||||
private long imageTagThreshold;
|
||||
private long pathsThreshold;
|
||||
private int convPdfToSvgTimeout = 60;
|
||||
private int pdfFontsTimeout = 3;
|
||||
private int svgResolutionPpi = 300;
|
||||
private boolean forceRasterizeSlides = false;
|
||||
private int pngWidthRasterizedSlides = 2048;
|
||||
private String BLANK_SVG;
|
||||
private int maxNumberOfAttempts = 3;
|
||||
|
||||
@Override
|
||||
public boolean createSvgImage(UploadedPresentation pres, int page) {
|
||||
public boolean createSvgImage(UploadedPresentation pres, int page) throws TimeoutException{
|
||||
boolean success = false;
|
||||
File svgImagesPresentationDir = determineSvgImagesDirectory(pres.getUploadedFile());
|
||||
if (!svgImagesPresentationDir.exists())
|
||||
@ -45,7 +48,7 @@ public class SvgImageCreatorImp implements SvgImageCreator {
|
||||
|
||||
try {
|
||||
success = generateSvgImage(svgImagesPresentationDir, pres, page);
|
||||
} catch (Exception e) {
|
||||
} catch (InterruptedException e) {
|
||||
log.error("Interrupted Exception while generating images {}", pres.getName(), e);
|
||||
success = false;
|
||||
}
|
||||
@ -53,10 +56,30 @@ public class SvgImageCreatorImp implements SvgImageCreator {
|
||||
return success;
|
||||
}
|
||||
|
||||
private PdfFontType3DetectorHandler createDetectFontType3tHandler(boolean done, int page, String source, UploadedPresentation pres) {
|
||||
//Detect if PDF contains text with font Type 3
|
||||
//Pdftocairo has problem to convert Pdf to Svg when text contains font Type 3
|
||||
//Case detects type 3, rasterize will be forced to avoid the problem
|
||||
NuProcessBuilder detectFontType3Process = this.createDetectFontType3Process(source, page);
|
||||
PdfFontType3DetectorHandler detectFontType3tHandler = new PdfFontType3DetectorHandler();
|
||||
detectFontType3Process.setProcessListener(detectFontType3tHandler);
|
||||
|
||||
NuProcess processDetectFontType3 = detectFontType3Process.start();
|
||||
try {
|
||||
processDetectFontType3.waitFor(pdfFontsTimeout + 1, TimeUnit.SECONDS);
|
||||
done = true;
|
||||
} catch (InterruptedException e) {
|
||||
done = false;
|
||||
log.error("InterruptedException while verifing font type 3 on {} page {}: {}", pres.getName(), page, e);
|
||||
}
|
||||
return detectFontType3tHandler;
|
||||
}
|
||||
|
||||
private boolean generateSvgImage(File imagePresentationDir, UploadedPresentation pres, int page)
|
||||
throws InterruptedException {
|
||||
throws InterruptedException, TimeoutException{
|
||||
String source = pres.getUploadedFile().getAbsolutePath();
|
||||
String dest;
|
||||
int countOfTimeOut = 0;
|
||||
|
||||
int numSlides = 1;
|
||||
boolean done = false;
|
||||
@ -95,25 +118,19 @@ public class SvgImageCreatorImp implements SvgImageCreator {
|
||||
// Continue image processing
|
||||
long startConv = System.currentTimeMillis();
|
||||
|
||||
PdfFontType3DetectorHandler detectFontType3tHandler = this.createDetectFontType3tHandler(done, page, source, pres);
|
||||
|
||||
//Detect if PDF contains text with font Type 3
|
||||
//Pdftocairo has problem to convert Pdf to Svg when text contains font Type 3
|
||||
//Case detects type 3, rasterize will be forced to avoid the problem
|
||||
NuProcessBuilder detectFontType3Process = this.createDetectFontType3Process(source,page);
|
||||
PdfFontType3DetectorHandler detectFontType3tHandler = new PdfFontType3DetectorHandler();
|
||||
detectFontType3Process.setProcessListener(detectFontType3tHandler);
|
||||
|
||||
NuProcess processDetectFontType3 = detectFontType3Process.start();
|
||||
try {
|
||||
processDetectFontType3.waitFor(convPdfToSvgTimeout + 1, TimeUnit.SECONDS);
|
||||
done = true;
|
||||
} catch (InterruptedException e) {
|
||||
done = false;
|
||||
log.error("InterruptedException while verifing font type 3 on {} page {}: {}", pres.getName(), page, e);
|
||||
}
|
||||
|
||||
if(detectFontType3tHandler.isCommandTimeout()) {
|
||||
log.error("Command execution (detectFontType3) exceeded the {} secs timeout for {} page {}.", convPdfToSvgTimeout, pres.getName(), page);
|
||||
while (detectFontType3tHandler.isCommandTimeout()) {
|
||||
// Took the first process of the function out of the count because it already happened above
|
||||
if (countOfTimeOut >= maxNumberOfAttempts - 1) {
|
||||
log.error("Command execution (detectFontType3) exceeded the {} secs timeout within {} attempts for {} page {}.", pdfFontsTimeout, maxNumberOfAttempts, pres.getName(), page);
|
||||
throw new TimeoutException("(Timeout error) The slide " + page +
|
||||
" could not be processed within "
|
||||
+ convPdfToSvgTimeout +
|
||||
" seconds.");
|
||||
}
|
||||
detectFontType3tHandler = this.createDetectFontType3tHandler(done, page, source, pres);
|
||||
countOfTimeOut += 1;
|
||||
}
|
||||
|
||||
if(detectFontType3tHandler.hasFontType3()) {
|
||||
@ -316,7 +333,7 @@ public class SvgImageCreatorImp implements SvgImageCreator {
|
||||
rawCommand += " | grep -m 1 'Type 3'";
|
||||
rawCommand += " | wc -l";
|
||||
|
||||
return new NuProcessBuilder(Arrays.asList("timeout", convPdfToSvgTimeout + "s", "/bin/sh", "-c", rawCommand));
|
||||
return new NuProcessBuilder(Arrays.asList("timeout", pdfFontsTimeout + "s", "/bin/sh", "-c", rawCommand));
|
||||
}
|
||||
|
||||
private File determineSvgImagesDirectory(File presentationFile) {
|
||||
@ -349,6 +366,12 @@ public class SvgImageCreatorImp implements SvgImageCreator {
|
||||
public void setBlankSvg(String blankSvg) {
|
||||
BLANK_SVG = blankSvg;
|
||||
}
|
||||
public void setMaxNumberOfAttempts(int maxNumberOfAttempts) {
|
||||
this.maxNumberOfAttempts = maxNumberOfAttempts;
|
||||
}
|
||||
public void setPdfFontsTimeout(int pdfFontsTimeout) {
|
||||
this.pdfFontsTimeout = pdfFontsTimeout;
|
||||
}
|
||||
|
||||
public void setImageTagThreshold(long threshold) {
|
||||
imageTagThreshold = threshold;
|
||||
|
@ -31,6 +31,7 @@ public class SwfSlidesGenerationProgressNotifier {
|
||||
private static Logger log = LoggerFactory.getLogger(SwfSlidesGenerationProgressNotifier.class);
|
||||
|
||||
private IBbbWebApiGWApp messagingService;
|
||||
private int maxNumberOfAttempts = 3;
|
||||
|
||||
private GeneratedSlidesInfoHelper generatedSlidesInfoHelper;
|
||||
|
||||
@ -50,6 +51,15 @@ public class SwfSlidesGenerationProgressNotifier {
|
||||
maxUploadFileSize);
|
||||
messagingService.sendDocConversionMsg(progress);
|
||||
}
|
||||
public void sendUploadFileTimedout(UploadedPresentation pres, int page) {
|
||||
UploadFileTimedoutMessage errorMessage = new UploadFileTimedoutMessage(
|
||||
pres.getPodId(),
|
||||
pres.getMeetingId(),
|
||||
pres.getName(),
|
||||
ConversionMessageConstants.CONVERSION_TIMEOUT_KEY,
|
||||
page, pres.getTemporaryPresentationId(), pres.getId(), maxNumberOfAttempts);
|
||||
messagingService.sendDocConversionMsg(errorMessage);
|
||||
}
|
||||
|
||||
public void sendConversionUpdateMessage(int slidesCompleted, UploadedPresentation pres, int pageGenerated) {
|
||||
DocPageGeneratedProgress progress = new DocPageGeneratedProgress(pres.getPodId(),
|
||||
@ -100,6 +110,10 @@ public class SwfSlidesGenerationProgressNotifier {
|
||||
messagingService = m;
|
||||
}
|
||||
|
||||
public void setMaxNumberOfAttempts(int maxNumberOfAttempts) {
|
||||
this.maxNumberOfAttempts = maxNumberOfAttempts;
|
||||
}
|
||||
|
||||
public void setGeneratedSlidesInfoHelper(GeneratedSlidesInfoHelper helper) {
|
||||
generatedSlidesInfoHelper = helper;
|
||||
}
|
||||
|
@ -0,0 +1,30 @@
|
||||
package org.bigbluebutton.presentation.messages;
|
||||
|
||||
public class UploadFileTimedoutMessage implements IDocConversionMsg {
|
||||
public final String podId;
|
||||
public final String meetingId;
|
||||
public final String filename;
|
||||
public final int page;
|
||||
public final String messageKey;
|
||||
public final String temporaryPresentationId;
|
||||
public final String presentationId;
|
||||
public final int maxNumberOfAttempts;
|
||||
|
||||
public UploadFileTimedoutMessage(String podId,
|
||||
String meetingId,
|
||||
String filename,
|
||||
String messageKey,
|
||||
int page,
|
||||
String temporaryPresentationId,
|
||||
String presentationId,
|
||||
int maxNumberOfAttempts) {
|
||||
this.podId = podId;
|
||||
this.meetingId = meetingId;
|
||||
this.temporaryPresentationId = temporaryPresentationId;
|
||||
this.filename = filename;
|
||||
this.messageKey = messageKey;
|
||||
this.page = page;
|
||||
this.presentationId = presentationId;
|
||||
this.maxNumberOfAttempts = maxNumberOfAttempts;
|
||||
}
|
||||
}
|
@ -333,6 +333,9 @@ class BbbWebApiGWApp(
|
||||
} else if (msg.isInstanceOf[UploadFileTooLargeMessage]) {
|
||||
val event = MsgBuilder.buildPresentationUploadedFileTooLargeErrorSysMsg(msg.asInstanceOf[UploadFileTooLargeMessage])
|
||||
msgToAkkaAppsEventBus.publish(MsgToAkkaApps(toAkkaAppsChannel, event))
|
||||
} else if (msg.isInstanceOf[UploadFileTimedoutMessage]) {
|
||||
val event = MsgBuilder.buildPresentationUploadedFileTimedoutErrorSysMsg(msg.asInstanceOf[UploadFileTimedoutMessage])
|
||||
msgToAkkaAppsEventBus.publish(MsgToAkkaApps(toAkkaAppsChannel, event))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -297,4 +297,18 @@ object MsgBuilder {
|
||||
BbbCommonEnvCoreMsg(envelope, req)
|
||||
}
|
||||
|
||||
def buildPresentationUploadedFileTimedoutErrorSysMsg(msg: UploadFileTimedoutMessage): BbbCommonEnvCoreMsg = {
|
||||
val routing = collection.immutable.HashMap("sender" -> "bbb-web")
|
||||
val envelope = BbbCoreEnvelope(PresentationUploadedFileTimeoutErrorSysPubMsg.NAME, routing)
|
||||
val header = BbbClientMsgHeader(PresentationUploadedFileTimeoutErrorSysPubMsg.NAME, msg.meetingId, "not-used")
|
||||
|
||||
val body = PresentationUploadedFileTimeoutErrorSysPubMsgBody(podId = msg.podId, presentationName = msg.filename,
|
||||
page = msg.page, meetingId = msg.meetingId, messageKey = msg.messageKey,
|
||||
temporaryPresentationId = msg.temporaryPresentationId, presentationId = msg.presentationId,
|
||||
maxNumberOfAttempts = msg.maxNumberOfAttempts)
|
||||
|
||||
val req = PresentationUploadedFileTimeoutErrorSysPubMsg(header, body)
|
||||
BbbCommonEnvCoreMsg(envelope, req)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ import handlePresentationDownloadableSet from './handlers/presentationDownloadab
|
||||
RedisPubSub.on('PdfConversionInvalidErrorEvtMsg', handlePresentationConversionUpdate);
|
||||
RedisPubSub.on('PresentationPageGeneratedEvtMsg', handlePresentationConversionUpdate);
|
||||
RedisPubSub.on('PresentationPageCountErrorEvtMsg', handlePresentationConversionUpdate);
|
||||
RedisPubSub.on('PresentationUploadedFileTimeoutErrorEvtMsg', handlePresentationConversionUpdate);
|
||||
RedisPubSub.on('PresentationConversionUpdateEvtMsg', handlePresentationConversionUpdate);
|
||||
RedisPubSub.on('PresentationUploadedFileTooLargeErrorEvtMsg', handlePresentationConversionUpdate);
|
||||
RedisPubSub.on('PresentationConversionCompletedEvtMsg', handlePresentationAdded);
|
||||
|
@ -12,6 +12,7 @@ const PAGE_COUNT_EXCEEDED_KEY = 'PAGE_COUNT_EXCEEDED';
|
||||
const PDF_HAS_BIG_PAGE_KEY = 'PDF_HAS_BIG_PAGE';
|
||||
const GENERATED_SLIDE_KEY = 'GENERATED_SLIDE';
|
||||
const FILE_TOO_LARGE_KEY = 'FILE_TOO_LARGE';
|
||||
const CONVERSION_TIMEOUT_KEY = "CONVERSION_TIMEOUT";
|
||||
// const GENERATING_THUMBNAIL_KEY = 'GENERATING_THUMBNAIL';
|
||||
// const GENERATED_THUMBNAIL_KEY = 'GENERATED_THUMBNAIL';
|
||||
// const GENERATING_TEXTFILES_KEY = 'GENERATING_TEXTFILES';
|
||||
@ -59,6 +60,11 @@ export default function handlePresentationConversionUpdate({ body }, meetingId)
|
||||
statusModifier['conversion.error'] = true;
|
||||
statusModifier['conversion.bigPageSize'] = body.bigPageSize;
|
||||
break;
|
||||
case CONVERSION_TIMEOUT_KEY:
|
||||
statusModifier['conversion.error'] = true;
|
||||
statusModifier['conversion.maxNumberOfAttempts'] = body.maxNumberOfAttempts;
|
||||
statusModifier['conversion.numberPageError'] = body.page;
|
||||
break;
|
||||
case GENERATED_SLIDE_KEY:
|
||||
statusModifier['conversion.pagesCompleted'] = body.pagesCompleted;
|
||||
statusModifier['conversion.numPages'] = body.numberOfPages;
|
||||
@ -87,9 +93,24 @@ export default function handlePresentationConversionUpdate({ body }, meetingId)
|
||||
|
||||
|
||||
try {
|
||||
const { insertedId } = Presentations.upsert(selector, modifier);
|
||||
const isPresentationPersisted = Presentations.find(selector).fetch().some((item) => {
|
||||
if (item.temporaryPresentationId && temporaryPresentationId){
|
||||
return item.temporaryPresentationId === temporaryPresentationId;
|
||||
} else{
|
||||
return item.id === presentationId;
|
||||
}
|
||||
});
|
||||
let insertedID;
|
||||
if (!isPresentationPersisted) {
|
||||
const { insertedId } = Presentations.upsert(selector, modifier);
|
||||
insertedID = insertedId;
|
||||
} else {
|
||||
selector['conversion.error'] = false;
|
||||
const { insertedId } = Presentations.update(selector, modifier);
|
||||
insertedID = insertedId;
|
||||
}
|
||||
|
||||
if (insertedId) {
|
||||
if (insertedID) {
|
||||
Logger.info(`Updated presentation conversion status=${status} id=${presentationId} meeting=${meetingId}`);
|
||||
} else {
|
||||
Logger.debug('Upserted presentation conversion', { status, presentationId, meetingId });
|
||||
|
@ -137,6 +137,10 @@ const intlMessages = defineMessages({
|
||||
TIMEOUT: {
|
||||
id: 'app.presentationUploder.conversion.timeout',
|
||||
},
|
||||
CONVERSION_TIMEOUT: {
|
||||
id:'app.presentationUploder.conversion.conversionTimeout',
|
||||
description: 'warns the user that the presentation timed out in the back-end in specific page of the document',
|
||||
},
|
||||
GENERATING_THUMBNAIL: {
|
||||
id: 'app.presentationUploder.conversion.generatingThumbnail',
|
||||
description: 'indicatess that it is generating thumbnails',
|
||||
@ -1036,6 +1040,10 @@ class PresentationUploader extends Component {
|
||||
const errorMessage = intlMessages[item.conversion.status] || intlMessages.genericConversionStatus;
|
||||
|
||||
switch (item.conversion.status) {
|
||||
case 'CONVERSION_TIMEOUT':
|
||||
constraint['0'] = item.conversion.numberPageError;
|
||||
constraint['1'] = item.conversion.maxNumberOfAttempts;
|
||||
break;
|
||||
case 'PAGE_COUNT_EXCEEDED':
|
||||
constraint['0'] = item.conversion.maxNumberPages;
|
||||
break;
|
||||
|
@ -91,7 +91,7 @@ const observePresentationConversion = (
|
||||
added: (doc) => {
|
||||
if (doc.temporaryPresentationId !== temporaryPresentationId) return;
|
||||
|
||||
if (doc.conversion.status === 'FILE_TOO_LARGE' || doc.conversion.status === 'UNSUPPORTED_DOCUMENT') {
|
||||
if (doc.conversion.status === 'FILE_TOO_LARGE' || doc.conversion.status === 'UNSUPPORTED_DOCUMENT' || doc.conversion.status === 'CONVERSION_TIMEOUT') {
|
||||
onConversion(doc.conversion);
|
||||
c.stop();
|
||||
clearTimeout(conversionTimeout);
|
||||
|
@ -230,6 +230,7 @@
|
||||
"app.presentationUploder.conversion.generatedSlides": "Slides generated ...",
|
||||
"app.presentationUploder.conversion.generatingSvg": "Generating SVG images ...",
|
||||
"app.presentationUploder.conversion.pageCountExceeded": "Number of pages exceeded maximum of {0}",
|
||||
"app.presentationUploder.conversion.conversionTimeout": "Slide {0} could not be processed within {1} attempts.",
|
||||
"app.presentationUploder.conversion.officeDocConversionInvalid": "Failed to process office document. Please upload a PDF instead.",
|
||||
"app.presentationUploder.conversion.officeDocConversionFailed": "Failed to process office document. Please upload a PDF instead.",
|
||||
"app.presentationUploder.conversion.pdfHasBigPage": "We could not convert the PDF file, please try optimizing it. Max page size {0}",
|
||||
|
@ -103,6 +103,14 @@ numFileProcessorThreads=2
|
||||
#------------------------------------
|
||||
svgConversionTimeout=60
|
||||
|
||||
#------------------------------------
|
||||
# pdfFonts is used to detect whether PDF contains text with font Type 3
|
||||
# it is also used to check if the pdf has some problem to be opened (timeout) and abort the conversion if so
|
||||
# Configuration for pdfFonts Timeout(secs) and Max number of attempts
|
||||
#------------------------------------
|
||||
pdfFontsTimeout=3
|
||||
maxNumberOfAttemptsForPdfFonts=3
|
||||
|
||||
#------------------------------------
|
||||
# Presentation resolution, in PPI (will be set to generated svg)
|
||||
#------------------------------------
|
||||
|
@ -87,6 +87,8 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||
<property name="pathsThreshold" value="${placementsThreshold}"/>
|
||||
<property name="blankSvg" value="${BLANK_SVG}"/>
|
||||
<property name="convPdfToSvgTimeout" value="${svgConversionTimeout}"/>
|
||||
<property name="pdfFontsTimeout" value="${pdfFontsTimeout}"/>
|
||||
<property name="maxNumberOfAttempts" value="${maxNumberOfAttemptsForPdfFonts}"/>
|
||||
<property name="svgResolutionPpi" value="${svgPresentationResolutionPpi}"/>
|
||||
<property name="forceRasterizeSlides" value="${forceRasterizeSlides}"/>
|
||||
<property name="pngWidthRasterizedSlides" value="${pngWidthRasterizedSlides}"/>
|
||||
@ -145,6 +147,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||
<bean id="swfSlidesGenerationProgressNotifier"
|
||||
class="org.bigbluebutton.presentation.imp.SwfSlidesGenerationProgressNotifier">
|
||||
<property name="messagingService" ref="bbbWebApiGWApp"/>
|
||||
<property name="maxNumberOfAttempts" value="${maxNumberOfAttemptsForPdfFonts}"/>
|
||||
<property name="generatedSlidesInfoHelper" ref="generatedSlidesInfoHelper"/>
|
||||
</bean>
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user