Nodejs accessing nested variable in global scope - javascript

How would I access socket in the global scope based on my following NodeJS code
io.on('connection', function (socket) {
console.log('connection '+socket)
socket.on("data",function(d){console.log('data from flash: ',d);});
socket.emit("message","wtfwtwftwftwf hello from server");
socket.on('disconnect', function (socket) {
console.log("disconnect");
});
});
I need to access socket from within the following app.post method
var express = require('express'),
multer = require('multer');
var app = express();
//auto save file to uploads folder
app.use(multer({ dest: './uploads/'}))
app.post('/', function (req, res) {
console.log(req.body); //contains the variables
console.log(req.files); //contains the file references
res.send('Thank you for uploading!');
});
app.listen(8080);
Haven't tested yet but going to try a simple getter function first
io.on('connection', function (socket) {
console.log('connection '+socket)
socket.on("data",function(d){console.log('data from flash: ',d);});
socket.emit("message","wtfwtwftwftwf hello from server");
return{
getSocket: function(){
return socket;
}
};
socket.on('disconnect', function (socket) {
console.log("disconnect");
});
});
io.getSocket() ??

Express's app and Socket.io have nothing to do with one another.
So fundamentally, you can't use socket inside app.post.
You need to identify the client. You can use Passport which has a Socket.io plugin that essentially bridges the app.post/get's req.user to socket.request.user.
Note: It doesn't have to be an authenticated client with user that's fetched from database, just a client with a temporary user stored in memory would do. Something like this:
app.use(function(req, res, next) {
if (!req.user) { // if a user doesn't exist, create one
var id = crypto.randomBytes(10).toString('hex');
var user = { id: id };
req.logIn(user);
res.redirect(req.lastpage || '/');
return;
}
next();
});
var Users = {};
passport.serialize(function(user) {
Users[user.id] = user;
done(null, user);
});
passport.deserialize(function(id) {
var user = Users[id];
done(null, user);
});
Then you can attach the client's socket ID to its user session.
io.on('connection', function (socket) {
socket.request.user.socketid = socket.id
});
And then instead of socket.emit use io.emit in app.post using the socketid
app.post('/', function (req, res) {
io.to(req.user.socketid).emit('whatever');
});
Note: io.to() is used to emit to a room, but every socket is by default joined to the same room named as its socket.id, so it'll work.

