gnunet-svn
[Top][All Lists]
Advanced

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

[taler-taler-ios] branch master updated: partial implementation of amoun


From: gnunet
Subject: [taler-taler-ios] branch master updated: partial implementation of amounts
Date: Wed, 04 Aug 2021 06:11:51 +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 62b6634  partial implementation of amounts
62b6634 is described below

commit 62b663428746c82a7eb46ff673364b8a03eea825
Author: Jonathan Buchanan <jonathan.russ.buchanan@gmail.com>
AuthorDate: Wed Aug 4 00:11:35 2021 -0400

    partial implementation of amounts
---
 Taler.xcodeproj/project.pbxproj |  10 +-
 Taler/Amount.swift              | 194 ++++++++++++++++++++++++++++++++++++++
 Taler/WalletBackend.swift       | 203 ++++++++++++++++++++++++++++++++++++++--
 TalerTests/AmountTests.swift    |  62 ++++++++++++
 4 files changed, 461 insertions(+), 8 deletions(-)

diff --git a/Taler.xcodeproj/project.pbxproj b/Taler.xcodeproj/project.pbxproj
index a8a4b3d..12f8c85 100644
--- a/Taler.xcodeproj/project.pbxproj
+++ b/Taler.xcodeproj/project.pbxproj
@@ -8,6 +8,7 @@
 
 /* Begin PBXBuildFile section */
                D112510026B12E3200D02E00 /* taler-wallet-embedded.js in 
CopyFiles */ = {isa = PBXBuildFile; fileRef = D11250FF26B12E3200D02E00 /* 
taler-wallet-embedded.js */; };
+               D1472E5526B9206800896566 /* AmountTests.swift in Sources */ = 
{isa = PBXBuildFile; fileRef = D1472E5426B9206800896566 /* AmountTests.swift 
*/; };
                D14AFD2124D232B300C51073 /* AppDelegate.swift in Sources */ = 
{isa = PBXBuildFile; fileRef = D14AFD2024D232B300C51073 /* AppDelegate.swift 
*/; };
                D14AFD2324D232B300C51073 /* SceneDelegate.swift in Sources */ = 
{isa = PBXBuildFile; fileRef = D14AFD2224D232B300C51073 /* SceneDelegate.swift 
*/; };
                D14AFD2524D232B300C51073 /* ContentView.swift in Sources */ = 
{isa = PBXBuildFile; fileRef = D14AFD2424D232B300C51073 /* ContentView.swift 
*/; };
@@ -34,6 +35,7 @@
                D17D8B8425ADB29B001BD43D /* libhistogram.a in Frameworks */ = 
{isa = PBXBuildFile; fileRef = D17D8B5625ADB130001BD43D /* libhistogram.a */; };
                D17D8B8525ADB29B001BD43D /* libcares.a in Frameworks */ = {isa 
= PBXBuildFile; fileRef = D17D8B4825ADB12B001BD43D /* libcares.a */; };
                D1AFF0F3268D59C200FBB744 /* libiono.a in Frameworks */ = {isa = 
PBXBuildFile; fileRef = D1AFF0F2268D59A500FBB744 /* libiono.a */; };
+               D1BA3F9226B8889600A5848B /* Amount.swift in Sources */ = {isa = 
PBXBuildFile; fileRef = D1BA3F9126B8889600A5848B /* Amount.swift */; };
                D1D65B9826992E4600C1012A /* WalletBackend.swift in Sources */ = 
{isa = PBXBuildFile; fileRef = D1D65B9726992E4600C1012A /* WalletBackend.swift 
*/; };
 /* End PBXBuildFile section */
 
