Skip to content

Commit c6d870a

Browse files
authored
feat(Storage): AWSS3PluginPrefixResolver (#1277)
* feat(Storage): PrefixResolver * address PR comments
1 parent 8e3f7bd commit c6d870a

29 files changed

+575
-274
lines changed

AmplifyPlugins/Storage/AWSS3StoragePlugin/AWSS3StoragePlugin+ClientBehavior.swift

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ extension AWSS3StoragePlugin {
3131
let options = options ?? StorageGetURLRequest.Options()
3232
let request = StorageGetURLRequest(key: key, options: options)
3333
let getURLOperation = AWSS3StorageGetURLOperation(request,
34+
storageConfiguration: storageConfiguration,
3435
storageService: storageService,
3536
authService: authService,
3637
resultListener: resultListener)
@@ -59,6 +60,7 @@ extension AWSS3StoragePlugin {
5960
let options = options ?? StorageDownloadDataRequest.Options()
6061
let request = StorageDownloadDataRequest(key: key, options: options)
6162
let downloadDataOperation = AWSS3StorageDownloadDataOperation(request,
63+
storageConfiguration: storageConfiguration,
6264
storageService: storageService,
6365
authService: authService,
6466
progressListener: progressListener,
@@ -90,6 +92,7 @@ extension AWSS3StoragePlugin {
9092
let options = options ?? StorageDownloadFileRequest.Options()
9193
let request = StorageDownloadFileRequest(key: key, local: local, options: options)
9294
let downloadFileOperation = AWSS3StorageDownloadFileOperation(request,
95+
storageConfiguration: storageConfiguration,
9396
storageService: storageService,
9497
authService: authService,
9598
progressListener: progressListener,
@@ -122,10 +125,11 @@ extension AWSS3StoragePlugin {
122125
let request = StorageUploadDataRequest(key: key, data: data, options: options)
123126

124127
let uploadDataOperation = AWSS3StorageUploadDataOperation(request,
125-
storageService: storageService,
126-
authService: authService,
127-
progressListener: progressListener,
128-
resultListener: resultListener)
128+
storageConfiguration: storageConfiguration,
129+
storageService: storageService,
130+
authService: authService,
131+
progressListener: progressListener,
132+
resultListener: resultListener)
129133

130134
queue.addOperation(uploadDataOperation)
131135

@@ -154,6 +158,7 @@ extension AWSS3StoragePlugin {
154158
let request = StorageUploadFileRequest(key: key, local: local, options: options)
155159

156160
let uploadFileOperation = AWSS3StorageUploadFileOperation(request,
161+
storageConfiguration: storageConfiguration,
157162
storageService: storageService,
158163
authService: authService,
159164
progressListener: progressListener,
@@ -182,6 +187,7 @@ extension AWSS3StoragePlugin {
182187
let options = options ?? StorageRemoveRequest.Options()
183188
let request = StorageRemoveRequest(key: key, options: options)
184189
let removeOperation = AWSS3StorageRemoveOperation(request,
190+
storageConfiguration: storageConfiguration,
185191
storageService: storageService,
186192
authService: authService,
187193
resultListener: resultListener)
@@ -205,6 +211,7 @@ extension AWSS3StoragePlugin {
205211
let options = options ?? StorageListRequest.Options()
206212
let request = StorageListRequest(options: options)
207213
let listOperation = AWSS3StorageListOperation(request,
214+
storageConfiguration: storageConfiguration,
208215
storageService: storageService,
209216
authService: authService,
210217
resultListener: resultListener)

AmplifyPlugins/Storage/AWSS3StoragePlugin/AWSS3StoragePlugin.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,13 @@ final public class AWSS3StoragePlugin: StorageCategoryPlugin {
2929
return PluginConstants.awsS3StoragePluginKey
3030
}
3131

32+
/// The storage plugin configuration
33+
let storageConfiguration: AWSS3StoragePluginConfiguration
34+
3235
/// Instantiates an instance of the AWSS3StoragePlugin.
33-
public init() {
36+
public init(configuration
37+
storageConfiguration: AWSS3StoragePluginConfiguration = AWSS3StoragePluginConfiguration()) {
38+
self.storageConfiguration = storageConfiguration
3439
}
3540
}
3641

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
//
2+
// Copyright Amazon.com Inc. or its affiliates.
3+
// All Rights Reserved.
4+
//
5+
// SPDX-License-Identifier: Apache-2.0
6+
//
7+
8+
import Foundation
9+
import Amplify
10+
import AWSPluginsCore
11+
12+
/// Resolves the final prefix prepended to the S3 key for a given request.
13+
public protocol AWSS3PluginPrefixResolver {
14+
func resolvePrefix(for accessLevel: StorageAccessLevel, targetIdentityId: String?) -> Result<String, StorageError>
15+
}
16+
17+
/// Convenience resolver. Resolves the provided key as-is, with no manipulation
18+
public struct PassThroughPrefixResolver: AWSS3PluginPrefixResolver {
19+
public func resolvePrefix(for accessLevel: StorageAccessLevel,
20+
targetIdentityId: String?) -> Result<String, StorageError> {
21+
return .success("")
22+
}
23+
}
24+
25+
/// AWSS3StoragePlugin default logic
26+
struct StorageAccessLevelAwarePrefixResolver: AWSS3PluginPrefixResolver {
27+
let authService: AWSAuthServiceBehavior
28+
29+
public init(authService: AWSAuthServiceBehavior) {
30+
self.authService = authService
31+
}
32+
33+
public func resolvePrefix(for accessLevel: StorageAccessLevel,
34+
targetIdentityId: String?) -> Result<String, StorageError> {
35+
let identityIdResult = authService.getIdentityId()
36+
switch identityIdResult {
37+
case .success(let identityId):
38+
let prefix = StorageRequestUtils.getAccessLevelPrefix(accessLevel: accessLevel,
39+
identityId: identityId,
40+
targetIdentityId: targetIdentityId)
41+
return .success(prefix)
42+
case .failure(let error):
43+
return .failure(StorageError.authError(error.errorDescription, error.recoverySuggestion))
44+
}
45+
}
46+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//
2+
// Copyright Amazon.com Inc. or its affiliates.
3+
// All Rights Reserved.
4+
//
5+
// SPDX-License-Identifier: Apache-2.0
6+
//
7+
8+
import Foundation
9+
10+
/// Plugin specific configuration
11+
public struct AWSS3StoragePluginConfiguration {
12+
13+
public let prefixResolver: AWSS3PluginPrefixResolver?
14+
15+
public init(prefixResolver: AWSS3PluginPrefixResolver? = nil) {
16+
self.prefixResolver = prefixResolver
17+
}
18+
19+
public static func prefixResolver(
20+
_ prefixResolver: AWSS3PluginPrefixResolver) -> AWSS3StoragePluginConfiguration {
21+
.init(prefixResolver: prefixResolver)
22+
}
23+
}

AmplifyPlugins/Storage/AWSS3StoragePlugin/Operation/AWSS3StorageDownloadDataOperation.swift

Lines changed: 14 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ public class AWSS3StorageDownloadDataOperation: AmplifyInProcessReportingOperati
2222
StorageError
2323
>, StorageDownloadDataOperation {
2424

25+
let storageConfiguration: AWSS3StoragePluginConfiguration
2526
let storageService: AWSS3StorageServiceBehaviour
2627
let authService: AWSAuthServiceBehavior
2728

@@ -31,11 +32,13 @@ public class AWSS3StorageDownloadDataOperation: AmplifyInProcessReportingOperati
3132
private let storageTaskActionQueue = DispatchQueue(label: "com.amazonaws.amplify.StorageTaskActionQueue")
3233

3334
init(_ request: StorageDownloadDataRequest,
35+
storageConfiguration: AWSS3StoragePluginConfiguration,
3436
storageService: AWSS3StorageServiceBehaviour,
3537
authService: AWSAuthServiceBehavior,
3638
progressListener: InProcessListener?,
3739
resultListener: ResultListener?) {
3840

41+
self.storageConfiguration = storageConfiguration
3942
self.storageService = storageService
4043
self.authService = authService
4144
super.init(categoryType: .storage,
@@ -82,29 +85,19 @@ public class AWSS3StorageDownloadDataOperation: AmplifyInProcessReportingOperati
8285
return
8386
}
8487

85-
let identityIdResult = authService.getIdentityId()
86-
87-
guard case let .success(identityId) = identityIdResult else {
88-
if case let .failure(error) = identityIdResult {
89-
dispatch(StorageError.authError(error.errorDescription, error.recoverySuggestion))
88+
let prefixResolver = storageConfiguration.prefixResolver ??
89+
StorageAccessLevelAwarePrefixResolver(authService: authService)
90+
let prefixResolution = prefixResolver.resolvePrefix(for: request.options.accessLevel,
91+
targetIdentityId: request.options.targetIdentityId)
92+
switch prefixResolution {
93+
case .success(let prefix):
94+
let serviceKey = prefix + request.key
95+
storageService.download(serviceKey: serviceKey, fileURL: nil) { [weak self] event in
96+
self?.onServiceEvent(event: event)
9097
}
91-
92-
finish()
93-
return
94-
}
95-
96-
let serviceKey = StorageRequestUtils.getServiceKey(accessLevel: request.options.accessLevel,
97-
identityId: identityId,
98-
key: request.key,
99-
targetIdentityId: request.options.targetIdentityId)
100-
101-
if isCancelled {
98+
case .failure(let error):
99+
dispatch(error)
102100
finish()
103-
return
104-
}
105-
106-
storageService.download(serviceKey: serviceKey, fileURL: nil) { [weak self] event in
107-
self?.onServiceEvent(event: event)
108101
}
109102
}
110103

AmplifyPlugins/Storage/AWSS3StoragePlugin/Operation/AWSS3StorageDownloadFileOperation.swift

Lines changed: 14 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ public class AWSS3StorageDownloadFileOperation: AmplifyInProcessReportingOperati
2525
StorageError
2626
>, StorageDownloadFileOperation {
2727

28+
let storageConfiguration: AWSS3StoragePluginConfiguration
2829
let storageService: AWSS3StorageServiceBehaviour
2930
let authService: AWSAuthServiceBehavior
3031

@@ -34,11 +35,13 @@ public class AWSS3StorageDownloadFileOperation: AmplifyInProcessReportingOperati
3435
private let storageTaskActionQueue = DispatchQueue(label: "com.amazonaws.amplify.StorageTaskActionQueue")
3536

3637
init(_ request: StorageDownloadFileRequest,
38+
storageConfiguration: AWSS3StoragePluginConfiguration,
3739
storageService: AWSS3StorageServiceBehaviour,
3840
authService: AWSAuthServiceBehavior,
3941
progressListener: InProcessListener?,
4042
resultListener: ResultListener?) {
4143

44+
self.storageConfiguration = storageConfiguration
4245
self.storageService = storageService
4346
self.authService = authService
4447
super.init(categoryType: .storage,
@@ -85,28 +88,19 @@ public class AWSS3StorageDownloadFileOperation: AmplifyInProcessReportingOperati
8588
return
8689
}
8790

88-
let identityIdResult = authService.getIdentityId()
89-
guard case let .success(identityId) = identityIdResult else {
90-
if case let .failure(error) = identityIdResult {
91-
dispatch(StorageError.authError(error.errorDescription, error.recoverySuggestion))
91+
let prefixResolver = storageConfiguration.prefixResolver ??
92+
StorageAccessLevelAwarePrefixResolver(authService: authService)
93+
let prefixResolution = prefixResolver.resolvePrefix(for: request.options.accessLevel,
94+
targetIdentityId: request.options.targetIdentityId)
95+
switch prefixResolution {
96+
case .success(let prefix):
97+
let serviceKey = prefix + request.key
98+
storageService.download(serviceKey: serviceKey, fileURL: request.local) { [weak self] event in
99+
self?.onServiceEvent(event: event)
92100
}
93-
94-
finish()
95-
return
96-
}
97-
98-
let serviceKey = StorageRequestUtils.getServiceKey(accessLevel: request.options.accessLevel,
99-
identityId: identityId,
100-
key: request.key,
101-
targetIdentityId: request.options.targetIdentityId)
102-
103-
if isCancelled {
101+
case .failure(let error):
102+
dispatch(error)
104103
finish()
105-
return
106-
}
107-
108-
storageService.download(serviceKey: serviceKey, fileURL: request.local) { [weak self] event in
109-
self?.onServiceEvent(event: event)
110104
}
111105
}
112106

AmplifyPlugins/Storage/AWSS3StoragePlugin/Operation/AWSS3StorageGetURLOperation.swift

Lines changed: 15 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,17 @@ public class AWSS3StorageGetURLOperation: AmplifyOperation<
2121
StorageError
2222
>, StorageGetURLOperation {
2323

24+
let storageConfiguration: AWSS3StoragePluginConfiguration
2425
let storageService: AWSS3StorageServiceBehaviour
2526
let authService: AWSAuthServiceBehavior
2627

2728
init(_ request: StorageGetURLRequest,
29+
storageConfiguration: AWSS3StoragePluginConfiguration,
2830
storageService: AWSS3StorageServiceBehaviour,
2931
authService: AWSAuthServiceBehavior,
3032
resultListener: ResultListener?) {
3133

34+
self.storageConfiguration = storageConfiguration
3235
self.storageService = storageService
3336
self.authService = authService
3437
super.init(categoryType: .storage,
@@ -55,28 +58,20 @@ public class AWSS3StorageGetURLOperation: AmplifyOperation<
5558
return
5659
}
5760

58-
let identityIdResult = authService.getIdentityId()
59-
guard case let .success(identityId) = identityIdResult else {
60-
if case let .failure(error) = identityIdResult {
61-
dispatch(StorageError.authError(error.errorDescription, error.recoverySuggestion))
61+
let prefixResolver = storageConfiguration.prefixResolver ??
62+
StorageAccessLevelAwarePrefixResolver(authService: authService)
63+
let prefixResolution = prefixResolver.resolvePrefix(for: request.options.accessLevel,
64+
targetIdentityId: request.options.targetIdentityId)
65+
switch prefixResolution {
66+
case .success(let prefix):
67+
let serviceKey = prefix + request.key
68+
storageService.getPreSignedURL(serviceKey: serviceKey,
69+
expires: request.options.expires) { [weak self] event in
70+
self?.onServiceEvent(event: event)
6271
}
63-
64-
finish()
65-
return
66-
}
67-
68-
let serviceKey = StorageRequestUtils.getServiceKey(accessLevel: request.options.accessLevel,
69-
identityId: identityId,
70-
key: request.key,
71-
targetIdentityId: request.options.targetIdentityId)
72-
73-
if isCancelled {
72+
case .failure(let error):
73+
dispatch(error)
7474
finish()
75-
return
76-
}
77-
78-
storageService.getPreSignedURL(serviceKey: serviceKey, expires: request.options.expires) { [weak self] event in
79-
self?.onServiceEvent(event: event)
8075
}
8176
}
8277

AmplifyPlugins/Storage/AWSS3StoragePlugin/Operation/AWSS3StorageListOperation.swift

Lines changed: 13 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,17 @@ public class AWSS3StorageListOperation: AmplifyOperation<
2121
StorageError
2222
>, StorageListOperation {
2323

24+
let storageConfiguration: AWSS3StoragePluginConfiguration
2425
let storageService: AWSS3StorageServiceBehaviour
2526
let authService: AWSAuthServiceBehavior
2627

2728
init(_ request: StorageListRequest,
29+
storageConfiguration: AWSS3StoragePluginConfiguration,
2830
storageService: AWSS3StorageServiceBehaviour,
2931
authService: AWSAuthServiceBehavior,
3032
resultListener: ResultListener?) {
3133

34+
self.storageConfiguration = storageConfiguration
3235
self.storageService = storageService
3336
self.authService = authService
3437
super.init(categoryType: .storage,
@@ -55,29 +58,18 @@ public class AWSS3StorageListOperation: AmplifyOperation<
5558
return
5659
}
5760

58-
let identityIdResult = authService.getIdentityId()
59-
60-
guard case let .success(identityId) = identityIdResult else {
61-
if case let .failure(error) = identityIdResult {
62-
dispatch(StorageError.authError(error.errorDescription, error.recoverySuggestion))
61+
let prefixResolver = storageConfiguration.prefixResolver ??
62+
StorageAccessLevelAwarePrefixResolver(authService: authService)
63+
let prefixResolution = prefixResolver.resolvePrefix(for: request.options.accessLevel,
64+
targetIdentityId: request.options.targetIdentityId)
65+
switch prefixResolution {
66+
case .success(let prefix):
67+
storageService.list(prefix: prefix, path: request.options.path) { [weak self] event in
68+
self?.onServiceEvent(event: event)
6369
}
64-
65-
finish()
66-
return
67-
}
68-
69-
let accessLevelPrefix = StorageRequestUtils
70-
.getAccessLevelPrefix(accessLevel: request.options.accessLevel,
71-
identityId: identityId,
72-
targetIdentityId: request.options.targetIdentityId)
73-
74-
if isCancelled {
70+
case .failure(let error):
71+
dispatch(error)
7572
finish()
76-
return
77-
}
78-
79-
storageService.list(prefix: accessLevelPrefix, path: request.options.path) { [weak self] event in
80-
self?.onServiceEvent(event: event)
8173
}
8274
}
8375

0 commit comments

Comments
 (0)