Skip to content

Commit d03f5e2

Browse files
authored
Merge pull request #2 from Couchbase-Ecosystem/8-fix-replication-configuration
updated to fix replication issues with configuration deserization
2 parents 8071b4f + 3e05e7d commit d03f5e2

File tree

4 files changed

+137
-92
lines changed

4 files changed

+137
-92
lines changed

CbliteSwiftJsLib.podspec

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

88
Pod::Spec.new do |s|
99
s.name = 'CbliteSwiftJsLib'
10-
s.version = '0.1.0'
10+
s.version = '0.1.6'
1111
s.summary = 'Couchbase Lite Swift libary for cblite.js (Javascript) Library'
1212

1313
# This description is used to generate tags and improve search results.

CbliteSwiftJsLib/Classes/CollectionManager.swift

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,27 @@
88
import Foundation
99
import CouchbaseLiteSwift
1010

11-
enum CollectionError: Error {
11+
public struct CollectionConfigItem: Codable {
12+
let collections: [CollectionDtoWrapper]
13+
let config: ConfigDto
14+
}
15+
16+
public struct CollectionDtoWrapper: Codable {
17+
let collection: CollectionDto
18+
}
19+
20+
public struct CollectionDto: Codable {
21+
let name: String
22+
let scopeName: String
23+
let databaseName: String
24+
}
25+
26+
public struct ConfigDto: Codable {
27+
let channels: [String]
28+
let documentIds: [String]
29+
}
30+
31+
public enum CollectionError: Error {
1232
case unableToFindCollection(collectionName: String, scopeName: String, databaseName: String)
1333
case getCollection(message: String, collectionName: String, scopeName: String, databaseName: String)
1434
case cannotCreateIndex(indexName: String)

CbliteSwiftJsLib/Classes/ReplicatorHelper.swift

Lines changed: 99 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -6,124 +6,139 @@
66
//
77

88
import Foundation
9+
import JavaScriptCore
910
import CouchbaseLiteSwift
1011

1112
public struct ReplicatorHelper {
12-
13-
public static func replicatorConfigFromJson(_ data: [String: Any]) throws -> ReplicatorConfiguration {
14-
guard let authenticatorData = data["authenticator"] as? [String: Any],
15-
let target = data["target"] as? [String: Any],
13+
14+
public static func replicatorConfigFromJson(_ data: [String: Any], collectionConfiguration: [CollectionConfigItem]) throws -> ReplicatorConfiguration {
15+
guard let target = data["target"] as? [String: Any],
1616
let url = target["url"] as? String,
1717
let replicatorType = data["replicatorType"] as? String,
1818
let continuous = data["continuous"] as? Bool,
19-
let collectionConfig = data["collectionConfig"] as? [String: Any] else {
19+
let acceptParentDomainCookies = data["acceptParentDomainCookies"] as? Bool,
20+
let acceptSelfSignedCerts = data["acceptSelfSignedCerts"] as? Bool,
21+
let allowReplicationInBackground = data["allowReplicationInBackground"] as? Bool,
22+
let autoPurgeEnabled = data["autoPurgeEnabled"] as? Bool,
23+
let heartbeat = data["heartbeat"] as? NSNumber,
24+
let maxAttempts = data["maxAttempts"] as? NSNumber,
25+
let maxAttemptWaitTime = data["maxAttemptWaitTime"] as? NSNumber
26+
else {
2027
throw ReplicatorError.fatalError(message: "Invalid JSON data")
2128
}
22-
29+
2330
let endpoint = URLEndpoint(url: URL(string: url)!)
31+
32+
//set values from data
2433
var replConfig = ReplicatorConfiguration(target: endpoint)
25-
26-
switch replicatorType {
27-
case "PUSH_AND_PULL":
28-
replConfig.replicatorType = .pushAndPull
29-
case "PULL":
30-
replConfig.replicatorType = .pull
31-
case "PUSH":
32-
replConfig.replicatorType = .push
33-
default:
34-
throw ReplicatorError.fatalError(message: "Invalid replicatorType")
35-
}
36-
34+
replConfig.acceptParentDomainCookie = acceptSelfSignedCerts
35+
replConfig.acceptParentDomainCookie = acceptParentDomainCookies
36+
replConfig.allowReplicatingInBackground = allowReplicationInBackground
3737
replConfig.continuous = continuous
38-
39-
if let authenticator = ReplicatorHelper.replicatorAuthenticatorFromConfig(authenticatorData) {
40-
replConfig.authenticator = authenticator
38+
replConfig.enableAutoPurge = autoPurgeEnabled
39+
40+
replConfig.heartbeat = TimeInterval(exactly: heartbeat.int64Value) ?? 300
41+
replConfig.maxAttemptWaitTime = TimeInterval(exactly: maxAttemptWaitTime.int64Value) ?? 0
42+
replConfig.maxAttempts = maxAttempts.uintValue
43+
44+
//check for headers
45+
if let headers = data["headers"] as? [String: String] {
46+
replConfig.headers = headers
4147
}
4248

43-
//setup collections
44-
let (collections, colConfig) = try ReplicatorHelper.replicatorCollectionConfigFromJson(collectionConfig)
45-
replConfig.addCollections(Array(collections), config: colConfig)
49+
if let authenticatorData = data["authenticator"], !(authenticatorData is String && authenticatorData as! String == "") {
50+
if let authenticatorConfig = authenticatorData as? [String: Any] {
51+
if let authenticator = ReplicatorHelper.replicatorAuthenticatorFromConfig(authenticatorConfig) {
52+
replConfig.authenticator = authenticator
53+
}
54+
}
55+
56+
}
4657

58+
try ReplicatorHelper.replicatorCollectionConfigFromJson(collectionConfiguration, replicationConfig: &replConfig)
59+
60+
switch replicatorType {
61+
case "PUSH_AND_PULL":
62+
replConfig.replicatorType = .pushAndPull
63+
case "PULL":
64+
replConfig.replicatorType = .pull
65+
case "PUSH":
66+
replConfig.replicatorType = .push
67+
default:
68+
throw ReplicatorError.fatalError(message: "Invalid replicatorType")
69+
}
4770
return replConfig
4871
}
49-
50-
private static func replicatorCollectionConfigFromJson(_ data: [String: Any]) throws -> (Set<Collection>, CollectionConfiguration) {
72+
73+
public static func replicatorCollectionConfigFromJson(_ data: [CollectionConfigItem], replicationConfig: inout ReplicatorConfiguration) throws {
5174

5275
//work on the collections sent in as part of the configuration with an array of collectionName, scopeName, and databaseName
53-
guard let collectionData = data["collections"] as? [[String: String]] else {
54-
throw ReplicatorError.configurationError(message: "collections doesn't include collections in the proper format")
55-
}
56-
guard let config = data["config"] as? [String: Any] else {
57-
throw ReplicatorError.configurationError(message: "ReplicationConfig collection config is incorrect format")
58-
}
59-
60-
var collections: Set<Collection> = []
61-
62-
for collectionItem in collectionData {
63-
guard let collectionName = collectionItem["collectionName"],
64-
let scopeName = collectionItem["scopeName"],
65-
let databaseName = collectionItem["databaseName"] else {
66-
// Handle the case where any required key is missing
67-
throw ReplicatorError.configurationError(message: "Error: collections missing required key in collection data - collectionName, scopeName, or databaseName")
76+
for item in data {
77+
78+
var collections: [Collection] = []
79+
80+
for col in item.collections {
81+
82+
guard let collection = try CollectionManager.shared.getCollection(col.collection.name, scopeName: col.collection.scopeName, databaseName: col.collection.databaseName) else {
83+
throw CollectionError.unableToFindCollection(collectionName: col.collection.name, scopeName: col.collection.scopeName, databaseName: col.collection.databaseName)
84+
}
85+
collections.append(collection)
6886
}
69-
guard let collection = try CollectionManager.shared.getCollection(collectionName, scopeName: scopeName, databaseName: databaseName) else {
70-
throw CollectionError.unableToFindCollection(collectionName: collectionName, scopeName: scopeName, databaseName: databaseName)
87+
88+
//process the config part of the data
89+
var collectionConfig = CollectionConfiguration()
90+
91+
//get the channels and documentIds to filter for the collections
92+
//these are optional
93+
if item.config.channels.count > 0 {
94+
collectionConfig.channels = item.config.channels
7195
}
72-
collections.insert(collection)
73-
}
74-
//process the config part of the data
75-
var collectionConfig = CollectionConfiguration()
76-
77-
//get the channels and documentIds to filter for the collections
78-
//these are optional
79-
if let channels = config["channels"] as? [String] {
80-
collectionConfig.channels = channels
81-
}
82-
if let documentIds = config["documentIds"] as? [String] {
83-
collectionConfig.documentIDs = documentIds
96+
if item.config.documentIds.count > 0 {
97+
collectionConfig.documentIDs = item.config.documentIds
98+
}
99+
replicationConfig.addCollections(collections, config: collectionConfig)
84100
}
85-
return (collections, collectionConfig)
86101
}
87-
102+
88103
private static func replicatorAuthenticatorFromConfig(_ config: [String: Any]?) -> Authenticator? {
89104
guard let type = config?["type"] as? String,
90105
let data = config?["data"] as? [String: Any] else {
91106
return nil
92107
}
93-
108+
94109
switch type {
95-
case "session":
96-
guard let sessionID = data["sessionID"] as? String,
97-
let cookieName = data["cookieName"] as? String else {
98-
return nil
99-
}
100-
return SessionAuthenticator(sessionID: sessionID, cookieName: cookieName)
101-
102-
case "basic":
103-
guard let username = data["username"] as? String,
104-
let password = data["password"] as? String else {
110+
case "session":
111+
guard let sessionID = data["sessionID"] as? String,
112+
let cookieName = data["cookieName"] as? String else {
113+
return nil
114+
}
115+
return SessionAuthenticator(sessionID: sessionID, cookieName: cookieName)
116+
117+
case "basic":
118+
guard let username = data["username"] as? String,
119+
let password = data["password"] as? String else {
120+
return nil
121+
}
122+
return BasicAuthenticator(username: username, password: password)
123+
124+
default:
105125
return nil
106-
}
107-
return BasicAuthenticator(username: username, password: password)
108-
109-
default:
110-
return nil
111126
}
112127
}
113-
128+
114129
public static func generateReplicatorStatusJson(_ status: Replicator.Status) -> [String: Any] {
115130
var errorJson: [String: Any]?
116131
if let error = status.error {
117132
errorJson = [
118133
"message": error.localizedDescription
119134
]
120135
}
121-
136+
122137
let progressJson: [String: Any] = [
123138
"completed": status.progress.completed,
124139
"total": status.progress.total
125140
]
126-
141+
127142
if let errorJson = errorJson {
128143
return [
129144
"activityLevel": status.activity.rawValue,
@@ -137,10 +152,10 @@ public struct ReplicatorHelper {
137152
]
138153
}
139154
}
140-
155+
141156
public static func generateReplicationJson(_ replication: [ReplicatedDocument], isPush: Bool) -> [String: Any] {
142157
var docs = [[String: Any]]()
143-
158+
144159
for document in replication {
145160
var flags = [String]()
146161
if document.flags.contains(.deleted) {
@@ -149,21 +164,21 @@ public struct ReplicatorHelper {
149164
if document.flags.contains(.accessRemoved) {
150165
flags.append("ACCESS_REMOVED")
151166
}
152-
var documentDictionary: [String: Any] = ["id": document.id, "flags": flags]
153-
167+
var documentDictionary: [String: Any] = ["id": document.id, "flags": flags, "scopeName": document.scope, "collectionName": document.collection]
168+
154169
if let error = document.error {
155170
documentDictionary["error"] = [
156171
"message": error.localizedDescription
157172
]
158173
}
159-
174+
160175
docs.append(documentDictionary)
161176
}
162-
177+
163178
return [
164-
"direction": isPush ? "PUSH" : "PULL",
179+
"isPush": isPush ? true : false,
165180
"documents": docs
166181
]
167182
}
168-
183+
169184
}

CbliteSwiftJsLib/Classes/ReplicatorManager.swift

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,16 +40,13 @@ public class ReplicatorManager {
4040

4141
// MARK: Replicator Functions
4242

43-
public func replicator(_ replicatorConfig: [String: Any]) throws -> String {
44-
do {
43+
public func replicator(_ replicatorConfig: [String: Any], collectionConfiguration: [CollectionConfigItem]) throws -> String {
4544
let id = UUID().uuidString
46-
let config = try ReplicatorHelper.replicatorConfigFromJson(replicatorConfig)
45+
let config = try ReplicatorHelper.replicatorConfigFromJson(replicatorConfig, collectionConfiguration: collectionConfiguration)
46+
4747
let replicator = Replicator(config: config)
4848
replicators[id] = replicator
4949
return id
50-
} catch {
51-
throw ReplicatorError.fatalError(message: error.localizedDescription)
52-
}
5350
}
5451

5552
public func start(_ replicatorId: String) throws {
@@ -91,6 +88,19 @@ public class ReplicatorManager {
9188
throw ReplicatorError.unableToFindReplicator(replicatorId: replicatorId)
9289
}
9390
}
91+
92+
public func getPendingDocumentIds(_ replicatorId: String, collection: Collection) throws -> [String:Any] {
93+
if let replicator = getReplicator(replicatorId: replicatorId) {
94+
do {
95+
let documentIds = try replicator.pendingDocumentIds(collection: collection)
96+
return ["documentIds": documentIds];
97+
} catch {
98+
throw error
99+
}
100+
} else {
101+
throw ReplicatorError.unableToFindReplicator(replicatorId: replicatorId)
102+
}
103+
}
94104

95105
public func cleanUp(_ replicatorId: String) throws {
96106
if let replicator = getReplicator(replicatorId: replicatorId) {

0 commit comments

Comments
 (0)