src/sagas/index.js
import { all, fork, select, put, cancel, takeEvery, takeLatest, take, call } from 'redux-saga/effects';
import { delay } from 'redux-saga';
import { push } from 'connected-react-router';
import * as types from '../actions/types';
import * as actions from '../actions/sync';
import * as apiSagas from './api';
import * as storageSagas from './localStorage';
import { getToken, getPathname, getLiveChartsAllIds, getMonitorsAddresses } from '../reducers';
import { getDefaultRouteByToken, isRouteDefined, isTokenRequired, LIVE_ROUTE } from '../routes';
import Notification from '../components/Notification';
function* dealWithNewLocation(pathname) {
const isTokenSet = Boolean(yield select(getToken));
if (pathname === '/') {
const newPathname = yield call(getDefaultRouteByToken, isTokenSet);
yield put(push(newPathname));
}
else if (yield call(isRouteDefined, pathname)) {
const tokenRequired = yield call(isTokenRequired, pathname);
if (tokenRequired === isTokenSet) {
yield put(actions.changeRoutingContext({ pathname }));
}
else {
const newPathname = yield call(getDefaultRouteByToken, isTokenSet);
yield put(push(newPathname));
}
}
else {
yield put(actions.changeRoutingContext({ pathname }));
}
}
function* watchForLocationChange() {
yield delay(0);
const startLocation = yield select(getPathname);
let task = yield fork(dealWithNewLocation, startLocation);
while (true) {
const action = yield take([
'@@router/LOCATION_CHANGE',
types.SIGN_IN_SUCCESS,
types.SIGN_UP_SUCCESS,
types.REMOVE_TOKEN
]);
yield cancel(task);
const newLocation = action.type === '@@router/LOCATION_CHANGE' ? action.payload.location.pathname : '/';
task = yield fork(dealWithNewLocation, newLocation);
}
}
function* keepLiveChartRefreshing(id) {
yield put(actions.getLiveMeasurementsRequest(id, true));
while(true) {
yield all([
take(types.GET_LIVE_MEASUREMENTS_SUCCESS),
delay(1000 * 15)
]);
yield put(actions.getLiveMeasurementsRequest(id, false));
}
}
function* conductLiveChartsUpdates() {
const liveCharts = yield select(getLiveChartsAllIds);
const tasks = {};
for (const id of liveCharts) {
tasks[id] = yield fork(keepLiveChartRefreshing, id);
}
while (true) {
const action = yield take([
types.CHANGE_ROUTING_CONTEXT,
types.ADD_LIVE_CHART,
types.REMOVE_LIVE_CHART,
types.SET_LIVE_CHART_METRIC,
types.ADD_LIVE_CHART_HOST,
types.REMOVE_LIVE_CHART_HOST
]);
if (action.type === types.CHANGE_ROUTING_CONTEXT && action.payload.pathname !== LIVE_ROUTE) {
yield cancel();
}
if (
action.type === types.REMOVE_LIVE_CHART
|| action.type === types.SET_LIVE_CHART_METRIC
|| action.type === types.ADD_LIVE_CHART_HOST
|| action.type === types.REMOVE_LIVE_CHART_HOST
) {
yield cancel(tasks[action.meta.id]);
}
if (action.type === types.ADD_LIVE_CHART) {
tasks[action.payload.id] = yield fork(keepLiveChartRefreshing, action.payload.id);
}
if (
action.type === types.SET_LIVE_CHART_METRIC
|| action.type === types.ADD_LIVE_CHART_HOST
|| action.type === types.REMOVE_LIVE_CHART_HOST
) {
tasks[action.meta.id] = yield fork(keepLiveChartRefreshing, action.meta.id);
}
}
}
function* watchForLiveChartContext() {
let task;
const pathname = yield select(getPathname);
if (pathname === LIVE_ROUTE) {
task = yield fork(conductLiveChartsUpdates);
}
while (true) {
const { payload } = yield take(types.CHANGE_ROUTING_CONTEXT);
if (payload.pathname === LIVE_ROUTE) {
if (task) {
cancel(task);
}
task = yield fork(conductLiveChartsUpdates);
}
}
}
function* loginWatcher() {
yield take(types.CHANGE_ROUTING_CONTEXT);
const token = yield select(getToken);
let worker;
if (token) {
worker = yield fork(authSiteWatcher);
yield call(Notification.info, 'Zostałeś zalogowany przy pomocy zapisanych danych uwierzytelniających');
}
while (true) {
const { type } = yield take([
types.SIGN_IN_SUCCESS,
types.SIGN_UP_SUCCESS,
types.REMOVE_TOKEN
]);
if (worker) {
yield cancel(worker);
}
if (type !== types.REMOVE_TOKEN) {
worker = yield fork(authSiteWatcher);
yield call(Notification.success, 'Zostałeś zalogowany pomyślnie');
}
else {
yield call(Notification.success, 'Zostałeś wylogowany pomyślnie');
}
}
}
function* getAllHosts() {
const monitors = yield select(getMonitorsAddresses);
yield all(monitors.map(monitor => put(actions.getHostsRequest(monitor))));
}
function* watchForHistoricalChartUpdates() {
let workers = {};
while (true) {
const action = yield take([
types.SET_HISTORICAL_CHART_RANGE,
types.SET_HISTORICAL_CHART_METRIC1,
types.SET_HISTORICAL_CHART_METRIC2,
types.ADD_HISTORICAL_CHART_HOST1,
types.ADD_HISTORICAL_CHART_HOST2,
types.REMOVE_HISTORICAL_CHART_HOST1,
types.REMOVE_HISTORICAL_CHART_HOST2,
types.REMOVE_HISTORICAL_CHART
]);
if (workers[action.meta.id]) {
yield cancel(action.meta.id);
}
if (action.type !== types.REMOVE_HISTORICAL_CHART) {
yield put(actions.getHistoricalMeasurementsRequest(action.meta.id));
}
}
}
function* triggerHostsUpdate() {
yield put(actions.getHosts());
}
function* authSiteWatcher() {
yield all([
fork(watchForLiveChartContext),
fork(watchForHistoricalChartUpdates),
takeEvery(types.GET_HOSTS, getAllHosts),
takeEvery(types.ADD_COMPLEX_METRIC_REQUEST, apiSagas.addComplexMetric),
takeEvery(types.REMOVE_COMPLEX_METRIC_REQUEST, apiSagas.removeComplexMetric),
takeEvery(types.GET_HOSTS_REQUEST, apiSagas.getHosts),
takeEvery(types.GET_LIVE_MEASUREMENTS_REQUEST, apiSagas.getLiveChartMeasurements),
takeEvery(types.GET_HISTORICAL_MEASUREMENTS_REQUEST, apiSagas.getHistoricalChartMeasurements),
takeLatest([
types.ADD_MONITOR,
types.SET_MONITOR_ADDRESS,
types.SET_MONITOR_DESCRIPTION,
types.REMOVE_MONITOR
], storageSagas.monitorsSaver),
takeEvery([
types.ADD_MONITOR,
types.SET_MONITOR_ADDRESS
], triggerHostsUpdate)
]);
yield put(actions.getHosts());
}
function* errorThrower() {
while (true) {
const action = yield take('*');
if (action.error) {
if (
!action.payload.status &&
(action.type === types.SIGN_IN_FAILURE || action.type === types.SIGN_UP_FAILURE)
) {
yield call(Notification.error, 'Serwer autoryzacyjny jest niedostępny');
continue;
}
if (!action.payload.status && action.meta && action.meta.monitor) {
yield call(Notification.error, 'Monitor ' + action.meta.monitor + ' jest niedostępny');
continue;
}
if (action.payload.status === 422 && action.meta && action.meta.monitor) {
yield call(
Notification.error,
'Nie udało się pobrać zasobów, gdyż dane uwierzytelniające są błędne (monitor: ' +
action.meta.monitor +
')'
);
continue;
}
if (action.type === types.SIGN_IN_FAILURE && action.payload.status === 401) {
yield call(Notification.error, 'Błędny login lub hasło!');
continue;
}
if (action.type === types.SIGN_UP_FAILURE && action.payload.status === 409) {
yield call(Notification.error, 'Użytkownik o podanym adresie email juz istnieje!');
continue;
}
yield call(Notification.error, action.payload.message + (status ? ' (Kod ' + status + ')' : ''));
}
}
}
export default function* root() {
yield all([
takeEvery(types.SIGN_UP_REQUEST, apiSagas.signUp),
takeEvery(types.SIGN_IN_REQUEST, apiSagas.signIn),
takeLatest(types.SIGN_IN_REQUEST, storageSagas.tokenSaver),
takeLatest(types.REMOVE_TOKEN, storageSagas.tokenEraser),
takeLatest(types.CHANGE_AUTH_SERVER, storageSagas.authServerSaver),
fork(watchForLocationChange),
fork(loginWatcher),
fork(errorThrower)
]);
}