NodeJS/Express Room Joining when a View is accessed - Sockets - node.js

I'm creating a simple NodeJS/Express webapp that has an api and sockets. Basically, what I want to do is send data to my API from an external source, and then send this data to the socket in pageView/id. Right now it works, but it is sending data to all of the views, not the specific pageView/id.
I know I have to create Rooms and I tried doing this by having my sockets join the room when the webapp is navigated to page/id: (note I do not have logged in users)
router.get('/:id', function (req, res, next) {
res.io.on('connection', function(socket) {
console.log("user connected");
//join room here
});
});
But then this creates multiple connections, every time I refresh the pageView I get a new connection + previous connections on my server side.
How can I join the room when a pageView/id is accessed? Here is my setup...
app.js
var express = require('express');
var app = express();
var server = require('http').Server(app);
var io = require('socket.io')(server);
app.use(function(req, res, next){
res.io = io;
next();
});
module.exports = {app: app, server: server};
/bin/www
var app = require('../app').app;
var http = require('http');
var server = require('../app').server;
server.listen(port);
pageView.hbs
var socket = io.connect();
socket.on('mySocket', function (data) {
console.log(data);
});
pageView.js
router.post('/updatePage', function (req, res, next){
//send to the view
res.io.emit("mySocket", {
device: device
});
});

