diff options
author | Florian Dold <florian.dold@gmail.com> | 2020-03-12 19:25:38 +0530 |
---|---|---|
committer | Florian Dold <florian.dold@gmail.com> | 2020-03-12 19:25:38 +0530 |
commit | b5b8f96cc94e3a3c0ee7d989819197ab5df393cd (patch) | |
tree | 0382770a735c4f43e09bfb9d03345bc93ecc498a /src/operations/errors.ts | |
parent | 2ec6799c8c6836d44944460a41fabefb8eb8186f (diff) | |
download | wallet-core-b5b8f96cc94e3a3c0ee7d989819197ab5df393cd.tar.xz |
improved error reporting / towards a working recoup
Diffstat (limited to 'src/operations/errors.ts')
-rw-r--r-- | src/operations/errors.ts | 104 |
1 files changed, 88 insertions, 16 deletions
diff --git a/src/operations/errors.ts b/src/operations/errors.ts index 7e97fdb3c..751a57111 100644 --- a/src/operations/errors.ts +++ b/src/operations/errors.ts @@ -1,8 +1,6 @@ -import { OperationError } from "../types/walletTypes"; - /* This file is part of GNU Taler - (C) 2019 GNUnet e.V. + (C) 2019-2020 Taler Systems SA GNU Taler is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -17,12 +15,25 @@ import { OperationError } from "../types/walletTypes"; */ /** + * Classes and helpers for error handling specific to wallet operations. + * + * @author Florian Dold <dold@taler.net> + */ + +/** + * Imports. + */ +import { OperationError } from "../types/walletTypes"; +import { HttpResponse } from "../util/http"; +import { Codec } from "../util/codec"; + +/** * This exception is there to let the caller know that an error happened, * but the error has already been reported by writing it to the database. */ export class OperationFailedAndReportedError extends Error { - constructor(message: string) { - super(message); + constructor(public operationError: OperationError) { + super(operationError.message); // Set the prototype explicitly. Object.setPrototypeOf(this, OperationFailedAndReportedError.prototype); @@ -34,8 +45,8 @@ export class OperationFailedAndReportedError extends Error { * responsible for recording the failure in the database. */ export class OperationFailedError extends Error { - constructor(message: string, public err: OperationError) { - super(message); + constructor(public operationError: OperationError) { + super(operationError.message); // Set the prototype explicitly. Object.setPrototypeOf(this, OperationFailedError.prototype); @@ -43,6 +54,65 @@ export class OperationFailedError extends Error { } /** + * Process an HTTP response that we expect to contain Taler-specific JSON. + * + * Depending on the status code, we throw an exception. This function + * will try to extract Taler-specific error information from the HTTP response + * if possible. + */ +export async function scrutinizeTalerJsonResponse<T>( + resp: HttpResponse, + codec: Codec<T>, +): Promise<T> { + + // FIXME: We should distinguish between different types of error status + // to react differently (throttle, report permanent failure) + + // FIXME: Make sure that when we receive an error message, + // it looks like a Taler error message + + if (resp.status !== 200) { + let exc: OperationFailedError | undefined = undefined; + try { + const errorJson = await resp.json(); + const m = `received error response (status ${resp.status})`; + exc = new OperationFailedError({ + type: "protocol", + message: m, + details: { + httpStatusCode: resp.status, + errorResponse: errorJson, + } + }); + } catch (e) { + const m = "could not parse response JSON"; + exc = new OperationFailedError({ + type: "network", + message: m, + details: { + status: resp.status, + } + }); + } + throw exc; + } + let json: any; + try { + json = await resp.json(); + } catch (e) { + const m = "could not parse response JSON"; + throw new OperationFailedError({ + type: "network", + message: m, + details: { + status: resp.status, + } + }); + } + return codec.decode(json); +} + +/** * Run an operation and call the onOpError callback * when there was an exception or operation error that must be reported. * The cause will be re-thrown to the caller. @@ -59,26 +129,28 @@ export async function guardOperationException<T>( throw e; } if (e instanceof OperationFailedError) { - await onOpError(e.err); - throw new OperationFailedAndReportedError(e.message); + await onOpError(e.operationError); + throw new OperationFailedAndReportedError(e.operationError); } if (e instanceof Error) { console.log("guard: caught Error"); - await onOpError({ + const opErr = { type: "exception", message: e.message, details: {}, - }); - throw new OperationFailedAndReportedError(e.message); + } + await onOpError(opErr); + throw new OperationFailedAndReportedError(opErr); } console.log("guard: caught something else"); - await onOpError({ + const opErr = { type: "exception", message: "non-error exception thrown", details: { value: e.toString(), }, - }); - throw new OperationFailedAndReportedError(e.message); + }; + await onOpError(opErr); + throw new OperationFailedAndReportedError(opErr); } -}
\ No newline at end of file +} |