How can I create live search using socket.io?
I use RethinkDB + Node + Express + Socket.io + Redux + React, I am listening to event (it is changefeed created using rethinkdb), which sends me lets say 10 items on client side and displaying them using react.
Now I want to create live search, which sends query to server, searches for results in DB, returns first 10 results and sends them to client with socket.io
// emit events for changes
r.table('stackoverflow_questions')
.changes({ includeInitial: true, squash: true })
.limit(10)
.run(connection)
.then(changefeedSocketEvents(socket, 'topic'))
-
// Socket.io events for changefeed
module.exports = function (socket, entityName) {
return function (rows) {
rows.each(function (err, row) {
if (err) { return console.log(err) } else if (row.new_val && !row.old_val) {
socket.emit(entityName + ':insert', row.new_val)
} else if (row.new_val && row.old_val) {
socket.emit(entityName + ':update', row.new_val)
} else if (row.old_val && !row.new_val) {
socket.emit(entityName + ':delete', { id: row.old_val.id })
}
})
}
}
I don't have Idea how you can achieve that using socket.io, do you have to create custom socket event listeners on the fly for every custom query? (It sounds ridiculous to me, I think, that there should be a simple way)
I found a solution, here is a bare minimum example:
// server.js
const express = require('express')
const app = express()
const http = require('http')
const server = http.Server(app)
const io = require('socket.io')(server)
app.use(express.static('client'))
io.on('connection', function(client){
setInterval(() => io.emit('found', 'dfasdfadsfasdfasdf'), 5000)
console.log('connected with socket: ' + client.id)
client.on('search', function (text) {
const data = Math.random()
io.emit('found', data + text)
})
client.on('disconnect', function(){})
})
app.get('/')
server.listen(3000)
-
<!- index.html ->
<!DOCTYPE html>
<html>
<head>
<script src="/socket.io/socket.io.js"></script>
<script src="./client.js"></script>
<title>socket-io-live-search</title>
</head>
<body>
<div id='search'>
<input type ='text' />
</div>
</body>
</html>
-
// client.js
var socket = io()
const loaded = () => {
const inputEl = document.querySelector('#search input')
inputEl.oninput = (e) => socket.emit('search', e.target.value)
}
socket.on('found', (data) => console.log('found: ' + data))
document.addEventListener('DOMContentLoaded', loaded, false)
Related
I'm a new member of socket.io. I'm using elephant.io and socket.io, I need to send some notification data to a specific client. but I can't use a socket.Id is autogenerated id, I need to use my user id, so how can I send the data please give me a server-side and client-side.
Another way to do it is to have a different event listener for every room then emit something like message_${room_id}.
Since you haven't provided any reference code the following code may not be specific to your use-case and will require adjusting.
backend-server.js
// Define variables
const express = require('express');
const app = express();
const server = require('http').createServer(app);
const io = require('socket.io')(server);
// room_id generator
function makeid(length) {
let result = '';
let characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
let charactersLength = characters.length;
for (let i = 0; i < length; i++) {
result += characters.charAt(Math.floor(Math.random() * charactersLength));
}
return result;
}
app.get('/request-room', function(req, res) { // Listen for the incoming request to /request/room
let room_id = makeid(20); // Generate a roomID 20 characters long
res.redirect('/rooms/' + room_id); // Redirect the user to the room
});
app.get('/rooms/:roomId', function(req, res) { // Listen for the incomign request to a random room
io.emit(`message_${req.params.roomId}`, { message: 'A user has joined your room!' }); // Emits to the room that a user has joined
// Send the user some sort of HTML page
});
server.listen(3000, () => console.log('server is online');
Then in your HTML file, listen for the message
<!DOCTYPE html>
<html lang="en">
<body>
<!-- Some HTML script -->
</body>
<script src="/socket.io/socket.io.js"></script> <!-- Import socket.io -->
<script>
let socket = io.connect(); // Connect to the server
let room_id = (window.location.href).split('/')[(window.location.href).split('/').length - 1]; // Get the last param in the URL
socket.on(`message_${room_id}`, function(data) { // Listen for the message specific to the room
// Do something with the data
});
</script>
Currently trying to learn how socket.io works and to create a room based game, but having trouble to get clients to the same room after trying to move my code in a seperated file.
If I use the same code from game.js in my app.js file within io.on("connection")... i´m able to access the room and put players in the same room.
app.js
const express = require("express");
const cors = require("cors");
var http = require("http");
const game = require("./core/game/game");
const app = express();
const port = process.env.PORT || 4001;
const index = require("./routes/index");
const server = http.createServer(app);
const io = require("socket.io")(server, {
cors: {
origin: "*",
},
});
/
app.use(cors({ origin: "*" }));
app.use("/", index);
// Reduce the logging output of Socket.IO
/* io.set('log level',1); */
io.on("connection", (socket) => {
console.log("New client connected");
game.initGame(io, socket);
});
server.listen(port, () => {
console.log(`listening on *:${port}`);
});
game.js
var io;
var gameSocket;
/**
* This function is called by index.js to initialize a new game instance.
*
* #param sio The Socket.IO library
* #param socket The socket object for the connected client.
*/
exports.initGame = function (sio, socket) {
io = sio;
gameSocket = socket;
gameSocket.emit("connected", { message: "You are connected!" });
// Host Events
gameSocket.on("hostCreateNewGame", createRoom);
/* gameSocket.on("hostRoomFull", hostPrepareGame);
gameSocket.on("hostCountdownFinished", hostStartGame);
gameSocket.on("hostNextRound", hostNextRound); */
// Player Events
gameSocket.on("playerJoinGame", addPlayer);
/* gameSocket.on("playerAnswer", playerAnswer);
gameSocket.on("playerRestart", playerRestart); */
};
async function createRoom(data) {
console.log("Create Session");
console.log(data);
console.log(data.username);
var gameId = (Math.random() * 100000) | 0;
console.log(data.username);
console.log(gameId);
//gameSocket.username = username;
gameSocket.join(gameId);
}
async function addPlayer(data) {
console.log("JOIN Session");
console.log(data.gameId);
//console.log(socket.username);
const clients = await io.in(data.gameId).allSockets();
console.log(clients);
if (!clients) {
console.error("[INTERNAL ERROR] Room creation failed!");
}
if (clients.size === 0) {
console.log("room does not exist");
return;
}
console.log(await io.in(data.gameId).allSockets());
gameSocket.username = data.username;
gameSocket.join(gameId);
console.log(await io.in(data.gameId).allSockets());
io.to(data.gameId).emit("joinSuccess", { message: "JUHU" });
If I try to use this code, the clients are always undefined which means I cannot the room from my current io object
const clients = await gameSocket.in(data.gameId).allSockets(); //undefined
Can someone show me what I would need to change in order to access the right io object and find the rooms. Maybe I´m trying to follow a bad approach here when trying to seperate the code from my app.js file.
Any help would be great.
Got this working finally.
The issue was that this returned a real number
var gameId = (Math.random() * 100000) | 0;
Whereas the value send to addPlayers function was a String...
I am somehow able to run Websocket but the problem is that it is sending me object blob on on message event while i want to send the text.
Here is my websocket server code:
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 })
var sockets = [];
wss.on('connection', ws => {
//var id = ws.upgradeReq.headers['sec-websocket-key'];
//console.log("New connection id ::", id);
//w.send(id);
sockets.push(ws);
console.log("New client connected"+ ws);
ws.on('message', message => {
console.log(`Received message => ${message}`)
//var id = ws.upgradeReq.headers['sec-websocket-key'];
//var mes = JSON.parse(message);
//sockets[message.to].send(mes.message);
// console.log('Message on :: ', id);
//console.log('On message :: ', message);
sockets.forEach(w=> {
w.send(message);
});
})
ws.send('Welcome by server!')
})
Client side Code Excerpt
connection.onmessage = (e) => {
document.getElementById("ReceviedText").innerHTML += ("<li>" + e.data + "</li>");
// ReceviedText
console.log(e.data);
console.log(e);
var reader = new FileReader(e.data);
console.log(reader.result);
//console.log(reader.readAsText());
console.log(reader.readAsText(e.data));
}
I found that I can convert blob to string using file reader but it returning null.
I had the same issue with an object array. Fixed it by converting the data as a JSON string with JSON.stringify. On the client, you can get the data with JSON.parse.
Server
sockets.forEach(w => {
w.send(JSON.stringify(message));
});
Client
connection.onmessage = (message: object) => {
console.log(JSON.parse(message['data']));
}
I also faced the same issue. I can fix it by adding {binary:isBinary} in Server.
Here is my code:-
wss.on('connection', function connection(ws) {
ws.on('message', function incoming(data,isBinary) {
wss.clients.forEach(function each(client) {
if (client !== ws && client.readyState === WebSocket.OPEN) {
client.send(data, { binary: isBinary });
}
})
})
})
I had the same issue when I send the message via firefox web socket client extension.
On the server side, I fixed it by converting the data as a JSON string with JSON.stringify. On the client, you can get the data with JSON.parse.
Server
wss.clients.forEach(function each(client) {
if (client !== ws && client.readyState === WebSocket.OPEN) {
console.log('data %s', data);
// client.send(data);
// this is to solve the issue where web socket client
// send data as blob instead of string
client.send(JSON.stringify(data));
}
});
Client
ws.onmessage = (e) => {
const arr = JSON.parse(e.data).data;
let newData = '';
arr.forEach((element) => {
newData+=String.fromCharCode(element);
});
console.log('newData ', newData);
};
I have resolved this issue..:
//index.js (Server)
const express = require('express');
const http = require('http');
const WebSocket = require("ws");
const PORT = 3000;
const server = http.createServer(express);
const wss = new WebSocket.Server({server});
wss.on('connection',function connection(ws){
ws.on('message',function incoming(message){
console.log("Received: "+message);
wss.clients.forEach(function each(client){
if(client!==ws && client.readyState===WebSocket.OPEN)
{
client.send(JSON.stringify(message));
}
});
});
});
server.listen(PORT,()=>console.log(`Server is listening to PORT ${PORT}`));
<!-- index.html page -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Client 1</title>
</head>
<body>
<input type="text" name="messageBox" id="messageBox">
<button type="button" id="sendBtn">Send</button>
<div class="container">
<div class="receive-message">
<p id="message"></p>
</div>
</div>
</body>
<script type="text/javascript">
var sendBtn = document.getElementById("sendBtn");
var messageBox = document.getElementById("messageBox");
var socket = new WebSocket("ws://localhost:3000");
sendBtn.addEventListener("click",()=>{
let val = messageBox.value;
socket.send(val);
});
socket.addEventListener("open",function(event){
socket.send("Connected.....");
});
socket.addEventListener('message',function(event){
var string_arr =JSON.parse(event['data']).data;
var string = "";
string_arr.forEach(element => {
string+=String.fromCharCode(element);
});
console.log(string);
});
</script>
</html>
FileReader.readAsText() is an event based API, as mentioned in MDN docs.
So you need to set reader.onload:
const reader = new FileReader();
reader.onload = function(evt) {
console.log(evt.target.result);
};
reader.readAsText(e.data);
Also, Blob.text() can be used.
websocket.addEventListener("message", e => {
e.data.text().then(txt=>console.log(txt))
});
Docs describes the difference between these two:
Blob.text() returns a promise, whereas FileReader.readAsText() is an
event based API. Blob.text() always uses UTF-8 as encoding, while
FileReader.readAsText() can use a different encoding depending on the
blob's type and a specified encoding name.
on the server side
ws.on('message', function message(data, isBinary) {
wss.clients.forEach(function each(client) {
if (client !== ws && client.readyState === WebSocket.OPEN) {
client.send(data, { binary: isBinary });
}
});
});
and on the client side
socket.addEventListener('message', (event, isBinary) =>
console.log(event.data)
})
the isBinary parameter solved the problem for me
I had a particularly confusing situation, while using Koa, that required the client side to do double duty:
//server side
myCtx.websocket.send( JSON.stringify( message ) );
// client side
let msg = JSON.parse( event.data );
let data = JSON.parse( String.fromCharCode( ...msg.data ) );
On the server if I just sent the message, it would show up as a blob on the client side.
On the client side, after I parsed the event.data the data was a binary array, [ 123, 34, 116...] so had to do the String.fromCharCode() call. The three dots ... is the javascript spreader operator, to get the whole array.
I'm running the below node-rdkafka code in Eclipse as Node.js application. This is the sample code from https://blizzard.github.io/node-rdkafka/current/tutorial-producer_.html
I want to run this in a test server and call from iOS Mobile application.
I knew about running node.js app in AWS.
Question I: Is there any other options to run in a free test server environment like Tomcat?
Question II: Even If I am able to run this node.js app in a server, how do i call from a mobile application? Do I need to call producer.on('ready', function(arg) (or) What function i need to call from Mobile app?
var Kafka = require('node-rdkafka');
//console.log(Kafka.features);
//console.log(Kafka.librdkafkaVersion);
var producer = new Kafka.Producer({
'metadata.broker.list': 'localhost:9092',
'dr_cb': true
});
var topicName = 'MyTest';
//logging debug messages, if debug is enabled
producer.on('event.log', function(log) {
console.log(log);
});
//logging all errors
producer.on('event.error', function(err) {
console.error('Error from producer');
console.error(err);
});
//counter to stop this sample after maxMessages are sent
var counter = 0;
var maxMessages = 10;
producer.on('delivery-report', function(err, report) {
console.log('delivery-report: ' + JSON.stringify(report));
counter++;
});
//Wait for the ready event before producing
producer.on('ready', function(arg) {
console.log('producer ready.' + JSON.stringify(arg));
for (var i = 0; i < maxMessages; i++) {
var value = new Buffer('MyProducerTest - value-' +i);
var key = "key-"+i;
// if partition is set to -1, librdkafka will use the default partitioner
var partition = -1;
producer.produce(topicName, partition, value, key);
}
//need to keep polling for a while to ensure the delivery reports are received
var pollLoop = setInterval(function() {
producer.poll();
if (counter === maxMessages) {
clearInterval(pollLoop);
producer.disconnect();
}
}, 1000);
});
/*
producer.on('disconnected', function(arg) {
console.log('producer disconnected. ' + JSON.stringify(arg));
});*/
//starting the producer
producer.connect();
First of all, you need an HTTP server. ExpressJS can be used. Then, just tack on the Express code basically at the end, but move the producer loop into the request route.
So, start with what you had
var Kafka = require('node-rdkafka');
//console.log(Kafka.features);
//console.log(Kafka.librdkafkaVersion);
var producer = new Kafka.Producer({
'metadata.broker.list': 'localhost:9092',
'dr_cb': true
});
var topicName = 'MyTest';
//logging debug messages, if debug is enabled
producer.on('event.log', function(log) {
console.log(log);
});
//logging all errors
producer.on('event.error', function(err) {
console.error('Error from producer');
console.error(err);
});
producer.on('delivery-report', function(err, report) {
console.log('delivery-report: ' + JSON.stringify(report));
counter++;
});
//Wait for the ready event before producing
producer.on('ready', function(arg) {
console.log('producer ready.' + JSON.stringify(arg));
});
producer.on('disconnected', function(arg) {
console.log('producer disconnected. ' + JSON.stringify(arg));
});
//starting the producer
producer.connect();
Then, you can add this in the same file.
var express = require('express')
var app = express()
app.get('/', (req, res) => res.send('Ready to send messages!'))
app.post('/:maxMessages', function (req, res) {
if (req.params.maxMessages) {
var maxMessages = parseInt(req.params.maxMessages);
for (var i = 0; i < maxMessages; i++) {
var value = new Buffer('MyProducerTest - value-' +i);
var key = "key-"+i;
// if partition is set to -1, librdkafka will use the default partitioner
var partition = -1;
producer.produce(topicName, partition, value, key);
} // end for
} // end if
}); // end app.post()
app.listen(3000, () => console.log('Example app listening on port 3000!'))
I don't think the poll loop is necessary since you don't care about the counter anymore.
Now, connect your mobile app to http://<your server IP>:3000/ and send test messages with a POST request to http://<your server IP>:3000/10, for example, and adjust to change the number of messages to send
I might be late on this but this is how I did using promises and found it better than have a time out etc.
const postMessageToPublisher = (req, res) => {
return new Promise((resolve, reject) => {
producer.connect();
producer.setPollInterval(globalConfigs.producerPollingTime);
const actualBody = requestBody.data;
const requestBody = req.body;
const topicName = req.body.topicName;
const key = requestBody.key || uuid();
const partition = requestBody.partition || undefined;
const data = Buffer.from(JSON.stringify(udpatedBody));
/**
* Actual messages are sent here when the producer is ready
*/
producer.on(kafkaEvents.READY, () => {
try {
producer.produce(
topic,
partition,
message,
key // setting key user provided or UUID
);
} catch (error) {
reject(error);
}
});
// Register listener for debug information; only invoked if debug option set in driver_options
producer.on(kafkaEvents.LOG, log => {
logger.info('Producer event log notification for debugging:', log);
});
// Register error listener
producer.on(kafkaEvents.ERROR, err => {
logger.error('Error from producer:' + JSON.stringify(err));
reject(err);
});
// Register delivery report listener
producer.on(kafkaEvents.PUBLISH_ACKNOWLEDGMENT, (err, ackMessage) => {
if (err) {
logger.error(
'Delivery report: Failed sending message ' + ackMessage.value
);
logger.error('and the error is :', err);
reject({ value: ackMessage.value, error: err });
} else {
resolve({
teamName: globalConfigs.TeamNameService,
topicName: ackMessage.topic,
key: ackMessage.key.toString()
});
}
});
});
};
Please note that kafkaEvents contains my constants for the events we listen to and it is just a reference such as kafkaEvents.LOG is same as event.log
and also the calling function is expecting this to a promise and accordingly we user .then(data => 'send your response to user from here') and .catch(error => 'send error response to user
this is how I achieved it using promises
How can I use dynamic namespaces in socket.io.
I'm looking in the (poor) documentation, and it says that namespaces must be used like this:
io.of('/news')
io.of('/akfda')
To use a namespace you do io.of("/namespace").
Do I need to register every single namespace in the server? Maybe I want a namespace for dynamic content.
How can I do something like :
io.of('/:somethign/:id')
Socket.IO supports 'rooms' (https://github.com/LearnBoost/socket.io/wiki/Rooms), you can use it instead of namespaces. Also when you need dynamic in routes (and you using express in your app) - best way is to use use route-engine from express box.
Best way to do dynamic routing with Express.js (node.js)
Using routes in Express-js
http://expressjs.com/api.html#app.routes
http://shtylman.com/post/expressjs-re-routing/
http://jordanhoff.com/post/22602013678/dynamic-express-routing
However, if you still think that you need dynamic in namespaces in socket.io, here is small example how it can be implemented:
User-side:
var connect = function (ns) {
return io.connect(ns, {
query: 'ns='+ns,
resource: "socket.io"
});
}
var socket = connect('/user/12');
Server-side:
var url = require('url');
, ev = new events.EventEmitter()
// <ns name>: <ns regexp>
var routes = {
// /user/:id
'user': '^\\/user\\/(\\d+)$',
// /:something/:id
'default': '^\\/(\\\w+)\\/(\\d+)$'
};
// global entry point for new connections
io.sockets.on('connection', function (socket) {
// extract namespace from connected url query param 'ns'
var ns = url.parse(socket.handshake.url, true).query.ns;
console.log('connected ns: '+ns)
//
for (var k in routes) {
var routeName = k;
var routeRegexp = new RegExp(routes[k]);
// if connected ns matched with route regexp
if (ns.match(routeRegexp)) {
console.log('matched: '+routeName)
// create new namespace (or use previously created)
io.of(ns).on('connection', function (socket) {
// fire event when socket connecting
ev.emit('socket.connection route.'+routeName, socket);
// #todo: add more if needed
// on('message') -> ev.emit(...)
});
break;
}
}
// when nothing matched
// ...
});
// event when socket connected in 'user' namespace
ev.on('socket.connection route.user', function () {
console.log('route[user] connecting..');
});
// event when socket connected in 'default' namespace
ev.on('socket.connection route.default', function () {
console.log('route[default] connecting..');
});
I hope this will help you!
I would use "rooms" to support your dynamic content.
Server Side
var server = require('http').createServer(),
io = require('socket.io')(server);
io.on('connection', function(socket){
var room = socket.handshake['query']['r_var'];
socket.join(room);
console.log('user joined room #'+room);
socket.on('disconnect', function() {
socket.leave(room)
console.log('user disconnected');
});
socket.on('chat message', function(msg){
io.to(room).emit('chat message', msg);
});
});
server.listen(3000);
Client Side
var socket_connect = function (room) {
return io('localhost:3000', {
query: 'r_var='+room
});
}
var random_room = Math.floor((Math.random() * 2) + 1);
var socket = socket_connect(random_room);
socket.emit('chat message', 'hello room #'+random_room);
....
As of version 2.1.1 I was able to make it work with this:
wss.of((nsp, query, next) => {
const { token } = query;
// Do your authentication or whatever here...
// If success
next(null, true);
}).on('connect', (socket) => {
// socket connected to your namespace
});
Server
var MAX_CLIENTS = 5;
var namespace_queue = [];
function searchObjectOnArray(nameKey, myArray) {
for (var i = 0; i < myArray.length; i++) {
if (myArray[i].id === nameKey) {
return myArray[i];
}
}
}
function createNamespace(data){
var ns = {
//id: require('node-uuid')(),
id : data.name,
clients: 0,
};
namespace_queue.push(ns);
return ns;
}
createNamespace({name: 'primer'});
io.of('').on('connection', function(socket){
console.log('-' + socket.id);
/// Welcome to the new client
socket.emit('Welcome', {SocketId : socket.id});
socket.on('JoinToApp', function (data, callback) {
var namespaceToConnect = searchObjectOnArray(data.namespace, namespace_queue)
if(namespaceToConnect.clients <= MAX_CLIENTS){
var dynamicNamespace = io.of('/' + namespaceToConnect.id);
dynamicNamespace.on('connection', function(ns_socket){
console.log('user connected to ' + namespaceToConnect.id);
dynamicNamespace.emit('hi', 'everyone!');
});
namespaceToConnect.clients++;
}
callback({namespaces:namespace_queue});
})
socket.on('createNamespace',function(data,join_cb){
createNamespace(data);
join_cb({message:'Namespace created'});
});
});
Client
<input id="namespaceInput" type="text" placeholder="New namespace name">
<input id="namespaceToConnect" type="text" placeholder="namespace to connect">
<button onclick="javascript: createNamespace()">Create Namespace</button>
<button onclick="javascript: joinToNamespace()">Connect to Namespace</button>
<script src="https://cdn.socket.io/socket.io-1.4.5.js"></script>
<script>
var socket = null;
(function(){
socket = io.connect('http://localhost:3000/');
})()
function createNamespace(){
var namespaceName = document.getElementById("namespaceInput").value;
socket.emit('createNamespace', {name : namespaceName}, function(data){
alert(data.message);
})
}
function joinToNamespace(){
var name = document.getElementById("namespaceToConnect").value;
socket.emit('JoinToApp', {namespace: name}, function(data){
console.log('Namespaces created:');
console.log(data)
var ns_socket = io.connect('http://localhost:3000/' + name);
ns_socket.on('connect',function(){
console.log('joined namespace ' + name);
});
ns_socket.on('hi', function(data){
console.log('hi ' + data)
})
});
}
</script>
More details on: https://ingcamilorodriguez.wordpress.com/2016/06/21/como-hacer-namespaces-dinamicos-en-socket-io/
Here is one way. Here is a socket.io subclass I created to solve the problem:
https://github.com/PencilCode/dynamic.io
That subclass adds dynamic namespaces as well as virtual hostname support (each host can go into its own namespace tree if you like). That repo has some examples.
Here is a universal socket.io listener that listens to every namespace requested, and logs a message for every socket that connects. You could listen to a different regexp to listen to any subset of namespaces.
It works with the standard socket.io client library without any modification.
var DynamicServer = require('dynamic.io');
io = DynamicServer({
host: true, // Enable virtual host handling
publicStatus: true // Enable /socket.io/status page.
});
// Any number of namespace patterns can be set up.
// This is an example of a single catch-all pattern.
io.setupNamespace(/.*/, function(nsp) {
nsp.on('connect', function(socket) {
console.log('a socket connected on', nsp.fullname());
});
nsp.expire(function() {
console.log(nsp.fullname(), 'is expiring');
});
});
io.listen(8888);
On newer versions you can use something like io.of(/^\/\w+$/).on('connection', (socket) where /^\/\w+$/ is a regular expression that will allow connection if it is a match.
Here is a full example on how to use this to setup many namespaces, here I suppose the only concerne is preventing emit diffusion from reaching other namespaces.
const workspaces = {}
io.of(/^\/\w+$/).on('connection', (socket) => {
const workspace = socket.nsp;
const namespace = workspace.name;
console.log("New Connection NameSpace", namespace);
// you can test here if "namespace" is allowed to be used
// if event handlers are set no need to got further
if (workspaces[namespace]) return;
// save workspace to prevent setting event handlers on each connection
workspaces[namespace] = workspace;
workspace.on("connection", (socket) => {
console.log(`${namespace} > connection from ${socket.id}`);
// set the event handlers same as normal socket
socket.on('event-1', (msg) => {
console.log("event-1", msg);
})
})
})