Better handling of SDK errors

## Issue
- Errors like "unexpected token at..." and "failed to fetch" are being logged, rather than the actual call error.
- Publish SDK timeout is sometimes successful, but the user doesn't know, so they re-created the same claim

## Change
- Attempt to make the logs more helpful, and the error message more meaningful to the user.
- Starting off with 'publish' and tip SDK call as an experiment. Can add others if this method works.
This commit is contained in:
infinite-persistence 2022-03-18 16:42:52 +08:00 committed by Thomas Zarebczan
parent ce46170b39
commit 5e2100000d
4 changed files with 46 additions and 12 deletions

View file

@ -1090,6 +1090,8 @@
"Channel to show support as": "Channel to show support as", "Channel to show support as": "Channel to show support as",
"This refundable boost will improve the discoverability of this %claimTypeText% while active. ": "This refundable boost will improve the discoverability of this %claimTypeText% while active. ", "This refundable boost will improve the discoverability of this %claimTypeText% while active. ": "This refundable boost will improve the discoverability of this %claimTypeText% while active. ",
"Show this channel your appreciation by sending a donation in USD. ": "Show this channel your appreciation by sending a donation in USD. ", "Show this channel your appreciation by sending a donation in USD. ": "Show this channel your appreciation by sending a donation in USD. ",
"Boost transaction failed.": "Boost transaction failed.",
"Tip transaction failed.": "Tip transaction failed.",
"Add a Card": "Add a Card", "Add a Card": "Add a Card",
"To Tip Creators": "To Tip Creators", "To Tip Creators": "To Tip Creators",
"Show this channel your appreciation by sending a donation of Credits. ": "Show this channel your appreciation by sending a donation of Credits. ", "Show this channel your appreciation by sending a donation of Credits. ": "Show this channel your appreciation by sending a donation of Credits. ",

View file

@ -177,19 +177,42 @@ const Lbry = {
}), }),
}; };
function checkAndParse(response: Response) { function checkAndParse(response: Response, method: string) {
if (!response.ok) {
// prettier-ignore
switch (response.status) {
case 504: // Gateway timeout
case 524: // Cloudflare: a timeout occurred
switch (method) {
case 'publish':
throw Error(__('[Publish]: Your action timed out, but may have been completed. Refresh and check your Uploads or Wallet page to confirm after a few minutes.'));
default:
throw Error(`${method}: ${response.statusText} (${response.status})`);
}
default:
throw Error(`${method}: ${response.statusText} (${response.status})`);
}
}
if (response.status >= 200 && response.status < 300) { if (response.status >= 200 && response.status < 300) {
return response.json(); return response.json();
} }
return response.json().then((json) => { return response
if (json.error) { .json()
const errorMessage = typeof json.error === 'object' ? json.error.message : json.error; .then((json) => {
return Promise.reject(new Error(errorMessage)); if (json.error) {
} else { const errorMessage = typeof json.error === 'object' ? json.error.message : json.error;
return Promise.reject(new Error('Protocol error with unknown response signature')); return Promise.reject(new Error(errorMessage));
} } else {
}); return Promise.reject(new Error('Protocol error with unknown response signature'));
}
})
.catch(() => {
// If not parsable, throw the initial response rather than letting
// the json failure ("unexpected token at..") pass through.
return Promise.reject(new Error(`${method}: ${response.statusText} (${response.status}, JSON)`));
});
} }
export function apiCall(method: string, params: ?{}, resolve: Function, reject: Function) { export function apiCall(method: string, params: ?{}, resolve: Function, reject: Function) {
@ -218,7 +241,7 @@ export function apiCall(method: string, params: ?{}, resolve: Function, reject:
: Lbry.daemonConnectionString; : Lbry.daemonConnectionString;
return fetch(connectionString + '?m=' + method, options) return fetch(connectionString + '?m=' + method, options)
.then(checkAndParse) .then((response) => checkAndParse(response, method))
.then((response) => { .then((response) => {
const error = response.error || (response.result && response.result.error); const error = response.error || (response.result && response.result.error);
return error ? reject(error) : resolve(response.result); return error ? reject(error) : resolve(response.result);

View file

@ -388,10 +388,19 @@ export function doSendTip(params, isSupport, successCallback, errorCallback, sho
}; };
const error = (err) => { const error = (err) => {
const baseMsg = isSupport ? __('Boost transaction failed.') : __('Tip transaction failed.');
const errMsg = typeof err === 'object' ? err.message : err;
// For now, spew to console for persistence until the Status Log component is ready.
// eslint-disable-next-line no-console
console.log(`${baseMsg}\n${errMsg}`);
dispatch( dispatch(
doToast({ doToast({
message: __(`There was an error sending support funds.`), message: baseMsg,
subMessage: errMsg,
isError: true, isError: true,
duration: 'long',
}) })
); );

View file

@ -79,7 +79,7 @@
} }
.snack-bar__messageText--sub { .snack-bar__messageText--sub {
font-size: var(--font-small); font-size: var(--font-xsmall);
color: var(--color-text-subtitle); color: var(--color-text-subtitle);
} }