Refactor (Async suffix, default cb), fix error page gradient

This commit is contained in:
Ilya Ig. Petrov 2016-12-03 10:01:06 -08:00
parent 38ac7450a6
commit 05d02438c9
6 changed files with 204 additions and 138 deletions

View File

@ -134,13 +134,22 @@
(details) => handlers.isNotControlled(details)
);
const openAndFocus = (url) => {
chrome.tabs.create(
{active: true, url: url},
(tab) => chrome.windows.update(tab.windowId, {focused: true})
);
};
chrome.notifications.onClicked.addListener( function(notId) {
chrome.notifications.clear(notId);
if(notId === 'no-control') {
return chrome.tabs.create({active: true, url: 'chrome://settings/#proxy'});
return openAndFocus('chrome://settings/#proxy');
}
chrome.tabs.create({active: true, url: './pages/view-error/index.html#' + notId});
openAndFocus('./pages/view-error/index.html#' + notId);
});
@ -151,9 +160,18 @@
if (handlers.ifNoControl) {
return;
}
/*
Example:
details: "line: 7: Uncaught Error: This is error, man.",
error: "net::ERR_PAC_SCRIPT_FAILED",
fatal: false,
*/
console.warn('PAC ERROR', details);
handlers.mayNotify('pac-error', 'Ошибка PAC!', details,
'pac-error-128.png' );
// TOOD: add "view pac script at this line" button.
handlers.mayNotify('pac-error', 'Ошибка PAC!',
details.error + '\n' + details.details,
'pac-error-128.png'
);
});
@ -163,7 +181,8 @@
const noCon = 'no-control';
if ( handlers.isNotControlled(details) ) {
console.log(details);
handlers.mayNotify(noCon, 'Прокси контролирует другое расширение', details,
handlers.mayNotify(noCon, 'Другое расширение контролирует прокси',
'Какое?',
'no-control-128.png');
} else {
chrome.notifications.clear( noCon );

View File

@ -16,6 +16,71 @@
*/
{ // Private namespace starts.
function mandatory() {
throw new TypeError('Missing required argument. ' +
'Be explicit if you swallow errors.');
}
function throwIfError(err) {
if(err) {
throw err;
}
}
function asyncLogGroup(...args) {
const cb = args.pop();
if(!(cb && typeof(cb) === 'function')) {
throw new TypeError('cb must be a function, but got: ' + cb);
}
console.group(...args);
return function(...cbArgs) {
console.groupEnd();
console.log('Group finished.');
cb(...cbArgs);
};
}
function checkChromeError(betterStack) {
// Chrome API calls your cb in a context different from the point of API
// method invokation.
const err = chrome.runtime.lastError || chrome.extension.lastError || null;
if (err) {
const args = ['API returned error:', err];
if (betterStack) {
args.push('\n' + betterStack);
}
console.warn(...args);
}
return err;
}
function chromified(cb = mandatory(), ...replaceArgs) {
const stack = (new Error()).stack;
// Take error first callback and convert it to chrome api callback.
return function(...args) {
if (replaceArgs.length) {
args = replaceArgs;
}
const err = checkChromeError(stack);
// setTimeout fixes error context.
setTimeout( cb.bind(null, err, ...args), 0 );
};
}
window.apis.antiCensorRu = {
version: chrome.runtime.getManifest().version,
@ -99,7 +164,7 @@
_periodicUpdateAlarmReason: 'Периодичное обновление PAC-скрипта Антизапрет',
pushToStorageAsync(cb) {
pushToStorageAsync(cb = throwIfError) {
console.log('Pushing to storage...');
@ -123,29 +188,10 @@
},
/*
pullFromStorage(cb) {
syncWithPacProviderAsync(
key = this.currentPacProvierKey, cb = throwIfError) {
chrome.storage.local.get(null, (storage) => {
const err = checkChromeError();
if (!err) {
console.log('Pulled from storage:', storage);
for(const key of Object.keys(storage)) {
this[key] = storage[key];
}
}
console.log('Synced with storage, any callback?', !!cb);
cb && cb(err, storage);
});
},
*/
syncWithPacProviderAsync(key, cb) {
if( !key || typeof(key) === 'function' ) {
if( typeof(key) === 'function' ) {
cb = key;
key = this.currentPacProviderKey;
}
@ -239,7 +285,7 @@
},
installPacAsync(key, cb) {
installPacAsync(key, cb = throwIfError) {
console.log('Installing PAC...');
if (!key) {
@ -253,7 +299,7 @@
},
clearPacAsync(cb) {
clearPacAsync(cb = throwIfError) {
cb = asyncLogGroup('Cearing alarms and PAC...', cb);
chrome.alarms.clearAll(
@ -279,7 +325,11 @@
// ON EACH LAUNCH, STARTUP, RELOAD, UPDATE, ENABLE
chrome.storage.local.get(null, (oldStorage) => {
checkChromeError();
const err = checkChromeError();
if (err) {
throw err;
}
/*
Event handlers that ALWAYS work (even if installation is not done
or failed).
@ -296,7 +346,7 @@
'Periodic PAC update triggered:',
new Date().toLocaleString('ru-RU')
);
antiCensorRu.syncWithPacProviderAsync(/* Swallows errors. */);
antiCensorRu.syncWithPacProviderAsync(() => {/* swallow */});
}
}
@ -358,7 +408,7 @@
// UPDATE & MIGRATION
console.log('Extension updated.');
if (!ifAlarmTriggered) {
antiCensorRu.pushToStorageAsync(/* Swallows errors. */);
antiCensorRu.pushToStorageAsync();
}
/*
@ -374,55 +424,7 @@
});
function asyncLogGroup(...args) {
const cb = args.pop() || (() => {});
console.group(...args);
return function(...cbArgs) {
console.groupEnd();
console.log('Group finished.');
cb(...cbArgs);
};
}
function checkChromeError(betterStack) {
// Chrome API calls your cb in a context different from the point of API
// method invokation.
const err = chrome.runtime.lastError || chrome.extension.lastError || null;
if (err) {
const args = ['API returned error:', err];
if (betterStack) {
args.push('\n' + betterStack);
}
console.warn(...args);
}
return err;
}
function chromified(cb, ...replaceArgs) {
const stack = (new Error()).stack;
// Take error first callback and convert it to chrome api callback.
return function(...args) {
if (replaceArgs.length) {
args = replaceArgs;
}
const err = checkChromeError(stack);
if (cb) {
setTimeout( cb.bind(null, err, ...args), 0 );
}
};
}
function setPac(pacData, cb) {
function setPac(pacData, cb = throwIfError) {
const config = {
mode: 'pac_script',
@ -452,15 +454,14 @@
}
function httpGet(url, cb) {
function httpGet(url, cb = mandatory()) {
const start = Date.now();
fetch(url).then(
(res) => {
const textCb =
(err) => cb && res.text()
.then( (text) => cb(err, text), cb );
(err) => res.text().then( (text) => cb(err, text), cb );
const status = res.status;
if ( !( status >= 200 && status < 300 || status === 304 ) ) {
res.clarification = {
@ -477,14 +478,14 @@
err.clarification = {
message: 'Что-то не так с сетью, проверьте соединение.',
};
cb && cb(err);
cb(err);
}
);
}
function getIpsFor(host, cb) {
function getIpsFor(host, cb = mandatory()) {
const types = [1, 28];
const promises = types.map(
@ -546,7 +547,7 @@
}
function updatePacProxyIps(provider, cb) {
function updatePacProxyIps(provider, cb = throwIfError) {
cb = asyncLogGroup(
'Getting IP for '+ provider.proxyHosts.join(', ') + '...',
@ -585,7 +586,7 @@
}
function setPacScriptFromProvider(provider, cb) {
function setPacScriptFromProvider(provider, cb = throwIfError) {
cb = asyncLogGroup(
'Getting pac script from provider...', provider.pacUrl,

View File

@ -26,13 +26,13 @@
);
createMenuLinkEntry(
'Открыть веб прокси (не наш)',
(tab) => 'https://kproxy.com'
'Через Google Translate',
(tab) => 'https://translate.google.com/translate?hl=&sl=en&tl=ru&anno=2&sandbox=1&u=' + tab.url
);
createMenuLinkEntry(
'Другие варианты разблокировки',
(tab) => 'https://rebrand.ly/unblock#' + tab.url
(tab) => 'https://rebrand.ly/ac-unblock#' + tab.url
);
createMenuLinkEntry(

View File

@ -89,16 +89,20 @@ chrome.runtime.getBackgroundPage( (backgroundPage) =>
</span>
<br/>
<span style="font-size: 0.9em; color: darkred">${message}</span>
<a href class="link-button">[Ещё&nbsp;подробнее]</a>`
<a href="../view-error/index.html" class="link-button">
[Ещё&nbsp;подробнее]
</a>`
);
getStatus().querySelector('.link-button').onclick = function() {
const div = document.createElement('div');
div.innerHTML = `
Более подробную информацию можно узнать из логов фоновой страницы:<br/>
<a href="chrome://extensions?id=${chrome.runtime.id}" data-in-bg="true">
chrome://extensions</a>
Это расширение Отладка страниц: фоновая страница Console (DevTools)
Более подробную информацию можно узнать из логов фоновой страницы:
<br/>
<a href="chrome://extensions?id=${chrome.runtime.id}"
data-in-bg="true">
chrome://extensions</a> Это расширение Отладка страниц: фоновая
страница Console (DevTools)
<br>
Ещё: ` + JSON.stringify({err: err, stack: err.stack});
getStatus().replaceChild(div, this);
@ -137,7 +141,8 @@ chrome.runtime.getBackgroundPage( (backgroundPage) =>
const _firstChild = ul.firstChild;
for( const providerKey of Object.keys(antiCensorRu.pacProviders).sort() ) {
const li = document.createElement('li');
li.innerHTML = `<input type="radio" name="pacProvider" id="${providerKey}">
li.innerHTML = `
<input type="radio" name="pacProvider" id="${providerKey}">
<label for="${providerKey}">${providerKey}</label>
<a href class="link-button checked-radio-panel"
id="update-${providerKey}">[обновить]</a>`;
@ -159,7 +164,9 @@ chrome.runtime.getBackgroundPage( (backgroundPage) =>
for(const radio of radios) {
radio.onclick = function(event) {
if (event.target.id === (antiCensorRu.currentPacProviderKey || 'none')) {
if (
event.target.id === (antiCensorRu.currentPacProviderKey || 'none')
) {
return false;
}
const pacKey = event.target.id;
@ -194,7 +201,10 @@ chrome.runtime.getBackgroundPage( (backgroundPage) =>
box.onclick = function() {
const id = this.id.replace('if-on-', '');
backgroundPage.apis.errorHandlers.switch(this.checked ? 'on' : 'off', id);
backgroundPage.apis.errorHandlers.switch(
this.checked ? 'on' : 'off',
id
);
};
conpanel.appendChild(li);

View File

@ -7,15 +7,13 @@
margin: 0;
padding: 0;
width: 100%;
height: 100%;
min-height: 100%;
}
html {
background: black url('./err.jpg') repeat;
background-position: left;
color: white;
}
body {
background: linear-gradient(to bottom, black 45em, transparent);
padding-bottom: 10em;
}
header {
padding-top: 1em;
@ -52,14 +50,20 @@
</style>
</head>
<body>
<div id='for-bg'>
<header>
<h2>Информация об ошибке</h2>
</header>
<main>
<main style="display: none">
<ol>
<li>Тип: <span>ext-error</span></li>
<li><pre><code id="output" class='hljs'></code></pre></li>
<li><textarea placeholder='Ваш комментарий (опционально)' id="comment"></textarea></li>
<li><textarea placeholder='Ваш комментарий (опционально)' id="comment">
К этой ошибке приводят следующие действия:
1. ...
2. ...
</textarea>
</li>
<li>
<button id="raven-report">Отправить автору</button>
<button id="github-search">Искать на GitHub</button>
@ -67,6 +71,7 @@
</li>
</ol>
</main>
</div>
<script src="./vendor/raven3.8.1.min.js" crossorigin="anonymous"></script>
<link rel="stylesheet" href="./vendor/highlight.js/styles/atom-one-dark.css">
<script src="./vendor/highlight.js/highlight9.8.0.min.js"></script>

View File

@ -1,8 +1,12 @@
'use strict';
/* global Raven:false, hljs:false */
function errorJsonReplacer(key, value) {
if ( !['Error', 'ErrorEvent'].includes( value.constructor.name ) ) {
if (!( value && value.constructor
&& ['Error', 'Event'].some(
(suff) => value.constructor.name.endsWith(suff)
)
)) {
return value;
}
const alt = {};
@ -34,34 +38,57 @@ function errorJsonReplacer(key, value) {
}
chrome.runtime.getBackgroundPage( (backgroundPage) =>
backgroundPage.apis.errorHandlers.installListenersOn(window, 'ErrView', () => {
chrome.runtime.getBackgroundPage( (bgPage) =>
bgPage.apis.errorHandlers.installListenersOn(window, 'ErrView', () => {
Raven.config('https://bc534321358f455b9ae861740c2d3af8@sentry.io/116007', {
release: chrome.runtime.getManifest().version,
autoBreadcrumbs: false,
}).install();
const originalComment = document.querySelector('#comment').value.trim();
let json;
let err;
{
const output = document.getElementById('output');
const errId = window.location.hash.slice(1);
const err = backgroundPage.apis.errorHandlers.idToErr[errId];
const json = JSON.stringify(err, errorJsonReplacer, 2);
document.getElementById('output').innerHTML = hljs.highlight('json', json).value;
const idToErr = bgPage.apis.errorHandlers.idToErr;
err = errId && idToErr[errId] || idToErr;
if (!Object.keys(err).length) {
output.innerHTML = 'Ошибок не найдено. ' +
'Оставьте, пожалуйста, подробный комментарий.';
} else {
json = JSON.stringify(err, errorJsonReplacer, 2);
output.innerHTML = hljs.highlight('json', json).value;
}
}
document.addEventListener('ravenSuccess', () => alert('Готово'));
document.addEventListener('ravenFailure', () => alert('Ошибка sentry.io! (подробности недоступны)'));
document.addEventListener('ravenFailure',
() => alert('Ошибка sentry.io! (подробности недоступны)'));
document.getElementById('raven-report').onclick = () => {
const e = err.error || err;
const extra = JSON.parse(json);
const comment = document.getElementById('comment').value;
if (comment.trim()) {
let comment = document.getElementById('comment').value.trim();
if (comment === originalComment) {
comment = '';
}
if (!comment && !json) {
return alert('Посылать нечего, так как вы не оставили комментария.');
}
const extra = json && JSON.parse(json) || {};
if (comment) {
extra.comment = comment;
}
Raven.captureException(e, {
extra: extra,
onSuccess: () => alert('Готово'),
onError: (err) => { throw err; }
onError: (err) => {
throw err;
},
});
};
@ -70,8 +97,7 @@ chrome.runtime.getBackgroundPage( (backgroundPage) =>
const title = err.message || err;
chrome.tabs.create({
active: true,
url: 'https://rebrand.ly/ac-search-issues?q=' + encodeURIComponent(title)
url: 'https://rebrand.ly/ac-search-issues?q=' + encodeURIComponent(title),
});
};
@ -90,11 +116,16 @@ ${json}
Версия: ${chrome.runtime.getManifest().version}
`;
chrome.tabs.create({
active: true,
url: `https://rebrand.ly/ac-new-issue?title=${encodeURIComponent(title)}&body=${encodeURIComponent(body)}`
url: `https://rebrand.ly/ac-new-issue?title=${encodeURIComponent(title)}&body=${encodeURIComponent(body)}`,
});
};
document.querySelector('main').style.display = '';
document.body.style.background =
'linear-gradient(to bottom, black ' +
document.querySelector('textarea').offsetTop +
'px, transparent)';
})
);