Real-time interactive applications

Instant messaging is used in many scenarios in modern Web applications, such as payment callbacks and three-way logins. These business scenarios basically follow the following process:

  • The client triggers the relevant business and generates the actions of the third-party application (such as payment)
  • The client waits for the response result from the server (the user has completed operations on the third-party application).
  • Third party application notifies server of processing result (payment completed)
  • The server notifies the client of the result
  • The client gives feedback based on the results (jump to the payment success page)

In the past, in order to achieve such instant communication, the client can correctly respond to the processing result, the most common technology is polling, because HTTP protocol is one-way, the client can only ask the server over and over again. This method has obvious defects, not only occupy server resources, but also can not get real-time server processing results.

We can now handle real-time interactions using the WebSocket protocol, which is a two-way protocol that allows the server to actively push information to the client. In this article we will leverage Laravel’s powerful event system to build real-time interactions. You will need the following knowledge:

  • Laravel Event
  • Redis
  • Socket.io
  • Node.js

Redis

To start, we need to start a Redis service and configure it in the Laravel application, because we need redis subscription and publishing mechanisms for instant messaging throughout the process.

Redis is an open source and efficient key-value pair storage system. It typically acts as a data structure server to store key-value pairs, which can support strings, hashes, lists, collections, and ordered combinations. To use Redis in Laravel you need to install predis/predis package files in Composer.

configuration

The Redis application configuration file is stored in config/database.php. In this file, you can see a Redis array containing the Redis service information:

'redis' = > [' cluster' = > false, 'default' = > [' host '= >' 127.0.0.1 ', 'port' = > 6379, 'database' = > 0,],]Copy the code

If you change the port of the Redis service, keep the port in the configuration file the same.

Laravel Event

Here we need Laravel’s powerful event broadcast capabilities:

Broadcast events

Many modern applications use Web Sockets to implement real-time interactive user interfaces. When some data changes on the server, a message is passed to the client for processing via a WebSocket connection. To help you build this type of application. Laravel makes it easy to broadcast events over WebSocket connections. Laravel allows you to broadcast events to share event names to your server-side and client-side JavaScript frameworks.

configuration

All event broadcast configuration options are stored in the config/broadcasting.php configuration file. Laravel comes with several available drivers such as Pusher, Redis, and Log. We will use Redis as the broadcast driver, relying on the Predis /predis class library.

Since the default broadcast driver uses pusher, we need to set BROADCAST_DRIVER=redis in the.env file.

We created a WechatLoginedEvent event class to broadcast after the user scans the wechat login:

token = $token; $this->channel = $channel; } /** * Get the channels the event should be broadcast on. * * @return array */ public function broadcastOn() { return [$this->channel]; } /** * Get the name the event should be broadcast on. * * @return string */ public function broadcastAs() { return 'wechat.login'; }}Copy the code

BroadcastOn returns an array of broadcast channels. BroadcastAs returns a string of broadcast events. Laravel returns the full name of the event class by default. Here is the App/Events/WechatLoginedEvent.

The most important thing is that you need to manually implement the ShouldBroadcast contract for this class. Laravel automatically added the namespace when it generated the event, and the contract only constrained the broadcastOn method.

The event is triggered by a simple line of code:

event(new WechatLoginedEvent($token, $channel));Copy the code

This action automatically triggers the execution of the event and broadcasts the information out. The underlying broadcast operation relies on redis’ subscription and publishing mechanism. RedisBroadcaster will publish the publicly accessible data of an event via a given channel. If you want more control over public data, you can add the broadcastWith method to the event, which should return an array:

/**
 * Get the data to broadcast.
 *
 * @return array
 */
 public function broadcastWith() 
 {
   return ['user' => $this->user->id];
 }Copy the code

Node. Js and Socket. IO

For published information, we need a service to connect, which can subscribe to redis published, and can forward information to the WebSocket protocol, here we can borrow Node.js and socket. IO to very convenient construction of this service:

// server.js var app = require('http').createServer(handler); var io = require('socket.io')(app); var Redis = require('ioredis'); var redis = new Redis(); app.listen(6001, function () { console.log('Server is running! '); }); function handler(req, res) { res.writeHead(200); res.end(''); } io.on('connection', function (socket) { socket.on('message', function (message) { console.log(message) }) socket.on('disconnect', function () { console.log('user disconnect') }) });  redis.psubscribe('*', function (err, count) { }); redis.on('pmessage', function (subscrbed, channel, message) { message = JSON.parse(message); io.emit(channel + ':' + message.event, message.data); });Copy the code

Here we use Node.js to import socket. IO server and listen on port 6001. We use redis’ pSUBSCRIBE command to use wildcards to quickly subscribe in batches, and then forward messages via WebSocket when triggered.

Socket. IO client

On the web front end, we need to introduce socket. IO client to open communication with server port 6001 and subscribe to channel events:

// client.js
let io = require('socket.io-client')

var socket = io(':6001')
      socket.on($channel + ':wechat.login', (data) => {
        socket.close()
        // save user token and redirect to dashboard
})Copy the code

At this point the communication loop is closed and the development process looks like this:

  • Build an event in Laravel that supports broadcast notifications
  • Set the channel and event name to be broadcast
  • Set up the broadcast to use the Redis driver
  • Provide a continuous service for subscribing to Redis releases and pushing them to clients via the WebSocket protocol
  • The client opens the server WebSocket tunnel, subscribes to the event, and responds to the push of the specified event.

PS: Welcome to pay attention to Laravel special topic, also welcome to contribute Laravel related articles :), the author’s knowledge and skill level is limited, if you have a better design scheme welcome to discuss and exchange, if there is any mistake, please also criticize and correct, thank you 🙂