Skip to content
Browse files

Basic IRC connections operational.

  • Loading branch information...
1 parent 95f9eb9 commit c1859c5849bbd323a9b6cb147036bdafe19d56f6 @ericbarch ericbarch committed May 5, 2013
Showing with 140 additions and 110 deletions.
  1. +2 −2 assets/js/views/chat.js
  2. +0 −2 assets/js/views/overview.js
  3. +2 −0 lib/config.js
  4. +30 −37 lib/irclink.js
  5. +4 −4 lib/models.js
  6. +99 −60 lib/socket.js
  7. +2 −1 package.json
  8. +1 −4 views/templates.jade
View
4 assets/js/views/chat.js
@@ -203,14 +203,14 @@ var ChatView = Backbone.View.extend({
},
handleClick: function() {
- $('.hide_embed').live("click", function() {
+ $('.hide_embed').on("click", function() {
var embed_div = $(this).parent().siblings('.embed');
embed_div.addClass('hide');
$(this).siblings('.show_embed').removeClass('hide');
$(this).addClass('hide');
});
- $('.show_embed').live("click", function() {
+ $('.show_embed').on("click", function() {
var embed_div = $(this).parent().siblings('.embed');
embed_div.removeClass('hide');
$(this).siblings('.hide_embed').removeClass('hide');
View
2 assets/js/views/overview.js
@@ -70,7 +70,6 @@ var OverviewView = Backbone.View.extend({
realName = $('#connect-realName').val() || nick,
secure = $('#connect-secure').is(':checked'),
selfSigned = $('#connect-selfSigned').is(':checked'),
- rejoin = $('#connect-rejoin').is(':checked'),
password = $('#connect-password').val(),
encoding = $('#connect-encoding').val(),
keepAlive = false;
@@ -97,7 +96,6 @@ var OverviewView = Backbone.View.extend({
port: port,
secure: secure,
selfSigned: selfSigned,
- rejoin: rejoin,
away: away,
realName: realName,
password: password,
View
2 lib/config.js
@@ -3,6 +3,7 @@ module.exports = {
sqlite_path: 'subway.db',
+ /* not implemented yet */
guest_access: {
enabled: false, // allow guests to use this instance (no account mode)
restrict_server: false, // only allow the following server?
@@ -13,6 +14,7 @@ module.exports = {
show_details: true // show the user the server/channel they're connecting to (if false, first channel in array is joined)
},
+ /* not implemented yet */
user_access: {
users_enabled: true, // show and allow logins
registration_enabled: true, // allow new users to register themselves
View
67 lib/irclink.js
@@ -18,14 +18,14 @@ module.exports = function IRCLink(connID, app) {
var instance = this;
// Find the connection ID in the db and wake it up
- Connection.findById(connID, function (err, userConn) {
+ Connection.get(connID, function (err, userConn) {
// that's not good, give up
if (err || userConn === null)
return;
// make sure this is reasonable
try {
- instance.port = parseInt(port);
+ instance.port = parseInt(userConn.port);
if (isNaN(instance.port) || instance.port < 1024 || instance.port > 65535)
instance.port = 6667;
} catch (pErr) {
@@ -37,29 +37,22 @@ module.exports = function IRCLink(connID, app) {
else
instance.srvPassword = null;
- if (userConn.server_username && userConn.server_username.length > 0)
- instance.srvUsername = userConn.server_username;
- else
- instance.srvUsername = userConn.nick;
-
if (userConn.real_name && userConn.real_name.length > 0)
instance.realName = userConn.real_name;
else
instance.realName = userConn.nick;
instance.client = new irc.Client(userConn.hostname, userConn.nick, {
password: instance.srvPassword,
- userName: instance.srvUsername,
+ userName: userConn.nick,
realName: instance.realName,
port: instance.port,
autoRejoin: false,
floodProtection: true,
secure: userConn.ssl,
selfSigned: userConn.selfSigned,
- encoding: encoding,
+ encoding: userConn.encoding,
certExpired: false,
- floodProtection: true,
- floodProtectionDelay: 1000,
stripColors: true
});
@@ -122,12 +115,24 @@ module.exports = function IRCLink(connID, app) {
// TODO: set timeout for channel join
break;
case 'join':
+ if(instance.client.chans[args.channel] === undefined)
+ instance.client.chans[args.channel] = {unread_messages: 0, unread_mentions: 0};
// TODO: add to db for channels joined
break;
case 'part':
// TODO: remove from db for channels joined
break;
case 'message#':
+ // check if any clients are connected to this IRC link
+ if(app.ircbridge.listeners(connID).length === 0){
+ // if not, increment unread message and mention counts
+ instance.client.chans[args.to].unread_messages++;
+
+ var re = new RegExp('\\b' + instance.client.nick.toLowerCase() + '\\b', 'g');
+ if(re.test(args.text.toLowerCase())){
+ instance.client.chans[args.to].unread_mentions++;
+ }
+ }
// TODO: LOG THIS
break;
case 'action':
@@ -153,7 +158,7 @@ module.exports = function IRCLink(connID, app) {
};
for (var event in instance.events) {
- instance.activateListener(event, this.events[event]);
+ instance.activateListener(event, instance.events[event]);
}
// Handle requests from user
@@ -162,15 +167,24 @@ module.exports = function IRCLink(connID, app) {
switch (event) {
case 'say':
instance.client.say(data.to.toLowerCase(), data.text);
- // log it
- var msg = new Message({conn_id: connID, from: instance.client.nick, chan: data.to.toLowerCase(), msg: data.text});
- msg.save();
+ instance.xmitEvent('message', {to:data.to.toLowerCase(), from: instance.client.nick, text:data.text});
+ // TODO: log this
break;
case 'join':
instance.client.join(data.channel.toLowerCase());
break;
case 'clearunreads':
- // TODO!
+ for(key in instance.client.chans){
+ if(instance.client.chans.hasOwnProperty(key)){
+ var channel = instance.client.chans[key];
+ channel.unread_messages = 0;
+ channel.unread_mentions = 0;
+ }
+ }
+ break;
+ case 'restore':
+ instance.xmitEvent('restore_connection', {nick: instance.client.nick,
+ server: instance.client.opt.server, channels: instance.client.chans});
break;
case 'part':
instance.client.part(data.channel.toLowerCase());
@@ -187,27 +201,6 @@ module.exports = function IRCLink(connID, app) {
case 'nick':
instance.client.send('NICK', data.nick);
break;
- case 'get_channels':
- var chanArray = new Array();
- for (var key in instance.client.chans) {
- chanArray.push(key);
- }
- instance.xmitEvent('channels', {'channels':chanArray});
- break;
- case 'get_channel_details':
- if (data.channel.toLowerCase() in instance.client.chans) {
- var response = {
- "channel": data.channel.toLowerCase(),
- "topic": instance.client.chans[data.channel.toLowerCase()].topic,
- "topic_by": instance.client.chans[data.channel.toLowerCase()].topicBy,
- "created": instance.client.chans[data.channel.toLowerCase()].created,
- "modes": instance.client.chans[data.channel.toLowerCase()].mode,
- "userlist": instance.client.chans[data.channel.toLowerCase()].users
- };
-
- instance.xmitEvent('channel_details', {'channel':response.channel,'topic':response.topic,'topic_by':response.topic_by,'modes':response.modes,'userlist':response.userlist});
- }
- break;
case 'disconnect':
if (instance.connected) {
instance.connected = false;
View
8 lib/models.js
@@ -1,6 +1,7 @@
module.exports = function (db, cb) {
db.define('user', {
- username: String
+ user_id: String
+ , username: String
, password: String
, joined: Date
});
@@ -14,7 +15,7 @@ module.exports = function (db, cb) {
, away: String // away message on the server
, ssl: Boolean // connect using ssl?
, selfSigned: Boolean // allow self signed ssl certs
- , encoding: Boolean
+ , encoding: String
, server_password: String // password for logging into server
, nickserv_password: String // nickserv password for logging into
, nickserv_enabled: Boolean // auth with nickserv?
@@ -24,7 +25,7 @@ module.exports = function (db, cb) {
, disabled: Boolean // is this connection prevented from starting?
, disabled_timeout: Date // do not allow the user to re-enable this connection until this date
, disabled_reason: String // why is this connection disabled? (could be user-initiated)
- , stay_online: Boolean // keep this connection active even if the user is disconnected
+ , keepAlive: Boolean // keep this connection active even if the user is disconnected
, temporary: Boolean // this was created for a guest (no account)
});
@@ -41,7 +42,6 @@ module.exports = function (db, cb) {
, from: String
, at: Date
, msg: String
- , read: Boolean
});
db.define('channel', {
View
159 lib/socket.js
@@ -1,8 +1,15 @@
-var bcrypt = require('bcrypt-nodejs');
+var bcrypt = require('bcrypt-nodejs'),
+ uuid = require('node-uuid');
module.exports = function(socket, app) {
- // once we are authed, this will no longer be null
- socket.user = null;
+ // once the user has authed, this will no longer be null
+ socket.userID = null;
+
+ // the user's IRC connection
+ // NOTE: going forward as multi-connection support is implemented client side, this
+ // will be removed and the user will signal which IRC connection they are controlling in
+ // the socket.io event payload
+ socket.connID = -1;
// establish db models
var User = app.db.models.user;
@@ -11,16 +18,17 @@ module.exports = function(socket, app) {
var PM = app.db.models.pm;
var Channel = app.db.models.channel;
+ // signal an IRC connection belonging to the user
socket.xmitEvent = function(connection, event, dict) {
+ var dict = (typeof dict === "undefined") ? {} : dict;
// TODO: only allow xmit to connections belonging to the user
// TODO: send back fail for all xmitEmit calls if connection is not online
app.ircbridge.emit(connection, event, dict);
}
- // TODO: lock down queries to only return connections that belong to user
- // TODO: idiot proof data inputs
-
/* auth commands */
+
+ // user registration
socket.on('register', function(data) {
// make sure user doesn't already exist
User.count({ username: data.username }, function (err, count) {
@@ -29,11 +37,16 @@ module.exports = function(socket, app) {
bcrypt.genSalt(10, function(err, salt) {
bcrypt.hash(data.password, salt, null, function(err, hash) {
// create the new user
- User.create([{username: data.username, password: hash, joined: Date.now() }], function (err, items) {
+ User.create([{
+ user_id: uuid.v1()
+ , username: data.username
+ , password: hash
+ , joined: Date.now()
+ }], function (err, users) {
socket.emit('register_success', {username: data.username});
- socket.user = items[0];
- // subscribe to all online IRC connections
- socket.join(socket.user.id);
+ socket.userID = users[0].user_id;
+ // subscribe to all online IRC connections using socket.io room
+ socket.join(socket.userID);
});
});
});
@@ -43,20 +56,30 @@ module.exports = function(socket, app) {
});
});
+ // user login
socket.on('login', function(data){
+ // find the user
User.find({username: data.username}, function(err, users) {
+ // does the user exist?
if(users[0]){
+ // check password
bcrypt.compare(data.password, users[0].password, function(err, res) {
+ // if the password matched...
if(res === true){
- var exists = false;
- socket.user = users[0];
- socket.join(socket.user.id);
- /*if(connections[user.username] !== undefined){
- exists = true;
- } else {
- exists = false;
- }*/
- socket.emit('login_success', {username: data.username, exists: exists});
+ socket.userID = users[0].user_id;
+ // subscribe to all online IRC connections using socket.io room
+ socket.join(socket.userID);
+
+ // find all connections belonging to the user
+ Connection.find({ user_id: socket.user.id }, function (err, connections) {
+ var exists = false;
+ if (connections.length > 0) {
+ exists = true;
+ // TEMPORARY - read note at top of this file on socket.connID
+ socket.connID = connections[0].id;
+ }
+ socket.emit('login_success', {username: data.username, exists: exists});
+ });
} else {
socket.emit('login_error', {message: 'Wrong password'});
}
@@ -67,50 +90,69 @@ module.exports = function(socket, app) {
});
});
+ // connection creation/restore
socket.on('connect', function(data) {
- /*var connection;
- if(current_user){
- connection = connections[current_user.username];
- }
- if(connection === undefined) {
- connection = new IRCLink(data.server, data.port, data.secure, data.selfSigned, data.nick, data.realName, data.password, data.rejoin, data.away, data.encoding, data.keepAlive);
-
- // save this connection
- if(current_user){
- // bind this socket to the proper IRC instance
- connection.associateUser(current_user.username);
-
- var conn = new Connection({ user: current_user.username,
- hostname: data.server,
- port: data.port || (data.secure ? 6697 : 6667),
- ssl: data.secure,
- rejoin: data.rejoin,
- away: data.away,
- realName: data.realName,
- selfSigned: data.selfSigned,
- channels: data.channels,
- nick: data.nick,
- password: data.password,
- encoding: data.encoding,
- keepAlive: data.keepAlive});
-
- conn.save();
- connections[current_user.username] = connection;
- }
+ if (socket.connID !== -1) {
+ // the user is authed and already has a connection
+ // wake up the connection in case it isn't already
+ app.ircbridge.emit('create_irclink', socket.connID);
+ socket.xmitEvent(socket.connID, 'restore');
+ socket.xmitEvent(socket.connID, 'clearunreads');
} else {
- if(!connection.keepAlive) {
- connection.connect();
+ // the user is authed and doesn't have a connection or guest is connecting
+
+ // if the user is auth'd, grab their ID. -1 represents a guest
+ var user_id = uuid.v1();
+ var keepAlive = false;
+ var temp = true;
+ if (socket.userID !== null) {
+ temp = false;
+ user_id = socket.userID;
+ if (data.keepAlive)
+ keepAlive = true;
+ } else {
+ // subscribe to all online IRC connections using guest socket.io room
+ socket.join(user_id);
}
- socket.emit('restore_connection', {nick: connection.client.nick,
- server: connection.client.opt.server, channels: connection.client.chans});
- connection.clearUnreads();*/
+
+ Connection.create([{
+ user_id: user_id
+ , label: data.server
+ , hostname: data.server
+ , port: data.port || 6667
+ , nick: data.nick
+ , away: data.away || 'AFK'
+ , ssl: data.secure || false
+ , selfSigned: data.selfSigned || false
+ , encoding: data.encoding || ''
+ , server_password: data.password || ''
+ , nickserv_password: ''
+ , nickserv_enabled: false
+ , sasl_enabled: false
+ , real_name: data.realName || data.nick
+ , creation: Date.now()
+ , disabled: false
+ , disabled_timeout: Date.now()
+ , disabled_reason: ''
+ , keepAlive: keepAlive
+ , temporary: temp
+
+ }], function (err, items) {
+ if (!err) {
+ // wake up the new connection
+ socket.connID = items[0].id;
+ app.ircbridge.emit('create_irclink', socket.connID);
+ socket.xmitEvent(socket.connID, 'restore');
+ }
+ });
+ }
});
socket.on('join', function(name) {
- /*if (name[0] != '#')
+ if (name[0] != '#')
name = '#' + name;
- connection.client.join(name);*/
+ socket.xmitEvent(socket.connID, 'join', {channel: name});
});
socket.on('part_pm', function(name){
@@ -131,11 +173,8 @@ module.exports = function(socket, app) {
});
socket.on('say', function(data) {
- /*connection.client.say(data.target, data.message);
- socket.emit('message', {to:data.target.toLowerCase(), from: connection.client.nick, text:data.message});
- if(current_user){
- connection.logMessage(data.target, connection.client.nick, data.message);
- }*/
+ // fire event to backend
+ socket.xmitEvent(socket.connID, 'say', {to: data.target, text: data.message});
});
socket.on('action', function(data) {
View
3 package.json
@@ -21,7 +21,8 @@
"socket.io": "0.9.x",
"bcrypt-nodejs": "0.0.x",
"sqlite3": "2.1.x",
- "orm": "2.0.x"
+ "orm": "2.0.x",
+ "node-uuid": "1.4.x"
},
"scripts": {
"start": "subway"
View
5 views/templates.jade
@@ -59,15 +59,12 @@ script(id="overview_connection", type="text/html")
label(for="connect-secure") SSL
input#connect-secure(type="checkbox")
.control-group#ssl-self-signed
- label(for="connect-selfSigned") Self-signed SSL Cert
+ label(for="connect-selfSigned") Allow Self-signed Certs
input#connect-selfSigned(type="checkbox")
.control-group
label(for="connect-away") Away Message
input#connect-away(type="text", placeholder="AFK")
.control-group
- label(for="connect-rejoin") Bouncer Mode
- input#connect-rejoin(type="checkbox")
- .control-group
label(for="connect-encoding") Encoding
select#connect-encoding
option(value="", selected="selected") UTF-8

0 comments on commit c1859c5

Please sign in to comment.
Something went wrong with that request. Please try again.