Added support for multiple users

This commit is contained in:
Mattias Erming 2014-06-23 19:28:36 +02:00
parent ffabc7cfea
commit a690395086
24 changed files with 285 additions and 265 deletions

View File

@ -81,8 +81,6 @@ socket.emit("join", {
id: 0, id: 0,
name: "", name: "",
type: "", type: "",
network: "",
count: 0,
messages: [], messages: [],
users: [], users: [],
} }

View File

@ -57,7 +57,7 @@ button {
font: bold 12px Lato, sans-serif; font: bold 12px Lato, sans-serif;
letter-spacing: 1px; letter-spacing: 1px;
margin-bottom: 10px; margin-bottom: 10px;
padding: 12px 18px; padding: 10px 18px;
text-transform: uppercase; text-transform: uppercase;
transition: background .2s, border-color .2s, color .2s; transition: background .2s, border-color .2s, color .2s;
word-spacing: 3px; word-spacing: 3px;
@ -138,12 +138,7 @@ button {
} }
#sidebar .octicon { #sidebar .octicon {
float: left; float: left;
margin-top: 1px; margin: 1px 8px 0 1px;
margin-right: 8px;
}
#sidebar .octicon-plus {
margin-left: 1px;
margin-right: 11px;
} }
#sidebar .lobby { #sidebar .lobby {
color: #84d1ff !important; color: #84d1ff !important;
@ -221,6 +216,9 @@ button {
#sidebar.signed-in #settings-link { #sidebar.signed-in #settings-link {
display: block; display: block;
} }
#sidebar .hidden {
display: none !important;
}
#main { #main {
bottom: 0; bottom: 0;
left: 220px; left: 220px;
@ -244,6 +242,7 @@ button {
margin: 0 auto; margin: 0 auto;
max-width: 480px; max-width: 480px;
overflow: auto; overflow: auto;
-webkit-overflow-scrolling: touch;
padding: 0 20px; padding: 0 20px;
} }
#windows a { #windows a {
@ -258,7 +257,8 @@ button {
#windows h2 { #windows h2 {
color: #2c3e50; color: #2c3e50;
font: 300 48px Lato, sans-serif; font: 300 48px Lato, sans-serif;
line-height: 1.5; line-height: 1.4;
margin-bottom: 16px;
} }
#windows h2, #windows h2,
#windows h3 { #windows h3 {
@ -268,7 +268,6 @@ button {
#windows h3 { #windows h3 {
border-bottom: 1px solid #eee; border-bottom: 1px solid #eee;
font-weight: 300; font-weight: 300;
margin-bottom: 10px; margin-bottom: 10px;
padding-bottom: 7px; padding-bottom: 7px;
} }
@ -276,20 +275,24 @@ button {
color: #95a5a6; color: #95a5a6;
font-size: 18px; font-size: 18px;
font-weight: normal; font-weight: normal;
margin-top: 0;
margin-bottom: 10px; margin-bottom: 10px;
} }
#windows form { #windows form {
margin: 0 0; margin: 0 0;
max-width: 250px; max-width: 250px;
} }
#windows .btn {
margin-top: 8px;
}
#windows .input { #windows .input {
border: 2px solid #e9ecef; border: 2px solid #e9ecef;
border-radius: 4px; border-radius: 4px;
color: #95a5a6; color: #95a5a6;
font-size: 24px; font-size: 18px;
margin-bottom: 16px; margin-bottom: 16px;
outline: 0; outline: 0;
padding: 10px 14px; padding: 8px 10px;
transition: border-color .2s; transition: border-color .2s;
-webkit-appearance: none; -webkit-appearance: none;
width: 100%; width: 100%;
@ -418,6 +421,7 @@ button {
} }
#chat .messages { #chat .messages {
display: table; display: table;
margin: 5px 0;
width: 100%; width: 100%;
} }
#chat .row { #chat .row {
@ -429,12 +433,6 @@ button {
padding-top: 2px; padding-top: 2px;
padding-bottom: 2px; padding-bottom: 2px;
} }
#chat .row:first-child span {
padding-top: 5px;
}
#chat .row:last-child span {
padding-bottom: 5px;
}
#chat .row:hover .time { #chat .row:hover .time {
color: #aaa; color: #aaa;
} }

View File

