I'm writing an application in Node.js/Express based around websockets. I'm using Node's EventEmitter in conjunction with socket.io for a nearly completely event-driven app.
I wonder if this this is a good architecture though. My main socket is managed in app.js right now, and has code like this:
socket.on(Events.InitialFetch, function(battle_id){
dispatcher.emit(Events.InitialFetch, battle_id);
});
dispatcher.on(Events.InitialFetched, function(data){
socket.emit(Events.InitialFetched, data);
});
... while in my controller, I have code like this:
dispatcher.on('initial-fetch', function(data){
Battle.findOne({_id: data})
.populate('players')
.populate('owner')
.exec(function(err, battle){
if (err) {
}
else {
dispatcher.emit(Events.InitialFetched, battle);
}
});
});
Instead of the normal RESTful routing. My concern is that it's a little confusing (ie 'fetch' and 'fetched' for describing data flow) and the fact that I'm basically passing methods from one type of event emitter (socket.io) to another (Event.EventEmitter).
How can this be architected better? Would it be better to have the controllers directly access the socket instead of using EventEmitter as a bus? How can I make the names of my events more clear?
I wouldn't worry about using multiple event emitters. They are kind good primitive to build upon in Node.js. As for design, I find a good question to ask is how deeply I have coupled my components.
By using an non-socket.io event emitter for your controller, Socket.io is an independent transport from the controller. This is good.
As a final stage, you should wire the two together using dependency injection. In your server.js file create your dispatcher, then initialize your socket.io module passing the dispatcher as a dependency.
var dispatcher = require('./dispatcher')
var socket_transport = require('./socket_transport')
socket_transport.init_with_dispatcher(dispatcher);
This will let you test your dispatcher independently of the transport. Debugging socket.io can be difficult.
Related
My question could be flagged as "opinion based" but I am wondering which approach is the best for my application as I am able to do it in both ways.
I am building chat application in which users and conversations are saved in MongoDB. I will have my react application consuming API/APIs. The question is - is it better to have REST API and Socket.io applications running separate? For example:
Have REST API running on port 3005
Have Socket.io running on port 3006
React Application consuming these 2 separately and basically they will not know about each other. My endpoints in REST API endpoints and socket.io will be invoked only in front-end.
On the other hand, I can have my socket.io application and REST API working together in 1 big application. I think it is possible to make it working without problems.
To sum up, at first glance I would take the first approach - more cleaner and easy to maintain. But I would like to hear other opinions or if somebody had a similar project. Usually how the things are made in this kind of projects when you have socket.io and REST API?
I would check the pros and cons for both scenario. For example code and resource reusability is better if you have a single application and you don't have to care about which versions are compatible with each other. On the other hand one error can kill both applications, so from security perspective it is better to have separate applications. I think the decision depends on what pros and cons are important to you.
you can make a separate file for socket.io logic like this:
// socket.mjs file
import { Server } from "socket.io"
let io = new Server()
const socketApi = {
io: io
}
io.on('connection',(socket)=>{
console.log('client connected:', socket.id)
socket.join('modbus-room')
socket.on('app-server', data=>{
console.log('**************')
console.log(data)
io.to('modbus-room').emit('modbus-client', data)
})
socket.on('disconnect',(reason)=>{
console.log(reason)
})
})
export default socketApi
and add it to your project like this:
// index.js or main file
//...
import socketApi from "../socket.mjs";
//...
//
/**
* Create HTTP server.
*/
const server = http.createServer(app);
socketApi.io.attach(server);
//
I'm using ws version 7.4.0 and I would want to display a console log or perfom operations between the moment where the client is sending a message to the server and before the server fire the on event message.
To represent it:
webserver.on('example', function callback(msg){console.log(msg);}); //act before the call of callback
client------server---[here]---callback
The only way I see right now would be to use a "root" function before the callback of all my events like this:
function callback(msg){console.log(msg);}
webserver.on('example', function root(msg) {console.log('example msg'); callback(msg);});
I don't know if this is a real and/or good solution I really wish to write a clean and organized application.
If someone could give me some advise or a real solution? Thank you.
You could make a wrapper for all of your callbacks like so:
function makeCallback(fn) {
return function(msg) {
if (!environment.prod) console.log(msg);
fn(msg)
};
}
var myCallback = makeCallback(function (msg) {
// something
});
webserver.on('example', myCallback);
Or I think the better solution is to stream the requets into your stdout although I don't know the implications of using this method.
And I want to address the naming of your websocket server. Even though a web socket server is technically a web server, it only responds to the websocket protocol and naming it webserver could be misleading, I would recommend using the naming like in their documents wss.
My goal is to build a chat application - similar to whatsapp
To my understanding, socket.io is a real-time communication library written in javascript and it is very simple to use
For example
// Serverside
io.on('connection', function(socket) {
socket.on('chat', function(msg) {
io.emit('chat', msg);
});
});
// ClientSide (Using jquery)
var socket = io();
$('form').submit(function(){
socket.emit('chat', $('#m').val());
$('#m').val('');
return false;
});
socket.on('chat', function(msg){
$('#messages').append($('<li>').text(msg));
});
1) do I always need to start an io.on('connection') to use the real-time feature or i could just start using socket.on object instead? for example i have a route
app.post('/postSomething', function(req, res) {
// Do i need to start an io.on or socket.on here?
});
because i want the real-time feature to be listen only on specific route.
2) Redis is a data structure library which handles the pub/sub, why do we need to use pub/sub mechanism?
I read alot of articles but couldn't grasp the concept. Article example http://ejosh.co/de/2015/01/node-js-socket-io-and-redis-intermediate-tutorial-server-side/
for example the code below
// Do i need redis for this, if so why? is it for caching purposes?
// Where does redis fit in this code?
var redis = require("redis");
var client = redis.createClient();
io.on('connection', function(socket) {
socket.on('chat', function(msg) {
io.emit('chat', msg);
});
});
3) Just wondering why I need nginx to scale node.js application? i found this stackoverflow answer:
Strategy to implement a scalable chat server
It says something about load balancing, read that online and couldn't grasp the concept as well.
So far I have only been dealing with node.js , mongoose simple CRUD application, but I'm willing work really hard if you guys could share some of your knowledge and share some useful resources so that I could deepen my knowledge about all of these technologies.
Cheers!
Q. Socket.on without IO.on
io.on("connection" ... )
Is called when you receive a new connection. Socket.on listens to all the emits at the client side. If you want your client to act as a server for some reason then (in short) yes io.on is required
Q. Redis pub/sub vs Socket.IO
Take a look at this SO question/anwer, quoting;
Redis pub/sub is great in case all clients have direct access to redis. If you have multiple node servers, one can push a message to the others.
But if you also have clients in the browser, you need something else to push data from a server to a client, and in this case, socket.io is great.
Now, if you use socket.io with the Redis store, socket.io will use Redis pub/sub under the hood to propagate messages between servers, and servers will propagate messages to clients.
So using socket.io rooms with socket.io configured with the Redis store is probably the simplest for you.
Redis can act like a message queue if it is a requirement. Redis is a datastore support many datatypes.
Q. Why Nginx with Node.js
Node.js can work standalone but nginx is faster to server static content.
Since nginx is a reverse proxy therefore servers are configured with nginx to handle all the static data (serving static files, doing redirects, handling SSL certificates and serving error pages.
) and every other request is sent to node.js
Check this Quora post as well: Should I host a node.js project without nginx?
Quoting:
Nginx can be used to remove some load from the Node.js processes, for example, serving static files, doing redirects, handling SSL certificates and serving error pages.
You can do everything without Nginx but it means You have to code it yourself, so why not use a fast and proven solution for this.
Challenge:
I would like to use SailsJS, and be able to join a room, by means of socket.io, and receive unsolicited messages from this room, not just when one enters or leaves the room but also receive objects.
So several clients connect to the server.
Afterwards broadcast (initiated from the server) messages/objects to every room and thus everey connected socket in this room.
I maybe could just send every connected socket a message, but dearly would like a example on how to do this with SailsJS 0.10, and a elegant method in the SailsJS 0.10 way.
I am looking at : https://github.com/balderdashy/sailsChat, but I think this is to close to the models themselves, with like e.g: autosubscribe: ['destroy', 'update']
In my opinion this should be more loosely coupled, and not so tied to the model itself.
Thanks in advance!
I.
The purpose of the SailsChat example is to demonstrate how Sails JS resourceful pubsub can take a lot of hassle out of socket messaging when you are mainly concerned with sending messages about models. The fact that you can make a full-featured chat app in Sails with very little back-end code is what makes it impressive. For situations where resourceful pubsub is not appropriate--or if you just plain don't want to use it--Sails exposes lower-level methods on the sails.sockets namespace. The docs are pretty clear on how they work.
To join a socket to an arbitrary room, do sails.sockets.join(<socket>, <roomName>), where <socket> is either a raw socket (probably from req.socket or a socket ID).
To broadcast a message to all sockets in a room, do sails.sockets.broadcast(<roomName>, <data>).
These and more methods are described in detail in the Sails JS documentation.
I'm just starting with SailsJS, and already a big fan.
I need to find out if this is also scalable with e.g. Heroku or other flavors of SAAS providers, but seems not that hard.
So just a follow up on what I did with SailsJS 0.10:
Server-side:
Made a controller with the following:
join: function (req, res) {
if (req.isSocket === true) {
sails.sockets.join(req.socket, 'mysecretroom');
return res.send(200, 'joined');
}
return res.send(200);
},
sendToRoom: function( req, res ) {
if (req.isSocket === true ) {
sails.sockets.broadcast('mysecretroom', 'messageevent', {message:'Listen very carefully, I'll shall say this only once..!'});
}
return res.send(200);
}
Client-side:
io.socket.on('messageevent', function (data) {
console.log(data);
})
+1 kudos #sgress454!
Thanks!
I don't understand the way DNode uses websocket communication.
Some say it uses socket.io others say sockjs.
Which one is it? Or is it possible to choose?
I'm trying to use DNode, but I also need access to the connections for (semi-)broadcasting in reaction to RPC calls. How do I do this?
Is there a more extensive manual on dnode somewhere?
Your question is kind of vague. I'm not exactly sure whether DNode uses socket.io or sockjs, not sure it even uses one of those based on their dependencies list, but that is not really important when you program it.
As for using connections with DNode, it is pretty straight forward. Here's an example:
var server = dnode({
pushMessageNotification: function(message, cb) {
contact = getClientFromId(message.receiver);
contact.socket.emit('messageNotification', {
message: message.message,
sender: message.sender,
time: message.time
});
cb('success');
}
});
So as you can see, pushMessageNotification is a method that I binded with DNode-PHP and the message is encoded in JSON through PHP. Afterward, all you need is a method to find the socket of the client based on its id.