fixes and timeouts
This commit is contained in:
parent
ef12c2f892
commit
e717d83f75
3 changed files with 52 additions and 13 deletions
|
@ -35,15 +35,17 @@ public class FileToPdf {
|
||||||
command.add("weasyprint");
|
command.add("weasyprint");
|
||||||
} else {
|
} else {
|
||||||
command.add("wkhtmltopdf");
|
command.add("wkhtmltopdf");
|
||||||
|
command.add("--enable-local-file-access");
|
||||||
}
|
}
|
||||||
|
|
||||||
command.add(tempInputFile.toString());
|
command.add(tempInputFile.toString());
|
||||||
command.add(tempOutputFile.toString());
|
command.add(tempOutputFile.toString());
|
||||||
ProcessExecutorResult returnCode;
|
ProcessExecutorResult returnCode;
|
||||||
if (fileName.endsWith(".zip")) {
|
if (fileName.endsWith(".zip")) {
|
||||||
|
|
||||||
if (htmlFormatsInstalled) {
|
if (htmlFormatsInstalled) {
|
||||||
command.add("--allow");
|
// command.add(1, "--allow");
|
||||||
command.add(tempOutputFile.getParent().toString());
|
// command.add(2, tempInputFile.getParent().toString());
|
||||||
}
|
}
|
||||||
returnCode =
|
returnCode =
|
||||||
ProcessExecutor.getInstance(ProcessExecutor.Processes.WEASYPRINT)
|
ProcessExecutor.getInstance(ProcessExecutor.Processes.WEASYPRINT)
|
||||||
|
|
|
@ -4,15 +4,22 @@ import java.io.BufferedReader;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.InterruptedIOException;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.Semaphore;
|
import java.util.concurrent.Semaphore;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
public class ProcessExecutor {
|
public class ProcessExecutor {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(ProcessExecutor.class);
|
||||||
|
|
||||||
public enum Processes {
|
public enum Processes {
|
||||||
LIBRE_OFFICE,
|
LIBRE_OFFICE,
|
||||||
OCR_MY_PDF,
|
OCR_MY_PDF,
|
||||||
|
@ -26,7 +33,7 @@ public class ProcessExecutor {
|
||||||
private static final Map<Processes, ProcessExecutor> instances = new ConcurrentHashMap<>();
|
private static final Map<Processes, ProcessExecutor> instances = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
public static ProcessExecutor getInstance(Processes processType) {
|
public static ProcessExecutor getInstance(Processes processType) {
|
||||||
return getInstance(processType, false);
|
return getInstance(processType, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ProcessExecutor getInstance(Processes processType, boolean liveUpdates) {
|
public static ProcessExecutor getInstance(Processes processType, boolean liveUpdates) {
|
||||||
|
@ -43,16 +50,29 @@ public class ProcessExecutor {
|
||||||
case INSTALL_APP -> 1;
|
case INSTALL_APP -> 1;
|
||||||
case CALIBRE -> 1;
|
case CALIBRE -> 1;
|
||||||
};
|
};
|
||||||
return new ProcessExecutor(semaphoreLimit, liveUpdates);
|
|
||||||
|
long timeoutMinutes =
|
||||||
|
switch (key) {
|
||||||
|
case LIBRE_OFFICE -> 30;
|
||||||
|
case OCR_MY_PDF -> 30;
|
||||||
|
case PYTHON_OPENCV -> 30;
|
||||||
|
case GHOSTSCRIPT -> 5;
|
||||||
|
case WEASYPRINT -> 30;
|
||||||
|
case INSTALL_APP -> 60;
|
||||||
|
case CALIBRE -> 30;
|
||||||
|
};
|
||||||
|
return new ProcessExecutor(semaphoreLimit, liveUpdates, timeoutMinutes);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private final Semaphore semaphore;
|
private final Semaphore semaphore;
|
||||||
private final boolean liveUpdates;
|
private final boolean liveUpdates;
|
||||||
|
private long timeoutDuration;
|
||||||
|
|
||||||
private ProcessExecutor(int semaphoreLimit, boolean liveUpdates) {
|
private ProcessExecutor(int semaphoreLimit, boolean liveUpdates, long timeout) {
|
||||||
this.semaphore = new Semaphore(semaphoreLimit);
|
this.semaphore = new Semaphore(semaphoreLimit);
|
||||||
this.liveUpdates = liveUpdates;
|
this.liveUpdates = liveUpdates;
|
||||||
|
this.timeoutDuration = timeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ProcessExecutorResult runCommandWithOutputHandling(List<String> command)
|
public ProcessExecutorResult runCommandWithOutputHandling(List<String> command)
|
||||||
|
@ -62,12 +82,12 @@ public class ProcessExecutor {
|
||||||
|
|
||||||
public ProcessExecutorResult runCommandWithOutputHandling(
|
public ProcessExecutorResult runCommandWithOutputHandling(
|
||||||
List<String> command, File workingDirectory) throws IOException, InterruptedException {
|
List<String> command, File workingDirectory) throws IOException, InterruptedException {
|
||||||
int exitCode = 1;
|
|
||||||
String messages = "";
|
String messages = "";
|
||||||
|
int exitCode = 1;
|
||||||
semaphore.acquire();
|
semaphore.acquire();
|
||||||
try {
|
try {
|
||||||
|
|
||||||
System.out.print("Running command: " + String.join(" ", command));
|
logger.info("Running command: " + String.join(" ", command));
|
||||||
ProcessBuilder processBuilder = new ProcessBuilder(command);
|
ProcessBuilder processBuilder = new ProcessBuilder(command);
|
||||||
|
|
||||||
// Use the working directory if it's set
|
// Use the working directory if it's set
|
||||||
|
@ -91,8 +111,11 @@ public class ProcessExecutor {
|
||||||
String line;
|
String line;
|
||||||
while ((line = errorReader.readLine()) != null) {
|
while ((line = errorReader.readLine()) != null) {
|
||||||
errorLines.add(line);
|
errorLines.add(line);
|
||||||
if (liveUpdates) System.out.println(line);
|
if (liveUpdates) logger.info(line);
|
||||||
}
|
}
|
||||||
|
} catch (InterruptedIOException e) {
|
||||||
|
logger.warn(
|
||||||
|
"Error reader thread was interrupted due to timeout.");
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
@ -109,8 +132,11 @@ public class ProcessExecutor {
|
||||||
String line;
|
String line;
|
||||||
while ((line = outputReader.readLine()) != null) {
|
while ((line = outputReader.readLine()) != null) {
|
||||||
outputLines.add(line);
|
outputLines.add(line);
|
||||||
if (liveUpdates) System.out.println(line);
|
if (liveUpdates) logger.info(line);
|
||||||
}
|
}
|
||||||
|
} catch (InterruptedIOException e) {
|
||||||
|
logger.warn(
|
||||||
|
"Error reader thread was interrupted due to timeout.");
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
@ -120,8 +146,17 @@ public class ProcessExecutor {
|
||||||
outputReaderThread.start();
|
outputReaderThread.start();
|
||||||
|
|
||||||
// Wait for the conversion process to complete
|
// Wait for the conversion process to complete
|
||||||
exitCode = process.waitFor();
|
boolean finished = process.waitFor(timeoutDuration, TimeUnit.MINUTES);
|
||||||
|
|
||||||
|
if (!finished) {
|
||||||
|
// Terminate the process
|
||||||
|
process.destroy();
|
||||||
|
// Interrupt the reader threads
|
||||||
|
errorReaderThread.interrupt();
|
||||||
|
outputReaderThread.interrupt();
|
||||||
|
throw new IOException("Process timeout exceeded.");
|
||||||
|
}
|
||||||
|
exitCode = process.exitValue();
|
||||||
// Wait for the reader threads to finish
|
// Wait for the reader threads to finish
|
||||||
errorReaderThread.join();
|
errorReaderThread.join();
|
||||||
outputReaderThread.join();
|
outputReaderThread.join();
|
||||||
|
@ -130,13 +165,13 @@ public class ProcessExecutor {
|
||||||
if (outputLines.size() > 0) {
|
if (outputLines.size() > 0) {
|
||||||
String outputMessage = String.join("\n", outputLines);
|
String outputMessage = String.join("\n", outputLines);
|
||||||
messages += outputMessage;
|
messages += outputMessage;
|
||||||
System.out.println("Command output:\n" + outputMessage);
|
logger.info("Command output:\n" + outputMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (errorLines.size() > 0) {
|
if (errorLines.size() > 0) {
|
||||||
String errorMessage = String.join("\n", errorLines);
|
String errorMessage = String.join("\n", errorLines);
|
||||||
messages += errorMessage;
|
messages += errorMessage;
|
||||||
System.out.println("Command error output:\n" + errorMessage);
|
logger.warn("Command error output:\n" + errorMessage);
|
||||||
if (exitCode != 0) {
|
if (exitCode != 0) {
|
||||||
throw new IOException(
|
throw new IOException(
|
||||||
"Command process failed with exit code "
|
"Command process failed with exit code "
|
||||||
|
|
|
@ -13,7 +13,9 @@ system:
|
||||||
defaultLocale: 'en-US' # Set the default language (e.g. 'de-DE', 'fr-FR', etc)
|
defaultLocale: 'en-US' # Set the default language (e.g. 'de-DE', 'fr-FR', etc)
|
||||||
googlevisibility: false # 'true' to allow Google visibility (via robots.txt), 'false' to disallow
|
googlevisibility: false # 'true' to allow Google visibility (via robots.txt), 'false' to disallow
|
||||||
enableAlphaFunctionality: false # Set to enable functionality which might need more testing before it fully goes live (This feature might make no changes)
|
enableAlphaFunctionality: false # Set to enable functionality which might need more testing before it fully goes live (This feature might make no changes)
|
||||||
# customExternalPort: 8000 used for when port mappings do not work correctly
|
customApplications:
|
||||||
|
installBookFormats: false # Installs Calibre for book format conversion (For non docker it must be manually downloaded but will need to be true to show in UI)
|
||||||
|
installAdvancedHtmlToPDF: false # DO NOT USE EXTERNALLY, NOT SAFE! Install wkHtmlToPDF (For non docker it must be manually downloaded but will need to be true to show in UI)
|
||||||
|
|
||||||
#ui:
|
#ui:
|
||||||
# appName: exampleAppName # Application's visible name
|
# appName: exampleAppName # Application's visible name
|
||||||
|
|
Loading…
Reference in a new issue