-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 { notify(n: WalletNotification): void {
logger.trace("Notification", n); logger.trace("Notification", j2s(n));
for (const l of this.listeners) { for (const l of this.listeners) {
const nc = JSON.parse(JSON.stringify(n)); const nc = JSON.parse(JSON.stringify(n));
setTimeout(() => { setTimeout(() => {

View File

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

View File

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