summaryrefslogtreecommitdiff
path: root/src/operations/errors.ts
diff options
context:
space:
mode:
authorFlorian Dold <florian.dold@gmail.com>2020-03-12 19:25:38 +0530
committerFlorian Dold <florian.dold@gmail.com>2020-03-12 19:25:38 +0530
commitb5b8f96cc94e3a3c0ee7d989819197ab5df393cd (patch)
tree0382770a735c4f43e09bfb9d03345bc93ecc498a /src/operations/errors.ts
parent2ec6799c8c6836d44944460a41fabefb8eb8186f (diff)
downloadwallet-core-b5b8f96cc94e3a3c0ee7d989819197ab5df393cd.tar.gz
wallet-core-b5b8f96cc94e3a3c0ee7d989819197ab5df393cd.tar.bz2
wallet-core-b5b8f96cc94e3a3c0ee7d989819197ab5df393cd.zip
improved error reporting / towards a working recoup
Diffstat (limited to 'src/operations/errors.ts')
-rw-r--r--src/operations/errors.ts104
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
+}