Force Node Change on Web3 Unset (#1207)

* add CONFIG_NODE_CHANGE_FORCE action

* implement forceful node change on web3

* update comment

* add test

* make tsc happy

* update test
This commit is contained in:
Danny Skubak 2018-02-28 23:31:33 -05:00 committed by Daniel Ternyak
parent 1a711b5c20
commit 23546a1cf9
7 changed files with 101 additions and 10 deletions

View File

@ -48,6 +48,14 @@ export function changeNodeIntent(payload: string): interfaces.ChangeNodeIntentAc
};
}
export type TChangeNodeForce = typeof changeNodeForce;
export function changeNodeForce(payload: string): interfaces.ChangeNodeForceAction {
return {
type: TypeKeys.CONFIG_NODE_CHANGE_FORCE,
payload
};
}
export type TAddCustomNode = typeof addCustomNode;
export function addCustomNode(
payload: interfaces.AddCustomNodeAction['payload']

View File

@ -36,6 +36,11 @@ export interface ChangeNodeIntentAction {
type: TypeKeys.CONFIG_NODE_CHANGE_INTENT;
payload: string;
}
/*** Force Change Node ***/
export interface ChangeNodeForceAction {
type: TypeKeys.CONFIG_NODE_CHANGE_FORCE;
payload: string;
}
/*** Add Custom Node ***/
export interface AddCustomNodeAction {

View File

@ -10,6 +10,7 @@ export enum TypeKeys {
CONFIG_NODE_WEB3_UNSET = 'CONFIG_NODE_WEB3_UNSET',
CONFIG_NODE_CHANGE = 'CONFIG_NODE_CHANGE',
CONFIG_NODE_CHANGE_INTENT = 'CONFIG_NODE_CHANGE_INTENT',
CONFIG_NODE_CHANGE_FORCE = 'CONFIG_NODE_CHANGE_FORCE',
CONFIG_ADD_CUSTOM_NODE = 'CONFIG_ADD_CUSTOM_NODE',
CONFIG_REMOVE_CUSTOM_NODE = 'CONFIG_REMOVE_CUSTOM_NODE',

View File

@ -27,6 +27,7 @@ import {
changeNodeIntent,
setLatestBlock,
AddCustomNodeAction,
ChangeNodeForceAction,
ChangeNodeIntentAction
} from 'actions/config';
import { showNotification } from 'actions/notifications';
@ -181,8 +182,30 @@ export function* handleNewNetwork() {
yield put(resetWallet());
}
export function* handleNodeChangeForce({ payload: staticNodeIdToSwitchTo }: ChangeNodeForceAction) {
// does not perform node online check before changing nodes
// necessary when switching back from Web3 provider so node
// dropdown does not get stuck if node is offline
const isStaticNode: boolean = yield select(isStaticNodeId, staticNodeIdToSwitchTo);
if (!isStaticNode) {
return;
}
const nodeConfig = yield select(getStaticNodeFromId, staticNodeIdToSwitchTo);
// force the node change
yield put(changeNode({ networkId: nodeConfig.network, nodeId: staticNodeIdToSwitchTo }));
// also put the change through as usual so status check and
// error messages occur if the node is unavailable
yield put(changeNodeIntent(staticNodeIdToSwitchTo));
}
export const node = [
takeEvery(TypeKeys.CONFIG_NODE_CHANGE_INTENT, handleNodeChangeIntent),
takeEvery(TypeKeys.CONFIG_NODE_CHANGE_FORCE, handleNodeChangeForce),
takeLatest(TypeKeys.CONFIG_POLL_OFFLINE_STATUS, handlePollOfflineStatus),
takeEvery(TypeKeys.CONFIG_LANGUAGE_CHANGE, reload),
takeEvery(TypeKeys.CONFIG_ADD_CUSTOM_NODE, switchToNewNode)

View File

@ -2,7 +2,7 @@ import { TypeKeys as WalletTypeKeys } from 'actions/wallet/constants';
import { Web3Wallet } from 'libs/wallet';
import { SagaIterator } from 'redux-saga';
import { select, put, takeEvery, call } from 'redux-saga/effects';
import { changeNodeIntent, TypeKeys, web3SetNode } from 'actions/config';
import { changeNodeForce, TypeKeys, web3SetNode } from 'actions/config';
import { getNodeId, getStaticAltNodeIdToWeb3, getNetworkNameByChainId } from 'selectors/config';
import { setupWeb3Node, Web3Service } from 'libs/nodes/web3';
import { Web3NodeConfig } from 'types/node';
@ -34,8 +34,8 @@ export function* unsetWeb3NodeOnWalletEvent(action): SagaIterator {
}
const altNode = yield select(getStaticAltNodeIdToWeb3);
// switch back to a node with the same network as MetaMask/Mist
yield put(changeNodeIntent(altNode));
// forcefully switch back to a node with the same network as MetaMask/Mist
yield put(changeNodeForce(altNode));
}
export function* unsetWeb3Node(): SagaIterator {
@ -46,8 +46,8 @@ export function* unsetWeb3Node(): SagaIterator {
}
const altNode = yield select(getStaticAltNodeIdToWeb3);
// switch back to a node with the same network as MetaMask/Mist
yield put(changeNodeIntent(altNode));
// forcefully switch back to a node with the same network as MetaMask/Mist
yield put(changeNodeForce(altNode));
}
export const web3 = [

View File

@ -2,7 +2,13 @@ import { configuredStore } from 'store';
import { delay } from 'redux-saga';
import { call, cancel, fork, put, take, select } from 'redux-saga/effects';
import { cloneableGenerator, createMockTask } from 'redux-saga/utils';
import { toggleOffline, changeNode, changeNodeIntent, setLatestBlock } from 'actions/config';
import {
toggleOffline,
changeNode,
changeNodeIntent,
changeNodeForce,
setLatestBlock
} from 'actions/config';
import {
handleNodeChangeIntent,
handlePollOfflineStatus,
@ -274,8 +280,8 @@ describe('unsetWeb3Node*', () => {
expect(gen.next(node).value).toEqual(select(getStaticAltNodeIdToWeb3));
});
it('should put changeNodeIntent', () => {
expect(gen.next(alternativeNodeId).value).toEqual(put(changeNodeIntent(alternativeNodeId)));
it('should put changeNodeForce', () => {
expect(gen.next(alternativeNodeId).value).toEqual(put(changeNodeForce(alternativeNodeId)));
});
it('should be done', () => {
@ -304,8 +310,8 @@ describe('unsetWeb3NodeOnWalletEvent*', () => {
expect(gen.next(mockNodeId).value).toEqual(select(getStaticAltNodeIdToWeb3));
});
it('should put changeNodeIntent', () => {
expect(gen.next(alternativeNodeId).value).toEqual(put(changeNodeIntent(alternativeNodeId)));
it('should put changeNodeForce', () => {
expect(gen.next(alternativeNodeId).value).toEqual(put(changeNodeForce(alternativeNodeId)));
});
it('should be done', () => {

View File

@ -0,0 +1,48 @@
import { configuredStore } from 'store';
import { cloneableGenerator } from 'redux-saga/utils';
import { handleNodeChangeForce } from 'sagas/config/node';
import { put, select } from 'redux-saga/effects';
import { isStaticNodeId, getStaticNodeFromId } from 'selectors/config';
import { changeNode, changeNodeIntent } from 'actions/config';
// init module
configuredStore.getState();
describe('handleNodeChangeForce*', () => {
const payload: any = 'nodeId';
const action: any = { payload };
const gen = cloneableGenerator(handleNodeChangeForce)(action);
const nodeConfig: any = { network: 'network' };
it('should select isStaticNodeId', () => {
expect(gen.next().value).toEqual(select(isStaticNodeId, payload));
});
it('should return if not static node', () => {
const clone = gen.clone();
expect(clone.next(false).done).toEqual(true);
});
it('should select getStaticNodeFromId', () => {
expect(gen.next(true).value).toEqual(select(getStaticNodeFromId, payload));
});
it('should force the node change', () => {
expect(gen.next(nodeConfig).value).toEqual(
put(
changeNode({
networkId: nodeConfig.network,
nodeId: payload
})
)
);
});
it('should put a change node intent', () => {
expect(gen.next().value).toEqual(put(changeNodeIntent(payload)));
});
it('should be done', () => {
expect(gen.next().done).toEqual(true);
});
});