-qjs fixes

This commit is contained in:
Florian Dold 2023-01-03 10:51:05 +01:00
parent 9ad1f2712a
commit f26cbe7c1f
No known key found for this signature in database
GPG Key ID: D2E4F00F29D02A4B
3 changed files with 61 additions and 49 deletions

View File

@ -1632,7 +1632,7 @@ class InternalWalletStateImpl implements InternalWalletState {
}
notify(n: WalletNotification): void {
logger.trace("Notification", n);
logger.trace("Notification", j2s(n));
for (const l of this.listeners) {
const nc = JSON.parse(JSON.stringify(n));
setTimeout(() => {

View File

@ -51,7 +51,7 @@ export const buildConfig = {
target: [
'es2020'
],
external: ["os"],
external: ["os", "std"],
format: 'esm',
platform: 'neutral',
mainFields: ["module", "main"],

View File

@ -21,8 +21,6 @@ import {
AccessStats,
DefaultNodeWalletArgs,
getErrorDetailFromException,
handleWorkerError,
handleWorkerMessage,
Headers,
HttpRequestLibrary,
HttpRequestOptions,
@ -51,6 +49,8 @@ import { shimIndexedDB } from "@gnu-taler/idb-bridge";
import { IDBFactory } from "@gnu-taler/idb-bridge";
import * as _qjsOsImp from "os";
// @ts-ignore
import * as _qjsStdImp from "std";
const textDecoder = new TextDecoder();
const textEncoder = new TextEncoder();
@ -80,12 +80,20 @@ export interface QjsHttpOptions {
export interface QjsOsLib {
// Not async!
fetchHttp(url: string, options?: QjsHttpOptions): QjsHttpResp;
postMessageToHost(s: string): void;
setMessageFromHostHandler(h: (s: string) => void): void;
rename(oldPath: string, newPath: string): number;
}
export interface QjsStdLib {
writeFile(filename: string, contents: string): void;
loadFile(filename: string): string;
}
// This is not the nodejs "os" module, but the qjs "os" module.
const qjsOs: QjsOsLib = _qjsOsImp as any;
export { handleWorkerError, handleWorkerMessage };
const qjsStd: QjsStdLib = _qjsStdImp as any;
const logger = new Logger("taler-wallet-embedded/index.ts");
@ -163,17 +171,22 @@ export class NativeHttpLib implements HttpRequestLibrary {
}
function sendNativeMessage(ev: CoreApiEnvelope): void {
// @ts-ignore
const sendMessage = globalThis.__native_sendMessage;
if (typeof sendMessage !== "function") {
const errMsg =
"FATAL: cannot install native wallet listener: native functions missing";
logger.error(errMsg);
throw new Error(errMsg);
}
const m = JSON.stringify(ev);
// @ts-ignore
sendMessage(m);
qjsOs.postMessageToHost(m);
}
/**
* Generate a random alphanumeric ID. Does *not* use cryptographically
* secure randomness.
*/
function makeId(length: number): string {
let result = "";
const characters =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
for (let i = 0; i < length; i++) {
result += characters.charAt(Math.floor(Math.random() * characters.length));
}
return result;
}
export async function getWallet(args: DefaultNodeWalletArgs = {}): Promise<{
@ -186,40 +199,32 @@ export async function getWallet(args: DefaultNodeWalletArgs = {}): Promise<{
const storagePath = args.persistentStoragePath;
if (storagePath) {
// try {
// const dbContentStr: string = fs.readFileSync(storagePath, {
// encoding: "utf-8",
// });
// const dbContent = JSON.parse(dbContentStr);
// myBackend.importDump(dbContent);
// } catch (e: any) {
// const code: string = e.code;
// if (code === "ENOENT") {
// logger.trace("wallet file doesn't exist yet");
// } else {
// logger.error("could not open wallet database file");
// throw e;
// }
// }
const dbContentStr = qjsStd.loadFile(storagePath);
if (dbContentStr != null) {
const dbContent = JSON.parse(dbContentStr);
myBackend.importDump(dbContent);
}
myBackend.afterCommitCallback = async () => {
logger.error("DB commit not implemented");
// logger.trace("committing database");
// // Allow caller to stop persisting the wallet.
// if (args.persistentStoragePath === undefined) {
// return;
// }
// const tmpPath = `${args.persistentStoragePath}-${makeId(5)}.tmp`;
// const dbContent = myBackend.exportDump();
// fs.writeFileSync(tmpPath, JSON.stringify(dbContent, undefined, 2), {
// encoding: "utf-8",
// });
// // Atomically move the temporary file onto the DB path.
// fs.renameSync(tmpPath, args.persistentStoragePath);
// logger.trace("committing database done");
logger.trace("committing database");
// Allow caller to stop persisting the wallet.
if (args.persistentStoragePath === undefined) {
return;
}
const tmpPath = `${args.persistentStoragePath}-${makeId(5)}.tmp`;
const dbContent = myBackend.exportDump();
qjsStd.writeFile(tmpPath, JSON.stringify(dbContent, undefined, 2));
// Atomically move the temporary file onto the DB path.
const res = qjsOs.rename(tmpPath, args.persistentStoragePath);
if (res != 0) {
throw Error("db commit failed at rename");
}
logger.trace("committing database done");
};
}
console.log("done processing storage path");
BridgeIDBFactory.enableTracing = false;
const myBridgeIdbFactory = new BridgeIDBFactory(myBackend);
@ -292,7 +297,7 @@ class NativeWalletMessageHandler {
const resp = await w.handleCoreApiRequest(
"initWallet",
"native-init",
{},
{...this.walletArgs},
);
initResponse = resp.type == "response" ? resp.result : resp.error;
w.runTaskLoop().catch((e) => {
@ -306,6 +311,7 @@ class NativeWalletMessageHandler {
switch (operation) {
case "init": {
this.walletArgs = {
...args,
notifyHandler: async (notification: WalletNotification) => {
sendNativeMessage({ type: "notification", payload: notification });
},
@ -378,7 +384,7 @@ export function installNativeWalletListener(): void {
logger.info(`native listener: got request for ${operation} (${id})`);
try {
const respMsg = await handler.handleMessage(operation, id, msg.args);
const respMsg = await handler.handleMessage(operation, id, msg.payload ?? {});
logger.info(
`native listener: sending success response for ${operation} (${id})`,
);
@ -395,8 +401,7 @@ export function installNativeWalletListener(): void {
}
};
// @ts-ignore
globalThis.__native_onMessage = onMessage;
qjsOs.setMessageFromHostHandler((m) => onMessage(m))
logger.info("native wallet listener installed");
}
@ -423,10 +428,15 @@ export async function testWithGv() {
}
export async function testWithLocal() {
const w = await getWallet();
console.log("running local test");
const w = await getWallet({
persistentStoragePath: "walletdb.json",
});
console.log("created wallet");
await w.wallet.client.call(WalletApiOperation.InitWallet, {
skipDefaults: true,
});
console.log("initialized wallet");
await w.wallet.client.call(WalletApiOperation.RunIntegrationTest, {
amountToSpend: "TESTKUDOS:1",
amountToWithdraw: "TESTKUDOS:3",
@ -435,9 +445,11 @@ export async function testWithLocal() {
exchangeBaseUrl: "http://localhost:8081/",
merchantBaseUrl: "http://localhost:8083/",
});
console.log("started integration test");
await w.wallet.runTaskLoop({
stopWhenDone: true,
});
console.log("done with task loop");
w.wallet.stop();
}