@ -28,16 +28,14 @@
<i class="octicon octicon-clippy"></i> <i class="octicon octicon-clippy"></i>
Settings Settings
</a> </a>
<% if (password) { %>
<a id="login" href="#sign-in" data-name="Sign in"> <a id="login" href="#sign-in" data-name="Sign in">
<i class="octicon octicon-sign-in"></i> <i class="octicon octicon-sign-in"></i>
Sign in Sign in
</a> </a>
<a id="logout" href=""> <a id="logout" href="" class="hidden">
<i class="octicon octicon-sign-out"></i> <i class="octicon octicon-sign-out"></i>
Sign out Sign out
</a> </a>
<% } %>
</section> </section>
<div id="networks"></div> <div id="networks"></div>
<footer class="footer"> <footer class="footer">
@ -95,11 +93,12 @@
</div> </div>
<div id="sign-in" class="window"> <div id="sign-in" class="window">
<div class="wrap"> <div class="wrap">
<h1>Shout</h1> <h1>Sign in</h1>
<h2>You need to sign in to continue.</h2>
<form id="sign-in-form" method="post"> <form id="sign-in-form" method="post">
<h4>Username:</h4>
<input name="user" class="name input" autocomplete="off">
<h4>Password:</h4> <h4>Password:</h4>
<input id="sign-in-input" class="input" type="password" autofocus> <input name="password" class="password input" type="password">
<button type="submit" class="btn"> <button type="submit" class="btn">
Sign in Sign in
</button> </button>

View File

@ -260,7 +260,11 @@ $(function() {
.end(); .end();
if (!touchDevice) { if (!touchDevice) {
window.find("input").focus(); if (window.is("#sign-in")) {
window.find("input[name='user']").focus();
} else {
window.find("input:last").focus();
}
} }
}); });
@ -411,8 +415,16 @@ $(function() {
$("#sign-in-form").on("submit", function(e) { $("#sign-in-form").on("submit", function(e) {
e.preventDefault(); e.preventDefault();
socket.emit("auth", $("#sign-in-input").val()); var user = $(this).find(".name").val();
var password = $(this).find(".password").val();
$.cookie("user", user);
$("#logout").removeClass("hidden");
socket.emit("auth", {
user: user,
password: password
}); });
}).find(".name")
.val($.cookie("user") || "");
$("#notification").on("click", function() { $("#notification").on("click", function() {
pop.play(); pop.play();

View File

@ -1,21 +1,22 @@
module.exports = { module.exports = {
port: 9000, port: 9000,
password: "",
log: false,
theme: "", theme: "",
defaults: { users: {
nick: "shout-user", "username": {
password: "",
nick: "shout",
realname: "http://github.com/erming/shout", realname: "http://github.com/erming/shout",
}, log: false,
networks: [{ networks: [{
host: "chat.freenode.net", host: "irc.freenode.org",
port: 6697, port: 6667,
tls: true, tls: false,
onConnect: { onConnect: {
commands: [""],
join: [ join: [
"#shout-irc", "#shout-irc"
] ]
} }
}] }]
}
}
}; };

View File

@ -3,14 +3,22 @@ var fs = require("fs");
var moment = require("moment"); var moment = require("moment");
module.exports = function log(chan, msg) { module.exports = function log(chan, msg) {
if (!config.log) { var client = chan.network.client;
if (!client.config.log) {
return; return;
} }
var network = chan.network.name; var network = chan.network.name;
var dir = "logs/" + network + "/"; var dir = "logs/";
dir += client.name + "/";
if (!fs.existsSync(dir)) { if (!fs.existsSync(dir)) {
fs.mkdir(dir); fs.mkdirSync(dir);
}
dir += network + "/";
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir);
} }
var date = moment().format("YYYY-MM-DD HH:mm"); var date = moment().format("YYYY-MM-DD HH:mm");

View File

@ -9,8 +9,7 @@ function Chan(attr) {
id: global.id = ++global.id || 1, id: global.id = ++global.id || 1,
name: "", name: "",
type: "channel", type: "channel",
network: "", network: null,
count: 0,
messages: [], messages: [],
users: [], users: [],
}, attr)); }, attr));
@ -47,8 +46,9 @@ Chan.prototype.sortUsers = function() {
}; };
Chan.prototype.toJSON = function() { Chan.prototype.toJSON = function() {
var clone = _.omit(this, ["network"]); var clone = _.omit(this, [
clone.count = clone.messages.length; "network"
]);
clone.messages = clone.messages.slice(-100); clone.messages = clone.messages.slice(-100);
return clone; return clone;
}; };

17
lib/models/client.js Normal file
View File

@ -0,0 +1,17 @@
var _ = require("lodash");
module.exports = Client;
function Client(attr) {
_.merge(this, _.extend({
name: "",
networks: [],
sockets: null,
}, attr));
};
Client.prototype.emit = function(event, data) {
if (this.sockets != null) {
this.sockets.in(this.name).emit(event, data);
}
};

View File

