From 5c5e736137927d16fb503d722ca64fe33fcb54c4 Mon Sep 17 00:00:00 2001 From: Sean Yesmunt Date: Thu, 8 Nov 2018 14:48:38 -0500 Subject: [PATCH 1/2] handle daemon startup errors --- flow-typed/i18n.js | 2 +- src/renderer/component/common/tooltip.jsx | 13 ++-- .../component/splash/internal/load-screen.jsx | 49 +++++++++--- src/renderer/component/splash/view.jsx | 75 +++++++++++++++---- src/renderer/scss/component/_button.scss | 10 +++ src/renderer/scss/component/_load-screen.scss | 7 +- src/renderer/types/status.js | 48 ++++++++++++ yarn.lock | 37 ++++++--- 8 files changed, 197 insertions(+), 44 deletions(-) create mode 100644 src/renderer/types/status.js diff --git a/flow-typed/i18n.js b/flow-typed/i18n.js index cbceb4b59..d65657ff9 100644 --- a/flow-typed/i18n.js +++ b/flow-typed/i18n.js @@ -1 +1 @@ -declare function __(a: string): string; +declare function __(a: string, b?: string | number): string; diff --git a/src/renderer/component/common/tooltip.jsx b/src/renderer/component/common/tooltip.jsx index d77d8dd27..5d5aacadc 100644 --- a/src/renderer/component/common/tooltip.jsx +++ b/src/renderer/component/common/tooltip.jsx @@ -22,7 +22,6 @@ class ToolTip extends React.PureComponent { constructor(props: Props) { super(props); - this.tooltip = React.createRef(); this.state = { direction: this.props.direction, }; @@ -33,11 +32,11 @@ class ToolTip extends React.PureComponent { } getVisibility = () => { - if (!this.tooltip.current) { + if (!this.tooltip) { return; } - const node = this.tooltip.current; + const node = this.tooltip; const rect = node.getBoundingClientRect(); // Get parent-container @@ -80,12 +79,12 @@ class ToolTip extends React.PureComponent { const visibility = this.getVisibility(); // Invert direction if tooltip is outside viewport bounds - if (!visibility[direction]) { + if (!visibility || !visibility[direction]) { this.invertDirection(); } }; - tooltip: { current: null | HTMLSpanElement }; + tooltip: ?HTMLSpanElement; render() { const { direction } = this.state; @@ -111,7 +110,9 @@ class ToolTip extends React.PureComponent { > {tooltipContent} { + this.tooltip = ref; + }} className={classnames('tooltip__body', { 'tooltip__body--short': isShortDescription, })} diff --git a/src/renderer/component/splash/internal/load-screen.jsx b/src/renderer/component/splash/internal/load-screen.jsx index 97d141c9a..0b0ff209d 100644 --- a/src/renderer/component/splash/internal/load-screen.jsx +++ b/src/renderer/component/splash/internal/load-screen.jsx @@ -1,13 +1,15 @@ // @flow -import * as React from 'react'; +import React, { Fragment } from 'react'; import Icon from 'component/common/icon'; import * as icons from 'constants/icons'; import Spinner from 'component/spinner'; +import Button from 'component/button'; type Props = { message: string, details: ?string, isWarning: boolean, + error: boolean, }; class LoadScreen extends React.PureComponent { @@ -16,7 +18,7 @@ class LoadScreen extends React.PureComponent { }; render() { - const { details, message, isWarning } = this.props; + const { details, message, isWarning, error } = this.props; return (
@@ -24,17 +26,42 @@ class LoadScreen extends React.PureComponent {

{__('LBRY')}

beta
- {isWarning ? ( - - - {` ${message}`} - + {error ? ( + +

{__('Uh oh. Sean must have messed something up. Try refreshing to fix it.')}

+
+
+
+

+ {__( + 'If you still have issues, your anti-virus software or firewall may be preventing startup.' + )} +

+

+ {__('Reach out to hello@lbry.io for help, or check out')}{' '} +

+
) : ( -
{message}
+ + {isWarning ? ( + + + {` ${message}`} + + ) : ( +
{message}
+ )} + {details &&
{details}
} + +
)} - - {details &&
{details}
} - ); } diff --git a/src/renderer/component/splash/view.jsx b/src/renderer/component/splash/view.jsx index 708dc731a..df8fe6113 100644 --- a/src/renderer/component/splash/view.jsx +++ b/src/renderer/component/splash/view.jsx @@ -1,4 +1,5 @@ // @flow +import type { Status } from 'types/status'; import * as React from 'react'; import { Lbry, MODALS } from 'lbry-redux'; import ModalWalletUnlock from 'modal/modalWalletUnlock'; @@ -7,6 +8,8 @@ import ModalUpgrade from 'modal/modalUpgrade'; import ModalDownloading from 'modal/modalDownloading'; import LoadScreen from './internal/load-screen'; +const ONE_MINUTE = 60 * 1000; + type Props = { checkDaemonVersion: () => Promise, notifyUnlockWallet: () => Promise, @@ -23,6 +26,7 @@ type State = { message: string, isRunning: boolean, launchedModal: boolean, + error: boolean, }; export class SplashScreen extends React.PureComponent { @@ -34,14 +38,17 @@ export class SplashScreen extends React.PureComponent { message: __('Connecting'), isRunning: false, launchedModal: false, + error: false, }; this.hasRecordedUser = false; + this.timeout = undefined; } componentDidMount() { const { checkDaemonVersion } = this.props; + this.adjustErrorTimeout(); Lbry.connect() .then(checkDaemonVersion) .then(() => { @@ -57,22 +64,54 @@ export class SplashScreen extends React.PureComponent { }); } + componentDidUpdate() { + this.adjustErrorTimeout(); + } + + componentWillUnmount() { + if (this.timeout) { + clearTimeout(this.timeout); + } + } + + adjustErrorTimeout() { + if (this.timeout) { + clearTimeout(this.timeout); + } + + // Every time we make it to a new step in the daemon startup process, reset the timer + // If nothing changes after 1 minute, show the error message. + this.timeout = setTimeout(() => { + this.setState({ error: true }); + }, ONE_MINUTE); + } + updateStatus() { Lbry.status().then(status => { this.updateStatusCallback(status); }); } - updateStatusCallback(status) { + updateStatusCallback(status: Status) { const { notifyUnlockWallet, authenticate } = this.props; const { launchedModal } = this.state; + if (status.error) { + this.setState({ + error: true, + }); + return; + } + if (!this.hasRecordedUser && status) { authenticate(); this.hasRecordedUser = true; } - if (status.wallet && status.wallet.is_locked) { + const { wallet, blockchain_headers: blockchainHeaders } = status; + + // If the wallet is locked, stop doing anything and make the user input their password + if (wallet && wallet.is_locked) { this.setState({ isRunning: true, }); @@ -97,43 +136,49 @@ export class SplashScreen extends React.PureComponent { this.props.onReadyToLaunch(); } }); + return; - } else if (status.blockchain_headers && status.blockchain_headers.download_progress < 100) { + } else if (blockchainHeaders) { + const blockChainHeaders = blockchainHeaders; + if (blockChainHeaders.download_progress < 100) { + this.setState({ + message: __('Blockchain Sync'), + details: `${__('Catching up with the blockchain')} (${ + blockchainHeaders.download_progress + }%)`, + }); + } + } else if (wallet && wallet.blocks_behind > 0) { + const format = wallet.blocks_behind === 1 ? '%s block behind' : '%s blocks behind'; this.setState({ message: __('Blockchain Sync'), - details: `${__('Catching up with the blockchain')} (${ - status.blockchain_headers.download_progress - }%)`, + details: __(format, wallet.blocks_behind), }); - } else if (status.wallet && status.wallet.blocks_behind > 0) { - const format = status.wallet.blocks_behind === 1 ? '%s block behind' : '%s blocks behind'; - this.setState({ - message: __('Blockchain Sync'), - details: __(format, status.wallet.blocks_behind), - }); - } else if (status.wallet && status.wallet.blocks_behind === 0) { + } else if (wallet && wallet.blocks_behind === 0) { this.setState({ message: 'Network Loading', details: 'Initializing LBRY service...', }); } + setTimeout(() => { this.updateStatus(); }, 500); } hasRecordedUser: boolean; + timeout: ?TimeoutID; render() { const { notification } = this.props; - const { message, details, isRunning } = this.state; + const { message, details, isRunning, error } = this.state; const notificationId = notification && notification.id; // {notificationId === MODALS.WALLET_UNLOCK && } return ( - + {/* Temp hack: don't show any modals on splash screen daemon is running; daemon doesn't let you quit during startup, so the "Quit" buttons in the modals won't work. */} diff --git a/src/renderer/scss/component/_button.scss b/src/renderer/scss/component/_button.scss index a12d1a77e..a59807421 100644 --- a/src/renderer/scss/component/_button.scss +++ b/src/renderer/scss/component/_button.scss @@ -183,6 +183,16 @@ text-transform: uppercase; } + &.btn--load-screen { + display: inline-block; + border-bottom: 1px solid $lbry-white; + + &:hover { + color: $lbry-blue-1; + border-bottom: 1px solid $lbry-blue-1; + } + } + .icon + .btn__label { padding-left: 5px; } diff --git a/src/renderer/scss/component/_load-screen.scss b/src/renderer/scss/component/_load-screen.scss index 51c3e5a33..7eab0e9bb 100644 --- a/src/renderer/scss/component/_load-screen.scss +++ b/src/renderer/scss/component/_load-screen.scss @@ -8,11 +8,11 @@ color: $lbry-white; display: flex; flex-direction: column; - justify-content: center; } .load-screen__header { display: flex; + margin-top: 35vh; } .load-screen__title { @@ -41,3 +41,8 @@ max-width: 400px; padding-top: $spacing-vertical * 2/3; } + +.load-screen--help { + font-size: 14px; + padding-top: $spacing-vertical; +} diff --git a/src/renderer/types/status.js b/src/renderer/types/status.js new file mode 100644 index 000000000..87c3e777e --- /dev/null +++ b/src/renderer/types/status.js @@ -0,0 +1,48 @@ +// @flow + +export type Status = { + error?: {}, + is_running: boolean, + is_first_run: boolean, + installation_id: string, + skipped_components: Array, + startup_status: { + blob_manager: boolean, + blockchain_headers: boolean, + database: boolean, + dht: boolean, + exchange_rate_manager: boolean, + file_manager: boolean, + hash_announcer: boolean, + payment_rate_manager: boolean, + peer_protocol_server: boolean, + rate_limiter: boolean, + stream_identifier: boolean, + upnp: boolean, + wallet: boolean, + }, + blob_manager: { + finished_blobs: number, + }, + connection_status: { + code: string, + message: string, + }, + dht: { + node_id: string, + peers_in_routing_table: number, + }, + hash_announcer: { + announce_queue_size: number, + }, + wallet?: { + best_blockhash: string, + blocks: number, + blocks_behind: number, + is_encrypted: boolean, + is_locked: boolean, + }, + blockchain_headers?: { + download_progress: number, + }, +}; diff --git a/yarn.lock b/yarn.lock index 3b0cfe49c..dddccddab 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2247,7 +2247,7 @@ copy-descriptor@^0.1.0: core-js@^1.0.0: version "1.2.7" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636" + resolved "http://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636" core-js@^2.4.0, core-js@^2.5.0: version "2.5.7" @@ -4076,7 +4076,7 @@ flatten@^1.0.2: flow-bin@^0.69.0: version "0.69.0" - resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.69.0.tgz#053159a684a6051fcbf0b71a2eb19a9679082da6" + resolved "http://registry.npmjs.org/flow-bin/-/flow-bin-0.69.0.tgz#053159a684a6051fcbf0b71a2eb19a9679082da6" flow-typed@^2.3.0: version "2.5.1" @@ -4870,12 +4870,18 @@ iconv-lite@0.4.19: version "0.4.19" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" -iconv-lite@^0.4.17, iconv-lite@^0.4.23, iconv-lite@^0.4.4, iconv-lite@^0.4.5, iconv-lite@~0.4.13: +iconv-lite@^0.4.17, iconv-lite@^0.4.23, iconv-lite@^0.4.4, iconv-lite@^0.4.5: version "0.4.23" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63" dependencies: safer-buffer ">= 2.1.2 < 3" +iconv-lite@~0.4.13: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + dependencies: + safer-buffer ">= 2.1.2 < 3" + icss-replace-symbols@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz#06ea6f83679a7749e386cfe1fe812ae5db223ded" @@ -7899,13 +7905,13 @@ react@^0.14.5: fbjs "^0.6.1" react@^16.3.0: - version "16.4.1" - resolved "https://registry.yarnpkg.com/react/-/react-16.4.1.tgz#de51ba5764b5dbcd1f9079037b862bd26b82fe32" + version "16.6.1" + resolved "https://registry.yarnpkg.com/react/-/react-16.6.1.tgz#ee2aef4f0a09e494594882029821049772f915fe" dependencies: - fbjs "^0.8.16" loose-envify "^1.1.0" object-assign "^4.1.1" - prop-types "^15.6.0" + prop-types "^15.6.2" + scheduler "^0.11.0" read-config-file@3.1.0, read-config-file@^3.0.0: version "3.1.0" @@ -8498,6 +8504,13 @@ sax@~1.1.1: version "1.1.6" resolved "https://registry.yarnpkg.com/sax/-/sax-1.1.6.tgz#5d616be8a5e607d54e114afae55b7eaf2fcc3240" +scheduler@^0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.11.0.tgz#def1f1bfa6550cc57981a87106e65e8aea41a6b5" + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + schema-utils@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-0.3.0.tgz#f5877222ce3e931edae039f17eb3716e7137f8cf" @@ -9561,7 +9574,11 @@ typo-js@*: version "1.0.3" resolved "https://registry.yarnpkg.com/typo-js/-/typo-js-1.0.3.tgz#54d8ebc7949f1a7810908b6002c6841526c99d5a" -ua-parser-js@^0.7.18, ua-parser-js@^0.7.9: +ua-parser-js@^0.7.18: + version "0.7.19" + resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.19.tgz#94151be4c0a7fb1d001af7022fdaca4642659e4b" + +ua-parser-js@^0.7.9: version "0.7.18" resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.18.tgz#a7bfd92f56edfb117083b69e31d2aa8882d4b1ed" @@ -10146,8 +10163,8 @@ websocket-extensions@>=0.1.1: resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.3.tgz#5d2ff22977003ec687a4b87073dfbbac146ccf29" whatwg-fetch@>=0.10.0: - version "2.0.4" - resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz#dde6a5df315f9d39991aa17621853d720b85566f" + version "3.0.0" + resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.0.0.tgz#fc804e458cc460009b1a2b966bc8817d2578aefb" whatwg-fetch@^0.9.0: version "0.9.0" From e3569035df19e1fc0ffaa48f9b359b674fb27f1a Mon Sep 17 00:00:00 2001 From: Sean Yesmunt Date: Thu, 8 Nov 2018 15:51:07 -0500 Subject: [PATCH 2/2] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fa8c666bd..e06d17eb1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). * Subscription improvements ([#2031](https://github.com/lbryio/lbry-desktop/pull/2031)) * Adds Persistence to File List Filter Selections ([#2050](https://github.com/lbryio/lbry-desktop/pull/2050)) * Add more share options for channel page ([#2088](https://github.com/lbryio/lbry-desktop/pull/2088)) + * Better error handling on app startup ([#2098](https://github.com/lbryio/lbry-desktop/pull/2098)) ### Changed * Upgraded to lbrynet v0.30.0 ([#1998](https://github.com/lbryio/lbry-desktop/pull/1998))