g33k57
6/15/2019 - 5:28 AM

Redux Saga with WebSocket

Redux Saga with WebSocket

import { eventChannel, END } from 'redux-saga';
import { call, put, take, fork, cancel, cancelled } from 'redux-saga/effects';
import * as LiveDataActions from '../../redux/LiveData/LiveData.actions';
import * as LiveDataTypes from '../../redux/LiveData/LiveData.types';

// Use this to actually throw exceptions, allows for easier debugging.
const dispatch = put.resolve;

function createWebSocketConnection() {
  return new Promise((resolve, reject) => {
    const socket = new WebSocket("ws://localhost:1555");

    socket.onopen = function () {
      resolve(socket);
    };

    socket.onerror = function (evt) {
      reject(evt);
    }
  });
}

function createSocketChannel(socket) {
  return eventChannel(emit => {
    socket.onmessage = (event) => {
      emit(event.data)
    };

    socket.onclose = () => {
      emit(END);
    };

    const unsubscribe = () => {
      socket.onmessage = null;
    };

    return unsubscribe;
  });
}

function* listenForSocketMessages() {
  let socket;
  let socketChannel;

  try {
    socket        = yield call(createWebSocketConnection);
    socketChannel = yield call(createSocketChannel, socket);

    // tell the application that we have a connection
    yield dispatch(LiveDataActions.connectionSuccess());

    while (true) {
      // wait for a message from the channel
      const payload = yield take(socketChannel);

      // a message has been received, dispatch an action with the message payload
      yield dispatch(LiveDataActions.incomingEvent(payload));
    }
  } catch (error) {
    yield dispatch(LiveDataActions.connectionError('Error while connecting to the WebSocket'));
  } finally {
    if (yield cancelled()) {
      // close the channel
      socketChannel.close();

      // close the WebSocket connection
      socket.close();
    } else {
      yield dispatch(LiveDataActions.connectionError('WebSocket disconnected'));
    }
  }
}

export function* connect() {
  // starts the task in the background
  const socketTask = yield fork(listenForSocketMessages);

  // when DISCONNECT action is dispatched, we cancel the socket task
  yield take(LiveDataTypes.DISCONNECT);
  yield cancel(socketTask);
  yield dispatch(LiveDataActions.disconnectSuccess());
}