gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-taler-ios] branch master updated: use AnyCodable for json interac


From: gnunet
Subject: [taler-taler-ios] branch master updated: use AnyCodable for json interaction with backend
Date: Thu, 30 Jun 2022 09:38:00 +0200

This is an automated email from the git hooks/post-receive script.

jonathan-buchanan pushed a commit to branch master
in repository taler-ios.

The following commit(s) were added to refs/heads/master by this push:
     new 119c594  use AnyCodable for json interaction with backend
119c594 is described below

commit 119c5946976e04d97a5943b09e3447182b6a3452
Author: Jonathan Buchanan <jonathan.russ.buchanan@gmail.com>
AuthorDate: Thu Jun 30 03:37:41 2022 -0400

    use AnyCodable for json interaction with backend
---
 Taler.xcodeproj/project.pbxproj                    |   30 +
 .../project.xcworkspace/contents.xcworkspacedata   |    2 +-
 .../xcshareddata/swiftpm/Package.resolved          |   14 +
 .../UserInterfaceState.xcuserstate                 |  Bin 42037 -> 48886 bytes
 Taler/AppDelegate.swift                            |    7 -
 Taler/BalanceRow.swift                             |    4 +-
 Taler/WalletBackend.swift                          | 1118 ++++++--------------
 TalerTests/WalletBackendTests.swift                |   25 +
 8 files changed, 395 insertions(+), 805 deletions(-)

diff --git a/Taler.xcodeproj/project.pbxproj b/Taler.xcodeproj/project.pbxproj
index 9d6f926..6fff46c 100644
--- a/Taler.xcodeproj/project.pbxproj
+++ b/Taler.xcodeproj/project.pbxproj
@@ -7,7 +7,9 @@
        objects = {
 
 /* Begin PBXBuildFile section */
+               AB8C3807286A88A600E0A1DD /* WalletBackendTests.swift in Sources 
*/ = {isa = PBXBuildFile; fileRef = AB8C3806286A88A500E0A1DD /* 
WalletBackendTests.swift */; };
                ABC13AA32859962800D23185 /* taler-swift in Frameworks */ = {isa 
= PBXBuildFile; productRef = ABC13AA22859962800D23185 /* taler-swift */; };
+               ABE97B1D286D82BF00580772 /* AnyCodable in Frameworks */ = {isa 
= PBXBuildFile; productRef = ABE97B1C286D82BF00580772 /* AnyCodable */; };
                D112510026B12E3200D02E00 /* taler-wallet-embedded.js in 
CopyFiles */ = {isa = PBXBuildFile; fileRef = D11250FF26B12E3200D02E00 /* 
taler-wallet-embedded.js */; };
                D14AFD2124D232B300C51073 /* AppDelegate.swift in Sources */ = 
{isa = PBXBuildFile; fileRef = D14AFD2024D232B300C51073 /* AppDelegate.swift 
*/; };
                D14AFD2324D232B300C51073 /* SceneDelegate.swift in Sources */ = 
{isa = PBXBuildFile; fileRef = D14AFD2224D232B300C51073 /* SceneDelegate.swift 
*/; };
@@ -70,6 +72,7 @@
 
 /* Begin PBXFileReference section */
                AB710490285995B6008B04F0 /* taler-swift */ = {isa = 
PBXFileReference; lastKnownFileType = text; path = "taler-swift"; sourceTree = 
SOURCE_ROOT; };
+               AB8C3806286A88A500E0A1DD /* WalletBackendTests.swift */ = {isa 
= PBXFileReference; lastKnownFileType = sourcecode.swift; path = 
WalletBackendTests.swift; sourceTree = "<group>"; };
                D11250FF26B12E3200D02E00 /* taler-wallet-embedded.js */ = {isa 
= PBXFileReference; lastKnownFileType = sourcecode.javascript; path = 
"taler-wallet-embedded.js"; sourceTree = "<group>"; };
                D11DB44E25A5C487009CF0BC /* libnode.a */ = {isa = 
PBXFileReference; lastKnownFileType = archive.ar; name = libnode.a; path = 
"nodejs-mobile/out/Release/libnode.a"; sourceTree = "<group>"; };
                D11DB45625A5C5C7009CF0BC /* libv8_initializers.a */ = {isa = 
PBXFileReference; lastKnownFileType = archive.ar; name = libv8_initializers.a; 
path = "nodejs-mobile/out/Release/libv8_initializers.a"; sourceTree = 
"<group>"; };
@@ -203,6 +206,7 @@
                                D17D8B7E25ADB29B001BD43D /* libuv.a in 
Frameworks */,
                                D17D8B7D25ADB29B001BD43D /* libuvwasi.a in 
Frameworks */,
                                D17D8B7325ADB29A001BD43D /* libzlib.a in 
Frameworks */,
+                               ABE97B1D286D82BF00580772 /* AnyCodable in 
Frameworks */,
                                D17D8B8225ADB29B001BD43D /* libnghttp2.a in 
Frameworks */,
                                D17D8B7425ADB29A001BD43D /* libv8_zlib.a in 
Frameworks */,
                                D17D8B8525ADB29B001BD43D /* libcares.a in 
Frameworks */,
@@ -283,6 +287,7 @@
                        isa = PBXGroup;
                        children = (
                                D14AFD3924D232B500C51073 /* Info.plist */,
+                               AB8C3806286A88A500E0A1DD /* 
WalletBackendTests.swift */,
                        );
                        path = TalerTests;
                        sourceTree = "<group>";
@@ -430,6 +435,7 @@
                        name = Taler;
                        packageProductDependencies = (
                                ABC13AA22859962800D23185 /* taler-swift */,
+                               ABE97B1C286D82BF00580772 /* AnyCodable */,
                        );
                        productName = Taler;
                        productReference = D14AFD1D24D232B300C51073 /* 
Taler.app */;
@@ -488,6 +494,7 @@
                                        };
                                        D14AFD3224D232B500C51073 = {
                                                CreatedOnToolsVersion = 11.6;
+                                               LastSwiftMigration = 1340;
                                                TestTargetID = 
D14AFD1C24D232B300C51073;
                                        };
                                        D14AFD3D24D232B500C51073 = {
@@ -505,6 +512,9 @@
                                Base,
                        );
                        mainGroup = D14AFD1424D232B300C51073;
+                       packageReferences = (
+                               ABE97B1B286D82BF00580772 /* 
XCRemoteSwiftPackageReference "AnyCodable" */,
+                       );
                        productRefGroup = D14AFD1E24D232B300C51073 /* Products 
*/;
                        projectDirPath = "";
                        projectRoot = "";
@@ -598,6 +608,7 @@
                        isa = PBXSourcesBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
+                               AB8C3807286A88A600E0A1DD /* 
WalletBackendTests.swift in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
@@ -858,6 +869,7 @@
                        buildSettings = {
                                ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
                                BUNDLE_LOADER = "$(TEST_HOST)";
+                               CLANG_ENABLE_MODULES = YES;
                                "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple 
Development";
                                CODE_SIGN_STYLE = Automatic;
                                DEVELOPMENT_TEAM = "";
@@ -870,6 +882,7 @@
                                );
                                PRODUCT_BUNDLE_IDENTIFIER = 
com.taler.TalerTests;
                                PRODUCT_NAME = "$(TARGET_NAME)";
+                               SWIFT_OPTIMIZATION_LEVEL = "-Onone";
                                SWIFT_VERSION = 5.0;
                                TARGETED_DEVICE_FAMILY = "1,2";
                                TEST_HOST = 
"$(BUILT_PRODUCTS_DIR)/Taler.app/Taler";
@@ -881,6 +894,7 @@
                        buildSettings = {
                                ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
                                BUNDLE_LOADER = "$(TEST_HOST)";
+                               CLANG_ENABLE_MODULES = YES;
                                "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple 
Development";
                                CODE_SIGN_STYLE = Automatic;
                                DEVELOPMENT_TEAM = "";
@@ -978,11 +992,27 @@
                };
 /* End XCConfigurationList section */
 
