comparison lightstring.js @ 17:b7bd814333eb

Move methods to the prototype.
author Sonny Piers <sonny.piers@gmail.com>
date Sun, 22 Jan 2012 12:58:45 +0100
parents 6707f450549e
children 48bc65a0e0f1
comparison
equal deleted inserted replaced
16:6707f450549e 17:b7bd814333eb
83 this.iqid = 1024; 83 this.iqid = 1024;
84 this.getNewId = function() { 84 this.getNewId = function() {
85 this.iqid++; 85 this.iqid++;
86 return 'sendiq:' + this.iqid; 86 return 'sendiq:' + this.iqid;
87 }; 87 };
88 /**
89 * @function Create and open a websocket then go though the XMPP authentification process.
90 * @param {String} [aJid] The JID (Jabber id) to use.
91 * @param {String} [aPassword] The associated password.
92 */
93 this.connect = function(aJid, aPassword) {
94 this.emit('connecting');
95 if (aJid)
96 this.jid = aJid;
97 if (this.jid) {
98 this.host = this.jid.split('@')[1];
99 this.node = this.jid.split('@')[0];
100 this.resource = this.jid.split('/')[1];
101 }
102 if (aPassword)
103 this.password = aPassword;
104
105 if (!this.jid)
106 throw 'Lightstring: Connection.jid is undefined.';
107 if (!this.password)
108 throw 'Lightstring: Connection.password is undefined.';
109 if (!this.service)
110 throw 'Lightstring: Connection.service is undefined.';
111
112 //"Bug 695635 - tracking bug: unprefix WebSockets" https://bugzil.la/695635
113 try {
114 this.socket = new WebSocket(this.service, 'xmpp');
115 }
116 catch (error) {
117 this.socket = new MozWebSocket(this.service, 'xmpp');
118 }
119
120 var that = this;
121 this.socket.addEventListener('open', function() {
122 if (this.protocol !== 'xmpp')
123 console.error('Lightstring: The server located at '+ that.service + ' doesn\'t seems to be XMPP aware.');
124
125 var stream = Lightstring.stanza.stream.open(that.host);
126
127 that.socket.send(stream);
128 that.emit('XMLOutput', stream);
129 });
130 this.socket.addEventListener('error', function(e) {
131 that.emit('error', e.data);
132 console.log(e.data);
133 });
134 this.socket.addEventListener('close', function(e) {
135 that.emit('disconnected', e.data);
136 });
137 this.socket.addEventListener('message', function(e) {
138 that.emit('XMLInput', e.data);
139 var elm = Lightstring.xml2dom(e.data);
140 that.emit('DOMInput', elm);
141 that.emit(elm.tagName, elm);
142
143 if (elm.tagName === 'iq')
144 that.emit(elm.getAttribute('id'), elm);
145 });
146 };
147 /**
148 * @function Send a message.
149 * @param {String|Object} aStanza The message to send.
150 * @param {Function} [aCallback] Executed on answer. (stanza must be iq)
151 */
152 this.send = function(aStanza, aCallback) {
153 if (typeof aStanza === 'string') {
154 var str = aStanza;
155 var elm = Lightstring.xml2dom(str);
156 }
157 else if (aStanza instanceof Element) {
158 var elm = aStanza;
159 var str = this.dom2xml(elm);
160 }
161 else {
162 this.emit('error', 'Unsupported data type.');
163 return;
164 }
165
166
167 if (elm.tagName === 'iq') {
168 var id = elm.getAttribute('id');
169 if (!id) {
170 elm.setAttribute('id', this.getNewId());
171 str = Lightstring.dom2xml(elm);
172 }
173 if (aCallback)
174 this.on(elm.getAttribute('id'), aCallback);
175 }
176 else if (aCallback) {
177 this.emit('warning', 'Callback can\'t be called with non-iq stanza.');
178 }
179
180
181 this.socket.send(str);
182 this.emit('XMLOutput', str);
183 this.emit('DOMOutput', elm);
184 };
185 /**
186 * @function Closes the XMPP stream and the socket.
187 */
188 this.disconnect = function() {
189 this.emit('disconnecting');
190 var stream = Lighstring.stanza.stream.close();
191 this.send(stream);
192 that.emit('XMLOutput', stream);
193 this.socket.close();
194 };
195 /**
196 * @function Emits an event.
197 * @param {String} aName The event name.
198 * @param {Function|Array|Object} [aData] Data about the event.
199 */
200 this.emit = function(aName, aData) {
201 var handlers = this.handlers[aName];
202 if (!handlers)
203 return;
204
205 //FIXME Better idea than passing the context as argument?
206 for (var i = 0; i < handlers.length; i++)
207 handlers[i](aData, this);
208
209 if (aName.match('sendiq:'))
210 delete this.handlers[aName];
211 };
212 /**
213 * @function Register an event handler.
214 * @param {String} aName The event name.
215 * @param {Function} aCallback The callback to call when the event is emitted.
216 */
217 this.on = function(aName, callback) {
218 if (!this.handlers[aName])
219 this.handlers[aName] = [];
220 this.handlers[aName].push(callback);
221 };
222 //FIXME do this!
223 //~ this.once = function(name, callback) {
224 //~ if(!this.handlers[name])
225 //~ this.handlers[name] = [];
226 //~ this.handlers[name].push(callback);
227 //~ };
228 this.on('stream:features', function(stanza, that) { 88 this.on('stream:features', function(stanza, that) {
229 var nodes = stanza.querySelectorAll('mechanism'); 89 var nodes = stanza.querySelectorAll('mechanism');
230 //SASL/Auth features 90 //SASL/Auth features
231 if (nodes.length > 0) { 91 if (nodes.length > 0) {
232 that.emit('mechanisms', stanza); 92 that.emit('mechanisms', stanza);
352 "<response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>" 212 "<response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>"
353 + btoa(responseText) + 213 + btoa(responseText) +
354 '</response>'); 214 '</response>');
355 }); 215 });
356 }; 216 };
217 Lightstring.Connection.prototype = {
218 /**
219 * @function Create and open a websocket then go though the XMPP authentification process.
220 * @param {String} [aJid] The JID (Jabber id) to use.
221 * @param {String} [aPassword] The associated password.
222 */
223 connect: function(aJid, aPassword) {
224 this.emit('connecting');
225 if (aJid)
226 this.jid = aJid;
227 if (this.jid) {
228 this.host = this.jid.split('@')[1];
229 this.node = this.jid.split('@')[0];
230 this.resource = this.jid.split('/')[1];
231 }
232 if (aPassword)
233 this.password = aPassword;
234
235 if (!this.jid)
236 throw 'Lightstring: Connection.jid is undefined.';
237 if (!this.password)
238 throw 'Lightstring: Connection.password is undefined.';
239 if (!this.service)
240 throw 'Lightstring: Connection.service is undefined.';
241
242 //"Bug 695635 - tracking bug: unprefix WebSockets" https://bugzil.la/695635
243 try {
244 this.socket = new WebSocket(this.service, 'xmpp');
245 }
246 catch (error) {
247 this.socket = new MozWebSocket(this.service, 'xmpp');
248 }
249
250 var that = this;
251 this.socket.addEventListener('open', function() {
252 if (this.protocol !== 'xmpp')
253 console.error('Lightstring: The server located at '+ that.service + ' doesn\'t seems to be XMPP aware.');
254
255 var stream = Lightstring.stanza.stream.open(that.host);
256
257 that.socket.send(stream);
258 that.emit('XMLOutput', stream);
259 });
260 this.socket.addEventListener('error', function(e) {
261 that.emit('error', e.data);
262 console.log(e.data);
263 });
264 this.socket.addEventListener('close', function(e) {
265 that.emit('disconnected', e.data);
266 });
267 this.socket.addEventListener('message', function(e) {
268 that.emit('XMLInput', e.data);
269 var elm = Lightstring.xml2dom(e.data);
270 that.emit('DOMInput', elm);
271 that.emit(elm.tagName, elm);
272
273 if (elm.tagName === 'iq')
274 that.emit(elm.getAttribute('id'), elm);
275 });
276 },
277 /**
278 * @function Send a message.
279 * @param {String|Object} aStanza The message to send.
280 * @param {Function} [aCallback] Executed on answer. (stanza must be iq)
281 */
282 send: function(aStanza, aCallback) {
283 if (typeof aStanza === 'string') {
284 var str = aStanza;
285 var elm = Lightstring.xml2dom(str);
286 }
287 else if (aStanza instanceof Element) {
288 var elm = aStanza;
289 var str = this.dom2xml(elm);
290 }
291 else {
292 this.emit('error', 'Unsupported data type.');
293 return;
294 }
295
296
297 if (elm.tagName === 'iq') {
298 var id = elm.getAttribute('id');
299 if (!id) {
300 elm.setAttribute('id', this.getNewId());
301 str = Lightstring.dom2xml(elm);
302 }
303 if (aCallback)
304 this.on(elm.getAttribute('id'), aCallback);
305 }
306 else if (aCallback) {
307 this.emit('warning', 'Callback can\'t be called with non-iq stanza.');
308 }
309
310
311 this.socket.send(str);
312 this.emit('XMLOutput', str);
313 this.emit('DOMOutput', elm);
314 },
315 /**
316 * @function Closes the XMPP stream and the socket.
317 */
318 disconnect: function() {
319 this.emit('disconnecting');
320 var stream = Lightstring.stanza.stream.close();
321 this.send(stream);
322 this.emit('XMLOutput', stream);
323 this.socket.close();
324 },
325 /**
326 * @function Emits an event.
327 * @param {String} aName The event name.
328 * @param {Function|Array|Object} [aData] Data about the event.
329 */
330 emit: function(aName, aData) {
331 var handlers = this.handlers[aName];
332 if (!handlers)
333 return;
334
335 //FIXME Better idea than passing the context as argument?
336 for (var i = 0; i < handlers.length; i++)
337 handlers[i](aData, this);
338
339 if (aName.match('sendiq:'))
340 delete this.handlers[aName];
341 },
342 /**
343 * @function Register an event handler.
344 * @param {String} aName The event name.
345 * @param {Function} aCallback The callback to call when the event is emitted.
346 */
347 on: function(aName, callback) {
348 if (!this.handlers[aName])
349 this.handlers[aName] = [];
350 this.handlers[aName].push(callback);
351 }
352 //FIXME do this!
353 //~ this.once = function(name, callback) {
354 //~ if(!this.handlers[name])
355 //~ this.handlers[name] = [];
356 //~ this.handlers[name].push(callback);
357 //~ };
358 };