Running a continuous function in nodejs after user logs in - javascript

Here is my issue - I have a user database on mongo which also has a topicsList to which a user is subscribed to. I need to continuously listen to the topics in the topicsList via Mqtt.
The topic list can be fetched from the database once the user logs in & is authenticated. How do I pass the topics list in a call back function in the main app.js file in the app.listen function.
For example :
app.listen(3000, function(){
console.log('Subscribed to the following topics : ", topics)
}
So that this function runs perpetually and listens to any incoming data to the topics, unless the user is logged out, where the topics list is back to being null.

I hope I understood your question correctly.
Firstly, need to up socket.
Server:
let app = express();
let http = require('http');
let server = http.Server(app);
let socketIO = require('socket.io');
let io = socketIO(server, {
cors: {
origin: ip,
methods: ["GET", "POST"]
}
});
server.listen(3000, function(){}
Client:
let socket = io.connect( ip );
Now we need to handle the user connection event on the server:
io.on('connection', function(socket) {
socket.emit('sendData', topics);
}
Handling the socket event on the client:
socket.on('sendData', function(data) {
console.log(data);
});

Related

Problem with socket when using it in express

I have a problem with the socket in my program. export the "io" connection and although I can broadcast from any part of the normal program (just by referring to "io"), I cannot use "socket" and broadcast with it unless it is within the same connection of "io." I would like to know how to use socket from any other part of the program, with functions such as "socket.emit ()" or "socket.broadcast.emit" etc. Or how to call this one.
This is my index.js:
const express = require('express');
const restApi = express();
const cors = require('cors');
const server = require('http').createServer(restApi);
const rutas = require('./src/routes/Routes.js');
const io = require('./src/socket/SocketManager.js');
io.attach(server);
restApi.use(express.json());
restApi.use(express.static('public'));
restApi.use(cors());
restApi.options('*', cors());
server.listen(4040, () => console.log('Listening server in port 4040'));
restApi.all('/*', function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "X-Requested-With");
next();
});
restApi.use('/api',rutas);
my managersocket.js:
const io = require('socket.io')();
io.on('connection', function (socket) {
console.log('NUEVA CONEXION: ',socket.id);
socket.emit('recoger',socket.id);
});
module.exports = io;
This is where I would like to use the socket or at least call the function.
and User.js:
var io = require('../../socket/SocketManager');
var RouterUser = function(){
this.practicafuncion = function (req,res){
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "X-Requested-With");
console.log('probando entrar por rest y que salga un mensaje por socket');
res.send({
status:'Aprobado',
msj:'Enviado por rest'
});
//this works correctly. io.sockets.emit('mensaje','**MENSAJESERVIDORPORSOCKET**');
//This is not the problem when using "socket". socket.broadcast.emit('mensaje','**MENSAJESERVIDORPORSOCKET**');
};
}
module.exports = function(){
var instancia = new RouterUser();
return instancia;
};
same is the repository where the whole code is
https://github.com/proxirv/Socket.io-router
socket is a temporary object that exists only for the duration of one particular client connection. And, there can be zillions of them (one or more for each connected client). As such, you don't just export one socket or stuff it in a global and try to use that everywhere.
So, if what you're trying to do is to access the socket.io connection for the user that you just received an http request for, that's a bit more complicated and there are several different ways to approach it.
One approach, I've used before is shown below:
const express = require('express');
const app = express();
const server = app.listen(80);
const io = require('socket.io')(server);
const expsession = require('express-session');
const path = require('path');
// install session middleware
const sessionMiddleware = expsession({
secret: 'random secret',
saveUninitialized: true,
resave: true
});
// run session middleware for regular http connections
app.use(sessionMiddleware);
// run session middleware for socket.io connections
io.use(function(socket, next) {
sessionMiddleware(socket.request, socket.request.res, next);
});
// when a socket.io connection connects, put the socket.id into the session
// so it can be accessed from other http requests from that client
io.on('connection', function(socket) {
// socket.handshake.headers
console.log(`socket.io connected: ${socket.id}`);
// save socket.io socket in the session
console.log("session at socket.io connection:\n", socket.request.session);
socket.request.session.socketio = socket.id;
socket.request.session.save();
});
// any arbitrary express route definition
// Note: you can't send socket.io data in a request that loads an HTML page
// because that client hasn't yet established the socket.io connection
// for that page. The socket.io connections will be created after
// the browser loads this page.
app.get("/", function(req, res) {
const session = req.session;
console.log("\n\npage load\n---------------------------\n");
console.log("session:\n", session);
res.sendFile(path.join(__dirname, "socket-io-session.html"));
});
// Upon an API call from a page that already has a socket.io connection,
// respond to the API call and send something to that page's socket.io socket
app.get("/api/test", function(req, res) {
const session = req.session;
io.sockets.connected[session.socketio].emit('show', "sending some data");
console.log("session:\n", session);
console.log("session.socketio:\n", session.socketio);
res.json({greeting: "hello"});
});
Here are the steps in that concept:
Set up express-session for regular http connections. This gives you a place to store stuff that belongs to one particular client (keyed by a cookie)
Set up express-session for the socket.io connection so you can also have access to express-session data in socket.io connections.
When a socket.io connection happens, store the socket.id in the sesssion. This makes the socket.id available for future http requests from that specific client
When some future http request comes in from that client, you can reach into the session, get the socket.id value (which is just a string) and then use that to get the socket for that user and once you have the socket, you can use socket.emit() to send data just to that user.
If you didn't have other reasons for using express-session, you could also just put the socket.id into a cookie all by itself when the socket.io connection connects and then get the socket.id from the cookie during your http request.

Make a cookie when a user connects with socket. io - node js

have a server that uses socket.io. When a user connects it will assign them the user id thats made on the server then increment it by 1 so the next user with have a different id.
I want to use cookies for this, to check if they have previously logged in, if so, use that id, if not, use the one on the server.
the way to create a cookie is by using
res.cookie('cookie', 'monster')
but im not where i would put it, i tried putting it in the connect function but res wouldnt exist. and if i put it outside the function, how would i call it? Here is my code. This is the start of my server:
//Require npm modules
var express = require('express');
var http = require('http');
var events = require('events');
var io = require('socket.io');
var ejs = require('ejs');
var app = express();
//Set the default user Id to 1 and the default username to Guest
exports.Server = Server = function()
{
this.userId = 1;
this.userName = "Guest";
};
app.set('view engine', 'ejs');
app.get('/game/:id', function (req, res)
{
res.render('game', {game: req.params.id});
});
Server.prototype.initialise = function(port)
{
//Create the server using the express module
this.server = http.createServer(app);
//Declare the 'public' folder and its contents public
app.use(express.static('public'));
//Listen to any incoming connections on the declared port and start using websockets
this.server.listen(port);
this.startSockets();
this.em = new events();
consoleLog('SERVER', 'Running on port: ' + port);
};
Server.prototype.startSockets = function()
{
//When a user connects to the server on the 'game' socket
this.socket = io.listen(this.server);
this.socket.of('game').on('connection', function(user)
{
res.cookie('cookie', 'monster')
//Set their usedId and username
user.userId = this.userId;
user.userName = this.userName + " " + this.userId;
//Increment the user id by 1 so each user with get a unique id
this.userId++;
//Send a response back to the client with the assigned username and user id and initialise them
user.emit('connected', user.userId, user.userName);
this.em.emit('initialiseUser', user.userId, user.userName);
So where i have the res.cookie is where i want to be able to read and write cookies, any help is appriciated
I think what you are looking for is the middleware pattern employed by express. You can define as many of these middleware calls as you wish, and they are the perfect scope for calling any other functions which may need the res instance (or the req instance for that matter).
app.use(function (req, res, next) {
// call function, passing in res here
next();
})
Reference: https://expressjs.com/en/guide/using-middleware.html
EDIT:
This answer is not correct for your situation. In a node/express server not using socket connections, then yes, you could easily use the above pattern anywhere you need the request and response objects in scope.
However, once you setup the socket io server, the game changes. During the socket communications, there are no express request and response objects in scope anymore, everything is handled directly between your socket handling code and the client. So the answer is you need to handle the situation in a socket io way, not in an express way.
Please see: Adding a cookie value on Socket.IO

Why isn't socket.io callback being triggered inside an express route

I've got the following setup (important bits only for brevity):
app.js
...
const app = express();
const server = require('http').Server(app);
const io = require('socket.io')(server);
server.listen(port, function() {
console.log(`Server is listening on port: ${port}`);
});
io.on('connection', function (socket) {
console.log('connection');
});
const routes = require('./routes/index')(io, passport);
app.use('/', routes);
index.js (server)
router.get('/game/:id', isAuthenticated, (req, res) => {
if (req.id)
{
var game = Game.findOne({_id: req.id}, (err, obj) => {
io.on('getGameInfo', (socket) => {
io.emit('gameInfo', obj);
});
res.render('game', obj);
});
}
else
{
// Id not valid, do something
}
});
client:
const socket = io('http://localhost:3000');
socket.on('gameInfo', function(data) {
console.log(data);
}.bind(this));
socket.on('connect', () => {
socket.emit('getGameInfo');
});
So basically I want to emit a getGameInfo call once I know the client has connected, and the getGameInfo listener has been set up in the game route. But when I emit the getGameInfo from the client, the server callback isn't being hit. I'm not sure if I'm missing something obvious, or if this is a closure issue, or if I'm just having one of those days, or if I'm going about this entirely the wrong way.
There are multiple problems here. I'll start by showing the correct way to listen for an incoming socket.io message on the server:
io.on('connection', function (socket) {
// here's where you have a new socket and you can listen for messages
// on that socket
console.log('connection');
socket.on('gameInfo', (data) => {
socket.emit('gameInfo', obj);
});
});
Some of the issues:
On the server, you listen for messages via the socket object, not via the io object. So, you would typically add these event listeners in the io.on('connection', ...) handler because that's where you first see newly connected sockets.
You pretty much never want to add event listeners inside an Express route handler because that is called many times. In addition, at the moment the route handler is called, the browser has not yet received the page and will not yet be connected so even if this was an OK place to do stuff, the page is not yet connected anyway.
When you want to send a message back to just one connection, you send it with socket.emit(), not io.emit(). io.emit() broadcasts to all connected clients which I don't think is what you want.
I'd suggest you not overload the same message name for client and server to mean two different things as this can lead to confusion when reading code or if you ever share some code between client and server. You client is really sending a "getGameInfo" message and then your server responds with a "gameInfo" message that contains the gameInfo.
If, in a route handler, you want to .emit() to the socket from that page which it looks like you are trying to do, then you have to do some work to create a link between the session of the current page and the socket for that page. There are a number of ways to do that. If you're using any session middleware, you can record the socket in the session at the point the socket connects. Then, from your express routes, you can get that socket from the session object at any time.

Socket.io trigger events between two node.js apps?

I have two servers, one for the back end app, and one that serves the front end. They are abstracted, but share the same database, I have a need for both to communicate real time events between each other using socket.io.
Front end
// serves a front end website
var appPort = 9200;
var express = require('express');
var app = express();
var http = require('http');
var server = http.createServer(app);
var io = require('socket.io').listen(server);
io.sockets.on('connection', function(socket) {
socket.on('createRoom', function(room) {
socket.join(room); // use this to create a room for each socket (room) is from client side
});
socket.on('messageFromClient', function(data) {
console.log(data)
socket.broadcast.to(data.chatRoom).emit('messageFromServer', data);
});
});
Back end
//Serves a back end app
var appPort = 3100;
var express = require('express');
var app = express();
var http = require('http');
var server = http.createServer(app);
var io = require('socket.io').listen(server);
io.sockets.on('connection', function(socket) {
socket.on('createRoom', function(room) {
socket.join(room); // use this to create a room for each socket (room) is from client side
});
socket.on('messageFromClient', function(data) {
console.log(data)
socket.broadcast.to(data.chatRoom).emit('messageFromServer', data);
});
});
As an admin I want to log in to my back end where I can see all the people logged in, there I can click on whom I would like to chat with.
Say they are logged in to the front end website, when the admin submits a message client side they trigger this socket.emit('messageFromClient', Message); how can I trigger messageFromClient on the front end using port 9200 submitting from the backend port 3100?
You really dont need to start the socket.io server in the front end for this use case.
The way you can get it to work is :
Keep the backend as it is, which acts as a Socket.IO server
In the font end connect to the server using a Socket.IO client.
You can install the client by calling
npm install socket.io-client
and then connect to the server using :
var io = require('socket.io-client'),
socket = io.connect('localhost', {
port: 3100
});
socket.on('connect', function () { console.log("socket connected"); });
socket.emit('messageFromClient', { user: 'someuser1', msg: 'i am online' });
You can then create a map of socket objects with their corresponding username and send a message to that user based on your business logic.
More Information :
You may have to add cases like client disconnection etc. You can read more about the call backs for that here :
https://github.com/Automattic/socket.io-client

Update all clients using Socket.io?

Is it possible to force all clients to update using socket.io? I've tried the following, but it doesn't seem to update other clients when a new client connects:
Serverside JavaScript:
I'm attempting to send a message to all clients, which contains the current number of connected users, it correctly sends the amount of users.... however the client itself doesn't seem to update until the page has been refreshed. I want this to happen is realtime.
var clients = 0;
io.sockets.on('connection', function (socket) {
++clients;
socket.emit('users_count', clients);
socket.on('disconnect', function () {
--clients;
});
});
Clientside JavaScript:
var socket = io.connect('http://localhost');
socket.on('connect', function(){
socket.on('users_count', function(data){
$('#client_count').text(data);
console.log("Connection");
});
});
It's not actually sending an update to the other clients at all, instead it's just emitting to the client that just connected (which is why you see the update when you first load)
// socket is the *current* socket of the client that just connected
socket.emit('users_count', clients);
Instead, you want to emit to all sockets
io.sockets.emit('users_count', clients);
Alternatively, you can use the broadcast function, which sends a message to everyone except the socket that starts it:
socket.broadcast.emit('users_count', clients);
I found that using socket.broadcast.emit() will only broadcast to the current "connection", but io.sockets.emit will broadcast to all the clients.
here the server is listening to "two connections", which are exactlly 2 socket namespaces
io.of('/namespace').on('connection', function(){
socket.broadcast.emit("hello");
});
io.of('/other namespace').on('connection',function(){/*...*/});
i have try to use io.sockets.emit() in one namespace but it was received by the client in the other namespace. however socket.broadcast.emit() will just broadcast the current socket namespace.
As of socket.io version 0.9, "emit" no longer worked for me, and I've been using "send"
Here's what I'm doing:
Server Side:
var num_of_clients = io.sockets.clients().length;
io.sockets.send(num_of_clients);
Client Side:
ws = io.connect...
ws.on('message', function(data)
{
var sampleAttributes = fullData.split(',');
if (sampleAttributes[0]=="NumberOfClients")
{
console.log("number of connected clients = "+sampleAttributes[1]);
}
});
You can follow this example for implementing your scenario.
You can let all of clients to join a common room for sending some updates.
Every socket can join room like this:
currentSocket.join("client-presence") //can be any name for room
Then you can have clients key in you sockets which contains multiple client's data(id and status) and if one client's status changes you can receive change event on socket like this:
socket.on('STATUS_CHANGE',emitClientsPresence(io,namespace,currentSocket); //event name should be same on client & server side for catching and emiting
and now you want all other clients to get updated, so you can do something like this:
emitClientsPresence => (io,namespace,currentSocket) {
io.of(namespace)
.to(client-presence)
.emit('STATUS_CHANGE', { id: "client 1", status: "changed status" });
}
This will emit STATUS_CHANGE event to all sockets that have joined "client-presence" room and then you can catch same event on client side and update other client's status.
According to this Broadcasting.
With nodejs server, you can use this:
io.emit('event_id', {your_property: 'your_property_field'});
Be sure to initialise websocket, for example:
var express = require('express');
var http = require('http');
var app = express();
var server = http.Server(app);
var io = require('socket.io')(server);
app.get('/', function (req, res) {
res.send('Hello World!');
io.emit('event_hello', {message: 'Hello Socket'});
});
server.listen(3000, function () {
console.log('Example app listening on port 3000!');
});
In this case, when user reach your server, there will be "event_hello" broadcasted to all web-socket clients with a json object {message: 'Hello Socket'}.

Categories

Resources