@ -6,8 +6,8 @@ module.exports = Network;
function Network(attr) { function Network(attr) {
_.merge(this, _.extend({ _.merge(this, _.extend({
id: global.id = ++global.id || 1, id: global.id = ++global.id || 1,
client: null,
connected: false, connected: false,
slate: null,
host: "", host: "",
name: attr.host.split(".")[1].capitalize() || attr.host, name: attr.host.split(".")[1].capitalize() || attr.host,
channels: [], channels: [],
@ -28,10 +28,13 @@ Network.prototype.toJSON = function() {
var clone = _.omit(this, [ var clone = _.omit(this, [
"client", "client",
"connected", "connected",
"slate"
]); ]);
return clone; return clone;
}; };
// Helper
String.prototype.capitalize = function() { String.prototype.capitalize = function() {
return this.charAt(0).toUpperCase() + this.slice(1); return this.charAt(0).toUpperCase() + this.slice(1);
} }

View File

@ -1,10 +1,9 @@
var config = require("../../config") || {};
var Msg = require("../models/msg"); var Msg = require("../models/msg");
module.exports = function(client, sockets) { module.exports = function(slate, network) {
var network = this; var client = this;
client.on("errors", function(data) { slate.on("errors", function(data) {
sockets.in("chat").emit("msg", { client.emit("msg", {
msg: new Msg({ msg: new Msg({
type: "error", type: "error",
from: "-!-", from: "-!-",
@ -13,8 +12,8 @@ module.exports = function(client, sockets) {
}); });
if (!network.connected) { if (!network.connected) {
if (data.cmd == "ERR_NICKNAMEINUSE") { if (data.cmd == "ERR_NICKNAMEINUSE") {
var random = config.defaults.nick + Math.floor(10 + (Math.random() * 89)); var random = client.nick + Math.floor(10 + (Math.random() * 89));
client.nick(random); slate.nick(random);
} }
} }
}); });

View File

@ -3,16 +3,16 @@ var Chan = require("../models/chan");
var Msg = require("../models/msg"); var Msg = require("../models/msg");
var User = require("../models/user"); var User = require("../models/user");
module.exports = function(client, sockets) { module.exports = function(slate, network) {
var network = this; var client = this;
client.on("join", function(data) { slate.on("join", function(data) {
var chan = _.findWhere(network.channels, {name: data.channel}); var chan = _.find(network.channels, {name: data.channel});
if (typeof chan === "undefined") { if (!chan) {
chan = new Chan({ chan = new Chan({
name: data.channel, name: data.channel
}); });
network.addChan(chan); network.addChan(chan);
sockets.in("chat").emit("join", { client.emit("join", {
id: network.id, id: network.id,
chan: chan, chan: chan,
}); });
@ -20,7 +20,7 @@ module.exports = function(client, sockets) {
var users = chan.users; var users = chan.users;
users.push(new User({name: data.nick})); users.push(new User({name: data.nick}));
chan.sortUsers(); chan.sortUsers();
sockets.in("chat").emit("users", { client.emit("users", {
id: chan.id, id: chan.id,
users: users, users: users,
}); });
@ -29,7 +29,7 @@ module.exports = function(client, sockets) {
type: "join", type: "join",
}); });
chan.addMsg(msg); chan.addMsg(msg);
sockets.in("chat").emit("msg", { client.emit("msg", {
id: chan.id, id: chan.id,
msg: msg, msg: msg,
}); });

View File

@ -2,19 +2,19 @@ var _ = require("lodash");
var Chan = require("../models/chan"); var Chan = require("../models/chan");
var Msg = require("../models/msg"); var Msg = require("../models/msg");
module.exports = function(client, sockets) { module.exports = function(slate, network) {
var network = this; var client = this;
client.on("kick", function(data) { slate.on("kick", function(data) {
var chan = _.findWhere(network.channels, {name: data.channel}); var chan = _.findWhere(network.channels, {name: data.channel});
if (typeof chan === "undefined") { if (typeof chan === "undefined") {
return; return;
} }
if (data.client == client.me) { if (data.client == slate.me) {
chan.users = []; chan.users = [];
} else { } else {
chan.users = _.without(chan.users, _.findWhere(chan.users, {name: data.client})); chan.users = _.without(chan.users, _.findWhere(chan.users, {name: data.client}));
} }
sockets.in("chat").emit("users", { client.emit("users", {
id: chan.id, id: chan.id,
users: chan.users, users: chan.users,
}); });
@ -24,7 +24,7 @@ module.exports = function(client, sockets) {
text: data.client, text: data.client,
}); });
chan.addMsg(msg); chan.addMsg(msg);
sockets.in("chat").emit("msg", { client.emit("msg", {
id: chan.id, id: chan.id,
msg: msg, msg: msg,
}); });

View File

@ -3,9 +3,9 @@ var Chan = require("../models/chan");
var Msg = require("../models/msg"); var Msg = require("../models/msg");
var Network = require("../models/network"); var Network = require("../models/network");
module.exports = function(client, sockets) { module.exports = function(slate, network) {
var network = this; var client = this;
client.on("message", function(data) { slate.on("message", function(data) {
var target = data.to; var target = data.to;
var chan = _.findWhere(network.channels, {name: target.charAt(0) == "#" ? target : data.from}); var chan = _.findWhere(network.channels, {name: target.charAt(0) == "#" ? target : data.from});
if (typeof chan === "undefined") { if (typeof chan === "undefined") {
@ -14,7 +14,7 @@ module.exports = function(client, sockets) {
type: "query", type: "query",
}); });
network.addChan(chan); network.addChan(chan);
sockets.in("chat").emit("join", { client.emit("join", {
id: network.id, id: network.id,
chan: chan, chan: chan,
}); });
@ -26,7 +26,7 @@ module.exports = function(client, sockets) {
text = text.replace(/\u0001|ACTION/g, ""); text = text.replace(/\u0001|ACTION/g, "");
} }
text.split(' ').forEach(function(w) { text.split(' ').forEach(function(w) {
if (w.indexOf(client.me) == 0) type += " highlight"; if (w.indexOf(slate.me) == 0) type += " highlight";
}); });
var msg = new Msg({ var msg = new Msg({
type: type || "normal", type: type || "normal",
@ -34,7 +34,7 @@ module.exports = function(client, sockets) {
text: text, text: text,
}); });
chan.addMsg(msg); chan.addMsg(msg);
sockets.in("chat").emit("msg", { client.emit("msg", {
id: chan.id, id: chan.id,
msg: msg, msg: msg,
}); });

View File

@ -2,15 +2,15 @@ var _ = require("lodash");
var Chan = require("../models/chan"); var Chan = require("../models/chan");
var Msg = require("../models/msg"); var Msg = require("../models/msg");
module.exports = function(client, sockets) { module.exports = function(slate, network) {
var network = this; var client = this;
var timer = null; var timer = null;
client.on("mode", function(data) { slate.on("mode", function(data) {
var chan = _.findWhere(network.channels, {name: data.target}); var chan = _.findWhere(network.channels, {name: data.target});
if (typeof chan !== "undefined") { if (typeof chan !== "undefined") {
clearTimeout(timer); clearTimeout(timer);
timer = setTimeout(function() { timer = setTimeout(function() {
client.write("NAMES " + data.target); slate.write("NAMES " + data.target);
}, 200); }, 200);
var nick = data.nick; var nick = data.nick;
if (nick.indexOf(".") !== -1) { if (nick.indexOf(".") !== -1) {
@ -22,7 +22,7 @@ module.exports = function(client, sockets) {
text: data.mode + " " + data.client, text: data.mode + " " + data.client,
}); });
chan.addMsg(msg); chan.addMsg(msg);
sockets.in("chat").emit("msg", { client.emit("msg", {
id: chan.id, id: chan.id,
msg: msg, msg: msg,
}); });

View File

@ -1,9 +1,9 @@
var Chan = require("../models/chan"); var Chan = require("../models/chan");
var Msg = require("../models/msg"); var Msg = require("../models/msg");
module.exports = function(client, sockets) { module.exports = function(slate, network) {
var network = this; var client = this;
client.on("motd", function(data) { slate.on("motd", function(data) {
var rows = data.motd; var rows = data.motd;
var chan = network.channels[0]; var chan = network.channels[0];
var msg = new Msg({ var msg = new Msg({
@ -11,7 +11,7 @@ module.exports = function(client, sockets) {
from: "-!-" from: "-!-"
}); });
chan.addMsg(msg); chan.addMsg(msg);
sockets.in("chat").emit("msg", { client.emit("msg", {
id: chan.id, id: chan.id,
msg: msg, msg: msg,
}); });
@ -22,7 +22,7 @@ module.exports = function(client, sockets) {
text: text, text: text,
}); });
chan.addMsg(msg); chan.addMsg(msg);
sockets.in("chat").emit("msg", { client.emit("msg", {
id: chan.id, id: chan.id,
msg: msg, msg: msg,
}); });

View File

@ -2,9 +2,9 @@ var _ = require("lodash");
var Chan = require("../models/chan"); var Chan = require("../models/chan");
var User = require("../models/user"); var User = require("../models/user");
module.exports = function(client, sockets) { module.exports = function(slate, network) {
var network = this; var client = this;
client.on("names", function(data) { slate.on("names", function(data) {
var chan = _.findWhere(network.channels, {name: data.channel}); var chan = _.findWhere(network.channels, {name: data.channel});
if (typeof chan === "undefined") { if (typeof chan === "undefined") {
return; return;
@ -14,7 +14,7 @@ module.exports = function(client, sockets) {
chan.addUser(new User(n)); chan.addUser(new User(n));
}); });
chan.sortUsers(); chan.sortUsers();
sockets.in("chat").emit("users", { client.emit("users", {
id: chan.id, id: chan.id,
users: chan.users, users: chan.users,
}); });

View File

@ -2,17 +2,17 @@ var _ = require("lodash");
var Chan = require("../models/chan"); var Chan = require("../models/chan");
var Msg = require("../models/msg"); var Msg = require("../models/msg");
module.exports = function(client, sockets) { module.exports = function(slate, network) {
var network = this; var client = this;
client.on("nick", function(data) { slate.on("nick", function(data) {
if (data["new"] == client.me) { if (data["new"] == slate.me) {
var chan = network.channels[0]; var chan = network.channels[0];
var msg = new Msg({ var msg = new Msg({
from: "-!-", from: "-!-",
text: "You're now known as " + data["new"], text: "You're now known as " + data["new"],
}); });
chan.addMsg(msg); chan.addMsg(msg);
sockets.in("chat").emit("msg", { client.emit("msg", {
id: chan.id, id: chan.id,
msg: msg, msg: msg,
}); });
@ -24,7 +24,7 @@ module.exports = function(client, sockets) {
} }
user.name = data["new"]; user.name = data["new"];
chan.sortUsers(); chan.sortUsers();
sockets.in("chat").emit("users", { client.emit("users", {
id: chan.id, id: chan.id,
users: chan.users, users: chan.users,
}); });
@ -34,7 +34,7 @@ module.exports = function(client, sockets) {
text: data["new"], text: data["new"],
}); });
chan.addMsg(msg); chan.addMsg(msg);
sockets.in("chat").emit("msg", { client.emit("msg", {
id: chan.id, id: chan.id,
msg: msg, msg: msg,
}); });

View File

@ -1,9 +1,9 @@
var Chan = require("../models/chan"); var Chan = require("../models/chan");
var Msg = require("../models/msg"); var Msg = require("../models/msg");
module.exports = function(client, sockets) { module.exports = function(slate, network) {
var network = this; var client = this;
client.on("notice", function(data) { slate.on("notice", function(data) {
var chan = network.channels[0]; var chan = network.channels[0];
var from = data.from || "-!-"; var from = data.from || "-!-";
if (data.to == "*" || data.from.indexOf(".") !== -1) { if (data.to == "*" || data.from.indexOf(".") !== -1) {
@ -15,7 +15,7 @@ module.exports = function(client, sockets) {
text: data.message, text: data.message,
}); });
chan.addMsg(msg); chan.addMsg(msg);
sockets.in("chat").emit("msg", { client.emit("msg", {
id: chan.id, id: chan.id,
msg: msg, msg: msg,
}); });

View File

@ -2,21 +2,21 @@ var _ = require("lodash");
var Chan = require("../models/chan"); var Chan = require("../models/chan");
var Msg = require("../models/msg"); var Msg = require("../models/msg");
module.exports = function(client, sockets) { module.exports = function(slate, network) {
var network = this; var client = this;
client.on("part", function(data) { slate.on("part", function(data) {
var chan = _.findWhere(network.channels, {name: data.channels[0]}); var chan = _.findWhere(network.channels, {name: data.channels[0]});
if (typeof chan === "undefined") { if (typeof chan === "undefined") {
return; return;
} }
if (data.nick == client.me) { if (data.nick == slate.me) {
network.channels = _.without(network.channels, chan); network.channels = _.without(network.channels, chan);
sockets.in("chat").emit("part", { client.emit("part", {
id: chan.id, id: chan.id,
}); });
} else { } else {
chan.users = _.without(chan.users, _.findWhere(chan.users, {name: data.nick})); chan.users = _.without(chan.users, _.findWhere(chan.users, {name: data.nick}));
sockets.in("chat").emit("users", { client.emit("users", {
id: chan.id, id: chan.id,
users: chan.users, users: chan.users,
}); });
@ -25,7 +25,7 @@ module.exports = function(client, sockets) {
from: data.nick, from: data.nick,
}); });
chan.addMsg(msg); chan.addMsg(msg);
sockets.in("chat").emit("msg", { client.emit("msg", {
id: chan.id, id: chan.id,
msg: msg, msg: msg,
}); });

View File

@ -2,16 +2,16 @@ var _ = require("lodash");
var Chan = require("../models/chan"); var Chan = require("../models/chan");
var Msg = require("../models/msg"); var Msg = require("../models/msg");
module.exports = function(client, sockets) { module.exports = function(slate, network) {
var network = this; var client = this;
client.on("quit", function(data) { slate.on("quit", function(data) {
network.channels.forEach(function(chan) { network.channels.forEach(function(chan) {
var user = _.findWhere(chan.users, {name: data.nick}); var user = _.findWhere(chan.users, {name: data.nick});
if (!user) { if (!user) {
return; return;
} }
chan.users = _.without(chan.users, user); chan.users = _.without(chan.users, user);
sockets.in("chat").emit("users", { client.emit("users", {
id: chan.id, id: chan.id,
users: chan.users, users: chan.users,
}); });
@ -20,7 +20,7 @@ module.exports = function(client, sockets) {
from: data.nick, from: data.nick,
}); });
chan.addMsg(msg); chan.addMsg(msg);
sockets.in("chat").emit("msg", { client.emit("msg", {
id: chan.id, id: chan.id,
msg: msg, msg: msg,
}); });

View File

@ -2,9 +2,9 @@ var _ = require("lodash");
var Chan = require("../models/chan"); var Chan = require("../models/chan");
var Msg = require("../models/msg"); var Msg = require("../models/msg");
module.exports = function(client, sockets) { module.exports = function(slate, network) {
var network = this; var client = this;
client.on("topic", function(data) { slate.on("topic", function(data) {
var chan = _.findWhere(network.channels, {name: data.channel}); var chan = _.findWhere(network.channels, {name: data.channel});
if (typeof chan === "undefined") { if (typeof chan === "undefined") {
return; return;
@ -16,7 +16,7 @@ module.exports = function(client, sockets) {
text: data.topic, text: data.topic,
}); });
chan.addMsg(msg); chan.addMsg(msg);
sockets.in("chat").emit("msg", { client.emit("msg", {
id: chan.id, id: chan.id,
msg: msg, msg: msg,
}); });

View File

@ -1,17 +1,18 @@
var Chan = require("../models/chan"); var Chan = require("../models/chan");
var Msg = require("../models/msg"); var Msg = require("../models/msg");
module.exports = function(client, sockets) { module.exports = function(slate, network) {
var network = this; var client = this;
client.on("welcome", function(data) { slate.on("welcome", function(data) {
network.connected = true; network.connected = true;
slate.write("PING " + network.host);
var chan = network.channels[0]; var chan = network.channels[0];
var msg = new Msg({ var msg = new Msg({
from: "-!-", from: "-!-",
text: "You're now known as " + data, text: "You're now known as " + data,
}); });
chan.addMsg(msg); chan.addMsg(msg);
sockets.in("chat").emit("msg", { client.emit("msg", {
id: chan.id, id: chan.id,
msg: msg, msg: msg,
}); });

View File

@ -2,9 +2,9 @@ var _ = require("lodash");
var Chan = require("../models/chan"); var Chan = require("../models/chan");
var Msg = require("../models/msg"); var Msg = require("../models/msg");
module.exports = function(client, sockets) { module.exports = function(slate, network) {
var network = this; var client = this;
client.on("whois", function(err, data) { slate.on("whois", function(err, data) {
if (!data) { if (!data) {
return; return;
} }
@ -15,7 +15,7 @@ module.exports = function(client, sockets) {
name: data.nickname, name: data.nickname,
}); });
network.addChan(chan); network.addChan(chan);
sockets.in("chat").emit("join", { client.emit("join", {
id: network.id, id: network.id,
chan: chan, chan: chan,
}); });
@ -38,7 +38,7 @@ module.exports = function(client, sockets) {
text: key + " " + data[k], text: key + " " + data[k],
}); });
chan.addMsg(msg); chan.addMsg(msg);
sockets.in("chat").emit("msg", { client.emit("msg", {
id: chan.id, id: chan.id,
msg: msg, msg: msg,
}); });
@ -49,7 +49,7 @@ module.exports = function(client, sockets) {
text: "End of /WHOIS list.", text: "End of /WHOIS list.",
}); });
chan.addMsg(msg); chan.addMsg(msg);
sockets.in("chat").emit("msg", { client.emit("msg", {
id: chan.id, id: chan.id,
msg: msg, msg: msg,
}); });

View File

@ -7,11 +7,12 @@ var irc = require("slate-irc");
var net = require("net"); var net = require("net");
var tls = require("tls"); var tls = require("tls");
var Client = require("./models/client");
var Msg = require("./models/msg"); var Msg = require("./models/msg");
var Network = require("./models/network"); var Network = require("./models/network");
var sockets = null; var sockets = null;
var networks = []; var clients = [];
var plugins = [ var plugins = [
"errors", "errors",
@ -37,32 +38,28 @@ module.exports = function listen() {
.use(http.static("client")) .use(http.static("client"))
.listen(port); .listen(port);
sockets = io.listen(app, {log: 0}).sockets.on("connection", function(socket) { sockets = io.listen(app, {log: 0});
init.call(
socket,
!!config.password
);
});
(config.networks || []).forEach(function(n) { var users = config.users;
connect(n); 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);
}); });
}
function init(login) {
if (login) {
this.on("auth", auth);
this.emit("auth");
} else {
this.join("chat");
this.on("debug", debug);
this.on("input", input);
this.on("fetch", fetch);
this.emit(
"networks",
{networks: networks}
);
} }
sockets.on("connection", function(socket) {
if (clients.length == 1 && !clients[0].config.password) {
init.call(socket, clients[0]);
} else {
init.call(socket);
}
});
} }
function index(req, res, next) { function index(req, res, next) {
@ -79,84 +76,75 @@ function index(req, res, next) {
}); });
} }
function connect(params) { function init(client) {
_.defaults( var socket = this;
params, if (!client) {
config.defaults 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) {
var host = params.host; var host = params.host;
var port = params.port || 6667; var port = params.port || 6667;
var options = { var options = {
host: host, host: host,
port: port, port: port
}; };
var stream = params.tls ? tls.connect(options) : net.connect(options); var stream = params.tls ? tls.connect(options) : net.connect(options);
stream.on("error", function(e) { stream.on("error", function(e) {
console.log(e); console.log(e);
}); });
var client = irc(stream); var slate = irc(stream);
slate.nick(client.config.nick);
slate.user(client.config.nick, client.config.realname);
var network = new Network({ var network = new Network({
host: host,
client: client, client: client,
host: host,
slate: slate,
}); });
networks.push(network); client.networks.push(network);
sockets.in("chat").emit("networks", {networks: networks}); client.emit("networks", {
networks: client.networks
client.nick(params.nick); });
client.user(params.nick, params.realname);
plugins.forEach(function(plugin) { plugins.forEach(function(plugin) {
require("./plugins/" + plugin).apply(network, [client, sockets]); require("./plugins/" + plugin).apply(client, [slate, network]);
}); });
if (!params.onConnect) { slate.on("welcome", function() {
return; ((params.onConnect || {}).join || []).forEach(function(chan) {
} slate.join.apply(
slate,
client.once("welcome", function() { chan.split(" ")
client.write("PING " + network.host);
var channels = params.onConnect.join || [];
channels.forEach(function(chan) {
client.join.apply(
client,
chan.split(' ')
); );
}); });
}); });
client.once("pong", function() {
var delay = 1000;
var commands = params.onConnect.commands || [];
commands.forEach(function(cmd) {
setTimeout(function() {
input({
id: network.channels[0].id,
text: cmd
});
}, delay);
delay += 1000;
});
});
} }
function auth(password) { function input(client, data) {
if (password == config.password) { var target = find(client.networks, data.id);
this.disable = false;
init.call(this);
}
}
function debug(data) {
console.log(data);
}
function input(data) {
var target = find(data.id);
if (!target) { if (!target) {
return; return;
} }
@ -164,7 +152,7 @@ function input(data) {
var network = target.network; var network = target.network;
var chan = target.chan; var chan = target.chan;
var client = network.client; var slate = network.slate;
var id = data.id; var id = data.id;
var text = data.text; var text = data.text;
@ -187,9 +175,9 @@ function input(data) {
case "msg": case "msg":
var user; var user;
var text = args.slice(2).join(" "); var text = args.slice(2).join(" ");
if (client) { if (slate) {
user = client.me; user = slate.me;
client.send(args[1], text); slate.send(args[1], text);
} }
var chan = _.findWhere(network.channels, {name: args[1]}); var chan = _.findWhere(network.channels, {name: args[1]});
if (typeof chan !== "undefined") { if (typeof chan !== "undefined") {
@ -198,7 +186,7 @@ function input(data) {
text: text, text: text,
}); });
chan.addMsg(msg) chan.addMsg(msg)
sockets.in("chat").emit("msg", { client.emit("msg", {
id: chan.id, id: chan.id,
msg: msg, msg: msg,
}); });
@ -206,8 +194,8 @@ function input(data) {
break; break;
case "notice": case "notice":
if (client && args[2]) { if (slate && args[2]) {
client.notice(args[1], args.slice(2).join(" ")); slate.notice(args[1], args.slice(2).join(" "));
} }
break; break;
@ -219,9 +207,9 @@ function input(data) {
} }
var user; var user;
var text = slap || args.slice(1).join(" "); var text = slap || args.slice(1).join(" ");
if (client) { if (slate) {
user = client.me; user = slate.me;
client.action(chan.name, text); slate.action(chan.name, text);
} }
var msg = new Msg({ var msg = new Msg({
type: "action", type: "action",
@ -229,7 +217,7 @@ function input(data) {
text: text, text: text,
}); });
chan.addMsg(msg) chan.addMsg(msg)
sockets.in("chat").emit("msg", { client.emit("msg", {
id: chan.id, id: chan.id,
msg: msg, msg: msg,
}); });
@ -238,7 +226,7 @@ function input(data) {
case "ame": case "ame":
var type = "action"; var type = "action";
case "amsg": case "amsg":
var user = client.me; var user = slate.me;
var text = args.slice(1).join(" "); var text = args.slice(1).join(" ");
var channels = []; var channels = [];
network.channels.forEach(function(chan) { network.channels.forEach(function(chan) {
@ -250,7 +238,7 @@ function input(data) {
text: text, text: text,
}); });
chan.addMsg(msg) chan.addMsg(msg)
sockets.in("chat").emit("msg", { client.emit("msg", {
id: chan.id, id: chan.id,
msg: msg, msg: msg,
}); });
@ -265,16 +253,16 @@ function input(data) {
case "server": case "server":
case "connect": case "connect":
if (args[1]) { if (args[1]) {
connect({host: args[1]}); connect(client, {host: args[1]});
} }
break; break;
case "join": case "join":
if (client && args[1]) { if (slate && args[1]) {
if (!args[2] || args[2].charAt(0) == "#") { if (!args[2] || args[2].charAt(0) == "#") {
client.join(args.slice(1)); slate.join(args.slice(1));
} else { } else {
client.join( slate.join(
args[1], args[1],
args[2] // Password args[2] // Password
); );
@ -283,8 +271,8 @@ function input(data) {
break; break;
case "nick": case "nick":
if (client && args[1]) { if (slate && args[1]) {
client.nick(args[1]); slate.nick(args[1]);
} }
break; break;
@ -299,12 +287,14 @@ function input(data) {
} }
var id = chan.id; var id = chan.id;
if (chan.type == "query" || !chan.users.length) { if (chan.type == "query" || !chan.users.length) {
remove(id); client.networks.forEach(function(n) {
sockets.in("chat").emit("part", { n.channels = _.without(n.channels, _.findWhere(n.channels, {id: id}));
});
client.emit("part", {
id: id, id: id,
}); });
} else if (client) { } else if (slate) {
client.part(chan.name); slate.part(chan.name);
} }
break; break;
@ -313,39 +303,37 @@ function input(data) {
network.channels.forEach(function(c) { network.channels.forEach(function(c) {
if (c.type == "channel") part.push(c.name); if (c.type == "channel") part.push(c.name);
}); });
console.log("PART"); slate.part(part);
console.log(part);
client.part(part);
break; break;
case "invite": case "invite":
if (client && args[2]) { if (slate && args[2]) {
client.invite(args[1], args[2]); slate.invite(args[1], args[2]);
} }
break; break;
case "topic": case "topic":
if (client) { if (slate) {
var msg = "TOPIC"; var msg = "TOPIC";
msg += " " + chan.name; msg += " " + chan.name;
msg += args[1] ? " :" + args.slice(1).join(" ") : ""; msg += args[1] ? " :" + args.slice(1).join(" ") : "";
client.write(msg); slate.write(msg);
} }
break; break;
case "whoami": case "whoami":
var user = client.me; var user = slate.me;
case "query": case "query":
case "whois": case "whois":
var user = user || args[1]; var user = user || args[1];
if (client && user) { if (slate && user) {
client.whois(user); slate.whois(user);
} }
break; break;
case "kick": case "kick":
if (client && args[1]) { if (slate && args[1]) {
client.kick(chan.name, args[1]); slate.kick(chan.name, args[1]);
} }
break; break;
@ -354,7 +342,7 @@ function input(data) {
case "voice": case "voice":
case "devoice": case "devoice":
case "mode": case "mode":
if (!client || !args[1]) { if (!slate || !args[1]) {
break; break;
} }
var mode; var mode;
@ -373,7 +361,7 @@ function input(data) {
mode = args[1]; mode = args[1];
user = args[2]; user = args[2];
} }
client.mode( slate.mode(
chan.name, chan.name,
mode, mode,
user user
@ -383,38 +371,39 @@ function input(data) {
case "quit": case "quit":
case "disconnect": case "disconnect":
if (client) { if (client) {
networks = _.without(networks, network); client.networks = _.without(client.networks, network);
sockets.in("chat").emit("networks", {networks: networks}); client.emit("networks", {networks: client.networks});
client.quit(); slate.quit();
} }
break; break;
case "raw": case "raw":
case "send": case "send":
if (client) { if (slate) {
client.write(args.slice(1).join(" ")); slate.write(args.slice(1).join(" "));
} }
break; break;
} }
} }
function fetch(data) { function fetch(client, socket, data) {
var socket = this; var target = find(client.networks, data.id);
var target = find(data.id);
if (!target) { if (!target) {
return; return;
} }
var chan = target.chan; var chan = target.chan;
var messages = chan var messages = chan
.messages .messages
.slice(0, chan.messages.length - (data.count || 0)); .slice(0, chan.messages.length - (data.count || 0));
socket.emit("messages", { socket.emit("messages", {
id: data.id, id: data.id,
msg: messages, msg: messages,
}); });
} }
function find(id) { function find(networks, id) {
for (var i = 0; i < networks.length; i++) { for (var i = 0; i < networks.length; i++) {
var result = { var result = {
network: networks[i], network: networks[i],
@ -424,10 +413,5 @@ function find(id) {
return result; return result;
} }
} }
} return false;
function remove(id) {
networks.forEach(function(n) {
n.channels = _.without(n.channels, _.findWhere(n.channels, {id: id}));
});
} }