comparison lightstring.js @ 67:1c8f326fe3ef

Several fixes and comments updated/added.
author Sonny Piers <sonny.piers@gmail.com>
date Wed, 01 Feb 2012 22:45:48 +0100
parents 2e8fbf3bce7f
children e1ccfb580228
comparison
equal deleted inserted replaced
66:fa184759fc41 67:1c8f326fe3ef
33 * @namespace Holds XMPP stanza builders. 33 * @namespace Holds XMPP stanza builders.
34 */ 34 */
35 stanzas: { 35 stanzas: {
36 stream: { 36 stream: {
37 open: function(aService) { 37 open: function(aService) {
38 //FIXME no ending "/" - node-xmpp-bosh bug 38 //WORKAROUND: no ending "/" - node-xmpp-bosh bug
39 return "<stream:stream to='" + aService + "'" + 39 return "<stream:stream to='" + aService + "'" +
40 " xmlns='" + Lightstring.ns['jabber_client'] + "'" + 40 " xmlns='" + Lightstring.ns['jabber_client'] + "'" +
41 " xmlns:stream='" + Lightstring.ns['streams'] + "'" + 41 " xmlns:stream='" + Lightstring.ns['streams'] + "'" +
42 " version='1.0'/>"; 42 " version='1.0'/>";
43 }, 43 },
56 "</error>" + 56 "</error>" +
57 "</iq>"; 57 "</iq>";
58 } 58 }
59 } 59 }
60 }, 60 },
61 /**
62 * @namespace Holds Lightstring plugins
63 */
61 plugins: {}, 64 plugins: {},
62 /** 65 /**
63 * @private 66 * @private
64 */ 67 */
65 parser: new DOMParser(), 68 parser: new DOMParser(),
76 var DOM = null; 79 var DOM = null;
77 try { 80 try {
78 DOM = this.parser.parseFromString(aString, 'text/xml').documentElement; 81 DOM = this.parser.parseFromString(aString, 'text/xml').documentElement;
79 } 82 }
80 catch (e) { 83 catch (e) {
81 alert(e); 84 //TODO: error
82 } 85 }
83 finally { 86 finally {
84 return DOM; 87 return DOM;
85 }; 88 };
86 }, 89 },
93 var XML = null; 96 var XML = null;
94 try { 97 try {
95 XML = this.serializer.serializeToString(aElement); 98 XML = this.serializer.serializeToString(aElement);
96 } 99 }
97 catch (e) { 100 catch (e) {
98 //TODO throw error 101 //TODO: error
99 } 102 }
100 finally { 103 finally {
101 return XML; 104 return XML;
102 }; 105 };
103 }, 106 },
122 * @memberOf Lightstring 125 * @memberOf Lightstring
123 */ 126 */
124 Lightstring.Connection = function(aService) { 127 Lightstring.Connection = function(aService) {
125 if (aService) 128 if (aService)
126 this.service = aService; 129 this.service = aService;
130 /**
131 * @namespace Holds connection events handlers
132 */
127 this.handlers = {}; 133 this.handlers = {};
134 /**
135 * @namespace Holds connection iq callbacks
136 */
128 this.callbacks = {}; 137 this.callbacks = {};
129 }; 138 };
130 Lightstring.Connection.prototype = { 139 Lightstring.Connection.prototype = {
131 /** 140 /**
132 * @function Create and open a websocket then go though the XMPP authentification process. 141 * @function Create and open a websocket then go though the XMPP authentification process.
138 this.jid = new Lightstring.JID(aJid); 147 this.jid = new Lightstring.JID(aJid);
139 if (aPassword) 148 if (aPassword)
140 this.password = aPassword; 149 this.password = aPassword;
141 150
142 if (!this.jid.bare) 151 if (!this.jid.bare)
143 throw 'Lightstring: Connection.jid is undefined.'; 152 return; //TODO: error
144 if (!this.service) 153 if (!this.service)
145 throw 'Lightstring: Connection.service is undefined.'; 154 return; //TODO: error
146 155
147 if(typeof(WebSocket) === "function") { 156 if(typeof(WebSocket) === "function") {
148 this.socket = new WebSocket(this.service, 'xmpp'); 157 this.socket = new WebSocket(this.service, 'xmpp');
149 } 158 }
150 else if(typeof(MozWebSocket) === "function") { 159 else if(typeof(MozWebSocket) === "function") {
151 this.socket = new MozWebSocket(this.service, 'xmpp'); 160 this.socket = new MozWebSocket(this.service, 'xmpp');
152 } 161 }
153 else { 162 else {
154 throw new Error('WebSocket not available.'); 163 return; //TODO: error
155 } 164 }
156 165
157 var that = this; 166 var Conn = this;
158 this.socket.addEventListener('open', function() { 167 this.socket.addEventListener('open', function() {
159 //TODO: if (this.protocol !== 'xmpp') 168 if (this.protocol !== 'xmpp')
160 169 return; //TODO: error
161 var stream = Lightstring.stanzas.stream.open(that.jid.domain); 170
162 //TODO: Use Lightstring.Connection.send (problem with parsing steam); 171 var stream = Lightstring.stanzas.stream.open(Conn.jid.domain);
163 that.socket.send(stream); 172 //FIXME: Use Lightstring.Connection.send (problem with parsing steam);
173 Conn.socket.send(stream);
164 var stanza = { 174 var stanza = {
165 XML: stream 175 XML: stream
166 }; 176 };
167 that.emit('output', stanza); 177 Conn.emit('output', stanza);
168 }); 178 });
169 this.socket.addEventListener('error', function(e) { 179 this.socket.addEventListener('error', function(e) {
170 that.emit('error', e.data); 180 Conn.emit('disconnecting', e.data);
171 console.log(e.data); 181 //TODO: error
172 }); 182 });
173 this.socket.addEventListener('close', function(e) { 183 this.socket.addEventListener('close', function(e) {
174 that.emit('disconnected', e.data); 184 Conn.emit('disconnected', e.data);
175 }); 185 });
176 this.socket.addEventListener('message', function(e) { 186 this.socket.addEventListener('message', function(e) {
177 var stanza = new Lightstring.Stanza(e.data); 187 var stanza = new Lightstring.Stanza(e.data);
178 188
179 //TODO node-xmpp-bosh sends a self-closing stream:stream tag; it is wrong! 189 //FIXME: node-xmpp-bosh sends a self-closing stream:stream tag; it is wrong!
180 that.emit('input', stanza); 190 Conn.emit('input', stanza);
181 191
182 if(!stanza.DOM) 192 if(!stanza.DOM)
183 return; 193 return;
184 194
185
186 var name = stanza.DOM.localName; 195 var name = stanza.DOM.localName;
196
197 //Authentication
187 //FIXME SASL mechanisms and XMPP features can be both in a stream:features 198 //FIXME SASL mechanisms and XMPP features can be both in a stream:features
188 if (name === 'features') { 199 if (name === 'features') {
189 //SASL mechanisms 200 //SASL mechanisms
190 if (stanza.DOM.firstChild.localName === 'mechanisms') { 201 if (stanza.DOM.firstChild.localName === 'mechanisms') {
191 stanza.mechanisms = []; 202 stanza.mechanisms = [];
192 var nodes = stanza.DOM.querySelectorAll('mechanism'); 203 var nodes = stanza.DOM.querySelectorAll('mechanism');
193 for (var i = 0; i < nodes.length; i++) 204 for (var i = 0; i < nodes.length; i++)
194 stanza.mechanisms.push(nodes[i].textContent); 205 stanza.mechanisms.push(nodes[i].textContent);
195 that.emit('mechanisms', stanza); 206 Conn.emit('mechanisms', stanza);
196 } 207 }
197 //XMPP features 208 //XMPP features
198 else { 209 else {
199 //TODO: stanza.features 210 //TODO: stanza.features
200 that.emit('features', stanza); 211 Conn.emit('features', stanza);
201 } 212 }
202 } 213 }
203 else if (name === 'challenge') { 214 else if (name === 'challenge') {
204 that.emit('challenge', stanza); 215 Conn.emit('challenge', stanza);
205 }
206 else if (name === 'response') {
207
208
209 } 216 }
210 else if (name === 'failure') { 217 else if (name === 'failure') {
211 that.emit('failure', stanza); 218 Conn.emit('failure', stanza);
212 } 219 }
213 else if (name === 'success') { 220 else if (name === 'success') {
214 that.emit('success', stanza); 221 Conn.emit('success', stanza);
215 } 222 }
216 else if(name === 'stream') {
217
218
219 }
220
221
222 223
223 //Iq callbacks 224 //Iq callbacks
224 else if (name === 'iq') { 225 else if (name === 'iq') {
225 var payload = stanza.DOM.firstChild; 226 var payload = stanza.DOM.firstChild;
226 if (payload) 227 if (payload)
227 that.emit('iq/' + payload.namespaceURI + ':' + payload.localName, stanza); 228 Conn.emit('iq/' + payload.namespaceURI + ':' + payload.localName, stanza);
228 229
229 var id = stanza.DOM.getAttributeNS(null, 'id'); 230 var id = stanza.DOM.getAttributeNS(null, 'id');
230 if (!(id && id in that.callbacks)) 231 if (!(id && id in Conn.callbacks))
231 return; 232 return;
232 233
233 var type = stanza.DOM.getAttributeNS(null, 'type'); 234 var type = stanza.DOM.getAttributeNS(null, 'type');
234 if (type !== 'result' && type !== 'error') 235 if (type !== 'result' && type !== 'error')
235 return; //TODO: emit an warning, perhaps. 236 return; //TODO: warning
236 237
237 var callback = that.callbacks[id]; 238 var callback = Conn.callbacks[id];
238 if (type === 'result' && callback.success) 239 if (type === 'result' && callback.success)
239 callback.success(stanza); 240 callback.success(stanza);
240 else if (type === 'error' && callback.error) 241 else if (type === 'error' && callback.error)
241 callback.error(stanza); 242 callback.error(stanza);
242 243
243 delete that.callbacks[id]; 244 delete Conn.callbacks[id];
244 } 245 }
245 }); 246 });
246 }, 247 },
247 /** 248 /**
248 * @function Send a message. 249 * @function Send a message.
259 return; 260 return;
260 261
261 if (stanza.DOM.tagName === 'iq') { 262 if (stanza.DOM.tagName === 'iq') {
262 var type = stanza.DOM.getAttributeNS(null, 'type'); 263 var type = stanza.DOM.getAttributeNS(null, 'type');
263 if (type !== 'get' || type !== 'set') 264 if (type !== 'get' || type !== 'set')
264 ; //TODO: emit an error. 265 ; //TODO: error
265 266
266 var callback = {success: aSuccess, error: aError}; 267 var callback = {success: aSuccess, error: aError};
267 268
268 var id = stanza.DOM.getAttributeNS(null, 'id'); 269 var id = stanza.DOM.getAttributeNS(null, 'id');
269 if (!id) 270 if (!id)
270 ; //TODO: emit an warning. 271 ; //TODO: warning
271 else 272 else
272 this.callbacks[id] = callback; 273 this.callbacks[id] = callback;
273 274
274 } else if (aSuccess || aError) 275 } else if (aSuccess || aError)
275 ; //TODO: callback can’t be called with non-iq stanza. 276 ; //TODO: warning (no callback without iq)
276 277
277 278
278 //TODO this.socket.send(stanza.XML); (need some work on Lightstring.Stanza) 279 //FIXME this.socket.send(stanza.XML); (need some work on Lightstring.Stanza)
279 var fixme = Lightstring.DOM2XML(stanza.DOM); 280 var fixme = Lightstring.DOM2XML(stanza.DOM);
280 stanza.XML = fixme; 281 stanza.XML = fixme;
281 this.socket.send(fixme); 282 this.socket.send(fixme);
282 this.emit('output', stanza); 283 this.emit('output', stanza);
283 }, 284 },
293 }, 294 },
294 load: function() { 295 load: function() {
295 for (var i = 0; i < arguments.length; i++) { 296 for (var i = 0; i < arguments.length; i++) {
296 var name = arguments[i]; 297 var name = arguments[i];
297 if (!(name in Lightstring.plugins)) 298 if (!(name in Lightstring.plugins))
298 continue; //TODO: throw an error? 299 continue; //TODO: error
299 300
300 var plugin = Lightstring.plugins[name]; 301 var plugin = Lightstring.plugins[name];
301 302
302 //Namespaces 303 //Namespaces
303 for (var ns in plugin.namespaces) 304 for (var ns in plugin.namespaces)
340 341
341 var ret; 342 var ret;
342 for (var i = 0; i < handlers.length; i++) { 343 for (var i = 0; i < handlers.length; i++) {
343 ret = handlers[i].call(this, aData); 344 ret = handlers[i].call(this, aData);
344 if (typeof ret !== 'boolean') 345 if (typeof ret !== 'boolean')
345 return; //TODO: emit a big error! 346 return; //TODO: error
346 347
347 if (ret) 348 if (ret)
348 return; 349 return;
349 } 350 }
350 351