summaryrefslogtreecommitdiff
path: root/packages/taler-wallet-embedded/src/wallet-qjs.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/taler-wallet-embedded/src/wallet-qjs.ts')
-rw-r--r--packages/taler-wallet-embedded/src/wallet-qjs.ts237
1 files changed, 14 insertions, 223 deletions
diff --git a/packages/taler-wallet-embedded/src/wallet-qjs.ts b/packages/taler-wallet-embedded/src/wallet-qjs.ts
index f7b73711c..77d166095 100644
--- a/packages/taler-wallet-embedded/src/wallet-qjs.ts
+++ b/packages/taler-wallet-embedded/src/wallet-qjs.ts
@@ -18,43 +18,25 @@
* Imports.
*/
import {
- AccessStats,
- DefaultNodeWalletArgs,
- getErrorDetailFromException,
- Headers,
- HttpRequestLibrary,
- HttpRequestOptions,
- HttpResponse,
- openPromise,
- openTalerDatabase,
- SetTimeoutTimerAPI,
- SynchronousCryptoWorkerFactoryPlain,
- Wallet,
- WalletApiOperation,
-} from "@gnu-taler/taler-wallet-core";
-
-import {
CoreApiMessageEnvelope,
CoreApiResponse,
CoreApiResponseSuccess,
+ createPlatformHttpLib,
+ getErrorDetailFromException,
InitRequest,
- j2s,
Logger,
setGlobalLogLevelFromString,
setPRNG,
WalletNotification,
} from "@gnu-taler/taler-util";
-import { BridgeIDBFactory } from "@gnu-taler/idb-bridge";
-import { MemoryBackend } from "@gnu-taler/idb-bridge";
-import { shimIndexedDB } from "@gnu-taler/idb-bridge";
-import { IDBFactory } from "@gnu-taler/idb-bridge";
-
-import * as _qjsOsImp from "os";
-// @ts-ignore
-import * as _qjsStdImp from "std";
-
-const textDecoder = new TextDecoder();
-const textEncoder = new TextEncoder();
+import { qjsOs } from "@gnu-taler/taler-util/qtart";
+import {
+ createNativeWalletHost2,
+ DefaultNodeWalletArgs,
+ openPromise,
+ Wallet,
+ WalletApiOperation,
+} from "@gnu-taler/taler-wallet-core";
setGlobalLogLevelFromString("trace");
@@ -66,210 +48,19 @@ setPRNG(function (x: Uint8Array, n: number) {
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");
-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 {
const m = JSON.stringify(ev);
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 {
walletArgs: DefaultNodeWalletArgs | undefined;
initRequest: InitRequest = {};
maybeWallet: Wallet | undefined;
wp = openPromise<Wallet>();
- httpLib = new NativeHttpLib();
+ httpLib = createPlatformHttpLib();
/**
* Handle a request from the native wallet.
@@ -292,7 +83,7 @@ class NativeWalletMessageHandler {
const reinit = async () => {
logger.info("in reinit");
- const wR = await getWallet(this.walletArgs);
+ const wR = await createNativeWalletHost2(this.walletArgs);
const w = wR.wallet;
this.maybeWallet = w;
const resp = await w.handleCoreApiRequest("initWallet", "native-init", {
@@ -422,7 +213,7 @@ globalThis.installNativeWalletListener = installNativeWalletListener;
globalThis.makeWallet = getWallet;
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.RunIntegrationTest, {
amountToSpend: "KUDOS:1",
@@ -438,7 +229,7 @@ export async function testWithGv() {
export async function testWithLocal() {
console.log("running local test");
- const w = await getWallet({
+ const w = await createNativeWalletHost2({
persistentStoragePath: "walletdb.json",
});
console.log("created wallet");