@@ -111,6 +113,7 @@
                D145D1EF25AC416B00CDD61B /* libv8_base_without_compiler.a */ = 
{isa = PBXFileReference; lastKnownFileType = archive.ar; name = 
libv8_base_without_compiler.a; path = 
"ios-node-v8/taler-ios-build/compiled/node-x64/libv8_base_without_compiler.a"; 
sourceTree = "<group>"; };
                D145D1F025AC416B00CDD61B /* libhistogram.a */ = {isa = 
PBXFileReference; lastKnownFileType = archive.ar; name = libhistogram.a; path = 
"ios-node-v8/taler-ios-build/compiled/node-x64/libhistogram.a"; sourceTree = 
"<group>"; };
                D145D1F125AC416B00CDD61B /* libv8_libbase.a */ = {isa = 
PBXFileReference; lastKnownFileType = archive.ar; name = libv8_libbase.a; path 
= "ios-node-v8/taler-ios-build/compiled/node-x64/libv8_libbase.a"; sourceTree = 
"<group>"; };
+               D1472E5426B9206800896566 /* AmountTests.swift */ = {isa = 
PBXFileReference; lastKnownFileType = sourcecode.swift; path = 
AmountTests.swift; sourceTree = "<group>"; };
                D14AFD1D24D232B300C51073 /* Taler.app */ = {isa = 
PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; 
path = Taler.app; sourceTree = BUILT_PRODUCTS_DIR; };
                D14AFD2024D232B300C51073 /* AppDelegate.swift */ = {isa = 
PBXFileReference; lastKnownFileType = sourcecode.swift; path = 
AppDelegate.swift; sourceTree = "<group>"; };
                D14AFD2224D232B300C51073 /* SceneDelegate.swift */ = {isa = 
PBXFileReference; lastKnownFileType = sourcecode.swift; path = 
SceneDelegate.swift; sourceTree = "<group>"; };
@@ -148,6 +151,7 @@
                D17D8B5725ADB130001BD43D /* libtorque_base.a */ = {isa = 
PBXFileReference; lastKnownFileType = archive.ar; name = libtorque_base.a; path 
= "ios-node-v8/taler-ios-build/compiled/node-arm64/libtorque_base.a"; 
sourceTree = "<group>"; };
                D1AB963B259EB13D00DEAB23 /* libnode.89.dylib */ = {isa = 
PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = 
libnode.89.dylib; path = 
"ios-node-v8/taler-ios-build/compiled/x64-v8a/libnode.89.dylib"; sourceTree = 
"<group>"; };
                D1AFF0F2268D59A500FBB744 /* libiono.a */ = {isa = 
PBXFileReference; lastKnownFileType = archive.ar; name = libiono.a; path = 
iono/compiled/x64/libiono.a; sourceTree = "<group>"; };
+               D1BA3F9126B8889600A5848B /* Amount.swift */ = {isa = 
PBXFileReference; lastKnownFileType = sourcecode.swift; path = Amount.swift; 
sourceTree = "<group>"; };
                D1D65B9726992E4600C1012A /* WalletBackend.swift */ = {isa = 
PBXFileReference; lastKnownFileType = sourcecode.swift; path = 
WalletBackend.swift; sourceTree = "<group>"; };
                D1F0C22F25A958AE00C3179D /* libllhttp.a */ = {isa = 
PBXFileReference; lastKnownFileType = archive.ar; name = libllhttp.a; path = 
"ios-node-v8/tools/ios-framework/bin/x64/libllhttp.a"; sourceTree = "<group>"; 
};
                D1F0C23025A958AE00C3179D /* libv8_initializers.a */ = {isa = 
PBXFileReference; lastKnownFileType = archive.ar; name = libv8_initializers.a; 
path = "ios-node-v8/tools/ios-framework/bin/x64/libv8_initializers.a"; 
sourceTree = "<group>"; };
@@ -266,6 +270,7 @@
                                D14AFD2024D232B300C51073 /* AppDelegate.swift 
*/,
                                D14AFD2224D232B300C51073 /* SceneDelegate.swift 
*/,
                                D1D65B9726992E4600C1012A /* WalletBackend.swift 
*/,
+                               D1BA3F9126B8889600A5848B /* Amount.swift */,
                                D14AFD2424D232B300C51073 /* ContentView.swift 
*/,
                                D14AFD2624D232B500C51073 /* Assets.xcassets */,
                                D14AFD2B24D232B500C51073 /* 
LaunchScreen.storyboard */,
@@ -279,6 +284,7 @@
                        children = (
                                D14AFD3724D232B500C51073 /* TalerTests.swift */,
                                D14AFD3924D232B500C51073 /* Info.plist */,
+                               D1472E5426B9206800896566 /* AmountTests.swift 
*/,
                        );
                        path = TalerTests;
                        sourceTree = "<group>";
