Total.js v5: Dynamic WebSocket Routing
Welcome back to our Beginner's Guide to Total.js! In the previous post, we introduced you to WebSocket routing and explored a simple real-time communication example. In this second part, we’ll delve deeper into dynamic WebSocket (ws) routing, which allows you to create more flexible and dynamic connections based on specific URL parameters, such as chat rooms or unique user IDs.
Dynamic routing is especially useful when building applications like multi-room chat systems or collaborative spaces where clients need to be grouped based on specific dynamic parameters.
What is Dynamic WS Routing?
Dynamic WS routing works similarly to dynamic HTTP routing, where certain parts of the URL are treated as variables. These variables can represent things like room names, user IDs, or session identifiers.
By using dynamic routing, you can create WS endpoints that are disigned to individual connections. For example, instead of creating separate WS routes for each room in a chat app, you can use a dynamic route like /chat/{room}/
where {room}
is a placeholder for the actual room name.
In Total.js, setting up a dynamic WS route is simple and effective, allowing you to handle custom parameters in your WS connections.
Setting up dynamic WS Routing
Let’s dive into a practical example where we create a dynamic WS route that allows users to connect to specific chat rooms. The dynamic part of the route will be the room name passed in the URL.
// File: /controllers/example.js
exports.install = function() {
// Define a WS route with a dynamic "room" parameter in the URL
ROUTE('SOCKET /{room}/', socket); // Data will be serialized/deserialized in JSON format
};
function socket($) {
// Access the dynamic room parameter
var room = $.params.room;
// Log the room name for debugging purposes
console.log('Connected to room:', room);
// Automatically destroy the controller when all clients disconnect
$.autodestroy();
// Event triggered when a client connects
$.on('open', function(client) {
// Send a welcome message to the newly connected client
client.send({ msg: 'Welcome to room ' + room });
});
// Event triggered when a client disconnects
$.on('close', function(client) {
console.log('Client disconnected from room:', room);
});
// Event triggered when a message is received from a client
$.on('message', function(client, message) {
// Log the received message
console.log('Message from client in room', room, ':', message);
});
}
How It Works:
- Dynamic Route: The
ROUTE('SOCKET /{room}/', socket)
defines a WS route where {room}
is a dynamic parameter. The actual room name will be extracted from the URL when a client connects.
- Accessing the Room Parameter: Inside the
socket
function, you can access the room name through $.params.room
. This allows you to differentiate between different rooms and handle them accordingly.
- ws Events: The standard WS events (
open
, message
, and close
) are used to manage the connection lifecycle. Each event can now handle interactions specific to the room.
- When a client connects, they receive a welcome message mentioning the room they’ve joined.
- The server logs messages received from clients, noting the room they came from.
- The server also logs when clients disconnect from specific rooms.
Example: Multi-Room Chat Application
Let’s enhance this example by creating a multi-room chat application. Users can connect to different chat rooms via dynamic WS URLs, and messages sent in one room are broadcasted to all clients in the same room.
// File: /controllers/chat.js
exports.install = function() {
ROUTE('SOCKET /chat/{room}/ @json', chat);
};
function chat($) {
var room = $.params.room;
console.log('New connection to room:', room);
$.autodestroy();
$.on('open', function(client) {
// Notify all clients in the room about a new user
broadcast('A new user has joined room: ' + room, client);
});
$.on('close', function(client) {
// Notify all clients in the room when a user leaves
broadcast('A user has left room: ' + room, client);
});
$.on('message', function(client, message) {
// Broadcast the received message to all clients in the same room
broadcast('Message from ' + room + ': ' + message.text, client);
});
// Broadcast function to send messages to all clients in the same room
function broadcast(msg, exceptClient) {
for (var id in $.connections) {
// Send the message to every client except the sender
if ($.connections[id] !== exceptClient) {
$.connections[id].send({ text: msg });
}
}
}
}
How This Example Works:
- Dynamic Room Routing: Users connect to specific rooms via URLs like
/chat/lobby/
or /chat/room1/
. The room name is extracted dynamically from the URL and used to manage messages within that room.
- Message Broadcasting: The
broadcast
function sends a message to all connected clients in the room, excluding the sender. This ensures that clients only receive messages meant for their room.
- Connection Events:
- When a client connects, all other clients in the room are notified.
- When a client sends a message, it’s broadcast to all clients in the room.
- When a client disconnects, the remaining clients are informed.
This simple structure allows you to scale easily, adding more functionality like private rooms, user authentication, or message logging.
Testing the Dynamic WS Server
To test the dynamic WS server, you can use ws clients such as Postman or Websocket King, or even create a simple HTML client to simulate the behavior.
Here’s an example HTML client that allows users to connect to different rooms dynamically:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Multi-Room Chat</title>
</head>
<body>
<h1>Multi-Room Chat</h1>
<div id="room">Room: <span id="roomName"></span></div>
<div id="messages"></div>
<input type="text" id="messageInput" placeholder="Type a message..." />
<button onclick="sendMessage()">Send</button>
<script>
const room = prompt('Enter room name:', 'lobby');
document.getElementById('roomName').innerText = room;
const ws = new WebSocket('ws://localhost:8000/chat/' + room + '/');
ws.onopen = function() {
console.log('Connected to room:', room);
};
ws.onmessage = function(event) {
const message = JSON.parse(event.data);
const messagesDiv = document.getElementById('messages');
const newMessage = document.createElement('div');
newMessage.innerText = message.text;
messagesDiv.appendChild(newMessage);
};
function sendMessage() {
const input = document.getElementById('messageInput');
const message = { text: input.value };
ws.send(JSON.stringify(message));
input.value = '';
}
</script>
</body>
</html>
Steps to Test:
- When you load the page, you’ll be prompted to enter a room name (e.g.,
lobby
, room1
, etc.).
- The client will connect to the WebSocket server using the dynamic route corresponding to the room.
- You can send messages by typing in the input field and clicking the "Send" button.
- Messages sent in the room are broadcast to all other clients connected to the same room.
Conclusion
Dynamic WebSocket routing in Total.js is a powerful feature that allows you to handle flexible, real-time interactions based on dynamic URL parameters. Whether you're building a multi-room chat application, a real-time collaborative tool, or a game server, dynamic routing makes it easy to manage different contexts for different users.
In this post, we’ve covered:
- How to set up a dynamic WebSocket route.
- Accessing URL parameters in WebSocket connections.
- Building a multi-room chat application with dynamic room names.
Stay tuned for the next installment, where we’ll explore more advanced WSocket use cases.
Thanks for reading, and feel free to experiment with dynamic WebSocket routing in your projects!