Make polls more efficient

Instead of emitting frames to each individual socket, group them into
socket.io rooms of people who can see hidden poll results and people who
can't, then just do 2 broadcasts.
This commit is contained in:
calzoneman 2016-04-02 11:57:26 -07:00
parent 20538e328f
commit 0ee7f05213
6 changed files with 58 additions and 33 deletions

View file

@ -2,7 +2,7 @@
"author": "Calvin Montgomery",
"name": "CyTube",
"description": "Online media synchronizer and chat",
"version": "3.14.6",
"version": "3.15.0",
"repository": {
"url": "http://github.com/calzoneman/sync"
},

View file

@ -646,12 +646,12 @@ Channel.prototype.handleReadLog = function (user) {
});
};
Channel.prototype._broadcast = function (msg, data, ns) {
Channel.prototype.broadcastToRoom = function (msg, data, ns) {
sio.instance.in(ns).emit(msg, data);
};
Channel.prototype.broadcastAll = function (msg, data) {
this._broadcast(msg, data, this.name);
this.broadcastToRoom(msg, data, this.name);
};
Channel.prototype.packInfo = function (isAdmin) {

View file

@ -740,6 +740,7 @@ PlaylistModule.prototype.handleAssignLeader = function (user, data) {
this.leader = null;
if (old.account.effectiveRank === 1.5) {
old.account.effectiveRank = old.account.oldRank;
old.emit("effectiveRankChange", old.account.effectiveRank);
old.socket.emit("rank", old.account.effectiveRank);
}
@ -766,6 +767,7 @@ PlaylistModule.prototype.handleAssignLeader = function (user, data) {
if (this.leader.account.effectiveRank < 1.5) {
this.leader.account.oldRank = this.leader.account.effectiveRank;
this.leader.account.effectiveRank = 1.5;
this.leader.emit("effectiveRankChange", 1.5);
this.leader.socket.emit("rank", 1.5);
}

View file

@ -12,10 +12,15 @@ const TYPE_VOTE = {
option: "number"
};
const ROOM_VIEW_HIDDEN = ":viewHidden";
const ROOM_NO_VIEW_HIDDEN = ":noViewHidden";
function PollModule(channel) {
ChannelModule.apply(this, arguments);
this.poll = null;
this.roomViewHidden = this.channel.uniqueName + ROOM_VIEW_HIDDEN;
this.roomNoViewHidden = this.channel.uniqueName + ROOM_NO_VIEW_HIDDEN;
if (this.channel.modules.chat) {
this.channel.modules.chat.registerCommand("poll", this.handlePollCmd.bind(this, false));
this.channel.modules.chat.registerCommand("hpoll", this.handlePollCmd.bind(this, true));
@ -59,20 +64,53 @@ PollModule.prototype.save = function (data) {
};
PollModule.prototype.onUserPostJoin = function (user) {
this.sendPoll([user]);
this.sendPoll(user);
user.socket.typecheckedOn("newPoll", TYPE_NEW_POLL, this.handleNewPoll.bind(this, user));
user.socket.typecheckedOn("vote", TYPE_VOTE, this.handleVote.bind(this, user));
user.socket.on("closePoll", this.handleClosePoll.bind(this, user));
this.addUserToPollRoom(user);
const self = this;
user.on("effectiveRankChange", () => {
self.addUserToPollRoom(user);
});
};
PollModule.prototype.addUserToPollRoom = function (user) {
const perms = this.channel.modules.permissions;
if (perms.canViewHiddenPoll(user)) {
user.socket.leave(this.roomNoViewHidden);
user.socket.join(this.roomViewHidden);
} else {
user.socket.leave(this.roomViewHidden);
user.socket.join(this.roomNoViewHidden);
}
};
PollModule.prototype.onUserPart = function(user) {
if (this.poll) {
this.poll.unvote(user.realip);
this.sendPollUpdate(this.channel.users);
this.broadcastPoll(false);
}
};
PollModule.prototype.sendPoll = function (users) {
PollModule.prototype.sendPoll = function (user) {
if (!this.poll) {
return;
}
var perms = this.channel.modules.permissions;
user.socket.emit("closePoll");
if (perms.canViewHiddenPoll(user)) {
var unobscured = this.poll.packUpdate(true);
user.socket.emit("newPoll", unobscured);
} else {
var obscured = this.poll.packUpdate(false);
user.socket.emit("newPoll", obscured);
}
};
PollModule.prototype.broadcastPoll = function (isNewPoll) {
if (!this.poll) {
return;
}
@ -81,32 +119,13 @@ PollModule.prototype.sendPoll = function (users) {
var unobscured = this.poll.packUpdate(true);
var perms = this.channel.modules.permissions;
users.forEach(function (u) {
u.socket.emit("closePoll");
if (perms.canViewHiddenPoll(u)) {
u.socket.emit("newPoll", unobscured);
} else {
u.socket.emit("newPoll", obscured);
}
});
};
PollModule.prototype.sendPollUpdate = function (users) {
if (!this.poll) {
return;
const event = isNewPoll ? "newPoll" : "updatePoll";
if (isNewPoll) {
this.channel.broadcastAll("closePoll");
}
var obscured = this.poll.packUpdate(false);
var unobscured = this.poll.packUpdate(true);
var perms = this.channel.modules.permissions;
users.forEach(function (u) {
if (perms.canViewHiddenPoll(u)) {
u.socket.emit("updatePoll", unobscured);
} else {
u.socket.emit("updatePoll", obscured);
}
});
this.channel.broadcastToRoom(event, unobscured, this.roomViewHidden);
this.channel.broadcastToRoom(event, obscured, this.roomNoViewHidden);
};
PollModule.prototype.handleNewPoll = function (user, data) {
@ -132,7 +151,7 @@ PollModule.prototype.handleNewPoll = function (user, data) {
}
this.poll = poll;
this.sendPoll(this.channel.users);
this.broadcastPoll(true);
this.channel.logger.log("[poll] " + user.getName() + " opened poll: '" + poll.title + "'");
};
@ -143,7 +162,7 @@ PollModule.prototype.handleVote = function (user, data) {
if (this.poll) {
this.poll.vote(user.realip, data.option);
this.sendPollUpdate(this.channel.users);
this.broadcastPoll(false);
}
};
@ -179,7 +198,7 @@ PollModule.prototype.handlePollCmd = function (obscured, user, msg, meta) {
var title = args.shift();
var poll = new Poll(user.getName(), title, args, obscured);
this.poll = poll;
this.sendPoll(this.channel.users);
this.broadcastPoll(true);
this.channel.logger.log("[poll] " + user.getName() + " opened poll: '" + poll.title + "'");
};

View file

@ -121,6 +121,7 @@ RankModule.prototype.handleRankChange = function (user, data) {
receiver.account.channelRank = rank;
receiver.account.effectiveRank = Math.max(receiver.account.globalRank, rank);
receiver.emit("effectiveRankChange", receiver.account.effectiveRank);
receiver.socket.emit("rank", receiver.account.effectiveRank);
this.channel.logger.log("[mod] " + user.getName() + " set " + name + "'s rank " +
"to " + rank);

View file

@ -429,6 +429,9 @@ User.prototype.refreshAccount = function (opts, cb) {
}
}
self.account = account;
if (account.effectiveRank !== old.effectiveRank) {
self.emit("effectiveRankChange", self.account.effectiveRank);
}
}
cb(err, account);
});