client/src/sagas/networkSaga.js
author ymh <ymh.work@gmail.com>
Mon, 26 Jun 2017 15:21:06 +0200
changeset 87 dbcee57de2c6
child 88 2a861fed6bde
permissions -rw-r--r--
Add first implementation of network monitor

import * as types from '../constants/actionTypes';
import { all, call, fork, race, take, cancelled, put, select } from 'redux-saga/effects'
import config from '../config';

// Utility function to delay effects
function delay(millis) {
    const promise = new Promise(resolve => {
        setTimeout(() => resolve(true), millis)
    });
    return promise;
}

function pingServer(client, token) {
  console.log("PING SERVER", token);
  if(token) {
    const timeout = new Promise((resolve, reject) => {
      setTimeout(reject, config.networkStatusTimeout, 'request timed out');
    });
    return Promise
      .race([timeout, client.post('/api/auth/refresh/', { token })]);
  } else {
    return Promise.reject({ error: 'No token in the store'})
  }
}

// Fetch data every 20 seconds
function* pollData(context) {
  try {
    yield call(delay, config.networkStatusInterval);
    const token = yield select(state => state.token);
    const res = yield pingServer(context.client, token);
    yield call(context.callback, true);
    yield put({
      type: types.AUTH_STORE_TOKEN_ASYNC,
      token: res.token,
    });
  } catch (error) {
    yield call(context.callback, false);
    // if the error is that there is no token, then we know we have to wait for a login
    if(error.error && error.error === 'No token in the store') {
      yield take(types.AUTH_LOGIN_SUCCESS);
    }
  } finally {
    if (yield cancelled()) {
      // pollDate cancelled
      // if there is a token : this was a LOGIN, set status to ok
      // if there is no token : this was a LOGOUT, set status to ko and wait for login
      const token = yield select(state => state.token);
      if(token) {
        yield call(context.callback, true);
      } else {
        yield call(context.callback, false);
        yield take(types.AUTH_LOGIN_SUCCESS);
      }
    }
  }
}

// Wait for successful response, then fire another request
// Cancel polling if user logs out or log in
function* watchPollData(context) {
  while (true) {
    yield race([
      call(pollData, context),
      take(types.AUTH_LOGOUT),
      take(types.AUTH_LOGIN_SUCCESS)
    ]);
  }
}

// Daemonize tasks in parallel
export default function* root(baseContext) {
  const actionRes = yield take(types.OFFLINE_CONFIG_INITIALIZED);
  const context = {...baseContext, ...actionRes.additionalContext};
  yield all([
    fork(watchPollData, context)
    // other watchers here
  ]);
}