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

Revision 429, 10.9 kB (checked in by jdecq, 1 year ago)

- add toOpenWindowByType needed for Vemkman
- add some logging in api.start for onreadystatechange when status is not 200
- add some check for rsp in the timeout handler

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                         Cc['@mozilla.org/consoleservice;1']
211                                 .getService(Ci.nsIConsoleService)
212                                 .logStringMessage('API REQUEST: ' + params.toSource() +
213                                 ', ' + url);
214                 }
215
216                 // Escape params and sign the call
217                 params = api.escape_and_sign(params, post);
218
219                 // Build either a POST payload or a GET URL
220                 //   There is an assumption here that no one will be sending a
221                 //   file over GET
222                 var mstream = '';
223                 var boundary = '------deadbeef---deadbeef---' + Math.random();
224                 if (post) {
225                         mstream = Cc['@mozilla.org/io/multiplex-input-stream;1']
226                                 .createInstance(Ci.nsIMultiplexInputStream);
227                         var sstream;
228                         for (var p in params) {
229                                 sstream = Cc['@mozilla.org/io/string-input-stream;1']
230                                         .createInstance(Ci.nsIStringInputStream);
231                                 sstream.setData('--' + boundary +
232                                         '\r\nContent-Disposition: form-data; name="' +
233                                         p + '"', -1);
234                                 mstream.appendStream(sstream);
235                                 if ('object' == typeof params[p] && null != params[p]) {
236                                         sstream = Cc['@mozilla.org/io/string-input-stream;1']
237                                                 .createInstance(Ci.nsIStringInputStream);
238                                         sstream.setData('; filename="' + params[p].filename +
239                                                 '"\r\nContent-Type: application/octet-stream\r\n\r\n',
240                                                 -1);
241                                         mstream.appendStream(sstream);
242                                         var file = Cc['@mozilla.org/file/local;1']
243                                                 .createInstance(Ci.nsILocalFile);
244                                         file.initWithPath(params[p].path);
245                                         var fstream =
246                                                 Cc['@mozilla.org/network/file-input-stream;1']
247                                                 .createInstance(Ci.nsIFileInputStream);
248                                         fstream.init(file, 1, 1,
249                                                 Ci.nsIFileInputStream.CLOSE_ON_EOF);
250                                         var bstream =
251                                                 Cc['@mozilla.org/network/buffered-input-stream;1']
252                                                 .createInstance(Ci.nsIBufferedInputStream);
253                                         bstream.init(fstream, 4096);
254                                         mstream.appendStream(bstream);
255                                         sstream = Cc['@mozilla.org/io/string-input-stream;1']
256                                                 .createInstance(Ci.nsIStringInputStream);
257                                         sstream.setData('\r\n', -1);
258                                         mstream.appendStream(sstream);
259                                 } else {
260                                         sstream = Cc['@mozilla.org/io/string-input-stream;1']
261                                                 .createInstance(Ci.nsIStringInputStream);
262                                         sstream.setData('\r\n\r\n' + params[p] + '\r\n', -1);
263                                         mstream.appendStream(sstream);
264                                 }
265                         }
266                         sstream = Cc['@mozilla.org/io/string-input-stream;1']
267                                 .createInstance(Ci.nsIStringInputStream);
268                         sstream.setData('--' + boundary + '--', -1);
269                         mstream.appendStream(sstream);
270                         upload.progress_total = mstream.available() >> 10;
271                 } else {
272                         var args = [];
273                         for (var p in params) {
274                                 args.push(p + '=' + params[p]);
275                         }
276                         url += '?' + args.join('&');
277                 }
278
279                 // Open a browser
280                 //   Only GET requests are supported here
281                 if (browser) {
282                         return launch_browser(url);
283                 }
284
285                 // Use XHR
286                 //   GET and POST are supported here
287                 else {
288
289                         // Callback
290                         var xhr = new XMLHttpRequest();
291                         xhr.onreadystatechange = function() {
292                             if (4 == xhr.readyState && 200 != xhr.status) {
293                                 if (conf.console.error){
294                                         Components.utils.reportError('STATUS: ' + xhr.status + ', calling: ' + params.method);
295                                     }
296                             }
297                                 if (4 == xhr.readyState && 200 == xhr.status
298                                         && xhr.responseXML) {
299                                         try {
300                                                 var rsp = xhr.responseXML.documentElement;
301                                                 if (conf.console.error && (
302                                                         'object' != typeof rsp
303                                                         || 'ok' != rsp.getAttribute('stat'))) {
304                                                         Components.utils.reportError('API ERROR: ' +
305                                                                 xhr.responseText);
306                                                 } else if (conf.console.response) {
307                                                         Cc['@mozilla.org/consoleservice;1']
308                                                                 .getService(Ci.nsIConsoleService)
309                                                                 .logStringMessage('API RESPONSE: ' +
310                                                                 xhr.responseText);
311                                                 }
312
313                                                 // If this is a normal method call
314                                                 if (params.method) {
315
316                                                         // It returned normally, don't timeout
317                                                         window.clearTimeout(
318                                                                 api.timeouts[params['api_sig']]);
319                                                         delete api.timeouts[params['api_sig']];
320
321                                                         if ('function' == typeof callback) {
322                                                                 if (id) { callback(rsp, id); }
323                                                                 else { callback(rsp); }
324                                                         }
325                                                 }
326
327                                                 // If this is an upload
328                                                 else {
329                                                         upload._start(rsp, id);
330                                                 }
331
332                                         } catch (err) {
333                                                 Components.utils.reportError(err);
334                                         }
335                                 }
336                         };
337
338                         // Send the request
339                         xhr.open(post ? 'POST' : 'GET', url, true);
340                         if (post) {
341                                 xhr.setRequestHeader('Content-Type',
342                                         'multipart/form-data; boundary=' + boundary);
343                         } else {
344                                 xhr.setRequestHeader('Content-Type',
345                                         'application/x-www-form-urlencoded');
346                         }
347                         xhr.send(mstream);
348
349                         // Setup upload progress indicator
350                         if (post && id && !params.method) {
351                                 upload.progress_handle = window.setInterval(function() {
352                                         upload.progress(mstream, id);
353                                 }, conf.check);
354                         }
355
356                         // Setup timeout guard on everything else
357                         else if (params.method) {
358                                 api.timeouts[params['api_sig']] = window.setTimeout(
359                                 function() {
360                                         if (conf.console.timeout) {
361                                                 Components.utils.reportError('API TIMEOUT: ' +
362                                                         params.method);
363                                         }
364                                         if ('function' == typeof callback) {
365                                                 if (id) { callback(false, id); }
366                                                 else {callback('undefined' === typeof rsp ? false : rsp); }
367                                         }
368                                 }, conf.timeout);
369                         }
370
371                 }
372
373         }
374
375 };
376
377 // Used when preparing the params and the signature
378 //   The URL parameter controls whether data is escaped for inclusion
379 //   in a URL or not
380 var escape_utf8 = function(data, url) {
381         if (null == url) {
382                 url = true;
383         }
384         if ('' == data || null == data || undefined == data) {
385                 return '';
386         }
387         var chars = '0123456789abcdef';
388         data = data.toString();
389         var buffer = [];
390         var ii = data.length;
391         for (var i = 0; i < ii; ++i) {
392                 var c = data.charCodeAt(i);
393                 var bs = new Array();
394                 if (c > 0x10000) {
395                         bs[0] = 0xf0 | ((c & 0x1c0000) >>> 18);
396                         bs[1] = 0x80 | ((c & 0x3f000) >>> 12);
397                         bs[2] = 0x80 | ((c & 0xfc0) >>> 6);
398                         bs[3] = 0x80 | (c & 0x3f);
399                 } else if (c > 0x800) {
400                         bs[0] = 0xe0 | ((c & 0xf000) >>> 12);
401                         bs[1] = 0x80 | ((c & 0xfc0) >>> 6);
402                         bs[2] = 0x80 | (c & 0x3f);
403                 } else if (c > 0x80) {
404                         bs[0] = 0xc0 | ((c & 0x7c0) >>> 6);
405                         bs[1] = 0x80 | (c & 0x3f);
406                 } else {
407                         bs[0] = c;
408                 }
409                 var jj = bs.length
410                 if (1 < jj) {
411                         if (url) {
412                                 for (var j = 0; j < jj; ++j) {
413                                         var b = bs[j];
414                                         buffer.push('%' + chars.charAt((b & 0xf0) >>> 4) +
415                                                 chars.charAt(b & 0x0f));
416                                 }
417                         } else {
418                                 for (var j = 0; j < jj; ++j) {
419                                         buffer.push(String.fromCharCode(bs[j]));
420                                 }
421                         }
422                 } else {
423                         if (url) {
424                                 buffer.push(encodeURIComponent(String.fromCharCode(bs[0])));
425                         } else {
426                                 buffer.push(String.fromCharCode(bs[0]));
427                         }
428                 }
429         }
430         return buffer.join('');
431 };
Note: See TracBrowser for help on using the browser.