mirror of
https://github.com/sismics/docs.git
synced 2024-11-22 14:07:55 +01:00
#182: thumbnail generation asynchronous
This commit is contained in:
parent
1e57ee5fb3
commit
2a619849f4
@ -26,13 +26,6 @@ public class FileCreatedAsyncEvent extends UserEvent {
|
|||||||
*/
|
*/
|
||||||
private Path unencryptedFile;
|
private Path unencryptedFile;
|
||||||
|
|
||||||
/**
|
|
||||||
* Unencrypted file containing PDF representation
|
|
||||||
* of the original file. May be null if the PDF conversion is not
|
|
||||||
* necessary or not possible.
|
|
||||||
*/
|
|
||||||
private Path unencryptedPdfFile;
|
|
||||||
|
|
||||||
public File getFile() {
|
public File getFile() {
|
||||||
return file;
|
return file;
|
||||||
}
|
}
|
||||||
@ -58,15 +51,6 @@ public class FileCreatedAsyncEvent extends UserEvent {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Path getUnencryptedPdfFile() {
|
|
||||||
return unencryptedPdfFile;
|
|
||||||
}
|
|
||||||
|
|
||||||
public FileCreatedAsyncEvent setUnencryptedPdfFile(Path unencryptedPdfFile) {
|
|
||||||
this.unencryptedPdfFile = unencryptedPdfFile;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return MoreObjects.toStringHelper(this)
|
return MoreObjects.toStringHelper(this)
|
||||||
|
@ -2,15 +2,23 @@ package com.sismics.docs.core.listener.async;
|
|||||||
|
|
||||||
import com.google.common.eventbus.Subscribe;
|
import com.google.common.eventbus.Subscribe;
|
||||||
import com.sismics.docs.core.dao.jpa.FileDao;
|
import com.sismics.docs.core.dao.jpa.FileDao;
|
||||||
|
import com.sismics.docs.core.dao.jpa.UserDao;
|
||||||
import com.sismics.docs.core.dao.lucene.LuceneDao;
|
import com.sismics.docs.core.dao.lucene.LuceneDao;
|
||||||
import com.sismics.docs.core.event.FileCreatedAsyncEvent;
|
import com.sismics.docs.core.event.FileCreatedAsyncEvent;
|
||||||
import com.sismics.docs.core.model.jpa.File;
|
import com.sismics.docs.core.model.jpa.File;
|
||||||
|
import com.sismics.docs.core.model.jpa.User;
|
||||||
|
import com.sismics.docs.core.util.EncryptionUtil;
|
||||||
import com.sismics.docs.core.util.FileUtil;
|
import com.sismics.docs.core.util.FileUtil;
|
||||||
|
import com.sismics.docs.core.util.PdfUtil;
|
||||||
import com.sismics.docs.core.util.TransactionUtil;
|
import com.sismics.docs.core.util.TransactionUtil;
|
||||||
|
import com.sismics.util.mime.MimeTypeUtil;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import javax.crypto.Cipher;
|
||||||
|
import java.nio.file.Path;
|
||||||
import java.text.MessageFormat;
|
import java.text.MessageFormat;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Listener on file created.
|
* Listener on file created.
|
||||||
@ -26,22 +34,55 @@ public class FileCreatedAsyncListener {
|
|||||||
/**
|
/**
|
||||||
* File created.
|
* File created.
|
||||||
*
|
*
|
||||||
* @param fileCreatedAsyncEvent File created event
|
* @param event File created event
|
||||||
*/
|
*/
|
||||||
@Subscribe
|
@Subscribe
|
||||||
public void on(final FileCreatedAsyncEvent fileCreatedAsyncEvent) {
|
public void on(final FileCreatedAsyncEvent event) {
|
||||||
if (log.isInfoEnabled()) {
|
if (log.isInfoEnabled()) {
|
||||||
log.info("File created event: " + fileCreatedAsyncEvent.toString());
|
log.info("File created event: " + event.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Guess the mime type a second time, for open document format (first detected as simple ZIP file)
|
||||||
|
final File file = event.getFile();
|
||||||
|
file.setMimeType(MimeTypeUtil.guessOpenDocumentFormat(file, event.getUnencryptedFile()));
|
||||||
|
|
||||||
|
// Convert to PDF if necessary (for thumbnail and text extraction)
|
||||||
|
Path unencryptedPdfFile = null;
|
||||||
|
try {
|
||||||
|
unencryptedPdfFile = PdfUtil.convertToPdf(file, event.getUnencryptedFile());
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Unable to convert to PDF", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the user from the database
|
||||||
|
final AtomicReference<User> user = new AtomicReference<>();
|
||||||
|
TransactionUtil.handle(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
UserDao userDao = new UserDao();
|
||||||
|
user.set(userDao.getById(event.getUserId()));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (user.get() == null) {
|
||||||
|
// The user has been deleted meanwhile
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate file variations
|
||||||
|
try {
|
||||||
|
Cipher cipher = EncryptionUtil.getEncryptionCipher(user.get().getPrivateKey());
|
||||||
|
FileUtil.saveVariations(file, event.getUnencryptedFile(), unencryptedPdfFile, cipher);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Unable to generate thumbnails", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract text content from the file
|
// Extract text content from the file
|
||||||
final File file = fileCreatedAsyncEvent.getFile();
|
|
||||||
long startTime = System.currentTimeMillis();
|
long startTime = System.currentTimeMillis();
|
||||||
final String content = FileUtil.extractContent(fileCreatedAsyncEvent.getLanguage(), file,
|
final String content = FileUtil.extractContent(event.getLanguage(), file,
|
||||||
fileCreatedAsyncEvent.getUnencryptedFile(), fileCreatedAsyncEvent.getUnencryptedPdfFile());
|
event.getUnencryptedFile(), unencryptedPdfFile);
|
||||||
log.info(MessageFormat.format("File content extracted in {0}ms", System.currentTimeMillis() - startTime));
|
log.info(MessageFormat.format("File content extracted in {0}ms", System.currentTimeMillis() - startTime));
|
||||||
|
|
||||||
// Store the text content in the database
|
// Save the file to database
|
||||||
TransactionUtil.handle(new Runnable() {
|
TransactionUtil.handle(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
@ -58,7 +99,7 @@ public class FileCreatedAsyncListener {
|
|||||||
|
|
||||||
// Update Lucene index
|
// Update Lucene index
|
||||||
LuceneDao luceneDao = new LuceneDao();
|
LuceneDao luceneDao = new LuceneDao();
|
||||||
luceneDao.createFile(fileCreatedAsyncEvent.getFile());
|
luceneDao.createFile(event.getFile());
|
||||||
|
|
||||||
FileUtil.endProcessingFile(file.getId());
|
FileUtil.endProcessingFile(file.getId());
|
||||||
}
|
}
|
||||||
|
@ -121,29 +121,6 @@ public class FileUtil {
|
|||||||
return ocrFile(image, language);
|
return ocrFile(image, language);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Save a file on the storage filesystem.
|
|
||||||
*
|
|
||||||
* @param unencryptedFile Unencrypted file
|
|
||||||
* @param unencryptedPdfFile Unencrypted PDF file
|
|
||||||
* @param file File to save
|
|
||||||
* @param privateKey Private key used for encryption
|
|
||||||
*/
|
|
||||||
public static void save(Path unencryptedFile, Path unencryptedPdfFile, File file, String privateKey) throws Exception {
|
|
||||||
Cipher cipher = EncryptionUtil.getEncryptionCipher(privateKey);
|
|
||||||
Path path = DirectoryUtil.getStorageDirectory().resolve(file.getId());
|
|
||||||
try (InputStream inputStream = Files.newInputStream(unencryptedFile)) {
|
|
||||||
Files.copy(new CipherInputStream(inputStream, cipher), path);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate file variations (errors non-blocking)
|
|
||||||
try {
|
|
||||||
saveVariations(file, unencryptedFile, unencryptedPdfFile, cipher);
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("Unable to generate thumbnails", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate file variations.
|
* Generate file variations.
|
||||||
*
|
*
|
||||||
@ -152,7 +129,7 @@ public class FileUtil {
|
|||||||
* @param unencryptedPdfFile Unencrypted PDF file
|
* @param unencryptedPdfFile Unencrypted PDF file
|
||||||
* @param cipher Cipher to use for encryption
|
* @param cipher Cipher to use for encryption
|
||||||
*/
|
*/
|
||||||
private static void saveVariations(File file, Path unencryptedFile, Path unencryptedPdfFile, Cipher cipher) throws Exception {
|
public static void saveVariations(File file, Path unencryptedFile, Path unencryptedPdfFile, Cipher cipher) throws Exception {
|
||||||
BufferedImage image = null;
|
BufferedImage image = null;
|
||||||
if (ImageUtil.isImage(file.getMimeType())) {
|
if (ImageUtil.isImage(file.getMimeType())) {
|
||||||
try (InputStream inputStream = Files.newInputStream(unencryptedFile)) {
|
try (InputStream inputStream = Files.newInputStream(unencryptedFile)) {
|
||||||
@ -262,14 +239,12 @@ public class FileUtil {
|
|||||||
file.setUserId(userId);
|
file.setUserId(userId);
|
||||||
String fileId = fileDao.create(file, userId);
|
String fileId = fileDao.create(file, userId);
|
||||||
|
|
||||||
// Guess the mime type a second time, for open document format (first detected as simple ZIP file)
|
|
||||||
file.setMimeType(MimeTypeUtil.guessOpenDocumentFormat(file, unencryptedFile));
|
|
||||||
|
|
||||||
// Convert to PDF if necessary (for thumbnail and text extraction)
|
|
||||||
java.nio.file.Path unencryptedPdfFile = PdfUtil.convertToPdf(file, unencryptedFile);
|
|
||||||
|
|
||||||
// Save the file
|
// Save the file
|
||||||
FileUtil.save(unencryptedFile, unencryptedPdfFile, file, user.getPrivateKey());
|
Cipher cipher = EncryptionUtil.getEncryptionCipher(user.getPrivateKey());
|
||||||
|
Path path = DirectoryUtil.getStorageDirectory().resolve(file.getId());
|
||||||
|
try (InputStream inputStream = Files.newInputStream(unencryptedFile)) {
|
||||||
|
Files.copy(new CipherInputStream(inputStream, cipher), path);
|
||||||
|
}
|
||||||
|
|
||||||
// Update the user quota
|
// Update the user quota
|
||||||
user.setStorageCurrent(user.getStorageCurrent() + fileSize);
|
user.setStorageCurrent(user.getStorageCurrent() + fileSize);
|
||||||
@ -283,7 +258,6 @@ public class FileUtil {
|
|||||||
fileCreatedAsyncEvent.setLanguage(language);
|
fileCreatedAsyncEvent.setLanguage(language);
|
||||||
fileCreatedAsyncEvent.setFile(file);
|
fileCreatedAsyncEvent.setFile(file);
|
||||||
fileCreatedAsyncEvent.setUnencryptedFile(unencryptedFile);
|
fileCreatedAsyncEvent.setUnencryptedFile(unencryptedFile);
|
||||||
fileCreatedAsyncEvent.setUnencryptedPdfFile(unencryptedPdfFile);
|
|
||||||
ThreadLocalContext.get().addAsyncEvent(fileCreatedAsyncEvent);
|
ThreadLocalContext.get().addAsyncEvent(fileCreatedAsyncEvent);
|
||||||
|
|
||||||
DocumentUpdatedAsyncEvent documentUpdatedAsyncEvent = new DocumentUpdatedAsyncEvent();
|
DocumentUpdatedAsyncEvent documentUpdatedAsyncEvent = new DocumentUpdatedAsyncEvent();
|
||||||
|
@ -17,7 +17,6 @@ import com.sismics.docs.core.model.jpa.User;
|
|||||||
import com.sismics.docs.core.util.DirectoryUtil;
|
import com.sismics.docs.core.util.DirectoryUtil;
|
||||||
import com.sismics.docs.core.util.EncryptionUtil;
|
import com.sismics.docs.core.util.EncryptionUtil;
|
||||||
import com.sismics.docs.core.util.FileUtil;
|
import com.sismics.docs.core.util.FileUtil;
|
||||||
import com.sismics.docs.core.util.PdfUtil;
|
|
||||||
import com.sismics.rest.exception.ClientException;
|
import com.sismics.rest.exception.ClientException;
|
||||||
import com.sismics.rest.exception.ForbiddenClientException;
|
import com.sismics.rest.exception.ForbiddenClientException;
|
||||||
import com.sismics.rest.exception.ServerException;
|
import com.sismics.rest.exception.ServerException;
|
||||||
@ -202,7 +201,6 @@ public class FileResource extends BaseResource {
|
|||||||
fileCreatedAsyncEvent.setLanguage(documentDto.getLanguage());
|
fileCreatedAsyncEvent.setLanguage(documentDto.getLanguage());
|
||||||
fileCreatedAsyncEvent.setFile(file);
|
fileCreatedAsyncEvent.setFile(file);
|
||||||
fileCreatedAsyncEvent.setUnencryptedFile(unencryptedFile);
|
fileCreatedAsyncEvent.setUnencryptedFile(unencryptedFile);
|
||||||
fileCreatedAsyncEvent.setUnencryptedPdfFile(PdfUtil.convertToPdf(file, unencryptedFile));
|
|
||||||
ThreadLocalContext.get().addAsyncEvent(fileCreatedAsyncEvent);
|
ThreadLocalContext.get().addAsyncEvent(fileCreatedAsyncEvent);
|
||||||
|
|
||||||
DocumentUpdatedAsyncEvent documentUpdatedAsyncEvent = new DocumentUpdatedAsyncEvent();
|
DocumentUpdatedAsyncEvent documentUpdatedAsyncEvent = new DocumentUpdatedAsyncEvent();
|
||||||
|
Loading…
Reference in New Issue
Block a user