+/* Begin XCRemoteSwiftPackageReference section */
+               ABE97B1B286D82BF00580772 /* XCRemoteSwiftPackageReference 
"AnyCodable" */ = {
+                       isa = XCRemoteSwiftPackageReference;
+                       repositoryURL = 
"https://github.com/Flight-School/AnyCodable";;
+                       requirement = {
+                               kind = upToNextMajorVersion;
+                               minimumVersion = 0.6.5;
+                       };
+               };
+/* End XCRemoteSwiftPackageReference section */
+
 /* Begin XCSwiftPackageProductDependency section */
                ABC13AA22859962800D23185 /* taler-swift */ = {
                        isa = XCSwiftPackageProductDependency;
                        productName = "taler-swift";
                };
+               ABE97B1C286D82BF00580772 /* AnyCodable */ = {
+                       isa = XCSwiftPackageProductDependency;
+                       package = ABE97B1B286D82BF00580772 /* 
XCRemoteSwiftPackageReference "AnyCodable" */;
+                       productName = AnyCodable;
+               };
 /* End XCSwiftPackageProductDependency section */
        };
        rootObject = D14AFD1524D232B300C51073 /* Project object */;
diff --git a/Taler.xcodeproj/project.xcworkspace/contents.xcworkspacedata 
b/Taler.xcodeproj/project.xcworkspace/contents.xcworkspacedata
index 1cf7755..919434a 100644
--- a/Taler.xcodeproj/project.xcworkspace/contents.xcworkspacedata
+++ b/Taler.xcodeproj/project.xcworkspace/contents.xcworkspacedata
@@ -2,6 +2,6 @@
 <Workspace
    version = "1.0">
    <FileRef
-      location = 
"self:../wallet-kotlin/build/bin/iosX64/debugFramework/TalerWallet.framework">
+      location = "self:">
    </FileRef>
 </Workspace>
diff --git 
a/Taler.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved 
b/Taler.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
new file mode 100644
index 0000000..7eca6e5
--- /dev/null
+++ b/Taler.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
@@ -0,0 +1,14 @@
+{
+  "pins" : [
+    {
+      "identity" : "anycodable",
+      "kind" : "remoteSourceControl",
+      "location" : "https://github.com/Flight-School/AnyCodable";,
+      "state" : {
+        "revision" : "f9fda69a7b704d46fb5123005f2f7e43dbb8a0fa",
+        "version" : "0.6.5"
+      }
+    }
+  ],
+  "version" : 2
+}
diff --git 
a/Taler.xcodeproj/project.xcworkspace/xcuserdata/jonathan.xcuserdatad/UserInterfaceState.xcuserstate
 
b/Taler.xcodeproj/project.xcworkspace/xcuserdata/jonathan.xcuserdatad/UserInterfaceState.xcuserstate
index 4d78d3c..f7e800f 100644
Binary files 
a/Taler.xcodeproj/project.xcworkspace/xcuserdata/jonathan.xcuserdatad/UserInterfaceState.xcuserstate
 and 
b/Taler.xcodeproj/project.xcworkspace/xcuserdata/jonathan.xcuserdatad/UserInterfaceState.xcuserstate
 differ
diff --git a/Taler/AppDelegate.swift b/Taler/AppDelegate.swift
index fd0327d..055475a 100644
--- a/Taler/AppDelegate.swift
+++ b/Taler/AppDelegate.swift
@@ -19,12 +19,8 @@ import iono
 
 @UIApplicationMain
 class AppDelegate: UIResponder, UIApplicationDelegate {
-
-
-
     func application(_ application: UIApplication, 
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: 
Any]?) -> Bool {
         // Override point for customization after application launch.
-        let _ = try! WalletBackend()
         return true
     }
 
@@ -41,7 +37,4 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
         // If any sessions were discarded while the application was not 
running, this will be called shortly after 
application:didFinishLaunchingWithOptions.
         // Use this method to release any resources that were specific to the 
discarded scenes, as they will not return.
     }
-
-
 }
-
diff --git a/Taler/BalanceRow.swift b/Taler/BalanceRow.swift
index b6e86c5..7a19eef 100644
--- a/Taler/BalanceRow.swift
+++ b/Taler/BalanceRow.swift
@@ -17,7 +17,7 @@
 import SwiftUI
 import taler_swift
 
