Abstracting socket io server from event name - node.js

I am trying to create a SocketIO server that can listen to a variable event name (that a client will initiate) like
socket.on( X, function(msg){ // X = any event name provided by the client
io.emit(X, msg); // Emit events to all the clients listening to the same event name
});
For example, if the client emits an event like "eventX", server should be able to listen to "eventX" and emit to all other clients that are connected to the server listening to "eventX".
My idea here is that, Server should not care about the name of the event that a group of clients use and the same piece of server code should be able to emit events when a different name is used by the group of clients for communication.

You can very easily do this by creating one master message name that the server listens for and then have the first argument when it is sent by a client be a sub-message name of the client's choosing. Other arguments could be sent that are specific to the sub-message name. That could meet your requirements.

Related

How to specify message destination on the nodejs websocket?

I want to send messages from nodejs backend to the specified websocket channel. So I want to implement/use similar function like convertAndSend function on the spring SimpMessagingTemplate.
I try to implement this with ws lib, but the send function only has two parameter: message & callback and I cannot specify the message destination. Here is a brief example from backend code:
const wss = new WebSocket.Server({
port: 8081,
server: app,
path: '/ws',
/*...*/
});
/*...*/
wss.send(`chat-room/${roomId}`, JSON.stringify(message)); // I want to this
And here is a brief frontend code that works well:
/*...*/
this.rxStomp.configure({
brokerURL: 'ws://localhost:8081/ws',
/*...*/
});
this.rxStomp.activate();
/*...*/
return this.rxStomp.watch(`chat-room/${roomId}`);
So my question is: it is possible to specify message destination with ws or other libs on the nodejs? If yes then how?
I have not used 'Convert and send' or the 'Web Socket' module ( I use socket.io personally ) but the concept should be the same.
The basic flow is
User connects to socket server ( gets a socket ID assigned to them )
On an action, lets say 'joinroom' from the client app you execute a 'emit' command to the websocket server (this is socket.io syntax) eg
socket.emit('joinRoom',roomID,otherparams)
In the sample above, we are 'emitting' a request to our 'socket' server, in the above example 'socket' is the namespace for our socket connection, so socket.emit send the request to the socket server.
Our socket server has code to 'listen' for requests to 'joinRoom' using the 'on' syntax eg
socket.on('joinRoom',(roomID,otherparams)=>{
//perform action, eg. query DB for room chats etc
// once action is done, emit back to user
socket.in(roomID).emit(data)
})
In the above code, we have an 'on' event that is the 'listener' on the socket server, this will listen for 'emits' to this action, so from the client we ran an 'emit' to the socket server, the socket server found the action (on event) 'joinRoom' and ran the code, after the code was successful it then finds all users 'in' the room (roomID that was passed to the emit) and sends it to all 'sockets' that are 'in' that room
On your client, you too have 'on' listeners, so when the socket server 'emits' to the client(s) they are listening for those specific commands. Because the 'socket.in' only 'emits' to clients who are 'in' the room only those users get the new payload from the server
You app will continue in this fashion, emits and on events. This is the basic flow and can be built out for 1 to 1 chats, group chats etc

I can't get my head around websockets (via socket.io and node.js)

