Mercurial > eldonilo > lightstring
annotate lightstring.js @ 108:5cb4733c5189
many api changes
author | Sonny Piers <sonny@fastmail.net> |
---|---|
date | Fri, 13 Jul 2012 15:26:18 +0200 |
parents | c06ec02217ee |
children |
rev | line source |
---|---|
1
96087680669f
Delete base64.js since I don't care about IE support for the moment.
Sonny Piers <sonny.piers@gmail.com>
parents:
diff
changeset
|
1 'use strict'; |
96087680669f
Delete base64.js since I don't care about IE support for the moment.
Sonny Piers <sonny.piers@gmail.com>
parents:
diff
changeset
|
2 |
2 | 3 /** |
4 Copyright (c) 2011, Sonny Piers <sonny at fastmail dot net> | |
5 | |
6 Permission to use, copy, modify, and/or distribute this software for any | |
7 purpose with or without fee is hereby granted, provided that the above | |
8 copyright notice and this permission notice appear in all copies. | |
9 | |
10 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
11 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
12 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
13 ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
17 */ | |
18 | |
108 | 19 (function() { |
20 define(['./jid', './stanza', './transports/websocket.js', './transports/bosh.js'], function(JID, Stanza, WebSocketTransport, BOSHTransport) { | |
21 Lightstring.JID = JID; | |
22 Lightstring.Stanza = Stanza.stanza; | |
23 Lightstring.IQ = Stanza.iq; | |
24 Lightstring.doc = Stanza.doc; | |
25 Lightstring.Presence = Stanza.presence; | |
26 Lightstring.Message = Stanza.message; | |
27 Lightstring.BOSHTransport = BOSHTransport; | |
28 Lightstring.WebSocketTransport = WebSocketTransport; | |
29 return Lightstring; | |
30 }); | |
12
9fbd0e3678b5
add comments, jsdoc syntax + move the parser and the serializer to the Lightstring namespace so they don't get recreated at every new Lightstring.Connection
Sonny Piers <sonny.piers@gmail.com>
parents:
9
diff
changeset
|
31 |
108 | 32 var Lightstring = { |
33 /* | |
34 * @namespace Holds XMPP namespaces. | |
35 * @description http://xmpp.org/xmpp-protocols/protocol-namespaces | |
36 */ | |
37 ns: { | |
38 streams: 'http://etherx.jabber.org/streams', | |
39 jabber_client: 'jabber:client', | |
40 xmpp_stanzas: 'urn:ietf:params:xml:ns:xmpp-stanzas' | |
41 }, | |
42 /** | |
43 * @namespace Holds XMPP stanza builders. | |
44 */ | |
45 stanzas: { | |
46 stream: { | |
47 open: function(aService) { | |
48 return "<stream:stream to='" + aService + "'" + | |
49 " xmlns='" + Lightstring.ns['jabber_client'] + "'" + | |
50 " xmlns:stream='" + Lightstring.ns['streams'] + "'" + | |
51 " version='1.0'>"; | |
52 }, | |
53 close: function() { | |
54 return "</stream:stream>"; | |
55 } | |
13
9aeb0750b9d1
fix an error with the stream builder
Sonny Piers <sonny.piers@gmail.com>
parents:
12
diff
changeset
|
56 }, |
108 | 57 errors: { |
58 iq: function(from, id, type, error) { | |
59 return "<iq to='" + from + "'" + | |
60 " id='" + id + "'" + | |
61 " type='error'>" + | |
62 "<error type='" + type + "'>" + | |
63 "<" + error + " xmlns='" + Lightstring.ns['xmpp_stanzas'] + "'/>" + //TODO: allow text content. | |
64 //TODO: allow text and payload. | |
65 "</error>" + | |
66 "</iq>"; | |
67 } | |
13
9aeb0750b9d1
fix an error with the stream builder
Sonny Piers <sonny.piers@gmail.com>
parents:
12
diff
changeset
|
68 } |
62
b1e75cdbb0ad
Don’t allow more than one iq handler to respond, and respond with an service-unavailable when not handled.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
60
diff
changeset
|
69 }, |
108 | 70 /** |
71 * @namespace Holds Lightstring plugins | |
72 */ | |
73 plugins: {}, | |
74 /** | |
75 * @private Holds the connections | |
76 */ | |
77 connections: [], | |
78 /** | |
79 * @function Returns a new unique identifier. | |
80 * @param {String} [aPrefix] Prefix to put before the identifier. | |
81 * @return {String} Identifier. | |
82 */ | |
83 id: function(aPrefix) { | |
84 return (aPrefix || '') + Date.now(); | |
13
9aeb0750b9d1
fix an error with the stream builder
Sonny Piers <sonny.piers@gmail.com>
parents:
12
diff
changeset
|
85 } |
108 | 86 }; |
87 | |
12
9fbd0e3678b5
add comments, jsdoc syntax + move the parser and the serializer to the Lightstring namespace so they don't get recreated at every new Lightstring.Connection
Sonny Piers <sonny.piers@gmail.com>
parents:
9
diff
changeset
|
88 /** |
108 | 89 * @constructor Creates a new Lightstring connection |
90 * @param {String} [aService] The connection manager URL. | |
91 * @memberOf Lightstring | |
33
88d24231bf24
Better newId function.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
28
diff
changeset
|
92 */ |
108 | 93 Lightstring.Connection = function(aService) { |
94 if (aService) | |
95 this.service = aService; | |
96 /** | |
97 * @namespace Holds connection events handlers | |
98 */ | |
99 this.handlers = {}; | |
100 /** | |
101 * @namespace Holds connection iq callbacks | |
102 */ | |
103 this.callbacks = {}; | |
104 | |
105 Lightstring.connections.push(this); | |
106 }; | |
107 Lightstring.Connection.prototype = new EventEmitter(); | |
108 Lightstring.Connection.prototype.onTransportLoaded = function() { | |
109 this.transport.open(); | |
110 | |
111 var that = this; | |
112 | |
113 this.transport.once('open', function() { | |
114 that.emit('open'); | |
115 }); | |
116 this.transport.on('out', function(stanza) { | |
117 setTimeout(function() { | |
118 that.emit('out', stanza); | |
119 }, 0); | |
120 }); | |
121 this.transport.on('in', function(stanza) { | |
122 //FIXME: node-xmpp-bosh sends a self-closing stream:stream tag; it is wrong! | |
123 that.emit('stanza', stanza); | |
124 | |
125 if (!stanza.el) | |
126 return; | |
127 | |
128 var el = stanza.el; | |
1
96087680669f
Delete base64.js since I don't care about IE support for the moment.
Sonny Piers <sonny.piers@gmail.com>
parents:
diff
changeset
|
129 |
108 | 130 //Authentication |
131 //FIXME SASL mechanisms and XMPP features can be both in a stream:features | |
132 if (el.localName === 'features') { | |
133 var children = el.childNodes; | |
134 for (var i = 0, length = children.length; i < length; i++) { | |
135 //SASL mechanisms | |
136 if(children[i].localName === 'mechanisms') { | |
137 stanza.mechanisms = []; | |
138 var nodes = el.getElementsByTagName('mechanism'); | |
139 for (var i = 0; i < nodes.length; i++) | |
140 stanza.mechanisms.push(nodes[i].textContent); | |
141 that.emit('mechanisms', stanza); | |
142 return; | |
143 } | |
144 } | |
145 //XMPP features | |
146 // else { | |
147 //TODO: stanza.features | |
148 that.emit('features', stanza); | |
149 // } | |
150 } | |
151 else if (el.localName === 'challenge') { | |
152 that.emit('challenge', stanza); | |
153 } | |
154 else if (el.localName === 'failure') { | |
155 that.emit('failure', stanza); | |
156 } | |
157 else if (el.localName === 'success') { | |
158 that.emit('success', stanza); | |
159 } | |
160 | |
161 //Iq callbacks | |
162 else if (el.localName === 'iq') { | |
163 var payload = el.firstChild; | |
164 if (payload) | |
165 that.emit('iq/' + payload.namespaceURI + ':' + payload.localName, stanza); | |
166 | |
167 var id = el.getAttribute('id'); | |
168 if (!(id && id in that.callbacks)) | |
169 return; | |
170 | |
171 var type = el.getAttribute('type'); | |
172 if (type !== 'result' && type !== 'error') | |
173 return; //TODO: warning | |
174 | |
175 var callback = that.callbacks[id]; | |
176 if (type === 'result' && callback.success) | |
177 callback.success.call(that, stanza); | |
178 else if (type === 'error' && callback.error) | |
179 callback.error.call(that, stanza); | |
180 | |
181 delete that.callbacks[id]; | |
182 } | |
183 | |
184 else if (el.localName === 'presence' || el.localName === 'message') { | |
185 that.emit(name, stanza); | |
186 } | |
187 }); | |
188 }; | |
67
1c8f326fe3ef
Several fixes and comments updated/added.
Sonny Piers <sonny.piers@gmail.com>
parents:
65
diff
changeset
|
189 /** |
108 | 190 * @function Create and open a websocket then go though the XMPP authentification process. |
191 * @param {String} [aJid] The JID (Jabber id) to use. | |
192 * @param {String} [aPassword] The associated password. | |
67
1c8f326fe3ef
Several fixes and comments updated/added.
Sonny Piers <sonny.piers@gmail.com>
parents:
65
diff
changeset
|
193 */ |
108 | 194 Lightstring.Connection.prototype.connect = function(aJid, aPassword) { |
195 this.emit('connecting'); | |
196 this.jid = new Lightstring.JID(aJid); | |
197 if (aPassword) | |
198 this.password = aPassword; | |
97
11e38a9bfe38
multi-transport is now possible
Sonny Piers <sonny.piers@gmail.com>
parents:
92
diff
changeset
|
199 |
108 | 200 if (!this.jid.bare) |
201 return; //TODO: error | |
202 if (!this.service) | |
203 return; //TODO: error | |
204 | |
205 function getProtocol(aURL) { | |
206 var a = document.createElement('a'); | |
207 a.href = aURL; | |
208 return a.protocol.replace(':', ''); | |
209 } | |
210 var protocol = getProtocol(this.service); | |
63
20da4fb67977
Auth PLAIN as plugin. Several fixes.
Sonny Piers <sonny.piers@gmail.com>
parents:
62
diff
changeset
|
211 |
108 | 212 if (protocol.match('http')) |
213 this.transport = new Lightstring.BOSHTransport(this.service, this.jid); | |
214 else if (protocol.match('ws')) | |
215 this.transport = new Lightstring.WebSocketTransport(this.service, this.jid); | |
43
136df1708856
Better iq callbacks. (breaks everything)
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
42
diff
changeset
|
216 |
108 | 217 this.onTransportLoaded(); |
218 }; | |
219 /** | |
220 * @function Send a message. | |
221 * @param {String|Object} aStanza The message to send. | |
222 * @param {Function} [aCallback] Executed on answer. (stanza must be iq) | |
223 */ | |
224 Lightstring.Connection.prototype.send = function(aStanza, aOnSuccess, aOnError) { | |
225 if (!(aStanza instanceof Lightstring.Stanza)) | |
226 var stanza = new Lightstring.Stanza(aStanza); | |
227 else | |
228 var stanza = aStanza; | |
72 | 229 |
108 | 230 if (!stanza) |
29
1e6d2ca2daae
Adds a Lightstring.Stanza object and use it.
Sonny Piers <sonny.piers@gmail.com>
parents:
28
diff
changeset
|
231 return; |
1e6d2ca2daae
Adds a Lightstring.Stanza object and use it.
Sonny Piers <sonny.piers@gmail.com>
parents:
28
diff
changeset
|
232 |
108 | 233 if (stanza.name === 'iq') { |
234 var type = stanza.type; | |
235 if (type !== 'get' || type !== 'set') | |
236 ; //TODO: error | |
42
ee874d064650
Check iq sending.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
41
diff
changeset
|
237 |
108 | 238 var callback = {success: aOnSuccess, error: aOnError}; |
99 | 239 |
108 | 240 var id = stanza.id; |
241 if (!id) | |
242 stanza.id = Lightstring.id(); | |
99 | 243 |
108 | 244 this.callbacks[stanza.id] = callback; |
78
4d0fc1c9ec88
Call iq-callbacks success/error with the right context.
Sonny Piers <sonny.piers@gmail.com>
parents:
77
diff
changeset
|
245 } |
108 | 246 else if (aOnSuccess || aOnError) |
247 ; //TODO: warning (no callback without iq) | |
99 | 248 |
108 | 249 this.transport.send(stanza.toString()); |
250 }; | |
251 /** | |
252 * @function Closes the XMPP stream and the socket. | |
253 */ | |
254 Lightstring.Connection.prototype.disconnect = function() { | |
255 this.emit('disconnecting'); | |
256 var stream = Lightstring.stanzas.stream.close(); | |
257 this.transport.send(stream); | |
258 this.emit('out', stream); | |
259 this.transport.close(); | |
260 }; | |
261 Lightstring.Connection.prototype.load = function() { | |
262 for (var i = 0; i < arguments.length; i++) { | |
263 var name = arguments[i]; | |
264 if (!(name in Lightstring.plugins)) | |
265 continue; //TODO: error | |
99 | 266 |
108 | 267 var plugin = Lightstring.plugins[name]; |
17
b7bd814333eb
Move methods to the prototype.
Sonny Piers <sonny.piers@gmail.com>
parents:
16
diff
changeset
|
268 |
108 | 269 //Namespaces |
270 for (var ns in plugin.namespaces) | |
271 Lightstring.ns[ns] = plugin.namespaces[ns]; | |
54
0b7dd59e264a
Fix Connection.load and add the init method to plugins.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
51
diff
changeset
|
272 |
108 | 273 //Stanzas |
274 Lightstring.stanzas[name] = {}; | |
275 for (var stanza in plugin.stanzas) | |
276 Lightstring.stanzas[name][stanza] = plugin.stanzas[stanza]; | |
17
b7bd814333eb
Move methods to the prototype.
Sonny Piers <sonny.piers@gmail.com>
parents:
16
diff
changeset
|
277 |
108 | 278 //Handlers |
279 for (var handler in plugin.handlers) | |
280 this.on(handler, plugin.handlers[handler]); | |
62
b1e75cdbb0ad
Don’t allow more than one iq handler to respond, and respond with an service-unavailable when not handled.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
60
diff
changeset
|
281 |
108 | 282 //Methods |
283 this[name] = {}; | |
284 for (var method in plugin.methods) | |
285 this[name][method] = plugin.methods[method].bind(this); | |
72 | 286 |
108 | 287 if (plugin.init) |
288 plugin.init.apply(this); | |
289 } | |
290 }; | |
291 })(); |