Real-time broadcasting integration in Laravel – Part 2

This is the second of a three-part series on implementing real-time broadcasting in Laravel using Redis, Node.js and Socket.io. The first part covered the basic workflow of the implementation, including firing an event to broadcast data. The third part deals with consuming the broadcast data by connecting to a Websocket channel.

In this part, we’ll setup the socket server, which does the following:

  • Listens to Redis channel for messages from any events that have been fired
  • Capture and broadcast the messages received on a Websocket

First, we will set up the Node.js server. In our implementation, this was setup on a separate machine to support autoscaling. For ease, we’ll refer to it as the “publishing” server.

Install required packages

We need to make sure that Node.JS and Redis are installed on this server.

The command ‘node -v’ on the command prompt should return the node version number, if node is installed and working. If not installed, please install Node.js and also its package manager npm, which would make it easy to install the other required packages.

The command ‘redis-cli ping’ will  return ‘pong’ if Redis is installed and running. If not, please install Redis and ensure it is working.

The following packages should also be installed on the publishing server:

  • express: This package is a framework for Node.js (just like Laravel is for php), which makes it easy for us to set up the node server.
  • ioredis: A Redis client for Node.js used to listen to messages on the Redis host.
  • socket.io: This package is used to listen to and broadcast data
  • dotenv: This package is used to access the configuration variables from the environment.

The following npm command installs all these required packages in one go:

npm install express ioredis socket.io dotenv --save

Socket server script

The following is the socket server script, set up using Node.js and Socket.io.

'use strict';
var app = require('express')();
var server = require('http').Server(app);
var io = require('socket.io')(server);
require('dotenv').config();

var redisPort = process.env.REDIS_PORT;
var redisHost = process.env.REDIS_HOST;
var ioRedis = require('ioredis');
var redis = new ioRedis(redisPort, redisHost);
redis.subscribe('action-channel-one', 'action-channel-two');
redis.on('message', function (channel, message) {
    message  = JSON.parse(message);
    io.emit(channel + ':' + message.event, message.data);
});

var broadcastPort = process.env.BROADCAST_PORT;
server.listen(broadcastPort, function () {
    console.log('Socket server is running.’);
});

The first three lines setup the Socket.io object io which will be broadcasting the data on the socket server. The require(‘dotenv’).config(); statement accesses the .env file on the Publishing server, and converts the values into a process.env JSON object. With this, we can change or update the redisHost, redisPort and broadcastPort values in the .env file without touching the server script.

The redisPort and redisHost values are used to connect to the Redis server. These port and host values should match the settings in the “Configure Redis” section in Part 1 of this blog series.

With the redis object created by connecting to the Redis server/port, we subscribe to the channels on which data will be broadcast. If you remember, in the previous part, we had broadcast the data on ‘action-channel-one’ from the ActionEvent class. If there are multiple channels that data is being broadcast on, we can setup the redis object to subscribe to multiple channels by adding them in the subscribe() call, as has been shown for ‘action-channel-two‘ in the script above.

When the ActionEvent event is fired and data is pushed onto Redis, the redis.on(‘message’) event is triggered, and the callback function is executed. The function accepts two variables – the channel name (‘action-channel-one‘) and the message object. The message object has the event name and the associated data. We will first parse the message (JSON), and then emit (i.e. broadcast) the message on a specific port (broadcastPort). Here the channel name is modified to channel:eventName, which would mean, for our example ‘action-channel-one:ActionEvent‘. This is the channel name that the Websocket on the frontend would be listening to.

The server.listen directive sets the port number (broadcastPort) on which the socket server listens for incoming requests. The port number can be any supported port on the server, which is not currently used by other processes. When creating the Websocket, we’ll connect the Websocket to the socket server on this specific port number.

If the script is named as socketScript.js, you can run it by calling ‘node socketScript.js’. The console should print out “Socket server is running.” This means the socket server script has been set up properly.

We can now move on to the concluding part which deals with creating the Websocket and consuming broadcast data.

For reference purposes, I’m adding example values for .env constants used in the code above.

BROADCAST_DRIVER=redis 
REDIS_HOST= 123.12.12.12 //127.0.0.1 if localhost 
REDIS_PASSWORD=yourRedisPassword 
REDIS_PORT=6379 // Redis port number, by default it is 6379 
BROADCAST_PORT=3444 //Can be any port number not used by other processes 
PUBLISHER_URL=http://app.publisher // The URL at which Publishing Server can be accessed

Read more in the concluding part of this series. Contact us if you are looking for a Laravel developer job in Kochi, India – or if you are looking to hire Laravel developers.