taler-ios

iOS apps for GNU Taler (wallet)
Log | Files | Refs | README | LICENSE

quickjs.swift (5508B)


      1 /*
      2  * This file is part of GNU Taler, ©2022-25 Taler Systems S.A.
      3  * See LICENSE.md
      4  */
      5 /**
      6  * @author Marc Stibane
      7  */
      8 import Foundation
      9 import os.log
     10 
     11 import FTalerWalletcore
     12 
     13 public protocol QuickjsMessageHandler: AnyObject {
     14     func handleMessage(message: String)
     15     func handleLog(message: String)
     16 }
     17 // MARK: -
     18 func notification_callback(userdata: Optional<UnsafeMutableRawPointer>,
     19                            payload: Optional<UnsafePointer<Int8>>) {
     20     let quickjs = Unmanaged<Quickjs>.fromOpaque(userdata!).takeUnretainedValue()
     21     let string = String(cString: payload!)
     22     quickjs.internalOnNotify(payload: string)
     23 }
     24 
     25 func logging_callback(userdata: Optional<UnsafeMutableRawPointer>,
     26                           level: TALER_WALLET_LogLevel,
     27                             tag: Optional<UnsafePointer<Int8>>,
     28                         message: Optional<UnsafePointer<Int8>>) {
     29     let quickjs = Unmanaged<Quickjs>.fromOpaque(userdata!).takeUnretainedValue()
     30     let logger = quickjs.logger
     31     let swiftTag = String(cString: tag!)
     32     let swiftMessage = String(cString: message!)
     33 
     34     switch level {
     35         case TALER_WALLET_LOG_ERROR:
     36             logger.error("\(swiftTag, privacy: .public)  \(swiftMessage, privacy: .public)")
     37         case TALER_WALLET_LOG_WARN:
     38             logger.warning("\(swiftTag, privacy: .public)  \(swiftMessage, privacy: .public)")
     39         case TALER_WALLET_LOG_MESSAGE:
     40             logger.notice("\(swiftTag, privacy: .public)  \(swiftMessage, privacy: .public)")
     41         case TALER_WALLET_LOG_INFO:
     42             logger.info("\(swiftTag, privacy: .public)  \(swiftMessage, privacy: .public)")
     43         case TALER_WALLET_LOG_TRACE:
     44             logger.trace("\(swiftTag, privacy: .public)  \(swiftMessage, privacy: .public)")
     45         default: break
     46     }
     47     quickjs.internalOnLog(message: swiftMessage)
     48 }
     49 // MARK: -
     50 public class Quickjs {      // acts as singleton, since only one instance ever exists
     51     var talerWalletInstance: OpaquePointer!
     52     public weak var messageHandler: QuickjsMessageHandler?
     53     var logger: Logger
     54 
     55     @Atomic(default: 0)                                                         // boilerPlate around NSLock…
     56     private var lastRequestID: Int32                                            // …to safeguard increments
     57     private var requests: [Int32: QuickDataTask] = [:]
     58 
     59     private lazy var urlSession: URLSession = {
     60         return URLSession(configuration: .ephemeral)    // we don't want the filesystem cache - keep it in RAM
     61     }()
     62 
     63     public init() {
     64         self.logger = Logger(subsystem: "net.taler.gnu", category: "QuickJS")
     65         self.talerWalletInstance = TALER_WALLET_create()
     66         TALER_WALLET_set_message_handler(talerWalletInstance,
     67                                          notification_callback,
     68                                          Unmanaged.passUnretained(self).toOpaque())
     69         TALER_WALLET_set_log_handler(talerWalletInstance,
     70                                      logging_callback,
     71                                      Unmanaged.passUnretained(self).toOpaque())
     72 #if USE_HTTP_CLIENT_CURL
     73         let http_impl = js_curl_http_client_create()
     74 #else
     75         let http_impl = TALER_pack_http_client_implementation(request_create, request_cancel,
     76                                                               Unmanaged.passUnretained(self).toOpaque())
     77 #endif
     78         // http_impl got malloc'd, and could possibly be free'd when the app terminates
     79         TALER_set_http_client_implementation(talerWalletInstance, http_impl)
     80         // - but we never free anything on termination, thus we don't save http_impl here
     81         TALER_WALLET_run(talerWalletInstance)
     82     }
     83 
     84     func reqCreate(_ request: URLRequest,
     85                 _ responseCb: JSHttpResponseCb?,
     86              _ responseCbCls: Optional<UnsafeMutableRawPointer>) -> Int32 {
     87         let requestID = $lastRequestID.atomicIncrement()                        // ensure requestID is unique
     88         let quickDataTask = QuickDataTask(urlSession: urlSession,
     89                                              request: request,
     90                                            requestID: requestID,
     91                                             requests: &requests,
     92                                           responseCb: responseCb,
     93                                        responseCbCls: responseCbCls)
     94         quickDataTask.run()
     95         requests[requestID] = quickDataTask
     96         return requestID
     97     }
     98 
     99     func reqCancel(_ requestID: Int32) -> Int32 {
    100         if let quickDataTask = requests[requestID] {
    101             if let dataTask = quickDataTask.dataTask {
    102                 dataTask.cancel()
    103             }
    104         }
    105         requests[requestID] = nil
    106         return 0
    107     }
    108 
    109     deinit {
    110         // No need to call TALER_WALLET_destroy - memory gets purged anyway
    111     }
    112 
    113     func internalOnNotify(payload: String) {
    114         if let handler = messageHandler {
    115             handler.handleMessage(message: payload)
    116         }
    117     }
    118 
    119     public func internalOnLog(message: String) {
    120         if let handler = messageHandler {
    121             handler.handleLog(message: message)
    122         }
    123     }
    124 
    125 //    public func notifyNative() {
    126 //        __notifyNative(instance)
    127 //    }
    128 
    129 //    public func evalNodeCode(source: String) {
    130 //        scheduleNodeThreadAsync {
    131 //            __makeCallbackNative(self.instance, source.cString(using: .utf8))
    132 //        }
    133 //    }
    134 
    135     public func sendMessage(message: String) {
    136         TALER_WALLET_send_request(talerWalletInstance, message)
    137     }
    138 }