Socket.io serverside broadcast - javascript

I want to update an array on the server and broadcast it to all clients. The problem I am facing is that I need the client parameter to broadcast. On the server:
var socket = io.listen(8000);
var plateaus = [];
setInterval(function () {
plateaus.push('new data');
-- send the updated array to all clients --
}, 1000);
socket.sockets.on("connection", setEventListeners);
function setEventListeners(client)
// loadExistingPlayer(client); <- normally I use the client param
}
How do I broadcast the updated array? Many thanks!

answer on my own question (hope I will help anyone in the future).
You can store the client parameter in an array and access it anytime:
var socket = io.listen(8000);
var plateaus = [];
var clients = []
setInterval(function () {
plateaus.push('new data');
for(var i = 0; i < clients.length; i++){
clients[i].emit('updata all clients', plateaus)
}
}, 1000);
socket.sockets.on("connection", setEventListeners);
function setEventListeners(client)
console.log('new client');
clients.push(client);
}

After you connect your client, wouldn't you just emit an event from your server and your client could listen to that event with on(event, cb)?
From the Docs: http://socket.io/docs/
Server:
var io = require('socket.io')(server);
io.on('connection', function (socket) {
socket.emit('news', { hello: 'world' });
socket.on('my other event', function (data) {
console.log(data);
});
});
Client:
var socket = io('http://localhost');
socket.on('news', function (data) {
console.log(data);
socket.emit('my other event', { my: 'data' });
});

Related

Socket.IO handling disconnect event

Can't handle this disconnect event, don't know why socket is not sent to the client / client doesn't respond!
Server
io.sockets.on('connection', function (socket) {
socket.on('NewPlayer', function(data1) {
online = online + 1;
console.log('Online players : ' + online);
console.log('New player connected : ' + data1);
Players[data1] = data1;
console.log(Players);
});
socket.on('DelPlayer', function(data) {
delete Players[data];
console.log(Players);
console.log('Adios' + data);
});
socket.on('disconnect', function () {
socket.emit('disconnected');
online = online - 1;
});
});
Client
var socket = io.connect('http://localhost');
socket.on('connect', function () {
person_name = prompt("Welcome. Please enter your name");
socket.emit('NewPlayer', person_name);
socket.on('disconnected', function() {
socket.emit('DelPlayer', person_name);
});
});
As you can see when a client disconnects the Array object[person_name] should be deleted, but it's not.
Ok, instead of identifying players by name track with sockets through which they have connected. You can have a implementation like
Server
var allClients = [];
io.sockets.on('connection', function(socket) {
allClients.push(socket);
socket.on('disconnect', function() {
console.log('Got disconnect!');
var i = allClients.indexOf(socket);
allClients.splice(i, 1);
});
});
Hope this will help you to think in another way
For those like #sha1 wondering why the OP's code doesn't work -
OP's logic for deleting player at server side is in the handler for DelPlayer event,
and the code that emits this event (DelPlayer) is in inside disconnected event callback of client.
The server side code that emits this disconnected event is inside the disconnect event callback which is fired when the socket loses connection. Since the socket already lost connection, disconnected event doesn't reach the client.
Accepted solution executes the logic on disconnect event at server side, which is fired when the socket disconnects, hence works.
Create a Map or a Set, and using "on connection" event set to it each connected socket, in reverse "once disconnect" event delete that socket from the Map we created earlier
import * as Server from 'socket.io';
const io = Server();
io.listen(3000);
const connections = new Set();
io.on('connection', function (s) {
connections.add(s);
s.once('disconnect', function () {
connections.delete(s);
});
});
You can also, if you like use socket id to manage your player list like this.
io.on('connection', function(socket){
socket.on('disconnect', function() {
console.log("disconnect")
for(var i = 0; i < onlineplayers.length; i++ ){
if(onlineplayers[i].socket === socket.id){
console.log(onlineplayers[i].code + " just disconnected")
onlineplayers.splice(i, 1)
}
}
io.emit('players', onlineplayers)
})
socket.on('lobby_join', function(player) {
if(player.available === false) return
var exists = false
for(var i = 0; i < onlineplayers.length; i++ ){
if(onlineplayers[i].code === player.code){
exists = true
}
}
if(exists === false){
onlineplayers.push({
code: player.code,
socket:socket.id
})
}
io.emit('players', onlineplayers)
})
socket.on('lobby_leave', function(player) {
var exists = false
for(var i = 0; i < onlineplayers.length; i++ ){
if(onlineplayers[i].code === player.code){
onlineplayers.splice(i, 1)
}
}
io.emit('players', onlineplayers)
})
})

