use factory instead of startWorker

This commit is contained in:
Florian Dold 2019-08-15 19:10:23 +02:00
parent 05e32fd855
commit 61bc36b90a
No known key found for this signature in database
GPG Key ID: D2E4F00F29D02A4B
6 changed files with 83 additions and 65 deletions

View File

@ -24,7 +24,7 @@ import {
ReserveRecord,
} from "../dbTypes";
import { CryptoApi } from "./cryptoApi";
import { CryptoApi, NodeCryptoWorkerFactory } from "./cryptoApi";
const masterPub1: string =
"CQQZ9DY3MZ1ARMN5K1VKDETS04Y2QCKMMCFHZSWJWWVN82BTTH00";
@ -73,7 +73,7 @@ const denomInvalid1 = JSON.parse(JSON.stringify(denomValid1));
denomInvalid1.value.value += 1;
test("string hashing", async t => {
const crypto = new CryptoApi();
const crypto = new CryptoApi(new NodeCryptoWorkerFactory());
const s = await crypto.hashString("hello taler");
const sh =
"8RDMADB3YNF3QZBS3V467YZVJAMC2QAQX0TZGVZ6Q5PFRRAJFT70HHN0QF661QR9QWKYMMC7YEMPD679D2RADXCYK8Y669A2A5MKQFR";
@ -82,7 +82,7 @@ test("string hashing", async t => {
});
test("precoin creation", async t => {
const crypto = new CryptoApi();
const crypto = new CryptoApi(new NodeCryptoWorkerFactory());
const { priv, pub } = await crypto.createEddsaKeypair();
const r: ReserveRecord = {
created: 0,
@ -103,7 +103,7 @@ test("precoin creation", async t => {
});
test("denom validation", async t => {
const crypto = new CryptoApi();
const crypto = new CryptoApi(new NodeCryptoWorkerFactory());
let v: boolean;
v = await crypto.isValidDenom(denomValid1, masterPub1);
t.true(v);

View File

@ -39,9 +39,7 @@ import { ContractTerms, PaybackRequest } from "../talerTypes";
import { BenchmarkResult, CoinWithDenom, PayCoinInfo } from "../walletTypes";
import * as timer from "../timer";
import { startWorker } from "./startWorker";
import { throws } from "assert";
import { string } from "prop-types";
/**
* State of a crypto worker.
@ -50,7 +48,7 @@ interface WorkerState {
/**
* The actual worker thread.
*/
w: Worker | null;
w: CryptoWorker | null;
/**
* Work we're currently executing or null if not busy.
@ -86,6 +84,67 @@ 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.
*/
startWorker(): CryptoWorker;
/**
* Query the number of workers that should be
* run at the same time.
*/
getConcurrency(): number
}
export class NodeCryptoWorkerFactory implements CryptoWorkerFactory {
startWorker(): CryptoWorker {
if (typeof require === "undefined") {
throw Error("cannot make worker, require(...) not defined");
}
const workerCtor = require("./nodeWorker").Worker;
const workerPath = __dirname + "/cryptoWorker.js";
return new workerCtor(workerPath);
}
getConcurrency(): number {
return 2;
}
}
export class BrowserCryptoWorkerFactory implements CryptoWorkerFactory {
startWorker(): CryptoWorker {
const workerCtor = Worker;
const workerPath = "/dist/cryptoWorker-bundle.js";
return new workerCtor(workerPath) as CryptoWorker;
}
getConcurrency(): number {
let concurrency = 2;
try {
// only works in the browser
// tslint:disable-next-line:no-string-literal
concurrency = (navigator as any)["hardwareConcurrency"];
concurrency = Math.max(1, Math.ceil(concurrency / 2));
} catch (e) {
concurrency = 2;
}
return concurrency;
}
}
/**
* Crypto API that interfaces manages a background crypto thread
* for the execution of expensive operations.
@ -94,6 +153,9 @@ export class CryptoApi {
private nextRpcId: number = 1;
private workers: WorkerState[];
private workQueues: WorkItem[][];
private workerFactory: CryptoWorkerFactory;
/**
* Number of busy workers.
*/
@ -106,6 +168,7 @@ export class CryptoApi {
public enableTracing = false;
/**
* Terminate all worker threads.
*/
@ -146,7 +209,7 @@ export class CryptoApi {
ws.currentWorkItem = work;
this.numBusy++;
if (!ws.w) {
const w = startWorker();
const w = this.workerFactory.startWorker();
w.onmessage = (m: MessageEvent) => this.handleWorkerMessage(ws, m);
w.onerror = (e: ErrorEvent) => this.handleWorkerError(ws, e);
ws.w = w;
@ -239,17 +302,9 @@ export class CryptoApi {
currentWorkItem.resolve(msg.data.result);
}
constructor() {
let concurrency = 2;
try {
// only works in the browser
// tslint:disable-next-line:no-string-literal
concurrency = (navigator as any)["hardwareConcurrency"];
concurrency = Math.max(1, Math.ceil(concurrency / 2));
} catch (e) {
// ignore
}
this.workers = new Array<WorkerState>(concurrency);
constructor(workerFactory: CryptoWorkerFactory) {
this.workerFactory = workerFactory;
this.workers = new Array<WorkerState>(workerFactory.getConcurrency());
for (let i = 0; i < this.workers.length; i++) {
this.workers[i] = {
@ -258,6 +313,7 @@ export class CryptoApi {
w: null,
};
}
this.workQueues = [];
for (let i = 0; i < NUM_PRIO; i++) {
this.workQueues.push([]);

View File

@ -1,41 +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
/**
* Start a crypto worker, using different worker
* mechanisms depending on the environment.
*
* @returns {Worker}
*/
export function startWorker() {
let workerCtor;
let workerPath;
if (typeof Worker !== "undefined") {
// we're in the browser
workerCtor = Worker;
workerPath = "/dist/cryptoWorker-bundle.js";
} else if (typeof "require" !== "undefined") {
workerCtor = require("./nodeWorker").Worker;
workerPath = __dirname + "/cryptoWorker.js";
} else {
throw Error("Can't create worker, unknown environment");
}
return new workerCtor(workerPath);
}

View File

@ -26,6 +26,7 @@ import URI = require("urijs");
import querystring = require("querystring");
import { CheckPaymentResponse } from "../talerTypes";
import { NodeCryptoWorkerFactory } from "../crypto/cryptoApi";
const enableTracing = false;
@ -268,7 +269,7 @@ export async function main() {
myUnsupportedUpgrade,
);
const myWallet = new Wallet(myDb, myHttpLib, myBadge, myNotifier);
const myWallet = new Wallet(myDb, myHttpLib, myBadge, myNotifier, new NodeCryptoWorkerFactory());
const reserveResponse = await myWallet.createReserve({
amount: amounts.parseOrThrow("TESTKUDOS:10.0"),

View File

@ -22,7 +22,7 @@
/**
* Imports.
*/
import { CryptoApi } from "./crypto/cryptoApi";
import { CryptoApi, CryptoWorkerFactory } from "./crypto/cryptoApi";
import {
amountToPretty,
canonicalJson,
@ -360,12 +360,13 @@ export class Wallet {
http: HttpRequestLibrary,
badge: Badge,
notifier: Notifier,
cryptoWorkerFactory: CryptoWorkerFactory,
) {
this.db = db;
this.http = http;
this.badge = badge;
this.notifier = notifier;
this.cryptoApi = new CryptoApi();
this.cryptoApi = new CryptoApi(cryptoWorkerFactory);
this.timerGroup = new TimerGroup();
const init = async () => {

View File

@ -58,6 +58,7 @@ import URI = require("urijs");
import Port = chrome.runtime.Port;
import MessageSender = chrome.runtime.MessageSender;
import { TipToken } from "../talerTypes";
import { BrowserCryptoWorkerFactory } from "../crypto/cryptoApi";
const NeedsWallet = Symbol("NeedsWallet");
@ -711,7 +712,7 @@ async function reinitWallet() {
const http = new BrowserHttpLib();
const notifier = new ChromeNotifier();
console.log("setting wallet");
const wallet = new Wallet(db, http, badge, notifier);
const wallet = new Wallet(db, http, badge, notifier, new BrowserCryptoWorkerFactory());
// Useful for debugging in the background page.
(window as any).talerWallet = wallet;
currentWallet = wallet;