Mercurial > eldonilo > avatar
comparison avatar.js @ 20:e4916f1763e5
Deactivable debug; fix a stupid bug in gravatar; add a better default image and make it configurable.
author | Emmanuel Gil Peyrot <linkmauve@linkmauve.fr> |
---|---|
date | Sat, 16 Jul 2011 13:54:47 +0200 |
parents | 9ff8f951da99 |
children | 46c42ec52680 |
comparison
equal
deleted
inserted
replaced
19:9ff8f951da99 | 20:e4916f1763e5 |
---|---|
39 | 39 |
40 process.addListener('uncaughtException', function (err) { | 40 process.addListener('uncaughtException', function (err) { |
41 console.log('[41;1mUncaught exception (' + err + '), this should never happen:[0m\n' + err.stack); | 41 console.log('[41;1mUncaught exception (' + err + '), this should never happen:[0m\n' + err.stack); |
42 }); | 42 }); |
43 | 43 |
44 (function() { | 44 if (config.debug) |
45 var send = conn.send; | 45 (function() { |
46 conn.send = function(s) { | 46 var send = conn.send; |
47 util.log('Sent: [1;32m' + s + '[0m'); | 47 conn.send = function(s) { |
48 send.call(conn, s); | 48 console.log('Sent: [1;32m' + s + '[0m'); |
49 }; | 49 send.call(conn, s); |
50 })(); | 50 }; |
51 })(); | |
51 | 52 |
52 conn.on('online', function () { | 53 conn.on('online', function () { |
53 console.log('Connected'); | 54 util.log('Connected'); |
54 }); | 55 }); |
55 | 56 |
56 conn.on('stanza', function (stanza) { | 57 conn.on('stanza', function (stanza) { |
57 util.log('Recv: [1;34m' + stanza + '[0m'); | 58 if (config.debug) |
59 console.log('Recv: [1;34m' + stanza + '[0m'); | |
60 | |
58 if (stanza.is('iq')) | 61 if (stanza.is('iq')) |
59 onIq(stanza); | 62 onIq(stanza); |
60 else | 63 else |
61 onError(stanza); | 64 onError(stanza); |
62 }); | 65 }); |
71 var jids = {}; | 74 var jids = {}; |
72 | 75 |
73 var sent = {}; | 76 var sent = {}; |
74 | 77 |
75 var svgError = function(res, message) { | 78 var svgError = function(res, message) { |
79 util.log('No avatar at all, display a default image with the error in the title.'); | |
80 | |
76 res.writeHead(200, {'Content-Type': 'image/svg+xml'}); | 81 res.writeHead(200, {'Content-Type': 'image/svg+xml'}); |
77 res.write('<?xml version="1.0" encoding="UTF-8"?>\n'); | 82 res.write('<?xml version="1.0" encoding="UTF-8"?>\n'); |
78 res.write('<svg xmlns="http://www.w3.org/2000/svg" viewBox="-32 -36 64 64">\n'); | 83 res.write('<svg xmlns="http://www.w3.org/2000/svg"'); |
79 res.write('\t<title>'+message+'</title>\n'); | 84 |
80 res.write('\t<rect x="-32" y="-36" width="64" height="64" fill="white"/>\n'); | 85 if (config.defaultImage) |
81 res.write('\t<text font-family="sans-serif" font-weight="bold" text-anchor="middle">Error</text>\n'); | 86 res.write(' xmlns:xlink="http://www.w3.org/1999/xlink"'); |
87 | |
88 res.write(' viewBox="0 0 64 64">\n'); | |
89 res.write('\t<title>' + message + '</title>\n'); | |
90 | |
91 if (config.defaultImage) | |
92 res.write('\t<image width="64" height="64" xlink:href="' + config.defaultImage + '"/>\n'); | |
93 else { | |
94 res.write('\t<rect width="64" height="64" fill="silver"/>\n'); | |
95 res.write('\t<circle cx="32" cy="26" r="14" fill="white"/>\n'); | |
96 res.write('\t<ellipse cx="32" cy="64" rx="24" ry="26" fill="white"/>\n'); | |
97 } | |
98 | |
82 res.end('</svg>\n'); | 99 res.end('</svg>\n'); |
83 } | 100 } |
84 | 101 |
85 var makeError = function(response) { | 102 var makeError = function(response) { |
86 response.attrs.type = 'error'; | 103 response.attrs.type = 'error'; |
90 | 107 |
91 return response; | 108 return response; |
92 } | 109 } |
93 | 110 |
94 if (config.useGravatar) | 111 if (config.useGravatar) |
95 var noAvatar = function(res, from, message) { | 112 var noAvatar = function(res, to, message) { |
96 var options = { | 113 var options = { |
97 host: 'gravatar.com', | 114 host: 'gravatar.com', |
98 port: 80, | 115 port: 80, |
99 path: '/avatar/' + hash('md5').update(from).digest('hex') + '?d=404', | 116 path: '/avatar/' + hash('md5').update(to).digest('hex') + '?d=404', |
100 method: 'GET' | 117 method: 'GET' |
101 }; | 118 }; |
119 | |
120 util.log('No XMPP avatar, falling back to Gravatar for ' + to + '.'); | |
102 | 121 |
103 var r = http.request(options, function(r) { | 122 var r = http.request(options, function(r) { |
104 if (r.statusCode != 200) | 123 if (r.statusCode != 200) |
105 return svgError(res, message + ' Additionaly, no gravatar available.'); | 124 return svgError(res, message + ' Additionaly, no gravatar available.'); |
106 | 125 |
119 }); | 138 }); |
120 | 139 |
121 return r.end(); | 140 return r.end(); |
122 }; | 141 }; |
123 else | 142 else |
124 var noAvatar = function(res, _, message) { | 143 var noAvatar = function(res, to, message) { |
144 util.log('No XMPP avatar for ' + to + '.'); | |
125 return svgError(res, message); | 145 return svgError(res, message); |
126 }; | 146 }; |
127 | 147 |
128 function onIq(stanza) { | 148 function onIq(stanza) { |
129 var type = stanza.getAttribute('type'); | 149 var type = stanza.getAttribute('type'); |
146 var err = stanza.getChild('error').getChild().name; | 166 var err = stanza.getChild('error').getChild().name; |
147 } catch (e) { | 167 } catch (e) { |
148 var err = 'none'; | 168 var err = 'none'; |
149 } | 169 } |
150 | 170 |
151 return noAvatar(res, from, 'Error during query of this user’s vCard: “'+err+'”.'); | 171 return noAvatar(res, to, 'Error during query of this user’s vCard: “'+err+'”.'); |
152 } | 172 } |
153 | 173 |
154 var vCard = stanza.getChild('vCard', 'vcard-temp'); | 174 var vCard = stanza.getChild('vCard', 'vcard-temp'); |
155 if (!vCard) | 175 if (!vCard) |
156 return noAvatar(res, from, 'Error: this user doesn’t have a vCard.'); | 176 return noAvatar(res, to, 'Error: this user doesn’t have a vCard.'); |
157 | 177 |
158 try { | 178 try { |
159 var photo = vCard.getChild('PHOTO', 'vcard-temp'); | 179 var photo = vCard.getChild('PHOTO', 'vcard-temp'); |
160 var base64 = photo.getChild('BINVAL', 'vcard-temp').getText(); | 180 var base64 = photo.getChild('BINVAL', 'vcard-temp').getText(); |
161 | 181 |
163 var type = photo.getChild('TYPE', 'vcard-temp').getText(); | 183 var type = photo.getChild('TYPE', 'vcard-temp').getText(); |
164 } catch (e) { | 184 } catch (e) { |
165 if (config.guessType) | 185 if (config.guessType) |
166 type = 'image/png'; // FIXME: use magic. | 186 type = 'image/png'; // FIXME: use magic. |
167 else | 187 else |
168 return noAvatar(res, from, 'Error: this user’s vCard doesn’t specify the MIME type of its avatar.'); | 188 return noAvatar(res, to, 'Error: this user’s vCard doesn’t specify the MIME type of its avatar.'); |
169 } | 189 } |
170 | 190 |
171 var ext; | 191 var ext; |
172 for (var i in config.extensions) | 192 for (var i in config.extensions) |
173 if (type == config.extensions[i]) | 193 if (type == config.extensions[i]) |
174 ext = i; | 194 ext = i; |
175 | 195 |
176 // Here we don’t try to guess the extension even if the option is set. | 196 // Here we don’t try to guess the extension even if the option is set. |
177 if (ext === undefined) { | 197 if (ext === undefined) { |
178 console.log('Unknown MIME type: '+type); | 198 console.log('Unknown MIME type: '+type); |
179 return noAvatar(res, from, 'Error: this user’s avatar is in an unknown format.'); | 199 return noAvatar(res, to, 'Error: this user’s avatar is in an unknown format.'); |
180 } | 200 } |
181 | 201 |
182 var binval = new Buffer(base64.replace(/\n/g, ''), 'base64'); | 202 var binval = new Buffer(base64.replace(/\n/g, ''), 'base64'); |
183 | 203 |
184 fs.writeFile(config.directory+'/'+to+'.'+ext, binval, function() { | 204 fs.writeFile(config.directory+'/'+to+'.'+ext, binval, function() { |
185 jids[to] = ext; | 205 jids[to] = ext; |
186 showImage(to, res); | 206 showImage(to, res); |
187 }); | 207 }); |
188 } catch (e) { | 208 } catch (e) { |
189 return noAvatar(res, from, 'Error: this user doesn’t have an avatar in his/her vCard.'); | 209 return noAvatar(res, to, 'Error: this user doesn’t have an avatar in his/her vCard.'); |
190 } | 210 } |
191 } | 211 } |
192 | 212 |
193 function onError(stanza) { | 213 function onError(stanza) { |
194 if (stanza.getAttribute('type') == 'error') | 214 if (stanza.getAttribute('type') == 'error') |
248 jids[tab[1]] = tab[2]; | 268 jids[tab[1]] = tab[2]; |
249 } | 269 } |
250 }); | 270 }); |
251 | 271 |
252 http.createServer(function (req, res) { | 272 http.createServer(function (req, res) { |
253 console.log('Connection from ' + (req.headers['x-forwarded-for'] || req.client.remoteAddress) + ' (' + req.headers['user-agent'] + ') to ' + req.method.toLocaleLowerCase() + ' “' + req.url + '”.'); | 273 util.log('Connection from ' + (req.headers['x-forwarded-for'] || req.client.remoteAddress) + ' (' + req.headers['user-agent'] + ') to ' + req.method.toLocaleLowerCase() + ' “' + req.url + '”.'); |
254 | 274 |
255 var easterEggs = { | 275 var easterEggs = { |
256 source: { | 276 source: { |
257 re: new RegExp(config.webRoot + 'source/code$'), | 277 re: new RegExp('^' + config.webRoot + 'source/code$'), |
258 file: process.argv[1], | 278 file: process.argv[1], |
259 mime: 'application/ecmascript', | 279 mime: 'application/ecmascript', |
260 error: 'source code unavailable! oO' | 280 error: 'source code unavailable! oO' |
261 }, | 281 }, |
262 README: {}, | 282 README: {}, |
271 req.setEncoding('utf-8'); | 291 req.setEncoding('utf-8'); |
272 | 292 |
273 for (var i in easterEggs) { | 293 for (var i in easterEggs) { |
274 var ee = easterEggs[i]; | 294 var ee = easterEggs[i]; |
275 var file = ee.file || i; | 295 var file = ee.file || i; |
276 var re = ee.re || new RegExp(config.webRoot + file + '$'); | 296 var re = ee.re || new RegExp('^' + config.webRoot + file + '$'); |
277 if (re.test(req.url)) { | 297 if (re.test(req.url)) { |
278 fs.readFile(file, function(err, content) { | 298 fs.readFile(file, function(err, content) { |
279 if (err) | 299 if (err) |
280 return noAvatar(res, from, 'Error: ' + (ee.error || file + ' unavailable.')); | 300 return noAvatar(res, to, 'Error: ' + (ee.error || file + ' unavailable.')); |
281 | 301 |
282 res.writeHead(200, {'Content-Type': ee.mime || 'text/plain'}); | 302 res.writeHead(200, {'Content-Type': ee.mime || 'text/plain'}); |
283 res.end(content); | 303 res.end(content); |
284 }); | 304 }); |
285 return; | 305 return; |
286 } | 306 } |
287 } | 307 } |
288 | 308 |
289 var jid = unescape(req.url.replace(new RegExp(config.webRoot), '')); | 309 var jid = unescape(req.url.replace(new RegExp('^' + config.webRoot), '')); |
290 | 310 |
291 if (jid === 'redirect') { | 311 if (jid === 'redirect') { |
292 if (req.method !== 'POST') { | 312 if (req.method !== 'POST') { |
293 res.writeHead(404, {'Content-Type': 'text/plain'}); | 313 res.writeHead(404, {'Content-Type': 'text/plain'}); |
294 res.end('Error: redirect unavailable.'); | 314 res.end('Error: redirect unavailable.'); |