taler-android

Android apps for GNU Taler (wallet, PoS, cashier)
Log | Files | Refs | README | LICENSE

BackendManager.kt (3353B)


      1 /*
      2  * This file is part of GNU Taler
      3  * (C) 2022 Taler Systems S.A.
      4  *
      5  * GNU Taler is free software; you can redistribute it and/or modify it under the
      6  * terms of the GNU General Public License as published by the Free Software
      7  * Foundation; either version 3, or (at your option) any later version.
      8  *
      9  * GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
     10  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
     11  * A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
     12  *
     13  * You should have received a copy of the GNU General Public License along with
     14  * GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
     15  */
     16 
     17 package net.taler.wallet.backend
     18 
     19 import android.util.Log
     20 import kotlinx.serialization.json.Json
     21 import net.taler.qtart.TalerWalletCore
     22 import net.taler.wallet.BuildConfig
     23 import org.json.JSONObject
     24 import java.util.concurrent.atomic.AtomicBoolean
     25 import kotlin.coroutines.resume
     26 import kotlin.coroutines.suspendCoroutine
     27 
     28 
     29 fun interface NotificationReceiver {
     30     fun onNotificationReceived(payload: NotificationPayload)
     31 }
     32 
     33 class BackendManager(
     34     private val notificationReceiver: NotificationReceiver,
     35 ) {
     36 
     37     companion object {
     38         private const val TAG = "BackendManager"
     39         private const val TAG_CORE = "taler-wallet-embedded"
     40         val json = Json {
     41             ignoreUnknownKeys = true
     42             coerceInputValues = true
     43         }
     44         @JvmStatic
     45         private val initialized = AtomicBoolean(false)
     46     }
     47 
     48     private val walletCore = TalerWalletCore()
     49     private val requestManager = RequestManager()
     50     private val networkInterface = NetworkInterface()
     51 
     52     fun run() {
     53         if (!initialized.getAndSet(true)) {
     54             walletCore.setMessageHandler { onMessageReceived(it) }
     55             walletCore.setHttpClient(networkInterface)
     56             if (BuildConfig.DEBUG) walletCore.setStdoutHandler {
     57                 Log.d(TAG_CORE, it)
     58             }
     59             walletCore.run()
     60         }
     61     }
     62 
     63     fun destroy() {
     64         if (initialized.getAndSet(false)) {
     65             walletCore.destroy()
     66         }
     67     }
     68 
     69     suspend fun send(operation: String, args: JSONObject? = null): ApiResponse =
     70         suspendCoroutine { cont ->
     71             requestManager.addRequest(cont) { id ->
     72                 val request = JSONObject().apply {
     73                     put("id", id)
     74                     put("operation", operation)
     75                     if (args != null) put("args", args)
     76                 }
     77                 Log.d(TAG, "sending message:\n${request.toString(2)}")
     78                 walletCore.sendRequest(request.toString())
     79             }
     80         }
     81 
     82     private fun onMessageReceived(msg: String) {
     83         Log.d(TAG, "message received: $msg")
     84         when (val message = json.decodeFromString<ApiMessage>(msg)) {
     85             is ApiMessage.Notification -> {
     86                 notificationReceiver.onNotificationReceived(message.payload)
     87             }
     88             is ApiResponse -> {
     89                 val id = message.id
     90                 val cont = requestManager.getAndRemoveContinuation(id)
     91                 if (cont == null) {
     92                     Log.e(TAG, "wallet returned unknown request ID ($id)")
     93                 } else {
     94                     cont.resume(message)
     95                 }
     96             }
     97         }
     98     }
     99 }