1 Xmpp4Js.Lang.namespace( "Xmpp4Js.Roster" ); 2 3 /** 4 * @constructor 5 */ 6 Xmpp4Js.Roster.PresenceManager = function() { 7 /** 8 * Map by jid => resource 9 */ 10 this.map = {}; 11 /** 12 * Map by jid 13 */ 14 this.best = {}; 15 16 this.getBestImpl = new Xmpp4Js.Roster.PresenceManager.GetBestImpl(); 17 18 this.addEvents({ 19 update: true 20 }); 21 22 } 23 24 Xmpp4Js.Roster.PresenceManager.prototype = { 25 26 /** 27 * Set presence based on jid and resource, and clear best presence cache. 28 * 29 * @param {Xmpp4Js.Packet.Presence} newPresence 30 */ 31 update: function(newPresence) { 32 var jid = newPresence.getFromJid().withoutResource().toString(); 33 var resource = newPresence.getFromJid().getResource(); 34 35 var type = newPresence.getType(); 36 37 if(type != "available" && type != "unavailable") { 38 throw new Error("Invalid prsence type: " + type); 39 } 40 41 // If a map entry for JID doesn't exist, create it. 42 if(this.map[jid]==undefined) { this.map[jid] = {}; } 43 44 // update the new presence 45 this.map[jid][resource] = newPresence; 46 47 // fire the update event. 48 this.fireEvent( "update", newPresence ); 49 50 delete this.best[jid]; 51 }, 52 /** 53 * Get the presnce of a JID with a specific resource. Calls 54 * getBest is resource is null. 55 * 56 * @return Xmpp4Js.Packet.Presence 57 */ 58 get: function( jid, resource) { 59 if( !resource ) { 60 // find "best" 61 return this.getBest(jid); 62 } 63 64 return this.map[jid] ? this.map[jid][resource] : undefined; 65 66 }, 67 /** 68 * Finds the presence with the "best" presence based on the algorithm 69 * implementation. In the future, it will be swappable. For now, 70 * see it. 71 * 72 * @param {String} jid 73 * @return Xmpp4Js.Packet.Presence 74 */ 75 getBest: function( jid ) { 76 var presenceList = this.map[jid]; 77 78 this.best[jid] = this.getBestImpl.getBest( presenceList ); 79 return this.best[jid]; 80 }, 81 82 /** 83 * Remove a jid/resource combo. If resource is empty, all resources are removed. 84 * @param {String} jid 85 * @param {String} resource 86 */ 87 remove: function(jid, resource) { 88 if( this.map[jid] == undefined ) { return; } 89 90 // remove all resources if none is specified 91 if( !resource ) { 92 for( var k in this.map[jid]) { 93 var mapResource = this.map[jid][k]; 94 this.remove( jid, mapResource); 95 } 96 delete this.map[jid]; 97 } else { 98 if( this.map[jid][resource] == undefined ) { return; } 99 100 this.fireEvent( "remove", this.map[jid][resource] ); 101 delete this.map[jid][resource]; 102 } 103 }, 104 /** 105 * Listen to presence packets 106 * @param {Packet} packet 107 * 108 * TODO ability to gracefully handle non-presence packets 109 */ 110 presencePacketListener: function ( packet ) { 111 112 try { 113 this.update( packet ); 114 } catch(e) { 115 // a presence type that we don't care about (subscribe, unsubscribe, etc) 116 } 117 } 118 } 119 120 Xmpp4Js.Lang.extend(Xmpp4Js.Roster.PresenceManager, Xmpp4Js.Event.EventProvider, Xmpp4Js.Roster.PresenceManager.prototype); 121 122 123 124 /** 125 * @constructor 126 */ 127 Xmpp4Js.Roster.PresenceManager.GetBestImpl = function() { 128 129 } 130 131 Xmpp4Js.Roster.PresenceManager.GetBestImpl.prototype = { 132 133 SHOW_WEIGHT: { 134 chat: 6, 135 normal: 5, 136 away: 4, 137 xa: 3, 138 dnd: 2 // always higher than unavailable 139 }, 140 TYPE_WEIGHT: { 141 available: 5, 142 unavailable: 1 143 }, 144 145 /** 146 * Finds the presence with the "best" presence based on availability followed by 147 * show followed by priority. Sets cache. 148 * 149 * @param {String} jid 150 * @return Xmpp4Js.Packet.Presence 151 */ 152 getBest: function( presenceList ) { 153 var bestPresence = undefined; 154 var bestWeight = 0; 155 156 for(var k in presenceList) { 157 var presence = presenceList[k]; 158 159 // these return default values if empty. 160 var show = presence.getShow(); 161 var type = presence.getType(); 162 var priority = presence.getPriority(); 163 164 // calculate the weight of the presence for getBest 165 var weight = this.SHOW_WEIGHT[show] * this.TYPE_WEIGHT[type] * priority; 166 167 //console.info( [show, type, priority]); 168 //console.info( weight+" > "+bestWeight+"="+(weight > bestWeight) ); 169 170 // use the weight determined in .update() 171 if( bestPresence == null || weight > bestWeight ) { 172 bestPresence = presence; 173 bestWeight = weight; 174 } 175 }; 176 177 return bestPresence; 178 } 179 } 180