stylus/background/update.js

249 lines
7.7 KiB
JavaScript
Raw Normal View History

2018-01-01 17:02:49 +00:00
/*
global getStyles saveStyle styleSectionsEqual
global calcStyleDigest cachedStyles getStyleWithNoCode
global usercss semverCompare
global API_METHODS
*/
2017-02-08 15:15:35 +00:00
'use strict';
2018-02-16 15:05:25 +00:00
(() => {
2018-01-01 17:02:49 +00:00
const STATES = {
UPDATED: 'updated',
SKIPPED: 'skipped',
// details for SKIPPED status
EDITED: 'locally edited',
MAYBE_EDITED: 'may be locally edited',
SAME_MD5: 'up-to-date: MD5 is unchanged',
SAME_CODE: 'up-to-date: code sections are unchanged',
SAME_VERSION: 'up-to-date: version is unchanged',
ERROR_MD5: 'error: MD5 is invalid',
ERROR_JSON: 'error: JSON is invalid',
ERROR_VERSION: 'error: version is older than installed style',
};
let lastUpdateTime = parseInt(localStorage.lastUpdateTime) || Date.now();
let checkingAll = false;
let logQueue = [];
let logLastWriteTime = 0;
const retrying = new Set();
2018-01-01 17:02:49 +00:00
API_METHODS.updateCheckAll = checkAllStyles;
API_METHODS.updateCheck = checkStyle;
2018-02-16 15:05:25 +00:00
API_METHODS.getUpdaterStates = () => STATES;
2018-01-01 17:02:49 +00:00
prefs.subscribe(['updateInterval'], schedule);
schedule();
return {checkAllStyles, checkStyle, STATES};
function checkAllStyles({
save = true,
ignoreDigest,
observe,
} = {}) {
resetInterval();
checkingAll = true;
retrying.clear();
2018-01-01 17:02:49 +00:00
const port = observe && chrome.runtime.connect({name: 'updater'});
2017-04-25 21:48:27 +00:00
return getStyles({}).then(styles => {
styles = styles.filter(style => style.updateUrl);
2018-01-01 17:02:49 +00:00
if (port) port.postMessage({count: styles.length});
log('');
log(`${save ? 'Scheduled' : 'Manual'} update check for ${styles.length} styles`);
2017-04-25 21:48:27 +00:00
return Promise.all(
styles.map(style =>
2018-01-01 17:02:49 +00:00
checkStyle({style, port, save, ignoreDigest})));
2017-04-25 21:48:27 +00:00
}).then(() => {
2018-01-01 17:02:49 +00:00
if (port) port.postMessage({done: true});
if (port) port.disconnect();
log('');
checkingAll = false;
retrying.clear();
2017-02-08 15:15:35 +00:00
});
2018-01-01 17:02:49 +00:00
}
function checkStyle({
id,
style = cachedStyles.byId.get(id),
port,
save = true,
ignoreDigest,
}) {
/*
Original style digests are calculated in these cases:
* style is installed or updated from server
* style is checked for an update and its code is equal to the server code
Update check proceeds in these cases:
* style has the original digest and it's equal to the current digest
* [ignoreDigest: true] style doesn't yet have the original digest but we ignore it
* [ignoreDigest: none/false] style doesn't yet have the original digest
so we compare the code to the server code and if it's the same we save the digest,
otherwise we skip the style and report MAYBE_EDITED status
'ignoreDigest' option is set on the second manual individual update check on the manage page.
*/
return Promise.resolve(style)
.then([calcStyleDigest][!ignoreDigest ? 0 : 'skip'])
.then([checkIfEdited][!ignoreDigest ? 0 : 'skip'])
.then([maybeUpdateUSO, maybeUpdateUsercss][style.usercssData ? 1 : 0])
2017-04-28 21:04:01 +00:00
.then(maybeSave)
.then(reportSuccess)
.catch(reportFailure);
function reportSuccess(saved) {
2018-01-01 17:02:49 +00:00
log(STATES.UPDATED + ` #${style.id} ${style.name}`);
const info = {updated: true, style: saved};
if (port) port.postMessage(info);
return info;
}
2018-01-01 17:02:49 +00:00
function reportFailure(error) {
// retry once if the error is 503 Service Unavailable
2018-05-04 19:06:50 +00:00
if (error === 503 && !retrying.has(id)) {
retrying.add(id);
return new Promise(resolve => {
setTimeout(() => {
resolve(checkStyle({id, style, port, save, ignoreDigest}));
}, 1000);
});
}
2018-01-01 17:02:49 +00:00
error = error === 0 ? 'server unreachable' : error;
log(STATES.SKIPPED + ` (${error}) #${style.id} ${style.name}`);
const info = {error, STATES, style: getStyleWithNoCode(style)};
if (port) port.postMessage(info);
return info;
}
Add: install styles from *.user.css file Fix: handle dup name+namespace Fix: eslint eqeqeq Fix: trim @name's spaces Add: check update for userstyle Add: build CSS variable Fix: only check dup when id is not provided Refactor: userStyle2json -> userstyle.json Add: style for input Add: config dialog Fix: preserve config during update Fix: onchange doesn't fire on keyboard enter event Fix: remove empty file Add: validator. Metas must stay in the same line Add: warn the user if installation failed Fix: add some delay before starting installation Add: open the editor after first installation Fix: add openEditor to globals Fix: i18n Add: preprocessor. Move userstyle.build to background page. Fix: remove unused global Fix: preserved unknown prop in saveStyleSource() like saveStyle() Add: edit userstyle source Fix: load preprocessor dynamically Fix: load content script dynamically Fix: buildCode is async function Fix: drop Object.entries Fix: style.sections is undefined Fix: don't hide the name input but disable it Fix: query the style before installation Revert: changes to editor, editor.html Refactor: use term `usercss` instead of `userstyle` Fix: don't show homepage action for usercss Refactor: move script-loader to js/ Refactor: pull out mozParser Fix: code style Fix: we don't need to build meta anymore Fix: use saveUsercss instead of saveStyle to get responsed error Fix: last is undefined, load script error Fix: switch to moz-format Fix: drop injectContentScript. Move usercss check into install-user-css Fix: response -> respond Fix: globals -> global Fix: queryUsercss -> filterUsercss Fix: add processUsercss function Fix: only open editor for usercss Fix: remove findupUsercss fixme Fix: globals -> global Fix: globals -> global Fix: global pollution Revert: update.js Refactor: checkStyle Add: support usercss Fix: no need to getURL in background page Fix: merget semver.js into usercss.js Fix: drop all_urls in match pattern Fix: drop respondWithError Move stylus -> stylus-lang Add stylus-lang/readme Fix: use include_globs Fix: global pollution
2017-08-05 16:49:25 +00:00
function checkIfEdited(digest) {
2017-09-16 01:24:50 +00:00
if (style.originalDigest && style.originalDigest !== digest) {
2018-01-01 17:02:49 +00:00
return Promise.reject(STATES.EDITED);
}
}
Add: install styles from *.user.css file Fix: handle dup name+namespace Fix: eslint eqeqeq Fix: trim @name's spaces Add: check update for userstyle Add: build CSS variable Fix: only check dup when id is not provided Refactor: userStyle2json -> userstyle.json Add: style for input Add: config dialog Fix: preserve config during update Fix: onchange doesn't fire on keyboard enter event Fix: remove empty file Add: validator. Metas must stay in the same line Add: warn the user if installation failed Fix: add some delay before starting installation Add: open the editor after first installation Fix: add openEditor to globals Fix: i18n Add: preprocessor. Move userstyle.build to background page. Fix: remove unused global Fix: preserved unknown prop in saveStyleSource() like saveStyle() Add: edit userstyle source Fix: load preprocessor dynamically Fix: load content script dynamically Fix: buildCode is async function Fix: drop Object.entries Fix: style.sections is undefined Fix: don't hide the name input but disable it Fix: query the style before installation Revert: changes to editor, editor.html Refactor: use term `usercss` instead of `userstyle` Fix: don't show homepage action for usercss Refactor: move script-loader to js/ Refactor: pull out mozParser Fix: code style Fix: we don't need to build meta anymore Fix: use saveUsercss instead of saveStyle to get responsed error Fix: last is undefined, load script error Fix: switch to moz-format Fix: drop injectContentScript. Move usercss check into install-user-css Fix: response -> respond Fix: globals -> global Fix: queryUsercss -> filterUsercss Fix: add processUsercss function Fix: only open editor for usercss Fix: remove findupUsercss fixme Fix: globals -> global Fix: globals -> global Fix: global pollution Revert: update.js Refactor: checkStyle Add: support usercss Fix: no need to getURL in background page Fix: merget semver.js into usercss.js Fix: drop all_urls in match pattern Fix: drop respondWithError Move stylus -> stylus-lang Add stylus-lang/readme Fix: use include_globs Fix: global pollution
2017-08-05 16:49:25 +00:00
function maybeUpdateUSO() {
return download(style.md5Url).then(md5 => {
if (!md5 || md5.length !== 32) {
2018-01-01 17:02:49 +00:00
return Promise.reject(STATES.ERROR_MD5);
Add: install styles from *.user.css file Fix: handle dup name+namespace Fix: eslint eqeqeq Fix: trim @name's spaces Add: check update for userstyle Add: build CSS variable Fix: only check dup when id is not provided Refactor: userStyle2json -> userstyle.json Add: style for input Add: config dialog Fix: preserve config during update Fix: onchange doesn't fire on keyboard enter event Fix: remove empty file Add: validator. Metas must stay in the same line Add: warn the user if installation failed Fix: add some delay before starting installation Add: open the editor after first installation Fix: add openEditor to globals Fix: i18n Add: preprocessor. Move userstyle.build to background page. Fix: remove unused global Fix: preserved unknown prop in saveStyleSource() like saveStyle() Add: edit userstyle source Fix: load preprocessor dynamically Fix: load content script dynamically Fix: buildCode is async function Fix: drop Object.entries Fix: style.sections is undefined Fix: don't hide the name input but disable it Fix: query the style before installation Revert: changes to editor, editor.html Refactor: use term `usercss` instead of `userstyle` Fix: don't show homepage action for usercss Refactor: move script-loader to js/ Refactor: pull out mozParser Fix: code style Fix: we don't need to build meta anymore Fix: use saveUsercss instead of saveStyle to get responsed error Fix: last is undefined, load script error Fix: switch to moz-format Fix: drop injectContentScript. Move usercss check into install-user-css Fix: response -> respond Fix: globals -> global Fix: queryUsercss -> filterUsercss Fix: add processUsercss function Fix: only open editor for usercss Fix: remove findupUsercss fixme Fix: globals -> global Fix: globals -> global Fix: global pollution Revert: update.js Refactor: checkStyle Add: support usercss Fix: no need to getURL in background page Fix: merget semver.js into usercss.js Fix: drop all_urls in match pattern Fix: drop respondWithError Move stylus -> stylus-lang Add stylus-lang/readme Fix: use include_globs Fix: global pollution
2017-08-05 16:49:25 +00:00
}
if (md5 === style.originalMd5 && style.originalDigest && !ignoreDigest) {
2018-01-01 17:02:49 +00:00
return Promise.reject(STATES.SAME_MD5);
Add: install styles from *.user.css file Fix: handle dup name+namespace Fix: eslint eqeqeq Fix: trim @name's spaces Add: check update for userstyle Add: build CSS variable Fix: only check dup when id is not provided Refactor: userStyle2json -> userstyle.json Add: style for input Add: config dialog Fix: preserve config during update Fix: onchange doesn't fire on keyboard enter event Fix: remove empty file Add: validator. Metas must stay in the same line Add: warn the user if installation failed Fix: add some delay before starting installation Add: open the editor after first installation Fix: add openEditor to globals Fix: i18n Add: preprocessor. Move userstyle.build to background page. Fix: remove unused global Fix: preserved unknown prop in saveStyleSource() like saveStyle() Add: edit userstyle source Fix: load preprocessor dynamically Fix: load content script dynamically Fix: buildCode is async function Fix: drop Object.entries Fix: style.sections is undefined Fix: don't hide the name input but disable it Fix: query the style before installation Revert: changes to editor, editor.html Refactor: use term `usercss` instead of `userstyle` Fix: don't show homepage action for usercss Refactor: move script-loader to js/ Refactor: pull out mozParser Fix: code style Fix: we don't need to build meta anymore Fix: use saveUsercss instead of saveStyle to get responsed error Fix: last is undefined, load script error Fix: switch to moz-format Fix: drop injectContentScript. Move usercss check into install-user-css Fix: response -> respond Fix: globals -> global Fix: queryUsercss -> filterUsercss Fix: add processUsercss function Fix: only open editor for usercss Fix: remove findupUsercss fixme Fix: globals -> global Fix: globals -> global Fix: global pollution Revert: update.js Refactor: checkStyle Add: support usercss Fix: no need to getURL in background page Fix: merget semver.js into usercss.js Fix: drop all_urls in match pattern Fix: drop respondWithError Move stylus -> stylus-lang Add stylus-lang/readme Fix: use include_globs Fix: global pollution
2017-08-05 16:49:25 +00:00
}
2018-03-13 14:24:10 +00:00
// USO can't handle POST requests for style json
return download(style.updateUrl, {body: null})
Add: install styles from *.user.css file Fix: handle dup name+namespace Fix: eslint eqeqeq Fix: trim @name's spaces Add: check update for userstyle Add: build CSS variable Fix: only check dup when id is not provided Refactor: userStyle2json -> userstyle.json Add: style for input Add: config dialog Fix: preserve config during update Fix: onchange doesn't fire on keyboard enter event Fix: remove empty file Add: validator. Metas must stay in the same line Add: warn the user if installation failed Fix: add some delay before starting installation Add: open the editor after first installation Fix: add openEditor to globals Fix: i18n Add: preprocessor. Move userstyle.build to background page. Fix: remove unused global Fix: preserved unknown prop in saveStyleSource() like saveStyle() Add: edit userstyle source Fix: load preprocessor dynamically Fix: load content script dynamically Fix: buildCode is async function Fix: drop Object.entries Fix: style.sections is undefined Fix: don't hide the name input but disable it Fix: query the style before installation Revert: changes to editor, editor.html Refactor: use term `usercss` instead of `userstyle` Fix: don't show homepage action for usercss Refactor: move script-loader to js/ Refactor: pull out mozParser Fix: code style Fix: we don't need to build meta anymore Fix: use saveUsercss instead of saveStyle to get responsed error Fix: last is undefined, load script error Fix: switch to moz-format Fix: drop injectContentScript. Move usercss check into install-user-css Fix: response -> respond Fix: globals -> global Fix: queryUsercss -> filterUsercss Fix: add processUsercss function Fix: only open editor for usercss Fix: remove findupUsercss fixme Fix: globals -> global Fix: globals -> global Fix: global pollution Revert: update.js Refactor: checkStyle Add: support usercss Fix: no need to getURL in background page Fix: merget semver.js into usercss.js Fix: drop all_urls in match pattern Fix: drop respondWithError Move stylus -> stylus-lang Add stylus-lang/readme Fix: use include_globs Fix: global pollution
2017-08-05 16:49:25 +00:00
.then(text => tryJSONparse(text));
});
}
function maybeUpdateUsercss() {
// TODO: when sourceCode is > 100kB use http range request(s) for version check
Add: install styles from *.user.css file Fix: handle dup name+namespace Fix: eslint eqeqeq Fix: trim @name's spaces Add: check update for userstyle Add: build CSS variable Fix: only check dup when id is not provided Refactor: userStyle2json -> userstyle.json Add: style for input Add: config dialog Fix: preserve config during update Fix: onchange doesn't fire on keyboard enter event Fix: remove empty file Add: validator. Metas must stay in the same line Add: warn the user if installation failed Fix: add some delay before starting installation Add: open the editor after first installation Fix: add openEditor to globals Fix: i18n Add: preprocessor. Move userstyle.build to background page. Fix: remove unused global Fix: preserved unknown prop in saveStyleSource() like saveStyle() Add: edit userstyle source Fix: load preprocessor dynamically Fix: load content script dynamically Fix: buildCode is async function Fix: drop Object.entries Fix: style.sections is undefined Fix: don't hide the name input but disable it Fix: query the style before installation Revert: changes to editor, editor.html Refactor: use term `usercss` instead of `userstyle` Fix: don't show homepage action for usercss Refactor: move script-loader to js/ Refactor: pull out mozParser Fix: code style Fix: we don't need to build meta anymore Fix: use saveUsercss instead of saveStyle to get responsed error Fix: last is undefined, load script error Fix: switch to moz-format Fix: drop injectContentScript. Move usercss check into install-user-css Fix: response -> respond Fix: globals -> global Fix: queryUsercss -> filterUsercss Fix: add processUsercss function Fix: only open editor for usercss Fix: remove findupUsercss fixme Fix: globals -> global Fix: globals -> global Fix: global pollution Revert: update.js Refactor: checkStyle Add: support usercss Fix: no need to getURL in background page Fix: merget semver.js into usercss.js Fix: drop all_urls in match pattern Fix: drop respondWithError Move stylus -> stylus-lang Add stylus-lang/readme Fix: use include_globs Fix: global pollution
2017-08-05 16:49:25 +00:00
return download(style.updateUrl).then(text => {
const json = usercss.buildMeta(text);
2017-09-16 01:24:50 +00:00
const {usercssData: {version}} = style;
const {usercssData: {version: newVersion}} = json;
2017-11-08 21:48:54 +00:00
switch (Math.sign(semverCompare(version, newVersion))) {
case 0:
// re-install is invalid in a soft upgrade
if (!ignoreDigest) {
2018-01-01 17:02:49 +00:00
return Promise.reject(STATES.SAME_VERSION);
} else if (text === style.sourceCode) {
2018-01-01 17:02:49 +00:00
return Promise.reject(STATES.SAME_CODE);
2017-11-08 21:48:54 +00:00
}
break;
case 1:
// downgrade is always invalid
2018-01-01 17:02:49 +00:00
return Promise.reject(STATES.ERROR_VERSION);
Add: install styles from *.user.css file Fix: handle dup name+namespace Fix: eslint eqeqeq Fix: trim @name's spaces Add: check update for userstyle Add: build CSS variable Fix: only check dup when id is not provided Refactor: userStyle2json -> userstyle.json Add: style for input Add: config dialog Fix: preserve config during update Fix: onchange doesn't fire on keyboard enter event Fix: remove empty file Add: validator. Metas must stay in the same line Add: warn the user if installation failed Fix: add some delay before starting installation Add: open the editor after first installation Fix: add openEditor to globals Fix: i18n Add: preprocessor. Move userstyle.build to background page. Fix: remove unused global Fix: preserved unknown prop in saveStyleSource() like saveStyle() Add: edit userstyle source Fix: load preprocessor dynamically Fix: load content script dynamically Fix: buildCode is async function Fix: drop Object.entries Fix: style.sections is undefined Fix: don't hide the name input but disable it Fix: query the style before installation Revert: changes to editor, editor.html Refactor: use term `usercss` instead of `userstyle` Fix: don't show homepage action for usercss Refactor: move script-loader to js/ Refactor: pull out mozParser Fix: code style Fix: we don't need to build meta anymore Fix: use saveUsercss instead of saveStyle to get responsed error Fix: last is undefined, load script error Fix: switch to moz-format Fix: drop injectContentScript. Move usercss check into install-user-css Fix: response -> respond Fix: globals -> global Fix: queryUsercss -> filterUsercss Fix: add processUsercss function Fix: only open editor for usercss Fix: remove findupUsercss fixme Fix: globals -> global Fix: globals -> global Fix: global pollution Revert: update.js Refactor: checkStyle Add: support usercss Fix: no need to getURL in background page Fix: merget semver.js into usercss.js Fix: drop all_urls in match pattern Fix: drop respondWithError Move stylus -> stylus-lang Add stylus-lang/readme Fix: use include_globs Fix: global pollution
2017-08-05 16:49:25 +00:00
}
return usercss.buildCode(json);
Add: install styles from *.user.css file Fix: handle dup name+namespace Fix: eslint eqeqeq Fix: trim @name's spaces Add: check update for userstyle Add: build CSS variable Fix: only check dup when id is not provided Refactor: userStyle2json -> userstyle.json Add: style for input Add: config dialog Fix: preserve config during update Fix: onchange doesn't fire on keyboard enter event Fix: remove empty file Add: validator. Metas must stay in the same line Add: warn the user if installation failed Fix: add some delay before starting installation Add: open the editor after first installation Fix: add openEditor to globals Fix: i18n Add: preprocessor. Move userstyle.build to background page. Fix: remove unused global Fix: preserved unknown prop in saveStyleSource() like saveStyle() Add: edit userstyle source Fix: load preprocessor dynamically Fix: load content script dynamically Fix: buildCode is async function Fix: drop Object.entries Fix: style.sections is undefined Fix: don't hide the name input but disable it Fix: query the style before installation Revert: changes to editor, editor.html Refactor: use term `usercss` instead of `userstyle` Fix: don't show homepage action for usercss Refactor: move script-loader to js/ Refactor: pull out mozParser Fix: code style Fix: we don't need to build meta anymore Fix: use saveUsercss instead of saveStyle to get responsed error Fix: last is undefined, load script error Fix: switch to moz-format Fix: drop injectContentScript. Move usercss check into install-user-css Fix: response -> respond Fix: globals -> global Fix: queryUsercss -> filterUsercss Fix: add processUsercss function Fix: only open editor for usercss Fix: remove findupUsercss fixme Fix: globals -> global Fix: globals -> global Fix: global pollution Revert: update.js Refactor: checkStyle Add: support usercss Fix: no need to getURL in background page Fix: merget semver.js into usercss.js Fix: drop all_urls in match pattern Fix: drop respondWithError Move stylus -> stylus-lang Add stylus-lang/readme Fix: use include_globs Fix: global pollution
2017-08-05 16:49:25 +00:00
});
}
function maybeSave(json = {}) {
// usercss is already validated while building
if (!json.usercssData && !styleJSONseemsValid(json)) {
2018-01-01 17:02:49 +00:00
return Promise.reject(STATES.ERROR_JSON);
}
2018-01-01 17:02:49 +00:00
2017-10-04 08:19:20 +00:00
json.id = style.id;
2017-11-26 17:47:23 +00:00
json.updateDate = Date.now();
json.reason = 'update';
// keep current state
delete json.enabled;
// keep local name customizations
if (style.originalName !== style.name && style.name !== json.name) {
delete json.name;
} else {
json.originalName = json.name;
}
if (styleSectionsEqual(json, style)) {
// update digest even if save === false as there might be just a space added etc.
saveStyle(Object.assign(json, {reason: 'update-digest'}));
2018-01-01 17:02:49 +00:00
return Promise.reject(STATES.SAME_CODE);
}
if (!style.originalDigest && !ignoreDigest) {
return Promise.reject(STATES.MAYBE_EDITED);
}
2018-01-01 17:02:49 +00:00
return save ?
API_METHODS[json.usercssData ? 'saveUsercss' : 'saveStyle'](json) :
json;
}
function styleJSONseemsValid(json) {
return json
&& json.sections
&& json.sections.length
2017-07-16 18:02:00 +00:00
&& typeof json.sections.every === 'function'
&& typeof json.sections[0].code === 'string';
}
2018-01-01 17:02:49 +00:00
}
2018-01-01 17:02:49 +00:00
function schedule() {
const interval = prefs.get('updateInterval') * 60 * 60 * 1000;
2017-02-14 15:35:53 +00:00
if (interval) {
2018-01-01 17:02:49 +00:00
const elapsed = Math.max(0, Date.now() - lastUpdateTime);
debounce(checkAllStyles, Math.max(10e3, interval - elapsed));
2017-04-22 18:02:49 +00:00
} else {
2018-01-01 17:02:49 +00:00
debounce.unregister(checkAllStyles);
2017-02-14 15:35:53 +00:00
}
2018-01-01 17:02:49 +00:00
}
function resetInterval() {
localStorage.lastUpdateTime = lastUpdateTime = Date.now();
schedule();
}
function log(text) {
logQueue.push({text, time: new Date().toLocaleString()});
debounce(flushQueue, text && checkingAll ? 1000 : 0);
}
2018-05-09 15:33:13 +00:00
function flushQueue(lines) {
if (!lines) {
chromeLocal.getValue('updateLog', []).then(flushQueue);
2018-01-01 17:02:49 +00:00
return;
2017-04-26 23:06:16 +00:00
}
2018-01-01 17:02:49 +00:00
const time = Date.now() - logLastWriteTime > 11e3 ?
logQueue[0].time + ' ' :
'';
if (!logQueue[0].text) {
logQueue.shift();
if (lines[lines.length - 1]) lines.push('');
}
lines.splice(0, lines.length - 1000);
lines.push(time + (logQueue[0] && logQueue[0].text || ''));
lines.push(...logQueue.slice(1).map(item => item.text));
2018-05-09 15:33:13 +00:00
chromeLocal.setValue('updateLog', lines);
2018-01-01 17:02:49 +00:00
logLastWriteTime = Date.now();
logQueue = [];
}
})();