diff options
Diffstat (limited to 'packages/taler-wallet-embedded')
| -rwxr-xr-x | packages/taler-wallet-embedded/build.mjs | 2 | ||||
| -rw-r--r-- | packages/taler-wallet-embedded/src/wallet-qjs.ts | 106 | 
2 files changed, 60 insertions, 48 deletions
| 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();  } | 