Using Socket.IO to show object count within Compound.js

I'm testing out Socket.IO for a new project that uses Compound.js (built on node.js/Express.js), but I've come across a problem. I've managed to get the basics working and the following message works fine:
Server-side JS (applicationname/config/initializers/socketio.js):
var sio = require('socket.io');
var http = require('http');
var activeClients = 0;
module.exports = function (compound) {
var app = compound.app;
var server = http.createServer(app);
compound.server = server;
var io = compound.io = sio.listen(server);
io.sockets.on('connection', function (socket) {
activeClients +=1;
var connections = setInterval(function () {
socket.emit('news', { clients: activeClients });
}, 1000);
socket.on('disconnect', function () {
activeClients -= 1;
io.sockets.emit('user disconnected');
clearInterval(connections);
});
});
}
Front-end JS (applicationname/public/index.html):
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io.connect('http://localhost');
function msgReceived(msg){
$clientCounter.html(msg.posts);
}
$(document).ready(function () {
$clientCounter = $("#client_count");
socket.on('news', function (data) {
msgReceived(data);
socket.emit('my other event', { my: 'data' });
});
});
</script>
What I'm trying to do now is get the number of posts that have been made on the server. I used a default scaffold to generate the Posts method, controller and views.
How do I now find the total number of posts and pass that value to the server-side JS?
Simply count the number of emits on the server side and send that?
...
var emits = 0;
var connections = setInterval(function () {
emits++;
socket.emit('news', { clients: activeClients , num_messages: emits});
}, 1000);
...
Or create a specific message that can be polled from the client

How to run script and pass arguments if client is connected over socket?

Is it possible to run some script and if client connected pass arguments to it, something like this:
var io = require('socket.io').listen(http);
io.sockets.on('connection', function (client) {
console.log('Client connected');
var notifikacija = function (array) {
client.emit('populate', array);
}
});
///////////////////////////////////////////////////////////////////////
setInterval(function(){
var array = newArray();
array[0]='test';
notifikacija(array);
}, 2000);
Now it shows error: notifikacija is not defined. It is quite a strugle...
The notifikacija function is local to the scope of the io.sockets.on handler. You want it to be global so that you can access it in setInterval:
var notifikacija = function(){}; // just an empty function, in case it gets called before it has something to do
var io = require('socket.io').listen(http);
io.sockets.on('connection', function(client) {
console.log('Client connected');
notifikacija = function(array){ // once the client is available assign the function
client.emit('populate', array);
}
});
setInterval(function(){
var array = newArray();
array[0]='test';
notifikacija(array);
}, 2000);
Here's a blog post with some more information on scope in Javascript.

Dynamic Namespaces Socket.IO

