gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[GNUnet-SVN] [taler-wallet-webex] branch master updated (ea2fb677 -> a1e


From: gnunet
Subject: [GNUnet-SVN] [taler-wallet-webex] branch master updated (ea2fb677 -> a1e0fc3b)
Date: Fri, 16 Aug 2019 15:04:01 +0200

This is an automated email from the git hooks/post-receive script.

dold pushed a change to branch master
in repository wallet-webex.

    from ea2fb677 worker refactoring / sync worker
     new 0cab39f2 load wasm manually from correct location
     new cc4eeec0 oops, actually pass arguments to emscripten
     new 0049a240 emscripten env consistency
     new 8f5b6ffd load wasm binary for akono
     new a1e0fc3b crypto worker refactoring

The 5 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 package.json                       |   2 +-
 src/crypto/browserWorkerEntry.ts   | 120 +++++++++++++++++++++++++++++++++++++
 src/crypto/cryptoApi-test.ts       |   3 +-
 src/crypto/cryptoApi.ts            |  44 +-------------
 src/crypto/cryptoWorker.ts         |  81 ++-----------------------
 src/crypto/emscInterface-test.ts   |  35 ++++++-----
 src/crypto/emscInterface.ts        |  49 ++++++++++++++-
 src/crypto/emscLoader.d.ts         |  64 --------------------
 src/crypto/emscLoader.js           | 117 ------------------------------------
 src/crypto/nodeEmscriptenLoader.ts | 102 +++++++++++++++++++++++++++++++
 src/crypto/nodeProcessWorker.ts    |  64 +++++++++++++-------
 src/crypto/nodeWorkerEntry.ts      | 105 ++++++++++++++++----------------
 src/crypto/synchronousWorker.ts    |  88 ++++++++++-----------------
 src/headless/taler-wallet-cli.ts   |   2 +-
 tsconfig.json                      |   4 +-
 webpack.config.js                  |   5 +-
 16 files changed, 430 insertions(+), 455 deletions(-)
 create mode 100644 src/crypto/browserWorkerEntry.ts
 delete mode 100644 src/crypto/emscLoader.d.ts
 delete mode 100644 src/crypto/emscLoader.js
 create mode 100644 src/crypto/nodeEmscriptenLoader.ts

diff --git a/package.json b/package.json
index d72316e7..6c844817 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "taler-wallet",
-  "version": "0.0.2",
+  "version": "0.0.6",
   "description": "",
   "main": "dist/node/index.js",
   "repository": {
diff --git a/src/crypto/browserWorkerEntry.ts b/src/crypto/browserWorkerEntry.ts
new file mode 100644
index 00000000..3df59fe0
--- /dev/null
+++ b/src/crypto/browserWorkerEntry.ts
@@ -0,0 +1,120 @@
+/*
+ This file is part of TALER
+ (C) 2016 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+
+/**
+ * Web worker for crypto operations.
+ */
+
+/**
+ * Imports.
+ */
+
+import { CryptoImplementation } from "./cryptoImplementation";
+import { EmscEnvironment } from "./emscInterface";
+
+const worker: Worker = (self as any) as Worker;
+
+class BrowserEmscriptenLoader {
+  private cachedEmscEnvironment: EmscEnvironment | undefined = undefined;
+  private cachedEmscEnvironmentPromise:
+    | Promise<EmscEnvironment>
+    | undefined = undefined;
+
+  async getEmscriptenEnvironment(): Promise<EmscEnvironment> {
+
+    if (this.cachedEmscEnvironment) {
+      return this.cachedEmscEnvironment;
+    }
+
+    if (this.cachedEmscEnvironmentPromise) {
+      return this.cachedEmscEnvironmentPromise;
+    }
+
+    console.log("loading emscripten lib with 'importScripts'");
+    // @ts-ignore
+    self.TalerEmscriptenLib = {};
+    // @ts-ignore
+    importScripts('/emscripten/taler-emscripten-lib.js')
+    // @ts-ignore
+    if (!self.TalerEmscriptenLib) {
+      throw Error("can't import taler emscripten lib");
+    }
+    const locateFile = (path: string, scriptDir: string) => {
+      console.log("locating file", "path", path, "scriptDir", scriptDir);
+      // This is quite hacky and assumes that our scriptDir is dist/
+      return scriptDir + "../emscripten/" + path;
+    };
+    console.log("instantiating TalerEmscriptenLib");
+    // @ts-ignore
+    const lib = self.TalerEmscriptenLib({ locateFile });
+    return new Promise((resolve, reject) => {
+      lib.then((mod: any) => {
+        this.cachedEmscEnvironmentPromise = undefined;
+        const emsc = new EmscEnvironment(mod);
+        this.cachedEmscEnvironment = new EmscEnvironment(mod);
+        console.log("emscripten module fully loaded");
+        resolve(emsc);
+      });
+    });
+  }
+}
+
+let loader = new BrowserEmscriptenLoader();
+
+async function handleRequest(operation: string, id: number, args: string[]) {
+  let emsc = await loader.getEmscriptenEnvironment();
+
+  const impl = new CryptoImplementation(emsc);
+
+  if (!(operation in impl)) {
+    console.error(`crypto operation '${operation}' not found`);
+    return;
+  }
+
+  try {
+    const result = (impl as any)[operation](...args);
+    worker.postMessage({ result, id });
+  } catch (e) {
+    console.log("error during operation", e);
+    return;
+  }
+}
+
+worker.onmessage = (msg: MessageEvent) => {
+  const args = msg.data.args;
+  if (!Array.isArray(args)) {
+    console.error("args must be array");
+    return;
+  }
+  const id = msg.data.id;
+  if (typeof id !== "number") {
+    console.error("RPC id must be number");
+    return;
+  }
+  const operation = msg.data.operation;
+  if (typeof operation !== "string") {
+    console.error("RPC operation must be string");
+    return;
+  }
+
+  if (CryptoImplementation.enableTracing) {
+    console.log("onmessage with", operation);
+  }
+
+  handleRequest(operation, id, args).catch((e) => {
+    console.error("error in browsere worker", e);
+  });
+};
diff --git a/src/crypto/cryptoApi-test.ts b/src/crypto/cryptoApi-test.ts
index 9c592412..48231e5f 100644
--- a/src/crypto/cryptoApi-test.ts
+++ b/src/crypto/cryptoApi-test.ts
@@ -24,7 +24,8 @@ import {
   ReserveRecord,
 } from "../dbTypes";
 
-import { CryptoApi, NodeCryptoWorkerFactory } from "./cryptoApi";
+import { CryptoApi } from "./cryptoApi";
+import { NodeCryptoWorkerFactory } from "./nodeProcessWorker";
 
 const masterPub1: string =
   "CQQZ9DY3MZ1ARMN5K1VKDETS04Y2QCKMMCFHZSWJWWVN82BTTH00";
diff --git a/src/crypto/cryptoApi.ts b/src/crypto/cryptoApi.ts
index c68b1070..a4e12c00 100644
--- a/src/crypto/cryptoApi.ts
+++ b/src/crypto/cryptoApi.ts
@@ -34,6 +34,8 @@ import {
   WireFee,
 } from "../dbTypes";
 
+import { CryptoWorker } from "./cryptoWorker";
+
 import { ContractTerms, PaybackRequest } from "../talerTypes";
 
 import { BenchmarkResult, CoinWithDenom, PayCoinInfo } from "../walletTypes";
@@ -83,15 +85,6 @@ interface WorkItem {
  */
 const NUM_PRIO = 5;
 
-interface CryptoWorker {
-  postMessage(message: any): void;
-
-  terminate(): void;
-
-  onmessage: (m: any) => void;
-  onerror: (m: any) => void;
-}
-
 export interface CryptoWorkerFactory {
   /**
    * Start a new worker.
@@ -105,21 +98,6 @@ export interface CryptoWorkerFactory {
   getConcurrency(): number;
 }
 
-export class NodeCryptoWorkerFactory implements CryptoWorkerFactory {
-  startWorker(): CryptoWorker {
-    if (typeof require === "undefined") {
-      throw Error("cannot make worker, require(...) not defined");
-    }
-    const workerCtor = require("./nodeProcessWorker").Worker;
-    const workerPath = __dirname + "/cryptoWorker.js";
-    return new workerCtor(workerPath);
-  }
-
-  getConcurrency(): number {
-    return 2;
-  }
-}
-
 export class BrowserCryptoWorkerFactory implements CryptoWorkerFactory {
   startWorker(): CryptoWorker {
     const workerCtor = Worker;
@@ -142,24 +120,6 @@ export class BrowserCryptoWorkerFactory implements 
CryptoWorkerFactory {
 }
 
 /**
- * The synchronous crypto worker produced by this factory doesn't run in the
- * background, but actually blocks the caller until the operation is done.
- */
-export class SynchronousCryptoWorkerFactory implements CryptoWorkerFactory {
-  startWorker(): CryptoWorker {
-    if (typeof require === "undefined") {
-      throw Error("cannot make worker, require(...) not defined");
-    }
-    const workerCtor = require("./synchronousWorker").SynchronousCryptoWorker;
-    return new workerCtor();
-  }
-
-  getConcurrency(): number {
-    return 1;
-  }
-}
-
-/**
  * Crypto API that interfaces manages a background crypto thread
  * for the execution of expensive operations.
  */
diff --git a/src/crypto/cryptoWorker.ts b/src/crypto/cryptoWorker.ts
index 11e3d964..0ea641dd 100644
--- a/src/crypto/cryptoWorker.ts
+++ b/src/crypto/cryptoWorker.ts
@@ -1,77 +1,8 @@
-/*
- This file is part of TALER
- (C) 2016 GNUnet e.V.
+export interface CryptoWorker {
+  postMessage(message: any): void;
 
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
+  terminate(): void;
 
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
- */
-
-/**
- * Web worker for crypto operations.
- */
-
-/**
- * Imports.
- */
-
-import * as emscLoader from "./emscLoader";
-
-import { CryptoImplementation } from "./cryptoImplementation";
-import { EmscEnvironment } from "./emscInterface";
-
-const worker: Worker = (self as any) as Worker;
-
-let impl: CryptoImplementation | undefined;
-
-
-worker.onmessage = (msg: MessageEvent) => {
-  const args = msg.data.args;
-  if (!Array.isArray(args)) {
-    console.error("args must be array");
-    return;
-  }
-  const id = msg.data.id;
-  if (typeof id !== "number") {
-    console.error("RPC id must be number");
-    return;
-  }
-  const operation = msg.data.operation;
-  if (typeof operation !== "string") {
-    console.error("RPC operation must be string");
-    return;
-  }
-
-  if (CryptoImplementation.enableTracing) {
-    console.log("onmessage with", operation);
-  }
-
-  emscLoader.getLib().then(p => {
-    const lib = p.lib;
-    const emsc = new EmscEnvironment(lib);
-    const impl = new CryptoImplementation(emsc);
-
-    if (!(operation in impl)) {
-      console.error(`unknown operation: '${operation}'`);
-      return;
-    }
-
-    if (CryptoImplementation.enableTracing) {
-      console.log("about to execute", operation);
-    }
-
-    const result = (impl as any)[operation](...args);
-
-    if (CryptoImplementation.enableTracing) {
-      console.log("finished executing", operation);
-    }
-    worker.postMessage({ result, id });
-  });
-};
+  onmessage: (m: any) => void;
+  onerror: (m: any) => void;
+}
\ No newline at end of file
diff --git a/src/crypto/emscInterface-test.ts b/src/crypto/emscInterface-test.ts
index 51f2d58b..b1a45cbc 100644
--- a/src/crypto/emscInterface-test.ts
+++ b/src/crypto/emscInterface-test.ts
@@ -17,13 +17,13 @@
 // tslint:disable:max-line-length
 
 import test from "ava";
-import * as emscLoader from "./emscLoader";
+import { NodeEmscriptenLoader } from "./nodeEmscriptenLoader";
 import * as native from "./emscInterface";
 
 
 test("string hashing", async (t) => {
-  const { lib } = await emscLoader.getLib();
-  const emsc = new native.EmscEnvironment(lib);
+  const loader =  new NodeEmscriptenLoader();
+  const emsc = await loader.getEmscriptenEnvironment();
 
   const x = native.ByteArray.fromStringWithNull(emsc, "hello taler");
   const h = 
"8RDMADB3YNF3QZBS3V467YZVJAMC2QAQX0TZGVZ6Q5PFRRAJFT70HHN0QF661QR9QWKYMMC7YEMPD679D2RADXCYK8Y669A2A5MKQFR";
@@ -35,8 +35,8 @@ test("string hashing", async (t) => {
 
 
 test("signing", async (t) => {
-  const { lib } = await emscLoader.getLib();
-  const emsc = new native.EmscEnvironment(lib);
+  const loader =  new NodeEmscriptenLoader();
+  const emsc = await loader.getEmscriptenEnvironment();
 
   const x = native.ByteArray.fromStringWithNull(emsc, "hello taler");
   const priv = native.EddsaPrivateKey.create(emsc, );
@@ -49,8 +49,8 @@ test("signing", async (t) => {
 
 
 test("signing-fixed-data", async (t) => {
-  const { lib } = await emscLoader.getLib();
-  const emsc = new native.EmscEnvironment(lib);
+  const loader =  new NodeEmscriptenLoader();
+  const emsc = await loader.getEmscriptenEnvironment();
 
   const x = native.ByteArray.fromStringWithNull(emsc, "hello taler");
   const purpose = new native.EccSignaturePurpose(emsc, 
native.SignaturePurpose.TEST, x);
@@ -74,8 +74,8 @@ const denomPubStr1 = 
"51R7ARKCD5HJTTV5F4G0M818E9SP280A40G2GVH04CR30G9R64VK6HHS6M
 
 
 test("rsa-encode", async (t) => {
-  const { lib } = await emscLoader.getLib();
-  const emsc = new native.EmscEnvironment(lib);
+  const loader =  new NodeEmscriptenLoader();
+  const emsc = await loader.getEmscriptenEnvironment();
 
   const pubHashStr = 
"JM63YM5X7X547164QJ3MGJZ4WDD47GEQR5DW5SH35G4JFZXEJBHE5JBNZM5K8XN5C4BRW25BE6GSVAYBF790G2BZZ13VW91D41S4DS0";
   const denomPub = native.RsaPublicKey.fromCrock(emsc, denomPubStr1);
@@ -86,8 +86,8 @@ test("rsa-encode", async (t) => {
 
 
 test("withdraw-request", async (t) => {
-  const { lib } = await emscLoader.getLib();
-  const emsc = new native.EmscEnvironment(lib);
+  const loader =  new NodeEmscriptenLoader();
+  const emsc = await loader.getEmscriptenEnvironment();
 
   const reservePrivStr = 
"G9R8KRRCAFKPD0KW7PW48CC2T03VQ8K2AN9J6J6K2YW27J5MHN90";
   const reservePriv = native.EddsaPrivateKey.fromCrock(emsc, reservePrivStr);
@@ -117,9 +117,8 @@ test("withdraw-request", async (t) => {
 
 
 test("currency-conversion", async (t) => {
-
-  const { lib } = await emscLoader.getLib();
-  const emsc = new native.EmscEnvironment(lib);
+  const loader =  new NodeEmscriptenLoader();
+  const emsc = await loader.getEmscriptenEnvironment();
 
   const a1 = new native.Amount(emsc, {currency: "KUDOS", value: 1, fraction: 
50000000});
   const a2 = new native.Amount(emsc, {currency: "KUDOS", value: 1, fraction: 
50000000});
@@ -133,8 +132,8 @@ test("currency-conversion", async (t) => {
 
 
 test("ecdsa", async (t) => {
-  const { lib } = await emscLoader.getLib();
-  const emsc = new native.EmscEnvironment(lib);
+  const loader =  new NodeEmscriptenLoader();
+  const emsc = await loader.getEmscriptenEnvironment();
 
   const priv = native.EcdsaPrivateKey.create(emsc);
   const pub1 = priv.getPublicKey();
@@ -145,8 +144,8 @@ test("ecdsa", async (t) => {
 
 
 test("ecdhe", async (t) => {
-  const { lib } = await emscLoader.getLib();
-  const emsc = new native.EmscEnvironment(lib);
+  const loader =  new NodeEmscriptenLoader();
+  const emsc = await loader.getEmscriptenEnvironment();
 
   const priv = native.EcdhePrivateKey.create(emsc);
   const pub = priv.getPublicKey();
diff --git a/src/crypto/emscInterface.ts b/src/crypto/emscInterface.ts
index 96e94e3f..0c7edefa 100644
--- a/src/crypto/emscInterface.ts
+++ b/src/crypto/emscInterface.ts
@@ -28,8 +28,6 @@
  */
 import { AmountJson } from "../amounts";
 
-import { EmscFunGen, EmscLib } from "./emscLoader";
-
 /**
  * Size of a native pointer.  Must match the size
  * use when compiling via emscripten.
@@ -38,6 +36,53 @@ const PTR_SIZE = 4;
 
 const GNUNET_OK = 1;
 
+
+/**
+ * Signature of the function that retrieves emscripten
+ * function implementations.
+ */
+export interface EmscFunGen {
+  (name: string,
+   ret: string,
+   args: string[]): ((...x: Array<number|string>) => any);
+  (name: string,
+   ret: "number",
+   args: string[]): ((...x: Array<number|string>) => number);
+  (name: string,
+   ret: "void",
+   args: string[]): ((...x: Array<number|string>) => void);
+  (name: string,
+   ret: "string",
+   args: string[]): ((...x: Array<number|string>) => string);
+}
+
+
+interface EmscLib {
+  cwrap: EmscFunGen;
+
+  ccall(name: string, ret: "number"|"string", argTypes: any[], args: any[]): 
any;
+
+  stringToUTF8(s: string, addr: number, maxLength: number): void;
+
+  onRuntimeInitialized(f: () => void): void;
+
+  readBinary?: (filename: string) => Promise<ArrayBuffer>;
+
+  calledRun?: boolean;
+
+  _free(ptr: number): void;
+
+  _malloc(n: number): number;
+
+  Pointer_stringify(p: number, len?: number): string;
+
+  getValue(ptr: number, type: string, noSafe?: boolean): number;
+
+  setValue(ptr: number, value: number, type: string, noSafe?: boolean): void;
+
+  writeStringToMemory(s: string, buffer: number, dontAddNull?: boolean): void;
+}
+
 interface EmscFunctions {
   amount_add(a1: number, a2: number, a3: number): number;
   amount_cmp(a1: number, a2: number): number;
diff --git a/src/crypto/emscLoader.d.ts b/src/crypto/emscLoader.d.ts
deleted file mode 100644
index 3ec4f4cf..00000000
--- a/src/crypto/emscLoader.d.ts
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- This file is part of TALER
- (C) 2016 GNUnet e.V.
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
- */
-
-
-declare function getLib(): Promise<{ lib: EmscLib }>;
-
-/**
- * Signature of the function that retrieves emscripten
- * function implementations.
- */
-export interface EmscFunGen {
-  (name: string,
-   ret: string,
-   args: string[]): ((...x: Array<number|string>) => any);
-  (name: string,
-   ret: "number",
-   args: string[]): ((...x: Array<number|string>) => number);
-  (name: string,
-   ret: "void",
-   args: string[]): ((...x: Array<number|string>) => void);
-  (name: string,
-   ret: "string",
-   args: string[]): ((...x: Array<number|string>) => string);
-}
-
-
-interface EmscLib {
-  cwrap: EmscFunGen;
-
-  ccall(name: string, ret: "number"|"string", argTypes: any[], args: any[]): 
any;
-
-  stringToUTF8(s: string, addr: number, maxLength: number): void;
-
-  onRuntimeInitialized(f: () => void): void;
-
-  readBinary?: (filename: string) => Promise<ArrayBuffer>;
-
-  calledRun?: boolean;
-
-  _free(ptr: number): void;
-
-  _malloc(n: number): number;
-
-  Pointer_stringify(p: number, len?: number): string;
-
-  getValue(ptr: number, type: string, noSafe?: boolean): number;
-
-  setValue(ptr: number, value: number, type: string, noSafe?: boolean): void;
-
-  writeStringToMemory(s: string, buffer: number, dontAddNull?: boolean): void;
-}
diff --git a/src/crypto/emscLoader.js b/src/crypto/emscLoader.js
deleted file mode 100644
index 25dc6b85..00000000
--- a/src/crypto/emscLoader.js
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- This file is part of TALER
- (C) 2017 Inria and GNUnet e.V.
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
- */
-
-
-// @ts-nocheck
-
-
-/**
- * This module loads the emscripten library, and is written in unchecked
- * JavaScript since it needs to do environment detection and dynamically select
- * the right way to load the library.
- */
-
-let cachedLib = undefined;
-let cachedLibPromise = undefined;
-
-export let enableTracing = false;
-
-/**
- * Load the taler emscripten lib.
- *
- * If in a WebWorker, importScripts is used.  Inside a browser, the module must
- * be globally available.  Inside node, require is used.
- * 
- * Returns a Promise<{ lib: EmscLib }>
- */
-export function getLib() {
-  enableTracing && console.log("in getLib");
-  if (cachedLib) {
-    enableTracing && console.log("lib is cached");
-    return Promise.resolve({ lib: cachedLib });
-  }
-  if (cachedLibPromise) {
-    return cachedLibPromise;
-  }
-  if (typeof require !== "undefined") {
-    enableTracing && console.log("trying to load emscripten lib with 
'require'");
-    // Make sure that TypeScript doesn't try
-    // to check the taler-emscripten-lib.
-    const indirectRequire = require;
-    const g = global;
-    // unavoidable hack, so that emscripten detects
-    // the environment as node even though importScripts
-    // is present.
-    const savedImportScripts = g.importScripts;
-    delete g.importScripts;
-    // Assume that the code is run from the build/ directory.
-    const libFn = 
indirectRequire("../../../emscripten/taler-emscripten-lib.js");
-    const lib = libFn();
-    g.importScripts = savedImportScripts;
-    if (lib) {
-      if (!lib.ccall) {
-        throw Error("sanity check failed: taler-emscripten lib does not have 
'ccall'");
-      }
-      cachedLibPromise = new Promise((resolve, reject) => {
-        lib.onRuntimeInitialized = () => {
-          cachedLib = lib;
-          cachedLibPromise = undefined;
-          resolve({ lib: cachedLib });
-        };
-      });
-      return cachedLibPromise;
-    } else {
-      // When we're running as a webpack bundle, the above require might
-      // have failed and returned 'undefined', so we try other ways to import.
-      console.log("failed to load emscripten lib with 'require', trying 
alternatives"); 
-    }
-  }
-
-  if (typeof importScripts !== "undefined") {
-    console.log("trying to load emscripten lib with 'importScripts'");
-    self.TalerEmscriptenLib = {};
-    importScripts('/emscripten/taler-emscripten-lib.js')
-    if (!self.TalerEmscriptenLib) {
-      throw Error("can't import taler emscripten lib");
-    }
-    const locateFile = (path, scriptDir) => {
-      console.log("locating file", "path", path, "scriptDir", scriptDir);
-      // This is quite hacky and assumes that our scriptDir is dist/
-      return scriptDir + "../emscripten/" + path;
-    };
-    console.log("instantiating TalerEmscriptenLib");
-    const lib = self.TalerEmscriptenLib({ locateFile });
-    cachedLib = lib;
-    return new Promise((resolve, reject) => {
-      lib.then(mod => {
-        console.log("emscripten module fully loaded");
-        resolve({ lib: mod });
-      });
-    });
-  }
-
-  // Last resort, we don't have require, we're not running in a webworker.
-  // Maybe we're on a normal browser page, in this case TalerEmscriptenLib
-  // must be included in a script tag on the page.
-
-  if (typeof window !== "undefined") {
-    if (window.TalerEmscriptenLib) {
-      return Promise.resolve(TalerEmscriptenLib);
-    }
-    throw Error("Looks like running in browser, but TalerEmscriptenLib is not 
defined");
-  }
-  throw Error("Running in unsupported environment");
-}
diff --git a/src/crypto/nodeEmscriptenLoader.ts 
b/src/crypto/nodeEmscriptenLoader.ts
new file mode 100644
index 00000000..6d6a7306
--- /dev/null
+++ b/src/crypto/nodeEmscriptenLoader.ts
@@ -0,0 +1,102 @@
+
+import { EmscEnvironment } from "./emscInterface";
+import { CryptoImplementation } from "./cryptoImplementation";
+
+import fs = require("fs");
+
+export class NodeEmscriptenLoader {
+  private cachedEmscEnvironment: EmscEnvironment | undefined = undefined;
+  private cachedEmscEnvironmentPromise:
+    | Promise<EmscEnvironment>
+    | undefined = undefined;
+
+    private async getWasmBinary(): Promise<Uint8Array> {
+      // @ts-ignore
+      const akonoGetData = global.__akono_getData;
+      if (akonoGetData) {
+        // We're running embedded node on Android
+        console.log("reading wasm binary from akono");
+        const data = akonoGetData("taler-emscripten-lib.wasm");
+        // The data we get is base64-encoded binary data
+        let buf = new Buffer(data, 'base64');
+        return new Uint8Array(buf);
+  
+      } else {
+        // We're in a normal node environment
+        const binaryPath = __dirname + 
"/../../../emscripten/taler-emscripten-lib.wasm";
+        console.log("reading from", binaryPath);
+        const wasmBinary = new Uint8Array(fs.readFileSync(binaryPath));
+        return wasmBinary;
+      }
+    }
+  
+    async getEmscriptenEnvironment(): Promise<EmscEnvironment> {
+      if (this.cachedEmscEnvironment) {
+        return this.cachedEmscEnvironment;
+      }
+  
+      if (this.cachedEmscEnvironmentPromise) {
+        return this.cachedEmscEnvironmentPromise;
+      }
+  
+      let lib: any;
+  
+      const wasmBinary = await this.getWasmBinary();
+  
+      return new Promise((resolve, reject) => {
+        // Arguments passed to the emscripten prelude
+        const libArgs = {
+          wasmBinary,
+          onRuntimeInitialized: () => {
+            if (!lib) {
+              console.error("fatal emscripten initialization error");
+              return;
+            }
+            this.cachedEmscEnvironmentPromise = undefined;
+            this.cachedEmscEnvironment = new EmscEnvironment(lib);
+            resolve(this.cachedEmscEnvironment);
+          },
+        };
+  
+        // Make sure that TypeScript doesn't try
+        // to check the taler-emscripten-lib.
+        const indirectRequire = require;
+  
+        const g = global;
+  
+        // unavoidable hack, so that emscripten detects
+        // the environment as node even though importScripts
+        // is present.
+  
+        // @ts-ignore
+        const savedImportScripts = g.importScripts;
+        // @ts-ignore
+        delete g.importScripts;
+        // @ts-ignore
+        const savedCrypto = g.crypto;
+        // @ts-ignore
+        delete g.crypto;
+  
+        // Assume that the code is run from the build/ directory.
+        const libFn = indirectRequire(
+          "../../../emscripten/taler-emscripten-lib.js",
+        );
+        lib = libFn(libArgs);
+  
+        // @ts-ignore
+        g.importScripts = savedImportScripts;
+        // @ts-ignore
+        g.crypto = savedCrypto;
+  
+        if (!lib) {
+          throw Error("could not load taler-emscripten-lib.js");
+        }
+  
+        if (!lib.ccall) {
+          throw Error(
+            "sanity check failed: taler-emscripten lib does not have 'ccall'",
+          );
+        }
+      });
+    }
+}
diff --git a/src/crypto/nodeProcessWorker.ts b/src/crypto/nodeProcessWorker.ts
index b5a2e8b4..c5d0f2e7 100644
--- a/src/crypto/nodeProcessWorker.ts
+++ b/src/crypto/nodeProcessWorker.ts
@@ -1,3 +1,5 @@
+import { CryptoWorkerFactory } from "./cryptoApi";
+
 /*
  This file is part of TALER
  (C) 2016 GNUnet e.V.
@@ -17,11 +19,29 @@
 
 // tslint:disable:no-var-requires
 
-const path = require("path");
-const fork = require("child_process").fork;
+import { CryptoWorker } from "./cryptoWorker";
+
+import path = require("path");
+import child_process = require("child_process");
 
 const nodeWorkerEntry = path.join(__dirname, "nodeWorkerEntry.js");
 
+
+export class NodeCryptoWorkerFactory implements CryptoWorkerFactory {
+  startWorker(): CryptoWorker {
+    if (typeof require === "undefined") {
+      throw Error("cannot make worker, require(...) not defined");
+    }
+    const workerCtor = require("./nodeProcessWorker").Worker;
+    const workerPath = __dirname + "/cryptoWorker.js";
+    return new workerCtor(workerPath);
+  }
+
+  getConcurrency(): number {
+    return 4;
+  }
+}
+
 /**
  * Worker implementation that uses node subprocesses.
  */
@@ -38,33 +58,35 @@ export class Worker {
    */
   onerror: undefined | ((m: any) => void);
 
-  constructor(scriptFilename: string) {
-    this.child = fork(nodeWorkerEntry);
+  private dispatchMessage(msg: any) {
+    if (this.onmessage) {
+      this.onmessage({ data: msg });
+    } else {
+      console.warn("no handler for worker event 'message' defined")
+    }
+  }
+
+  private dispatchError(msg: any) {
+    if (this.onerror) {
+      this.onerror({ data: msg });
+    } else {
+      console.warn("no handler for worker event 'error' defined")
+    }
+  }
+
+  constructor() {
+    this.child = child_process.fork(nodeWorkerEntry);
     this.onerror = undefined;
     this.onmessage = undefined;
 
     this.child.on("error", (e: any) => {
-      if (this.onerror) {
-        this.onerror(e);
-      }
+      this.dispatchError(e);
     });
 
     this.child.on("message", (msg: any) => {
-      const message = JSON.parse(msg);
-
-      if (!message.error && this.onmessage) {
-        this.onmessage(message);
-      }
-
-      if (message.error && this.onerror) {
-        const error = new Error(message.error);
-        error.stack = message.stack;
-
-        this.onerror(error);
-      }
+      console.log("nodeProcessWorker got child message", msg);
+      this.dispatchMessage(msg);
     });
-
-    this.child.send({scriptFilename, cwd: process.cwd()});
   }
 
   /**
diff --git a/src/crypto/nodeWorkerEntry.ts b/src/crypto/nodeWorkerEntry.ts
index 9e2647ff..1ed16f87 100644
--- a/src/crypto/nodeWorkerEntry.ts
+++ b/src/crypto/nodeWorkerEntry.ts
@@ -17,61 +17,64 @@
 
 // tslint:disable:no-var-requires
 
-const fs = require("fs");
-const vm = require("vm");
-
-process.once("message", (obj: any) => {
-  const g: any = global as any;
-
-  (g as any).self = {
-    addEventListener: (event: "error" | "message", fn: (x: any) => void) => {
-      if (event === "error") {
-        g.onerror = fn;
-      } else if (event === "message") {
-        g.onmessage = fn;
-      }
-    },
-    close: () => {
-      process.exit(0);
-    },
-    onerror: (err: any) => {
-      const str: string = JSON.stringify({error: err.message, stack: 
err.stack});
-      if (process.send) {
-        process.send(str);
-      }
-    },
-    onmessage: undefined,
-    postMessage: (msg: any) => {
-      const str: string = JSON.stringify({data: msg});
-      if (process.send) {
-        process.send(str);
-      }
-    },
-  };
-
-  g.__dirname = obj.cwd;
-  g.__filename = __filename;
-  g.importScripts = (...files: string[]) => {
-    if (files.length > 0) {
-      vm.createScript(files.map((file) => fs.readFileSync(file, 
"utf8")).join("\n")).runInThisContext();
-    }
-  };
+import fs = require("fs");
+import vm = require("vm");
+import { NodeEmscriptenLoader } from "./nodeEmscriptenLoader";
+import { CryptoImplementation } from "./cryptoImplementation";
 
-  Object.keys(g.self).forEach((key) => {
-    g[key] = g.self[key];
-  });
+const loader = new NodeEmscriptenLoader();
+
+async function handleRequest(operation: string, id: number, args: string[]) {
+  let emsc = await loader.getEmscriptenEnvironment();
 
-  process.on("message", (msg: any) => {
-    try {
-      (g.onmessage || g.self.onmessage || (() => undefined))(JSON.parse(msg));
-    } catch (err) {
-      (g.onerror || g.self.onerror || (() => undefined))(err);
+  const impl = new CryptoImplementation(emsc);
+
+  if (!(operation in impl)) {
+    console.error(`crypto operation '${operation}' not found`);
+    return;
+  }
+
+  try {
+    const result = (impl as any)[operation](...args);
+    if (process.send) {
+      process.send({ result, id });
+    } else {
+      console.error("process.send not available");
     }
-  });
+  } catch (e) {
+    console.log("error during operation", e);
+    return;
+  }
+}
 
-  process.on("uncaughtException", (err: any) => {
-    (g.onerror || g.self.onerror || (() => undefined))(err);
+process.on("message", (msgStr: any) => {
+  console.log("got message in node worker entry", msgStr);
+
+  console.log("typeof msg", typeof msgStr);
+
+  const msg = JSON.parse(msgStr);
+
+  const args = msg.data.args;
+  if (!Array.isArray(args)) {
+    console.error("args must be array");
+    return;
+  }
+  const id = msg.data.id;
+  if (typeof id !== "number") {
+    console.error("RPC id must be number");
+    return;
+  }
+  const operation = msg.data.operation;
+  if (typeof operation !== "string") {
+    console.error("RPC operation must be string");
+    return;
+  }
+
+  handleRequest(operation, id, args).catch((e) => {
+    console.error("error in node worker", e);
   });
+});
 
-  require(obj.scriptFilename);
+process.on("uncaughtException", (err: any) => {
+  console.log("uncaught exception in node worker entry", err);
 });
diff --git a/src/crypto/synchronousWorker.ts b/src/crypto/synchronousWorker.ts
index d8a3d83c..4369612a 100644
--- a/src/crypto/synchronousWorker.ts
+++ b/src/crypto/synchronousWorker.ts
@@ -14,15 +14,37 @@
  GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 
-import { EmscEnvironment } from "./emscInterface";
 import { CryptoImplementation } from "./cryptoImplementation";
 
+import { NodeEmscriptenLoader } from "./nodeEmscriptenLoader";
+
+import fs = require("fs");
+import { CryptoWorkerFactory } from "./cryptoApi";
+import { CryptoWorker } from "./cryptoWorker";
+
+/**
+ * The synchronous crypto worker produced by this factory doesn't run in the
+ * background, but actually blocks the caller until the operation is done.
+ */
+export class SynchronousCryptoWorkerFactory implements CryptoWorkerFactory {
+  startWorker(): CryptoWorker {
+    if (typeof require === "undefined") {
+      throw Error("cannot make worker, require(...) not defined");
+    }
+    const workerCtor = require("./synchronousWorker").SynchronousCryptoWorker;
+    return new workerCtor();
+  }
+
+  getConcurrency(): number {
+    return 1;
+  }
+}
+
+
 /**
  * Worker implementation that uses node subprocesses.
  */
 export class SynchronousCryptoWorker {
-  private cachedEmscEnvironment: EmscEnvironment | undefined = undefined;
-  private cachedEmscEnvironmentPromise: Promise<EmscEnvironment> | undefined = 
undefined;
 
   /**
    * Function to be called when we receive a message from the worker thread.
@@ -34,6 +56,8 @@ export class SynchronousCryptoWorker {
    */
   onerror: undefined | ((m: any) => void);
 
+  private emscriptenLoader = new NodeEmscriptenLoader();
+
   constructor() {
     this.onerror = undefined;
     this.onmessage = undefined;
@@ -53,58 +77,6 @@ export class SynchronousCryptoWorker {
     }
   }
 
-  private getEmscriptenEnvironment(): Promise<EmscEnvironment> {
-    if (this.cachedEmscEnvironment) {
-      return Promise.resolve(this.cachedEmscEnvironment);
-    }
-
-    if (this.cachedEmscEnvironmentPromise) {
-      return this.cachedEmscEnvironmentPromise;
-    }
-
-    // Make sure that TypeScript doesn't try
-    // to check the taler-emscripten-lib.
-    const indirectRequire = require;
-
-    const g = global;
-
-    // unavoidable hack, so that emscripten detects
-    // the environment as node even though importScripts
-    // is present.
-
-    // @ts-ignore
-    const savedImportScripts = g.importScripts;
-    // @ts-ignore
-    delete g.importScripts;
-
-    // Assume that the code is run from the build/ directory.
-    const libFn = indirectRequire(
-      "../../../emscripten/taler-emscripten-lib.js",
-    );
-    const lib = libFn();
-    // @ts-ignore
-    g.importScripts = savedImportScripts;
-
-    if (!lib) {
-      throw Error("could not load taler-emscripten-lib.js");
-    }
-
-    if (!lib.ccall) {
-      throw Error(
-        "sanity check failed: taler-emscripten lib does not have 'ccall'",
-      );
-    }
-
-    this.cachedEmscEnvironmentPromise = new Promise((resolve, reject) => {
-      lib.onRuntimeInitialized = () => {
-        this.cachedEmscEnvironmentPromise = undefined;
-        this.cachedEmscEnvironment = new EmscEnvironment(lib);
-        resolve(this.cachedEmscEnvironment);
-      };
-    });
-    return this.cachedEmscEnvironmentPromise;
-  }
-
   private dispatchMessage(msg: any) {
     if (this.onmessage) {
       this.onmessage({ data: msg });
@@ -112,7 +84,7 @@ export class SynchronousCryptoWorker {
   }
 
   private async handleRequest(operation: string, id: number, args: string[]) {
-    let emsc = await this.getEmscriptenEnvironment();
+    let emsc = await this.emscriptenLoader.getEmscriptenEnvironment();
 
     const impl = new CryptoImplementation(emsc);
 
@@ -150,7 +122,9 @@ export class SynchronousCryptoWorker {
       return;
     }
 
-    this.handleRequest(operation, id, args);
+    this.handleRequest(operation, id, args).catch(e => {
+      console.error("Error while handling crypto request:", e);
+    });
   }
 
   /**
diff --git a/src/headless/taler-wallet-cli.ts b/src/headless/taler-wallet-cli.ts
index 1e501cdc..49cc608d 100644
--- a/src/headless/taler-wallet-cli.ts
+++ b/src/headless/taler-wallet-cli.ts
@@ -26,7 +26,7 @@ import URI = require("urijs");
 
 import querystring = require("querystring");
 import { CheckPaymentResponse } from "../talerTypes";
-import { NodeCryptoWorkerFactory, SynchronousCryptoWorkerFactory } from 
"../crypto/cryptoApi";
+import { SynchronousCryptoWorkerFactory } from "../crypto/synchronousWorker";
 
 const enableTracing = false;
 
diff --git a/tsconfig.json b/tsconfig.json
index 8104054a..c833ef9a 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -27,14 +27,14 @@
     "decl/urijs.d.ts",
     "src/amounts.ts",
     "src/checkable.ts",
+    "src/crypto/browserWorkerEntry.ts",
     "src/crypto/cryptoApi-test.ts",
     "src/crypto/cryptoApi.ts",
     "src/crypto/cryptoImplementation.ts",
     "src/crypto/cryptoWorker.ts",
     "src/crypto/emscInterface-test.ts",
     "src/crypto/emscInterface.ts",
-    "src/crypto/emscLoader.d.ts",
-    "src/crypto/emscLoader.js",
+    "src/crypto/nodeEmscriptenLoader.ts",
     "src/crypto/nodeProcessWorker.ts",
     "src/crypto/nodeWorkerEntry.ts",
     "src/crypto/synchronousWorker.ts",
diff --git a/webpack.config.js b/webpack.config.js
index 845b56fe..55014618 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -27,8 +27,7 @@ module.exports = function (env) {
         {
           test: /\.tsx?$/,
           loader: 'awesome-typescript-loader',
-          exclude: /node_modules/,
-          exclude: /taler-emscripten-lib/,
+          exclude: 
/node_modules|taler-emscripten-lib|nodeEmscriptenLoader|synchronousWorker/,
         }
       ]
     },
@@ -58,7 +57,7 @@ module.exports = function (env) {
     }
   }
   const configWebWorker = {
-    entry: {"cryptoWorker": "./src/crypto/cryptoWorker.ts"},
+    entry: {"cryptoWorker": "./src/crypto/browserWorkerEntry.ts"},
     target: "webworker",
     name: "webworker",
   };

-- 
To stop receiving notification emails like this one, please contact
address@hidden.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]