add generateMultipartDownloadUrl method (#22)

Co-authored-by: ggmaleva <ggmaleva@yandex.ru>
This commit is contained in:
Gregory 2024-01-24 14:52:17 +03:00 committed by GitHub
parent c0205a2290
commit 769c158620
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 83 additions and 13 deletions

View File

@ -30,7 +30,7 @@
<dependency> <dependency>
<groupId>dev.vality</groupId> <groupId>dev.vality</groupId>
<artifactId>file-storage-proto</artifactId> <artifactId>file-storage-proto</artifactId>
<version>1.47-0f31e02</version> <version>1.48-4569cea</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>dev.vality</groupId> <groupId>dev.vality</groupId>

View File

@ -92,6 +92,22 @@ public class FileStorageHandler implements FileStorageSrv.Iface {
return result; return result;
} }
@Override
public String generateMultipartDownloadUrl(String fileDataId, String expiresAt) throws TException {
try {
log.info("Receive request for generate download url with fileDataId={}", fileDataId);
CheckerUtil.checkString(fileDataId, "Bad request parameter, fileDataId required and not empty arg");
CheckerUtil.checkString(expiresAt, "Bad request parameter, expiresAt required and not empty arg");
Instant instant = TypeUtil.stringToInstant(expiresAt);
URL url = storageService.generateMultipartDownloadUrl(fileDataId, instant);
log.info("Successfully generate download url with fileDataId={}", fileDataId);
log.debug("Generated download url={}", url);
return url.toString();
} catch (FileNotFoundException e) {
throw fileNotFound(e);
}
}
private FileNotFound fileNotFound(FileNotFoundException e) { private FileNotFound fileNotFound(FileNotFoundException e) {
log.warn("File not found", e); log.warn("File not found", e);
return new FileNotFound(); return new FileNotFound();

View File

@ -134,6 +134,11 @@ public class S3Service implements StorageService {
throw new UnsupportedOperationException(METHOD_NOT_SUPPORTED); throw new UnsupportedOperationException(METHOD_NOT_SUPPORTED);
} }
@Override
public URL generateMultipartDownloadUrl(String fileDataId, Instant expirationTime) {
throw new UnsupportedOperationException(METHOD_NOT_SUPPORTED);
}
@PreDestroy @PreDestroy
public void terminate() { public void terminate() {
transferManager.shutdownNow(true); transferManager.shutdownNow(true);

View File

@ -20,6 +20,7 @@ import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.model.*; import software.amazon.awssdk.services.s3.model.*;
import software.amazon.awssdk.services.s3.presigner.S3Presigner; import software.amazon.awssdk.services.s3.presigner.S3Presigner;
import software.amazon.awssdk.services.s3.presigner.model.GetObjectPresignRequest; import software.amazon.awssdk.services.s3.presigner.model.GetObjectPresignRequest;
import software.amazon.awssdk.services.s3.presigner.model.PresignedGetObjectRequest;
import software.amazon.awssdk.services.s3.presigner.model.PutObjectPresignRequest; import software.amazon.awssdk.services.s3.presigner.model.PutObjectPresignRequest;
import javax.annotation.PostConstruct; import javax.annotation.PostConstruct;
@ -66,18 +67,7 @@ public class S3V2Service implements StorageService {
var versions = getObjectVersions(fileId); var versions = getObjectVersions(fileId);
checkFileExist(fileId, versions); checkFileExist(fileId, versions);
var fileVersionId = getFileVersionId(fileId, versions); var fileVersionId = getFileVersionId(fileId, versions);
var presignRequest = GetObjectPresignRequest.builder() PresignedGetObjectRequest presignedRequest = getPresignedRequest(fileId, expirationTime, fileVersionId);
.signatureDuration(Duration.between(Instant.now(), expirationTime))
.getObjectRequest(GetObjectRequest.builder()
.bucket(s3SdkV2Properties.getBucketName())
.key(fileId)
.versionId(fileVersionId)
.build())
.build();
var presignedRequest = s3Presigner.presignGetObject(presignRequest);
log.info("Download url was presigned, fileId={}, bucketName={}, isBrowserExecutable={}",
fileId, s3SdkV2Properties.getBucketName(), presignedRequest.isBrowserExecutable());
log.debug("Presigned http request={}", presignedRequest.httpRequest().toString());
return presignedRequest.url(); return presignedRequest.url();
} }
@ -510,6 +500,36 @@ public class S3V2Service implements StorageService {
} }
} }
@Override
public URL generateMultipartDownloadUrl(String fileId, Instant expirationTime) {
var versions = getObjectVersions(fileId);
if (CollectionUtils.isEmpty(versions)) {
throw new FileNotFoundException(String.format(
"Failed to check object version with file on exist, fileId=%s, bucketName=%s ",
fileId,
s3SdkV2Properties.getBucketName()));
}
var fileVersionId = getFileVersionId(fileId, versions);
PresignedGetObjectRequest presignedRequest = getPresignedRequest(fileId, expirationTime, fileVersionId);
return presignedRequest.url();
}
private PresignedGetObjectRequest getPresignedRequest(String fileId, Instant expirationTime, String fileVersionId) {
var presignRequest = GetObjectPresignRequest.builder()
.signatureDuration(Duration.between(Instant.now(), expirationTime))
.getObjectRequest(GetObjectRequest.builder()
.bucket(s3SdkV2Properties.getBucketName())
.key(fileId)
.versionId(fileVersionId)
.build())
.build();
var presignedRequest = s3Presigner.presignGetObject(presignRequest);
log.info("Download url was presigned, fileId={}, bucketName={}, isBrowserExecutable={}",
fileId, s3SdkV2Properties.getBucketName(), presignedRequest.isBrowserExecutable());
log.debug("Presigned http request={}", presignedRequest.httpRequest().toString());
return presignedRequest;
}
private software.amazon.awssdk.services.s3.model.CompleteMultipartUploadRequest buildRequest( private software.amazon.awssdk.services.s3.model.CompleteMultipartUploadRequest buildRequest(
CompleteMultipartUploadRequest request, CompleteMultipartUploadRequest request,
String fileId, String fileId,

View File

@ -23,4 +23,6 @@ public interface StorageService {
CompleteMultipartUploadResult completeMultipartUpload(CompleteMultipartUploadRequest request); CompleteMultipartUploadResult completeMultipartUpload(CompleteMultipartUploadRequest request);
URL generateMultipartDownloadUrl(String fileDataId, Instant expirationTime);
} }

View File

@ -27,6 +27,7 @@ import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.nio.file.StandardCopyOption; import java.nio.file.StandardCopyOption;
import java.time.Instant;
import java.util.*; import java.util.*;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
@ -425,4 +426,30 @@ public abstract class FileStorageTest {
assertNotNull(multipartFileData.getCreatedAt()); assertNotNull(multipartFileData.getCreatedAt());
assertNotNull(multipartFileData.getMetadata()); assertNotNull(multipartFileData.getMetadata());
} }
@Test
void generateMultipartDownloadUrl() throws Exception {
dev.vality.msgpack.Value value = new dev.vality.msgpack.Value();
String fileName = "test_registry.csv";
value.setStr(fileName);
Map<String, dev.vality.msgpack.Value> metadata = Map.of("filename", value);
CreateMultipartUploadResult createResult = fileStorageClient.createMultipartUpload(metadata);
assertNotNull(createResult.getFileDataId());
assertNotNull(createResult.getMultipartUploadId());
List<CompletedMultipart> completedParts = new ArrayList<>();
processMultipartUpload(createResult, completedParts);
var completeRequest = new CompleteMultipartUploadRequest()
.setMultipartUploadId(createResult.getMultipartUploadId())
.setFileDataId(createResult.getFileDataId())
.setCompletedParts(completedParts);
fileStorageClient.completeMultipartUpload(completeRequest);
String expiredTime = Instant.now().toString();
String url = fileStorageClient.generateMultipartDownloadUrl(createResult.getFileDataId(), expiredTime);
assertNotNull(url);
}
} }