diff --git a/backup-server/src/storage.js b/backup-server/src/storage.js index 250003bc..de333d0a 100644 --- a/backup-server/src/storage.js +++ b/backup-server/src/storage.js @@ -59,10 +59,17 @@ class Storage { //TODO must be a better way instead of iterating over all files let files = []; const list = await this.storage.listFiles(); + list.forEach((file) => { - const [fileName] = file; - if (fileName.startsWith(filePath) && fileName.endsWith('.bin')) { - files.push(fileName.substring(fileName.lastIndexOf('/') + 1)); + const [fullFilePath] = file; + + if (fullFilePath.startsWith(filePath) && fullFilePath.endsWith('.bin')) { + //Ignore directories + if (fullFilePath.replaceAll(filePath, '').replace(/^\//, "").indexOf('/') !== -1) { + return; + } + + files.push(fullFilePath.substring(fullFilePath.lastIndexOf('/') + 1)); } }); diff --git a/lib/android/src/main/java/com/reactnativeldk/LdkModule.kt b/lib/android/src/main/java/com/reactnativeldk/LdkModule.kt index 9d1b4a3c..e4aa7425 100644 --- a/lib/android/src/main/java/com/reactnativeldk/LdkModule.kt +++ b/lib/android/src/main/java/com/reactnativeldk/LdkModule.kt @@ -1108,7 +1108,6 @@ class LdkModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMod promise.resolve((res as Result_TransactionNoneZ.Result_TransactionNoneZ_OK).res.hexEncodedString()) } - @ReactMethod fun nodeSign(message: String, promise: Promise) { keysManager ?: return handleReject(promise, LdkErrors.init_keys_manager) @@ -1210,6 +1209,29 @@ class LdkModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMod handleReject(promise, LdkErrors.backup_check_failed, Error(e)) } } + + @ReactMethod + fun backupListFiles(promise: Promise) { + if (BackupClient.requiresSetup) { + return handleReject(promise, LdkErrors.backup_setup_required) + } + + try { + val list = BackupClient.listFiles() + + val map = Arguments.createMap() + val files = Arguments.createArray() + list.first.forEach { files.pushString(it) } + val channelMonitors = Arguments.createArray() + list.second.forEach { channelMonitors.pushString(it) } + map.putArray("list", files) + map.putArray("channel_monitors", channelMonitors) + + promise.resolve(map) + } catch (e: Exception) { + handleReject(promise, LdkErrors.backup_check_failed, Error(e)) + } + } } object LdkEventEmitter { diff --git a/lib/android/src/main/java/com/reactnativeldk/classes/BackupClient.kt b/lib/android/src/main/java/com/reactnativeldk/classes/BackupClient.kt index 5f83b555..155c16af 100644 --- a/lib/android/src/main/java/com/reactnativeldk/classes/BackupClient.kt +++ b/lib/android/src/main/java/com/reactnativeldk/classes/BackupClient.kt @@ -280,7 +280,7 @@ class BackupClient { } @Throws(BackupError::class) - fun retrieveCompleteBackup(): CompleteBackup { + fun listFiles(): Pair, Array> { val bearer = authToken() val url = backupUrl(Method.LIST) @@ -310,20 +310,35 @@ class BackupClient { inputStream.close() val jsonObject = JSONObject(jsonString) + val fileList = jsonObject.getJSONArray("list") + val channelFileList = jsonObject.getJSONArray("channel_monitors") + + println("fileList: $fileList") + + return Pair( + Array(fileList.length()) { idx -> + fileList.getString(idx) + }, + Array(channelFileList.length()) { idx -> + channelFileList.getString(idx) + }, + ) + } + + @Throws(BackupError::class) + fun retrieveCompleteBackup(): CompleteBackup { + val list = listFiles() + val fileNames = list.first + val channelFileNames = list.second val files = mutableMapOf() - val fileNames = jsonObject.getJSONArray("list") - for (i in 0 until fileNames.length()) { - val filename = fileNames.getString(i) - files[filename] = retrieve(Label.MISC(filename)) + for (fileName in fileNames) { + files[fileName] = retrieve(Label.MISC(fileName)) } val channelFiles = mutableMapOf() - val channelFileNames = jsonObject.getJSONArray("channel_monitors") - for (i in 0 until channelFileNames.length()) { - val filename = channelFileNames.getString(i) - - channelFiles[filename] = retrieve(Label.CHANNEL_MONITOR(channelId=filename.replace(".bin", ""))) + for (fileName in channelFileNames) { + channelFiles[fileName] = retrieve(Label.CHANNEL_MONITOR(channelId=fileName.replace(".bin", ""))) } return CompleteBackup(files = files, channelFiles = channelFiles) diff --git a/lib/ios/Classes/BackupClient.swift b/lib/ios/Classes/BackupClient.swift index bb755857..d0d55a7a 100644 --- a/lib/ios/Classes/BackupClient.swift +++ b/lib/ios/Classes/BackupClient.swift @@ -53,6 +53,11 @@ struct BackupRetrieveBearer: Codable { let expires: Int } +struct ListFilesResponse: Codable { + let list: [String] + let channel_monitors: [String] +} + class BackupClient { enum Label { case ping @@ -309,13 +314,8 @@ class BackupClient { return try decrypt(encryptedBackup) } - static func retrieveCompleteBackup() throws -> CompleteBackup { + static func listFiles() throws -> ListFilesResponse { let bearer = try authToken() - - struct ListFilesResponse: Codable { - let list: [String] - let channel_monitors: [String] - } var backedUpFilenames: ListFilesResponse? @@ -362,6 +362,11 @@ class BackupClient { throw BackupError.missingResponse } + return backedUpFilenames + } + + static func retrieveCompleteBackup() throws -> CompleteBackup { + let backedUpFilenames = try listFiles() var allFiles: [String: Data] = [:] var channelFiles: [String: Data] = [:] @@ -385,6 +390,11 @@ class BackupClient { return CompleteBackup(files: allFiles, channelFiles: channelFiles) } + struct BackupExists { + let exists: Bool + let channelFiles: Int + } + static func selfCheck() throws { //Store a random encrypted string and retrieve it again to confirm the server is working let ping = "ping\(arc4random_uniform(99999))" diff --git a/lib/ios/Ldk.m b/lib/ios/Ldk.m index 0c76f7e8..5b2bab56 100644 --- a/lib/ios/Ldk.m +++ b/lib/ios/Ldk.m @@ -173,6 +173,8 @@ @interface RCT_EXTERN_MODULE(Ldk, NSObject) reject:(RCTPromiseRejectBlock)reject) RCT_EXTERN_METHOD(backupSelfCheck:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) +RCT_EXTERN_METHOD(backupListFiles:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject) @end diff --git a/lib/ios/Ldk.swift b/lib/ios/Ldk.swift index e1dbe8e0..3451c752 100644 --- a/lib/ios/Ldk.swift +++ b/lib/ios/Ldk.swift @@ -73,6 +73,7 @@ enum LdkErrors: String { case backup_check_failed = "backup_check_failed" case backup_restore_failed = "backup_restore_failed" case backup_restore_failed_existing_files = "backup_restore_failed_existing_files" + case backup_list_files_failed = "backup_list_files_failed" } enum LdkCallbackResponses: String { @@ -884,7 +885,7 @@ class Ldk: NSObject { guard let invoice = res.getValue() else { return handleReject(reject, .invoice_create_failed) } - + return resolve(invoice.asJson) //Invoice class extended in Helpers file } @@ -1323,6 +1324,23 @@ class Ldk: NSObject { handleReject(reject, .backup_check_failed, error, error.localizedDescription) } } + + @objc + func backupListFiles(_ resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) { + guard !BackupClient.requiresSetup else { + return handleReject(reject, .backup_setup_required) + } + + do { + let result = try BackupClient.listFiles() + resolve([ + "list": result.list, + "channel_monitors": result.channel_monitors + ]) + } catch { + handleReject(reject, .backup_list_files_failed, error, error.localizedDescription) + } + } } //MARK: Singleton react native event emitter diff --git a/lib/package.json b/lib/package.json index 9d366a82..d9fcd78e 100644 --- a/lib/package.json +++ b/lib/package.json @@ -1,7 +1,7 @@ { "name": "@synonymdev/react-native-ldk", "title": "React Native LDK", - "version": "0.0.111", + "version": "0.0.112", "description": "React Native wrapper for LDK", "main": "./dist/index.js", "types": "./dist/index.d.ts", diff --git a/lib/src/ldk.ts b/lib/src/ldk.ts index af3519d0..54aefddd 100644 --- a/lib/src/ldk.ts +++ b/lib/src/ldk.ts @@ -34,6 +34,7 @@ import { TAcceptChannelReq, TBackupServerDetails, TNodeSignReq, + TBackedUpFileList, } from './utils/types'; import { extractPaymentRequest } from './utils/helpers'; @@ -1248,6 +1249,18 @@ class LDK { return err(e); } } + + /** + * List all files that have been backed up + */ + async backupListFiles(): Promise> { + try { + const res = await NativeLDK.backupListFiles(); + return ok(res); + } catch (e) { + return err(e); + } + } } export default new LDK(); diff --git a/lib/src/utils/types.ts b/lib/src/utils/types.ts index f09a9b87..6f8c9aa1 100644 --- a/lib/src/utils/types.ts +++ b/lib/src/utils/types.ts @@ -584,6 +584,11 @@ export type TBackupServerDetails = { serverPubKey: string; }; +export type TBackedUpFileList = { + list: [string]; + channel_monitors: [string]; +}; + export type TNodeSignReq = { message: string; messagePrefix?: string;