Skip to content

Commit

Permalink
Major refactoring & simplification of the API.
Browse files Browse the repository at this point in the history
  • Loading branch information
Joachim Kainz committed Apr 30, 2012
1 parent b8f5d0b commit f4d7d28
Show file tree
Hide file tree
Showing 2 changed files with 160 additions and 95 deletions.
13 changes: 7 additions & 6 deletions examples/send-msg.js
Expand Up @@ -6,27 +6,28 @@ if (process.argv.length < 5) {
}

var simpler = require('../index'),
Element = require('node-xmpp').Element,
jid = process.argv[2],
password = process.argv[3],
to = process.argv[4],
xmpp = simpler({
client = simpler({
jid:jid,
password:password,
host:'talk.google.com'
}),
connection;

xmpp.on('online', function () {
client.on('online', function () {
console.log('Yes, I\'m connected!');
connection.send(to, "this is a message from the send-msg script");
});

xmpp.on('chat', function (from, message) {
client.on('chat', function (from, message) {
console.log("from %s: ", from, message);
});

xmpp.on('error', function (err) {
client.on('error', function (err) {
console.error(err);
});

connection = xmpp.connect();
client.send(to, "this is a message from the send-msg script");
//client.discoverServices('gmail.com');
242 changes: 153 additions & 89 deletions lib/simple-xmpp.js
Expand Up @@ -28,45 +28,12 @@

var STATUS_ONLINE = "online",
STATUS_OFFLINE = "offline",
DISCO_URL = 'http://jabber.org/protocol/disco#info',
xmpp = require('node-xmpp'),
debug = require('./debug'),
EventEmitter = require('events').EventEmitter,
util = require('util');

function SimpleXMPP(connection, events, probeBuddies) {
this.send = function (to, message) {
var stanza = new xmpp.Element('message', {
to:to,
type:'chat'
});
stanza.c('body').t(message);
connection.send(stanza);
};

this.probe = function (buddy, callback) {
probeBuddies[buddy] = true;

var stanza = new xmpp.Element('presence', {
type:'probe',
to:buddy
});
events.once('probe_' + buddy, callback);
connection.send(stanza);
};

this.on = function (event, listener) {
events.on(event, listener);
};

this.removeListener = function (event, listener) {
return events.removeListener(event, listener);
};

this.removeAllListeners = function (event) {
return events.removeListener(event);
}
}

function getState(stanza) {
if (stanza.attrs.type === 'unavailable') {
return STATUS_OFFLINE;
Expand Down Expand Up @@ -105,85 +72,182 @@
events.emit('chat', id, message);
}

function processStanza(events, stanza, probeBuddies) {
function processPresence(events, stanza, probeBuddies) {
var frm = stanza.attrs.from;

if (!frm) {
return;
}
var iD = frm.split('/')[0],
state = getState(stanza);

debug('presence', iD, state);

if (!probeBuddies[iD]) {
return events.emit('buddy', iD, state);
}

events.emit('probe_' + iD, state);
delete probeBuddies[iD];
}

function match(stanza, handler) {
if (handler.from && handler.from !== stanza.attr.from) {
return undefined;
}

if (handler.to && handler.to !== stanza.attr.to) {
return undefined;
}

var child = stanza.getChild(handler.name, handler.xmlns);

if (!child) {
return undefined;
}

return {
child:child,
stanza:stanza
};
}

function processStanza(handlers, events, stanza, probeBuddies) {
events.emit('stanza', stanza);
debug("stanza", stanza);

if (stanza.is('message')) {
return processMessage(events, stanza);
}

if (!stanza.is('presence')) {
return;
if (stanza.is('presence')) {
return processPresence(events, stanza, probeBuddies);
}

//looking for presence stenza for availability changes
var frm = stanza.attrs.from;
for (var idx = 0; idx < handlers.length; idx++) {
var handler = handlers[0];
var matched = match(stanza, handler);

if (!frm) {
return;
}
var iD = frm.split('/')[0];
var state = getState(stanza);

if (probeBuddies[iD]) {
events.emit('probe_' + iD, state);
delete probeBuddies[iD];
} else {
events.emit('buddy', iD, state);
if (matched) {
if (matched.stanza.attrs.type == 'error') {
return handler(handler.callback(matched.stanza));
}

return handler.callback(undefined, matched.child, matched.stanza);
}
}

debug("tangling stanza", stanza);
}

function connect(config, events, probeBuddies) {
var conn = new xmpp.Client(config);
function sendMessage(pending, connection) {
var args = Array.prototype.splice.call(arguments, 2);

conn.on('online', function () {
conn.send(new xmpp.Element('presence'));
events.emit('online');
//make the connection live
setInterval(function () {
conn.send(new xmpp.Element('presence'));
}, 1000 * 10)
});

conn.on('stanza', function (stanza) {
debug("stanza", util.inspect(stanza, true, 100));
processStanza(events, stanza, probeBuddies);
});
debug("sending", args);

conn.on('error', function (err) {
debug("error", util.inspect(err, true, 100));
events.emit('error', err);
});
if (pending) {
return pending.push(args);
}

return new SimpleXMPP(conn, events, probeBuddies);
return xmpp.Client.prototype.send.apply(connection, args);
}

module.exports = function (config) {
var events = new EventEmitter();
var probeBuddies = {};
function SimpleXMPP(params) {
EventEmitter.call(this);

return {
"on":function (event, listener) {
return events.on(event, listener);
var connection,
config = {
jid:new xmpp.JID(params.jid),
password:params.password,
host:params.host,
port:params.port
},
probeBuddies = {},
handlers = [],
pending = [],
self = this;

process.nextTick(function () {
connection = new xmpp.Client(config);
connection.on('stanza', function (stanza) {
processStanza(handlers, self, stanza, probeBuddies);
});

"removeListener":function (event, listener) {
return events.removeListener(event, listener);
},
connection.on('error', function (err) {
debug("error", util.inspect(err, true, 100));
self.emit('error', err);
});

"removeAllListeners":function (event) {
return events.removeListener(event);
},
connection.on('online', function () {
sendMessage(pending, connection, new xmpp.Presence());
self.emit('online');

"setMaxListeners":function (n) {
return events.setMaxListeners(n);
},
setInterval(function () {
sendMessage(pending, connection, new xmpp.Presence());
}, config.presenceInterval || 10000);

"connect":function () {
return connect(config, events, probeBuddies);
}
var queue = pending;
pending = undefined;

queue.forEach(function (msg) {
xmpp.Client.prototype.send.apply(connection, msg);
});
});

});
self.discoverServices = function (to, cb) {
var jid = config.jid.toString(),
disco = new xmpp.Iq('iq', {
type:'get',
to:to,
from:jid
}).c('query', { xmlns:DISCO_URL });

handlers.push({
matcher:{
from:to,
to:jid,
xmlns:DISCO_URL,
name:'query',
callback:cb
}
});

sendMessage(pending, connection, disco);

/*
var roster = new xmpp.Element('iq', {
type: 'get',
from: connection.jid.toString(),
id: 'roster_1'
}).c('query', { xmlns: 'jabber:iq:roster' });
sendMessage(pending, connection, roster);
*/
};
self.send = function (to, message) {
var stanza = new xmpp.Message({
to:to,
type:'chat'
});
stanza.c('body').t(message);

sendMessage(pending, connection, stanza);
};
self.probe = function (buddy, callback) {
probeBuddies[buddy] = true;

var stanza = new xmpp.Element('presence', {
type:'probe',
to:buddy
});
self.once('probe_' + buddy, callback);
sendMessage(pending, connection, stanza);
};
}

util.inherits(SimpleXMPP, EventEmitter);

module.exports = function (config) {
return new SimpleXMPP(config);
};
})(module);

0 comments on commit f4d7d28

Please sign in to comment.