From 825d2c4352022e7397854b2bd9ba7d3589873c07 Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Wed, 15 Feb 2023 23:32:42 +0100 Subject: make wallet-cli runnable under qtart --- packages/taler-wallet-embedded/build.mjs | 1 + packages/taler-wallet-embedded/src/index.ts | 28 ++- packages/taler-wallet-embedded/src/wallet-qjs.ts | 237 ++--------------------- 3 files changed, 28 insertions(+), 238 deletions(-) (limited to 'packages/taler-wallet-embedded') diff --git a/packages/taler-wallet-embedded/build.mjs b/packages/taler-wallet-embedded/build.mjs index 537a4fbc0..28351e6e5 100755 --- a/packages/taler-wallet-embedded/build.mjs +++ b/packages/taler-wallet-embedded/build.mjs @@ -55,6 +55,7 @@ export const buildConfig = { format: 'esm', platform: 'neutral', mainFields: ["module", "main"], + conditions: ["qtart"], sourcemap: true, define: { '__VERSION__': `"${_package.version}"`, diff --git a/packages/taler-wallet-embedded/src/index.ts b/packages/taler-wallet-embedded/src/index.ts index b505a2d9d..e0a13390d 100644 --- a/packages/taler-wallet-embedded/src/index.ts +++ b/packages/taler-wallet-embedded/src/index.ts @@ -18,27 +18,25 @@ * Imports. */ import { + createNativeWalletHost, DefaultNodeWalletArgs, - getDefaultNodeWallet, - getErrorDetailFromException, handleWorkerError, handleWorkerMessage, - Headers, - HttpRequestLibrary, - HttpRequestOptions, - HttpResponse, - NodeHttpLib, OpenedPromise, openPromise, Wallet, - WALLET_EXCHANGE_PROTOCOL_VERSION, - WALLET_MERCHANT_PROTOCOL_VERSION, } from "@gnu-taler/taler-wallet-core"; import { CoreApiMessageEnvelope, CoreApiResponse, CoreApiResponseSuccess, + createPlatformHttpLib, + getErrorDetailFromException, + Headers, + HttpRequestLibrary, + HttpRequestOptions, + HttpResponse, Logger, WalletNotification, } from "@gnu-taler/taler-util"; @@ -51,7 +49,7 @@ const logger = new Logger("taler-wallet-embedded/index.ts"); export class NativeHttpLib implements HttpRequestLibrary { useNfcTunnel = false; - private nodeHttpLib: HttpRequestLibrary = new NodeHttpLib(); + private httpLib: HttpRequestLibrary = createPlatformHttpLib(); private requestId = 1; @@ -62,7 +60,7 @@ export class NativeHttpLib implements HttpRequestLibrary { constructor(private sendMessage: (m: string) => void) {} fetch(url: string, opt?: HttpRequestOptions): Promise { - return this.nodeHttpLib.fetch(url, opt); + return this.httpLib.fetch(url, opt); } get(url: string, opt?: HttpRequestOptions): Promise { @@ -83,7 +81,7 @@ export class NativeHttpLib implements HttpRequestLibrary { ); return p.promise; } else { - return this.nodeHttpLib.get(url, opt); + return this.httpLib.get(url, opt); } } @@ -106,7 +104,7 @@ export class NativeHttpLib implements HttpRequestLibrary { ); return p.promise; } else { - return this.nodeHttpLib.postJson(url, body, opt); + return this.httpLib.postJson(url, body, opt); } } @@ -158,7 +156,7 @@ class NativeWalletMessageHandler { walletArgs: DefaultNodeWalletArgs | undefined; maybeWallet: Wallet | undefined; wp = openPromise(); - httpLib = new NodeHttpLib(); + httpLib = createPlatformHttpLib(); /** * Handle a request from the native wallet. @@ -181,7 +179,7 @@ class NativeWalletMessageHandler { const reinit = async () => { logger.info("in reinit"); - const w = await getDefaultNodeWallet(this.walletArgs); + const w = await createNativeWalletHost(this.walletArgs); this.maybeWallet = w; const resp = await w.handleCoreApiRequest( "initWallet", diff --git a/packages/taler-wallet-embedded/src/wallet-qjs.ts b/packages/taler-wallet-embedded/src/wallet-qjs.ts index f7b73711c..77d166095 100644 --- a/packages/taler-wallet-embedded/src/wallet-qjs.ts +++ b/packages/taler-wallet-embedded/src/wallet-qjs.ts @@ -17,44 +17,26 @@ /** * Imports. */ -import { - AccessStats, - DefaultNodeWalletArgs, - getErrorDetailFromException, - Headers, - HttpRequestLibrary, - HttpRequestOptions, - HttpResponse, - openPromise, - openTalerDatabase, - SetTimeoutTimerAPI, - SynchronousCryptoWorkerFactoryPlain, - Wallet, - WalletApiOperation, -} from "@gnu-taler/taler-wallet-core"; - import { CoreApiMessageEnvelope, CoreApiResponse, CoreApiResponseSuccess, + createPlatformHttpLib, + getErrorDetailFromException, InitRequest, - j2s, Logger, setGlobalLogLevelFromString, setPRNG, WalletNotification, } from "@gnu-taler/taler-util"; -import { BridgeIDBFactory } from "@gnu-taler/idb-bridge"; -import { MemoryBackend } from "@gnu-taler/idb-bridge"; -import { shimIndexedDB } from "@gnu-taler/idb-bridge"; -import { IDBFactory } from "@gnu-taler/idb-bridge"; - -import * as _qjsOsImp from "os"; -// @ts-ignore -import * as _qjsStdImp from "std"; - -const textDecoder = new TextDecoder(); -const textEncoder = new TextEncoder(); +import { qjsOs } from "@gnu-taler/taler-util/qtart"; +import { + createNativeWalletHost2, + DefaultNodeWalletArgs, + openPromise, + Wallet, + WalletApiOperation, +} from "@gnu-taler/taler-wallet-core"; setGlobalLogLevelFromString("trace"); @@ -66,210 +48,19 @@ setPRNG(function (x: Uint8Array, n: number) { for (let i = 0; i < v.length; i++) v[i] = 0; }); -export interface QjsHttpResp { - status: number; - data: ArrayBuffer; -} - -export interface QjsHttpOptions { - method: string; - debug?: boolean; - data?: ArrayBuffer; - headers?: string[]; -} - -export interface QjsOsLib { - fetchHttp(url: string, options?: QjsHttpOptions): Promise; - postMessageToHost(s: string): void; - setMessageFromHostHandler(h: (s: string) => void): void; - rename(oldPath: string, newPath: string): number; -} - -export interface QjsStdLib { - writeFile(filename: string, contents: string): void; - loadFile(filename: string): string; -} - -// This is not the nodejs "os" module, but the qjs "os" module. -const qjsOs: QjsOsLib = _qjsOsImp as any; - -const qjsStd: QjsStdLib = _qjsStdImp as any; - const logger = new Logger("taler-wallet-embedded/index.ts"); -export class NativeHttpLib implements HttpRequestLibrary { - get( - url: string, - opt?: HttpRequestOptions | undefined, - ): Promise { - return this.fetch(url, { - method: "GET", - ...opt, - }); - } - postJson( - url: string, - body: any, - opt?: HttpRequestOptions | undefined, - ): Promise { - return this.fetch(url, { - method: "POST", - body, - ...opt, - }); - } - async fetch( - url: string, - opt?: HttpRequestOptions | undefined, - ): Promise { - const method = opt?.method ?? "GET"; - let data: ArrayBuffer | undefined = undefined; - let headers: string[] = []; - if (opt?.headers) { - for (let headerName of Object.keys(opt.headers)) { - headers.push(`${headerName}: ${opt.headers[headerName]}`); - } - } - if (method.toUpperCase() === "POST") { - if (opt?.body) { - if (typeof opt.body === "string") { - data = textEncoder.encode(opt.body).buffer; - } else if (ArrayBuffer.isView(opt.body)) { - data = opt.body.buffer; - } else if (opt.body instanceof ArrayBuffer) { - data = opt.body; - } else if (typeof opt.body === "object") { - data = textEncoder.encode(JSON.stringify(opt.body)).buffer; - } - } else { - data = new ArrayBuffer(0); - } - } - const res = await qjsOs.fetchHttp(url, { - method, - data, - headers, - }); - return { - requestMethod: method, - headers: new Headers(), - async bytes() { - return res.data; - }, - json() { - const text = textDecoder.decode(res.data); - return JSON.parse(text); - }, - async text() { - const text = textDecoder.decode(res.data); - return text; - }, - requestUrl: url, - status: res.status, - }; - } -} - function sendNativeMessage(ev: CoreApiMessageEnvelope): void { const m = JSON.stringify(ev); qjsOs.postMessageToHost(m); } -/** - * Generate a random alphanumeric ID. Does *not* use cryptographically - * secure randomness. - */ -function makeId(length: number): string { - let result = ""; - const characters = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; - for (let i = 0; i < length; i++) { - result += characters.charAt(Math.floor(Math.random() * characters.length)); - } - return result; -} - -export async function getWallet(args: DefaultNodeWalletArgs = {}): Promise<{ - wallet: Wallet; - getDbStats: () => AccessStats; -}> { - BridgeIDBFactory.enableTracing = false; - const myBackend = new MemoryBackend(); - myBackend.enableTracing = false; - - const storagePath = args.persistentStoragePath; - if (storagePath) { - const dbContentStr = qjsStd.loadFile(storagePath); - if (dbContentStr != null) { - const dbContent = JSON.parse(dbContentStr); - myBackend.importDump(dbContent); - } - - myBackend.afterCommitCallback = async () => { - logger.trace("committing database"); - // Allow caller to stop persisting the wallet. - if (args.persistentStoragePath === undefined) { - return; - } - const tmpPath = `${args.persistentStoragePath}-${makeId(5)}.tmp`; - const dbContent = myBackend.exportDump(); - qjsStd.writeFile(tmpPath, JSON.stringify(dbContent, undefined, 2)); - // Atomically move the temporary file onto the DB path. - const res = qjsOs.rename(tmpPath, args.persistentStoragePath); - if (res != 0) { - throw Error("db commit failed at rename"); - } - logger.trace("committing database done"); - }; - } - - console.log("done processing storage path"); - - BridgeIDBFactory.enableTracing = false; - - const myBridgeIdbFactory = new BridgeIDBFactory(myBackend); - const myIdbFactory: IDBFactory = myBridgeIdbFactory as any as IDBFactory; - - let myHttpLib; - if (args.httpLib) { - myHttpLib = args.httpLib; - } else { - myHttpLib = new NativeHttpLib(); - } - - const myVersionChange = (): Promise => { - logger.error("version change requested, should not happen"); - throw Error( - "BUG: wallet DB version change event can't happen with memory IDB", - ); - }; - - shimIndexedDB(myBridgeIdbFactory); - - const myDb = await openTalerDatabase(myIdbFactory, myVersionChange); - - let workerFactory; - workerFactory = new SynchronousCryptoWorkerFactoryPlain(); - - const timer = new SetTimeoutTimerAPI(); - - const w = await Wallet.create(myDb, myHttpLib, timer, workerFactory); - - if (args.notifyHandler) { - w.addNotificationListener(args.notifyHandler); - } - return { - wallet: w, - getDbStats: () => myBackend.accessStats, - }; -} - class NativeWalletMessageHandler { walletArgs: DefaultNodeWalletArgs | undefined; initRequest: InitRequest = {}; maybeWallet: Wallet | undefined; wp = openPromise(); - httpLib = new NativeHttpLib(); + httpLib = createPlatformHttpLib(); /** * Handle a request from the native wallet. @@ -292,7 +83,7 @@ class NativeWalletMessageHandler { const reinit = async () => { logger.info("in reinit"); - const wR = await getWallet(this.walletArgs); + const wR = await createNativeWalletHost2(this.walletArgs); const w = wR.wallet; this.maybeWallet = w; const resp = await w.handleCoreApiRequest("initWallet", "native-init", { @@ -422,7 +213,7 @@ globalThis.installNativeWalletListener = installNativeWalletListener; globalThis.makeWallet = getWallet; export async function testWithGv() { - const w = await getWallet(); + const w = await createNativeWalletHost2(); await w.wallet.client.call(WalletApiOperation.InitWallet, {}); await w.wallet.client.call(WalletApiOperation.RunIntegrationTest, { amountToSpend: "KUDOS:1", @@ -438,7 +229,7 @@ export async function testWithGv() { export async function testWithLocal() { console.log("running local test"); - const w = await getWallet({ + const w = await createNativeWalletHost2({ persistentStoragePath: "walletdb.json", }); console.log("created wallet"); -- cgit v1.2.3