@@ -570,7 +576,7 @@
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                        shellPath = /bin/sh;
-                       shellScript = 
"WALLET_CORE_VERSION=\"v0.8.1\"\nWALLET_CORE_HASH=\"23bf89b663f0fd0e84a3d7e54a19766766c7306e5704e43a25df57da72056fa7\"\nWALLET_SRC=\"https://git.taler.net/wallet-core.git/plain/${WALLET_CORE_VERSION}/taler-wallet-embedded.js?h=prebuilt\"\nWALLET_DST=\"${SRCROOT}/taler-wallet-embedded.js\"\n\n[
 ! -e $WALLET_DST ] || rm $WALLET_DST\ncurl $WALLET_SRC --output 
$WALLET_DST\n\nRECEIVED_HASH=$(openssl sha256 -r 
$WALLET_DST)\nRECEIVED_HASH_SPLIT=($RECEIVED_HASH)\nif [ $WALLET_CO [...]
+                       shellScript = "exit 
0\nWALLET_CORE_VERSION=\"v0.8.1\"\nWALLET_CORE_HASH=\"23bf89b663f0fd0e84a3d7e54a19766766c7306e5704e43a25df57da72056fa7\"\nWALLET_SRC=\"https://git.taler.net/wallet-core.git/plain/${WALLET_CORE_VERSION}/taler-wallet-embedded.js?h=prebuilt\"\nWALLET_DST=\"${SRCROOT}/taler-wallet-embedded.js\"\n\n[
 ! -e $WALLET_DST ] || rm $WALLET_DST\ncurl $WALLET_SRC --output 
$WALLET_DST\n\nRECEIVED_HASH=$(openssl sha256 -r 
$WALLET_DST)\nRECEIVED_HASH_SPLIT=($RECEIVED_HASH)\nif [ $W [...]
                };
 /* End PBXShellScriptBuildPhase section */
 
@@ -579,6 +585,7 @@
                        isa = PBXSourcesBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
