allow running the app with mismatched daemon versions

This commit is contained in:
Sean Yesmunt 2019-01-09 20:38:26 -05:00
parent f63410e7f8
commit ac8d5aef5b
8 changed files with 88 additions and 41 deletions

View file

@ -1,6 +1,6 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { selectDaemonVersionMatched, selectModal } from 'redux/selectors/app'; import { selectDaemonVersionMatched, selectModal } from 'redux/selectors/app';
import { doCheckDaemonVersion, doNotifyUnlockWallet } from 'redux/actions/app'; import { doCheckDaemonVersion, doNotifyUnlockWallet, doHideModal } from 'redux/actions/app';
import SplashScreen from './view'; import SplashScreen from './view';
const select = state => ({ const select = state => ({
@ -11,6 +11,7 @@ const select = state => ({
const perform = dispatch => ({ const perform = dispatch => ({
checkDaemonVersion: () => dispatch(doCheckDaemonVersion()), checkDaemonVersion: () => dispatch(doCheckDaemonVersion()),
notifyUnlockWallet: () => dispatch(doNotifyUnlockWallet()), notifyUnlockWallet: () => dispatch(doNotifyUnlockWallet()),
hideModal: () => dispatch(doHideModal()),
}); });
export default connect( export default connect(

View file

@ -17,6 +17,7 @@ type Props = {
daemonVersionMatched: boolean, daemonVersionMatched: boolean,
onReadyToLaunch: () => void, onReadyToLaunch: () => void,
authenticate: () => void, authenticate: () => void,
hideModal: () => void,
modal: ?{ modal: ?{
id: string, id: string,
}, },
@ -27,9 +28,11 @@ type State = {
message: string, message: string,
launchedModal: boolean, launchedModal: boolean,
error: boolean, error: boolean,
isRunning: boolean,
launchWithIncompatibleDaemon: boolean,
}; };
export class SplashScreen extends React.PureComponent<Props, State> { export default class SplashScreen extends React.PureComponent<Props, State> {
constructor(props: Props) { constructor(props: Props) {
super(props); super(props);
@ -38,9 +41,12 @@ export class SplashScreen extends React.PureComponent<Props, State> {
message: __('Connecting'), message: __('Connecting'),
launchedModal: false, launchedModal: false,
error: false, error: false,
launchWithIncompatibleDaemon: false,
isRunning: false,
}; };
(this: any).renderModals = this.renderModals.bind(this); (this: any).renderModals = this.renderModals.bind(this);
(this: any).runWithIncompatibleDaemon = this.runWithIncompatibleDaemon.bind(this);
this.hasRecordedUser = false; this.hasRecordedUser = false;
this.timeout = undefined; this.timeout = undefined;
} }
@ -128,12 +134,7 @@ export class SplashScreen extends React.PureComponent<Props, State> {
} }
Lbry.resolve({ uri: 'lbry://one' }).then(() => { Lbry.resolve({ uri: 'lbry://one' }).then(() => {
// Only leave the load screen if the daemon version matched; this.setState({ isRunning: true }, () => this.continueAppLaunch());
// otherwise we'll notify the user at the end of the load screen.
if (this.props.daemonVersionMatched) {
this.props.onReadyToLaunch();
}
}); });
return; return;
@ -165,6 +166,26 @@ export class SplashScreen extends React.PureComponent<Props, State> {
}, 500); }, 500);
} }
runWithIncompatibleDaemon() {
const { hideModal } = this.props;
hideModal();
this.setState({ launchWithIncompatibleDaemon: true }, () => this.continueAppLaunch());
}
continueAppLaunch() {
const { daemonVersionMatched, onReadyToLaunch } = this.props;
const { isRunning, launchWithIncompatibleDaemon } = this.state;
if (daemonVersionMatched) {
onReadyToLaunch();
} else if (launchWithIncompatibleDaemon && isRunning) {
// The user may have decided to run the app with mismatched daemons
// They could make this decision before the daemon is finished starting up
// If it isn't running, this function will be called after the daemon is started
onReadyToLaunch();
}
}
hasRecordedUser: boolean; hasRecordedUser: boolean;
timeout: ?TimeoutID; timeout: ?TimeoutID;
@ -178,7 +199,7 @@ export class SplashScreen extends React.PureComponent<Props, State> {
switch (modalId) { switch (modalId) {
case MODALS.INCOMPATIBLE_DAEMON: case MODALS.INCOMPATIBLE_DAEMON:
return <ModalIncompatibleDaemon />; return <ModalIncompatibleDaemon onContinueAnyway={this.runWithIncompatibleDaemon} />;
case MODALS.WALLET_UNLOCK: case MODALS.WALLET_UNLOCK:
return <ModalWalletUnlock />; return <ModalWalletUnlock />;
case MODALS.UPGRADE: case MODALS.UPGRADE:
@ -204,5 +225,3 @@ export class SplashScreen extends React.PureComponent<Props, State> {
); );
} }
} }
export default SplashScreen;

View file

@ -23,7 +23,7 @@ type ModalProps = {
expandButtonLabel?: string, expandButtonLabel?: string,
hideButtonLabel?: string, hideButtonLabel?: string,
fullScreen: boolean, fullScreen: boolean,
title: string, title?: string | React.Node,
}; };
export class Modal extends React.PureComponent<ModalProps> { export class Modal extends React.PureComponent<ModalProps> {

View file

@ -1,9 +1,8 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { doQuit, doQuitAnyDaemon } from 'redux/actions/app'; import { doQuitAnyDaemon } from 'redux/actions/app';
import ModalIncompatibleDaemon from './view'; import ModalIncompatibleDaemon from './view';
const perform = dispatch => ({ const perform = dispatch => ({
quit: () => dispatch(doQuit()),
quitAnyDaemon: () => dispatch(doQuitAnyDaemon()), quitAnyDaemon: () => dispatch(doQuitAnyDaemon()),
}); });

View file

@ -4,13 +4,13 @@ import { Modal } from 'modal/modal';
import Button from 'component/button'; import Button from 'component/button';
type Props = { type Props = {
quit: () => void, onContinueAnyway: () => void,
quitAnyDaemon: () => void, quitAnyDaemon: () => void,
}; };
class ModalIncompatibleDaemon extends React.PureComponent<Props> { class ModalIncompatibleDaemon extends React.PureComponent<Props> {
render() { render() {
const { quit, quitAnyDaemon } = this.props; const { onContinueAnyway, quitAnyDaemon } = this.props;
return ( return (
<Modal <Modal
@ -18,21 +18,23 @@ class ModalIncompatibleDaemon extends React.PureComponent<Props> {
title={__('Incompatible Daemon')} title={__('Incompatible Daemon')}
contentLabel={__('Incompatible daemon running')} contentLabel={__('Incompatible daemon running')}
type="confirm" type="confirm"
confirmButtonLabel={__('Close LBRY and daemon')} confirmButtonLabel={__('Close App and LBRY Processes')}
abortButtonLabel={__('Do nothing')} abortButtonLabel={__('Continue Anyway')}
onConfirmed={quitAnyDaemon} onConfirmed={quitAnyDaemon}
onAborted={quit} onAborted={onContinueAnyway}
> >
<p> <div className="card__content">
{__( <p>
'This browser is running with an incompatible version of the LBRY protocol, please close the LBRY app and rerun the installation package to repair it. ' {__(
)} 'This app is running with an incompatible version of the LBRY protocol. You can still use it, but there may be issues. Re-run the installation package for best results.'
</p> )}
<Button </p>
button="link" <Button
label={__('Learn more')} button="link"
href="https://lbry.io/faq/incompatible-protocol-version" label={__('Learn more')}
/> href="https://lbry.io/faq/incompatible-protocol-version"
/>.
</div>
</Modal> </Modal>
); );
} }

View file

@ -1,4 +1,5 @@
// @flow // @flow
import type { Transaction } from 'types/transaction';
import React from 'react'; import React from 'react';
import { Modal } from 'modal/modal'; import { Modal } from 'modal/modal';
import * as txnTypes from 'constants/transaction_types'; import * as txnTypes from 'constants/transaction_types';
@ -8,6 +9,7 @@ type Props = {
abandonClaim: (string, number) => void, abandonClaim: (string, number) => void,
txid: string, txid: string,
nout: number, nout: number,
transactionItems: Array<Transaction>,
}; };
class ModalRevokeClaim extends React.PureComponent<Props> { class ModalRevokeClaim extends React.PureComponent<Props> {
@ -17,14 +19,14 @@ class ModalRevokeClaim extends React.PureComponent<Props> {
(this: any).revokeClaim = this.revokeClaim.bind(this); (this: any).revokeClaim = this.revokeClaim.bind(this);
} }
getButtonLabel(type) { getButtonLabel(type: string) {
if (type === txnTypes.TIP) { if (type === txnTypes.TIP) {
return 'Confirm Tip Unlock'; return 'Confirm Tip Unlock';
} }
return 'Confirm Claim Revoke'; return 'Confirm Claim Revoke';
} }
getMsgBody(type) { getMsgBody(type: string) {
if (type === txnTypes.TIP) { if (type === txnTypes.TIP) {
return ( return (
<React.Fragment> <React.Fragment>
@ -58,7 +60,13 @@ class ModalRevokeClaim extends React.PureComponent<Props> {
render() { render() {
const { transactionItems, txid, nout, closeModal } = this.props; const { transactionItems, txid, nout, closeModal } = this.props;
const { type } = transactionItems.find(claim => claim.txid == txid && claim.nout == nout); const { type } =
transactionItems.find(claim => claim.txid === txid && claim.nout === nout) || {};
if (!type) {
console.error('Tried to render modalRevokeClaim but no matching tx type found.');
return null;
}
return ( return (
<Modal <Modal

View file

@ -32,10 +32,28 @@ import ModalRewardCode from 'modal/modalRewardCode';
type Props = { type Props = {
modal: { id: string, modalProps: {} }, modal: { id: string, modalProps: {} },
error: string | { message: string }, error: { message: string },
openModal: string => void,
page: string,
isWelcomeAcknowledged: boolean,
isEmailCollectionAcknowledged: boolean,
isVerificationCandidate: boolean,
isCreditIntroAcknowledged: boolean,
balance: number,
showPageCost: number,
user: {
is_reward_approved: boolean,
is_identity_verified: boolean,
has_verified_email: boolean,
},
}; };
class ModalRouter extends React.PureComponent<Props> { type State = {
lastTransitionModal: ?string,
lastTransitionPage: ?string,
};
class ModalRouter extends React.PureComponent<Props, State> {
constructor(props: Props) { constructor(props: Props) {
super(props); super(props);
@ -49,11 +67,11 @@ class ModalRouter extends React.PureComponent<Props> {
this.showTransitionModals(this.props); this.showTransitionModals(this.props);
} }
componentWillReceiveProps(nextProps) { componentWillReceiveProps(nextProps: Props) {
this.showTransitionModals(nextProps); this.showTransitionModals(nextProps);
} }
showTransitionModals(props) { showTransitionModals(props: Props) {
const { modal, openModal, page } = props; const { modal, openModal, page } = props;
if (modal) { if (modal) {
@ -78,7 +96,7 @@ class ModalRouter extends React.PureComponent<Props> {
} }
} }
checkShowWelcome(props) { checkShowWelcome(props: Props) {
const { isWelcomeAcknowledged, user } = props; const { isWelcomeAcknowledged, user } = props;
if (!isWelcomeAcknowledged && user && !user.is_reward_approved && !user.is_identity_verified) { if (!isWelcomeAcknowledged && user && !user.is_reward_approved && !user.is_identity_verified) {
@ -88,7 +106,7 @@ class ModalRouter extends React.PureComponent<Props> {
return undefined; return undefined;
} }
checkShowEmail(props) { checkShowEmail(props: Props) {
const { isEmailCollectionAcknowledged, isVerificationCandidate, user } = props; const { isEmailCollectionAcknowledged, isVerificationCandidate, user } = props;
if ( if (
!isEmailCollectionAcknowledged && !isEmailCollectionAcknowledged &&
@ -102,7 +120,7 @@ class ModalRouter extends React.PureComponent<Props> {
return undefined; return undefined;
} }
checkShowCreditIntro(props) { checkShowCreditIntro(props: Props) {
const { balance, page, isCreditIntroAcknowledged } = props; const { balance, page, isCreditIntroAcknowledged } = props;
if ( if (
@ -116,7 +134,7 @@ class ModalRouter extends React.PureComponent<Props> {
return undefined; return undefined;
} }
isPaidShowPage(props) { isPaidShowPage(props: Props) {
const { page, showPageCost } = props; const { page, showPageCost } = props;
return page === 'show' && showPageCost > 0; return page === 'show' && showPageCost > 0;
} }

View file

@ -258,7 +258,7 @@ export function doCheckDaemonVersion() {
Lbry.version().then(({ lbrynet_version: lbrynetVersion }) => { Lbry.version().then(({ lbrynet_version: lbrynetVersion }) => {
// Avoid the incompatible daemon modal if running in dev mode // Avoid the incompatible daemon modal if running in dev mode
// Lets you run a different daemon than the one specified in package.json // Lets you run a different daemon than the one specified in package.json
if (isDev || config.lbrynetDaemonVersion === lbrynetVersion) { if (config.lbrynetDaemonVersion === lbrynetVersion) {
return dispatch({ return dispatch({
type: ACTIONS.DAEMON_VERSION_MATCH, type: ACTIONS.DAEMON_VERSION_MATCH,
}); });