Newer
Older
import Retry
import Models
import Combine
import Defaults
import Foundation
public class Client {
@KeyObject(.inappnotifications, defaultValue: true) var inappnotifications: Bool
let bindings: BindingsInterface
var dummyManager: DummyTrafficManaging?
var groupManager: GroupManagerInterface?
var userDiscovery: UserDiscoveryInterface?
var transferManager: TransferManagerInterface?
var backup: AnyPublisher<Data, Never> { backupSubject.eraseToAnyPublisher() }
var network: AnyPublisher<Bool, Never> { networkSubject.eraseToAnyPublisher() }
var resets: AnyPublisher<Contact, Never> { resetsSubject.eraseToAnyPublisher() }
var messages: AnyPublisher<Message, Never> { messagesSubject.eraseToAnyPublisher() }
var requests: AnyPublisher<Contact, Never> { requestsSubject.eraseToAnyPublisher() }
var events: AnyPublisher<BackendEvent, Never> { eventsSubject.eraseToAnyPublisher() }
var requestsSent: AnyPublisher<Contact, Never> { requestsSentSubject.eraseToAnyPublisher() }
var confirmations: AnyPublisher<Contact, Never> { confirmationsSubject.eraseToAnyPublisher() }
var groupMessages: AnyPublisher<GroupMessage, Never> { groupMessagesSubject.eraseToAnyPublisher() }
var incomingTransfers: AnyPublisher<FileTransfer, Never> { transfersSubject.eraseToAnyPublisher() }
var groupRequests: AnyPublisher<(Group, [Data], String?), Never> { groupRequestsSubject.eraseToAnyPublisher() }
private let backupSubject = PassthroughSubject<Data, Never>()
private let networkSubject = PassthroughSubject<Bool, Never>()
private let resetsSubject = PassthroughSubject<Contact, Never>()
private let requestsSubject = PassthroughSubject<Contact, Never>()
private let messagesSubject = PassthroughSubject<Message, Never>()
private let eventsSubject = PassthroughSubject<BackendEvent, Never>()
private let requestsSentSubject = PassthroughSubject<Contact, Never>()
private let confirmationsSubject = PassthroughSubject<Contact, Never>()
private let transfersSubject = PassthroughSubject<FileTransfer, Never>()
private let groupMessagesSubject = PassthroughSubject<GroupMessage, Never>()
private let groupRequestsSubject = PassthroughSubject<(Group, [Data], String?), Never>()
private var isBackupInitialization = false
private var isBackupInitializationCompleted = false
init(
_ bindings: BindingsInterface,
fromBackup: Bool,
email: String?,
phone: String?
) {
if fromBackup {
try instantiateUserDiscoveryFromBackup(email: email, phone: phone)
} else {
try instantiateUserDiscovery()
}
try instantiateTransferManager()
try instantiateDummyTrafficManager()
updatePreImage()
} catch {
log(string: error.localizedDescription, type: .error)
}
}
backupManager = bindings.initializeBackup(passphrase: passphrase) { [weak backupSubject] in
public func resumeBackup() {
backupManager = nil
backupManager = bindings.resumeBackup { [weak backupSubject] in
backupSubject?.send($0)
}
}
// public func isBackupRunning() -> Bool {
// guard let backupManager = backupManager else { return false }
// return backupManager.isBackupRunning()
// }
public func addJson(_ string: String) {
guard let backupManager = backupManager else { return }
backupManager.addJson(string)
}
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
public func stopListeningBackup() {
guard let backupManager = backupManager else { return }
try? backupManager.stop()
self.backupManager = nil
}
public func restoreContacts(fromBackup backup: Data) {
var totalPendingRestoration: Int = 0
let report = bindings.restore(
ids: backup,
using: userDiscovery!) { [weak self] in
guard let self = self else { return }
switch $0 {
case .success(var contact):
contact.status = .requested
self.requestsSentSubject.send(contact)
print(">>> Restored \(contact.username). Setting status as requested")
case .failure(let error):
print(">>> \(error.localizedDescription)")
}
} restoreCallback: { numFound, numRestored, total, errorString in
totalPendingRestoration = total
let results =
"""
>>> Results from within closure of RestoreContacts:
- numFound: \(numFound)
- numRestored: \(numRestored)
- total: \(total)
- errorString: \(errorString)
"""
print(results)
}
guard totalPendingRestoration > 0 else { fatalError("Total is zero, why called restore contacts?") }
guard report.lenRestored() == totalPendingRestoration else {
print(">>> numRestored \(report.lenRestored()) is != than the total (\(totalPendingRestoration)). Going on recursion...\nnumFailed: \(report.lenFailed())\n\(report.getRestoreContactsError())")
restoreContacts(fromBackup: backup)
return
isBackupInitializationCompleted = true
}
private func registerListenersAndStart() throws {
bindings.listenNetworkUpdates { [weak networkSubject] in networkSubject?.send($0) }
bindings.listenRequests { [weak self] in
guard let self = self else { return }
if self.isBackupInitialization {
if self.isBackupInitializationCompleted {
self.requestsSubject.send($0)
}
} else {
self.requestsSubject.send($0)
}
} _: { [weak confirmationsSubject] in
} _: { [weak resetsSubject] in
resetsSubject?.send($0)
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
}
bindings.listenEvents { [weak eventsSubject] in
eventsSubject?.send($0)
}
groupManager = try bindings.listenGroupRequests { [weak groupRequestsSubject] request, members, welcome in
groupRequestsSubject?.send((request, members, welcome))
} groupMessages: { [weak groupMessagesSubject] in
groupMessagesSubject?.send($0)
}
bindings.listenPreImageUpdates()
try bindings.listenMessages { [weak messagesSubject] in
messagesSubject?.send($0)
}
bindings.startNetwork()
}
private func instantiateTransferManager() throws {
transferManager = try bindings.generateTransferManager { [weak transfersSubject] tid, name, type, sender in
/// Someone transfered something to me
/// but I haven't received yet. I'll store an
/// IncomingTransfer object so later on I can
/// pull up whatever this contact has sent me.
///
guard let name = name,
let type = type,
let contact = sender,
let _extension = Attachment.Extension.from(type) else {
log(string: "Transfer of \(name ?? "nil").\(type ?? "nil") is being dismissed", type: .error)
return
}
transfersSubject?.send(
FileTransfer(
tid: tid,
contact: contact,
fileName: name,
fileType: _extension.written,
isIncoming: true
)
)
}
}
private func instantiateUserDiscovery() throws {
retry(max: 4, retryStrategy: .delay(seconds: 1)) { [weak self] in
guard let self = self else { return }
self.userDiscovery = try self.bindings.generateUD()
}
}
private func instantiateUserDiscoveryFromBackup(email: String?, phone: String?) throws {
retry(max: 4, retryStrategy: .delay(seconds: 1)) { [weak self] in
guard let self = self else { return }
self.userDiscovery = try self.bindings.generateUDFromBackup(email: email, phone: phone)
}
}
private func instantiateDummyTrafficManager() throws {
dummyManager = try bindings.generateDummyTraficManager()
}
private func updatePreImage() {
if let defaults = UserDefaults(suiteName: "group.elixxir.messenger") {
defaults.set(bindings.getPreImages(), forKey: "preImage")
}
}
}