Merge pull request #310 from calzoneman/commandrefactor

Refactor command system
This commit is contained in:
Calvin Montgomery 2013-11-19 11:29:16 -08:00
commit a232b96786
4 changed files with 265 additions and 168 deletions

View File

@ -604,7 +604,7 @@ Channel.prototype.tryNameBan = function(actor, name) {
var notice = { var notice = {
username: "[server]", username: "[server]",
msg: actor.name + " banned " + name, msg: actor.name + " banned " + name,
msgclass: "server-whisper", meta: { addClass: "server-whisper" },
time: Date.now() time: Date.now()
}; };
self.users.forEach(function(u) { self.users.forEach(function(u) {
@ -716,7 +716,7 @@ Channel.prototype.tryIPBan = function(actor, name, range) {
username: "[server]", username: "[server]",
msg: actor.name + " banned " + $util.maskIP(ip) + msg: actor.name + " banned " + $util.maskIP(ip) +
" (" + name + ")", " (" + name + ")",
msgclass: "server-whisper", meta: { addClass: "server-whisper" },
time: Date.now() time: Date.now()
}; };
self.users.forEach(function(u) { self.users.forEach(function(u) {
@ -1133,7 +1133,7 @@ Channel.prototype.broadcastNewUser = function(user) {
var pkt = { var pkt = {
username: "[server]", username: "[server]",
msg: msg, msg: msg,
msgclass: "server-whisper", meta: { addClass: "server-whisper" },
time: Date.now() time: Date.now()
}; };
self.sendAllWithRank(2, "joinMessage", pkt); self.sendAllWithRank(2, "joinMessage", pkt);
@ -2186,6 +2186,10 @@ Channel.prototype.tryUpdateMotd = function(user, data) {
/* REGION Chat */ /* REGION Chat */
Channel.prototype.tryChat = function(user, data) { Channel.prototype.tryChat = function(user, data) {
if (data.meta === undefined) {
data.meta = {};
}
if(user.name == "") { if(user.name == "") {
return; return;
} }
@ -2205,6 +2209,15 @@ Channel.prototype.tryChat = function(user, data) {
return; return;
} }
// Validate meta
var meta = {};
if (user.rank >= 2) {
if ("modflair" in data.meta && data.meta.modflair === user.rank) {
meta.modflair = data.meta.modflair;
}
}
data.meta = meta;
var msg = data.msg; var msg = data.msg;
if(msg.length > 240) { if(msg.length > 240) {
msg = msg.substring(0, 240); msg = msg.substring(0, 240);
@ -2219,14 +2232,21 @@ Channel.prototype.tryChat = function(user, data) {
var msgobj = { var msgobj = {
username: user.name, username: user.name,
msg: msg, msg: msg,
msgclass: "", meta: data.meta,
time: Date.now() time: Date.now()
}; };
user.socket.emit("chatMsg", msgobj); user.socket.emit("chatMsg", msgobj);
return; return;
} }
this.chainMessage(user, msg); if (msg.indexOf("/") === 0) {
ChatCommand.handle(this, user, msg, data.meta);
} else {
if (msg.indexOf(">") === 0) {
data.meta.addClass = "greentext";
}
this.sendMessage(user, msg, data.meta);
}
} }
Channel.prototype.chainMessage = function(user, msg, data) { Channel.prototype.chainMessage = function(user, msg, data) {
@ -2271,7 +2291,30 @@ Channel.prototype.filterMessage = function(msg) {
return subs.join(""); return subs.join("");
} }
Channel.prototype.sendMessage = function(username, msg, msgclass, data) { Channel.prototype.sendMessage = function (user, msg, meta, filter) {
msg = sanitize(msg).escape();
msg = this.filterMessage(msg);
var msgobj = {
username: user.name,
msg: msg,
meta: meta,
time: Date.now()
}
if (filter && filter.byRank !== undefined) {
this.sendAllWithRank("chatMsg", msgobj, filter.byRank);
} else {
this.sendAll("chatMsg", msgobj);
this.chatbuffer.push(msgobj);
if(this.chatbuffer.length > 15)
this.chatbuffer.shift();
var unescaped = sanitize(msg).entityDecode();
this.logger.log("<" + user.name + (meta.addClass ? "." + meta.addclass : "")
+ "> " + unescaped);
}
};
Channel.prototype.sendMessageOld = function(username, msg, msgclass, data) {
// I don't want HTML from strangers // I don't want HTML from strangers
msg = sanitize(msg).escape(); msg = sanitize(msg).escape();
msg = this.filterMessage(msg); msg = this.filterMessage(msg);

View File

@ -12,113 +12,172 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
var Logger = require("./logger.js"); var Logger = require("./logger.js");
var Poll = require("./poll").Poll; var Poll = require("./poll").Poll;
function handle(chan, user, msg, data) { var handlers = {
if(msg.indexOf("/me ") == 0) /* commands that send chat messages */
chan.sendMessage(user.name, msg.substring(4), "action", data); "me": function (chan, user, msg, meta) {
else if(msg.indexOf("/sp ") == 0) meta.addClass = "action";
chan.sendMessage(user.name, msg.substring(4), "spoiler", data); meta.action = true;
else if(msg.indexOf("/say ") == 0) { chan.sendMessage(user, msg, meta);
if(user.rank >= 1.5) { },
chan.sendMessage(user.name, msg.substring(5), "shout", data); "sp": function (chan, user, msg, meta) {
meta.addClass = "spoiler";
chan.sendMessage(user, msg, meta);
},
"say": function (chan, user, msg, meta) {
if (user.rank >= 1.5) {
meta.addClass = "shout";
meta.forceShowName = true;
chan.sendMessage(user, msg, meta);
} }
},
"a": function (chan, user, msg, meta) {
if (user.global_rank < 255) {
return;
} }
else if(msg.indexOf("/afk") == 0) { var superadminflair = {
user.setAFK(!user.meta.afk);
}
else if(msg.indexOf("/m ") == 0) {
if(user.rank >= 2) {
chan.chainMessage(user, msg.substring(3), {modflair: user.rank})
}
}
else if(msg.indexOf("/a ") == 0) {
if(user.rank >= 255) {
var flair = {
superadminflair: {
labelclass: "label-important", labelclass: "label-important",
icon: "icon-globe" icon: "icon-globe"
}
}; };
var args = msg.substring(3).split(" ");
var args = msg.split(" ");
var cargs = []; var cargs = [];
for(var i = 0; i < args.length; i++) { for (var i = 0; i < args.length; i++) {
var a = args[i]; var a = args[i];
if(a.indexOf("!icon-") == 0) if (a.indexOf("!icon-") === 0) {
flair.superadminflair.icon = a.substring(1); superadminflair.icon = a.substring(1);
else if(a.indexOf("!label-") == 0) } else if (a.indexOf("!label-") === 0) {
flair.superadminflair.labelclass = a.substring(1); superadminflair.labelclass = a.substring(1);
else { } else {
cargs.push(a); cargs.push(a);
} }
} }
chan.chainMessage(user, cargs.join(" "), flair);
} meta.superadminflair = superadminflair;
} meta.forceShowName = true;
else if(msg.indexOf("/mute ") == 0) { chan.sendMessage(user, cargs.join(" "), meta);
handleMute(chan, user, msg.substring(6).split(" ")); },
} "poll": function (chan, user, msg, meta) {
else if(msg.indexOf("/smute ") == 0) { handlePoll(chan, user, msg, false);
handleShadowMute(chan, user, msg.substring(7).split(" ")); },
} "hpoll": function (chan, user, msg, meta) {
else if(msg.indexOf("/unmute ") == 0) { handlePoll(chan, user, msg, true);
handleUnmute(chan, user, msg.substring(8).split(" ")); },
}
else if(msg.indexOf("/kick ") == 0) { /* commands that do not send chat messages */
handleKick(chan, user, msg.substring(6).split(" ")); "afk": function (chan, user, msg, meta) {
} user.setAFK(!user.meta.afk);
else if(msg.indexOf("/ban ") == 0) { },
handleBan(chan, user, msg.substring(5).split(" ")); "mute": function (chan, user, msg, meta) {
} handleMute(chan, user, msg.split(" "));
else if(msg.indexOf("/ipban ") == 0) { },
handleIPBan(chan, user, msg.substring(7).split(" ")); "smute": function (chan, user, msg, meta) {
} handleShadowMute(chan, user, msg.split(" "));
else if(msg.indexOf("/unban ") == 0) { },
handleUnban(chan, user, msg.substring(7).split(" ")); "unmute": function (chan, user, msg, meta) {
} handleUnmute(chan, user, msg.split(" "));
else if(msg.indexOf("/poll ") == 0) { },
handlePoll(chan, user, msg.substring(6), false); "kick": function (chan, user, msg, meta) {
} handleKick(chan, user, msg.split(" "));
else if(msg.indexOf("/hpoll ") == 0) { },
handlePoll(chan, user, msg.substring(6), true); "ban": function (chan, user, msg, meta) {
} handleBan(chan, user, msg.split(" "));
else if(msg.indexOf("/d") == 0 && msg.length > 2 && },
msg[2].match(/[-0-9 ]/)) { "ipban": function (chan, user, msg, meta) {
if(msg[2] == "-") { handleIPBan(chan, user, msg.split(" "));
if(msg.length == 3) },
return; "unban": function (chan, user, msg, meta) {
if(!msg[3].match(/[0-9]/)) handleUnban(chan, user, msg.split(" "));
return; },
} "clear": function (chan, user, msg, meta) {
handleDrink(chan, user, msg.substring(2), data);
}
else if(msg.indexOf("/clear") == 0) {
handleClear(chan, user); handleClear(chan, user);
},
"clean": function (chan, user, msg, meta) {
handleClean(chan, user, msg);
},
"cleantitle": function (chan, user, msg, meta) {
handleCleanTitle(chan, user, msg);
} }
else if(msg.indexOf("/clean ") == 0) { };
handleClean(chan, user, msg.substring(7));
var handlerList = [];
for (var key in handlers) {
handlerList.push({
// match /command followed by a space or end of string
re: new RegExp("^\\/" + key + "(?:\\s|$)"),
fn: handlers[key]
});
}
function handle(chan, user, msg, meta) {
// Special case because the drink command can vary
var m = msg.match(/^\/d(-?[0-9]*)(?:\s|$)(.*)/);
if (m) {
handleDrink(chan, user, m[1], m[2], meta);
return;
}
for (var i = 0; i < handlerList.length; i++) {
var h = handlerList[i];
if (msg.match(h.re)) {
var rest;
if (msg.indexOf(" ") >= 0) {
rest = msg.substring(msg.indexOf(" ") + 1);
} else {
rest = "";
}
h.fn(chan, user, rest, meta);
break;
} }
else if(msg.indexOf("/cleantitle ") == 0) {
handleCleanTitle(chan, user, msg.substring(12));
} }
} }
function handleDrink(chan, user, count, msg, meta) {
if (!chan.hasPermission(user, "drink")) {
return;
}
if (count === "") {
count = 1;
}
count = parseInt(count);
if (isNaN(count)) {
return;
}
meta.drink = true;
meta.forceShowName = true;
meta.addClass = "drink";
chan.drinks += count;
chan.broadcastDrinks();
if (count < 0 && msg.trim() === "") {
return;
}
msg = msg + " drink!";
if (count !== 1) {
msg += " (x" + count + ")";
}
chan.sendMessage(user, msg, meta);
}
function handleShadowMute(chan, user, args) { function handleShadowMute(chan, user, args) {
if(chan.hasPermission(user, "mute") && args.length > 0) { if (chan.hasPermission(user, "mute") && args.length > 0) {
args[0] = args[0].toLowerCase(); args[0] = args[0].toLowerCase();
var person = false; var person = false;
for(var i = 0; i < chan.users.length; i++) { for (var i = 0; i < chan.users.length; i++) {
if(chan.users[i].name.toLowerCase() == args[0]) { if (chan.users[i].name.toLowerCase() === args[0]) {
person = chan.users[i]; person = chan.users[i];
break; break;
} }
} }
if(person) { if (person) {
if(person.rank >= user.rank) { if (person.rank >= user.rank) {
user.socket.emit("errorMsg", { user.socket.emit("errorMsg", {
msg: "You don't have permission to mute that person." msg: "You don't have permission to mute that person."
}); });
return; return;
} }
/* Reset a previous regular mute */ /* Reset a previous regular mute */
if (chan.mutedUsers.contains(person.name.toLowerCase())) { if (chan.mutedUsers.contains(person.name.toLowerCase())) {
chan.mutedUsers.remove(person.name.toLowerCase()); chan.mutedUsers.remove(person.name.toLowerCase());
@ -137,7 +196,7 @@ function handleShadowMute(chan, user, args) {
var pkt = { var pkt = {
username: "[server]", username: "[server]",
msg: user.name + " shadow muted " + args[0], msg: user.name + " shadow muted " + args[0],
msgclass: "server-whisper", meta: { addClass: "server-whisper" },
time: Date.now() time: Date.now()
}; };
chan.users.forEach(function (u) { chan.users.forEach(function (u) {
@ -150,18 +209,18 @@ function handleShadowMute(chan, user, args) {
} }
function handleMute(chan, user, args) { function handleMute(chan, user, args) {
if(chan.hasPermission(user, "mute") && args.length > 0) { if (chan.hasPermission(user, "mute") && args.length > 0) {
args[0] = args[0].toLowerCase(); args[0] = args[0].toLowerCase();
var person = false; var person = false;
for(var i = 0; i < chan.users.length; i++) { for (var i = 0; i < chan.users.length; i++) {
if(chan.users[i].name.toLowerCase() == args[0]) { if (chan.users[i].name.toLowerCase() == args[0]) {
person = chan.users[i]; person = chan.users[i];
break; break;
} }
} }
if(person) { if (person) {
if(person.rank >= user.rank) { if (person.rank >= user.rank) {
user.socket.emit("errorMsg", { user.socket.emit("errorMsg", {
msg: "You don't have permission to mute that person." msg: "You don't have permission to mute that person."
}); });
@ -179,18 +238,18 @@ function handleMute(chan, user, args) {
} }
function handleUnmute(chan, user, args) { function handleUnmute(chan, user, args) {
if(chan.hasPermission(user, "mute") && args.length > 0) { if (chan.hasPermission(user, "mute") && args.length > 0) {
args[0] = args[0].toLowerCase(); args[0] = args[0].toLowerCase();
var person = false; var person = false;
for(var i = 0; i < chan.users.length; i++) { for (var i = 0; i < chan.users.length; i++) {
if(chan.users[i].name.toLowerCase() == args[0]) { if (chan.users[i].name.toLowerCase() == args[0]) {
person = chan.users[i]; person = chan.users[i];
break; break;
} }
} }
if(person) { if (person) {
if(person.rank >= user.rank) { if (person.rank >= user.rank) {
user.socket.emit("errorMsg", { user.socket.emit("errorMsg", {
msg: "You don't have permission to unmute that person." msg: "You don't have permission to unmute that person."
}); });
@ -209,18 +268,18 @@ function handleUnmute(chan, user, args) {
} }
function handleKick(chan, user, args) { function handleKick(chan, user, args) {
if(chan.hasPermission(user, "kick") && args.length > 0) { if (chan.hasPermission(user, "kick") && args.length > 0) {
args[0] = args[0].toLowerCase(); args[0] = args[0].toLowerCase();
if(args[0] == user.name.toLowerCase()) { if (args[0] == user.name.toLowerCase()) {
user.socket.emit("costanza", { user.socket.emit("costanza", {
msg: "Kicking yourself?" msg: "Kicking yourself?"
}); });
return; return;
} }
var kickee; var kickee;
for(var i = 0; i < chan.users.length; i++) { for (var i = 0; i < chan.users.length; i++) {
if(chan.users[i].name.toLowerCase() == args[0]) { if (chan.users[i].name.toLowerCase() == args[0]) {
if(chan.users[i].rank >= user.rank) { if (chan.users[i].rank >= user.rank) {
user.socket.emit("errorMsg", { user.socket.emit("errorMsg", {
msg: "You don't have permission to kick " + args[0] msg: "You don't have permission to kick " + args[0]
}); });
@ -230,7 +289,7 @@ function handleKick(chan, user, args) {
break; break;
} }
} }
if(kickee) { if (kickee) {
chan.logger.log("*** " + user.name + " kicked " + args[0]); chan.logger.log("*** " + user.name + " kicked " + args[0]);
args[0] = ""; args[0] = "";
var reason = args.join(" "); var reason = args.join(" ");
@ -250,9 +309,9 @@ function handleBan(chan, user, args) {
} }
function handleUnban(chan, user, args) { function handleUnban(chan, user, args) {
if(chan.hasPermission(user, "ban") && args.length > 0) { if (chan.hasPermission(user, "ban") && args.length > 0) {
chan.logger.log("*** " + user.name + " unbanned " + args[0]); chan.logger.log("*** " + user.name + " unbanned " + args[0]);
if(args[0].match(/(\d+)\.(\d+)\.(\d+)\.(\d+)/)) { if (args[0].match(/(\d+)\.(\d+)\.(\d+)\.(\d+)/)) {
chan.unbanIP(user, args[0]); chan.unbanIP(user, args[0]);
} }
else { else {
@ -262,7 +321,7 @@ function handleUnban(chan, user, args) {
} }
function handlePoll(chan, user, msg, hidden) { function handlePoll(chan, user, msg, hidden) {
if(chan.hasPermission(user, "pollctl")) { if (chan.hasPermission(user, "pollctl")) {
var args = msg.split(","); var args = msg.split(",");
var title = args[0]; var title = args[0];
args.splice(0, 1); args.splice(0, 1);
@ -273,32 +332,8 @@ function handlePoll(chan, user, msg, hidden) {
} }
} }
function handleDrink(chan, user, msg, data) {
if(!chan.hasPermission(user, "drink")) {
return;
}
var count = msg.split(" ")[0];
msg = msg.substring(count.length + 1);
if(count == "")
count = 1;
else
count = parseInt(count);
chan.drinks += count;
chan.broadcastDrinks();
if(count < 0 && msg.trim() == "") {
return;
}
msg = msg + " drink!";
if(count != 1)
msg += " (x" + count + ")";
chan.sendMessage(user.name, msg, "drink", data);
}
function handleClear(chan, user) { function handleClear(chan, user) {
if(user.rank < 2) { if (user.rank < 2) {
return; return;
} }

View File

@ -150,13 +150,20 @@ $("#chatline").keydown(function(ev) {
if(ev.keyCode == 13) { if(ev.keyCode == 13) {
var msg = $("#chatline").val(); var msg = $("#chatline").val();
if(msg.trim()) { if(msg.trim()) {
var meta = {};
if (USEROPTS.adminhat && CLIENT.rank >= 255) { if (USEROPTS.adminhat && CLIENT.rank >= 255) {
msg = "/a " + msg; msg = "/a " + msg;
} else if(USEROPTS.modhat && CLIENT.rank >= Rank.Moderator) { } else if (USEROPTS.modhat && CLIENT.rank >= Rank.Moderator) {
msg = "/m " + msg; meta.modflair = CLIENT.rank;
} }
if (CLIENT.rank >= 2 && msg.indexOf("/m ") === 0) {
meta.modflair = CLIENT.rank;
msg = msg.substring(4);
}
socket.emit("chatMsg", { socket.emit("chatMsg", {
msg: msg msg: msg,
meta: meta
}); });
CHATHIST.push($("#chatline").val()); CHATHIST.push($("#chatline").val());
CHATHISTIDX = CHATHIST.length; CHATHISTIDX = CHATHIST.length;

View File

@ -1442,67 +1442,79 @@ function sendVideoUpdate() {
/* chat */ /* chat */
function formatChatMessage(data) { function formatChatMessage(data) {
var skip = data.username == LASTCHATNAME; // Phase 1: Determine whether to show the username or not
if(data.msgclass == "drink" || data.msgclass == "shout") { var skip = data.username === LASTCHATNAME;
skip = false; if(data.meta.addClass === "server-whisper")
}
if(data.superadminflair)
skip = false;
if(data.msgclass == "server-whisper")
skip = true; skip = true;
// Prevent impersonation by abuse of the bold filter // Prevent impersonation by abuse of the bold filter
if(data.msg.match(/^\s*<strong>\w+\s*:\s*<\/strong>\s*/)) if(data.msg.match(/^\s*<strong>\w+\s*:\s*<\/strong>\s*/))
skip = false; skip = false;
if (data.meta.forceShowName)
skip = false;
LASTCHATNAME = data.username; LASTCHATNAME = data.username;
LASTCHATTIME = data.time; LASTCHATTIME = data.time;
var div = $("<div/>"); var div = $("<div/>");
if(USEROPTS.show_timestamps) { /* drink is a special case because the entire container gets the class, not
just the message */
if (data.meta.addClass === "drink") {
div.addClass("drink");
data.meta.addClass = "";
}
// Add timestamps (unless disabled)
if (USEROPTS.show_timestamps) {
var time = $("<span/>").addClass("timestamp").appendTo(div); var time = $("<span/>").addClass("timestamp").appendTo(div);
var timestamp = new Date(data.time).toTimeString().split(" ")[0]; var timestamp = new Date(data.time).toTimeString().split(" ")[0];
time.text("["+timestamp+"] "); time.text("["+timestamp+"] ");
if(data.msgclass == "shout" || data.msgclass == "server-whisper") if (data.meta.addClass &&
time.addClass(data.msgclass); data.meta.addClass.match(/shout|server-whisper/)) {
time.addClass(data.meta.addClass);
} }
}
// Add username
var name = $("<span/>"); var name = $("<span/>");
if(!skip) { if (!skip) {
name.appendTo(div); name.appendTo(div);
} }
$("<strong/>").addClass("username").text(data.username + ": ").appendTo(name); $("<strong/>").addClass("username").text(data.username + ": ").appendTo(name);
var message = $("<span/>").appendTo(div); if (data.meta.modflair) {
message[0].innerHTML = data.msg; name.addClass(getNameColor(data.meta.modflair));
if(data.modflair) {
name.addClass(getNameColor(data.modflair));
} }
if(data.superadminflair) { if (data.meta.addClass) {
name.addClass(data.meta.addClass);
}
if (data.meta.superadminflair) {
name.addClass("label") name.addClass("label")
.addClass(data.superadminflair.labelclass); .addClass(data.meta.superadminflair.labelclass);
$("<i/>").addClass(data.superadminflair.icon) $("<i/>").addClass(data.meta.superadminflair.icon)
.addClass("icon-white") .addClass("icon-white")
.prependTo(name); .prependTo(name);
} }
if(data.msgclass == "action") {
// Add the message itself
var message = $("<span/>").appendTo(div);
message[0].innerHTML = data.msg;
// For /me the username is part of the message
if (data.meta.action) {
name.remove(); name.remove();
message.addClass("action");
message[0].innerHTML = data.username + " " + data.msg; message[0].innerHTML = data.username + " " + data.msg;
} }
else if(data.msgclass == "drink") { if (data.meta.addClass) {
div.addClass("drink"); message.addClass(data.meta.addClass);
}
else if(data.msgclass == "shout") {
message.addClass("shout");
name.addClass("shout");
}
else {
message.addClass(data.msgclass);
} }
return div; return div;
} }
function addChatMessage(data) { function addChatMessage(data) {
if(IGNORED.indexOf(data.username) != -1) { if(IGNORED.indexOf(data.username) !== -1) {
return; return;
} }
var div = formatChatMessage(data); var div = formatChatMessage(data);
// Incoming: a bunch of crap for the feature where if you hover over
// a message, it highlights messages from that user
div.data("sender", data.username); div.data("sender", data.username);
div.appendTo($("#messagebuffer")); div.appendTo($("#messagebuffer"));
div.mouseover(function() { div.mouseover(function() {