Mercurial > eldonilo > blog
annotate server.js @ 15:5149a856d9dd default tip
Fix hybrid mode.
author | Emmanuel Gil Peyrot <linkmauve@linkmauve.fr> |
---|---|
date | Thu, 03 Nov 2011 17:28:49 -0700 |
parents | 03be0717d3f8 |
children |
rev | line source |
---|---|
0 | 1 #!/usr/bin/env node |
2 | |
3 'use strict'; | |
4 | |
5 var config = require('./configuration'); | |
6 | |
7 var util = require('util'); | |
8 var http = require('http'); | |
6
29becdd02dea
Fix server file handling.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
4
diff
changeset
|
9 var parseurl = require('url').parse; |
0 | 10 var fs = require('fs'); |
11 var xmpp = require('node-xmpp'); | |
12 var Element = xmpp.Element; | |
2
eb5b6d3ab09b
Better import of ns and jid; fix email and missing ns.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
1
diff
changeset
|
13 var JID = require('./jid'); |
eb5b6d3ab09b
Better import of ns and jid; fix email and missing ns.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
1
diff
changeset
|
14 var ns = require('./ns'); |
0 | 15 var forms = require('./forms'); |
16 require('./date'); | |
14
03be0717d3f8
Use the same code for client- and server-side Atom parsing.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
10
diff
changeset
|
17 var Atom = require('./atom'); |
0 | 18 |
19 var received = {}; | |
20 | |
21 var cl = new xmpp.Client(config); | |
22 | |
23 (function() { | |
24 var send = cl.send; | |
25 cl.send = function(s) { | |
26 util.log('Sent: [1;32m' + s + '[0m'); | |
27 send.call(cl, s); | |
28 } | |
29 })(); | |
30 | |
31 cl.on('online', function() { | |
32 util.log('Connected.'); | |
33 cl.send(new Element('presence')); | |
34 }); | |
35 | |
36 var getUniqId = (function() { | |
37 var id = 0; | |
38 return function() { | |
39 return ++id; | |
40 } | |
41 })(); | |
42 | |
43 var getNodeInfo = function(jid) { | |
44 var iq = new Element('iq', {to: jid.bare, type: 'get', id: getUniqId()}) | |
45 .c('query', {xmlns: ns.info, node: jid.resource}) | |
46 .up(); | |
47 | |
48 cl.send(iq); | |
49 }; | |
50 | |
51 var getNodeItems = function(jid) { | |
52 var iq = new Element('iq', {to: jid.bare, type: 'get', id: getUniqId()}) | |
53 .c('pubsub', {xmlns: ns.ps}) | |
54 .c('items', {node: jid.resource}) | |
55 .up() | |
56 .up(); | |
57 | |
58 cl.send(iq); | |
59 }; | |
60 | |
61 var makeError = function(response) { | |
62 response.attrs.type = 'error'; | |
63 | |
64 response.c('error', {type: 'cancel'}) | |
65 .c('feature-not-implemented', {xmlns: 'urn:ietf:params:xml:ns:xmpp-stanzas'}); | |
66 | |
67 return cl.send(response); | |
68 }; | |
69 | |
70 var handleInfo = function(query, from) { | |
71 var x = query.getChild('x', ns.data); | |
72 if (!x) | |
73 return; | |
74 | |
75 var jid = new JID; | |
76 jid.bare = from; | |
77 jid.resource = query.attrs.node; | |
78 | |
79 var form = forms.parse(x, true).fields; | |
80 received[jid].form = form; | |
81 generatePage(jid); | |
82 }; | |
83 | |
84 var handlePubSub = function(pubsub, from) { | |
85 var items = pubsub.getChild('items'); | |
86 if (!items) | |
87 return; | |
88 | |
89 var itemsNS = items.getNS(); | |
90 if (itemsNS !== ns.ps && itemsNS !== ns.pse) | |
91 return; | |
92 | |
93 var jid = new JID; | |
94 jid.bare = from; | |
95 jid.resource = items.attrs.node; | |
96 | |
97 items = items.getChildren('item', itemsNS); | |
98 if (!items) | |
99 return; | |
100 | |
101 if (!received[jid]) | |
102 received[jid] = {data: null, form: null, wait: {}}; | |
103 | |
104 var data = received[jid].data || {}; | |
105 | |
106 for (var i in items) { | |
107 var item = items[i]; | |
108 var id = item.attrs.id; | |
109 | |
110 var payload = item.children[0]; | |
111 delete payload.parent; | |
112 data[id] = payload; | |
113 } | |
114 | |
115 received[jid].data = data; | |
116 generatePage(jid); | |
117 }; | |
118 | |
119 cl.on('stanza', function(stanza) { | |
120 util.log('Recv: [1;34m' + stanza + '[0m'); | |
121 if (stanza.is('iq', ns.j)) { | |
122 var type = stanza.attrs.type; | |
123 if (type === 'error') | |
124 return; | |
125 | |
126 var result = new Element('iq', {to: stanza.attrs.from, from: stanza.attrs.to, type: 'result'}); | |
127 if (type === 'get' || type === 'set') | |
128 return makeError(result); | |
129 | |
130 var payload = stanza.getChild('query', ns.info); | |
131 if (payload) | |
132 return handleInfo(payload, stanza.attrs.from); | |
133 | |
134 payload = stanza.getChild('pubsub', ns.ps); | |
135 if (payload) | |
136 return handlePubSub(payload, stanza.attrs.from); | |
137 | |
2
eb5b6d3ab09b
Better import of ns and jid; fix email and missing ns.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
1
diff
changeset
|
138 } else if (stanza.is('message', ns.j)) { |
0 | 139 var type = stanza.attrs.type; |
140 if (type === 'error') | |
141 return; | |
142 | |
143 if (type !== 'headline') | |
144 return; | |
145 | |
146 var payload = stanza.getChild('event', ns.pse); | |
147 if (payload) | |
148 return handlePubSub(payload, stanza.attrs.from); | |
149 } | |
150 }); | |
151 | |
152 var generatePage = function(jid) { | |
153 var r = received[jid.full]; | |
154 var s = r.wait; | |
155 var form = r.form; | |
156 var data = r.data; | |
157 | |
158 if (!form || !data) | |
159 return; | |
160 | |
161 for (var i in s) { | |
162 r = s[i]; | |
163 delete s[i]; | |
1
82905edac9d8
Fix some things.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
0
diff
changeset
|
164 makePage(r.res, jid, form, data, r.noscript); |
0 | 165 } |
166 }; | |
167 | |
168 var makePage = function(res, jid, form, data, noscript) { | |
169 var body = '</div>'; | |
170 | |
171 for (var id in data) { | |
14
03be0717d3f8
Use the same code for client- and server-side Atom parsing.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
10
diff
changeset
|
172 var payload = data[id]; |
03be0717d3f8
Use the same code for client- and server-side Atom parsing.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
10
diff
changeset
|
173 var article = new Atom({id: id, ns: payload.attrs['xmlns'], payload: payload}); // , jid ? |
03be0717d3f8
Use the same code for client- and server-side Atom parsing.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
10
diff
changeset
|
174 body = article.html + body; |
0 | 175 } |
1
82905edac9d8
Fix some things.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
0
diff
changeset
|
176 body = '<div e:jid="' + jid.full + '">' + body; |
2
eb5b6d3ab09b
Better import of ns and jid; fix email and missing ns.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
1
diff
changeset
|
177 |
0 | 178 home(res, form['pubsub#title'], form['pubsub#description'], body, 'Node created the <time>' + form['pubsub#creation_date'] + '</time> by <cite>' + form['pubsub#creator'] + '</cite> with <a href="http://linkmauve.fr/dev/eldonilo/blog">Eldonilo blog</a>.', noscript); |
179 }; | |
180 | |
181 var servePage = function(url, res) { | |
182 util.log(url.href); | |
183 | |
184 var query = require('querystring').parse(url.query, ';'); | |
185 | |
186 var page = new JID(config.defaultNode); | |
187 if (query.jid) | |
188 page.bare = query.jid; | |
189 if (query.node) | |
190 page.resource = query.node; | |
191 | |
192 if (query.type === 'atom' && config.atomRoot) { | |
193 res.writeHead(301, {'Location': config.atomRoot + page.resource}); | |
194 return res.end(); | |
195 } | |
196 | |
197 res.writeHead(200, {'Content-Type': 'application/xhtml+xml'}); | |
198 | |
199 var noscript = false; | |
200 if (query.no === 'server') | |
201 return fs.readFile('index.xhtml', function(err, data) { | |
202 res.end(data); | |
203 }); | |
204 else if (query.no === 'client') | |
205 noscript = true; | |
206 | |
207 var jid = page.full; | |
208 if (!received[jid]) { | |
209 getNodeInfo(page); | |
210 getNodeItems(page); | |
211 received[jid] = {data: null, form: null, wait: {}}; | |
212 received[jid].wait[getUniqId()] = {res: res, noscript: noscript}; | |
213 } else { | |
214 received[jid].wait[getUniqId()] = {res: res, noscript: noscript}; | |
215 generatePage(page); | |
216 } | |
217 } | |
218 | |
219 var home = function(res, title, desc, body, footer, noscript) { | |
220 res.writeHead(200, {'Content-Type': 'application/xhtml+xml'}); | |
221 res.write('<?xml version="1.0" encoding="utf-8"?>\n'); | |
222 res.write('<?xml-stylesheet type="text/css" href="theme.css" media="screen"?>\n'); | |
223 res.write('<!DOCTYPE html>\n'); | |
224 res.write('<html xmlns="http://www.w3.org/1999/xhtml">\n'); | |
225 res.write(' <head>\n'); | |
226 res.write(' <title>' + (title? title: 'Eldonilo blog') + '</title>\n'); | |
227 | |
228 if (!noscript) { | |
229 res.write('\n'); | |
15
5149a856d9dd
Fix hybrid mode.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
14
diff
changeset
|
230 res.write(' <!-- Configuration -->'); |
5149a856d9dd
Fix hybrid mode.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
14
diff
changeset
|
231 res.write(' <script type="application/ecmascript" src="configuration.js" defer=""/>'); |
5149a856d9dd
Fix hybrid mode.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
14
diff
changeset
|
232 res.write('\n'); |
5149a856d9dd
Fix hybrid mode.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
14
diff
changeset
|
233 res.write(' <!-- XMPP library -->'); |
5149a856d9dd
Fix hybrid mode.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
14
diff
changeset
|
234 res.write(' <script type="application/ecmascript" src="md5.js" defer=""/>'); |
5149a856d9dd
Fix hybrid mode.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
14
diff
changeset
|
235 res.write(' <script type="application/ecmascript" src="xmpp.js" defer=""/>'); |
5149a856d9dd
Fix hybrid mode.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
14
diff
changeset
|
236 res.write('\n'); |
5149a856d9dd
Fix hybrid mode.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
14
diff
changeset
|
237 res.write(' <!-- XMPP helpers -->'); |
5149a856d9dd
Fix hybrid mode.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
14
diff
changeset
|
238 res.write(' <script type="application/ecmascript" src="ns.js" defer=""/>'); |
5149a856d9dd
Fix hybrid mode.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
14
diff
changeset
|
239 res.write(' <script type="application/ecmascript" src="stanzas.js" defer=""/>'); |
5149a856d9dd
Fix hybrid mode.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
14
diff
changeset
|
240 res.write(' <script type="application/ecmascript" src="functions.js" defer=""/>'); |
5149a856d9dd
Fix hybrid mode.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
14
diff
changeset
|
241 res.write('\n'); |
5149a856d9dd
Fix hybrid mode.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
14
diff
changeset
|
242 res.write(' <!-- Core of the blog -->'); |
5149a856d9dd
Fix hybrid mode.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
14
diff
changeset
|
243 res.write(' <script type="application/ecmascript" src="date.js" defer=""/>'); |
5149a856d9dd
Fix hybrid mode.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
14
diff
changeset
|
244 res.write(' <script type="application/ecmascript" src="jid.js" defer=""/>'); |
5149a856d9dd
Fix hybrid mode.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
14
diff
changeset
|
245 res.write(' <script type="application/ecmascript" src="atom.js" defer=""/>'); |
5149a856d9dd
Fix hybrid mode.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
14
diff
changeset
|
246 res.write(' <script type="application/ecmascript" src="nothing.js" defer=""/>'); |
0 | 247 } |
248 | |
249 if (config.atomRoot) { | |
250 res.write('\n'); | |
251 res.write(' <link rel="alternate" type="application/atom+xml" title="Atom feed" href="?type=atom"/>\n'); | |
252 } | |
253 | |
254 res.write(' </head>\n'); | |
255 res.write('\n'); | |
256 res.write(' <body>\n'); | |
257 res.write(' <header>\n'); | |
258 res.write(' <h1>' + (title? title: 'Eldonilo blog') + '</h1>\n'); | |
259 res.write(' <p>' + (desc? desc: 'Displaying your nodes.') + '</p>\n'); | |
3
2e2a2154efbb
Use a better XHTML semantic and fix the theme a bit.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
2
diff
changeset
|
260 res.write('\n'); |
2e2a2154efbb
Use a better XHTML semantic and fix the theme a bit.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
2
diff
changeset
|
261 res.write(' <nav>\n'); |
2e2a2154efbb
Use a better XHTML semantic and fix the theme a bit.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
2
diff
changeset
|
262 res.write(' <ul>\n'); |
2e2a2154efbb
Use a better XHTML semantic and fix the theme a bit.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
2
diff
changeset
|
263 res.write(' <li><a href="?no=client">Without client-side</a></li>\n'); |
2e2a2154efbb
Use a better XHTML semantic and fix the theme a bit.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
2
diff
changeset
|
264 res.write(' <li><a href="?no=server">Without server-side</a></li>\n'); |
2e2a2154efbb
Use a better XHTML semantic and fix the theme a bit.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
2
diff
changeset
|
265 res.write(' <li><a href="?">Hybrid mode</a></li>\n'); |
2e2a2154efbb
Use a better XHTML semantic and fix the theme a bit.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
2
diff
changeset
|
266 res.write(' </ul>\n'); |
2e2a2154efbb
Use a better XHTML semantic and fix the theme a bit.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
2
diff
changeset
|
267 res.write(' </nav>\n'); |
0 | 268 res.write(' </header>\n'); |
269 res.write('\n'); | |
270 | |
271 if (!body) | |
272 res.write(' <section id="messages"/>\n'); | |
273 else { | |
274 res.write(' <section id="messages" xmlns:e="' + ns.e + '">\n'); | |
275 res.write(body); | |
276 res.write(' </section>\n'); | |
277 } | |
278 | |
279 res.write('\n'); | |
280 | |
281 if (!footer) | |
282 res.write(' <footer/>\n'); | |
283 else { | |
284 res.write(' <footer>\n'); | |
285 res.write(footer); | |
286 res.write(' </footer>\n'); | |
287 } | |
288 | |
289 if (!noscript) { | |
290 res.write('\n'); | |
291 res.write(' <script type="application/ecmascript" src="blog.js"/>\n'); | |
292 } | |
293 | |
294 res.write(' </body>\n'); | |
295 res.end('</html>\n'); | |
296 }; | |
297 | |
298 http.createServer(function(req, res) { | |
4
f630f4b90564
Remove the old log system and use console.log instead.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
3
diff
changeset
|
299 util.log('Connection from ' + (req.headers['x-forwarded-for'] || req.client.remoteAddress) + ' (' + req.headers['user-agent'] + ') to ' + req.method.toLocaleLowerCase() + ' “' + req.url + '” from ' + req.headers['referer'] + '.'); |
f630f4b90564
Remove the old log system and use console.log instead.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
3
diff
changeset
|
300 |
0 | 301 var re = new RegExp('^' + config.webRoot); |
6
29becdd02dea
Fix server file handling.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
4
diff
changeset
|
302 var url = parseurl(req.url.replace(re, '')); |
29becdd02dea
Fix server file handling.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
4
diff
changeset
|
303 var pathname = url.pathname || ''; |
29becdd02dea
Fix server file handling.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
4
diff
changeset
|
304 var ext = pathname.substring(pathname.lastIndexOf('.')+1); |
0 | 305 |
6
29becdd02dea
Fix server file handling.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
4
diff
changeset
|
306 if (pathname === '') |
0 | 307 return servePage(url, res); |
308 | |
6
29becdd02dea
Fix server file handling.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
4
diff
changeset
|
309 fs.readFile(pathname, function(err, data) { |
29becdd02dea
Fix server file handling.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
4
diff
changeset
|
310 if (err || pathname === 'index.xhtml') |
0 | 311 return servePage(url, res); |
312 | |
313 res.writeHead(200, {'Content-Type': config.types[ext] || 'application/octet-stream'}); | |
314 | |
315 res.end(data); | |
316 }); | |
317 }).listen(config.webPort, config.webHost); |