I'm new to websockets/socket.io/node.js. I'm trying to write a card game app, but pretty much all the example tutorials I've found are creating chat applications. So I'm struggling to get my head around the concepts and how they can be applied to my card game.
Keeping it simple, the card game will involve two players. The game involves moving cards around the table. Each player has to see the other player's moves as they happen (hence the need for constant connections). But the opponents cards are concealed to the other.
So two people browse to the same table then click to sit (and play, when both seats are taken). Using
io.on("connection", function(sock){
//socket events in here
});
am I creating the one socket ('io', or 'sock'?) that both clients and the server share, or is that two separate sockets (server/clientA and sever/clientB)? I ask, because I'm struggling to understand what's happening when a message is emitted and/or broadcast. If a client emits a message, is that message sent to both the server and the other client, or just the server? And then, further does it also send the message to itself as well?? It seems as though that's the logic... or what is the purpose of the 'broadcast' method?
From a functional perspective, I need the server to send different messages to each player. So it's not like a chatroom where the server sends the chat to everyone. But if it's one socket that the three of us share (clients and server), how do I manage who sees what? I've read about namespaces, but I'm struggling to work out how that could be used. And if it's two separate sockets, then I can more easily imagine sending different data to the separate clients. But how is that implemented - is that two 'io' objects, or two 'sock' objects?
Finally, I've got no idea if this is the sort of long-winded question that is accepted here, so if it's not, can someone direct me to a forum that discussions can occur? Cheers!
(in case it matters I'm also using Expressjs as the server).
Edit to add:
Part of my confusion is regarding the difference between 'io' and 'sock'. This code eg from the socket.io page is a good example of methods being applied to either of them:
io.on('connection', function(socket){
socket.emit('request', /* */); // emit an event to the socket
io.emit('broadcast', /* */); // emit an event to all connected sockets
socket.on('reply', function(){ /* */ }); // listen to the event
});
WebSocket server side listens for incoming socket connections from clients.
Each client upon connection opens its own socket between him and server. The server is the one that keeps track of all clients.
So once client emits the message server is listening for, the server can do with that message whatever. The message itself can contain information about who is the recipient of that message.
The server can pass the message to everyone or broadcast it to specific user or users based on information your client has sent you or some other logic.
For a card game:
The server listens for incoming connections. Once two clients are connected both of them should emit game ID in which they want to participate. The server can join their sockets in one game(Room) and all of the communication between those two clients can continue in that room. Each time one of the clients passes data to the server, that data should contain info about the recipient.
Here is one simple example that could maybe get you going:
Client side
// set-up a connection between the client and the server
var socket = io.connect();
// get some game identifier
var game = "thebestgameever";
socket.on('connect', function() {
// Let server know which game you want to play
socket.emit('game', game);
});
function makeAMove(move)
{
socket.emit('madeAMove', {move:move, game:game});
}
socket.on('move', function(data) {
console.log('Player made a move', data);
});
Server side
io = socketio.listen(server);
//listen for new connections from clients
io.sockets.on('connection', function(socket) {
// if client joined game get his socket assigned to the game
socket.on('game', function(game) {
socket.join(game);
});
socket.on('madeAMove', function(data){
let game = data.game;
let move = data.move;
io.sockets.in(game).emit('move', move);
});
})

Using Socket.io with Sequelize

I am trying to use Socket.io and Sequelize to create a chat app. Socket.io will handle the socket to allow for instant messaging. Sequelize will handle storing the messages so when you refresh the screen you still have your messages.
What is happening is that on localhost my socket works, but it does not send the messages to the database. When I put it onto Heroku, my database worked, but it does not use the sockets.
My socket is located in app.js and my database route is located in routes/messages.js.
I have been working on this bug for a while now and I have been trying to get help with it. I think the best way to share this is with my markdown I created detailing my efforts to fix my bug that can be found at here. My repo for this can be found here.
There are a few different parts that you need to distinguish:
the HTTP server, in your code represented by the variable http
the Express app, represented by app
the Socket.IO server, represented by io
a Socket.IO (client) connection (see below)
The HTTP server directs "normal" HTTP requests to the Express app, which will handle them according to the middleware and routes that are set up. A router handler gets called with (at least) two arguments, generally called req and res, to represent the (incoming) HTTP request and the (outgoing) HTTP response.
The Socket.IO server gets to handle specific Socket.IO requests, which get sent to the server by the Socket.IO client (running in the browser). When such a client sets up a connection with the server, the connection event gets triggered on the server. Any handlers for this event will get passed an argument, generally called socket, that represents the (bidirectional) connection with that client.
That Socket.IO connection can receive messages (sent from the client running in the browser), which trigger events on the socket. You can install a handler to listen for particular messages (like "chat message"), which will receive, as argument, the data that was sent to it by the client.
The issue in your code seems to be with setting up everything to handle those chat messages. The correct setup order would be:
listen on the Socket.IO server for connection events
when such an event is received, add a listener for the chat message event on the connection
when such an event is received, write the data to the database.
In code:
// Listen for new client connections.
io.on('connection', function(socket) {
// Listen for the client to send a _"chat message"_ message.
socket.on('chat message', function(data) {
// Store the data in the database.
models.Messages.create({
message : data.message,
username : data.username
});
});
});
As you can see, req and res aren't available inside of those Socket.IO event handlers, because those are only used for normal HTTP requests.
Also, as opposed to HTTP, you don't necessarily have to send anything back to the client when you have received a message, so I left that part out. The handler above only writes the message data to the database (it also doesn't check for, or handle, errors, which eventually you should add).

Socket io on ELB, need to connect to all instances of application servers

I have a socket server application written on node js, hosted on Amazon EBS(Elastic bean stalk) which is managed by load balancer
Clients connects to the socket and pass specified id, say event_id my application creates room with name "event_event_id" and join the room. Different clients have different "event_id"
A lambda function connects to the socket and emits an event named "event_push" to the application with necessary data such as event_id
Whenever my socket application(in one of the instances in EBS) detects a push event with event_id, it broadcast the pushed data to all members of the room "event_event_id", thus all members gets notified of the event
clients can connect any of the servers, decided by load balancer and sticky sessions can maintain the connection
Now my problem:
Is there a way to emit the "event_push" to only the server having a room named "event_event_id"
Qn: Is there a way to emit an event to all instances of the servers in EBS?
OR
Qn: Is there any alternate solutions?
What you can do is you can use Redis or mongoDb for saving some information about in your case event_event_id. You can save this information in data storage for example sample doc
{
_id : ObjectId,
userId : 23,
event : event_event_id,
server : 1
},
{
_id : ObjectId,
userId : 23,
event : event_event_id,
server : 2
}
Now what this will do is you will have the information that which event belongs to which server. Now if loadbalancer send request of server1 to server 2 and server 2 doesnt recognize that request you can create a communication channel between the servers(you can use socketio, microservice or anything) and redirect that request to server 1 so it can trigger that particular socket event.
You have to delete the socket id from mongo or redis when disconnect event is triggered.

How can a client connect to a specific room via socketio

I have a server which emits events (something like live updates) to multiple rooms within the default namespace of a socket.io server. The server does NOT post anything to the default room. Clients connecting to the server are interested only in specific rooms and not all rooms.
How can clients connect to a specific room that they are interested in? The client connect URL has information about the server and namespace but nothing about a room. So, how should the client tell the server which room it wants to connect to?
First of all send the room name with event from client side
client side
io.emit('room', {room_name : 'test'});
on server side
io.on('connection', function(socket){
socket.on('room', function(data){
socket.join(data.room_name);
});
});

Resources