Changes of Linux ptb v0.0.18
This commit is contained in:
parent
3185a0ea9f
commit
9dd45e7cc0
4 changed files with 543 additions and 314 deletions
|
@ -4,22 +4,24 @@ Object.defineProperty(exports, "__esModule", {
|
||||||
value: true
|
value: true
|
||||||
});
|
});
|
||||||
|
|
||||||
var _events = require('events');
|
|
||||||
|
|
||||||
var _squirrelUpdate = require('./squirrelUpdate');
|
|
||||||
|
|
||||||
var squirrelUpdate = _interopRequireWildcard(_squirrelUpdate);
|
|
||||||
|
|
||||||
var _electron = require('electron');
|
var _electron = require('electron');
|
||||||
|
|
||||||
|
var _events = require('events');
|
||||||
|
|
||||||
var _request = require('./request');
|
var _request = require('./request');
|
||||||
|
|
||||||
var _request2 = _interopRequireDefault(_request);
|
var _request2 = _interopRequireDefault(_request);
|
||||||
|
|
||||||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
var _squirrelUpdate = require('./squirrelUpdate');
|
||||||
|
|
||||||
|
var squirrelUpdate = _interopRequireWildcard(_squirrelUpdate);
|
||||||
|
|
||||||
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
|
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
|
||||||
|
|
||||||
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||||
|
|
||||||
|
function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
|
||||||
|
|
||||||
function versionParse(verString) {
|
function versionParse(verString) {
|
||||||
return verString.split('.').map(i => parseInt(i));
|
return verString.split('.').map(i => parseInt(i));
|
||||||
}
|
}
|
||||||
|
@ -127,43 +129,50 @@ class AutoUpdaterLinux extends _events.EventEmitter {
|
||||||
this.updateUrl = url;
|
this.updateUrl = url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
quitAndInstall() {
|
||||||
|
// Just restart. The splash screen will hit the update manually state and
|
||||||
|
// prompt the user to download the new package.
|
||||||
|
_electron.app.relaunch();
|
||||||
|
_electron.app.quit();
|
||||||
|
}
|
||||||
|
|
||||||
checkForUpdates() {
|
checkForUpdates() {
|
||||||
const currVersion = versionParse(_electron.app.getVersion());
|
var _this = this;
|
||||||
this.emit('checking-for-update');
|
|
||||||
|
|
||||||
_request2.default.get({ url: this.updateUrl, encoding: null }, (error, response, body) => {
|
return _asyncToGenerator(function* () {
|
||||||
if (error) {
|
const currVersion = versionParse(_electron.app.getVersion());
|
||||||
console.error('[Updates] Error fetching ' + this.updateUrl + ': ' + error);
|
_this.emit('checking-for-update');
|
||||||
this.emit('error', error);
|
|
||||||
return;
|
try {
|
||||||
}
|
const response = yield _request2.default.get(_this.updateUrl);
|
||||||
|
|
||||||
|
if (response.statusCode === 204) {
|
||||||
|
// you are up to date
|
||||||
|
_this.emit('update-not-available');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (response.statusCode === 204) {
|
|
||||||
// you are up to date
|
|
||||||
this.emit('update-not-available');
|
|
||||||
} else if (response.statusCode === 200) {
|
|
||||||
let latestVerStr = '';
|
let latestVerStr = '';
|
||||||
let latestVersion = [];
|
let latestVersion = [];
|
||||||
try {
|
try {
|
||||||
const latestMetadata = JSON.parse(body);
|
const latestMetadata = JSON.parse(response.body);
|
||||||
latestVerStr = latestMetadata.name;
|
latestVerStr = latestMetadata.name;
|
||||||
latestVersion = versionParse(latestVerStr);
|
latestVersion = versionParse(latestVerStr);
|
||||||
} catch (e) {}
|
} catch (_) {}
|
||||||
|
|
||||||
if (versionNewer(latestVersion, currVersion)) {
|
if (versionNewer(latestVersion, currVersion)) {
|
||||||
console.log('[Updates] You are out of date!');
|
console.log('[Updates] You are out of date!');
|
||||||
// you need to update
|
// you need to update
|
||||||
this.emit('update-manually', latestVerStr);
|
_this.emit('update-manually', latestVerStr);
|
||||||
} else {
|
} else {
|
||||||
console.log('[Updates] You are living in the future!');
|
console.log('[Updates] You are living in the future!');
|
||||||
this.emit('update-not-available');
|
_this.emit('update-not-available');
|
||||||
}
|
}
|
||||||
} else {
|
} catch (err) {
|
||||||
// something is wrong
|
console.error('[Updates] Error fetching ' + _this.updateUrl + ': ' + err.message);
|
||||||
console.error(`[Updates] Error: fetch returned: ${response.statusCode}`);
|
_this.emit('error', err);
|
||||||
this.emit('update-not-available');
|
|
||||||
}
|
}
|
||||||
});
|
})();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,84 @@ Object.defineProperty(exports, "__esModule", {
|
||||||
|
|
||||||
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
|
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
|
||||||
|
|
||||||
|
let electronRequest = (() => {
|
||||||
|
var _ref = _asyncToGenerator(function* ({ method, url, headers, qs, timeout, body, stream }) {
|
||||||
|
yield _electron.app.whenReady();
|
||||||
|
|
||||||
|
const { net, session } = require('electron');
|
||||||
|
const req = net.request({
|
||||||
|
method,
|
||||||
|
url: `${url}${qs != null ? `?${_querystring2.default.stringify(qs)}` : ''}`,
|
||||||
|
redirect: 'follow',
|
||||||
|
session: session.defaultSession
|
||||||
|
});
|
||||||
|
|
||||||
|
if (headers != null) {
|
||||||
|
for (const headerKey of Object.keys(headers)) {
|
||||||
|
req.setHeader(headerKey, headers[headerKey]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (body != null) {
|
||||||
|
req.write(body, 'utf-8');
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Promise(function (resolve, reject) {
|
||||||
|
const reqTimeout = setTimeout(function () {
|
||||||
|
req.abort();
|
||||||
|
reject(new Error(`network timeout: ${url}`));
|
||||||
|
}, timeout != null ? timeout : DEFAULT_REQUEST_TIMEOUT);
|
||||||
|
|
||||||
|
req.on('login', function (authInfo, callback) {
|
||||||
|
return callback();
|
||||||
|
});
|
||||||
|
|
||||||
|
req.on('response', function (response) {
|
||||||
|
clearTimeout(reqTimeout);
|
||||||
|
handleHTTPResponse(resolve, reject, response, stream);
|
||||||
|
});
|
||||||
|
|
||||||
|
req.on('error', function (err) {
|
||||||
|
clearTimeout(reqTimeout);
|
||||||
|
reject(err);
|
||||||
|
});
|
||||||
|
|
||||||
|
req.end();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return function electronRequest(_x) {
|
||||||
|
return _ref.apply(this, arguments);
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
|
let requestWithMethod = (() => {
|
||||||
|
var _ref2 = _asyncToGenerator(function* (method, options) {
|
||||||
|
if (typeof options === 'string') {
|
||||||
|
options = { url: options };
|
||||||
|
}
|
||||||
|
|
||||||
|
options = _extends({}, options, { method });
|
||||||
|
|
||||||
|
try {
|
||||||
|
return yield electronRequest(options);
|
||||||
|
} catch (err) {
|
||||||
|
console.log(`Error downloading with electron net: ${err.message}`);
|
||||||
|
console.log('Falling back to node net library..');
|
||||||
|
}
|
||||||
|
|
||||||
|
return nodeRequest(options);
|
||||||
|
});
|
||||||
|
|
||||||
|
return function requestWithMethod(_x2, _x3) {
|
||||||
|
return _ref2.apply(this, arguments);
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
|
// only supports get for now, since retrying is non-idempotent and
|
||||||
|
// we'd want to grovel the errors to make sure it's safe to retry
|
||||||
|
|
||||||
|
|
||||||
var _electron = require('electron');
|
var _electron = require('electron');
|
||||||
|
|
||||||
var _querystring = require('querystring');
|
var _querystring = require('querystring');
|
||||||
|
@ -16,100 +94,88 @@ var _request = require('request');
|
||||||
|
|
||||||
var _request2 = _interopRequireDefault(_request);
|
var _request2 = _interopRequireDefault(_request);
|
||||||
|
|
||||||
var _events = require('events');
|
|
||||||
|
|
||||||
var _events2 = _interopRequireDefault(_events);
|
|
||||||
|
|
||||||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||||
|
|
||||||
function _log(_msg) {
|
function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
|
||||||
// console.log('[Request] ' + _msg);
|
|
||||||
|
const DEFAULT_REQUEST_TIMEOUT = 30000;
|
||||||
|
|
||||||
|
function makeHTTPResponse({ method, url, headers, statusCode, statusMessage }, body) {
|
||||||
|
return {
|
||||||
|
method,
|
||||||
|
url,
|
||||||
|
headers,
|
||||||
|
statusCode,
|
||||||
|
statusMessage,
|
||||||
|
body
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function requestWithMethod(method, origOpts, origCallback) {
|
function makeHTTPStatusError(response) {
|
||||||
if (typeof origOpts == 'string') {
|
const err = new Error(`HTTP Error: Status Code ${response.statusCode}`);
|
||||||
origOpts = { url: origOpts };
|
err.response = response;
|
||||||
}
|
return err;
|
||||||
|
}
|
||||||
const opts = _extends({}, origOpts, { method });
|
|
||||||
|
function handleHTTPResponse(resolve, reject, response, stream) {
|
||||||
let callback;
|
const totalBytes = parseInt(response.headers['content-length'] || 1, 10);
|
||||||
if (origCallback || opts.callback) {
|
let receivedBytes = 0;
|
||||||
const origOptsCallback = opts.callback;
|
const chunks = [];
|
||||||
delete opts.callback;
|
|
||||||
callback = (...args) => {
|
// don't stream response if it's a failure
|
||||||
if (origCallback) {
|
if (response.statusCode >= 300) {
|
||||||
origCallback.apply(this, args);
|
stream = null;
|
||||||
}
|
}
|
||||||
if (origOptsCallback) {
|
|
||||||
origOptsCallback.apply(this, args);
|
response.on('data', chunk => {
|
||||||
}
|
if (stream != null) {
|
||||||
};
|
receivedBytes += chunk.length;
|
||||||
}
|
stream.write(chunk);
|
||||||
|
stream.emit('progress', { totalBytes, receivedBytes });
|
||||||
const strictOpts = _extends({}, opts, { strictSSL: true });
|
return;
|
||||||
const laxOpts = _extends({}, opts, { strictSSL: false });
|
}
|
||||||
|
|
||||||
const rv = new _events2.default();
|
chunks.push(chunk);
|
||||||
|
});
|
||||||
if (callback) {
|
|
||||||
_log('have callback, so wrapping');
|
response.on('end', () => {
|
||||||
rv.on('response', response => {
|
if (stream != null) {
|
||||||
const chunks = [];
|
stream.on('finish', () => resolve(makeHTTPResponse(response, null)));
|
||||||
response.on('data', chunk => chunks.push(chunk));
|
stream.end();
|
||||||
response.on('end', () => {
|
return;
|
||||||
callback(null, response, Buffer.concat(chunks));
|
}
|
||||||
});
|
|
||||||
});
|
const res = makeHTTPResponse(response, Buffer.concat(chunks));
|
||||||
rv.on('error', error => callback(error));
|
|
||||||
}
|
if (res.statusCode >= 300) {
|
||||||
|
reject(makeHTTPStatusError(res));
|
||||||
const requestTypes = [{
|
return;
|
||||||
factory: function () {
|
}
|
||||||
return (0, _request2.default)(strictOpts);
|
|
||||||
},
|
resolve(res);
|
||||||
method: 'node_request_strict'
|
});
|
||||||
}, {
|
}
|
||||||
factory: function () {
|
|
||||||
const qs = _querystring2.default.stringify(strictOpts.qs);
|
function nodeRequest({ method, url, headers, qs, timeout, body, stream }) {
|
||||||
const nr = _electron.net.request(_extends({}, strictOpts, { url: `${strictOpts.url}?${qs}` }));
|
return new Promise((resolve, reject) => {
|
||||||
nr.end();
|
const req = (0, _request2.default)({
|
||||||
return nr;
|
method,
|
||||||
},
|
url,
|
||||||
method: 'electron_net_request_strict'
|
qs,
|
||||||
}, {
|
headers,
|
||||||
factory: function () {
|
followAllRedirects: true,
|
||||||
return (0, _request2.default)(laxOpts);
|
encoding: null,
|
||||||
},
|
timeout: timeout != null ? timeout : DEFAULT_REQUEST_TIMEOUT,
|
||||||
method: 'node_request_lax'
|
body
|
||||||
}];
|
});
|
||||||
|
|
||||||
function attempt(index) {
|
req.on('response', response => handleHTTPResponse(resolve, reject, response, stream));
|
||||||
const { factory, method } = requestTypes[index];
|
req.on('error', err => reject(err));
|
||||||
_log(`Attempt #${index + 1}: ${method}`);
|
});
|
||||||
factory().on('response', response => {
|
|
||||||
_log(`${method} success! emitting response ${response}`);
|
|
||||||
rv.emit('response', response);
|
|
||||||
}).on('error', error => {
|
|
||||||
if (index + 1 < requestTypes.length) {
|
|
||||||
_log(`${method} failure, trying next option`);
|
|
||||||
attempt(index + 1);
|
|
||||||
} else {
|
|
||||||
_log(`${method} failure, out of options`);
|
|
||||||
rv.emit('error', error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
attempt(0);
|
|
||||||
|
|
||||||
return rv;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// only supports get for now, since retrying is non-idempotent and
|
|
||||||
// we'd want to grovel the errors to make sure it's safe to retry
|
|
||||||
for (const method of ['get']) {
|
for (const method of ['get']) {
|
||||||
requestWithMethod[method] = requestWithMethod.bind(null, method);
|
requestWithMethod[method] = requestWithMethod.bind(null, method.toUpperCase());
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.default = requestWithMethod;
|
exports.default = requestWithMethod;
|
||||||
|
|
|
@ -13,6 +13,12 @@ exports.pageReady = pageReady;
|
||||||
|
|
||||||
var _electron = require('electron');
|
var _electron = require('electron');
|
||||||
|
|
||||||
|
var _events = require('events');
|
||||||
|
|
||||||
|
var _fs = require('fs');
|
||||||
|
|
||||||
|
var _fs2 = _interopRequireDefault(_fs);
|
||||||
|
|
||||||
var _path = require('path');
|
var _path = require('path');
|
||||||
|
|
||||||
var _path2 = _interopRequireDefault(_path);
|
var _path2 = _interopRequireDefault(_path);
|
||||||
|
@ -21,23 +27,17 @@ var _url = require('url');
|
||||||
|
|
||||||
var _url2 = _interopRequireDefault(_url);
|
var _url2 = _interopRequireDefault(_url);
|
||||||
|
|
||||||
var _events = require('events');
|
|
||||||
|
|
||||||
var _moduleUpdater = require('../common/moduleUpdater');
|
var _moduleUpdater = require('../common/moduleUpdater');
|
||||||
|
|
||||||
var moduleUpdater = _interopRequireWildcard(_moduleUpdater);
|
var moduleUpdater = _interopRequireWildcard(_moduleUpdater);
|
||||||
|
|
||||||
var _ipcMain = require('./ipcMain');
|
|
||||||
|
|
||||||
var _ipcMain2 = _interopRequireDefault(_ipcMain);
|
|
||||||
|
|
||||||
var _paths = require('../common/paths');
|
var _paths = require('../common/paths');
|
||||||
|
|
||||||
var paths = _interopRequireWildcard(_paths);
|
var paths = _interopRequireWildcard(_paths);
|
||||||
|
|
||||||
var _fs = require('fs');
|
var _ipcMain = require('./ipcMain');
|
||||||
|
|
||||||
var _fs2 = _interopRequireDefault(_fs);
|
var _ipcMain2 = _interopRequireDefault(_ipcMain);
|
||||||
|
|
||||||
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
|
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
|
||||||
|
|
||||||
|
@ -86,6 +86,7 @@ let updateAttempt;
|
||||||
let splashState;
|
let splashState;
|
||||||
let launchedMainWindow;
|
let launchedMainWindow;
|
||||||
let quoteCachePath;
|
let quoteCachePath;
|
||||||
|
let restartRequired = false;
|
||||||
|
|
||||||
function initSplash(startMinimized = false) {
|
function initSplash(startMinimized = false) {
|
||||||
modulesListeners = {};
|
modulesListeners = {};
|
||||||
|
@ -98,56 +99,68 @@ function initSplash(startMinimized = false) {
|
||||||
updateSplashState(CHECKING_FOR_UPDATES);
|
updateSplashState(CHECKING_FOR_UPDATES);
|
||||||
});
|
});
|
||||||
|
|
||||||
addModulesListener(UPDATE_CHECK_FINISHED, (succeeded, updateCount, manualRequired) => {
|
addModulesListener(UPDATE_CHECK_FINISHED, ({ succeeded, updateCount, manualRequired }) => {
|
||||||
stopUpdateTimeout();
|
stopUpdateTimeout();
|
||||||
if (!succeeded) {
|
if (!succeeded) {
|
||||||
scheduleUpdateCheck();
|
scheduleUpdateCheck();
|
||||||
updateSplashState(UPDATE_FAILURE);
|
updateSplashState(UPDATE_FAILURE);
|
||||||
} else if (updateCount === 0) {
|
} else if (updateCount === 0) {
|
||||||
|
moduleUpdater.setInBackground();
|
||||||
launchMainWindow();
|
launchMainWindow();
|
||||||
updateSplashState(LAUNCHING);
|
updateSplashState(LAUNCHING);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
addModulesListener(DOWNLOADING_MODULE, (name, current, total) => {
|
addModulesListener(DOWNLOADING_MODULE, ({ name, current, total }) => {
|
||||||
stopUpdateTimeout();
|
stopUpdateTimeout();
|
||||||
splashState = { current, total };
|
splashState = { current, total };
|
||||||
updateSplashState(DOWNLOADING_UPDATES);
|
updateSplashState(DOWNLOADING_UPDATES);
|
||||||
});
|
});
|
||||||
|
|
||||||
addModulesListener(DOWNLOADING_MODULE_PROGRESS, (name, progress) => {
|
addModulesListener(DOWNLOADING_MODULE_PROGRESS, ({ name, progress }) => {
|
||||||
splashState.progress = progress;
|
splashState.progress = progress;
|
||||||
updateSplashState(DOWNLOADING_UPDATES);
|
updateSplashState(DOWNLOADING_UPDATES);
|
||||||
});
|
});
|
||||||
|
|
||||||
addModulesListener(DOWNLOADED_MODULE, (name, current, total, succeeded) => delete splashState.progress);
|
addModulesListener(DOWNLOADED_MODULE, ({ name, current, total, succeeded }) => {
|
||||||
|
delete splashState.progress;
|
||||||
|
if (name === 'host') {
|
||||||
|
restartRequired = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
addModulesListener(DOWNLOADING_MODULES_FINISHED, (succeeded, failed) => {
|
addModulesListener(DOWNLOADING_MODULES_FINISHED, ({ succeeded, failed }) => {
|
||||||
if (failed > 0) {
|
if (failed > 0) {
|
||||||
scheduleUpdateCheck();
|
scheduleUpdateCheck();
|
||||||
updateSplashState(UPDATE_FAILURE);
|
updateSplashState(UPDATE_FAILURE);
|
||||||
} else {
|
} else {
|
||||||
process.nextTick(() => moduleUpdater.quitAndInstallUpdates());
|
process.nextTick(() => {
|
||||||
|
if (restartRequired) {
|
||||||
|
moduleUpdater.quitAndInstallUpdates();
|
||||||
|
} else {
|
||||||
|
moduleUpdater.installPendingUpdates();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
addModulesListener(NO_PENDING_UPDATES, () => moduleUpdater.checkForUpdates());
|
addModulesListener(NO_PENDING_UPDATES, () => moduleUpdater.checkForUpdates());
|
||||||
|
|
||||||
addModulesListener(INSTALLING_MODULE, (name, current, total) => {
|
addModulesListener(INSTALLING_MODULE, ({ name, current, total }) => {
|
||||||
splashState = { current, total };
|
splashState = { current, total };
|
||||||
updateSplashState(INSTALLING_UPDATES);
|
updateSplashState(INSTALLING_UPDATES);
|
||||||
});
|
});
|
||||||
|
|
||||||
addModulesListener(INSTALLED_MODULE, (name, current, total, succeeded) => delete splashState.progress);
|
addModulesListener(INSTALLED_MODULE, ({ name, current, total, succeeded }) => delete splashState.progress);
|
||||||
|
|
||||||
addModulesListener(INSTALLING_MODULE_PROGRESS, (name, progress) => {
|
addModulesListener(INSTALLING_MODULE_PROGRESS, ({ name, progress }) => {
|
||||||
splashState.progress = progress;
|
splashState.progress = progress;
|
||||||
updateSplashState(INSTALLING_UPDATES);
|
updateSplashState(INSTALLING_UPDATES);
|
||||||
});
|
});
|
||||||
|
|
||||||
addModulesListener(INSTALLING_MODULES_FINISHED, (succeeded, failed) => moduleUpdater.checkForUpdates());
|
addModulesListener(INSTALLING_MODULES_FINISHED, ({ succeeded, failed }) => moduleUpdater.checkForUpdates());
|
||||||
|
|
||||||
addModulesListener(UPDATE_MANUALLY, newVersion => {
|
addModulesListener(UPDATE_MANUALLY, ({ newVersion }) => {
|
||||||
splashState.newVersion = newVersion;
|
splashState.newVersion = newVersion;
|
||||||
updateSplashState(UPDATE_MANUALLY);
|
updateSplashState(UPDATE_MANUALLY);
|
||||||
});
|
});
|
||||||
|
@ -242,7 +255,7 @@ function launchSplashWindow(startMinimized) {
|
||||||
}
|
}
|
||||||
|
|
||||||
_ipcMain2.default.on('SPLASH_SCREEN_READY', () => {
|
_ipcMain2.default.on('SPLASH_SCREEN_READY', () => {
|
||||||
let cachedQuote = chooseCachedQuote();
|
const cachedQuote = chooseCachedQuote();
|
||||||
if (cachedQuote) {
|
if (cachedQuote) {
|
||||||
webContentsSend(splashWindow, 'SPLASH_SCREEN_QUOTE', cachedQuote);
|
webContentsSend(splashWindow, 'SPLASH_SCREEN_QUOTE', cachedQuote);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,17 +3,152 @@
|
||||||
Object.defineProperty(exports, "__esModule", {
|
Object.defineProperty(exports, "__esModule", {
|
||||||
value: true
|
value: true
|
||||||
});
|
});
|
||||||
exports.events = exports.NO_PENDING_UPDATES = exports.INSTALLING_MODULE_PROGRESS = exports.INSTALLING_MODULE = exports.INSTALLING_MODULES_FINISHED = exports.DOWNLOADED_MODULE = exports.UPDATE_MANUALLY = exports.DOWNLOADING_MODULES_FINISHED = exports.DOWNLOADING_MODULE_PROGRESS = exports.DOWNLOADING_MODULE = exports.UPDATE_CHECK_FINISHED = exports.INSTALLED_MODULE = exports.CHECKING_FOR_UPDATES = undefined;
|
exports.supportsEventObjects = exports.events = exports.NO_PENDING_UPDATES = exports.INSTALLING_MODULE_PROGRESS = exports.INSTALLING_MODULE = exports.INSTALLING_MODULES_FINISHED = exports.DOWNLOADED_MODULE = exports.UPDATE_MANUALLY = exports.DOWNLOADING_MODULES_FINISHED = exports.DOWNLOADING_MODULE_PROGRESS = exports.DOWNLOADING_MODULE = exports.UPDATE_CHECK_FINISHED = exports.INSTALLED_MODULE = exports.CHECKING_FOR_UPDATES = undefined;
|
||||||
|
|
||||||
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; // Manages additional module installation and management.
|
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
|
||||||
// We add the module folder path to require() lookup paths here.
|
|
||||||
|
|
||||||
// undocumented node API
|
let checkForModuleUpdates = (() => {
|
||||||
|
var _ref = _asyncToGenerator(function* () {
|
||||||
|
const query = _extends({}, remoteQuery, { _: Math.floor(Date.now() / 1000 / 60 / 5) });
|
||||||
|
const url = `${remoteBaseURL}/versions.json`;
|
||||||
|
logger.log(`Checking for module updates at ${url}`);
|
||||||
|
|
||||||
|
let response;
|
||||||
|
try {
|
||||||
|
response = yield request.get({ url, qs: query, timeout: REQUEST_TIMEOUT });
|
||||||
|
checkingForUpdates = false;
|
||||||
|
} catch (err) {
|
||||||
|
checkingForUpdates = false;
|
||||||
|
logger.log(`Failed fetching module versions: ${String(err)}`);
|
||||||
|
|
||||||
|
events.append({
|
||||||
|
type: UPDATE_CHECK_FINISHED,
|
||||||
|
succeeded: false,
|
||||||
|
updateCount: 0,
|
||||||
|
manualRequired: false
|
||||||
|
});
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
remoteModuleVersions = JSON.parse(response.body);
|
||||||
|
if (settings.get(USE_LOCAL_MODULE_VERSIONS)) {
|
||||||
|
try {
|
||||||
|
remoteModuleVersions = JSON.parse(_fs2.default.readFileSync(localModuleVersionsFilePath));
|
||||||
|
console.log('Using local module versions: ', remoteModuleVersions);
|
||||||
|
} catch (err) {
|
||||||
|
console.warn('Failed to parse local module versions: ', err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const updatesToDownload = [];
|
||||||
|
for (const moduleName of Object.keys(installedModules)) {
|
||||||
|
const installedModule = installedModules[moduleName];
|
||||||
|
const installed = installedModule.installedVersion;
|
||||||
|
if (installed === null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const update = installedModule.updateVersion || 0;
|
||||||
|
const remote = remoteModuleVersions[getRemoteModuleName(moduleName)] || 0;
|
||||||
|
if (installed !== remote && update !== remote) {
|
||||||
|
logger.log(`Module update available: ${moduleName}@${remote} [installed: ${installed}]`);
|
||||||
|
updatesToDownload.push({ name: moduleName, version: remote });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
events.append({
|
||||||
|
type: UPDATE_CHECK_FINISHED,
|
||||||
|
succeeded: true,
|
||||||
|
updateCount: updatesToDownload.length,
|
||||||
|
manualRequired: false
|
||||||
|
});
|
||||||
|
|
||||||
|
if (updatesToDownload.length === 0) {
|
||||||
|
logger.log(`No module updates available.`);
|
||||||
|
} else {
|
||||||
|
updatesToDownload.forEach(function (e) {
|
||||||
|
return addModuleToDownloadQueue(e.name, e.version);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return function checkForModuleUpdates() {
|
||||||
|
return _ref.apply(this, arguments);
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
|
let processDownloadQueue = (() => {
|
||||||
|
var _ref2 = _asyncToGenerator(function* () {
|
||||||
|
if (download.active) return;
|
||||||
|
if (download.queue.length === 0) return;
|
||||||
|
|
||||||
|
download.active = true;
|
||||||
|
|
||||||
|
const queuedModule = download.queue[download.next];
|
||||||
|
download.next += 1;
|
||||||
|
|
||||||
|
events.append({
|
||||||
|
type: DOWNLOADING_MODULE,
|
||||||
|
name: queuedModule.name,
|
||||||
|
current: download.next,
|
||||||
|
total: download.queue.length,
|
||||||
|
foreground: !runningInBackground
|
||||||
|
});
|
||||||
|
|
||||||
|
let progress = 0;
|
||||||
|
let receivedBytes = 0;
|
||||||
|
|
||||||
|
const url = `${remoteBaseURL}/${encodeURIComponent(getRemoteModuleName(queuedModule.name))}/${encodeURIComponent(queuedModule.version)}`;
|
||||||
|
logger.log(`Fetching ${queuedModule.name}@${queuedModule.version} from ${url}`);
|
||||||
|
const headers = {};
|
||||||
|
if (queuedModule.authToken) {
|
||||||
|
headers['Authorization'] = queuedModule.authToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
const moduleZipPath = _path2.default.join(moduleDownloadPath, `${queuedModule.name}-${queuedModule.version}.zip`);
|
||||||
|
const stream = _fs2.default.createWriteStream(moduleZipPath);
|
||||||
|
stream.on('progress', function ({ receivedBytes: newReceivedBytes, totalBytes }) {
|
||||||
|
receivedBytes = newReceivedBytes;
|
||||||
|
const newProgress = Math.min(Math.floor(100 * (receivedBytes / totalBytes)), 100);
|
||||||
|
if (progress !== newProgress) {
|
||||||
|
progress = newProgress;
|
||||||
|
logger.log(`Streaming ${queuedModule.name}@${queuedModule.version} to ${moduleZipPath}: ${progress}%`);
|
||||||
|
events.append({
|
||||||
|
type: DOWNLOADING_MODULE_PROGRESS,
|
||||||
|
name: queuedModule.name,
|
||||||
|
progress: progress
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
logger.log(`Streaming ${queuedModule.name}@${queuedModule.version} to ${moduleZipPath}`);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = yield request.get({
|
||||||
|
url,
|
||||||
|
qs: remoteQuery,
|
||||||
|
headers,
|
||||||
|
timeout: REQUEST_TIMEOUT,
|
||||||
|
stream
|
||||||
|
});
|
||||||
|
|
||||||
|
finishModuleDownload(queuedModule.name, queuedModule.version, moduleZipPath, receivedBytes, response.statusCode === 200);
|
||||||
|
} catch (err) {
|
||||||
|
logger.log(`Failed fetching module ${queuedModule.name}@${queuedModule.version}: ${String(err)}`);
|
||||||
|
finishModuleDownload(queuedModule.name, queuedModule.version, null, false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return function processDownloadQueue() {
|
||||||
|
return _ref2.apply(this, arguments);
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
exports.initPathsOnly = initPathsOnly;
|
exports.initPathsOnly = initPathsOnly;
|
||||||
exports.init = init;
|
exports.init = init;
|
||||||
exports.checkForUpdates = checkForUpdates;
|
exports.checkForUpdates = checkForUpdates;
|
||||||
|
exports.setInBackground = setInBackground;
|
||||||
exports.quitAndInstallUpdates = quitAndInstallUpdates;
|
exports.quitAndInstallUpdates = quitAndInstallUpdates;
|
||||||
exports.isInstalled = isInstalled;
|
exports.isInstalled = isInstalled;
|
||||||
exports.getInstalled = getInstalled;
|
exports.getInstalled = getInstalled;
|
||||||
|
@ -38,27 +173,71 @@ var _mkdirp = require('mkdirp');
|
||||||
|
|
||||||
var _mkdirp2 = _interopRequireDefault(_mkdirp);
|
var _mkdirp2 = _interopRequireDefault(_mkdirp);
|
||||||
|
|
||||||
|
var _process = require('process');
|
||||||
|
|
||||||
var _yauzl = require('yauzl');
|
var _yauzl = require('yauzl');
|
||||||
|
|
||||||
var _yauzl2 = _interopRequireDefault(_yauzl);
|
var _yauzl2 = _interopRequireDefault(_yauzl);
|
||||||
|
|
||||||
var _paths = require('./paths');
|
|
||||||
|
|
||||||
var paths = _interopRequireWildcard(_paths);
|
|
||||||
|
|
||||||
var _Backoff = require('./Backoff');
|
var _Backoff = require('./Backoff');
|
||||||
|
|
||||||
var _Backoff2 = _interopRequireDefault(_Backoff);
|
var _Backoff2 = _interopRequireDefault(_Backoff);
|
||||||
|
|
||||||
|
var _paths = require('./paths');
|
||||||
|
|
||||||
|
var paths = _interopRequireWildcard(_paths);
|
||||||
|
|
||||||
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
|
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
|
||||||
|
|
||||||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||||
|
|
||||||
|
function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; } // Manages additional module installation and management.
|
||||||
|
// We add the module folder path to require() lookup paths here.
|
||||||
|
|
||||||
|
// undocumented node API
|
||||||
|
|
||||||
|
|
||||||
const originalFs = require('original-fs');
|
const originalFs = require('original-fs');
|
||||||
|
|
||||||
|
// events
|
||||||
|
const CHECKING_FOR_UPDATES = exports.CHECKING_FOR_UPDATES = 'checking-for-updates';
|
||||||
|
const INSTALLED_MODULE = exports.INSTALLED_MODULE = 'installed-module';
|
||||||
|
const UPDATE_CHECK_FINISHED = exports.UPDATE_CHECK_FINISHED = 'update-check-finished';
|
||||||
|
const DOWNLOADING_MODULE = exports.DOWNLOADING_MODULE = 'downloading-module';
|
||||||
|
const DOWNLOADING_MODULE_PROGRESS = exports.DOWNLOADING_MODULE_PROGRESS = 'downloading-module-progress';
|
||||||
|
const DOWNLOADING_MODULES_FINISHED = exports.DOWNLOADING_MODULES_FINISHED = 'downloading-modules-finished';
|
||||||
|
const UPDATE_MANUALLY = exports.UPDATE_MANUALLY = 'update-manually';
|
||||||
|
const DOWNLOADED_MODULE = exports.DOWNLOADED_MODULE = 'downloaded-module';
|
||||||
|
const INSTALLING_MODULES_FINISHED = exports.INSTALLING_MODULES_FINISHED = 'installing-modules-finished';
|
||||||
|
const INSTALLING_MODULE = exports.INSTALLING_MODULE = 'installing-module';
|
||||||
|
const INSTALLING_MODULE_PROGRESS = exports.INSTALLING_MODULE_PROGRESS = 'installing-module-progress';
|
||||||
|
const NO_PENDING_UPDATES = exports.NO_PENDING_UPDATES = 'no-pending-updates';
|
||||||
|
|
||||||
|
// settings
|
||||||
|
const ALWAYS_ALLOW_UPDATES = 'ALWAYS_ALLOW_UPDATES';
|
||||||
|
const SKIP_HOST_UPDATE = 'SKIP_HOST_UPDATE';
|
||||||
|
const SKIP_MODULE_UPDATE = 'SKIP_MODULE_UPDATE';
|
||||||
|
const ALWAYS_BOOTSTRAP_MODULES = 'ALWAYS_BOOTSTRAP_MODULES';
|
||||||
|
const USE_LOCAL_MODULE_VERSIONS = 'USE_LOCAL_MODULE_VERSIONS';
|
||||||
|
|
||||||
class Events extends _events.EventEmitter {
|
class Events extends _events.EventEmitter {
|
||||||
emit(...args) {
|
constructor() {
|
||||||
process.nextTick(() => super.emit.apply(this, args));
|
super();
|
||||||
|
this.history = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
append(evt) {
|
||||||
|
evt.now = String(_process.hrtime.bigint());
|
||||||
|
|
||||||
|
if (this._eventIsInteresting(evt)) {
|
||||||
|
this.history.push(evt);
|
||||||
|
}
|
||||||
|
|
||||||
|
process.nextTick(() => this.emit(evt.type, evt));
|
||||||
|
}
|
||||||
|
|
||||||
|
_eventIsInteresting(evt) {
|
||||||
|
return evt.type !== DOWNLOADING_MODULE_PROGRESS && evt.type !== INSTALLING_MODULE_PROGRESS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,31 +267,11 @@ class LogStream {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// events
|
|
||||||
const CHECKING_FOR_UPDATES = exports.CHECKING_FOR_UPDATES = 'checking-for-updates';
|
|
||||||
const INSTALLED_MODULE = exports.INSTALLED_MODULE = 'installed-module';
|
|
||||||
const UPDATE_CHECK_FINISHED = exports.UPDATE_CHECK_FINISHED = 'update-check-finished';
|
|
||||||
const DOWNLOADING_MODULE = exports.DOWNLOADING_MODULE = 'downloading-module';
|
|
||||||
const DOWNLOADING_MODULE_PROGRESS = exports.DOWNLOADING_MODULE_PROGRESS = 'downloading-module-progress';
|
|
||||||
const DOWNLOADING_MODULES_FINISHED = exports.DOWNLOADING_MODULES_FINISHED = 'downloading-modules-finished';
|
|
||||||
const UPDATE_MANUALLY = exports.UPDATE_MANUALLY = 'update-manually';
|
|
||||||
const DOWNLOADED_MODULE = exports.DOWNLOADED_MODULE = 'downloaded-module';
|
|
||||||
const INSTALLING_MODULES_FINISHED = exports.INSTALLING_MODULES_FINISHED = 'installing-modules-finished';
|
|
||||||
const INSTALLING_MODULE = exports.INSTALLING_MODULE = 'installing-module';
|
|
||||||
const INSTALLING_MODULE_PROGRESS = exports.INSTALLING_MODULE_PROGRESS = 'installing-module-progress';
|
|
||||||
const NO_PENDING_UPDATES = exports.NO_PENDING_UPDATES = 'no-pending-updates';
|
|
||||||
|
|
||||||
// settings
|
|
||||||
const ALWAYS_ALLOW_UPDATES = 'ALWAYS_ALLOW_UPDATES';
|
|
||||||
const SKIP_HOST_UPDATE = 'SKIP_HOST_UPDATE';
|
|
||||||
const SKIP_MODULE_UPDATE = 'SKIP_MODULE_UPDATE';
|
|
||||||
const ALWAYS_BOOTSTRAP_MODULES = 'ALWAYS_BOOTSTRAP_MODULES';
|
|
||||||
const USE_LOCAL_MODULE_VERSIONS = 'USE_LOCAL_MODULE_VERSIONS';
|
|
||||||
|
|
||||||
const request = require('../app_bootstrap/request');
|
const request = require('../app_bootstrap/request');
|
||||||
const REQUEST_TIMEOUT = 15000;
|
const REQUEST_TIMEOUT = 15000;
|
||||||
const backoff = new _Backoff2.default(1000, 20000);
|
const backoff = new _Backoff2.default(1000, 20000);
|
||||||
const events = exports.events = new Events();
|
const events = exports.events = new Events();
|
||||||
|
const supportsEventObjects = exports.supportsEventObjects = true;
|
||||||
|
|
||||||
let logger;
|
let logger;
|
||||||
let locallyInstalledModules;
|
let locallyInstalledModules;
|
||||||
|
@ -136,6 +295,7 @@ let newInstallInProgress;
|
||||||
let localModuleVersionsFilePath;
|
let localModuleVersionsFilePath;
|
||||||
let updatable;
|
let updatable;
|
||||||
let bootstrapManifestFilePath;
|
let bootstrapManifestFilePath;
|
||||||
|
let runningInBackground = false;
|
||||||
|
|
||||||
function initPathsOnly(_buildInfo) {
|
function initPathsOnly(_buildInfo) {
|
||||||
if (locallyInstalledModules || moduleInstallPath) {
|
if (locallyInstalledModules || moduleInstallPath) {
|
||||||
|
@ -229,14 +389,16 @@ function init(_endpoint, _settings, _buildInfo) {
|
||||||
|
|
||||||
hostUpdater = require('../app_bootstrap/hostUpdater');
|
hostUpdater = require('../app_bootstrap/hostUpdater');
|
||||||
// TODO: hostUpdater constants
|
// TODO: hostUpdater constants
|
||||||
hostUpdater.on('checking-for-update', () => events.emit(CHECKING_FOR_UPDATES));
|
hostUpdater.on('checking-for-update', () => events.append({
|
||||||
|
type: CHECKING_FOR_UPDATES
|
||||||
|
}));
|
||||||
hostUpdater.on('update-available', () => hostOnUpdateAvailable());
|
hostUpdater.on('update-available', () => hostOnUpdateAvailable());
|
||||||
hostUpdater.on('update-progress', progress => hostOnUpdateProgress(progress));
|
hostUpdater.on('update-progress', progress => hostOnUpdateProgress(progress));
|
||||||
hostUpdater.on('update-not-available', () => hostOnUpdateNotAvailable());
|
hostUpdater.on('update-not-available', () => hostOnUpdateNotAvailable());
|
||||||
hostUpdater.on('update-manually', newVersion => hostOnUpdateManually(newVersion));
|
hostUpdater.on('update-manually', newVersion => hostOnUpdateManually(newVersion));
|
||||||
hostUpdater.on('update-downloaded', () => hostOnUpdateDownloaded());
|
hostUpdater.on('update-downloaded', () => hostOnUpdateDownloaded());
|
||||||
hostUpdater.on('error', err => hostOnError(err));
|
hostUpdater.on('error', err => hostOnError(err));
|
||||||
let setFeedURL = hostUpdater.setFeedURL.bind(hostUpdater);
|
const setFeedURL = hostUpdater.setFeedURL.bind(hostUpdater);
|
||||||
|
|
||||||
remoteBaseURL = `${endpoint}/modules/${buildInfo.releaseChannel}`;
|
remoteBaseURL = `${endpoint}/modules/${buildInfo.releaseChannel}`;
|
||||||
// eslint-disable-next-line camelcase
|
// eslint-disable-next-line camelcase
|
||||||
|
@ -286,13 +448,28 @@ function cleanDownloadedModules(installedModules) {
|
||||||
function hostOnUpdateAvailable() {
|
function hostOnUpdateAvailable() {
|
||||||
logger.log(`Host update is available.`);
|
logger.log(`Host update is available.`);
|
||||||
hostUpdateAvailable = true;
|
hostUpdateAvailable = true;
|
||||||
events.emit(UPDATE_CHECK_FINISHED, true, 1, false);
|
events.append({
|
||||||
events.emit(DOWNLOADING_MODULE, 'host', 1, 1);
|
type: UPDATE_CHECK_FINISHED,
|
||||||
|
succeeded: true,
|
||||||
|
updateCount: 1,
|
||||||
|
manualRequired: false
|
||||||
|
});
|
||||||
|
events.append({
|
||||||
|
type: DOWNLOADING_MODULE,
|
||||||
|
name: 'host',
|
||||||
|
current: 1,
|
||||||
|
total: 1,
|
||||||
|
foreground: !runningInBackground
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function hostOnUpdateProgress(progress) {
|
function hostOnUpdateProgress(progress) {
|
||||||
logger.log(`Host update progress: ${progress}%`);
|
logger.log(`Host update progress: ${progress}%`);
|
||||||
events.emit(DOWNLOADING_MODULE_PROGRESS, 'host', progress);
|
events.append({
|
||||||
|
type: DOWNLOADING_MODULE_PROGRESS,
|
||||||
|
name: 'host',
|
||||||
|
progress: progress
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function hostOnUpdateNotAvailable() {
|
function hostOnUpdateNotAvailable() {
|
||||||
|
@ -300,7 +477,12 @@ function hostOnUpdateNotAvailable() {
|
||||||
if (!skipModuleUpdate) {
|
if (!skipModuleUpdate) {
|
||||||
checkForModuleUpdates();
|
checkForModuleUpdates();
|
||||||
} else {
|
} else {
|
||||||
events.emit(UPDATE_CHECK_FINISHED, true, 0, false);
|
events.append({
|
||||||
|
type: UPDATE_CHECK_FINISHED,
|
||||||
|
succeeded: true,
|
||||||
|
updateCount: 0,
|
||||||
|
manualRequired: false
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -308,15 +490,33 @@ function hostOnUpdateManually(newVersion) {
|
||||||
logger.log(`Host update is available. Manual update required!`);
|
logger.log(`Host update is available. Manual update required!`);
|
||||||
hostUpdateAvailable = true;
|
hostUpdateAvailable = true;
|
||||||
checkingForUpdates = false;
|
checkingForUpdates = false;
|
||||||
events.emit(UPDATE_MANUALLY, newVersion);
|
events.append({
|
||||||
events.emit(UPDATE_CHECK_FINISHED, true, 1, true);
|
type: UPDATE_MANUALLY,
|
||||||
|
newVersion: newVersion
|
||||||
|
});
|
||||||
|
events.append({
|
||||||
|
type: UPDATE_CHECK_FINISHED,
|
||||||
|
succeeded: true,
|
||||||
|
updateCount: 1,
|
||||||
|
manualRequired: true
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function hostOnUpdateDownloaded() {
|
function hostOnUpdateDownloaded() {
|
||||||
logger.log(`Host update downloaded.`);
|
logger.log(`Host update downloaded.`);
|
||||||
checkingForUpdates = false;
|
checkingForUpdates = false;
|
||||||
events.emit(DOWNLOADED_MODULE, 'host', 1, 1, true);
|
events.append({
|
||||||
events.emit(DOWNLOADING_MODULES_FINISHED, 1, 0);
|
type: DOWNLOADED_MODULE,
|
||||||
|
name: 'host',
|
||||||
|
current: 1,
|
||||||
|
total: 1,
|
||||||
|
succeeded: true
|
||||||
|
});
|
||||||
|
events.append({
|
||||||
|
type: DOWNLOADING_MODULES_FINISHED,
|
||||||
|
succeeded: 1,
|
||||||
|
failed: 0
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function hostOnError(err) {
|
function hostOnError(err) {
|
||||||
|
@ -331,10 +531,25 @@ function hostOnError(err) {
|
||||||
|
|
||||||
checkingForUpdates = false;
|
checkingForUpdates = false;
|
||||||
if (!hostUpdateAvailable) {
|
if (!hostUpdateAvailable) {
|
||||||
events.emit(UPDATE_CHECK_FINISHED, false, 0, false);
|
events.append({
|
||||||
|
type: UPDATE_CHECK_FINISHED,
|
||||||
|
succeeded: false,
|
||||||
|
updateCount: 0,
|
||||||
|
manualRequired: false
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
events.emit(DOWNLOADED_MODULE, 'host', 1, 1, false);
|
events.append({
|
||||||
events.emit(DOWNLOADING_MODULES_FINISHED, 0, 1);
|
type: DOWNLOADED_MODULE,
|
||||||
|
name: 'host',
|
||||||
|
current: 1,
|
||||||
|
total: 1,
|
||||||
|
succeeded: false
|
||||||
|
});
|
||||||
|
events.append({
|
||||||
|
type: DOWNLOADING_MODULES_FINISHED,
|
||||||
|
succeeded: 0,
|
||||||
|
failed: 1
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -344,7 +559,7 @@ function checkForUpdates() {
|
||||||
checkingForUpdates = true;
|
checkingForUpdates = true;
|
||||||
hostUpdateAvailable = false;
|
hostUpdateAvailable = false;
|
||||||
if (skipHostUpdate) {
|
if (skipHostUpdate) {
|
||||||
events.emit(CHECKING_FOR_UPDATES);
|
events.append({ type: CHECKING_FOR_UPDATES });
|
||||||
hostOnUpdateNotAvailable();
|
hostOnUpdateNotAvailable();
|
||||||
} else {
|
} else {
|
||||||
logger.log('Checking for host updates.');
|
logger.log('Checking for host updates.');
|
||||||
|
@ -352,6 +567,14 @@ function checkForUpdates() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Indicates that the initial update process is complete and that future updates
|
||||||
|
// are background updates. This merely affects the content of the events sent to
|
||||||
|
// the app so that analytics can correctly attribute module download/installs
|
||||||
|
// depending on whether they were ui-blocking or not.
|
||||||
|
function setInBackground() {
|
||||||
|
runningInBackground = true;
|
||||||
|
}
|
||||||
|
|
||||||
function getRemoteModuleName(name) {
|
function getRemoteModuleName(name) {
|
||||||
if (process.platform === 'win32' && process.arch === 'x64') {
|
if (process.platform === 'win32' && process.arch === 'x64') {
|
||||||
return `${name}.x64`;
|
return `${name}.x64`;
|
||||||
|
@ -360,142 +583,17 @@ function getRemoteModuleName(name) {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkForModuleUpdates() {
|
|
||||||
const query = _extends({}, remoteQuery, { _: Math.floor(Date.now() / 1000 / 60 / 5) });
|
|
||||||
const url = `${remoteBaseURL}/versions.json`;
|
|
||||||
logger.log(`Checking for module updates at ${url}`);
|
|
||||||
|
|
||||||
request.get({
|
|
||||||
url,
|
|
||||||
agent: false,
|
|
||||||
encoding: null,
|
|
||||||
qs: query,
|
|
||||||
timeout: REQUEST_TIMEOUT,
|
|
||||||
strictSSL: false
|
|
||||||
}, (err, response, body) => {
|
|
||||||
checkingForUpdates = false;
|
|
||||||
|
|
||||||
if (!err && response.statusCode !== 200) {
|
|
||||||
err = new Error(`Non-200 response code: ${response.statusCode}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (err) {
|
|
||||||
logger.log(`Failed fetching module versions: ${String(err)}`);
|
|
||||||
events.emit(UPDATE_CHECK_FINISHED, false, 0, false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
remoteModuleVersions = JSON.parse(body);
|
|
||||||
if (settings.get(USE_LOCAL_MODULE_VERSIONS)) {
|
|
||||||
try {
|
|
||||||
remoteModuleVersions = JSON.parse(_fs2.default.readFileSync(localModuleVersionsFilePath));
|
|
||||||
console.log('Using local module versions: ', remoteModuleVersions);
|
|
||||||
} catch (err) {
|
|
||||||
console.warn('Failed to parse local module versions: ', err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const updatesToDownload = [];
|
|
||||||
for (const moduleName of Object.keys(installedModules)) {
|
|
||||||
const installedModule = installedModules[moduleName];
|
|
||||||
const installed = installedModule.installedVersion;
|
|
||||||
if (installed === null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const update = installedModule.updateVersion || 0;
|
|
||||||
const remote = remoteModuleVersions[getRemoteModuleName(moduleName)] || 0;
|
|
||||||
// TODO: strict equality?
|
|
||||||
if (installed != remote && update != remote) {
|
|
||||||
logger.log(`Module update available: ${moduleName}@${remote} [installed: ${installed}]`);
|
|
||||||
updatesToDownload.push({ name: moduleName, version: remote });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
events.emit(UPDATE_CHECK_FINISHED, true, updatesToDownload.length, false);
|
|
||||||
if (updatesToDownload.length === 0) {
|
|
||||||
logger.log(`No module updates available.`);
|
|
||||||
} else {
|
|
||||||
updatesToDownload.forEach(e => addModuleToDownloadQueue(e.name, e.version));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function addModuleToDownloadQueue(name, version, authToken) {
|
function addModuleToDownloadQueue(name, version, authToken) {
|
||||||
download.queue.push({ name, version, authToken });
|
download.queue.push({ name, version, authToken });
|
||||||
process.nextTick(() => processDownloadQueue());
|
process.nextTick(() => processDownloadQueue());
|
||||||
}
|
}
|
||||||
|
|
||||||
function processDownloadQueue() {
|
|
||||||
if (download.active) return;
|
|
||||||
if (download.queue.length === 0) return;
|
|
||||||
|
|
||||||
download.active = true;
|
|
||||||
|
|
||||||
const queuedModule = download.queue[download.next];
|
|
||||||
download.next += 1;
|
|
||||||
|
|
||||||
events.emit(DOWNLOADING_MODULE, queuedModule.name, download.next, download.queue.length);
|
|
||||||
|
|
||||||
let totalBytes = 1;
|
|
||||||
let receivedBytes = 0;
|
|
||||||
let progress = 0;
|
|
||||||
let hasErrored = false;
|
|
||||||
|
|
||||||
const url = `${remoteBaseURL}/${getRemoteModuleName(queuedModule.name)}/${queuedModule.version}`;
|
|
||||||
logger.log(`Fetching ${queuedModule.name}@${queuedModule.version} from ${url}`);
|
|
||||||
const headers = {};
|
|
||||||
if (queuedModule.authToken) {
|
|
||||||
headers['Authorization'] = queuedModule.authToken;
|
|
||||||
}
|
|
||||||
request.get({
|
|
||||||
url,
|
|
||||||
agent: false,
|
|
||||||
encoding: null,
|
|
||||||
followAllRedirects: true,
|
|
||||||
qs: remoteQuery,
|
|
||||||
timeout: REQUEST_TIMEOUT,
|
|
||||||
strictSSL: false,
|
|
||||||
headers
|
|
||||||
}).on('error', err => {
|
|
||||||
if (hasErrored) return;
|
|
||||||
hasErrored = true;
|
|
||||||
logger.log(`Failed fetching ${queuedModule.name}@${queuedModule.version}: ${String(err)}`);
|
|
||||||
finishModuleDownload(queuedModule.name, queuedModule.version, null, false);
|
|
||||||
}).on('response', response => {
|
|
||||||
totalBytes = response.headers['content-length'] || 1;
|
|
||||||
|
|
||||||
const moduleZipPath = _path2.default.join(moduleDownloadPath, `${queuedModule.name}-${queuedModule.version}.zip`);
|
|
||||||
logger.log(`Streaming ${queuedModule.name}@${queuedModule.version} [${totalBytes} bytes] to ${moduleZipPath}`);
|
|
||||||
|
|
||||||
const stream = _fs2.default.createWriteStream(moduleZipPath);
|
|
||||||
stream.on('finish', () => finishModuleDownload(queuedModule.name, queuedModule.version, moduleZipPath, response.statusCode === 200));
|
|
||||||
|
|
||||||
response.on('data', chunk => {
|
|
||||||
receivedBytes += chunk.length;
|
|
||||||
stream.write(chunk);
|
|
||||||
|
|
||||||
const fraction = receivedBytes / totalBytes;
|
|
||||||
const newProgress = Math.min(Math.floor(100 * fraction), 100);
|
|
||||||
if (progress != newProgress) {
|
|
||||||
progress = newProgress;
|
|
||||||
events.emit(DOWNLOADING_MODULE_PROGRESS, queuedModule.name, progress);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// TODO: on response error
|
|
||||||
// TODO: on stream error
|
|
||||||
|
|
||||||
response.on('end', () => stream.end());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function commitInstalledModules() {
|
function commitInstalledModules() {
|
||||||
const data = JSON.stringify(installedModules, null, 2);
|
const data = JSON.stringify(installedModules, null, 2);
|
||||||
_fs2.default.writeFileSync(installedModulesFilePath, data);
|
_fs2.default.writeFileSync(installedModulesFilePath, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
function finishModuleDownload(name, version, zipfile, succeeded) {
|
function finishModuleDownload(name, version, zipfile, receivedBytes, succeeded) {
|
||||||
if (!installedModules[name]) {
|
if (!installedModules[name]) {
|
||||||
installedModules[name] = {};
|
installedModules[name] = {};
|
||||||
}
|
}
|
||||||
|
@ -508,12 +606,23 @@ function finishModuleDownload(name, version, zipfile, succeeded) {
|
||||||
download.failures += 1;
|
download.failures += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
events.emit(DOWNLOADED_MODULE, name, download.next, download.queue.length, succeeded);
|
events.append({
|
||||||
|
type: DOWNLOADED_MODULE,
|
||||||
|
name: name,
|
||||||
|
current: download.next,
|
||||||
|
total: download.queue.length,
|
||||||
|
succeeded: succeeded,
|
||||||
|
receivedBytes: receivedBytes
|
||||||
|
});
|
||||||
|
|
||||||
if (download.next >= download.queue.length) {
|
if (download.next >= download.queue.length) {
|
||||||
const successes = download.queue.length - download.failures;
|
const successes = download.queue.length - download.failures;
|
||||||
logger.log(`Finished module downloads. [success: ${successes}] [failure: ${download.failures}]`);
|
logger.log(`Finished module downloads. [success: ${successes}] [failure: ${download.failures}]`);
|
||||||
events.emit(DOWNLOADING_MODULES_FINISHED, successes, download.failures);
|
events.append({
|
||||||
|
type: DOWNLOADING_MODULES_FINISHED,
|
||||||
|
succeeded: successes,
|
||||||
|
failed: download.failures
|
||||||
|
});
|
||||||
download.queue = [];
|
download.queue = [];
|
||||||
download.next = 0;
|
download.next = 0;
|
||||||
download.failures = 0;
|
download.failures = 0;
|
||||||
|
@ -550,9 +659,19 @@ function processUnzipQueue() {
|
||||||
unzip.active = true;
|
unzip.active = true;
|
||||||
|
|
||||||
const queuedModule = unzip.queue[unzip.next];
|
const queuedModule = unzip.queue[unzip.next];
|
||||||
|
const installedModule = installedModules[queuedModule.name];
|
||||||
|
const installedVersion = installedModule != null ? installedModule.installedVersion : null;
|
||||||
unzip.next += 1;
|
unzip.next += 1;
|
||||||
|
|
||||||
events.emit(INSTALLING_MODULE, queuedModule.name, unzip.next, unzip.queue.length);
|
events.append({
|
||||||
|
type: INSTALLING_MODULE,
|
||||||
|
name: queuedModule.name,
|
||||||
|
current: unzip.next,
|
||||||
|
total: unzip.queue.length,
|
||||||
|
foreground: !runningInBackground,
|
||||||
|
oldVersion: installedVersion,
|
||||||
|
newVersion: queuedModule.version
|
||||||
|
});
|
||||||
|
|
||||||
let hasErrored = false;
|
let hasErrored = false;
|
||||||
const onError = (error, zipfile) => {
|
const onError = (error, zipfile) => {
|
||||||
|
@ -583,7 +702,11 @@ function processUnzipQueue() {
|
||||||
zipfile.on('entry', entry => {
|
zipfile.on('entry', entry => {
|
||||||
processedEntries += 1;
|
processedEntries += 1;
|
||||||
const percent = Math.min(Math.floor(processedEntries / totalEntries * 100), 100);
|
const percent = Math.min(Math.floor(processedEntries / totalEntries * 100), 100);
|
||||||
events.emit(INSTALLING_MODULE_PROGRESS, queuedModule.name, percent);
|
events.append({
|
||||||
|
type: INSTALLING_MODULE_PROGRESS,
|
||||||
|
name: queuedModule.name,
|
||||||
|
progress: percent
|
||||||
|
});
|
||||||
|
|
||||||
// skip directories
|
// skip directories
|
||||||
if (/\/$/.test(entry.fileName)) {
|
if (/\/$/.test(entry.fileName)) {
|
||||||
|
@ -668,7 +791,13 @@ function finishModuleUnzip(unzippedModule, succeeded) {
|
||||||
unzip.failures += 1;
|
unzip.failures += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
events.emit(INSTALLED_MODULE, unzippedModule.name, unzip.next, unzip.queue.length, succeeded);
|
events.append({
|
||||||
|
type: INSTALLED_MODULE,
|
||||||
|
name: unzippedModule.name,
|
||||||
|
current: unzip.next,
|
||||||
|
total: unzip.queue.length,
|
||||||
|
succeeded: succeeded
|
||||||
|
});
|
||||||
|
|
||||||
if (unzip.next >= unzip.queue.length) {
|
if (unzip.next >= unzip.queue.length) {
|
||||||
const successes = unzip.queue.length - unzip.failures;
|
const successes = unzip.queue.length - unzip.failures;
|
||||||
|
@ -678,7 +807,11 @@ function finishModuleUnzip(unzippedModule, succeeded) {
|
||||||
unzip.next = 0;
|
unzip.next = 0;
|
||||||
unzip.failures = 0;
|
unzip.failures = 0;
|
||||||
unzip.active = false;
|
unzip.active = false;
|
||||||
events.emit(INSTALLING_MODULES_FINISHED, successes, unzip.failures);
|
events.append({
|
||||||
|
type: INSTALLING_MODULES_FINISHED,
|
||||||
|
succeeded: successes,
|
||||||
|
failed: unzip.failures
|
||||||
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -722,7 +855,13 @@ function install(name, defer, options) {
|
||||||
let { version, authToken } = options || {};
|
let { version, authToken } = options || {};
|
||||||
if (isInstalled(name, version)) {
|
if (isInstalled(name, version)) {
|
||||||
if (!defer) {
|
if (!defer) {
|
||||||
events.emit(INSTALLED_MODULE, name, 1, 1, true);
|
events.append({
|
||||||
|
type: INSTALLED_MODULE,
|
||||||
|
name: name,
|
||||||
|
current: 1,
|
||||||
|
total: 1,
|
||||||
|
succeeded: true
|
||||||
|
});
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -780,6 +919,8 @@ function installPendingUpdates() {
|
||||||
updatesToInstall.forEach(e => addModuleToUnzipQueue(e.moduleName, e.update, e.zipfile));
|
updatesToInstall.forEach(e => addModuleToUnzipQueue(e.moduleName, e.update, e.zipfile));
|
||||||
} else {
|
} else {
|
||||||
logger.log('No updates to install');
|
logger.log('No updates to install');
|
||||||
events.emit(NO_PENDING_UPDATES);
|
events.append({
|
||||||
|
type: NO_PENDING_UPDATES
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in a new issue