use message envelope as documented

This commit is contained in:
Florian Dold 2020-07-31 22:46:23 +05:30
parent 3db00d9d73
commit b37c98346d
No known key found for this signature in database
GPG Key ID: D2E4F00F29D02A4B
3 changed files with 49 additions and 40 deletions

View File

@ -40,7 +40,10 @@ import {
handleCoreApiRequest, handleCoreApiRequest,
CoreApiResponseSuccess, CoreApiResponseSuccess,
CoreApiResponse, CoreApiResponse,
CoreApiEnvelope,
} from "../walletCoreApiHandler"; } from "../walletCoreApiHandler";
import { makeErrorDetails } from "../operations/errors";
import { TalerErrorCode } from "../TalerErrorCode";
// @ts-ignore: special built-in module // @ts-ignore: special built-in module
//import akono = require("akono"); //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 // @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 { class AndroidWalletMessageHandler {
@ -154,7 +166,6 @@ class AndroidWalletMessageHandler {
const wrapResponse = (result: unknown): CoreApiResponseSuccess => { const wrapResponse = (result: unknown): CoreApiResponseSuccess => {
return { return {
type: "response", type: "response",
isError: false,
id, id,
operation, operation,
result, result,
@ -164,9 +175,7 @@ class AndroidWalletMessageHandler {
case "init": { case "init": {
this.walletArgs = { this.walletArgs = {
notifyHandler: async (notification: WalletNotification) => { notifyHandler: async (notification: WalletNotification) => {
sendAkonoMessage( sendAkonoMessage({ type: "notification", payload: notification });
JSON.stringify({ type: "notification", payload: notification }),
);
}, },
persistentStoragePath: args.persistentStoragePath, persistentStoragePath: args.persistentStoragePath,
httpLib: this.httpLib, httpLib: this.httpLib,
@ -232,14 +241,6 @@ class AndroidWalletMessageHandler {
} }
export function installAndroidWalletListener(): void { 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 handler = new AndroidWalletMessageHandler();
const onMessage = async (msgStr: any): Promise<void> => { const onMessage = async (msgStr: any): Promise<void> => {
if (typeof msgStr !== "string") { if (typeof msgStr !== "string") {
@ -262,16 +263,19 @@ export function installAndroidWalletListener(): void {
console.log( console.log(
`android listener: sending success response for ${operation} (${id})`, `android listener: sending success response for ${operation} (${id})`,
); );
sendMessage(JSON.stringify(respMsg)); sendAkonoMessage(respMsg);
} catch (e) { } catch (e) {
const respMsg = { const respMsg: CoreApiResponse = {
type: "response", type: "error",
id, id,
operation, operation,
isError: true, error: makeErrorDetails(
result: { message: e.toString() }, TalerErrorCode.WALLET_UNEXPECTED_EXCEPTION,
"unexpected exception",
{},
),
}; };
sendMessage(JSON.stringify(respMsg)); sendAkonoMessage(respMsg);
return; return;
} }
}; };

View File

@ -30,6 +30,7 @@ import {
makeCodecOptional, makeCodecOptional,
} from "./util/codec"; } from "./util/codec";
import { Amounts } from "./util/amounts"; import { Amounts } from "./util/amounts";
import { OperationErrorDetails } from "./types/walletTypes";
interface AddExchangeRequest { interface AddExchangeRequest {
exchangeBaseUrl: string; exchangeBaseUrl: string;
@ -156,10 +157,11 @@ async function dispatchRequestInternal(
wallet: Wallet, wallet: Wallet,
operation: string, operation: string,
payload: unknown, payload: unknown,
): Promise<unknown> { ): Promise<Record<string, any>> {
switch (operation) { switch (operation) {
case "withdrawTestkudos": case "withdrawTestkudos":
return await withdrawTestBalance(wallet); await withdrawTestBalance(wallet);
return {};
case "getTransactions": { case "getTransactions": {
const req = codecForTransactionsRequest().decode(payload); const req = codecForTransactionsRequest().decode(payload);
return await wallet.getTransactions(req); return await wallet.getTransactions(req);
@ -201,10 +203,11 @@ async function dispatchRequestInternal(
} }
case "setExchangeTosAccepted": { case "setExchangeTosAccepted": {
const req = codecForAcceptExchangeTosRequest().decode(payload); const req = codecForAcceptExchangeTosRequest().decode(payload);
return await wallet.acceptExchangeTermsOfService( await wallet.acceptExchangeTermsOfService(
req.exchangeBaseUrl, req.exchangeBaseUrl,
req.etag, req.etag,
); );
return {};
} }
case "applyRefund": { case "applyRefund": {
const req = codecForApplyRefundRequest().decode(payload); const req = codecForApplyRefundRequest().decode(payload);
@ -225,7 +228,8 @@ async function dispatchRequestInternal(
} }
case "abortProposal": { case "abortProposal": {
const req = codecForAbortProposalRequest().decode(payload); const req = codecForAbortProposalRequest().decode(payload);
return await wallet.refuseProposal(req.proposalId); await wallet.refuseProposal(req.proposalId);
return {};
} }
case "retryPendingNow": { case "retryPendingNow": {
await wallet.runPending(true); await wallet.runPending(true);
@ -253,10 +257,18 @@ export type CoreApiResponse =
| CoreApiResponseSuccess | CoreApiResponseSuccess
| CoreApiResponseError; | CoreApiResponseError;
export type CoreApiEnvelope =
| CoreApiResponse
| CoreApiNotification;
export interface CoreApiNotification {
type: "notification";
payload: unknown;
}
export interface CoreApiResponseSuccess { export interface CoreApiResponseSuccess {
// To distinguish the message from notifications // To distinguish the message from notifications
type: "response"; type: "response";
isError: false,
operation: string, operation: string,
id: string; id: string;
result: unknown; result: unknown;
@ -264,11 +276,10 @@ export interface CoreApiResponseSuccess {
export interface CoreApiResponseError { export interface CoreApiResponseError {
// To distinguish the message from notifications // To distinguish the message from notifications
type: "response"; type: "error";
isError: true,
operation: string, operation: string,
id: string; id: string;
error: unknown; error: OperationErrorDetails;
} }
/** /**
@ -283,11 +294,10 @@ export async function handleCoreApiRequest(
try { try {
const result = await dispatchRequestInternal(w, operation, payload); const result = await dispatchRequestInternal(w, operation, payload);
return { return {
isError: false, type: "response",
operation, operation,
id, id,
result, result,
type: "response",
}; };
} catch (e) { } catch (e) {
if ( if (
@ -295,15 +305,14 @@ export async function handleCoreApiRequest(
e instanceof OperationFailedAndReportedError e instanceof OperationFailedAndReportedError
) { ) {
return { return {
isError: true, type: "error",
operation, operation,
id, id,
error: e.operationError, error: e.operationError,
type: "response",
}; };
} else { } else {
return { return {
isError: true, type: "error",
operation, operation,
id, id,
error: makeErrorDetails( error: makeErrorDetails(
@ -311,7 +320,6 @@ export async function handleCoreApiRequest(
`unexpected exception: ${e}`, `unexpected exception: ${e}`,
{}, {},
), ),
type: "response",
}; };
} }
} }

View File

@ -21,12 +21,9 @@ class Wallet:
print(r) print(r)
assert r.returncode == 0 assert r.returncode == 0
json_r = json.loads(r.stdout) json_r = json.loads(r.stdout)
if json_r["isError"]: if json_r["type"] != "response" or "result" not in json_r:
print(r) print(json_r)
assert not json_r["isError"] assert json_r["type"] == "response"
if "result" not in json_r:
# TODO should there not always be a "result"?
return None
return json_r["result"] return json_r["result"]
def testing_withdraw(self, amount, exchange_url, bank_url): def testing_withdraw(self, amount, exchange_url, bank_url):