Changes of Linux canary v0.0.102
This commit is contained in:
parent
747890c6ad
commit
3185a0ea9f
|
@ -20,6 +20,8 @@ function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj;
|
||||||
|
|
||||||
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"); }); }; }
|
||||||
|
|
||||||
function versionParse(verString) {
|
function versionParse(verString) {
|
||||||
return verString.split('.').map(i => parseInt(i));
|
return verString.split('.').map(i => parseInt(i));
|
||||||
}
|
}
|
||||||
|
@ -135,42 +137,42 @@ class AutoUpdaterLinux extends _events.EventEmitter {
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
||||||
|
yield (0, _util.promisify)(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 (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,90 @@ var _request = require('request');
|
||||||
|
|
||||||
var _request2 = _interopRequireDefault(_request);
|
var _request2 = _interopRequireDefault(_request);
|
||||||
|
|
||||||
var _events = require('events');
|
var _util = require('util');
|
||||||
|
|
||||||
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;
|
||||||
|
|
|
@ -5,11 +5,145 @@ Object.defineProperty(exports, "__esModule", {
|
||||||
});
|
});
|
||||||
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;
|
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;
|
||||||
|
@ -57,6 +191,12 @@ function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj;
|
||||||
|
|
||||||
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
|
// events
|
||||||
|
@ -443,156 +583,11 @@ 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.append({
|
|
||||||
type: UPDATE_CHECK_FINISHED,
|
|
||||||
succeeded: false,
|
|
||||||
updateCount: 0,
|
|
||||||
manualRequired: 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.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(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.append({
|
|
||||||
type: DOWNLOADING_MODULE,
|
|
||||||
name: queuedModule.name,
|
|
||||||
current: download.next,
|
|
||||||
total: download.queue.length,
|
|
||||||
foreground: !runningInBackground
|
|
||||||
});
|
|
||||||
|
|
||||||
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, receivedBytes, 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.append({
|
|
||||||
type: DOWNLOADING_MODULE_PROGRESS,
|
|
||||||
name: queuedModule.name,
|
|
||||||
progress: 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);
|
||||||
|
|
Loading…
Reference in New Issue