Skip to content

Commit 7cab76f

Browse files
authored
feat(datastore): StartSync with Auth (#471)
* feat(datastore): RemoteSyncEngine handles authentication state * Add Integration test target * Add integration test set up * Move sync requirement to SyncEngine * add check for listeners since each DataStore call will register a new listener * update Auth plugin name * Add clearCompleted event with integ test passing * remove auth state listeners * SyncQuery propagate error to error handler * Coode clean up, remove clearCompleted hub event, Amplify core changes * change hasAuth to hasAuthenticationRules * PR feedback * readme update * fix unit test
1 parent 213c5d6 commit 7cab76f

File tree

43 files changed

+1177
-92
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+1177
-92
lines changed

Amplify/Categories/Auth/AuthCategoryDeviceBehavior.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
import Foundation
99

10-
public protocol AuthCategoryDeviceBehavior {
10+
public protocol AuthCategoryDeviceBehavior: class {
1111

1212
/// Fetch devices assigned to the current device
1313
/// - Parameters:

Amplify/Categories/Auth/AuthCategoryUserBehavior.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
import Foundation
99

10-
public protocol AuthCategoryUserBehavior {
10+
public protocol AuthCategoryUserBehavior: class {
1111

1212
/// Returns the currently logged in user.
1313
///

Amplify/Categories/DataStore/Model/Schema/ModelSchema+Attributes.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,7 @@ public extension ModelSchema {
1616
attributes.contains(.isSystem)
1717
}
1818

19+
var hasAuthenticationRules: Bool {
20+
return !authRules.isEmpty
21+
}
1922
}

AmplifyPlugins/API/AWSAPICategoryPluginIntegrationTests/GraphQL/GraphQLWithUserPoolIntegrationTests/AuthDirective/GraphQLAuthDirectiveIntegrationTests+Auth.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
import XCTest
99
import AWSPluginsCore
1010
import AWSAPICategoryPlugin
11-
import AWSMobileClient
1211

1312
@testable import Amplify
1413
@testable import AWSAPICategoryPluginTestCommon

AmplifyPlugins/API/AWSAPICategoryPluginIntegrationTests/GraphQL/GraphQLWithUserPoolIntegrationTests/AuthDirective/GraphQLAuthDirectiveIntegrationTests+Support.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
import XCTest
99
import AWSPluginsCore
1010
import AWSAPICategoryPlugin
11-
import AWSMobileClient
1211
import AmplifyPlugins
1312

1413
@testable import Amplify

AmplifyPlugins/API/AWSAPICategoryPluginIntegrationTests/GraphQL/GraphQLWithUserPoolIntegrationTests/AuthDirective/GraphQLAuthDirectiveIntegrationTests.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import XCTest
99
import AWSPluginsCore
1010
import AWSAPICategoryPlugin
1111
import AmplifyPlugins
12-
import AWSMobileClient
1312

1413
@testable import Amplify
1514
@testable import AWSAPICategoryPluginTestCommon

AmplifyPlugins/DataStore/AWSDataStoreCategoryPlugin/AWSDataStorePlugin.swift

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ final public class AWSDataStorePlugin: DataStoreCategoryPlugin {
2424
let dataStoreConfiguration: DataStoreConfiguration
2525

2626
let validAPIPluginKey: String
27+
28+
let validAuthPluginKey: String
29+
2730
/// The local storage provider. Resolved during configuration phase
2831
var storageEngine: StorageEngineBehavior!
2932

@@ -48,6 +51,7 @@ final public class AWSDataStorePlugin: DataStoreCategoryPlugin {
4851
self.dataStoreConfiguration = dataStoreConfiguration
4952
self.isSyncEnabled = false
5053
self.validAPIPluginKey = "awsAPIPlugin"
54+
self.validAuthPluginKey = "awsCognitoAuthPlugin"
5155
if #available(iOS 13.0, *) {
5256
self.dataStorePublisher = DataStorePublisher()
5357
} else {
@@ -60,13 +64,15 @@ final public class AWSDataStorePlugin: DataStoreCategoryPlugin {
6064
configuration dataStoreConfiguration: DataStoreConfiguration = .default,
6165
storageEngine: StorageEngineBehavior,
6266
dataStorePublisher: DataStoreSubscribeBehavior,
63-
validAPIPluginKey: String) {
67+
validAPIPluginKey: String,
68+
validAuthPluginKey: String) {
6469
self.modelRegistration = modelRegistration
6570
self.dataStoreConfiguration = dataStoreConfiguration
6671
self.isSyncEnabled = false
6772
self.storageEngine = storageEngine
6873
self.dataStorePublisher = dataStorePublisher
6974
self.validAPIPluginKey = validAPIPluginKey
75+
self.validAuthPluginKey = validAuthPluginKey
7076
}
7177

7278
/// By the time this method gets called, DataStore will already have invoked
@@ -82,27 +88,13 @@ final public class AWSDataStorePlugin: DataStoreCategoryPlugin {
8288
let filter = HubFilters.forEventName(HubPayload.EventName.Amplify.configured)
8389
var token: UnsubscribeToken?
8490
token = Amplify.Hub.listen(to: .dataStore, isIncluded: filter) { _ in
85-
if self.hasValidAPIPlugin() {
86-
self.storageEngine.startSync()
87-
} else {
88-
self.log.info("Unable to find suitable plugin for syncEngine. syncEngine will not be started")
89-
}
90-
91+
self.storageEngine.startSync()
9192
if let token = token {
9293
Amplify.Hub.removeListener(token)
9394
}
9495
}
9596
}
9697

97-
func hasValidAPIPlugin() -> Bool {
98-
do {
99-
_ = try Amplify.API.getPlugin(for: validAPIPluginKey)
100-
return true
101-
} catch {
102-
return false
103-
}
104-
}
105-
10698
func reinitStorageEngineIfNeeded() {
10799
if storageEngine != nil {
108100
return
@@ -124,7 +116,10 @@ final public class AWSDataStorePlugin: DataStoreCategoryPlugin {
124116
return
125117
}
126118

127-
storageEngine = try StorageEngine(isSyncEnabled: isSyncEnabled, dataStoreConfiguration: dataStoreConfiguration)
119+
storageEngine = try StorageEngine(isSyncEnabled: isSyncEnabled,
120+
dataStoreConfiguration: dataStoreConfiguration,
121+
validAPIPluginKey: validAPIPluginKey,
122+
validAuthPluginKey: validAuthPluginKey)
128123
if #available(iOS 13.0, *) {
129124
setupStorageSink()
130125
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
//
2+
// Copyright 2018-2020 Amazon.com,
3+
// Inc. or its affiliates. All Rights Reserved.
4+
//
5+
// SPDX-License-Identifier: Apache-2.0
6+
//
7+
8+
import Amplify
9+
import Combine
10+
import Foundation
11+
import AWSPluginsCore
12+
13+
extension StorageEngine {
14+
15+
func startSync() {
16+
guard let api = tryGetAPIPlugin() else {
17+
log.info("Unable to find suitable API plugin for syncEngine. syncEngine will not be started")
18+
return
19+
}
20+
21+
let authPluginRequired = requiresAuthPlugin()
22+
23+
guard authPluginRequired else {
24+
syncEngine?.start(api: api, auth: nil)
25+
return
26+
}
27+
28+
guard let auth = tryGetAuthPlugin() else {
29+
log.warn("Unable to find suitable Auth plugin for syncEngine. Models require auth")
30+
return
31+
}
32+
33+
syncEngine?.start(api: api, auth: auth)
34+
}
35+
36+
private func tryGetAPIPlugin() -> APICategoryGraphQLBehavior? {
37+
do {
38+
return try Amplify.API.getPlugin(for: validAPIPluginKey)
39+
} catch {
40+
return nil
41+
}
42+
}
43+
44+
private func tryGetAuthPlugin() -> AuthCategoryBehavior? {
45+
do {
46+
return try Amplify.Auth.getPlugin(for: validAuthPluginKey)
47+
} catch {
48+
return nil
49+
}
50+
}
51+
52+
private func requiresAuthPlugin() -> Bool {
53+
let containsAuthEnabledSyncableModels = ModelRegistry.models.contains {
54+
$0.schema.isSyncable && $0.schema.hasAuthenticationRules
55+
}
56+
57+
return containsAuthEnabledSyncableModels
58+
}
59+
}

AmplifyPlugins/DataStore/AWSDataStoreCategoryPlugin/Storage/StorageEngine.swift

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,10 @@ final class StorageEngine: StorageEngineBehavior {
1414
// TODO: Make this private once we get a mutation flow that passes the type of mutation as needed
1515
let storageAdapter: StorageEngineAdapter
1616
private let dataStoreConfiguration: DataStoreConfiguration
17-
private var syncEngine: RemoteSyncEngineBehavior?
18-
private weak var api: APICategoryGraphQLBehavior?
17+
var syncEngine: RemoteSyncEngineBehavior?
18+
let validAPIPluginKey: String
19+
let validAuthPluginKey: String
20+
var signInListener: UnsubscribeToken?
1921

2022
var iSyncEngineSink: Any?
2123
@available(iOS 13.0, *)
@@ -63,13 +65,20 @@ final class StorageEngine: StorageEngineBehavior {
6365
// storageAdapter must have already been set up with system models
6466
init(storageAdapter: StorageEngineAdapter,
6567
dataStoreConfiguration: DataStoreConfiguration,
66-
syncEngine: RemoteSyncEngineBehavior?) {
68+
syncEngine: RemoteSyncEngineBehavior?,
69+
validAPIPluginKey: String,
70+
validAuthPluginKey: String) {
6771
self.storageAdapter = storageAdapter
6872
self.dataStoreConfiguration = dataStoreConfiguration
6973
self.syncEngine = syncEngine
74+
self.validAPIPluginKey = validAPIPluginKey
75+
self.validAuthPluginKey = validAuthPluginKey
7076
}
7177

72-
convenience init(isSyncEnabled: Bool, dataStoreConfiguration: DataStoreConfiguration) throws {
78+
convenience init(isSyncEnabled: Bool,
79+
dataStoreConfiguration: DataStoreConfiguration,
80+
validAPIPluginKey: String = "awsAPIPlugin",
81+
validAuthPluginKey: String = "awsCognitoAuthPlugin") throws {
7382
let key = kCFBundleNameKey as String
7483
let databaseName = Bundle.main.object(forInfoDictionaryKey: key) as? String
7584
let storageAdapter = try SQLiteStorageEngineAdapter(databaseName: databaseName ?? "app")
@@ -80,14 +89,18 @@ final class StorageEngine: StorageEngineBehavior {
8089
dataStoreConfiguration: dataStoreConfiguration) : nil
8190
self.init(storageAdapter: storageAdapter,
8291
dataStoreConfiguration: dataStoreConfiguration,
83-
syncEngine: syncEngine)
92+
syncEngine: syncEngine,
93+
validAPIPluginKey: validAPIPluginKey,
94+
validAuthPluginKey: validAuthPluginKey)
8495
self.storageEnginePublisher = PassthroughSubject<StorageEngineEvent, DataStoreError>()
8596
sinkEngineSink = syncEngine?.publisher.sink(receiveCompletion: onReceiveCompletion(receiveCompletion:),
8697
receiveValue: onReceive(receiveValue:))
8798
} else {
8899
self.init(storageAdapter: storageAdapter,
89100
dataStoreConfiguration: dataStoreConfiguration,
90-
syncEngine: nil)
101+
syncEngine: nil,
102+
validAPIPluginKey: validAPIPluginKey,
103+
validAuthPluginKey: validAuthPluginKey)
91104
}
92105
}
93106

@@ -319,10 +332,6 @@ final class StorageEngine: StorageEngineBehavior {
319332
completion: completion)
320333
}
321334

322-
func startSync() {
323-
syncEngine?.start(api: Amplify.API)
324-
}
325-
326335
func clear(completion: @escaping DataStoreCallback<Void>) {
327336
if let syncEngine = syncEngine {
328337
syncEngine.stop(completion: { _ in

AmplifyPlugins/DataStore/AWSDataStoreCategoryPlugin/Storage/StorageEngineBehavior.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ protocol StorageEngineBehavior: class, ModelStorageBehavior {
1919
@available(iOS 13.0, *)
2020
var publisher: AnyPublisher<StorageEngineEvent, DataStoreError> { get }
2121

22-
/// Tells the StorageEngine to begin syncing, if sync is enabled
22+
/// start remote sync, based on if sync is enabled and/or authentication is required
2323
func startSync()
2424

2525
func clear(completion: @escaping DataStoreCallback<Void>)

0 commit comments

Comments
 (0)