lore-hook-websockets-socketio

WARNING! This hook is a proof of concept, and has never been used in a production application. It was developed to prove that Lore's architecture accounted for the unique concerns that come with using websockets in a real application, and that the interface developed could work with Socket.io.

Provides an implementation of lore-websockets designed to work with socket.io

lore-hook-websockets-socketio

Source code for this hook can be found on GitHub at this link.

Purpose

This hook is built on top of the lore-websockets library and implements the interface for socket.io.

This hook does two things:

  1. It provides an implementation of the lore-websockets interface that can be used with socket.io.
  2. Provides a set of methods and dispatchers that can be used by default with any model in the application (using some overridable conventions)

Example

See the websockets example to see this hook in action.

Implementation

Implementing support for socket.io is fairly straight forward. The implementation just needs to know the serverUrl (which is the root URL for the socket.io server), the namespace (if your server uses one) and the event that will be emitted when CRUD operations occur for the desired resource.

import io from 'socket.io-client';
import { WebSocketConnection } from 'lore-websockets';

export default WebSocketConnection.extend({

  // These three values are provided by the project configuration or conventions
  serverUrl: 'http://localhost:1337',
  namespace: '/posts',
  event: 'post',

  connect: function() {
    const url = this.serverUrl + this.namespace;
    this.socket = io(url);
  },

  subscribe: function() {
    this.socket.on(this.event, this.dispatch);
  },

  unsubscribe: function() {
    this.socket.off(this.event, this.dispatch);
  }

});

Default Methods and Dispatchers

The code below illustrates the general setup process used when the hook creates the WebSocket instance:

// these "guess" the namespace and event based on conventions
// can be provided explicitly by the user
var conventions = {
  namespace: config.pluralize ? `${pluralize(modelName)}` : `${modelName}`,
  event: modelName
};

// these three dispatchers are provided by default to update the Redux store
// based on data that was created, updated or deleted by other users.
var dispatchers = {
  created: blueprints.dispatchers.created(modelName, Model)(store),
  updated: blueprints.dispatchers.updated(modelName, Model)(store),
  destroyed: blueprints.dispatchers.destroyed(modelName, Model)(store)
};

// override the SocketIo WebSocketConnection with conventions and configuration
var CustomWebSocketConnection = SocketIoWebSocketConnection.extend(_.extend(conventions, config));

// make the connection accessible under lore.websockets, i.e. lore.websockets.post for example.
lore.websockets[modelName] = new CustomSocketIoWebSocketConnection(dispatchers);

If you want to listen for events during the entire lifecycle of your application, a good place to connect and listen for data is within the componentDidMount method of the Master component, like so:

// src/components/Master.js
createReactClass({
  componentDidMount: function() {
    lore.websockets.post.connect();
    lore.websockets.post.subscribe();
  },

  componentWillUnmount: function() {
    lore.websockets.post.unsubscribe();
  }
})

Calling lore.websockets.post.connect() will cause the websocket instance to connect with the server. Calling lore.websockets.post.subscribe() will cause it to listen for the event it was configured for, such as events called post that contain data about Post resources that have been created, updated or deleted by other users.