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

@ -57,7 +57,7 @@
isNotControlled(details) { isNotControlled(details) {
this.ifNotControlled = window.utils.areSettingsNotControlledFor( details ); this.ifNotControlled = window.utils.areSettingsNotControlledFor(details);
if (this.ifNotControlled) { if (this.ifNotControlled) {
chrome.browserAction.disable(); chrome.browserAction.disable();
} else { } else {
@ -134,13 +134,22 @@
(details) => handlers.isNotControlled(details) (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.onClicked.addListener( function(notId) {
chrome.notifications.clear(notId); chrome.notifications.clear(notId);
if(notId === 'no-control') { 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) { if (handlers.ifNoControl) {
return; return;
} }
/*
Example:
details: "line: 7: Uncaught Error: This is error, man.",
error: "net::ERR_PAC_SCRIPT_FAILED",
fatal: false,
*/
console.warn('PAC ERROR', details); console.warn('PAC ERROR', details);
handlers.mayNotify('pac-error', 'Ошибка PAC!', details, // TOOD: add "view pac script at this line" button.
'pac-error-128.png' ); handlers.mayNotify('pac-error', 'Ошибка PAC!',
details.error + '\n' + details.details,
'pac-error-128.png'
);
}); });
@ -163,7 +181,8 @@
const noCon = 'no-control'; const noCon = 'no-control';
if ( handlers.isNotControlled(details) ) { if ( handlers.isNotControlled(details) ) {
console.log(details); console.log(details);
handlers.mayNotify(noCon, 'Прокси контролирует другое расширение', details, handlers.mayNotify(noCon, 'Другое расширение контролирует прокси',
'Какое?',
'no-control-128.png'); 'no-control-128.png');
} else { } else {
chrome.notifications.clear( noCon ); chrome.notifications.clear( noCon );

View File

@ -16,6 +16,71 @@
*/ */
{ // Private namespace starts. { // 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 = { window.apis.antiCensorRu = {
version: chrome.runtime.getManifest().version, version: chrome.runtime.getManifest().version,
@ -99,7 +164,7 @@
_periodicUpdateAlarmReason: 'Периодичное обновление PAC-скрипта Антизапрет', _periodicUpdateAlarmReason: 'Периодичное обновление PAC-скрипта Антизапрет',
pushToStorageAsync(cb) { pushToStorageAsync(cb = throwIfError) {
console.log('Pushing to storage...'); console.log('Pushing to storage...');
@ -123,29 +188,10 @@
}, },
/* syncWithPacProviderAsync(
pullFromStorage(cb) { key = this.currentPacProvierKey, cb = throwIfError) {
chrome.storage.local.get(null, (storage) => { if( typeof(key) === 'function' ) {
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' ) {
cb = key; cb = key;
key = this.currentPacProviderKey; key = this.currentPacProviderKey;
} }
@ -239,7 +285,7 @@
}, },
installPacAsync(key, cb) { installPacAsync(key, cb = throwIfError) {
console.log('Installing PAC...'); console.log('Installing PAC...');
if (!key) { if (!key) {
@ -253,7 +299,7 @@
}, },
clearPacAsync(cb) { clearPacAsync(cb = throwIfError) {
cb = asyncLogGroup('Cearing alarms and PAC...', cb); cb = asyncLogGroup('Cearing alarms and PAC...', cb);
chrome.alarms.clearAll( chrome.alarms.clearAll(
@ -279,7 +325,11 @@
// ON EACH LAUNCH, STARTUP, RELOAD, UPDATE, ENABLE // ON EACH LAUNCH, STARTUP, RELOAD, UPDATE, ENABLE
chrome.storage.local.get(null, (oldStorage) => { 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 Event handlers that ALWAYS work (even if installation is not done
or failed). or failed).
@ -296,7 +346,7 @@
'Periodic PAC update triggered:', 'Periodic PAC update triggered:',
new Date().toLocaleString('ru-RU') new Date().toLocaleString('ru-RU')
); );
antiCensorRu.syncWithPacProviderAsync(/* Swallows errors. */); antiCensorRu.syncWithPacProviderAsync(() => {/* swallow */});
} }
} }
@ -358,7 +408,7 @@
// UPDATE & MIGRATION // UPDATE & MIGRATION
console.log('Extension updated.'); console.log('Extension updated.');
if (!ifAlarmTriggered) { if (!ifAlarmTriggered) {
antiCensorRu.pushToStorageAsync(/* Swallows errors. */); antiCensorRu.pushToStorageAsync();
} }
/* /*
@ -374,55 +424,7 @@
}); });
function asyncLogGroup(...args) { function setPac(pacData, cb = throwIfError) {
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) {
const config = { const config = {
mode: 'pac_script', mode: 'pac_script',
@ -452,15 +454,14 @@
} }
function httpGet(url, cb) { function httpGet(url, cb = mandatory()) {
const start = Date.now(); const start = Date.now();
fetch(url).then( fetch(url).then(
(res) => { (res) => {
const textCb = const textCb =
(err) => cb && res.text() (err) => res.text().then( (text) => cb(err, text), cb );
.then( (text) => cb(err, text), cb );
const status = res.status; const status = res.status;
if ( !( status >= 200 && status < 300 || status === 304 ) ) { if ( !( status >= 200 && status < 300 || status === 304 ) ) {
res.clarification = { res.clarification = {
@ -477,14 +478,14 @@
err.clarification = { err.clarification = {
message: 'Что-то не так с сетью, проверьте соединение.', message: 'Что-то не так с сетью, проверьте соединение.',
}; };
cb && cb(err); cb(err);
} }
); );
} }
function getIpsFor(host, cb) { function getIpsFor(host, cb = mandatory()) {
const types = [1, 28]; const types = [1, 28];
const promises = types.map( const promises = types.map(
@ -546,7 +547,7 @@
} }
function updatePacProxyIps(provider, cb) { function updatePacProxyIps(provider, cb = throwIfError) {
cb = asyncLogGroup( cb = asyncLogGroup(
'Getting IP for '+ provider.proxyHosts.join(', ') + '...', 'Getting IP for '+ provider.proxyHosts.join(', ') + '...',
@ -585,7 +586,7 @@
} }
function setPacScriptFromProvider(provider, cb) { function setPacScriptFromProvider(provider, cb = throwIfError) {
cb = asyncLogGroup( cb = asyncLogGroup(
'Getting pac script from provider...', provider.pacUrl, 'Getting pac script from provider...', provider.pacUrl,

View File

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

View File

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

View File

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

View File

@ -1,13 +1,17 @@
'use strict'; 'use strict';
/* global Raven:false, hljs:false */
function errorJsonReplacer(key, value) { 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; return value;
} }
const alt = {}; const alt = {};
Object.getOwnPropertyNames(value).forEach(function (key) { Object.getOwnPropertyNames(value).forEach(function(key) {
alt[key] = value[key]; alt[key] = value[key];
}, value); }, value);
@ -34,34 +38,57 @@ function errorJsonReplacer(key, value) {
} }
chrome.runtime.getBackgroundPage( (backgroundPage) => chrome.runtime.getBackgroundPage( (bgPage) =>
backgroundPage.apis.errorHandlers.installListenersOn(window, 'ErrView', () => { bgPage.apis.errorHandlers.installListenersOn(window, 'ErrView', () => {
Raven.config('https://bc534321358f455b9ae861740c2d3af8@sentry.io/116007', { Raven.config('https://bc534321358f455b9ae861740c2d3af8@sentry.io/116007', {
release: chrome.runtime.getManifest().version, release: chrome.runtime.getManifest().version,
autoBreadcrumbs: false, autoBreadcrumbs: false,
}).install(); }).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 errId = window.location.hash.slice(1);
const err = backgroundPage.apis.errorHandlers.idToErr[errId]; const idToErr = bgPage.apis.errorHandlers.idToErr;
const json = JSON.stringify(err, errorJsonReplacer, 2); err = errId && idToErr[errId] || idToErr;
document.getElementById('output').innerHTML = hljs.highlight('json', json).value; 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('ravenSuccess', () => alert('Готово'));
document.addEventListener('ravenFailure', () => alert('Ошибка sentry.io! (подробности недоступны)')); document.addEventListener('ravenFailure',
() => alert('Ошибка sentry.io! (подробности недоступны)'));
document.getElementById('raven-report').onclick = () => { document.getElementById('raven-report').onclick = () => {
const e = err.error || err; const e = err.error || err;
const extra = JSON.parse(json); let comment = document.getElementById('comment').value.trim();
const comment = document.getElementById('comment').value; if (comment === originalComment) {
if (comment.trim()) { comment = '';
}
if (!comment && !json) {
return alert('Посылать нечего, так как вы не оставили комментария.');
}
const extra = json && JSON.parse(json) || {};
if (comment) {
extra.comment = comment; extra.comment = comment;
} }
Raven.captureException(e, { Raven.captureException(e, {
extra: extra, extra: extra,
onSuccess: () => alert('Готово'), onSuccess: () => alert('Готово'),
onError: (err) => { throw err; } onError: (err) => {
throw err;
},
}); });
}; };
@ -70,8 +97,7 @@ chrome.runtime.getBackgroundPage( (backgroundPage) =>
const title = err.message || err; const title = err.message || err;
chrome.tabs.create({ 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.runtime.getManifest().version}
`; `;
chrome.tabs.create({ 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)';
}) })
); );