From 3729588db215453cd60f6294c6ab6ce32fdc3fbd Mon Sep 17 00:00:00 2001 From: Saijad Dhuka Date: Thu, 23 Feb 2023 16:55:56 -0600 Subject: [PATCH 01/14] feat: Add support for S3 acceleration mode --- .../auth/cognito/AWSCognitoAuthService.kt | 4 +- ...ointResolver.kt => AWSEndpointProvider.kt} | 14 +- .../storage/s3/AWSS3StorageDownloadTest.java | 31 +++- .../storage/s3/AWSS3StorageUploadTest.java | 58 ++++++-- .../storage/s3/transfer/TransferDBTest.kt | 12 +- .../storage/s3/AWSS3StoragePlugin.java | 23 ++- .../AWSS3StorageDownloadFileOperation.kt | 7 +- .../AWSS3StorageGetPresignedUrlOperation.java | 41 +++--- .../AWSS3StorageUploadFileOperation.kt | 8 +- .../AWSS3StorageUploadInputStreamOperation.kt | 3 +- .../AWSS3StorageDownloadFileOptions.java | 27 +++- .../AWSS3StorageGetPresignedUrlOptions.java | 23 +++ .../AWSS3StorageUploadFileOptions.java | 22 +++ .../AWSS3StorageUploadInputStreamOptions.java | 22 +++ .../AWSS3StorageDownloadFileRequest.java | 15 +- .../AWSS3StorageGetPresignedUrlRequest.java | 15 +- .../s3/request/AWSS3StorageUploadRequest.java | 15 +- .../storage/s3/service/AWSS3StorageService.kt | 50 +++++-- .../storage/s3/service/StorageService.java | 16 ++- .../ProgressListenerHttpInterceptor.kt | 133 ++++++++++++++++++ .../storage/s3/transfer/TransferDB.kt | 24 +++- .../storage/s3/transfer/TransferDBHelper.kt | 2 +- .../storage/s3/transfer/TransferManager.kt | 33 +++-- .../storage/s3/transfer/TransferRecord.kt | 6 +- .../storage/s3/transfer/TransferTable.kt | 15 ++ .../worker/AbortMultiPartUploadWorker.kt | 5 +- .../s3/transfer/worker/BaseTransferWorker.kt | 75 +--------- .../worker/CompleteMultiPartUploadWorker.kt | 5 +- .../s3/transfer/worker/DownloadWorker.kt | 83 ++++++----- .../InitiateMultiPartUploadTransferWorker.kt | 5 +- .../worker/PartUploadTransferWorker.kt | 17 ++- .../transfer/worker/SinglePartUploadWorker.kt | 7 +- .../storage/s3/StorageComponentTest.java | 31 ++-- .../AWSS3StorageDownloadFileOperationTest.kt | 18 ++- ...WSS3StorageGetPresignedUrlOperationTest.kt | 15 +- .../AWSS3StorageUploadFileOperationTest.kt | 38 +++-- ...S3StorageUploadInputStreamOperationTest.kt | 65 +++++---- .../worker/AbortMultiPartUploadWorkerTest.kt | 13 +- .../s3/transfer/worker/DownloadWorkerTest.kt | 68 +++------ ...itiateMultiPartUploadTransferWorkerTest.kt | 31 +++- .../options/StorageDownloadFileOptions.java | 1 - settings.gradle.kts | 2 +- 42 files changed, 775 insertions(+), 323 deletions(-) rename aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/{AWSEndpointResolver.kt => AWSEndpointProvider.kt} (57%) create mode 100644 aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/ProgressListenerHttpInterceptor.kt diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/AWSCognitoAuthService.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/AWSCognitoAuthService.kt index 38d9c9c3d1..cc6c8bf9b4 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/AWSCognitoAuthService.kt +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/AWSCognitoAuthService.kt @@ -30,8 +30,8 @@ interface AWSCognitoAuthService { CognitoIdentityProviderClient { this.region = it.region - this.endpointResolver = it.endpoint?.let { endpoint -> - AWSEndpointResolver(Endpoint(endpoint)) + this.endpointProvider = it.endpoint?.let { endpoint -> + AWSEndpointProvider(Endpoint(endpoint)) } } } diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/AWSEndpointResolver.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/AWSEndpointProvider.kt similarity index 57% rename from aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/AWSEndpointResolver.kt rename to aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/AWSEndpointProvider.kt index bae41aed97..8f634e4c48 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/AWSEndpointResolver.kt +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/AWSEndpointProvider.kt @@ -1,5 +1,5 @@ /* - * Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Copyright 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"). * You may not use this file except in compliance with the License. @@ -12,16 +12,14 @@ * express or implied. See the License for the specific language governing * permissions and limitations under the License. */ - package com.amplifyframework.auth.cognito -import aws.sdk.kotlin.runtime.endpoint.AwsEndpoint -import aws.sdk.kotlin.runtime.endpoint.AwsEndpointResolver -import aws.sdk.kotlin.runtime.endpoint.CredentialScope +import aws.sdk.kotlin.services.cognitoidentityprovider.endpoints.EndpointParameters +import aws.sdk.kotlin.services.cognitoidentityprovider.endpoints.EndpointProvider import aws.smithy.kotlin.runtime.http.endpoints.Endpoint -internal class AWSEndpointResolver(val endpoint: Endpoint) : AwsEndpointResolver { - override suspend fun resolve(service: String, region: String): AwsEndpoint { - return AwsEndpoint(endpoint.uri, CredentialScope(region, service)) +internal class AWSEndpointProvider(val endpoint: Endpoint) : EndpointProvider { + override suspend fun resolveEndpoint(params: EndpointParameters): Endpoint { + return Endpoint(endpoint.uri) } } diff --git a/aws-storage-s3/src/androidTest/java/com/amplifyframework/storage/s3/AWSS3StorageDownloadTest.java b/aws-storage-s3/src/androidTest/java/com/amplifyframework/storage/s3/AWSS3StorageDownloadTest.java index 41fc7d9729..8191f7dbc0 100644 --- a/aws-storage-s3/src/androidTest/java/com/amplifyframework/storage/s3/AWSS3StorageDownloadTest.java +++ b/aws-storage-s3/src/androidTest/java/com/amplifyframework/storage/s3/AWSS3StorageDownloadTest.java @@ -32,6 +32,7 @@ import com.amplifyframework.storage.operation.StorageDownloadFileOperation; import com.amplifyframework.storage.options.StorageDownloadFileOptions; import com.amplifyframework.storage.options.StorageUploadFileOptions; +import com.amplifyframework.storage.s3.options.AWSS3StorageDownloadFileOptions; import com.amplifyframework.storage.s3.test.R; import com.amplifyframework.storage.s3.util.WorkmanagerTestUtils; import com.amplifyframework.testutils.FileAssert; @@ -52,6 +53,7 @@ import java.util.concurrent.atomic.AtomicReference; import static androidx.test.core.app.ApplicationProvider.getApplicationContext; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; @@ -63,7 +65,7 @@ public final class AWSS3StorageDownloadTest { private static final StorageAccessLevel TESTING_ACCESS_LEVEL = StorageAccessLevel.PUBLIC; private static final long LARGE_FILE_SIZE = 10 * 1024 * 1024L; // 10 MB - private static final long SMALL_FILE_SIZE = 100L; + private static final long SMALL_FILE_SIZE = 4 * 1024 * 1024L; private static final String LARGE_FILE_NAME = "large-" + System.currentTimeMillis(); private static final String SMALL_FILE_NAME = "small-" + System.currentTimeMillis(); @@ -96,8 +98,8 @@ public static void setUpOnce() throws Exception { // Upload to PUBLIC for consistency String key; StorageUploadFileOptions uploadOptions = StorageUploadFileOptions.builder() - .accessLevel(TESTING_ACCESS_LEVEL) - .build(); + .accessLevel(TESTING_ACCESS_LEVEL) + .build(); // Upload large test file largeFile = new RandomTempFile(LARGE_FILE_NAME, LARGE_FILE_SIZE); @@ -119,8 +121,8 @@ public static void setUpOnce() throws Exception { public void setUp() throws Exception { // Always interact with PUBLIC access for consistency options = StorageDownloadFileOptions.builder() - .accessLevel(TESTING_ACCESS_LEVEL) - .build(); + .accessLevel(TESTING_ACCESS_LEVEL) + .build(); // Create a set to remember all the subscriptions subscriptions = new HashSet<>(); @@ -273,7 +275,7 @@ public void testGetTransferOnPause() throws Exception { final AtomicReference> opContainer = new AtomicReference<>(); final AtomicReference transferId = new AtomicReference<>(); final AtomicReference errorContainer = new AtomicReference<>(); - // Listen to Hub events to resume when operation has been paused + // Listen to Hub events to resume when operation has been paused SubscriptionToken resumeToken = Amplify.Hub.subscribe(HubChannel.STORAGE, hubEvent -> { if (StorageChannelEventName.DOWNLOAD_STATE.toString().equals(hubEvent.getName())) { HubEvent stateEvent = (HubEvent) hubEvent; @@ -317,4 +319,21 @@ public void testGetTransferOnPause() throws Exception { assertNull(errorContainer.get()); FileAssert.assertEquals(largeFile, downloadFile); } + + /** + * Tests download fails due to acceleration mode disabled. + * + * @throws Exception download fails because acceleration is not enabled on test bucket. + */ + @Test + public void testDownloadLargeFileWithAccelerationEnabled() throws Exception { + try { + AWSS3StorageDownloadFileOptions awsS3Options = + AWSS3StorageDownloadFileOptions.builder().setUseAccelerateEndpoint(true).build(); + synchronousStorage.downloadFile(LARGE_FILE_NAME, downloadFile, awsS3Options, EXTENDED_TIMEOUT_MS); + } catch (Exception exception) { + assertEquals(exception.getCause().getCause().getMessage(), + "S3 Transfer Acceleration is disabled on this bucket"); + } + } } diff --git a/aws-storage-s3/src/androidTest/java/com/amplifyframework/storage/s3/AWSS3StorageUploadTest.java b/aws-storage-s3/src/androidTest/java/com/amplifyframework/storage/s3/AWSS3StorageUploadTest.java index 7199f81fb2..cf85592aea 100644 --- a/aws-storage-s3/src/androidTest/java/com/amplifyframework/storage/s3/AWSS3StorageUploadTest.java +++ b/aws-storage-s3/src/androidTest/java/com/amplifyframework/storage/s3/AWSS3StorageUploadTest.java @@ -28,11 +28,13 @@ import com.amplifyframework.storage.StorageAccessLevel; import com.amplifyframework.storage.StorageCategory; import com.amplifyframework.storage.StorageChannelEventName; +import com.amplifyframework.storage.StorageException; import com.amplifyframework.storage.TransferState; import com.amplifyframework.storage.operation.StorageUploadFileOperation; import com.amplifyframework.storage.operation.StorageUploadInputStreamOperation; import com.amplifyframework.storage.options.StorageUploadFileOptions; import com.amplifyframework.storage.options.StorageUploadInputStreamOptions; +import com.amplifyframework.storage.s3.options.AWSS3StorageUploadFileOptions; import com.amplifyframework.storage.s3.test.R; import com.amplifyframework.storage.s3.util.WorkmanagerTestUtils; import com.amplifyframework.testutils.random.RandomTempFile; @@ -53,6 +55,7 @@ import java.util.concurrent.atomic.AtomicReference; import static androidx.test.core.app.ApplicationProvider.getApplicationContext; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; @@ -74,6 +77,7 @@ public final class AWSS3StorageUploadTest { /** * Initialize mobile client and configure the storage. + * * @throws Exception if mobile client initialization fails */ @BeforeClass @@ -95,8 +99,8 @@ public static void setUpOnce() throws Exception { public void setUp() { // Always interact with PUBLIC access for consistency options = StorageUploadFileOptions.builder() - .accessLevel(TESTING_ACCESS_LEVEL) - .build(); + .accessLevel(TESTING_ACCESS_LEVEL) + .build(); // Create a set to remember all the subscriptions subscriptions = new HashSet<>(); @@ -157,7 +161,7 @@ public void testUploadLargeFile() throws Exception { * transfer hasn't completed yet. * * @throws Exception if upload is not canceled successfully - * before timeout + * before timeout */ @SuppressWarnings("unchecked") @Test @@ -206,7 +210,7 @@ public void testUploadFileIsCancelable() throws Exception { * while the transfer hasn't completed yet. * * @throws Exception if upload is not paused, resumed, and - * completed successfully before timeout + * completed successfully before timeout */ @SuppressWarnings("unchecked") @Test @@ -258,7 +262,7 @@ public void testUploadFileIsResumable() throws Exception { * using getTransfer API. * * @throws Exception if upload is not paused, resumed, and - * completed successfully before timeout + * completed successfully before timeout */ @SuppressWarnings("unchecked") @Test @@ -303,7 +307,8 @@ public void testUploadFileGetTransferOnPause() throws Exception { opContainer.get().pause(); } }, - result -> { }, + result -> { + }, errorContainer::set ); opContainer.set(op); @@ -320,7 +325,7 @@ public void testUploadFileGetTransferOnPause() throws Exception { * using getTransfer API. * * @throws Exception if upload is not paused, resumed, and - * completed successfully before timeout + * completed successfully before timeout */ @SuppressWarnings("unchecked") @Test @@ -367,7 +372,8 @@ public void testUploadInputStreamGetTransferOnPause() throws Exception { opContainer.get().pause(); } }, - result -> { }, + result -> { + }, errorContainer::set ); opContainer.set(op); @@ -378,4 +384,40 @@ public void testUploadInputStreamGetTransferOnPause() throws Exception { assertTrue(completed.await(EXTENDED_TIMEOUT_MS, TimeUnit.MILLISECONDS)); assertNull(errorContainer.get()); } + + /** + * Tests that small file (single-part) uploads successfully. + * + * @throws Exception if upload fails + */ + @Test(expected = StorageException.class) + public void testUploadSmallFileWithAccelerationEnabled() throws Exception { + File uploadFile = new RandomTempFile(SMALL_FILE_SIZE); + String fileName = uploadFile.getName(); + AWSS3StorageUploadFileOptions awss3StorageUploadFileOptions = + AWSS3StorageUploadFileOptions.builder().setUseAccelerateEndpoint(true).build(); + synchronousStorage.uploadFile(fileName, uploadFile, + awss3StorageUploadFileOptions); + } + + /** + * Tests that large file (single-part) uploads successfully. + * + * @throws Exception if upload fails + */ + @Test + public void testUploadLargeFileWithAccelerationEnabled() throws Exception { + try { + File uploadFile = new RandomTempFile(LARGE_FILE_SIZE); + String fileName = uploadFile.getName(); + AWSS3StorageUploadFileOptions awss3StorageUploadFileOptions = + AWSS3StorageUploadFileOptions.builder().setUseAccelerateEndpoint(true).build(); + synchronousStorage.uploadFile(fileName, uploadFile, + awss3StorageUploadFileOptions); + } catch (StorageException exception) { + assertEquals(exception.getCause().getCause().getMessage(), + "S3 Transfer Acceleration is disabled on this bucket"); + } + } + } diff --git a/aws-storage-s3/src/androidTest/java/com/amplifyframework/storage/s3/transfer/TransferDBTest.kt b/aws-storage-s3/src/androidTest/java/com/amplifyframework/storage/s3/transfer/TransferDBTest.kt index 4937f389f0..17cc84e95c 100644 --- a/aws-storage-s3/src/androidTest/java/com/amplifyframework/storage/s3/transfer/TransferDBTest.kt +++ b/aws-storage-s3/src/androidTest/java/com/amplifyframework/storage/s3/transfer/TransferDBTest.kt @@ -120,7 +120,8 @@ open class TransferDBTest { ongoingRestore = false, restoreExpirationTime = restoreExpirationTime ), - null + null, + useAccelerateEndpoint = false ) val uri = transferDB.bulkInsertTransferRecords(contentValues) transferDB.getTransferRecordById(uri).run { @@ -144,7 +145,8 @@ open class TransferDBTest { 1L, 0, null, - null + null, + false ) contentValues[1] = transferDB.generateContentValuesForMultiPartUpload( key, @@ -157,7 +159,8 @@ open class TransferDBTest { 1L, 0, null, - null + null, + false ) contentValues[2] = transferDB.generateContentValuesForMultiPartUpload( key, @@ -170,7 +173,8 @@ open class TransferDBTest { 1L, 1, null, - null + null, + false ) val bulkInsertUri = transferDB.bulkInsertTransferRecords(contentValues) transferDB.getTransferRecordById(bulkInsertUri) diff --git a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/AWSS3StoragePlugin.java b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/AWSS3StoragePlugin.java index 9ba0247471..4f354a6fd4 100644 --- a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/AWSS3StoragePlugin.java +++ b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/AWSS3StoragePlugin.java @@ -55,6 +55,8 @@ import com.amplifyframework.storage.s3.operation.AWSS3StorageRemoveOperation; import com.amplifyframework.storage.s3.operation.AWSS3StorageUploadFileOperation; import com.amplifyframework.storage.s3.operation.AWSS3StorageUploadInputStreamOperation; +import com.amplifyframework.storage.s3.options.AWSS3StorageDownloadFileOptions; +import com.amplifyframework.storage.s3.options.AWSS3StorageGetPresignedUrlOptions; import com.amplifyframework.storage.s3.options.AWSS3StorageUploadFileOptions; import com.amplifyframework.storage.s3.options.AWSS3StorageUploadInputStreamOptions; import com.amplifyframework.storage.s3.request.AWSS3StorageDownloadFileRequest; @@ -254,6 +256,8 @@ public StorageGetUrlOperation getUrl( @NonNull StorageGetUrlOptions options, @NonNull Consumer onSuccess, @NonNull Consumer onError) { + boolean useAccelerateEndpoint = options instanceof AWSS3StorageGetPresignedUrlOptions && + ((AWSS3StorageGetPresignedUrlOptions) options).useAccelerateEndpoint(); AWSS3StorageGetPresignedUrlRequest request = new AWSS3StorageGetPresignedUrlRequest( key, options.getAccessLevel() != null @@ -262,7 +266,8 @@ public StorageGetUrlOperation getUrl( options.getTargetIdentityId(), options.getExpires() != 0 ? options.getExpires() - : defaultUrlExpiration + : defaultUrlExpiration, + useAccelerateEndpoint ); AWSS3StorageGetPresignedUrlOperation operation = @@ -313,13 +318,17 @@ public StorageDownloadFileOperation downloadFile( @NonNull Consumer onSuccess, @NonNull Consumer onError ) { + boolean useAccelerateEndpoint = + options instanceof AWSS3StorageDownloadFileOptions && + ((AWSS3StorageDownloadFileOptions) options).useAccelerateEndpoint(); AWSS3StorageDownloadFileRequest request = new AWSS3StorageDownloadFileRequest( key, local, options.getAccessLevel() != null ? options.getAccessLevel() : defaultAccessLevel, - options.getTargetIdentityId() + options.getTargetIdentityId(), + useAccelerateEndpoint ); AWSS3StorageDownloadFileOperation operation = new AWSS3StorageDownloadFileOperation( @@ -371,6 +380,8 @@ public StorageUploadFileOperation uploadFile( @NonNull Consumer onSuccess, @NonNull Consumer onError ) { + boolean useAccelerateEndpoint = options instanceof AWSS3StorageUploadFileOptions && + ((AWSS3StorageUploadFileOptions) options).useAccelerateEndpoint(); AWSS3StorageUploadRequest request = new AWSS3StorageUploadRequest<>( key, local, @@ -382,7 +393,8 @@ public StorageUploadFileOperation uploadFile( options instanceof AWSS3StorageUploadFileOptions ? ((AWSS3StorageUploadFileOptions) options).getServerSideEncryption() : ServerSideEncryption.NONE, - options.getMetadata() + options.getMetadata(), + useAccelerateEndpoint ); AWSS3StorageUploadFileOperation operation = new AWSS3StorageUploadFileOperation( @@ -434,6 +446,8 @@ public StorageUploadInputStreamOperation uploadInputStream( @NonNull Consumer onSuccess, @NonNull Consumer onError ) { + boolean useAccelerateEndpoint = options instanceof AWSS3StorageUploadInputStreamOptions && + ((AWSS3StorageUploadInputStreamOptions) options).useAccelerateEndpoint(); AWSS3StorageUploadRequest request = new AWSS3StorageUploadRequest<>( key, local, @@ -445,7 +459,8 @@ public StorageUploadInputStreamOperation uploadInputStream( options instanceof AWSS3StorageUploadInputStreamOptions ? ((AWSS3StorageUploadInputStreamOptions) options).getServerSideEncryption() : ServerSideEncryption.NONE, - options.getMetadata() + options.getMetadata(), + useAccelerateEndpoint ); AWSS3StorageUploadInputStreamOperation operation = new AWSS3StorageUploadInputStreamOperation( diff --git a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/operation/AWSS3StorageDownloadFileOperation.kt b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/operation/AWSS3StorageDownloadFileOperation.kt index 79720f01e5..2fd538df16 100644 --- a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/operation/AWSS3StorageDownloadFileOperation.kt +++ b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/operation/AWSS3StorageDownloadFileOperation.kt @@ -93,7 +93,12 @@ class AWSS3StorageDownloadFileOperation @JvmOverloads internal constructor( try { val serviceKey = prefix + downloadRequest.key this.file = downloadRequest.local - transferObserver = storageService.downloadToFile(transferId, serviceKey, file) + transferObserver = storageService.downloadToFile( + transferId, + serviceKey, + file, + downloadRequest.useAccelerateEndpoint() + ) transferObserver?.setTransferListener(DownloadTransferListener()) } catch (exception: Exception) { onError?.accept( diff --git a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/operation/AWSS3StorageGetPresignedUrlOperation.java b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/operation/AWSS3StorageGetPresignedUrlOperation.java index 9bd067bf10..9f9c52797b 100644 --- a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/operation/AWSS3StorageGetPresignedUrlOperation.java +++ b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/operation/AWSS3StorageGetPresignedUrlOperation.java @@ -34,7 +34,7 @@ * An operation to retrieve pre-signed object URL from AWS S3. */ public final class AWSS3StorageGetPresignedUrlOperation - extends StorageGetUrlOperation { + extends StorageGetUrlOperation { private final StorageService storageService; private final ExecutorService executorService; private final AuthCredentialsProvider authCredentialsProvider; @@ -45,23 +45,23 @@ public final class AWSS3StorageGetPresignedUrlOperation /** * Constructs a new AWSS3StorageGetUrlOperation. * - * @param storageService S3 client wrapper - * @param executorService Executor service used for running - * blocking operations on a separate thread - * @param authCredentialsProvider Interface to retrieve AWS specific auth information - * @param request getUrl request parameters + * @param storageService S3 client wrapper + * @param executorService Executor service used for running + * blocking operations on a separate thread + * @param authCredentialsProvider Interface to retrieve AWS specific auth information + * @param request getUrl request parameters * @param awss3StoragePluginConfiguration s3Plugin configuration - * @param onSuccess Notified when URL is generated. - * @param onError Notified upon URL generation error + * @param onSuccess Notified when URL is generated. + * @param onError Notified upon URL generation error */ public AWSS3StorageGetPresignedUrlOperation( - @NonNull StorageService storageService, - @NonNull ExecutorService executorService, - @NonNull AuthCredentialsProvider authCredentialsProvider, - @NonNull AWSS3StorageGetPresignedUrlRequest request, - @NonNull AWSS3StoragePluginConfiguration awss3StoragePluginConfiguration, - @NonNull Consumer onSuccess, - @NonNull Consumer onError + @NonNull StorageService storageService, + @NonNull ExecutorService executorService, + @NonNull AuthCredentialsProvider authCredentialsProvider, + @NonNull AWSS3StorageGetPresignedUrlRequest request, + @NonNull AWSS3StoragePluginConfiguration awss3StoragePluginConfiguration, + @NonNull Consumer onSuccess, + @NonNull Consumer onError ) { super(request); this.storageService = storageService; @@ -76,13 +76,16 @@ public AWSS3StorageGetPresignedUrlOperation( @Override public void start() { executorService.submit(() -> { - awsS3StoragePluginConfiguration.getAWSS3PluginPrefixResolver(authCredentialsProvider). + awsS3StoragePluginConfiguration.getAWSS3PluginPrefixResolver(authCredentialsProvider). resolvePrefix(getRequest().getAccessLevel(), - getRequest().getTargetIdentityId(), + getRequest().getTargetIdentityId(), prefix -> { try { String serviceKey = prefix.concat(getRequest().getKey()); - URL url = storageService.getPresignedUrl(serviceKey, getRequest().getExpires()); + URL url = storageService.getPresignedUrl( + serviceKey, + getRequest().getExpires(), + getRequest().useAccelerateEndpoint()); onSuccess.accept(StorageGetUrlResult.fromUrl(url)); } catch (Exception exception) { onError.accept(new StorageException( @@ -93,7 +96,7 @@ public void start() { } }, - onError); + onError); } ); } diff --git a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/operation/AWSS3StorageUploadFileOperation.kt b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/operation/AWSS3StorageUploadFileOperation.kt index 4d8bf235c7..6f750f1f36 100644 --- a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/operation/AWSS3StorageUploadFileOperation.kt +++ b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/operation/AWSS3StorageUploadFileOperation.kt @@ -105,7 +105,13 @@ class AWSS3StorageUploadFileOperation @JvmOverloads internal constructor( objectMetadata.metaData[ObjectMetadata.SERVER_SIDE_ENCRYPTION] = storageServerSideEncryption.getName() } - transferObserver = storageService.uploadFile(transferId, serviceKey, file, objectMetadata) + transferObserver = storageService.uploadFile( + transferId, + serviceKey, + file, + objectMetadata, + uploadRequest.useAccelerateEndpoint() + ) transferObserver?.setTransferListener(UploadTransferListener()) } catch (exception: Exception) { onError?.accept( diff --git a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/operation/AWSS3StorageUploadInputStreamOperation.kt b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/operation/AWSS3StorageUploadInputStreamOperation.kt index 9289b3398d..912990bb16 100644 --- a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/operation/AWSS3StorageUploadInputStreamOperation.kt +++ b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/operation/AWSS3StorageUploadInputStreamOperation.kt @@ -116,7 +116,8 @@ class AWSS3StorageUploadInputStreamOperation @JvmOverloads internal constructor( transferId, serviceKey, inputStream, - objectMetadata + objectMetadata, + uploadRequest.useAccelerateEndpoint() ) transferObserver?.setTransferListener(UploadTransferListener()) } catch (ioException: IOException) { diff --git a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/options/AWSS3StorageDownloadFileOptions.java b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/options/AWSS3StorageDownloadFileOptions.java index 77c4e1be62..81167c78a8 100644 --- a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/options/AWSS3StorageDownloadFileOptions.java +++ b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/options/AWSS3StorageDownloadFileOptions.java @@ -24,9 +24,11 @@ * Options to specify attributes of object download operation from an AWS S3 bucket. */ public final class AWSS3StorageDownloadFileOptions extends StorageDownloadFileOptions { + private final boolean useAccelerationMode; private AWSS3StorageDownloadFileOptions(final Builder builder) { super(builder); + this.useAccelerationMode = builder.useAccelerateEndpoint; } /** @@ -55,7 +57,8 @@ public static Builder builder() { public static Builder from(@NonNull final AWSS3StorageDownloadFileOptions options) { return builder() .accessLevel(options.getAccessLevel()) - .targetIdentityId(options.getTargetIdentityId()); + .targetIdentityId(options.getTargetIdentityId()) + .setUseAccelerateEndpoint(options.useAccelerateEndpoint()); } /** @@ -67,6 +70,15 @@ public static AWSS3StorageDownloadFileOptions defaultInstance() { return builder().build(); } + /** + * Gets the flag to determine whether to use acceleration endpoint. + * + * @return boolean flag + */ + public boolean useAccelerateEndpoint() { + return useAccelerationMode; + } + @Override public boolean equals(Object obj) { if (this == obj) { @@ -94,6 +106,7 @@ public String toString() { return "AWSS3StorageDownloadFileOptions {" + "accessLevel=" + getAccessLevel() + ", targetIdentityId=" + getTargetIdentityId() + + ", useAccelerationMode=" + useAccelerateEndpoint() + '}'; } @@ -103,6 +116,18 @@ public String toString() { * fluent configuration method calls. */ public static final class Builder extends StorageDownloadFileOptions.Builder { + private boolean useAccelerateEndpoint; + + /** + * Configure to use acceleration mode on new StorageDownloadFileOptions instances. + * @param useAccelerateEndpoint flag to represent acceleration mode for new DownloadFileOptions instance + * @return Current Builder instance for fluent chaining + */ + public Builder setUseAccelerateEndpoint(boolean useAccelerateEndpoint) { + this.useAccelerateEndpoint = useAccelerateEndpoint; + return this; + } + @Override @NonNull public AWSS3StorageDownloadFileOptions build() { diff --git a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/options/AWSS3StorageGetPresignedUrlOptions.java b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/options/AWSS3StorageGetPresignedUrlOptions.java index f2ed339f96..cb824d28a6 100644 --- a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/options/AWSS3StorageGetPresignedUrlOptions.java +++ b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/options/AWSS3StorageGetPresignedUrlOptions.java @@ -25,9 +25,11 @@ * Options to specify attributes of presigned URL generation from an AWS S3 bucket. */ public final class AWSS3StorageGetPresignedUrlOptions extends StorageGetUrlOptions { + private final boolean useAccelerationMode; private AWSS3StorageGetPresignedUrlOptions(final Builder builder) { super(builder); + this.useAccelerationMode = builder.useAccelerateEndpoint; } /** @@ -68,6 +70,15 @@ public static AWSS3StorageGetPresignedUrlOptions defaultInstance() { return builder().build(); } + /** + * Gets the flag to determine whether to use acceleration endpoint. + * + * @return boolean flag + */ + public boolean useAccelerateEndpoint() { + return useAccelerationMode; + } + @Override public boolean equals(Object obj) { if (this == obj) { @@ -107,6 +118,18 @@ public String toString() { * fluent configuration method calls. */ public static final class Builder extends StorageGetUrlOptions.Builder { + private boolean useAccelerateEndpoint; + + /** + * Configure to use acceleration mode on new StorageDownloadFileOptions instances. + * @param useAccelerateEndpoint flag to represent acceleration mode for new DownloadFileOptions instance + * @return Current Builder instance for fluent chaining + */ + public Builder setUseAccelerateEndpoint(boolean useAccelerateEndpoint) { + this.useAccelerateEndpoint = useAccelerateEndpoint; + return this; + } + @Override @NonNull public AWSS3StorageGetPresignedUrlOptions build() { diff --git a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/options/AWSS3StorageUploadFileOptions.java b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/options/AWSS3StorageUploadFileOptions.java index 3c3a73d54e..358cc19db1 100644 --- a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/options/AWSS3StorageUploadFileOptions.java +++ b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/options/AWSS3StorageUploadFileOptions.java @@ -28,10 +28,12 @@ */ public final class AWSS3StorageUploadFileOptions extends StorageUploadFileOptions { private final ServerSideEncryption serverSideEncryption; + private final boolean useAccelerationMode; private AWSS3StorageUploadFileOptions(final Builder builder) { super(builder); this.serverSideEncryption = builder.getServerSideEncryption(); + this.useAccelerationMode = builder.useAccelerateEndpoint; } /** @@ -84,6 +86,15 @@ public static AWSS3StorageUploadFileOptions defaultInstance() { return builder().build(); } + /** + * Gets the flag to determine whether to use acceleration endpoint. + * + * @return boolean flag + */ + public boolean useAccelerateEndpoint() { + return useAccelerationMode; + } + @Override public boolean equals(Object obj) { if (this == obj) { @@ -130,12 +141,23 @@ public String toString() { */ public static final class Builder extends StorageUploadFileOptions.Builder { private ServerSideEncryption serverSideEncryption; + private boolean useAccelerateEndpoint; private Builder() { super(); this.serverSideEncryption = ServerSideEncryption.NONE; } + /** + * Configure to use acceleration mode. + * @param useAccelerateEndpoint flag to represent acceleration mode for new DownloadFileOptions instance + * @return Current Builder instance for fluent chaining + */ + public Builder setUseAccelerateEndpoint(boolean useAccelerateEndpoint) { + this.useAccelerateEndpoint = useAccelerateEndpoint; + return this; + } + /** * Configures the server side encryption algorithm for a new AWSS3StorageUploadFileOptions instance. * @param serverSideEncryption server side encryption algorithm diff --git a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/options/AWSS3StorageUploadInputStreamOptions.java b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/options/AWSS3StorageUploadInputStreamOptions.java index b06af8d5f0..a8f1b895f2 100644 --- a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/options/AWSS3StorageUploadInputStreamOptions.java +++ b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/options/AWSS3StorageUploadInputStreamOptions.java @@ -28,10 +28,12 @@ */ public final class AWSS3StorageUploadInputStreamOptions extends StorageUploadInputStreamOptions { private final ServerSideEncryption serverSideEncryption; + private final boolean useAccelerationMode; private AWSS3StorageUploadInputStreamOptions(final Builder builder) { super(builder); this.serverSideEncryption = builder.serverSideEncryption; + this.useAccelerationMode = builder.useAccelerateEndpoint; } /** @@ -84,6 +86,15 @@ public static AWSS3StorageUploadInputStreamOptions defaultInstance() { return builder().build(); } + /** + * Gets the flag to determine whether to use acceleration endpoint. + * + * @return boolean flag + */ + public boolean useAccelerateEndpoint() { + return useAccelerationMode; + } + @Override public boolean equals(Object obj) { if (this == obj) { @@ -130,12 +141,23 @@ public String toString() { */ public static final class Builder extends StorageUploadInputStreamOptions.Builder { private ServerSideEncryption serverSideEncryption; + private boolean useAccelerateEndpoint; private Builder() { super(); this.serverSideEncryption = ServerSideEncryption.NONE; } + /** + * Configure to use acceleration mode on new StorageDownloadFileOptions instances. + * @param useAccelerateEndpoint flag to represent acceleration mode for new DownloadFileOptions instance + * @return Current Builder instance for fluent chaining + */ + public Builder setUseAccelerateEndpoint(boolean useAccelerateEndpoint) { + this.useAccelerateEndpoint = useAccelerateEndpoint; + return this; + } + /** * Configures the server side encryption algorithm for a new AWSS3StorageUploadInputStreamOptions instance. * @param serverSideEncryption server side encryption algorithm diff --git a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/request/AWSS3StorageDownloadFileRequest.java b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/request/AWSS3StorageDownloadFileRequest.java index 0e1e89bb32..1f982868a8 100644 --- a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/request/AWSS3StorageDownloadFileRequest.java +++ b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/request/AWSS3StorageDownloadFileRequest.java @@ -31,6 +31,7 @@ public final class AWSS3StorageDownloadFileRequest { private final File local; private final StorageAccessLevel accessLevel; private final String targetIdentityId; + private final boolean useAccelerateEndpoint; /** * Constructs a new AWSS3StorageDownloadFileRequest. @@ -42,17 +43,20 @@ public final class AWSS3StorageDownloadFileRequest { * @param accessLevel Storage access level * @param targetIdentityId If set, this should override the current user's identity ID. * If null, the operation will fetch the current identity ID. + * @param useAccelerateEndpoint Flag to enable acceleration mode */ public AWSS3StorageDownloadFileRequest( @NonNull String key, @NonNull File local, @NonNull StorageAccessLevel accessLevel, - @Nullable String targetIdentityId + @Nullable String targetIdentityId, + boolean useAccelerateEndpoint ) { this.key = key; this.local = local; this.accessLevel = accessLevel; this.targetIdentityId = targetIdentityId; + this.useAccelerateEndpoint = useAccelerateEndpoint; } /** @@ -90,5 +94,14 @@ public String getTargetIdentityId() { public File getLocal() { return local; } + + /** + * Gets the flag to determine whether to use acceleration endpoint. + * + * @return boolean flag + */ + public boolean useAccelerateEndpoint() { + return useAccelerateEndpoint; + } } diff --git a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/request/AWSS3StorageGetPresignedUrlRequest.java b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/request/AWSS3StorageGetPresignedUrlRequest.java index 9c54976eee..73242917eb 100644 --- a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/request/AWSS3StorageGetPresignedUrlRequest.java +++ b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/request/AWSS3StorageGetPresignedUrlRequest.java @@ -29,6 +29,7 @@ public final class AWSS3StorageGetPresignedUrlRequest { private final StorageAccessLevel accessLevel; private final String targetIdentityId; private final int expires; + private final boolean useAccelerateEndpoint; /** * Constructs a new AWSS3StorageGetUrlRequest. @@ -40,16 +41,19 @@ public final class AWSS3StorageGetPresignedUrlRequest { * @param targetIdentityId If set, this should override the current user's identity ID. * If null, the operation will fetch the current identity ID. * @param expires The number of seconds before the URL expires + * @param useAccelerateEndpoint Flag to enable acceleration mode */ public AWSS3StorageGetPresignedUrlRequest( @NonNull String key, @NonNull StorageAccessLevel accessLevel, @Nullable String targetIdentityId, - int expires) { + int expires, + boolean useAccelerateEndpoint) { this.key = key; this.accessLevel = accessLevel; this.targetIdentityId = targetIdentityId; this.expires = expires; + this.useAccelerateEndpoint = useAccelerateEndpoint; } /** @@ -86,5 +90,14 @@ public String getTargetIdentityId() { public int getExpires() { return expires; } + + /** + * Gets the flag to determine whether to use acceleration endpoint. + * + * @return boolean flag + */ + public boolean useAccelerateEndpoint() { + return useAccelerateEndpoint; + } } diff --git a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/request/AWSS3StorageUploadRequest.java b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/request/AWSS3StorageUploadRequest.java index d5838d741d..093f37fb4a 100644 --- a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/request/AWSS3StorageUploadRequest.java +++ b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/request/AWSS3StorageUploadRequest.java @@ -36,6 +36,7 @@ public final class AWSS3StorageUploadRequest { private final String contentType; private final ServerSideEncryption serverSideEncryption; private final Map metadata; + private final boolean useAccelerateEndpoint; /** * Constructs a new AWSS3StorageUploadRequest. @@ -50,6 +51,7 @@ public final class AWSS3StorageUploadRequest { * @param contentType The standard MIME type describing the format of the object to store * @param serverSideEncryption server side encryption type for the current storage bucket * @param metadata Metadata for the object to store + * @param useAccelerateEndpoint flag to use acceleration endpoint. */ public AWSS3StorageUploadRequest( @NonNull String key, @@ -58,7 +60,8 @@ public AWSS3StorageUploadRequest( @Nullable String targetIdentityId, @Nullable String contentType, @NonNull ServerSideEncryption serverSideEncryption, - @Nullable Map metadata + @Nullable Map metadata, + boolean useAccelerateEndpoint ) { this.key = key; this.local = local; @@ -70,6 +73,7 @@ public AWSS3StorageUploadRequest( if (metadata != null) { this.metadata.putAll(metadata); } + this.useAccelerateEndpoint = useAccelerateEndpoint; } /** @@ -134,5 +138,14 @@ public ServerSideEncryption getServerSideEncryption() { public Map getMetadata() { return metadata; } + + /** + * Gets the flag to determine whether to use acceleration endpoint. + * + * @return boolean flag + */ + public boolean useAccelerateEndpoint() { + return useAccelerateEndpoint; + } } diff --git a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/service/AWSS3StorageService.kt b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/service/AWSS3StorageService.kt index db252cd057..56b390181e 100644 --- a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/service/AWSS3StorageService.kt +++ b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/service/AWSS3StorageService.kt @@ -21,6 +21,7 @@ import aws.sdk.kotlin.services.s3.deleteObject import aws.sdk.kotlin.services.s3.model.GetObjectRequest import aws.sdk.kotlin.services.s3.paginators.listObjectsV2Paginated import aws.sdk.kotlin.services.s3.presigners.presign +import aws.sdk.kotlin.services.s3.withConfig import com.amplifyframework.auth.AuthCredentialsProvider import com.amplifyframework.storage.ObjectMetadata import com.amplifyframework.storage.StorageItem @@ -65,12 +66,16 @@ internal class AWSS3StorageService( * @return A pre-signed URL */ @OptIn(ExperimentalTime::class) - override fun getPresignedUrl(serviceKey: String, expires: Int): URL { - val presignUrlRequest = runBlocking { - GetObjectRequest { - bucket = s3BucketName - key = serviceKey - }.presign(s3Client.config, expires.seconds) + override fun getPresignedUrl(serviceKey: String, expires: Int, useAccelerateEndpoint: Boolean): URL { + val presignUrlRequest = s3Client.withConfig { + enableAccelerate = useAccelerateEndpoint + }.use { + runBlocking { + GetObjectRequest { + bucket = s3BucketName + key = serviceKey + }.presign(it.config, expires.seconds) + } } return URL(presignUrlRequest.url.toString()) } @@ -79,10 +84,22 @@ internal class AWSS3StorageService( * Begin downloading a file. * @param serviceKey S3 service key * @param file Target file + * @param useAccelerateEndpoint Flag to use accelerate endpoint * @return A transfer observer */ - override fun downloadToFile(transferId: String, serviceKey: String, file: File): TransferObserver { - return transferManager.download(transferId, s3BucketName, serviceKey, file) + override fun downloadToFile( + transferId: String, + serviceKey: String, + file: File, + useAccelerateEndpoint: Boolean + ): TransferObserver { + return transferManager.download( + transferId, + s3BucketName, + serviceKey, + file, + useAccelerateEndpoint = useAccelerateEndpoint + ) } /** @@ -96,9 +113,17 @@ internal class AWSS3StorageService( transferId: String, serviceKey: String, file: File, - metadata: ObjectMetadata + metadata: ObjectMetadata, + useAccelerateEndpoint: Boolean ): TransferObserver { - return transferManager.upload(transferId, s3BucketName, serviceKey, file, metadata) + return transferManager.upload( + transferId, + s3BucketName, + serviceKey, + file, + metadata, + useAccelerateEndpoint = useAccelerateEndpoint + ) } /** @@ -113,10 +138,11 @@ internal class AWSS3StorageService( transferId: String, serviceKey: String, inputStream: InputStream, - metadata: ObjectMetadata + metadata: ObjectMetadata, + useAccelerateEndpoint: Boolean ): TransferObserver { val uploadOptions = UploadOptions(s3BucketName, metadata) - return transferManager.upload(transferId, serviceKey, inputStream, uploadOptions) + return transferManager.upload(transferId, serviceKey, inputStream, uploadOptions, useAccelerateEndpoint) } /** diff --git a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/service/StorageService.java b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/service/StorageService.java index 0fa5056c2c..500c9096fa 100644 --- a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/service/StorageService.java +++ b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/service/StorageService.java @@ -39,9 +39,10 @@ public interface StorageService { * * @param serviceKey key to uniquely specify item to generate URL for * @param expires Number of seconds before URL expires + * @param useAccelerateEndpoint Flag to enable acceleration endpoint * @return A pre-signed URL */ - URL getPresignedUrl(@NonNull String serviceKey, int expires); + URL getPresignedUrl(@NonNull String serviceKey, int expires, boolean useAccelerateEndpoint); /** * Begin downloading a specific item to a file and return an observer @@ -50,11 +51,14 @@ public interface StorageService { * @param transferId unique id for this transfer * @param serviceKey key to uniquely specify item to download * @param file file to write downloaded item + * @param useAccelerateEndpoint flag to use accelerate endpoint * @return An instance of {@link TransferObserver} to monitor download */ TransferObserver downloadToFile(@NonNull String transferId, @NonNull String serviceKey, - @NonNull File file); + @NonNull File file, + boolean useAccelerateEndpoint); + /** * Begin uploading a file to a key in storage and return an observer @@ -65,12 +69,14 @@ TransferObserver downloadToFile(@NonNull String transferId, * @param serviceKey Key to uniquely label item in storage * @param file file to upload * @param metadata metadata to attach to uploaded item + * @param useAccelerateEndpoint flag to use accelerate endpoint * @return An instance of {@link TransferObserver} to monitor upload */ TransferObserver uploadFile(@NonNull String transferId, @NonNull String serviceKey, @NonNull File file, - @NonNull ObjectMetadata metadata); + @NonNull ObjectMetadata metadata, + boolean useAccelerateEndpoint); /** * Begin uploading an InputStream to a key in storage and return an observer @@ -81,6 +87,7 @@ TransferObserver uploadFile(@NonNull String transferId, * @param serviceKey key to uniquely label item in storage * @param inputStream InputStream from which to read content * @param metadata Metadata to attach to uploaded item + * @param useAccelerateEndpoint Flag to use accelerate endpoint * @return An instance of {@link TransferObserver} to monitor upload * @throws IOException on error reading the InputStream, or saving it to a temporary * File before the upload begins. @@ -88,7 +95,8 @@ TransferObserver uploadFile(@NonNull String transferId, TransferObserver uploadInputStream(@NonNull String transferId, @NonNull String serviceKey, @NonNull InputStream inputStream, - @NonNull ObjectMetadata metadata) + @NonNull ObjectMetadata metadata, + boolean useAccelerateEndpoint) throws IOException; /** diff --git a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/ProgressListenerHttpInterceptor.kt b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/ProgressListenerHttpInterceptor.kt new file mode 100644 index 0000000000..a66c6a2038 --- /dev/null +++ b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/ProgressListenerHttpInterceptor.kt @@ -0,0 +1,133 @@ +/* + * Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ +package com.amplifyframework.storage.s3.transfer + +import aws.smithy.kotlin.runtime.client.ProtocolRequestInterceptorContext +import aws.smithy.kotlin.runtime.client.ProtocolResponseInterceptorContext +import aws.smithy.kotlin.runtime.http.HttpBody +import aws.smithy.kotlin.runtime.http.interceptors.HttpInterceptor +import aws.smithy.kotlin.runtime.http.request.HttpRequest +import aws.smithy.kotlin.runtime.http.request.toBuilder +import aws.smithy.kotlin.runtime.http.response.HttpResponse +import aws.smithy.kotlin.runtime.io.SdkBuffer +import aws.smithy.kotlin.runtime.io.SdkByteReadChannel +import aws.smithy.kotlin.runtime.io.SdkSource +import aws.smithy.kotlin.runtime.io.readAll + +internal open class ProgressListenerInterceptor( + private val progressListener: ProgressListener +) : HttpInterceptor { + fun convertBodyWithProgressUpdates(httpBody: HttpBody): HttpBody { + return when (httpBody) { + is HttpBody.ChannelContent -> { + SdkByteReadChannelWithProgressUpdates( + httpBody, + progressListener + ) + } + is HttpBody.SourceContent -> { + SourceContentWithProgressUpdates( + httpBody, + progressListener + ) + } + is HttpBody.Bytes -> { + httpBody + } + is HttpBody.Empty -> { + httpBody + } + } + } + + internal class SourceContentWithProgressUpdates( + private val sourceContent: HttpBody.SourceContent, + private val progressListener: ProgressListener + ) : HttpBody.SourceContent() { + private val delegate = sourceContent.readFrom() + override val contentLength: Long? + get() = sourceContent.contentLength + + override fun readFrom(): SdkSource { + return object : SdkSource { + override fun close() { + delegate.close() + } + + override fun read(sink: SdkBuffer, limit: Long): Long { + return delegate.read(sink, limit).also { + if (it > 0) { + progressListener.progressChanged(it) + } + } + } + } + } + } + + internal class SdkByteReadChannelWithProgressUpdates( + private val httpBody: ChannelContent, + private val progressListener: ProgressListener + ) : HttpBody.ChannelContent() { + val delegate = httpBody.readFrom() + override fun readFrom(): SdkByteReadChannel { + return object : SdkByteReadChannel by delegate { + override val availableForRead: Int + get() = delegate.availableForRead + + override val isClosedForRead: Boolean + get() = delegate.isClosedForRead + + override val isClosedForWrite: Boolean + get() = delegate.isClosedForWrite + + override fun cancel(cause: Throwable?): Boolean { + return delegate.cancel(cause) + } + + override suspend fun read(sink: SdkBuffer, limit: Long): Long { + return delegate.readAll(sink).also { + if (it > 0) { + progressListener.progressChanged(it) + } + } + } + } + } + } +} + +internal class DownloadProgressListenerInterceptor( + private val progressListener: ProgressListener +) : ProgressListenerInterceptor(progressListener) { + override suspend fun modifyBeforeDeserialization( + context: ProtocolResponseInterceptorContext + ): HttpResponse { + val body = convertBodyWithProgressUpdates(context.protocolResponse.body) + return HttpResponse(context.protocolResponse.status, context.protocolResponse.headers, body) + } +} + +internal class UploadProgressListenerInterceptor( + private val progressListener: ProgressListener +) : ProgressListenerInterceptor(progressListener) { + override suspend fun modifyBeforeTransmit( + context: ProtocolRequestInterceptorContext + ): HttpRequest { + val builder = context.protocolRequest.toBuilder() + builder.body = convertBodyWithProgressUpdates(builder.body) + return builder.build() + } +} diff --git a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/TransferDB.kt b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/TransferDB.kt index 09fa778a4f..68b51d28ee 100644 --- a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/TransferDB.kt +++ b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/TransferDB.kt @@ -83,13 +83,15 @@ internal class TransferDB private constructor(context: Context) { partNumber: Int, uploadId: String, bytesTotal: Long, - isLastPart: Int + isLastPart: Int, + useAccelerateEndpoint: Boolean = false ): Uri { val values: ContentValues = generateContentValuesForMultiPartUpload( transferId, bucket, key, file, fileOffset, partNumber, uploadId, bytesTotal, isLastPart, ObjectMetadata(), - null + null, + useAccelerateEndpoint ) return transferDBHelper.insert(transferDBHelper.contentUri, values) } @@ -114,6 +116,7 @@ internal class TransferDB private constructor(context: Context) { file: File?, cannedAcl: ObjectCannedAcl? = null, metadata: ObjectMetadata? = ObjectMetadata(), + useAccelerateEndpoint: Boolean = false ): Uri { val values = generateContentValuesForSinglePartTransfer( transferId, @@ -122,7 +125,8 @@ internal class TransferDB private constructor(context: Context) { key, file, metadata, - cannedAcl + cannedAcl, + useAccelerateEndpoint ) return transferDBHelper.insert(transferDBHelper.contentUri, values) } @@ -557,7 +561,8 @@ internal class TransferDB private constructor(context: Context) { key: String, file: File, metadata: ObjectMetadata?, - cannedAcl: ObjectCannedAcl? + cannedAcl: ObjectCannedAcl?, + useAccelerateEndpoint: Boolean ): Uri { val values = generateContentValuesForSinglePartTransfer( transferId, @@ -566,7 +571,8 @@ internal class TransferDB private constructor(context: Context) { key, file, metadata, - cannedAcl + cannedAcl, + useAccelerateEndpoint ) return transferDBHelper.insert( transferDBHelper.contentUri, @@ -602,7 +608,8 @@ internal class TransferDB private constructor(context: Context) { bytesTotal: Long, isLastPart: Int, metadata: ObjectMetadata?, - cannedAcl: ObjectCannedAcl? + cannedAcl: ObjectCannedAcl?, + useAccelerateEndpoint: Boolean ): ContentValues { val values = ContentValues() values.put(TransferTable.COLUMN_TRANSFER_ID, transferId) @@ -619,6 +626,7 @@ internal class TransferDB private constructor(context: Context) { values.put(TransferTable.COLUMN_MULTIPART_ID, uploadId) values.put(TransferTable.COLUMN_IS_LAST_PART, isLastPart) values.put(TransferTable.COLUMN_IS_ENCRYPTED, 0) + values.put(TransferTable.COLUMN_USE_ACCELERATE_ENDPOINT, if (useAccelerateEndpoint) 1 else 0) values.putAll(generateContentValuesForObjectMetadata(metadata)) cannedAcl?.let { values.put(TransferTable.COLUMN_CANNED_ACL, it.value) @@ -716,7 +724,8 @@ internal class TransferDB private constructor(context: Context) { key: String, file: File?, metadata: ObjectMetadata?, - cannedAcl: ObjectCannedAcl? + cannedAcl: ObjectCannedAcl?, + useAccelerateEndpoint: Boolean ): ContentValues { val values = ContentValues() values.put(TransferTable.COLUMN_TRANSFER_ID, transferId) @@ -734,6 +743,7 @@ internal class TransferDB private constructor(context: Context) { values.put(TransferTable.COLUMN_IS_ENCRYPTED, 0) values.putAll(generateContentValuesForObjectMetadata(metadata)) values.put(TransferTable.COLUMN_CANNED_ACL, cannedAcl?.value) + values.put(TransferTable.COLUMN_USE_ACCELERATE_ENDPOINT, if (useAccelerateEndpoint) 1 else 0) return values } diff --git a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/TransferDBHelper.kt b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/TransferDBHelper.kt index 96604b48c4..c03962eb2e 100644 --- a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/TransferDBHelper.kt +++ b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/TransferDBHelper.kt @@ -44,7 +44,7 @@ internal class TransferDBHelper(private val context: Context) : // This represents the latest database version. // Update this when the database is being upgraded. - private const val DATABASE_VERSION = 8 + private const val DATABASE_VERSION = 9 private const val BASE_PATH = "transfers" private const val TRANSFERS = 10 private const val TRANSFER_ID = 20 diff --git a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/TransferManager.kt b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/TransferManager.kt index 43fedc00b9..9df0c28ead 100644 --- a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/TransferManager.kt +++ b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/TransferManager.kt @@ -94,10 +94,11 @@ internal class TransferManager @JvmOverloads constructor( file: File, metadata: ObjectMetadata, cannedAcl: ObjectCannedAcl? = null, - listener: TransferListener? = null + listener: TransferListener? = null, + useAccelerateEndpoint: Boolean = false ): TransferObserver { val transferRecordId = if (shouldUploadInMultipart(file)) { - createMultipartUploadRecords(transferId, bucket, key, file, metadata, cannedAcl) + createMultipartUploadRecords(transferId, bucket, key, file, metadata, cannedAcl, useAccelerateEndpoint) } else { val uri = transferDB.insertSingleTransferRecord( transferId, @@ -106,7 +107,8 @@ internal class TransferManager @JvmOverloads constructor( key, file, cannedAcl, - metadata + metadata, + useAccelerateEndpoint = useAccelerateEndpoint ) uri.lastPathSegment?.toInt() ?: throw IllegalStateException("Invalid TransferRecord ID ${uri.lastPathSegment}") @@ -135,7 +137,8 @@ internal class TransferManager @JvmOverloads constructor( transferId: String, key: String, inputStream: InputStream, - options: UploadOptions + options: UploadOptions, + useAccelerateEndpoint: Boolean ): TransferObserver { val file = writeInputStreamToFile(inputStream) return upload( @@ -145,7 +148,8 @@ internal class TransferManager @JvmOverloads constructor( file, options.objectMetadata, options.cannedAcl, - options.transferListener + options.transferListener, + useAccelerateEndpoint ) } @@ -155,12 +159,20 @@ internal class TransferManager @JvmOverloads constructor( bucket: String, key: String, file: File, - listener: TransferListener? = null + listener: TransferListener? = null, + useAccelerateEndpoint: Boolean = false ): TransferObserver { if (file.isDirectory) { throw IllegalArgumentException("Invalid file: $file") } - val uri = transferDB.insertSingleTransferRecord(transferId, TransferType.DOWNLOAD, bucket, key, file) + val uri = transferDB.insertSingleTransferRecord( + transferId, + TransferType.DOWNLOAD, + bucket, + key, + file, + useAccelerateEndpoint = useAccelerateEndpoint + ) val transferRecordId: Int = uri.lastPathSegment?.toInt() ?: throw IllegalStateException("Invalid TransferRecord ID ${uri.lastPathSegment}") if (file.isFile) { @@ -235,6 +247,7 @@ internal class TransferManager @JvmOverloads constructor( file: File, metadata: ObjectMetadata, cannedAcl: ObjectCannedAcl?, + useAccelerateEndpoint: Boolean ): Int { var remainingLength = file.length() val partSize = @@ -255,7 +268,8 @@ internal class TransferManager @JvmOverloads constructor( file.length(), 0, metadata, - cannedAcl + cannedAcl, + useAccelerateEndpoint ) repeat(partCount) { val bytesForPart = min(optimalPartSize, remainingLength) @@ -270,7 +284,8 @@ internal class TransferManager @JvmOverloads constructor( bytesForPart, if (remainingLength - optimalPartSize <= 0) 1 else 0, metadata, - cannedAcl + cannedAcl, + useAccelerateEndpoint ) partNum++ fileOffset += optimalPartSize diff --git a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/TransferRecord.kt b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/TransferRecord.kt index a49d07edc5..c32a85c7ce 100644 --- a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/TransferRecord.kt +++ b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/TransferRecord.kt @@ -55,7 +55,8 @@ internal data class TransferRecord( var sseKMSKey: String? = null, var md5: String? = null, var cannedAcl: String? = null, - var workManagerRequestId: String? = null + var workManagerRequestId: String? = null, + var useAccelerateEndpoint: Int = 0 ) { companion object { @@ -144,6 +145,9 @@ internal data class TransferRecord( c.getString(c.getColumnIndexOrThrow(TransferTable.COLUMN_CANNED_ACL)) this.headerStorageClass = c.getString(c.getColumnIndexOrThrow(TransferTable.COLUMN_HEADER_STORAGE_CLASS)) + this.useAccelerateEndpoint = c.getInt( + c.getColumnIndexOrThrow(TransferTable.COLUMN_USE_ACCELERATE_ENDPOINT) + ) } } } diff --git a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/TransferTable.kt b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/TransferTable.kt index 2490a09413..85b515062d 100644 --- a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/TransferTable.kt +++ b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/TransferTable.kt @@ -132,6 +132,8 @@ internal class TransferTable { // A unique transfer id for user to query const val COLUMN_TRANSFER_ID = "transfer_id" + const val COLUMN_USE_ACCELERATE_ENDPOINT = "useAccelerateEndpoint" + private const val TABLE_VERSION_2 = 2 private const val TABLE_VERSION_3 = 3 private const val TABLE_VERSION_4 = 4 @@ -139,6 +141,7 @@ internal class TransferTable { private const val TABLE_VERSION_6 = 6 private const val TABLE_VERSION_7 = 7 private const val TABLE_VERSION_8 = 8 + private const val TABLE_VERSION_9 = 9 // Database creation SQL statement const val DATABASE_CREATE = "create table $TABLE_TRANSFER (" + @@ -213,6 +216,9 @@ internal class TransferTable { if (TABLE_VERSION_8 in (oldVersion + 1)..newVersion) { addVersion8Columns(database) } + if (TABLE_VERSION_9 in (oldVersion + 1)..newVersion) { + addVersion9Columns(database) + } database.setTransactionSuccessful() database.endTransaction() } @@ -281,5 +287,14 @@ internal class TransferTable { "DEFAULT '${UUID.randomUUID()}';" database.execSQL(addConnectionType) } + + /** + * Adds columns that were introduced in version 8 to the database + */ + private fun addVersion9Columns(database: SQLiteDatabase) { + val addConnectionType = "ALTER TABLE $TABLE_TRANSFER ADD COLUMN $COLUMN_USE_ACCELERATE_ENDPOINT int " + + "DEFAULT 0;" + database.execSQL(addConnectionType) + } } } diff --git a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/worker/AbortMultiPartUploadWorker.kt b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/worker/AbortMultiPartUploadWorker.kt index af45343ee0..30aa2d20b9 100644 --- a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/worker/AbortMultiPartUploadWorker.kt +++ b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/worker/AbortMultiPartUploadWorker.kt @@ -18,6 +18,7 @@ import android.content.Context import androidx.work.WorkerParameters import aws.sdk.kotlin.services.s3.S3Client import aws.sdk.kotlin.services.s3.abortMultipartUpload +import aws.sdk.kotlin.services.s3.withConfig import com.amplifyframework.storage.TransferState import com.amplifyframework.storage.s3.transfer.TransferDB import com.amplifyframework.storage.s3.transfer.TransferStatusUpdater @@ -34,7 +35,9 @@ internal class AbortMultiPartUploadWorker( ) : BaseTransferWorker(transferStatusUpdater, transferDB, context, workerParameters) { override suspend fun performWork(): Result { - return s3.abortMultipartUpload { + return s3.withConfig { + enableAccelerate = transferRecord.useAccelerateEndpoint == 1 + }.abortMultipartUpload { bucket = transferRecord.bucketName key = transferRecord.key uploadId = transferRecord.multipartId diff --git a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/worker/BaseTransferWorker.kt b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/worker/BaseTransferWorker.kt index 67fb649352..84588ad75e 100644 --- a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/worker/BaseTransferWorker.kt +++ b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/worker/BaseTransferWorker.kt @@ -21,6 +21,7 @@ import android.content.Context import android.net.ConnectivityManager import android.net.NetworkCapabilities import android.os.Build +import android.util.Log import androidx.annotation.RequiresApi import androidx.core.app.NotificationCompat import androidx.work.CoroutineWorker @@ -34,10 +35,8 @@ import aws.sdk.kotlin.services.s3.model.RequestPayer import aws.sdk.kotlin.services.s3.model.ServerSideEncryption import aws.sdk.kotlin.services.s3.model.StorageClass import aws.smithy.kotlin.runtime.content.ByteStream -import aws.smithy.kotlin.runtime.io.SdkByteReadChannel -import aws.smithy.kotlin.runtime.io.readChannel +import aws.smithy.kotlin.runtime.content.fromFile import aws.smithy.kotlin.runtime.time.Instant -import aws.smithy.kotlin.runtime.util.InternalApi import com.amplifyframework.core.Amplify import com.amplifyframework.storage.ObjectMetadata import com.amplifyframework.storage.TransferState @@ -50,7 +49,6 @@ import com.amplifyframework.storage.s3.transfer.TransferStatusUpdater import java.io.File import java.lang.Exception import java.net.SocketException -import java.nio.ByteBuffer import kotlinx.coroutines.CancellationException /** @@ -112,7 +110,9 @@ internal abstract class BaseTransferWorker( } else -> { val ex = result.exceptionOrNull() - logger.error("${this.javaClass.simpleName} failed with exception: $ex") + if (!isStopped) { + logger.error("${this.javaClass.simpleName} failed with exception: ${Log.getStackTraceString(ex)}") + } if (isRetryableError(ex)) { Result.retry() } else { @@ -206,7 +206,7 @@ internal abstract class BaseTransferWorker( return PutObjectRequest { bucket = transferRecord.bucketName key = transferRecord.key - body = ByteStream.readWithProgressUpdates(file, progressListener = progressListener) + body = ByteStream.fromFile(file) cacheControl = transferRecord.headerCacheControl contentDisposition = transferRecord.headerContentDisposition serverSideEncryption = transferRecord.sseAlgorithm?.let { @@ -228,67 +228,4 @@ internal abstract class BaseTransferWorker( tagging = transferRecord.userMetadata?.get(ObjectMetadata.S3_TAGGING) } } - - @OptIn(InternalApi::class) - fun ByteStream.Companion.readWithProgressUpdates( - file: File, - start: Long = 0, - length: Long = file.length(), - progressListener: ProgressListener? - ): ByteStream { - return object : ByteStream.OneShotStream() { - override val contentLength: Long = length - override fun readFrom(): SdkByteReadChannel { - val oneShotStream = file.readChannel(start, start + length - 1) - return object : SdkByteReadChannel { - override val availableForRead: Int - get() = oneShotStream.availableForRead - override val isClosedForRead: Boolean - get() = oneShotStream.isClosedForRead - override val isClosedForWrite: Boolean - get() = oneShotStream.isClosedForWrite - - override suspend fun awaitContent() { - oneShotStream.awaitContent() - } - - override fun cancel(cause: Throwable?): Boolean { - return oneShotStream.cancel(cause) - } - - override suspend fun readAvailable(sink: ByteBuffer): Int { - return oneShotStream.readAvailable(sink).also { - if (it > 0) { - progressListener?.progressChanged(it.toLong()) - } - } - } - - override suspend fun readAvailable(sink: ByteArray, offset: Int, length: Int): Int { - return oneShotStream.readAvailable(sink, offset, length).also { - if (it > 0) { - progressListener?.progressChanged(it.toLong()) - } - } - } - - override suspend fun readFully(sink: ByteArray, offset: Int, length: Int) { - return oneShotStream.readFully(sink, offset, length).also { - if (sink.isNotEmpty()) { - progressListener?.progressChanged(sink.size.toLong()) - } - } - } - - override suspend fun readRemaining(limit: Int): ByteArray { - return readRemaining(limit).also { - if (it.isNotEmpty()) { - progressListener?.progressChanged(it.size.toLong()) - } - } - } - } - } - } - } } diff --git a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/worker/CompleteMultiPartUploadWorker.kt b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/worker/CompleteMultiPartUploadWorker.kt index c4484ac659..8b48014a87 100644 --- a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/worker/CompleteMultiPartUploadWorker.kt +++ b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/worker/CompleteMultiPartUploadWorker.kt @@ -19,6 +19,7 @@ import androidx.work.WorkerParameters import aws.sdk.kotlin.services.s3.S3Client import aws.sdk.kotlin.services.s3.completeMultipartUpload import aws.sdk.kotlin.services.s3.model.CompletedMultipartUpload +import aws.sdk.kotlin.services.s3.withConfig import com.amplifyframework.storage.s3.transfer.TransferDB import com.amplifyframework.storage.s3.transfer.TransferStatusUpdater @@ -35,7 +36,9 @@ internal class CompleteMultiPartUploadWorker( override suspend fun performWork(): Result { val completedParts = transferDB.queryPartETagsOfUpload(transferRecord.id) - return s3.completeMultipartUpload { + return s3.withConfig { + enableAccelerate = transferRecord.useAccelerateEndpoint == 1 + }.completeMultipartUpload { bucket = transferRecord.bucketName key = transferRecord.key multipartUpload = CompletedMultipartUpload { diff --git a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/worker/DownloadWorker.kt b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/worker/DownloadWorker.kt index 4222153877..083ccad2b6 100644 --- a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/worker/DownloadWorker.kt +++ b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/worker/DownloadWorker.kt @@ -19,14 +19,19 @@ import android.content.Context import androidx.work.WorkerParameters import aws.sdk.kotlin.services.s3.S3Client import aws.sdk.kotlin.services.s3.model.GetObjectRequest +import aws.sdk.kotlin.services.s3.withConfig import aws.smithy.kotlin.runtime.content.ByteStream -import aws.smithy.kotlin.runtime.util.InternalApi +import aws.smithy.kotlin.runtime.content.writeToFile +import aws.smithy.kotlin.runtime.io.SdkSource +import aws.smithy.kotlin.runtime.io.buffer import com.amplifyframework.storage.s3.transfer.DownloadProgressListener +import com.amplifyframework.storage.s3.transfer.DownloadProgressListenerInterceptor import com.amplifyframework.storage.s3.transfer.TransferDB import com.amplifyframework.storage.s3.transfer.TransferStatusUpdater import java.io.BufferedOutputStream import java.io.File import java.io.FileOutputStream +import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext @@ -42,10 +47,12 @@ internal class DownloadWorker( ) : BaseTransferWorker(transferStatusUpdater, transferDB, context, workerParameters) { private lateinit var downloadProgressListener: DownloadProgressListener - private val defaultBufferSize = 4096 - - @OptIn(InternalApi::class) + private val defaultBufferSize = 8192L + val coroutineScope = CoroutineScope(Dispatchers.IO) override suspend fun performWork(): Result { + s3.withConfig { + enableAccelerate = transferRecord.useAccelerateEndpoint == 1 + } val file = File(transferRecord.file) val downloadedBytes = file.length() if (downloadedBytes > 0 && transferRecord.bytesTotal == downloadedBytes) { @@ -56,13 +63,19 @@ internal class DownloadWorker( bucket = transferRecord.bucketName range = "bytes=$downloadedBytes-" } - return s3.getObject(getObjectRequest) { response -> + + downloadProgressListener = DownloadProgressListener(transferRecord, transferStatusUpdater) + return s3.withConfig { + interceptors += DownloadProgressListenerInterceptor(downloadProgressListener) + enableAccelerate = transferRecord.useAccelerateEndpoint == 1 + }.getObject(getObjectRequest) { response -> val totalBytes = (response.body?.contentLength ?: 0L) + downloadedBytes transferRecord.bytesTotal = totalBytes transferRecord.bytesCurrent = downloadedBytes file.parentFile?.takeIf { !it.exists() }?.mkdirs() - downloadProgressListener = DownloadProgressListener(transferRecord, transferStatusUpdater) - writeToFileWithProgressUpdates(response.body as ByteStream.OneShotStream, file, downloadProgressListener) + response.body?.let { + writeStreamToFile(it, file) + } transferStatusUpdater.updateProgress( transferRecord.id, totalBytes, @@ -73,34 +86,38 @@ internal class DownloadWorker( } } - @OptIn(InternalApi::class) - private suspend fun writeToFileWithProgressUpdates( - stream: ByteStream.OneShotStream, - file: File, - progressListener: DownloadProgressListener + private suspend fun writeStreamToFile( + stream: ByteStream, + file: File ) { withContext(Dispatchers.IO) { - val sdkByteReadChannel = stream.readFrom() - val limit = stream.contentLength ?: 0L - val buffer = ByteArray(defaultBufferSize) - val append = file.length() > 0 - val fileOutputStream = FileOutputStream(file, append) - var totalRead = 0L - BufferedOutputStream(fileOutputStream).use { fileOutput -> - val copied = 0L - while (!isStopped) { - val remaining = limit - copied - if (remaining == 0L) break - val readBytes = - sdkByteReadChannel.readAvailable(buffer, 0, minOf(buffer.size.toLong(), remaining).toInt()) - if (readBytes == -1) break - if (readBytes > 0) { - totalRead += readBytes - progressListener.progressChanged(readBytes.toLong()) - } - fileOutput.write(buffer, 0, readBytes) - if (sdkByteReadChannel.availableForRead == 0) { - fileOutput.flush() + when (stream) { + is ByteStream.ChannelStream, is ByteStream.Buffer -> { + stream.writeToFile(file) + } + is ByteStream.SourceStream -> { + val sourceStream: SdkSource = stream.readFrom() + val limit = stream.contentLength ?: 0L + val buffer = ByteArray(defaultBufferSize.toInt()) + val append = file.length() > 0 + val fileOutputStream = FileOutputStream(file, append) + var totalRead = 0L + BufferedOutputStream(fileOutputStream).use { fileOutput -> + val copied = 0L + while (!isStopped) { + val remaining = limit - copied + if (remaining == 0L) break + val readBytes = + sourceStream.buffer().read(buffer, 0, minOf(buffer.size.toLong(), remaining).toInt()) + if (readBytes == -1) break + if (readBytes > 0) { + totalRead += readBytes + } + fileOutput.write(buffer, 0, readBytes) + } + if (sourceStream.buffer().exhausted()) { + fileOutput.flush() + } } } } diff --git a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/worker/InitiateMultiPartUploadTransferWorker.kt b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/worker/InitiateMultiPartUploadTransferWorker.kt index f586d565ce..ec7be7cb35 100644 --- a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/worker/InitiateMultiPartUploadTransferWorker.kt +++ b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/worker/InitiateMultiPartUploadTransferWorker.kt @@ -19,6 +19,7 @@ import androidx.work.Data import androidx.work.WorkerParameters import aws.sdk.kotlin.services.s3.S3Client import aws.sdk.kotlin.services.s3.createMultipartUpload +import aws.sdk.kotlin.services.s3.withConfig import com.amplifyframework.storage.TransferState import com.amplifyframework.storage.s3.transfer.TransferDB import com.amplifyframework.storage.s3.transfer.TransferStatusUpdater @@ -37,7 +38,9 @@ internal class InitiateMultiPartUploadTransferWorker( override suspend fun performWork(): Result { transferStatusUpdater.updateTransferState(transferRecord.id, TransferState.IN_PROGRESS) val putObjectRequest = createPutObjectRequest(transferRecord, null) - return s3.createMultipartUpload { + return s3.withConfig { + enableAccelerate = transferRecord.useAccelerateEndpoint == 1 + }.createMultipartUpload { bucket = putObjectRequest.bucket key = putObjectRequest.key acl = putObjectRequest.acl diff --git a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/worker/PartUploadTransferWorker.kt b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/worker/PartUploadTransferWorker.kt index 8d725538d1..41c7c7fd0d 100644 --- a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/worker/PartUploadTransferWorker.kt +++ b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/worker/PartUploadTransferWorker.kt @@ -18,11 +18,13 @@ import android.content.Context import androidx.work.WorkerParameters import aws.sdk.kotlin.services.s3.S3Client import aws.sdk.kotlin.services.s3.uploadPart -import aws.smithy.kotlin.runtime.content.ByteStream +import aws.sdk.kotlin.services.s3.withConfig +import aws.smithy.kotlin.runtime.content.asByteStream import com.amplifyframework.storage.TransferState import com.amplifyframework.storage.s3.transfer.PartUploadProgressListener import com.amplifyframework.storage.s3.transfer.TransferDB import com.amplifyframework.storage.s3.transfer.TransferStatusUpdater +import com.amplifyframework.storage.s3.transfer.UploadProgressListenerInterceptor import java.io.File /** @@ -47,15 +49,16 @@ internal class PartUploadTransferWorker( transferStatusUpdater.updateTransferState(transferRecord.mainUploadId, TransferState.IN_PROGRESS) multiPartUploadId = inputData.keyValueMap[MULTI_PART_UPLOAD_ID] as String partUploadProgressListener = PartUploadProgressListener(transferRecord, transferStatusUpdater) - return s3.uploadPart { + return s3.withConfig { + interceptors += UploadProgressListenerInterceptor(partUploadProgressListener) + enableAccelerate = transferRecord.useAccelerateEndpoint == 1 + }.uploadPart { bucket = transferRecord.bucketName key = transferRecord.key uploadId = multiPartUploadId - body = ByteStream.readWithProgressUpdates( - File(transferRecord.file), - transferRecord.fileOffset, - transferRecord.bytesTotal, - partUploadProgressListener + body = File(transferRecord.file).asByteStream( + start = transferRecord.fileOffset, + transferRecord.fileOffset + transferRecord.bytesTotal - 1 ) partNumber = transferRecord.partNumber }.let { response -> diff --git a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/worker/SinglePartUploadWorker.kt b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/worker/SinglePartUploadWorker.kt index 2662945272..21de0db80c 100644 --- a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/worker/SinglePartUploadWorker.kt +++ b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/worker/SinglePartUploadWorker.kt @@ -21,9 +21,11 @@ package com.amplifyframework.storage.s3.transfer.worker import android.content.Context import androidx.work.WorkerParameters import aws.sdk.kotlin.services.s3.S3Client +import aws.sdk.kotlin.services.s3.withConfig import com.amplifyframework.storage.s3.transfer.TransferDB import com.amplifyframework.storage.s3.transfer.TransferStatusUpdater import com.amplifyframework.storage.s3.transfer.UploadProgressListener +import com.amplifyframework.storage.s3.transfer.UploadProgressListenerInterceptor internal class SinglePartUploadWorker( private val s3: S3Client, @@ -38,7 +40,10 @@ internal class SinglePartUploadWorker( override suspend fun performWork(): Result { uploadProgressListener = UploadProgressListener(transferRecord, transferStatusUpdater) val putObjectRequest = createPutObjectRequest(transferRecord, uploadProgressListener) - return s3.putObject(putObjectRequest).let { + return s3.withConfig { + interceptors += UploadProgressListenerInterceptor(uploadProgressListener) + enableAccelerate = transferRecord.useAccelerateEndpoint == 1 + }.putObject(putObjectRequest).let { Result.success(outputData) } } diff --git a/aws-storage-s3/src/test/java/com/amplifyframework/storage/s3/StorageComponentTest.java b/aws-storage-s3/src/test/java/com/amplifyframework/storage/s3/StorageComponentTest.java index 91fb399ec8..ad497bc81f 100644 --- a/aws-storage-s3/src/test/java/com/amplifyframework/storage/s3/StorageComponentTest.java +++ b/aws-storage-s3/src/test/java/com/amplifyframework/storage/s3/StorageComponentTest.java @@ -57,6 +57,7 @@ import static androidx.test.core.app.ApplicationProvider.getApplicationContext; import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.anyString; @@ -140,7 +141,7 @@ public void testGenerateUrlGetsPresignedUrl() throws StorageException { // Allow mock StorageService instance to return a non-null // URL instance. - when(storageService.getPresignedUrl(anyString(), anyInt())) + when(storageService.getPresignedUrl(anyString(), anyInt(), anyBoolean())) .thenReturn(urlFromRemoteKey); // Let Storage category invoke getUrl on mock Storage Service. @@ -171,7 +172,7 @@ public void testDownloadToFileGetsFile() throws Exception { // result by default. We need a non-null transfer observer. // One option is to mock that, too. TransferObserver observer = mock(TransferObserver.class); - when(storageService.downloadToFile(anyString(), anyString(), any(File.class))) + when(storageService.downloadToFile(anyString(), anyString(), any(File.class), anyBoolean())) .thenReturn(observer); // Since we use a mock TransferObserver, it has no internal logic @@ -214,7 +215,7 @@ public void testDownloadError() throws IOException { final File toLocalFile = new RandomTempFile(); TransferObserver observer = mock(TransferObserver.class); - when(storageService.downloadToFile(anyString(), anyString(), any(File.class))) + when(storageService.downloadToFile(anyString(), anyString(), any(File.class), anyBoolean())) .thenReturn(observer); doAnswer(invocation -> { @@ -251,7 +252,13 @@ public void testUploadFileGetsKey() throws Exception { TransferObserver observer = mock(com.amplifyframework.storage.s3.transfer.TransferObserver.class); - when(storageService.uploadFile(anyString(), anyString(), any(File.class), any(ObjectMetadata.class))) + when( + storageService.uploadFile(anyString(), + anyString(), + any(File.class), + any(ObjectMetadata.class), + anyBoolean()) + ) .thenReturn(observer); doAnswer(invocation -> { @@ -291,7 +298,8 @@ public void testUploadInputStreamGetsKey() throws Exception { anyString(), anyString(), any(InputStream.class), - any(ObjectMetadata.class)) + any(ObjectMetadata.class), + anyBoolean()) ) .thenReturn(observer); @@ -333,8 +341,14 @@ public void testUploadFileError() throws IOException { com.amplifyframework.storage.s3.transfer.TransferObserver observer = mock(com.amplifyframework.storage.s3.transfer.TransferObserver.class); - when(storageService.uploadFile(anyString(), anyString(), any(File.class), any(ObjectMetadata.class))) - .thenReturn(observer); + when( + storageService.uploadFile( + anyString(), + anyString(), + any(File.class), + any(ObjectMetadata.class), + anyBoolean()) + ).thenReturn(observer); doAnswer(invocation -> { com.amplifyframework.storage.s3.transfer.TransferListener listener = invocation.getArgument(0); @@ -377,7 +391,8 @@ public void testInputStreamError() throws IOException { anyString(), anyString(), any(InputStream.class), - any(ObjectMetadata.class)) + any(ObjectMetadata.class), + anyBoolean()) ) .thenReturn(observer); diff --git a/aws-storage-s3/src/test/java/com/amplifyframework/storage/s3/operation/AWSS3StorageDownloadFileOperationTest.kt b/aws-storage-s3/src/test/java/com/amplifyframework/storage/s3/operation/AWSS3StorageDownloadFileOperationTest.kt index c9805059be..a62805a666 100644 --- a/aws-storage-s3/src/test/java/com/amplifyframework/storage/s3/operation/AWSS3StorageDownloadFileOperationTest.kt +++ b/aws-storage-s3/src/test/java/com/amplifyframework/storage/s3/operation/AWSS3StorageDownloadFileOperationTest.kt @@ -55,7 +55,8 @@ class AWSS3StorageDownloadFileOperationTest { key, tempFile, StorageAccessLevel.PUBLIC, - null + null, + false ) coEvery { authCredentialsProvider.getIdentityId() } returns "abc" awsS3StorageDownloadFileOperation = AWSS3StorageDownloadFileOperation( @@ -72,7 +73,8 @@ class AWSS3StorageDownloadFileOperationTest { Mockito.verify(storageService).downloadToFile( awsS3StorageDownloadFileOperation.transferId, expectedKey, - tempFile + tempFile, + false ) } @@ -85,7 +87,8 @@ class AWSS3StorageDownloadFileOperationTest { key, tempFile, StorageAccessLevel.PUBLIC, - null + null, + false ) coEvery { authCredentialsProvider.getIdentityId() } returns "abc" awsS3StorageDownloadFileOperation = AWSS3StorageDownloadFileOperation( @@ -113,7 +116,8 @@ class AWSS3StorageDownloadFileOperationTest { Mockito.verify(storageService).downloadToFile( awsS3StorageDownloadFileOperation.transferId, expectedKey, - tempFile + tempFile, + false ) } @@ -126,7 +130,8 @@ class AWSS3StorageDownloadFileOperationTest { key, tempFile, StorageAccessLevel.PUBLIC, - null + null, + false ) coEvery { authCredentialsProvider.getIdentityId() } returns "abc" awsS3StorageDownloadFileOperation = AWSS3StorageDownloadFileOperation( @@ -154,7 +159,8 @@ class AWSS3StorageDownloadFileOperationTest { Mockito.verify(storageService).downloadToFile( awsS3StorageDownloadFileOperation.transferId, expectedKey, - tempFile + tempFile, + false ) } } diff --git a/aws-storage-s3/src/test/java/com/amplifyframework/storage/s3/operation/AWSS3StorageGetPresignedUrlOperationTest.kt b/aws-storage-s3/src/test/java/com/amplifyframework/storage/s3/operation/AWSS3StorageGetPresignedUrlOperationTest.kt index dda278d8fd..01777f6836 100644 --- a/aws-storage-s3/src/test/java/com/amplifyframework/storage/s3/operation/AWSS3StorageGetPresignedUrlOperationTest.kt +++ b/aws-storage-s3/src/test/java/com/amplifyframework/storage/s3/operation/AWSS3StorageGetPresignedUrlOperationTest.kt @@ -50,7 +50,8 @@ public class AWSS3StorageGetPresignedUrlOperationTest { key, StorageAccessLevel.PUBLIC, "", - 1 + 1, + false ) coEvery { authCredentialsProvider.getIdentityId() } returns "abc" awsS3StorageGetPresignedUrlOperation = AWSS3StorageGetPresignedUrlOperation( @@ -63,7 +64,7 @@ public class AWSS3StorageGetPresignedUrlOperationTest { {} ) awsS3StorageGetPresignedUrlOperation.start() - Mockito.verify(storageService).getPresignedUrl(expectedKey, 1) + Mockito.verify(storageService).getPresignedUrl(expectedKey, 1, false) } @Test @@ -74,7 +75,8 @@ public class AWSS3StorageGetPresignedUrlOperationTest { key, StorageAccessLevel.PUBLIC, "", - 1 + 1, + false ) coEvery { authCredentialsProvider.getIdentityId() } returns "abc" awsS3StorageGetPresignedUrlOperation = AWSS3StorageGetPresignedUrlOperation( @@ -98,7 +100,7 @@ public class AWSS3StorageGetPresignedUrlOperationTest { { Log.e("TAG", "$it") } ) awsS3StorageGetPresignedUrlOperation.start() - Mockito.verify(storageService).getPresignedUrl(expectedKey, 1) + Mockito.verify(storageService).getPresignedUrl(expectedKey, 1, false) } @Test @@ -109,7 +111,8 @@ public class AWSS3StorageGetPresignedUrlOperationTest { key, StorageAccessLevel.PUBLIC, "", - 1 + 1, + false ) coEvery { authCredentialsProvider.getIdentityId() } returns "abc" awsS3StorageGetPresignedUrlOperation = AWSS3StorageGetPresignedUrlOperation( @@ -133,6 +136,6 @@ public class AWSS3StorageGetPresignedUrlOperationTest { { Log.e("TAG", "$it") } ) awsS3StorageGetPresignedUrlOperation.start() - Mockito.verify(storageService).getPresignedUrl(expectedKey, 1) + Mockito.verify(storageService).getPresignedUrl(expectedKey, 1, false) } } diff --git a/aws-storage-s3/src/test/java/com/amplifyframework/storage/s3/operation/AWSS3StorageUploadFileOperationTest.kt b/aws-storage-s3/src/test/java/com/amplifyframework/storage/s3/operation/AWSS3StorageUploadFileOperationTest.kt index 7015562e45..fce3093071 100644 --- a/aws-storage-s3/src/test/java/com/amplifyframework/storage/s3/operation/AWSS3StorageUploadFileOperationTest.kt +++ b/aws-storage-s3/src/test/java/com/amplifyframework/storage/s3/operation/AWSS3StorageUploadFileOperationTest.kt @@ -30,6 +30,8 @@ import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mockito +import org.mockito.Mockito.any +import org.mockito.Mockito.eq import org.robolectric.RobolectricTestRunner @RunWith(RobolectricTestRunner::class) @@ -57,7 +59,8 @@ class AWSS3StorageUploadFileOperationTest { "", "/image", ServerSideEncryption.NONE, - mutableMapOf() + mutableMapOf(), + false ) awsS3StorageUploadFileOperation = AWSS3StorageUploadFileOperation( storageService, @@ -71,10 +74,11 @@ class AWSS3StorageUploadFileOperationTest { ) awsS3StorageUploadFileOperation.start() Mockito.verify(storageService).uploadFile( - Mockito.eq(awsS3StorageUploadFileOperation.transferId), - Mockito.eq(expectedKey), - Mockito.eq(tempFile), - Mockito.any(ObjectMetadata::class.java) + eq(awsS3StorageUploadFileOperation.transferId), + eq(expectedKey), + eq(tempFile), + any(ObjectMetadata::class.java), + eq(false) ) } @@ -90,7 +94,8 @@ class AWSS3StorageUploadFileOperationTest { "", "/image", ServerSideEncryption.NONE, - mutableMapOf() + mutableMapOf(), + false ) awsS3StorageUploadFileOperation = AWSS3StorageUploadFileOperation( storageService, @@ -115,10 +120,11 @@ class AWSS3StorageUploadFileOperationTest { ) awsS3StorageUploadFileOperation.start() Mockito.verify(storageService).uploadFile( - Mockito.eq(awsS3StorageUploadFileOperation.transferId), - Mockito.eq(expectedKey), - Mockito.eq(tempFile), - Mockito.any(ObjectMetadata::class.java) + eq(awsS3StorageUploadFileOperation.transferId), + eq(expectedKey), + eq(tempFile), + any(ObjectMetadata::class.java), + eq(false) ) } @@ -134,7 +140,8 @@ class AWSS3StorageUploadFileOperationTest { "", "/image", ServerSideEncryption.NONE, - mutableMapOf() + mutableMapOf(), + false ) awsS3StorageUploadFileOperation = AWSS3StorageUploadFileOperation( storageService, @@ -159,10 +166,11 @@ class AWSS3StorageUploadFileOperationTest { ) awsS3StorageUploadFileOperation.start() Mockito.verify(storageService).uploadFile( - Mockito.eq(awsS3StorageUploadFileOperation.transferId), - Mockito.eq(expectedKey), - Mockito.eq(tempFile), - Mockito.any(ObjectMetadata::class.java) + eq(awsS3StorageUploadFileOperation.transferId), + eq(expectedKey), + eq(tempFile), + any(ObjectMetadata::class.java), + eq(false) ) } } diff --git a/aws-storage-s3/src/test/java/com/amplifyframework/storage/s3/operation/AWSS3StorageUploadInputStreamOperationTest.kt b/aws-storage-s3/src/test/java/com/amplifyframework/storage/s3/operation/AWSS3StorageUploadInputStreamOperationTest.kt index 3840ee1781..f73d467a6a 100644 --- a/aws-storage-s3/src/test/java/com/amplifyframework/storage/s3/operation/AWSS3StorageUploadInputStreamOperationTest.kt +++ b/aws-storage-s3/src/test/java/com/amplifyframework/storage/s3/operation/AWSS3StorageUploadInputStreamOperationTest.kt @@ -34,6 +34,8 @@ import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mockito +import org.mockito.Mockito.any +import org.mockito.Mockito.eq import org.robolectric.RobolectricTestRunner @RunWith(RobolectricTestRunner::class) @@ -57,10 +59,11 @@ class AWSS3StorageUploadInputStreamOperationTest { coEvery { authCredentialsProvider.getIdentityId() } returns "abc" Mockito.`when`( storageService.uploadInputStream( - Mockito.any(), - Mockito.any(), - Mockito.any(), - Mockito.any() + any(), + any(), + any(), + any(), + eq(false) ) ).thenReturn(Mockito.mock(TransferObserver::class.java)) val request = AWSS3StorageUploadRequest( @@ -70,7 +73,8 @@ class AWSS3StorageUploadInputStreamOperationTest { "", "/image", ServerSideEncryption.NONE, - mutableMapOf() + mutableMapOf(), + false ) inputStreamOperation = AWSS3StorageUploadInputStreamOperation( storageService, @@ -84,10 +88,11 @@ class AWSS3StorageUploadInputStreamOperationTest { ) inputStreamOperation.start() Mockito.verify(storageService).uploadInputStream( - Mockito.eq(inputStreamOperation.transferId), - Mockito.eq(expectedKey), - Mockito.eq(tempInputStream), - Mockito.any(ObjectMetadata::class.java) + eq(inputStreamOperation.transferId), + eq(expectedKey), + eq(tempInputStream), + any(ObjectMetadata::class.java), + eq(false) ) } @@ -99,10 +104,11 @@ class AWSS3StorageUploadInputStreamOperationTest { coEvery { authCredentialsProvider.getIdentityId() } returns "abc" Mockito.`when`( storageService.uploadInputStream( - Mockito.any(), - Mockito.any(), - Mockito.any(), - Mockito.any() + any(), + any(), + any(), + any(), + eq(false) ) ) .thenReturn(Mockito.mock(TransferObserver::class.java)) @@ -113,7 +119,8 @@ class AWSS3StorageUploadInputStreamOperationTest { "", "/image", ServerSideEncryption.NONE, - mutableMapOf() + mutableMapOf(), + false ) inputStreamOperation = AWSS3StorageUploadInputStreamOperation( storageService, @@ -138,10 +145,11 @@ class AWSS3StorageUploadInputStreamOperationTest { ) inputStreamOperation.start() Mockito.verify(storageService).uploadInputStream( - Mockito.eq(inputStreamOperation.transferId), - Mockito.eq(expectedKey), - Mockito.eq(tempInputStream), - Mockito.any(ObjectMetadata::class.java) + eq(inputStreamOperation.transferId), + eq(expectedKey), + eq(tempInputStream), + any(ObjectMetadata::class.java), + eq(false) ) } @@ -153,10 +161,11 @@ class AWSS3StorageUploadInputStreamOperationTest { coEvery { authCredentialsProvider.getIdentityId() } returns "abc" Mockito.`when`( storageService.uploadInputStream( - Mockito.any(), - Mockito.any(), - Mockito.any(), - Mockito.any() + any(), + any(), + any(), + any(), + eq(false) ) ).thenReturn(Mockito.mock(TransferObserver::class.java)) val request = AWSS3StorageUploadRequest( @@ -166,7 +175,8 @@ class AWSS3StorageUploadInputStreamOperationTest { "", "/image", ServerSideEncryption.NONE, - mutableMapOf() + mutableMapOf(), + false ) inputStreamOperation = AWSS3StorageUploadInputStreamOperation( storageService, @@ -191,10 +201,11 @@ class AWSS3StorageUploadInputStreamOperationTest { ) inputStreamOperation.start() Mockito.verify(storageService).uploadInputStream( - Mockito.eq(inputStreamOperation.transferId), - Mockito.eq(expectedKey), - Mockito.eq(tempInputStream), - Mockito.any(ObjectMetadata::class.java) + eq(inputStreamOperation.transferId), + eq(expectedKey), + eq(tempInputStream), + any(ObjectMetadata::class.java), + eq(false) ) } } diff --git a/aws-storage-s3/src/test/java/com/amplifyframework/storage/s3/transfer/worker/AbortMultiPartUploadWorkerTest.kt b/aws-storage-s3/src/test/java/com/amplifyframework/storage/s3/transfer/worker/AbortMultiPartUploadWorkerTest.kt index 510a3b98a3..45fe031cff 100644 --- a/aws-storage-s3/src/test/java/com/amplifyframework/storage/s3/transfer/worker/AbortMultiPartUploadWorkerTest.kt +++ b/aws-storage-s3/src/test/java/com/amplifyframework/storage/s3/transfer/worker/AbortMultiPartUploadWorkerTest.kt @@ -22,6 +22,7 @@ import androidx.work.workDataOf import aws.sdk.kotlin.services.s3.S3Client import aws.sdk.kotlin.services.s3.model.AbortMultipartUploadRequest import aws.sdk.kotlin.services.s3.model.AbortMultipartUploadResponse +import aws.sdk.kotlin.services.s3.withConfig import com.amplifyframework.storage.TransferState import com.amplifyframework.storage.s3.transfer.TransferDB import com.amplifyframework.storage.s3.transfer.TransferRecord @@ -29,10 +30,13 @@ import com.amplifyframework.storage.s3.transfer.TransferStatusUpdater import io.mockk.coEvery import io.mockk.every import io.mockk.mockk +import io.mockk.mockkStatic +import io.mockk.unmockkStatic import io.mockk.verify import java.util.UUID import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.runTest +import org.junit.After import org.junit.Assert.assertEquals import org.junit.Before import org.junit.Test @@ -52,12 +56,19 @@ internal class AbortMultiPartUploadWorkerTest { fun setup() { context = ApplicationProvider.getApplicationContext() workerParameters = mockk(WorkerParameters::class.java.name) - s3Client = mockk(S3Client::class.java.name) + s3Client = mockk(relaxed = true, relaxUnitFun = true) + mockkStatic(S3Client::withConfig) transferDB = mockk(TransferDB::class.java.name) transferStatusUpdater = mockk(TransferStatusUpdater::class.java.name) every { workerParameters.inputData }.answers { workDataOf(BaseTransferWorker.TRANSFER_RECORD_ID to 1) } every { workerParameters.runAttemptCount }.answers { 1 } every { workerParameters.taskExecutor }.answers { ImmediateTaskExecutor() } + every { s3Client.withConfig(any()) } returns s3Client + } + + @After + fun tearDown() { + unmockkStatic(S3Client::withConfig) } @Test diff --git a/aws-storage-s3/src/test/java/com/amplifyframework/storage/s3/transfer/worker/DownloadWorkerTest.kt b/aws-storage-s3/src/test/java/com/amplifyframework/storage/s3/transfer/worker/DownloadWorkerTest.kt index 63f49d0250..9d7ad8114c 100644 --- a/aws-storage-s3/src/test/java/com/amplifyframework/storage/s3/transfer/worker/DownloadWorkerTest.kt +++ b/aws-storage-s3/src/test/java/com/amplifyframework/storage/s3/transfer/worker/DownloadWorkerTest.kt @@ -21,24 +21,26 @@ import androidx.work.WorkerParameters import androidx.work.workDataOf import aws.sdk.kotlin.services.s3.S3Client import aws.sdk.kotlin.services.s3.model.GetObjectResponse +import aws.sdk.kotlin.services.s3.withConfig import aws.smithy.kotlin.runtime.content.ByteStream -import aws.smithy.kotlin.runtime.io.SdkByteReadChannel -import aws.smithy.kotlin.runtime.io.readChannel -import aws.smithy.kotlin.runtime.util.InternalApi +import aws.smithy.kotlin.runtime.content.fromFile import com.amplifyframework.storage.TransferState +import com.amplifyframework.storage.s3.transfer.DownloadProgressListenerInterceptor import com.amplifyframework.storage.s3.transfer.TransferDB import com.amplifyframework.storage.s3.transfer.TransferRecord import com.amplifyframework.storage.s3.transfer.TransferStatusUpdater import io.mockk.coEvery import io.mockk.every import io.mockk.mockk +import io.mockk.mockkStatic +import io.mockk.unmockkStatic import io.mockk.verify import java.io.File import java.io.RandomAccessFile -import java.nio.ByteBuffer import java.util.UUID import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.runTest +import org.junit.After import org.junit.Assert.assertEquals import org.junit.Before import org.junit.Test @@ -53,17 +55,26 @@ internal class DownloadWorkerTest { private lateinit var transferDB: TransferDB private lateinit var transferStatusUpdater: TransferStatusUpdater private lateinit var workerParameters: WorkerParameters + private lateinit var downloadInterceptor: DownloadProgressListenerInterceptor @Before fun setup() { context = ApplicationProvider.getApplicationContext() workerParameters = mockk(WorkerParameters::class.java.name) s3Client = mockk(relaxed = true, relaxUnitFun = true) + mockkStatic(S3Client::withConfig) + downloadInterceptor = mockk(relaxed = true, relaxUnitFun = true) transferDB = mockk(TransferDB::class.java.name) transferStatusUpdater = mockk(TransferStatusUpdater::class.java.name) every { workerParameters.inputData }.answers { workDataOf(BaseTransferWorker.TRANSFER_RECORD_ID to 1) } every { workerParameters.runAttemptCount }.answers { 1 } every { workerParameters.taskExecutor }.answers { ImmediateTaskExecutor() } + every { s3Client.withConfig(any()) } returns s3Client + } + + @After + fun tearDown() { + unmockkStatic(S3Client::withConfig) } @Test @@ -78,8 +89,9 @@ internal class DownloadWorkerTest { val response = GetObjectResponse { contentLength = 10 - body = ByteStream.readAsOneShotStream(createFile(10)) + body = ByteStream.fromFile(createFile(10)) } + coEvery { s3Client.getObject( any(), @@ -145,50 +157,4 @@ internal class DownloadWorkerTest { file.deleteOnExit() return file } - - @OptIn(InternalApi::class) - private fun ByteStream.Companion.readAsOneShotStream( - file: File, - start: Long = 0, - length: Long = file.length(), - ): ByteStream { - return object : ByteStream.OneShotStream() { - override val contentLength: Long = length - override fun readFrom(): SdkByteReadChannel { - val oneShotStream = file.readChannel(start, start + length - 1) - return object : SdkByteReadChannel { - override val availableForRead: Int - get() = oneShotStream.availableForRead - override val isClosedForRead: Boolean - get() = oneShotStream.isClosedForRead - override val isClosedForWrite: Boolean - get() = oneShotStream.isClosedForWrite - - override suspend fun awaitContent() { - oneShotStream.awaitContent() - } - - override fun cancel(cause: Throwable?): Boolean { - return oneShotStream.cancel(cause) - } - - override suspend fun readAvailable(sink: ByteBuffer): Int { - return oneShotStream.readAvailable(sink) - } - - override suspend fun readAvailable(sink: ByteArray, offset: Int, length: Int): Int { - return oneShotStream.readAvailable(sink, offset, length) - } - - override suspend fun readFully(sink: ByteArray, offset: Int, length: Int) { - return oneShotStream.readFully(sink, offset, length) - } - - override suspend fun readRemaining(limit: Int): ByteArray { - return readRemaining(limit) - } - } - } - } - } } diff --git a/aws-storage-s3/src/test/java/com/amplifyframework/storage/s3/transfer/worker/InitiateMultiPartUploadTransferWorkerTest.kt b/aws-storage-s3/src/test/java/com/amplifyframework/storage/s3/transfer/worker/InitiateMultiPartUploadTransferWorkerTest.kt index 1ce988a8f3..ea423d392e 100644 --- a/aws-storage-s3/src/test/java/com/amplifyframework/storage/s3/transfer/worker/InitiateMultiPartUploadTransferWorkerTest.kt +++ b/aws-storage-s3/src/test/java/com/amplifyframework/storage/s3/transfer/worker/InitiateMultiPartUploadTransferWorkerTest.kt @@ -21,6 +21,7 @@ import androidx.work.WorkerParameters import androidx.work.workDataOf import aws.sdk.kotlin.services.s3.S3Client import aws.sdk.kotlin.services.s3.model.CreateMultipartUploadResponse +import aws.sdk.kotlin.services.s3.withConfig import com.amplifyframework.storage.TransferState import com.amplifyframework.storage.s3.transfer.TransferDB import com.amplifyframework.storage.s3.transfer.TransferRecord @@ -28,10 +29,15 @@ import com.amplifyframework.storage.s3.transfer.TransferStatusUpdater import io.mockk.coEvery import io.mockk.every import io.mockk.mockk +import io.mockk.mockkStatic +import io.mockk.unmockkStatic import io.mockk.verify +import java.io.File +import java.io.RandomAccessFile import java.util.UUID import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.runTest +import org.junit.After import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -51,20 +57,29 @@ internal class InitiateMultiPartUploadTransferWorkerTest { context = ApplicationProvider.getApplicationContext() workerParameters = mockk(WorkerParameters::class.java.name) s3Client = mockk(relaxed = true) + mockkStatic(S3Client::withConfig) transferDB = mockk(TransferDB::class.java.name) transferStatusUpdater = mockk(TransferStatusUpdater::class.java.name) every { workerParameters.inputData }.answers { workDataOf(BaseTransferWorker.TRANSFER_RECORD_ID to 1) } every { workerParameters.runAttemptCount }.answers { 1 } every { workerParameters.taskExecutor }.answers { ImmediateTaskExecutor() } + every { s3Client.withConfig(any()) } returns s3Client + } + + @After + fun tearDown() { + unmockkStatic(S3Client::withConfig) } @Test fun testPerformWorkOnSuccess() = runTest { + val file = createFile(1) val transferRecord = TransferRecord( 1, UUID.randomUUID().toString(), bucketName = "bucket_name", - key = "key" + key = "key", + file = file.path ) val createUploadResponse = CreateMultipartUploadResponse { uploadId = "upload_id" @@ -91,11 +106,13 @@ internal class InitiateMultiPartUploadTransferWorkerTest { @Test fun testPerformWorkOnError() = runTest { + val file = createFile(1) val transferRecord = TransferRecord( 1, UUID.randomUUID().toString(), bucketName = "bucket_name", - key = "key" + key = "key", + file = file.path ) coEvery { s3Client.createMultipartUpload(any()) }.answers { @@ -119,4 +136,14 @@ internal class InitiateMultiPartUploadTransferWorkerTest { val output = workDataOf(BaseTransferWorker.OUTPUT_TRANSFER_RECORD_ID to 1) assert(ListenableWorker.Result.failure(output) == result) } + + private fun createFile(size: Int): File { + val file = File((System.getProperty("java.io.tmpdir")?.plus(File.separator)) + "file") + file.createNewFile() + val raf = RandomAccessFile(file, "rw") + raf.setLength((size * 1024 * 1024).toLong()) + raf.close() + file.deleteOnExit() + return file + } } diff --git a/core/src/main/java/com/amplifyframework/storage/options/StorageDownloadFileOptions.java b/core/src/main/java/com/amplifyframework/storage/options/StorageDownloadFileOptions.java index 28eb8e818d..0d7869c8f0 100644 --- a/core/src/main/java/com/amplifyframework/storage/options/StorageDownloadFileOptions.java +++ b/core/src/main/java/com/amplifyframework/storage/options/StorageDownloadFileOptions.java @@ -23,7 +23,6 @@ * Options to specify attributes of get API invocation. */ public class StorageDownloadFileOptions extends StorageOptions { - /** * Constructs a StorageDownloadFileOptions instance with the * attributes from builder instance. diff --git a/settings.gradle.kts b/settings.gradle.kts index 2c806d4cf7..52cc4cead2 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -85,7 +85,7 @@ dependencyResolutionManagement { // AWS val awsKotlinSdk = "awsKotlinSdk" - version(awsKotlinSdk, "0.17.12-beta") + version(awsKotlinSdk, "0.20.3-beta") library("aws-sdk-core", "com.amazonaws:aws-android-sdk-core:2.62.2") From e75112b7a4ce0a20dbdb864da2c2492c4f0c1fed Mon Sep 17 00:00:00 2001 From: Saijad Dhuka Date: Mon, 27 Feb 2023 09:00:04 -0600 Subject: [PATCH 02/14] fix tests --- .../storage/s3/AWSS3StorageDownloadTest.java | 2 +- .../storage/s3/AWSS3StorageUploadTest.java | 21 ++++++++++++------- .../ProgressListenerHttpInterceptor.kt | 2 ++ .../worker/AbortMultiPartUploadWorkerTest.kt | 7 +++++-- 4 files changed, 22 insertions(+), 10 deletions(-) diff --git a/aws-storage-s3/src/androidTest/java/com/amplifyframework/storage/s3/AWSS3StorageDownloadTest.java b/aws-storage-s3/src/androidTest/java/com/amplifyframework/storage/s3/AWSS3StorageDownloadTest.java index 8191f7dbc0..94bfca5c21 100644 --- a/aws-storage-s3/src/androidTest/java/com/amplifyframework/storage/s3/AWSS3StorageDownloadTest.java +++ b/aws-storage-s3/src/androidTest/java/com/amplifyframework/storage/s3/AWSS3StorageDownloadTest.java @@ -65,7 +65,7 @@ public final class AWSS3StorageDownloadTest { private static final StorageAccessLevel TESTING_ACCESS_LEVEL = StorageAccessLevel.PUBLIC; private static final long LARGE_FILE_SIZE = 10 * 1024 * 1024L; // 10 MB - private static final long SMALL_FILE_SIZE = 4 * 1024 * 1024L; + private static final long SMALL_FILE_SIZE = 100L; private static final String LARGE_FILE_NAME = "large-" + System.currentTimeMillis(); private static final String SMALL_FILE_NAME = "small-" + System.currentTimeMillis(); diff --git a/aws-storage-s3/src/androidTest/java/com/amplifyframework/storage/s3/AWSS3StorageUploadTest.java b/aws-storage-s3/src/androidTest/java/com/amplifyframework/storage/s3/AWSS3StorageUploadTest.java index cf85592aea..28a7793ea1 100644 --- a/aws-storage-s3/src/androidTest/java/com/amplifyframework/storage/s3/AWSS3StorageUploadTest.java +++ b/aws-storage-s3/src/androidTest/java/com/amplifyframework/storage/s3/AWSS3StorageUploadTest.java @@ -392,12 +392,18 @@ public void testUploadInputStreamGetTransferOnPause() throws Exception { */ @Test(expected = StorageException.class) public void testUploadSmallFileWithAccelerationEnabled() throws Exception { - File uploadFile = new RandomTempFile(SMALL_FILE_SIZE); - String fileName = uploadFile.getName(); - AWSS3StorageUploadFileOptions awss3StorageUploadFileOptions = - AWSS3StorageUploadFileOptions.builder().setUseAccelerateEndpoint(true).build(); - synchronousStorage.uploadFile(fileName, uploadFile, - awss3StorageUploadFileOptions); + try { + File uploadFile = new RandomTempFile(SMALL_FILE_SIZE); + String fileName = uploadFile.getName(); + AWSS3StorageUploadFileOptions awss3StorageUploadFileOptions = + AWSS3StorageUploadFileOptions.builder().setUseAccelerateEndpoint(true).build(); + synchronousStorage.uploadFile(fileName, uploadFile, + awss3StorageUploadFileOptions); + } catch (Exception e) { + assertEquals(e.getCause().getCause().getMessage(), + "S3 Transfer Acceleration is disabled on this bucket"); + throw e; + } } /** @@ -405,7 +411,7 @@ public void testUploadSmallFileWithAccelerationEnabled() throws Exception { * * @throws Exception if upload fails */ - @Test + @Test(expected = StorageException.class) public void testUploadLargeFileWithAccelerationEnabled() throws Exception { try { File uploadFile = new RandomTempFile(LARGE_FILE_SIZE); @@ -417,6 +423,7 @@ public void testUploadLargeFileWithAccelerationEnabled() throws Exception { } catch (StorageException exception) { assertEquals(exception.getCause().getCause().getMessage(), "S3 Transfer Acceleration is disabled on this bucket"); + throw exception; } } diff --git a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/ProgressListenerHttpInterceptor.kt b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/ProgressListenerHttpInterceptor.kt index a66c6a2038..82206f3359 100644 --- a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/ProgressListenerHttpInterceptor.kt +++ b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/ProgressListenerHttpInterceptor.kt @@ -82,6 +82,8 @@ internal open class ProgressListenerInterceptor( private val progressListener: ProgressListener ) : HttpBody.ChannelContent() { val delegate = httpBody.readFrom() + override val contentLength: Long? + get() = httpBody.contentLength override fun readFrom(): SdkByteReadChannel { return object : SdkByteReadChannel by delegate { override val availableForRead: Int diff --git a/aws-storage-s3/src/test/java/com/amplifyframework/storage/s3/transfer/worker/AbortMultiPartUploadWorkerTest.kt b/aws-storage-s3/src/test/java/com/amplifyframework/storage/s3/transfer/worker/AbortMultiPartUploadWorkerTest.kt index 45fe031cff..0bee6763b4 100644 --- a/aws-storage-s3/src/test/java/com/amplifyframework/storage/s3/transfer/worker/AbortMultiPartUploadWorkerTest.kt +++ b/aws-storage-s3/src/test/java/com/amplifyframework/storage/s3/transfer/worker/AbortMultiPartUploadWorkerTest.kt @@ -31,6 +31,7 @@ import io.mockk.coEvery import io.mockk.every import io.mockk.mockk import io.mockk.mockkStatic +import io.mockk.spyk import io.mockk.unmockkStatic import io.mockk.verify import java.util.UUID @@ -54,16 +55,17 @@ internal class AbortMultiPartUploadWorkerTest { @Before fun setup() { + context = ApplicationProvider.getApplicationContext() workerParameters = mockk(WorkerParameters::class.java.name) - s3Client = mockk(relaxed = true, relaxUnitFun = true) + s3Client = spyk(recordPrivateCalls = true) mockkStatic(S3Client::withConfig) transferDB = mockk(TransferDB::class.java.name) transferStatusUpdater = mockk(TransferStatusUpdater::class.java.name) every { workerParameters.inputData }.answers { workDataOf(BaseTransferWorker.TRANSFER_RECORD_ID to 1) } every { workerParameters.runAttemptCount }.answers { 1 } every { workerParameters.taskExecutor }.answers { ImmediateTaskExecutor() } - every { s3Client.withConfig(any()) } returns s3Client + every { any().withConfig(any()) }.answers { s3Client } } @After @@ -99,6 +101,7 @@ internal class AbortMultiPartUploadWorkerTest { val expectedResult = ListenableWorker.Result.success(workDataOf(BaseTransferWorker.OUTPUT_TRANSFER_RECORD_ID to 1)) verify(exactly = 1) { transferStatusUpdater.updateTransferState(1, TransferState.FAILED) } + verify(exactly = 1) { any().withConfig(any())} assertEquals(expectedResult, result) } From 0d23d16a6d88526fcad6e352ed2b1e9a0c3727e9 Mon Sep 17 00:00:00 2001 From: Saijad Dhuka Date: Fri, 3 Mar 2023 14:35:47 -0600 Subject: [PATCH 03/14] updated version and testes --- .../auth/cognito/AWSCognitoAuthService.kt | 2 +- .../auth/cognito/AWSEndpointProvider.kt | 4 +- .../storage/s3/AWSS3StorageDownloadTest.java | 11 ++--- .../storage/s3/AWSS3StorageUploadTest.java | 44 +++++++------------ .../worker/AbortMultiPartUploadWorkerTest.kt | 2 +- settings.gradle.kts | 2 +- 6 files changed, 25 insertions(+), 40 deletions(-) diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/AWSCognitoAuthService.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/AWSCognitoAuthService.kt index cc6c8bf9b4..f5defb6ac5 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/AWSCognitoAuthService.kt +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/AWSCognitoAuthService.kt @@ -17,7 +17,7 @@ package com.amplifyframework.auth.cognito import aws.sdk.kotlin.services.cognitoidentity.CognitoIdentityClient import aws.sdk.kotlin.services.cognitoidentityprovider.CognitoIdentityProviderClient -import aws.smithy.kotlin.runtime.http.endpoints.Endpoint +import aws.smithy.kotlin.runtime.client.endpoints.Endpoint import com.amplifyframework.statemachine.codegen.data.AuthConfiguration interface AWSCognitoAuthService { diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/AWSEndpointProvider.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/AWSEndpointProvider.kt index 8f634e4c48..3e6290ca3b 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/AWSEndpointProvider.kt +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/AWSEndpointProvider.kt @@ -16,10 +16,10 @@ package com.amplifyframework.auth.cognito import aws.sdk.kotlin.services.cognitoidentityprovider.endpoints.EndpointParameters import aws.sdk.kotlin.services.cognitoidentityprovider.endpoints.EndpointProvider -import aws.smithy.kotlin.runtime.http.endpoints.Endpoint +import aws.smithy.kotlin.runtime.client.endpoints.Endpoint internal class AWSEndpointProvider(val endpoint: Endpoint) : EndpointProvider { override suspend fun resolveEndpoint(params: EndpointParameters): Endpoint { - return Endpoint(endpoint.uri) + return Endpoint(uri = endpoint.uri) } } diff --git a/aws-storage-s3/src/androidTest/java/com/amplifyframework/storage/s3/AWSS3StorageDownloadTest.java b/aws-storage-s3/src/androidTest/java/com/amplifyframework/storage/s3/AWSS3StorageDownloadTest.java index 94bfca5c21..c6ae188f1a 100644 --- a/aws-storage-s3/src/androidTest/java/com/amplifyframework/storage/s3/AWSS3StorageDownloadTest.java +++ b/aws-storage-s3/src/androidTest/java/com/amplifyframework/storage/s3/AWSS3StorageDownloadTest.java @@ -327,13 +327,8 @@ public void testGetTransferOnPause() throws Exception { */ @Test public void testDownloadLargeFileWithAccelerationEnabled() throws Exception { - try { - AWSS3StorageDownloadFileOptions awsS3Options = - AWSS3StorageDownloadFileOptions.builder().setUseAccelerateEndpoint(true).build(); - synchronousStorage.downloadFile(LARGE_FILE_NAME, downloadFile, awsS3Options, EXTENDED_TIMEOUT_MS); - } catch (Exception exception) { - assertEquals(exception.getCause().getCause().getMessage(), - "S3 Transfer Acceleration is disabled on this bucket"); - } + AWSS3StorageDownloadFileOptions awsS3Options = + AWSS3StorageDownloadFileOptions.builder().setUseAccelerateEndpoint(true).build(); + synchronousStorage.downloadFile(LARGE_FILE_NAME, downloadFile, awsS3Options, EXTENDED_TIMEOUT_MS); } } diff --git a/aws-storage-s3/src/androidTest/java/com/amplifyframework/storage/s3/AWSS3StorageUploadTest.java b/aws-storage-s3/src/androidTest/java/com/amplifyframework/storage/s3/AWSS3StorageUploadTest.java index 28a7793ea1..f2b27c0577 100644 --- a/aws-storage-s3/src/androidTest/java/com/amplifyframework/storage/s3/AWSS3StorageUploadTest.java +++ b/aws-storage-s3/src/androidTest/java/com/amplifyframework/storage/s3/AWSS3StorageUploadTest.java @@ -136,7 +136,7 @@ public void testUploadSmallFile() throws Exception { */ @Test public void testUploadSmallFileStream() throws Exception { - File uploadFile = new RandomTempFile(4 * 1024 * 1024); + File uploadFile = new RandomTempFile(SMALL_FILE_SIZE); String fileName = uploadFile.getName(); StorageUploadInputStreamOptions options = StorageUploadInputStreamOptions.builder() .accessLevel(TESTING_ACCESS_LEVEL) @@ -153,6 +153,8 @@ public void testUploadSmallFileStream() throws Exception { public void testUploadLargeFile() throws Exception { File uploadFile = new RandomTempFile(LARGE_FILE_SIZE); String fileName = uploadFile.getName(); + AWSS3StorageUploadFileOptions options = + AWSS3StorageUploadFileOptions.builder().setUseAccelerateEndpoint(true).build(); synchronousStorage.uploadFile(fileName, uploadFile, options, EXTENDED_TIMEOUT_MS); } @@ -390,20 +392,14 @@ public void testUploadInputStreamGetTransferOnPause() throws Exception { * * @throws Exception if upload fails */ - @Test(expected = StorageException.class) + @Test public void testUploadSmallFileWithAccelerationEnabled() throws Exception { - try { - File uploadFile = new RandomTempFile(SMALL_FILE_SIZE); - String fileName = uploadFile.getName(); - AWSS3StorageUploadFileOptions awss3StorageUploadFileOptions = - AWSS3StorageUploadFileOptions.builder().setUseAccelerateEndpoint(true).build(); - synchronousStorage.uploadFile(fileName, uploadFile, - awss3StorageUploadFileOptions); - } catch (Exception e) { - assertEquals(e.getCause().getCause().getMessage(), - "S3 Transfer Acceleration is disabled on this bucket"); - throw e; - } + File uploadFile = new RandomTempFile(SMALL_FILE_SIZE); + String fileName = uploadFile.getName(); + AWSS3StorageUploadFileOptions awss3StorageUploadFileOptions = + AWSS3StorageUploadFileOptions.builder().setUseAccelerateEndpoint(true).build(); + synchronousStorage.uploadFile(fileName, uploadFile, + awss3StorageUploadFileOptions); } /** @@ -411,20 +407,14 @@ public void testUploadSmallFileWithAccelerationEnabled() throws Exception { * * @throws Exception if upload fails */ - @Test(expected = StorageException.class) + @Test public void testUploadLargeFileWithAccelerationEnabled() throws Exception { - try { - File uploadFile = new RandomTempFile(LARGE_FILE_SIZE); - String fileName = uploadFile.getName(); - AWSS3StorageUploadFileOptions awss3StorageUploadFileOptions = - AWSS3StorageUploadFileOptions.builder().setUseAccelerateEndpoint(true).build(); - synchronousStorage.uploadFile(fileName, uploadFile, - awss3StorageUploadFileOptions); - } catch (StorageException exception) { - assertEquals(exception.getCause().getCause().getMessage(), - "S3 Transfer Acceleration is disabled on this bucket"); - throw exception; - } + File uploadFile = new RandomTempFile(LARGE_FILE_SIZE); + String fileName = uploadFile.getName(); + AWSS3StorageUploadFileOptions awss3StorageUploadFileOptions = + AWSS3StorageUploadFileOptions.builder().setUseAccelerateEndpoint(true).build(); + synchronousStorage.uploadFile(fileName, uploadFile, + awss3StorageUploadFileOptions); } } diff --git a/aws-storage-s3/src/test/java/com/amplifyframework/storage/s3/transfer/worker/AbortMultiPartUploadWorkerTest.kt b/aws-storage-s3/src/test/java/com/amplifyframework/storage/s3/transfer/worker/AbortMultiPartUploadWorkerTest.kt index 0bee6763b4..c3097d71c0 100644 --- a/aws-storage-s3/src/test/java/com/amplifyframework/storage/s3/transfer/worker/AbortMultiPartUploadWorkerTest.kt +++ b/aws-storage-s3/src/test/java/com/amplifyframework/storage/s3/transfer/worker/AbortMultiPartUploadWorkerTest.kt @@ -101,7 +101,7 @@ internal class AbortMultiPartUploadWorkerTest { val expectedResult = ListenableWorker.Result.success(workDataOf(BaseTransferWorker.OUTPUT_TRANSFER_RECORD_ID to 1)) verify(exactly = 1) { transferStatusUpdater.updateTransferState(1, TransferState.FAILED) } - verify(exactly = 1) { any().withConfig(any())} + verify(exactly = 1) { any().withConfig(any()) } assertEquals(expectedResult, result) } diff --git a/settings.gradle.kts b/settings.gradle.kts index 52cc4cead2..be52503bfa 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -85,7 +85,7 @@ dependencyResolutionManagement { // AWS val awsKotlinSdk = "awsKotlinSdk" - version(awsKotlinSdk, "0.20.3-beta") + version(awsKotlinSdk, "0.21.1-beta") library("aws-sdk-core", "com.amazonaws:aws-android-sdk-core:2.62.2") From c020ef59ad886a8d28d202e23c20b6472e188aed Mon Sep 17 00:00:00 2001 From: Saijad Dhuka Date: Fri, 3 Mar 2023 15:50:36 -0600 Subject: [PATCH 04/14] fix breaking prediction changes --- .../maplibre/http/AWSRequestSignerInterceptor.kt | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/maplibre-adapter/src/main/java/com/amplifyframework/geo/maplibre/http/AWSRequestSignerInterceptor.kt b/maplibre-adapter/src/main/java/com/amplifyframework/geo/maplibre/http/AWSRequestSignerInterceptor.kt index 92dc711753..da17f1dbcd 100644 --- a/maplibre-adapter/src/main/java/com/amplifyframework/geo/maplibre/http/AWSRequestSignerInterceptor.kt +++ b/maplibre-adapter/src/main/java/com/amplifyframework/geo/maplibre/http/AWSRequestSignerInterceptor.kt @@ -19,17 +19,20 @@ import aws.smithy.kotlin.runtime.auth.awssigning.AwsSigningConfig import aws.smithy.kotlin.runtime.auth.awssigning.DefaultAwsSigner import aws.smithy.kotlin.runtime.http.Headers as AwsHeaders import aws.smithy.kotlin.runtime.http.HttpMethod -import aws.smithy.kotlin.runtime.http.Protocol -import aws.smithy.kotlin.runtime.http.QueryParameters -import aws.smithy.kotlin.runtime.http.Url import aws.smithy.kotlin.runtime.http.content.ByteArrayContent import aws.smithy.kotlin.runtime.http.request.HttpRequest +import aws.smithy.kotlin.runtime.net.Host +import aws.smithy.kotlin.runtime.net.QueryParameters +import aws.smithy.kotlin.runtime.net.Scheme +import aws.smithy.kotlin.runtime.net.Url +import aws.smithy.kotlin.runtime.net.toUrlString import com.amplifyframework.geo.location.AWSLocationGeoPlugin import java.io.ByteArrayOutputStream import java.io.IOException import kotlinx.coroutines.runBlocking import okhttp3.HttpUrl import okhttp3.Interceptor +import okhttp3.Protocol import okhttp3.Request import okhttp3.RequestBody import okhttp3.Response @@ -71,7 +74,7 @@ internal class AWSRequestSignerInterceptor( private fun Request.Builder.copyFrom(request: HttpRequest): Request.Builder { val urlBuilder = HttpUrl.Builder() - .host(request.url.host) + .host(request.url.host.toUrlString()) .scheme(request.url.scheme.protocolName) .encodedPath(request.url.encodedPath) @@ -106,8 +109,8 @@ internal class AWSRequestSignerInterceptor( } val httpUrl = Url( - scheme = Protocol.parse(url.scheme), - host = url.host, + scheme = Scheme(url.scheme, url.port), + host = Host.parse(url.host), port = url.port, path = url.encodedPath, parameters = QueryParameters.invoke { From a62acc04d4c13e641db7979f40d790f9de81e8a4 Mon Sep 17 00:00:00 2001 From: Saijad Dhuka Date: Fri, 3 Mar 2023 15:59:51 -0600 Subject: [PATCH 05/14] fix checkstyle --- .../amplifyframework/storage/s3/AWSS3StorageDownloadTest.java | 1 - .../com/amplifyframework/storage/s3/AWSS3StorageUploadTest.java | 2 -- 2 files changed, 3 deletions(-) diff --git a/aws-storage-s3/src/androidTest/java/com/amplifyframework/storage/s3/AWSS3StorageDownloadTest.java b/aws-storage-s3/src/androidTest/java/com/amplifyframework/storage/s3/AWSS3StorageDownloadTest.java index c6ae188f1a..1dc99cc184 100644 --- a/aws-storage-s3/src/androidTest/java/com/amplifyframework/storage/s3/AWSS3StorageDownloadTest.java +++ b/aws-storage-s3/src/androidTest/java/com/amplifyframework/storage/s3/AWSS3StorageDownloadTest.java @@ -53,7 +53,6 @@ import java.util.concurrent.atomic.AtomicReference; import static androidx.test.core.app.ApplicationProvider.getApplicationContext; -import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; diff --git a/aws-storage-s3/src/androidTest/java/com/amplifyframework/storage/s3/AWSS3StorageUploadTest.java b/aws-storage-s3/src/androidTest/java/com/amplifyframework/storage/s3/AWSS3StorageUploadTest.java index f2b27c0577..9c61bf7009 100644 --- a/aws-storage-s3/src/androidTest/java/com/amplifyframework/storage/s3/AWSS3StorageUploadTest.java +++ b/aws-storage-s3/src/androidTest/java/com/amplifyframework/storage/s3/AWSS3StorageUploadTest.java @@ -28,7 +28,6 @@ import com.amplifyframework.storage.StorageAccessLevel; import com.amplifyframework.storage.StorageCategory; import com.amplifyframework.storage.StorageChannelEventName; -import com.amplifyframework.storage.StorageException; import com.amplifyframework.storage.TransferState; import com.amplifyframework.storage.operation.StorageUploadFileOperation; import com.amplifyframework.storage.operation.StorageUploadInputStreamOperation; @@ -55,7 +54,6 @@ import java.util.concurrent.atomic.AtomicReference; import static androidx.test.core.app.ApplicationProvider.getApplicationContext; -import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; From bb8e5a8baebd57208a7667fff5bf572fb9220d27 Mon Sep 17 00:00:00 2001 From: Saijad Dhuka Date: Mon, 6 Mar 2023 09:56:35 -0600 Subject: [PATCH 06/14] upgrade okhttp --- settings.gradle.kts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/settings.gradle.kts b/settings.gradle.kts index be52503bfa..fc89d64878 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -58,7 +58,7 @@ dependencyResolutionManagement { library("androidx-test-workmanager", "androidx.work:work-testing:2.7.1") // Misc - library("mockwebserver", "com.squareup.okhttp3:mockwebserver:5.0.0-alpha.9") + library("mockwebserver", "com.squareup.okhttp3:mockwebserver:5.0.0-alpha.11") library("robolectric", "org.robolectric:robolectric:4.7") library("jsonassert", "org.skyscreamer:jsonassert:1.5.0") library("json", "org.json:json:20210307") @@ -127,7 +127,7 @@ dependencyResolutionManagement { // Misc library("oauth2", "com.google.auth:google-auth-library-oauth2-http:0.26.0") - library("okhttp", "com.squareup.okhttp3:okhttp:5.0.0-alpha.9") + library("okhttp", "com.squareup.okhttp3:okhttp:5.0.0-alpha.11") library("gson", "com.google.code.gson:gson:2.8.9") library("tensorflow", "org.tensorflow:tensorflow-lite:2.0.0") library("uuidgen", "com.fasterxml.uuid:java-uuid-generator:4.0.1") From 8f4f8267b99cfb4d5334a72cc9fd8417f7d51aed Mon Sep 17 00:00:00 2001 From: Saijad Dhuka Date: Mon, 6 Mar 2023 10:51:57 -0600 Subject: [PATCH 07/14] upgrade signing package --- .../amplifyframework/api/aws/auth/IamRequestDecorator.java | 6 ++++-- settings.gradle.kts | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/aws-api/src/main/java/com/amplifyframework/api/aws/auth/IamRequestDecorator.java b/aws-api/src/main/java/com/amplifyframework/api/aws/auth/IamRequestDecorator.java index 0381dc33b5..c5431aecc3 100644 --- a/aws-api/src/main/java/com/amplifyframework/api/aws/auth/IamRequestDecorator.java +++ b/aws-api/src/main/java/com/amplifyframework/api/aws/auth/IamRequestDecorator.java @@ -18,6 +18,9 @@ import com.amplifyframework.api.ApiException.ApiAuthException; import com.amplifyframework.api.aws.sigv4.AWS4Signer; +import aws.smithy.kotlin.runtime.http.DeferredHeaders; +import aws.smithy.kotlin.runtime.http.request.HttpRequestKt; +import aws.smithy.kotlin.runtime.net.Url; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.List; @@ -26,7 +29,6 @@ import aws.smithy.kotlin.runtime.auth.awscredentials.CredentialsProvider; import aws.smithy.kotlin.runtime.http.Headers; import aws.smithy.kotlin.runtime.http.HttpMethod; -import aws.smithy.kotlin.runtime.http.Url; import aws.smithy.kotlin.runtime.http.content.ByteArrayContent; import aws.smithy.kotlin.runtime.http.request.HttpRequest; import okhttp3.MediaType; @@ -79,7 +81,7 @@ public final okhttp3.Request decorate(okhttp3.Request req) throws ApiAuthExcepti return null; }); - HttpRequest req2 = new HttpRequest(method, url, headers, body2); + HttpRequest req2 = HttpRequestKt.HttpRequest(method, url, headers, body2, DeferredHeaders.Companion.getEmpty()); HttpRequest request = v4Signer.signBlocking(req2, credentialsProvider, serviceName).getOutput(); diff --git a/settings.gradle.kts b/settings.gradle.kts index fc89d64878..bfe7ffaec1 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -91,7 +91,7 @@ dependencyResolutionManagement { library("aws-credentials", "aws.smithy.kotlin:aws-credentials:0.12.6") library("aws-ktor", "aws.smithy.kotlin:http-client-engine-ktor:0.7.7") - library("aws-signing", "aws.smithy.kotlin:aws-signing-default:0.12.6") + library("aws-signing", "aws.smithy.kotlin:aws-signing-default:0.16.2") library("aws-cognitoidentity", "aws.sdk.kotlin", "cognitoidentity").versionRef(awsKotlinSdk) library( "aws-cognitoidentityprovider", From ecc3305042d517ed86ae4d2a2797ba002c5e9c83 Mon Sep 17 00:00:00 2001 From: Saijad Dhuka Date: Mon, 6 Mar 2023 11:15:39 -0600 Subject: [PATCH 08/14] fix checkstyle --- .../api/aws/auth/IamRequestDecorator.java | 9 +++++---- .../geo/maplibre/http/AWSRequestSignerInterceptor.kt | 1 - 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/aws-api/src/main/java/com/amplifyframework/api/aws/auth/IamRequestDecorator.java b/aws-api/src/main/java/com/amplifyframework/api/aws/auth/IamRequestDecorator.java index c5431aecc3..7f392b5ec3 100644 --- a/aws-api/src/main/java/com/amplifyframework/api/aws/auth/IamRequestDecorator.java +++ b/aws-api/src/main/java/com/amplifyframework/api/aws/auth/IamRequestDecorator.java @@ -18,19 +18,20 @@ import com.amplifyframework.api.ApiException.ApiAuthException; import com.amplifyframework.api.aws.sigv4.AWS4Signer; -import aws.smithy.kotlin.runtime.http.DeferredHeaders; -import aws.smithy.kotlin.runtime.http.request.HttpRequestKt; import aws.smithy.kotlin.runtime.net.Url; + import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.List; import java.util.Map; import aws.smithy.kotlin.runtime.auth.awscredentials.CredentialsProvider; +import aws.smithy.kotlin.runtime.http.DeferredHeaders; import aws.smithy.kotlin.runtime.http.Headers; import aws.smithy.kotlin.runtime.http.HttpMethod; import aws.smithy.kotlin.runtime.http.content.ByteArrayContent; import aws.smithy.kotlin.runtime.http.request.HttpRequest; +import aws.smithy.kotlin.runtime.http.request.HttpRequestKt; import okhttp3.MediaType; import okhttp3.RequestBody; import okio.Buffer; @@ -126,8 +127,8 @@ private byte[] getBytes(RequestBody body) throws ApiAuthException { return output.toByteArray(); } catch (IOException exception) { throw new ApiAuthException("Unable to calculate SigV4 signature for the request", - exception, - "Check your application logs for details."); + exception, + "Check your application logs for details."); } } } diff --git a/maplibre-adapter/src/main/java/com/amplifyframework/geo/maplibre/http/AWSRequestSignerInterceptor.kt b/maplibre-adapter/src/main/java/com/amplifyframework/geo/maplibre/http/AWSRequestSignerInterceptor.kt index da17f1dbcd..af5b6f6b61 100644 --- a/maplibre-adapter/src/main/java/com/amplifyframework/geo/maplibre/http/AWSRequestSignerInterceptor.kt +++ b/maplibre-adapter/src/main/java/com/amplifyframework/geo/maplibre/http/AWSRequestSignerInterceptor.kt @@ -32,7 +32,6 @@ import java.io.IOException import kotlinx.coroutines.runBlocking import okhttp3.HttpUrl import okhttp3.Interceptor -import okhttp3.Protocol import okhttp3.Request import okhttp3.RequestBody import okhttp3.Response From 2ec2c0060c4e83537ff0da6ce7f61723634e63da Mon Sep 17 00:00:00 2001 From: Saijad Dhuka Date: Mon, 6 Mar 2023 11:35:03 -0600 Subject: [PATCH 09/14] upgrade sdk-core --- settings.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/settings.gradle.kts b/settings.gradle.kts index bfe7ffaec1..784c9bec53 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -89,7 +89,7 @@ dependencyResolutionManagement { library("aws-sdk-core", "com.amazonaws:aws-android-sdk-core:2.62.2") - library("aws-credentials", "aws.smithy.kotlin:aws-credentials:0.12.6") + library("aws-credentials", "aws.smithy.kotlin:aws-credentials:0.16.2") library("aws-ktor", "aws.smithy.kotlin:http-client-engine-ktor:0.7.7") library("aws-signing", "aws.smithy.kotlin:aws-signing-default:0.16.2") library("aws-cognitoidentity", "aws.sdk.kotlin", "cognitoidentity").versionRef(awsKotlinSdk) From 914774aee24fc3b3081db7c7cb446b4f3a5efed4 Mon Sep 17 00:00:00 2001 From: Saijad Dhuka Date: Mon, 6 Mar 2023 14:24:20 -0600 Subject: [PATCH 10/14] fix polly client --- .../aws/service/AmazonPollyPresigningClient.kt | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/aws-predictions/src/main/java/com/amplifyframework/predictions/aws/service/AmazonPollyPresigningClient.kt b/aws-predictions/src/main/java/com/amplifyframework/predictions/aws/service/AmazonPollyPresigningClient.kt index bef6e3834d..e09c3c7851 100644 --- a/aws-predictions/src/main/java/com/amplifyframework/predictions/aws/service/AmazonPollyPresigningClient.kt +++ b/aws-predictions/src/main/java/com/amplifyframework/predictions/aws/service/AmazonPollyPresigningClient.kt @@ -16,9 +16,12 @@ package com.amplifyframework.predictions.aws.service import androidx.annotation.WorkerThread import aws.sdk.kotlin.services.polly.PollyClient +import aws.sdk.kotlin.services.polly.endpoints.DefaultEndpointProvider +import aws.sdk.kotlin.services.polly.endpoints.EndpointParameters import aws.sdk.kotlin.services.polly.model.SynthesizeSpeechRequest import aws.sdk.kotlin.services.polly.presigners.PollyPresignConfig import aws.sdk.kotlin.services.polly.presigners.presign +import aws.smithy.kotlin.runtime.auth.awssigning.SigningContextualizedEndpoint import java.net.URL import kotlin.time.Duration.Companion.seconds import kotlinx.coroutines.runBlocking @@ -54,6 +57,14 @@ class AmazonPollyPresigningClient(pollyClient: PollyClient) : PollyClient by pol val presignConfig = PollyPresignConfig { region = this@AmazonPollyPresigningClient.config.region credentialsProvider = presignCredentialsProvider + endpointProvider = { + val endpoint = DefaultEndpointProvider().resolveEndpoint( + EndpointParameters.invoke { + region = it.region + } + ) + SigningContextualizedEndpoint(endpoint, it) + } } val presignedRequest = runBlocking { synthesizeSpeechRequest.presign(presignConfig, options.expires.seconds) From d6dd678e463cbe2aedf1e767d8b5b71ec2ac146a Mon Sep 17 00:00:00 2001 From: Saijad Dhuka Date: Tue, 7 Mar 2023 09:19:12 -0600 Subject: [PATCH 11/14] removed endpoint provider --- .../auth/cognito/AWSCognitoAuthService.kt | 3 ++- .../auth/cognito/AWSEndpointProvider.kt | 25 ------------------- 2 files changed, 2 insertions(+), 26 deletions(-) delete mode 100644 aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/AWSEndpointProvider.kt diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/AWSCognitoAuthService.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/AWSCognitoAuthService.kt index f5defb6ac5..a6ce418015 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/AWSCognitoAuthService.kt +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/AWSCognitoAuthService.kt @@ -18,6 +18,7 @@ package com.amplifyframework.auth.cognito import aws.sdk.kotlin.services.cognitoidentity.CognitoIdentityClient import aws.sdk.kotlin.services.cognitoidentityprovider.CognitoIdentityProviderClient import aws.smithy.kotlin.runtime.client.endpoints.Endpoint +import aws.smithy.kotlin.runtime.client.endpoints.EndpointProvider import com.amplifyframework.statemachine.codegen.data.AuthConfiguration interface AWSCognitoAuthService { @@ -31,7 +32,7 @@ interface AWSCognitoAuthService { CognitoIdentityProviderClient { this.region = it.region this.endpointProvider = it.endpoint?.let { endpoint -> - AWSEndpointProvider(Endpoint(endpoint)) + EndpointProvider { Endpoint(endpoint) } } } } diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/AWSEndpointProvider.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/AWSEndpointProvider.kt deleted file mode 100644 index 3e6290ca3b..0000000000 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/AWSEndpointProvider.kt +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"). - * You may not use this file except in compliance with the License. - * A copy of the License is located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed - * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ -package com.amplifyframework.auth.cognito - -import aws.sdk.kotlin.services.cognitoidentityprovider.endpoints.EndpointParameters -import aws.sdk.kotlin.services.cognitoidentityprovider.endpoints.EndpointProvider -import aws.smithy.kotlin.runtime.client.endpoints.Endpoint - -internal class AWSEndpointProvider(val endpoint: Endpoint) : EndpointProvider { - override suspend fun resolveEndpoint(params: EndpointParameters): Endpoint { - return Endpoint(uri = endpoint.uri) - } -} From 4359a669dd081aad7299de733617c032fdc0c4ad Mon Sep 17 00:00:00 2001 From: Saijad Dhuka Date: Wed, 8 Mar 2023 08:42:16 -0600 Subject: [PATCH 12/14] update pollypresignconfig with polly client config --- .../service/AmazonPollyPresigningClient.kt | 20 +++---------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/aws-predictions/src/main/java/com/amplifyframework/predictions/aws/service/AmazonPollyPresigningClient.kt b/aws-predictions/src/main/java/com/amplifyframework/predictions/aws/service/AmazonPollyPresigningClient.kt index e09c3c7851..e5b6e942ea 100644 --- a/aws-predictions/src/main/java/com/amplifyframework/predictions/aws/service/AmazonPollyPresigningClient.kt +++ b/aws-predictions/src/main/java/com/amplifyframework/predictions/aws/service/AmazonPollyPresigningClient.kt @@ -16,12 +16,8 @@ package com.amplifyframework.predictions.aws.service import androidx.annotation.WorkerThread import aws.sdk.kotlin.services.polly.PollyClient -import aws.sdk.kotlin.services.polly.endpoints.DefaultEndpointProvider -import aws.sdk.kotlin.services.polly.endpoints.EndpointParameters import aws.sdk.kotlin.services.polly.model.SynthesizeSpeechRequest -import aws.sdk.kotlin.services.polly.presigners.PollyPresignConfig import aws.sdk.kotlin.services.polly.presigners.presign -import aws.smithy.kotlin.runtime.auth.awssigning.SigningContextualizedEndpoint import java.net.URL import kotlin.time.Duration.Companion.seconds import kotlinx.coroutines.runBlocking @@ -54,20 +50,10 @@ class AmazonPollyPresigningClient(pollyClient: PollyClient) : PollyClient by pol options: PresignedSynthesizeSpeechUrlOptions ): URL { val presignCredentialsProvider = options.credentialsProvider ?: this.config.credentialsProvider - val presignConfig = PollyPresignConfig { - region = this@AmazonPollyPresigningClient.config.region - credentialsProvider = presignCredentialsProvider - endpointProvider = { - val endpoint = DefaultEndpointProvider().resolveEndpoint( - EndpointParameters.invoke { - region = it.region - } - ) - SigningContextualizedEndpoint(endpoint, it) - } - } + val configBuilder = this@AmazonPollyPresigningClient.config.toBuilder() + configBuilder.credentialsProvider = presignCredentialsProvider val presignedRequest = runBlocking { - synthesizeSpeechRequest.presign(presignConfig, options.expires.seconds) + synthesizeSpeechRequest.presign(configBuilder.build(), options.expires.seconds) } return URL(presignedRequest.url.toString()) } From 1304b728c0b26d6158064f8892bc541d582a2fb4 Mon Sep 17 00:00:00 2001 From: Saijad Dhuka Date: Wed, 8 Mar 2023 08:50:32 -0600 Subject: [PATCH 13/14] fix copyright year --- .../storage/s3/transfer/ProgressListenerHttpInterceptor.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/ProgressListenerHttpInterceptor.kt b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/ProgressListenerHttpInterceptor.kt index 82206f3359..66e11013c6 100644 --- a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/ProgressListenerHttpInterceptor.kt +++ b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/ProgressListenerHttpInterceptor.kt @@ -1,5 +1,5 @@ /* - * Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Copyright 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"). * You may not use this file except in compliance with the License. From 30caceb49f740c8455ed129bd9d2c41657c90cff Mon Sep 17 00:00:00 2001 From: Saijad Dhuka Date: Wed, 8 Mar 2023 10:16:22 -0600 Subject: [PATCH 14/14] fix documentation --- .../s3/options/AWSS3StorageGetPresignedUrlOptions.java | 4 ++-- .../storage/s3/options/AWSS3StorageUploadFileOptions.java | 4 ++-- .../s3/options/AWSS3StorageUploadInputStreamOptions.java | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/options/AWSS3StorageGetPresignedUrlOptions.java b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/options/AWSS3StorageGetPresignedUrlOptions.java index cb824d28a6..d4bad7e8db 100644 --- a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/options/AWSS3StorageGetPresignedUrlOptions.java +++ b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/options/AWSS3StorageGetPresignedUrlOptions.java @@ -121,8 +121,8 @@ public static final class Builder extends StorageGetUrlOptions.Builder private boolean useAccelerateEndpoint; /** - * Configure to use acceleration mode on new StorageDownloadFileOptions instances. - * @param useAccelerateEndpoint flag to represent acceleration mode for new DownloadFileOptions instance + * Configure to use acceleration mode on new StorageGetPresignedUrlOptions instances. + * @param useAccelerateEndpoint flag to represent acceleration mode for new GetPresignedUrlOptions instance * @return Current Builder instance for fluent chaining */ public Builder setUseAccelerateEndpoint(boolean useAccelerateEndpoint) { diff --git a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/options/AWSS3StorageUploadFileOptions.java b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/options/AWSS3StorageUploadFileOptions.java index 358cc19db1..d855462523 100644 --- a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/options/AWSS3StorageUploadFileOptions.java +++ b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/options/AWSS3StorageUploadFileOptions.java @@ -149,8 +149,8 @@ private Builder() { } /** - * Configure to use acceleration mode. - * @param useAccelerateEndpoint flag to represent acceleration mode for new DownloadFileOptions instance + * Configure to use acceleration mode on new StorageUploadFileOptions instances. + * @param useAccelerateEndpoint flag to represent acceleration mode for new UploadFileOptions instance * @return Current Builder instance for fluent chaining */ public Builder setUseAccelerateEndpoint(boolean useAccelerateEndpoint) { diff --git a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/options/AWSS3StorageUploadInputStreamOptions.java b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/options/AWSS3StorageUploadInputStreamOptions.java index a8f1b895f2..77bf047767 100644 --- a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/options/AWSS3StorageUploadInputStreamOptions.java +++ b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/options/AWSS3StorageUploadInputStreamOptions.java @@ -149,8 +149,8 @@ private Builder() { } /** - * Configure to use acceleration mode on new StorageDownloadFileOptions instances. - * @param useAccelerateEndpoint flag to represent acceleration mode for new DownloadFileOptions instance + * Configure to use acceleration mode on new StorageUploadInputStreamOptions instances. + * @param useAccelerateEndpoint flag to represent acceleration mode for new UploadInputStreamOptions instance * @return Current Builder instance for fluent chaining */ public Builder setUseAccelerateEndpoint(boolean useAccelerateEndpoint) {