diff options
Diffstat (limited to 'wallet/src/main/java/net/taler/wallet/backend/WalletBackendService.kt')
-rw-r--r-- | wallet/src/main/java/net/taler/wallet/backend/WalletBackendService.kt | 252 |
1 files changed, 0 insertions, 252 deletions
diff --git a/wallet/src/main/java/net/taler/wallet/backend/WalletBackendService.kt b/wallet/src/main/java/net/taler/wallet/backend/WalletBackendService.kt deleted file mode 100644 index ccb995a..0000000 --- a/wallet/src/main/java/net/taler/wallet/backend/WalletBackendService.kt +++ /dev/null @@ -1,252 +0,0 @@ -/* - * This file is part of GNU Taler - * (C) 2020 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/> - */ - - -package net.taler.wallet.backend - -import akono.AkonoJni -import android.app.Service -import android.content.Intent -import android.os.Handler -import android.os.IBinder -import android.os.Message -import android.os.Messenger -import android.os.RemoteException -import android.util.Log -import net.taler.wallet.BuildConfig.WALLET_CORE_VERSION -import net.taler.wallet.HostCardEmulatorService -import org.json.JSONObject -import java.lang.ref.WeakReference -import java.util.LinkedList -import java.util.concurrent.ConcurrentHashMap -import kotlin.system.exitProcess - -private const val TAG = "taler-wallet-backend" - -class RequestData(val clientRequestId: Int, val messenger: Messenger) - - -class WalletBackendService : Service() { - /** - * Target we publish for clients to send messages to IncomingHandler. - */ - private val messenger: Messenger = Messenger(IncomingHandler(this)) - - private lateinit var akono: AkonoJni - - private var initialized = false - - private var nextRequestID = 1 - - private val requests = ConcurrentHashMap<Int, RequestData>() - - private val subscribers = LinkedList<Messenger>() - - override fun onCreate() { - val talerWalletAndroidCode = - assets.open("taler-wallet-android-$WALLET_CORE_VERSION.js").use { - it.readBytes().toString(Charsets.UTF_8) - } - - - Log.i(TAG, "onCreate in wallet backend service") - akono = AkonoJni() - akono.putModuleCode("@gnu-taler/taler-wallet-android", talerWalletAndroidCode) - akono.setMessageHandler(object : AkonoJni.MessageHandler { - override fun handleMessage(message: String) { - this@WalletBackendService.handleAkonoMessage(message) - } - }) - //akono.evalNodeCode("require('source-map-support').install();") - akono.evalNodeCode("require('akono');") - akono.evalNodeCode("tw = require('@gnu-taler/taler-wallet-android');") - akono.evalNodeCode("tw.installAndroidWalletListener();") - sendInitMessage() - initialized = true - super.onCreate() - } - - private fun sendInitMessage() { - val msg = JSONObject() - msg.put("operation", "init") - val args = JSONObject() - msg.put("args", args) - args.put("persistentStoragePath", "${application.filesDir}/talerwalletdb-v30.json") - akono.sendMessage(msg.toString()) - } - - /** - * Handler of incoming messages from clients. - */ - class IncomingHandler( - service: WalletBackendService - ) : Handler() { - - private val serviceWeakRef = WeakReference(service) - - override fun handleMessage(msg: Message) { - val svc = serviceWeakRef.get() ?: return - when (msg.what) { - MSG_COMMAND -> { - val data = msg.data - val serviceRequestID = svc.nextRequestID++ - val clientRequestID = data.getInt("requestID", 0) - if (clientRequestID == 0) { - Log.e(TAG, "client requestID missing") - return - } - val args = data.getString("args") - val argsObj = if (args == null) { - JSONObject() - } else { - JSONObject(args) - } - val operation = data.getString("operation", "") - if (operation == "") { - Log.e(TAG, "client command missing") - return - } - Log.i(TAG, "got request for operation $operation") - val request = JSONObject() - request.put("operation", operation) - request.put("id", serviceRequestID) - request.put("args", argsObj) - svc.akono.sendMessage(request.toString(2)) - Log.i( - TAG, - "mapping service request ID $serviceRequestID to client request ID $clientRequestID" - ) - svc.requests[serviceRequestID] = RequestData(clientRequestID, msg.replyTo) - } - MSG_SUBSCRIBE_NOTIFY -> { - Log.i(TAG, "subscribing client") - val r = msg.replyTo - if (r == null) { - Log.e( - TAG, - "subscriber did not specify replyTo object in MSG_SUBSCRIBE_NOTIFY" - ) - } else { - svc.subscribers.add(msg.replyTo) - } - } - MSG_UNSUBSCRIBE_NOTIFY -> { - Log.i(TAG, "unsubscribing client") - svc.subscribers.remove(msg.replyTo) - } - else -> { - Log.e(TAG, "unknown message from client") - super.handleMessage(msg) - } - } - } - } - - override fun onBind(p0: Intent?): IBinder? { - return messenger.binder - } - - private fun sendNotify(payload: String) { - var rm: LinkedList<Messenger>? = null - for (s in subscribers) { - val m = Message.obtain(null, MSG_NOTIFY) - val b = m.data - b.putString("payload", payload) - try { - s.send(m) - } catch (e: RemoteException) { - if (rm == null) { - rm = LinkedList() - } - rm.add(s) - subscribers.remove(s) - } - } - if (rm != null) { - for (s in rm) { - subscribers.remove(s) - } - } - } - - private fun handleAkonoMessage(messageStr: String) { - val message = JSONObject(messageStr) - when (val type = message.getString("type")) { - "notification" -> { - val payload = message.getJSONObject("payload") - if (payload.optString("type") != "waiting-for-retry") { - Log.v(TAG, "got back notification: ${message.toString(2)}") - } - sendNotify(payload.toString()) - } - "tunnelHttp" -> { - Log.v(TAG, "got http tunnel request! ${message.toString(2)}") - Intent().also { intent -> - intent.action = HostCardEmulatorService.HTTP_TUNNEL_REQUEST - intent.putExtra("tunnelMessage", messageStr) - application.sendBroadcast(intent) - } - } - "response" -> { - when (message.getString("operation")) { - "init" -> { - Log.v(TAG, "got response for init operation: ${message.toString(2)}") - sendNotify(message.toString(2)) - } - "reset" -> { - Log.v(TAG, "got back message: ${message.toString(2)}") - exitProcess(1) - } - else -> { - Log.v(TAG, "got back response: ${message.toString(2)}") - val payload = message.getJSONObject("result").toString(2) - handleResponse(false, message, payload) - } - } - } - "error" -> { - Log.v(TAG, "got back error: ${message.toString(2)}") - val payload = message.getJSONObject("error").toString(2) - handleResponse(true, message, payload) - } - else -> throw IllegalArgumentException("Unknown message type: $type") - } - } - - private fun handleResponse(isError: Boolean, message: JSONObject, payload: String) { - val id = message.getInt("id") - val rId = requests[id] - if (rId == null) { - Log.e(TAG, "wallet returned unknown request ID ($id)") - return - } - val m = Message.obtain(null, MSG_REPLY) - val b = m.data - b.putInt("requestID", rId.clientRequestId) - b.putBoolean("isError", isError) - b.putString("response", payload) - b.putString("operation", message.getString("operation")) - rId.messenger.send(m) - } - - companion object { - const val MSG_SUBSCRIBE_NOTIFY = 1 - const val MSG_UNSUBSCRIBE_NOTIFY = 2 - const val MSG_COMMAND = 3 - const val MSG_REPLY = 4 - const val MSG_NOTIFY = 5 - } -} |