Javascript and socketIO experts > please tell me why this simple solution shouldn't work. It seems to...
1 Define a global pointer
var _this=this;
2 In my socketIO handler make a reference to the socket object
_this.socket=socket;
3 And finally within app.post, access the socket like thus
_this.socket.emit(....

Related

How to use socket.io with express-session that coming from controller

In my app.js ı using route in middleware like this:
app.use('/myPage', pageRoute);
my route page:
router.get('/new', pageController.pageFunc);
and my controller:
exports.pageFunc = (req, res, next) => {
res.render('myPage/pugFile', {
name: req.session.userName
});
}
Its working perfectly but i want use this session with my socket in my app.js
my socket is like this:
io.on('connection', socket => {
socket.on('myIo', (par) => {
console.log(par);
});
});
if i try to use req.session.userName in my socket i taking req is not defined error. How can i use my sessions in this socket?
i solved my problem with middleware like this:
app.use('/myPage', pageRoute);
let mySession;
app.use((req,res,next)=>{
mySession = req.session.userName;
next();
});
io.on('connection', socket => {
socket.on('myIo', () => {
console.log(mySession );
});
});
EDIT: There are some problems in this solution , because mySession value changing with other user connection but finally i found solution.
You can use socket.request.session they explain how you can use in there: Usage with express-session

Using redis in an Express route

I want to simply be able to store a value in a key in one route
/api/foo?redisKey="1" (set value for id=1)
then I want to get the value in another route.
/api/bar?redisKey="1" (get value for id=1)
However, redis is async so you have to wait for it to connect
client.on('connect', function() {
//perform redis operations
});
I'm not sure how to synchronize this in my router.
I am going to assume you're using redis for your client library.
In your express route file, you do not want to create the connection during each request. Instead you will instantiate your redis client outside of the express middleware function, and use it during requests.
Here's a sample app:
var redis = require("redis");
var client = redis.createClient();
var express = require('express')
var app = express()
// GET request
// example: curl "localhost:3000/api/foo?redisKey=1"
app.get('/api/foo', function (req, res) {
var redisKey = req.query.redisKey
client.get(redisKey, function (err, reply) {
if(err){ res.status(400).send(err.getMessage()); return; }
res.status(200).send(reply.toString())
});
})
// for setting, use POST request
// example: curl -X POST "localhost:3000/api/foo?redisKey=1&redisValue=helloWorld"
app.post('/api/foo', function(req, res){
var redisKey = req.query.redisKey,
redisValue = req.query.redisValue
// assuming value is also a string in URL query string
client.set(redisKey, redisValue, function (err, reply){
res.status(200).send(reply.toString())
});
})
app.listen(3000, function () {
console.log('Example app listening on port 3000!')
})

NodeJS, websocket, and module.export

I have a server.js file.
Inside, i defined my routes.
// routes
var mainRoutes = require('./routes/main.js')(app, express);
var apiRoutes = require('./routes/api.js')(app, express);
var socketRoutes = require('./routes/socket.js');
app.use('/', mainRoutes);
app.use('/api', apiRoutes);
// socket.io communication
io.sockets.on('connection', socketRoutes);
My socket.js file looks like that :
module.exports = function (socket) {
console.log('user connected');
socket.on('myEvent', function(data) {
// whatever ...
});
}
Inside this function, i can catch events and send some.
BUT i need to send a message to everyone at some point. Let say when i receive an 'myEvent' event.
So basically, i would like to do :
io.sockets.emit('messageForEveryone', "This is a test");
But here, i can only work on the 'socket' argument, which is for 1 person only i guess.
I would like to pass io from server.js, to socket.js.
I tried that (in server.js) :
var socketRoutes = require('./routes/socket.js', io);
And that (in socket.js) :
module.exports = function (io, socket)
Obviously, it's not working. I don't even understand where the socket argument is coming from.
Question : How can i work on io object, when i'm inside the module.export of the sockets.js file ?
I would really appreciate any help, i'm new to all of this.
Thanks !
Since you just want to emit to all clients, instead of passing io to socketRoutes, you can simply do this.
module.exports = function (socket) {
var sockets = this;
console.log('user connected');
socket.on('myEvent', function(data) {
sockets.emit('hello_all_clients',data);
});
}
You could return a function from exports as such.
module.exports = function (io) { // pass io to initialize
return function (socket) {
// io and socket are both scoped
}
}
then in server.js
// socket.io communication
io.sockets.on('connection', socketRoutes(io));

How to emit an event in socket.io from the routes file?

This is my app configuration
app.js
//SERVER
var server = app.listen(3000, function(){
console.log("Express server listening on port %d in %s mode", app.get('port'),
app.settings.env);
});
//SOCKET.IO
var io = require('./socket.io').listen(server)
/socketio
var socketio = require('socket.io')
module.exports.listen = function(app)
{
io = socketio.listen(app);
io.configure('development',function()
{
//io.set('transports', ['websocket', 'xhr-polling']);
//io.enable('log');
});
io.configure('production',function()
{
io.enable('browser client minification'); // send minified client
io.enable('browser client etag'); // apply etag caching logic based on version number
io.set('log level', 1); // reduce logging
io.set('transports', [ // enable all transports (optional if you want flashsocket)
'websocket'
, 'flashsocket'
, 'htmlfile'
, 'xhr-polling'
, 'jsonp-polling'
]);
});
io.sockets.on('connection', function (socket)
{
console.log("new connection: "+socket.id);
socket.on('disconnect',function(){console.log("device "+socket.id+" disconnected");});
socket.emit('news', { hello: 'world' });
socket.on('reloadAccounts',function(data)
{
var accounts=['account1','account2']
socket.emit('news',accounts)
});
});
return io
}
/routes
exports.newAccount=function(fields,callback)//localhost:3000/newAccountForm
{
//... bla bla bla config db connection bla bla bla
db.collection('accounts').insert(fields,function(err,result)
{
if(err)
{
console.warn(err);
db.close();
return callback(err,null);
}else{
if(result)
{
db.close();
return callback(null,result);
socket.emit('new account created',result) // i want to emit a new event when any user create an account
}else{
db.close();
return callback('no se consigue resultado',null);
}
}
})
});
}
How to emit an event in socket.io from the routes file?
First you need to decide that what socket you want to send the new info. If it's all of them(to everyone connected to your app), it would be easy, just use io.sockets.emit:
In the ./socket.io file you add exports.sockets = io.sockets; somewhere after io = socketio.listen(app);. Then in the routes file, you can emit like this:
var socketio = require('./socket.io');
socketio.sockets.emit('new account created', result);
If you know the socket id that you want to send to, then you can do this:
var socketio = require('./socket.io');
socketio.sockets.sockets[socketId].emit('new account created', result);
You can also select the socket by express session id:
First you need to attach the session id to the socket on authorization:
io.set('authorization', function (data, accept) {
// check if there's a cookie header
if (data.headers.cookie) {
// if there is, parse the cookie
data.cookie = cookie.parse(data.headers.cookie);
// note that you will need to use the same key to grad the
// session id, as you specified in the Express setup.
data.sessionID = data.cookie['express.sid'];
} else {
// if there isn't, turn down the connection with a message
// and leave the function.
return accept('No cookie transmitted.', false);
}
// accept the incoming connection
accept(null, true);
});
Then you can select sockets with the session id:
var socketio = require('./socket.io');
var sockets = socketio.sockets.forEach(function (socket) {
if (socket.handshake.sessionID === req.sesssionID)
socket.emit('new account created', result);
});
You can also query your session store and using the method I described above, emit the event to sockets with sessionId that matched your query.