+                               D1BA3F9226B8889600A5848B /* Amount.swift in 
Sources */,
                                D14AFD2124D232B300C51073 /* AppDelegate.swift 
in Sources */,
                                D14AFD2324D232B300C51073 /* SceneDelegate.swift 
in Sources */,
                                D14AFD2524D232B300C51073 /* ContentView.swift 
in Sources */,
@@ -591,6 +598,7 @@
                        buildActionMask = 2147483647;
                        files = (
                                D14AFD3824D232B500C51073 /* TalerTests.swift in 
Sources */,
+                               D1472E5526B9206800896566 /* AmountTests.swift 
in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
diff --git a/Taler/Amount.swift b/Taler/Amount.swift
new file mode 100644
index 0000000..83445b4
--- /dev/null
+++ b/Taler/Amount.swift
@@ -0,0 +1,194 @@
+/*
+ * This file is part of GNU Taler
+ * (C) 2021 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 Foundation
+
+enum AmountError: Error {
+    case invalidStringRepresentation
+    case incompatibleCurrency
+    case invalidAmount
+    case negativeAmount
+}
+
+class Amount: Codable, CustomStringConvertible {
+    private static let maxValue: UInt64 = 1 << 52
+    private static let fractionalBase: UInt32 = 100000000
+    private static let fractionalBaseDigits: UInt = 8
+    var currency: String
+    var value: UInt64
+    var fraction: UInt32
+    var description: String {
+        if fraction == 0 {
+            return "\(currency):\(value)"
+        } else {
+            var frac = fraction
+            var fracStr = ""
+            while (frac > 0) {
+                fracStr += "\(frac / (Amount.fractionalBase / 10))"
+                frac = (frac * 10) % Amount.fractionalBase
+            }
+            return "\(currency):\(value).\(fracStr)"
+        }
+    }
+    var valid: Bool {
+        return (value <= Amount.maxValue && currency != "")
+    }
+    
+    init(fromString string: String) throws {
+        guard let separatorIndex = string.firstIndex(of: ":") else { throw 
AmountError.invalidStringRepresentation }
+        self.currency = String(string[..<separatorIndex])
+        let amountStr = String(string[string.index(separatorIndex, offsetBy: 
1)...])
+        if let dotIndex = amountStr.firstIndex(of: ".") {
+            let valueStr = String(amountStr[..<dotIndex])
+            let fractionStr = String(amountStr[string.index(dotIndex, 
offsetBy: 1)...])
+            guard let _value = UInt64(valueStr) else { throw 
AmountError.invalidStringRepresentation }
+            self.value = _value
+            self.fraction = 0
+            var digitValue = Amount.fractionalBase / 10
+            for char in fractionStr {
+                guard let digit = char.wholeNumberValue else { throw 
AmountError.invalidStringRepresentation }
+                self.fraction += digitValue * UInt32(digit)
+                digitValue /= 10
+            }
+        } else {
+            guard let _value = UInt64(amountStr) else { throw 
AmountError.invalidStringRepresentation }
+            self.value = _value
+            self.fraction = 0
+        }
+        guard self.valid else { throw AmountError.invalidAmount }
+    }
+    
+    init(currency: String, value: UInt64, fraction: UInt32) {
+        self.currency = currency
+        self.value = value
+        self.fraction = fraction
+    }
+    
+    init(fromDecoder decoder: Decoder) throws {
+        let container = try decoder.singleValueContainer()
+        let string = try container.decode(String.self)
+        /* TODO: de-duplicate */
+        guard let separatorIndex = string.firstIndex(of: ":") else { throw 
AmountError.invalidStringRepresentation }
+        self.currency = String(string[..<separatorIndex])
+        let amountStr = String(string[string.index(separatorIndex, offsetBy: 
1)...])
+        if let dotIndex = amountStr.firstIndex(of: ".") {
+            let valueStr = String(amountStr[..<dotIndex])
+            let fractionStr = String(amountStr[string.index(dotIndex, 
offsetBy: 1)...])
+            guard let _value = UInt64(valueStr) else { throw 
AmountError.invalidStringRepresentation }
+            self.value = _value
+            self.fraction = 0
+            var digitValue = Amount.fractionalBase / 10
+            for char in fractionStr {
+                guard let digit = char.wholeNumberValue else { throw 
AmountError.invalidStringRepresentation }
+                self.fraction += digitValue * UInt32(digit)
+                digitValue /= 10
+            }
+        } else {
+            guard let _value = UInt64(amountStr) else { throw 
AmountError.invalidStringRepresentation }
+            self.value = _value
+            self.fraction = 0
+        }
+        guard self.valid else { throw AmountError.invalidAmount }
+    }
+    
+    func copy() -> Amount {
+        return Amount(currency: self.currency, value: self.value, fraction: 
self.fraction)
+    }
+    
+    func normalizedCopy() throws -> Amount {
+        let amount = self.copy()
+        try amount.normalize()
+        return amount
+    }
+    
+    func encode(to encoder: Encoder) throws {
+        var container = encoder.singleValueContainer()
+        try container.encode(self.description)
+    }
+    
+    func normalize() throws {
+        if !valid {
+            throw AmountError.invalidAmount
+        }
+        self.value += UInt64(self.fraction / Amount.fractionalBase)
+        self.fraction = self.fraction % Amount.fractionalBase
+        if !valid {
+            throw AmountError.invalidAmount
+        }
+    }
+    
+    static func + (left: Amount, right: Amount) throws -> Amount {
+        if left.currency != right.currency {
+            throw AmountError.incompatibleCurrency
+        }
+        let leftNormalized = try left.normalizedCopy()
+        let rightNormalized = try right.normalizedCopy()
+        let result: Amount = leftNormalized
+        result.value += rightNormalized.value
+        result.fraction += rightNormalized.fraction
+        try result.normalize()
+        return result
+    }
+    
+    static func - (left: Amount, right: Amount) throws -> Amount {
+        if left.currency != right.currency {
+            throw AmountError.incompatibleCurrency
+        }
+        let leftNormalized = try left.normalizedCopy()
+        let rightNormalized = try right.normalizedCopy()
+        if (leftNormalized.fraction < rightNormalized.fraction) {
+            guard leftNormalized.value != 0 else { throw 
AmountError.negativeAmount }
+            leftNormalized.value -= 1
+            leftNormalized.fraction += Amount.fractionalBase
+        }
+        guard leftNormalized.value >= rightNormalized.value else { throw 
AmountError.negativeAmount }
+        let diff = Amount.zero(currency: left.currency)
+        diff.value = leftNormalized.value - rightNormalized.value
+        diff.fraction = leftNormalized.fraction - rightNormalized.fraction
+        try diff.normalize()
+        return diff
+    }
+    
+    static func == (left: Amount, right: Amount) throws -> Bool {
+        if left.currency != right.currency {
+            throw AmountError.incompatibleCurrency
+        }
+        let leftNormalized = try left.normalizedCopy()
+        let rightNormalized = try right.normalizedCopy()
+        return (leftNormalized.value == rightNormalized.value && 
leftNormalized.fraction == rightNormalized.fraction)
+    }
+    
+    static func < (left: Amount, right: Amount) throws -> Bool {
+        if left.currency != right.currency {
+            throw AmountError.incompatibleCurrency
+        }
+        let leftNormalized = try left.normalizedCopy()
+        let rightNormalized = try right.normalizedCopy()
+        if (leftNormalized.value == rightNormalized.value) {
+            return (leftNormalized.fraction < rightNormalized.fraction)
+        } else {
+            return (leftNormalized.value < rightNormalized.value)
+        }
+    }
+    
+    static func > (left: Amount, right: Amount) throws -> Bool {
+        return try right < left
+    }
+    
+    static func zero(currency: String) -> Amount {
+        return Amount(currency: currency, value: 0, fraction: 0)
+    }
+}
diff --git a/Taler/WalletBackend.swift b/Taler/WalletBackend.swift
index 5a28371..d5cc3ab 100644
--- a/Taler/WalletBackend.swift
+++ b/Taler/WalletBackend.swift
@@ -17,19 +17,26 @@
 import Foundation
 import iono
 
