Detect Active Users in Angular Using NestJs and Socket.IO
A comparison between Socket.IO and SignalR
I wrote an article titled “Detect Active Users in Angular App Using SignalR ” a couple of years ago. It wasn’t a long time ago, but technology has evolved quickly. In the world of real-time web apps, Socket.IO is emerging.
SignalR and Socket.IO share many similarities. Both are designed for real-time bidirectional communications between web client and server and use WebSocket as the default transport protocol.
Similarities aside, SignalR is part of the .Net ecosystem, and Socket.IO is built for NodeJS. But in practice, how different is Socket.IO compared with SignalR? What are the pros and cons?
To answer those questions, I rewrote the sample app in the previous article using NestJS and Socket.IO.
Let me show you how this experiment goes.
Jump ahead:
- Setup a WebSocket Server with NestJs
- Configure NestJS Gateway
- Receive and Broadcast Messages with Socket.IO
- Manage the user session data with Cache Manager
- Angular Client
- Socket.IO vs SignalR
Overview
The following diagram illustrates the technology stack used in this contrived example. Reading my previous blog post, you will find that we use NestJS/Socket.IO instead of .Net Core/SignalR.
Setup a WebSocket Server with NestJs
NestJS provides the WebSocket module, which supporting two WebSocket platforms (Socket. IO and ws ) out-of-the-box. In this article, we will use Socket.IO.
To get started, let’s create a new NestJS app and install the necessary dependencies.
1 | nest new nest-waiting-room |
After setting up the NestJS app skeleton, we must add a Gateway for the new app.
Configure NestJS Gateway
Gateway is introduced in NestJS as a platform-agnostic interface to web socket platforms. We can generate a gateway with NestJS CLI as below.
1 | nest g gateway app |
Please note that the class is decorated with the @WebsocketGateway()
which gives us access to the web socket functionality.
We also implement 3 lifecycle hooks: OnGatewayInit
, OnGatewayConnection
and OnGatewayDisconnect
. They are self-explanatory from their name.
CORS must be enabled as below to allow the angular client to access the gateway from different domains.
@WebSocketGateway({ cors: true })
Receive and Broadcast Messages with Socket.IO
The core of the Gateway
class is to handle incoming and outgoing event messages.
To listen to incoming messages, we use @SubscribeMessage
decorator.
To send an Event to all connected clients, you will need to use the WebSocketServer
decorator and use the native WebSocket instance to emit a message:
1 | @WebSocketServer() server;// Boardcast message to all connected clients |
Manage the user session data with Cache Manager
Like the SignalR version, we use an in-memory cache to store the state. This is mainly for illustration. In a real-world project, consider persisting the state into a database or Redis, to make it more scalable.
The user session data is managed by the UserSessionCache
class. UserSessoinCache
Class is built on top of Cache Manager . It exposes CRUD operations for the user session data.
When updating the cache data, we set this sample app’s expiration time to 60 minutes.
When the user session data is cached, we also update the lastConnectedTime
property. If it’s 60 seconds more than the current time, we assume the user has disconnected.
Angular Client
To use the Socket.IO client in Angular, we need to install ngx-socket-io , an Angular wrapper, over Socket.IO client libraries.
1 | npm i @ngx-socket-io --save |
In App.module.ts, we declare the socket server config as below.
1 | const config: SocketIoConfig = { url: 'http://localhost:3000', options: {} }; |
We also need to import SocketIoModule
in AppModule
. This will initialize the client connection to the socket server whenAppModule
loads.
1 | imports: [ |
We create a WebScoketService
to handle the client-side events:
In the above code snippet, userPing
function invokes the socket.emit
to send the event to the socket server. This function is called in the waitingroom
Angular component every second so the server will be aware that the user is active on the page.
1 | this.interval = setInterval(() => { |
The waiting room page also has an activeUsers$
observable. It subscribes from the socket.IO server patientList
event. Thus, any change of connected users will be shown in real-time.
The final result is identical to the SignalR version!
Socket.IO vs. SignalR
Overall, I like Socket.IO. It’s surprisingly straightforward to set up and has all the required features.
Compared with the implementation using SignalR, I only need to write half the code to get the same features for both client and server. That’s proof that much less boilerplate code is needed when using Socket.IO.
Although we only use the most basic functionalities in this simple example, it’s worth highlighting that Socket.IO provides many other important features. It includes Rooms
, an arbitrary channel that can be used to broadcast events to a subset of clients. It also supports load balancing and data streaming.
Summary
Socket.IO enables bi-directional communication between web clients and servers. It adds a nice abstraction on top of WebSocket and exposes enough but not overly complicated APIs to get work done.
Another major benefit of using Socket.IO is the active and vibrant NodeJS community and ecosystem. I prefer to use NestJS/Socket.IO for future projects unless the project is based on the .Net platform.
The source code for the Angular client sample is here , and the NestJS sample can be found here .
- Title: Detect Active Users in Angular Using NestJs and Socket.IO
- Author: Sunny Sun
- Created at : 2022-01-07 00:00:00
- Updated at : 2024-08-16 19:46:17
- Link: http://coffeethinkcode.com/2022/01/07/detect-active-users-in-angular-using-netsjs-and-socket-io/
- License: This work is licensed under CC BY-NC-SA 4.0.