How to push changes in a database to the client using socket.io?

I am working on an app which, among other things, pushes data to the client when an updation occurs on the database. The trouble is that the websocket on node.js listens to the databse on a different port then the node. The guy before me wrote a piece of code and then dumped it on me. The node looks somewhat like this:
var handler=http.createServer(function(req, res){
session(req, res, function(req, res, body) {
if (!req.session || !req.session.data || !req.session.data.uid || req.session.data.uid == '' || !req.session.data.role || req.session.data.role =='') {
var uri = url.parse(req.url).pathname;
if(req.method == 'GET' && uri =="/attendance-node/getMonthFromReport") {
var uri = url.parse(req.url).pathname;
var url_parts = url.parse(req.url,true);
processgetMonthFromReport(req, res, uri, url_parts.query);
return;
}
res.writeHead(401, {"Content-Type": "text/plain"});
res.write("401 Unauthorized");
res.end();
return;
}
if(req.method == 'POST') {
var uri = url.parse(req.url).pathname;
var qs = require('querystring');
var POSTVAR = qs.parse(body, '&', '=', {"maxKeys" : 0});
//var POSTVAR=JSON.parse(body);
handleRequest(req, res, uri, POSTVAR);
}
if (req.method=='GET') {
var uri = url.parse(req.url).pathname;
var url_parts = url.parse(req.url,true);
handleRequest(req, res, uri, url_parts.query);
}
});
}).listen(3014,"127.0.0.1");
var io = require('socket.io').listen(8077,"127.0.0.1");
sys.puts("websocket Server running on port 8077");
io.configure(function () {
io.set('transports', ['websocket', 'flashsocket', 'xhr-polling','jsonp-polling']);
io.set('log level', 0);
});
io.sockets.on('connection', function (socket) {
io.sockets.emit('init',"i am working via websocket");
});
As you can see the node is listening on 3014 and the socket on 8077. Now how am I suppossed to provide an handler for the message received on the socket and forward it to the node's client?
Note: I am fairly new to web development. So basically I was thrown in the water and now I am learning to swim.
P.S. Also, what would the client side of the socket look like?
P.P.S. The database sending update notification to the socket is already taken care of. It comes as a POST request.
Thanx in advance!!
It sounds like you want to have socket.io also on the client side (browser?) as well.
I'd say the best solution would be to have socket.io run on the same port as your web server. However, if it this not possible and you must keep the web socket that the database uses separate from the web server you could run two instances of socket.io.
One would be attached to the web server, and the other would be for the database.
var app = require('http').createServer(handler)
, IO = require('socket.io')
, web_io = IO.listen(app)
, data_io = IO.listen(8080)
, fs = require('fs')
app.listen(80);
function handler (req, res) {
fs.readFile(__dirname + '/index.html',
function (err, data) {
if (err) {
res.writeHead(500);
return res.end('Error loading index.html');
}
res.writeHead(200);
res.end(data);
});
}
web_io.sockets.on('connection', function (socket) {
socket.on('some_event', function (data) {
console.log(data);
});
});
data_io.sockets.on('connection', function (socket) {
socket.on('database_update', function (data) {
// Will be sent to everyone socket listening on port 80 (browser sockets mostlikely)
web_io.sockets.emit('database_update', data);
});
socket.on('disconnect', function () {
io.sockets.emit('user disconnected');
});
});

Categories