+enum WalletBackendResponseError: Error {
+    case malformedResponse
+}
+
 protocol WalletBackendRequest {
     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: Int
+    var id: UInt
     var args: T.Args
     
-    init(request: T, id: Int) {
+    init(request: T, id: UInt) {
         operation = request.operation()
         self.id = id
         args = request.args()
@@ -41,10 +48,22 @@ fileprivate struct WalletBackendInitRequest: 
WalletBackendRequest {
         var persistentStoragePath: String
     }
     typealias Args = RequestArgs
+    struct Response: Codable {
+        struct SupportedProtocolVersions: Codable {
+            var exchange: String
+            var merchant: String
+        }
+        var supportedProtocolVersions: SupportedProtocolVersions
+        enum CodingKeys: String, CodingKey {
+            case supportedProtocolVersions = "supported_protocol_versions"
+        }
+    }
     private var requestArgs: RequestArgs
+    private let success: () -> Void
     
-    init(persistentStoragePath: String) {
+    init(persistentStoragePath: String, onSuccess: @escaping () -> Void) {
         requestArgs = RequestArgs(persistentStoragePath: persistentStoragePath)
+        self.success = onSuccess
     }
     
     func operation() -> String {
@@ -54,6 +73,14 @@ fileprivate struct WalletBackendInitRequest: 
WalletBackendRequest {
     func args() -> Args {
         return requestArgs
     }
+    
+    func success(result: Response) {
+        self.success()
+    }
+    
+    func error(_ err: WalletBackendResponseError) {
+        
+    }
 }
 
 fileprivate struct WalletBackendGetTransactionsRequest: WalletBackendRequest {
@@ -61,6 +88,7 @@ fileprivate struct WalletBackendGetTransactionsRequest: 
WalletBackendRequest {
         
     }
     typealias Args = RequestArgs
+    typealias Response = String
     private var requestArgs: RequestArgs
     
     init() {
@@ -74,19 +102,110 @@ fileprivate struct WalletBackendGetTransactionsRequest: 
WalletBackendRequest {
     func args() -> Args {
         return requestArgs
     }
+    
+    func success(result: Response) {
+        
+    }
+    
+    func error(_ err: WalletBackendResponseError) {
+        
+    }
+}
+
+struct WalletBackendGetBalancesRequest: WalletBackendRequest {
+    struct Balance: Decodable {
+        var available: Amount
+        var pendingIncoming: Amount
+        var pendingOutgoing: Amount
+        var requiresUserInput: Bool
+    }
+    struct BalancesResponse: Decodable {
+        var balances: [Balance]
+    }
+    struct RequestArgs: 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
+    }
+    
+    func operation() -> String {
+        return "getBalances"
+    }
+    
+    func args() -> Args {
+        return requestArgs
+    }
+    
+    func success(result: Response) {
+        print("balances???")
+    }
+    
+    func error(_ err: WalletBackendResponseError) {
+        
+    }
+}
+
+struct WalletBackendWithdrawTestBalance: WalletBackendRequest {
+    struct RequestArgs: Encodable {
+        var amount: String
+        var bankBaseUrl: String
+        var exchangeBaseUrl: String
+    }
+    typealias Args = RequestArgs
+    typealias Response = String
+    private var requestArgs: RequestArgs
+    
+    init(amount: String, 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) {
+        
+    }
 }
 
 enum WalletBackendError: Error {
     case serializationError
+    case deserializationError
 }
 
 class WalletBackend: IonoMessageHandler {
     private var iono: Iono
-    private var requestsMade: Int
+    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] = [:]
     
     init() {
         iono = Iono()
         requestsMade = 0
+        self.backendReady = false
+        self.backendReadyCondition = NSCondition()
         
         iono.messageHandler = self
         
@@ -107,21 +226,91 @@ class WalletBackend: IonoMessageHandler {
             var storageDir = documentUrls[0]
             storageDir.appendPathComponent("talerwalletdb-v30", isDirectory: 
false)
             storageDir.appendPathExtension("json")
-            try! sendRequest(request: 
WalletBackendInitRequest(persistentStoragePath: storageDir.path))
+            try! sendRequest(request: 
WalletBackendInitRequest(persistentStoragePath: storageDir.path, onSuccess: {
+                self.backendReady = true
+                self.backendReadyCondition.broadcast()
+            }))
+        }
+        
+        waitUntilReady()
+        //try! sendRequest(request: WalletBackendWithdrawTestBalance(amount: 
"TESTKUDOS:10", bankBaseUrl: "https://bank.test.taler.net/";, exchangeBaseUrl: 
"https://exchange.test.taler.net/";))
+        try! sendRequest(request: WalletBackendGetBalancesRequest(onSuccess: { 
([WalletBackendGetBalancesRequest.Balance]) -> Void in
+            
+        }, onFailure: { () -> Void in
+            
+        }))
+    }
+    
+    func waitUntilReady() {
+        backendReadyCondition.lock()
+        while (!self.backendReady) {
+            backendReadyCondition.wait()
         }
-        //try! sendRequest(request: WalletBackendGetTransactionsRequest())
+        backendReadyCondition.unlock()
     }
     
     func handleMessage(message: String) {
-        print("received message \(message)")
+        print(message)
+        do {
+            guard let messageData = message.data(using: .utf8) else { throw 
WalletBackendError.deserializationError }
+            let data = try JSONSerialization.jsonObject(with: messageData, 
options: .allowFragments) as? [String : Any]
+            if let responseData = data {
+                let type = (responseData["type"] as? String) ?? ""
+                if type == "response" {
+                    guard let id = responseData["id"] as? UInt else { /* TODO: 
error. */ return }
+                    guard let request = requests[id] else { /* TODO: error. */ 
return }
+                    request.decodeSuccess(messageData)
+                    requests[id] = nil
+                } else if type == "tunnelHttp" {
+                    
+                } else if type == "notification" {
+                    
+                } else if type == "error" {
+                    guard let id = responseData["id"] as? UInt else { /* TODO: 
error. */ return }
+                    guard let request = requests[id] else { /* TODO: error. */ 
return }
+                    //request.handleError(messageData)
+                    requests[id] = nil
+                } else {
+                    /* TODO: unknown response type. */
+                }
+            }
+        } catch {
+            
+        }
     }
     
+    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: WalletErrorDetail
+    }*/
+    
     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 {
+                
+            }
+        }
+        
+        /* Encode the request and send it to the backend. */
         do {
             let encoded = try JSONEncoder().encode(data)
             guard let jsonString = String(data: encoded, encoding: .utf8) else 
{ throw WalletBackendError.serializationError }
+            let detail = RequestDetail(decodeSuccess: decodeSuccess)
+            requests[data.id] = detail
             iono.sendMessage(message: jsonString)
         } catch {
             throw WalletBackendError.serializationError
diff --git a/TalerTests/AmountTests.swift b/TalerTests/AmountTests.swift
new file mode 100644
index 0000000..b7dd28d
--- /dev/null
+++ b/TalerTests/AmountTests.swift
@@ -0,0 +1,62 @@
+/*
+ * This file is part of GNU Taler
+ * (C) 2021 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 AmountTests: XCTestCase {
+
+    override func setUpWithError() throws {
+        // Put setup code here. This method is called before the invocation of 
each test method in the class.
+    }
+
+    override func tearDownWithError() throws {
+        // Put teardown code here. This method is called after the invocation 
of each test method in the class.
+    }
+
+    func testAmounts() throws {
+        var amount: Amount = try! Amount(fromString: "EUR:633.59")
+        XCTAssert(amount.currency == "EUR")
+        XCTAssert(amount.value == 633)
+        XCTAssert(amount.fraction == 59000000)
+        XCTAssert(amount.description == "EUR:633.59")
+        XCTAssert(try amount == Amount(currency: "EUR", value: 633, fraction: 
59000000))
+        XCTAssert(try amount == amount)
+        
+        amount = try! Amount(fromString: "EUR:883")
+        XCTAssert(amount.currency == "EUR")
+        XCTAssert(amount.value == 883)
+        XCTAssert(amount.fraction == 0)
+        XCTAssert(amount.description == "EUR:883")
+        
+        XCTAssertThrowsError(try Amount(fromString: "EUR:6548$f.59.**"))
+        
+        let amount2: Amount = try! Amount(fromString: "EUR:971.32")
+        XCTAssert(try amount < amount2)
+        XCTAssert(try amount2 > amount)
+        XCTAssert(try (amount + amount2) == Amount(fromString: "EUR:1854.32"))
+        XCTAssert(try (amount2 - amount) == Amount(fromString: "EUR:88.32"))
+        XCTAssertThrowsError(try amount - amount2)
+        
+        let amount3: Amount = try! Amount(fromString: "USD:12.34")
+        XCTAssertThrowsError(try amount == amount3)
+        XCTAssertThrowsError(try amount < amount3)
+        XCTAssertThrowsError(try amount > amount3)
+        XCTAssertThrowsError(try amount + amount3)
+        XCTAssertThrowsError(try amount - amount3)
+    }
+
+}

-- 
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]