From d20ea5148d1b8e67ddeeecd47b8516dc79a3ebb9 Mon Sep 17 00:00:00 2001 From: team-pct Date: Tue, 8 Nov 2016 14:45:46 +0100 Subject: [PATCH 1/4] P2p updater (#1) * P2P updater * Update Updater.js * Add UpdateSeed on Settings * Add Webtorrent on package.json --- package.json | 1 + src/app/settings.js | 1 + src/app/templates/settings-container.tpl | 8 +- src/app/updater.js | 370 +++++++++++++++-------- 4 files changed, 259 insertions(+), 121 deletions(-) diff --git a/package.json b/package.json index 9efee0284f..f4e803a13b 100644 --- a/package.json +++ b/package.json @@ -60,6 +60,7 @@ "nodecast-js": "^1.0.1", "opensubtitles-api": "^3.1.0", "peerflix": "^0.35.0", + "webtorrent": "0.97.2", "q": "2.0.3", "read-torrent": "1.3.0", "readdirp": "*", diff --git a/src/app/settings.js b/src/app/settings.js index 1819fbbe46..5efa1476f1 100644 --- a/src/app/settings.js +++ b/src/app/settings.js @@ -149,6 +149,7 @@ Settings.tmpLocation = path.join(os.tmpDir(), Settings.projectName); Settings.databaseLocation = path.join(data_path, 'data'); Settings.deleteTmpOnClose = true; Settings.automaticUpdating = true; +Settings.UpdateSeed = true; Settings.events = true; Settings.minimizeToTray = false; Settings.bigPicture = false; diff --git a/src/app/templates/settings-container.tpl b/src/app/templates/settings-container.tpl index 140be63bff..5402a28c3f 100644 --- a/src/app/templates/settings-container.tpl +++ b/src/app/templates/settings-container.tpl @@ -556,8 +556,12 @@ - > - + > + + + + > + > diff --git a/src/app/updater.js b/src/app/updater.js index 105b940b0d..2544a118df 100644 --- a/src/app/updater.js +++ b/src/app/updater.js @@ -1,7 +1,12 @@ (function (App) { 'use strict'; - var CHANNELS = ['stable', 'beta', 'nightly'], + var client = new WebTorrent({ + dht: true, + maxConns: '5', + } + ), + CHANNELS = ['stable', 'beta', 'nightly'], FILENAME = 'package.nw.new', VERIFY_PUBKEY = Settings.updateKey; @@ -19,7 +24,7 @@ var self = this; this.options = _.defaults(options || {}, { - endpoint: AdvSettings.get('updateEndpoint').url + 'update3.json' + '?version=' + App.settings.version + '&nwversion=' + process.versions['node-webkit'], + endpoint: AdvSettings.get('updateEndpoint').url + 'updatemagnet.json' + '?version=' + App.settings.version + '&nwversion=' + process.versions['node-webkit'], channel: 'beta' }); @@ -77,21 +82,46 @@ self.updateData = updateData; return true; } + if (App.settings.UpdateSeed) { + client.add(updateData.UpdateUrl, { + path: os.tmpdir() + }, function (torrent) { + torrent.on('error', function (err) { + win.debug('ERROR' + err.message); + }); + torrent.on('done', function () { + win.debug('Seeding the Current Update!'); + }); + }); + } win.debug('Not updating because we are running the latest version'); return false; }); }; - Updater.prototype.download = function (source, output) { + Updater.prototype.download = function (source, outputDir) { var defer = Q.defer(); - var downloadStream = request(source); - win.debug('Downloading update... Please allow a few minutes'); - downloadStream.pipe(fs.createWriteStream(output)); - downloadStream.on('complete', function () { - win.debug('Update downloaded!'); - defer.resolve(output); + + client.on('error', function (err) { + win.debug('ERROR: ' + err.message); + defer.reject(err); }); + + client.add(source, { + path: outputDir + }, function (torrent) { + win.debug('Downloading update... Please allow a few minutes'); + torrent.on('error', function (err) { + win.debug('ERROR' + err.message); + defer.reject(err); + }); + torrent.on('done', function () { + win.debug('Update downloaded!'); + defer.resolve(path.join(outputDir, torrent.name)); + }); + }); + return defer.promise; }; @@ -121,142 +151,216 @@ return defer.promise; }; - function extractSimple(pack, downloadPath) { - // Extended: false - var installDir = path.dirname(downloadPath); + function installWindows(downloadPath, updateData) { var defer = Q.defer(); - pack.extractAllToAsync(installDir, true, function (err) { - if (err) { - defer.reject(err); - } else { - fs.unlink(downloadPath, function (err) { - if (err) { - defer.reject(err); - } else { - win.debug('Extraction success!'); - defer.resolve(); - } - }); - } - }); + var pack = new AdmZip(downloadPath); - return defer.promise; - } + if (updateData.extended) { - function installWindows(downloadPath, updateData) { - var pack = new AdmZip(downloadPath); + // Extended: true + var extractDir = os.tmpdir(); + win.debug('Extracting update.exe'); + pack.extractAllToAsync(extractDir, true, function (err) { + if (err) { + defer.reject(err); + } else { + var startWinUpdate = function () { + fs.unlinkSync(downloadPath); + var updateEXE = 'update.exe'; + var cmd = path.join(extractDir, updateEXE); + + var updateprocess = child.spawn(cmd, [], { + detached: true, + stdio: ['ignore', 'ignore', 'ignore'] + }); + win.close(true); + }; + + App.vent.trigger('notification:show', new App.Model.Notification({ + title: 'Update ' + this.updateData.version + ' Installed', + body: this.updateData.description, + showRestart: false, + type: 'info', + buttons: [{ + title: 'Update Now', + action: startWinUpdate + }] + })); + win.on('close', function () { + startWinUpdate(); + }); - if (!updateData.extended) { - return extractSimple(pack, downloadPath); - } + win.debug('Extraction success!'); + win.debug('Update ready to be installed!'); + } + }); - var defer = Q.defer(); + } else { + // Extended: false || undefined + var installDir = path.dirname(downloadPath); - // Extended: true - var extractDir = os.tmpdir(); - win.debug('Extracting update.exe'); - pack.extractAllToAsync(extractDir, true, function (err) { - if (err) { - defer.reject(err); - } else { - var startWinUpdate = function () { - fs.unlinkSync(downloadPath); - var updateEXE = 'update.exe'; - var cmd = path.join(extractDir, updateEXE); - - var updateprocess = child.spawn(cmd, [], { - detached: true, - stdio: ['ignore', 'ignore', 'ignore'] + win.debug('Extracting update files...'); + pack.extractAllToAsync(installDir, true, function (err) { + if (err) { + defer.reject(err); + } else { + fs.unlink(downloadPath, function (err) { + if (err) { + defer.reject(err); + } else { + win.debug('Extraction success!'); + defer.resolve(); + } }); - win.close(true); - }; - - App.vent.trigger('notification:show', new App.Model.Notification({ - title: 'Update ' + (updateData.version || 'Hotfix') + ' Installed', - body: (updateData.description || 'Auto update'), - showRestart: false, - type: 'info', - buttons: [{ - title: 'Update Now', - action: startWinUpdate - }] - })); - win.on('close', function () { - startWinUpdate(); - }); + } + }); - win.debug('Extraction success!'); - win.debug('Update ready to be installed!'); - } - }); + } return defer.promise; } - function installUnix(downloadPath, outputDir, updateData) { - win.debug('Extracting update...'); + function installLinux(downloadPath, updateData) { + var defer = Q.defer(); - var packageFile = path.join(outputDir, 'package.nw'), + win.debug('Extracting update...'); + var outputDir = path.dirname(downloadPath), + packageFile = path.join(outputDir, 'package.nw'), pack = new AdmZip(downloadPath); - if (!updateData.extended) { - return extractSimple(pack, downloadPath); - } + if (updateData.extended) { - var defer = Q.defer(); + // Extended: true + var updateTAR = path.join(os.tmpdir(), 'update.tar'); - // Extended: true - var extractDir = os.tmpdir(); - var updateTAR = path.join(extractDir, 'update.tar'); + pack.extractAllToAsync(os.tmpdir(), true, function (err) { //extract tar from zip + if (err) { + defer.reject(err); + } else { + rimraf(outputDir, function (err) { //delete old app + if (err) { + defer.reject(err); + } else { + var extractor = tar.Extract({ + path: outputDir + }) //extract files from tar + .on('error', function (err) { + defer.reject(err); + }) + .on('end', function () { + App.vent.trigger('notification:show', new App.Model.Notification({ + title: 'Update ' + this.updateData.version + ' Installed', + body: this.updateData.description, + showRestart: true, + type: 'info' + })); + + win.debug('Extraction success!'); + }); + fs.createReadStream(updateTAR) + .on('error', function (err) { + defer.reject(err); + }) + .pipe(extractor); + } + }); + } + }); - pack.extractAllToAsync(extractDir, true, function (err) { //extract tar from zip - if (err) { - defer.reject(err); - } else { - var delDir = process.cwd().match('Contents') ? path.join(outputDir, 'Contents') : outputDir; - rimraf(delDir, function (err) { //delete old app - if (err) { - defer.reject(err); - } else { - var extractor = tar.Extract({ - path: outputDir - }) //extract files from tar - .on('error', function (err) { - defer.reject(err); - }) - .on('end', function () { - App.vent.trigger('notification:show', new App.Model.Notification({ - title: 'Update ' + (updateData.version || 'Hotfix') + ' Installed', - body: (updateData.description || 'Auto update'), - showRestart: true, - type: 'info' - })); - - win.debug('Extraction success!'); - }); - fs.createReadStream(updateTAR) - .on('error', function (err) { - defer.reject(err); - }) - .pipe(extractor); - } - }); - } - }); + } else { - return defer.promise; - } + // Extended: false + var installDir = path.dirname(downloadPath); - function installLinux(downloadPath, updateData) { - return installUnix(downloadPath, path.dirname(downloadPath), updateData); + pack.extractAllToAsync(installDir, true, function (err) { + if (err) { + defer.reject(err); + } else { + fs.unlink(downloadPath, function (err) { + if (err) { + defer.reject(err); + } else { + win.debug('Extraction success!'); + defer.resolve(); + } + }); + } + }); + + } + + return defer.promise; } function installOSX(downloadPath, updateData) { - var outputDir = updateData.extended ? process.cwd().split('Contents')[0] : path.dirname(downloadPath); + var defer = Q.defer(); + var pack = new AdmZip(downloadPath); - return installUnix(downloadPath, outputDir, updateData); + win.debug('Extracting update...'); + if (updateData.extended) { + + // Extended: true + var installDir = process.cwd().split('Contents')[0]; + var updateTAR = path.join(os.tmpdir(), 'update.tar'); + + pack.extractAllToAsync(os.tmpdir(), true, function (err) { //extract tar from zip + if (err) { + defer.reject(err); + } else { + rimraf(path.join(installDir, 'Contents'), function (err) { //delete old app + if (err) { + defer.reject(err); + } else { + var extractor = tar.Extract({ + path: installDir + }) //extract files from tar + .on('error', function (err) { + defer.reject(err); + }) + .on('end', function () { + App.vent.trigger('notification:show', new App.Model.Notification({ + title: 'Update ' + this.updateData.version + ' Installed', + body: this.updateData.description, + showRestart: true, + type: 'info' + })); + + win.debug('Extraction success!'); + }); + fs.createReadStream(updateTAR) + .on('error', function (err) { + defer.reject(err); + }) + .pipe(extractor); + } + }); + } + }); + + } else { + + // Extended: false + var outputDir = path.dirname(downloadPath); + + pack.extractAllToAsync(outputDir, true, function (err) { + if (err) { + defer.reject(err); + } else { + fs.unlink(downloadPath, function (err) { + if (err) { + defer.reject(err); + } else { + win.debug('Extraction success!'); + defer.resolve(); + } + }); + } + }); + } + + return defer.promise; } Updater.prototype.install = function (downloadPath) { @@ -298,6 +402,34 @@ })); }; + + Updater.prototype.update = function () { + var outputFile = path.join(path.dirname(this.outputDir), FILENAME); + + if (this.updateData) { + // If we have already checked for updates... + return this.download(this.updateData.updateUrl, outputFile) + .then(forcedBind(this.verify, this)) + .then(forcedBind(this.install, this)) + .then(forcedBind(this.displayNotification, this)); + } else { + // Otherwise, check for updates then install if needed! + var self = this; + return this.check().then(function (updateAvailable) { + if (updateAvailable) { + return self.download(self.updateData.updateUrl, outputFile) + .then(forcedBind(self.verify, self)) + .then(forcedBind(self.install, self)) + .then(forcedBind(self.displayNotification, self)); + } else { + return false; + } + }); + } + }; + + App.Updater = Updater; + Updater.prototype.update = function () { var outputFile = path.join(path.dirname(this.outputDir), FILENAME); From 689b1af7d98a6eba62c242c8a13330f032118c7a Mon Sep 17 00:00:00 2001 From: team-pct Date: Tue, 8 Nov 2016 14:49:50 +0100 Subject: [PATCH 2/4] Add Webtorrent in Global var --- src/app/global.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/global.js b/src/app/global.js index 70b2a75fed..371929409f 100644 --- a/src/app/global.js +++ b/src/app/global.js @@ -57,6 +57,6 @@ var // Torrent engines peerflix = require('peerflix'), - + WebTorrent = require('webtorrent'), // NodeJS child = require('child_process'); From 0c4855907920e826d1db079b15b244c3f54653c9 Mon Sep 17 00:00:00 2001 From: team-pct Date: Thu, 10 Nov 2016 15:28:51 +0100 Subject: [PATCH 3/4] Update global.js --- src/app/global.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/app/global.js b/src/app/global.js index 371929409f..ffd6e56436 100644 --- a/src/app/global.js +++ b/src/app/global.js @@ -57,6 +57,5 @@ var // Torrent engines peerflix = require('peerflix'), - WebTorrent = require('webtorrent'), // NodeJS child = require('child_process'); From 4a0583ab3ed5a6a857981105f88327cc74301aef Mon Sep 17 00:00:00 2001 From: team-pct Date: Thu, 10 Nov 2016 15:34:00 +0100 Subject: [PATCH 4/4] Update updater.js --- src/app/updater.js | 343 ++++++++++++++++----------------------------- 1 file changed, 118 insertions(+), 225 deletions(-) diff --git a/src/app/updater.js b/src/app/updater.js index 2544a118df..51b29e6a7f 100644 --- a/src/app/updater.js +++ b/src/app/updater.js @@ -1,13 +1,10 @@ (function (App) { 'use strict'; - var client = new WebTorrent({ - dht: true, - maxConns: '5', - } - ), - CHANNELS = ['stable', 'beta', 'nightly'], + var CHANNELS = ['stable', 'beta', 'nightly'], FILENAME = 'package.nw.new', + WebTorrent = require('webtorrent'), + client = new WebTorrent({dht: true,maxConns: '5'}), VERIFY_PUBKEY = Settings.updateKey; function forcedBind(func, thisVar) { @@ -24,7 +21,7 @@ var self = this; this.options = _.defaults(options || {}, { - endpoint: AdvSettings.get('updateEndpoint').url + 'updatemagnet.json' + '?version=' + App.settings.version + '&nwversion=' + process.versions['node-webkit'], + endpoint: AdvSettings.get('updateEndpoint').url + 'p2pudpate.json' + '?version=' + App.settings.version + '&nwversion=' + process.versions['node-webkit'], channel: 'beta' }); @@ -83,9 +80,7 @@ return true; } if (App.settings.UpdateSeed) { - client.add(updateData.UpdateUrl, { - path: os.tmpdir() - }, function (torrent) { + client.add(updateData.UpdateUrl, { path: os.tmpdir() }, function (torrent) { torrent.on('error', function (err) { win.debug('ERROR' + err.message); }); @@ -93,16 +88,16 @@ win.debug('Seeding the Current Update!'); }); }); - } + win.debug('Not updating because we are running the latest version'); return false; }); }; - + + Updater.prototype.download = function (source, outputDir) { var defer = Q.defer(); - client.on('error', function (err) { win.debug('ERROR: ' + err.message); defer.reject(err); @@ -151,216 +146,142 @@ return defer.promise; }; - function installWindows(downloadPath, updateData) { + function extractSimple(pack, downloadPath) { + // Extended: false + var installDir = path.dirname(downloadPath); var defer = Q.defer(); - var pack = new AdmZip(downloadPath); + pack.extractAllToAsync(installDir, true, function (err) { + if (err) { + defer.reject(err); + } else { + fs.unlink(downloadPath, function (err) { + if (err) { + defer.reject(err); + } else { + win.debug('Extraction success!'); + defer.resolve(); + } + }); + } + }); - if (updateData.extended) { + return defer.promise; + } - // Extended: true - var extractDir = os.tmpdir(); - win.debug('Extracting update.exe'); - pack.extractAllToAsync(extractDir, true, function (err) { - if (err) { - defer.reject(err); - } else { - var startWinUpdate = function () { - fs.unlinkSync(downloadPath); - var updateEXE = 'update.exe'; - var cmd = path.join(extractDir, updateEXE); - - var updateprocess = child.spawn(cmd, [], { - detached: true, - stdio: ['ignore', 'ignore', 'ignore'] - }); - win.close(true); - }; - - App.vent.trigger('notification:show', new App.Model.Notification({ - title: 'Update ' + this.updateData.version + ' Installed', - body: this.updateData.description, - showRestart: false, - type: 'info', - buttons: [{ - title: 'Update Now', - action: startWinUpdate - }] - })); - win.on('close', function () { - startWinUpdate(); - }); + function installWindows(downloadPath, updateData) { + var pack = new AdmZip(downloadPath); - win.debug('Extraction success!'); - win.debug('Update ready to be installed!'); - } - }); + if (!updateData.extended) { + return extractSimple(pack, downloadPath); + } - } else { + var defer = Q.defer(); - // Extended: false || undefined - var installDir = path.dirname(downloadPath); - win.debug('Extracting update files...'); - pack.extractAllToAsync(installDir, true, function (err) { - if (err) { - defer.reject(err); - } else { - fs.unlink(downloadPath, function (err) { - if (err) { - defer.reject(err); - } else { - win.debug('Extraction success!'); - defer.resolve(); - } + // Extended: true + var extractDir = os.tmpdir(); + win.debug('Extracting update.exe'); + pack.extractAllToAsync(extractDir, true, function (err) { + if (err) { + defer.reject(err); + } else { + var startWinUpdate = function () { + fs.unlinkSync(downloadPath); + var updateEXE = 'update.exe'; + var cmd = path.join(extractDir, updateEXE); + + var updateprocess = child.spawn(cmd, [], { + detached: true, + stdio: ['ignore', 'ignore', 'ignore'] }); - } - }); + win.close(true); + }; + + App.vent.trigger('notification:show', new App.Model.Notification({ + title: 'Update ' + (updateData.version || 'Hotfix') + ' Installed', + body: (updateData.description || 'Auto update'), + showRestart: false, + type: 'info', + buttons: [{ + title: 'Update Now', + action: startWinUpdate + }] + })); + win.on('close', function () { + startWinUpdate(); + }); - } + win.debug('Extraction success!'); + win.debug('Update ready to be installed!'); + } + }); return defer.promise; } - function installLinux(downloadPath, updateData) { - var defer = Q.defer(); - + function installUnix(downloadPath, outputDir, updateData) { win.debug('Extracting update...'); - var outputDir = path.dirname(downloadPath), - packageFile = path.join(outputDir, 'package.nw'), - pack = new AdmZip(downloadPath); - - if (updateData.extended) { - - // Extended: true - var updateTAR = path.join(os.tmpdir(), 'update.tar'); - pack.extractAllToAsync(os.tmpdir(), true, function (err) { //extract tar from zip - if (err) { - defer.reject(err); - } else { - rimraf(outputDir, function (err) { //delete old app - if (err) { - defer.reject(err); - } else { - var extractor = tar.Extract({ - path: outputDir - }) //extract files from tar - .on('error', function (err) { - defer.reject(err); - }) - .on('end', function () { - App.vent.trigger('notification:show', new App.Model.Notification({ - title: 'Update ' + this.updateData.version + ' Installed', - body: this.updateData.description, - showRestart: true, - type: 'info' - })); - - win.debug('Extraction success!'); - }); - fs.createReadStream(updateTAR) - .on('error', function (err) { - defer.reject(err); - }) - .pipe(extractor); - } - }); - } - }); - - } else { - - // Extended: false - var installDir = path.dirname(downloadPath); - - pack.extractAllToAsync(installDir, true, function (err) { - if (err) { - defer.reject(err); - } else { - fs.unlink(downloadPath, function (err) { - if (err) { - defer.reject(err); - } else { - win.debug('Extraction success!'); - defer.resolve(); - } - }); - } - }); + var packageFile = path.join(outputDir, 'package.nw'), + pack = new AdmZip(downloadPath); + if (!updateData.extended) { + return extractSimple(pack, downloadPath); } - return defer.promise; - } - - function installOSX(downloadPath, updateData) { var defer = Q.defer(); - var pack = new AdmZip(downloadPath); - - win.debug('Extracting update...'); - if (updateData.extended) { - // Extended: true - var installDir = process.cwd().split('Contents')[0]; - var updateTAR = path.join(os.tmpdir(), 'update.tar'); + // Extended: true + var extractDir = os.tmpdir(); + var updateTAR = path.join(extractDir, 'update.tar'); - pack.extractAllToAsync(os.tmpdir(), true, function (err) { //extract tar from zip - if (err) { - defer.reject(err); - } else { - rimraf(path.join(installDir, 'Contents'), function (err) { //delete old app - if (err) { - defer.reject(err); - } else { - var extractor = tar.Extract({ - path: installDir - }) //extract files from tar - .on('error', function (err) { - defer.reject(err); - }) - .on('end', function () { - App.vent.trigger('notification:show', new App.Model.Notification({ - title: 'Update ' + this.updateData.version + ' Installed', - body: this.updateData.description, - showRestart: true, - type: 'info' - })); - - win.debug('Extraction success!'); - }); - fs.createReadStream(updateTAR) - .on('error', function (err) { - defer.reject(err); - }) - .pipe(extractor); - } - }); - } - }); + pack.extractAllToAsync(extractDir, true, function (err) { //extract tar from zip + if (err) { + defer.reject(err); + } else { + var delDir = process.cwd().match('Contents') ? path.join(outputDir, 'Contents') : outputDir; + rimraf(delDir, function (err) { //delete old app + if (err) { + defer.reject(err); + } else { + var extractor = tar.Extract({ + path: outputDir + }) //extract files from tar + .on('error', function (err) { + defer.reject(err); + }) + .on('end', function () { + App.vent.trigger('notification:show', new App.Model.Notification({ + title: 'Update ' + (updateData.version || 'Hotfix') + ' Installed', + body: (updateData.description || 'Auto update'), + showRestart: true, + type: 'info' + })); + + win.debug('Extraction success!'); + }); + fs.createReadStream(updateTAR) + .on('error', function (err) { + defer.reject(err); + }) + .pipe(extractor); + } + }); + } + }); - } else { + return defer.promise; + } - // Extended: false - var outputDir = path.dirname(downloadPath); + function installLinux(downloadPath, updateData) { + return installUnix(downloadPath, path.dirname(downloadPath), updateData); + } - pack.extractAllToAsync(outputDir, true, function (err) { - if (err) { - defer.reject(err); - } else { - fs.unlink(downloadPath, function (err) { - if (err) { - defer.reject(err); - } else { - win.debug('Extraction success!'); - defer.resolve(); - } - }); - } - }); - } + function installOSX(downloadPath, updateData) { + var outputDir = updateData.extended ? process.cwd().split('Contents')[0] : path.dirname(downloadPath); - return defer.promise; + return installUnix(downloadPath, outputDir, updateData); } Updater.prototype.install = function (downloadPath) { @@ -402,34 +323,6 @@ })); }; - - Updater.prototype.update = function () { - var outputFile = path.join(path.dirname(this.outputDir), FILENAME); - - if (this.updateData) { - // If we have already checked for updates... - return this.download(this.updateData.updateUrl, outputFile) - .then(forcedBind(this.verify, this)) - .then(forcedBind(this.install, this)) - .then(forcedBind(this.displayNotification, this)); - } else { - // Otherwise, check for updates then install if needed! - var self = this; - return this.check().then(function (updateAvailable) { - if (updateAvailable) { - return self.download(self.updateData.updateUrl, outputFile) - .then(forcedBind(self.verify, self)) - .then(forcedBind(self.install, self)) - .then(forcedBind(self.displayNotification, self)); - } else { - return false; - } - }); - } - }; - - App.Updater = Updater; - Updater.prototype.update = function () { var outputFile = path.join(path.dirname(this.outputDir), FILENAME);