I am working on a node.js project that I am leveraging Socket.IO in, and am having an issue getting my head around a scoping issue. Here is what I am trying to do:
var io = require('socket.io').listen(80);
session_manager = require('./includes/session_manager');
// client joins the socket server
io.sockets.on('connection', function(client) {
client.on('X.Session.join', function(session_id, client) {
session_manager.joinSession(session_id, function(err, session) {
// do whatever
});
});
// BRING IN MORE LISTENERS/EMITTERS?
require('someModuleIBuild');
});
As you can see I am basically setting up the initial connection, joining a session via a managing class (so I know who to emit to for which session) and then I am trying to dynamically bring in some custom stuff that ALSO is going to be emitting and listening via the socket connection.
So how do I reference this current connection from within the confines of my custom modules? All the examples I have seen have all the "on" and "emit" functions in one file, which seems like it could get out of control pretty quickly.
I am possibly over-thinking/over-complicating this (this is my first node.js project, first socket-based project, first mostly-javascript project....etc) but any help would be appreciated.
create your modules like this and you can pass the client into the module
module.exports = function(client) {
client.on("whatever", function () {
});
client.on("whenever", function (data) {
});
};
and then do the require like this
require('someModuleIBuild')(client);
Related
I write a Node.Js app and I use Socket.Io as the data transfer system, so requests should be particular to per user. How can I make this?
My actual code;
node:
io.on('connection', (socket) => {
socket.on('loginP', data => {
console.log(data);
})
})
js:
var socket = io('',{forceNew : false});
$("#loginbutton").click(function() {
var sessionInfo = {
name : $("#login input[name='username']").val(),
pass : $("#login input[name='pass']").val()
}
socket.emit("loginP", sessionInfo)
})
It returns one more data for per request and this is a problem for me. Can I make this on Socket.Io or should I use another module, and If I should, which module?
If I understand your question correctly (It's possible I don't), you want to have just one connection from each user's browser to your nodejs program.
On the nodejs side, your io.on('connection'...) event fires with each new incoming user connection, and gives you the socket for that specific connection. So, keep track of your sockets; you'll have one socket per user.
On the browser side, you should build your code to ensure it only calls
var socket = io(path, ...);
once for each path (your path is ''). TheforceNew option is for situations where you have multiple paths from one program.
This question already has an answer here:
Emitting a message in sails v0.11 (client-side)
(1 answer)
Closed 6 years ago.
The server: sails.js (0.11.x) is the server
The client: A node.js script with sails.io#0.11.5 and socket.io-client#1.3.5
Big picture: I have, or will have, a farm of node.js scripts that connect to the sails.js server and will perform various tasks.
Immediate Goal: I want to emit an event during a socket connection from client->server such as:
socket.emit('got_job', job.id);
Why? If this is possible I can create various event handlers on the server side in one controller (or controller + service) and keep my code clean while managing a set of stateful transactions between client/server endpoints for supporting this script farm.
The documentation: This is how one goes about using socket.io-client for sails.js this per sails docs: https://github.com/balderdashy/sails.io.js?files=1#for-nodejs
I haven't much code to share other than what's in that link, but I'll paste it here just in case:
var socketIOClient = require('socket.io-client');
var sailsIOClient = require('sails.io.js');
// Instantiate the socket client (`io`)
// (for now, you must explicitly pass in the socket.io client when using this library from Node.js)
var io = sailsIOClient(socketIOClient);
// Set some options:
// (you have to specify the host and port of the Sails backend when using this library from Node.js)
io.sails.url = 'http://localhost:1337';
// ...
// Send a GET request to `http://localhost:1337/hello`:
io.socket.get('/hello', function serverResponded (body, JWR) {
// body === JWR.body
console.log('Sails responded with: ', body);
console.log('with headers: ', JWR.headers);
console.log('and with status code: ', JWR.statusCode);
// When you are finished with `io.socket`, or any other sockets you connect manually,
// you should make sure and disconnect them, e.g.:
io.socket.disconnect();
// (note that there is no callback argument to the `.disconnect` method)
});
What I have looked into: I've drilled into various levels of these objects and I can't seem to find anything exposed to use. And simply trying io.socket.emit() as it doesn't exist. But io.socket.get() and io.socket.post(), etc work fine.
console.log(socketIOClient);
console.log(sailsIOClient);
console.log(io);
console.log(io.socket._raw);
console.log(io.sails);
Thanks, and I'll try to update this as needed for clarification.
UPDATE:
Misc Server Info.:
I'm using nginx on port 443, with SSL termination, pointing to 4 (and
soon more) sails.js instances on separate ports (3000-3003).
I'm also using Redis for sessions and sockets.
You're close:
Your io.socket.get call is kind of like a rest api call. You'd need a sails controller bound to a get request on the url '/hello',
//client
io.socket.get('/hello', function serverResponded (body, JWR) {
//this is the response from the server, not a socket event handler
console.dir(body);//{message:"hello"}
});
in
config/routes.js:
{
'get /hello':'MyController.hello'
}
//controllers/MyController
{
hello:function(req,res){
res.json({message:"hello"});
}
}
The method you're looking for is, io.socket.on('eventName');
Here's an example:
//client
io.socket.get('/hello', function serverResponded (body, JWR) {
//all we're doing now is subscribing to a room
console.dir(body);
});
io.socket.on('anevent',function(message){
console.dir(message);
});
in
config/routes.js:
{
'get /hello':'MyController.hello'
}
//controllers/MyController
{
hello:function(req,res){
sails.sockets.join(req.socket,'myroom');
res.json({message:'youve subscribed to a room'});
}
}
What we've effectively done is, setup our socket to be part of a "room", which is basically an event namespace. Then, some other controller only has to do this:
sails.sockets.broadcast('myroom','anevent',{message:'socket event!'});
After this call is made, you would receive the message in the callback of io.socket.on('anevent').
I have a MEAN app setup with npm socket.io with expressjs and btford.socket-io on the client.
angular.module('myApp',['btford.socket-io'])
.factory('socket',function(socketFactory){
return socketFactory();
}
).controller('myAppCtrl',['$scope','socket',
function(a,b){
b.on('test',function(data){
console.log(data);
});
}
]);
Here's the node-express setup:
var app = express(),
server = app.listen(3000);
var socket = require('socket.io'),
io = socket.listen(server);
require('/config/routes/index.js')(app,io);
require('/config/routes/test.js')(app,io);
Routes : (config/routes/index.js)
module.exports = function(app,io){
app.get('/',function(req,res){
io.on('connection',function(socket){
socket.join(req.session._id);
});
res.render('index');
});
};
config/routes/test.js
module.exports = function(app,io){
app.get('/route1',function(req,res){
io.to(req.session._id).emit('test',{
data : 'Works'
});
res.render('route1');
});
};
A) Whenever the user goes to route1, the emit event is being fired and sent to all the users.
B) Is there a better approach to avoid using unique room for each user? This is not a chat application but rather implements push notifications
You have a couple major misunderstandings about how sockets and requests work. They are very separate operations and are not connected the way you appear to think they are. I will try to explain the problems with your code.
In this block of code:
module.exports = function(app,io){
app.get('/',function(req,res){
io.on('connection',function(socket){
socket.join(req.session._id);
});
res.render('index');
});
};
You are processing the / page request and EVERY time that request is hit, you add yet another event handler for io.on('connection', ...), thus you could have many of those.
Further, if the connection event happens BEFORE the user hits the / page, then you will miss it entirely and that socket will not be placed into the proper chat room.
Then, in this block of code:
module.exports = function(app,io){
app.get('/route1',function(req,res){
io.to(req.session._id).emit('test',{
data : 'Works'
});
res.render('route1');
});
};
io.to() takes a string that is the name of a chat room. So, this will send a message to every socket that is in the req.session._id chat room. For this to work, you'd have to make absolutely sure that req.session._id was completely unique to this user and that the desired user had already joined a chat room by this name. This could work, but it depends upon those specific things being correct.
You need to think of the connection from socket.io separately from a request. They are NOT tied together the way that you think they are. Your connection listener is for any connection not just a connection related to a given request... what you are trying to do simply will not work that way.
Imagine that your socket.io portions of your project are completely separate from the http requests in the web/express portions of your application. This is how you should think of passing messages.
Also worth consideration is that if you are using cluster or similar scaling methods, your default socket.io setup in one instance doesn't communicate with other instances.
where is a good place to put my logic if I want to use sails.io? Is config/bootstrap.js a good place to put it? Or is there some other file I can create somewhere else?
This code below works:
// config/bootstrap.js
module.exports.bootstrap = function (cb) {
sails.io.sockets.on('connection', function(socket) {
console.log("Got a connected client");
});
cb();
};
It doesn't support this until 0.9.4.
step 1. Get the latest version of sails.js
step 2. Generate sails with the the cli
step 3. See config/sockets.js, customize onConnect function, see below:
module.exports.sockets = {
// This custom onConnect function will be run each time AFTER a new socket connects
// (To control whether a socket is allowed to connect, check out `authorization` config.)
// Keep in mind that Sails' RESTful simulation for sockets
// mixes in socket.io events for your routes and blueprints automatically.
onConnect: function(session, socket) {
// By default: do nothing
// This is a good place to subscribe a new socket to a room, inform other users that
// someone new has come online, or any other custom socket.io logic
console.log("Got a connected client");
},
...
For logic processing, you can put it in the following places:
Controller: if a request should trigger a real-time event
Service: if you want :) but I think Controller is referred
/config/socket.js onConnect(), onDisconnect(): If you want to add or remove the connected socket to/from some rooms, or some initial socket setup, etc.
/policies/sessionAuth.js: for some real-time authen logic
Other places...
Beside, you should consider the resourceful-pubsub feature which may help you save a lot of effort on implementing real-time process with socket. I found that it's very cool :)
I'm making an application where I need to map sockets to some object. I thought I would be safe using the socket.id variable provided by Socket.IO. Unfortunately while debugging I found out that the socket.id changed without the client disconnecting/reconnecting or whatever.
Here's a small piece of code to show what I'm trying to do:
var io = require('socket.io').listen(8080),
var myVariable = new Array();
// Main event loop
io.sockets.on('connection', function (socket) {
socket.on('myEvent', function(data) {
myVariable[socket.id] = data;
}
// 'someOtherEvent' which uses the mapped data.
socket.on('someOtherEvent', function(data) {
// Doesn't always work because socket.id has changed and var is empty
doSomethingWith(myVariable[socket.id]);
}
});
I'm not sure but I don't think this is the desired effect. Why does this happen and how would I work around it?
I was using node-inspector to debug my application and because I was holding the code on some breakpoint it disconnected the client (probably some timeout client side). That's why I got a new socket.id when I continued the code execution.
Looks like 'someOtherEvent' emited before 'myEvent' or socket has been reconnected. I use socket.id as connection identifier on two different projects in production and it works without any problems.