summaryrefslogtreecommitdiff
path: root/Taler/WalletBackend.swift
diff options
context:
space:
mode:
Diffstat (limited to 'Taler/WalletBackend.swift')
-rw-r--r--Taler/WalletBackend.swift203
1 files changed, 196 insertions, 7 deletions
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