Ok, I understand now, your mistake is to create the listeners inside your route. You need only one set of event listeners on io. So, this would work :
var express = require('express');
var app = express();
var server = require('http').Server(app);
var io = require('socket.io')(server);
io.on('connection', function(socket) {
console.log("user connected");
socket.join(room);
});
module.exports = {app: app, server: server};
remember that you can pass parameters on your connection, for example, you can do :
var myroom = window.location.pathname.split('pageView/')[1]; //example to get room name, be creative !
var socket = io.connect("http://127.0.0.1:3000/", { query: 'room='+myroom+' });
and on the server :
io.on('connection', function(socket) {
console.log("user connected");
var room = socket.handshake.query.room; // === 'myRoom'
socket.join(room);
socket.emit("mySocket", {
device: device
});
});
pageView.js
router.post('/updatePage', function (req, res, next){
});

Related

'Sharing' object between NodeJS modules

I'm new to NodeJS development and I'm doing some tests with the socket.io library. Basically, what I want to do is to stablish a socket.io connection between the clients (Angular 6 web app) and the server and broadcast a message when a new user connects.
Right now, the code is quite simple, and this is what I have:
app.js
var express = require('express');
var http = require('http');
var socketIO = require('socket.io');
// Routes
var twitterRoutes = require('./routes/user');
var app = express();
var server = http.Server(app);
var io = socketIO(server); // <== THIS OBJECT IS WHAT I WANT TO USE FROM THE ROUTES
[ ... ]
io.on('connect', (socket) => {
console.log('New user connected');
socket.on('disconnect', (reason) => {
console.log('User disconnected:', reason);
});
socket.on('error', (err) => {
console.log('Error in connection: ', err);
});
});
I want to use the io object inside the user route, but I don't know how to do it:
routes/user.js
var express = require('express');
var config = require('../config/config');
var router = express.Router();
router.post('/login', (req, res, next) => {
// DO ROUTE LOGIC
// I WANT TO BROADCAST THE NEW LOGGED USER USING io.broadcast.emit, BUT DON'T KNOW HOW
// <=====
});
How could I do it? Thanks in advance,
Not sure if it is the best way but you could share things between request handlers using middleware
// define and use a middleware
app.use(function shareIO(req, res, next) {
req.io = io;
next();
})
Then you could use req.io inside request handlers.
router.post('/login', (req, res, next) => {
// DO ROUTE LOGIC
req.io.emit('event')
});
You could do what you want by injecting your IO var in a function
// app.js
var app = express();
var server = http.Server(app);
var io = socketIO(server);
server.use(require('./router')(io))
...
// router.js
module.exports = function makeRouter(io) {
var router = express.Router();
router.post('/login', (req, res, next) => {
// do something with io
}
return router
}
I don't know if it's the best practice, but I've assigned the io object to a property of the global object, and I can access it from everywhere all across the application. So this is what I did:
app.js
var io = socketIO(server);
global.ioObj = io;
routes/user.js
router.post('/login', (req, res, next) => {
// DO ROUTE LOGIC
if (global.ioObj) {
global.ioObj.sockets.clients().emit('new-message', { type: 'message', text: 'New user has logged in' });
}
});

NodeJS, socketIO, multiple files

I'm a little bit confused;
I would like to use socketIO on NodeJS app.
I've created this (pseudo)code:
//server.js
var app = express();
//some code...
var router = require('./app/router');
app.use(router);
var server = app.listen(appConfig.app.port, function () {
var port = server.address().port;
});
var io = require('socket.io')(server);
io.on('connection', function (client) {
console.log('Client connected...');
client.on('join', function (data) {
console.log(data);
});
});
//client.js
var socket = io.connect('http://localhost:5555');
socket.on('connect', function(data) {
socket.emit('join', 'Hello World from client');
});
Everything is fine. But !
At now, I would like to emit event in another file.
I have router and POST request. I want to emit event on POST request (request handler is in another file).
//router.js
router.route("/addmenu").post(function (req, res) {
menuModel.addMenu(req.body,function(data){
//I WANT EMIT HERE
res.json(data)
});
};
);
I have to initialize router before start server, but I have to pass server to IO... How pass IO to router ?
You can try this
//server.js
var app = express();
//some code...
var io;
var getIOInstance = function(){
return io;
};
var router = require('./app/router')(getIOInstance);
app.use(router);
var server = app.listen(appConfig.app.port, function () {
var port = server.address().port;
});
io = require('socket.io')(server);
io.on('connection', function (client) {
console.log('Client connected...');
client.on('join', function (data) {
console.log(data);
});
});
//router.js
module.exports = function(getIOInstance){
router.route("/addmenu").post(function (req, res) {
menuModel.addMenu(req.body,function(data){
//I WANT EMIT HERE
getIOInstance().sockets.emit(...)
res.json(data)
});
};
return router;
);
This solution will work if you want to 'notify' all connected clients.
If you need to notify only a specific client, then I will advise you to use an event-emitter module in order to communicate these events and not share your socket instances across multiple files.
In router.js you can do something like:
//router.js
module.exports = function(io) {
var router = //What you declared it to be
router.route("/addmenu").post(function (req, res) {
menuModel.addMenu(req.body,function(data){
//I WANT EMIT HERE
res.json(data)
});
};
);
return router;
}
//server.js
//Change this line to be like the one below
var router = require('./app/router');
//.........
//.......
//Desired way
var router = require('./app/router')(io);
The answer of #jahnestacado does the job, but in case you already have an existing code base, then you need to change the structure of each file, where you might need the socket.io object, to pass it in as an argument.
A better way to do it then, would be:
To create the getIO() function—just as #jahnestacado did—, where you instantiate the io object (inside server.js), and export it.
var io;
exports.getIO = () => io;
Then require it wherever you need it. But make sure to execute the function only when you need it. Typically inside your controller function:
const getIO = require('../server').getIO;
exports.updateSAE = (req, res) => {
let io = getIO();
io.emit();
// rest of your controller function code
}
Note that I did not call the getIO function outside the controller function. For example, the following would probably not work:
const getIO = require('../server').getIO;
var io = getIO();
exports.updateSAE = (req, res) => {
io.emit();
// rest of your controller function code
}
Simply because the socket.io object could have not been initialized when you call the function, thus returning undefined.

Can't seem to get socket io to display any emits

I've been trying to figure out why I can't get any emits to show up in my terminal and it seems that everything is running fine.... except for seeing the emits. Here is my code
var express = require('express');
var path = require('path');
// Create a new Express application
var app = express();
var views = path.join(process.cwd(), 'views');
app.use("/static", express.static("public"));
// Create an http server with Node's HTTP module.
// Pass it the Express application, and listen on port 3000.
var server = require('http').createServer(app).listen(3000, function() {
console.log('listening on port ' + 3000)
});
// Instantiate Socket.IO hand have it listen on the Express/HTTP server
var io = require('socket.io')(server);
var game = require('./game');
app.get('/', function(req,res) {
res.sendFile(path.join(views, 'index.html'));
});
io.on('connect', function(socket) {
io.emit('connection', { message: "You are connected!" });
game.initGame(io, socket);
socket.emit('connected', { message: "You are connected!" });
io.sockets.emit('test', 'test')
});
Any help would be great!
Emits are not automatically printed. socket.emit will send a message back to the client, not to the terminal. Use console.log("whatever") to print to the terminal:
io.on('connect', function(socket) {
console.log('Client connected');
socket.on('test', function(data) {
console.log("Got message of type 'test'containing data:", data);
});
});

Make two socket connections talk to each other

Here is the scenario...
I am working on an app I had an idea for, I'm building it in ember with an express backend. I am using the express-ws so I can run the ws websocket package inside express better. I was not able to get just ws to work with express.
My app will have two people connecting to two different url's that are socket connections, so that they can send and receive information to the server without the other getting it. At least that's the way I've come up in my mind to do it.
What I want is when one user does an interaction over the socket, for that socket to send a message to the other socket to perform an action and send it's information to the user connected on it.
I hope that makes sense. With express-ws here is what I have done so far which works at a basic level.
var express = require('express');
var app = express();
var expressWs = require('express-ws')(app);
app.use(function (req, res, next) {
console.log('middleware');
req.testing = 'testing';
return next();
});
app.get('/', function(req, res, next){
console.log('browser connected');
res.send('welcome to the api browser');
});
app.ws('/', function(ws, req) {
console.log('socket connected');
var object = {
message: 'welcome to the socket api',
time: Date.now().toString()
}
ws.send(JSON.stringify(object));
});
app.listen(1337);
I haven't made the other connection yet but for the time being it will be the same, but when the user on one connection sends a certain message to their socket, I want that socket to perform something and then pass some data to the other socket so it can send some information to it's user.
This might give you an idea of how to store the references for later use:
var express = require('express');
var app = express();
var expressWs = require('express-ws')(app);
// array to hold the connections
var openChannels = [];
app.use(function(req, res, next) {
console.log('middleware');
req.testing = 'testing';
return next();
});
app.get('/', function(req, res, next) {
console.log('browser connected');
res.send('welcome to the api browser');
});
app.ws('/', function(ws, req) {
console.log('socket connected');
// store connection for later reference
openChannels.push(ws);
// #todo: remove from array on disconnect
// set broadcast callback
ws.onmessage = function(msg) {
openChannels.forEach(function(index, item) {
if (item !== ws) { // make sure we're not sending to ourselves
item.send(msg);
}
});
};
var object = {
message: 'welcome to the socket api',
time: Date.now().toString()
}
ws.send(JSON.stringify(object));
});
app.listen(1337);

Routing with restify and socket.io in node

I have a node app which routes the request based on the url using restfy.
Now in want to bring socket into picture. But app doesnot redirect to the function when when socket.io is used. I am using FlexSocket.IO library in flex.
Here's my code snippet.
// In app.js
var restify = require('restify')
, http = require('http')
,socket = require('./routes/socket');
var app = restify.createServer();
app.get('/', socket.handle);
app.post('/', socket.handle);
var io = require('socket.io').listen(app);
app.listen(8080, function() {
console.log('%s listening at %s', app.name, app.url);
});
io.configure(function() {
io.set('transports', ['websocket','flashsocket']);
io.set('flash policy port', 843);
});
exports.io = io;
//In socket.js
exports.handle = function (req, res, next) {
console.log('In Handle'); //doesn't print this
io.sockets.on('connection', function(client){
console.log('Connection establiished');
});
In Flex
private var socket:FlashSocket;
socket = new FlashSocket("localhost:8080");
socket.addEventListener(FlashSocketEvent.CONNECT, onConnect);
socket.addEventListener(FlashSocketEvent.MESSAGE, onMessage);
protected function onConnect(event:FlashSocketEvent):void
{
Alert.show('connect'); //This alert is shown.
}
Is there anything wrong with the code? Why is the socket.handle function not called in node?
In app.js, try
var io = require('socket.io').listen(app.server); //app.server instead of just app

Resources