function MongoMetrics (mongoUrl, collection) { collection = collection || 'metrics'; var mongoDatabase = qbox.create(); mongo.MongoClient.connect(mongoUrl, function(err, db) { if(err) { throw err; } mongoDatabase.db = db; mongoDatabase.start(); db.on('error', function(err) { console.error('mongodb error: ' + err.toString()); }); }); this.track = function track(name, value, source, date, callback) { if((typeof date) == 'function') { callback = date; date = null; } date = date || new Date(); var metric = { name: name, value: value, source: source, date: date.getTime(), resolution: getResolution(date) }; mongoDatabase.ready(function() { if(callback) { mongoDatabase.db.collection(collection).insert(metric, callback); } else { mongoDatabase.db.collection(collection).insert(metric, {w: 0}); } }); }; /* Aggregate metrics @param {String} name - name of the metric @param {Constant} resolution - resolution type possible values: "DAY", "HOUR", "MINUTE", "FIVE_SECS" @param {String} valueAggregator - aggregation function to be used for aggregating metric of the each source possible values: "sum", "avg", "min", "max" @param {String} sourceAggregator - aggregation function to be used for the aggregating sources(value from metricsAggregation) possible values: "sum", "avg", "min", "max" @param {Object} query - mongodb query for filtering out metrics only supports date and source only @param {Function} callback - callback function callback(err, results) */ this.aggregate = function aggregate(name, resolution, valueAggregator, sourceAggregator, query, callback) { if(typeof(query) == 'function') { callback = query; query = {}; } if(!MongoMetrics.RESOLUTION[resolution]) { return callback(new Error("invalid resolution")); } if(!MongoMetrics.AGGREGATORS[valueAggregator]) { return callback(new Error("valueAggregator is not supported")); } if(!MongoMetrics.AGGREGATORS[sourceAggregator]) { return callback(new Error("sourceAggregator is not supported")); } var filter = { name: name }; ['date', 'source'].forEach(function(field) { if(query[field]) { filter[field] = query[field]; } }); var aggreation = [ {$match: filter}, {$group: this._generateValueGrouping(resolution, valueAggregator)}, {$group: this._generateSourceGrouping(sourceAggregator)}, {$sort: {"_id.y": 1, "_id.mo": 1, "_id.d": 1, "_id.h": 1, "_id.m": 1, "_id.s": 1}} ]; mongoDatabase.ready(function() { mongoDatabase.db.collection(collection).aggregate(aggreation, callback); }); }; this._generateValueGrouping = function _generateValueGrouping(resolution, aggregator) { var _id = { date: { y: "$resolution.y", mo: "$resolution.mo" }, source: "$source" }; var value = {}; value["$" + aggregator] = "$value"; switch(resolution) { case "five_secs": _id.date['s5'] = "$resolution.s5" case "minute": _id.date['m'] = "$resolution.m" case "hour": _id.date['h'] = "$resolution.h" case "day": _id.date['d'] = "$resolution.d"; } return { _id: _id, value: value }; }; this._generateSourceGrouping = function _generateSourceGrouping(aggregator) { var value = {}; value['$' + aggregator] = "$value"; return { _id: "$_id.date", value: value }; }; }
function LoLXMPP() { //Settings var conn; var events; var self = this; var $ = qbox.create(); var internalEvents = new EventEmitter(); self.events = new EventEmitter(); //LoL XMPP Settings; var username; var password_prefix = 'AIR_'; var resource = 'xiff'; var domain = 'pvp.net'; var port = 5223; var legacySSL = true; //Sending presence self.setPresence = function (show, status) { //TODO Add set Presence }; self.getRoster = function () { $.ready(function () { var roster = new xmpp.Element('iq', { id: 'roster_0', type: 'get' }); roster.c('query', { xmlns: 'jabber:iq:roster' }); conn.send(roster); }); }; self.connect = function (username, password, server) { conn = new xmpp.Client({ jid: username + '@' + domain + '/' + resource, password: password_prefix + password, host: server, port: port, legacySSL: legacySSL }); self.conn = conn; self.username = username; conn.on('close', function () { $.stop(); internalEvents.emit('close'); }); conn.on('error', function (err) { internalEvents.emit('error', err); }); conn.on('online', function (data) { console.log(xmpp.Element); console.log(data); conn.send(new xmpp.Element('presence')); internalEvents.emit('online', data); $.start(); // keepalive if (self.conn.connection.socket) { self.conn.connection.socket.setTimeout(0); self.conn.connection.socket.setKeepAlive(true, 10000); } self.getRoster(); }); conn.on('stanza', function (stanza) { if (stanza.is('presence')) { var onlineofflinehandle = function onlineofflinehandle() { var friendname = allFriends[stanza.attrs.from.split('/')[0]]; var toSplit = stanza.attrs.from.split('/'); var friend = toSplit[0]; if (stanza.attrs.type && stanza.attrs.type === 'unavailable') { //If we get a logoff message, remove them from online list delete onlineFriends[friendname]; } else if (stanza.children.length > 0) { //otherwise add them to online friends var friendstuff = { status: stanza.children[0].children[0], body: stanza.children[1].children[0] }; var name = allFriends[friend]; var body = friendstuff.body; var info; parser(body, function (err, result) { info = (result && result.body) ? result.body : body; //TODO }); addInfo = { status: friendstuff.status, body: friendstuff.body, jid: friend } var extended = extend(info); onlineFriends[name] = extend(info, addInfo); if (name) { self.events.emit('onlineFriendsUpdate', name); } } }; if (allFriends[stanza.attrs.from.split('/')[0]]) { onlineofflinehandle(); } else { allQ[stanza.attrs.from.split('/')[0]] = onlineofflinehandle; } } else if (stanza.is('iq')) { internalEvents.emit('allFriends', stanza); for (var f in stanza.children[0].children) { allFriends[stanza.children[0].children[f].attrs.jid] = stanza.children[0].children[f].attrs.name; if (allQ[stanza.children[0].children[f].attrs.jid]) { // If the showed up online before getting the iq stanza // then finish running that computation and del it allQ[stanza.children[0].children[f].attrs.jid](); delete allQ[stanza.children[0].children[f].attrs.jid]; } } } else if (stanza.is('message')) { if (stanza.attrs.type == 'chat') { var body = stanza.getChild('body'); if (body) { var message = body.getText(); var from = stanza.attrs.from; var id = from.split('/')[0]; internalEvents.emit('receiveMessage', id, message); } } } }); }; self.getAllFriends = function () { return allFriends; } // to is the name we are sending to, message is the string to send. self.sendMessage = function (to, message) { // Use a regex so you can match mismatched cases. // in the client xxx == xXx === XXX var to_name = new RegExp(to, 'i'); $.ready(function () { var jid = (function () { var key; for (key in onlineFriends) { if (key.match(to_name)) { return onlineFriends[key].jid; } } return undefined; })(); if (!jid) { return; } jid += '/xiff'; var stanza = new xmpp.Element('message', { to: jid, type: 'chat' }); stanza.c('body').t(message); self.conn.send(stanza); }); }; internalEvents.on('receiveMessage', function (from, message) { var friendName = allFriends[from]; self.events.emit('incomingMessage', friendName, message); }); }
function SimpleXMPP() { //setting status here this.STATUS = STATUS; var self = this; this.Element = xmpp.Element; var config; var conn; var probeBuddies = {}; var capabilities = {}; var capBuddies = {}; var iqCallbacks = {}; var $ = qbox.create(); var events = new EventEmitter(); this.on = function() { events.on.apply(events, Array.prototype.slice.call(arguments)); }; this.removeListener = function() { events.removeListener.apply(events, Array.prototype.slice.call(arguments)); }; this.events = events; this.conn = conn; this.send = function(to, message, group) { $.ready(function() { var stanza = new xmpp.Element('message', { to: to, type: (group ? 'groupchat' : 'chat') }); stanza.c('body').t(message); conn.send(stanza); }); }; this.join = function(to) { $.ready(function() { var stanza = new xmpp.Element('presence', { to: to }). c('x', { xmlns: 'http://jabber.org/protocol/muc' }); conn.send(stanza); }); }; this.subscribe = function(to) { $.ready(function() { var stanza = new xmpp.Element('presence', { to: to, type: 'subscribe' }); conn.send(stanza); }); }; this.unsubscribe = function(to) { $.ready(function() { var stanza = new xmpp.Element('presence', { to: to, type: 'unsubscribe' }); conn.send(stanza); }); }; this.acceptSubscription = function(to) { // Send a 'subscribed' notification back to accept the incoming // subscription request $.ready(function() { var stanza = new xmpp.Element('presence', { to: to, type: 'subscribed' }); conn.send(stanza); }); }; this.acceptUnsubscription = function(to) { $.ready(function() { var stanza = new xmpp.Element('presence', { to: to, type: 'unsubscribed' }); conn.send(stanza); }); }; this.getRoster = function() { $.ready(function() { var roster = new xmpp.Element('iq', { id: 'roster_0', type: 'get' }); roster.c('query', { xmlns: 'jabber:iq:roster' }); conn.send(roster); }); }; this.probe = function(buddy, callback) { probeBuddies[buddy] = true; $.ready(function() { var stanza = new xmpp.Element('presence', {type: 'probe', to: buddy}); events.once('probe_' + buddy, callback); conn.send(stanza); }); }; function parseVCard(vcard) { return vcard.children.reduce(function(jcard, child) { jcard[child.name.toLowerCase()] = ( (typeof(child.children[0]) === 'object') ? parseVCard(child) : child.children.join('') ); return jcard; }, {}); } this.getVCard = function(buddy, callback) { $.ready(function() { var id = 'get-vcard-' + buddy.split('@').join('--'); var stanza = new xmpp.Element('iq', { type: 'get', id: id }). c('vCard', { xmlns: 'vcard-temp' }). up(); iqCallbacks[id] = function(response) { if(response.attrs.type === 'error') { callback(null); } else { callback(parseVCard(response.children[0])); } }; conn.send(stanza); }); }; // Method: setPresence // // Change presence appearance and set status message. // // Parameters: // show - <show/> value to send. Valid values are: ['away', 'chat', 'dnd', 'xa']. // See http://xmpp.org/rfcs/rfc3921.html#rfc.section.2.2.2.1 for details. // Pass anything that evaluates to 'false' to skip sending the <show/> element. // status - (optional) status string. This is free text. // // TODO: // * add caps support this.setPresence = function(show, status) { $.ready(function() { var stanza = new xmpp.Element('presence'); if(show && show !== STATUS.ONLINE) { stanza.c('show').t(show); } if(typeof(status) !== 'undefined') { stanza.c('status').t(status); } conn.send(stanza); }); }; // Method: setChatstate // // Send current chatstate to the given recipient. Chatstates are defined in // <XEP-0085 at http://xmpp.org/extensions/xep-0085.html>. // // Parameters: // to - JID to send the chatstate to // state - State to publish. One of: active, composing, paused, inactive, gone // // See XEP-0085 for details on the meaning of those states. this.setChatstate = function(to, state) { $.ready(function() { var stanza = new xmpp.Element('message', { to: to }). c(state, { xmlns: NS_CHATSTATES }). up(); conn.send(stanza); }); }; // TODO: document! // // Options: // * skipPresence - don't send initial empty <presence/> when connecting // this.disconnect = function() { $.ready(function() { var stanza = new xmpp.Element('presence', { type: 'unavailable' }); stanza.c('status').t('Logged out'); conn.send(stanza); }); var ref = this.conn.connection; if (ref.socket.writable) { if (ref.streamOpened) { ref.socket.write('</stream:stream>'); delete ref.streamOpened; } else { ref.socket.end(); } } }; this.connect = function(params) { config = params; conn = new xmpp.Client(params); self.conn = conn; conn.on('close', function() { $.stop(); events.emit('close'); }); conn.on('online', function(){ if(! config.skipPresence) { conn.send(new xmpp.Element('presence')); } events.emit('online'); $.start(); // keepalive self.conn.connection.socket.setTimeout(0); self.conn.connection.socket.setKeepAlive(true, 10000); }); conn.on('stanza', function(stanza) { events.emit('stanza', stanza); //console.log(stanza); //looking for message stanza if (stanza.is('message')) { //getting the chat message if(stanza.attrs.type == 'chat') { var body = stanza.getChild('body'); if(body) { var message = body.getText(); var from = stanza.attrs.from; var id = from.split('/')[0]; events.emit('chat', id, message); } var chatstate = stanza.getChildByAttr('xmlns', NS_CHATSTATES); if(chatstate) { // Event: chatstate // // Emitted when an incoming <message/> with a chatstate notification // is received. // // Event handler parameters: // jid - the JID this chatstate noticiation originates from // state - new chatstate we're being notified about. // // See <SimpleXMPP#setChatstate> for details on chatstates. // events.emit('chatstate', stanza.attrs.from, chatstate.name); } } else if(stanza.attrs.type == 'groupchat') { var body = stanza.getChild('body'); if(body) { var message = body.getText(); var from = stanza.attrs.from; var conference = from.split('/')[0]; var id = from.split('/')[1]; var stamp = null; if(stanza.getChild('x') && stanza.getChild('x').attrs.stamp) stamp = stanza.getChild('x').attrs.stamp; events.emit('groupchat', conference, id, message, stamp); } } } else if(stanza.is('presence')) { var from = stanza.attrs.from; if(from) { if(stanza.attrs.type == 'subscribe') { //handling incoming subscription requests events.emit('subscribe', from); } else if(stanza.attrs.type == 'unsubscribe') { //handling incoming unsubscription requests events.emit('unsubscribe', from); } else { //looking for presence stenza for availability changes var id = from.split('/')[0]; var statusText = stanza.getChildText('status'); var state = (stanza.getChild('show'))? stanza.getChild('show').getText(): STATUS.ONLINE; state = (state == 'chat')? STATUS.ONLINE : state; state = (stanza.attrs.type == 'unavailable')? STATUS.OFFLINE : state; //checking if this is based on probe if(probeBuddies[id]) { events.emit('probe_' + id, state, statusText); delete probeBuddies[id]; } else { //specifying roster changes events.emit('buddy', id, state, statusText); } // Check if capabilities are provided var caps = stanza.getChild('c', 'http://jabber.org/protocol/caps'); if (caps) { var node = caps.attrs.node, ver = caps.attrs.ver; if (ver) { var fullNode = node + '#' + ver; // Check if it's already been cached if (capabilities[fullNode]) { events.emit('buddyCapabilities', id, capabilities[fullNode]); } else { // Save this buddy so we can send the capability data when it arrives if (!capBuddies[fullNode]) { capBuddies[fullNode] = []; } capBuddies[fullNode].push(id); var getCaps = new xmpp.Element('iq', { id: 'disco1', to: from, type: 'get' }); getCaps.c('query', { xmlns: 'http://jabber.org/protocol/disco#info', node: fullNode }); conn.send(getCaps); } } } } } } else if (stanza.is('iq')) { // Response to capabilities request? if (stanza.attrs.id === 'disco1') { var query = stanza.getChild('query', 'http://jabber.org/protocol/disco#info'); // Ignore it if there's no <query> element - Not much we can do in this case! if (!query) { return; } var node = query.attrs.node, identity = query.getChild('identity'), features = query.getChildren('feature'); var result = { clientName: identity && identity.attrs.name, features: features.map(function (feature) { return feature.attrs['var']; }) }; capabilities[node] = result; // Send it to all buddies that were waiting if (capBuddies[node]) { capBuddies[node].forEach(function (id) { events.emit('buddyCapabilities', id, result); }); delete capBuddies[node]; } } var cb = iqCallbacks[stanza.attrs.id]; if(cb) { cb(stanza); delete iqCallbacks[stanza.attrs.id]; } } }); conn.on('error', function(err) { events.emit('error', err); }); }; }
function SimpleXMPP() { //setting status here this.STATUS = STATUS; var self = this; this.Element = xmpp.Element; var config; var conn; var probeBuddies = {}; var $ = qbox.create(); var events = new EventEmitter(); this.on = function() { events.on.apply(events, arguments); }; this.send = function(to, message) { $.ready(function() { var stanza = new xmpp.Element('message', { to: to, type: 'chat', from: conn.jid }); stanza.c('body').t(message); conn.send(stanza); }); }; this.probe = function(buddy, callback) { probeBuddies[buddy] = true; $.ready(function() { var stanza = new xmpp.Element('presence', {type: 'probe', to: buddy, from: conn.jid }); events.once('probe_' + buddy, callback); conn.send(stanza); }); }; this.connect = function(params) { config = params conn = new xmpp.Client(params); self.conn = conn; conn.on('online', function(){ conn.send(new xmpp.Element('presence')); // +JOIN conn.send(new xmpp.Element('presence', {type: 'available'}).c('show').t('chat')) var roster_query = new xmpp.Element('iq', {type: 'get', id: (new Date()).getTime()}).c('query', {xmlns: 'jabber:iq:roster'}) // conn.send(roster_query) // /+JOIN events.emit('online'); $.start(); //make the connection live setInterval(function() { // +JOIN conn.send(new xmpp.Element('presence')); // conn.send(roster_query) // /+JOIN }, 1000 * 10) }); conn.on('stanza', function(stanza) { events.emit('stanza', stanza); //console.log(stanza); //looking for message stanza if (stanza.is('message')) { //getting the chat message if(stanza.attrs.type == 'chat') { var body = stanza.getChild('body'); if(body) { var message = body.getText(); var from = stanza.attrs.from; var id = from.split('/')[0]; events.emit('chat', id, message); } } } else if(stanza.is('presence')) { //looking for presence stenza for availability changes var from = stanza.attrs.from; if(from) { var id = from.split('/')[0]; var state = (stanza.getChild('show'))? stanza.getChild('show').getText(): STATUS.ONLINE; state = (state == 'chat')? STATUS.ONLINE : state; state = (stanza.attrs.type == 'unavailable')? STATUS.OFFLINE : state; //checking if this is based on probe if(probeBuddies[id]) { events.emit('probe_' + id, state); delete probeBuddies[id]; } else { //specifying roster changes events.emit('buddy', id, state); } } if(stanza.attrs.type == 'subscribe') { console.log(stanza.attrs.from + ' subscribed to us. Subscribing in return.') conn.send(new xmpp.Element('presence', {from: stanza.attrs.to, to: stanza.attrs.from, id: stanza.attrs.id, type:'subscribed'})) } } }); conn.on('error', function(err) { events.emit('error', err); }); }; }