TalerWalletCore.kt (8231B)
1 /* 2 * This file is part of GNU Taler 3 * (C) 2023 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 /* 18 * This file is part of GNU Taler 19 * (C) 2023 Taler Systems S.A. 20 * 21 * GNU Taler is free software; you can redistribute it and/or modify it under the 22 * terms of the GNU General Public License as published by the Free Software 23 * Foundation; either version 3, or (at your option) any later version. 24 * 25 * GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY 26 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 27 * A PARTICULAR PURPOSE. See the GNU General Public License for more details. 28 * 29 * You should have received a copy of the GNU General Public License along with 30 * GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> 31 */ 32 33 package net.taler.qtart 34 35 import com.sun.jna.Callback 36 import com.sun.jna.Library 37 import com.sun.jna.Native 38 import com.sun.jna.Pointer 39 import com.sun.jna.Structure 40 41 class TalerWalletCore { 42 internal interface TalerNative : Library { 43 companion object { 44 val INSTANCE: TalerNative by lazy { 45 Native.setProtected(true) 46 Native.load("talerwalletcore", TalerNative::class.java) 47 } 48 } 49 50 interface TALER_WALLET_MessageHandlerFn : Callback { 51 fun invoke(handler_p: Pointer, message: String) 52 } 53 54 interface TALER_LogFn : Callback { 55 fun invoke(cls: Pointer, stream: Int, msg: String) 56 } 57 58 fun TALER_WALLET_create(): Pointer 59 fun TALER_WALLET_set_message_handler( 60 twi: Pointer, 61 handler_f: TALER_WALLET_MessageHandlerFn, 62 handler_p: Pointer 63 ) 64 65 fun TALER_WALLET_send_request(twi: Pointer, request: String): Int 66 fun TALER_WALLET_run(twi: Pointer): Int 67 fun TALER_WALLET_join(twi: Pointer) 68 fun TALER_WALLET_destroy(twi: Pointer) 69 fun TALER_start_redirect_std(logfn: TALER_LogFn, cls: Pointer) 70 fun TALER_set_curl_http_client(twi: Pointer) 71 72 /** 73 * Native networking 74 */ 75 76 class JSHttpRequestInfo: Structure() { 77 @JvmField var response_cb: JSHttpResponseCb? = null 78 @JvmField var response_cb_cls: Pointer? = null 79 @JvmField var url: String? = null 80 @JvmField var method: String? = null 81 @JvmField var request_headers: Pointer? = null // Array<String> 82 @JvmField var redirect: Int? = null 83 @JvmField var timeout_ms: Int? = null 84 @JvmField var debug: Int? = null 85 @JvmField var req_body: Pointer? = null // ByteArray 86 @JvmField var req_body_len: Int? = null 87 88 override fun getFieldOrder() = mutableListOf( 89 "response_cb", 90 "response_cb_cls", 91 "url", 92 "method", 93 "request_headers", 94 "redirect", 95 "timeout_ms", 96 "debug", 97 "req_body", 98 "req_body_len", 99 ) 100 } 101 102 class JSHttpResponseInfo: Structure() { 103 @JvmField var request_id: Int? = null 104 @JvmField var status: Int? = null 105 @JvmField var errmsg: String? = null 106 @JvmField var response_headers: Pointer? = null 107 @JvmField var num_response_headers: Int? = null 108 @JvmField var body: Pointer? = null 109 @JvmField var body_len: Int? = null 110 111 override fun getFieldOrder() = mutableListOf( 112 "request_id", 113 "status", 114 "errmsg", 115 "response_headers", 116 "num_response_headers", 117 "body", 118 "body_len", 119 ) 120 } 121 122 interface JSHttpResponseCb: Callback { 123 fun invoke(cls: Pointer, resp: JSHttpResponseInfo) 124 } 125 126 interface JSHttpRequestCb: Callback { 127 fun invoke(cls: Pointer, req_info: JSHttpRequestInfo) 128 } 129 130 interface JSHttpReqCreateFn: Callback { 131 fun invoke(cls: Pointer, req_info: JSHttpRequestInfo): Int 132 } 133 134 interface JSHttpReqCancelFn: Callback { 135 fun invoke(cls: Pointer, request_id: Int): Int 136 } 137 138 fun TALER_set_http_client_implementation(twi: Pointer, impl: Pointer) 139 140 fun TALER_pack_http_client_implementation( 141 req_create: JSHttpReqCreateFn, 142 req_cancel: JSHttpReqCancelFn, 143 handler_p: Pointer, 144 ): Pointer 145 } 146 147 private val walletInstance: Pointer = TalerNative.INSTANCE.TALER_WALLET_create() 148 149 // Handlers must be here, so that GC doesn't wipe them! 150 // Please don't refactor them, or else you'll suffer! 151 private var currentMessageHandler: TalerNative.TALER_WALLET_MessageHandlerFn? = null 152 private var currentLogHandler: TalerNative.TALER_LogFn? = null 153 private var currentReqCreateHandler: TalerNative.JSHttpReqCreateFn? = null 154 private var currentReqCancelHandler: TalerNative.JSHttpReqCancelFn? = null 155 private var currentResHandler: TalerNative.JSHttpResponseCb? = null 156 157 fun setMessageHandler(handler: (msg: String) -> Unit) { 158 this.currentMessageHandler = object : TalerNative.TALER_WALLET_MessageHandlerFn { 159 override fun invoke(handler_p: Pointer, message: String) { 160 handler(message) 161 } 162 } 163 TalerNative.INSTANCE.TALER_WALLET_set_message_handler( 164 walletInstance, 165 this.currentMessageHandler!!, 166 walletInstance 167 ) 168 } 169 170 fun setStdoutHandler(handler: (msg: String) -> Unit) { 171 this.currentLogHandler = object : TalerNative.TALER_LogFn { 172 override fun invoke(cls: Pointer, stream: Int, msg: String) { 173 handler(msg) 174 } 175 } 176 TalerNative.INSTANCE.TALER_start_redirect_std(this.currentLogHandler!!, walletInstance) 177 } 178 179 fun sendRequest(request: String) { 180 TalerNative.INSTANCE.TALER_WALLET_send_request(walletInstance, request) 181 } 182 183 fun setCurlHttpClient() { 184 TalerNative.INSTANCE.TALER_set_curl_http_client(walletInstance) 185 } 186 187 fun run() { 188 TalerNative.INSTANCE.TALER_WALLET_run(walletInstance) 189 } 190 191 fun destroy() { 192 TalerNative.INSTANCE.TALER_WALLET_destroy(walletInstance) 193 } 194 195 fun join() { 196 TalerNative.INSTANCE.TALER_WALLET_join(walletInstance) 197 } 198 199 /** 200 * Native networking 201 */ 202 203 fun setHttpClient(handler: Networking.RequestHandler) { 204 this.currentReqCreateHandler = object: TalerNative.JSHttpReqCreateFn { 205 override fun invoke(cls: Pointer, req_info: TalerNative.JSHttpRequestInfo): Int { 206 // TODO: return positive request_id on success, negative on failure 207 // right now, this can't be done synchronously; doing it async 208 // might require a modification in the C API. 209 return Networking.httpCreateRequest(req_info, handler) 210 } 211 } 212 this.currentReqCancelHandler = object: TalerNative.JSHttpReqCancelFn { 213 override fun invoke(cls: Pointer, request_id: Int): Int { 214 return Networking.httpCancelRequest(request_id, handler) 215 } 216 } 217 218 val client = TalerNative.INSTANCE.TALER_pack_http_client_implementation( 219 this.currentReqCreateHandler!!, 220 this.currentReqCancelHandler!!, 221 this.walletInstance, 222 ) 223 224 TalerNative.INSTANCE.TALER_set_http_client_implementation(walletInstance, client) 225 } 226 }