quickjs-tart

quickjs-based runtime for wallet-core logic
Log | Files | Refs | README | LICENSE

Networking.kt (4041B)


      1 package net.taler.qtart
      2 
      3 import android.util.Log
      4 import com.sun.jna.Memory
      5 import com.sun.jna.Pointer
      6 import com.sun.jna.StringArray
      7 import java.util.concurrent.atomic.AtomicInteger
      8 import net.taler.qtart.TalerWalletCore.TalerNative.*
      9 
     10 object Networking {
     11     private val lastRequestId = AtomicInteger(0)
     12 
     13     // Add your pointer here to protect it from the GC!
     14     private val pointerReferences = mutableListOf<Pointer>()
     15 
     16     interface RequestHandler {
     17         fun handleRequest(req: RequestInfo, id: Int, sendResponse: (resp: ResponseInfo) -> Unit)
     18         fun cancelRequest(id: Int): Boolean
     19     }
     20 
     21     enum class RedirectMode(val value: Int) {
     22         Unknown(-1),
     23 
     24         /**
     25          * Handle redirects transparently.
     26          */
     27         Transparent(0),
     28 
     29         /**
     30          * Redirect status codes are returned to the client.
     31          * The client can choose to follow them manually (or not).
     32          */
     33         Manual(1),
     34 
     35         /**
     36          * All redirect status codes result in an error.
     37          */
     38         Error(2);
     39 
     40         companion object {
     41             fun fromValue(value: Int): RedirectMode =
     42                 RedirectMode.values().find { it.value == value } ?: Unknown
     43         }
     44     }
     45 
     46     class RequestInfo(
     47         val url: String,
     48         val method: String,
     49         val headers: Array<String>,
     50         val redirectMode: RedirectMode,
     51         val timeoutMs: Long,
     52         val debug: Boolean,
     53         val body: ByteArray?,
     54     )
     55 
     56     class ResponseInfo(
     57         val requestId: Int,
     58         val status: Int,
     59         val errorMsg: String?,
     60         val headers: Array<String>,
     61         val body: ByteArray?,
     62     )
     63 
     64     /**
     65      * Function to create a new HTTP fetch request.
     66      * The request can still be configured until it is started.
     67      * An identifier for the request will be written to @a handle.
     68      *
     69      * @return negative number on error, positive request_id on success
     70      */
     71     internal fun httpCreateRequest(
     72         reqInfo: JSHttpRequestInfo,
     73         reqHandler: RequestHandler,
     74     ): Int {
     75         val requestId = lastRequestId.addAndGet(1)
     76 
     77         reqHandler.handleRequest(
     78             req = RequestInfo(
     79                 url = reqInfo.url!!,
     80                 method = reqInfo.method!!,
     81                 headers = reqInfo.request_headers!!.getStringArray(0),
     82                 redirectMode = RedirectMode.fromValue(reqInfo.redirect!!),
     83                 timeoutMs = reqInfo.timeout_ms!!.toLong(),
     84                 debug = reqInfo.debug != 0,
     85                 body = if (reqInfo.req_body_len!! > 0) {
     86                     reqInfo.req_body!!.getByteArray(0, reqInfo.req_body_len!!)
     87                 } else null,
     88             ),
     89             id = requestId,
     90         ) { resp ->
     91             val rawResp = JSHttpResponseInfo()
     92             rawResp.request_id = resp.requestId
     93             rawResp.status = resp.status
     94             rawResp.errmsg = resp.errorMsg ?: ""
     95             rawResp.response_headers = StringArray(resp.headers, false)
     96             rawResp.num_response_headers = resp.headers.size
     97             if (resp.body != null && resp.body.isNotEmpty()) {
     98                 // Manually allocate and write memory
     99                 val pointer = Memory(resp.body.size.toLong())
    100                 pointer.write(0, resp.body, 0, resp.body.size)
    101                 pointerReferences.add(pointer)
    102                 rawResp.body = pointer
    103                 rawResp.body_len = resp.body.size
    104             } else {
    105                 rawResp.body_len = 0
    106             }
    107 
    108             Log.d("Networking", "Response to request $requestId ready to send to qtart")
    109             reqInfo.response_cb?.invoke(reqInfo.response_cb_cls!!, rawResp)
    110         }
    111 
    112         return requestId
    113     }
    114 
    115     /**
    116      * Cancel a request. The request_id will become invalid
    117      * and the callback won't be called with request_id.
    118      */
    119     internal fun httpCancelRequest(
    120         requestId: Int,
    121         handler: RequestHandler,
    122     ): Int {
    123         val success = handler.cancelRequest(requestId)
    124         return if (success) requestId else -requestId
    125     }
    126 }