From 285c1ca7b611c2be2f7f2f5d96278dfdcf81d543 Mon Sep 17 00:00:00 2001 From: Alex Liebowitz Date: Sat, 18 Nov 2017 00:08:44 -0500 Subject: [PATCH 01/34] Add electron-updater requirement and import --- package.json | 1 + src/main/index.js | 1 + 2 files changed, 2 insertions(+) diff --git a/package.json b/package.json index d0dc3f9c7..f96b5740a 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,7 @@ "bluebird": "^3.5.1", "classnames": "^2.2.5", "electron-dl": "^1.6.0", + "electron-updater": "^2.16.1", "formik": "^0.10.4", "from2": "^2.3.0", "install": "^0.10.2", diff --git a/src/main/index.js b/src/main/index.js index 30a78c3e6..5f85e58ec 100644 --- a/src/main/index.js +++ b/src/main/index.js @@ -9,6 +9,7 @@ import Keytar from 'keytar'; import ChildProcess from 'child_process'; import Assert from 'assert'; import { app, BrowserWindow, globalShortcut, ipcMain, Menu, Tray } from 'electron'; +import { autoUpdater } from 'electron-updater'; import mainMenu from './menu/mainMenu'; import contextMenu from './menu/contextMenu'; From 2031f36f7ccca8c974f2938362d81e76b44e2ec5 Mon Sep 17 00:00:00 2001 From: Alex Liebowitz Date: Sun, 19 Nov 2017 00:15:18 -0500 Subject: [PATCH 02/34] Upgrade to electron-builder 19.45.5 It's not clear yet if this will be needed for the new upgrade process, but we need to get on the latest version eventually anyway. --- build/upload_assets.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/build/upload_assets.py b/build/upload_assets.py index 2ba8b56b5..07cae795f 100644 --- a/build/upload_assets.py +++ b/build/upload_assets.py @@ -19,14 +19,16 @@ def get_asset_filename(): this_dir = os.path.dirname(os.path.realpath(__file__)) system = platform.system() if system == 'Darwin': - return glob.glob(this_dir + '/../dist/LBRY*.dmg')[0] + suffix = 'dmg' elif system == 'Linux': - return glob.glob(this_dir + '/../dist/LBRY*.deb')[0] + suffix = 'deb' elif system == 'Windows': - return glob.glob(this_dir + '/../dist/LBRY*.exe')[0] + suffix = 'exe' else: raise Exception("I don't know about any artifact on {}".format(system)) + return glob.glob(this_dir + '/../dist/LBRY*.' + suffix)[0] + def upload_to_s3(folder): tag = subprocess.check_output(['git', 'describe', '--always', '--abbrev=8', 'HEAD']).strip() From 43297ce41404c339ba141c2866a423d3e8fb08f5 Mon Sep 17 00:00:00 2001 From: Alex Liebowitz Date: Mon, 27 Nov 2017 03:13:33 -0500 Subject: [PATCH 03/34] Add electron-log The daemon and lbryum log all kinds of useful status/debug info, might as well start doing that in the app too. --- package.json | 1 + src/main/index.js | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/package.json b/package.json index f96b5740a..04f50ed1b 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,7 @@ "bluebird": "^3.5.1", "classnames": "^2.2.5", "electron-dl": "^1.6.0", + "electron-log": "^2.2.12", "electron-updater": "^2.16.1", "formik": "^0.10.4", "from2": "^2.3.0", diff --git a/src/main/index.js b/src/main/index.js index 5f85e58ec..a774cf8ee 100644 --- a/src/main/index.js +++ b/src/main/index.js @@ -10,6 +10,7 @@ import ChildProcess from 'child_process'; import Assert from 'assert'; import { app, BrowserWindow, globalShortcut, ipcMain, Menu, Tray } from 'electron'; import { autoUpdater } from 'electron-updater'; +import log from 'electron-log'; import mainMenu from './menu/mainMenu'; import contextMenu from './menu/contextMenu'; @@ -18,6 +19,9 @@ const localVersion = app.getVersion(); // Debug configs const isDevelopment = process.env.NODE_ENV === 'development'; +// For now, log info messages in production for easier debugging of built apps +log.transports.file.level = 'info'; + // Misc constants const LATEST_RELEASE_API_URL = 'https://api.github.com/repos/lbryio/lbry-app/releases/latest'; const DAEMON_PATH = process.env.LBRY_DAEMON || Path.join(__static, 'daemon/lbrynet-daemon'); From dade1174766a932e487bd5e7947e2d3c1e8a719a Mon Sep 17 00:00:00 2001 From: Alex Liebowitz Date: Sun, 3 Dec 2017 18:49:26 -0500 Subject: [PATCH 04/34] Add updater settings to package.json --- electron-builder.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/electron-builder.json b/electron-builder.json index 9e0a8f86b..09c928130 100644 --- a/electron-builder.json +++ b/electron-builder.json @@ -1,5 +1,10 @@ { "appId": "io.lbry.LBRY", + "publish": { + "provider": "s3", + "bucket": "releases.lbry.io", + "path": "app/latest" + }, "mac": { "category": "public.app-category.entertainment" }, From b202de449e718c5d6700454e44f296b237a731dc Mon Sep 17 00:00:00 2001 From: Alex Liebowitz Date: Sat, 2 Dec 2017 01:37:09 -0500 Subject: [PATCH 05/34] Upload assets for latest version to S3 in a separate directory These are the assets that go in s3://releases.lbry.io/app/latest. Included are the built asset used for updates (on Mac this is actually a zip file, not the dmg), as well as the update metadata file for this platform (latest.yml, etc.) Also includes some refactoring in the update build script. --- build/upload_assets.py | 73 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 59 insertions(+), 14 deletions(-) diff --git a/build/upload_assets.py b/build/upload_assets.py index 07cae795f..970de642e 100644 --- a/build/upload_assets.py +++ b/build/upload_assets.py @@ -9,13 +9,16 @@ import github import uritemplate import boto3 +S3_BUCKET = 'releases.lbry.io' +RELEASES_S3_PATH = 'app' +LATEST_S3_PATH = 'app/latest' def main(): upload_to_github_if_tagged('lbryio/lbry-app') - upload_to_s3('app') + upload_to_s3(RELEASES_S3_PATH) -def get_asset_filename(): +def get_asset_path(): this_dir = os.path.dirname(os.path.realpath(__file__)) system = platform.system() if system == 'Darwin': @@ -27,31 +30,73 @@ def get_asset_filename(): else: raise Exception("I don't know about any artifact on {}".format(system)) - return glob.glob(this_dir + '/../dist/LBRY*.' + suffix)[0] + return os.path.realpath(glob.glob(this_dir + '/../dist/LBRY*.' + suffix)[0]) + +def get_update_asset_path(): + # Get the asset used used for updates. On Mac, this is a .zip; on + # Windows it's just the installer file. + if platform.system() == 'Darwin': + this_dir = os.path.dirname(os.path.realpath(__file__)) + return os.path.realpath(glob.glob(this_dir + '/../dist/LBRY*.zip')[0]) + else: + return get_asset_path() + + +def get_latest_file_path(): + # The update metadata file is called latest.yml on Windows, latest-mac.yml on + # Mac, latest-linux.yml on Linux + this_dir = os.path.dirname(os.path.realpath(__file__)) + return os.path.realpath(glob.glob(this_dir + '/../dist/latest*.yml')[0]) def upload_to_s3(folder): - tag = subprocess.check_output(['git', 'describe', '--always', '--abbrev=8', 'HEAD']).strip() - commit_date = subprocess.check_output([ - 'git', 'show', '-s', '--format=%cd', '--date=format:%Y%m%d-%H%I%S', 'HEAD']).strip() - - asset_path = get_asset_filename() - bucket = 'releases.lbry.io' - key = folder + '/' + commit_date + '-' + tag + '/' + os.path.basename(asset_path) - - print "Uploading " + asset_path + " to s3://" + bucket + '/' + key + '' + asset_path = get_asset_path() if 'AWS_ACCESS_KEY_ID' not in os.environ or 'AWS_SECRET_ACCESS_KEY' not in os.environ: print 'Must set AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY to publish assets to s3' return 1 + asset_filename = os.path.basename(asset_path) + + tag = subprocess.check_output(['git', 'describe', '--always', '--abbrev=8', 'HEAD']).strip() + commit_date = subprocess.check_output([ + 'git', 'show', '-s', '--format=%cd', '--date=format:%Y%m%d-%H%I%S', 'HEAD']).strip() + key = folder + '/' + commit_date + '-' + tag + '/' + asset_filename + + print "Uploading asset file at " + asset_path + " to s3://" + S3_BUCKET + '/' + key + s3 = boto3.resource( 's3', aws_access_key_id=os.environ['AWS_ACCESS_KEY_ID'], aws_secret_access_key=os.environ['AWS_SECRET_ACCESS_KEY'], config=boto3.session.Config(signature_version='s3v4') ) - s3.meta.client.upload_file(asset_path, bucket, key) + + s3.Object(S3_BUCKET, key).upload_file(asset_path) + + # Populate the update bucket (update.lbry.io) + + update_asset_path = get_update_asset_path() + if asset_path == update_asset_path: + # If the update asset and the regular built file are the same, we can + # just copy over. + print "Copying asset file to s3://" + S3_BUCKET + "/" + LATEST_S3_PATH + "/" + asset_filename + s3.Object(S3_BUCKET, LATEST_S3_PATH + "/" + asset_filename).copy_from(CopySource={ + 'Bucket': S3_BUCKET, + 'Key': key + }) + else: + update_asset_filename = os.path.basename(update_asset_path) + print "Uploading update asset file at", update_asset_path, \ + "to s3://" + S3_BUCKET + "/" + LATEST_S3_PATH + "/" + update_asset_filename + s3.Object(S3_BUCKET, LATEST_S3_PATH + "/" + update_asset_filename).upload_file(update_asset_path) + + # Upload update metadata file to update bucket + metadatafilepath = get_latest_file_path() + metadatafilename = os.path.basename(metadatafilepath) + + print "Uploading update metadata file at", metadatafilepath, "to S3" + s3.Object(S3_BUCKET, LATEST_S3_PATH + "/" + metadatafilename).upload_file(metadatafilepath) def upload_to_github_if_tagged(repo_name): @@ -77,7 +122,7 @@ def upload_to_github_if_tagged(repo_name): # TODO: maybe this should be an error return 1 - asset_path = get_asset_filename() + asset_path = get_asset_path() print "Uploading " + asset_path + " to Github tag " + current_tag release = get_github_release(repo, current_tag) upload_asset_to_github(release, asset_path, gh_token) From bd8146a86ca2b0d31b2cebde9ddfab57a6d1af10 Mon Sep 17 00:00:00 2001 From: Alex Liebowitz Date: Sun, 3 Dec 2017 21:41:42 -0500 Subject: [PATCH 06/34] Add electron-publisher-s3 requirement Needed for update system --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 04f50ed1b..8cd6c8cb0 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ "classnames": "^2.2.5", "electron-dl": "^1.6.0", "electron-log": "^2.2.12", + "electron-publisher-s3": "^19.47.0", "electron-updater": "^2.16.1", "formik": "^0.10.4", "from2": "^2.3.0", From 67c3863bd665f9d200f126b5a07f6eb109499688 Mon Sep 17 00:00:00 2001 From: Alex Liebowitz Date: Thu, 7 Dec 2017 03:08:27 -0500 Subject: [PATCH 07/34] Don't try to upload latest-linux.yml file on Linux It's not being generated on Linux. I'm pretty sure this is a bug (or at least undocumented behavior), but it's OK because Linux doesn't support updates yet anyway. --- build/upload_assets.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/build/upload_assets.py b/build/upload_assets.py index 970de642e..59817cf60 100644 --- a/build/upload_assets.py +++ b/build/upload_assets.py @@ -46,7 +46,10 @@ def get_latest_file_path(): # The update metadata file is called latest.yml on Windows, latest-mac.yml on # Mac, latest-linux.yml on Linux this_dir = os.path.dirname(os.path.realpath(__file__)) - return os.path.realpath(glob.glob(this_dir + '/../dist/latest*.yml')[0]) + + latestfilematches = glob.glob(this_dir + '/../dist/latest*.yml') + + return latestfilematches[0] if latestfilematches else None def upload_to_s3(folder): @@ -91,12 +94,15 @@ def upload_to_s3(folder): "to s3://" + S3_BUCKET + "/" + LATEST_S3_PATH + "/" + update_asset_filename s3.Object(S3_BUCKET, LATEST_S3_PATH + "/" + update_asset_filename).upload_file(update_asset_path) - # Upload update metadata file to update bucket metadatafilepath = get_latest_file_path() - metadatafilename = os.path.basename(metadatafilepath) - print "Uploading update metadata file at", metadatafilepath, "to S3" - s3.Object(S3_BUCKET, LATEST_S3_PATH + "/" + metadatafilename).upload_file(metadatafilepath) + if metadatafilepath is not None: + # For some reason latest-linux.yml isn't being created, but it's OK because updates don't + # work on Linux yet anyway. + metadatafilename = os.path.basename(metadatafilepath) + + print "Uploading update metadata file at", metadatafilepath, "to S3" + s3.Object(S3_BUCKET, LATEST_S3_PATH + "/" + metadatafilename).upload_file(metadatafilepath) def upload_to_github_if_tagged(repo_name): From e39470c3cc2dd150ae715c886cd4cf76920a72d7 Mon Sep 17 00:00:00 2001 From: Alex Liebowitz Date: Thu, 7 Dec 2017 20:38:10 -0500 Subject: [PATCH 08/34] Copy dmg file into dist/mac for TeamCity TeamCity expects the dmg to be in dist/mac, but in the new electron-builder it's put directly in dist/ (in the long run the right way to solve this is to update the TeamCity config). --- build/build.sh | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/build/build.sh b/build/build.sh index 2273eff00..1ace2ad48 100755 --- a/build/build.sh +++ b/build/build.sh @@ -79,6 +79,12 @@ if [ "$FULL_BUILD" == "true" ]; then yarn build + # Workaround: TeamCity expects the dmg to be in dist/mac, but in the new electron-builder + # it's put directly in dist/ (the right way to solve this is to update the TeamCity config) + if $OSX; then + cp dist/*.dmg dist/mac + fi + # electron-build has a publish feature, but I had a hard time getting # it to reliably work and it also seemed difficult to configure. Not proud of # this, but it seemed better to write my own. From 5fff24b0fbb7c19c617c53abbd20846079b89dd5 Mon Sep 17 00:00:00 2001 From: Alex Liebowitz Date: Fri, 8 Dec 2017 05:08:50 -0500 Subject: [PATCH 09/34] Add "auto update downloaded" modal --- src/renderer/constants/modal_types.js | 1 + .../modal/modalAutoUpdateDownloaded/index.js | 5 +++ .../modal/modalAutoUpdateDownloaded/view.jsx | 31 +++++++++++++++++++ src/renderer/modal/modalRouter/view.jsx | 3 ++ 4 files changed, 40 insertions(+) create mode 100644 src/renderer/modal/modalAutoUpdateDownloaded/index.js create mode 100644 src/renderer/modal/modalAutoUpdateDownloaded/view.jsx diff --git a/src/renderer/constants/modal_types.js b/src/renderer/constants/modal_types.js index 9c6d457f9..8e56e8237 100644 --- a/src/renderer/constants/modal_types.js +++ b/src/renderer/constants/modal_types.js @@ -2,6 +2,7 @@ export const CONFIRM_FILE_REMOVE = 'confirmFileRemove'; export const INCOMPATIBLE_DAEMON = 'incompatibleDaemon'; export const FILE_TIMEOUT = 'file_timeout'; export const DOWNLOADING = 'downloading'; +export const AUTO_UPDATE_DOWNLOADED = "auto_update_downloaded"; export const ERROR = 'error'; export const INSUFFICIENT_CREDITS = 'insufficient_credits'; export const UPGRADE = 'upgrade'; diff --git a/src/renderer/modal/modalAutoUpdateDownloaded/index.js b/src/renderer/modal/modalAutoUpdateDownloaded/index.js new file mode 100644 index 000000000..921271126 --- /dev/null +++ b/src/renderer/modal/modalAutoUpdateDownloaded/index.js @@ -0,0 +1,5 @@ +import React from "react"; +import { connect } from "react-redux"; +import ModalAutoUpdateDownloaded from "./view"; + +export default connect(null, null)(ModalAutoUpdateDownloaded); diff --git a/src/renderer/modal/modalAutoUpdateDownloaded/view.jsx b/src/renderer/modal/modalAutoUpdateDownloaded/view.jsx new file mode 100644 index 000000000..46803c645 --- /dev/null +++ b/src/renderer/modal/modalAutoUpdateDownloaded/view.jsx @@ -0,0 +1,31 @@ +import React from "react"; +import { Modal } from "modal/modal"; +import { Line } from "rc-progress"; +import Link from "component/link/index"; + +const { remote } = require("electron"); +const { autoUpdater } = remote.require("electron-updater"); + +class ModalAutoUpdateDownloaded extends React.PureComponent { + render() { + return ( + +
+

