Socket.io : Do I need to disconnect the client after every new message in a socket.io chat app? - socket.io

I am new to web-sockets. I was reading this article on medium and in a part of the client code, the code disconnects the socket every time a new message is emitted.
Why is it so? Does this have some design advantage, is this how it is done?
Why not leave the socket connected for more message streams?
-----EDIT------
Here is the code that I am talking about. The code is from this blog
newMessageReceived() {
const observable = new Observable<{ user: String, message: String}>(observer => {
this.socket.on('new message', (data) => {
observer.next(data);
});
return () => {
// Why is the coder disconnecting the socket here?
this.socket.disconnect();
};
});
return observable;
}

Related

Add identifier to websocket

I am using the Node.js ws library, to listen to events in user accounts on a 3rd party API. For each user, I open a websocket to listen to the events in the user's account.
Turns out, the 3rd-party API doesn't provide a userID for each event, so if I have 10 websocket connections to user-accounts, I cannot determine which account an event came from.
I have access to a unique userId prior to starting each of my connections.
Is there a way to append or wrap the websocket connection with the userId identifier, to each connection I make, such that when I receive an event, I can access the custom identifier, and subsequently know which user's account the event came from?
The code below is a mix of real code, and pseudocode (i.e customSocket)
const ws = new WebSocket('wss://thirdparty-api.com/accounts', {
port: 8080,
});
ws.send(
JSON.stringify({
action: 'authenticate',
data: {
oauth_token: access_token,
},
})
);
// wrap and attach data here (pseudocode at top-level)
customSocket.add({userId,
ws.send(
JSON.stringify({
action: 'listen',
data: {
streams: ['action_updates'],
},
})
)
})
// listen for wrapper data here, pseudocode at top level
customSocket.emit((customData) {
ws.on('message', function incoming(data) {
console.log('incoming -> data', data.toString());
})
console.log('emit -> customData', customData);
})
Looking at the socket.io library, the namespace feature may solve for this, but I can't determine if that's true or not. Below is an example in their documentation:
// your application has multiple tenants so you want to dynamically create one namespace per tenant
const workspaces = io.of(/^\/\w+$/);
workspaces.on('connection', socket => {
const workspace = socket.nsp;
workspace.emit('hello');
});
// this middleware will be assigned to each namespace
workspaces.use((socket, next) => {
// ensure the user has access to the workspace
next();
});
I found a solution to this which is fairly simple. First create a message handler function:
const eventHandler = (uid, msg) => {
console.log(`${uid} did ${msg}`);
};
Then, when you create the websocket for the given user, wrap the .on event with the handler:
const createSocketForUser = (uid, eventHandler) => {
const socket = new WebSocket(/* ... */);
socket.onmessage = (msg) => {
eventHandler(uid, msg)
};
return socket;
}

c# SocketIoClientDotNet, node js socket.IO

c# winform tries to send node.js socket through socket.
The client is connected to server, but the socket.emit value and socket.on value do not communicate normally.
I'd like to find a solution to this.
I would like to send this name of client to the server as json type data, receive json type data from the server, read it, and send data back to json.
The data of socket.emit and socket.on are not working properly, so the code has been deleted.
c# code
private void socketLogin(string email, string pw)
{
var socket = IO.Socket("http://localhost:3000/login.html");
socket.On(Socket.EVENT_CONNECT, () =>
{
});
var loginjson = new JObject();
loginjson.Add("email", email);
loginjson.Add("password", pw);
socket.Emit("socketlogin", loginjson.ToString());
socket.On("login", (data) => {
MessageBox.Show(data.ToString());
});
}
node.js Code
var server = require('http').Server(app);
var io = require('socket.io')(server);
io.on('connection', function(socket) {
console.log('connection');
socket.on('socketlogin', function(data) {
var testLogin = { 'Login': "success" };
socket.emit('login', data);
});
});
server.listen(app.get('3000'))
in your C# you are making your socket inside a function, but at the end of the function the socket is thrown away because it is only a local variable.
There are many ways to deal with this, but essentially what you want to do is use a thread to handle the socket comms then dispatch things back to your UI thread.

Issue Broadcasting to Socket.io Rooms of A Namespace

