# HG changeset patch # User Emmanuel Gil Peyrot # Date 1320355390 25200 # Node ID 161d4ea1c3f8b421ca0fa34ae96d1fb3c3d826dc # Parent d6738065768713669e26fbff6da7f6017b2cfcb3 Migration of the client-side to XMPP.js instead of Strophe.js. Drop BOSH support and add WebSockets support. The server-side is untested, may be broken. diff --git a/atom.js b/atom.js --- a/atom.js +++ b/atom.js @@ -13,26 +13,33 @@ if (!document.createTextNode) return text; }; -parsers[ns.atom] = function(id, xml) { +parsers[ns.atom] = function(item) { var toDate = function(atom) { + var d = new Date; + if (!atom) - return new Date; + return d; - var last = atom.getChild('updated'); - if (!last) { - last = atom.getChild('published'); - if (!last) - return new Date; + try { + var last = atom.getElementsByTagNameNS(ns.atom, 'updated')[0].textContent; + } catch (e) { + try { + var last = atom.getElementsByTagNameNS(ns.atom, 'published')[0].textContent; + } catch (e) { + return d; + } } // var d = new Date(last); // FIXME: don't work in obsolete browsers - var d = new Date; d.set8601(last); return d; }; - var toHTML = function(atom, date) { + var toHTML = function(item, date) { + var atom = item.payload; + var id = item.id; + var article = document.createElementNS(ns.xhtml, 'article'); article.setAttributeNS(ns.e, 'id', id); @@ -42,22 +49,26 @@ parsers[ns.atom] = function(id, xml) { var aside = document.createElementNS(ns.xhtml, 'aside'); article.appendChild(aside); - var atomTitle = atom.getChild('title'); - if (atomTitle) { + try { + var atomTitle = atom.getElementsByTagNameNS(ns.atom, 'title')[0].textContent; var title = document.createElementNS(ns.xhtml, 'h2'); title.appendChild(document.createTextNode(atomTitle)); article.appendChild(title); + } catch (e) { } var footer = document.createElementNS(ns.xhtml, 'footer'); - var atomAuthor = atom.getChild('author', ns.atom); - if (atomAuthor) { - var atomName = atomAuthor.getChild('name'); + try { + var atomAuthor = atom.getElementsByTagNameNS(ns.atom, 'author')[0]; + try { + var atomName = atomAuthor.getElementsByTagNameNS(ns.atom, 'name')[0].textContent; + } catch (e) { + } - var atomURI = atomAuthor.getChild('uri'); var cite = document.createElementNS(ns.xhtml, 'cite'); - if (atomURI) { + try { + var atomURI = atomAuthor.getElementsByTagNameNS(ns.atom, 'uri')[0].textContent; var a = document.createElementNS(ns.xhtml, 'a'); a.href = atomURI; var atomJID = new JID; @@ -69,49 +80,54 @@ parsers[ns.atom] = function(id, xml) { var img = document.createElementNS(ns.xhtml, 'img'); img.src = config.avatarRoot + atomJID.bare; aside.appendChild(img); - } else + } catch (e) { cite.appendChild(document.createTextNode(atomName)); + } footer.appendChild(document.createTextNode('By ')); footer.appendChild(cite); - var atomEmail = atomAuthor.getChild('email'); - if (atomEmail) { + try { + var atomEmail = atomAuthor.getElementsByTagNameNS(ns.atom, 'email')[0].textContent; footer.appendChild(document.createTextNode(' (')); var a = document.createElementNS(ns.xhtml, 'a'); a.href = 'mailto:' + atomEmail; a.appendChild(document.createTextNode('email')); footer.appendChild(a); footer.appendChild(document.createTextNode(')')); + } catch (e) { } article.appendChild(footer); + } catch (e) { } footer.innerHTML += ', '; - var atomSummary = atom.getChild('summary'); - if (atomSummary) { + try { + var atomSummary = atomAuthor.getElementsByTagNameNS(ns.atom, 'summary')[0].textContent; var p = document.createElementNS(ns.xhtml, 'p'); p.appendChild(document.createTextNode(atomSummary)); article.appendChild(p); + } catch (e) { } - var atomContent = atom.getChild('content'); - if (atomContent) { - var contentType = atomContent.getAttribute('type'); + try { + var atomContent = atom.getElementsByTagNameNS(ns.atom, 'content')[0]; + var contentType = atomContent.getAttributeNS(null, 'type'); if (/^text$/.test(contentType)) { var p = document.createElementNS(ns.xhtml, 'p'); - p.appendChild(document.createTextNode(atomContent.getText())); + p.appendChild(document.createTextNode(atomContent.textContent)); article.appendChild(p); } else if (/^html$/.test(contentType)) { - article.insertAdjacentHTML('beforeend', atomContent.getText()); // FIXME: could be not-well-formed. + article.insertAdjacentHTML('beforeend', atomContent.textContent); // FIXME: could be not-well-formed. } else if (/^xhtml$/.test(contentType)) { - // TODO: use a better xml2json lib that allow to json2xml - /*var div = atomContent.getChild(); - article.appendChild(div.innerXml());*/ + var div = atomContent.firstChild; + var children = div.childNodes; + for (var i=0; iComments !'; } @@ -155,7 +172,7 @@ parsers[ns.atom] = function(id, xml) { return article; }; - this.xml = xml; - this.date = toDate(xml); - this.html = toHTML(xml, this.date); + this.xml = item.payload; + this.date = toDate(item.payload); + this.html = toHTML(item, this.date); } diff --git a/blog.js b/blog.js --- a/blog.js +++ b/blog.js @@ -1,6 +1,6 @@ //'use strict'; -const BOSH_SERVICE = 'http://linkmauve.fr/http-bind/'; +const WS_SERVICE = 'ws://plugsbee.com:5280/'; var conn = null; var jid = 'blog@linkmauve.fr'; // FIXME: Strophe should accept anonymous connections. var password = 'blog'; @@ -100,67 +100,22 @@ var updateMessage = function(name, id) { } } -var convert = function(id, xml) { - var ns = xml['@xmlns']; - if (ns in parsers) - return new parsers[ns](id, xml); - return new parsers[''](id, xml); +var convert = function(item) { + if (item.ns in parsers) + return new parsers[item.ns](item); + return new parsers[''](item); }; -var parsePubSubEvent = function(stanza) { - var e = {}; - - e.service = stanza.getAttribute('from'); - - var pubsub = stanza.getChild('event', ns.pse); - if (!pubsub) { - pubsub = stanza.getChild('pubsub', ns.ps); - if (!pubsub) - return; - } - e.ns = pubsub.getAttribute('xmlns'); - - var items = pubsub.getChild('items', e.ns); - if (!items) - return; - - e.node = items.getAttribute('node'); - items = items.getChildren('item', e.ns); - if (!items) - return; - - e.name = e.service + '/' + e.node; +var onMessages = function(stanza) { + var name = stanza.service+'/'+stanza.node; + if (!received[name]) + received[name] = {}; - e.items = {}; - for (var i in items) { - var item = items[i]; - if (!item.getAttribute) - continue; - - var pl = item.getChild(); - if (!pl) - continue; - - var id = item.getAttribute('id'); - - e.items[id] = pl; - } + var r = received[name]; - return e; -} - -var onMessages = function(stanza) { - conn.addHandler(onMessages, null, 'message', null, null, null); - - stanza = xml2json(stanza); - var e = parsePubSubEvent(stanza); - - if (!received[e.name]) - received[e.name] = {}; - - for (var id in e.items) { - received[e.name][id] = convert(id, e.items[id]); - updateMessage(e.name, id); + for (var id in stanza.items) { + r[id] = convert(stanza.items[id]); + updateMessage(name, id); } } @@ -171,17 +126,16 @@ var onInfo = function(stanza) { var form = forms.parse(x);*/ } -var onSubscribed = function(stanza) { - var type = stanza.getAttribute('type'); - if (type !== 'result') { - messages.innerHTML = 'Error, impossible to retrieve messages.'; - re = false; - conn.disconnect(); +function onConnect() { + conn.send(''); + // TODO: verify the subscription. + //conn.pubsubSubscribe(service, node); + if (params.no === 'server') { + conn.pubsubItems(service, node, onMessages); + conn.discoInfo(service, node, onInfo); } -} -function onConnect(status) { - if (status == Strophe.Status.CONNFAIL) { + /*if (status == Strophe.Status.CONNFAIL) { console.log('Failed to connect.'); } else if (status == Strophe.Status.DISCONNECTING) { console.log('Disconnecting.'); @@ -189,20 +143,23 @@ function onConnect(status) { console.log('Disconnected.'); if (re) conn.connect(jid, password, onConnect); - } else if (status == Strophe.Status.CONNECTED) { - conn.addHandler(onMessages, null, 'message', null, null, null); - conn.send($pres().tree()); - conn.pubsub.subscribe(jid, service, node, undefined, onMessages, onSubscribed); - if (params.no === 'server') { - conn.pubsub.items(jid, service, node, onMessages); - conn.pubsub.info(jid, service, node, onInfo); - } - } + }*/ } window.addEventListener('load', function () { - conn = new Strophe.Connection(BOSH_SERVICE); - conn.connect(jid, password, onConnect); + conn = new XMPP(WS_SERVICE); + + // Debug + conn.on('DOMOutput', function(stanza) { + console.log('out:', stanza); + }); + conn.on('DOMInput', function(stanza) { + console.log('in:', stanza); + }); + + conn.on('connected', onConnect); + conn.on('message', onMessages); + conn.connect(jid, password); }, false); window.addEventListener('unload', function (e) { diff --git a/functions.js b/functions.js new file mode 100644 --- /dev/null +++ b/functions.js @@ -0,0 +1,73 @@ +var Error = function(s) { + this.error = s; + this.toString = function() { + return this.error; + }; +}; + +var Item = function(service, node, id, payload) { + this.service = service; + this.node = node; + this.id = id; + this.payload = payload; + this.ns = payload.namespaceURI; +}; + +var verify = function(elem, ns, name, attributes, children) { + if (ns && elem.namespaceURI !== ns) + throw new Error('not the right namespace.'); + if (name && elem.localName !== name) + throw new Error('not the right name.'); + if (attributes) + for (var attribute in attributes) { + var value = attributes[attribute] + if (elem.getAttributeNS(null, attribute) !== value) + throw new Error('attribute '+attribute+' invalid.'); + } + if (typeof children === 'number' && children < 2 && elem.children.length != children) + throw new Error('not the right number of children'); +}; + +XMPP.prototype = { + discoInfo: function(aTo, aNode, aCallback) { + this.send(stanzas.discoInfo(aTo, aNode), function(answer){ + aCallback(answer); + }); + }, + + pubsubItems: function(aTo, aNode, aCallback) { + this.send(stanzas.pubsubItems(aTo, aNode), function(answer){ + var items = []; + //try { + verify(answer, ns.j, 'iq', {type: 'result', from: aTo}, 1); + + var pubsub = answer.firstChild; + verify(pubsub, ns.ps, 'pubsub', undefined, 1); + + var items = pubsub.firstChild; + verify(items, ns.ps, 'items', {node: aNode}); + + var items = items.children; + + var list = []; + for (var i in items) { + var node = items[i]; + var id = node.getAttributeNS(null, 'id'); + if (!id) + throw new Error('WARNING: invalid item! (no id)'); + + if (node.children.length != 1) + throw new Error('WARNING: invalid item! (more than one payload)'); + + var payload = node.firstChild; + + list[id] = new Item(aTo, aNode, id, payload); + } + /*} catch (e) { + aCallback(e); + }*/ + if(aCallback) + aCallback({service: aTo, node: aNode, items: list}); + }); + } +}; diff --git a/index.xhtml b/index.xhtml --- a/index.xhtml +++ b/index.xhtml @@ -5,12 +5,20 @@ Eldonilo blog +