mirror of
https://github.com/the-djmaze/snappymail.git
synced 2025-10-09 13:17:32 +08:00
Cleanup AbstractFetch
and added fetchJSON mockup code for error handling regarding issue #49
This commit is contained in:
parent
4723e1241e
commit
fa7ea413dc
2 changed files with 176 additions and 172 deletions
|
@ -17,54 +17,73 @@ updateToken = data => {
|
||||||
|
|
||||||
checkResponseError = data => {
|
checkResponseError = data => {
|
||||||
const err = data ? data.ErrorCode : null;
|
const err = data ? data.ErrorCode : null;
|
||||||
if ([
|
if (Notification.InvalidToken === err && 10 < ++iTokenErrorCount) {
|
||||||
Notification.AuthError,
|
|
||||||
Notification.AccessError,
|
|
||||||
Notification.ConnectionError,
|
|
||||||
Notification.DomainNotAllowed,
|
|
||||||
Notification.AccountNotAllowed,
|
|
||||||
Notification.MailServerError,
|
|
||||||
Notification.UnknownNotification,
|
|
||||||
Notification.UnknownError
|
|
||||||
].includes(err)
|
|
||||||
) {
|
|
||||||
++iJsonErrorCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Notification.InvalidToken === err) {
|
|
||||||
++iTokenErrorCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (10 < iTokenErrorCount) {
|
|
||||||
rl.logoutReload();
|
rl.logoutReload();
|
||||||
}
|
} else {
|
||||||
|
if ([
|
||||||
if (window.rl && (data.ClearAuth || data.Logout || 7 < iJsonErrorCount)) {
|
Notification.AuthError,
|
||||||
rl.hash.clear();
|
Notification.AccessError,
|
||||||
|
Notification.ConnectionError,
|
||||||
if (!data.ClearAuth) {
|
Notification.DomainNotAllowed,
|
||||||
rl.logoutReload();
|
Notification.AccountNotAllowed,
|
||||||
|
Notification.MailServerError,
|
||||||
|
Notification.UnknownNotification,
|
||||||
|
Notification.UnknownError
|
||||||
|
].includes(err)
|
||||||
|
) {
|
||||||
|
++iJsonErrorCount;
|
||||||
|
}
|
||||||
|
if (window.rl && (data.ClearAuth || data.Logout || 7 < iJsonErrorCount)) {
|
||||||
|
rl.hash.clear();
|
||||||
|
if (!data.ClearAuth) {
|
||||||
|
rl.logoutReload();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
oRequests = {};
|
oRequests = {},
|
||||||
|
|
||||||
|
abort = (sAction, bClearOnly) => {
|
||||||
|
if (oRequests[sAction]) {
|
||||||
|
if (!bClearOnly && oRequests[sAction].abort) {
|
||||||
|
// oRequests[sAction].__aborted = true;
|
||||||
|
oRequests[sAction].abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
oRequests[sAction] = null;
|
||||||
|
delete oRequests[sAction];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
fetchJSON = (action, sGetAdd, params, timeout, jsonCallback) => {
|
||||||
|
sGetAdd = pString(sGetAdd);
|
||||||
|
params = params || {};
|
||||||
|
params.Action = action;
|
||||||
|
let init = {};
|
||||||
|
if (window.AbortController) {
|
||||||
|
abort(action);
|
||||||
|
const controller = new AbortController();
|
||||||
|
timeout && setTimeout(() => controller.abort(), timeout);
|
||||||
|
oRequests[action] = controller;
|
||||||
|
init.signal = controller.signal;
|
||||||
|
}
|
||||||
|
return rl.fetchJSON(getURL(sGetAdd), init, sGetAdd ? null : params)
|
||||||
|
.then(jsonCallback)
|
||||||
|
.catch(err => {
|
||||||
|
if (err.name == 'AbortError') { // handle abort()
|
||||||
|
err = Notification.JsonAbort;
|
||||||
|
}
|
||||||
|
return Promise.reject(err);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
addEventListener('unload', () => bUnload = true);
|
addEventListener('unload', () => bUnload = true);
|
||||||
|
|
||||||
class AbstractFetchRemote
|
export class AbstractFetchRemote
|
||||||
{
|
{
|
||||||
abort(sAction, bClearOnly) {
|
abort(sAction, bClearOnly) {
|
||||||
if (oRequests[sAction]) {
|
abort(sAction, bClearOnly);
|
||||||
if (!bClearOnly && oRequests[sAction].abort) {
|
|
||||||
// oRequests[sAction].__aborted = true;
|
|
||||||
oRequests[sAction].abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
oRequests[sAction] = null;
|
|
||||||
delete oRequests[sAction];
|
|
||||||
}
|
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,84 +97,74 @@ class AbstractFetchRemote
|
||||||
*/
|
*/
|
||||||
defaultRequest(fCallback, sAction, params, iTimeout, sGetAdd, abortActions) {
|
defaultRequest(fCallback, sAction, params, iTimeout, sGetAdd, abortActions) {
|
||||||
params = params || {};
|
params = params || {};
|
||||||
params.Action = sAction;
|
|
||||||
|
|
||||||
sGetAdd = pString(sGetAdd);
|
const start = Date.now();
|
||||||
|
|
||||||
const start = Date.now(),
|
if (sAction && abortActions) {
|
||||||
action = params.Action || '';
|
abortActions.forEach(actionToAbort => abort(actionToAbort));
|
||||||
|
|
||||||
if (action && abortActions) {
|
|
||||||
abortActions.forEach(actionToAbort => this.abort(actionToAbort));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return rl.fetchJSON(getURL(sGetAdd), {
|
return fetchJSON(sAction, sGetAdd,
|
||||||
signal: this.createAbort(action, undefined === iTimeout ? 30000 : pInt(iTimeout))
|
params,
|
||||||
}, sGetAdd ? null : params
|
undefined === iTimeout ? 30000 : pInt(iTimeout),
|
||||||
).then(data => {
|
data => {
|
||||||
let cached = false;
|
let cached = false;
|
||||||
if (data) {
|
if (data) {
|
||||||
if (data.Time) {
|
if (data.Time) {
|
||||||
cached = pInt(data.Time) > Date.now() - start;
|
cached = pInt(data.Time) > Date.now() - start;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateToken(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateToken(data);
|
let sType = 'success';
|
||||||
}
|
if (sAction && oRequests[sAction]) {
|
||||||
|
if (oRequests[sAction].__aborted) {
|
||||||
let sType = 'success';
|
sType = 'abort';
|
||||||
if (action && oRequests[action]) {
|
}
|
||||||
if (oRequests[action].__aborted) {
|
abort(sAction, true);
|
||||||
sType = 'abort';
|
|
||||||
}
|
|
||||||
this.abort(action, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
const fCall = () => {
|
|
||||||
if (StorageResultType.Success !== sType && bUnload) {
|
|
||||||
sType = StorageResultType.Unload;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (StorageResultType.Success === sType && data && !data.Result) {
|
const fCall = () => {
|
||||||
checkResponseError(data);
|
if (StorageResultType.Success !== sType && bUnload) {
|
||||||
} else if (StorageResultType.Success === sType && data && data.Result) {
|
sType = StorageResultType.Unload;
|
||||||
iJsonErrorCount = iTokenErrorCount = 0;
|
}
|
||||||
|
|
||||||
|
if (StorageResultType.Success === sType && data) {
|
||||||
|
if (data.Result) {
|
||||||
|
iJsonErrorCount = iTokenErrorCount = 0;
|
||||||
|
} else {
|
||||||
|
checkResponseError(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fCallback) {
|
||||||
|
fCallback(
|
||||||
|
sType,
|
||||||
|
StorageResultType.Success === sType ? data : null,
|
||||||
|
cached,
|
||||||
|
sAction,
|
||||||
|
params
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (sType) {
|
||||||
|
case 'success':
|
||||||
|
sType = StorageResultType.Success;
|
||||||
|
fCall();
|
||||||
|
break;
|
||||||
|
case 'abort':
|
||||||
|
sType = StorageResultType.Abort;
|
||||||
|
fCall();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
sType = StorageResultType.Error;
|
||||||
|
setTimeout(fCall, 300);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fCallback) {
|
|
||||||
fCallback(
|
|
||||||
sType,
|
|
||||||
StorageResultType.Success === sType ? data : null,
|
|
||||||
cached,
|
|
||||||
action,
|
|
||||||
params
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
switch (sType) {
|
|
||||||
case 'success':
|
|
||||||
sType = StorageResultType.Success;
|
|
||||||
break;
|
|
||||||
case 'abort':
|
|
||||||
sType = StorageResultType.Abort;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
sType = StorageResultType.Error;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
);
|
||||||
if (StorageResultType.Error === sType) {
|
|
||||||
setTimeout(fCall, 300);
|
|
||||||
} else {
|
|
||||||
fCall();
|
|
||||||
}
|
|
||||||
|
|
||||||
}).catch(err => {
|
|
||||||
if (err.name == 'AbortError') { // handle abort()
|
|
||||||
err = Notification.JsonAbort;
|
|
||||||
}
|
|
||||||
return Promise.reject(err);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -182,18 +191,6 @@ class AbstractFetchRemote
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
createAbort(action, timeout) {
|
|
||||||
if (window.AbortController) {
|
|
||||||
this.abort(action);
|
|
||||||
const controller = new AbortController();
|
|
||||||
if (timeout) {
|
|
||||||
setTimeout(() => controller.abort(), timeout);
|
|
||||||
}
|
|
||||||
oRequests[action] = controller;
|
|
||||||
return controller.signal;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fastResolve(mData) {
|
fastResolve(mData) {
|
||||||
return Promise.resolve(mData);
|
return Promise.resolve(mData);
|
||||||
}
|
}
|
||||||
|
@ -201,65 +198,51 @@ class AbstractFetchRemote
|
||||||
setTrigger(trigger, value) {
|
setTrigger(trigger, value) {
|
||||||
if (trigger) {
|
if (trigger) {
|
||||||
value = !!value;
|
value = !!value;
|
||||||
(Array.isArray(trigger) ? trigger : [trigger]).forEach((fTrigger) => {
|
(Array.isArray(trigger) ? trigger : [trigger]).forEach(fTrigger => {
|
||||||
if (fTrigger) {
|
fTrigger && fTrigger(value);
|
||||||
fTrigger(value);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
postRequest(action, fTrigger, params, timeOut) {
|
postRequest(action, fTrigger, params, timeOut) {
|
||||||
params = params || {};
|
|
||||||
params.Action = action;
|
|
||||||
|
|
||||||
this.setTrigger(fTrigger, true);
|
this.setTrigger(fTrigger, true);
|
||||||
|
return fetchJSON(action, '', params, pInt(timeOut, 30000),
|
||||||
|
data => {
|
||||||
|
abort(action, true);
|
||||||
|
|
||||||
return rl.fetchJSON(getURL(), {
|
if (!data) {
|
||||||
signal: this.createAbort(action, pInt(timeOut, 30000))
|
return Promise.reject(Notification.JsonParse);
|
||||||
}, params
|
}
|
||||||
).then(data => {
|
|
||||||
this.abort(action, true);
|
|
||||||
|
|
||||||
if (!data) {
|
updateToken(data);
|
||||||
return Promise.reject(Notification.JsonParse);
|
|
||||||
}
|
|
||||||
|
|
||||||
updateToken(data);
|
|
||||||
/*
|
/*
|
||||||
let isCached = false, type = '';
|
let isCached = false, type = '';
|
||||||
if (data && data.Time) {
|
if (data && data.Time) {
|
||||||
isCached = pInt(data.Time) > microtime() - start;
|
isCached = pInt(data.Time) > microtime() - start;
|
||||||
}
|
}
|
||||||
// backward capability
|
// backward capability
|
||||||
switch (true) {
|
switch (true) {
|
||||||
case 'success' === textStatus && data && data.Result && action === data.Action:
|
case 'success' === textStatus && data && data.Result && action === data.Action:
|
||||||
type = StorageResultType.Success;
|
type = StorageResultType.Success;
|
||||||
break;
|
break;
|
||||||
case 'abort' === textStatus && (!data || !data.__aborted__):
|
case 'abort' === textStatus && (!data || !data.__aborted__):
|
||||||
type = StorageResultType.Abort;
|
type = StorageResultType.Abort;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
type = StorageResultType.Error;
|
type = StorageResultType.Error;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
this.setTrigger(fTrigger, false);
|
this.setTrigger(fTrigger, false);
|
||||||
|
|
||||||
if (!data.Result || action !== data.Action) {
|
if (!data.Result || action !== data.Action) {
|
||||||
checkResponseError(data);
|
checkResponseError(data);
|
||||||
const err = data ? data.ErrorCode : null;
|
const err = data ? data.ErrorCode : null;
|
||||||
return Promise.reject(err || Notification.JsonFalse);
|
return Promise.reject(err || Notification.JsonFalse);
|
||||||
}
|
}
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
}).catch(err => {
|
|
||||||
if (err.name == 'AbortError') { // handle abort()
|
|
||||||
return Promise.reject(Notification.JsonAbort);
|
|
||||||
}
|
}
|
||||||
return Promise.reject(err);
|
);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export { AbstractFetchRemote, AbstractFetchRemote as default };
|
|
||||||
|
|
35
dev/bootstrap.js
vendored
35
dev/bootstrap.js
vendored
|
@ -90,15 +90,13 @@ export default (App) => {
|
||||||
cache: 'no-cache',
|
cache: 'no-cache',
|
||||||
redirect: 'error',
|
redirect: 'error',
|
||||||
referrerPolicy: 'no-referrer',
|
referrerPolicy: 'no-referrer',
|
||||||
credentials: 'same-origin'
|
credentials: 'same-origin',
|
||||||
|
headers: {}
|
||||||
}, init);
|
}, init);
|
||||||
|
init.headers.Accept = 'application/json';
|
||||||
if (postData) {
|
if (postData) {
|
||||||
init.method = 'POST';
|
init.method = 'POST';
|
||||||
init.headers = {
|
init.headers['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8';
|
||||||
// 'Content-Type': 'application/json'
|
|
||||||
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
|
|
||||||
};
|
|
||||||
postData.XToken = rl.settings.app('token');
|
postData.XToken = rl.settings.app('token');
|
||||||
// init.body = JSON.stringify(postData);
|
// init.body = JSON.stringify(postData);
|
||||||
const formData = new FormData(),
|
const formData = new FormData(),
|
||||||
|
@ -115,7 +113,30 @@ export default (App) => {
|
||||||
init.body = new URLSearchParams(formData);
|
init.body = new URLSearchParams(formData);
|
||||||
}
|
}
|
||||||
|
|
||||||
return fetch(resource, init).then(response => response.json());
|
return fetch(resource, init).then(response => {
|
||||||
|
if (!response.ok) {
|
||||||
|
// return Promise.reject('Network response error: ' + response.status);
|
||||||
|
throw new Error('Network response error: ' + response.status);
|
||||||
|
}
|
||||||
|
/* TODO: use this for non-developers?
|
||||||
|
response.clone()
|
||||||
|
let data = response.text();
|
||||||
|
try {
|
||||||
|
return JSON.parse(data);
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
// console.log(data);
|
||||||
|
return Promise.reject(Notification.JsonParse);
|
||||||
|
return {
|
||||||
|
Result: false,
|
||||||
|
ErrorCode: 952, // Notification.JsonParse
|
||||||
|
ErrorMessage: e.message,
|
||||||
|
ErrorMessageAdditional: data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
return response.json();
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
window.__APP_BOOT = fErrorCallback => {
|
window.__APP_BOOT = fErrorCallback => {
|
||||||
|
|
Loading…
Add table
Reference in a new issue