From f26cbe7c1f10d2d6430c9f444342180d1445ed33 Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Tue, 3 Jan 2023 10:51:05 +0100 Subject: -qjs fixes --- packages/taler-wallet-embedded/build.mjs | 2 +- packages/taler-wallet-embedded/src/wallet-qjs.ts | 106 +++++++++++++---------- 2 files changed, 60 insertions(+), 48 deletions(-) (limited to 'packages/taler-wallet-embedded') diff --git a/packages/taler-wallet-embedded/build.mjs b/packages/taler-wallet-embedded/build.mjs index 0f12ef2c6..537a4fbc0 100755 --- a/packages/taler-wallet-embedded/build.mjs +++ b/packages/taler-wallet-embedded/build.mjs @@ -51,7 +51,7 @@ export const buildConfig = { target: [ 'es2020' ], - external: ["os"], + external: ["os", "std"], format: 'esm', platform: 'neutral', mainFields: ["module", "main"], diff --git a/packages/taler-wallet-embedded/src/wallet-qjs.ts b/packages/taler-wallet-embedded/src/wallet-qjs.ts index a9c314c6d..4c39e6188 100644 --- a/packages/taler-wallet-embedded/src/wallet-qjs.ts +++ b/packages/taler-wallet-embedded/src/wallet-qjs.ts @@ -21,8 +21,6 @@ import { AccessStats, DefaultNodeWalletArgs, getErrorDetailFromException, - handleWorkerError, - handleWorkerMessage, Headers, HttpRequestLibrary, HttpRequestOptions, @@ -51,6 +49,8 @@ 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(); @@ -80,12 +80,20 @@ export interface QjsHttpOptions { export interface QjsOsLib { // Not async! fetchHttp(url: string, options?: QjsHttpOptions): QjsHttpResp; + 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; -export { handleWorkerError, handleWorkerMessage }; +const qjsStd: QjsStdLib = _qjsStdImp as any; const logger = new Logger("taler-wallet-embedded/index.ts"); @@ -163,17 +171,22 @@ export class NativeHttpLib implements HttpRequestLibrary { } function sendNativeMessage(ev: CoreApiEnvelope): void { - // @ts-ignore - const sendMessage = globalThis.__native_sendMessage; - if (typeof sendMessage !== "function") { - const errMsg = - "FATAL: cannot install native wallet listener: native functions missing"; - logger.error(errMsg); - throw new Error(errMsg); - } const m = JSON.stringify(ev); - // @ts-ignore - sendMessage(m); + 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<{ @@ -186,40 +199,32 @@ export async function getWallet(args: DefaultNodeWalletArgs = {}): Promise<{ const storagePath = args.persistentStoragePath; if (storagePath) { - // try { - // const dbContentStr: string = fs.readFileSync(storagePath, { - // encoding: "utf-8", - // }); - // const dbContent = JSON.parse(dbContentStr); - // myBackend.importDump(dbContent); - // } catch (e: any) { - // const code: string = e.code; - // if (code === "ENOENT") { - // logger.trace("wallet file doesn't exist yet"); - // } else { - // logger.error("could not open wallet database file"); - // throw e; - // } - // } + const dbContentStr = qjsStd.loadFile(storagePath); + if (dbContentStr != null) { + const dbContent = JSON.parse(dbContentStr); + myBackend.importDump(dbContent); + } myBackend.afterCommitCallback = async () => { - logger.error("DB commit not implemented"); - // 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(); - // fs.writeFileSync(tmpPath, JSON.stringify(dbContent, undefined, 2), { - // encoding: "utf-8", - // }); - // // Atomically move the temporary file onto the DB path. - // fs.renameSync(tmpPath, args.persistentStoragePath); - // logger.trace("committing database done"); + 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); @@ -292,7 +297,7 @@ class NativeWalletMessageHandler { const resp = await w.handleCoreApiRequest( "initWallet", "native-init", - {}, + {...this.walletArgs}, ); initResponse = resp.type == "response" ? resp.result : resp.error; w.runTaskLoop().catch((e) => { @@ -306,6 +311,7 @@ class NativeWalletMessageHandler { switch (operation) { case "init": { this.walletArgs = { + ...args, notifyHandler: async (notification: WalletNotification) => { sendNativeMessage({ type: "notification", payload: notification }); }, @@ -378,7 +384,7 @@ export function installNativeWalletListener(): void { logger.info(`native listener: got request for ${operation} (${id})`); try { - const respMsg = await handler.handleMessage(operation, id, msg.args); + const respMsg = await handler.handleMessage(operation, id, msg.payload ?? {}); logger.info( `native listener: sending success response for ${operation} (${id})`, ); @@ -395,8 +401,7 @@ export function installNativeWalletListener(): void { } }; - // @ts-ignore - globalThis.__native_onMessage = onMessage; + qjsOs.setMessageFromHostHandler((m) => onMessage(m)) logger.info("native wallet listener installed"); } @@ -423,10 +428,15 @@ export async function testWithGv() { } export async function testWithLocal() { - const w = await getWallet(); + console.log("running local test"); + const w = await getWallet({ + persistentStoragePath: "walletdb.json", + }); + console.log("created wallet"); await w.wallet.client.call(WalletApiOperation.InitWallet, { skipDefaults: true, }); + console.log("initialized wallet"); await w.wallet.client.call(WalletApiOperation.RunIntegrationTest, { amountToSpend: "TESTKUDOS:1", amountToWithdraw: "TESTKUDOS:3", @@ -435,9 +445,11 @@ export async function testWithLocal() { exchangeBaseUrl: "http://localhost:8081/", merchantBaseUrl: "http://localhost:8083/", }); + console.log("started integration test"); await w.wallet.runTaskLoop({ stopWhenDone: true, }); + console.log("done with task loop"); w.wallet.stop(); } -- cgit v1.2.3