root/trunk/uploadr/MacUploadr.app/Contents/Resources/chrome/content/uploadr/flickr.js

Revision 493, 10.8 kB (checked in by jdecq, 11 months ago)

add timestamps in log message

Line 
1 /*
2  * Flickr Uploadr
3  *
4  * Copyright (c) 2007-2008 Yahoo! Inc.  All rights reserved.  This library is
5  * free software; you can redistribute it and/or modify it under the terms of
6  * the GNU General Public License (GPL), version 2 only.  This library is
7  * distributed WITHOUT ANY WARRANTY, whether express or implied. See the GNU
8  * GPL for more details (http://www.gnu.org/licenses/gpl.html)
9  */
10
11 // The API key and secret are defined in flKey.cpp and included here
12 try {
13         var key = Cc['@flickr.com/key;1'].createInstance(Ci.flIKey);
14 } catch (err) {
15         Components.utils.reportError(err);
16 }
17
18 function toOpenWindowByType(inType, uri) {
19   var winopts = "chrome,extrachrome,menubar,resizable,scrollbars,status,toolbar";
20   window.open(uri, "_blank", winopts);
21 }
22
23 // The standard API
24 var flickr = {
25
26         auth: {
27
28                 checkToken: function(callback, token) {
29                         api.start({
30                                 'method': 'flickr.auth.checkToken',
31                                 'auth_token': token
32                         }, callback);
33                 },
34
35                 getFrob: function(callback, fresh) {
36                         api.start({
37                                 'method': 'flickr.auth.getFrob'
38                         }, callback, null, null, null, fresh);
39                 },
40
41                 getToken: function(callback, frob) {
42                         if (frob) {
43                                 api.start({
44                                         'method': 'flickr.auth.getToken',
45                                         'frob': frob
46                                 }, callback);
47                         }
48                 }
49
50         },
51
52         people: {
53
54                 getInfo: function(callback, token, nsid) {
55                         api.start({
56                                 'method': 'flickr.people.getInfo',
57                                 'auth_token': token,
58                                 'user_id': nsid
59                         }, callback, null, null, null, nsid);
60                 },
61
62                 getUploadStatus: function(callback, token) {
63                         api.start({
64                                 'method': 'flickr.people.getUploadStatus',
65                                 'auth_token': token
66                         }, callback);
67                 }
68
69         },
70
71         photos: {
72
73                 upload: {
74
75                         checkTickets: function(callback, token, tickets) {
76                                 api.start({
77                                         'method': 'flickr.photos.upload.checkTickets',
78                                         'auth_token': token,
79                                         'tickets': tickets.join(',')
80                                 }, callback);
81                         }
82
83                 }
84
85         },
86
87         photosets: {
88
89                 addPhoto: function(callback, token, photoset_id, photo_id){
90                         api.start({
91                                 'method': 'flickr.photosets.addPhoto',
92                                 'auth_token': token,
93                                 'photoset_id': photoset_id,
94                                 'photo_id': photo_id
95                         }, callback, null, null, true);
96                 },
97
98                 create: function(callback, token, title, description,
99                         primary_photo_id) {
100                         api.start({
101                                 'method': 'flickr.photosets.create',
102                                 'auth_token': token,
103                                 'title': title,
104                                 'description': description,
105                                 'primary_photo_id': primary_photo_id
106                         }, callback, null, null, true);
107                 },
108
109                 getList: function(callback, token, nsid) {
110                         api.start({
111                                 'method': 'flickr.photosets.getList',
112                                 'auth_token': token,
113                                 'user_id': nsid
114                         }, callback);
115                 }
116
117         },
118
119         // Preferences are fetched from the site when no stored version can be found
120         prefs: {
121
122                 getContentType: function(callback, token) {
123                         api.start({
124                                 'method': 'flickr.prefs.getContentType',
125                                 'auth_token': token
126                         }, callback);
127                 },
128
129                 getHidden: function(callback, token) {
130                         api.start({
131                                 'method': 'flickr.prefs.getHidden',
132                                 'auth_token': token
133                         }, callback);
134                 },
135
136                 getPrivacy: function(callback, token) {
137                         api.start({
138                                 'method': 'flickr.prefs.getPrivacy',
139                                 'auth_token': token
140                         }, callback);
141                 },
142
143                 getSafetyLevel: function(callback, token) {
144                         api.start({
145                                 'method': 'flickr.prefs.getSafetyLevel',
146                                 'auth_token': token
147                         }, callback);
148                 }
149
150         },
151
152         utils: {
153
154                 logUploadStats: function(callback, token, source, num_photos,
155                         upload_time, bytes, errors) {
156                         api.start({
157                                 'method': 'flickr.utils.logUploadStats',
158                                 'auth_token': token,
159                                 'source': source,
160                                 'photos': num_photos,
161                                 'upload_time': upload_time,
162                                 'bytes': bytes,
163                                 'errors': errors
164                         }, callback, null, null, true);
165                 }
166
167         }
168
169 };
170
171 var api = {
172
173         // Hashes of timeouts and XHRs being used to track running API calls
174         timeouts: {},
175
176         // Escape and sign a set of parameters, returning the new version
177         escape_and_sign: function(params, post) {
178                 params['api_key'] = key.key();
179                 var sig = [];
180                 var esc_params = {api_key: '', api_sig: ''};
181                 for (var p in params) {
182                         if ('object' == typeof params[p]) {
183                                 esc_params[p] = params[p];
184                         } else {
185                                 sig.push(p);
186                                 esc_params[p] = escape_utf8('' + params[p], !post)
187                                         .replace(/(^\s+|\s+$)/g, '');
188                         }
189                 }
190                 sig.sort();
191                 var calc = [];
192                 var ii = sig.length;
193                 for (var i = 0; i < ii; ++i) {
194                         calc.push(sig[i] + (post ? esc_params[sig[i]] : escape_utf8('' +
195                                 params[sig[i]], false)));
196                 }
197                 esc_params['api_sig'] = key.sign(calc.join(''));
198                 return esc_params;
199         },
200
201         // The guts of the API object - this actually makes the XHR calls and
202         // calls back
203         start: function(params, callback, url, browser, post, id) {
204                 if (null == url) {
205                         url = 'http://' + REST_HOST + '/services/rest/';
206                 }
207                 if (null == browser) { browser = false; }
208                 if (null == post) { post = false; }
209                 if (conf.console.request) {
210                     logStringMessage('API REQUEST: ' + params.toSource() +
211                                 ', ' + url);
212                 }
213
214                 // Escape params and sign the call
215                 params = api.escape_and_sign(params, post);
216
217                 // Build either a POST payload or a GET URL
218                 //   There is an assumption here that no one will be sending a
219                 //   file over GET
220                 var mstream = '';
221                 var boundary = '------deadbeef---deadbeef---' + Math.random();
222                 if (post) {
223                         mstream = Cc['@mozilla.org/io/multiplex-input-stream;1']
224                                 .createInstance(Ci.nsIMultiplexInputStream);
225                         var sstream;
226                         for (var p in params) {
227                                 sstream = Cc['@mozilla.org/io/string-input-stream;1']
228                                         .createInstance(Ci.nsIStringInputStream);
229                                 sstream.setData('--' + boundary +
230                                         '\r\nContent-Disposition: form-data; name="' +
231                                         p + '"', -1);
232                                 mstream.appendStream(sstream);
233                                 if ('object' == typeof params[p] && null != params[p]) {
234                                         sstream = Cc['@mozilla.org/io/string-input-stream;1']
235                                                 .createInstance(Ci.nsIStringInputStream);
236                                         sstream.setData('; filename="' + params[p].filename +
237                                                 '"\r\nContent-Type: application/octet-stream\r\n\r\n',
238                                                 -1);
239                                         mstream.appendStream(sstream);
240                                         var file = Cc['@mozilla.org/file/local;1']
241                                                 .createInstance(Ci.nsILocalFile);
242                                         file.initWithPath(params[p].path);
243                                         var fstream =
244                                                 Cc['@mozilla.org/network/file-input-stream;1']
245                                                 .createInstance(Ci.nsIFileInputStream);
246                                         fstream.init(file, 1, 1,
247                                                 Ci.nsIFileInputStream.CLOSE_ON_EOF);
248                                         var bstream =
249                                                 Cc['@mozilla.org/network/buffered-input-stream;1']
250                                                 .createInstance(Ci.nsIBufferedInputStream);
251                                         bstream.init(fstream, 4096);
252                                         mstream.appendStream(bstream);
253                                         sstream = Cc['@mozilla.org/io/string-input-stream;1']
254                                                 .createInstance(Ci.nsIStringInputStream);
255                                         sstream.setData('\r\n', -1);
256                                         mstream.appendStream(sstream);
257                                 } else {
258                                         sstream = Cc['@mozilla.org/io/string-input-stream;1']
259                                                 .createInstance(Ci.nsIStringInputStream);
260                                         sstream.setData('\r\n\r\n' + params[p] + '\r\n', -1);
261                                         mstream.appendStream(sstream);
262                                 }
263                         }
264                         sstream = Cc['@mozilla.org/io/string-input-stream;1']
265                                 .createInstance(Ci.nsIStringInputStream);
266                         sstream.setData('--' + boundary + '--', -1);
267                         mstream.appendStream(sstream);
268                         upload.progress_total = mstream.available() >> 10;
269                 } else {
270                         var args = [];
271                         for (var p in params) {
272                                 args.push(p + '=' + params[p]);
273                         }
274                         url += '?' + args.join('&');
275                 }
276
277                 // Open a browser
278                 //   Only GET requests are supported here
279                 if (browser) {
280                         return launch_browser(url);
281                 }
282
283                 // Use XHR
284                 //   GET and POST are supported here
285                 else {
286
287                         // Callback
288                         var xhr = new XMLHttpRequest();
289                         xhr.onreadystatechange = function() {
290                             if (4 == xhr.readyState && 200 != xhr.status) {
291                                 if (conf.console.error){
292                                         Components.utils.reportError('STATUS: ' + xhr.status + ', calling: ' + params.method);
293                                     }
294                             }
295                                 if (4 == xhr.readyState && 200 == xhr.status
296                                         && xhr.responseXML) {
297                                         try {
298                                                 var rsp = xhr.responseXML.documentElement;
299                                                 if (conf.console.error && (
300                                                         'object' != typeof rsp
301                                                         || 'ok' != rsp.getAttribute('stat'))) {
302                                                         Components.utils.reportError('API ERROR: ' +
303                                                                 xhr.responseText);
304                                                 } else if (conf.console.response) {
305                                                         logStringMessage('API RESPONSE: ' +
306                                                                 xhr.responseText);
307                                                 }
308
309                                                 // If this is a normal method call
310                                                 if (params.method) {
311
312                                                         // It returned normally, don't timeout
313                                                         window.clearTimeout(
314                                                                 api.timeouts[params['api_sig']]);
315                                                         delete api.timeouts[params['api_sig']];
316
317                                                         if ('function' == typeof callback) {
318                                                                 if (id) { callback(rsp, id); }
319                                                                 else { callback(rsp); }
320                                                         }
321                                                 }
322
323                                                 // If this is an upload
324                                                 else {
325                                                         upload._start(rsp, id);
326                                                 }
327
328                                         } catch (err) {
329                                                 Components.utils.reportError(err);
330                                         }
331                                 }
332                         };
333
334                         // Send the request
335                         xhr.open(post ? 'POST' : 'GET', url, true);
336                         if (post) {
337                                 xhr.setRequestHeader('Content-Type',
338                                         'multipart/form-data; boundary=' + boundary);
339                         } else {
340                                 xhr.setRequestHeader('Content-Type',
341                                         'application/x-www-form-urlencoded');
342                         }
343                         xhr.send(mstream);
344
345                         // Setup upload progress indicator
346                         if (post && id && !params.method) {
347                                 upload.progress_handle = window.setInterval(function() {
348                                         upload.progress(mstream, id);
349                                 }, conf.check);
350                         }
351
352                         // Setup timeout guard on everything else
353                         else if (params.method) {
354                                 api.timeouts[params['api_sig']] = window.setTimeout(
355                                 function() {
356                                         if (conf.console.timeout) {
357                                                 Components.utils.reportError('API TIMEOUT: ' +
358                                                         params.method);
359                                         }
360                                         if ('function' == typeof callback) {
361                                                 if (id) { callback(false, id); }
362                                                 else {callback('undefined' === typeof rsp ? false : rsp); }
363                                         }
364                                 }, conf.timeout);
365                         }
366
367                 }
368
369         }
370
371 };
372
373 // Used when preparing the params and the signature
374 //   The URL parameter controls whether data is escaped for inclusion
375 //   in a URL or not
376 var escape_utf8 = function(data, url) {
377         if (null == url) {
378                 url = true;
379         }
380         if ('' == data || null == data || undefined == data) {
381                 return '';
382         }
383         var chars = '0123456789abcdef';
384         data = data.toString();
385         var buffer = [];
386         var ii = data.length;
387         for (var i = 0; i < ii; ++i) {
388                 var c = data.charCodeAt(i);
389                 var bs = new Array();
390                 if (c > 0x10000) {
391                         bs[0] = 0xf0 | ((c & 0x1c0000) >>> 18);
392                         bs[1] = 0x80 | ((c & 0x3f000) >>> 12);
393                         bs[2] = 0x80 | ((c & 0xfc0) >>> 6);
394                         bs[3] = 0x80 | (c & 0x3f);
395                 } else if (c > 0x800) {
396                         bs[0] = 0xe0 | ((c & 0xf000) >>> 12);
397                         bs[1] = 0x80 | ((c & 0xfc0) >>> 6);
398                         bs[2] = 0x80 | (c & 0x3f);
399                 } else if (c > 0x80) {
400                         bs[0] = 0xc0 | ((c & 0x7c0) >>> 6);
401                         bs[1] = 0x80 | (c & 0x3f);
402                 } else {
403                         bs[0] = c;
404                 }
405                 var jj = bs.length
406                 if (1 < jj) {
407                         if (url) {
408                                 for (var j = 0; j < jj; ++j) {
409                                         var b = bs[j];
410                                         buffer.push('%' + chars.charAt((b & 0xf0) >>> 4) +
411                                                 chars.charAt(b & 0x0f));
412                                 }
413                         } else {
414                                 for (var j = 0; j < jj; ++j) {
415                                         buffer.push(String.fromCharCode(bs[j]));
416                                 }
417                         }
418                 } else {
419                         if (url) {
420                                 buffer.push(encodeURIComponent(String.fromCharCode(bs[0])));
421                         } else {
422                                 buffer.push(String.fromCharCode(bs[0]));
423                         }
424                 }
425         }
426         return buffer.join('');
427 };
Note: See TracBrowser for help on using the browser.