I'm trying to set up a server that can dynamically create many rooms for many namespaces. I'm currently just trying to broadcast to sockets of a room, when a new socket has joined that room.
So far I have been able to broadcast to a specific namespace and my event listeners on the client receives the message. However when I try to broadcast to a room, of a specific namespace, my event listener doesn't receive that message.
I've turned on the Debugger mode and see the socket.io-client:socket emitting the event with the right payload and event type. So I am not sure what I am missing since the documentation also seems fairly straightforward. Any help would be much appreciated. Below is my code.
Server
const colorNs = io.of('/color');
colorNs.on('connection', (socket) => {
const { id } = socket.handshake.query;
const { id:connId } = socket.conn;
if(id) {
socket.join(id);
socket.broadcast.to(id).emit('user:connect', { id: connId });
}
socket.on('disconnect', () => {
const { id } = socket.handshake.query;
const { id:connId } = socket.conn;
socket.broadcast.to(id).emit('user:disconnect', { id: connId });
});
});
Client
const socket = io('/color?id="123"');
socket.on('user:connect', () => console.log('data', data));
Client - Debug Trace
socket.io-parser decoded 2/color,["user:connect",{"id":"IZTTPidF121JCzf9AAAO"}] as {"type":2,"nsp":"/color","data":["user:connect",{"id":"IZTTPidF121JCzf9AAAO"}]} +1ms
browser.js:133
socket.io-client:socket emitting event ["user:connect",{"id":"IZTTPidF121JCzf9AAAO"}] +3ms

Socket.emit() outside socket.on()

Do we always have to use socket.emit() inside a socket.on() like that:
io.sockets.on('connection', function (socket) {
console.log('User connected !');
retrieveDictionnary((dictionnary) =>{
socket.emit('dictionnarySend', dictionnary);
}
}
I want to create on my client side a function which ask information to the server when I click on a button:
translateServer(parameter, control){
this.socket.emit('translate', [parameter,control]);
}
But it seems that it's not working, the server never receive this message.
Thank you !
The pattern you are using above is the recommended way of interacting with a socket (ie acquiring a socket instance when the 'connection' event fires, and then calling emit() from that socket instance, etc).
If I understand your client-side requirements correctly, you are wanting to send data to the server via web sockets - are you sure the socket that you have established a web socket connection between the client and server?
For instance, if you add the following to your client-side code, you should see a success message in your console:
const socket = io.connect('YOUR SERVER ADDRESS');
socket.on('connect', () => {
console.log('connected to server!');
// [UPDATE]
// This assumes you have a <button> element on your page. When
// clicked, a message will be sent to the server via sockets
document.querySelector('button').addEventListener('click', (event) => {
// Prevent button click reloading page
event.preventDefault();
// Send message to server via socket
socket.emit('MESSAGE_ID', 'test message from client' + new Date());
});
});
Update
This shows your original server code, expanded with the detail needed to receive and print data sent from client via sockets:
io.sockets.on('connection', function (socket) {
console.log('User connected !');
// Register a server handler for any messages from client on MESSAGE_ID channel
socket.on('MESSAGE_ID', (message) => {
// Print the message received from client in console
console.log('message from client', message);
})
retrieveDictionnary((dictionnary) =>{
socket.emit('dictionnarySend', dictionnary);
}
}

Socket.IO subscribe to multiple channels

I want to build a simple chat room system on top of Socket.IO where user can create a new chat room and then people can start chatting.
This sound simple but as the Socket.IO 0.9.4 I'm running now, after reading a few SO posts together with the document on socket.io, i'm getting more and more confused. So, I hope that someone can provide me with instruction that WORK with 0.9.4:
I need a way to subscribe to a room. The room name is chosen by user. When a message is posted in a room, the user should receive it. How should I write the server code, how should I write the client code?
A user can join multiple rooms simultaneously.
I want another system to send a message to all user in a certain room. This 'another system' send the message through a request handled by express. How would I write that request handler?
This is all pretty straightforward with the socket.io rooms feature. Take a look at the documentation on LearnBoost wiki.
https://github.com/LearnBoost/socket.io/wiki/Rooms
It allows for being connected to multiple rooms over a single socket. I put together a quick test with the following code.
Server
io.sockets.on('connection', function(client){
client.on('subscribe', function(room) {
console.log('joining room', room);
client.join(room);
})
client.on('unsubscribe', function(room) {
console.log('leaving room', room);
client.leave(room);
})
client.on('send', function(data) {
console.log('sending message');
io.sockets.in(data.room).emit('message', data);
});
});
Client
var socket = io.connect();
socket.on('message', function (data) {
console.log(data);
});
socket.emit('subscribe', 'roomOne');
socket.emit('subscribe', 'roomTwo');
$('#send').click(function() {
var room = $('#room').val(),
message = $('#message').val();
socket.emit('send', { room: room, message: message });
});
Sending a message from an Express route is pretty simple as well.
app.post('/send/:room/', function(req, res) {
var room = req.params.room
message = req.body;
io.sockets.in(room).emit('message', { room: room, message: message });
res.end('message sent');
});

Resources