I have this app in socket.io using node.js server and I want to update the points for every one connected in the app. I keep a list of connected users by socket.id and secret in the clients array.
And I tried like this but the points won't update. Can anyone tell me what's wrong?
function updatePoints(){
points = [];
pool.getConnection(function(err, connection) {
connection.query("SELECT * FROM `users`", function(error, rows) {
for (var i = 0; i < rows.length; i++) {
points.push({"secret" : rows[i].secret, "points" : rows[i].pontos});
}
for (var l = 0; l < points.length; l++) {
for (var p = 0; p < clients.length; p++) {
if(points[l].secret == clients[p].secret){
var socketID = clients[p].socket;
var pontos = points[l].points;
io.sockets.connected[socketID].emit('update points', pontos);
}
}
}
});
});
}
Socket.io version: 1.3.7
How about make a client object theb assigning a socket and a point property then push it in a the clients array?
socketServer.on('connection', function(socket){
//make your query here
...
//make a client object
var client = {point: row.point, socket: socket};
clients[row.secret] = client;
});
then you can retrieve the client by:
//query...
....
clients[row.secret].socket.emit('something', function);
edit:
if you want to broadcast to connected clients then you can:
socketServer.emit('something', function);
if you want to broad to everyone except the one who emitted the broadcast. then you can:
clients[row.secret].broadcast.emit('something', function;
Replace the
io.sockets.connected[socketID].emit('update points', pontos);
with this
socket.broadcast.to(socketID).emit('update points', pontos);
Related
I'm using my own rooms implementation in Socket.io (got my own Room/Player classes), since I need to perform several filters the room. For now, I save all sockets inside "players" property in a Room, and implemented my own "emit" to the room, the loops players and emits to their sockets.
Is it considerably slower to the traditional broadcast.to('room')? or it basically does what I did to my own room implementation? I'm aiming on having thousands of rooms with 2-4 players in each...
Thanks :)
As you can see by looking at the code for the socket.io adapter .broadcast() on GitHub, all socket.io is doing is looping over a list of sockets and sending a packet to each one (see code below).
So, if your code is doing something similar, then performance would likely be something similar.
Where you might notice a feature difference is if you are using a custom adapter such as the redis adapter that is used with clustering, then the logic of broadcasting to users connected to different servers would be handled for you by the built-in adapter, but may be something you'd have to implement yourself if doing your own broadcast.
Here's the socket.io-adapter version of .broadcast():
Adapter.prototype.broadcast = function(packet, opts){
var rooms = opts.rooms || [];
var except = opts.except || [];
var flags = opts.flags || {};
var packetOpts = {
preEncoded: true,
volatile: flags.volatile,
compress: flags.compress
};
var ids = {};
var self = this;
var socket;
packet.nsp = this.nsp.name;
this.encoder.encode(packet, function(encodedPackets) {
if (rooms.length) {
for (var i = 0; i < rooms.length; i++) {
var room = self.rooms[rooms[i]];
if (!room) continue;
var sockets = room.sockets;
for (var id in sockets) {
if (sockets.hasOwnProperty(id)) {
if (ids[id] || ~except.indexOf(id)) continue;
socket = self.nsp.connected[id];
if (socket) {
socket.packet(encodedPackets, packetOpts);
ids[id] = true;
}
}
}
}
} else {
for (var id in self.sids) {
if (self.sids.hasOwnProperty(id)) {
if (~except.indexOf(id)) continue;
socket = self.nsp.connected[id];
if (socket) socket.packet(encodedPackets, packetOpts);
}
}
}
});
};
I am trying to adapt a piece of code that was coded with socket.io 0.9 that returns a list of clients in a specific room and list of rooms(typical chat-room example)
Users in room
var usersInRoom = io.sockets.clients(room);
List of rooms
socket.on('rooms', function() {
var tmp = io.sockets.manager.rooms;
socket.emit('rooms', tmp);
});
tmp looks like this
{
0: Array[1],
1: /Lobby: Array[1]
}
So I can show the list in the client with this javascript run on the browser.
socket.on('rooms', function(rooms) {
$('#room-list').empty();
debugger;
for(var room in rooms) {
room = room.substring(1, room.length);
if (room != '') {
$('#room-list').append(divEscapedContentElement(room));
}
}
$('#room-list div').click(function() {
chatApp.processCommand('/join ' + $(this).text());
$('#send-message').focus();
});
});
But for version >1.x I just found the clients/rooms changed.
Following some links I found here, I could manage to get a list of rooms by doing this:
socket.on('rooms', function(){
var tmp = socket.rooms;
socket.emit('rooms', tmp);
});
The problem here is that socket.rooms returns
{
0: "RandomString",
1: "Lobby",
length: 2
}
And I just need to pass the 'Lobby' room. I don't know from where the random string come from.
EDIT
Through some debugging I discovered, the randomstring is the socket.id ... Is it normal this behavior? Returning the room and the socket.id together?
Updated
I finally got some results
Users in room
var usersInRoom = getUsersByRoom('/', room);
function getUsersByRoom(nsp, room) {
var users = []
for (var id in io.of(nsp).adapter.rooms[room]) {
users.push(io.of(nsp).adapter.nsp.connected[id]);
};
return users;
};
List of rooms
function getRooms(io){
var allRooms = io.sockets.adapter.rooms;
var allClients = io.engine.clients;
var result = [];
for(var room in allRooms){
// check the value is not a 'client-socket-id' but a room's name
if(!allClients.hasOwnProperty(room)){
result.push(room);
}
}
return result;
}
Better and more straightforward ways to achieve the results?
These are the links I checked:
How to get room's clients list in socket.io 1.0
socket.io get rooms which socket is currently in
It seems there is no better approach, so I will use my own answer. In case any of you has a better solution, I would update the accepted one.
Users in room
var usersInRoom = getUsersByRoom('/', room);
function getUsersByRoom(nsp, room) {
var users = []
for (var id in io.of(nsp).adapter.rooms[room]) {
users.push(io.of(nsp).adapter.nsp.connected[id]);
};
return users;
};
List of rooms
function getRooms(io){
var allRooms = io.sockets.adapter.rooms;
var allClients = io.engine.clients;
var result = [];
for(var room in allRooms){
// check the value is not a 'client-socket-id' but a room's name
if(!allClients.hasOwnProperty(room)){
result.push(room);
}
}
return result;
}
I'm trying to count the total number of users in a specific room and broadcast it to all the people in that room.
Here is what I have but I get an error:
var clients = io.sockets.clients(cc.lowerCase(data.roomname)).length;
io.sockets.in(cc.lowerCase(data.roomname)).emit('updatetotal', { total: clients });
ERROR:
TypeError: Object #<Namespace> has no method 'clients'
Thanks.
Since socket.io 1.0 its API was significantly changed so the old code might not work.
To get the number of clients in a room you can use this function:
var getUsersInRoomNumber = function(roomName, namespace) {
if (!namespace) namespace = '/';
var room = io.nsps[namespace].adapter.rooms[roomName];
if (!room) return null;
var num = 0;
for (var i in room) num++;
return num;
}
or more laconically:
var getUsersInRoomNumber = function(roomName, namespace) {
if (!namespace) namespace = '/';
var room = io.nsps[namespace].adapter.rooms[roomName];
if (!room) return null;
return Object.keys(room).length;
}
This function takes two agruments:
roomName
namespace (optional) default = '/'
To send message to users of this room only use .to method:
io.to(yourRoomName).emit('updatetotal', { total: getUsersInRoomNumber(yourRoomName) });
to get total users in a room
io.sockets.adapter.rooms.get(roomName).size
I am now starting in this world of Node.js, I've done several tests, initially as the typical "Hello World", up to the creation of a simple chat, I have embarked on the creation of one a bit more complex, which I describe below:
A chat in which users already exist, which are housed in a MySQL database.
It should create multiple chat rooms, where every conversation is one to one.
Initially I did Mysql connection tests, achieving it efficiently, but coming across problems when closing the connection to it, so I found another "solution" which will ask if it is advisable to do it or the Otherwise it would be a big mistake.
To chat'm making use of Seller Socket.io known, which, reading the documentation I have found related to the ID of the session, you can associate more information, what I'm doing is the following:
I a room through socket.join option (room)
With the property "set" of socket.io, I am storing information related to the connected user, such as name, database id and url of the picture, through an object.
Using io.sockets.clients (room), get users who are in the room, given that a user can have more than one session (several windows / tabs), so do the validation client side with the user id, to show just one.
Server:
var io = require("socket.io").listen(8080, {log: false});
io.on("connection", function(socket)
{
socket.on("newUser", function(data)
{
var participants = [];
var room = data.ig;
socket.set('iduser', data.d, function ()
{
socket.join(room);
for (var ver in pas = io.sockets.clients(room))
{
participants.push({id: pas[ver].store.data.iduser[0].id, n: pas[ver].store.data.iduser[0].n, f: pas[ver].store.data.iduser[0].f});
}
io.sockets.in(room).emit("newConnection", {participants: participants});
});
});
socket.on("disconnect", function()
{
var rooms = io.sockets.manager.roomClients[socket.id];
for(var room in rooms)
{
if(room.length > 0)
{
room = room.substr(1);
}
}
var idusuario = 0;
for(var ver in pas = io.sockets.clients(room))
{
if(pas[ver].id == socket.id)
{
idusuario = pas[ver].store.data.iduser[0].id;
break;
}
}
if(idusuario != 0)
{
//El número de veces que tiene una sesión...
var num = 0;
for(var ver in pas = io.sockets.clients(room))
{
if(pas[ver].store.data.iduser[0].id == idusuario)
{
num++;
}
}
if(num <= 1)
{
io.sockets.in(room).emit("userDisconnected", {id: idusuario, sender:"system"});
}
}
});
});
Client
Appreciate their opinions or suggestions on how to deal with this difficulty.
Thanks in advance for their help.
I am trying to implement a small chatservice using flapjax. I use an eventStream to get all the clients that connect to the server, and when broadcasting a message (the function on 'message') I map over this eventStream with the function that emits the message to the current client.
// Event stream yielding received clients
var clientReceiverE = receiverE();
// Event stream collecting all the clients
var clientsE = clientReceiverE.collectE([], function (client, clients) {return clients.concat([client]);});
socket.on('connection', function(client) {
clientReceiverE.sendEvent(client);
for (i = 0; i < chatMessages.length; i++) {
client.emit('message', chatMessages[i]);
}
client.on('message', function(message) {
chatMessages.push(message);
//for (i = 0; i < clients.length; i++) {
// clients[i].emit('message', message);
//}
mapE(clientReceiverE, function(client) {console.log(client); client.emit('message', message); return client});
});
client.on('nickname', function(name) {
});
});
The registring of the clients on the eventstream succeeds with this code, but the mapE doesn't result in a loop over all this clients. Does anybody know what is wrong here?
If you are still not guessed :) I think it's because mapE doesn't produce any action itself, mapE only creates and returns another EventStream which behaves like a given source, but with modified value by means of a given function.
You should not be using mapE like that. In your code you are attempting to recreate the mapE event bindings with each client.on('message', ...).
This problem is solved using a receiverE. This function is used to translate, external event streams into flapjax EventStream 's.
// Event stream yielding received clients
var clientReceiverE = receiverE();
// Event stream collecting all the clients
var clientsE = clientReceiverE.collectE([], function (client, clients) {return clients.concat([client]);});
var clientsB = clientsE.startsWith(undefined); //Turn the event stream into a behaviour (event + value)
var messagesE = receiverE();
messagesE.mapE(function(messagePacket){
var clients = clientsB.valueNow(); //Grab current value of client list behaviour
if(clients==undefined){
return;
}
var from = messagePacket.client;
for(var index in clients){
clients[index].emit('message', messagePacket.message);
console.log(messagePacket.message);
}
});
socket.on('connection', function(client) {
clientReceiverE.sendEvent(client);
client.on('message', function(message) {
messagesE.sendEvent({client: client, message: message});
});
});
The difference is this. The flapjax tree is isolated from the WebSocket event code and there is no shared state between them.