i'm having a problem accessing the socket from a secondary file:
Having two files:
1) main.js
2) secondary.js
In main.js:
var sec = require('./secondary.js');
function DoFuncOnSecondaryFile(){
setInterval(function(){
//here i can't pass the socket, because it is not inside "io.on connection"
sec.myExternalFunc( socket );
}, 5000);
}
io.on('connection', function(socket){
//all the socket events in here
});
In secondary.js:
module.exports = {
myExternalFunc: function(){
socket.emit("message", "I cannot reach the socket so i will throw an error");
socket.to(anId).emit("message", "Supposing 'anId' is correctly defined and it is the id of a connected socket, this function won't work anyway!");
}
}
I need the function "myExternalFunc()" to be executed every 5 seconds, if i want to pass the socket as argument, i need to put it inside io.on('connection') so that the socket variable is defined, but then my Interval will start everytime someone connects.
How can I use an emit in an external file where i am not able to pass the socket variable?
Related
I am using socket.io in one of express route to populate data from server and send it to on client with different event names, firstsocket and secondsocket.
var io
router.get('/start', function(req, res, next) {
io = req.app.get('socketio');
var socketlist = [{name:"firstsocket"},{name:"secondsocket"}]
for (var key in socketlist){
myInterval = setInterval(function(){
JsonObj.marks = socketlist[key].name+' '+parseInt(Math.random()*100);
io.emit(socketname, JsonObj);
}, 2000);
}
});
it is working and i can see the data on client console for these to socket events. Now i want to stop one of the socket event based on user button click. I am not getting idea to list and stop sockets.
router.get('/stop', function(req, res) {
if(req.socketname=='firstsocket') {
//stop and destroy firstsocket
}
if(req.socketname=='secondsocket') {
//stop and destroy secondsocket
}
res.redirect('/');
});
please suggest, how to identify and stop one socket session out of multiple sessions.
Thanks
If you store the socket.id information of each socket within your
var socketlist = [{name:"firstsocket"},{name:"secondsocket"}]; array,
then you would be able to close a socket connection by doing;
io.sockets.sockets[socketlist[req.socketname].socket_id].disconnect(true);
Though, I would recommend you to check if
io.sockets.sockets[socketlist[req.socketname].socket_id]
returns undefined before accessing it's disconnect property.
If you try to access disconnect property of an already closed socket, the code above will return undefined and you will have an error thrown saying
"Can't access the property disconnect of undefined"
Final code should be something like this;
if (io.sockets.sockets[socketlist[req.socketname].socket_id]) {
io.sockets.sockets[socketlist[req.socketname].socket_id].disconnect(true);
}
You can get the socket.id information of a socket on the initial connection to the server.
I'd advise you to move your io decleration out of the route and declare it like this with your socket list;
var io = require('socket.io')(server);
var socketlist = [], first_socket_connected = false;
The server variable should be your express server.
Then, use the code below to receive socket connections and push to your socket list;
io.on("connection", function(socket) {
socketlist.push({name: first_socket_connected ? "secondsocket" : "firstsocket", id: socket.id});
first_socket_connected = true;
});
I'm trying to learn node.js cluster with socket.io to create a chat application... the problem is that I can't seem to get things working.
i've been trying to go through all the tutorials including the one that I get from this http://stackoverflow.com/questions/18310635/scaling-socket-io-to-multiple-node-js-processes-using-cluster/18650183#18650183
when I try to open two browsers, the messages does not go to the other browser.
here's the code that i got
var express = require('express'),
cluster = require('cluster'),
net = require('net'),
socketio = require('socket.io'),
socket_redis = require('socket.io-redis');
var port = 3000,
num_processes = require('os').cpus().length;
if (cluster.isMaster) {
// This stores our workers. We need to keep them to be able to reference
// them based on source IP address. It's also useful for auto-restart,
// for example.
var workers = [];
// Helper function for spawning worker at index 'i'.
var spawn = function(i) {
workers[i] = cluster.fork();
// Optional: Restart worker on exit
workers[i].on('exit', function(code, signal) {
console.log('respawning worker', i);
spawn(i);
});
};
// Spawn workers.
for (var i = 0; i < num_processes; i++) {
spawn(i);
}
// Helper function for getting a worker index based on IP address.
// This is a hot path so it should be really fast. The way it works
// is by converting the IP address to a number by removing non numeric
// characters, then compressing it to the number of slots we have.
//
// Compared against "real" hashing (from the sticky-session code) and
// "real" IP number conversion, this function is on par in terms of
// worker index distribution only much faster.
var worker_index = function(ip, len) {
var s = '';
for (var i = 0, _len = ip.length; i < _len; i++) {
if (!isNaN(ip[i])) {
s += ip[i];
}
}
return Number(s) % len;
};
// Create the outside facing server listening on our port.
var server = net.createServer({ pauseOnConnect: true }, function(connection) {
// We received a connection and need to pass it to the appropriate
// worker. Get the worker for this connection's source IP and pass
// it the connection.
var worker = workers[worker_index(connection.remoteAddress, num_processes)];
worker.send('sticky-session:connection', connection);
}).listen(port);
} else {
// Note we don't use a port here because the master listens on it for us.
var app = new express();
// Here you might use middleware, attach routes, etc.
app.use('/assets', express.static(__dirname +'/public'));
app.get('/', function(req, res){
res.sendFile(__dirname + '/index.html');
});
// Don't expose our internal server to the outside.
var server = app.listen(),
io = socketio(server);
// Tell Socket.IO to use the redis adapter. By default, the redis
// server is assumed to be on localhost:6379. You don't have to
// specify them explicitly unless you want to change them.
io.adapter(socket_redis({ host: 'localhost', port: 6379 }));
// Here you might use Socket.IO middleware for authorization etc.
io.on('connection', function(socket) {
console.log('New client connection detected on process ' + process.pid);
socket.emit('welcome', {message: 'Welcome to BlueFrog Chat Room'});
socket.on('new.message', function(message) {
socket.emit('new.message', message);
})
});
// Listen to messages sent from the master. Ignore everything else.
process.on('message', function(message, connection) {
if (message !== 'sticky-session:connection') {
return;
}
// Emulate a connection event on the server by emitting the
// event with the connection the master sent us.
server.emit('connection', connection);
connection.resume();
});
}
If I understand correctly, your problem is that the messages from a client are not broadcasted to the other clients. you can solve this easily using :
io.on('connection', function(socket) {
console.log('New client connection detected on process ' + process.pid);
socket.emit('welcome', {message: 'Welcome to BlueFrog Chat Room'});
socket.on('new.message', function(message) {
socket.emit('new.message', message); // this line sends the message back to the emitter
socket.broadcast.emit('my message', msg); // this broadcasts the message to all the clients
})
});
There are different ways to emit a message. The one you're using emits the message only to the socket that first sent a 'new.message' message to the server. Which means that a socket will receive the message that you emit there only if it first sent a message 'new.message'. That's why, in your browser, the client originating the message is the only one receiving it back.
Change it to:
socket.on('new.message', function(message) {
io.sockets.emit('new.message', message);//use this if even the browser originating the message should be updated.
socket.broadcast.emit('new.message', message);//use this if everyone should be updated excpet the browser source of the message.
})
Here are the different ways you can emit:
io.sockets.on('connection', function(socket) {
//This message is only sent to the client corresponding to this socket.
socket.emit('private message', 'only you can see this');
//This message is sent to every single socket connected in this
//session, including this very socket.
io.sockets.emit('public message', 'everyone sees this');
//This message is sent to every single connected socket, except
//this very one (the one requesting the message to be broadcasted).
socket.broadcast.emit('exclude sender', 'one client wanted all of you to see this');
});
You can also add sockets to different rooms when they connect so that you only communicate messages with sockets from a given room:
io.sockets.on('connection', function(socket) {
//Add this socket to a room called 'room 1'.
socket.join('room 1');
//This message is received by every socket that has joined
//'room 1', including this one. (Note that a socket doesn't
//necessarily need to belong to a certain room to be able to
//request messages to be sent to that room).
io.to('room 1').emit('room message', 'everyone in room 1 sees this');
//This message is received by every socket that has joined
//'room 1', except this one.
socket.broadcast.to('room 1').emit('room message', 'everyone in room 1 sees this');
});
I am trying to make a chat app which sends first message as "Hi. there".
But due to some some reasons (unstable internet connection might be one) the socket get initialized multiple times and sends the "Hi. there" message multiple times. Below is the code. How to stop the app for sending multiple messages?
io.socket.on('connect', function() {
/* On successfull connection to server */
console.log('Connected to server');
//Some code here
io.socket.get(url + '/userstatus/subscribe', function(resData, jwres) {
//Some code here
io.socket.on("userstatus", function(event) {
//Socket updartes
// Send Message code at this line.
}
}
});
You need to change your client side code, so that it stores state, and sends it to the server on reconnect. That way the server can give the correct response.
Something like this might work:
socket.on('connect', function() {
/* On successfull connection to server */
console.log('Connected to server');
socket.emit('state', state_object);
});
Is there a way to set up socket.io listeners for certain clients after they execute a command? For example:
socket.on('setupServer', function (data) {
console.log("setupServer called");
// Now set up listeners
socket.on('serverAction', function (data) {
console.log('Listener for clients calling setupServer');
});
});
In the above, a client has connected and has issued a 'setupServer' command to the node.js server. The server now listens for 'serverAction' from the specific client. Other clients won't be able to use 'serverAction' without calling 'setupServer' first.
You could create a room and validate some data from user and then join those users to that room, after that emit some events to that users in that room.
Something like this.
server.js
var io = require('socket.io')(server);
io.on('connection',function(socket){
socket.emit('auth_user')
socket.on('response_from_user',function(data){
if(data.name === "Blashadow"){
//join that user to the room
socket.join('/room',function(){
//emit some custom event to users in that room
io.in('/room').emit('custom_event_room', { info: 'new used connected from room' });
});
}
});
});
client.html
var socket = io('localhost');
socket.on('auth_user', function (data) {
socket.emit('response_from_user', { name : "Blashadow" });
});
socket.on('custom_event_room',function(data){
console.log(data);
});
I have been trying to disconnect from a namespace or even from the main socket connection itself but have been failing. Below is my code
Server Side:
socket.on('userDisconnect', function () {
socket.disconnect();
console.log("User Disconnected");
});
Client Side:
// already connected to /world namespace
socket.emit('userDisconnect');
socket.disconnect();
socket = io.connect('http://something/india' );
I tried disconnecting from both client and serve side but it doesnt work. Can anyone point out the mistake.
This is what is been written to console by socket.io
info - booting client
debug - websocket writing 0::/world
User Disconnected
debug - client authorized for /india
debug - websocket writing 1::/india
/world is the namespace its trying to disconnect from and then its trying to connect to /india namespace.
This worked for me
broadcastSocket.packet({ type: 'disconnect' });
broadcastSocket.$emit('disconnect');
disconnectNamespace(broadcastSocket.name, broadcastSocket.socket);
function disconnectNamespace (name,socket) {
if (socket.namespaces[name]) {
var nsp = socket.of(name);
nsp.packet({ type: 'disconnect' });
nsp.$emit('disconnect');
delete socket.namespaces[name];
if (Object.keys(socket.namespaces).length === 0) {
socket.disconnect();
}
}
};
For socket.io v.1.3.2
Create with:
sio = io('ws://localhost:13000/device');
Delete with:
sio.disconnect();
delete sio.io.nsps[sio.nsp]; // sio.nsp = '/device'
delete sio;
This worked for me.
On the server
nsp.on('connection', (socket) => {
setTimeout(() => {
socket.disconnect(false)
}, 5000);
});
Disconnects this client. If the value of close is true, closes the underlying connection. Otherwise, it just disconnects the namespace. It's in the documentation https://socket.io/docs/server-api/
It doesn't look like you told the client to wait for disconnect before reconnecting.
// already connected to /world namespace
socket.emit('userDisconnect');
socket.on('disconnect', function () {
socket = io.connect('http://something/india');
// stuff with india socket
});
Use disconnect() method on the server or on the client (or both like your did in your example). When you first connect to the server, add 'forceNew':false to the client connect method, something like this:
var socket = io('http://localhost:3001', {'forceNew':false});