How can I use dynamic namespaces in socket.io.
I'm looking in the (poor) documentation, and it says that namespaces must be used like this:
io.of('/news')
io.of('/akfda')
To use a namespace you do io.of("/namespace").
Do I need to register every single namespace in the server? Maybe I want a namespace for dynamic content.
How can I do something like :
io.of('/:somethign/:id')
Socket.IO supports 'rooms' (https://github.com/LearnBoost/socket.io/wiki/Rooms), you can use it instead of namespaces. Also when you need dynamic in routes (and you using express in your app) - best way is to use use route-engine from express box.
Best way to do dynamic routing with Express.js (node.js)
Using routes in Express-js
http://expressjs.com/api.html#app.routes
http://shtylman.com/post/expressjs-re-routing/
http://jordanhoff.com/post/22602013678/dynamic-express-routing
However, if you still think that you need dynamic in namespaces in socket.io, here is small example how it can be implemented:
User-side:
var connect = function (ns) {
return io.connect(ns, {
query: 'ns='+ns,
resource: "socket.io"
});
}
var socket = connect('/user/12');
Server-side:
var url = require('url');
, ev = new events.EventEmitter()
// <ns name>: <ns regexp>
var routes = {
// /user/:id
'user': '^\\/user\\/(\\d+)$',
// /:something/:id
'default': '^\\/(\\\w+)\\/(\\d+)$'
};
// global entry point for new connections
io.sockets.on('connection', function (socket) {
// extract namespace from connected url query param 'ns'
var ns = url.parse(socket.handshake.url, true).query.ns;
console.log('connected ns: '+ns)
//
for (var k in routes) {
var routeName = k;
var routeRegexp = new RegExp(routes[k]);
// if connected ns matched with route regexp
if (ns.match(routeRegexp)) {
console.log('matched: '+routeName)
// create new namespace (or use previously created)
io.of(ns).on('connection', function (socket) {
// fire event when socket connecting
ev.emit('socket.connection route.'+routeName, socket);
// #todo: add more if needed
// on('message') -> ev.emit(...)
});
break;
}
}
// when nothing matched
// ...
});
// event when socket connected in 'user' namespace
ev.on('socket.connection route.user', function () {
console.log('route[user] connecting..');
});
// event when socket connected in 'default' namespace
ev.on('socket.connection route.default', function () {
console.log('route[default] connecting..');
});
I hope this will help you!
I would use "rooms" to support your dynamic content.
Server Side
var server = require('http').createServer(),
io = require('socket.io')(server);
io.on('connection', function(socket){
var room = socket.handshake['query']['r_var'];
socket.join(room);
console.log('user joined room #'+room);
socket.on('disconnect', function() {
socket.leave(room)
console.log('user disconnected');
});
socket.on('chat message', function(msg){
io.to(room).emit('chat message', msg);
});
});
server.listen(3000);
Client Side
var socket_connect = function (room) {
return io('localhost:3000', {
query: 'r_var='+room
});
}
var random_room = Math.floor((Math.random() * 2) + 1);
var socket = socket_connect(random_room);
socket.emit('chat message', 'hello room #'+random_room);
....
As of version 2.1.1 I was able to make it work with this:
wss.of((nsp, query, next) => {
const { token } = query;
// Do your authentication or whatever here...
// If success
next(null, true);
}).on('connect', (socket) => {
// socket connected to your namespace
});
Server
var MAX_CLIENTS = 5;
var namespace_queue = [];
function searchObjectOnArray(nameKey, myArray) {
for (var i = 0; i < myArray.length; i++) {
if (myArray[i].id === nameKey) {
return myArray[i];
}
}
}
function createNamespace(data){
var ns = {
//id: require('node-uuid')(),
id : data.name,
clients: 0,
};
namespace_queue.push(ns);
return ns;
}
createNamespace({name: 'primer'});
io.of('').on('connection', function(socket){
console.log('-' + socket.id);
/// Welcome to the new client
socket.emit('Welcome', {SocketId : socket.id});
socket.on('JoinToApp', function (data, callback) {
var namespaceToConnect = searchObjectOnArray(data.namespace, namespace_queue)
if(namespaceToConnect.clients <= MAX_CLIENTS){
var dynamicNamespace = io.of('/' + namespaceToConnect.id);
dynamicNamespace.on('connection', function(ns_socket){
console.log('user connected to ' + namespaceToConnect.id);
dynamicNamespace.emit('hi', 'everyone!');
});
namespaceToConnect.clients++;
}
callback({namespaces:namespace_queue});
})
socket.on('createNamespace',function(data,join_cb){
createNamespace(data);
join_cb({message:'Namespace created'});
});
});
Client
<input id="namespaceInput" type="text" placeholder="New namespace name">
<input id="namespaceToConnect" type="text" placeholder="namespace to connect">
<button onclick="javascript: createNamespace()">Create Namespace</button>
<button onclick="javascript: joinToNamespace()">Connect to Namespace</button>
<script src="https://cdn.socket.io/socket.io-1.4.5.js"></script>
<script>
var socket = null;
(function(){
socket = io.connect('http://localhost:3000/');
})()
function createNamespace(){
var namespaceName = document.getElementById("namespaceInput").value;
socket.emit('createNamespace', {name : namespaceName}, function(data){
alert(data.message);
})
}
function joinToNamespace(){
var name = document.getElementById("namespaceToConnect").value;
socket.emit('JoinToApp', {namespace: name}, function(data){
console.log('Namespaces created:');
console.log(data)
var ns_socket = io.connect('http://localhost:3000/' + name);
ns_socket.on('connect',function(){
console.log('joined namespace ' + name);
});
ns_socket.on('hi', function(data){
console.log('hi ' + data)
})
});
}
</script>
More details on: https://ingcamilorodriguez.wordpress.com/2016/06/21/como-hacer-namespaces-dinamicos-en-socket-io/
Here is one way. Here is a socket.io subclass I created to solve the problem:
https://github.com/PencilCode/dynamic.io
That subclass adds dynamic namespaces as well as virtual hostname support (each host can go into its own namespace tree if you like). That repo has some examples.
Here is a universal socket.io listener that listens to every namespace requested, and logs a message for every socket that connects. You could listen to a different regexp to listen to any subset of namespaces.
It works with the standard socket.io client library without any modification.
var DynamicServer = require('dynamic.io');
io = DynamicServer({
host: true, // Enable virtual host handling
publicStatus: true // Enable /socket.io/status page.
});
// Any number of namespace patterns can be set up.
// This is an example of a single catch-all pattern.
io.setupNamespace(/.*/, function(nsp) {
nsp.on('connect', function(socket) {
console.log('a socket connected on', nsp.fullname());
});
nsp.expire(function() {
console.log(nsp.fullname(), 'is expiring');
});
});
io.listen(8888);
On newer versions you can use something like io.of(/^\/\w+$/).on('connection', (socket) where /^\/\w+$/ is a regular expression that will allow connection if it is a match.
Here is a full example on how to use this to setup many namespaces, here I suppose the only concerne is preventing emit diffusion from reaching other namespaces.
const workspaces = {}
io.of(/^\/\w+$/).on('connection', (socket) => {
const workspace = socket.nsp;
const namespace = workspace.name;
console.log("New Connection NameSpace", namespace);
// you can test here if "namespace" is allowed to be used
// if event handlers are set no need to got further
if (workspaces[namespace]) return;
// save workspace to prevent setting event handlers on each connection
workspaces[namespace] = workspace;
workspace.on("connection", (socket) => {
console.log(`${namespace} > connection from ${socket.id}`);
// set the event handlers same as normal socket
socket.on('event-1', (msg) => {
console.log("event-1", msg);
})
})
})

how to get session id of socket.io client in Client

I want to get session id of client in my socket.io client.
here is my socket.io client :
var socket = new io.Socket(config.host, {port: config.port, rememberTransport: false});
// when connected, clear out display
socket.on('connect',function() {
console.log('dummy user connected');
});
socket.on('disconnect',function() {
console.log('disconnected');
});
socket.connect();
return socket;
I want to get session id of this client , how can i get that ?
Have a look at my primer on exactly this topic.
UPDATE:
var sio = require('socket.io'),
app = require('express').createServer();
app.listen(8080);
sio = sio.listen(app);
sio.on('connection', function (client) {
console.log('client connected');
// send the clients id to the client itself.
client.send(client.id);
client.on('disconnect', function () {
console.log('client disconnected');
});
});
On socket.io >=1.0, after the connect event has triggered:
var socket = io('localhost');
var id = socket.io.engine.id
I just had the same problem/question and solved it like this (only client code):
var io = io.connect('localhost');
io.on('connect', function () {
console.log(this.socket.sessionid);
});
* Please Note: as of v0.9 the set and get API has been deprecated *
The following code should only be used for version socket.io < 0.9
See: http://socket.io/docs/migrating-from-0-9/
It can be done through the handshake/authorization mechanism.
var cookie = require('cookie');
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);
});
All the attributes, that are assigned to the data object are now accessible through the handshake attribute of the socket.io connection object.
io.sockets.on('connection', function (socket) {
console.log('sessionID ' + socket.handshake.sessionID);
});
On Server side
io.on('connection', socket => {
console.log(socket.id)
})
On Client side
import io from 'socket.io-client';
socket = io.connect('http://localhost:5000');
socket.on('connect', () => {
console.log(socket.id, socket.io.engine.id, socket.json.id)
})
If socket.id, doesn't work, make sure you call it in on('connect') or after the connection.
For some reason
socket.on('connect', function() {
console.log(socket.io.engine.id);
});
did not work for me. However
socket.on('connect', function() {
console.log(io().id);
});
did work for me. Hopefully this is helpful for people who also had issues with getting the id. I use Socket IO >= 1.0, by the way.
Try from your code
socket.socket.sessionid
ie.
var socket = io.connect('http://localhost');
alert(socket.socket.sessionid);
var sendBtn= document.getElementById('btnSend');
sendBtn.onclick= function(){
var userId=document.getElementById('txt1').value;
var userMsg = document.getElementById('txt2').value;
socket.emit('sendto',{username: userId, message: userMsg});
};
socket.on('news', function (data) {
console.log(data);
socket.emit('my other event', { my: 'data' });
});
socket.on('message',function(data){ console.log(data);});
Try this way.
var socket = io.connect('http://...');
console.log(socket.Socket.sessionid);

Categories