{__("LBRY Leveled Up")}

+

+ {__( + "A new version of LBRY has been downloaded and is ready to install." + )} +

+
+
+ ); + } +} + +export default ModalAutoUpdateDownloaded; diff --git a/src/renderer/modal/modalRouter/view.jsx b/src/renderer/modal/modalRouter/view.jsx index b2d68fbf2..81925c966 100644 --- a/src/renderer/modal/modalRouter/view.jsx +++ b/src/renderer/modal/modalRouter/view.jsx @@ -2,6 +2,7 @@ import React from 'react'; import ModalError from 'modal/modalError'; import ModalAuthFailure from 'modal/modalAuthFailure'; import ModalDownloading from 'modal/modalDownloading'; +import ModalAutoUpdateDownloaded from "modal/modalAutoUpdateDownloaded"; import ModalUpgrade from 'modal/modalUpgrade'; import ModalWelcome from 'modal/modalWelcome'; import ModalFirstReward from 'modal/modalFirstReward'; @@ -102,6 +103,8 @@ class ModalRouter extends React.PureComponent { return ; case modals.DOWNLOADING: return ; + case modals.AUTO_UPDATE_DOWNLOADED: + return ; case modals.ERROR: return ; case modals.FILE_TIMEOUT: From 24ced8ede7a0134b57cf47a13b1c37e8df4ace28 Mon Sep 17 00:00:00 2001 From: Alex Liebowitz Date: Fri, 8 Dec 2017 07:14:37 -0500 Subject: [PATCH 10/34] More core UI for auto-update We keep the old dialog flow on Linux, and on Windows and Mac we show a single dialog when the file is downloaded. --- src/renderer/constants/action_types.js | 1 + src/renderer/index.js | 7 ++++++- src/renderer/redux/actions/app.js | 17 +++++++++++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/renderer/constants/action_types.js b/src/renderer/constants/action_types.js index 3c828f5cb..f09e13167 100644 --- a/src/renderer/constants/action_types.js +++ b/src/renderer/constants/action_types.js @@ -19,6 +19,7 @@ export const DOWNLOAD_UPGRADE = 'DOWNLOAD_UPGRADE'; export const UPGRADE_DOWNLOAD_STARTED = 'UPGRADE_DOWNLOAD_STARTED'; export const UPGRADE_DOWNLOAD_COMPLETED = 'UPGRADE_DOWNLOAD_COMPLETED'; export const UPGRADE_DOWNLOAD_PROGRESSED = 'UPGRADE_DOWNLOAD_PROGRESSED'; +export const AUTO_UPDATE_DOWNLOAD_COMPLETED = "AUTO_UPDATE_DOWNLOAD_COMPLETED"; export const CHECK_UPGRADE_AVAILABLE = 'CHECK_UPGRADE_AVAILABLE'; export const CHECK_UPGRADE_START = 'CHECK_UPGRADE_START'; export const CHECK_UPGRADE_SUCCESS = 'CHECK_UPGRADE_SUCCESS'; diff --git a/src/renderer/index.js b/src/renderer/index.js index fd6dcc1f7..d7152880a 100644 --- a/src/renderer/index.js +++ b/src/renderer/index.js @@ -9,7 +9,7 @@ import lbry from 'lbry'; import React from 'react'; import ReactDOM from 'react-dom'; import { Provider } from 'react-redux'; -import { doConditionalAuthNavigate, doDaemonReady, doShowSnackBar } from 'redux/actions/app'; +import { doConditionalAuthNavigate, doDaemonReady, doShowSnackBar, doAutoUpdate } from 'redux/actions/app'; import { doNavigate } from 'redux/actions/navigation'; import { doDownloadLanguages } from 'redux/actions/settings'; import { doUserEmailVerify } from 'redux/actions/user'; @@ -17,6 +17,7 @@ import 'scss/all.scss'; import store from 'store'; import app from './app'; +const { autoUpdater } = remote.require('electron-updater'); const { contextMenu } = remote.require('./main.js'); window.addEventListener('contextmenu', event => { @@ -97,6 +98,10 @@ document.addEventListener('click', event => { }); const init = () => { + autoUpdater.on("update-downloaded", () => { + app.store.dispatch(doAutoUpdate()); + }); + app.store.dispatch(doDownloadLanguages()); function onDaemonReady() { diff --git a/src/renderer/redux/actions/app.js b/src/renderer/redux/actions/app.js index 2ecc1dcaf..26eb5bd7b 100644 --- a/src/renderer/redux/actions/app.js +++ b/src/renderer/redux/actions/app.js @@ -20,6 +20,7 @@ import { selectUpgradeFilename, } from 'redux/selectors/app'; +const { autoUpdater } = remote.require('electron-updater'); const { download } = remote.require('electron-dl'); const Fs = remote.require('fs'); const { lbrySettings: config } = require('package.json'); @@ -105,6 +106,16 @@ export function doDownloadUpgrade() { }; } +export function doAutoUpdate() { + return function(dispatch, getState) { + const state = getState(); + dispatch({ + type: types.OPEN_MODAL, + data: modals.AUTO_UPDATE_DOWNLOADED, + }); + }; +} + export function doCancelUpgrade() { return (dispatch, getState) => { const state = getState(); @@ -135,6 +146,12 @@ export function doCheckUpgradeAvailable() { type: ACTIONS.CHECK_UPGRADE_START, }); + if (["win32", "darwin"].includes(process.platform)) { + // On Windows and Mac, updates happen silently + autoUpdater.checkForUpdates(); + return; + } + const success = ({ remoteVersion, upgradeAvailable }) => { dispatch({ type: ACTIONS.CHECK_UPGRADE_SUCCESS, From 565f4119860e6e38335c5bba19ae955f66bffcb5 Mon Sep 17 00:00:00 2001 From: Alex Liebowitz Date: Sun, 10 Dec 2017 03:01:24 -0500 Subject: [PATCH 11/34] Make app actually quit for update Before, it was just minimizing and the app wouldn't even update because electron-updater expects to be able to close the app. --- src/main/index.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/main/index.js b/src/main/index.js index a774cf8ee..1dfb4145b 100644 --- a/src/main/index.js +++ b/src/main/index.js @@ -436,6 +436,9 @@ app.on('before-quit', event => { shutdownDaemonAndQuit(); } else { console.log('Quitting.'); + if (autoUpdating) { + minimize = false; + } } }); @@ -522,6 +525,11 @@ ipcMain.on('version-info-requested', () => { }); }); +ipcMain.on('autoUpdate', () => { + minimize = false; + autoUpdater.quitAndInstall(); +}); + ipcMain.on('get-auth-token', event => { Keytar.getPassword('LBRY', 'auth_token').then(token => { event.sender.send('auth-token-response', token ? token.toString().trim() : null); From 3957bf2afc7aaa614824d28dd06826049d9c2e3f Mon Sep 17 00:00:00 2001 From: Alex Liebowitz Date: Sun, 10 Dec 2017 03:06:30 -0500 Subject: [PATCH 12/34] Finish core UI for auto update --- src/main/index.js | 3 --- src/renderer/constants/action_types.js | 1 - src/renderer/index.js | 14 ++++++++++++++ .../modal/modalAutoUpdateDownloaded/view.jsx | 7 ++++--- src/renderer/redux/actions/app.js | 2 +- 5 files changed, 19 insertions(+), 8 deletions(-) diff --git a/src/main/index.js b/src/main/index.js index 1dfb4145b..e4c3e1ffb 100644 --- a/src/main/index.js +++ b/src/main/index.js @@ -436,9 +436,6 @@ app.on('before-quit', event => { shutdownDaemonAndQuit(); } else { console.log('Quitting.'); - if (autoUpdating) { - minimize = false; - } } }); diff --git a/src/renderer/constants/action_types.js b/src/renderer/constants/action_types.js index f09e13167..3c828f5cb 100644 --- a/src/renderer/constants/action_types.js +++ b/src/renderer/constants/action_types.js @@ -19,7 +19,6 @@ export const DOWNLOAD_UPGRADE = 'DOWNLOAD_UPGRADE'; export const UPGRADE_DOWNLOAD_STARTED = 'UPGRADE_DOWNLOAD_STARTED'; export const UPGRADE_DOWNLOAD_COMPLETED = 'UPGRADE_DOWNLOAD_COMPLETED'; export const UPGRADE_DOWNLOAD_PROGRESSED = 'UPGRADE_DOWNLOAD_PROGRESSED'; -export const AUTO_UPDATE_DOWNLOAD_COMPLETED = "AUTO_UPDATE_DOWNLOAD_COMPLETED"; export const CHECK_UPGRADE_AVAILABLE = 'CHECK_UPGRADE_AVAILABLE'; export const CHECK_UPGRADE_START = 'CHECK_UPGRADE_START'; export const CHECK_UPGRADE_SUCCESS = 'CHECK_UPGRADE_SUCCESS'; diff --git a/src/renderer/index.js b/src/renderer/index.js index d7152880a..cafd41c35 100644 --- a/src/renderer/index.js +++ b/src/renderer/index.js @@ -20,6 +20,8 @@ import app from './app'; const { autoUpdater } = remote.require('electron-updater'); const { contextMenu } = remote.require('./main.js'); +autoUpdater.logger = remote.require("electron-log"); + window.addEventListener('contextmenu', event => { contextMenu(remote.getCurrentWindow(), event.x, event.y, app.env === 'development'); event.preventDefault(); @@ -102,6 +104,18 @@ const init = () => { app.store.dispatch(doAutoUpdate()); }); + if (["win32", "darwin"].includes(process.platform)) { + autoUpdater.on("update-available", () => { + console.log("Update available"); + }); + autoUpdater.on("update-not-available", () => { + console.log("Update not available"); + }); + autoUpdater.on("update-downloaded", () => { + console.log("Update downloaded"); + app.store.dispatch(doAutoUpdate()); + }); + } app.store.dispatch(doDownloadLanguages()); function onDaemonReady() { diff --git a/src/renderer/modal/modalAutoUpdateDownloaded/view.jsx b/src/renderer/modal/modalAutoUpdateDownloaded/view.jsx index 46803c645..2d136071a 100644 --- a/src/renderer/modal/modalAutoUpdateDownloaded/view.jsx +++ b/src/renderer/modal/modalAutoUpdateDownloaded/view.jsx @@ -3,8 +3,7 @@ import { Modal } from "modal/modal"; import { Line } from "rc-progress"; import Link from "component/link/index"; -const { remote } = require("electron"); -const { autoUpdater } = remote.require("electron-updater"); +const { ipcRenderer } = require("electron"); class ModalAutoUpdateDownloaded extends React.PureComponent { render() { @@ -13,7 +12,9 @@ class ModalAutoUpdateDownloaded extends React.PureComponent { isOpen={true} contentLabel={__("Update downloaded")} confirmButtonLabel={__("Update and Restart")} - onConfirmed={autoUpdater.quitAndInstall()} + onConfirmed={() => { + ipcRenderer.send("autoUpdate"); + }} >

{__("LBRY Leveled Up")}

diff --git a/src/renderer/redux/actions/app.js b/src/renderer/redux/actions/app.js index 26eb5bd7b..e2b36470b 100644 --- a/src/renderer/redux/actions/app.js +++ b/src/renderer/redux/actions/app.js @@ -111,7 +111,7 @@ export function doAutoUpdate() { const state = getState(); dispatch({ type: types.OPEN_MODAL, - data: modals.AUTO_UPDATE_DOWNLOADED, + data: { modal: modals.AUTO_UPDATE_DOWNLOADED }, }); }; } From acec4a745f219c52379156bd1b9c7280ee1df7c6 Mon Sep 17 00:00:00 2001 From: Alex Liebowitz Date: Sat, 16 Dec 2017 19:42:40 -0500 Subject: [PATCH 13/34] Remove S3 upload from upload_assets.py --- build/upload_assets.py | 59 ------------------------------------------ 1 file changed, 59 deletions(-) diff --git a/build/upload_assets.py b/build/upload_assets.py index 59817cf60..b0fb5513c 100644 --- a/build/upload_assets.py +++ b/build/upload_assets.py @@ -9,13 +9,8 @@ import github import uritemplate import boto3 -S3_BUCKET = 'releases.lbry.io' -RELEASES_S3_PATH = 'app' -LATEST_S3_PATH = 'app/latest' - def main(): upload_to_github_if_tagged('lbryio/lbry-app') - upload_to_s3(RELEASES_S3_PATH) def get_asset_path(): @@ -51,60 +46,6 @@ def get_latest_file_path(): return latestfilematches[0] if latestfilematches else None - -def upload_to_s3(folder): - asset_path = get_asset_path() - - if 'AWS_ACCESS_KEY_ID' not in os.environ or 'AWS_SECRET_ACCESS_KEY' not in os.environ: - print 'Must set AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY to publish assets to s3' - return 1 - - asset_filename = os.path.basename(asset_path) - - tag = subprocess.check_output(['git', 'describe', '--always', '--abbrev=8', 'HEAD']).strip() - commit_date = subprocess.check_output([ - 'git', 'show', '-s', '--format=%cd', '--date=format:%Y%m%d-%H%I%S', 'HEAD']).strip() - key = folder + '/' + commit_date + '-' + tag + '/' + asset_filename - - print "Uploading asset file at " + asset_path + " to s3://" + S3_BUCKET + '/' + key - - s3 = boto3.resource( - 's3', - aws_access_key_id=os.environ['AWS_ACCESS_KEY_ID'], - aws_secret_access_key=os.environ['AWS_SECRET_ACCESS_KEY'], - config=boto3.session.Config(signature_version='s3v4') - ) - - s3.Object(S3_BUCKET, key).upload_file(asset_path) - - # Populate the update bucket (update.lbry.io) - - update_asset_path = get_update_asset_path() - if asset_path == update_asset_path: - # If the update asset and the regular built file are the same, we can - # just copy over. - print "Copying asset file to s3://" + S3_BUCKET + "/" + LATEST_S3_PATH + "/" + asset_filename - s3.Object(S3_BUCKET, LATEST_S3_PATH + "/" + asset_filename).copy_from(CopySource={ - 'Bucket': S3_BUCKET, - 'Key': key - }) - else: - update_asset_filename = os.path.basename(update_asset_path) - print "Uploading update asset file at", update_asset_path, \ - "to s3://" + S3_BUCKET + "/" + LATEST_S3_PATH + "/" + update_asset_filename - s3.Object(S3_BUCKET, LATEST_S3_PATH + "/" + update_asset_filename).upload_file(update_asset_path) - - metadatafilepath = get_latest_file_path() - - if metadatafilepath is not None: - # For some reason latest-linux.yml isn't being created, but it's OK because updates don't - # work on Linux yet anyway. - metadatafilename = os.path.basename(metadatafilepath) - - print "Uploading update metadata file at", metadatafilepath, "to S3" - s3.Object(S3_BUCKET, LATEST_S3_PATH + "/" + metadatafilename).upload_file(metadatafilepath) - - def upload_to_github_if_tagged(repo_name): try: current_tag = subprocess.check_output( From bc15d24d66954d07b7f416146241d0bb3419ef1b Mon Sep 17 00:00:00 2001 From: Alex Liebowitz Date: Fri, 22 Dec 2017 01:42:04 -0500 Subject: [PATCH 14/34] Add ability to decline updates --- src/main/index.js | 2 ++ src/renderer/modal/modalAutoUpdateDownloaded/index.js | 7 ++++++- src/renderer/modal/modalAutoUpdateDownloaded/view.jsx | 5 +++++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/main/index.js b/src/main/index.js index e4c3e1ffb..eb5d53b6a 100644 --- a/src/main/index.js +++ b/src/main/index.js @@ -21,6 +21,8 @@ const isDevelopment = process.env.NODE_ENV === 'development'; // For now, log info messages in production for easier debugging of built apps log.transports.file.level = 'info'; +autoUpdater.autoDownload = true; + // Misc constants const LATEST_RELEASE_API_URL = 'https://api.github.com/repos/lbryio/lbry-app/releases/latest'; diff --git a/src/renderer/modal/modalAutoUpdateDownloaded/index.js b/src/renderer/modal/modalAutoUpdateDownloaded/index.js index 921271126..740a2dca2 100644 --- a/src/renderer/modal/modalAutoUpdateDownloaded/index.js +++ b/src/renderer/modal/modalAutoUpdateDownloaded/index.js @@ -1,5 +1,10 @@ import React from "react"; import { connect } from "react-redux"; +import { doCloseModal } from "redux/actions/app"; import ModalAutoUpdateDownloaded from "./view"; -export default connect(null, null)(ModalAutoUpdateDownloaded); +const perform = dispatch => ({ + closeModal: () => dispatch(doCloseModal()), +}); + +export default connect(null, perform)(ModalAutoUpdateDownloaded); diff --git a/src/renderer/modal/modalAutoUpdateDownloaded/view.jsx b/src/renderer/modal/modalAutoUpdateDownloaded/view.jsx index 2d136071a..39971118a 100644 --- a/src/renderer/modal/modalAutoUpdateDownloaded/view.jsx +++ b/src/renderer/modal/modalAutoUpdateDownloaded/view.jsx @@ -7,14 +7,19 @@ const { ipcRenderer } = require("electron"); class ModalAutoUpdateDownloaded extends React.PureComponent { render() { + const { closeModal } = this.props; + return ( { ipcRenderer.send("autoUpdate"); }} + onAborted={closeModal} >

{__("LBRY Leveled Up")}

From b08d96da1e942c7ad177dbacdda31ecac6f0a484 Mon Sep 17 00:00:00 2001 From: Alex Liebowitz Date: Tue, 2 Jan 2018 06:51:37 -0500 Subject: [PATCH 15/34] Add alert before close after update is declined on Windows --- src/main/index.js | 25 ++++++++++++++++++- src/renderer/constants/modal_types.js | 1 + src/renderer/index.js | 4 +-- .../modal/modalAutoUpdateDownloaded/index.js | 1 + src/renderer/modal/modalRouter/view.jsx | 3 +++ .../modal/modalUpdateCloseAlert/index.js | 12 +++++++++ .../modal/modalUpdateCloseAlert/view.jsx | 23 +++++++++++++++++ src/renderer/redux/actions/app.js | 4 +-- 8 files changed, 68 insertions(+), 5 deletions(-) create mode 100644 src/renderer/modal/modalUpdateCloseAlert/index.js create mode 100644 src/renderer/modal/modalUpdateCloseAlert/view.jsx diff --git a/src/main/index.js b/src/main/index.js index eb5d53b6a..e880d562c 100644 --- a/src/main/index.js +++ b/src/main/index.js @@ -48,6 +48,20 @@ let daemonSubprocess; // if it dies when we didn't ask it to shut down, we want to alert the user. let daemonStopRequested = false; +// This keeps track of whether a new file has been downloaded. We mostly +// handle auto-update stuff in the render process, but need to know this +// in order to display the extra confirmation dialog we show on close +// on Windows. +let updateDownloaded; +if (process.platform === 'win32') { + updateDownloaded = false; +} + +// This is used to keep track of whether we are showing he special dialog +// that we show on Windows after you decline an upgrade and close the app later. +let showingUpdateCloseAlert = false; + + // When a quit is attempted, we cancel the quit, do some preparations, then // this is set to true and app.quit() is called again to quit for real. let readyToQuit = false; @@ -406,6 +420,10 @@ if (isDevelopment) { }); } +autoUpdater.on('update-downloaded', () => { + updateDownloaded = true; +}); + app.setAsDefaultProtocolClient('lbry'); app.on('ready', () => { @@ -431,7 +449,12 @@ app.on('window-all-closed', () => { }); app.on('before-quit', event => { - if (!readyToQuit) { + if (process.platform === 'darwin' && updateDownloaded && !showingUpdateCloseAlert) { + // We haven't shown the special dialog that we show on Windows + // if the user declines an update and then quits later + rendererWindow.webContents.send('quitRequested'); + showingUpdateCloseAlert = true; + } else if (!readyToQuit) { // We need to shutdown the daemon before we're ready to actually quit. This // event will be triggered re-entrantly once preparation is done. event.preventDefault(); diff --git a/src/renderer/constants/modal_types.js b/src/renderer/constants/modal_types.js index 8e56e8237..aba7e21aa 100644 --- a/src/renderer/constants/modal_types.js +++ b/src/renderer/constants/modal_types.js @@ -3,6 +3,7 @@ export const INCOMPATIBLE_DAEMON = 'incompatibleDaemon'; export const FILE_TIMEOUT = 'file_timeout'; export const DOWNLOADING = 'downloading'; export const AUTO_UPDATE_DOWNLOADED = "auto_update_downloaded"; +export const UPDATE_CLOSE_ALERT = "updateCloseAlert"; export const ERROR = 'error'; export const INSUFFICIENT_CREDITS = 'insufficient_credits'; export const UPGRADE = 'upgrade'; diff --git a/src/renderer/index.js b/src/renderer/index.js index cafd41c35..cd9ab98ff 100644 --- a/src/renderer/index.js +++ b/src/renderer/index.js @@ -9,7 +9,7 @@ import lbry from 'lbry'; import React from 'react'; import ReactDOM from 'react-dom'; import { Provider } from 'react-redux'; -import { doConditionalAuthNavigate, doDaemonReady, doShowSnackBar, doAutoUpdate } from 'redux/actions/app'; +import { doConditionalAuthNavigate, doOpenModal, doDaemonReady, doShowSnackBar, doAutoUpdate } from 'redux/actions/app'; import { doNavigate } from 'redux/actions/navigation'; import { doDownloadLanguages } from 'redux/actions/settings'; import { doUserEmailVerify } from 'redux/actions/user'; @@ -62,7 +62,7 @@ ipcRenderer.on('window-is-focused', () => { dock.setBadge(''); }); -((history, ...args) => { +(function(history, ...args) { const { replaceState } = history; const newHistory = history; newHistory.replaceState = (_, __, path) => { diff --git a/src/renderer/modal/modalAutoUpdateDownloaded/index.js b/src/renderer/modal/modalAutoUpdateDownloaded/index.js index 740a2dca2..0ce6cdcbe 100644 --- a/src/renderer/modal/modalAutoUpdateDownloaded/index.js +++ b/src/renderer/modal/modalAutoUpdateDownloaded/index.js @@ -2,6 +2,7 @@ import React from "react"; import { connect } from "react-redux"; import { doCloseModal } from "redux/actions/app"; import ModalAutoUpdateDownloaded from "./view"; +import { doCloseModal } from "redux/actions/app"; const perform = dispatch => ({ closeModal: () => dispatch(doCloseModal()), diff --git a/src/renderer/modal/modalRouter/view.jsx b/src/renderer/modal/modalRouter/view.jsx index 81925c966..a8fa1dfbf 100644 --- a/src/renderer/modal/modalRouter/view.jsx +++ b/src/renderer/modal/modalRouter/view.jsx @@ -3,6 +3,7 @@ import ModalError from 'modal/modalError'; import ModalAuthFailure from 'modal/modalAuthFailure'; import ModalDownloading from 'modal/modalDownloading'; import ModalAutoUpdateDownloaded from "modal/modalAutoUpdateDownloaded"; +import ModalUpdateCloseAlert from "modal/modalUpdateCloseAlert"; import ModalUpgrade from 'modal/modalUpgrade'; import ModalWelcome from 'modal/modalWelcome'; import ModalFirstReward from 'modal/modalFirstReward'; @@ -105,6 +106,8 @@ class ModalRouter extends React.PureComponent { return ; case modals.AUTO_UPDATE_DOWNLOADED: return ; + case modals.UPDATE_CLOSE_ALERT: + return ; case modals.ERROR: return ; case modals.FILE_TIMEOUT: diff --git a/src/renderer/modal/modalUpdateCloseAlert/index.js b/src/renderer/modal/modalUpdateCloseAlert/index.js new file mode 100644 index 000000000..caff049a6 --- /dev/null +++ b/src/renderer/modal/modalUpdateCloseAlert/index.js @@ -0,0 +1,12 @@ +import React from 'react'; +import { connect } from 'react-redux'; +import { doQuit } from 'redux/actions/app'; +import ModalUpdateCloseAlert from './view'; + +const select = state => ({}); + +const perform = dispatch => ({ + quit: () => dispatch(doSkipUpgrade()), +}); + +export default connect(select, perform)(ModalUpdateCloseAlert); diff --git a/src/renderer/modal/modalUpdateCloseAlert/view.jsx b/src/renderer/modal/modalUpdateCloseAlert/view.jsx new file mode 100644 index 000000000..9f0b28c3a --- /dev/null +++ b/src/renderer/modal/modalUpdateCloseAlert/view.jsx @@ -0,0 +1,23 @@ +import React from 'react'; +import { Modal } from 'modal/modal'; +import Link from 'component/link'; + +class ModalUpdateCloseAlert extends React.PureComponent { + render() { + const { quit } = this.props; + + return ( + +

{__('LBRY Will Upgrade')}

+

{__('Please select yes to the upgrade prompt shown after the app closes.')}

+
+ ); + } +} + +export default ModalUpdateCloseAlert; diff --git a/src/renderer/redux/actions/app.js b/src/renderer/redux/actions/app.js index e2b36470b..8ae003bf7 100644 --- a/src/renderer/redux/actions/app.js +++ b/src/renderer/redux/actions/app.js @@ -110,8 +110,8 @@ export function doAutoUpdate() { return function(dispatch, getState) { const state = getState(); dispatch({ - type: types.OPEN_MODAL, - data: { modal: modals.AUTO_UPDATE_DOWNLOADED }, + type: ACTIONS.OPEN_MODAL, + data: { modal: MODALS.AUTO_UPDATE_DOWNLOADED }, }); }; } From b03623eb68ef7624c25539ea500c01183bd1f3bf Mon Sep 17 00:00:00 2001 From: Alex Liebowitz Date: Fri, 5 Jan 2018 01:29:31 -0500 Subject: [PATCH 16/34] Convert Windows update alert dialog to native dialog in main process Maybe a bit less polished, but I couldn't find a way to prevent the main window from closing that works on the current version of Electron, and in general it was starting to get too complicated. --- src/main/index.js | 49 ++++++++++--------- src/renderer/constants/modal_types.js | 1 - src/renderer/index.js | 4 +- .../modal/modalAutoUpdateDownloaded/index.js | 1 - .../modal/modalAutoUpdateDownloaded/view.jsx | 5 +- src/renderer/modal/modalRouter/view.jsx | 3 -- .../modal/modalUpdateCloseAlert/index.js | 12 ----- .../modal/modalUpdateCloseAlert/view.jsx | 23 --------- 8 files changed, 32 insertions(+), 66 deletions(-) delete mode 100644 src/renderer/modal/modalUpdateCloseAlert/index.js delete mode 100644 src/renderer/modal/modalUpdateCloseAlert/view.jsx diff --git a/src/main/index.js b/src/main/index.js index e880d562c..c5aed361f 100644 --- a/src/main/index.js +++ b/src/main/index.js @@ -8,7 +8,7 @@ import Https from 'https'; import Keytar from 'keytar'; import ChildProcess from 'child_process'; import Assert from 'assert'; -import { app, BrowserWindow, globalShortcut, ipcMain, Menu, Tray } from 'electron'; +import { app, dialog, BrowserWindow, globalShortcut, ipcMain, Menu, Tray } from 'electron'; import { autoUpdater } from 'electron-updater'; import log from 'electron-log'; import mainMenu from './menu/mainMenu'; @@ -48,18 +48,14 @@ let daemonSubprocess; // if it dies when we didn't ask it to shut down, we want to alert the user. let daemonStopRequested = false; -// This keeps track of whether a new file has been downloaded. We mostly -// handle auto-update stuff in the render process, but need to know this -// in order to display the extra confirmation dialog we show on close -// on Windows. -let updateDownloaded; -if (process.platform === 'win32') { - updateDownloaded = false; -} +// This keeps track of whether the user has declined an update that was downloaded +// through the Electron auto-update system. When the user declines an update on Windows, +// they will get a confusing dialog, so we show our own dialog first. +let autoUpdateDeclined = false; // This is used to keep track of whether we are showing he special dialog // that we show on Windows after you decline an upgrade and close the app later. -let showingUpdateCloseAlert = false; +let showingAutoUpdateCloseAlert = false; // When a quit is attempted, we cancel the quit, do some preparations, then @@ -420,10 +416,6 @@ if (isDevelopment) { }); } -autoUpdater.on('update-downloaded', () => { - updateDownloaded = true; -}); - app.setAsDefaultProtocolClient('lbry'); app.on('ready', () => { @@ -449,18 +441,25 @@ app.on('window-all-closed', () => { }); app.on('before-quit', event => { - if (process.platform === 'darwin' && updateDownloaded && !showingUpdateCloseAlert) { - // We haven't shown the special dialog that we show on Windows - // if the user declines an update and then quits later - rendererWindow.webContents.send('quitRequested'); - showingUpdateCloseAlert = true; - } else if (!readyToQuit) { + if (!readyToQuit) { // We need to shutdown the daemon before we're ready to actually quit. This // event will be triggered re-entrantly once preparation is done. event.preventDefault(); shutdownDaemonAndQuit(); - } else { - console.log('Quitting.'); + } else if (process.platform == 'win32' && autoUpdateDeclined && !showingAutoUpdateCloseAlert) { + // On Windows, if the user declined an update and closes the app later, + // they get a confusing permission escalation dialog, so we display a + // dialog to warn them. + event.preventDefault(); + showingAutoUpdateCloseAlert = true; + dialog.showMessageBox({ + type: "info", + title: "LBRY Will Upgrade", + message: "Please select \"Yes\" at the upgrade prompt shown after the app closes.", + }, () => { + // After the user approves the dialog, we can quit once and for all. + quitNow(); + }); } }); @@ -549,7 +548,11 @@ ipcMain.on('version-info-requested', () => { ipcMain.on('autoUpdate', () => { minimize = false; - autoUpdater.quitAndInstall(); + app.quit(); +}); + +ipcMain.on('autoUpdateDeclined', () => { + autoUpdateDeclined = true; }); ipcMain.on('get-auth-token', event => { diff --git a/src/renderer/constants/modal_types.js b/src/renderer/constants/modal_types.js index aba7e21aa..8e56e8237 100644 --- a/src/renderer/constants/modal_types.js +++ b/src/renderer/constants/modal_types.js @@ -3,7 +3,6 @@ export const INCOMPATIBLE_DAEMON = 'incompatibleDaemon'; export const FILE_TIMEOUT = 'file_timeout'; export const DOWNLOADING = 'downloading'; export const AUTO_UPDATE_DOWNLOADED = "auto_update_downloaded"; -export const UPDATE_CLOSE_ALERT = "updateCloseAlert"; export const ERROR = 'error'; export const INSUFFICIENT_CREDITS = 'insufficient_credits'; export const UPGRADE = 'upgrade'; diff --git a/src/renderer/index.js b/src/renderer/index.js index cd9ab98ff..cafd41c35 100644 --- a/src/renderer/index.js +++ b/src/renderer/index.js @@ -9,7 +9,7 @@ import lbry from 'lbry'; import React from 'react'; import ReactDOM from 'react-dom'; import { Provider } from 'react-redux'; -import { doConditionalAuthNavigate, doOpenModal, doDaemonReady, doShowSnackBar, doAutoUpdate } from 'redux/actions/app'; +import { doConditionalAuthNavigate, doDaemonReady, doShowSnackBar, doAutoUpdate } from 'redux/actions/app'; import { doNavigate } from 'redux/actions/navigation'; import { doDownloadLanguages } from 'redux/actions/settings'; import { doUserEmailVerify } from 'redux/actions/user'; @@ -62,7 +62,7 @@ ipcRenderer.on('window-is-focused', () => { dock.setBadge(''); }); -(function(history, ...args) { +((history, ...args) => { const { replaceState } = history; const newHistory = history; newHistory.replaceState = (_, __, path) => { diff --git a/src/renderer/modal/modalAutoUpdateDownloaded/index.js b/src/renderer/modal/modalAutoUpdateDownloaded/index.js index 0ce6cdcbe..740a2dca2 100644 --- a/src/renderer/modal/modalAutoUpdateDownloaded/index.js +++ b/src/renderer/modal/modalAutoUpdateDownloaded/index.js @@ -2,7 +2,6 @@ import React from "react"; import { connect } from "react-redux"; import { doCloseModal } from "redux/actions/app"; import ModalAutoUpdateDownloaded from "./view"; -import { doCloseModal } from "redux/actions/app"; const perform = dispatch => ({ closeModal: () => dispatch(doCloseModal()), diff --git a/src/renderer/modal/modalAutoUpdateDownloaded/view.jsx b/src/renderer/modal/modalAutoUpdateDownloaded/view.jsx index 39971118a..ac347d7c5 100644 --- a/src/renderer/modal/modalAutoUpdateDownloaded/view.jsx +++ b/src/renderer/modal/modalAutoUpdateDownloaded/view.jsx @@ -19,7 +19,10 @@ class ModalAutoUpdateDownloaded extends React.PureComponent { onConfirmed={() => { ipcRenderer.send("autoUpdate"); }} - onAborted={closeModal} + onAborted={() => { + ipcRenderer.send("autoUpdateDeclined"); + closeModal(); + }} >

{__("LBRY Leveled Up")}

diff --git a/src/renderer/modal/modalRouter/view.jsx b/src/renderer/modal/modalRouter/view.jsx index a8fa1dfbf..81925c966 100644 --- a/src/renderer/modal/modalRouter/view.jsx +++ b/src/renderer/modal/modalRouter/view.jsx @@ -3,7 +3,6 @@ import ModalError from 'modal/modalError'; import ModalAuthFailure from 'modal/modalAuthFailure'; import ModalDownloading from 'modal/modalDownloading'; import ModalAutoUpdateDownloaded from "modal/modalAutoUpdateDownloaded"; -import ModalUpdateCloseAlert from "modal/modalUpdateCloseAlert"; import ModalUpgrade from 'modal/modalUpgrade'; import ModalWelcome from 'modal/modalWelcome'; import ModalFirstReward from 'modal/modalFirstReward'; @@ -106,8 +105,6 @@ class ModalRouter extends React.PureComponent { return ; case modals.AUTO_UPDATE_DOWNLOADED: return ; - case modals.UPDATE_CLOSE_ALERT: - return ; case modals.ERROR: return ; case modals.FILE_TIMEOUT: diff --git a/src/renderer/modal/modalUpdateCloseAlert/index.js b/src/renderer/modal/modalUpdateCloseAlert/index.js deleted file mode 100644 index caff049a6..000000000 --- a/src/renderer/modal/modalUpdateCloseAlert/index.js +++ /dev/null @@ -1,12 +0,0 @@ -import React from 'react'; -import { connect } from 'react-redux'; -import { doQuit } from 'redux/actions/app'; -import ModalUpdateCloseAlert from './view'; - -const select = state => ({}); - -const perform = dispatch => ({ - quit: () => dispatch(doSkipUpgrade()), -}); - -export default connect(select, perform)(ModalUpdateCloseAlert); diff --git a/src/renderer/modal/modalUpdateCloseAlert/view.jsx b/src/renderer/modal/modalUpdateCloseAlert/view.jsx deleted file mode 100644 index 9f0b28c3a..000000000 --- a/src/renderer/modal/modalUpdateCloseAlert/view.jsx +++ /dev/null @@ -1,23 +0,0 @@ -import React from 'react'; -import { Modal } from 'modal/modal'; -import Link from 'component/link'; - -class ModalUpdateCloseAlert extends React.PureComponent { - render() { - const { quit } = this.props; - - return ( - -

{__('LBRY Will Upgrade')}

-

{__('Please select yes to the upgrade prompt shown after the app closes.')}

-
- ); - } -} - -export default ModalUpdateCloseAlert; From 3959d4aeee7ad91735865f3498aedf1009868f07 Mon Sep 17 00:00:00 2001 From: Alex Liebowitz Date: Mon, 8 Jan 2018 15:43:25 -0500 Subject: [PATCH 17/34] Make app restart after user approves update Forgot to call quitAndInstall(). If you don't, it will still install the update, but won't restart. --- src/main/index.js | 57 ++++++++++++------- .../modal/modalAutoUpdateDownloaded/view.jsx | 2 +- 2 files changed, 36 insertions(+), 23 deletions(-) diff --git a/src/main/index.js b/src/main/index.js index c5aed361f..5d6b4b451 100644 --- a/src/main/index.js +++ b/src/main/index.js @@ -48,10 +48,14 @@ let daemonSubprocess; // if it dies when we didn't ask it to shut down, we want to alert the user. let daemonStopRequested = false; -// This keeps track of whether the user has declined an update that was downloaded -// through the Electron auto-update system. When the user declines an update on Windows, -// they will get a confusing dialog, so we show our own dialog first. -let autoUpdateDeclined = false; + +// This is set to true if an auto update has been downloaded through the Electron +// auto-update system and is ready to install. If the user declined an update earlier, +// it will still install on shutdown. +let autoUpdateDownloaded = false; + +// Keeps track of whether the user has accepted an auto-update through the interface. +let autoUpdateAccepted = false; // This is used to keep track of whether we are showing he special dialog // that we show on Windows after you decline an upgrade and close the app later. @@ -446,20 +450,26 @@ app.on('before-quit', event => { // event will be triggered re-entrantly once preparation is done. event.preventDefault(); shutdownDaemonAndQuit(); - } else if (process.platform == 'win32' && autoUpdateDeclined && !showingAutoUpdateCloseAlert) { - // On Windows, if the user declined an update and closes the app later, - // they get a confusing permission escalation dialog, so we display a - // dialog to warn them. - event.preventDefault(); - showingAutoUpdateCloseAlert = true; - dialog.showMessageBox({ - type: "info", - title: "LBRY Will Upgrade", - message: "Please select \"Yes\" at the upgrade prompt shown after the app closes.", - }, () => { - // After the user approves the dialog, we can quit once and for all. - quitNow(); - }); + } else if (autoUpdateDownloaded) { + if (autoUpdateAccepted) { + // User accepted the update, so install the update and restart. + autoUpdater.quitAndInstall(); + } else if (process.platform == 'win32' && !showingAutoUpdateCloseAlert) { + // We have an update downloaded, but the user declined it (or closed the app without + // accepting it). Now the user is closing the app, so the new update will install. + // On Mac this is silent, but on Windows they get a confusing permission escalation + // dialog, so we show Windows users a warning dialog first. + event.preventDefault(); + showingAutoUpdateCloseAlert = true; + dialog.showMessageBox({ + type: "info", + title: "LBRY Will Upgrade", + message: "Please select \"Yes\" at the upgrade prompt shown after the app closes.", + }, () => { + // After the user approves the dialog, we can quit once and for all. + quitNow(); + }); + } } }); @@ -546,14 +556,17 @@ ipcMain.on('version-info-requested', () => { }); }); -ipcMain.on('autoUpdate', () => { + +autoUpdater.on('update-downloaded', () => { + autoUpdateDownloaded = true; +}); + +ipcMain.on('autoUpdateAccepted', () => { + autoUpdateAccepted = true; minimize = false; app.quit(); }); -ipcMain.on('autoUpdateDeclined', () => { - autoUpdateDeclined = true; -}); ipcMain.on('get-auth-token', event => { Keytar.getPassword('LBRY', 'auth_token').then(token => { diff --git a/src/renderer/modal/modalAutoUpdateDownloaded/view.jsx b/src/renderer/modal/modalAutoUpdateDownloaded/view.jsx index ac347d7c5..a5b4cb722 100644 --- a/src/renderer/modal/modalAutoUpdateDownloaded/view.jsx +++ b/src/renderer/modal/modalAutoUpdateDownloaded/view.jsx @@ -17,7 +17,7 @@ class ModalAutoUpdateDownloaded extends React.PureComponent { confirmButtonLabel={__("Update and Restart")} abortButtonLabel={__("Don't Update")} onConfirmed={() => { - ipcRenderer.send("autoUpdate"); + ipcRenderer.send("autoUpdateAccepted"); }} onAborted={() => { ipcRenderer.send("autoUpdateDeclined"); From cf3406f926d93e59720e837c39fb358592b76ea3 Mon Sep 17 00:00:00 2001 From: Alex Liebowitz Date: Mon, 8 Jan 2018 15:53:48 -0500 Subject: [PATCH 18/34] Remove icon from the Windows auto-update alert dialog shown on closing --- src/main/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/index.js b/src/main/index.js index 5d6b4b451..bc7945245 100644 --- a/src/main/index.js +++ b/src/main/index.js @@ -463,7 +463,7 @@ app.on('before-quit', event => { showingAutoUpdateCloseAlert = true; dialog.showMessageBox({ type: "info", - title: "LBRY Will Upgrade", + title: "LBRY will upgrade", message: "Please select \"Yes\" at the upgrade prompt shown after the app closes.", }, () => { // After the user approves the dialog, we can quit once and for all. From fb8aee46323d659c7f77c97de41a4940168d514b Mon Sep 17 00:00:00 2001 From: Alex Liebowitz Date: Mon, 8 Jan 2018 15:57:13 -0500 Subject: [PATCH 19/34] Version 0.31 [temp, for testing] --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8cd6c8cb0..3951c7723 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "LBRY", - "version": "0.19.4", + "version": "0.31.0", "description": "A browser for the LBRY network, a digital marketplace controlled by its users.", "homepage": "https://lbry.io/", "bugs": { From 5a475f4ba458f1a5a6c2a0575181a5e02b7a2fbd Mon Sep 17 00:00:00 2001 From: Alex Liebowitz Date: Mon, 8 Jan 2018 15:57:49 -0500 Subject: [PATCH 20/34] Version 0.32 [temp, for testing] --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 3951c7723..ab612689e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "LBRY", - "version": "0.31.0", + "version": "0.32.0", "description": "A browser for the LBRY network, a digital marketplace controlled by its users.", "homepage": "https://lbry.io/", "bugs": { From 0c8ba50207553fbd27caae183feb3974c7007548 Mon Sep 17 00:00:00 2001 From: Alex Liebowitz Date: Fri, 12 Jan 2018 22:18:55 -0500 Subject: [PATCH 21/34] Update Auto Update-related copy --- src/main/index.js | 6 +++--- src/renderer/modal/modalAutoUpdateDownloaded/view.jsx | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/index.js b/src/main/index.js index bc7945245..b3330c129 100644 --- a/src/main/index.js +++ b/src/main/index.js @@ -462,9 +462,9 @@ app.on('before-quit', event => { event.preventDefault(); showingAutoUpdateCloseAlert = true; dialog.showMessageBox({ - type: "info", - title: "LBRY will upgrade", - message: "Please select \"Yes\" at the upgrade prompt shown after the app closes.", + type: 'info', + title: 'LBRY Will Upgrade', + message: 'LBRY has a pending upgrade. Please select "Yes" to install it on the prompt shown after this one.', }, () => { // After the user approves the dialog, we can quit once and for all. quitNow(); diff --git a/src/renderer/modal/modalAutoUpdateDownloaded/view.jsx b/src/renderer/modal/modalAutoUpdateDownloaded/view.jsx index a5b4cb722..12aa2d819 100644 --- a/src/renderer/modal/modalAutoUpdateDownloaded/view.jsx +++ b/src/renderer/modal/modalAutoUpdateDownloaded/view.jsx @@ -13,9 +13,9 @@ class ModalAutoUpdateDownloaded extends React.PureComponent { { ipcRenderer.send("autoUpdateAccepted"); }} @@ -28,7 +28,7 @@ class ModalAutoUpdateDownloaded extends React.PureComponent {

{__("LBRY Leveled Up")}

{__( - "A new version of LBRY has been downloaded and is ready to install." + 'A new version of LBRY has been released, downloaded, and is ready for you to use pending a restart.' )}

From f244f9035bcd5d55750dd486e7ffdf0fcb7ea0f3 Mon Sep 17 00:00:00 2001 From: Alex Liebowitz Date: Tue, 16 Jan 2018 00:38:23 -0500 Subject: [PATCH 22/34] Add back "Upgrade App" button on Mac/Win with different dialog on click --- src/renderer/component/header/index.js | 7 ++-- src/renderer/component/header/view.jsx | 7 ++-- src/renderer/constants/action_types.js | 1 + src/renderer/constants/modal_types.js | 1 + .../modal/modalAutoUpdateConfirm/index.js | 10 +++++ .../modal/modalAutoUpdateConfirm/view.jsx | 39 +++++++++++++++++++ src/renderer/modal/modalRouter/view.jsx | 3 ++ src/renderer/redux/actions/app.js | 24 ++++++++++++ src/renderer/redux/reducers/app.js | 6 +++ src/renderer/redux/selectors/app.js | 2 + 10 files changed, 94 insertions(+), 6 deletions(-) create mode 100644 src/renderer/modal/modalAutoUpdateConfirm/index.js create mode 100644 src/renderer/modal/modalAutoUpdateConfirm/view.jsx diff --git a/src/renderer/component/header/index.js b/src/renderer/component/header/index.js index f25257214..59c98d0ff 100644 --- a/src/renderer/component/header/index.js +++ b/src/renderer/component/header/index.js @@ -5,13 +5,14 @@ import { selectIsBackDisabled, selectIsForwardDisabled } from 'redux/selectors/n import { selectBalance } from 'redux/selectors/wallet'; import { doNavigate, doHistoryBack, doHistoryForward } from 'redux/actions/navigation'; import Header from './view'; -import { selectIsUpgradeAvailable } from 'redux/selectors/app'; -import { doDownloadUpgrade } from 'redux/actions/app'; +import { selectIsUpgradeAvailable, selectAutoUpdateDownloaded } from 'redux/selectors/app'; +import { doDownloadUpgradeRequested } from 'redux/actions/app'; const select = state => ({ isBackDisabled: selectIsBackDisabled(state), isForwardDisabled: selectIsForwardDisabled(state), isUpgradeAvailable: selectIsUpgradeAvailable(state), + autoUpdateDownloaded: selectAutoUpdateDownloaded(state), balance: formatCredits(selectBalance(state) || 0, 2), }); @@ -19,7 +20,7 @@ const perform = dispatch => ({ navigate: path => dispatch(doNavigate(path)), back: () => dispatch(doHistoryBack()), forward: () => dispatch(doHistoryForward()), - downloadUpgrade: () => dispatch(doDownloadUpgrade()), + downloadUpgradeRequested: () => dispatch(doDownloadUpgradeRequested()), }); export default connect(select, perform)(Header); diff --git a/src/renderer/component/header/view.jsx b/src/renderer/component/header/view.jsx index c1289c889..7109d7b8b 100644 --- a/src/renderer/component/header/view.jsx +++ b/src/renderer/component/header/view.jsx @@ -10,8 +10,9 @@ export const Header = props => { isBackDisabled, isForwardDisabled, isUpgradeAvailable, + autoUpdateDownloaded, navigate, - downloadUpgrade, + downloadUpgradeRequested, } = props; return (
); From 8c0bf32fe52b0762d7f1210d72735823fe30d3d2 Mon Sep 17 00:00:00 2001 From: Alex Liebowitz Date: Tue, 23 Jan 2018 19:46:49 -0500 Subject: [PATCH 31/34] Small changes to prepare auto update for release --- package.json | 1 + src/main/index.js | 7 +++---- src/renderer/index.js | 1 + 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 45f9687f1..42d1dce3a 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "dev": "electron-webpack dev", "compile": "electron-webpack && yarn extract-langs", "build": "yarn compile && electron-builder build", + "build:dir": "yarn build -- --dir -c.compression=store -c.mac.identity=null", "postinstall": "electron-builder install-app-deps", "postmerge": "yarnhook", "postcheckout": "yarnhook", diff --git a/src/main/index.js b/src/main/index.js index 22de0ce76..16f9648aa 100644 --- a/src/main/index.js +++ b/src/main/index.js @@ -6,7 +6,6 @@ import url from 'url'; import https from 'https'; import { shell, app, ipcMain, dialog } from 'electron'; import { autoUpdater } from 'electron-updater'; -import log from 'electron-log'; import Daemon from './Daemon'; import Tray from './Tray'; import createWindow from './createWindow'; @@ -23,7 +22,7 @@ let autoUpdateDownloaded = false; // Keeps track of whether the user has accepted an auto-update through the interface. let autoUpdateAccepted = false; -// This is used to keep track of whether we are showing he special dialog +// This is used to keep track of whether we are showing the special dialog // that we show on Windows after you decline an upgrade and close the app later. let showingAutoUpdateCloseAlert = false; @@ -86,7 +85,7 @@ app.on('activate', () => { if (!rendererWindow) rendererWindow = createWindow(); }); -app.on('will-quit', (e) => { +app.on('will-quit', (event) => { if (process.platform === 'win32' && autoUpdateDownloaded && !autoUpdateAccepted && !showingAutoUpdateCloseAlert) { // We're on Win and have an update downloaded, but the user declined it (or closed // the app without accepting it). Now the user is closing the app, so the new update @@ -102,7 +101,7 @@ app.on('will-quit', (e) => { app.quit(); }); - e.preventDefault(); + event.preventDefault(); return; } diff --git a/src/renderer/index.js b/src/renderer/index.js index 5ee4a84bf..bcf092707 100644 --- a/src/renderer/index.js +++ b/src/renderer/index.js @@ -10,6 +10,7 @@ import React from 'react'; import ReactDOM from 'react-dom'; import { Provider } from 'react-redux'; import { doConditionalAuthNavigate, doDaemonReady, doShowSnackBar, doAutoUpdate } from 'redux/actions/app'; +import { doUpdateIsNightAsync } from 'redux/actions/settings'; import { doNavigate } from 'redux/actions/navigation'; import { doDownloadLanguages } from 'redux/actions/settings'; import { doUserEmailVerify } from 'redux/actions/user'; From eef3f6a816c63b0bf449a7bc6959a06ea9b610bf Mon Sep 17 00:00:00 2001 From: Alex Liebowitz Date: Tue, 23 Jan 2018 20:09:30 -0500 Subject: [PATCH 32/34] Restore version number with -dev suffix (needed for new build process) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b02867682..00ae8ed48 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "LBRY", - "version": "0.3.0", + "version": "0.19.4-dev", "description": "A browser for the LBRY network, a digital marketplace controlled by its users.", "homepage": "https://lbry.io/", "bugs": { From 76f6b1efa94f74849a2233a708a8ff299aab6b14 Mon Sep 17 00:00:00 2001 From: Alex Liebowitz Date: Tue, 23 Jan 2018 20:30:58 -0500 Subject: [PATCH 33/34] Remove remaining traces of logging code from main/index.js We might need this later, but right now no logging is happening here. --- src/main/index.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/index.js b/src/main/index.js index 16f9648aa..6894ee5a1 100644 --- a/src/main/index.js +++ b/src/main/index.js @@ -10,8 +10,6 @@ import Daemon from './Daemon'; import Tray from './Tray'; import createWindow from './createWindow'; -// For now, log info messages in production for easier debugging -log.transports.file.level = ''; autoUpdater.autoDownload = true; // This is set to true if an auto update has been downloaded through the Electron From e98231fed37fcf111707fd534635384234af89e5 Mon Sep 17 00:00:00 2001 From: Alex Liebowitz Date: Wed, 24 Jan 2018 15:42:49 -0500 Subject: [PATCH 34/34] Don't show auto-update dialog after decline on Win/Mac --- src/renderer/redux/actions/app.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/renderer/redux/actions/app.js b/src/renderer/redux/actions/app.js index ef79a0f6a..0d94fe4d4 100644 --- a/src/renderer/redux/actions/app.js +++ b/src/renderer/redux/actions/app.js @@ -198,8 +198,13 @@ export function doCheckUpgradeAvailable() { }); if (["win32", "darwin"].includes(process.platform)) { - // On Windows and Mac, updates happen silently - autoUpdater.checkForUpdates(); + // On Windows and Mac, updates happen silently through + // electron-updater. + const autoUpdateDeclined = selectAutoUpdateDeclined(state); + + if (!autoUpdateDeclined) { + autoUpdater.checkForUpdates(); + } return; }