thelounge/lib/server.js

418 lines
7.4 KiB
JavaScript
Raw Normal View History

2014-04-24 22:34:40 +02:00
var _ = require("lodash");
var config = require("../config") || {};
var fs = require("fs");
var http = require("connect");
var io = require("socket.io");
var irc = require("slate-irc");
var net = require("net");
var tls = require("tls");
2014-03-06 16:11:25 +01:00
2014-06-23 19:28:36 +02:00
var Client = require("./models/client");
var Msg = require("./models/msg");
var Network = require("./models/network");
var sockets = null;
2014-06-23 19:28:36 +02:00
var clients = [];
2014-03-06 16:11:25 +01:00
2014-06-19 17:28:53 +02:00
var plugins = [
2014-06-13 15:57:11 +02:00
"errors",
2014-03-24 16:47:29 +01:00
"join",
"kick",
2014-04-08 00:03:21 +02:00
"mode",
2014-04-03 22:55:51 +02:00
"motd",
2014-03-30 05:12:29 +02:00
"message",
2014-03-24 16:47:29 +01:00
"names",
"nick",
"notice",
"part",
"quit",
"topic",
"welcome",
2014-04-06 00:01:19 +02:00
"whois",
2014-03-24 16:47:29 +01:00
];
2014-06-19 17:28:53 +02:00
module.exports = function listen() {
2014-04-26 19:44:16 +02:00
var port = config.port || 9000;
2014-03-24 16:47:29 +01:00
var app = http()
2014-04-24 22:34:40 +02:00
.use(index)
2014-03-24 16:47:29 +01:00
.use(http.static("client"))
2014-04-26 19:44:16 +02:00
.listen(port);
2014-03-24 16:47:29 +01:00
2014-06-23 19:28:36 +02:00
sockets = io.listen(app, {log: 0});
2014-03-24 14:44:41 +01:00
2014-06-23 19:28:36 +02:00
var users = config.users;
for (var user in users) {
var client = new Client({
name: user,
config: users[user],
sockets: sockets
});
clients.push(client);
users[user].networks.forEach(function(network) {
connect(client, network);
});
2014-06-15 21:18:45 +02:00
}
2014-06-23 19:28:36 +02:00
sockets.on("connection", function(socket) {
if (clients.length == 1 && !clients[0].config.password) {
init.call(socket, clients[0]);
} else {
init.call(socket);
}
});
2014-06-15 19:26:05 +02:00
}
2014-04-24 22:34:40 +02:00
function index(req, res, next) {
2014-04-25 01:57:51 +02:00
if (req.url != "/") return next();
2014-06-19 17:28:53 +02:00
return fs.readFile("client/index.html", function(err, file) {
2014-04-25 01:57:51 +02:00
var data = _.merge(
2014-04-24 22:34:40 +02:00
require("../package.json"),
2014-06-14 22:28:17 +02:00
config
2014-04-24 22:34:40 +02:00
);
2014-04-25 01:57:51 +02:00
res.end(_.template(
file,
data
));
});
2014-04-24 22:34:40 +02:00
}
2014-06-23 19:28:36 +02:00
function init(client) {
var socket = this;
if (!client) {
socket.on("auth", auth);
socket.emit("auth");
} else {
socket.on("input", function(data) { input(client, data); });
socket.on("fetch", function(data) { fetch(client, socket, data); });
socket.join(client.name);
socket.emit("networks", {
networks: client.networks
});
}
}
function auth(data) {
var user = config.users[data.user];
if (user && data.password == user.password) {
var socket = this;
clients.forEach(function(c) {
if (c.name == data.user) init.call(socket, c);
});
}
}
function connect(client, params) {
2014-04-06 00:01:19 +02:00
var host = params.host;
2014-04-25 01:57:51 +02:00
var port = params.port || 6667;
var options = {
2014-03-24 16:47:29 +01:00
host: host,
2014-06-23 19:28:36 +02:00
port: port
};
2014-03-24 16:47:29 +01:00
2014-06-23 19:28:36 +02:00
var stream = params.tls ? tls.connect(options) : net.connect(options);
2014-03-24 16:47:29 +01:00
stream.on("error", function(e) {
console.log(e);
});
2014-06-23 19:28:36 +02:00
var slate = irc(stream);
slate.nick(client.config.nick);
slate.user(client.config.nick, client.config.realname);
var network = new Network({
2014-03-30 00:59:28 +01:00
client: client,
2014-06-23 19:28:36 +02:00
host: host,
slate: slate,
});
2014-03-24 16:47:29 +01:00
2014-06-23 19:28:36 +02:00
client.networks.push(network);
client.emit("networks", {
networks: client.networks
});
2014-06-13 16:45:32 +02:00
2014-06-19 17:28:53 +02:00
plugins.forEach(function(plugin) {
2014-06-23 19:28:36 +02:00
require("./plugins/" + plugin).apply(client, [slate, network]);
2014-06-19 01:26:28 +02:00
});
2014-06-23 19:28:36 +02:00
slate.on("welcome", function() {
((params.onConnect || {}).join || []).forEach(function(chan) {
slate.join.apply(
slate,
chan.split(" ")
2014-06-13 16:45:32 +02:00
);
2014-04-06 00:01:19 +02:00
});
2014-06-17 22:30:17 +02:00
});
2014-06-15 21:18:45 +02:00
}
2014-06-23 19:28:36 +02:00
function input(client, data) {
var target = find(client.networks, data.id);
2014-03-09 22:22:37 +01:00
if (!target) {
return;
}
2014-03-24 14:44:41 +01:00
var network = target.network;
var chan = target.chan;
2014-03-30 05:12:29 +02:00
2014-06-23 19:28:36 +02:00
var slate = network.slate;
var id = data.id;
var text = data.text;
2014-05-14 00:47:35 +02:00
if (!text) {
return;
}
2014-03-24 14:44:41 +01:00
var args = text.replace(/^\//, '').split(" ");
var cmd = text.charAt(0) == "/" ? args[0].toLowerCase() : "";
2014-03-24 14:44:41 +01:00
2014-03-09 22:22:37 +01:00
switch (cmd) {
2014-05-15 23:56:23 +02:00
case "say":
// Remove '/say' and treat this command as a message.
args.shift();
2014-03-24 14:44:41 +01:00
case "":
args.unshift(
"msg",
chan.name
2014-03-13 16:25:01 +01:00
);
2014-03-29 16:36:12 +01:00
case "msg":
2014-03-30 05:12:29 +02:00
var user;
2014-05-03 21:22:14 +02:00
var text = args.slice(2).join(" ");
2014-06-23 19:28:36 +02:00
if (slate) {
user = slate.me;
slate.send(args[1], text);
}
2014-05-04 02:33:05 +02:00
var chan = _.findWhere(network.channels, {name: args[1]});
if (typeof chan !== "undefined") {
var msg = new Msg({
from: user,
text: text,
});
2014-06-15 17:01:38 +02:00
chan.addMsg(msg)
2014-06-23 19:28:36 +02:00
client.emit("msg", {
2014-05-04 02:33:05 +02:00
id: chan.id,
msg: msg,
});
}
2014-03-24 14:44:41 +01:00
break;
2014-05-03 19:21:11 +02:00
case "notice":
2014-06-23 19:28:36 +02:00
if (slate && args[2]) {
slate.notice(args[1], args.slice(2).join(" "));
2014-05-03 19:21:11 +02:00
}
break;
2014-05-28 16:12:16 +02:00
case "slap":
var slap = "slaps " + args[1] + " around a bit with a large trout";
2014-05-03 21:22:14 +02:00
case "me":
if (!args[1]) {
break;
}
var user;
2014-05-28 16:12:16 +02:00
var text = slap || args.slice(1).join(" ");
2014-06-23 19:28:36 +02:00
if (slate) {
user = slate.me;
slate.action(chan.name, text);
2014-05-03 21:22:14 +02:00
}
var msg = new Msg({
type: "action",
from: user,
text: text,
});
2014-06-15 17:01:38 +02:00
chan.addMsg(msg)
2014-06-23 19:28:36 +02:00
client.emit("msg", {
2014-05-03 21:22:14 +02:00
id: chan.id,
msg: msg,
});
break;
2014-05-18 18:18:19 +02:00
case "ame":
var type = "action";
case "amsg":
2014-06-23 19:28:36 +02:00
var user = slate.me;
2014-05-18 18:18:19 +02:00
var text = args.slice(1).join(" ");
var channels = [];
network.channels.forEach(function(chan) {
if (chan.type == "channel") {
channels.push(chan.name);
var msg = new Msg({
2014-05-25 22:46:54 +02:00
type: type || "normal",
2014-05-18 18:18:19 +02:00
from: user,
text: text,
});
2014-06-15 17:01:38 +02:00
chan.addMsg(msg)
2014-06-23 19:28:36 +02:00
client.emit("msg", {
2014-05-18 18:18:19 +02:00
id: chan.id,
msg: msg,
});
}
});
client[type || "send"](
channels,
text
);
break;
2014-03-24 14:44:41 +01:00
case "server":
case "connect":
2014-03-24 16:47:29 +01:00
if (args[1]) {
2014-06-23 19:28:36 +02:00
connect(client, {host: args[1]});
2014-03-14 16:12:01 +01:00
}
2014-03-12 19:06:08 +01:00
break;
2014-03-24 14:44:41 +01:00
2014-03-30 00:59:28 +01:00
case "join":
2014-06-23 19:28:36 +02:00
if (slate && args[1]) {
2014-06-13 00:35:39 +02:00
if (!args[2] || args[2].charAt(0) == "#") {
2014-06-23 19:28:36 +02:00
slate.join(args.slice(1));
2014-06-13 00:35:39 +02:00
} else {
2014-06-23 19:28:36 +02:00
slate.join(
2014-06-13 00:35:39 +02:00
args[1],
args[2] // Password
);
}
2014-05-18 23:23:31 +02:00
}
break;
2014-03-30 05:12:29 +02:00
case "nick":
2014-06-23 19:28:36 +02:00
if (slate && args[1]) {
slate.nick(args[1]);
2014-03-30 00:59:28 +01:00
}
break;
2014-05-16 15:12:57 +02:00
case "part":
if (chan.type != "channel") {
return;
}
2014-05-15 23:58:50 +02:00
case "close":
2014-04-06 22:53:07 +02:00
case "leave":
2014-05-16 15:12:57 +02:00
if (chan.type == "lobby") {
return;
}
var id = chan.id;
if (chan.type == "query" || !chan.users.length) {
2014-06-23 19:28:36 +02:00
client.networks.forEach(function(n) {
n.channels = _.without(n.channels, _.findWhere(n.channels, {id: id}));
});
client.emit("part", {
id: id,
});
2014-06-23 19:28:36 +02:00
} else if (slate) {
slate.part(chan.name);
2014-04-06 22:53:07 +02:00
}
break;
2014-05-16 15:12:57 +02:00
case "partall":
var part = [];
network.channels.forEach(function(c) {
if (c.type == "channel") part.push(c.name);
});
2014-06-23 19:28:36 +02:00
slate.part(part);
2014-05-16 15:12:57 +02:00
break;
2014-05-18 00:17:50 +02:00
case "invite":
2014-06-23 19:28:36 +02:00
if (slate && args[2]) {
slate.invite(args[1], args[2]);
2014-05-18 00:17:50 +02:00
}
break;
2014-03-30 05:12:29 +02:00
case "topic":
2014-06-23 19:28:36 +02:00
if (slate) {
var msg = "TOPIC";
msg += " " + chan.name;
msg += args[1] ? " :" + args.slice(1).join(" ") : "";
2014-06-23 19:28:36 +02:00
slate.write(msg);
2014-03-30 00:59:28 +01:00
}
break;
2014-06-12 14:11:12 +02:00
case "whoami":
2014-06-23 19:28:36 +02:00
var user = slate.me;
2014-04-02 17:24:33 +02:00
case "query":
case "whois":
2014-06-12 14:11:12 +02:00
var user = user || args[1];
2014-06-23 19:28:36 +02:00
if (slate && user) {
slate.whois(user);
2014-04-02 17:24:33 +02:00
}
break;
case "kick":
2014-06-23 19:28:36 +02:00
if (slate && args[1]) {
slate.kick(chan.name, args[1]);
2014-04-06 17:46:42 +02:00
}
break;
2014-04-08 00:03:21 +02:00
case "op":
case "deop":
case "voice":
case "devoice":
2014-04-06 17:46:42 +02:00
case "mode":
2014-06-23 19:28:36 +02:00
if (!slate || !args[1]) {
2014-04-08 00:03:21 +02:00
break;
}
var mode;
var user;
if (cmd != "mode") {
user = args[1];
mode = {
"op": "+o",
"deop": "-o",
"voice": "+v",
"devoice": "-v",
}[cmd];
} else if (!args[2]) {
break;
} else {
mode = args[1];
user = args[2];
}
2014-06-23 19:28:36 +02:00
slate.mode(
chan.name,
2014-04-08 00:03:21 +02:00
mode,
user
);
2014-04-02 17:24:33 +02:00
break;
2014-03-30 05:12:29 +02:00
case "quit":
case "disconnect":
if (client) {
2014-06-23 19:28:36 +02:00
client.networks = _.without(client.networks, network);
client.emit("networks", {networks: client.networks});
slate.quit();
}
2014-03-30 05:12:29 +02:00
break;
2014-05-07 21:30:14 +02:00
2014-05-15 23:58:50 +02:00
case "raw":
2014-05-07 21:30:14 +02:00
case "send":
2014-06-23 19:28:36 +02:00
if (slate) {
slate.write(args.slice(1).join(" "));
2014-05-07 21:30:14 +02:00
}
break;
2014-03-12 16:09:37 +01:00
}
2014-03-24 16:47:29 +01:00
}
2014-06-23 19:28:36 +02:00
function fetch(client, socket, data) {
var target = find(client.networks, data.id);
2014-06-02 23:08:03 +02:00
if (!target) {
return;
}
2014-06-23 19:28:36 +02:00
2014-06-02 23:08:03 +02:00
var chan = target.chan;
var messages = chan
.messages
.slice(0, chan.messages.length - (data.count || 0));
2014-06-23 19:28:36 +02:00
2014-06-02 23:08:03 +02:00
socket.emit("messages", {
id: data.id,
msg: messages,
});
}
2014-06-23 19:28:36 +02:00
function find(networks, id) {
2014-04-25 01:57:51 +02:00
for (var i = 0; i < networks.length; i++) {
var result = {
network: networks[i],
chan: _.findWhere(networks[i].channels, {id: id}),
};
2014-04-25 01:57:51 +02:00
if (result.chan) {
return result;
}
2014-04-25 01:57:51 +02:00
}
2014-06-23 19:28:36 +02:00
return false;
}