-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathReplicatorHelper.swift
182 lines (151 loc) · 7.27 KB
/
ReplicatorHelper.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
//
// ReplicatorHelper.swift
// CbliteSwiftJsLib
//
import Foundation
import JavaScriptCore
import CouchbaseLiteSwift
public struct ReplicatorHelper {
public static func replicatorConfigFromJson(_ data: [String: Any], collectionConfiguration: [CollectionConfigItem]) throws -> ReplicatorConfiguration {
guard let target = data["target"] as? [String: Any],
let url = target["url"] as? String,
let replicatorType = data["replicatorType"] as? String,
let continuous = data["continuous"] as? Bool,
let acceptParentDomainCookies = data["acceptParentDomainCookies"] as? Bool,
let acceptSelfSignedCerts = data["acceptSelfSignedCerts"] as? Bool,
let allowReplicationInBackground = data["allowReplicationInBackground"] as? Bool,
let autoPurgeEnabled = data["autoPurgeEnabled"] as? Bool,
let heartbeat = data["heartbeat"] as? NSNumber,
let maxAttempts = data["maxAttempts"] as? NSNumber,
let maxAttemptWaitTime = data["maxAttemptWaitTime"] as? NSNumber
else {
throw ReplicatorError.fatalError(message: "Invalid JSON data")
}
let endpoint = URLEndpoint(url: URL(string: url)!)
//set values from data
var replConfig = ReplicatorConfiguration(target: endpoint)
replConfig.acceptParentDomainCookie = acceptSelfSignedCerts
replConfig.acceptParentDomainCookie = acceptParentDomainCookies
replConfig.allowReplicatingInBackground = allowReplicationInBackground
replConfig.continuous = continuous
replConfig.enableAutoPurge = autoPurgeEnabled
replConfig.heartbeat = TimeInterval(exactly: heartbeat.int64Value) ?? 300
replConfig.maxAttemptWaitTime = TimeInterval(exactly: maxAttemptWaitTime.int64Value) ?? 0
replConfig.maxAttempts = maxAttempts.uintValue
//check for headers
if let headers = data["headers"] as? [String: String] {
replConfig.headers = headers
}
if let authenticatorData = data["authenticator"], !(authenticatorData is String && authenticatorData as! String == "") {
if let authenticatorConfig = authenticatorData as? [String: Any] {
if let authenticator = ReplicatorHelper.replicatorAuthenticatorFromConfig(authenticatorConfig) {
replConfig.authenticator = authenticator
}
}
}
try ReplicatorHelper.replicatorCollectionConfigFromJson(collectionConfiguration, replicationConfig: &replConfig)
switch replicatorType {
case "PUSH_AND_PULL":
replConfig.replicatorType = .pushAndPull
case "PULL":
replConfig.replicatorType = .pull
case "PUSH":
replConfig.replicatorType = .push
default:
throw ReplicatorError.fatalError(message: "Invalid replicatorType")
}
return replConfig
}
public static func replicatorCollectionConfigFromJson(_ data: [CollectionConfigItem], replicationConfig: inout ReplicatorConfiguration) throws {
//work on the collections sent in as part of the configuration with an array of collectionName, scopeName, and databaseName
for item in data {
var collections: [Collection] = []
for col in item.collections {
guard let collection = try CollectionManager.shared.getCollection(col.collection.name, scopeName: col.collection.scopeName, databaseName: col.collection.databaseName) else {
throw CollectionError.unableToFindCollection(collectionName: col.collection.name, scopeName: col.collection.scopeName, databaseName: col.collection.databaseName)
}
collections.append(collection)
}
//process the config part of the data
var collectionConfig = CollectionConfiguration()
//get the channels and documentIds to filter for the collections
//these are optional
if item.config.channels.count > 0 {
collectionConfig.channels = item.config.channels
}
if item.config.documentIds.count > 0 {
collectionConfig.documentIDs = item.config.documentIds
}
replicationConfig.addCollections(collections, config: collectionConfig)
}
}
private static func replicatorAuthenticatorFromConfig(_ config: [String: Any]?) -> Authenticator? {
guard let type = config?["type"] as? String,
let data = config?["data"] as? [String: Any] else {
return nil
}
switch type {
case "session":
guard let sessionID = data["sessionID"] as? String,
let cookieName = data["cookieName"] as? String else {
return nil
}
return SessionAuthenticator(sessionID: sessionID, cookieName: cookieName)
case "basic":
guard let username = data["username"] as? String,
let password = data["password"] as? String else {
return nil
}
return BasicAuthenticator(username: username, password: password)
default:
return nil
}
}
public static func generateReplicatorStatusJson(_ status: Replicator.Status) -> [String: Any] {
var errorJson: [String: Any]?
if let error = status.error {
errorJson = [
"message": error.localizedDescription
]
}
let progressJson: [String: Any] = [
"completed": status.progress.completed,
"total": status.progress.total
]
if let errorJson = errorJson {
return [
"activityLevel": status.activity.rawValue,
"error": errorJson,
"progress": progressJson
]
} else {
return [
"activityLevel": status.activity.rawValue,
"progress": progressJson
]
}
}
public static func generateReplicationJson(_ replication: [ReplicatedDocument], isPush: Bool) -> [String: Any] {
var docs = [[String: Any]]()
for document in replication {
var flags = [String]()
if document.flags.contains(.deleted) {
flags.append("DELETED")
}
if document.flags.contains(.accessRemoved) {
flags.append("ACCESS_REMOVED")
}
var documentDictionary: [String: Any] = ["id": document.id, "flags": flags, "scopeName": document.scope, "collectionName": document.collection]
if let error = document.error {
documentDictionary["error"] = [
"message": error.localizedDescription
]
}
docs.append(documentDictionary)
}
return [
"isPush": isPush ? true : false,
"documents": docs
]
}
}