diff options
author | Florian Dold <florian.dold@gmail.com> | 2020-07-20 17:46:49 +0530 |
---|---|---|
committer | Florian Dold <florian.dold@gmail.com> | 2020-07-20 17:46:49 +0530 |
commit | dd2efc3d78f2dfda44f8182f9638723dcb839781 (patch) | |
tree | 9cfbd31607f044fb80da80d8f740ae5eaa21a2f4 /src/operations | |
parent | 5a8931d90320ebc8454969ea133c48b6998ad60a (diff) | |
download | wallet-core-dd2efc3d78f2dfda44f8182f9638723dcb839781.tar.xz |
nicer HTTP helper in preparation for better error handling
Diffstat (limited to 'src/operations')
-rw-r--r-- | src/operations/errors.ts | 58 | ||||
-rw-r--r-- | src/operations/pay.ts | 43 | ||||
-rw-r--r-- | src/operations/recoup.ts | 26 | ||||
-rw-r--r-- | src/operations/withdraw.ts | 12 |
4 files changed, 47 insertions, 92 deletions
diff --git a/src/operations/errors.ts b/src/operations/errors.ts index c8885c9e7..9def02b0e 100644 --- a/src/operations/errors.ts +++ b/src/operations/errors.ts @@ -54,64 +54,6 @@ 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. diff --git a/src/operations/pay.ts b/src/operations/pay.ts index a16190743..abcb2ad1d 100644 --- a/src/operations/pay.ts +++ b/src/operations/pay.ts @@ -52,12 +52,13 @@ import { import * as Amounts from "../util/amounts"; import { AmountJson } from "../util/amounts"; import { Logger } from "../util/logging"; -import { getOrderDownloadUrl, parsePayUri } from "../util/taleruri"; +import { parsePayUri } from "../util/taleruri"; import { guardOperationException } from "./errors"; import { createRefreshGroup, getTotalRefreshCost } from "./refresh"; import { InternalWalletState } from "./state"; import { getTimestampNow, timestampAddDuration } from "../util/time"; import { strcmp, canonicalJson } from "../util/helpers"; +import { httpPostTalerJson } from "../util/http"; /** * Logger. @@ -534,7 +535,9 @@ async function incrementProposalRetry( pr.lastError = err; await tx.put(Stores.proposals, pr); }); - ws.notify({ type: NotificationType.ProposalOperationError }); + if (err) { + ws.notify({ type: NotificationType.ProposalOperationError, error: err }); + } } async function incrementPurchasePayRetry( @@ -600,25 +603,25 @@ async function processDownloadProposalImpl( return; } - const parsedUrl = new URL( - getOrderDownloadUrl(proposal.merchantBaseUrl, proposal.orderId), - ); - parsedUrl.searchParams.set("nonce", proposal.noncePub); - const urlWithNonce = parsedUrl.href; - console.log("downloading contract from '" + urlWithNonce + "'"); - let resp; - try { - resp = await ws.http.get(urlWithNonce); - } catch (e) { - console.log("contract download failed", e); - throw e; - } - - if (resp.status !== 200) { - throw Error(`contract download failed with status ${resp.status}`); - } + const orderClaimUrl = new URL( + `orders/${proposal.orderId}/claim`, + proposal.merchantBaseUrl, + ).href; + logger.trace("downloading contract from '" + orderClaimUrl + "'"); + + + const proposalResp = await httpPostTalerJson({ + url: orderClaimUrl, + body: { + nonce: proposal.noncePub, + }, + codec: codecForProposal(), + http: ws.http, + }); - const proposalResp = codecForProposal().decode(await resp.json()); + // The proposalResp contains the contract terms as raw JSON, + // as the coded to parse them doesn't necessarily round-trip. + // We need this raw JSON to compute the contract terms hash. const contractTermsHash = await ws.cryptoApi.hashString( canonicalJson(proposalResp.contract_terms), diff --git a/src/operations/recoup.ts b/src/operations/recoup.ts index e1c2325d7..d1b3c3bda 100644 --- a/src/operations/recoup.ts +++ b/src/operations/recoup.ts @@ -48,7 +48,8 @@ import { RefreshReason, OperationError } from "../types/walletTypes"; import { TransactionHandle } from "../util/query"; import { encodeCrock, getRandomBytes } from "../crypto/talerCrypto"; import { getTimestampNow } from "../util/time"; -import { guardOperationException, scrutinizeTalerJsonResponse } from "./errors"; +import { guardOperationException } from "./errors"; +import { httpPostTalerJson } from "../util/http"; async function incrementRecoupRetry( ws: InternalWalletState, @@ -146,11 +147,12 @@ async function recoupWithdrawCoin( const recoupRequest = await ws.cryptoApi.createRecoupRequest(coin); const reqUrl = new URL(`/coins/${coin.coinPub}/recoup`, coin.exchangeBaseUrl); - const resp = await ws.http.postJson(reqUrl.href, recoupRequest); - const recoupConfirmation = await scrutinizeTalerJsonResponse( - resp, - codecForRecoupConfirmation(), - ); + const recoupConfirmation = await httpPostTalerJson({ + url: reqUrl.href, + body: recoupRequest, + codec: codecForRecoupConfirmation(), + http: ws.http, + }); if (recoupConfirmation.reserve_pub !== reservePub) { throw Error(`Coin's reserve doesn't match reserve on recoup`); @@ -220,11 +222,13 @@ async function recoupRefreshCoin( const recoupRequest = await ws.cryptoApi.createRecoupRequest(coin); const reqUrl = new URL(`/coins/${coin.coinPub}/recoup`, coin.exchangeBaseUrl); console.log("making recoup request"); - const resp = await ws.http.postJson(reqUrl.href, recoupRequest); - const recoupConfirmation = await scrutinizeTalerJsonResponse( - resp, - codecForRecoupConfirmation(), - ); + + const recoupConfirmation = await httpPostTalerJson({ + url: reqUrl.href, + body: recoupRequest, + codec: codecForRecoupConfirmation(), + http: ws.http, + }); if (recoupConfirmation.old_coin_pub != cs.oldCoinPub) { throw Error(`Coin's oldCoinPub doesn't match reserve on recoup`); diff --git a/src/operations/withdraw.ts b/src/operations/withdraw.ts index 19b470e83..98969d213 100644 --- a/src/operations/withdraw.ts +++ b/src/operations/withdraw.ts @@ -46,7 +46,7 @@ import { updateExchangeFromUrl, getExchangeTrust } from "./exchanges"; import { WALLET_EXCHANGE_PROTOCOL_VERSION } from "./versions"; import * as LibtoolVersion from "../util/libtoolVersion"; -import { guardOperationException, scrutinizeTalerJsonResponse } from "./errors"; +import { guardOperationException } from "./errors"; import { NotificationType } from "../types/notifications"; import { getTimestampNow, @@ -54,6 +54,7 @@ import { timestampCmp, timestampSubtractDuraction, } from "../util/time"; +import { httpPostTalerJson } from "../util/http"; const logger = new Logger("withdraw.ts"); @@ -308,8 +309,13 @@ async function processPlanchet( `reserves/${planchet.reservePub}/withdraw`, exchange.baseUrl, ).href; - const resp = await ws.http.postJson(reqUrl, wd); - const r = await scrutinizeTalerJsonResponse(resp, codecForWithdrawResponse()); + + const r = await httpPostTalerJson({ + url: reqUrl, + body: wd, + codec: codecForWithdrawResponse(), + http: ws.http, + }); logger.trace(`got response for /withdraw`); |