diff --git a/src/android/index.ts b/src/android/index.ts index 9e58fc8a6..389a081b7 100644 --- a/src/android/index.ts +++ b/src/android/index.ts @@ -40,7 +40,10 @@ import { handleCoreApiRequest, CoreApiResponseSuccess, CoreApiResponse, + CoreApiEnvelope, } from "../walletCoreApiHandler"; +import { makeErrorDetails } from "../operations/errors"; +import { TalerErrorCode } from "../TalerErrorCode"; // @ts-ignore: special built-in module //import akono = require("akono"); @@ -132,9 +135,18 @@ export class AndroidHttpLib implements HttpRequestLibrary { } } -function sendAkonoMessage(m: string): void { +function sendAkonoMessage(ev: CoreApiEnvelope): void { // @ts-ignore - globalThis.__akono_sendMessage(m); + const sendMessage = globalThis.__akono_sendMessage; + if (typeof sendMessage !== "function") { + const errMsg = + "FATAL: cannot install android wallet listener: akono functions missing"; + console.error(errMsg); + throw new Error(errMsg); + } + const m = JSON.stringify(ev); + // @ts-ignore + sendMessage(m); } class AndroidWalletMessageHandler { @@ -154,7 +166,6 @@ class AndroidWalletMessageHandler { const wrapResponse = (result: unknown): CoreApiResponseSuccess => { return { type: "response", - isError: false, id, operation, result, @@ -164,9 +175,7 @@ class AndroidWalletMessageHandler { case "init": { this.walletArgs = { notifyHandler: async (notification: WalletNotification) => { - sendAkonoMessage( - JSON.stringify({ type: "notification", payload: notification }), - ); + sendAkonoMessage({ type: "notification", payload: notification }); }, persistentStoragePath: args.persistentStoragePath, httpLib: this.httpLib, @@ -232,14 +241,6 @@ class AndroidWalletMessageHandler { } export function installAndroidWalletListener(): void { - // @ts-ignore - const sendMessage: (m: string) => void = globalThis.__akono_sendMessage; - if (typeof sendMessage !== "function") { - const errMsg = - "FATAL: cannot install android wallet listener: akono functions missing"; - console.error(errMsg); - throw new Error(errMsg); - } const handler = new AndroidWalletMessageHandler(); const onMessage = async (msgStr: any): Promise => { if (typeof msgStr !== "string") { @@ -262,16 +263,19 @@ export function installAndroidWalletListener(): void { console.log( `android listener: sending success response for ${operation} (${id})`, ); - sendMessage(JSON.stringify(respMsg)); + sendAkonoMessage(respMsg); } catch (e) { - const respMsg = { - type: "response", + const respMsg: CoreApiResponse = { + type: "error", id, operation, - isError: true, - result: { message: e.toString() }, + error: makeErrorDetails( + TalerErrorCode.WALLET_UNEXPECTED_EXCEPTION, + "unexpected exception", + {}, + ), }; - sendMessage(JSON.stringify(respMsg)); + sendAkonoMessage(respMsg); return; } }; diff --git a/src/walletCoreApiHandler.ts b/src/walletCoreApiHandler.ts index 02b916af7..a16490d5a 100644 --- a/src/walletCoreApiHandler.ts +++ b/src/walletCoreApiHandler.ts @@ -30,6 +30,7 @@ import { makeCodecOptional, } from "./util/codec"; import { Amounts } from "./util/amounts"; +import { OperationErrorDetails } from "./types/walletTypes"; interface AddExchangeRequest { exchangeBaseUrl: string; @@ -156,10 +157,11 @@ async function dispatchRequestInternal( wallet: Wallet, operation: string, payload: unknown, -): Promise { +): Promise> { switch (operation) { case "withdrawTestkudos": - return await withdrawTestBalance(wallet); + await withdrawTestBalance(wallet); + return {}; case "getTransactions": { const req = codecForTransactionsRequest().decode(payload); return await wallet.getTransactions(req); @@ -201,10 +203,11 @@ async function dispatchRequestInternal( } case "setExchangeTosAccepted": { const req = codecForAcceptExchangeTosRequest().decode(payload); - return await wallet.acceptExchangeTermsOfService( + await wallet.acceptExchangeTermsOfService( req.exchangeBaseUrl, req.etag, ); + return {}; } case "applyRefund": { const req = codecForApplyRefundRequest().decode(payload); @@ -225,7 +228,8 @@ async function dispatchRequestInternal( } case "abortProposal": { const req = codecForAbortProposalRequest().decode(payload); - return await wallet.refuseProposal(req.proposalId); + await wallet.refuseProposal(req.proposalId); + return {}; } case "retryPendingNow": { await wallet.runPending(true); @@ -253,10 +257,18 @@ export type CoreApiResponse = | CoreApiResponseSuccess | CoreApiResponseError; +export type CoreApiEnvelope = + | CoreApiResponse + | CoreApiNotification; + +export interface CoreApiNotification { + type: "notification"; + payload: unknown; +} + export interface CoreApiResponseSuccess { // To distinguish the message from notifications type: "response"; - isError: false, operation: string, id: string; result: unknown; @@ -264,11 +276,10 @@ export interface CoreApiResponseSuccess { export interface CoreApiResponseError { // To distinguish the message from notifications - type: "response"; - isError: true, + type: "error"; operation: string, id: string; - error: unknown; + error: OperationErrorDetails; } /** @@ -283,11 +294,10 @@ export async function handleCoreApiRequest( try { const result = await dispatchRequestInternal(w, operation, payload); return { - isError: false, + type: "response", operation, id, result, - type: "response", }; } catch (e) { if ( @@ -295,15 +305,14 @@ export async function handleCoreApiRequest( e instanceof OperationFailedAndReportedError ) { return { - isError: true, + type: "error", operation, id, error: e.operationError, - type: "response", }; } else { return { - isError: true, + type: "error", operation, id, error: makeErrorDetails( @@ -311,7 +320,6 @@ export async function handleCoreApiRequest( `unexpected exception: ${e}`, {}, ), - type: "response", }; } } diff --git a/tests/components/wallet.py b/tests/components/wallet.py index cedae84e1..bfdbd9ba1 100644 --- a/tests/components/wallet.py +++ b/tests/components/wallet.py @@ -21,12 +21,9 @@ class Wallet: print(r) assert r.returncode == 0 json_r = json.loads(r.stdout) - if json_r["isError"]: - print(r) - assert not json_r["isError"] - if "result" not in json_r: - # TODO should there not always be a "result"? - return None + if json_r["type"] != "response" or "result" not in json_r: + print(json_r) + assert json_r["type"] == "response" return json_r["result"] def testing_withdraw(self, amount, exchange_url, bank_url):