make wallet-cli runnable under qtart

This commit is contained in:
Florian Dold 2023-02-15 23:32:42 +01:00
parent cb2f4c21d8
commit 825d2c4352
No known key found for this signature in database
GPG Key ID: D2E4F00F29D02A4B
81 changed files with 1069 additions and 1046 deletions

View File

@ -1,4 +1,4 @@
import { clk } from "@gnu-taler/taler-util"; import { clk } from "@gnu-taler/taler-util/clk";
import { import {
getBackupStartState, getBackupStartState,
getRecoveryStartState, getRecoveryStartState,

View File

@ -20,7 +20,7 @@
*/ */
import { expect } from "chai"; import { expect } from "chai";
import { AMOUNT_REGEX, PAYTO_REGEX } from "../../src/utils/constants.js"; import { AMOUNT_REGEX, PAYTO_REGEX } from "./constants.js";
describe("payto uri format", () => { describe("payto uri format", () => {
const valids = [ const valids = [

View File

@ -19,19 +19,19 @@
*/ */
import { import {
buildCodecForObject, buildCodecForObject,
codecForBoolean,
codecForNumber, codecForNumber,
codecForString, codecForString,
codecForBoolean,
codecOptional, codecOptional,
j2s, j2s,
Logger, Logger,
} from "@gnu-taler/taler-util"; } from "@gnu-taler/taler-util";
import { createPlatformHttpLib } from "@gnu-taler/taler-util/http";
import { import {
getDefaultNodeWallet2,
NodeHttpLib,
WalletApiOperation,
Wallet,
AccessStats, AccessStats,
createNativeWalletHost2,
Wallet,
WalletApiOperation,
} from "@gnu-taler/taler-wallet-core"; } from "@gnu-taler/taler-wallet-core";
/** /**
@ -46,8 +46,9 @@ export async function runBench1(configJson: any): Promise<void> {
// Validate the configuration file for this benchmark. // Validate the configuration file for this benchmark.
const b1conf = codecForBench1Config().decode(configJson); const b1conf = codecForBench1Config().decode(configJson);
const myHttpLib = new NodeHttpLib(); const myHttpLib = createPlatformHttpLib({
myHttpLib.setThrottling(false); enableThrottling: false,
});
const numIter = b1conf.iterations ?? 1; const numIter = b1conf.iterations ?? 1;
const numDeposits = b1conf.deposits ?? 5; const numDeposits = b1conf.deposits ?? 5;
@ -81,7 +82,7 @@ export async function runBench1(configJson: any): Promise<void> {
console.log("wallet DB stats", j2s(getDbStats!())); console.log("wallet DB stats", j2s(getDbStats!()));
} }
const res = await getDefaultNodeWallet2({ const res = await createNativeWalletHost2({
// No persistent DB storage. // No persistent DB storage.
persistentStoragePath: undefined, persistentStoragePath: undefined,
httpLib: myHttpLib, httpLib: myHttpLib,

View File

@ -24,6 +24,7 @@ import {
codecOptional, codecOptional,
Logger, Logger,
} from "@gnu-taler/taler-util"; } from "@gnu-taler/taler-util";
import { createPlatformHttpLib } from "@gnu-taler/taler-util/http";
import { import {
checkReserve, checkReserve,
createFakebankReserve, createFakebankReserve,
@ -31,9 +32,8 @@ import {
depositCoin, depositCoin,
downloadExchangeInfo, downloadExchangeInfo,
findDenomOrThrow, findDenomOrThrow,
NodeHttpLib,
refreshCoin, refreshCoin,
SynchronousCryptoWorkerFactoryNode, SynchronousCryptoWorkerFactoryPlain,
withdrawCoin, withdrawCoin,
} from "@gnu-taler/taler-wallet-core"; } from "@gnu-taler/taler-wallet-core";
@ -50,12 +50,13 @@ export async function runBench2(configJson: any): Promise<void> {
const benchConf = codecForBench2Config().decode(configJson); const benchConf = codecForBench2Config().decode(configJson);
const curr = benchConf.currency; const curr = benchConf.currency;
const cryptoDisp = new CryptoDispatcher( const cryptoDisp = new CryptoDispatcher(
new SynchronousCryptoWorkerFactoryNode(), new SynchronousCryptoWorkerFactoryPlain(),
); );
const cryptoApi = cryptoDisp.cryptoApi; const cryptoApi = cryptoDisp.cryptoApi;
const http = new NodeHttpLib(); const http = createPlatformHttpLib({
http.setThrottling(false); enableThrottling: false,
});
const numIter = benchConf.iterations ?? 1; const numIter = benchConf.iterations ?? 1;
const numDeposits = benchConf.deposits ?? 5; const numDeposits = benchConf.deposits ?? 5;

View File

@ -25,12 +25,12 @@ import {
j2s, j2s,
Logger, Logger,
} from "@gnu-taler/taler-util"; } from "@gnu-taler/taler-util";
import { createPlatformHttpLib } from "@gnu-taler/taler-util/http";
import { import {
getDefaultNodeWallet2,
NodeHttpLib,
WalletApiOperation,
Wallet,
AccessStats, AccessStats,
createNativeWalletHost2,
Wallet,
WalletApiOperation,
} from "@gnu-taler/taler-wallet-core"; } from "@gnu-taler/taler-wallet-core";
import benchMerchantIDGenerator from "./benchMerchantIDGenerator.js"; import benchMerchantIDGenerator from "./benchMerchantIDGenerator.js";
@ -50,8 +50,9 @@ export async function runBench3(configJson: any): Promise<void> {
throw new Error("Payto template url must contain '${id}' placeholder"); throw new Error("Payto template url must contain '${id}' placeholder");
} }
const myHttpLib = new NodeHttpLib(); const myHttpLib = createPlatformHttpLib({
myHttpLib.setThrottling(false); enableThrottling: false,
});
const numIter = b3conf.iterations ?? 1; const numIter = b3conf.iterations ?? 1;
const numDeposits = b3conf.deposits ?? 5; const numDeposits = b3conf.deposits ?? 5;
@ -89,7 +90,7 @@ export async function runBench3(configJson: any): Promise<void> {
console.log("wallet DB stats", j2s(getDbStats!())); console.log("wallet DB stats", j2s(getDbStats!()));
} }
const res = await getDefaultNodeWallet2({ const res = await createNativeWalletHost2({
// No persistent DB storage. // No persistent DB storage.
persistentStoragePath: undefined, persistentStoragePath: undefined,
httpLib: myHttpLib, httpLib: myHttpLib,

View File

@ -41,17 +41,15 @@ import {
MerchantTemplateAddDetails, MerchantTemplateAddDetails,
parsePaytoUri, parsePaytoUri,
stringToBytes, stringToBytes,
TalerError,
TalerProtocolDuration, TalerProtocolDuration,
WalletNotification, WalletNotification,
} from "@gnu-taler/taler-util"; } from "@gnu-taler/taler-util";
import { import {
BankAccessApi,
BankApi, BankApi,
BankServiceHandle, BankServiceHandle,
HarnessExchangeBankAccount, HarnessExchangeBankAccount,
NodeHttpLib,
openPromise, openPromise,
TalerError,
WalletCoreApiClient, WalletCoreApiClient,
} from "@gnu-taler/taler-wallet-core"; } from "@gnu-taler/taler-wallet-core";
import { deepStrictEqual } from "assert"; import { deepStrictEqual } from "assert";
@ -83,6 +81,7 @@ import {
RemoteWallet, RemoteWallet,
WalletNotificationWaiter, WalletNotificationWaiter,
} from "@gnu-taler/taler-wallet-core/remote"; } from "@gnu-taler/taler-wallet-core/remote";
import { createPlatformHttpLib } from "@gnu-taler/taler-util/http";
const logger = new Logger("harness.ts"); const logger = new Logger("harness.ts");
@ -507,7 +506,7 @@ class LibEuFinBankService extends BankServiceBase implements BankServiceHandle {
sandboxProc: ProcessWrapper | undefined; sandboxProc: ProcessWrapper | undefined;
nexusProc: ProcessWrapper | undefined; nexusProc: ProcessWrapper | undefined;
http = new NodeHttpLib(); http = createPlatformHttpLib();
static async create( static async create(
gc: GlobalTestState, gc: GlobalTestState,
@ -794,7 +793,7 @@ export class FakebankService
{ {
proc: ProcessWrapper | undefined; proc: ProcessWrapper | undefined;
http = new NodeHttpLib(); http = createPlatformHttpLib();
// We store "created" accounts during setup and // We store "created" accounts during setup and
// register them after startup. // register them after startup.

View File

@ -23,7 +23,6 @@ import os from "os";
import path from "path"; import path from "path";
import { import {
Amounts, Amounts,
clk,
Configuration, Configuration,
decodeCrock, decodeCrock,
Logger, Logger,
@ -38,6 +37,7 @@ import { GlobalTestState, runTestWithState } from "./harness/harness.js";
import { getTestInfo, runTests } from "./integrationtests/testrunner.js"; import { getTestInfo, runTests } from "./integrationtests/testrunner.js";
import { lintExchangeDeployment } from "./lint.js"; import { lintExchangeDeployment } from "./lint.js";
import { runEnvFull } from "./env-full.js"; import { runEnvFull } from "./env-full.js";
import { clk } from "@gnu-taler/taler-util/clk";
const logger = new Logger("taler-harness:index.ts"); const logger = new Logger("taler-harness:index.ts");
@ -74,6 +74,15 @@ const advancedCli = testingCli.subcommand("advancedArgs", "advanced", {
help: "Subcommands for advanced operations (only use if you know what you're doing!).", help: "Subcommands for advanced operations (only use if you know what you're doing!).",
}); });
advancedCli
.subcommand("decode", "decode", {
help: "Decode base32-crockford.",
})
.action((args) => {
const enc = fs.readFileSync(0, "utf8");
console.log(decodeCrock(enc.trim()));
});
advancedCli advancedCli
.subcommand("bench1", "bench1", { .subcommand("bench1", "bench1", {
help: "Run the 'bench1' benchmark", help: "Run the 'bench1' benchmark",
@ -272,7 +281,7 @@ testingCli
help: "Produce less output.", help: "Produce less output.",
}) })
.flag("noTimeout", ["--no-timeout"], { .flag("noTimeout", ["--no-timeout"], {
help: "Do not time out tests." help: "Do not time out tests.",
}) })
.action(async (args) => { .action(async (args) => {
await runTests({ await runTests({

View File

@ -24,22 +24,18 @@ import {
Duration, Duration,
durationFromSpec, durationFromSpec,
} from "@gnu-taler/taler-util"; } from "@gnu-taler/taler-util";
import { import { createPlatformHttpLib, readSuccessResponseJsonOrThrow } from "@gnu-taler/taler-util/http";
NodeHttpLib,
readSuccessResponseJsonOrThrow,
} from "@gnu-taler/taler-wallet-core";
import { makeNoFeeCoinConfig } from "../harness/denomStructures.js"; import { makeNoFeeCoinConfig } from "../harness/denomStructures.js";
import { import {
BankService, BankService,
ExchangeService, ExchangeService,
GlobalTestState, GlobalTestState,
MerchantPrivateApi,
MerchantService, MerchantService,
setupDb, setupDb,
WalletCli, WalletCli,
getPayto, getPayto,
} from "../harness/harness.js"; } from "../harness/harness.js";
import { startWithdrawViaBank, withdrawViaBank } from "../harness/helpers.js"; import { withdrawViaBank } from "../harness/helpers.js";
async function applyTimeTravel( async function applyTimeTravel(
timetravelDuration: Duration, timetravelDuration: Duration,
@ -69,7 +65,7 @@ async function applyTimeTravel(
} }
} }
const http = new NodeHttpLib(); const http = createPlatformHttpLib();
/** /**
* Basic time travel test. * Basic time travel test.

View File

@ -17,11 +17,14 @@
/** /**
* Imports. * Imports.
*/ */
import { Duration, j2s, NotificationType } from "@gnu-taler/taler-util"; import {
Duration,
j2s,
NotificationType,
} from "@gnu-taler/taler-util";
import { import {
BankAccessApi, BankAccessApi,
BankApi, BankApi,
NodeHttpLib,
WalletApiOperation, WalletApiOperation,
} from "@gnu-taler/taler-wallet-core"; } from "@gnu-taler/taler-wallet-core";
import { CoinConfig, defaultCoinConfig } from "../harness/denomStructures.js"; import { CoinConfig, defaultCoinConfig } from "../harness/denomStructures.js";
@ -37,6 +40,7 @@ import {
} from "../harness/harness.js"; } from "../harness/harness.js";
import { EnvOptions, SimpleTestEnvironmentNg } from "../harness/helpers.js"; import { EnvOptions, SimpleTestEnvironmentNg } from "../harness/helpers.js";
import * as http from "node:http"; import * as http from "node:http";
import { createPlatformHttpLib } from "@gnu-taler/taler-util/http";
export async function createKycTestkudosEnvironment( export async function createKycTestkudosEnvironment(
t: GlobalTestState, t: GlobalTestState,
@ -336,12 +340,12 @@ export async function runKycTest(t: GlobalTestState) {
// We now simulate the user interacting with the KYC service, // We now simulate the user interacting with the KYC service,
// which would usually done in the browser. // which would usually done in the browser.
const httpClient = new NodeHttpLib(); const httpLib = createPlatformHttpLib();
const kycServerResp = await httpClient.get(kycNotif.kycUrl); const kycServerResp = await httpLib.get(kycNotif.kycUrl);
const kycLoginResp = await kycServerResp.json(); const kycLoginResp = await kycServerResp.json();
console.log("kyc server resp:", j2s(kycLoginResp)); console.log("kyc server resp:", j2s(kycLoginResp));
const kycProofUrl = kycLoginResp.redirect_uri; const kycProofUrl = kycLoginResp.redirect_uri;
const proofHttpResp = await httpClient.get(kycProofUrl); const proofHttpResp = await httpLib.get(kycProofUrl);
console.log("proof resp status", proofHttpResp.status); console.log("proof resp status", proofHttpResp.status);
console.log("resp headers", proofHttpResp.headers.toJSON()); console.log("resp headers", proofHttpResp.headers.toJSON());

View File

@ -24,7 +24,8 @@ import {
encodeCrock, encodeCrock,
getRandomBytes, getRandomBytes,
} from "@gnu-taler/taler-util"; } from "@gnu-taler/taler-util";
import { NodeHttpLib, WalletApiOperation } from "@gnu-taler/taler-wallet-core"; import { createPlatformHttpLib } from "@gnu-taler/taler-util/http";
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
import { import {
BankService, BankService,
ExchangeService, ExchangeService,
@ -38,7 +39,7 @@ import {
withdrawViaBank, withdrawViaBank,
} from "../harness/helpers.js"; } from "../harness/helpers.js";
const httpLib = new NodeHttpLib(); const httpLib = createPlatformHttpLib();
interface Context { interface Context {
merchant: MerchantService; merchant: MerchantService;

View File

@ -24,8 +24,8 @@ import {
BankApi, BankApi,
BankAccessApi, BankAccessApi,
BankServiceHandle, BankServiceHandle,
NodeHttpLib,
} from "@gnu-taler/taler-wallet-core"; } from "@gnu-taler/taler-wallet-core";
import { createPlatformHttpLib } from "@gnu-taler/taler-util/http";
/** /**
* Run test for basic, bank-integrated withdrawal and payment. * Run test for basic, bank-integrated withdrawal and payment.
@ -35,7 +35,7 @@ export async function runPaymentDemoTest(t: GlobalTestState) {
let bankInterface: BankServiceHandle = { let bankInterface: BankServiceHandle = {
baseUrl: "https://bank.demo.taler.net/", baseUrl: "https://bank.demo.taler.net/",
bankAccessApiBaseUrl: "https://bank.demo.taler.net/", bankAccessApiBaseUrl: "https://bank.demo.taler.net/",
http: new NodeHttpLib(), http: createPlatformHttpLib(),
}; };
let user = await BankApi.createRandomBankUser(bankInterface); let user = await BankApi.createRandomBankUser(bankInterface);
let wop = await BankAccessApi.createWithdrawalOperation( let wop = await BankAccessApi.createWithdrawalOperation(

View File

@ -17,23 +17,10 @@
/** /**
* Imports. * Imports.
*/ */
import { j2s } from "@gnu-taler/taler-util";
import { import {
checkReserve,
CryptoDispatcher,
depositCoin,
downloadExchangeInfo,
findDenomOrThrow,
NodeHttpLib,
refreshCoin,
SynchronousCryptoWorkerFactoryNode,
TalerError,
topupReserveWithDemobank,
WalletApiOperation, WalletApiOperation,
withdrawCoin,
} from "@gnu-taler/taler-wallet-core"; } from "@gnu-taler/taler-wallet-core";
import { GlobalTestState, WalletCli } from "../harness/harness.js"; import { GlobalTestState, WalletCli } from "../harness/harness.js";
import { createSimpleTestkudosEnvironment } from "../harness/helpers.js";
/** /**
* Run test for the different crypto workers. * Run test for the different crypto workers.

View File

@ -17,17 +17,16 @@
/** /**
* Imports. * Imports.
*/ */
import { j2s } from "@gnu-taler/taler-util"; import { j2s, TalerError } from "@gnu-taler/taler-util";
import { createPlatformHttpLib } from "@gnu-taler/taler-util/http";
import { import {
checkReserve, checkReserve,
CryptoDispatcher, CryptoDispatcher,
depositCoin, depositCoin,
downloadExchangeInfo, downloadExchangeInfo,
findDenomOrThrow, findDenomOrThrow,
NodeHttpLib,
refreshCoin, refreshCoin,
SynchronousCryptoWorkerFactoryNode, SynchronousCryptoWorkerFactoryPlain,
TalerError,
topupReserveWithDemobank, topupReserveWithDemobank,
withdrawCoin, withdrawCoin,
} from "@gnu-taler/taler-wallet-core"; } from "@gnu-taler/taler-wallet-core";
@ -42,9 +41,9 @@ export async function runWalletDblessTest(t: GlobalTestState) {
const { bank, exchange } = await createSimpleTestkudosEnvironment(t); const { bank, exchange } = await createSimpleTestkudosEnvironment(t);
const http = new NodeHttpLib(); const http = createPlatformHttpLib();
const cryptiDisp = new CryptoDispatcher( const cryptiDisp = new CryptoDispatcher(
new SynchronousCryptoWorkerFactoryNode(), new SynchronousCryptoWorkerFactoryPlain(),
); );
const cryptoApi = cryptiDisp.cryptoApi; const cryptoApi = cryptiDisp.cryptoApi;

View File

@ -37,13 +37,13 @@ import {
Configuration, Configuration,
decodeCrock, decodeCrock,
} from "@gnu-taler/taler-util"; } from "@gnu-taler/taler-util";
import {
NodeHttpLib,
readSuccessResponseJsonOrThrow,
} from "@gnu-taler/taler-wallet-core";
import { URL } from "url"; import { URL } from "url";
import { spawn } from "child_process"; import { spawn } from "child_process";
import { delayMs } from "./harness/harness.js"; import { delayMs } from "./harness/harness.js";
import {
createPlatformHttpLib,
readSuccessResponseJsonOrThrow,
} from "@gnu-taler/taler-util/http";
interface BasicConf { interface BasicConf {
mainCurrency: string; mainCurrency: string;
@ -53,7 +53,7 @@ interface PubkeyConf {
masterPublicKey: string; masterPublicKey: string;
} }
const httpLib = new NodeHttpLib(); const httpLib = createPlatformHttpLib();
interface ShellResult { interface ShellResult {
stdout: string; stdout: string;

View File

@ -15,12 +15,38 @@
}, },
"./twrpc": { "./twrpc": {
"default": "./lib/twrpc.js" "default": "./lib/twrpc.js"
},
"./compat": {
"types": "./lib/compat.node.js",
"node": "./lib/compat.node.js",
"qtart": "./lib/compat.qtart.js",
"default": "./lib/not-implemented.js"
},
"./clk": {
"default": "./lib/clk.js"
},
"./http": {
"default": "./lib/http.js"
},
"./qtart": {
"types": "./lib/qtart.js",
"qtart": "./lib/qtart.js",
"default": "./lib/not-implemented.js"
} }
}, },
"imports": { "imports": {
"#twrpc-impl": { "#twrpc-impl": {
"node": "./lib/twrpc-impl.node.js", "node": "./lib/twrpc-impl.node.js"
"default": "./lib/twrpc-impl.missing.js" },
"#compat-impl": {
"node": "./lib/compat.node.js",
"qtart": "./lib/compat.qtart.js",
"type": "./lib/compat.d.ts"
},
"#http-impl": {
"type": "./lib/http-impl.node.js",
"node": "./lib/http-impl.node.js",
"qtart": "./lib/http-impl.qtart.js"
} }
}, },
"scripts": { "scripts": {

View File

@ -17,10 +17,12 @@
/** /**
* Imports. * Imports.
*/ */
import process from "process"; import {
import path from "path"; processExit,
import readline from "readline"; processArgv,
import { devNull } from "os"; readlinePrompt,
pathBasename,
} from "#compat-impl";
export namespace clk { export namespace clk {
class Converter<T> {} class Converter<T> {}
@ -359,13 +361,13 @@ export namespace clk {
console.error( console.error(
`error: unknown option '--${r.key}' for ${currentName}`, `error: unknown option '--${r.key}' for ${currentName}`,
); );
process.exit(-1); processExit(-1);
throw Error("not reached"); throw Error("not reached");
} }
if (d.isFlag) { if (d.isFlag) {
if (r.value !== undefined) { if (r.value !== undefined) {
console.error(`error: flag '--${r.key}' does not take a value`); console.error(`error: flag '--${r.key}' does not take a value`);
process.exit(-1); processExit(-1);
throw Error("not reached"); throw Error("not reached");
} }
storeFlag(d, true); storeFlag(d, true);
@ -373,7 +375,7 @@ export namespace clk {
if (r.value === undefined) { if (r.value === undefined) {
if (i === unparsedArgs.length - 1) { if (i === unparsedArgs.length - 1) {
console.error(`error: option '--${r.key}' needs an argument`); console.error(`error: option '--${r.key}' needs an argument`);
process.exit(-1); processExit(-1);
throw Error("not reached"); throw Error("not reached");
} }
storeOption(d, unparsedArgs[i + 1]); storeOption(d, unparsedArgs[i + 1]);
@ -391,7 +393,7 @@ export namespace clk {
const opt = this.shortOptions[chr]; const opt = this.shortOptions[chr];
if (!opt) { if (!opt) {
console.error(`error: option '-${chr}' not known`); console.error(`error: option '-${chr}' not known`);
process.exit(-1); processExit(-1);
} }
if (opt.isFlag) { if (opt.isFlag) {
storeFlag(opt, true); storeFlag(opt, true);
@ -399,7 +401,7 @@ export namespace clk {
if (si == optShort.length - 1) { if (si == optShort.length - 1) {
if (i === unparsedArgs.length - 1) { if (i === unparsedArgs.length - 1) {
console.error(`error: option '-${chr}' needs an argument`); console.error(`error: option '-${chr}' needs an argument`);
process.exit(-1); processExit(-1);
throw Error("not reached"); throw Error("not reached");
} else { } else {
storeOption(opt, unparsedArgs[i + 1]); storeOption(opt, unparsedArgs[i + 1]);
@ -418,7 +420,7 @@ export namespace clk {
const subcmd = this.subcommandMap[argVal]; const subcmd = this.subcommandMap[argVal];
if (!subcmd) { if (!subcmd) {
console.error(`error: unknown command '${argVal}'`); console.error(`error: unknown command '${argVal}'`);
process.exit(-1); processExit(-1);
throw Error("not reached"); throw Error("not reached");
} }
foundSubcommand = subcmd.commandGroup; foundSubcommand = subcmd.commandGroup;
@ -427,7 +429,7 @@ export namespace clk {
const d = this.arguments[posArgIndex]; const d = this.arguments[posArgIndex];
if (!d) { if (!d) {
console.error(`error: too many arguments for ${currentName}`); console.error(`error: too many arguments for ${currentName}`);
process.exit(-1); processExit(-1);
throw Error("not reached"); throw Error("not reached");
} }
myArgs[d.name] = unparsedArgs[i]; myArgs[d.name] = unparsedArgs[i];
@ -437,7 +439,7 @@ export namespace clk {
if (parsedArgs[this.argKey].help) { if (parsedArgs[this.argKey].help) {
this.printHelp(progname, parents); this.printHelp(progname, parents);
process.exit(0); processExit(0);
throw Error("not reached"); throw Error("not reached");
} }
@ -450,7 +452,7 @@ export namespace clk {
console.error( console.error(
`error: missing positional argument '${d.name}' for ${currentName}`, `error: missing positional argument '${d.name}' for ${currentName}`,
); );
process.exit(-1); processExit(-1);
throw Error("not reached"); throw Error("not reached");
} }
} }
@ -464,7 +466,7 @@ export namespace clk {
} else { } else {
const name = option.flagspec.join(","); const name = option.flagspec.join(",");
console.error(`error: missing option '${name}'`); console.error(`error: missing option '${name}'`);
process.exit(-1); processExit(-1);
throw Error("not reached"); throw Error("not reached");
} }
} }
@ -492,16 +494,16 @@ export namespace clk {
} catch (e) { } catch (e) {
console.error(`An error occurred while running ${currentName}`); console.error(`An error occurred while running ${currentName}`);
console.error(e); console.error(e);
process.exit(1); processExit(1);
} }
Promise.resolve(r).catch((e) => { Promise.resolve(r).catch((e) => {
console.error(`An error occurred while running ${currentName}`); console.error(`An error occurred while running ${currentName}`);
console.error(e); console.error(e);
process.exit(1); processExit(1);
}); });
} else { } else {
this.printHelp(progname, parents); this.printHelp(progname, parents);
process.exit(-1); processExit(-1);
throw Error("not reached"); throw Error("not reached");
} }
} }
@ -524,15 +526,15 @@ export namespace clk {
if (cmdlineArgs) { if (cmdlineArgs) {
args = cmdlineArgs; args = cmdlineArgs;
} else { } else {
args = process.argv.slice(1); args = processArgv().slice(1);
} }
if (args.length < 1) { if (args.length < 1) {
console.error( console.error(
"Error while parsing command line arguments: not enough arguments", "Error while parsing command line arguments: not enough arguments",
); );
process.exit(-1); processExit(-1);
} }
const progname = path.basename(args[0]); const progname = pathBasename(args[0]);
const rest = args.slice(1); const rest = args.slice(1);
this.mainCommand.run(progname, [], rest, {}); this.mainCommand.run(progname, [], rest, {});
@ -622,15 +624,6 @@ export namespace clk {
} }
export function prompt(question: string): Promise<string> { export function prompt(question: string): Promise<string> {
const stdinReadline = readline.createInterface({ return readlinePrompt(question);
input: process.stdin,
output: process.stdout,
});
return new Promise<string>((resolve, reject) => {
stdinReadline.question(question, (res) => {
resolve(res);
stdinReadline.close();
});
});
} }
} }

View File

@ -1,6 +1,6 @@
/* /*
This file is part of GNU Taler This file is part of GNU Taler
(C) 2019 GNUnet e.V. (C) 2023 Taler Systems S.A.
GNU Taler is free software; you can redistribute it and/or modify it under the GNU 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 terms of the GNU General Public License as published by the Free Software
@ -14,23 +14,9 @@
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/ */
/** export function processExit(status: number): never;
* Imports. export function processArgv(): string[];
*/ export function readlinePrompt(prompt: string): Promise<string>;
import { CryptoWorkerFactory } from "./crypto-dispatcher.js"; export function pathBasename(s: string): string;
import { CryptoWorker } from "./cryptoWorkerInterface.js"; export function setUnhandledRejectionHandler(h: (e: any) => void): void;
import { SynchronousCryptoWorkerNode } from "./synchronousWorkerNode.js"; export function getenv(name: string): string | undefined;
/**
* 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 SynchronousCryptoWorkerFactoryNode implements CryptoWorkerFactory {
startWorker(): CryptoWorker {
return new SynchronousCryptoWorkerNode();
}
getConcurrency(): number {
return 1;
}
}

View File

@ -0,0 +1,59 @@
/*
This file is part of GNU Taler
(C) 2023 Taler Systems S.A.
GNU 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.
GNU 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
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
import process from "node:process";
import readline from "node:readline";
import path from "node:path";
import os from "node:os";
export function processExit(status: number): never {
process.exit(1);
}
export function processArgv(): string[] {
return [...process.argv];
}
export function readlinePrompt(prompt: string): Promise<string> {
const stdinReadline = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
return new Promise<string>((resolve, reject) => {
stdinReadline.question(prompt, (res) => {
resolve(res);
stdinReadline.close();
});
});
}
export function pathBasename(p: string): string {
return path.basename(p);
}
export function pathHomedir(): string {
return os.homedir();
}
export function setUnhandledRejectionHandler(h: (e: any) => void): void {
process.on("unhandledRejection", (e) => {
h(e);
});
}
export function getenv(name: string): string | undefined {
return process.env[name];
}

View File

@ -0,0 +1,53 @@
/*
This file is part of GNU Taler
(C) 2023 Taler Systems S.A.
GNU 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.
GNU 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
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
// qtart "std" library
// @ts-ignore
import * as std from "std";
export function processExit(status: number): never {
std.exit(status);
throw Error("not reached");
}
export function processArgv(): string[] {
// @ts-ignore
return ["qtart", ...globalThis.scriptArgs];
}
export function readlinePrompt(prompt: string): Promise<string> {
throw new Error("not supported");
}
export function pathBasename(p: string): string {
const slashIndex = p.lastIndexOf("/");
if (slashIndex < 0) {
return p;
}
return p.substring(0, slashIndex);
}
export function pathHomedir(): string {
return std.getenv("HOME");
}
export function setUnhandledRejectionHandler(h: (e: any) => void): void {
// not supported
}
export function getenv(name: string): string | undefined {
return std.getenv(name);
}

View File

@ -0,0 +1,39 @@
/*
This file is part of GNU Taler
(C) 2023 Taler Systems S.A.
GNU 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.
GNU 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
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
SPDX-License-Identifier: AGPL3.0-or-later
*/
const textEncoder = new TextEncoder();
export interface HttpLibArgs {
enableThrottling?: boolean,
}
export function encodeBody(body: any): ArrayBuffer {
if (body == null) {
return new ArrayBuffer(0);
}
if (typeof body === "string") {
return textEncoder.encode(body).buffer;
} else if (ArrayBuffer.isView(body)) {
return body.buffer;
} else if (body instanceof ArrayBuffer) {
return body;
} else if (typeof body === "object") {
return textEncoder.encode(JSON.stringify(body)).buffer;
}
throw new TypeError("unsupported request body type");
}

View File

@ -0,0 +1,17 @@
import { HttpLibArgs } from "./http-common.js";
import { HttpRequestLibrary, HttpRequestOptions, HttpResponse } from "./http.js";
/**
* Implementation of the HTTP request library interface for node.
*/
export declare class HttpLibImpl implements HttpRequestLibrary {
private throttle;
private throttlingEnabled;
constructor(args?: HttpLibArgs);
/**
* Set whether requests should be throttled.
*/
setThrottling(enabled: boolean): void;
fetch(url: string, opt?: HttpRequestOptions): Promise<HttpResponse>;
get(url: string, opt?: HttpRequestOptions): Promise<HttpResponse>;
postJson(url: string, body: any, opt?: HttpRequestOptions): Promise<HttpResponse>;
}

View File

@ -0,0 +1,175 @@
/*
This file is part of GNU Taler
(C) 2019 Taler Systems S.A.
GNU 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.
GNU 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
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
SPDX-License-Identifier: AGPL3.0-or-later
*/
/**
* Imports.
*/
import * as http from "node:http";
import { RequestOptions } from "node:http";
import { TalerError } from "./errors.js";
import { encodeBody, HttpLibArgs } from "./http-common.js";
import {
DEFAULT_REQUEST_TIMEOUT_MS,
Headers,
HttpRequestLibrary,
HttpRequestOptions,
HttpResponse,
} from "./http.js";
import {
Logger,
RequestThrottler,
TalerErrorCode,
typedArrayConcat,
URL,
} from "./index.js";
const logger = new Logger("http-impl.node.ts");
const textDecoder = new TextDecoder();
/**
* Implementation of the HTTP request library interface for node.
*/
export class HttpLibImpl implements HttpRequestLibrary {
private throttle = new RequestThrottler();
private throttlingEnabled = true;
constructor(args?: HttpLibArgs) {
this.throttlingEnabled = args?.enableThrottling ?? false;
}
/**
* Set whether requests should be throttled.
*/
setThrottling(enabled: boolean): void {
this.throttlingEnabled = enabled;
}
async fetch(url: string, opt?: HttpRequestOptions): Promise<HttpResponse> {
const method = opt?.method?.toUpperCase() ?? "GET";
let body = opt?.body;
logger.trace(`Requesting ${method} ${url}`);
const parsedUrl = new URL(url);
if (this.throttlingEnabled && this.throttle.applyThrottle(url)) {
throw TalerError.fromDetail(
TalerErrorCode.WALLET_HTTP_REQUEST_THROTTLED,
{
requestMethod: method,
requestUrl: url,
throttleStats: this.throttle.getThrottleStats(url),
},
`request to origin ${parsedUrl.origin} was throttled`,
);
}
let timeoutMs: number | undefined;
if (typeof opt?.timeout?.d_ms === "number") {
timeoutMs = opt.timeout.d_ms;
} else {
timeoutMs = DEFAULT_REQUEST_TIMEOUT_MS;
}
const headers = { ...opt?.headers };
headers["Content-Type"] = "application/json";
let reqBody: ArrayBuffer | undefined;
if (opt?.method == "POST") {
reqBody = encodeBody(opt.body);
}
const options: RequestOptions = {
protocol: parsedUrl.protocol,
port: parsedUrl.port,
host: parsedUrl.host,
method: method,
path: parsedUrl.pathname,
headers: opt?.headers,
};
const chunks: Uint8Array[] = [];
return new Promise((resolve, reject) => {
const req = http.request(options, (res) => {
res.on("data", (d) => {
chunks.push(d);
});
res.on("end", () => {
const headers: Headers = new Headers();
for (const [k, v] of Object.entries(res.headers)) {
if (!v) {
continue;
}
if (typeof v === "string") {
headers.set(k, v);
} else {
headers.set(k, v.join(", "));
}
}
const data = typedArrayConcat(chunks);
const resp: HttpResponse = {
requestMethod: method,
requestUrl: parsedUrl.href,
status: res.statusCode || 0,
headers,
async bytes() {
return data;
},
json() {
const text = textDecoder.decode(data);
return JSON.parse(text);
},
async text() {
const text = textDecoder.decode(data);
return text;
},
};
resolve(resp);
});
res.on("error", (e) => {
reject(e);
});
});
if (reqBody) {
req.write(reqBody);
}
req.end();
});
}
async get(url: string, opt?: HttpRequestOptions): Promise<HttpResponse> {
return this.fetch(url, {
method: "GET",
...opt,
});
}
async postJson(
url: string,
body: any,
opt?: HttpRequestOptions,
): Promise<HttpResponse> {
return this.fetch(url, {
method: "POST",
body,
...opt,
});
}
}

View File

@ -0,0 +1,127 @@
/*
This file is part of GNU Taler
(C) 2019 Taler Systems S.A.
GNU 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.
GNU 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
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
SPDX-License-Identifier: AGPL3.0-or-later
*/
/**
* Imports.
*/
import { Logger } from "@gnu-taler/taler-util";
import { TalerError } from "./errors.js";
import { encodeBody, HttpLibArgs } from "./http-common.js";
import {
Headers,
HttpRequestLibrary,
HttpRequestOptions,
HttpResponse,
} from "./http.js";
import { RequestThrottler, TalerErrorCode, URL } from "./index.js";
import { qjsOs } from "./qtart.js";
const logger = new Logger("http-impl.qtart.ts");
const textDecoder = new TextDecoder();
/**
* Implementation of the HTTP request library interface for node.
*/
export class HttpLibImpl implements HttpRequestLibrary {
private throttle = new RequestThrottler();
private throttlingEnabled = true;
constructor(args?: HttpLibArgs) {
this.throttlingEnabled = args?.enableThrottling ?? false;
}
/**
* Set whether requests should be throttled.
*/
setThrottling(enabled: boolean): void {
this.throttlingEnabled = enabled;
}
async fetch(url: string, opt?: HttpRequestOptions): Promise<HttpResponse> {
const method = opt?.method ?? "GET";
logger.trace(`Requesting ${method} ${url}`);
const parsedUrl = new URL(url);
if (this.throttlingEnabled && this.throttle.applyThrottle(url)) {
throw TalerError.fromDetail(
TalerErrorCode.WALLET_HTTP_REQUEST_THROTTLED,
{
requestMethod: method,
requestUrl: url,
throttleStats: this.throttle.getThrottleStats(url),
},
`request to origin ${parsedUrl.origin} was throttled`,
);
}
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") {
data = encodeBody(opt?.body);
}
const res = await qjsOs.fetchHttp(url, {
method,
data,
headers,
});
return {
requestMethod: method,
// FIXME: We don't return headers!
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,
};
}
async get(url: string, opt?: HttpRequestOptions): Promise<HttpResponse> {
return this.fetch(url, {
method: "GET",
...opt,
});
}
async postJson(
url: string,
body: any,
opt?: HttpRequestOptions,
): Promise<HttpResponse> {
return this.fetch(url, {
method: "POST",
body,
...opt,
});
}
}

View File

@ -34,7 +34,9 @@ import {
CancellationToken, CancellationToken,
} from "@gnu-taler/taler-util"; } from "@gnu-taler/taler-util";
import { TalerErrorCode } from "@gnu-taler/taler-util"; import { TalerErrorCode } from "@gnu-taler/taler-util";
import { makeErrorDetail, TalerError } from "../errors.js"; import { makeErrorDetail, TalerError } from "./errors.js";
import * as impl from "#http-impl";
import { HttpLibArgs } from "./http-common.js";
const logger = new Logger("http.ts"); const logger = new Logger("http.ts");
@ -352,3 +354,7 @@ export function getExpiry(
} }
return t; return t;
} }
export function createPlatformHttpLib(args?: HttpLibArgs): HttpRequestLibrary {
return new impl.HttpLibImpl(args);
}

View File

@ -19,3 +19,7 @@
import { loadBrowserPrng } from "./prng-browser.js"; import { loadBrowserPrng } from "./prng-browser.js";
loadBrowserPrng(); loadBrowserPrng();
export * from "./index.js"; export * from "./index.js";
// The web stuff doesn't support package.json export declarations yet,
// so we export more stuff here than we should.
export * from "./http.js";

View File

@ -21,4 +21,3 @@ initNodePrng();
export * from "./index.js"; export * from "./index.js";
export * from "./talerconfig.js"; export * from "./talerconfig.js";
export * from "./globbing/minimatch.js"; export * from "./globbing/minimatch.js";
export { clk } from "./clk.js";

View File

@ -36,3 +36,4 @@ export * from "./CancellationToken.js";
export * from "./contract-terms.js"; export * from "./contract-terms.js";
export * from "./base64.js"; export * from "./base64.js";
export * from "./merchant-api-types.js"; export * from "./merchant-api-types.js";
export * from "./errors.js";

View File

@ -0,0 +1,36 @@
// @ts-ignore
import * as _qjsOsImp from "os";
// @ts-ignore
import * as _qjsStdImp from "std";
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<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.
export const qjsOs: QjsOsLib = _qjsOsImp as any;
export const qjsStd: QjsStdLib = _qjsStdImp as any;

View File

@ -14,4 +14,13 @@
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/ */
import type { RpcConnectArgs, RpcServerArgs } from "./twrpc.js";
// Not implemented. // Not implemented.
export async function connectRpc<T>(args: RpcConnectArgs<T>): Promise<T> {
throw Error("not implemented");
}
export async function runRpcServer(args: RpcServerArgs): Promise<void> {
throw Error("not implemented");
}

View File

@ -53,7 +53,7 @@ function git_hash() {
export const buildConfig = { export const buildConfig = {
entryPoints: ["src/index.ts"], entryPoints: ["src/index.ts"],
outfile: "dist/taler-wallet-cli.mjs", outfile: "dist/taler-wallet-cli.qtart.mjs",
bundle: true, bundle: true,
minify: false, minify: false,
target: [ target: [
@ -61,7 +61,11 @@ export const buildConfig = {
], ],
format: 'esm', format: 'esm',
platform: 'neutral', platform: 'neutral',
mainFields: ["module", "main"],
conditions: ["qtart"],
sourcemap: true, sourcemap: true,
// quickjs standard library
external: ["std", "os"],
define: { define: {
'__VERSION__': `"${_package.version}"`, '__VERSION__': `"${_package.version}"`,
'__GIT_HASH__': `"${GIT_HASH}"`, '__GIT_HASH__': `"${GIT_HASH}"`,

View File

@ -21,12 +21,11 @@ import {
addPaytoQueryParams, addPaytoQueryParams,
AgeRestriction, AgeRestriction,
classifyTalerUri, classifyTalerUri,
clk,
codecForList, codecForList,
codecForString, codecForString,
CoreApiResponse, CoreApiResponse,
decodeCrock,
encodeCrock, encodeCrock,
getErrorDetailFromException,
getRandomBytes, getRandomBytes,
j2s, j2s,
Logger, Logger,
@ -35,20 +34,26 @@ import {
RecoveryMergeStrategy, RecoveryMergeStrategy,
setDangerousTimetravel, setDangerousTimetravel,
setGlobalLogLevelFromString, setGlobalLogLevelFromString,
summarizeTalerErrorDetail,
TalerUriType, TalerUriType,
WalletNotification, WalletNotification,
} from "@gnu-taler/taler-util"; } from "@gnu-taler/taler-util";
import { clk } from "@gnu-taler/taler-util/clk";
import {
getenv,
pathHomedir,
processExit,
setUnhandledRejectionHandler,
} from "@gnu-taler/taler-util/compat";
import { createPlatformHttpLib } from "@gnu-taler/taler-util/http";
import { JsonMessage, runRpcServer } from "@gnu-taler/taler-util/twrpc"; import { JsonMessage, runRpcServer } from "@gnu-taler/taler-util/twrpc";
import { import {
createNativeWalletHost,
createNativeWalletHost2,
CryptoDispatcher, CryptoDispatcher,
getDefaultNodeWallet,
getDefaultNodeWallet2,
getErrorDetailFromException,
nativeCrypto, nativeCrypto,
NodeHttpLib, //NodeThreadCryptoWorkerFactory,
NodeThreadCryptoWorkerFactory, //SynchronousCryptoWorkerFactoryPlain,
summarizeTalerErrorDetail,
SynchronousCryptoWorkerFactoryNode,
TalerCryptoInterface, TalerCryptoInterface,
Wallet, Wallet,
WalletApiOperation, WalletApiOperation,
@ -60,8 +65,6 @@ import {
getClientFromRemoteWallet, getClientFromRemoteWallet,
makeNotificationWaiter, makeNotificationWaiter,
} from "@gnu-taler/taler-wallet-core/remote"; } from "@gnu-taler/taler-wallet-core/remote";
import fs from "fs";
import os from "os";
// This module also serves as the entry point for the crypto // This module also serves as the entry point for the crypto
// thread worker, and thus must expose these two handlers. // thread worker, and thus must expose these two handlers.
@ -76,13 +79,13 @@ const EXIT_EXCEPTION = 4;
const EXIT_API_ERROR = 5; const EXIT_API_ERROR = 5;
const EXIT_RETRIES_EXCEEDED = 6; const EXIT_RETRIES_EXCEEDED = 6;
process.on("unhandledRejection", (error: any) => { setUnhandledRejectionHandler((error: any) => {
logger.error("unhandledRejection", error.message); logger.error("unhandledRejection", error.message);
logger.error("stack", error.stack); logger.error("stack", error.stack);
process.exit(2); processExit(1);
}); });
const defaultWalletDbPath = os.homedir + "/" + ".talerwalletdb.json"; const defaultWalletDbPath = pathHomedir() + "/" + ".talerwalletdb.json";
function assertUnreachable(x: never): never { function assertUnreachable(x: never): never {
throw new Error("Didn't expect to get here"); throw new Error("Didn't expect to get here");
@ -99,7 +102,7 @@ async function doPay(
if (result.status === PreparePayResultType.InsufficientBalance) { if (result.status === PreparePayResultType.InsufficientBalance) {
console.log("contract", result.contractTerms); console.log("contract", result.contractTerms);
console.error("insufficient balance"); console.error("insufficient balance");
process.exit(1); processExit(1);
return; return;
} }
if (result.status === PreparePayResultType.AlreadyConfirmed) { if (result.status === PreparePayResultType.AlreadyConfirmed) {
@ -108,8 +111,7 @@ async function doPay(
} else { } else {
console.log("payment already in progress"); console.log("payment already in progress");
} }
processExit(0);
process.exit(0);
return; return;
} }
if (result.status === "payment-possible") { if (result.status === "payment-possible") {
@ -154,7 +156,7 @@ function applyVerbose(verbose: boolean): void {
declare const __VERSION__: string; declare const __VERSION__: string;
function printVersion(): void { function printVersion(): void {
console.log(__VERSION__); console.log(__VERSION__);
process.exit(0); processExit(0);
} }
export const walletCli = clk export const walletCli = clk
@ -203,7 +205,7 @@ export const walletCli = clk
type WalletCliArgsType = clk.GetArgType<typeof walletCli>; type WalletCliArgsType = clk.GetArgType<typeof walletCli>;
function checkEnvFlag(name: string): boolean { function checkEnvFlag(name: string): boolean {
const val = process.env[name]; const val = getenv(name);
if (val == "1") { if (val == "1") {
return true; return true;
} }
@ -238,11 +240,10 @@ async function createLocalWallet(
notificationHandler?: (n: WalletNotification) => void, notificationHandler?: (n: WalletNotification) => void,
): Promise<Wallet> { ): Promise<Wallet> {
const dbPath = walletCliArgs.wallet.walletDbFile ?? defaultWalletDbPath; const dbPath = walletCliArgs.wallet.walletDbFile ?? defaultWalletDbPath;
const myHttpLib = new NodeHttpLib(); const myHttpLib = createPlatformHttpLib({
if (walletCliArgs.wallet.noThrottle) { enableThrottling: walletCliArgs.wallet.noThrottle ? false : true,
myHttpLib.setThrottling(false); });
} const wallet = await createNativeWalletHost({
const wallet = await getDefaultNodeWallet({
persistentStoragePath: dbPath !== ":memory:" ? dbPath : undefined, persistentStoragePath: dbPath !== ":memory:" ? dbPath : undefined,
httpLib: myHttpLib, httpLib: myHttpLib,
notifyHandler: (n) => { notifyHandler: (n) => {
@ -268,7 +269,7 @@ async function createLocalWallet(
const ed = getErrorDetailFromException(e); const ed = getErrorDetailFromException(e);
console.error("Operation failed: " + summarizeTalerErrorDetail(ed)); console.error("Operation failed: " + summarizeTalerErrorDetail(ed));
console.error("Error details:", JSON.stringify(ed, undefined, 2)); console.error("Error details:", JSON.stringify(ed, undefined, 2));
process.exit(1); processExit(1);
} finally { } finally {
logger.trace("operation with wallet finished, stopping"); logger.trace("operation with wallet finished, stopping");
logger.trace("stopped wallet"); logger.trace("stopped wallet");
@ -357,7 +358,7 @@ walletCli
requestJson = JSON.parse(args.api.request); requestJson = JSON.parse(args.api.request);
} catch (e) { } catch (e) {
console.error("Invalid JSON"); console.error("Invalid JSON");
process.exit(1); processExit(1);
} }
try { try {
const resp = await wallet.makeCoreApiRequest( const resp = await wallet.makeCoreApiRequest(
@ -367,12 +368,12 @@ walletCli
console.log(JSON.stringify(resp, undefined, 2)); console.log(JSON.stringify(resp, undefined, 2));
if (resp.type === "error") { if (resp.type === "error") {
if (args.api.expectSuccess) { if (args.api.expectSuccess) {
process.exit(EXIT_API_ERROR); processExit(EXIT_API_ERROR);
} }
} }
} catch (e) { } catch (e) {
logger.error(`Got exception while handling API request ${e}`); logger.error(`Got exception while handling API request ${e}`);
process.exit(EXIT_EXCEPTION); processExit(EXIT_EXCEPTION);
} }
}); });
logger.info("finished handling API request"); logger.info("finished handling API request");
@ -475,7 +476,7 @@ walletCli
}); });
wallet.ws.stop(); wallet.ws.stop();
if (resp.retriesExceeded && args.finishPendingOpt.failOnMaxRetries) { if (resp.retriesExceeded && args.finishPendingOpt.failOnMaxRetries) {
process.exit(EXIT_RETRIES_EXCEEDED); processExit(EXIT_RETRIES_EXCEEDED);
} }
}); });
}); });
@ -594,7 +595,7 @@ walletCli
const selectedExchange = withdrawInfo.defaultExchangeBaseUrl; const selectedExchange = withdrawInfo.defaultExchangeBaseUrl;
if (!selectedExchange) { if (!selectedExchange) {
console.error("no suggested exchange!"); console.error("no suggested exchange!");
process.exit(1); processExit(1);
return; return;
} }
const res = await wallet.client.call( const res = await wallet.client.call(
@ -1014,9 +1015,10 @@ advancedCli
help: "Run the 'bench-internal' benchmark", help: "Run the 'bench-internal' benchmark",
}) })
.action(async (args) => { .action(async (args) => {
const myHttpLib = new NodeHttpLib(); const myHttpLib = createPlatformHttpLib({
myHttpLib.setThrottling(false); enableThrottling: false,
const res = await getDefaultNodeWallet2({ });
const res = await createNativeWalletHost2({
// No persistent DB storage. // No persistent DB storage.
persistentStoragePath: undefined, persistentStoragePath: undefined,
httpLib: myHttpLib, httpLib: myHttpLib,
@ -1060,15 +1062,6 @@ advancedCli
}); });
}); });
advancedCli
.subcommand("decode", "decode", {
help: "Decode base32-crockford.",
})
.action((args) => {
const enc = fs.readFileSync(0, "utf8");
console.log(decodeCrock(enc.trim()));
});
advancedCli advancedCli
.subcommand("genSegwit", "gen-segwit") .subcommand("genSegwit", "gen-segwit")
.requiredArgument("paytoUri", clk.STRING) .requiredArgument("paytoUri", clk.STRING)
@ -1229,7 +1222,7 @@ advancedCli
); );
} catch (e: any) { } catch (e: any) {
console.log("could not parse coin list:", e.message); console.log("could not parse coin list:", e.message);
process.exit(1); processExit(1);
} }
for (const c of coinPubList) { for (const c of coinPubList) {
await wallet.client.call(WalletApiOperation.SetCoinSuspended, { await wallet.client.call(WalletApiOperation.SetCoinSuspended, {
@ -1254,7 +1247,7 @@ advancedCli
); );
} catch (e: any) { } catch (e: any) {
console.log("could not parse coin list:", e.message); console.log("could not parse coin list:", e.message);
process.exit(1); processExit(1);
} }
for (const c of coinPubList) { for (const c of coinPubList) {
await wallet.client.call(WalletApiOperation.SetCoinSuspended, { await wallet.client.call(WalletApiOperation.SetCoinSuspended, {
@ -1420,33 +1413,33 @@ async function read(stream: NodeJS.ReadStream) {
return Buffer.concat(chunks).toString("utf8"); return Buffer.concat(chunks).toString("utf8");
} }
testCli // testCli
.subcommand("cryptoworker", "cryptoworker") // .subcommand("cryptoworker", "cryptoworker")
.maybeOption("impl", ["--impl"], clk.STRING) // .maybeOption("impl", ["--impl"], clk.STRING)
.action(async (args) => { // .action(async (args) => {
let cryptoApi: TalerCryptoInterface; // let cryptoApi: TalerCryptoInterface;
if (!args.cryptoworker.impl || args.cryptoworker.impl === "node") { // if (!args.cryptoworker.impl || args.cryptoworker.impl === "node") {
const workerFactory = new NodeThreadCryptoWorkerFactory(); // const workerFactory = new NodeThreadCryptoWorkerFactory();
const cryptoDisp = new CryptoDispatcher(workerFactory); // const cryptoDisp = new CryptoDispatcher(workerFactory);
cryptoApi = cryptoDisp.cryptoApi; // cryptoApi = cryptoDisp.cryptoApi;
} else if (args.cryptoworker.impl === "sync") { // } else if (args.cryptoworker.impl === "sync") {
const workerFactory = new SynchronousCryptoWorkerFactoryNode(); // const workerFactory = new SynchronousCryptoWorkerFactoryPlain();
const cryptoDisp = new CryptoDispatcher(workerFactory); // const cryptoDisp = new CryptoDispatcher(workerFactory);
cryptoApi = cryptoDisp.cryptoApi; // cryptoApi = cryptoDisp.cryptoApi;
} else if (args.cryptoworker.impl === "none") { // } else if (args.cryptoworker.impl === "none") {
cryptoApi = nativeCrypto; // cryptoApi = nativeCrypto;
} else { // } else {
throw Error(`invalid crypto worker type ${args.cryptoworker.impl}`); // throw Error(`invalid crypto worker type ${args.cryptoworker.impl}`);
} // }
const input = "foo"; // const input = "foo";
console.log(`testing crypto worker by hashing string '${input}'`); // console.log(`testing crypto worker by hashing string '${input}'`);
const res = await cryptoApi.hashString({ str: input }); // const res = await cryptoApi.hashString({ str: input });
console.log(res); // console.log(res);
}); // });
export function main() { export function main() {
if (process.env["TALER_WALLET_DEBUG_DENOMSEL_ALLOW_LATE"]) { if (getenv("TALER_WALLET_DEBUG_DENOMSEL_ALLOW_LATE")) {
logger.warn("Allowing withdrawal of late denominations for debugging"); logger.warn("Allowing withdrawal of late denominations for debugging");
walletCoreDebugFlags.denomselAllowLate = true; walletCoreDebugFlags.denomselAllowLate = true;
} }

View File

@ -38,7 +38,13 @@
"default": "./lib/index.js" "default": "./lib/index.js"
}, },
"./remote": { "./remote": {
"node": "./lib/remote.js" "default": "./lib/remote.js"
}
},
"imports": {
"#host-impl": {
"node": "./lib/host-impl.node.js",
"qtart": "./lib/host-impl.qtart.js"
} }
}, },
"devDependencies": { "devDependencies": {

View File

@ -33,13 +33,10 @@ import {
j2s, j2s,
Logger, Logger,
stringToBytes, stringToBytes,
TalerError,
TalerErrorCode, TalerErrorCode,
} from "@gnu-taler/taler-util"; } from "@gnu-taler/taler-util";
import { TalerError } from "./errors.js"; import { HttpRequestLibrary, readSuccessResponseJsonOrThrow } from "@gnu-taler/taler-util/http";
import {
HttpRequestLibrary,
readSuccessResponseJsonOrThrow,
} from "./util/http.js";
const logger = new Logger("bank-api-client.ts"); const logger = new Logger("bank-api-client.ts");

View File

@ -21,8 +21,6 @@ import {
CryptoWorker, CryptoWorker,
CryptoWorkerResponseMessage, CryptoWorkerResponseMessage,
} from "./cryptoWorkerInterface.js"; } from "./cryptoWorkerInterface.js";
import { SynchronousCryptoWorkerFactoryNode } from "./synchronousWorkerFactoryNode.js";
import { processRequestWithImpl } from "./worker-common.js";
export class MyCryptoWorker implements CryptoWorker { export class MyCryptoWorker implements CryptoWorker {
/** /**

View File

@ -24,7 +24,7 @@
* Imports. * Imports.
*/ */
import { j2s, Logger, TalerErrorCode } from "@gnu-taler/taler-util"; import { j2s, Logger, TalerErrorCode } from "@gnu-taler/taler-util";
import { TalerError } from "../../errors.js"; import { TalerError } from "@gnu-taler/taler-util";
import { openPromise } from "../../util/promiseUtils.js"; import { openPromise } from "../../util/promiseUtils.js";
import { timer, performanceNow, TimerHandle } from "../../util/timer.js"; import { timer, performanceNow, TimerHandle } from "../../util/timer.js";
import { nullCrypto, TalerCryptoInterface } from "../cryptoImplementation.js"; import { nullCrypto, TalerCryptoInterface } from "../cryptoImplementation.js";

View File

@ -1,92 +0,0 @@
/*
This file is part of GNU Taler
(C) 2022 Taler Systems S.A.
GNU 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.
GNU 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
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
/**
* Imports.
*/
import { Logger } from "@gnu-taler/taler-util";
import child_process from "child_process";
import type internal from "stream";
import { OpenedPromise, openPromise } from "../../util/promiseUtils.js";
const logger = new Logger("synchronousWorkerFactory.ts");
/**
* Client for the crypto helper process (taler-crypto-worker from exchange.git).
*/
export class CryptoRpcClient {
proc: child_process.ChildProcessByStdio<
internal.Writable,
internal.Readable,
null
>;
requests: Array<{
p: OpenedPromise<any>;
req: any;
}> = [];
constructor() {
const stdoutChunks: Buffer[] = [];
this.proc = child_process.spawn("taler-crypto-worker", {
//stdio: ["pipe", "pipe", "inherit"],
stdio: ["pipe", "pipe", "inherit"],
detached: true,
});
this.proc.on("close", (): void => {
logger.error("child process exited");
});
(this.proc.stdout as any).unref();
(this.proc.stdin as any).unref();
this.proc.unref();
this.proc.stdout.on("data", (x) => {
if (x instanceof Buffer) {
const nlIndex = x.indexOf("\n");
if (nlIndex >= 0) {
const before = x.slice(0, nlIndex);
const after = x.slice(nlIndex + 1);
stdoutChunks.push(after);
const str = Buffer.concat([...stdoutChunks, before]).toString(
"utf-8",
);
const req = this.requests.shift();
if (!req) {
throw Error("request was undefined");
}
if (this.requests.length === 0) {
this.proc.unref();
}
//logger.info(`got response: ${str}`);
req.p.resolve(JSON.parse(str));
} else {
stdoutChunks.push(x);
}
} else {
throw Error(`unexpected data chunk type (${typeof x})`);
}
});
}
async queueRequest(req: any): Promise<any> {
const p = openPromise<any>();
if (this.requests.length === 0) {
this.proc.ref();
}
this.requests.push({ req, p });
this.proc.stdin.write(`${JSON.stringify(req)}\n`);
return p.promise;
}
}

View File

@ -1,174 +0,0 @@
/*
This file is part of GNU Taler
(C) 2019 GNUnet e.V.
GNU 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.
GNU 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
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
import { j2s, Logger } from "@gnu-taler/taler-util";
import {
nativeCryptoR,
TalerCryptoInterfaceR,
} from "../cryptoImplementation.js";
import { CryptoWorker } from "./cryptoWorkerInterface.js";
import { CryptoRpcClient } from "./rpcClient.js";
import { processRequestWithImpl } from "./worker-common.js";
const logger = new Logger("synchronousWorker.ts");
/**
* Worker implementation that uses node subprocesses.
*
* The node crypto worker can also use IPC to offload cryptographic
* operations to a helper process (usually written in C / part of taler-exchange).
*/
export class SynchronousCryptoWorkerNode implements CryptoWorker {
/**
* Function to be called when we receive a message from the worker thread.
*/
onmessage: undefined | ((m: any) => void);
/**
* Function to be called when we receive an error from the worker thread.
*/
onerror: undefined | ((m: any) => void);
cryptoImplR: TalerCryptoInterfaceR;
rpcClient: CryptoRpcClient | undefined;
constructor() {
this.onerror = undefined;
this.onmessage = undefined;
this.cryptoImplR = { ...nativeCryptoR };
if (process.env["TALER_WALLET_PRIMITIVE_WORKER"]) {
logger.info("using RPC for some crypto operations");
const rpc = (this.rpcClient = new CryptoRpcClient());
this.cryptoImplR.eddsaSign = async (_, req) => {
return await rpc.queueRequest({
op: "eddsa_sign",
args: {
msg: req.msg,
priv: req.priv,
},
});
};
this.cryptoImplR.setupRefreshPlanchet = async (_, req) => {
const res = await rpc.queueRequest({
op: "setup_refresh_planchet",
args: {
coin_index: req.coinNumber,
transfer_secret: req.transferSecret,
},
});
return {
bks: res.blinding_key,
coinPriv: res.coin_priv,
coinPub: res.coin_pub,
};
};
this.cryptoImplR.rsaBlind = async (_, req) => {
const res = await rpc.queueRequest({
op: "rsa_blind",
args: {
bks: req.bks,
hm: req.hm,
pub: req.pub,
},
});
return {
blinded: res.blinded,
};
};
this.cryptoImplR.keyExchangeEcdheEddsa = async (_, req) => {
const res = await rpc.queueRequest({
op: "kx_ecdhe_eddsa",
args: {
ecdhe_priv: req.ecdhePriv,
eddsa_pub: req.eddsaPub,
},
});
return {
h: res.h,
};
};
this.cryptoImplR.eddsaGetPublic = async (_, req) => {
const res = await rpc.queueRequest({
op: "eddsa_get_public",
args: {
eddsa_priv: req.priv,
},
});
return {
pub: res.eddsa_pub,
};
};
this.cryptoImplR.ecdheGetPublic = async (_, req) => {
const res = await rpc.queueRequest({
op: "ecdhe_get_public",
args: {
ecdhe_priv: req.priv,
},
});
return {
pub: res.ecdhe_pub,
};
};
}
}
/**
* Add an event listener for either an "error" or "message" event.
*/
addEventListener(event: "message" | "error", fn: (x: any) => void): void {
switch (event) {
case "message":
this.onmessage = fn;
break;
case "error":
this.onerror = fn;
break;
}
}
private dispatchMessage(msg: any): void {
if (this.onmessage) {
this.onmessage(msg);
}
}
/**
* Send a message to the worker thread.
*/
postMessage(msg: any): void {
const handleRequest = async () => {
const responseMsg = await processRequestWithImpl(msg, this.cryptoImplR);
try {
setTimeout(() => this.dispatchMessage(responseMsg), 0);
} catch (e) {
logger.error("got error during dispatch", e);
}
};
handleRequest().catch((e) => {
logger.error("Error while handling crypto request:", e);
});
}
/**
* Forcibly terminate the worker thread.
*/
terminate(): void {
// This is a no-op.
}
}

View File

@ -23,7 +23,7 @@ import {
stringifyError as safeStringifyError, stringifyError as safeStringifyError,
TalerErrorCode, TalerErrorCode,
} from "@gnu-taler/taler-util"; } from "@gnu-taler/taler-util";
import { getErrorDetailFromException, makeErrorDetail } from "../../errors.js"; import { getErrorDetailFromException, makeErrorDetail } from "@gnu-taler/taler-util";
import { TalerCryptoInterfaceR } from "../cryptoImplementation.js"; import { TalerCryptoInterfaceR } from "../cryptoImplementation.js";
import { import {
CryptoWorkerRequestMessage, CryptoWorkerRequestMessage,

View File

@ -2659,6 +2659,9 @@ function onMetaDbUpgradeNeeded(
/** /**
* Return a promise that resolves * Return a promise that resolves
* to the taler wallet db. * to the taler wallet db.
*
* @param onVersionChange Called when another client concurrenctly connects to the database
* with a higher version.
*/ */
export async function openTalerDatabase( export async function openTalerDatabase(
idbFactory: IDBFactory, idbFactory: IDBFactory,

View File

@ -58,7 +58,7 @@ import {
import { import {
HttpRequestLibrary, HttpRequestLibrary,
readSuccessResponseJsonOrThrow, readSuccessResponseJsonOrThrow,
} from "./util/http.js"; } from "@gnu-taler/taler-util/http";
import { import {
getBankStatusUrl, getBankStatusUrl,
getBankWithdrawalInfo, getBankWithdrawalInfo,

View File

@ -32,7 +32,7 @@ import {
HttpRequestLibrary, HttpRequestLibrary,
HttpRequestOptions, HttpRequestOptions,
HttpResponse, HttpResponse,
} from "./util/http.js"; } from "@gnu-taler/taler-util/http";
const logger = new Logger("dev-experiments.ts"); const logger = new Logger("dev-experiments.ts");

View File

@ -1,183 +0,0 @@
/*
This file is part of GNU Taler
(C) 2019 Taler Systems S.A.
GNU 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.
GNU 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
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
SPDX-License-Identifier: AGPL3.0-or-later
*/
/**
* Imports.
*/
import {
DEFAULT_REQUEST_TIMEOUT_MS,
Headers,
HttpRequestLibrary,
HttpRequestOptions,
HttpResponse,
} from "../util/http.js";
import { RequestThrottler } from "@gnu-taler/taler-util";
import axios, { AxiosResponse } from "axios";
import { TalerError } from "../errors.js";
import { Logger, bytesToString } from "@gnu-taler/taler-util";
import { TalerErrorCode, URL } from "@gnu-taler/taler-util";
const logger = new Logger("NodeHttpLib.ts");
/**
* Implementation of the HTTP request library interface for node.
*/
export class NodeHttpLib implements HttpRequestLibrary {
private throttle = new RequestThrottler();
private throttlingEnabled = true;
/**
* Set whether requests should be throttled.
*/
setThrottling(enabled: boolean): void {
this.throttlingEnabled = enabled;
}
async fetch(url: string, opt?: HttpRequestOptions): Promise<HttpResponse> {
const method = opt?.method ?? "GET";
let body = opt?.body;
logger.trace(`Requesting ${method} ${url}`);
const parsedUrl = new URL(url);
if (this.throttlingEnabled && this.throttle.applyThrottle(url)) {
throw TalerError.fromDetail(
TalerErrorCode.WALLET_HTTP_REQUEST_THROTTLED,
{
requestMethod: method,
requestUrl: url,
throttleStats: this.throttle.getThrottleStats(url),
},
`request to origin ${parsedUrl.origin} was throttled`,
);
}
let timeoutMs: number | undefined;
if (typeof opt?.timeout?.d_ms === "number") {
timeoutMs = opt.timeout.d_ms;
} else {
timeoutMs = DEFAULT_REQUEST_TIMEOUT_MS;
}
// FIXME: Use AbortController / etc. to handle cancellation
let resp: AxiosResponse;
try {
let respPromise = axios.default({
method,
url: url,
responseType: "arraybuffer",
headers: opt?.headers,
validateStatus: () => true,
transformResponse: (x) => x,
data: body,
timeout: timeoutMs,
maxRedirects: 0,
});
if (opt?.cancellationToken) {
respPromise = opt.cancellationToken.racePromise(respPromise);
}
resp = await respPromise;
} catch (e: any) {
throw TalerError.fromDetail(
TalerErrorCode.WALLET_NETWORK_ERROR,
{
requestUrl: url,
requestMethod: method,
},
`${e.message}`,
);
}
const makeText = async (): Promise<string> => {
opt?.cancellationToken?.throwIfCancelled();
const respText = new Uint8Array(resp.data);
return bytesToString(respText);
};
const makeJson = async (): Promise<any> => {
opt?.cancellationToken?.throwIfCancelled();
let responseJson;
const respText = await makeText();
try {
responseJson = JSON.parse(respText);
} catch (e) {
logger.trace(`invalid json: '${resp.data}'`);
throw TalerError.fromDetail(
TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE,
{
httpStatusCode: resp.status,
requestUrl: url,
requestMethod: method,
},
"Could not parse response body as JSON",
);
}
if (responseJson === null || typeof responseJson !== "object") {
logger.trace(`invalid json (not an object): '${respText}'`);
throw TalerError.fromDetail(
TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE,
{
httpStatusCode: resp.status,
requestUrl: url,
requestMethod: method,
},
`invalid JSON`,
);
}
return responseJson;
};
const makeBytes = async () => {
opt?.cancellationToken?.throwIfCancelled();
if (typeof resp.data.byteLength !== "number") {
throw Error("expected array buffer");
}
const buf = resp.data;
return buf;
};
const headers = new Headers();
for (const hn of Object.keys(resp.headers)) {
headers.set(hn, resp.headers[hn]);
}
return {
requestUrl: url,
requestMethod: method,
headers,
status: resp.status,
text: makeText,
json: makeJson,
bytes: makeBytes,
};
}
async get(url: string, opt?: HttpRequestOptions): Promise<HttpResponse> {
return this.fetch(url, {
method: "GET",
...opt,
});
}
async postJson(
url: string,
body: any,
opt?: HttpRequestOptions,
): Promise<HttpResponse> {
return this.fetch(url, {
method: "POST",
body,
...opt,
});
}
}

View File

@ -0,0 +1,60 @@
/*
This file is part of GNU Taler
(C) 2019 Taler Systems S.A.
GNU 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.
GNU 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
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
import { WalletNotification } from "@gnu-taler/taler-util";
import { HttpRequestLibrary } from "@gnu-taler/taler-util/http";
/**
* Helpers to initiate a wallet in a host environment.
*/
/**
*/
export interface DefaultNodeWalletArgs {
/**
* Location of the wallet database.
*
* If not specified, the wallet starts out with an empty database and
* the wallet database is stored only in memory.
*/
persistentStoragePath?: string;
/**
* Handler for asynchronous notifications from the wallet.
*/
notifyHandler?: (n: WalletNotification) => void;
/**
* If specified, use this as HTTP request library instead
* of the default one.
*/
httpLib?: HttpRequestLibrary;
cryptoWorkerType?: "sync" | "node-worker-thread";
}
/**
* Generate a random alphanumeric ID. Does *not* use cryptographically
* secure randomness.
*/
export function makeTempfileId(length: number): string {
let result = "";
const characters = "abcdefghijklmnopqrstuvwxyz0123456789";
for (let i = 0; i < length; i++) {
result += characters.charAt(Math.floor(Math.random() * characters.length));
}
return result;
}

View File

@ -30,70 +30,27 @@ import {
shimIndexedDB, shimIndexedDB,
} from "@gnu-taler/idb-bridge"; } from "@gnu-taler/idb-bridge";
import { AccessStats } from "@gnu-taler/idb-bridge"; import { AccessStats } from "@gnu-taler/idb-bridge";
import { Logger, WalletNotification } from "@gnu-taler/taler-util"; import { Logger } from "@gnu-taler/taler-util";
import * as fs from "fs"; import * as fs from "fs";
import { NodeThreadCryptoWorkerFactory } from "../crypto/workers/nodeThreadWorker.js"; import { NodeThreadCryptoWorkerFactory } from "./crypto/workers/nodeThreadWorker.js";
import { SynchronousCryptoWorkerFactoryNode } from "../crypto/workers/synchronousWorkerFactoryNode.js"; import { SynchronousCryptoWorkerFactoryPlain } from "./crypto/workers/synchronousWorkerFactoryPlain.js";
import { openTalerDatabase } from "../index.js"; import { openTalerDatabase } from "./index.js";
import { HttpRequestLibrary } from "../util/http.js"; import {
import { SetTimeoutTimerAPI } from "../util/timer.js"; createPlatformHttpLib,
import { Wallet } from "../wallet.js"; } from "@gnu-taler/taler-util/http";
import { NodeHttpLib } from "./NodeHttpLib.js"; import { SetTimeoutTimerAPI } from "./util/timer.js";
import { Wallet } from "./wallet.js";
import { DefaultNodeWalletArgs, makeTempfileId } from "./host-common.js";
const logger = new Logger("headless/helpers.ts"); const logger = new Logger("host-impl.node.ts");
export interface DefaultNodeWalletArgs {
/**
* Location of the wallet database.
*
* If not specified, the wallet starts out with an empty database and
* the wallet database is stored only in memory.
*/
persistentStoragePath?: string;
/**
* Handler for asynchronous notifications from the wallet.
*/
notifyHandler?: (n: WalletNotification) => void;
/**
* If specified, use this as HTTP request library instead
* of the default one.
*/
httpLib?: HttpRequestLibrary;
cryptoWorkerType?: "sync" | "node-worker-thread";
}
/**
* Generate a random alphanumeric ID. Does *not* use cryptographically
* secure randomness.
*/
function makeId(length: number): string {
let result = "";
const characters = "abcdefghijklmnopqrstuvwxyz0123456789";
for (let i = 0; i < length; i++) {
result += characters.charAt(Math.floor(Math.random() * characters.length));
}
return result;
}
/**
* Get a wallet instance with default settings for node.
*/
export async function getDefaultNodeWallet(
args: DefaultNodeWalletArgs = {},
): Promise<Wallet> {
const res = await getDefaultNodeWallet2(args);
return res.wallet;
}
/** /**
* Get a wallet instance with default settings for node. * Get a wallet instance with default settings for node.
* *
* Extended version that allows getting DB stats. * Extended version that allows getting DB stats.
*/ */
export async function getDefaultNodeWallet2( export async function createNativeWalletHost2(
args: DefaultNodeWalletArgs = {}, args: DefaultNodeWalletArgs = {},
): Promise<{ ): Promise<{
wallet: Wallet; wallet: Wallet;
@ -127,7 +84,8 @@ export async function getDefaultNodeWallet2(
if (args.persistentStoragePath === undefined) { if (args.persistentStoragePath === undefined) {
return; return;
} }
const tmpPath = `${args.persistentStoragePath}-${makeId(5)}.tmp`; const tmpPath = `${args.persistentStoragePath}-${makeTempfileId(5)}.tmp`;
logger.trace("exported DB dump");
const dbContent = myBackend.exportDump(); const dbContent = myBackend.exportDump();
fs.writeFileSync(tmpPath, JSON.stringify(dbContent, undefined, 2), { fs.writeFileSync(tmpPath, JSON.stringify(dbContent, undefined, 2), {
encoding: "utf-8", encoding: "utf-8",
@ -147,7 +105,9 @@ export async function getDefaultNodeWallet2(
if (args.httpLib) { if (args.httpLib) {
myHttpLib = args.httpLib; myHttpLib = args.httpLib;
} else { } else {
myHttpLib = new NodeHttpLib(); myHttpLib = createPlatformHttpLib({
enableThrottling: true,
});
} }
const myVersionChange = (): Promise<void> => { const myVersionChange = (): Promise<void> => {
@ -165,7 +125,7 @@ export async function getDefaultNodeWallet2(
const cryptoWorkerType = args.cryptoWorkerType ?? "node-worker-thread"; const cryptoWorkerType = args.cryptoWorkerType ?? "node-worker-thread";
if (cryptoWorkerType === "sync") { if (cryptoWorkerType === "sync") {
logger.info("using synchronous crypto worker"); logger.info("using synchronous crypto worker");
workerFactory = new SynchronousCryptoWorkerFactoryNode(); workerFactory = new SynchronousCryptoWorkerFactoryPlain();
} else if (cryptoWorkerType === "node-worker-thread") { } else if (cryptoWorkerType === "node-worker-thread") {
try { try {
// Try if we have worker threads available, fails in older node versions. // Try if we have worker threads available, fails in older node versions.
@ -179,7 +139,7 @@ export async function getDefaultNodeWallet2(
logger.warn( logger.warn(
"worker threads not available, falling back to synchronous workers", "worker threads not available, falling back to synchronous workers",
); );
workerFactory = new SynchronousCryptoWorkerFactoryNode(); workerFactory = new SynchronousCryptoWorkerFactoryPlain();
} }
} else { } else {
throw Error(`unsupported crypto worker type '${cryptoWorkerType}'`); throw Error(`unsupported crypto worker type '${cryptoWorkerType}'`);

View File

@ -0,0 +1,120 @@
/*
This file is part of GNU Taler
(C) 2019 Taler Systems S.A.
GNU 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.
GNU 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
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
/**
* Helpers to create headless wallets.
* @author Florian Dold <dold@taler.net>
*/
/**
* Imports.
*/
import type { IDBFactory } from "@gnu-taler/idb-bridge";
// eslint-disable-next-line no-duplicate-imports
import {
BridgeIDBFactory,
MemoryBackend,
shimIndexedDB,
} from "@gnu-taler/idb-bridge";
import { AccessStats } from "@gnu-taler/idb-bridge";
import { SynchronousCryptoWorkerFactoryPlain } from "./crypto/workers/synchronousWorkerFactoryPlain.js";
import { openTalerDatabase } from "./index.js";
import { Logger } from "@gnu-taler/taler-util";
import { createPlatformHttpLib } from "@gnu-taler/taler-util/http";
import { SetTimeoutTimerAPI } from "./util/timer.js";
import { Wallet } from "./wallet.js";
import { qjsOs, qjsStd } from "@gnu-taler/taler-util/qtart";
import { DefaultNodeWalletArgs, makeTempfileId } from "./host-common.js";
const logger = new Logger("host-impl.qtart.ts");
export async function createNativeWalletHost2(
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}-${makeTempfileId(5)}.tmp`;
const dbContent = myBackend.exportDump();
logger.trace("exported DB dump");
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");
};
}
logger.info("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 = createPlatformHttpLib();
}
const myVersionChange = (): Promise<void> => {
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,
};
}

View File

@ -0,0 +1,47 @@
/*
This file is part of GNU Taler
(C) 2019 Taler Systems S.A.
GNU 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.
GNU 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
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
import { DefaultNodeWalletArgs } from "./host-common.js";
import { Wallet } from "./index.js";
import * as hostImpl from "#host-impl";
import { AccessStats } from "@gnu-taler/idb-bridge";
/**
* Helpers to initiate a wallet in a host environment.
*/
/**
* Get a wallet instance.
*/
export async function createNativeWalletHost2(
args: DefaultNodeWalletArgs = {},
): Promise<{
wallet: Wallet;
getDbStats: () => AccessStats;
}> {
return hostImpl.createNativeWalletHost2(args);
}
/**
* Get a wallet instance.
*/
export async function createNativeWalletHost(
args: DefaultNodeWalletArgs = {},
): Promise<Wallet> {
const res = await hostImpl.createNativeWalletHost2(args);
return res.wallet;
}

View File

@ -16,15 +16,8 @@
export * from "./index.js"; export * from "./index.js";
// Utils for using the wallet under node
export { NodeHttpLib } from "./headless/NodeHttpLib.js";
export {
getDefaultNodeWallet,
getDefaultNodeWallet2,
DefaultNodeWalletArgs,
} from "./headless/helpers.js";
export * from "./crypto/workers/nodeThreadWorker.js"; export * from "./crypto/workers/nodeThreadWorker.js";
export { SynchronousCryptoWorkerNode as SynchronousCryptoWorker } from "./crypto/workers/synchronousWorkerNode.js"; export { SynchronousCryptoWorkerPlain } from "./crypto/workers/synchronousWorkerPlain.js";
export type { AccessStats } from "@gnu-taler/idb-bridge"; export type { AccessStats } from "@gnu-taler/idb-bridge";
export * from "./crypto/workers/synchronousWorkerFactoryNode.js"; export * from "./crypto/workers/synchronousWorkerFactoryPlain.js";

View File

@ -18,13 +18,9 @@
* Module entry point for the wallet when used as a node module. * Module entry point for the wallet when used as a node module.
*/ */
// Errors
export * from "./errors.js";
// Util functionality // Util functionality
export * from "./util/promiseUtils.js"; export * from "./util/promiseUtils.js";
export * from "./util/query.js"; export * from "./util/query.js";
export * from "./util/http.js";
export * from "./versions.js"; export * from "./versions.js";
@ -67,3 +63,5 @@ export * from "./util/timer.js";
export * from "./util/denominations.js"; export * from "./util/denominations.js";
export { SynchronousCryptoWorkerFactoryPlain } from "./crypto/workers/synchronousWorkerFactoryPlain.js"; export { SynchronousCryptoWorkerFactoryPlain } from "./crypto/workers/synchronousWorkerFactoryPlain.js";
export * from "./host-common.js";
export * from "./host.js";

View File

@ -30,18 +30,14 @@
* Imports. * Imports.
*/ */
import { import {
WalletNotification,
BalancesResponse,
AmountJson,
DenominationPubKey,
TalerProtocolTimestamp,
CancellationToken, CancellationToken,
CoinRefreshRequest,
DenominationInfo, DenominationInfo,
RefreshGroupId, RefreshGroupId,
CoinRefreshRequest,
RefreshReason, RefreshReason,
WalletNotification,
} from "@gnu-taler/taler-util"; } from "@gnu-taler/taler-util";
import { CryptoDispatcher } from "./crypto/workers/crypto-dispatcher.js"; import { HttpRequestLibrary } from "@gnu-taler/taler-util/http";
import { TalerCryptoInterface } from "./crypto/cryptoImplementation.js"; import { TalerCryptoInterface } from "./crypto/cryptoImplementation.js";
import { import {
ExchangeDetailsRecord, ExchangeDetailsRecord,
@ -49,9 +45,6 @@ import {
RefreshReasonDetails, RefreshReasonDetails,
WalletStoresV1, WalletStoresV1,
} from "./db.js"; } from "./db.js";
import { PendingOperationsResponse } from "./pending-types.js";
import { AsyncOpMemoMap, AsyncOpMemoSingle } from "./util/asyncMemo.js";
import { HttpRequestLibrary } from "./util/http.js";
import { AsyncCondition } from "./util/promiseUtils.js"; import { AsyncCondition } from "./util/promiseUtils.js";
import { import {
DbAccess, DbAccess,

View File

@ -85,13 +85,13 @@ import {
ConfigRecordKey, ConfigRecordKey,
WalletBackupConfState, WalletBackupConfState,
} from "../../db.js"; } from "../../db.js";
import { TalerError } from "../../errors.js"; import { TalerError } from "@gnu-taler/taler-util";
import { InternalWalletState } from "../../internal-wallet-state.js"; import { InternalWalletState } from "../../internal-wallet-state.js";
import { assertUnreachable } from "../../util/assertUnreachable.js"; import { assertUnreachable } from "../../util/assertUnreachable.js";
import { import {
readSuccessResponseJsonOrThrow, readSuccessResponseJsonOrThrow,
readTalerErrorResponse, readTalerErrorResponse,
} from "../../util/http.js"; } from "@gnu-taler/taler-util/http";
import { import {
checkDbInvariant, checkDbInvariant,
checkLogicInvariant, checkLogicInvariant,

View File

@ -42,7 +42,7 @@ import {
ExchangeDetailsRecord, ExchangeDetailsRecord,
ExchangeRecord, ExchangeRecord,
} from "../db.js"; } from "../db.js";
import { makeErrorDetail, TalerError } from "../errors.js"; import { makeErrorDetail, TalerError } from "@gnu-taler/taler-util";
import { InternalWalletState } from "../internal-wallet-state.js"; import { InternalWalletState } from "../internal-wallet-state.js";
import { checkDbInvariant, checkLogicInvariant } from "../util/invariants.js"; import { checkDbInvariant, checkLogicInvariant } from "../util/invariants.js";
import { GetReadWriteAccess } from "../util/query.js"; import { GetReadWriteAccess } from "../util/query.js";

View File

@ -62,10 +62,10 @@ import {
OperationStatus, OperationStatus,
TransactionStatus, TransactionStatus,
} from "../db.js"; } from "../db.js";
import { TalerError } from "../errors.js"; import { TalerError } from "@gnu-taler/taler-util";
import { checkWithdrawalKycStatus, KycPendingInfo, KycUserType } from "../index.js"; import { KycPendingInfo, KycUserType } from "../index.js";
import { InternalWalletState } from "../internal-wallet-state.js"; import { InternalWalletState } from "../internal-wallet-state.js";
import { readSuccessResponseJsonOrThrow } from "../util/http.js"; import { readSuccessResponseJsonOrThrow } from "@gnu-taler/taler-util/http";
import { OperationAttemptResult } from "../util/retries.js"; import { OperationAttemptResult } from "../util/retries.js";
import { makeTransactionId, spendCoins } from "./common.js"; import { makeTransactionId, spendCoins } from "./common.js";
import { getExchangeDetails } from "./exchanges.js"; import { getExchangeDetails } from "./exchanges.js";

View File

@ -41,6 +41,7 @@ import {
NotificationType, NotificationType,
parsePaytoUri, parsePaytoUri,
Recoup, Recoup,
TalerError,
TalerErrorCode, TalerErrorCode,
TalerProtocolDuration, TalerProtocolDuration,
TalerProtocolTimestamp, TalerProtocolTimestamp,
@ -49,6 +50,7 @@ import {
WireFeeMap, WireFeeMap,
WireInfo, WireInfo,
} from "@gnu-taler/taler-util"; } from "@gnu-taler/taler-util";
import { HttpRequestLibrary, readSuccessResponseTextOrThrow, readSuccessResponseJsonOrThrow, getExpiry } from "@gnu-taler/taler-util/http";
import { import {
DenominationRecord, DenominationRecord,
DenominationVerificationStatus, DenominationVerificationStatus,
@ -56,14 +58,7 @@ import {
ExchangeRecord, ExchangeRecord,
WalletStoresV1, WalletStoresV1,
} from "../db.js"; } from "../db.js";
import { TalerError } from "../errors.js";
import { InternalWalletState, TrustInfo } from "../internal-wallet-state.js"; import { InternalWalletState, TrustInfo } from "../internal-wallet-state.js";
import {
getExpiry,
HttpRequestLibrary,
readSuccessResponseJsonOrThrow,
readSuccessResponseTextOrThrow,
} from "../util/http.js";
import { checkDbInvariant } from "../util/invariants.js"; import { checkDbInvariant } from "../util/invariants.js";
import { import {
DbAccess, DbAccess,

View File

@ -25,7 +25,7 @@ import {
LibtoolVersion, LibtoolVersion,
} from "@gnu-taler/taler-util"; } from "@gnu-taler/taler-util";
import { InternalWalletState, MerchantInfo } from "../internal-wallet-state.js"; import { InternalWalletState, MerchantInfo } from "../internal-wallet-state.js";
import { readSuccessResponseJsonOrThrow } from "../util/http.js"; import { readSuccessResponseJsonOrThrow } from "@gnu-taler/taler-util/http";
const logger = new Logger("taler-wallet-core:merchants.ts"); const logger = new Logger("taler-wallet-core:merchants.ts");

View File

@ -94,13 +94,12 @@ import {
makePendingOperationFailedError, makePendingOperationFailedError,
TalerError, TalerError,
TalerProtocolViolationError, TalerProtocolViolationError,
} from "../errors.js"; } from "@gnu-taler/taler-util";
import { GetReadWriteAccess } from "../index.browser.js"; import { GetReadWriteAccess } from "../index.js";
import { import {
EXCHANGE_COINS_LOCK, EXCHANGE_COINS_LOCK,
InternalWalletState, InternalWalletState,
} from "../internal-wallet-state.js"; } from "../internal-wallet-state.js";
import { PendingTaskType } from "../pending-types.js";
import { assertUnreachable } from "../util/assertUnreachable.js"; import { assertUnreachable } from "../util/assertUnreachable.js";
import { import {
CoinSelectionTally, CoinSelectionTally,
@ -114,7 +113,7 @@ import {
readTalerErrorResponse, readTalerErrorResponse,
readUnexpectedResponseDetails, readUnexpectedResponseDetails,
throwUnexpectedRequestError, throwUnexpectedRequestError,
} from "../util/http.js"; } from "@gnu-taler/taler-util/http";
import { checkDbInvariant, checkLogicInvariant } from "../util/invariants.js"; import { checkDbInvariant, checkLogicInvariant } from "../util/invariants.js";
import { import {
OperationAttemptResult, OperationAttemptResult,

View File

@ -81,16 +81,15 @@ import {
WithdrawalGroupStatus, WithdrawalGroupStatus,
WithdrawalRecordType, WithdrawalRecordType,
} from "../db.js"; } from "../db.js";
import { TalerError } from "../errors.js"; import { TalerError } from "@gnu-taler/taler-util";
import { InternalWalletState } from "../internal-wallet-state.js"; import { InternalWalletState } from "../internal-wallet-state.js";
import { import {
makeTransactionId, makeTransactionId,
runOperationWithErrorReporting, runOperationWithErrorReporting,
spendCoins, spendCoins,
} from "../operations/common.js"; } from "../operations/common.js";
import { readSuccessResponseJsonOrThrow } from "../util/http.js"; import { readSuccessResponseJsonOrThrow } from "@gnu-taler/taler-util/http";
import { checkDbInvariant } from "../util/invariants.js"; import { checkDbInvariant } from "../util/invariants.js";
import { GetReadOnlyAccess } from "../util/query.js";
import { import {
OperationAttemptResult, OperationAttemptResult,
OperationAttemptResultType, OperationAttemptResultType,

View File

@ -49,7 +49,7 @@ import {
WithdrawCoinSource, WithdrawCoinSource,
} from "../db.js"; } from "../db.js";
import { InternalWalletState } from "../internal-wallet-state.js"; import { InternalWalletState } from "../internal-wallet-state.js";
import { readSuccessResponseJsonOrThrow } from "../util/http.js"; import { readSuccessResponseJsonOrThrow } from "@gnu-taler/taler-util/http";
import { checkDbInvariant } from "../util/invariants.js"; import { checkDbInvariant } from "../util/invariants.js";
import { GetReadWriteAccess } from "../util/query.js"; import { GetReadWriteAccess } from "../util/query.js";
import { import {

View File

@ -63,7 +63,7 @@ import {
RefreshReasonDetails, RefreshReasonDetails,
WalletStoresV1, WalletStoresV1,
} from "../db.js"; } from "../db.js";
import { TalerError } from "../errors.js"; import { TalerError } from "@gnu-taler/taler-util";
import { import {
EXCHANGE_COINS_LOCK, EXCHANGE_COINS_LOCK,
InternalWalletState, InternalWalletState,
@ -72,7 +72,7 @@ import { assertUnreachable } from "../util/assertUnreachable.js";
import { import {
readSuccessResponseJsonOrThrow, readSuccessResponseJsonOrThrow,
readUnexpectedResponseDetails, readUnexpectedResponseDetails,
} from "../util/http.js"; } from "@gnu-taler/taler-util/http";
import { checkDbInvariant } from "../util/invariants.js"; import { checkDbInvariant } from "../util/invariants.js";
import { GetReadWriteAccess } from "../util/query.js"; import { GetReadWriteAccess } from "../util/query.js";
import { import {

View File

@ -29,7 +29,7 @@ import {
HttpRequestLibrary, HttpRequestLibrary,
readSuccessResponseJsonOrThrow, readSuccessResponseJsonOrThrow,
checkSuccessResponseOrThrow, checkSuccessResponseOrThrow,
} from "../util/http.js"; } from "@gnu-taler/taler-util/http";
import { import {
AmountString, AmountString,
codecForAny, codecForAny,

View File

@ -45,12 +45,12 @@ import {
DenominationRecord, DenominationRecord,
TipRecord, TipRecord,
} from "../db.js"; } from "../db.js";
import { makeErrorDetail } from "../errors.js"; import { makeErrorDetail } from "@gnu-taler/taler-util";
import { InternalWalletState } from "../internal-wallet-state.js"; import { InternalWalletState } from "../internal-wallet-state.js";
import { import {
getHttpResponseErrorDetails, getHttpResponseErrorDetails,
readSuccessResponseJsonOrThrow, readSuccessResponseJsonOrThrow,
} from "../util/http.js"; } from "@gnu-taler/taler-util/http";
import { checkDbInvariant, checkLogicInvariant } from "../util/invariants.js"; import { checkDbInvariant, checkLogicInvariant } from "../util/invariants.js";
import { import {
OperationAttemptResult, OperationAttemptResult,

View File

@ -85,7 +85,7 @@ import {
getErrorDetailFromException, getErrorDetailFromException,
makeErrorDetail, makeErrorDetail,
TalerError, TalerError,
} from "../errors.js"; } from "@gnu-taler/taler-util";
import { InternalWalletState } from "../internal-wallet-state.js"; import { InternalWalletState } from "../internal-wallet-state.js";
import { import {
makeCoinAvailable, makeCoinAvailable,
@ -99,7 +99,7 @@ import {
readSuccessResponseJsonOrErrorCode, readSuccessResponseJsonOrErrorCode,
readSuccessResponseJsonOrThrow, readSuccessResponseJsonOrThrow,
throwUnexpectedRequestError, throwUnexpectedRequestError,
} from "../util/http.js"; } from "@gnu-taler/taler-util/http";
import { import {
checkDbInvariant, checkDbInvariant,
checkLogicInvariant, checkLogicInvariant,

View File

@ -19,10 +19,10 @@ import {
CoreApiResponse, CoreApiResponse,
j2s, j2s,
Logger, Logger,
TalerError,
WalletNotification, WalletNotification,
} from "@gnu-taler/taler-util"; } from "@gnu-taler/taler-util";
import { connectRpc, JsonMessage } from "@gnu-taler/taler-util/twrpc"; import { connectRpc, JsonMessage } from "@gnu-taler/taler-util/twrpc";
import { TalerError } from "./errors.js";
import { OpenedPromise, openPromise } from "./index.js"; import { OpenedPromise, openPromise } from "./index.js";
import { WalletCoreApiClient } from "./wallet-api-types.js"; import { WalletCoreApiClient } from "./wallet-api-types.js";

View File

@ -40,7 +40,7 @@ import {
WalletStoresV1, WalletStoresV1,
WithdrawalGroupRecord, WithdrawalGroupRecord,
} from "../db.js"; } from "../db.js";
import { TalerError } from "../errors.js"; import { TalerError } from "@gnu-taler/taler-util";
import { InternalWalletState } from "../internal-wallet-state.js"; import { InternalWalletState } from "../internal-wallet-state.js";
import { PendingTaskType } from "../pending-types.js"; import { PendingTaskType } from "../pending-types.js";
import { GetReadWriteAccess } from "./query.js"; import { GetReadWriteAccess } from "./query.js";

View File

@ -129,7 +129,7 @@ import {
maybeInitDevMode, maybeInitDevMode,
setDevMode, setDevMode,
} from "./dev-experiments.js"; } from "./dev-experiments.js";
import { getErrorDetailFromException, TalerError } from "./errors.js"; import { getErrorDetailFromException, TalerError } from "@gnu-taler/taler-util";
import { import {
ActiveLongpollInfo, ActiveLongpollInfo,
ExchangeOperations, ExchangeOperations,
@ -247,7 +247,7 @@ import {
import { import {
HttpRequestLibrary, HttpRequestLibrary,
readSuccessResponseJsonOrThrow, readSuccessResponseJsonOrThrow,
} from "./util/http.js"; } from "@gnu-taler/taler-util/http";
import { checkDbInvariant } from "./util/invariants.js"; import { checkDbInvariant } from "./util/invariants.js";
import { import {
AsyncCondition, AsyncCondition,

View File

@ -55,6 +55,7 @@ export const buildConfig = {
format: 'esm', format: 'esm',
platform: 'neutral', platform: 'neutral',
mainFields: ["module", "main"], mainFields: ["module", "main"],
conditions: ["qtart"],
sourcemap: true, sourcemap: true,
define: { define: {
'__VERSION__': `"${_package.version}"`, '__VERSION__': `"${_package.version}"`,

View File

@ -18,27 +18,25 @@
* Imports. * Imports.
*/ */
import { import {
createNativeWalletHost,
DefaultNodeWalletArgs, DefaultNodeWalletArgs,
getDefaultNodeWallet,
getErrorDetailFromException,
handleWorkerError, handleWorkerError,
handleWorkerMessage, handleWorkerMessage,
Headers,
HttpRequestLibrary,
HttpRequestOptions,
HttpResponse,
NodeHttpLib,
OpenedPromise, OpenedPromise,
openPromise, openPromise,
Wallet, Wallet,
WALLET_EXCHANGE_PROTOCOL_VERSION,
WALLET_MERCHANT_PROTOCOL_VERSION,
} from "@gnu-taler/taler-wallet-core"; } from "@gnu-taler/taler-wallet-core";
import { import {
CoreApiMessageEnvelope, CoreApiMessageEnvelope,
CoreApiResponse, CoreApiResponse,
CoreApiResponseSuccess, CoreApiResponseSuccess,
createPlatformHttpLib,
getErrorDetailFromException,
Headers,
HttpRequestLibrary,
HttpRequestOptions,
HttpResponse,
Logger, Logger,
WalletNotification, WalletNotification,
} from "@gnu-taler/taler-util"; } from "@gnu-taler/taler-util";
@ -51,7 +49,7 @@ const logger = new Logger("taler-wallet-embedded/index.ts");
export class NativeHttpLib implements HttpRequestLibrary { export class NativeHttpLib implements HttpRequestLibrary {
useNfcTunnel = false; useNfcTunnel = false;
private nodeHttpLib: HttpRequestLibrary = new NodeHttpLib(); private httpLib: HttpRequestLibrary = createPlatformHttpLib();
private requestId = 1; private requestId = 1;
@ -62,7 +60,7 @@ export class NativeHttpLib implements HttpRequestLibrary {
constructor(private sendMessage: (m: string) => void) {} constructor(private sendMessage: (m: string) => void) {}
fetch(url: string, opt?: HttpRequestOptions): Promise<HttpResponse> { fetch(url: string, opt?: HttpRequestOptions): Promise<HttpResponse> {
return this.nodeHttpLib.fetch(url, opt); return this.httpLib.fetch(url, opt);
} }
get(url: string, opt?: HttpRequestOptions): Promise<HttpResponse> { get(url: string, opt?: HttpRequestOptions): Promise<HttpResponse> {
@ -83,7 +81,7 @@ export class NativeHttpLib implements HttpRequestLibrary {
); );
return p.promise; return p.promise;
} else { } 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; return p.promise;
} else { } else {
return this.nodeHttpLib.postJson(url, body, opt); return this.httpLib.postJson(url, body, opt);
} }
} }
@ -158,7 +156,7 @@ class NativeWalletMessageHandler {
walletArgs: DefaultNodeWalletArgs | undefined; walletArgs: DefaultNodeWalletArgs | undefined;
maybeWallet: Wallet | undefined; maybeWallet: Wallet | undefined;
wp = openPromise<Wallet>(); wp = openPromise<Wallet>();
httpLib = new NodeHttpLib(); httpLib = createPlatformHttpLib();
/** /**
* Handle a request from the native wallet. * Handle a request from the native wallet.
@ -181,7 +179,7 @@ class NativeWalletMessageHandler {
const reinit = async () => { const reinit = async () => {
logger.info("in reinit"); logger.info("in reinit");
const w = await getDefaultNodeWallet(this.walletArgs); const w = await createNativeWalletHost(this.walletArgs);
this.maybeWallet = w; this.maybeWallet = w;
const resp = await w.handleCoreApiRequest( const resp = await w.handleCoreApiRequest(
"initWallet", "initWallet",

View File

@ -17,44 +17,26 @@
/** /**
* Imports. * Imports.
*/ */
import {
AccessStats,
DefaultNodeWalletArgs,
getErrorDetailFromException,
Headers,
HttpRequestLibrary,
HttpRequestOptions,
HttpResponse,
openPromise,
openTalerDatabase,
SetTimeoutTimerAPI,
SynchronousCryptoWorkerFactoryPlain,
Wallet,
WalletApiOperation,
} from "@gnu-taler/taler-wallet-core";
import { import {
CoreApiMessageEnvelope, CoreApiMessageEnvelope,
CoreApiResponse, CoreApiResponse,
CoreApiResponseSuccess, CoreApiResponseSuccess,
createPlatformHttpLib,
getErrorDetailFromException,
InitRequest, InitRequest,
j2s,
Logger, Logger,
setGlobalLogLevelFromString, setGlobalLogLevelFromString,
setPRNG, setPRNG,
WalletNotification, WalletNotification,
} from "@gnu-taler/taler-util"; } from "@gnu-taler/taler-util";
import { BridgeIDBFactory } from "@gnu-taler/idb-bridge"; import { qjsOs } from "@gnu-taler/taler-util/qtart";
import { MemoryBackend } from "@gnu-taler/idb-bridge"; import {
import { shimIndexedDB } from "@gnu-taler/idb-bridge"; createNativeWalletHost2,
import { IDBFactory } from "@gnu-taler/idb-bridge"; DefaultNodeWalletArgs,
openPromise,
import * as _qjsOsImp from "os"; Wallet,
// @ts-ignore WalletApiOperation,
import * as _qjsStdImp from "std"; } from "@gnu-taler/taler-wallet-core";
const textDecoder = new TextDecoder();
const textEncoder = new TextEncoder();
setGlobalLogLevelFromString("trace"); setGlobalLogLevelFromString("trace");
@ -66,210 +48,19 @@ setPRNG(function (x: Uint8Array, n: number) {
for (let i = 0; i < v.length; i++) v[i] = 0; 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<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;
const qjsStd: QjsStdLib = _qjsStdImp as any;
const logger = new Logger("taler-wallet-embedded/index.ts"); const logger = new Logger("taler-wallet-embedded/index.ts");
export class NativeHttpLib implements HttpRequestLibrary {
get(
url: string,
opt?: HttpRequestOptions | undefined,
): Promise<HttpResponse> {
return this.fetch(url, {
method: "GET",
...opt,
});
}
postJson(
url: string,
body: any,
opt?: HttpRequestOptions | undefined,
): Promise<HttpResponse> {
return this.fetch(url, {
method: "POST",
body,
...opt,
});
}
async fetch(
url: string,
opt?: HttpRequestOptions | undefined,
): Promise<HttpResponse> {
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 { function sendNativeMessage(ev: CoreApiMessageEnvelope): void {
const m = JSON.stringify(ev); const m = JSON.stringify(ev);
qjsOs.postMessageToHost(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<{
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<void> => {
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 { class NativeWalletMessageHandler {
walletArgs: DefaultNodeWalletArgs | undefined; walletArgs: DefaultNodeWalletArgs | undefined;
initRequest: InitRequest = {}; initRequest: InitRequest = {};
maybeWallet: Wallet | undefined; maybeWallet: Wallet | undefined;
wp = openPromise<Wallet>(); wp = openPromise<Wallet>();
httpLib = new NativeHttpLib(); httpLib = createPlatformHttpLib();
/** /**
* Handle a request from the native wallet. * Handle a request from the native wallet.
@ -292,7 +83,7 @@ class NativeWalletMessageHandler {
const reinit = async () => { const reinit = async () => {
logger.info("in reinit"); logger.info("in reinit");
const wR = await getWallet(this.walletArgs); const wR = await createNativeWalletHost2(this.walletArgs);
const w = wR.wallet; const w = wR.wallet;
this.maybeWallet = w; this.maybeWallet = w;
const resp = await w.handleCoreApiRequest("initWallet", "native-init", { const resp = await w.handleCoreApiRequest("initWallet", "native-init", {
@ -422,7 +213,7 @@ globalThis.installNativeWalletListener = installNativeWalletListener;
globalThis.makeWallet = getWallet; globalThis.makeWallet = getWallet;
export async function testWithGv() { 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.InitWallet, {});
await w.wallet.client.call(WalletApiOperation.RunIntegrationTest, { await w.wallet.client.call(WalletApiOperation.RunIntegrationTest, {
amountToSpend: "KUDOS:1", amountToSpend: "KUDOS:1",
@ -438,7 +229,7 @@ export async function testWithGv() {
export async function testWithLocal() { export async function testWithLocal() {
console.log("running local test"); console.log("running local test");
const w = await getWallet({ const w = await createNativeWalletHost2({
persistentStoragePath: "walletdb.json", persistentStoragePath: "walletdb.json",
}); });
console.log("created wallet"); console.log("created wallet");

View File

@ -18,19 +18,17 @@
* Imports. * Imports.
*/ */
import { import {
Logger,
RequestThrottler,
TalerErrorCode,
HttpRequestLibrary, HttpRequestLibrary,
HttpRequestOptions, HttpRequestOptions,
HttpResponse, HttpResponse,
Headers, Headers,
TalerError, TalerError,
} from "@gnu-taler/taler-wallet-core";
import {
Logger,
RequestThrottler,
stringToBytes,
TalerErrorCode,
} from "@gnu-taler/taler-util"; } from "@gnu-taler/taler-util";
const logger = new Logger("browserHttpLib"); const logger = new Logger("browserHttpLib");
/** /**

View File

@ -22,11 +22,12 @@
* Imports. * Imports.
*/ */
import { j2s, Logger } from "@gnu-taler/taler-util";
import { import {
j2s,
Logger,
getErrorDetailFromException, getErrorDetailFromException,
nativeCrypto, } from "@gnu-taler/taler-util";
} from "@gnu-taler/taler-wallet-core"; import { nativeCrypto } from "@gnu-taler/taler-wallet-core";
const logger = new Logger("browserWorkerEntry.ts"); const logger = new Logger("browserWorkerEntry.ts");

View File

@ -16,7 +16,7 @@
/* eslint-disable react-hooks/rules-of-hooks */ /* eslint-disable react-hooks/rules-of-hooks */
import { Amounts, TalerProtocolTimestamp } from "@gnu-taler/taler-util"; import { Amounts, TalerProtocolTimestamp } from "@gnu-taler/taler-util";
import { TalerError, WalletApiOperation } from "@gnu-taler/taler-wallet-core"; import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
import { isFuture, parse } from "date-fns"; import { isFuture, parse } from "date-fns";
import { useState } from "preact/hooks"; import { useState } from "preact/hooks";
import { alertFromError, useAlertContext } from "../../context/alert.js"; import { alertFromError, useAlertContext } from "../../context/alert.js";

View File

@ -20,16 +20,14 @@ import {
NotificationType, NotificationType,
PreparePayResult, PreparePayResult,
PreparePayResultType, PreparePayResultType,
TalerErrorDetail,
TalerProtocolTimestamp, TalerProtocolTimestamp,
} from "@gnu-taler/taler-util"; } from "@gnu-taler/taler-util";
import { TalerError, WalletApiOperation } from "@gnu-taler/taler-wallet-core"; import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
import { useEffect, useState } from "preact/hooks"; import { useEffect } from "preact/hooks";
import { alertFromError, useAlertContext } from "../../context/alert.js"; import { alertFromError, useAlertContext } from "../../context/alert.js";
import { useBackendContext } from "../../context/backend.js"; import { useBackendContext } from "../../context/backend.js";
import { useTranslationContext } from "../../context/translation.js"; import { useTranslationContext } from "../../context/translation.js";
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js"; import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
import { withSafe } from "../../mui/handlers.js";
import { Props, State } from "./index.js"; import { Props, State } from "./index.js";
export function useComponentState({ export function useComponentState({

View File

@ -15,11 +15,9 @@
*/ */
import { import {
Amounts, Amounts, TalerProtocolTimestamp
TalerErrorDetail,
TalerProtocolTimestamp,
} from "@gnu-taler/taler-util"; } from "@gnu-taler/taler-util";
import { TalerError, WalletApiOperation } from "@gnu-taler/taler-wallet-core"; import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
import { isFuture, parse } from "date-fns"; import { isFuture, parse } from "date-fns";
import { useState } from "preact/hooks"; import { useState } from "preact/hooks";
import { alertFromError, useAlertContext } from "../../context/alert.js"; import { alertFromError, useAlertContext } from "../../context/alert.js";

View File

@ -16,12 +16,9 @@
import { import {
AbsoluteTime, AbsoluteTime,
Amounts, Amounts, TalerProtocolTimestamp
TalerErrorDetail,
TalerProtocolTimestamp,
} from "@gnu-taler/taler-util"; } from "@gnu-taler/taler-util";
import { TalerError, WalletApiOperation } from "@gnu-taler/taler-wallet-core"; import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
import { useState } from "preact/hooks";
import { alertFromError, useAlertContext } from "../../context/alert.js"; import { alertFromError, useAlertContext } from "../../context/alert.js";
import { useBackendContext } from "../../context/backend.js"; import { useBackendContext } from "../../context/backend.js";
import { useTranslationContext } from "../../context/translation.js"; import { useTranslationContext } from "../../context/translation.js";

View File

@ -20,8 +20,9 @@ import {
Amounts, Amounts,
ExchangeListItem, ExchangeListItem,
ExchangeTosStatus, ExchangeTosStatus,
TalerError,
} from "@gnu-taler/taler-util"; } from "@gnu-taler/taler-util";
import { TalerError, WalletApiOperation } from "@gnu-taler/taler-wallet-core"; import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
import { useState } from "preact/hooks"; import { useState } from "preact/hooks";
import { alertFromError, useAlertContext } from "../../context/alert.js"; import { alertFromError, useAlertContext } from "../../context/alert.js";
import { useBackendContext } from "../../context/backend.js"; import { useBackendContext } from "../../context/backend.js";

View File

@ -13,8 +13,7 @@
You should have received a copy of the GNU General Public License along with You should have received a copy of the GNU General Public License along with
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/ */
import { TalerErrorDetail } from "@gnu-taler/taler-util"; import { TalerErrorDetail, TalerError } from "@gnu-taler/taler-util";
import { TalerError } from "@gnu-taler/taler-wallet-core";
import { useEffect, useMemo, useState } from "preact/hooks"; import { useEffect, useMemo, useState } from "preact/hooks";
import { BackgroundError } from "../wxApi.js"; import { BackgroundError } from "../wxApi.js";

View File

@ -19,8 +19,9 @@ import {
Logger, Logger,
TalerErrorCode, TalerErrorCode,
TalerUriType, TalerUriType,
TalerError,
} from "@gnu-taler/taler-util"; } from "@gnu-taler/taler-util";
import { TalerError, WalletOperations } from "@gnu-taler/taler-wallet-core"; import { WalletOperations } from "@gnu-taler/taler-wallet-core";
import { BackgroundOperations } from "../wxApi.js"; import { BackgroundOperations } from "../wxApi.js";
import { import {
BackgroundPlatformAPI, BackgroundPlatformAPI,

View File

@ -22,12 +22,12 @@
import { import {
CryptoWorker, CryptoWorker,
CryptoWorkerFactory, CryptoWorkerFactory,
SynchronousCryptoWorker, SynchronousCryptoWorkerPlain,
} from "@gnu-taler/taler-wallet-core"; } from "@gnu-taler/taler-wallet-core";
export class SynchronousCryptoWorkerFactory implements CryptoWorkerFactory { export class SynchronousCryptoWorkerFactory implements CryptoWorkerFactory {
startWorker(): CryptoWorker { startWorker(): CryptoWorker {
return new SynchronousCryptoWorker(); return new SynchronousCryptoWorkerPlain();
} }
getConcurrency(): number { getConcurrency(): number {

View File

@ -21,14 +21,12 @@ import {
Logger, Logger,
RequestThrottler, RequestThrottler,
TalerErrorCode, TalerErrorCode,
} from "@gnu-taler/taler-util";
import {
Headers, Headers,
HttpRequestLibrary, HttpRequestLibrary,
HttpRequestOptions, HttpRequestOptions,
HttpResponse, HttpResponse,
TalerError, TalerError,
} from "@gnu-taler/taler-wallet-core"; } from "@gnu-taler/taler-util";
/** /**
* An implementation of the [[HttpRequestLibrary]] using the * An implementation of the [[HttpRequestLibrary]] using the

View File

@ -29,20 +29,18 @@ import {
NotificationType, NotificationType,
TalerErrorCode, TalerErrorCode,
TalerErrorDetail, TalerErrorDetail,
WalletDiagnostics, WalletDiagnostics
} from "@gnu-taler/taler-util"; } from "@gnu-taler/taler-util";
import { import {
TalerError,
WalletCoreApiClient, WalletCoreApiClient,
WalletCoreOpKeys, WalletCoreOpKeys,
WalletCoreRequestType, WalletCoreRequestType,
WalletCoreResponseType, WalletCoreResponseType
WalletOperations,
} from "@gnu-taler/taler-wallet-core"; } from "@gnu-taler/taler-wallet-core";
import { import {
MessageFromBackend, MessageFromBackend,
MessageFromFrontendBackground, MessageFromFrontendBackground,
MessageFromFrontendWallet, MessageFromFrontendWallet
} from "./platform/api.js"; } from "./platform/api.js";
import { platform } from "./platform/foreground.js"; import { platform } from "./platform/foreground.js";

View File

@ -32,14 +32,14 @@ import {
TalerErrorCode, TalerErrorCode,
TalerUriType, TalerUriType,
WalletDiagnostics, WalletDiagnostics,
makeErrorDetail,
getErrorDetailFromException,
} from "@gnu-taler/taler-util"; } from "@gnu-taler/taler-util";
import { import {
DbAccess, DbAccess,
deleteTalerDatabase, deleteTalerDatabase,
exportDb, exportDb,
getErrorDetailFromException,
importDb, importDb,
makeErrorDetail,
OpenedPromise, OpenedPromise,
openPromise, openPromise,
openTalerDatabase, openTalerDatabase,