@@ -0,0 +1,41 @@
|
|||||||
|
package ru.soune.nocopy.controller;
|
||||||
|
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import ru.soune.nocopy.migration.S3MigrationTool;
|
||||||
|
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/admin/migration")
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Slf4j
|
||||||
|
public class MigrationController {
|
||||||
|
|
||||||
|
private final S3MigrationTool migrationTool;
|
||||||
|
|
||||||
|
@PostMapping("/start")
|
||||||
|
public ResponseEntity<String> startMigration() {
|
||||||
|
log.info("Migration triggered via API");
|
||||||
|
|
||||||
|
CompletableFuture.runAsync(() -> {
|
||||||
|
try {
|
||||||
|
migrationTool.migrationFilesToS3();
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Migration failed", e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return ResponseEntity.ok("Migration started. Check logs for progress.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/status")
|
||||||
|
public ResponseEntity<String> getStatus() {
|
||||||
|
return ResponseEntity.ok("Check application logs and migration_failed.txt for details");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,119 @@
|
|||||||
|
package ru.soune.nocopy.migration;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import ru.soune.nocopy.entity.file.FileEntity;
|
||||||
|
import ru.soune.nocopy.repository.FileEntityRepository;
|
||||||
|
import ru.soune.nocopy.service.file.cloud.CloudStorageService;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.nio.file.StandardOpenOption;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@Slf4j
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class S3MigrationTool {
|
||||||
|
|
||||||
|
private final FileEntityRepository fileEntityRepository;
|
||||||
|
private final CloudStorageService cloudStorageService;
|
||||||
|
|
||||||
|
private static final Path FAILED_LOG = Paths.get("migration_failed.txt");
|
||||||
|
|
||||||
|
public void migrationFilesToS3() {
|
||||||
|
log.info("=== START MIGRATION ===");
|
||||||
|
clearLogFile();
|
||||||
|
|
||||||
|
List<FileEntity> allFiles = fileEntityRepository.findAll();
|
||||||
|
log.info("Total files: {}", allFiles.size());
|
||||||
|
|
||||||
|
int success = 0;
|
||||||
|
List<String> failedIds = new ArrayList<>();
|
||||||
|
|
||||||
|
for (FileEntity file : allFiles) {
|
||||||
|
if (migrateFile(file)) {
|
||||||
|
success++;
|
||||||
|
} else {
|
||||||
|
failedIds.add(file.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info("=== COMPLETED: success {}, failed {} ===", success, failedIds.size());
|
||||||
|
if (!failedIds.isEmpty()) {
|
||||||
|
log.info("Failed file IDs: {}", String.join(", ", failedIds));
|
||||||
|
log.info("Details saved to: {}", FAILED_LOG.toAbsolutePath());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean migrateFile(FileEntity file) {
|
||||||
|
StringBuilder errors = new StringBuilder();
|
||||||
|
|
||||||
|
try {
|
||||||
|
cloudStorageService.saveFilesToStorage(
|
||||||
|
file.getMimeType(), file.getFileExtension(), file.getFilePath()
|
||||||
|
);
|
||||||
|
} catch (Exception e) {
|
||||||
|
errors.append("main:").append(e.getMessage()).append("; ");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ("image".equals(file.getMimeType())) {
|
||||||
|
try {
|
||||||
|
cloudStorageService.saveFilesToStorage(
|
||||||
|
file.getMimeType(), file.getFileExtension(), file.getMediumPath()
|
||||||
|
);
|
||||||
|
} catch (Exception e) {
|
||||||
|
errors.append("medium:").append(e.getMessage()).append("; ");
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
cloudStorageService.saveFilesToStorage(
|
||||||
|
file.getMimeType(), file.getFileExtension(), file.getThumbnailPath()
|
||||||
|
);
|
||||||
|
} catch (Exception e) {
|
||||||
|
errors.append("thumb:").append(e.getMessage()).append("; ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file.getProtectedFilePath() != null) {
|
||||||
|
try {
|
||||||
|
cloudStorageService.saveFilesToStorage(
|
||||||
|
file.getMimeType() != null ? file.getMimeType() : "application",
|
||||||
|
file.getFileExtension(),
|
||||||
|
file.getProtectedFilePath()
|
||||||
|
);
|
||||||
|
} catch (Exception e) {
|
||||||
|
errors.append("protected:").append(e.getMessage()).append("; ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (errors.length() > 0) {
|
||||||
|
writeToFile(String.format("%s | %s | %s",
|
||||||
|
file.getId(), file.getOriginalFileName(), errors));
|
||||||
|
log.warn("Failed to migrate: {} | {}", file.getId(), file.getOriginalFileName());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void clearLogFile() {
|
||||||
|
try {
|
||||||
|
Files.deleteIfExists(FAILED_LOG);
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.warn("Failed to clear log file");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeToFile(String line) {
|
||||||
|
try {
|
||||||
|
Files.write(FAILED_LOG, (line + "\n").getBytes(),
|
||||||
|
StandardOpenOption.CREATE, StandardOpenOption.APPEND);
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("Failed to write to log file", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user