Handle daemon startup errors/timeouts #2098
9 changed files with 198 additions and 44 deletions
|
@ -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))
|
||||
|
|
2
flow-typed/i18n.js
vendored
2
flow-typed/i18n.js
vendored
|
@ -1 +1 @@
|
|||
declare function __(a: string): string;
|
||||
declare function __(a: string, b?: string | number): string;
|
||||
|
|
|
@ -22,7 +22,6 @@ class ToolTip extends React.PureComponent<Props, State> {
|
|||
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
this.tooltip = React.createRef();
|
||||
this.state = {
|
||||
direction: this.props.direction,
|
||||
};
|
||||
|
@ -33,11 +32,11 @@ class ToolTip extends React.PureComponent<Props, State> {
|
|||
}
|
||||
|
||||
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<Props, State> {
|
|||
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<Props, State> {
|
|||
>
|
||||
{tooltipContent}
|
||||
<span
|
||||
ref={this.tooltip}
|
||||
ref={ref => {
|
||||
this.tooltip = ref;
|
||||
}}
|
||||
className={classnames('tooltip__body', {
|
||||
'tooltip__body--short': isShortDescription,
|
||||
})}
|
||||
|
|
|
@ -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<Props> {
|
||||
|
@ -16,7 +18,7 @@ class LoadScreen extends React.PureComponent<Props> {
|
|||
};
|
||||
|
||||
render() {
|
||||
const { details, message, isWarning } = this.props;
|
||||
const { details, message, isWarning, error } = this.props;
|
||||
|
||||
return (
|
||||
<div className="load-screen">
|
||||
|
@ -24,17 +26,42 @@ class LoadScreen extends React.PureComponent<Props> {
|
|||
<h1 className="load-screen__title">{__('LBRY')}</h1>
|
||||
<sup className="load-screen__beta">beta</sup>
|
||||
</div>
|
||||
{isWarning ? (
|
||||
<span className="load-screen__message">
|
||||
<Icon size={20} icon={icons.ALERT} />
|
||||
{` ${message}`}
|
||||
</span>
|
||||
{error ? (
|
||||
<Fragment>
|
||||
<h3>{__('Uh oh. Sean must have messed something up. Try refreshing to fix it.')}</h3>
|
||||
<div className="card__actions">
|
||||
<Button label="Refresh" button="alt" onClick={() => window.location.reload()} />
|
||||
</div>
|
||||
<div className="load-screen--help">
|
||||
<p>
|
||||
{__(
|
||||
'If you still have issues, your anti-virus software or firewall may be preventing startup.'
|
||||
)}
|
||||
</p>
|
||||
<p>
|
||||
{__('Reach out to hello@lbry.io for help, or check out')}{' '}
|
||||
<Button
|
||||
className="btn--load-screen"
|
||||
href="https://lbry.io/faq/startup-troubleshooting"
|
||||
label="this link"
|
||||
/>.
|
||||
</p>
|
||||
</div>
|
||||
</Fragment>
|
||||
) : (
|
||||
<div className="load-screen__message">{message}</div>
|
||||
<Fragment>
|
||||
{isWarning ? (
|
||||
<span className="load-screen__message">
|
||||
<Icon size={20} icon={icons.ALERT} />
|
||||
{` ${message}`}
|
||||
</span>
|
||||
) : (
|
||||
<div className="load-screen__message">{message}</div>
|
||||
)}
|
||||
{details && <div className="load-screen__details">{details}</div>}
|
||||
<Spinner type="splash" />
|
||||
</Fragment>
|
||||
)}
|
||||
|
||||
{details && <div className="load-screen__details">{details}</div>}
|
||||
<Spinner type="splash" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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<any>,
|
||||
notifyUnlockWallet: () => Promise<any>,
|
||||
|
@ -23,6 +26,7 @@ type State = {
|
|||
message: string,
|
||||
isRunning: boolean,
|
||||
launchedModal: boolean,
|
||||
error: boolean,
|
||||
};
|
||||
|
||||
export class SplashScreen extends React.PureComponent<Props, State> {
|
||||
|
@ -34,14 +38,17 @@ export class SplashScreen extends React.PureComponent<Props, State> {
|
|||
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<Props, State> {
|
|||
});
|
||||
}
|
||||
|
||||
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<Props, State> {
|
|||
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 && <ModalWalletUnlock />}
|
||||
return (
|
||||
<React.Fragment>
|
||||
<LoadScreen message={message} details={details} />
|
||||
<LoadScreen message={message} details={details} error={error} />
|
||||
{/* 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. */}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
48
src/renderer/types/status.js
Normal file
48
src/renderer/types/status.js
Normal file
|
@ -0,0 +1,48 @@
|
|||
// @flow
|
||||
|
||||
export type Status = {
|
||||
error?: {},
|
||||
is_running: boolean,
|
||||
is_first_run: boolean,
|
||||
installation_id: string,
|
||||
skipped_components: Array<string>,
|
||||
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,
|
||||
},
|
||||
};
|
37
yarn.lock
37
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"
|
||||
|
|
Loading…
Reference in a new issue