FileReadiness (#5985)

This commit is contained in:
Anthony Stirling
2026-03-24 15:25:33 +00:00
committed by GitHub
parent f03f0d4adb
commit 7b3985e34a
12 changed files with 665 additions and 24 deletions
@@ -66,7 +66,8 @@ public class ExtractImagesController {
Set<Integer> processedImageHashes = new HashSet<>();
TempFile zipFile = new TempFile(tempFileManager, ".zip");
try (ZipOutputStream zipStream = new ZipOutputStream(Files.newOutputStream(zipFile.getPath()));
try (ZipOutputStream zipStream =
new ZipOutputStream(Files.newOutputStream(zipFile.getPath()));
PDDocument pdfDoc = pdfDocumentFactory.load(file)) {
zipStream.setLevel(Deflater.BEST_COMPRESSION);
@@ -75,8 +76,12 @@ public class ExtractImagesController {
for (int pageIndex = 0; pageIndex < totalPages; pageIndex++) {
PDPage currentPage = pdfDoc.getPage(pageIndex);
extractAndAddImagesToZip(
currentPage, imageFormat, baseFilename, pageIndex + 1,
processedImageHashes, zipStream);
currentPage,
imageFormat,
baseFilename,
pageIndex + 1,
processedImageHashes,
zipStream);
}
} catch (Exception e) {
zipFile.close();
@@ -119,7 +124,12 @@ public class ExtractImagesController {
BufferedImage convertedImage = convertImageToFormat(sourceImage, imageFormat);
String imagePath =
baseFilename + "_page_" + pageNumber + "_" + imageCount++ + "."
baseFilename
+ "_page_"
+ pageNumber
+ "_"
+ imageCount++
+ "."
+ imageFormat;
ByteArrayOutputStream imageBuffer = new ByteArrayOutputStream();
ImageIO.write(convertedImage, imageFormat, imageBuffer);
@@ -36,6 +36,7 @@ import stirling.software.SPDF.model.PipelineResult;
import stirling.software.SPDF.service.ApiDocService;
import stirling.software.common.configuration.RuntimePathConfig;
import stirling.software.common.service.PostHogService;
import stirling.software.common.util.FileReadinessChecker;
import tools.jackson.databind.ObjectMapper;
@@ -50,6 +51,7 @@ public class PipelineDirectoryProcessor {
private final ApiDocService apiDocService;
private final PipelineProcessor processor;
private final PostHogService postHogService;
private final FileReadinessChecker fileReadinessChecker;
private final List<String> watchedFoldersDirs;
private final String finishedFoldersDir;
@@ -62,11 +64,13 @@ public class PipelineDirectoryProcessor {
ApiDocService apiDocService,
PipelineProcessor processor,
PostHogService postHogService,
FileReadinessChecker fileReadinessChecker,
RuntimePathConfig runtimePathConfig) {
this.objectMapper = objectMapper;
this.apiDocService = apiDocService;
this.processor = processor;
this.postHogService = postHogService;
this.fileReadinessChecker = fileReadinessChecker;
this.watchedFoldersDirs = runtimePathConfig.getPipelineWatchedFoldersPaths();
this.finishedFoldersDir = runtimePathConfig.getPipelineFinishedFoldersPath();
}
@@ -269,6 +273,18 @@ public class PipelineDirectoryProcessor {
}
return isAllowed;
})
.filter(
path -> {
if (!fileReadinessChecker.isReady(path)) {
log.info(
"File '{}' is not yet ready for processing"
+ " (still being written or locked),"
+ " will retry on next scan cycle",
path.getFileName());
return false;
}
return true;
})
.map(Path::toAbsolutePath)
.filter(path -> true)
.map(Path::toFile)
@@ -178,8 +178,7 @@ public class ReactRoutingController {
String escapedBaseUrlJs = JavaScriptUtils.javaScriptEscape(baseUrl);
String serverUrl = "(window.location.origin + '" + escapedBaseUrlJs + "')";
return
"""
return """
<!doctype html>
<html>
<head>
@@ -238,8 +237,7 @@ public class ReactRoutingController {
String escapedBaseUrlJs = JavaScriptUtils.javaScriptEscape(baseUrl);
String serverUrl = "(window.location.origin + '" + escapedBaseUrlJs + "')";
return
"""
return """
<!doctype html>
<html>
<head>
@@ -581,10 +581,10 @@ public class PdfJsonFallbackFontService {
Character.UnicodeScript script = Character.UnicodeScript.of(codePoint);
return switch (script) {
// HAN script is used by both Simplified and Traditional Chinese
// Default to Simplified (mainland China, 1.4B speakers) as it's more common
// Traditional Chinese PDFs are detected via font name aliases (MingLiU, PMingLiU,
// etc.)
// HAN script is used by both Simplified and Traditional Chinese
// Default to Simplified (mainland China, 1.4B speakers) as it's more common
// Traditional Chinese PDFs are detected via font name aliases (MingLiU, PMingLiU,
// etc.)
case HAN -> FALLBACK_FONT_CJK_ID;
case HIRAGANA, KATAKANA -> FALLBACK_FONT_JP_ID;
case HANGUL -> FALLBACK_FONT_KR_ID;
@@ -237,6 +237,14 @@ system:
databaseBackup:
cron: "0 0 0 * * ?" # Cron expression for automatic database backups "0 0 0 * * ?" daily at midnight
autoPipeline:
outputFolder: "" # Output folder for processed pipeline files (leave empty for default)
fileReadiness:
enabled: true # Set to 'false' to skip all readiness checks and process files immediately (legacy behaviour)
settleTimeMillis: 5000 # How long (ms) a file must be unmodified before it is considered fully written and stable. Default: 5000 (5 seconds)
sizeCheckDelayMillis: 500 # Pause (ms) between two file-size reads used to detect active writes (Linux/macOS mid-copy detection). Default: 500
allowedExtensions: [] # Optional extension allow-list (case-insensitive, without the leading dot). Empty list = accept all extensions. Example: ["pdf", "tiff"]
ui:
appNameNavbar: "" # name displayed on the navigation bar
logoStyle: classic # Options: 'classic' (default - classic S icon) or 'modern' (minimalist logo)