@functionland/react-native-fula 1.36.2 → 1.36.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/ios/Fula.swift CHANGED
@@ -1,1292 +1,1334 @@
1
- import Foundation
2
- import Foundation.NSDate // for TimeInterval
3
- import CommonCrypto
4
- import Wnfs
5
- import Fula
6
- import os.log
7
-
8
- extension OSLog {
9
-
10
- private static var subsystem = Bundle.main.bundleIdentifier!
11
-
12
- /// Logs the view cycles like a view that appeared.
13
- static let viewCycle = OSLog(subsystem: subsystem, category: "viewcycle")
14
-
15
- /// All logs related to tracking and analytics.
16
- static let statistics = OSLog(subsystem: subsystem, category: "statistics")
17
- }
18
-
19
- extension OSLog {
20
-
21
- func info(_ msg: String, _ args: CVarArg...) {
22
- os_log("%{public}@", log: self, type: .info, msg)
23
- }
24
-
25
- func error(_ msg: String, _ args: CVarArg...) {
26
- os_log("%{public}@", log: self, type: .error, msg)
27
- }
28
-
29
- // ... (more methods for different log levels, if needed)
30
- }
31
-
32
-
33
- @objc(FulaModule)
34
- class FulaModule: NSObject {
35
- public let NAME: String = "FulaModule"
36
- var fula: FulamobileClient?
37
-
38
- var client: Client?
39
- var wnfs: Wnfs?
40
- var fulaConfig: FulamobileConfig?
41
- var appDir: URL
42
- var fulaStorePath: String
43
- // Related to the Wnfs library
44
- var rootCid: Cid?
45
- var wnfsKey: Data?
46
- let userDataHelper = UserDataHelper()
47
- var secretKeyGlobal: Array<UInt8>?
48
- var identityEncryptedGlobal: String?
49
- static let PRIVATE_KEY_STORE_ID = "PRIVATE_KEY"
50
-
51
- // FIXME: Hardcoded ,fula should remove all the codec arguments as the rs-wnfs library removed its usage now.
52
- static let CODEC_DAG_CBOR = Int(113)
53
-
54
- enum MyError: Error {
55
- case runtimeError(String)
56
- }
57
-
58
- @objc(Client)
59
- public class Client: NSObject {
60
- let internalClient: FulamobileClient
61
-
62
- init(clientInput: FulamobileClient) {
63
- internalClient = clientInput
64
- }
65
-
66
- func get(_ cid: Data) throws -> Data {
67
- do {
68
- print(String(format: "ReactNative get cid: %s", cid.toHex()))
69
- return try internalClient.get(cid)
70
- } catch let error {
71
- throw error
72
- }
73
- }
74
-
75
- func put(_ cid: Data, _ data: Data) throws -> Void {
76
- do {
77
- print(String(format: "ReactNative put(%s) data: %s", cid.toHex(), data.toHex()))
78
- try internalClient.put(data, codec: 0xFF & Int64(cid[1]))
79
- } catch let error {
80
- print("ReactNative put: ", error.localizedDescription)
81
- throw error
82
- }
83
- }
84
- }
85
- override init() {
86
-
87
- self.appDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
88
- let fulaStoreURL = appDir.appendingPathComponent("/fula")
89
-
90
- self.fulaStorePath = fulaStoreURL.path
91
- let fileManager = FileManager.default
92
- var success = true
93
- if !fileManager.fileExists(atPath: fulaStorePath) {
94
- do{
95
- try fileManager.createDirectory(atPath: fulaStorePath, withIntermediateDirectories: true)
96
- }catch let error{
97
- print(error.localizedDescription)
98
- success = false
99
- }
100
-
101
- }
102
- if success {
103
- print("Fula store folder created")
104
- } else {
105
- print("Unable to create fula store folder!")
106
-
107
- }
108
- super.init()
109
-
110
- }
111
- func convertConfigToJson(config: Cid) -> String {
112
- return String(format: "{\"cid\": \"%@\"}", config)
113
- }
114
-
115
- func getName() -> String {
116
- return NAME
117
- }
118
-
119
- func toByte(_ input: String) -> Data {
120
- return input.data(using: .utf8)!
121
- }
122
-
123
-
124
- func stringArrToIntArr(_ s: Array<String>) -> Array<Int> {
125
- return s.map { Int($0)!}
126
- }
127
-
128
- func convertIntToByte(_ s: Array<Int>) -> Array<UInt8> {
129
- return s.map { UInt8(exactly: $0)!}
130
- }
131
-
132
- func convertStringToByte(_ input: String) -> Array<UInt8> {
133
- let splitted = input.split(separator: ",").map { String($0) }
134
- let keyInt = stringArrToIntArr(splitted)
135
- return convertIntToByte(keyInt)
136
- }
137
-
138
- @objc(checkConnection:withResolver:withRejecter:)
139
- func checkConnection(timeout: NSNumber, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
140
- OSLog.viewCycle.info("ReactNative checkConnection started with timeout=\(timeout)")
141
-
142
- if let timeoutInt = timeout as? Int {
143
- if fula != nil {
144
- DispatchQueue.global(qos: .default).async {
145
- do {
146
- let connectionStatus = try self.checkConnectionInternal(timeout: timeoutInt)
147
- OSLog.viewCycle.info("ReactNative checkConnection ended \(connectionStatus)")
148
- resolve(connectionStatus)
149
- }
150
- catch let error {
151
- OSLog.viewCycle.info("ReactNative checkConnection failed with Error: \(error.localizedDescription)")
152
- resolve(false)
153
- }
154
- }
155
- } else {
156
- OSLog.viewCycle.info("ReactNative checkConnection fula is null")
157
- resolve(false)
158
- }
159
- } else {
160
- OSLog.viewCycle.error("ReactNative checkConnection - invalid timeout value")
161
- reject("ERR_INVALID_TIMEOUT", "Invalid timeout value", nil)
162
- }
163
- }
164
-
165
-
166
- @objc(newClient:withStorePath:withBloxAddr:withExchange:withAutoFlush:withUseRelay:withRefresh:withResolver:withRejecter:)
167
- func newClient(identityString: String, storePath: String, bloxAddr: String, exchange: String, autoFlush: Bool, useRelay: Bool, refresh: Bool, resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
168
- print("ReactNative", "newClient storePath= " , storePath , " bloxAddr= " , bloxAddr , " exchange= " , exchange , " autoFlush= " , autoFlush , " useRelay= " , useRelay , " refresh= " , refresh);
169
- do {
170
- print("ReactNative", "newClient storePath= ", storePath)
171
- let identity = toByte(identityString)
172
- print("ReactNative", "newClient identity= ", identityString)
173
- try newClientInternal(identity: identity, storePath: storePath, bloxAddr: bloxAddr, exchange: exchange, autoFlush: autoFlush, useRelay: useRelay, refresh: refresh)
174
- let peerId = fula?.id_()
175
- resolve(peerId)
176
- } catch let error {
177
- print("ReactNative", "newClient failed with Error: ", error.localizedDescription)
178
- reject("ERR_FULA", "Can't create client", error)
179
- }
180
-
181
- }
182
-
183
- @objc(isReady:withResolver:withRejecter:)
184
- func isReady(filesystemCheck: Bool, resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void{
185
- print("ReactNative", "isReady started")
186
- var initialized = false
187
- do {
188
- if (fula != nil && !fula!.id_().isEmpty) {
189
- if (filesystemCheck) {
190
- if (client != nil && rootCid != nil && !rootCid!.isEmpty) {
191
- initialized = true
192
- }
193
- } else {
194
- initialized = true
195
- }
196
- }
197
- resolve(initialized)
198
- } catch let error {
199
- print("ReactNative", "isReady failed with Error: " + error.localizedDescription)
200
- reject("ERR_FULA", "Check if fula is ready", error)
201
- }
202
- }
203
-
204
- //TODO: we should consider refactor the name of this \
205
- // function to be compatible with the android version.
206
- @objc(initFula:withStorePath:withBloxAddr:withExchange:withAutoFlush:withRootConfig:withUseRelay:withRefresh:withResolver:withRejecter:)
207
- func initFula(identityString: String, storePath: String, bloxAddr: String, exchange: String, autoFlush: Bool, rootConfig: String, useRelay: Bool, refresh: Bool, resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
208
-
209
- OSLog.viewCycle.info("ReactNative - init started")
210
-
211
- do {
212
-
213
- var resultData = Dictionary<String, String>()
214
- OSLog.viewCycle.info("ReactNative init storePath= \(storePath)")
215
- let identity = self.toByte(identityString)
216
- OSLog.viewCycle.info("ReactNative init identity= \(identityString)")
217
- let obj = try initInternal(identity: identity, storePath: storePath, bloxAddr: bloxAddr, exchange: exchange, autoFlush: autoFlush, _rootCid: rootConfig, useRelay: useRelay, refresh: refresh)
218
- OSLog.viewCycle.info("ReactNative init object created: [ \(obj[0]), \(obj[1]), \(obj[2]) ]")
219
- resultData["peerId"] = obj[0]
220
- resultData["rootCid"] = obj[1]
221
- resultData["wnfs_key"] = obj[2]
222
- resolve(resultData as NSDictionary)
223
-
224
- } catch let error {
225
- OSLog.viewCycle.info("ReactNative init failed with Error: \(error.localizedDescription)")
226
- reject("ERR_FULA", "init failed", error)
227
- }
228
-
229
- }
230
-
231
- @objc(logout:withStorePath:withResolver:withRejecter:)
232
- func logout(identityString: String, storePath: String, resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void{
233
-
234
- print("ReactNative", "logout started")
235
- do {
236
- let identity = toByte(identityString)
237
- try logoutInternal(identity: identity, _storePath: storePath)
238
- print("ReactNative", "logout completed")
239
- resolve("")
240
-
241
- } catch let error {
242
- print("ReactNative", "logout failed with Error: ", error.localizedDescription)
243
- reject("ERR_FULA", "logout failed", error)
244
- }
245
-
246
- }
247
-
248
- func checkConnectionInternal(timeout: Int) throws -> Bool {
249
- OSLog.viewCycle.info("ReactNative checkConnectionInternal started with timeout: \(timeout)")
250
- var connectionStatus = false
251
-
252
- if let fula = self.fula {
253
- let semaphore = DispatchSemaphore(value: 0)
254
- let queue = DispatchQueue(label: "com.yourapp.checkConnection", attributes: .concurrent)
255
-
256
- queue.async {
257
- do {
258
- OSLog.viewCycle.info("ReactNative connectToBlox started")
259
- try fula.connectToBlox()
260
- connectionStatus = true
261
- OSLog.viewCycle.info("ReactNative checkConnectionInternal succeeded")
262
- semaphore.signal()
263
- } catch let error {
264
- OSLog.viewCycle.info("ReactNative checkConnectionInternal failed with Error: \(error.localizedDescription)")
265
- semaphore.signal()
266
- }
267
- }
268
-
269
- let timeoutResult = semaphore.wait(timeout: .now() + .seconds(timeout))
270
- switch timeoutResult {
271
- case .timedOut:
272
- OSLog.viewCycle.info("ReactNative checkConnectionInternal timed out")
273
- return false
274
- case .success:
275
- return connectionStatus
276
- }
277
- } else {
278
- OSLog.viewCycle.info("ReactNative checkConnectionInternal failed because fula is not initialized")
279
- return false
280
- }
281
- }
282
-
283
- @objc(checkFailedActions:withTimeout:withResolver:withRejecter:)
284
- func checkFailedActions(retry: Bool, timeout: Int, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void {
285
- do {
286
- guard let fula = fula else {
287
- throw NSError(domain: "ERR_FULA", code: 1001, userInfo: [NSLocalizedDescriptionKey: "Fula is not initialized"])
288
- }
289
-
290
- if !retry {
291
- OSLog.viewCycle.info("ReactNative checkFailedActions without retry")
292
- let failedLinks = try fula.listFailedPushes()
293
-
294
- let nextFailedLink = try failedLinks.next()
295
- if nextFailedLink != nil {
296
- // Assuming nextFailedLink is of type Data; replace `toHex()` with an appropriate method to convert Data to a hex string
297
- OSLog.viewCycle.info("ReactNative checkFailedActions found")
298
- resolve(true)
299
- } else {
300
- resolve(false)
301
- }
302
- } else {
303
- OSLog.viewCycle.info("ReactNative checkFailedActions with retry")
304
- let retryResults = try retryFailedActionsInternal(timeout: timeout) // Ensure retryFailedActionsInternal accepts a timeout parameter
305
- resolve(!retryResults)
306
- }
307
- } catch let error {
308
- OSLog.viewCycle.info("ReactNative checkFailedActions failed with Error: \(error.localizedDescription)")
309
- reject("ERR_FULA", "CheckFailedActions failed", error)
310
- }
311
- }
312
-
313
-
314
-
315
- func retryFailedActionsInternal(timeout: Int) throws -> Bool {
316
- OSLog.viewCycle.info("ReactNative retryFailedActionsInternal started")
317
-
318
- guard let fula = fula else {
319
- OSLog.viewCycle.info("ReactNative retryFailedActionsInternal failed because fula is not initialized")
320
- return false
321
- }
322
-
323
- do {
324
- let connectionCheck = try checkConnectionInternal(timeout: timeout)
325
-
326
- if connectionCheck {
327
- do {
328
- OSLog.viewCycle.info("ReactNative retryFailedPushes started")
329
- try fula.retryFailedPushes()
330
- OSLog.viewCycle.info("ReactNative flush started")
331
- try fula.flush()
332
- return true
333
- } catch let error {
334
- try fula.flush()
335
- OSLog.viewCycle.info("ReactNative retryFailedActionsInternal failed with Error: \(error.localizedDescription)")
336
- return false
337
- }
338
- } else {
339
- OSLog.viewCycle.info("ReactNative retryFailedActionsInternal failed because blox is offline")
340
- return false
341
- }
342
- } catch let error {
343
- OSLog.viewCycle.info("ReactNative retryFailedActionsInternal failed with Error: \(error.localizedDescription)")
344
- return false
345
- }
346
- }
347
-
348
-
349
-
350
- func createPeerIdentity(privateKey: Data) throws -> Data {
351
- do {
352
- // 1: First: create public key from provided private key
353
- // 2: Should read the local keychain store (if it is key-value, key is public key above,
354
- // 3: if found, decrypt using the private key
355
- // 4: If not found or decryption not successful, generate an identity
356
- // 5: then encrypt and store in keychain
357
- // TODO: recheck error handling
358
- var encryptedKey = userDataHelper.getValue(FulaModule.PRIVATE_KEY_STORE_ID)
359
- let secretKey = try Cryptography.generateKey(privateKey)
360
- if (encryptedKey == nil) {
361
- var error: NSError?
362
- let autoGeneratedIdentity = FulamobileGenerateEd25519Key(&error)
363
- if error != nil {
364
- throw error!
365
- }
366
- encryptedKey = try Cryptography.encryptMsg(autoGeneratedIdentity!.toUint8Array(), secretKey)
367
- userDataHelper.add(FulaModule.PRIVATE_KEY_STORE_ID, encryptedKey!)
368
- }
369
- return try Cryptography.decryptMsg(encryptedKey!, secretKey).toData()
370
-
371
- } catch let error {
372
- print("ReactNative", "createPeerIdentity failed with Error: ", error.localizedDescription)
373
- throw error
374
- }
375
- }
376
-
377
- func createNewrootCid(identity: Data) throws -> Void {
378
- let hash32 = identity.sha256()
379
- print("ReactNative", "wnfsKey=" , identity.toHex() , "; hash32 = " , hash32.toHex());
380
- if (fula != nil) {
381
- try fula?.flush()
382
- }
383
- rootCid = try wnfs?.Init(wnfsKey: hash32)
384
- print("ReactNative", "privateForest is created: ", rootCid!)
385
- wnfsKey = identity
386
- print("ReactNative", "rootCid is created: cid=", rootCid!, " ; wnfs_key=", wnfsKey!.toHex(), "; hash32=", hash32)
387
- try encryptAndStoreConfig()
388
- }
389
-
390
- func loadWnfs(_ _wnfsKey: Data , _ _rootCid: String) throws {
391
- OSLog.viewCycle.info("ReactNative loadWnfs called: rootCid=\(_rootCid)")
392
- let hash32 = _wnfsKey.sha256()
393
- OSLog.viewCycle.info("ReactNative wnfsKey= \(_wnfsKey.toHex()) ; hash32 = \(hash32.toHex())");
394
- try wnfs?.LoadWithWNFSKey(wnfsKey: hash32, cid: _rootCid)
395
- rootCid = _rootCid
396
- wnfsKey = _wnfsKey
397
- if (fula != nil) {
398
- try fula?.flush()
399
- }
400
- OSLog.viewCycle.info("ReactNative loadWnfs completed")
401
- try encryptAndStoreConfig()
402
- }
403
-
404
-
405
- func encryptAndStoreConfig() throws {
406
- do {
407
- if let identityEncryptedGlobalUnwrapped = identityEncryptedGlobal {
408
- OSLog.viewCycle.info("ReactNative encryptAndStoreConfig started")
409
-
410
- if let rootCidUnwrapped = rootCid, let wnfsKeyUnwrapped = wnfsKey, let secretKeyGlobalUnwrapped = secretKeyGlobal {
411
- OSLog.viewCycle.info("ReactNative encryptAndStoreConfig started with rootCid: \(rootCidUnwrapped.toUint8Array()) and wnfsKey:\(wnfsKeyUnwrapped)")
412
-
413
- let cid_encrypted = try Cryptography.encryptMsg(rootCidUnwrapped.toUint8Array(), secretKeyGlobalUnwrapped)
414
- OSLog.viewCycle.info("ReactNative encryptAndStoreConfig cid_encrypted: \(cid_encrypted)")
415
-
416
- let wnfs_key_encrypted = try Cryptography.encryptMsg(wnfsKeyUnwrapped.toUint8Array(), secretKeyGlobalUnwrapped)
417
- OSLog.viewCycle.info("ReactNative encryptAndStoreConfig wnfs_key_encrypted: \(wnfs_key_encrypted)")
418
-
419
- userDataHelper.add("cid_encrypted_" + identityEncryptedGlobalUnwrapped, cid_encrypted)
420
- userDataHelper.add("wnfs_key_encrypted_" + identityEncryptedGlobalUnwrapped, wnfs_key_encrypted)
421
- } else {
422
- // Handle the case where rootCid, wnfsKey, or secretKeyGlobal is nil
423
- OSLog.viewCycle.info("ReactNative encryptAndStoreConfig failed because one of the values is nil")
424
- }
425
- }
426
- } catch let error {
427
- OSLog.viewCycle.info("ReactNative encryptAndStoreConfig failed with Error: \(error.localizedDescription)")
428
- throw error
429
- }
430
- }
431
-
432
- func logoutInternal(identity: Data, _storePath: String?) throws {
433
- do {
434
- if (fula != nil) {
435
- try fula?.flush()
436
- }
437
- let secretKey = try Cryptography.generateKey(identity)
438
- let identity_encrypted: String = try Cryptography.encryptMsg(identity.toUint8Array(), secretKey)
439
- userDataHelper.remove("cid_encrypted_"+identity_encrypted)
440
-
441
- //TODO: Should also remove peerid @Mahdi
442
-
443
- userDataHelper.remove("cid_encrypted_"+identity_encrypted)
444
-
445
- rootCid = nil
446
- secretKeyGlobal = nil
447
- identityEncryptedGlobal = nil
448
- var storePath = _storePath
449
- if (storePath == nil || storePath!.isEmpty) {
450
- storePath = fulaStorePath
451
- }
452
-
453
- do{
454
- try FileManager.default.removeItem(atPath: fulaStorePath)
455
- }catch let error{
456
- print("Deleting fula store path", error.localizedDescription)
457
- throw error
458
- }
459
- } catch let error {
460
- print("ReactNative", "logout internal failed with Error: ", error.localizedDescription)
461
- throw error
462
- }
463
- }
464
-
465
- func getFulaClient() -> FulamobileClient? {
466
- return fula
467
- }
468
-
469
- func newClientInternal(identity: Data, storePath: String?, bloxAddr: String, exchange: String, autoFlush: Bool, useRelay: Bool, refresh: Bool) throws -> Data {
470
- do {
471
- fulaConfig = FulamobileConfig()
472
- if (storePath == nil || storePath!.isEmpty) {
473
- fulaConfig!.storePath = fulaStorePath
474
- } else {
475
- fulaConfig!.storePath = storePath!
476
- }
477
- print("ReactNative", "storePath is set: " + fulaConfig!.storePath)
478
-
479
- let peerIdentity = try createPeerIdentity(privateKey: identity)
480
- fulaConfig!.identity = peerIdentity
481
- print("ReactNative", "peerIdentity is set: " + fulaConfig!.identity!.toHex())
482
- fulaConfig!.bloxAddr = bloxAddr
483
- print("ReactNative", "bloxAddr is set: " + fulaConfig!.bloxAddr)
484
- fulaConfig!.exchange = exchange
485
- fulaConfig!.syncWrites = autoFlush
486
- if (useRelay) {
487
- fulaConfig!.allowTransientConnection = true
488
- fulaConfig!.forceReachabilityPrivate = true
489
- }
490
- if (fula == nil || refresh) {
491
- print("ReactNative", "Creating a new Fula instance");
492
- do {
493
- try shutdownInternal();
494
- fula = FulamobileClient(fulaConfig)
495
- if (fula != nil) {
496
- try fula?.flush();
497
- }
498
- } catch let error {
499
- print("ReactNative", "Failed to create new Fula instance: " , error.localizedDescription);
500
- throw MyError.runtimeError("Failed to create new Fula instance")
501
- }
502
- }
503
- return peerIdentity
504
- } catch let error {
505
- print("ReactNative", "newclientInternal failed with Error: ", error.localizedDescription)
506
- throw error
507
- }
508
- }
509
-
510
- func initInternal(identity: Data, storePath: String, bloxAddr: String, exchange: String, autoFlush: Bool, _rootCid: String, useRelay: Bool, refresh: Bool) throws -> [String] {
511
-
512
- do {
513
- if (fula == nil || refresh) {
514
- try newClientInternal(identity: identity, storePath: storePath, bloxAddr: bloxAddr, exchange: exchange, autoFlush: autoFlush, useRelay: useRelay, refresh: refresh)
515
- OSLog.viewCycle.info("ReactNative fula initialized: \(self.fula!.id_())")
516
- }
517
- if(client == nil || refresh) {
518
- client = Client(clientInput: fula!)
519
- wnfs = Wnfs(putFn: { cid, data in
520
- guard let c = self.client else {
521
- throw MyError.runtimeError("wnfs: fula client not ready")
522
- }
523
- try c.put(cid, data)
524
- }, getFn: { cid in
525
- guard let c = self.client else {
526
- throw MyError.runtimeError("wnfs: fula client not ready")
527
- }
528
- return try c.get(cid)
529
- })
530
- OSLog.viewCycle.info("ReactNative wnfs initialized")
531
- }
532
-
533
- let secretKey = try Cryptography.generateKey(identity)
534
- let identity_encrypted = try Cryptography.encryptMsg(identity.toUint8Array(), secretKey)
535
- identityEncryptedGlobal = identity_encrypted
536
- secretKeyGlobal = secretKey
537
-
538
- if (rootCid == nil || rootCid!.isEmpty) {
539
- OSLog.viewCycle.info("ReactNative rootCid is empty.")
540
- //Load from keystore
541
-
542
- let cid_encrypted_fetched = userDataHelper.getValue("cid_encrypted_"+identity_encrypted)
543
- OSLog.viewCycle.info("ReactNative Here1")
544
- var cid: Array<UInt8>? = nil
545
- if(cid_encrypted_fetched != nil && !cid_encrypted_fetched!.isEmpty) {
546
- OSLog.viewCycle.info("ReactNative decrypting cid= \(cid_encrypted_fetched!) with secret \(secretKey.toHex())")
547
- cid = try Cryptography.decryptMsg(cid_encrypted_fetched!, secretKey)
548
- }
549
- print("ReactNative", "Here2")
550
- //print("ReactNative", "Attempted to fetch cid from keystore cid="+cid+" & wnfs_key="+wnfs_key)
551
- if(cid == nil || cid!.isEmpty){
552
- OSLog.viewCycle.info("ReactNative cid or wnfs key was not found")
553
- if(!_rootCid.isEmpty){
554
- OSLog.viewCycle.info("ReactNative Re-setting cid from input: \(_rootCid)")
555
- cid = _rootCid.toUint8Array()
556
- }
557
-
558
- }
559
- if(cid == nil || cid!.isEmpty){
560
- OSLog.viewCycle.info("ReactNative Tried to recover cid but was not successful. Creating ones")
561
- try createNewrootCid(identity: identity)
562
- } else {
563
- OSLog.viewCycle.info("ReactNative Found cid and wnfs key in keychain store")
564
- OSLog.viewCycle.info("ReactNative Recovered cid and private ref from keychain store. cid=\(cid!) & wnfs_key=\(identity)")
565
- try loadWnfs(identity, cid!.toData().toUTF8String()!)
566
- }
567
- OSLog.viewCycle.info("ReactNative creating/reloading rootCid completed")
568
-
569
- /*
570
- byte[] testbyte = convertStringToByte("-104,40,24,-93,24,100,24,114,24,111,24,111,24,116,24,-126,24,-126,0,0,24,-128,24,103,24,118,24,101,24,114,24,115,24,105,24,111,24,110,24,101,24,48,24,46,24,49,24,46,24,48,24,105,24,115,24,116,24,114,24,117,24,99,24,116,24,117,24,114,24,101,24,100,24,104,24,97,24,109,24,116")
571
- long testcodec = 85
572
- byte[] testputcid = client!.put(testbyte, testcodec)
573
- print("ReactNative", "client!.put test done"+ Arrays.toString(testputcid))
574
- byte[] testfetchedcid = convertStringToByte("1,113,18,32,-6,-63,-128,79,-102,-89,57,77,-8,67,-98,8,-81,40,-87,123,122,29,-52,-124,-60,-53,100,105,125,123,-5,-99,41,106,-124,-64")
575
- byte[] testfetchedbytes = client!.get(testfetchedcid)
576
- print("ReactNative", "client!.get test done"+ Arrays.toString(testfetchedbytes))
577
- */
578
-
579
-
580
- OSLog.viewCycle.info("ReactNative rootCid is created: cid=\(self.rootCid!) & wnfs_key=\(self.wnfsKey!.toHex())")
581
- } else {
582
- OSLog.viewCycle.info("ReactNative rootCid existed: cid=\(self.rootCid!) & wnfs_key=\(self.wnfsKey!.toHex())")
583
- }
584
- let peerId = fula!.id_()
585
- var obj = [String]()
586
- obj.append(peerId)
587
- obj.append(rootCid!)
588
- obj.append(wnfsKey!.toHex())
589
- OSLog.viewCycle.info("ReactNative initInternal is completed successfully")
590
- if (fula != nil) {
591
- try fula?.flush()
592
- }
593
- return obj
594
- } catch let error {
595
- OSLog.viewCycle.info("ReactNative init internal failed with Error: \(error.localizedDescription)")
596
- throw error
597
- }
598
- }
599
-
600
-
601
- @objc(mkdir:withResolver:withRejecter:)
602
- func mkdir(path: String, resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
603
- print("ReactNative", "mkdir: path = " + path)
604
- do {
605
- let cid = try wnfs?.MkDir(cid: rootCid!, remotePath: path)
606
- if(cid != nil) {
607
- rootCid = cid
608
- try encryptAndStoreConfig()
609
- if (fula != nil) {
610
- try fula?.flush()
611
- }
612
- resolve(rootCid)
613
- } else {
614
- print("ReactNative", "mkdir Error: config is nil")
615
- reject("ERR_WNFS", "Can't make dir", nil)
616
- }
617
-
618
- } catch let error{
619
- print("mkdir", error.localizedDescription)
620
- reject("ERR_WNFS", "mkdir", error)
621
- }
622
- }
623
-
624
- @objc(writeFile:withLocalFilename:withResolver:withRejecter:)
625
- func writeFile(fulaTargetFilename: String, localFilename: String, resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
626
- /*
627
- // reads content of the file form localFilename (should include full absolute path to local file with read permission
628
- // writes content to the specified location by fulaTargetFilename in Fula filesystem
629
- // fulaTargetFilename: a string including full path and filename of target file on Fula (e.g. root/pictures/cat.jpg)
630
- // localFilename: a string containing full path and filename of local file on hte device (e.g /usr/bin/cat.jpg)
631
- // Returns: new cid of the root after this file is placed in the tree
632
- */
633
- print("ReactNative", "writeFile to : path = " + fulaTargetFilename + ", from: " + localFilename)
634
- do {
635
- let cid = try wnfs?.WriteFileFromPath(cid: rootCid!, remotePath: fulaTargetFilename, fileUrl: URL.init(string: localFilename)!)
636
- if(cid != nil) {
637
- rootCid = cid
638
- try encryptAndStoreConfig()
639
- if (fula != nil) {
640
- try fula?.flush()
641
- }
642
- resolve(rootCid)
643
- } else {
644
- print("ReactNative", "writeFile Error: config is nil")
645
- reject("ERR_WNFS", "writeFile Error: config is nil", nil)
646
- }
647
- } catch let error {
648
- print("writeFile", error.localizedDescription)
649
- reject("ERR_WNFS", "writeFile", error)
650
- }
651
- }
652
-
653
- @objc(writeFileContent:withContentString:withResolver:withRejecter:)
654
- func writeFileContent(path: String, contentString: String, resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
655
-
656
- print("ReactNative", "writeFile: contentString = " + contentString)
657
- print("ReactNative", "writeFile: path = " + path)
658
- do {
659
- let content = convertStringToByte(contentString)
660
- let cid = try wnfs?.WriteFile(cid: rootCid!, remotePath: path, data: content.toData())
661
- rootCid = cid
662
- try encryptAndStoreConfig()
663
- if (fula != nil) {
664
- try fula?.flush()
665
- }
666
- resolve(rootCid)
667
- } catch let error {
668
- print("writeFileContent", error.localizedDescription)
669
- reject("ERR_WNFS", "writeFileContent", error)
670
- }
671
-
672
- }
673
-
674
- @objc(ls:withResolver:withRejecter:)
675
- func ls(path: String, resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
676
- print("ReactNative", "ls: path = " + path)
677
- do {
678
- let res = try wnfs?.Ls(cid: rootCid!, remotePath: path)
679
-
680
- //JSONArray jsonArray = new JSONArray(res)
681
- guard let s = res?.toUTF8String() else {
682
- throw MyError.runtimeError("converting bytes to utf8 string")
683
- }
684
- print("ReactNative", "ls: res = " + s)
685
- resolve(s)
686
- } catch let error {
687
- print("ls", error.localizedDescription)
688
- reject("ERR_WNFS", "ls", error)
689
- }
690
-
691
- }
692
-
693
- @objc(rm:withResolver:withRejecter:)
694
- func rm(path: String, resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
695
-
696
- print("ReactNative", "rm: path = " + path)
697
- do {
698
- let cid = try wnfs?.Rm(cid: rootCid!, remotePath: path)
699
- if(cid != nil) {
700
- rootCid = cid
701
- try encryptAndStoreConfig()
702
- if (fula != nil) {
703
- try fula?.flush()
704
- }
705
- resolve(rootCid)
706
- } else {
707
- print("ReactNative", "rm Error: config is nil")
708
- reject("ERR_WNFS", "rm Error: config is nil", nil)
709
- }
710
- } catch let error {
711
- print("rm", error.localizedDescription)
712
- reject("ERR_WNFS", "rm", error)
713
- }
714
-
715
- }
716
-
717
- @objc(cp:withTargetPath:withResolver:withRejecter:)
718
- func cp(sourcePath: String, targetPath: String, resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
719
-
720
- print("ReactNative", "rm: sourcePath = " + sourcePath)
721
- do {
722
- let cid = try wnfs?.Cp(cid: rootCid!, remotePathFrom: sourcePath, remotePathTo: targetPath)
723
- if(cid != nil) {
724
- rootCid = cid
725
- try encryptAndStoreConfig()
726
- if (fula != nil) {
727
- try fula?.flush()
728
- }
729
- resolve(rootCid)
730
- } else {
731
- print("ReactNative", "cp Error: config is nil")
732
- reject("ERR_WNFS", "cp Error: config is nil", nil)
733
- }
734
- } catch let error {
735
- print("cp", error.localizedDescription)
736
- reject("ERR_WNFS", "cp", error)
737
- }
738
-
739
- }
740
-
741
- @objc(mv:withTargetPath:withResolver:withRejecter:)
742
- func mv(sourcePath: String, targetPath: String, resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
743
- print("ReactNative", "rm: sourcePath = " + sourcePath)
744
- do {
745
- let cid = try wnfs?.Mv(cid: rootCid!, remotePathFrom: sourcePath, remotePathTo: targetPath)
746
- if(cid != nil) {
747
- rootCid = cid
748
- try encryptAndStoreConfig()
749
- if (fula != nil) {
750
- try fula?.flush()
751
- }
752
- resolve(rootCid)
753
- } else {
754
- print("ReactNative", "mv Error: config is nil")
755
- reject("ERR_WNFS", "mv Error: config is nil", nil)
756
- }
757
- } catch let error {
758
- print("mv", error.localizedDescription)
759
- reject("ERR_WNFS", "mv", error)
760
- }
761
-
762
- }
763
-
764
- @objc(readFile:withLocalFilename:withResolver:withRejecter:)
765
- func readFile(fulaTargetFilename: String, localFilename: String, resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
766
- /*
767
- // reads content of the file form localFilename (should include full absolute path to local file with read permission
768
- // writes content to the specified location by fulaTargetFilename in Fula filesystem
769
- // fulaTargetFilename: a string including full path and filename of target file on Fula (e.g. root/pictures/cat.jpg)
770
- // localFilename: a string containing full path and filename of local file on hte device (e.g /usr/bin/cat.jpg)
771
- // Returns: new cid of the root after this file is placed in the tree
772
- */
773
- print("ReactNative", "readFile: fulaTargetFilename = " + fulaTargetFilename)
774
- do {
775
- let path = try wnfs?.ReadFileToPath(cid: rootCid!, remotePath: fulaTargetFilename, fileUrl: URL.init(string: localFilename)!)
776
- resolve(path)
777
- } catch let error {
778
- print("readFile", error.localizedDescription)
779
- reject("ERR_WNFS", "readFile", error)
780
- }
781
-
782
- }
783
-
784
- @objc(readFileContent:withResolver:withRejecter:)
785
- func readFileContent(path: String, resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
786
-
787
- print("ReactNative", "readFileContent: path = " + path)
788
- do {
789
- // FIXME: dhouldn't we output an NSData object instead?
790
- let res = try wnfs?.ReadFile(cid: rootCid!, remotePath: path)
791
- guard let resString = res?.toUTF8String() else{
792
- throw MyError.runtimeError("converting bytes to utf8 string")
793
- }
794
- resolve(resString)
795
- } catch let error {
796
- print("readFileContent", error.localizedDescription)
797
- reject("ERR_WNFS", "readFileContent", error)
798
- }
799
-
800
- }
801
-
802
- @objc(get:withResolver:withRejecter:)
803
- func get(keyString: String, resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
804
-
805
- print("ReactNative", "get: keyString = " + keyString)
806
- do {
807
- let key: Data = convertStringToByte(keyString).toData()
808
- let value = try getInternal(key)
809
- let valueString: String = value.toUTF8String()!
810
- resolve(valueString)
811
- } catch let error {
812
- print("get", error.localizedDescription)
813
- reject("ERR_FULA", "get", error)
814
- }
815
-
816
- }
817
-
818
- func getInternal(_ key: Data) throws -> Data {
819
- do {
820
- print("ReactNative", "getInternal: key.toUTF8String() = " , key.toUTF8String()!)
821
- print("ReactNative", "getInternal: key.toHex().bytes = " , key.toHex())
822
- let value = try fula!.get(key)
823
- print("ReactNative", "getInternal: value.toHex() = " , value.toHex())
824
- return value
825
- } catch let error {
826
- print("ReactNative", "getInternal: error = " + error.localizedDescription)
827
- print("getInternal", error.localizedDescription)
828
- throw error
829
- }
830
- }
831
-
832
- @objc(has:withResolver:withRejecter:)
833
- func has(keyString: String, resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
834
-
835
- print("ReactNative", "has: keyString = " + keyString)
836
- do {
837
- let key: Data = convertStringToByte(keyString).toData()
838
- let result = try hasInternal(key)
839
- resolve(result)
840
- } catch let error {
841
- print("has", error.localizedDescription)
842
- reject("ERR_FULA", "has", error)
843
- }
844
-
845
- }
846
-
847
- func hasInternal(_ key: Data) throws -> Bool {
848
- do {
849
- let ret = UnsafeMutablePointer<ObjCBool>.allocate(capacity: 1)
850
- try fula?.has(key, ret0_: ret)
851
- let res = ret.pointee.boolValue
852
- ret.deallocate()
853
- return res
854
- } catch let error {
855
- print("hasInternal", error.localizedDescription)
856
- throw error
857
- }
858
- }
859
-
860
- func pullInternal(key: Data) throws -> Void {
861
- do {
862
- try fula!.pull(key)
863
- } catch let error {
864
- print("pullInternal", error.localizedDescription)
865
- throw error
866
- }
867
- }
868
-
869
- @objc(push:withRejecter:)
870
- func push(resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
871
- print("ReactNative", "push started")
872
- do {
873
- try pushInternal(key: convertStringToByte(rootCid!).toData())
874
- resolve(rootCid)
875
- } catch let error {
876
- print("get", error.localizedDescription)
877
- reject("ERR_FULA", "push", error)
878
- }
879
- }
880
-
881
- func pushInternal(key: Data) throws -> Void {
882
- do {
883
- let hasIt = try hasInternal(key)
884
- if (fula != nil && hasIt) {
885
- try fula?.push(key)
886
- try fula?.flush()
887
- } else {
888
- print("ReactNative", "pushInternal error: key wasn't found or fula is not initialized")
889
- throw MyError.runtimeError("pushInternal error: key wasn't found or fula is not initialized")
890
- }
891
- } catch let error {
892
- print("ReactNative", "pushInternal", error.localizedDescription)
893
- throw error
894
- }
895
- }
896
-
897
- // FIXME: unused codecString arg
898
- @objc(put:withCodecString:withResolver:withRejecter:)
899
- func put(valueString: String, codecString: String, resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
900
-
901
- print("ReactNative", "put: codecString = " + codecString)
902
- print("ReactNative", "put: valueString = " + valueString)
903
- do {
904
- //byte[] codec = convertStringToByte(CodecString)
905
- let codec = FulaModule.CODEC_DAG_CBOR
906
-
907
-
908
- print("ReactNative", "put: codec = ", codec)
909
- let value = valueString.toData()
910
-
911
- print("ReactNative", "put: value.toHex() = " , value.toHex())
912
- let key = try putInternal(value: value, codec: codec)
913
- print("ReactNative", "put: key.toHex() = " , key.toUTF8String()!)
914
- resolve(key.toUTF8String()!)
915
- } catch let error {
916
- print("ReactNative", "put: error = ", error.localizedDescription)
917
- reject("ERR_FULA", "put", error)
918
- }
919
-
920
- }
921
-
922
- // FIXME: unused codec arg
923
- func putInternal(value: Data, codec: Int) throws -> Data {
924
- do {
925
- if(fula != nil) {
926
- let key: Data = try fula!.put(value, codec: Int64(FulaModule.CODEC_DAG_CBOR))
927
- try fula?.flush()
928
- return key
929
- } else {
930
- print("ReactNative", "putInternal Error: fula is not initialized")
931
- throw MyError.runtimeError("putInternal Error: fula is not initialized")
932
- }
933
- } catch let error {
934
- print("ReactNative", "putInternal", error.localizedDescription)
935
- throw error
936
- }
937
- }
938
-
939
- @objc(setAuth:withAllow:withResolver:withRejecter:)
940
- func setAuth(peerIdString: String, allow: Bool, resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
941
-
942
- print("ReactNative", "setAuth: peerIdString = " + peerIdString)
943
- do {
944
- if (fula != nil && !(fula?.id_().isEmpty)! && fulaConfig != nil && !fulaConfig!.bloxAddr.isEmpty) {
945
- let bloxAddr = fulaConfig!.bloxAddr
946
- print("ReactNative", "setAuth: bloxAddr = '",bloxAddr,"'"," peerIdString = '",peerIdString,"'")
947
- let parts = bloxAddr.split(separator: "/").map(String.init)
948
- try fula?.setAuth(parts.last, subject: peerIdString, allow: allow)
949
- resolve(true)
950
- } else {
951
- print("ReactNative", "setAuth error: fula is not initialized")
952
- throw MyError.runtimeError("fula is not initialized")
953
- }
954
- resolve(false)
955
- } catch let error {
956
- print("get", error.localizedDescription)
957
- reject("ERR_FULA", "setAuth", error)
958
- }
959
-
960
- }
961
-
962
- @objc(shutdown:withRejecter:)
963
- func shutdown( resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) {
964
- do {
965
- try shutdownInternal()
966
- resolve(true)
967
- } catch let error {
968
- print("ReactNative", "shutdown", error.localizedDescription)
969
- reject("ERR_FULA", "shutdown", error)
970
- }
971
-
972
- }
973
-
974
- func shutdownInternal() throws {
975
- if(fula != nil) {
976
- try fula?.shutdown()
977
- fula = nil
978
- client = nil
979
- wnfs = nil
980
- }
981
- }
982
-
983
- ///////////////////////////////////////////////////////////
984
- ///////////////////////////////////////////////////////////
985
- ///////////////////////////////////////////////////////////
986
- ///////////////////////////////////////////////////////////
987
- //////////////////////ANYTHING BELOW IS FOR BLOCKCHAIN/////
988
- ///////////////////////////////////////////////////////////
989
- @objc(createAccount:withResolver:withRejecter:)
990
- func createAccount(seedString: String, resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
991
- print("ReactNative", "createAccount: seedString = ", seedString)
992
- do {
993
- if (fula == nil || ((fula?.id_().isEmpty) != nil)) {
994
- reject("ERR_FULA", "createAccount", MyError.runtimeError("Fula client is not initialized"))
995
- } else {
996
-
997
- if (!seedString.starts(with: "/")) {
998
- reject("ERR_FULA", "createAccount", MyError.runtimeError("seed should start with /"))
999
- }
1000
- let result = try fula!.seeded(seedString)
1001
- let resultString = result.toUTF8String()!
1002
- resolve(resultString)
1003
- }
1004
- } catch let error {
1005
- print("createAccount", error.localizedDescription)
1006
- reject("ERR_FULA", "createAccount", error)
1007
- }
1008
-
1009
- }
1010
-
1011
- @objc(checkAccountExists:withResolver:withRejecter:)
1012
- func checkAccountExists(accountString: String, resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
1013
- print("ReactNative", "checkAccountExists: accountString = ", accountString)
1014
- do {
1015
- let result = try fula!.accountExists(accountString)
1016
- let resultString = result.toUTF8String()!
1017
- resolve(resultString)
1018
- } catch let error {
1019
- print("checkAccountExists", error.localizedDescription)
1020
- reject("ERR_FULA", "checkAccountExists", error)
1021
- }
1022
-
1023
- }
1024
-
1025
- @objc(createPool:withPoolName:withResolver:withRejecter:)
1026
- func createPool(seedString: String, poolName: String, resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
1027
- print("ReactNative", "createPool: seedString = " + seedString + " poolName = " + poolName)
1028
- do {
1029
- let result = try fula!.poolCreate(seedString, poolName: poolName)
1030
- let resultString = result.toUTF8String()!
1031
- resolve(resultString)
1032
- } catch let error {
1033
- print("createPool", error.localizedDescription)
1034
- reject("ERR_FULA", "createPool", error)
1035
- }
1036
-
1037
- }
1038
-
1039
- @objc(listPools:withRejecter:)
1040
- func listPools( resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
1041
- print("ReactNative", "listPools")
1042
- do {
1043
- let result = try fula!.poolList()
1044
- let resultString = result.toUTF8String()!
1045
- resolve(resultString)
1046
- } catch let error {
1047
- print("listPools", error.localizedDescription)
1048
- reject("ERR_FULA", "listPools", error)
1049
- }
1050
-
1051
- }
1052
-
1053
- @objc(listPoolJoinRequests:withResolver:withRejecter:)
1054
- func listPoolJoinRequests(poolID: Int, resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
1055
- print("ReactNative", "listPoolJoinRequests: poolID = ", poolID)
1056
- do {
1057
- let result = try fula!.poolRequests(poolID)
1058
- let resultString = result.toUTF8String()!
1059
- resolve(resultString)
1060
- } catch let error {
1061
- print("listPoolJoinRequests", error.localizedDescription)
1062
- reject("ERR_FULA", "listPoolJoinRequests", error)
1063
- }
1064
-
1065
- }
1066
-
1067
- @objc(votePoolJoinRequest:withPoolID:withAccountString:withAccept:withResolver:withRejecter:)
1068
- func votePoolJoinRequest(seedString: String, poolID: Int, accountString: String, accept: Bool, resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
1069
- print("ReactNative", "votePoolJoinRequest: seedString = ", seedString ," poolID = ", poolID, " accountString = ", accountString , " accept = ", accept)
1070
- do {
1071
- let result = try fula!.poolVote(seedString, poolID: Int(poolID), account: accountString, voteValue: accept)
1072
- let resultString = result.toUTF8String()!
1073
- resolve(resultString)
1074
- } catch let error {
1075
- print("votePoolJoinRequest", error.localizedDescription)
1076
- reject("ERR_FULA", "votePoolJoinRequest", error)
1077
- }
1078
-
1079
- }
1080
-
1081
- @objc(newReplicationRequest:withPoolID:withReplicationFactor:withCid:withResolver:withRejecter:)
1082
- func newReplicationRequest(seedString: String, poolID: Int, replicationFactor: Int, cid: String, resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
1083
- print("ReactNative", "newReplicationRequest: seedString = " , seedString , " poolID = " , poolID , " replicationFactor = " , replicationFactor , " cid = " , cid)
1084
- do {
1085
- let result = try fula!.manifestUpload(seedString, poolID: poolID, replicationFactor: replicationFactor, uri: cid)
1086
- let resultString = result.toUTF8String()!
1087
- resolve(resultString)
1088
- } catch let error {
1089
- print("newReplicationRequest", error.localizedDescription)
1090
- reject("ERR_FULA", "newReplicationRequest", error)
1091
- }
1092
-
1093
- }
1094
-
1095
- @objc(newStoreRequest:withPoolID:withUploader:withCid:withResolver:withRejecter:)
1096
- func newStoreRequest(seedString: String, poolID: Int, uploader: String, cid: String, resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
1097
- print("ReactNative", "newStoreRequest: seedString = " + seedString + " poolID = " , poolID , " uploader = " , uploader , " cid = " , cid)
1098
- do {
1099
- let result = try fula!.manifestStore(seedString, poolID: poolID, uploader: uploader, cid: cid)
1100
- let resultString = result.toUTF8String()!
1101
- resolve(resultString)
1102
- } catch let error {
1103
- print("newStoreRequest", error.localizedDescription)
1104
- reject("ERR_FULA", "newStoreRequest", error)
1105
- }
1106
-
1107
- }
1108
-
1109
- @objc(listAvailableReplicationRequests:withResolver:withRejecter:)
1110
- func listAvailableReplicationRequests(poolID: Int, resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
1111
- print("ReactNative", "listAvailableReplicationRequests: poolID = ", poolID)
1112
- do {
1113
- let result = try fula!.manifestAvailable(poolID)
1114
- let resultString = result.toUTF8String()!
1115
- resolve(resultString)
1116
- } catch let error {
1117
- print("listAvailableReplicationRequests", error.localizedDescription)
1118
- reject("ERR_FULA", "listAvailableReplicationRequests", error)
1119
- }
1120
-
1121
- }
1122
-
1123
- @objc(removeReplicationRequest:withPoolID:withCid:withResolver:withRejecter:)
1124
- func removeReplicationRequest(seedString: String, poolID: Int, cid: String, resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
1125
- print("ReactNative", "newReplicationRequest: seedString = " , seedString , " poolID = " , poolID , " cid = " , cid)
1126
- do {
1127
- let result = try fula!.manifestRemove(seedString, poolID: poolID, cid: cid)
1128
- let resultString = result.toUTF8String()!
1129
- resolve(resultString)
1130
- } catch let error {
1131
- print("removeReplicationRequest", error.localizedDescription)
1132
- reject("ERR_FULA", "removeReplicationRequest", error)
1133
- }
1134
-
1135
- }
1136
-
1137
- @objc(removeStorer:withStorage:withPoolID:withCid:withResolver:withRejecter:)
1138
- func removeStorer(seedString: String, storage: String, poolID: Int, cid: String, resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
1139
- print("ReactNative", "removeStorer: seedString = " , seedString , " storage = " , storage , " poolID = " , poolID , " cid = " , cid)
1140
- do {
1141
- let result = try fula!.manifestRemoveStorer(seedString, storage: storage, poolID: poolID, cid: cid)
1142
- let resultString = result.toUTF8String()!
1143
- resolve(resultString)
1144
- } catch let error {
1145
- print("removeStorer", error.localizedDescription)
1146
- reject("ERR_FULA", "removeStorer", error)
1147
- }
1148
-
1149
- }
1150
-
1151
- @objc(removeStoredReplication:withUploader:withPoolID:withCid:withResolver:withRejecter:)
1152
- func removeStoredReplication(seedString: String, uploader: String, poolID: Int, cid: String, resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
1153
- print("ReactNative", "removeStoredReplication: seedString = " , seedString , " uploader = " , uploader , " poolID = " , poolID , " cid = " , cid)
1154
- do {
1155
- let result = try fula!.manifestRemoveStored(seedString, uploader: uploader, poolID: poolID, cid: cid)
1156
- let resultString = result.toUTF8String()!
1157
- resolve(resultString)
1158
- } catch let error {
1159
- print("removeStoredReplication", error.localizedDescription)
1160
- reject("ERR_FULA", "removeStoredReplication", error)
1161
- }
1162
-
1163
- }
1164
-
1165
- @objc(bloxFreeSpace:withRejecter:)
1166
- func bloxFreeSpace( resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
1167
- print("ReactNative", "bloxFreeSpace")
1168
- do {
1169
- let result = try fula!.bloxFreeSpace()
1170
- let resultString = result.toUTF8String()!
1171
- resolve(resultString)
1172
- } catch let error {
1173
- print("bloxFreeSpace", error.localizedDescription)
1174
- reject("ERR_FULA", "bloxFreeSpace", error)
1175
- }
1176
-
1177
- }
1178
-
1179
- @objc(transferToFula:wallet:chain:withResolver:withRejecter:)
1180
- func transferToFula(amount: String, wallet: String, chain: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
1181
- DispatchQueue.global(qos: .default).async {
1182
- do {
1183
- print("ReactNative", "transferToFula called")
1184
- let result = try fula!.transferToFula(amount, wallet: wallet, chain: chain)
1185
- let resultString = String(data: result!, encoding: .utf8)
1186
- resolve(resultString)
1187
- } catch let error {
1188
- print("ReactNative", "transferToFula failed with Error: \(error.localizedDescription)")
1189
- reject("ERR_FULA_TRANSFER", "transferToFula failed", error)
1190
- }
1191
- }
1192
- }
1193
-
1194
-
1195
- @objc(getAccount:withRejecter:)
1196
- func getAccount(resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
1197
- do {
1198
- let account = try fula!.getAccount()
1199
- let accountString = String(data: account, encoding: .utf8)
1200
- resolve(accountString)
1201
- } catch let error {
1202
- reject("ERR_FULA", "getAccount: \(error.localizedDescription)", error)
1203
- }
1204
- }
1205
-
1206
- @objc(assetsBalance:assetId:classId:withResolver:withRejecter:)
1207
- func assetsBalance(account: String, assetId: String, classId: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
1208
- do {
1209
- let balance = try fula!.assetsBalance(account, assetId: assetId, classId: classId)
1210
- let balanceString = String(data: balance, encoding: .utf8)
1211
- resolve(balanceString)
1212
- } catch let error {
1213
- reject("ERR_FULA", "assetsBalance: \(error.localizedDescription)", error)
1214
- }
1215
- }
1216
-
1217
-
1218
- @objc(joinPool:withResolver:withRejecter:)
1219
- func joinPool(poolID: Int, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
1220
- print("ReactNative", "joinPool: poolID = ", poolID)
1221
- do {
1222
- let result = try fula!.joinPool(poolID: poolID)
1223
- let resultString = String(data: result, encoding: .utf8)
1224
- resolve(resultString)
1225
- } catch let error {
1226
- reject("ERR_FULA", "joinPool: \(error.localizedDescription)", error)
1227
- }
1228
- }
1229
-
1230
-
1231
- @objc(cancelPoolJoin:withResolver:withRejecter:)
1232
- func cancelPoolJoin(poolID: Int, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
1233
- do {
1234
- let result = try fula!.cancelPoolJoin(poolID: poolID)
1235
- let resultString = String(data: result, encoding: .utf8)
1236
- resolve(resultString)
1237
- } catch let error {
1238
- reject("ERR_FULA", "cancelPoolJoin: \(error.localizedDescription)", error)
1239
- }
1240
- }
1241
-
1242
-
1243
- @objc(leavePool:withResolver:withRejecter:)
1244
- func leavePool(poolID: Int, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
1245
- print("ReactNative", "leavePool: poolID = ", poolID)
1246
- do {
1247
- let result = try fula!.leavePool(poolID: poolID)
1248
- let resultString = String(data: result, encoding: .utf8)
1249
- resolve(resultString)
1250
- } catch let error {
1251
- reject("ERR_FULA", "leavePool: \(error.localizedDescription)", error)
1252
- }
1253
- }
1254
-
1255
- @objc(eraseBlData:withRejecter:)
1256
- func eraseBlData(resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
1257
- do {
1258
- let result = try fula!.eraseBlData()
1259
- let resultString = String(data: result, encoding: .utf8)
1260
- resolve(resultString)
1261
- } catch let error {
1262
- reject("ERR_FULA", "eraseBlData: \(error.localizedDescription)", error)
1263
- }
1264
- }
1265
-
1266
- @objc(reboot:withRejecter:)
1267
- func reboot(resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void {
1268
- do {
1269
- let result = try fula!.reboot()
1270
- let resultString = result.toUTF8String()!
1271
- resolve(resultString)
1272
- } catch let error {
1273
- print("reboot", error.localizedDescription)
1274
- reject("ERR_FULA", "reboot", error)
1275
- }
1276
- }
1277
-
1278
- @objc(wifiRemoveall:withRejecter:)
1279
- func wifiRemoveall(resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void {
1280
- do {
1281
- let result = try fula!.wifiRemoveall()
1282
- let resultString = result.toUTF8String()!
1283
- resolve(resultString)
1284
- } catch let error {
1285
- print("wifiRemoveall", error.localizedDescription)
1286
- reject("ERR_FULA", "wifiRemoveall", error)
1287
- }
1288
- }
1289
-
1290
- }
1291
-
1292
-
1
+ import Foundation
2
+ import Foundation.NSDate // for TimeInterval
3
+ import CommonCrypto
4
+ import Wnfs
5
+ import Fula
6
+ import os.log
7
+
8
+ extension OSLog {
9
+
10
+ private static var subsystem = Bundle.main.bundleIdentifier!
11
+
12
+ /// Logs the view cycles like a view that appeared.
13
+ static let viewCycle = OSLog(subsystem: subsystem, category: "viewcycle")
14
+
15
+ /// All logs related to tracking and analytics.
16
+ static let statistics = OSLog(subsystem: subsystem, category: "statistics")
17
+ }
18
+
19
+ extension OSLog {
20
+
21
+ func info(_ msg: String, _ args: CVarArg...) {
22
+ os_log("%{public}@", log: self, type: .info, msg)
23
+ }
24
+
25
+ func error(_ msg: String, _ args: CVarArg...) {
26
+ os_log("%{public}@", log: self, type: .error, msg)
27
+ }
28
+
29
+ // ... (more methods for different log levels, if needed)
30
+ }
31
+
32
+
33
+ @objc(FulaModule)
34
+ class FulaModule: NSObject {
35
+ public let NAME: String = "FulaModule"
36
+ var fula: FulamobileClient?
37
+
38
+ var client: Client?
39
+ var wnfs: Wnfs?
40
+ var fulaConfig: FulamobileConfig?
41
+ var appDir: URL
42
+ var fulaStorePath: String
43
+ // Related to the Wnfs library
44
+ var rootCid: Cid?
45
+ var wnfsKey: Data?
46
+ let userDataHelper = UserDataHelper()
47
+ var secretKeyGlobal: Array<UInt8>?
48
+ var identityEncryptedGlobal: String?
49
+ static let PRIVATE_KEY_STORE_ID = "PRIVATE_KEY"
50
+
51
+ // FIXME: Hardcoded ,fula should remove all the codec arguments as the rs-wnfs library removed its usage now.
52
+ static let CODEC_DAG_CBOR = Int(113)
53
+
54
+ enum MyError: Error {
55
+ case runtimeError(String)
56
+ }
57
+
58
+ @objc(Client)
59
+ public class Client: NSObject {
60
+ let internalClient: FulamobileClient
61
+
62
+ init(clientInput: FulamobileClient) {
63
+ internalClient = clientInput
64
+ }
65
+
66
+ func get(_ cid: Data) throws -> Data {
67
+ do {
68
+ print(String(format: "ReactNative get cid: %s", cid.toHex()))
69
+ return try internalClient.get(cid)
70
+ } catch let error {
71
+ throw error
72
+ }
73
+ }
74
+
75
+ func put(_ cid: Data, _ data: Data) throws -> Void {
76
+ do {
77
+ print(String(format: "ReactNative put(%s) data: %s", cid.toHex(), data.toHex()))
78
+ try internalClient.put(data, codec: 0xFF & Int64(cid[1]))
79
+ } catch let error {
80
+ print("ReactNative put: ", error.localizedDescription)
81
+ throw error
82
+ }
83
+ }
84
+ }
85
+ override init() {
86
+
87
+ self.appDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
88
+ let fulaStoreURL = appDir.appendingPathComponent("/fula")
89
+
90
+ self.fulaStorePath = fulaStoreURL.path
91
+ let fileManager = FileManager.default
92
+ var success = true
93
+ if !fileManager.fileExists(atPath: fulaStorePath) {
94
+ do{
95
+ try fileManager.createDirectory(atPath: fulaStorePath, withIntermediateDirectories: true)
96
+ }catch let error{
97
+ print(error.localizedDescription)
98
+ success = false
99
+ }
100
+
101
+ }
102
+ if success {
103
+ print("Fula store folder created")
104
+ } else {
105
+ print("Unable to create fula store folder!")
106
+
107
+ }
108
+ super.init()
109
+
110
+ }
111
+ func convertConfigToJson(config: Cid) -> String {
112
+ return String(format: "{\"cid\": \"%@\"}", config)
113
+ }
114
+
115
+ func getName() -> String {
116
+ return NAME
117
+ }
118
+
119
+ func toByte(_ input: String) -> Data {
120
+ return input.data(using: .utf8)!
121
+ }
122
+
123
+
124
+ func stringArrToIntArr(_ s: Array<String>) -> Array<Int> {
125
+ return s.map { Int($0)!}
126
+ }
127
+
128
+ func convertIntToByte(_ s: Array<Int>) -> Array<UInt8> {
129
+ return s.map { UInt8(exactly: $0)!}
130
+ }
131
+
132
+ func convertStringToByte(_ input: String) -> Array<UInt8> {
133
+ let splitted = input.split(separator: ",").map { String($0) }
134
+ let keyInt = stringArrToIntArr(splitted)
135
+ return convertIntToByte(keyInt)
136
+ }
137
+
138
+ @objc func registerLifecycleListener() {
139
+ NotificationCenter.default.addObserver(
140
+ self,
141
+ selector: #selector(applicationWillResignActive),
142
+ name: UIApplication.willResignActiveNotification,
143
+ object: nil)
144
+
145
+ NotificationCenter.default.addObserver(
146
+ self,
147
+ selector: #selector(applicationDidEnterBackground),
148
+ name: UIApplication.didEnterBackgroundNotification,
149
+ object: nil)
150
+
151
+ NotificationCenter.default.addObserver(
152
+ self,
153
+ selector: #selector(applicationWillTerminate),
154
+ name: UIApplication.willTerminateNotification,
155
+ object: nil)
156
+ }
157
+
158
+ deinit {
159
+ NotificationCenter.default.removeObserver(self)
160
+ }
161
+
162
+ @objc func applicationWillResignActive() {
163
+ // Handle app will resign active (similar to onHostPause)
164
+ }
165
+
166
+ @objc func applicationDidEnterBackground() {
167
+ // Handle app entered background
168
+ }
169
+
170
+ @objc func applicationWillTerminate() {
171
+ // Attempt to shut down Fula cleanly (similar to onHostDestroy)
172
+ do {
173
+ try shutdownInternal()
174
+ } catch {
175
+ print("Error shutting down Fula: \(error)")
176
+ }
177
+ }
178
+
179
+
180
+ @objc(checkConnection:withResolver:withRejecter:)
181
+ func checkConnection(timeout: NSNumber, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
182
+ OSLog.viewCycle.info("ReactNative checkConnection started with timeout=\(timeout)")
183
+
184
+ if let timeoutInt = timeout as? Int {
185
+ if fula != nil {
186
+ DispatchQueue.global(qos: .default).async {
187
+ do {
188
+ let connectionStatus = try self.checkConnectionInternal(timeout: timeoutInt)
189
+ OSLog.viewCycle.info("ReactNative checkConnection ended \(connectionStatus)")
190
+ resolve(connectionStatus)
191
+ }
192
+ catch let error {
193
+ OSLog.viewCycle.info("ReactNative checkConnection failed with Error: \(error.localizedDescription)")
194
+ resolve(false)
195
+ }
196
+ }
197
+ } else {
198
+ OSLog.viewCycle.info("ReactNative checkConnection fula is null")
199
+ resolve(false)
200
+ }
201
+ } else {
202
+ OSLog.viewCycle.error("ReactNative checkConnection - invalid timeout value")
203
+ reject("ERR_INVALID_TIMEOUT", "Invalid timeout value", nil)
204
+ }
205
+ }
206
+
207
+
208
+ @objc(newClient:withStorePath:withBloxAddr:withExchange:withAutoFlush:withUseRelay:withRefresh:withResolver:withRejecter:)
209
+ func newClient(identityString: String, storePath: String, bloxAddr: String, exchange: String, autoFlush: Bool, useRelay: Bool, refresh: Bool, resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
210
+ print("ReactNative", "newClient storePath= " , storePath , " bloxAddr= " , bloxAddr , " exchange= " , exchange , " autoFlush= " , autoFlush , " useRelay= " , useRelay , " refresh= " , refresh);
211
+ do {
212
+ print("ReactNative", "newClient storePath= ", storePath)
213
+ let identity = toByte(identityString)
214
+ print("ReactNative", "newClient identity= ", identityString)
215
+ try newClientInternal(identity: identity, storePath: storePath, bloxAddr: bloxAddr, exchange: exchange, autoFlush: autoFlush, useRelay: useRelay, refresh: refresh)
216
+ let peerId = fula?.id_()
217
+ resolve(peerId)
218
+ } catch let error {
219
+ print("ReactNative", "newClient failed with Error: ", error.localizedDescription)
220
+ reject("ERR_FULA", "Can't create client", error)
221
+ }
222
+
223
+ }
224
+
225
+ @objc(isReady:withResolver:withRejecter:)
226
+ func isReady(filesystemCheck: Bool, resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void{
227
+ print("ReactNative", "isReady started")
228
+ var initialized = false
229
+ do {
230
+ if (fula != nil && !fula!.id_().isEmpty) {
231
+ if (filesystemCheck) {
232
+ if (client != nil && rootCid != nil && !rootCid!.isEmpty) {
233
+ initialized = true
234
+ }
235
+ } else {
236
+ initialized = true
237
+ }
238
+ }
239
+ resolve(initialized)
240
+ } catch let error {
241
+ print("ReactNative", "isReady failed with Error: " + error.localizedDescription)
242
+ reject("ERR_FULA", "Check if fula is ready", error)
243
+ }
244
+ }
245
+
246
+ //TODO: we should consider refactor the name of this \
247
+ // function to be compatible with the android version.
248
+ @objc(initFula:withStorePath:withBloxAddr:withExchange:withAutoFlush:withRootConfig:withUseRelay:withRefresh:withResolver:withRejecter:)
249
+ func initFula(identityString: String, storePath: String, bloxAddr: String, exchange: String, autoFlush: Bool, rootConfig: String, useRelay: Bool, refresh: Bool, resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
250
+
251
+ OSLog.viewCycle.info("ReactNative - init started")
252
+
253
+ do {
254
+
255
+ var resultData = Dictionary<String, String>()
256
+ OSLog.viewCycle.info("ReactNative init storePath= \(storePath)")
257
+ let identity = self.toByte(identityString)
258
+ OSLog.viewCycle.info("ReactNative init identity= \(identityString)")
259
+ let obj = try initInternal(identity: identity, storePath: storePath, bloxAddr: bloxAddr, exchange: exchange, autoFlush: autoFlush, _rootCid: rootConfig, useRelay: useRelay, refresh: refresh)
260
+ OSLog.viewCycle.info("ReactNative init object created: [ \(obj[0]), \(obj[1]), \(obj[2]) ]")
261
+ resultData["peerId"] = obj[0]
262
+ resultData["rootCid"] = obj[1]
263
+ resultData["wnfs_key"] = obj[2]
264
+ resolve(resultData as NSDictionary)
265
+
266
+ } catch let error {
267
+ OSLog.viewCycle.info("ReactNative init failed with Error: \(error.localizedDescription)")
268
+ reject("ERR_FULA", "init failed", error)
269
+ }
270
+
271
+ }
272
+
273
+ @objc(logout:withStorePath:withResolver:withRejecter:)
274
+ func logout(identityString: String, storePath: String, resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void{
275
+
276
+ print("ReactNative", "logout started")
277
+ do {
278
+ let identity = toByte(identityString)
279
+ try logoutInternal(identity: identity, _storePath: storePath)
280
+ print("ReactNative", "logout completed")
281
+ resolve("")
282
+
283
+ } catch let error {
284
+ print("ReactNative", "logout failed with Error: ", error.localizedDescription)
285
+ reject("ERR_FULA", "logout failed", error)
286
+ }
287
+
288
+ }
289
+
290
+ func checkConnectionInternal(timeout: Int) throws -> Bool {
291
+ OSLog.viewCycle.info("ReactNative checkConnectionInternal started with timeout: \(timeout)")
292
+ var connectionStatus = false
293
+
294
+ if let fula = self.fula {
295
+ let semaphore = DispatchSemaphore(value: 0)
296
+ let queue = DispatchQueue(label: "com.yourapp.checkConnection", attributes: .concurrent)
297
+
298
+ queue.async {
299
+ do {
300
+ OSLog.viewCycle.info("ReactNative connectToBlox started")
301
+ try fula.connectToBlox()
302
+ connectionStatus = true
303
+ OSLog.viewCycle.info("ReactNative checkConnectionInternal succeeded")
304
+ semaphore.signal()
305
+ } catch let error {
306
+ OSLog.viewCycle.info("ReactNative checkConnectionInternal failed with Error: \(error.localizedDescription)")
307
+ semaphore.signal()
308
+ }
309
+ }
310
+
311
+ let timeoutResult = semaphore.wait(timeout: .now() + .seconds(timeout))
312
+ switch timeoutResult {
313
+ case .timedOut:
314
+ OSLog.viewCycle.info("ReactNative checkConnectionInternal timed out")
315
+ return false
316
+ case .success:
317
+ return connectionStatus
318
+ }
319
+ } else {
320
+ OSLog.viewCycle.info("ReactNative checkConnectionInternal failed because fula is not initialized")
321
+ return false
322
+ }
323
+ }
324
+
325
+ @objc(checkFailedActions:withTimeout:withResolver:withRejecter:)
326
+ func checkFailedActions(retry: Bool, timeout: Int, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void {
327
+ do {
328
+ guard let fula = fula else {
329
+ throw NSError(domain: "ERR_FULA", code: 1001, userInfo: [NSLocalizedDescriptionKey: "Fula is not initialized"])
330
+ }
331
+
332
+ if !retry {
333
+ OSLog.viewCycle.info("ReactNative checkFailedActions without retry")
334
+ let failedLinks = try fula.listFailedPushes()
335
+
336
+ let nextFailedLink = try failedLinks.next()
337
+ if nextFailedLink != nil {
338
+ // Assuming nextFailedLink is of type Data; replace `toHex()` with an appropriate method to convert Data to a hex string
339
+ OSLog.viewCycle.info("ReactNative checkFailedActions found")
340
+ resolve(true)
341
+ } else {
342
+ resolve(false)
343
+ }
344
+ } else {
345
+ OSLog.viewCycle.info("ReactNative checkFailedActions with retry")
346
+ let retryResults = try retryFailedActionsInternal(timeout: timeout) // Ensure retryFailedActionsInternal accepts a timeout parameter
347
+ resolve(!retryResults)
348
+ }
349
+ } catch let error {
350
+ OSLog.viewCycle.info("ReactNative checkFailedActions failed with Error: \(error.localizedDescription)")
351
+ reject("ERR_FULA", "CheckFailedActions failed", error)
352
+ }
353
+ }
354
+
355
+
356
+
357
+ func retryFailedActionsInternal(timeout: Int) throws -> Bool {
358
+ OSLog.viewCycle.info("ReactNative retryFailedActionsInternal started")
359
+
360
+ guard let fula = fula else {
361
+ OSLog.viewCycle.info("ReactNative retryFailedActionsInternal failed because fula is not initialized")
362
+ return false
363
+ }
364
+
365
+ do {
366
+ let connectionCheck = try checkConnectionInternal(timeout: timeout)
367
+
368
+ if connectionCheck {
369
+ do {
370
+ OSLog.viewCycle.info("ReactNative retryFailedPushes started")
371
+ try fula.retryFailedPushes()
372
+ OSLog.viewCycle.info("ReactNative flush started")
373
+ try fula.flush()
374
+ return true
375
+ } catch let error {
376
+ try fula.flush()
377
+ OSLog.viewCycle.info("ReactNative retryFailedActionsInternal failed with Error: \(error.localizedDescription)")
378
+ return false
379
+ }
380
+ } else {
381
+ OSLog.viewCycle.info("ReactNative retryFailedActionsInternal failed because blox is offline")
382
+ return false
383
+ }
384
+ } catch let error {
385
+ OSLog.viewCycle.info("ReactNative retryFailedActionsInternal failed with Error: \(error.localizedDescription)")
386
+ return false
387
+ }
388
+ }
389
+
390
+
391
+
392
+ func createPeerIdentity(privateKey: Data) throws -> Data {
393
+ do {
394
+ // 1: First: create public key from provided private key
395
+ // 2: Should read the local keychain store (if it is key-value, key is public key above,
396
+ // 3: if found, decrypt using the private key
397
+ // 4: If not found or decryption not successful, generate an identity
398
+ // 5: then encrypt and store in keychain
399
+ // TODO: recheck error handling
400
+ var encryptedKey = userDataHelper.getValue(FulaModule.PRIVATE_KEY_STORE_ID)
401
+ let secretKey = try Cryptography.generateKey(privateKey)
402
+ if (encryptedKey == nil) {
403
+ var error: NSError?
404
+ let autoGeneratedIdentity = FulamobileGenerateEd25519Key(&error)
405
+ if error != nil {
406
+ throw error!
407
+ }
408
+ encryptedKey = try Cryptography.encryptMsg(autoGeneratedIdentity!.toUint8Array(), secretKey)
409
+ userDataHelper.add(FulaModule.PRIVATE_KEY_STORE_ID, encryptedKey!)
410
+ }
411
+ return try Cryptography.decryptMsg(encryptedKey!, secretKey).toData()
412
+
413
+ } catch let error {
414
+ print("ReactNative", "createPeerIdentity failed with Error: ", error.localizedDescription)
415
+ throw error
416
+ }
417
+ }
418
+
419
+ func createNewrootCid(identity: Data) throws -> Void {
420
+ let hash32 = identity.sha256()
421
+ print("ReactNative", "wnfsKey=" , identity.toHex() , "; hash32 = " , hash32.toHex());
422
+ if (fula != nil) {
423
+ try fula?.flush()
424
+ }
425
+ rootCid = try wnfs?.Init(wnfsKey: hash32)
426
+ print("ReactNative", "privateForest is created: ", rootCid!)
427
+ wnfsKey = identity
428
+ print("ReactNative", "rootCid is created: cid=", rootCid!, " ; wnfs_key=", wnfsKey!.toHex(), "; hash32=", hash32)
429
+ try encryptAndStoreConfig()
430
+ }
431
+
432
+ func loadWnfs(_ _wnfsKey: Data , _ _rootCid: String) throws {
433
+ OSLog.viewCycle.info("ReactNative loadWnfs called: rootCid=\(_rootCid)")
434
+ let hash32 = _wnfsKey.sha256()
435
+ OSLog.viewCycle.info("ReactNative wnfsKey= \(_wnfsKey.toHex()) ; hash32 = \(hash32.toHex())");
436
+ try wnfs?.LoadWithWNFSKey(wnfsKey: hash32, cid: _rootCid)
437
+ rootCid = _rootCid
438
+ wnfsKey = _wnfsKey
439
+ if (fula != nil) {
440
+ try fula?.flush()
441
+ }
442
+ OSLog.viewCycle.info("ReactNative loadWnfs completed")
443
+ try encryptAndStoreConfig()
444
+ }
445
+
446
+
447
+ func encryptAndStoreConfig() throws {
448
+ do {
449
+ if let identityEncryptedGlobalUnwrapped = identityEncryptedGlobal {
450
+ OSLog.viewCycle.info("ReactNative encryptAndStoreConfig started")
451
+
452
+ if let rootCidUnwrapped = rootCid, let wnfsKeyUnwrapped = wnfsKey, let secretKeyGlobalUnwrapped = secretKeyGlobal {
453
+ OSLog.viewCycle.info("ReactNative encryptAndStoreConfig started with rootCid: \(rootCidUnwrapped.toUint8Array()) and wnfsKey:\(wnfsKeyUnwrapped)")
454
+
455
+ let cid_encrypted = try Cryptography.encryptMsg(rootCidUnwrapped.toUint8Array(), secretKeyGlobalUnwrapped)
456
+ OSLog.viewCycle.info("ReactNative encryptAndStoreConfig cid_encrypted: \(cid_encrypted)")
457
+
458
+ let wnfs_key_encrypted = try Cryptography.encryptMsg(wnfsKeyUnwrapped.toUint8Array(), secretKeyGlobalUnwrapped)
459
+ OSLog.viewCycle.info("ReactNative encryptAndStoreConfig wnfs_key_encrypted: \(wnfs_key_encrypted)")
460
+
461
+ userDataHelper.add("cid_encrypted_" + identityEncryptedGlobalUnwrapped, cid_encrypted)
462
+ userDataHelper.add("wnfs_key_encrypted_" + identityEncryptedGlobalUnwrapped, wnfs_key_encrypted)
463
+ } else {
464
+ // Handle the case where rootCid, wnfsKey, or secretKeyGlobal is nil
465
+ OSLog.viewCycle.info("ReactNative encryptAndStoreConfig failed because one of the values is nil")
466
+ }
467
+ }
468
+ } catch let error {
469
+ OSLog.viewCycle.info("ReactNative encryptAndStoreConfig failed with Error: \(error.localizedDescription)")
470
+ throw error
471
+ }
472
+ }
473
+
474
+ func logoutInternal(identity: Data, _storePath: String?) throws {
475
+ do {
476
+ if (fula != nil) {
477
+ try fula?.flush()
478
+ }
479
+ let secretKey = try Cryptography.generateKey(identity)
480
+ let identity_encrypted: String = try Cryptography.encryptMsg(identity.toUint8Array(), secretKey)
481
+ userDataHelper.remove("cid_encrypted_"+identity_encrypted)
482
+
483
+ //TODO: Should also remove peerid @Mahdi
484
+
485
+ userDataHelper.remove("cid_encrypted_"+identity_encrypted)
486
+
487
+ rootCid = nil
488
+ secretKeyGlobal = nil
489
+ identityEncryptedGlobal = nil
490
+ var storePath = _storePath
491
+ if (storePath == nil || storePath!.isEmpty) {
492
+ storePath = fulaStorePath
493
+ }
494
+
495
+ do{
496
+ try FileManager.default.removeItem(atPath: fulaStorePath)
497
+ }catch let error{
498
+ print("Deleting fula store path", error.localizedDescription)
499
+ throw error
500
+ }
501
+ } catch let error {
502
+ print("ReactNative", "logout internal failed with Error: ", error.localizedDescription)
503
+ throw error
504
+ }
505
+ }
506
+
507
+ func getFulaClient() -> FulamobileClient? {
508
+ return fula
509
+ }
510
+
511
+ func newClientInternal(identity: Data, storePath: String?, bloxAddr: String, exchange: String, autoFlush: Bool, useRelay: Bool, refresh: Bool) throws -> Data {
512
+ do {
513
+ fulaConfig = FulamobileConfig()
514
+ if (storePath == nil || storePath!.isEmpty) {
515
+ fulaConfig!.storePath = fulaStorePath
516
+ } else {
517
+ fulaConfig!.storePath = storePath!
518
+ }
519
+ print("ReactNative", "storePath is set: " + fulaConfig!.storePath)
520
+
521
+ let peerIdentity = try createPeerIdentity(privateKey: identity)
522
+ fulaConfig!.identity = peerIdentity
523
+ print("ReactNative", "peerIdentity is set: " + fulaConfig!.identity!.toHex())
524
+ fulaConfig!.bloxAddr = bloxAddr
525
+ print("ReactNative", "bloxAddr is set: " + fulaConfig!.bloxAddr)
526
+ fulaConfig!.exchange = exchange
527
+ fulaConfig!.syncWrites = autoFlush
528
+ if (useRelay) {
529
+ fulaConfig!.allowTransientConnection = true
530
+ fulaConfig!.forceReachabilityPrivate = true
531
+ }
532
+ if (fula == nil || refresh) {
533
+ print("ReactNative", "Creating a new Fula instance");
534
+ do {
535
+ try shutdownInternal();
536
+ fula = FulamobileClient(fulaConfig)
537
+ if (fula != nil) {
538
+ try fula?.flush();
539
+ }
540
+ } catch let error {
541
+ print("ReactNative", "Failed to create new Fula instance: " , error.localizedDescription);
542
+ throw MyError.runtimeError("Failed to create new Fula instance")
543
+ }
544
+ }
545
+ return peerIdentity
546
+ } catch let error {
547
+ print("ReactNative", "newclientInternal failed with Error: ", error.localizedDescription)
548
+ throw error
549
+ }
550
+ }
551
+
552
+ func initInternal(identity: Data, storePath: String, bloxAddr: String, exchange: String, autoFlush: Bool, _rootCid: String, useRelay: Bool, refresh: Bool) throws -> [String] {
553
+
554
+ do {
555
+ if (fula == nil || refresh) {
556
+ try newClientInternal(identity: identity, storePath: storePath, bloxAddr: bloxAddr, exchange: exchange, autoFlush: autoFlush, useRelay: useRelay, refresh: refresh)
557
+ OSLog.viewCycle.info("ReactNative fula initialized: \(self.fula!.id_())")
558
+ }
559
+ if(client == nil || refresh) {
560
+ client = Client(clientInput: fula!)
561
+ wnfs = Wnfs(putFn: { cid, data in
562
+ guard let c = self.client else {
563
+ throw MyError.runtimeError("wnfs: fula client not ready")
564
+ }
565
+ try c.put(cid, data)
566
+ }, getFn: { cid in
567
+ guard let c = self.client else {
568
+ throw MyError.runtimeError("wnfs: fula client not ready")
569
+ }
570
+ return try c.get(cid)
571
+ })
572
+ OSLog.viewCycle.info("ReactNative wnfs initialized")
573
+ }
574
+
575
+ let secretKey = try Cryptography.generateKey(identity)
576
+ let identity_encrypted = try Cryptography.encryptMsg(identity.toUint8Array(), secretKey)
577
+ identityEncryptedGlobal = identity_encrypted
578
+ secretKeyGlobal = secretKey
579
+
580
+ if (rootCid == nil || rootCid!.isEmpty) {
581
+ OSLog.viewCycle.info("ReactNative rootCid is empty.")
582
+ //Load from keystore
583
+
584
+ let cid_encrypted_fetched = userDataHelper.getValue("cid_encrypted_"+identity_encrypted)
585
+ OSLog.viewCycle.info("ReactNative Here1")
586
+ var cid: Array<UInt8>? = nil
587
+ if(cid_encrypted_fetched != nil && !cid_encrypted_fetched!.isEmpty) {
588
+ OSLog.viewCycle.info("ReactNative decrypting cid= \(cid_encrypted_fetched!) with secret \(secretKey.toHex())")
589
+ cid = try Cryptography.decryptMsg(cid_encrypted_fetched!, secretKey)
590
+ }
591
+ print("ReactNative", "Here2")
592
+ //print("ReactNative", "Attempted to fetch cid from keystore cid="+cid+" & wnfs_key="+wnfs_key)
593
+ if(cid == nil || cid!.isEmpty){
594
+ OSLog.viewCycle.info("ReactNative cid or wnfs key was not found")
595
+ if(!_rootCid.isEmpty){
596
+ OSLog.viewCycle.info("ReactNative Re-setting cid from input: \(_rootCid)")
597
+ cid = _rootCid.toUint8Array()
598
+ }
599
+
600
+ }
601
+ if(cid == nil || cid!.isEmpty){
602
+ OSLog.viewCycle.info("ReactNative Tried to recover cid but was not successful. Creating ones")
603
+ try createNewrootCid(identity: identity)
604
+ } else {
605
+ OSLog.viewCycle.info("ReactNative Found cid and wnfs key in keychain store")
606
+ OSLog.viewCycle.info("ReactNative Recovered cid and private ref from keychain store. cid=\(cid!) & wnfs_key=\(identity)")
607
+ try loadWnfs(identity, cid!.toData().toUTF8String()!)
608
+ }
609
+ OSLog.viewCycle.info("ReactNative creating/reloading rootCid completed")
610
+
611
+ /*
612
+ byte[] testbyte = convertStringToByte("-104,40,24,-93,24,100,24,114,24,111,24,111,24,116,24,-126,24,-126,0,0,24,-128,24,103,24,118,24,101,24,114,24,115,24,105,24,111,24,110,24,101,24,48,24,46,24,49,24,46,24,48,24,105,24,115,24,116,24,114,24,117,24,99,24,116,24,117,24,114,24,101,24,100,24,104,24,97,24,109,24,116")
613
+ long testcodec = 85
614
+ byte[] testputcid = client!.put(testbyte, testcodec)
615
+ print("ReactNative", "client!.put test done"+ Arrays.toString(testputcid))
616
+ byte[] testfetchedcid = convertStringToByte("1,113,18,32,-6,-63,-128,79,-102,-89,57,77,-8,67,-98,8,-81,40,-87,123,122,29,-52,-124,-60,-53,100,105,125,123,-5,-99,41,106,-124,-64")
617
+ byte[] testfetchedbytes = client!.get(testfetchedcid)
618
+ print("ReactNative", "client!.get test done"+ Arrays.toString(testfetchedbytes))
619
+ */
620
+
621
+
622
+ OSLog.viewCycle.info("ReactNative rootCid is created: cid=\(self.rootCid!) & wnfs_key=\(self.wnfsKey!.toHex())")
623
+ } else {
624
+ OSLog.viewCycle.info("ReactNative rootCid existed: cid=\(self.rootCid!) & wnfs_key=\(self.wnfsKey!.toHex())")
625
+ }
626
+ let peerId = fula!.id_()
627
+ var obj = [String]()
628
+ obj.append(peerId)
629
+ obj.append(rootCid!)
630
+ obj.append(wnfsKey!.toHex())
631
+ OSLog.viewCycle.info("ReactNative initInternal is completed successfully")
632
+ if (fula != nil) {
633
+ try fula?.flush()
634
+ }
635
+ return obj
636
+ } catch let error {
637
+ OSLog.viewCycle.info("ReactNative init internal failed with Error: \(error.localizedDescription)")
638
+ throw error
639
+ }
640
+ }
641
+
642
+
643
+ @objc(mkdir:withResolver:withRejecter:)
644
+ func mkdir(path: String, resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
645
+ print("ReactNative", "mkdir: path = " + path)
646
+ do {
647
+ let cid = try wnfs?.MkDir(cid: rootCid!, remotePath: path)
648
+ if(cid != nil) {
649
+ rootCid = cid
650
+ try encryptAndStoreConfig()
651
+ if (fula != nil) {
652
+ try fula?.flush()
653
+ }
654
+ resolve(rootCid)
655
+ } else {
656
+ print("ReactNative", "mkdir Error: config is nil")
657
+ reject("ERR_WNFS", "Can't make dir", nil)
658
+ }
659
+
660
+ } catch let error{
661
+ print("mkdir", error.localizedDescription)
662
+ reject("ERR_WNFS", "mkdir", error)
663
+ }
664
+ }
665
+
666
+ @objc(writeFile:withLocalFilename:withResolver:withRejecter:)
667
+ func writeFile(fulaTargetFilename: String, localFilename: String, resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
668
+ /*
669
+ // reads content of the file form localFilename (should include full absolute path to local file with read permission
670
+ // writes content to the specified location by fulaTargetFilename in Fula filesystem
671
+ // fulaTargetFilename: a string including full path and filename of target file on Fula (e.g. root/pictures/cat.jpg)
672
+ // localFilename: a string containing full path and filename of local file on hte device (e.g /usr/bin/cat.jpg)
673
+ // Returns: new cid of the root after this file is placed in the tree
674
+ */
675
+ print("ReactNative", "writeFile to : path = " + fulaTargetFilename + ", from: " + localFilename)
676
+ do {
677
+ let cid = try wnfs?.WriteFileFromPath(cid: rootCid!, remotePath: fulaTargetFilename, fileUrl: URL.init(string: localFilename)!)
678
+ if(cid != nil) {
679
+ rootCid = cid
680
+ try encryptAndStoreConfig()
681
+ if (fula != nil) {
682
+ try fula?.flush()
683
+ }
684
+ resolve(rootCid)
685
+ } else {
686
+ print("ReactNative", "writeFile Error: config is nil")
687
+ reject("ERR_WNFS", "writeFile Error: config is nil", nil)
688
+ }
689
+ } catch let error {
690
+ print("writeFile", error.localizedDescription)
691
+ reject("ERR_WNFS", "writeFile", error)
692
+ }
693
+ }
694
+
695
+ @objc(writeFileContent:withContentString:withResolver:withRejecter:)
696
+ func writeFileContent(path: String, contentString: String, resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
697
+
698
+ print("ReactNative", "writeFile: contentString = " + contentString)
699
+ print("ReactNative", "writeFile: path = " + path)
700
+ do {
701
+ let content = convertStringToByte(contentString)
702
+ let cid = try wnfs?.WriteFile(cid: rootCid!, remotePath: path, data: content.toData())
703
+ rootCid = cid
704
+ try encryptAndStoreConfig()
705
+ if (fula != nil) {
706
+ try fula?.flush()
707
+ }
708
+ resolve(rootCid)
709
+ } catch let error {
710
+ print("writeFileContent", error.localizedDescription)
711
+ reject("ERR_WNFS", "writeFileContent", error)
712
+ }
713
+
714
+ }
715
+
716
+ @objc(ls:withResolver:withRejecter:)
717
+ func ls(path: String, resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
718
+ print("ReactNative", "ls: path = " + path)
719
+ do {
720
+ let res = try wnfs?.Ls(cid: rootCid!, remotePath: path)
721
+
722
+ //JSONArray jsonArray = new JSONArray(res)
723
+ guard let s = res?.toUTF8String() else {
724
+ throw MyError.runtimeError("converting bytes to utf8 string")
725
+ }
726
+ print("ReactNative", "ls: res = " + s)
727
+ resolve(s)
728
+ } catch let error {
729
+ print("ls", error.localizedDescription)
730
+ reject("ERR_WNFS", "ls", error)
731
+ }
732
+
733
+ }
734
+
735
+ @objc(rm:withResolver:withRejecter:)
736
+ func rm(path: String, resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
737
+
738
+ print("ReactNative", "rm: path = " + path)
739
+ do {
740
+ let cid = try wnfs?.Rm(cid: rootCid!, remotePath: path)
741
+ if(cid != nil) {
742
+ rootCid = cid
743
+ try encryptAndStoreConfig()
744
+ if (fula != nil) {
745
+ try fula?.flush()
746
+ }
747
+ resolve(rootCid)
748
+ } else {
749
+ print("ReactNative", "rm Error: config is nil")
750
+ reject("ERR_WNFS", "rm Error: config is nil", nil)
751
+ }
752
+ } catch let error {
753
+ print("rm", error.localizedDescription)
754
+ reject("ERR_WNFS", "rm", error)
755
+ }
756
+
757
+ }
758
+
759
+ @objc(cp:withTargetPath:withResolver:withRejecter:)
760
+ func cp(sourcePath: String, targetPath: String, resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
761
+
762
+ print("ReactNative", "rm: sourcePath = " + sourcePath)
763
+ do {
764
+ let cid = try wnfs?.Cp(cid: rootCid!, remotePathFrom: sourcePath, remotePathTo: targetPath)
765
+ if(cid != nil) {
766
+ rootCid = cid
767
+ try encryptAndStoreConfig()
768
+ if (fula != nil) {
769
+ try fula?.flush()
770
+ }
771
+ resolve(rootCid)
772
+ } else {
773
+ print("ReactNative", "cp Error: config is nil")
774
+ reject("ERR_WNFS", "cp Error: config is nil", nil)
775
+ }
776
+ } catch let error {
777
+ print("cp", error.localizedDescription)
778
+ reject("ERR_WNFS", "cp", error)
779
+ }
780
+
781
+ }
782
+
783
+ @objc(mv:withTargetPath:withResolver:withRejecter:)
784
+ func mv(sourcePath: String, targetPath: String, resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
785
+ print("ReactNative", "rm: sourcePath = " + sourcePath)
786
+ do {
787
+ let cid = try wnfs?.Mv(cid: rootCid!, remotePathFrom: sourcePath, remotePathTo: targetPath)
788
+ if(cid != nil) {
789
+ rootCid = cid
790
+ try encryptAndStoreConfig()
791
+ if (fula != nil) {
792
+ try fula?.flush()
793
+ }
794
+ resolve(rootCid)
795
+ } else {
796
+ print("ReactNative", "mv Error: config is nil")
797
+ reject("ERR_WNFS", "mv Error: config is nil", nil)
798
+ }
799
+ } catch let error {
800
+ print("mv", error.localizedDescription)
801
+ reject("ERR_WNFS", "mv", error)
802
+ }
803
+
804
+ }
805
+
806
+ @objc(readFile:withLocalFilename:withResolver:withRejecter:)
807
+ func readFile(fulaTargetFilename: String, localFilename: String, resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
808
+ /*
809
+ // reads content of the file form localFilename (should include full absolute path to local file with read permission
810
+ // writes content to the specified location by fulaTargetFilename in Fula filesystem
811
+ // fulaTargetFilename: a string including full path and filename of target file on Fula (e.g. root/pictures/cat.jpg)
812
+ // localFilename: a string containing full path and filename of local file on hte device (e.g /usr/bin/cat.jpg)
813
+ // Returns: new cid of the root after this file is placed in the tree
814
+ */
815
+ print("ReactNative", "readFile: fulaTargetFilename = " + fulaTargetFilename)
816
+ do {
817
+ let path = try wnfs?.ReadFileToPath(cid: rootCid!, remotePath: fulaTargetFilename, fileUrl: URL.init(string: localFilename)!)
818
+ resolve(path)
819
+ } catch let error {
820
+ print("readFile", error.localizedDescription)
821
+ reject("ERR_WNFS", "readFile", error)
822
+ }
823
+
824
+ }
825
+
826
+ @objc(readFileContent:withResolver:withRejecter:)
827
+ func readFileContent(path: String, resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
828
+
829
+ print("ReactNative", "readFileContent: path = " + path)
830
+ do {
831
+ // FIXME: dhouldn't we output an NSData object instead?
832
+ let res = try wnfs?.ReadFile(cid: rootCid!, remotePath: path)
833
+ guard let resString = res?.toUTF8String() else{
834
+ throw MyError.runtimeError("converting bytes to utf8 string")
835
+ }
836
+ resolve(resString)
837
+ } catch let error {
838
+ print("readFileContent", error.localizedDescription)
839
+ reject("ERR_WNFS", "readFileContent", error)
840
+ }
841
+
842
+ }
843
+
844
+ @objc(get:withResolver:withRejecter:)
845
+ func get(keyString: String, resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
846
+
847
+ print("ReactNative", "get: keyString = " + keyString)
848
+ do {
849
+ let key: Data = convertStringToByte(keyString).toData()
850
+ let value = try getInternal(key)
851
+ let valueString: String = value.toUTF8String()!
852
+ resolve(valueString)
853
+ } catch let error {
854
+ print("get", error.localizedDescription)
855
+ reject("ERR_FULA", "get", error)
856
+ }
857
+
858
+ }
859
+
860
+ func getInternal(_ key: Data) throws -> Data {
861
+ do {
862
+ print("ReactNative", "getInternal: key.toUTF8String() = " , key.toUTF8String()!)
863
+ print("ReactNative", "getInternal: key.toHex().bytes = " , key.toHex())
864
+ let value = try fula!.get(key)
865
+ print("ReactNative", "getInternal: value.toHex() = " , value.toHex())
866
+ return value
867
+ } catch let error {
868
+ print("ReactNative", "getInternal: error = " + error.localizedDescription)
869
+ print("getInternal", error.localizedDescription)
870
+ throw error
871
+ }
872
+ }
873
+
874
+ @objc(has:withResolver:withRejecter:)
875
+ func has(keyString: String, resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
876
+
877
+ print("ReactNative", "has: keyString = " + keyString)
878
+ do {
879
+ let key: Data = convertStringToByte(keyString).toData()
880
+ let result = try hasInternal(key)
881
+ resolve(result)
882
+ } catch let error {
883
+ print("has", error.localizedDescription)
884
+ reject("ERR_FULA", "has", error)
885
+ }
886
+
887
+ }
888
+
889
+ func hasInternal(_ key: Data) throws -> Bool {
890
+ do {
891
+ let ret = UnsafeMutablePointer<ObjCBool>.allocate(capacity: 1)
892
+ try fula?.has(key, ret0_: ret)
893
+ let res = ret.pointee.boolValue
894
+ ret.deallocate()
895
+ return res
896
+ } catch let error {
897
+ print("hasInternal", error.localizedDescription)
898
+ throw error
899
+ }
900
+ }
901
+
902
+ func pullInternal(key: Data) throws -> Void {
903
+ do {
904
+ try fula!.pull(key)
905
+ } catch let error {
906
+ print("pullInternal", error.localizedDescription)
907
+ throw error
908
+ }
909
+ }
910
+
911
+ @objc(push:withRejecter:)
912
+ func push(resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
913
+ print("ReactNative", "push started")
914
+ do {
915
+ try pushInternal(key: convertStringToByte(rootCid!).toData())
916
+ resolve(rootCid)
917
+ } catch let error {
918
+ print("get", error.localizedDescription)
919
+ reject("ERR_FULA", "push", error)
920
+ }
921
+ }
922
+
923
+ func pushInternal(key: Data) throws -> Void {
924
+ do {
925
+ let hasIt = try hasInternal(key)
926
+ if (fula != nil && hasIt) {
927
+ try fula?.push(key)
928
+ try fula?.flush()
929
+ } else {
930
+ print("ReactNative", "pushInternal error: key wasn't found or fula is not initialized")
931
+ throw MyError.runtimeError("pushInternal error: key wasn't found or fula is not initialized")
932
+ }
933
+ } catch let error {
934
+ print("ReactNative", "pushInternal", error.localizedDescription)
935
+ throw error
936
+ }
937
+ }
938
+
939
+ // FIXME: unused codecString arg
940
+ @objc(put:withCodecString:withResolver:withRejecter:)
941
+ func put(valueString: String, codecString: String, resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
942
+
943
+ print("ReactNative", "put: codecString = " + codecString)
944
+ print("ReactNative", "put: valueString = " + valueString)
945
+ do {
946
+ //byte[] codec = convertStringToByte(CodecString)
947
+ let codec = FulaModule.CODEC_DAG_CBOR
948
+
949
+
950
+ print("ReactNative", "put: codec = ", codec)
951
+ let value = valueString.toData()
952
+
953
+ print("ReactNative", "put: value.toHex() = " , value.toHex())
954
+ let key = try putInternal(value: value, codec: codec)
955
+ print("ReactNative", "put: key.toHex() = " , key.toUTF8String()!)
956
+ resolve(key.toUTF8String()!)
957
+ } catch let error {
958
+ print("ReactNative", "put: error = ", error.localizedDescription)
959
+ reject("ERR_FULA", "put", error)
960
+ }
961
+
962
+ }
963
+
964
+ // FIXME: unused codec arg
965
+ func putInternal(value: Data, codec: Int) throws -> Data {
966
+ do {
967
+ if(fula != nil) {
968
+ let key: Data = try fula!.put(value, codec: Int64(FulaModule.CODEC_DAG_CBOR))
969
+ try fula?.flush()
970
+ return key
971
+ } else {
972
+ print("ReactNative", "putInternal Error: fula is not initialized")
973
+ throw MyError.runtimeError("putInternal Error: fula is not initialized")
974
+ }
975
+ } catch let error {
976
+ print("ReactNative", "putInternal", error.localizedDescription)
977
+ throw error
978
+ }
979
+ }
980
+
981
+ @objc(setAuth:withAllow:withResolver:withRejecter:)
982
+ func setAuth(peerIdString: String, allow: Bool, resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
983
+
984
+ print("ReactNative", "setAuth: peerIdString = " + peerIdString)
985
+ do {
986
+ if (fula != nil && !(fula?.id_().isEmpty)! && fulaConfig != nil && !fulaConfig!.bloxAddr.isEmpty) {
987
+ let bloxAddr = fulaConfig!.bloxAddr
988
+ print("ReactNative", "setAuth: bloxAddr = '",bloxAddr,"'"," peerIdString = '",peerIdString,"'")
989
+ let parts = bloxAddr.split(separator: "/").map(String.init)
990
+ try fula?.setAuth(parts.last, subject: peerIdString, allow: allow)
991
+ resolve(true)
992
+ } else {
993
+ print("ReactNative", "setAuth error: fula is not initialized")
994
+ throw MyError.runtimeError("fula is not initialized")
995
+ }
996
+ resolve(false)
997
+ } catch let error {
998
+ print("get", error.localizedDescription)
999
+ reject("ERR_FULA", "setAuth", error)
1000
+ }
1001
+
1002
+ }
1003
+
1004
+ @objc(shutdown:withRejecter:)
1005
+ func shutdown( resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) {
1006
+ do {
1007
+ try shutdownInternal()
1008
+ resolve(true)
1009
+ } catch let error {
1010
+ print("ReactNative", "shutdown", error.localizedDescription)
1011
+ reject("ERR_FULA", "shutdown", error)
1012
+ }
1013
+
1014
+ }
1015
+
1016
+ func shutdownInternal() throws {
1017
+ if(fula != nil) {
1018
+ try fula?.shutdown()
1019
+ fula = nil
1020
+ client = nil
1021
+ wnfs = nil
1022
+ }
1023
+ }
1024
+
1025
+ ///////////////////////////////////////////////////////////
1026
+ ///////////////////////////////////////////////////////////
1027
+ ///////////////////////////////////////////////////////////
1028
+ ///////////////////////////////////////////////////////////
1029
+ //////////////////////ANYTHING BELOW IS FOR BLOCKCHAIN/////
1030
+ ///////////////////////////////////////////////////////////
1031
+ @objc(createAccount:withResolver:withRejecter:)
1032
+ func createAccount(seedString: String, resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
1033
+ print("ReactNative", "createAccount: seedString = ", seedString)
1034
+ do {
1035
+ if (fula == nil || ((fula?.id_().isEmpty) != nil)) {
1036
+ reject("ERR_FULA", "createAccount", MyError.runtimeError("Fula client is not initialized"))
1037
+ } else {
1038
+
1039
+ if (!seedString.starts(with: "/")) {
1040
+ reject("ERR_FULA", "createAccount", MyError.runtimeError("seed should start with /"))
1041
+ }
1042
+ let result = try fula!.seeded(seedString)
1043
+ let resultString = result.toUTF8String()!
1044
+ resolve(resultString)
1045
+ }
1046
+ } catch let error {
1047
+ print("createAccount", error.localizedDescription)
1048
+ reject("ERR_FULA", "createAccount", error)
1049
+ }
1050
+
1051
+ }
1052
+
1053
+ @objc(checkAccountExists:withResolver:withRejecter:)
1054
+ func checkAccountExists(accountString: String, resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
1055
+ print("ReactNative", "checkAccountExists: accountString = ", accountString)
1056
+ do {
1057
+ let result = try fula!.accountExists(accountString)
1058
+ let resultString = result.toUTF8String()!
1059
+ resolve(resultString)
1060
+ } catch let error {
1061
+ print("checkAccountExists", error.localizedDescription)
1062
+ reject("ERR_FULA", "checkAccountExists", error)
1063
+ }
1064
+
1065
+ }
1066
+
1067
+ @objc(createPool:withPoolName:withResolver:withRejecter:)
1068
+ func createPool(seedString: String, poolName: String, resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
1069
+ print("ReactNative", "createPool: seedString = " + seedString + " poolName = " + poolName)
1070
+ do {
1071
+ let result = try fula!.poolCreate(seedString, poolName: poolName)
1072
+ let resultString = result.toUTF8String()!
1073
+ resolve(resultString)
1074
+ } catch let error {
1075
+ print("createPool", error.localizedDescription)
1076
+ reject("ERR_FULA", "createPool", error)
1077
+ }
1078
+
1079
+ }
1080
+
1081
+ @objc(listPools:withRejecter:)
1082
+ func listPools( resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
1083
+ print("ReactNative", "listPools")
1084
+ do {
1085
+ let result = try fula!.poolList()
1086
+ let resultString = result.toUTF8String()!
1087
+ resolve(resultString)
1088
+ } catch let error {
1089
+ print("listPools", error.localizedDescription)
1090
+ reject("ERR_FULA", "listPools", error)
1091
+ }
1092
+
1093
+ }
1094
+
1095
+ @objc(listPoolJoinRequests:withResolver:withRejecter:)
1096
+ func listPoolJoinRequests(poolID: Int, resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
1097
+ print("ReactNative", "listPoolJoinRequests: poolID = ", poolID)
1098
+ do {
1099
+ let result = try fula!.poolRequests(poolID)
1100
+ let resultString = result.toUTF8String()!
1101
+ resolve(resultString)
1102
+ } catch let error {
1103
+ print("listPoolJoinRequests", error.localizedDescription)
1104
+ reject("ERR_FULA", "listPoolJoinRequests", error)
1105
+ }
1106
+
1107
+ }
1108
+
1109
+ @objc(votePoolJoinRequest:withPoolID:withAccountString:withAccept:withResolver:withRejecter:)
1110
+ func votePoolJoinRequest(seedString: String, poolID: Int, accountString: String, accept: Bool, resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
1111
+ print("ReactNative", "votePoolJoinRequest: seedString = ", seedString ," poolID = ", poolID, " accountString = ", accountString , " accept = ", accept)
1112
+ do {
1113
+ let result = try fula!.poolVote(seedString, poolID: Int(poolID), account: accountString, voteValue: accept)
1114
+ let resultString = result.toUTF8String()!
1115
+ resolve(resultString)
1116
+ } catch let error {
1117
+ print("votePoolJoinRequest", error.localizedDescription)
1118
+ reject("ERR_FULA", "votePoolJoinRequest", error)
1119
+ }
1120
+
1121
+ }
1122
+
1123
+ @objc(newReplicationRequest:withPoolID:withReplicationFactor:withCid:withResolver:withRejecter:)
1124
+ func newReplicationRequest(seedString: String, poolID: Int, replicationFactor: Int, cid: String, resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
1125
+ print("ReactNative", "newReplicationRequest: seedString = " , seedString , " poolID = " , poolID , " replicationFactor = " , replicationFactor , " cid = " , cid)
1126
+ do {
1127
+ let result = try fula!.manifestUpload(seedString, poolID: poolID, replicationFactor: replicationFactor, uri: cid)
1128
+ let resultString = result.toUTF8String()!
1129
+ resolve(resultString)
1130
+ } catch let error {
1131
+ print("newReplicationRequest", error.localizedDescription)
1132
+ reject("ERR_FULA", "newReplicationRequest", error)
1133
+ }
1134
+
1135
+ }
1136
+
1137
+ @objc(newStoreRequest:withPoolID:withUploader:withCid:withResolver:withRejecter:)
1138
+ func newStoreRequest(seedString: String, poolID: Int, uploader: String, cid: String, resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
1139
+ print("ReactNative", "newStoreRequest: seedString = " + seedString + " poolID = " , poolID , " uploader = " , uploader , " cid = " , cid)
1140
+ do {
1141
+ let result = try fula!.manifestStore(seedString, poolID: poolID, uploader: uploader, cid: cid)
1142
+ let resultString = result.toUTF8String()!
1143
+ resolve(resultString)
1144
+ } catch let error {
1145
+ print("newStoreRequest", error.localizedDescription)
1146
+ reject("ERR_FULA", "newStoreRequest", error)
1147
+ }
1148
+
1149
+ }
1150
+
1151
+ @objc(listAvailableReplicationRequests:withResolver:withRejecter:)
1152
+ func listAvailableReplicationRequests(poolID: Int, resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
1153
+ print("ReactNative", "listAvailableReplicationRequests: poolID = ", poolID)
1154
+ do {
1155
+ let result = try fula!.manifestAvailable(poolID)
1156
+ let resultString = result.toUTF8String()!
1157
+ resolve(resultString)
1158
+ } catch let error {
1159
+ print("listAvailableReplicationRequests", error.localizedDescription)
1160
+ reject("ERR_FULA", "listAvailableReplicationRequests", error)
1161
+ }
1162
+
1163
+ }
1164
+
1165
+ @objc(removeReplicationRequest:withPoolID:withCid:withResolver:withRejecter:)
1166
+ func removeReplicationRequest(seedString: String, poolID: Int, cid: String, resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
1167
+ print("ReactNative", "newReplicationRequest: seedString = " , seedString , " poolID = " , poolID , " cid = " , cid)
1168
+ do {
1169
+ let result = try fula!.manifestRemove(seedString, poolID: poolID, cid: cid)
1170
+ let resultString = result.toUTF8String()!
1171
+ resolve(resultString)
1172
+ } catch let error {
1173
+ print("removeReplicationRequest", error.localizedDescription)
1174
+ reject("ERR_FULA", "removeReplicationRequest", error)
1175
+ }
1176
+
1177
+ }
1178
+
1179
+ @objc(removeStorer:withStorage:withPoolID:withCid:withResolver:withRejecter:)
1180
+ func removeStorer(seedString: String, storage: String, poolID: Int, cid: String, resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
1181
+ print("ReactNative", "removeStorer: seedString = " , seedString , " storage = " , storage , " poolID = " , poolID , " cid = " , cid)
1182
+ do {
1183
+ let result = try fula!.manifestRemoveStorer(seedString, storage: storage, poolID: poolID, cid: cid)
1184
+ let resultString = result.toUTF8String()!
1185
+ resolve(resultString)
1186
+ } catch let error {
1187
+ print("removeStorer", error.localizedDescription)
1188
+ reject("ERR_FULA", "removeStorer", error)
1189
+ }
1190
+
1191
+ }
1192
+
1193
+ @objc(removeStoredReplication:withUploader:withPoolID:withCid:withResolver:withRejecter:)
1194
+ func removeStoredReplication(seedString: String, uploader: String, poolID: Int, cid: String, resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
1195
+ print("ReactNative", "removeStoredReplication: seedString = " , seedString , " uploader = " , uploader , " poolID = " , poolID , " cid = " , cid)
1196
+ do {
1197
+ let result = try fula!.manifestRemoveStored(seedString, uploader: uploader, poolID: poolID, cid: cid)
1198
+ let resultString = result.toUTF8String()!
1199
+ resolve(resultString)
1200
+ } catch let error {
1201
+ print("removeStoredReplication", error.localizedDescription)
1202
+ reject("ERR_FULA", "removeStoredReplication", error)
1203
+ }
1204
+
1205
+ }
1206
+
1207
+ @objc(bloxFreeSpace:withRejecter:)
1208
+ func bloxFreeSpace( resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
1209
+ print("ReactNative", "bloxFreeSpace")
1210
+ do {
1211
+ let result = try fula!.bloxFreeSpace()
1212
+ let resultString = result.toUTF8String()!
1213
+ resolve(resultString)
1214
+ } catch let error {
1215
+ print("bloxFreeSpace", error.localizedDescription)
1216
+ reject("ERR_FULA", "bloxFreeSpace", error)
1217
+ }
1218
+
1219
+ }
1220
+
1221
+ @objc(transferToFula:wallet:chain:withResolver:withRejecter:)
1222
+ func transferToFula(amount: String, wallet: String, chain: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
1223
+ DispatchQueue.global(qos: .default).async {
1224
+ do {
1225
+ print("ReactNative", "transferToFula called")
1226
+ let result = try fula!.transferToFula(amount, wallet: wallet, chain: chain)
1227
+ let resultString = String(data: result!, encoding: .utf8)
1228
+ resolve(resultString)
1229
+ } catch let error {
1230
+ print("ReactNative", "transferToFula failed with Error: \(error.localizedDescription)")
1231
+ reject("ERR_FULA_TRANSFER", "transferToFula failed", error)
1232
+ }
1233
+ }
1234
+ }
1235
+
1236
+
1237
+ @objc(getAccount:withRejecter:)
1238
+ func getAccount(resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
1239
+ do {
1240
+ let account = try fula!.getAccount()
1241
+ let accountString = String(data: account, encoding: .utf8)
1242
+ resolve(accountString)
1243
+ } catch let error {
1244
+ reject("ERR_FULA", "getAccount: \(error.localizedDescription)", error)
1245
+ }
1246
+ }
1247
+
1248
+ @objc(assetsBalance:assetId:classId:withResolver:withRejecter:)
1249
+ func assetsBalance(account: String, assetId: String, classId: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
1250
+ do {
1251
+ let balance = try fula!.assetsBalance(account, assetId: assetId, classId: classId)
1252
+ let balanceString = String(data: balance, encoding: .utf8)
1253
+ resolve(balanceString)
1254
+ } catch let error {
1255
+ reject("ERR_FULA", "assetsBalance: \(error.localizedDescription)", error)
1256
+ }
1257
+ }
1258
+
1259
+
1260
+ @objc(joinPool:withResolver:withRejecter:)
1261
+ func joinPool(poolID: Int, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
1262
+ print("ReactNative", "joinPool: poolID = ", poolID)
1263
+ do {
1264
+ let result = try fula!.joinPool(poolID: poolID)
1265
+ let resultString = String(data: result, encoding: .utf8)
1266
+ resolve(resultString)
1267
+ } catch let error {
1268
+ reject("ERR_FULA", "joinPool: \(error.localizedDescription)", error)
1269
+ }
1270
+ }
1271
+
1272
+
1273
+ @objc(cancelPoolJoin:withResolver:withRejecter:)
1274
+ func cancelPoolJoin(poolID: Int, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
1275
+ do {
1276
+ let result = try fula!.cancelPoolJoin(poolID: poolID)
1277
+ let resultString = String(data: result, encoding: .utf8)
1278
+ resolve(resultString)
1279
+ } catch let error {
1280
+ reject("ERR_FULA", "cancelPoolJoin: \(error.localizedDescription)", error)
1281
+ }
1282
+ }
1283
+
1284
+
1285
+ @objc(leavePool:withResolver:withRejecter:)
1286
+ func leavePool(poolID: Int, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
1287
+ print("ReactNative", "leavePool: poolID = ", poolID)
1288
+ do {
1289
+ let result = try fula!.leavePool(poolID: poolID)
1290
+ let resultString = String(data: result, encoding: .utf8)
1291
+ resolve(resultString)
1292
+ } catch let error {
1293
+ reject("ERR_FULA", "leavePool: \(error.localizedDescription)", error)
1294
+ }
1295
+ }
1296
+
1297
+ @objc(eraseBlData:withRejecter:)
1298
+ func eraseBlData(resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
1299
+ do {
1300
+ let result = try fula!.eraseBlData()
1301
+ let resultString = String(data: result, encoding: .utf8)
1302
+ resolve(resultString)
1303
+ } catch let error {
1304
+ reject("ERR_FULA", "eraseBlData: \(error.localizedDescription)", error)
1305
+ }
1306
+ }
1307
+
1308
+ @objc(reboot:withRejecter:)
1309
+ func reboot(resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void {
1310
+ do {
1311
+ let result = try fula!.reboot()
1312
+ let resultString = result.toUTF8String()!
1313
+ resolve(resultString)
1314
+ } catch let error {
1315
+ print("reboot", error.localizedDescription)
1316
+ reject("ERR_FULA", "reboot", error)
1317
+ }
1318
+ }
1319
+
1320
+ @objc(wifiRemoveall:withRejecter:)
1321
+ func wifiRemoveall(resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void {
1322
+ do {
1323
+ let result = try fula!.wifiRemoveall()
1324
+ let resultString = result.toUTF8String()!
1325
+ resolve(resultString)
1326
+ } catch let error {
1327
+ print("wifiRemoveall", error.localizedDescription)
1328
+ reject("ERR_FULA", "wifiRemoveall", error)
1329
+ }
1330
+ }
1331
+
1332
+ }
1333
+
1334
+