diff --git a/src/client/actions.js b/src/client/actions.js
index 26e99e3..5a36f3f 100644
--- a/src/client/actions.js
+++ b/src/client/actions.js
@@ -8,3 +8,6 @@ export const removeUser = createAction('remove user');
export const newMessage = createAction('new message');
export const sendMessage = createAction('send message');
+
+export const ws_disconnected = createAction('ws is disconnected');
+export const connecting = createAction('connecting');
diff --git a/src/client/app.js b/src/client/app.js
index 932e4f6..82258e2 100644
--- a/src/client/app.js
+++ b/src/client/app.js
@@ -3,6 +3,7 @@ import { connect } from 'react-redux';
import { AppBar, FlatButton } from 'material-ui';
import { Welcome, Room } from './views';
import { logout } from './actions';
+import CircularProgress from 'material-ui/CircularProgress';
class App extends Component {
handleLogout() {
@@ -10,12 +11,19 @@ class App extends Component {
}
render() {
- const { username } = this.props;
+ const { username, connecting } = this.props;
let body, right;
if (username) {
- body = ;
- right = ;
+ if (connecting) {
+
+
+ body =
;
+ }
+ else {
+ body = ;
+ }
+ right = ;
} else {
body = ;
}
diff --git a/src/client/reducers.js b/src/client/reducers.js
index 701ced3..d36ce18 100644
--- a/src/client/reducers.js
+++ b/src/client/reducers.js
@@ -1,12 +1,13 @@
import { combineReducers } from 'redux';
import { createReducer } from 'redux-act';
import {
- login, logout, addUser, removeUser, newMessage
+ login, logout, addUser, removeUser, newMessage, connecting
} from './actions';
const initial = {
app: {
- username: null
+ username: null,
+ connecting: false
},
users: {},
messages: {
@@ -20,7 +21,10 @@ const app = createReducer({
return { ...state, username: payload.username };
},
[logout]: (state, payload) => {
- return { ...state, username: null };
+ return { ...state, username: null, connecting: false };
+ },
+ [connecting]: (state, payload) => {
+ return { ...state, connecting: payload.connecting };
},
}, initial.app);
diff --git a/src/client/sagas.js b/src/client/sagas.js
index e3b645f..30eace5 100644
--- a/src/client/sagas.js
+++ b/src/client/sagas.js
@@ -1,17 +1,30 @@
import io from 'socket.io-client';
-import { eventChannel } from 'redux-saga';
+import { eventChannel, END } from 'redux-saga';
import { fork, take, call, put, cancel } from 'redux-saga/effects';
import {
- login, logout, addUser, removeUser, newMessage, sendMessage
+ login, logout, addUser, removeUser, newMessage, sendMessage,
+ connecting, ws_disconnected
} from './actions';
function connect() {
- const socket = io('http://localhost:3000');
- return new Promise(resolve => {
+ const socket = io('http://localhost:3000', {
+ 'reconnection': true,
+ 'reconnectionDelay': 1000,
+ 'reconnectionDelayMax': 5000,
+ 'reconnectionAttempts': 5
+ });
+ return new Promise((resolve, reject) => {
socket.on('connect', () => {
resolve(socket);
});
- });
+ socket.on('reconnect_failed', (err) => {
+ reject(new Error('ws:reconnect_failed '))
+ });
+ }).then(
+ response => ({ socket: response })
+ ).catch(
+ error => ({ socket, error })
+ );
}
function subscribe(socket) {
@@ -26,24 +39,34 @@ function subscribe(socket) {
emit(newMessage({ message }));
});
socket.on('disconnect', e => {
- // TODO: handle
+ emit(END)
});
- return () => {};
+ return () => { };
});
}
function* read(socket) {
const channel = yield call(subscribe, socket);
- while (true) {
- let action = yield take(channel);
- yield put(action);
+ try {
+ while (true) {
+ let action = yield take(channel);
+ yield put(action);
+ }
+ }
+ finally {
+ yield put(ws_disconnected())
}
}
function* write(socket) {
- while (true) {
- const { payload } = yield take(`${sendMessage}`);
- socket.emit('message', payload);
+ try {
+ while (true) {
+ const { payload } = yield take(`${sendMessage}`);
+ socket.emit('message', payload);
+ }
+ }
+ finally {
+
}
}
@@ -52,20 +75,46 @@ function* handleIO(socket) {
yield fork(write, socket);
}
-function* flow() {
- while (true) {
- let { payload } = yield take(`${login}`);
- const socket = yield call(connect);
- socket.emit('login', { username: payload.username });
+function* flow(username) {
+ try {
+ while (true) {
+ yield put(connecting({ connecting: true }));
+ const { socket, error } = yield call(connect);
+ yield put(connecting({ connecting: false }));
+
+ if (error) {
+ yield call([socket, socket.disconnect]);
+ yield put(logout());
+ break;
+ }
- const task = yield fork(handleIO, socket);
+ if (socket) {
+ socket.emit('login', { username });
+
+ const task = yield fork(handleIO, socket);
+
+ let action = yield take([`${logout}`, `${ws_disconnected}`]);
+ yield cancel(task);
+ socket.emit('logout');
+ yield call([socket, socket.disconnect]);
+ if (action.type == logout().type) {
+ break;
+ }
+ }
+ }
+ }
+ finally {
- let action = yield take(`${logout}`);
- yield cancel(task);
- socket.emit('logout');
}
}
export default function* rootSaga() {
- yield fork(flow);
+ let myFlow;
+ while (true) {
+ let {payload} = yield take(`${login}`);
+ if (myFlow) {
+ yield cancel(myFlow);
+ }
+ myFlow = yield fork(flow, payload.username);
+ }
}