Handle connection loss gracefully
This commit is contained in:
parent
54030bb341
commit
a1aa140848
|
@ -1,5 +1,10 @@
|
||||||
export const SOCKET_CONNECTED = "SOCKET_CONNECTED";
|
export const SOCKET_STATE = {
|
||||||
export const SOCKET_DISCONNECTED = "SOCKET_DISCONNECTED";
|
CONNECTED: "SOCKET_CONNECTED",
|
||||||
|
CONNECTING: "SOCKET_CONNECTING",
|
||||||
|
DISCONNECTED: "SOCKET_DISCONNECTED"
|
||||||
|
};
|
||||||
|
|
||||||
export const socket_connected = () => ({ type: SOCKET_CONNECTED });
|
export const SOCKET_UPDATE = "SOCKET_UPDATE";
|
||||||
export const socket_disconnected = () => ({ type: SOCKET_DISCONNECTED });
|
|
||||||
|
export const socket_update = (state, reason=null) =>
|
||||||
|
({ type: SOCKET_UPDATE, state, reason });
|
||||||
|
|
10
src/index.js
10
src/index.js
|
@ -6,21 +6,25 @@ import { ConnectedRouter } from 'react-router-redux';
|
||||||
import 'preact/devtools';
|
import 'preact/devtools';
|
||||||
import './polyfills';
|
import './polyfills';
|
||||||
|
|
||||||
import store, { history } from './store';
|
import store, { create, history } from './store';
|
||||||
import scss from '../scss/main.scss';
|
import scss from '../scss/main.scss';
|
||||||
import { ws_init } from './socket';
|
import { ws_init } from './socket';
|
||||||
import { filter_subscribe } from './actions/filter_subscribe';
|
import { filter_subscribe } from './actions/filter_subscribe';
|
||||||
import { socket_connected, socket_disconnected } from './actions/socket';
|
import { socket_update, SOCKET_STATE } from './actions/socket';
|
||||||
|
|
||||||
import Nav from './ui/navigation';
|
import Nav from './ui/navigation';
|
||||||
import Main from './ui/main';
|
import Main from './ui/main';
|
||||||
import Connection from './ui/connection';
|
import Connection from './ui/connection';
|
||||||
|
|
||||||
export function initialize(uri) {
|
export function initialize(uri) {
|
||||||
|
store.dispatch(socket_update(SOCKET_STATE.CONNECTING));
|
||||||
ws_init(uri, () => {
|
ws_init(uri, () => {
|
||||||
store.dispatch(socket_connected());
|
store.dispatch(socket_update(SOCKET_STATE.CONNECTED));
|
||||||
store.dispatch(filter_subscribe());
|
store.dispatch(filter_subscribe());
|
||||||
store.dispatch(filter_subscribe('server'));
|
store.dispatch(filter_subscribe('server'));
|
||||||
|
}, () => {
|
||||||
|
store.dispatch(socket_update(SOCKET_STATE.DISCONNECTED,
|
||||||
|
"You were disconnected."));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { UPDATE_RESOURCES, RESOURCES_REMOVED } from '../actions/resources';
|
import { UPDATE_RESOURCES, RESOURCES_REMOVED } from '../actions/resources';
|
||||||
|
import { SOCKET_STATE, SOCKET_UPDATE } from '../actions/socket';
|
||||||
|
|
||||||
export default function resourceReducer(type) {
|
export default function resourceReducer(type) {
|
||||||
return (state = {}, action) => {
|
return (state = {}, action) => {
|
||||||
|
@ -17,6 +18,9 @@ export default function resourceReducer(type) {
|
||||||
return Object.values(state)
|
return Object.values(state)
|
||||||
.filter(r => action.ids.indexOf(r.id) === -1)
|
.filter(r => action.ids.indexOf(r.id) === -1)
|
||||||
.reduce((s, r) => ({ ...s, [r.id]: r }), {});
|
.reduce((s, r) => ({ ...s, [r.id]: r }), {});
|
||||||
|
case SOCKET_UPDATE:
|
||||||
|
const _state = action.state;
|
||||||
|
return _state === SOCKET_STATE.CONNECTING ? {} : state;
|
||||||
}
|
}
|
||||||
return state;
|
return state;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
import { SOCKET_CONNECTED, SOCKET_DISCONNECTED } from '../actions/socket';
|
import { SOCKET_STATE, SOCKET_UPDATE } from '../actions/socket';
|
||||||
|
|
||||||
export default function socket(state = { connected: false }, action) {
|
export default function socket(_state = {
|
||||||
|
state: SOCKET_STATE.DISCONNECTED,
|
||||||
|
reason: null
|
||||||
|
}, action) {
|
||||||
|
const { state, reason } = action;
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case SOCKET_CONNECTED:
|
case SOCKET_UPDATE:
|
||||||
return { ...state, connected: true };
|
return { ..._state, state, reason };
|
||||||
case SOCKET_DISCONNECTED:
|
|
||||||
return { ...state, connected: false };
|
|
||||||
default:
|
default:
|
||||||
return state;
|
return _state;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,9 +35,9 @@ function ws_recv(e) {
|
||||||
handler && handler(msg);
|
handler && handler(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ws_init(uri, cb) {
|
export function ws_init(uri, open, close) {
|
||||||
ws = new WebSocket(uri);
|
ws = new WebSocket(uri);
|
||||||
ws.addEventListener("open", cb);
|
ws.addEventListener("open", open);
|
||||||
ws.addEventListener("message", ws_recv);
|
ws.addEventListener("message", ws_recv);
|
||||||
ws.addEventListener("close", () => console.log("ws closed"));
|
ws.addEventListener("close", close);
|
||||||
}
|
}
|
||||||
|
|
14
src/store.js
14
src/store.js
|
@ -13,10 +13,16 @@ export const history = createHistory();
|
||||||
const _compose =
|
const _compose =
|
||||||
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
|
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
|
||||||
|| compose;
|
|| compose;
|
||||||
const store = createStore(
|
|
||||||
reducer,
|
let store;
|
||||||
_compose(applyMiddleware(thunk, routerMiddleware(history))),
|
|
||||||
);
|
export const create = () => {
|
||||||
|
store = createStore(
|
||||||
|
reducer,
|
||||||
|
_compose(applyMiddleware(thunk, routerMiddleware(history))),
|
||||||
|
);
|
||||||
|
};
|
||||||
|
create();
|
||||||
|
|
||||||
if (module.hot) {
|
if (module.hot) {
|
||||||
// Enable webpack hot module replacement for reducers
|
// Enable webpack hot module replacement for reducers
|
||||||
|
|
|
@ -1,14 +1,17 @@
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import {
|
import {
|
||||||
|
Alert,
|
||||||
Card,
|
Card,
|
||||||
CardHeader,
|
CardHeader,
|
||||||
CardBlock,
|
CardBlock,
|
||||||
FormGroup,
|
FormGroup,
|
||||||
|
Progress,
|
||||||
Label,
|
Label,
|
||||||
Input
|
Input
|
||||||
} from 'reactstrap';
|
} from 'reactstrap';
|
||||||
import { initialize } from '..';
|
import { initialize } from '..';
|
||||||
|
import { SOCKET_STATE } from '../actions/socket';
|
||||||
|
|
||||||
class ConnectionOverlay extends Component {
|
class ConnectionOverlay extends Component {
|
||||||
constructor() {
|
constructor() {
|
||||||
|
@ -25,15 +28,29 @@ class ConnectionOverlay extends Component {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { socket } = this.props;
|
const { socket } = this.props;
|
||||||
if (socket.connected) {
|
if (socket.state === SOCKET_STATE.CONNECTED) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
if (socket.state === SOCKET_STATE.CONNECTING) {
|
||||||
|
return (
|
||||||
|
<div className="connection-overlay">
|
||||||
|
<Card>
|
||||||
|
<CardHeader>Connect to synapse</CardHeader>
|
||||||
|
<CardBlock>
|
||||||
|
<p className="text-center">Connecting...</p>
|
||||||
|
<Progress value={100} animated />
|
||||||
|
</CardBlock>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
const { uri, autoconnect } = this.state;
|
const { uri, autoconnect } = this.state;
|
||||||
return (
|
return (
|
||||||
<div className="connection-overlay">
|
<div className="connection-overlay">
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader>Connect to synapse</CardHeader>
|
<CardHeader>Connect to synapse</CardHeader>
|
||||||
<CardBlock>
|
<CardBlock>
|
||||||
|
{socket.reason && <Alert color="info">{socket.reason}</Alert>}
|
||||||
<FormGroup>
|
<FormGroup>
|
||||||
<Label for="socket-uri">Server URI</Label>
|
<Label for="socket-uri">Server URI</Label>
|
||||||
<Input
|
<Input
|
||||||
|
@ -56,7 +73,7 @@ class ConnectionOverlay extends Component {
|
||||||
<button
|
<button
|
||||||
className="btn btn-primary"
|
className="btn btn-primary"
|
||||||
onClick={() => initialize(this.state.uri)}
|
onClick={() => initialize(this.state.uri)}
|
||||||
>Connect</button>
|
>{socket.reason ? "Reconnect" : "Connect"}</button>
|
||||||
</CardBlock>
|
</CardBlock>
|
||||||
</Card>
|
</Card>
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user