This commit is contained in:
@@ -0,0 +1,146 @@
|
||||
package ru.soune.nocopy.service.file;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import ru.soune.nocopy.entity.file.FileEntity;
|
||||
import ru.soune.nocopy.entity.file.moderation.ModerationPassportFile;
|
||||
import ru.soune.nocopy.service.file.moderation.ModerationFileService;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Base64;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class ZipService {
|
||||
|
||||
private final ModerationFileService moderationFileService;
|
||||
|
||||
private static final int MAX_SIZE_MB = 20;
|
||||
|
||||
private static final int FIRST_PART = 1;
|
||||
|
||||
private static final int SECOND_PART = 2;
|
||||
|
||||
public void createAndSplitZip(Long userId, List<FileEntity> files) throws IOException {
|
||||
byte[] zipBytes = createZip(files);
|
||||
String base64String = Base64.getEncoder().encodeToString(zipBytes);
|
||||
String[] parts = splitBase64(base64String);
|
||||
saveSplitFiles(userId, parts[0], parts[1]);
|
||||
}
|
||||
|
||||
public byte[] assembleZipFromSplitFiles(Long userId) throws IOException {
|
||||
List<ModerationPassportFile> activeFiles = moderationFileService.getActiveFiles();
|
||||
|
||||
String part1Content = null;
|
||||
String part2Content = null;
|
||||
|
||||
for (ModerationPassportFile file : activeFiles) {
|
||||
Path filePath = Paths.get(file.getPath());
|
||||
String content = Files.readString(filePath);
|
||||
|
||||
if (file.getPart() == FIRST_PART) {
|
||||
part1Content = content;
|
||||
} else if (file.getPart() == SECOND_PART) {
|
||||
part2Content = content;
|
||||
}
|
||||
}
|
||||
|
||||
if (part1Content == null || part2Content == null) {
|
||||
throw new IOException("Missing part 1 or part 2 for user: " + userId);
|
||||
}
|
||||
|
||||
String base64String = mergeBase64(part1Content, part2Content);
|
||||
|
||||
return Base64.getDecoder().decode(base64String);
|
||||
}
|
||||
|
||||
private byte[] createZip(List<FileEntity> files) throws IOException {
|
||||
long totalSize = files.stream()
|
||||
.map(FileEntity::getFileSize)
|
||||
.reduce(0L, Long::sum);
|
||||
|
||||
|
||||
if (totalSize > MAX_SIZE_MB * 1024 * 1024) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format("Total size %.2f MB exceeds %d MB limit",
|
||||
totalSize / (1024.0 * 1024.0), MAX_SIZE_MB)
|
||||
);
|
||||
}
|
||||
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
try (ZipOutputStream zos = new ZipOutputStream(baos)) {
|
||||
|
||||
for (FileEntity file: files) {
|
||||
String filePath = file.getFilePath();
|
||||
String fileName = file.getStoredFileName();
|
||||
|
||||
Path path = Paths.get(filePath);
|
||||
ZipEntry zipEntry = new ZipEntry(fileName);
|
||||
zos.putNextEntry(zipEntry);
|
||||
Files.copy(path, zos);
|
||||
zos.closeEntry();
|
||||
|
||||
log.info("Added file {} to ZIP", fileName);
|
||||
}
|
||||
}
|
||||
|
||||
return baos.toByteArray();
|
||||
}
|
||||
|
||||
private String[] splitBase64(String base64) {
|
||||
StringBuilder part1 = new StringBuilder();
|
||||
StringBuilder part2 = new StringBuilder();
|
||||
|
||||
for (int i = 0; i < base64.length(); i++) {
|
||||
if (i % 2 == 0) {
|
||||
part1.append(base64.charAt(i));
|
||||
} else {
|
||||
part2.append(base64.charAt(i));
|
||||
}
|
||||
}
|
||||
|
||||
return new String[]{part1.toString(), part2.toString()};
|
||||
}
|
||||
|
||||
private void saveSplitFiles(Long userId, String part1, String part2) throws IOException {
|
||||
Path userDir = Paths.get("/uploads/passport", String.valueOf(userId));
|
||||
Files.createDirectories(userDir);
|
||||
|
||||
Path file1 = userDir.resolve(userId + "___1.txt");
|
||||
Files.writeString(file1, part1);
|
||||
Path file2 = userDir.resolve(userId + "___2.txt");
|
||||
Files.writeString(file2, part2);
|
||||
Map<Integer, String> files = Map.of(FIRST_PART, file1.toString(), SECOND_PART, file2.toString());
|
||||
|
||||
moderationFileService.addFiles(userId, files);
|
||||
|
||||
log.info("Saved split files: {} and {}", file1, file2);
|
||||
}
|
||||
|
||||
private String mergeBase64(String part1, String part2) {
|
||||
StringBuilder merged = new StringBuilder();
|
||||
|
||||
int maxLength = Math.max(part1.length(), part2.length());
|
||||
|
||||
for (int i = 0; i < maxLength; i++) {
|
||||
if (i < part1.length()) {
|
||||
merged.append(part1.charAt(i));
|
||||
}
|
||||
if (i < part2.length()) {
|
||||
merged.append(part2.charAt(i));
|
||||
}
|
||||
}
|
||||
|
||||
return merged.toString();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user