Shuo/lib/server.js

560 lines
10 KiB
JavaScript
Raw Normal View History

2014-03-04 16:31:52 +00:00
var connect = require("connect");
2014-03-09 21:22:37 +00:00
var io = require("socket.io");
2014-03-06 15:11:25 +00:00
2014-03-13 12:44:54 +00:00
// Local libraries
var config = require("./../config.js");
2014-03-09 21:22:37 +00:00
var models = require("./models.js");
2014-03-06 15:11:25 +00:00
2014-03-07 21:24:02 +00:00
module.exports = Server;
2014-03-06 15:11:25 +00:00
2014-03-07 21:24:02 +00:00
function Server() {
2014-03-14 02:00:01 +00:00
this.sockets = false;
2014-03-07 21:24:02 +00:00
this.networks = new models.NetworkCollection;
}
2014-03-06 15:11:25 +00:00
2014-03-07 21:24:02 +00:00
Server.prototype.listen = function(port) {
2014-03-13 17:50:02 +00:00
var self = this;
2014-03-06 15:11:25 +00:00
var http = connect()
.use(connect.static("client"))
.listen(port);
2014-03-11 22:57:29 +00:00
2014-03-17 16:24:32 +00:00
this.networks.on("all", function(action, data) {
this.sockets.emit(action, data);
2014-03-13 15:25:01 +00:00
}, this);
2014-03-11 22:57:29 +00:00
2014-03-13 17:50:02 +00:00
this.sockets = io.listen(http, {log: false}).sockets;
2014-03-07 21:24:02 +00:00
this.sockets.on("connection", function(socket) {
2014-03-17 16:24:32 +00:00
socket.emit("NETWORKS", self.networks);
socket.on("input", function(input) { handleInput.call(self, input); });
2014-03-07 21:24:02 +00:00
});
2014-03-06 18:02:43 +00:00
2014-03-13 17:50:02 +00:00
if (config.autoConnect) {
this.connect(config.host, config.channels);
}
2014-03-07 21:24:02 +00:00
return this;
};
2014-03-06 18:02:43 +00:00
2014-03-13 17:50:02 +00:00
Server.prototype.connect = function(host, channels) {
var network = new models.Network({
host: host
});
2014-03-17 16:24:32 +00:00
this.networks.add(network, {silent: true});
this.networks.trigger(
"NETWORKS",
this.networks
);
2014-03-13 17:50:02 +00:00
network.connect(channels).addListener("raw", function() {
handleEvent.apply(network, arguments);
});
};
2014-03-09 23:14:22 +00:00
function handleInput(input) {
2014-03-09 21:22:37 +00:00
var target = this.networks.find(input.id);
if (!target) {
return;
}
2014-03-13 15:25:01 +00:00
var network = target.network;
var channel = target.channel;
2014-03-09 21:22:37 +00:00
var argv = input.text.substr(1).split(" ");
var cmd = input.text.charAt(0) == "/" ? argv[0].toUpperCase()
2014-03-13 15:25:01 +00:00
: "MESSAGE";
2014-03-09 21:22:37 +00:00
switch (cmd) {
2014-03-13 12:44:54 +00:00
2014-03-13 15:25:01 +00:00
case "MESSAGE":
var irc = network.irc;
if (typeof irc !== "undefined") {
irc.say(target.channel.get("name"), input.text);
}
channel.get("messages").add(
new models.Message({
user: network.get("nick"),
text: input.text
2014-03-13 12:44:54 +00:00
})
);
2014-03-13 15:25:01 +00:00
break;
case "SERVER":
case "CONNECT":
2014-03-13 17:50:02 +00:00
this.connect(argv[1]);
2014-03-13 12:44:54 +00:00
break;
case "QUIT":
case "DISCONNECT":
2014-03-13 15:25:01 +00:00
this.networks.remove(network);
2014-03-13 12:44:54 +00:00
break;
2014-03-13 15:25:01 +00:00
case "JOIN":
case "PART":
var irc = network.irc;
if (typeof irc !== "undefined") {
2014-03-13 15:25:01 +00:00
irc.send(cmd, argv[1] || target.channel.get("name"));
}
2014-03-09 21:22:37 +00:00
break;
2014-03-14 21:57:54 +00:00
case "UNQUERY":
case "LEAVE":
var channel = target.channel;
if (channel.get("name").charAt(0) == "#") {
handleInput.call(this, {
id: input.id,
text: "/part"
});
} else if (channel.get("type") != "network") {
network.get("channels").remove(
channel
);
}
break;
2014-03-13 00:00:59 +00:00
case "NOTICE":
2014-03-13 15:25:01 +00:00
var irc = network.irc;
if (!argv[2] || typeof irc === "undefined") {
break;
2014-03-13 00:00:59 +00:00
}
2014-03-13 15:25:01 +00:00
var user = argv[1];
var text = argv.slice(2).join(" ");
irc.notice(user, text);
channel.get("messages").add(
new models.Message({
2014-03-13 15:50:33 +00:00
text: "Notice to " + user + ": " + text,
type: "notice"
2014-03-13 15:25:01 +00:00
})
);
2014-03-13 00:00:59 +00:00
break;
2014-03-13 15:25:01 +00:00
case "TOPIC":
var irc = network.irc;
if (typeof irc === "undefined") {
break;
2014-03-12 13:10:53 +00:00
}
2014-03-13 15:25:01 +00:00
var params = [
"topic",
channel.get("name")
];
if (argv[1]) {
var text = argv.slice(1).join(" ");
params.push(text);
2014-03-12 21:58:24 +00:00
}
2014-03-13 15:25:01 +00:00
irc.send.apply(
irc,
params
);
2014-03-12 21:58:24 +00:00
break;
2014-03-13 00:38:20 +00:00
case "NICK":
2014-03-13 15:25:01 +00:00
var irc = network.irc;
2014-03-12 21:58:24 +00:00
if (typeof irc !== "undefined") {
2014-03-14 14:26:00 +00:00
irc.send("NICK", argv[1] || config.nick);
}
break;
case "KICK":
var irc = network.irc;
if (argv[1] && typeof irc !== "undefined") {
irc.send(
"KICK",
target.channel.get("name"),
argv[1]
);
2014-03-12 18:06:08 +00:00
}
break;
2014-03-15 15:51:21 +00:00
case "QUERY":
2014-03-14 13:24:47 +00:00
case "WHOIS":
var irc = network.irc;
if (typeof irc !== "undefined") {
2014-03-14 14:26:00 +00:00
irc.send("WHOIS", argv[1] || target.channel.get("name"));
}
break;
2014-03-14 16:52:24 +00:00
case "OP":
case "DEOP":
case "VOICE":
case "DEVOICE":
case "MODE":
var irc = network.irc;
if (!argv[1] && typeof irc === "undefined") {
break;
}
var mode;
var user;
if (cmd != "MODE") {
user = argv[1];
mode = {
"OP": "+o",
"DEOP": "-o",
"VOICE": "+v",
"DEVOICE": "-v"
}[cmd];
} else if (!argv[2]) {
break;
} else {
mode = argv[1];
user = argv[2];
}
irc.send(
"MODE",
target.channel.get("name"),
mode,
user
);
break;
2014-03-14 14:26:00 +00:00
// This command is used for debugging purposes.
// Send raw commands.
case "SEND":
var irc = network.irc;
if (typeof irc !== "undefined") {
irc.send.apply(irc, argv.splice(1));
2014-03-14 13:24:47 +00:00
}
break;
2014-03-09 21:22:37 +00:00
default:
2014-03-13 15:25:01 +00:00
channel.get("messages").add(
new models.Message({
2014-03-15 16:14:05 +00:00
text: cmd + " Unknown command",
2014-03-13 15:50:33 +00:00
type: "error"
2014-03-13 15:25:01 +00:00
})
2014-03-09 19:27:44 +00:00
);
2014-03-15 16:14:05 +00:00
break;
2014-03-13 15:25:01 +00:00
2014-03-09 19:27:44 +00:00
}
2014-03-09 23:14:22 +00:00
}
2014-03-09 21:22:37 +00:00
2014-03-09 23:14:22 +00:00
function handleEvent(argv) {
2014-03-14 02:00:01 +00:00
var network = this;
2014-03-12 15:09:37 +00:00
var channels = network.get("channels");
2014-03-13 12:44:54 +00:00
var event = argv.commandType != "error" ? argv.command
: "ERROR";
2014-03-12 15:09:37 +00:00
switch (event) {
case "PRIVMSG":
var target = argv.args[0];
if (target.charAt(0) != "#") {
target = argv.nick;
}
var channel = channels.findWhere({name: target});
var message = argv.args[1];
if (typeof channel == "undefined") {
channel = channels.add(
new models.Channel({
2014-03-15 15:51:21 +00:00
type: "query",
name: target
})
);
}
2014-03-14 21:57:54 +00:00
var mode;
var user = channel.get("users").findWhere({name: argv.nick});
if (typeof user !== "undefined") {
mode = user.get("mode");
}
channel.get("messages").add(
new models.Message({
2014-03-14 21:57:54 +00:00
mode: mode,
user: argv.nick,
text: message
})
);
break;
2014-03-13 00:00:59 +00:00
case "NOTICE":
2014-03-13 17:50:02 +00:00
var from = argv.nick ? argv.nick : "-!-";
2014-03-16 16:19:53 +00:00
channels.first().get("messages").add(new models.Message({
2014-03-13 00:00:59 +00:00
user: from,
2014-03-13 15:50:33 +00:00
text: "notice: " + argv.args[1],
type: "notice"
2014-03-16 16:19:53 +00:00
}));
2014-03-13 00:00:59 +00:00
break;
2014-03-12 15:09:37 +00:00
case "JOIN":
2014-03-14 02:00:01 +00:00
var channel = channels.findWhere({name: argv.args[0]});
if (typeof channel === "undefined") {
channel = channels.add(
2014-03-12 18:06:08 +00:00
new models.Channel({
name: argv.args[0]
})
2014-03-12 15:09:37 +00:00
);
2014-03-14 02:00:01 +00:00
}
2014-03-14 13:24:47 +00:00
2014-03-14 02:00:01 +00:00
var users = channel.get("users");
var messages = channel.get("messages");
2014-03-14 13:24:47 +00:00
2014-03-14 02:00:01 +00:00
if (argv.nick != network.get("nick")) {
2014-03-12 15:09:37 +00:00
users.add(
new models.User({
name: argv.nick
})
);
2014-03-16 16:19:53 +00:00
users.sort();
2014-03-12 15:09:37 +00:00
}
2014-03-14 13:24:47 +00:00
2014-03-14 02:00:01 +00:00
messages.add(
new models.Message({
user: argv.nick,
2014-03-14 15:12:01 +00:00
text: "join",
2014-03-14 02:00:01 +00:00
type: "join"
})
);
2014-03-12 15:09:37 +00:00
break;
case "PART":
var channel = channels.findWhere({name: argv.args[0]});
if (argv.nick == network.get("nick")) {
channels.remove(channel);
} else {
var users = channel.get("users");
users.remove(
users.findWhere({
name: argv.nick
})
);
2014-03-14 14:26:00 +00:00
2014-03-12 15:09:37 +00:00
var messages = channel.get("messages");
messages.add(
new models.Message({
user: argv.nick,
2014-03-14 15:12:01 +00:00
text: "part",
2014-03-13 15:50:33 +00:00
type: "part"
2014-03-12 15:09:37 +00:00
})
);
}
break;
2014-03-12 18:06:08 +00:00
2014-03-13 00:38:20 +00:00
case "NICK":
channels.each(function(channel) {
2014-03-15 01:19:50 +00:00
var users = channel.get("users");
var messages = channel.get("messages");
var user = users.findWhere({name: argv.nick});
2014-03-15 16:14:05 +00:00
if (typeof user === "undefined") {
return;
}
2014-03-15 01:19:50 +00:00
2014-03-15 16:14:05 +00:00
user.set("name", argv.args[0]);
2014-03-15 01:19:50 +00:00
2014-03-15 16:14:05 +00:00
users.sort();
users.trigger(
"change", {}, users
);
messages.add(new models.Message({
user: argv.nick,
text: "changed name to " + argv.args[0],
type: "nick"
}));
2014-03-13 00:38:20 +00:00
});
2014-03-14 13:24:47 +00:00
2014-03-14 02:00:01 +00:00
if (argv.nick == network.get("nick")) {
2014-03-15 01:19:50 +00:00
network.set({nick: argv.args[0]}, {silent: true});
2014-03-14 02:00:01 +00:00
}
2014-03-13 00:38:20 +00:00
break;
2014-03-14 14:26:00 +00:00
case "KICK":
var channel = channels.findWhere({
name: argv.args[0]
});
var users = channel.get("users");
2014-03-14 15:12:01 +00:00
var messages = channel.get("messages");
2014-03-14 14:26:00 +00:00
if (argv.args[1] == network.get("nick")) {
users.reset();
} else {
users.remove(
users.findWhere({
name: argv.args[1]
})
);
}
messages.add(
new models.Message({
user: argv.args[1],
2014-03-14 15:12:01 +00:00
text: "was kicked by " + argv.nick,
2014-03-14 14:26:00 +00:00
type: "kick"
})
);
break;
2014-03-14 15:12:01 +00:00
case "QUIT":
var message = new models.Message({
user: argv.nick,
text: "quit",
type: "quit"
});
channels.each(function(channel) {
var user = channel.get("users").findWhere({name: argv.nick});
if (typeof user !== "undefined") {
channel.get("users").remove(user);
channel.get("messages").add(message);
}
});
break;
case "MODE":
var channel = channels.findWhere({name: argv.args[0]});
if (typeof channel === "undefined") {
break;
}
2014-03-14 21:57:54 +00:00
var target = argv.args[2] || argv.args[0];
2014-03-14 15:12:01 +00:00
var messages = channel.get("messages");
messages.add(
new models.Message({
user: argv.nick,
2014-03-14 21:57:54 +00:00
text: "sets mode: " + argv.args[1] + " " + target,
2014-03-14 15:12:01 +00:00
type: "mode"
})
);
var irc = network.irc;
2014-03-14 21:57:54 +00:00
if (argv.args[2] && typeof irc !== "undefined") {
irc.send(
"NAMES",
channel.get("name")
);
2014-03-14 15:12:01 +00:00
}
break;
2014-03-12 21:58:24 +00:00
case "TOPIC":
2014-03-14 02:00:01 +00:00
var channel = channels.findWhere({name: argv.args[0]});
2014-03-12 21:58:24 +00:00
var messages = channel.get("messages");
2014-03-14 13:24:47 +00:00
2014-03-12 21:58:24 +00:00
messages.add(
new models.Message({
user: argv.nick,
2014-03-13 15:50:33 +00:00
text: "changed topic to: " + argv.args[1],
type: "topic"
2014-03-12 21:58:24 +00:00
})
);
break;
case "rpl_notopic":
case "rpl_topic":
var channel = channels.findWhere({name: argv.args[1]});
if (typeof channel !== "undefined") {
var messages = channel.get("messages");
messages.add(
new models.Message({
2014-03-13 15:50:33 +00:00
text: "Topic for " + argv.args[1] + ": " + argv.args[2],
type: "topic"
2014-03-12 21:58:24 +00:00
})
);
}
break;
2014-03-12 18:06:08 +00:00
case "rpl_namreply":
var channel = network.get("channels").findWhere({name: argv.args[2]});
2014-03-14 15:12:01 +00:00
var users = channel.get("users");
2014-03-14 13:24:47 +00:00
2014-03-14 02:00:01 +00:00
if (typeof channel === "undefined") {
channel = channels.add(
new models.Channel({
name: argv.args[2]
})
);
}
2014-03-14 13:24:47 +00:00
2014-03-14 21:57:54 +00:00
if (typeof rpl_namreply === "undefined") {
2014-03-17 16:24:32 +00:00
channel.get("users").reset(undefined, {silent: true});
2014-03-12 18:06:08 +00:00
}
2014-03-15 01:19:50 +00:00
// This variable is global but will be deleted when
// rpl_endofnames is triggered..
2014-03-14 21:57:54 +00:00
rpl_namreply = true;
2014-03-14 15:12:01 +00:00
2014-03-14 21:57:54 +00:00
var names = argv.args[3].split(' ');
2014-03-12 18:06:08 +00:00
for (var i in names) {
2014-03-15 01:19:50 +00:00
var mode = (names[i].match(/^\W/) || "").toString();
var user = new models.User({
mode: mode,
name: names[i].replace(mode, '')
});
2014-03-12 18:06:08 +00:00
users.add(
2014-03-15 01:19:50 +00:00
user,
{silent: true}
2014-03-12 18:06:08 +00:00
);
}
break;
case "rpl_endofnames":
2014-03-14 15:12:01 +00:00
var channel = channels.findWhere({name: argv.args[1]});
2014-03-12 18:06:08 +00:00
var users = channel.get("users");
2014-03-14 21:57:54 +00:00
2014-03-15 01:19:50 +00:00
// .. here!
2014-03-14 21:57:54 +00:00
delete rpl_namreply;
2014-03-16 16:19:53 +00:00
users.sort();
2014-03-12 18:06:08 +00:00
users.trigger(
"add", {}, users
);
break;
2014-03-14 02:00:01 +00:00
case "001": // `registered`
network.set("nick", argv.args[0]);
2014-03-13 17:50:02 +00:00
case "rpl_motdstart":
case "rpl_endofmotd":
case "rpl_motd":
2014-03-13 00:00:59 +00:00
channels.first().get("messages").add(
new models.Message({
2014-03-13 17:50:02 +00:00
user: "-!-",
text: argv.args[1]
})
);
break;
2014-03-13 00:00:59 +00:00
2014-03-14 13:24:47 +00:00
case "rpl_whoisuser":
case "rpl_whoischannels":
case "rpl_whoisserver":
case "rpl_endofwhois":
var channel = channels.findWhere({name: argv.args[1]});
var message = argv.args.slice(2).join(" ");
if (typeof channel == "undefined") {
channel = channels.add(
new models.Channel({
2014-03-15 15:51:21 +00:00
type: "query",
2014-03-14 13:24:47 +00:00
name: argv.args[1]
})
);
}
channel.get("messages").add(
new models.Message({
user: argv.args[1],
text: message
})
);
break;
case "ERROR":
var args = argv.args;
channels.first().get("messages").add(
new models.Message({
2014-03-15 16:14:05 +00:00
text: args[args.length - 2].toUpperCase() + " " + args[args.length - 1],
2014-03-14 13:24:47 +00:00
type: "error"
})
);
break;
2014-03-12 15:09:37 +00:00
}
2014-03-09 19:27:44 +00:00
}