NCBACK-35 add cloud for save when download last chunk and after protected
Test Workflow / test (push) Successful in 3s

This commit is contained in:
vladp
2026-02-13 21:11:30 +07:00
parent 03a330b570
commit 2985d84b04
10 changed files with 305 additions and 30 deletions
@@ -32,6 +32,7 @@ import ru.soune.nocopy.repository.AuthTokenRepository;
import ru.soune.nocopy.repository.FileEntityRepository;
import ru.soune.nocopy.service.FileSimilarityService;
import ru.soune.nocopy.service.file.ProtectionsLimitService;
import ru.soune.nocopy.service.file.cloud.CloudStorageService;
import ru.soune.nocopy.service.register.AuthService;
import ru.soune.nocopy.service.file.FileEntityService;
import ru.soune.nocopy.service.file.FileUploadService;
@@ -291,6 +292,8 @@ public class ApiController {
}
}
private final CloudStorageService cloudStorageService;
@GetMapping("/v{version}/files/download/{fileId}")
public ResponseEntity<?> downloadFile(
@PathVariable(required = false) String fileId,
@@ -342,29 +345,29 @@ public class ApiController {
errorData));
}
Path filePath = Paths.get(entityResponse.getProtectedFilePath());
// Resource resource = new UrlResource(filePath.toUri());
FileSystemResource resource = new FileSystemResource(filePath);
File file = cloudStorageService.readFileFromStorageByPath(
entityResponse.getProtectedFilePath());
long fileSize = Files.size(filePath);
if (!resource.exists()) {
if (!file.exists()) {
Map<String, Object> errorData = new HashMap<>();
errorData.put("resource", resource.exists());
errorData.put("file", file.exists());
return ResponseEntity.ok().body(new BaseResponse(20004,
MessageCode.FILE_DOWNLOAD_ERROR.getCode(),
MessageCode.FILE_DOWNLOAD_ERROR.getDescription(),
errorData));
}
String contentType = determineContentType(filePath);
String contentType = determineContentType(filePath);
return ResponseEntity.ok()
.contentLength(fileSize)
.contentType(MediaType.parseMediaType(contentType))
.header(HttpHeaders.CONTENT_DISPOSITION,
"attachment; filename=\"" + entityResponse.getFileName() + "\"")
.body(resource);
.body(file);
} catch (FileEntityNotFoundException e) {
Map<String, Object> errorData = new HashMap<>();
errorData.put("fileId", fileId);
@@ -0,0 +1,86 @@
package ru.soune.nocopy.controller;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
import software.amazon.awssdk.auth.credentials.AwsCredentials;
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
import software.amazon.awssdk.core.sync.RequestBody;
import software.amazon.awssdk.http.apache.ApacheHttpClient;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.model.GetObjectRequest;
import software.amazon.awssdk.services.s3.model.PutObjectRequest;
import java.io.IOException;
import java.net.URI;
import static org.springframework.http.MediaType.MULTIPART_FORM_DATA_VALUE;
@RestController
@RequestMapping("/photos")
@Tag(name = "Photos")
@ApiResponses(@ApiResponse(responseCode = "200", useReturnTypeSchema = true))
public class PhotoController {
private static final String KEY_ID = "YCAJEmHZcWxzf4oGWvETG3mms";
private static final String SECRET_KEY = "YCPAPZ32XC-LWb8xE0b_xTcBD8NZUCHpSOfu8LUG";
private static final String REGION = "ru-central1";
private static final String S3_ENDPOINT = "https://storage.yandexcloud.net";
private static final String BUCKET = "ncp-test-storage";
private final S3Client s3Client;
public PhotoController() {
AwsCredentials credentials = AwsBasicCredentials.create(KEY_ID, SECRET_KEY);
s3Client = S3Client.builder()
.httpClient(ApacheHttpClient.create())
.region(Region.of(REGION))
.endpointOverride(URI.create(S3_ENDPOINT))
.credentialsProvider(StaticCredentialsProvider.create(credentials))
.build();
}
@PutMapping(consumes = MULTIPART_FORM_DATA_VALUE)
public String uploadFile(@RequestParam MultipartFile photo) throws IOException {
String key = "photos/" + photo.getOriginalFilename();
PutObjectRequest putObjectRequest = PutObjectRequest.builder()
.bucket(BUCKET)
.key(key)
.contentType(photo.getContentType())
.build();
s3Client.putObject(putObjectRequest, RequestBody.fromBytes(photo.getBytes()));
return key;
}
@GetMapping
public ResponseEntity<byte[]> downloadFile(@RequestParam String key) throws IOException {
GetObjectRequest objectRequest = GetObjectRequest.builder()
.bucket(BUCKET)
.key(key)
.build();
var inputStream = s3Client.getObject(objectRequest);
byte[] data = inputStream.readAllBytes();
var headers = new HttpHeaders();
headers.add(HttpHeaders.CONTENT_DISPOSITION, "inline");
headers.add(HttpHeaders.CONTENT_TYPE, inputStream.response().contentType());
return ResponseEntity.ok()
.headers(headers)
.body(data);
}
}