diff --git a/public/less/admin/general/dashboard.less b/public/less/admin/general/dashboard.less
index 1001893ed7..ebf65e9fd0 100644
--- a/public/less/admin/general/dashboard.less
+++ b/public/less/admin/general/dashboard.less
@@ -38,7 +38,7 @@
li {
float: left;
- width: 48%;
+ width: 100%;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
@@ -90,7 +90,7 @@
border-color: #46BFBD;
background-color: #5AD3D1;
}
- &.on-homepage {
+ &.on-categories {
border-color: #F7464A;
background-color: #FF5A5E;
}
diff --git a/public/src/admin/general/dashboard.js b/public/src/admin/general/dashboard.js
index 7a2243465d..40ace1ecc1 100644
--- a/public/src/admin/general/dashboard.js
+++ b/public/src/admin/general/dashboard.js
@@ -141,10 +141,10 @@ define('admin/general/dashboard', ['semver'], function(semver) {
'
Connections
' +
'';
- var idle = data.socketCount - (data.users.home + data.users.topics + data.users.category);
+ var idle = data.socketCount - (data.users.categories + data.users.topics + data.users.category);
updateRegisteredGraph(data.onlineRegisteredCount, data.onlineGuestCount);
- updatePresenceGraph(data.users.home, data.users.topics, data.users.category, idle);
+ updatePresenceGraph(data.users.categories, data.users.topics, data.users.category, idle);
updateTopicsGraph(data.topics);
$('#active-users').html(html);
@@ -266,7 +266,7 @@ define('admin/general/dashboard', ['semver'], function(semver) {
value: 1,
color:"#F7464A",
highlight: "#FF5A5E",
- label: "On homepage"
+ label: "On categories list"
},
{
value: 1,
@@ -345,8 +345,8 @@ define('admin/general/dashboard', ['semver'], function(semver) {
graphs.registered.update();
}
- function updatePresenceGraph(homepage, posts, topics, idle) {
- graphs.presence.segments[0].value = homepage;
+ function updatePresenceGraph(categories, posts, topics, idle) {
+ graphs.presence.segments[0].value = categories;
graphs.presence.segments[1].value = posts;
graphs.presence.segments[2].value = topics;
graphs.presence.segments[3].value = idle;
@@ -424,6 +424,9 @@ define('admin/general/dashboard', ['semver'], function(semver) {
function buildTopicsLegend() {
var legend = $('#topics-legend').html('');
+ segments.sort(function(a, b) {
+ return b.value - a.value;
+ });
for (var i = 0, ii = segments.length; i < ii; i++) {
var topic = segments[i],
label = topic.tid === '0' ? topic.label : ' ' + topic.label + '';
diff --git a/public/src/app.js b/public/src/app.js
index 8974d2316a..dadf141702 100644
--- a/public/src/app.js
+++ b/public/src/app.js
@@ -105,8 +105,8 @@ app.cacheBuster = null;
case 'admin':
room = 'admin';
break;
- case 'home':
- room = 'home';
+ case 'categories':
+ room = 'categories';
break;
}
app.currentRoom = '';
diff --git a/src/socket.io/index.js b/src/socket.io/index.js
index 337320e226..e0fd83f7b7 100644
--- a/src/socket.io/index.js
+++ b/src/socket.io/index.js
@@ -12,6 +12,7 @@ var SocketIO = require('socket.io'),
user = require('../user'),
logger = require('../logger'),
ratelimit = require('../middleware/ratelimit'),
+ rooms = require('./rooms'),
Sockets = {},
Namespaces = {};
@@ -63,8 +64,8 @@ function onConnection(socket) {
function onConnect(socket) {
if (socket.uid) {
- socket.join('uid_' + socket.uid);
- socket.join('online_users');
+ rooms.enter(socket, 'uid_' + socket.uid);
+ rooms.enter(socket, 'online_users');
user.getUserFields(socket.uid, ['status'], function(err, userData) {
if (err || !userData) {
@@ -77,7 +78,7 @@ function onConnect(socket) {
}
});
} else {
- socket.join('online_guests');
+ rooms.enter(socket, 'online_guests');
socket.emit('event:connect');
}
}
@@ -85,7 +86,7 @@ function onConnect(socket) {
function onDisconnect(socket, data) {
if (socket.uid) {
var socketCount = Sockets.getUserSocketCount(socket.uid);
- if (socketCount <= 0) {
+ if (socketCount <= 1) {
socket.broadcast.emit('event:user_status_change', {uid: socket.uid, status: 'offline'});
}
@@ -96,6 +97,7 @@ function onDisconnect(socket, data) {
}
});
}
+ rooms.leaveAll(socket, data.rooms);
}
function onMessage(socket, payload) {
@@ -183,7 +185,7 @@ function authorize(socket, callback) {
socket.uid = parseInt(sessionData.passport.user, 10);
} else {
socket.uid = 0;
- }
+ }
next();
});
}
@@ -218,27 +220,25 @@ Sockets.in = function(room) {
};
Sockets.getSocketCount = function() {
- // TODO: io.sockets.adapter.sids is local to this worker
- // use redis-adapter
-
- var clients = Object.keys(io.sockets.adapter.sids || {});
- return Array.isArray(clients) ? clients.length : 0;
+ return rooms.socketCount();
};
Sockets.getUserSocketCount = function(uid) {
- // TODO: io.sockets.adapter.rooms is local to this worker
- // use .clients('uid_' + uid, fn)
+ return rooms.clients('uid_' + uid).length;
+};
- var roomClients = Object.keys(io.sockets.adapter.rooms['uid_' + uid] || {});
- return Array.isArray(roomClients) ? roomClients.length : 0;
+Sockets.getOnlineUserCount = function() {
+ var count = 0;
+ Object.keys(rooms.roomClients()).forEach(function(roomName) {
+ if (roomName.startsWith('uid_')) {
+ ++ count;
+ }
+ });
+ return count;
};
Sockets.getOnlineAnonCount = function () {
- // TODO: io.sockets.adapter.rooms is local to this worker
- // use .clients()
-
- var guestSocketIds = Object.keys(io.sockets.adapter.rooms.online_guests || {});
- return Array.isArray(guestSocketIds) ? guestSocketIds.length : 0;
+ return rooms.clients('online_guests').length;
};
Sockets.reqFromSocket = function(socket) {
@@ -258,9 +258,7 @@ Sockets.reqFromSocket = function(socket) {
};
Sockets.isUserOnline = function(uid) {
- // TODO: io.sockets.adapter.rooms is local to this worker
- // use .clients('uid_' + uid, fn)
- return io ? !!io.sockets.adapter.rooms['uid_' + uid] : false;
+ return !!rooms.clients('uid_' + uid).length;
};
Sockets.isUsersOnline = function(uids, callback) {
@@ -301,26 +299,29 @@ Sockets.getUsersInRoom = function (uid, roomName, callback) {
Sockets.getUidsInRoom = function(roomName, callback) {
callback = callback || function() {};
- // TODO : doesnt work in cluster
var uids = [];
- var socketids = Object.keys(io.sockets.adapter.rooms[roomName] || {});
+ var socketids = rooms.clients(roomName);
if (!Array.isArray(socketids) || !socketids.length) {
callback(null, []);
return [];
}
for(var i=0; i 0) {
+ topTenTopics = topTenTopics.concat(scores[mostActive.pop()]);
+ }
+
+ topTenTopics = topTenTopics.slice(0, 10);
+
+ topics.getTopicsFields(topTenTopics, ['title'], function(err, titles) {
if (err) {
return callback(err);
}
-
- var rooms = {}; // TODO: websockets.server.sockets.manager.rooms; doesnt work in socket.io 1.x
- var socketData = {
- onlineGuestCount: websockets.getOnlineAnonCount(),
- onlineRegisteredCount: onlineRegisteredCount,
- socketCount: websockets.getSocketCount(),
- users: {
- home: rooms['/home'] ? rooms['/home'].length : 0,
- topics: 0,
- category: 0
- },
- topics: {}
+ topTenTopics.forEach(function(tid, id) {
+ socketData.topics[tid] = {
+ value: Array.isArray(roomClients['topic_' + tid]) ? roomClients['topic_' + tid].length : 0,
+ title: validator.escape(titles[id].title)
};
-
- var scores = {},
- topTenTopics = [],
- tid;
-
- for (var room in rooms) {
- if (rooms.hasOwnProperty(room)) {
- if (tid = room.match(/^\/topic_(\d+)/)) {
- var length = rooms[room].length;
- socketData.users.topics += length;
-
- if (scores[length]) {
- scores[length].push(tid[1]);
- } else {
- scores[length] = [tid[1]];
- }
- } else if (room.match(/^\/category/)) {
- socketData.users.category += rooms[room].length;
- }
- }
- }
-
- var scoreKeys = Object.keys(scores),
- mostActive = scoreKeys.sort();
-
- while(topTenTopics.length < 10 && mostActive.length > 0) {
- topTenTopics = topTenTopics.concat(scores[mostActive.pop()]);
- }
-
- topTenTopics = topTenTopics.slice(0, 10);
-
- topics.getTopicsFields(topTenTopics, ['title'], function(err, titles) {
- if (err) {
- return callback(err);
- }
- topTenTopics.forEach(function(tid, id) {
- socketData.topics[tid] = {
- value: rooms['/topic_' + tid].length,
- title: validator.escape(titles[id].title)
- };
- });
-
- callback(null, socketData);
});
+
+ callback(null, socketData);
});
+
};
/* Exports */
diff --git a/src/socket.io/rooms.js b/src/socket.io/rooms.js
new file mode 100644
index 0000000000..e392abf3f9
--- /dev/null
+++ b/src/socket.io/rooms.js
@@ -0,0 +1,95 @@
+'use strict';
+
+
+// Temp solution until
+// https://github.com/NodeBB/NodeBB/issues/2486
+// and
+// https://github.com/Automattic/socket.io/issues/1945
+// are closed.
+// Once they are closed switch to .clients() and async calls
+
+
+var pubsub = require('../pubsub');
+
+var rooms = {};
+
+var clientRooms = {};
+var roomClients = {};
+
+rooms.enter = function(socket, room) {
+ socket.join(room);
+ pubsub.publish('socket:join', {id: socket.id, room: room});
+};
+
+rooms.leave = function(socket, room) {
+ socket.leave(room);
+ pubsub.publish('socket:leave', {id: socket.id, room: room});
+};
+
+rooms.leaveAll = function(socket, roomsToLeave) {
+ roomsToLeave.forEach(function(room) {
+ rooms.leave(socket, room);
+ });
+};
+
+pubsub.on('socket:join', onSocketJoin);
+pubsub.on('socket:leave', onSocketLeave);
+
+function onSocketJoin(data) {
+ clientRooms[data.id] = clientRooms[data.id] || [];
+ if (clientRooms[data.id].indexOf(data.room) === -1) {
+ clientRooms[data.id].push(data.room);
+ }
+
+ roomClients[data.room] = roomClients[data.room] || [];
+ if (roomClients[data.room].indexOf(data.id) === -1) {
+ roomClients[data.room].push(data.id);
+ }
+}
+
+
+function onSocketLeave(data) {
+ var index;
+ if (Array.isArray(clientRooms[data.id])) {
+ index = clientRooms[data.id].indexOf(data.room);
+ if (index !== -1) {
+ clientRooms[data.id].splice(index, 1);
+ if (!clientRooms[data.id].length) {
+ delete clientRooms[data.id];
+ }
+ }
+ }
+
+ if (Array.isArray(roomClients[data.room])) {
+ index = roomClients[data.room].indexOf(data.id);
+ if (index !== -1) {
+ roomClients[data.room].splice(index, 1);
+ if (!roomClients[data.room].length) {
+ delete roomClients[data.room];
+ }
+ }
+ }
+}
+
+
+rooms.clients = function(room) {
+ return Array.isArray(roomClients[room]) ? roomClients[room] : [];
+};
+
+rooms.clientRooms = function(id) {
+ return Array.isArray(clientRooms[id]) ? clientRooms[id] : [];
+};
+
+rooms.socketCount = function() {
+ return Object.keys(clientRooms || {}).length;
+};
+
+rooms.roomClients = function() {
+ return roomClients;
+};
+
+
+
+
+module.exports = rooms;
+
diff --git a/src/views/admin/general/dashboard.tpl b/src/views/admin/general/dashboard.tpl
index 759144152d..94f9125fab 100644
--- a/src/views/admin/general/dashboard.tpl
+++ b/src/views/admin/general/dashboard.tpl
@@ -1,6 +1,5 @@
-
-
+
Forum Traffic
@@ -88,8 +87,8 @@
-
-
+
+
Anonymous vs Registered Users
@@ -108,7 +107,7 @@
- - On Homepage
+ - On categories list
- Reading posts
- Browsing topics
- Idle