-struct BalanceRow: View {
+/*struct BalanceRow: View {
     var balance: Balance
     
     var body: some View {
@@ -35,4 +35,4 @@ struct BalanceRow_Previews: PreviewProvider {
     static var previews: some View {
         try! BalanceRow(balance: Balance(available: Amount(fromString: 
"USD:0.01"), pendingIncoming: Amount(fromString: "USD:0.02"), pendingOutgoing: 
Amount(fromString: "USD:0.03"), requiresUserInput: true))
     }
-}
+}*/
diff --git a/Taler/WalletBackend.swift b/Taler/WalletBackend.swift
index eb1087a..5f2308f 100644
--- a/Taler/WalletBackend.swift
+++ b/Taler/WalletBackend.swift
@@ -16,41 +16,47 @@
 import Foundation
 import iono
 import taler_swift
+import AnyCodable
 
+/// Information supplied by the backend describing an error.
 struct WalletBackendResponseError: Decodable {
+    /// Numeric error code defined defined in the GANA gnu-taler-error-codes 
registry.
     var talerErrorCode: Int
+    
+    /// English description of the error code.
     var talerErrorHint: String
+    
+    /// English diagnostic message that can give details for the instance of 
the error.
     var message: String
+    
+    /// Error details, type depends on `talerErrorCode`.
     var details: Data?
 }
 
-protocol WalletBackendRequest {
+/// A request sent to the wallet backend.
+struct WalletBackendRequest: Encodable {
+    /// The operation name of the request.
+    var operation: String
+    
+    /// The body of the request as JSON.
+    var args: AnyEncodable
+}
+
+protocol WalletBackendFormattedRequest {
     associatedtype Args: Encodable
     associatedtype Response: Decodable
     
     func operation() -> String
     func args() -> Args
-    func success(result: Response)
-    func error(_ err: WalletBackendResponseError)
 }
 
-fileprivate struct WalletBackendRequestData<T: WalletBackendRequest>: 
Encodable {
-    var operation: String
-    var id: UInt
-    var args: T.Args
+fileprivate struct WalletBackendInitRequest: WalletBackendFormattedRequest {
+    var persistentStoragePath: String
     
-    init(request: T, id: UInt) {
-        operation = request.operation()
-        self.id = id
-        args = request.args()
-    }
-}
-
-fileprivate struct WalletBackendInitRequest: WalletBackendRequest {
-    struct RequestArgs: Encodable {
+    struct Args: Encodable {
         var persistentStoragePath: String
     }
-    typealias Args = RequestArgs
+    
     struct Response: Codable {
         struct SupportedProtocolVersions: Codable {
             var exchange: String
@@ -61,34 +67,17 @@ fileprivate struct WalletBackendInitRequest: 
WalletBackendRequest {
             case supportedProtocolVersions = "supported_protocol_versions"
         }
     }
-    private var requestArgs: RequestArgs
-    private let success: () -> Void
-    
-    init(persistentStoragePath: String, onSuccess: @escaping () -> Void) {
-        requestArgs = RequestArgs(persistentStoragePath: persistentStoragePath)
-        self.success = onSuccess
-    }
     
     func operation() -> String {
         return "init"
     }
     
     func args() -> Args {
-        return requestArgs
-    }
-    
-    func success(result: Response) {
-        self.success()
-    }
-    
-    func error(_ err: WalletBackendResponseError) {
-        
+        return Args(persistentStoragePath: persistentStoragePath)
     }
 }
 
-/**
-    An balance on a wallet.
- */
+/// An balance on a wallet.
 struct Balance: Decodable {
     var available: Amount
     var pendingIncoming: Amount
@@ -96,26 +85,14 @@ struct Balance: Decodable {
     var requiresUserInput: Bool
 }
 
-/**
-    A request to get the balances held in the wallet.
- */
-class WalletBackendGetBalancesRequest: WalletBackendRequest {
-    struct BalancesResponse: Decodable {
-        var balances: [Balance]
-    }
-    struct RequestArgs: Encodable {
+/// A request to get the balances held in the wallet.
+struct WalletBackendGetBalancesRequest: WalletBackendFormattedRequest {
+    struct Args: Encodable {
         
     }
-    typealias Args = RequestArgs
-    typealias Response = BalancesResponse
-    private var requestArgs: RequestArgs
-    private let success: ([Balance]) -> Void
-    private let failure: () -> Void
     
-    init(onSuccess: @escaping ([Balance]) -> Void, onFailure: @escaping () -> 
Void) {
-        self.requestArgs = RequestArgs()
-        self.success = onSuccess
-        self.failure = onFailure
+    struct Response: Decodable {
+        var balances: [Balance]
     }
     
     func operation() -> String {
@@ -123,21 +100,11 @@ class WalletBackendGetBalancesRequest: 
WalletBackendRequest {
     }
     
     func args() -> Args {
-        return requestArgs
-    }
-    
-    func success(result: Response) {
-        self.success(result.balances)
-    }
-    
-    func error(_ err: WalletBackendResponseError) {
-        self.failure()
+        return Args()
     }
 }
 
-/**
-    A billing or mailing location.
- */
+/// A billing or mailing location.
 struct Location: Codable {
     var country: String?
     var country_subdivision: String?
@@ -151,26 +118,20 @@ struct Location: Codable {
     var address_lines: [String]?
 }
 
-/**
-    Information identifying a merchant.
- */
+/// Information identifying a merchant.
 struct Merchant: Codable {
     var name: String
     var address: Location?
     var jurisdiction: Location?
 }
 
-/**
-    A tax made on a payment.
- */
+/// A tax made on a payment.
 struct Tax: Codable {
     var name: String
     var tax: Amount
 }
 
-/**
-    A product being purchased from a merchant.
- */
+/// A product being purchased from a merchant.
 struct Product: Codable {
     var product_id: String?
     var description: String
@@ -183,9 +144,7 @@ struct Product: Codable {
     var delivery_date: Timestamp?
 }
 
-/**
-    Brief information about an order.
- */
+/// Brief information about an order.
 struct OrderShortInfo: Codable {
     var orderId: String
     var merchant: Merchant
@@ -201,9 +160,7 @@ enum TransactionTypeError: Error {
     case unknownTypeError
 }
 
-/**
-    Different types of transactions.
- */
+/// Different types of transactions.
 enum TransactionType: Codable {
     case withdrawal
     case payment
@@ -245,18 +202,14 @@ enum TransactionType: Codable {
     }
 }
 
-/**
-    An error associated with a transaction.
- */
+/// An error associated with a transaction.
 struct TransactionError: Codable {
     var ec: Int
     var hint: String?
     //var details: Any?
 }
 
-/**
-    A wallet transaction.
- */
+/// A wallet transaction.
 struct Transaction: Codable {
     var transactionId: String
     var type: TransactionType
@@ -267,45 +220,18 @@ struct Transaction: Codable {
     var amountEffective: Amount
 }
 
-/**
-    A request to get the transactions in the wallet's history.
- */
-class WalletBackendGetTransactionsRequest: WalletBackendRequest {
-    struct RequestArgs: Encodable {
+/// A request to get the transactions in the wallet's history.
+struct WalletBackendGetTransactionsRequest: WalletBackendFormattedRequest {
+    var currency: String?
+    var search: String?
+    
+    struct Args: Encodable {
         var currency: String?
         var search: String?
     }
-    struct TransactionsResponse: Decodable {
-        
-    }
-    typealias Args = RequestArgs
-    typealias Response = TransactionsResponse
-    private var requestArgs: RequestArgs
-    private let success: () -> Void
-    private let failure: () -> Void
-    
-    init(onSuccess: @escaping () -> Void, onFailure: @escaping () -> Void) {
-        self.requestArgs = RequestArgs(currency: nil, search: nil)
-        self.success = onSuccess
-        self.failure = onFailure
-    }
     
-    init(filterCurrency: String, onSuccess: @escaping () -> Void, onFailure: 
@escaping () -> Void) {
-        self.requestArgs = RequestArgs(currency: filterCurrency, search: nil)
-        self.success = onSuccess
-        self.failure = onFailure
-    }
-    
-    init(searchString: String, onSuccess: @escaping () -> Void, onFailure: 
@escaping () -> Void) {
-        self.requestArgs = RequestArgs(currency: nil, search: searchString)
-        self.success = onSuccess
-        self.failure = onFailure
-    }
-    
-    init(filterCurrency: String, searchString: String, onSuccess: @escaping () 
-> Void, onFailure: @escaping () -> Void) {
-        self.requestArgs = RequestArgs(currency: filterCurrency, search: 
searchString)
-        self.success = onSuccess
-        self.failure = onFailure
+    struct Response: Decodable {
+        
     }
     
     func operation() -> String {
@@ -313,38 +239,20 @@ class WalletBackendGetTransactionsRequest: 
WalletBackendRequest {
     }
     
     func args() -> Args {
-        return requestArgs
-    }
-    
-    func success(result: Response) {
-        self.success()
-    }
-    
-    func error(_ err: WalletBackendResponseError) {
-        self.failure()
+        return Args(currency: currency, search: search)
     }
 }
 
-/**
-    A request to delete a wallet transaction by ID.
- */
-class WalletBackendDeleteTransactionRequest: WalletBackendRequest {
-    struct RequestArgs: Encodable {
+/// A request to delete a wallet transaction by ID.
+struct WalletBackendDeleteTransactionRequest: WalletBackendFormattedRequest {
+    var transactionId: String
+    
+    struct Args: Encodable {
         var transactionId: String
     }
-    struct RequestResponse: Decodable {
-        
-    }
-    typealias Args = RequestArgs
-    typealias Response = RequestResponse
-    private var requestArgs: RequestArgs
-    private let success: () -> Void
-    private let failure: () -> Void
     
-    init(transactionID: String, onSuccess: @escaping () -> Void, onFailure: 
@escaping () -> Void) {
-        self.requestArgs = RequestArgs(transactionId: transactionID)
-        self.success = onSuccess
-        self.failure = onFailure
+    struct Response: Decodable {
+        
     }
     
     func operation() -> String {
@@ -352,26 +260,19 @@ class WalletBackendDeleteTransactionRequest: 
WalletBackendRequest {
     }
     
     func args() -> Args {
-        return requestArgs
-    }
-    
-    func success(result: Response) {
-        self.success()
-    }
-    
-    func error(_ err: WalletBackendResponseError) {
-        self.failure()
+        return Args(transactionId: transactionId)
     }
 }
 
-/**
-    A request to process a refund.
- */
-class WalletBackendApplyRefundRequest: WalletBackendRequest {
-    struct RequestArgs: Encodable {
+/// A request to process a refund.
+struct WalletBackendApplyRefundRequest: WalletBackendFormattedRequest {
+    var talerRefundUri: String
+    
+    struct Args: Encodable {
         var talerRefundUri: String
     }
-    struct RequestResponse: Decodable {
+    
+    struct Response: Decodable {
         var contractTermsHash: String
         var amountEffectivePaid: Amount
         var amountRefundGranted: Amount
@@ -379,233 +280,126 @@ class WalletBackendApplyRefundRequest: 
WalletBackendRequest {
         var pendingAtExchange: Bool
         var info: OrderShortInfo
     }
-    typealias Args = RequestArgs
-    typealias Response = RequestResponse
-    private let requestArgs: RequestArgs
-    private let success: (RequestResponse) -> Void
-    private let failure: () -> Void
-    
-    init(refundURI: String, onSuccess: @escaping (RequestResponse) -> Void, 
onFailure: @escaping () -> Void) {
-        self.requestArgs = RequestArgs(talerRefundUri: refundURI)
-        self.success = onSuccess
-        self.failure = onFailure
-    }
     
     func operation() -> String {
         return "applyRefund"
     }
     
     func args() -> Args {
-        return requestArgs
-    }
-    
-    func success(result: Response) {
-        self.success(result)
-    }
-    
-    func error(_ err: WalletBackendResponseError) {
-        self.failure()
+        return Args(talerRefundUri: talerRefundUri)
     }
 }
 
-/**
-    A request to list exchanges.
- */
-class WalletBackendListExchanges: WalletBackendRequest {
-    struct RequestArgs: Encodable {
+/// A request to list exchanges.
+struct WalletBackendListExchanges: WalletBackendFormattedRequest {
+    struct Args: Encodable {
         
     }
+    
     struct ExchangeListItem: Decodable {
         var exchangeBaseUrl: String
         var currency: String
         var paytoUris: [String]
     }
-    struct RequestResponse: Decodable {
-        var exchanges: [ExchangeListItem]
-    }
-    typealias Args = RequestArgs
-    typealias Response = RequestResponse
-    private let success: ([ExchangeListItem]) -> Void
-    private let failure: () -> Void
     
-    init(onSuccess: @escaping ([ExchangeListItem]) -> Void, onFailure: 
@escaping () -> Void) {
-        self.success = onSuccess
-        self.failure = onFailure
+    struct Response: Decodable {
+        var exchanges: [ExchangeListItem]
     }
     
     func operation() -> String {
         return "listExchanges"
     }
     
-    func args() -> RequestArgs {
-        return RequestArgs()
-    }
-    
-    func success(result: RequestResponse) {
-        self.success(result.exchanges)
-    }
-    
-    func error(_ err: WalletBackendResponseError) {
-        self.failure()
+    func args() -> Args {
+        return Args()
     }
 }
 
-/**
-    A request to add an exchange.
- */
-class WalletBackendAddRequest: WalletBackendRequest {
-    struct RequestArgs: Encodable {
+/// A request to add an exchange.
+struct WalletBackendAddRequest: WalletBackendFormattedRequest {
+    var exchangeBaseUrl: String
+    
+    struct Args: Encodable {
         var exchangeBaseUrl: String
     }
-    struct RequestResponse: Decodable {
-        
-    }
-    typealias Args = RequestArgs
-    typealias Response = RequestResponse
-    private let requestArgs: RequestArgs
-    private let success: () -> Void
-    private let failure: () -> Void
     
-    init(exchangeBaseURL: String, onSuccess: @escaping () -> Void, onFailure: 
@escaping () -> Void) {
-        self.requestArgs = RequestArgs(exchangeBaseUrl: exchangeBaseURL)
-        self.success = onSuccess
-        self.failure = onFailure
+    struct Response: Decodable {
+        
     }
     
     func operation() -> String {
         return "addRequest"
     }
     
-    func args() -> RequestArgs {
-        return requestArgs
-    }
-    
-    func success(result: RequestResponse) {
-        self.success()
-    }
-    
-    func error(_ err: WalletBackendResponseError) {
-        self.failure()
+    func args() -> Args {
+        return Args(exchangeBaseUrl: exchangeBaseUrl)
     }
 }
 
-/**
-    A request to force update an exchange.
- */
-class WalletBackendForceUpdateRequest: WalletBackendRequest {
-    struct RequestArgs: Encodable {
+/// A request to force update an exchange.
+struct WalletBackendForceUpdateRequest: WalletBackendFormattedRequest {
+    var exchangeBaseUrl: String
+    
+    struct Args: Encodable {
         var exchangeBaseUrl: String
     }
-    struct RequestResponse: Decodable {
-        
-    }
-    typealias Args = RequestArgs
-    typealias Response = RequestResponse
-    private let requestArgs: RequestArgs
-    private let success: () -> Void
-    private let failure: () -> Void
     
-    init(exchangeBaseURL: String, onSuccess: @escaping () -> Void, onFailure: 
@escaping () -> Void) {
-        self.requestArgs = RequestArgs(exchangeBaseUrl: exchangeBaseURL)
-        self.success = onSuccess
-        self.failure = onFailure
+    struct Response: Decodable {
+        
     }
     
     func operation() -> String {
         return "addRequest"
     }
     
-    func args() -> RequestArgs {
-        return requestArgs
-    }
-    
-    func success(result: RequestResponse) {
-        self.success()
-    }
-    
-    func error(_ err: WalletBackendResponseError) {
-        self.failure()
+    func args() -> Args {
+        return Args(exchangeBaseUrl: exchangeBaseUrl)
     }
 }
 
-/**
-    A request to query an exchange's terms of service.
- */
-class WalletBackendGetExchangeTermsOfService: WalletBackendRequest {
-    struct RequestArgs: Encodable {
+/// A request to query an exchange's terms of service.
+struct WalletBackendGetExchangeTermsOfService: WalletBackendFormattedRequest {
+    var exchangeBaseUrl: String
+    
+    struct Args: Encodable {
         var exchangeBaseUrl: String
     }
-    struct RequestResponse: Decodable {
+    
+    struct Response: Decodable {
         var tos: String
         var currentEtag: String
         var acceptedEtag: String
     }
-    typealias Args = RequestArgs
-    typealias Response = RequestResponse
-    private let requestArgs: RequestArgs
-    private let success: () -> Void
-    private let failure: () -> Void
-    
-    init(exchangeBaseURL: String, onSuccess: @escaping () -> Void, onFailure: 
@escaping () -> Void) {
-        self.requestArgs = RequestArgs(exchangeBaseUrl: exchangeBaseURL)
-        self.success = onSuccess
-        self.failure = onFailure
-    }
     
     func operation() -> String {
         return "getExchangeTos"
     }
     
-    func args() -> RequestArgs {
-        return requestArgs
-    }
-    
-    func success(result: RequestResponse) {
-        self.success()
-    }
-    
-    func error(_ err: WalletBackendResponseError) {
-        self.failure()
+    func args() -> Args {
+        return Args(exchangeBaseUrl: exchangeBaseUrl)
     }
 }
 
-/**
-    A request to mark an exchange's terms of service as accepted.
- */
-class WalletBackendSetExchangeTermsOfServiceAccepted: WalletBackendRequest {
-    struct RequestArgs: Encodable {
+/// A request to mark an exchange's terms of service as accepted.
+struct WalletBackendSetExchangeTermsOfServiceAccepted: 
WalletBackendFormattedRequest {
+    var exchangeBaseUrl: String
+    var acceptedEtag: String
+    
+    struct Args: Encodable {
         var exchangeBaseUrl: String
         var acceptedEtag: String
     }
-    struct RequestResponse: Decodable {
-        
-    }
-    typealias Args = RequestArgs
-    typealias Response = RequestResponse
-    private let requestArgs: RequestArgs
-    private let success: () -> Void
-    private let failure: () -> Void
     
-    init(exchangeBaseURL: String, acceptedEtag: String, onSuccess: @escaping 
() -> Void, onFailure: @escaping () -> Void) {
-        self.requestArgs = RequestArgs(exchangeBaseUrl: exchangeBaseURL, 
acceptedEtag: acceptedEtag)
-        self.success = onSuccess
-        self.failure = onFailure
+    struct Response: Decodable {
+        
     }
     
     func operation() -> String {
         return "setExchangeTosAccepted"
     }
     
-    func args() -> RequestArgs {
-        return requestArgs
-    }
-    
-    func success(result: RequestResponse) {
-        self.success()
-    }
-    
-    func error(_ err: WalletBackendResponseError) {
-        self.failure()
+    func args() -> Args {
+        return Args(exchangeBaseUrl: exchangeBaseUrl, acceptedEtag: 
acceptedEtag)
     }
 }
 
@@ -615,295 +409,174 @@ struct ExchangeListItem: Codable {
     var paytoUris: [String]
 }
 
-/**
-    A request to get an exchange's withdrawal details.
- */
-class WalletBackendGetWithdrawalDetailsForURIRequest: WalletBackendRequest {
-    struct RequestArgs: Encodable {
+/// A request to get an exchange's withdrawal details.
+struct WalletBackendGetWithdrawalDetailsForURIRequest: 
WalletBackendFormattedRequest {
+    var talerWithdrawUri: String
+    
+    struct Args: Encodable {
         var talerWithdrawUri: String
     }
-    struct RequestResponse: Decodable {
+    
+    struct Response: Decodable {
         var amount: Amount
         var defaultExchangeBaseUrl: String?
         var possibleExchanges: [ExchangeListItem]
     }
-    typealias Args = RequestArgs
-    typealias Response = RequestResponse
-    private let requestArgs: RequestArgs
-    private let success: () -> Void
-    private let failure: () -> Void
-    
-    init(talerWithdrawUri: String, onSuccess: @escaping () -> Void, onFailure: 
@escaping () -> Void) {
-        self.requestArgs = RequestArgs(talerWithdrawUri: talerWithdrawUri)
-        self.success = onSuccess
-        self.failure = onFailure
-    }
     
     func operation() -> String {
         return "getWithdrawalDetailsForUri"
     }
     
-    func args() -> RequestArgs {
-        return requestArgs
-    }
-    
-    func success(result: RequestResponse) {
-        self.success()
-    }
-    
-    func error(_ err: WalletBackendResponseError) {
-        self.failure()
+    func args() -> Args {
+        return Args(talerWithdrawUri: talerWithdrawUri)
     }
 }
 
-/**
-    A request to get an exchange's withdrawal details.
- */
-class WalletBackendGetWithdrawalDetailsForAmountRequest: WalletBackendRequest {
-    struct RequestArgs: Encodable {
+/// A request to get an exchange's withdrawal details.
+struct WalletBackendGetWithdrawalDetailsForAmountRequest: 
WalletBackendFormattedRequest {
+    var exchangeBaseUrl: String
+    var amount: Amount
+    
+    struct Args: Encodable {
         var exchangeBaseUrl: String
         var amount: Amount
     }
-    struct RequestResponse: Decodable {
+    
+    struct Response: Decodable {
         var tosAccepted: Bool
         var amountRaw: Amount
         var amountEffective: Amount
     }
-    typealias Args = RequestArgs
-    typealias Response = RequestResponse
-    private let requestArgs: RequestArgs
-    private let success: () -> Void
-    private let failure: () -> Void
-    
-    init(exchangeBaseURL: String, amount: Amount, onSuccess: @escaping () -> 
Void, onFailure: @escaping () -> Void) {
-        self.requestArgs = RequestArgs(exchangeBaseUrl: exchangeBaseURL, 
amount: amount)
-        self.success = onSuccess
-        self.failure = onFailure
-    }
     
     func operation() -> String {
         return "getWithdrawalDetailsForAmount"
     }
     
-    func args() -> RequestArgs {
-        return requestArgs
-    }
-    
-    func success(result: RequestResponse) {
-        self.success()
-    }
-    
-    func error(_ err: WalletBackendResponseError) {
-        self.failure()
+    func args() -> Args {
+        return Args(exchangeBaseUrl: exchangeBaseUrl, amount: amount)
     }
 }
 
-/**
-    A request to accept a bank-integrated withdrawl.
- */
-class WalletBackendAcceptBankIntegratedWithdrawalRequest: WalletBackendRequest 
{
-    struct RequestArgs: Encodable {
+/// A request to accept a bank-integrated withdrawl.
+struct WalletBackendAcceptBankIntegratedWithdrawalRequest: 
WalletBackendFormattedRequest {
+    var talerWithdrawUri: String
+    var exchangeBaseUrl: String
+    
+    struct Args: Encodable {
         var talerWithdrawUri: String
         var exchangeBaseUrl: String
     }
-    struct RequestResponse: Decodable {
-        var bankConfirmationUrl: String?
-    }
-    typealias Args = RequestArgs
-    typealias Response = RequestResponse
-    private let requestArgs: RequestArgs
-    private let success: () -> Void
-    private let failure: () -> Void
     
-    init(talerWithdrawURI: String, exchangeBaseURL: String, onSuccess: 
@escaping () -> Void, onFailure: @escaping () -> Void) {
-        self.requestArgs = RequestArgs(talerWithdrawUri: talerWithdrawURI, 
exchangeBaseUrl: exchangeBaseURL)
-        self.success = onSuccess
-        self.failure = onFailure
+    struct Response: Decodable {
+        var bankConfirmationUrl: String?
     }
     
     func operation() -> String {
         return "acceptWithdrawal"
     }
     
-    func args() -> RequestArgs {
-        return requestArgs
-    }
-    
-    func success(result: RequestResponse) {
-        self.success()
-    }
-    
-    func error(_ err: WalletBackendResponseError) {
-        self.failure()
+    func args() -> Args {
+        return Args(talerWithdrawUri: talerWithdrawUri, exchangeBaseUrl: 
exchangeBaseUrl)
     }
 }
 
-/**
-    A request to accept a manual withdrawl.
- */
-class WalletBackendAcceptManualWithdrawalRequest: WalletBackendRequest {
-    struct RequestArgs: Encodable {
+/// A request to accept a manual withdrawl.
+struct WalletBackendAcceptManualWithdrawalRequest: 
WalletBackendFormattedRequest {
+    var exchangeBaseUrl: String
+    var amount: Amount
+    
+    struct Args: Encodable {
         var exchangeBaseUrl: String
         var amount: Amount
     }
-    struct RequestResponse: Decodable {
-        var exchangePaytoUris: [String]
-    }
-    typealias Args = RequestArgs
-    typealias Response = RequestResponse
-    private let requestArgs: RequestArgs
-    private let success: () -> Void
-    private let failure: () -> Void
     
-    init(exchangeBaseURL: String, amount: Amount, onSuccess: @escaping () -> 
Void, onFailure: @escaping () -> Void) {
-        self.requestArgs = RequestArgs(exchangeBaseUrl: exchangeBaseURL, 
amount: amount)
-        self.success = onSuccess
-        self.failure = onFailure
+    struct Response: Decodable {
+        var exchangePaytoUris: [String]
     }
     
     func operation() -> String {
         return "acceptManualWithdrawal"
     }
     
-    func args() -> RequestArgs {
-        return requestArgs
-    }
-    
-    func success(result: RequestResponse) {
-        self.success()
-    }
-    
-    func error(_ err: WalletBackendResponseError) {
-        self.failure()
+    func args() -> Args {
+        return Args(exchangeBaseUrl: exchangeBaseUrl, amount: amount)
     }
 }
 
-/**
-    A request to deposit funds.
- */
-class WalletBackendCreateDepositGroupRequest: WalletBackendRequest {
-    struct RequestArgs: Encodable {
+/// A request to deposit funds.
+struct WalletBackendCreateDepositGroupRequest: WalletBackendFormattedRequest {
+    var depositePayToUri: String
+    var amount: Amount
+    
+    struct Args: Encodable {
         var depositPayToUri: String
         var amount: Amount
     }
-    struct RequestResponse: Decodable {
-        var depositGroupId: String
-    }
-    typealias Args = RequestArgs
-    typealias Response = RequestResponse
-    private let requestArgs: RequestArgs
-    private let success: () -> Void
-    private let failure: () -> Void
     
-    init(depositPayToUri: String, amount: Amount, onSuccess: @escaping () -> 
Void, onFailure: @escaping () -> Void) {
-        self.requestArgs = RequestArgs(depositPayToUri: depositPayToUri, 
amount: amount)
-        self.success = onSuccess
-        self.failure = onFailure
+    struct Response: Decodable {
+        var depositGroupId: String
     }
     
     func operation() -> String {
         return "createDepositGroup"
     }
     
-    func args() -> RequestArgs {
-        return requestArgs
-    }
-    
-    func success(result: RequestResponse) {
-        self.success()
-    }
-    
-    func error(_ err: WalletBackendResponseError) {
-        self.failure()
+    func args() -> Args {
+        return Args(depositPayToUri: depositePayToUri, amount: amount)
     }
 }
 
-/**
-    A request to get information about a payment request.
- */
-class WalletBackendPreparePayRequest: WalletBackendRequest {
-    struct RequestArgs: Encodable {
+/// A request to get information about a payment request.
+struct WalletBackendPreparePayRequest: WalletBackendFormattedRequest {
+    var talerPayUri: String
+    
+    struct Args: Encodable {
         var talerPayUri: String
     }
-    struct RequestResponse: Decodable {
-        
-    }
-    typealias Args = RequestArgs
-    typealias Response = RequestResponse
-    private let requestArgs: RequestArgs
-    private let success: () -> Void
-    private let failure: () -> Void
     
-    init(talerPayUri: String, onSuccess: @escaping () -> Void, onFailure: 
@escaping () -> Void) {
-        self.requestArgs = RequestArgs(talerPayUri: talerPayUri)
-        self.success = onSuccess
-        self.failure = onFailure
+    struct Response: Decodable {
+        
     }
     
     func operation() -> String {
         return "preparePay"
     }
     
-    func args() -> RequestArgs {
-        return requestArgs
-    }
-    
-    func success(result: RequestResponse) {
-        self.success()
-    }
-    
-    func error(_ err: WalletBackendResponseError) {
-        self.failure()
+    func args() -> Args {
+        return Args(talerPayUri: talerPayUri)
     }
 }
 
-/**
-    A request to confirm a payment.
- */
-class WalletBackendConfirmPayRequest: WalletBackendRequest {
-    struct RequestArgs: Encodable {
+/// A request to confirm a payment.
+struct WalletBackendConfirmPayRequest: WalletBackendFormattedRequest {
+    var proposalId: String
+    
+    struct Args: Encodable {
         var proposalId: String
     }
-    struct RequestResponse: Decodable {
-        
-    }
-    typealias Args = RequestArgs
-    typealias Response = RequestResponse
-    private let requestArgs: RequestArgs
-    private let success: () -> Void
-    private let failure: () -> Void
     
-    init(proposalId: String, onSuccess: @escaping () -> Void, onFailure: 
@escaping () -> Void) {
-        self.requestArgs = RequestArgs(proposalId: proposalId)
-        self.success = onSuccess
-        self.failure = onFailure
+    struct Response: Decodable {
+        
     }
     
     func operation() -> String {
         return "abortFailedPayWithRefund"
     }
     
-    func args() -> RequestArgs {
-        return requestArgs
-    }
-    
-    func success(result: RequestResponse) {
-        self.success()
-    }
-    
-    func error(_ err: WalletBackendResponseError) {
-        self.failure()
+    func args() -> Args {
+        return Args(proposalId: proposalId)
     }
 }
 
-/**
-    A request to prepare a tip.
- */
-class WalletBackendPrepareTipRequest: WalletBackendRequest {
-    struct RequestArgs: Encodable {
+/// A request to prepare a tip.
+struct WalletBackendPrepareTipRequest: WalletBackendFormattedRequest {
+    var talerTipUri: String
+    
+    struct Args: Encodable {
         var talerTipUri: String
     }
-    struct RequestResponse: Decodable {
+    
+    struct Response: Decodable {
         var walletTipId: String
         var accepted: Bool
         var tipAmountRaw: Amount
@@ -911,131 +584,66 @@ class WalletBackendPrepareTipRequest: 
WalletBackendRequest {
         var exchangeBaseUrl: String
         var expirationTimestamp: Timestamp
     }
-    typealias Args = RequestArgs
-    typealias Response = RequestResponse
-    private let requestArgs: RequestArgs
-    private let success: () -> Void
-    private let failure: () -> Void
-    
-    init(talerTipURI: String, onSuccess: @escaping () -> Void, onFailure: 
@escaping () -> Void) {
-        self.requestArgs = RequestArgs(talerTipUri: talerTipURI)
-        self.success = onSuccess
-        self.failure = onFailure
-    }
     
     func operation() -> String {
         return "prepareTip"
     }
     
-    func args() -> RequestArgs {
-        return requestArgs
-    }
-    
-    func success(result: RequestResponse) {
-        self.success()
-    }
-    
-    func error(_ err: WalletBackendResponseError) {
-        self.failure()
+    func args() -> Args {
+        return Args(talerTipUri: talerTipUri)
     }
 }
 
-/**
-    A request to accept a tip.
- */
-class WalletBackendAcceptTipRequest: WalletBackendRequest {
-    struct RequestArgs: Encodable {
+/// A request to accept a tip.
+struct WalletBackendAcceptTipRequest: WalletBackendFormattedRequest {
+    var walletTipId: String
+    
+    struct Args: Encodable {
         var walletTipId: String
     }
-    struct RequestResponse: Decodable {
-        
-    }
-    typealias Args = RequestArgs
-    typealias Response = RequestResponse
-    private let requestArgs: RequestArgs
-    private let success: () -> Void
-    private let failure: () -> Void
     
-    init(walletTipId: String, onSuccess: @escaping () -> Void, onFailure: 
@escaping () -> Void) {
-        self.requestArgs = RequestArgs(walletTipId: walletTipId)
-        self.success = onSuccess
-        self.failure = onFailure
+    struct Response: Decodable {
+        
     }
     
     func operation() -> String {
         return "acceptTip"
     }
     
-    func args() -> RequestArgs {
-        return requestArgs
-    }
-    
-    func success(result: RequestResponse) {
-        self.success()
-    }
-    
-    func error(_ err: WalletBackendResponseError) {
-        self.failure()
+    func args() -> Args {
+        return Args(walletTipId: walletTipId)
     }
 }
 
-/**
-    A request to abort a failed payment.
- */
-class WalletBackendAbortFailedPaymentRequest: WalletBackendRequest {
-    struct RequestArgs: Encodable {
+/// A request to abort a failed payment.
+struct WalletBackendAbortFailedPaymentRequest: WalletBackendFormattedRequest {
+    var proposalId: String
+    
+    struct Args: Encodable {
         var proposalId: String
     }
-    struct RequestResponse: Decodable {
-        
-    }
-    typealias Args = RequestArgs
-    typealias Response = RequestResponse
-    private let requestArgs: RequestArgs
-    private let success: () -> Void
-    private let failure: () -> Void
     
-    init(proposalId: String, onSuccess: @escaping () -> Void, onFailure: 
@escaping () -> Void) {
-        self.requestArgs = RequestArgs(proposalId: proposalId)
-        self.success = onSuccess
-        self.failure = onFailure
+    struct Response: Decodable {
+        
     }
     
     func operation() -> String {
         return "confirmPay"
     }
     
-    func args() -> RequestArgs {
-        return requestArgs
-    }
-    
-    func success(result: RequestResponse) {
-        self.success()
-    }
-    
-    func error(_ err: WalletBackendResponseError) {
-        self.failure()
+    func args() -> Args {
+        return Args(proposalId: proposalId)
     }
 }
 
-/**
-    A request to withdraw a balance from the TESTKUDOS environment.
- */
-class WalletBackendWithdrawTestkudosRequest: WalletBackendRequest {
-    struct RequestArgs: Encodable {
+/// A request to withdraw a balance from the TESTKUDOS environment.
+struct WalletBackendWithdrawTestkudosRequest: WalletBackendFormattedRequest {
+    struct Args: Encodable {
         
     }
-    struct RequestResponse: Decodable {
-        
-    }
-    typealias Args = RequestArgs
-    typealias Response = RequestResponse
-    private let success: () -> Void
-    private let failure: () -> Void
     
-    init(onSuccess: @escaping () -> Void, onFailure: @escaping () -> Void) {
-        self.success = onSuccess
-        self.failure = onFailure
+    struct Response: Decodable {
+        
     }
     
     func operation() -> String {
@@ -1043,49 +651,29 @@ class WalletBackendWithdrawTestkudosRequest: 
WalletBackendRequest {
     }
     
     func args() -> Args {
-        return RequestArgs()
-    }
-    
-    func success(result: Response) {
-        self.success()
-    }
-    
-    func error(_ err: WalletBackendResponseError) {
-        self.failure()
+        return Args()
     }
 }
 
-/**
-    A request to add a test balance to the wallet.
- */
-class WalletBackendWithdrawTestBalance: WalletBackendRequest {
-    struct RequestArgs: Encodable {
+/// A request to add a test balance to the wallet.
+struct WalletBackendWithdrawTestBalance: WalletBackendFormattedRequest {
+    var amount: Amount
+    var bankBaseUrl: String
+    var exchangeBaseUrl: String
+    
+    struct Args: Encodable {
         var amount: Amount
         var bankBaseUrl: String
         var exchangeBaseUrl: String
     }
-    typealias Args = RequestArgs
     typealias Response = String
-    private var requestArgs: RequestArgs
-    
-    init(amount: Amount, bankBaseUrl: String, exchangeBaseUrl: String) {
-        requestArgs = RequestArgs(amount: amount, bankBaseUrl: bankBaseUrl, 
exchangeBaseUrl: exchangeBaseUrl)
-    }
     
     func operation() -> String {
         return "withdrawTestBalance"
     }
     
     func args() -> Args {
-        return requestArgs
-    }
-    
-    func success(result: Response) {
-        
-    }
-    
-    func error(_ err: WalletBackendResponseError) {
-        
+        return Args(amount: amount, bankBaseUrl: bankBaseUrl, exchangeBaseUrl: 
exchangeBaseUrl)
     }
 }
 
@@ -1098,23 +686,14 @@ struct IntegrationTestArgs: Codable {
     var amountToSpend: String
 }
 
-/**
-    A request to run a basic integration test.
- */
-class WalletBackendRunIntegrationTestRequest: WalletBackendRequest {
-    struct RequestResponse: Decodable {
-        
-    }
+/// A request to run a basic integration test.
+struct WalletBackendRunIntegrationTestRequest: WalletBackendFormattedRequest {
+    var integrationTestArgs: IntegrationTestArgs
+    
     typealias Args = IntegrationTestArgs
-    typealias Response = RequestResponse
-    private let requestArgs: IntegrationTestArgs
-    private let success: () -> Void
-    private let failure: () -> Void
     
-    init(args: IntegrationTestArgs, onSuccess: @escaping () -> Void, 
onFailure: @escaping () -> Void) {
-        self.requestArgs = args
-        self.success = onSuccess
-        self.failure = onFailure
+    struct Response: Decodable {
+        
     }
     
     func operation() -> String {
@@ -1122,15 +701,7 @@ class WalletBackendRunIntegrationTestRequest: 
WalletBackendRequest {
     }
     
     func args() -> Args {
-        return requestArgs
-    }
-    
-    func success(result: Response) {
-        self.success()
-    }
-    
-    func error(_ err: WalletBackendResponseError) {
-        self.failure()
+        return integrationTestArgs
     }
 }
 
@@ -1141,23 +712,14 @@ struct TestPayArgs: Codable {
     var summary: String
 }
 
-/**
-    A request to make a test payment.
- */
-class WalletBackendTestPayRequest: WalletBackendRequest {
-    struct RequestResponse: Decodable {
-        
-    }
+/// A request to make a test payment.
+struct WalletBackendTestPayRequest: WalletBackendFormattedRequest {
+    var testPayArgs: TestPayArgs
+    
     typealias Args = TestPayArgs
-    typealias Response = RequestResponse
-    private let requestArgs: TestPayArgs
-    private let success: () -> Void
-    private let failure: () -> Void
     
-    init(args: TestPayArgs, onSuccess: @escaping () -> Void, onFailure: 
@escaping () -> Void) {
-        self.requestArgs = args
-        self.success = onSuccess
-        self.failure = onFailure
+    struct Response: Decodable {
+        
     }
     
     func operation() -> String {
@@ -1165,15 +727,7 @@ class WalletBackendTestPayRequest: WalletBackendRequest {
     }
     
     func args() -> Args {
-        return requestArgs
-    }
-    
-    func success(result: Response) {
-        self.success()
-    }
-    
-    func error(_ err: WalletBackendResponseError) {
-        self.failure()
+        return testPayArgs
     }
 }
 
@@ -1189,24 +743,14 @@ struct Coin: Codable {
     var coin_suspended: Bool
 }
 
-/**
-    A request to dump all coins to JSON.
- */
-class WalletBackendDumpCoinsRequest: WalletBackendRequest {
-    struct RequestArgs: Encodable {
+/// A request to dump all coins to JSON.
+struct WalletBackendDumpCoinsRequest: WalletBackendFormattedRequest {
+    struct Args: Encodable {
         
     }
-    struct RequestResponse: Decodable {
-        var coins: [Coin]
-    }
-    typealias Args = RequestArgs
-    typealias Response = RequestResponse
-    private let success: () -> Void
-    private let failure: () -> Void
     
-    init(onSuccess: @escaping () -> Void, onFailure: @escaping () -> Void) {
-        self.success = onSuccess
-        self.failure = onFailure
+    struct Response: Decodable {
+        var coins: [Coin]
     }
     
     func operation() -> String {
@@ -1214,39 +758,22 @@ class WalletBackendDumpCoinsRequest: 
WalletBackendRequest {
     }
     
     func args() -> Args {
-        return RequestArgs()
-    }
-    
-    func success(result: Response) {
-        self.success()
-    }
-    
-    func error(_ err: WalletBackendResponseError) {
-        self.failure()
+        return Args()
     }
 }
 
-/**
-    A request to suspend or unsuspend a coin.
- */
-class WalletBackendSuspendCoinRequest: WalletBackendRequest {
-    struct RequestArgs: Encodable {
+/// A request to suspend or unsuspend a coin.
+struct WalletBackendSuspendCoinRequest: WalletBackendFormattedRequest {
+    var coinPub: String
+    var suspended: Bool
+    
+    struct Args: Encodable {
         var coinPub: String
         var suspended: Bool
     }
-    struct RequestResponse: Decodable {
-        
-    }
-    typealias Args = RequestArgs
-    typealias Response = RequestResponse
-    private let requestArgs: RequestArgs
-    private let success: () -> Void
-    private let failure: () -> Void
     
-    init(coinPub: String, suspended: Bool, onSuccess: @escaping () -> Void, 
onFailure: @escaping () -> Void) {
-        self.requestArgs = RequestArgs(coinPub: coinPub, suspended: suspended)
-        self.success = onSuccess
-        self.failure = onFailure
+    struct Response: Decodable {
+        
     }
     
     func operation() -> String {
@@ -1254,15 +781,7 @@ class WalletBackendSuspendCoinRequest: 
WalletBackendRequest {
     }
     
     func args() -> Args {
-        return requestArgs
-    }
-    
-    func success(result: Response) {
-        self.success()
-    }
-    
-    func error(_ err: WalletBackendResponseError) {
-        self.failure()
+        return Args(coinPub: coinPub, suspended: suspended)
     }
 }
 
@@ -1276,6 +795,7 @@ enum WalletBackendError: Error {
 
 /// Delegate for the wallet backend.
 protocol WalletBackendDelegate {
+    /// Called when the backend interface receives a message it does not know 
how to handle.
     func walletBackendReceivedUnknownMessage(_ walletBackend: WalletBackend, 
message: String)
 }
 
@@ -1285,13 +805,29 @@ class WalletBackend: IonoMessageHandler {
     private var requestsMade: UInt
     private var backendReady: Bool
     private var backendReadyCondition: NSCondition
-    private struct RequestDetail {
-        let decodeSuccess: (Data) -> Void
-        let handleError: (Data) -> Void
-    }
-    private var requests: [UInt : RequestDetail] = [:]
+    private var requests: [UInt : (AnyCodable?, WalletBackendResponseError?) 
-> Void] = [:]
     var delegate: WalletBackendDelegate?
     
+    private struct FullRequest: Encodable {
+        let operation: String
+        let id: UInt
+        let args: AnyEncodable
+    }
+    
+    private struct FullResponse: Decodable {
+        let type: String
+        let operation: String
+        let id: UInt
+        let result: AnyCodable
+    }
+    
+    private struct FullError: Decodable {
+        let type: String
+        let operation: String
+        let id: UInt
+        let error: WalletBackendResponseError
+    }
+    
     init() throws {
         iono = Iono()
         requestsMade = 0
@@ -1317,10 +853,10 @@ class WalletBackend: IonoMessageHandler {
             var storageDir = documentUrls[0]
             storageDir.appendPathComponent("talerwalletdb-v30", isDirectory: 
false)
             storageDir.appendPathExtension("json")
-            try sendRequest(request: 
WalletBackendInitRequest(persistentStoragePath: storageDir.path, onSuccess: {
+            sendFormattedRequest(request: 
WalletBackendInitRequest(persistentStoragePath: storageDir.path), 
completionHandler: { (resp: WalletBackendInitRequest.Response?, err: 
WalletBackendResponseError?) in
                 self.backendReady = true
                 self.backendReadyCondition.broadcast()
-            }))
+            })
         }
         
         waitUntilReady()
@@ -1341,33 +877,31 @@ class WalletBackend: IonoMessageHandler {
             if let responseData = data {
                 let type = (responseData["type"] as? String) ?? ""
                 if type == "response" {
-                    guard let id = responseData["id"] as? UInt else {
-                        
self.delegate?.walletBackendReceivedUnknownMessage(self, message: message)
-                        return
+                    guard let id = responseData["id"] as? UInt else { throw 
WalletBackendError.deserializationError }
+                    guard let request = requests[id] else { throw 
WalletBackendError.deserializationError }
+                    do {
+                        let decoded = try 
JSONDecoder().decode(FullResponse.self, from: messageData)
+                        request(decoded.result, nil)
+                    } catch {
+                        request(nil, WalletBackend.parseResponseError())
                     }
-                    guard let request = requests[id] else {
-                        
self.delegate?.walletBackendReceivedUnknownMessage(self, message: message)
-                        return
-                    }
-                    request.decodeSuccess(messageData)
                     requests[id] = nil
                 } else if type == "tunnelHttp" {
-                    
+                    // TODO: Handle
                 } else if type == "notification" {
-                    
+                    // TODO: Handle
                 } else if type == "error" {
-                    guard let id = responseData["id"] as? UInt else {
-                        
self.delegate?.walletBackendReceivedUnknownMessage(self, message: message)
-                        return
-                    }
-                    guard let request = requests[id] else {
-                        
self.delegate?.walletBackendReceivedUnknownMessage(self, message: message)
-                        return
+                    guard let id = responseData["id"] as? UInt else { throw 
WalletBackendError.deserializationError }
+                    guard let request = requests[id] else { throw 
WalletBackendError.deserializationError }
+                    do {
+                        let decoded = try JSONDecoder().decode(FullError.self, 
from: messageData)
+                        request(nil, decoded.error)
+                    } catch {
+                        request(nil, WalletBackend.parseFailureError())
                     }
-                    request.handleError(messageData)
                     requests[id] = nil
                 } else {
-                    self.delegate?.walletBackendReceivedUnknownMessage(self, 
message: message)
+                    throw WalletBackendError.deserializationError
                 }
             }
         } catch {
@@ -1375,53 +909,47 @@ class WalletBackend: IonoMessageHandler {
         }
     }
     
-    private struct FullResponse<T: WalletBackendRequest>: Decodable {
-        let type: String
-        let operation: String
-        let id: UInt
-        let result: T.Response
-    }
-    
-    private struct FullError: Decodable {
-        let type: String
-        let operation: String
-        let id: UInt
-        let error: WalletBackendResponseError
-    }
-    
-    func sendRequest<T: WalletBackendRequest>(request: T) throws {
-        let data = WalletBackendRequestData<T>(request: request, id: 
requestsMade)
-        requestsMade += 1
-        
-        let decodeSuccess = { (data: Data) -> Void in
-            do {
-                let decoded = try JSONDecoder().decode(FullResponse<T>.self, 
from: data)
-                request.success(result: decoded.result)
-            } catch {
-                let err = WalletBackendResponseError(talerErrorCode: -1, 
talerErrorHint: "Could not parse response.", message: "")
-                request.error(err)
-            }
-        }
-        
-        let handleError = { (data: Data) -> Void in
-            do {
-                let decoded = try JSONDecoder().decode(FullError.self, from: 
data)
-                request.error(decoded.error)
-            } catch {
-                let err = WalletBackendResponseError(talerErrorCode: -2, 
talerErrorHint: "Could not parse error detail.", message: "")
-                request.error(err)
-            }
-        }
-        
+    func sendRequest(request: WalletBackendRequest, completionHandler: 
@escaping (AnyCodable?, WalletBackendResponseError?) -> Void) {
         /* Encode the request and send it to the backend. */
         do {
-            let encoded = try JSONEncoder().encode(data)
+            let full = FullRequest(operation: request.operation, id: 
requestsMade, args: request.args)
+            let encoded = try JSONEncoder().encode(full)
             guard let jsonString = String(data: encoded, encoding: .utf8) else 
{ throw WalletBackendError.serializationError }
-            let detail = RequestDetail(decodeSuccess: decodeSuccess, 
handleError: handleError)
-            requests[data.id] = detail
+            requests[full.id] = completionHandler
+            requestsMade += 1
             iono.sendMessage(message: jsonString)
         } catch {
-            throw WalletBackendError.serializationError
+            completionHandler(nil, WalletBackend.serializeRequestError());
+        }
+    }
+    
+    func sendFormattedRequest<T: WalletBackendFormattedRequest>(request: T, 
completionHandler: @escaping (T.Response?, WalletBackendResponseError?) -> 
Void) {
+        let reqData = WalletBackendRequest(operation: request.operation(), 
args: AnyEncodable(request.args()))
+        sendRequest(request: reqData) { (result: AnyCodable?, err: 
WalletBackendResponseError?) in
+            if let res = result {
+                do {
+                    /* TODO: Don't use a hack (there is no reason to pass to 
JSON): */
+                    let jsonStr = try JSONEncoder().encode(res)
+                    let decoded = try JSONDecoder().decode(T.Response.self, 
from: jsonStr)
+                    completionHandler(decoded, err)
+                } catch {
+                    completionHandler(nil, WalletBackend.parseResponseError())
+                }
+            } else {
+                completionHandler(nil, err)
+            }
         }
     }
+    
+    static func serializeRequestError() -> WalletBackendResponseError {
+        return WalletBackendResponseError(talerErrorCode: -1, talerErrorHint: 
"Could not serialize request.", message: "")
+    }
+    
+    static func parseResponseError() -> WalletBackendResponseError {
+        return WalletBackendResponseError(talerErrorCode: -2, talerErrorHint: 
"Could not parse response.", message: "")
+    }
+    
+    static func parseFailureError() -> WalletBackendResponseError {
+        return WalletBackendResponseError(talerErrorCode: -3, talerErrorHint: 
"Could not parse error detail.", message: "")
+    }
 }
diff --git a/TalerTests/WalletBackendTests.swift 
b/TalerTests/WalletBackendTests.swift
new file mode 100644
index 0000000..4bfdc62
--- /dev/null
+++ b/TalerTests/WalletBackendTests.swift
@@ -0,0 +1,25 @@
+/*
+ * This file is part of GNU Taler
+ * (C) 2022 Taler Systems S.A.
+ *
+ * GNU Taler is free software; you can redistribute it and/or modify it under 
the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 3, or (at your option) any later version.
+ *
+ * GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
FOR
+ * A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+import XCTest
+@testable import Taler
+
+class WalletBackendTests: XCTestCase {
+    // TODO: Test multiple backends. This ends up hanging, and this should not 
happen!
+    
+    func testX() {
+        let _ = try! WalletBackend()
+    }
+}

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]