Merge pull request #15855 from GuiLeme/backport-pdf-100

This commit is contained in:
Gustavo Trott 2022-10-18 10:34:51 -03:00 committed by GitHub
commit 195beda6cb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 260 additions and 32 deletions

View File

@ -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)
}

View File

@ -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
}
}

View File

@ -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 =>

View File

@ -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)

View File

@ -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,

View File

@ -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.");

View File

@ -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;
}

View File

@ -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);

View File

@ -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);
}

View File

@ -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;
}
}
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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))
}
}

View File

@ -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)
}
}

View File

@ -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);

View File

@ -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 });

View File

@ -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;

View File

@ -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);

View File

@ -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}",

View File

@ -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)
#------------------------------------

View File

@ -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>