diff --git a/app/main.js b/app/main.js index 07aed14d0..eb867a2d7 100644 --- a/app/main.js +++ b/app/main.js @@ -1,11 +1,18 @@ const {app, BrowserWindow, ipcMain} = require('electron'); +const url = require('url'); const path = require('path'); const jayson = require('jayson'); +const semver = require('semver'); +const https = require('https'); // tree-kill has better cross-platform handling of // killing a process. child-process.kill was unreliable const kill = require('tree-kill'); const child_process = require('child_process'); const assert = require('assert'); +const {version: localVersion} = require(app.getAppPath() + '/package.json'); + +const VERSION_CHECK_INTERVAL = 30 * 60 * 1000; +const LATEST_RELEASE_API_URL = 'https://api.github.com/repos/lbryio/lbry-app/releases/latest'; let client = jayson.client.http('http://localhost:5279/lbryapi'); @@ -23,6 +30,46 @@ let daemonStopRequested = false; // this is set to true and app.quit() is called again to quit for real. let readyToQuit = false; +function checkForNewVersion(callback) { + function formatRc(ver) { + // Adds dash if needed to make RC suffix semver friendly + return ver.replace(/([^-])rc/, '$1-rc'); + } + + let result = ''; + const opts = { + headers: { + 'User-Agent': `LBRY/${localVersion}`, + } + }; + const req = https.get(Object.assign(opts, url.parse(LATEST_RELEASE_API_URL)), (res) => { + res.on('data', (data) => { + result += data; + }); + res.on('end', () => { + console.log('Local version:', localVersion); + const tagName = JSON.parse(result).tag_name; + const [_, remoteVersion] = tagName.match(/^v([\d.]+(?:-?rc\d+)?)$/); + if (!remoteVersion) { + console.log('Malformed remote version string:', tagName); + win.webContents.send('version-info-received', null); + } else { + console.log('Remote version:', remoteVersion); + const upgradeAvailable = semver.gt(formatRc(remoteVersion), formatRc(localVersion)); + console.log(upgradeAvailable ? 'Upgrade available' : 'No upgrade available'); + win.webContents.send('version-info-received', {remoteVersion, localVersion, upgradeAvailable}); + } + }) + }); + + req.on('error', (err) => { + console.log('Failed to get current version from GitHub. Error:', err); + win.webContents.send('version-info-received', null); + }); +} + +ipcMain.on('version-info-requested', checkForNewVersion); + /* * Replacement for Electron's shell.openItem. The Electron version doesn't * reliably work from the main process, and we need to be able to run it diff --git a/app/package.json b/app/package.json index a2b1a644d..0e7151bce 100644 --- a/app/package.json +++ b/app/package.json @@ -12,6 +12,7 @@ "install": "^0.8.7", "jayson": "^2.0.2", "npm": "^4.2.0", + "semver": "^5.3.0", "tree-kill": "^1.1.0" } } diff --git a/package.json b/package.json index f342a1e52..45142bbaa 100644 --- a/package.json +++ b/package.json @@ -42,5 +42,6 @@ "devDependencies": { "electron": "^1.4.15", "electron-builder": "^11.7.0" - } + }, + "dependencies": {} } diff --git a/ui/js/app.js b/ui/js/app.js index 9cfb43137..1f686d07d 100644 --- a/ui/js/app.js +++ b/ui/js/app.js @@ -115,17 +115,13 @@ var App = React.createClass({ }); if (!sessionStorage.getItem('upgradeSkipped')) { - lbry.checkNewVersionAvailable(({isAvailable}) => { - if (!isAvailable) { - return; - } - - lbry.getVersionInfo((versionInfo) => { - this._version = versionInfo.lbrynet_version; + lbry.getVersionInfo().then(({remoteVersion, upgradeAvailable}) => { + if (upgradeAvailable) { + this._version = remoteVersion; this.setState({ modal: 'upgrade', }); - }); + } }); } }, diff --git a/ui/js/lbry.js b/ui/js/lbry.js index 999f192c2..e2807090a 100644 --- a/ui/js/lbry.js +++ b/ui/js/lbry.js @@ -4,7 +4,7 @@ import jsonrpc from './jsonrpc.js'; import lbryuri from './lbryuri.js'; import {getLocal, getSession, setSession, setLocal} from './utils.js'; -const {remote} = require('electron'); +const {remote, ipcRenderer} = require('electron'); const menu = remote.require('./menu/main-menu'); /** @@ -361,44 +361,6 @@ lbry.publish = function(params, fileListedCallback, publishedCallback, errorCall //}); } -lbry.getVersionInfo = function(callback) { - lbry.call('version', {}, callback); -}; - -lbry.checkNewVersionAvailable = function(callback) { - lbry.call('version', {}, function(versionInfo) { - var ver = versionInfo.lbrynet_version.split('.'); - - var maj = parseInt(ver[0]), - min = parseInt(ver[1]), - patch = parseInt(ver[2]); - - var remoteVer = versionInfo.remote_lbrynet.split('.'); - var remoteMaj = parseInt(remoteVer[0]), - remoteMin = parseInt(remoteVer[1]), - remotePatch = parseInt(remoteVer[2]); - - if (maj < remoteMaj) { - var newVersionAvailable = true; - } else if (maj == remoteMaj) { - if (min < remoteMin) { - var newVersionAvailable = true; - } else if (min == remoteMin) { - var newVersionAvailable = (patch < remotePatch); - } else { - var newVersionAvailable = false; - } - } else { - var newVersionAvailable = false; - } - callback(newVersionAvailable); - }, function(err) { - if (err.fault == 'NoSuchFunction') { - // Really old daemon that can't report a version - callback(true); - } - }); -} lbry.getClientSettings = function() { var outSettings = {}; @@ -608,6 +570,14 @@ lbry.showMenuIfNeeded = function() { sessionStorage.setItem('menuShown', chosenMenu); }; +lbry.getVersionInfo = function() { + return new Promise((resolve, reject) => { + ipcRenderer.once('version-info-received', (event, versionInfo) => { resolve(versionInfo) }); + ipcRenderer.send('version-info-requested'); + }); +} + + /** * Wrappers for API methods to simulate missing or future behavior. Unlike the old-style stubs, * these are designed to be transparent wrappers around the corresponding API methods.