diff --git a/server/src/main/java/sunflower/server/application/event/BrailleTranslateEvent.java b/server/src/main/java/sunflower/server/application/event/BrailleTranslateEvent.java new file mode 100644 index 0000000..cad0149 --- /dev/null +++ b/server/src/main/java/sunflower/server/application/event/BrailleTranslateEvent.java @@ -0,0 +1,15 @@ +package sunflower.server.application.event; + +import lombok.Getter; +import org.springframework.context.ApplicationEvent; + +@Getter +public class BrailleTranslateEvent extends ApplicationEvent { + + private final Long id; + + public BrailleTranslateEvent(final Object source, final Long id) { + super(source); + this.id = id; + } +} diff --git a/server/src/main/java/sunflower/server/application/event/OcrStatusEvent.java b/server/src/main/java/sunflower/server/application/event/OcrStatusEvent.java index 7ad81ec..379cdde 100644 --- a/server/src/main/java/sunflower/server/application/event/OcrStatusEvent.java +++ b/server/src/main/java/sunflower/server/application/event/OcrStatusEvent.java @@ -7,11 +7,9 @@ public class OcrStatusEvent extends ApplicationEvent { private final Long id; - private final String pdfId; - public OcrStatusEvent(final Object source, final Long id, final String pdfId) { + public OcrStatusEvent(final Object source, final Long id) { super(source); this.id = id; - this.pdfId = pdfId; } } diff --git a/server/src/main/java/sunflower/server/application/eventlistener/BrailleTranslateEventListener.java b/server/src/main/java/sunflower/server/application/eventlistener/BrailleTranslateEventListener.java new file mode 100644 index 0000000..e4343ad --- /dev/null +++ b/server/src/main/java/sunflower/server/application/eventlistener/BrailleTranslateEventListener.java @@ -0,0 +1,80 @@ +package sunflower.server.application.eventlistener; + +import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.transaction.event.TransactionalEventListener; +import sunflower.server.application.event.BrailleTranslateEvent; +import sunflower.server.client.BrailleTranslationClient; +import sunflower.server.entity.Translations; +import sunflower.server.repository.TranslationsRepository; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; + +import static org.springframework.transaction.annotation.Propagation.REQUIRES_NEW; + +@Slf4j +@NoArgsConstructor +@Component +public class BrailleTranslateEventListener { + + private TranslationsRepository translationsRepository; + private BrailleTranslationClient brailleTranslationClient; + private ApplicationEventPublisher eventPublisher; + + @Autowired + public BrailleTranslateEventListener( + final TranslationsRepository translationsRepository, + final BrailleTranslationClient brailleTranslationClient, + final ApplicationEventPublisher eventPublisher + ) { + this.translationsRepository = translationsRepository; + this.brailleTranslationClient = brailleTranslationClient; + this.eventPublisher = eventPublisher; + } + + @Async + @TransactionalEventListener + @Transactional(propagation = REQUIRES_NEW) + public void downloadLatexFile(final BrailleTranslateEvent event) { + final Translations translations = translationsRepository.getById(event.getId()); + + final String latexPath = translations.getLatexPath(); + final File latexFile = Paths.get(latexPath).toFile(); + + if (!latexFile.exists()) { + throw new RuntimeException("파일이 존재하지 않습니다!"); + } + + final String brfContent = brailleTranslationClient.translate(latexFile); + final String brfPath = saveBrfFile(brfContent, translations.getOcrPdfId()); + + translations.registerBrfPath(brfPath); + } + + private String saveBrfFile(final String content, final String ocrPdfId) { + final String directory = "src/main/brf"; + + final String fileName = ocrPdfId + ".brf"; + final Path brfPath = Paths.get(directory, fileName); + + final File file = brfPath.toFile(); + try { + final FileWriter writer = new FileWriter(file); + writer.write(content); + writer.close(); + } catch (IOException e) { + throw new RuntimeException(e); + } + + return brfPath.toString(); + } +} diff --git a/server/src/main/java/sunflower/server/application/eventlistener/OcrDownloadEventListener.java b/server/src/main/java/sunflower/server/application/eventlistener/OcrDownloadEventListener.java index a5bad54..7673deb 100644 --- a/server/src/main/java/sunflower/server/application/eventlistener/OcrDownloadEventListener.java +++ b/server/src/main/java/sunflower/server/application/eventlistener/OcrDownloadEventListener.java @@ -8,6 +8,7 @@ import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.event.TransactionalEventListener; +import sunflower.server.application.event.BrailleTranslateEvent; import sunflower.server.application.event.OcrDownloadEvent; import sunflower.server.client.OcrDownloadClient; import sunflower.server.entity.Translations; @@ -45,8 +46,9 @@ public void downloadLatexFile(final OcrDownloadEvent event) { final byte[] latex = ocrDownloadClient.download(pdfId); final String latexPath = saveLatexFile(pdfId, latex); + log.info("Latex File 저장! 경로: {}", latexPath); translations.registerLatexPath(latexPath); - // TODO: publish event + eventPublisher.publishEvent(new BrailleTranslateEvent(this, event.getId())); } } diff --git a/server/src/main/java/sunflower/server/application/eventlistener/OcrRegisterEventListener.java b/server/src/main/java/sunflower/server/application/eventlistener/OcrRegisterEventListener.java index 38f921c..c79099a 100644 --- a/server/src/main/java/sunflower/server/application/eventlistener/OcrRegisterEventListener.java +++ b/server/src/main/java/sunflower/server/application/eventlistener/OcrRegisterEventListener.java @@ -54,6 +54,6 @@ public void registerOcr(final OcrRegisterEvent event) { final String pdfId = ocrRegisterClient.requestPdfId(file); translations.registerPdfId(pdfId); - eventPublisher.publishEvent(new OcrStatusEvent(this, id, pdfId)); + eventPublisher.publishEvent(new OcrStatusEvent(this, id)); } } diff --git a/server/src/main/java/sunflower/server/application/eventlistener/OcrStatusEventListener.java b/server/src/main/java/sunflower/server/application/eventlistener/OcrStatusEventListener.java index 141ec80..1a4316e 100644 --- a/server/src/main/java/sunflower/server/application/eventlistener/OcrStatusEventListener.java +++ b/server/src/main/java/sunflower/server/application/eventlistener/OcrStatusEventListener.java @@ -48,7 +48,7 @@ public void checkOcrStatus(final OcrStatusEvent event) { final Long id = event.getId(); final Translations translations = translationsRepository.getById(id); - final String pdfId = event.getPdfId(); + final String pdfId = translations.getOcrPdfId(); final OcrStatusDto status = ocrStatusClient.checkStatus(pdfId); translations.changeOcrStatus(status); @@ -63,6 +63,6 @@ public void checkOcrStatus(final OcrStatusEvent event) { @Scheduled(fixedDelay = 1000) private void retryCheckOcrStatus(final Long id, final String pdfId) { log.info("Cheking OCR status for translations id: {}, pdf id: {}", id, pdfId); - eventPublisher.publishEvent(new OcrStatusEvent(this, id, pdfId)); + eventPublisher.publishEvent(new OcrStatusEvent(this, id)); } } diff --git a/server/src/main/java/sunflower/server/client/ApiBrailleTranslationClient.java b/server/src/main/java/sunflower/server/client/ApiBrailleTranslationClient.java index cb56649..e6e2156 100644 --- a/server/src/main/java/sunflower/server/client/ApiBrailleTranslationClient.java +++ b/server/src/main/java/sunflower/server/client/ApiBrailleTranslationClient.java @@ -3,6 +3,10 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Profile; +import org.springframework.core.io.FileSystemResource; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Component; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; @@ -10,29 +14,53 @@ import java.io.File; +import static org.springframework.http.MediaType.MULTIPART_FORM_DATA; + @Slf4j @Profile("!test") @Component public class ApiBrailleTranslationClient implements BrailleTranslationClient { private final String appURI; - private final String key; + private final String keyName; private final RestTemplate restTemplate; public ApiBrailleTranslationClient( - @Value("${braille-translation.url}") String appURI, - @Value("${braille-translation.key-name}") String key, + @Value("${braille-translation.uri}") String appURI, + @Value("${braille-translation.key-name}") String keyName, RestTemplate restTemplate ) { this.appURI = appURI; - this.key = key; + this.keyName = keyName; this.restTemplate = restTemplate; } @Override - public File translate(final Long id) { - MultiValueMap requestBody = new LinkedMultiValueMap<>(); + public String translate(final File file) { + final HttpHeaders requestHeader = createRequestHeader(); + MultiValueMap requestBody = createRequestBody(file); + final HttpEntity> requestEntity = new HttpEntity<>(requestBody, requestHeader); + + log.info("Request URI: {}", appURI); + log.info("Request Headers: {}", requestHeader); + log.info("Request Parameters: {}", requestBody); + + final ResponseEntity response = restTemplate.postForEntity(appURI, requestEntity, String.class); + + log.info("Response Body: {}", response.getBody()); - return null; + return response.getBody(); + } + + private HttpHeaders createRequestHeader() { + HttpHeaders requestHeader = new HttpHeaders(); + requestHeader.setContentType(MULTIPART_FORM_DATA); + return requestHeader; + } + + private MultiValueMap createRequestBody(final File file) { + MultiValueMap requestBody = new LinkedMultiValueMap<>(); + requestBody.add(keyName, new FileSystemResource(file)); + return requestBody; } } diff --git a/server/src/main/java/sunflower/server/client/ApiOcrRegisterClient.java b/server/src/main/java/sunflower/server/client/ApiOcrRegisterClient.java index 5398943..877d966 100644 --- a/server/src/main/java/sunflower/server/client/ApiOcrRegisterClient.java +++ b/server/src/main/java/sunflower/server/client/ApiOcrRegisterClient.java @@ -6,6 +6,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Profile; +import org.springframework.core.io.FileSystemResource; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; @@ -15,7 +16,6 @@ import org.springframework.util.MultiValueMap; import org.springframework.web.client.RestTemplate; import org.springframework.web.multipart.MultipartFile; -import sunflower.server.util.FileUtil; import java.io.File; import java.util.Arrays; @@ -87,7 +87,7 @@ private HttpHeaders createRequestHeader() { @Deprecated private MultiValueMap createRequestBody(final MultipartFile file) { MultiValueMap requestBody = new LinkedMultiValueMap<>(); - requestBody.add("file", FileUtil.convertToFileSystemResource(file)); + requestBody.add("file", file.getResource()); Map bodyMap = new HashMap<>(); bodyMap.put("conversion_formats", Map.of("docx", true, "tex.zip", true)); @@ -136,7 +136,7 @@ public String requestPdfId(final File file) { private MultiValueMap createRequestBody(final File file) { MultiValueMap requestBody = new LinkedMultiValueMap<>(); - requestBody.add("file", FileUtil.convertToFileSystemResource(file)); + requestBody.add("file", new FileSystemResource(file)); Map bodyMap = new HashMap<>(); bodyMap.put("conversion_formats", Map.of("docx", true, "tex.zip", true)); diff --git a/server/src/main/java/sunflower/server/client/BrailleTranslationClient.java b/server/src/main/java/sunflower/server/client/BrailleTranslationClient.java index d698e5c..3725cd4 100644 --- a/server/src/main/java/sunflower/server/client/BrailleTranslationClient.java +++ b/server/src/main/java/sunflower/server/client/BrailleTranslationClient.java @@ -4,5 +4,5 @@ public interface BrailleTranslationClient { - File translate(final Long id); + String translate(File file); } diff --git a/server/src/main/java/sunflower/server/entity/Translations.java b/server/src/main/java/sunflower/server/entity/Translations.java index 2abc7ac..a6838fd 100644 --- a/server/src/main/java/sunflower/server/entity/Translations.java +++ b/server/src/main/java/sunflower/server/entity/Translations.java @@ -39,11 +39,17 @@ public class Translations { public static Translations of(final String pdfPath, final String inputFileName) { final Translations translations = new Translations(); + translations.start(); translations.changePdfPath(pdfPath); translations.changeInputFileName(inputFileName); return translations; } + private void start() { + this.ocrPercentDone = 0; + this.translationPercentDone = 0; + } + private void changePdfPath(final String pdfPath) { this.pdfPath = pdfPath; } @@ -69,4 +75,8 @@ public void changeOcrStatus(final OcrStatusDto dto) { public void registerLatexPath(final String latexPath) { this.latexPath = latexPath; } + + public void registerBrfPath(final String brfPath) { + this.brfPath = brfPath; + } } diff --git a/server/src/main/java/sunflower/server/util/FileUtil.java b/server/src/main/java/sunflower/server/util/FileUtil.java index cb38777..5507019 100644 --- a/server/src/main/java/sunflower/server/util/FileUtil.java +++ b/server/src/main/java/sunflower/server/util/FileUtil.java @@ -1,25 +1,31 @@ package sunflower.server.util; +import lombok.extern.slf4j.Slf4j; import org.springframework.core.io.FileSystemResource; import org.springframework.core.io.Resource; import org.springframework.web.multipart.MultipartFile; +import java.io.ByteArrayInputStream; import java.io.File; -import java.io.FileOutputStream; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; +@Slf4j public final class FileUtil { + private static final String BASE_PATH = "src/main/latex/"; + public static String savePdfFile(final MultipartFile file, String fileName) { final Path path = Paths.get("src", "main", "pdf", fileName); try { Files.copy(file.getInputStream(), path); Resource resource = new FileSystemResource(path.toFile()); - return resource.getURI().getPath(); + return resource.getFile().getPath(); } catch (IOException e) { throw new RuntimeException(e); } @@ -34,13 +40,21 @@ public static FileSystemResource convertToFileSystemResource(final File file) { } public static String saveLatexFile(final String pdfId, byte[] content) { - final File file = new File("src/main/latex/" + pdfId + ".zip"); - - try (FileOutputStream fos = new FileOutputStream(file)) { - fos.write(content); + String path = BASE_PATH + pdfId + ".tex"; + + try (ZipInputStream zipInputStream = new ZipInputStream(new ByteArrayInputStream(content))) { + ZipEntry entry; + while ((entry = zipInputStream.getNextEntry()) != null) { + if (!entry.isDirectory()) { + Files.copy(zipInputStream, Paths.get(path)); + break; + } + } } catch (IOException e) { - throw new RuntimeException("파일을 읽는데 실패함!"); + log.error("Error extracting file from zip: {}", e.getMessage()); + throw new RuntimeException(e); } - return file.getPath(); + + return path; } } diff --git a/server/src/main/resources/security b/server/src/main/resources/security index f4d19e9..5334c68 160000 --- a/server/src/main/resources/security +++ b/server/src/main/resources/security @@ -1 +1 @@ -Subproject commit f4d19e90f5cda125b739c35fa18d39f54e28ac22 +Subproject commit 5334c6882ff5c13d96a970e17d11ef2ab94fba8d diff --git a/server/src/test/java/sunflower/server/client/MockBrailleTranslationClient.java b/server/src/test/java/sunflower/server/client/MockBrailleTranslationClient.java new file mode 100644 index 0000000..970552b --- /dev/null +++ b/server/src/test/java/sunflower/server/client/MockBrailleTranslationClient.java @@ -0,0 +1,16 @@ +package sunflower.server.client; + +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Component; + +import java.io.File; + +@Component +@Profile("test") +public class MockBrailleTranslationClient implements BrailleTranslationClient { + + @Override + public String translate(final File file) { + return null; + } +}