[Pkg-mozext-commits] [gcontactsync] 04/11: Issue #63: Throttle setPhoto requests

David Prévot taffit at moszumanska.debian.org
Tue Mar 24 22:41:22 UTC 2015


This is an automated email from the git hooks/post-receive script.

taffit pushed a commit to branch master
in repository gcontactsync.

commit ae9195173dde99ead555345bd7e45062eb9d175f
Author: Josh Geenen <joshgeenen at gmail.com>
Date:   Sun Mar 22 13:59:08 2015 -0500

    Issue #63: Throttle setPhoto requests
---
 src/content/GContact.js                  |  99 +++++++++++++++---------------
 src/content/Sync.js                      | 101 +++++++++++++++++++++----------
 src/locale/en-US/gcontactsync.properties |   1 +
 3 files changed, 119 insertions(+), 82 deletions(-)

diff --git a/src/content/GContact.js b/src/content/GContact.js
index c43f794..63e2ef6 100644
--- a/src/content/GContact.js
+++ b/src/content/GContact.js
@@ -802,24 +802,25 @@ com.gContactSync.GContact.prototype = {
     return val.substr(val.lastIndexOf("/") + 1);
   },
   /**
-   * Sets the photo for this contact.  Note that this may not immediately take
+   * Sets the photo for this contact.  Note that this will not immediately take
    * effect as contacts must be added to Google and then retrieved before a
-   * photo can be added.
+   * photo can be added, and Google throttles requests.
    *
    * @param aURI {string|nsIURI} A string with the URI of a contact photo.
    */
   setPhoto: function GContact_setPhoto(aURI) {
     com.gContactSync.LOGGER.VERBOSE_LOG("Entering GContact.setPhoto:");
-    var photoInfo = this.getPhotoInfo();
     // If the URI is empty or a chrome URL remove the photo, if present
     // TODO - this should probably just check if it is the default photo
     if (!aURI) {
+      var photoInfo = this.getPhotoInfo();
       // Easy case: URI is empty and this contact doesn't have a photo
       if (!photoInfo || !(photoInfo.etag)) {
         com.gContactSync.LOGGER.VERBOSE_LOG(" * URI is empty, contact has no photo");
         return;
       }
       com.gContactSync.LOGGER.VERBOSE_LOG(" * URI is empty, photo will be removed");
+      // TODO - this needs to be queued
       // Remove the photo
       var httpReq = new com.gContactSync.GHttpRequest("delete",
                                                       com.gContactSync.Sync.mCurrentAuthToken,
@@ -837,54 +838,54 @@ com.gContactSync.GContact.prototype = {
       httpReq.mOn503 = com.gContactSync.Sync.m503Function;
       httpReq.addHeaderItem("If-Match", "*");
       httpReq.send();
+    } else {
+      // The URI exists, so update or add the photo
+      // NOTE: A photo cannot be added until the contact has been added
+      com.gContactSync.LOGGER.VERBOSE_LOG(" * Photo will be uploaded");
+      this.mNewPhotoURI = aURI;
+    }
+  },
+  /**
+   * Uploads the photo at the given URI.
+   *
+   * @param aURI {string|nsIURI} A string with the URI of a contact photo.
+   */
+  uploadPhoto: function GContact_uploadPhoto(aURI) {
+    var photoInfo = this.getPhotoInfo();
+    // Send the PUT request
+    // TODO - this really needs error handling...
+    var ios = Components.classes["@mozilla.org/network/io-service;1"]
+                        .getService(Components.interfaces.nsIIOService),
+        outChannel = ios.newChannel(photoInfo.url, null, null),
+        inChannel  = aURI instanceof Components.interfaces.nsIURI ?
+                       ios.newChannelFromURI(aURI) :
+                       ios.newChannel(aURI, null, null);
+    outChannel = outChannel.QueryInterface(Components.interfaces.nsIHttpChannel);
+    // Set the upload data
+    outChannel = outChannel.QueryInterface(Components.interfaces.nsIUploadChannel);
+    // Set the input stream as the photo URI
+    // See https://www.mozdev.org/bugs/show_bug.cgi?id=22757 for the try/catch
+    // block, I didn't see a way to tell if the item pointed to by aURI exists
+    try {
+      outChannel.setUploadStream(inChannel.open(), photoInfo.type, -1);
+    }
+    catch (e) {
+      com.gContactSync.LOGGER.LOG_WARNING("The photo at '" + aURI + "' doesn't exist", e);
       return;
     }
-    // The URI exists, so update or add the photo
-    // NOTE: A photo cannot be added until the contact has been added
-    else {
-      // If this is a new contact then nothing can be done until the contact is
-      // added to Google
-      if (this.mIsNew || !photoInfo) {
-        com.gContactSync.LOGGER.VERBOSE_LOG(" * Photo will be added after the contact is created");
-        this.mNewPhotoURI = aURI;
-        return;
-      }
-      com.gContactSync.LOGGER.VERBOSE_LOG(" * Photo will be updated");
-      // Otherwise send the PUT request
-      // TODO - this really needs error handling...
-      var ios = Components.classes["@mozilla.org/network/io-service;1"]
-                          .getService(Components.interfaces.nsIIOService),
-          outChannel = ios.newChannel(photoInfo.url, null, null),
-          inChannel  = aURI instanceof Components.interfaces.nsIURI ?
-                         ios.newChannelFromURI(aURI) :
-                         ios.newChannel(aURI, null, null);
-      outChannel = outChannel.QueryInterface(Components.interfaces.nsIHttpChannel);
-      // Set the upload data
-      outChannel = outChannel.QueryInterface(Components.interfaces.nsIUploadChannel);
-      // Set the input stream as the photo URI
-      // See https://www.mozdev.org/bugs/show_bug.cgi?id=22757 for the try/catch
-      // block, I didn't see a way to tell if the item pointed to by aURI exists
-      try {
-        outChannel.setUploadStream(inChannel.open(), photoInfo.type, -1);
-      }
-      catch (e) {
-        com.gContactSync.LOGGER.LOG_WARNING("The photo at '" + aURI + "' doesn't exist", e);
-        return;
-      }
-      // set the request type to PUT (this has to be after setting the upload data)
-      outChannel = outChannel.QueryInterface(Components.interfaces.nsIHttpChannel);
-      outChannel.requestMethod = "PUT";
-      // Setup the header: Authorization and Content-Type: image/*
-      outChannel.setRequestHeader("Authorization", com.gContactSync.Sync.mCurrentAuthToken, false);
-      outChannel.setRequestHeader("Content-Type",  photoInfo.type, false);
-      outChannel.setRequestHeader("If-Match",      "*", false);
-      outChannel.open();
-      try {
-        com.gContactSync.LOGGER.VERBOSE_LOG(" * Update status: " + outChannel.responseStatus);
-      }
-      catch (e) {
-        com.gContactSync.LOGGER.LOG_WARNING(" * outChannel.responseStatus failed", e);
-      }
+    // set the request type to PUT (this has to be after setting the upload data)
+    outChannel = outChannel.QueryInterface(Components.interfaces.nsIHttpChannel);
+    outChannel.requestMethod = "PUT";
+    // Setup the header: Authorization and Content-Type: image/*
+    outChannel.setRequestHeader("Authorization", com.gContactSync.Sync.mCurrentAuthToken, false);
+    outChannel.setRequestHeader("Content-Type",  photoInfo.type, false);
+    outChannel.setRequestHeader("If-Match",      "*", false);
+    outChannel.open();
+    try {
+      com.gContactSync.LOGGER.VERBOSE_LOG(" * Update status: " + outChannel.responseStatus);
+    }
+    catch (e) {
+      com.gContactSync.LOGGER.LOG_WARNING(" * outChannel.responseStatus failed", e);
     }
   },
   /**
diff --git a/src/content/Sync.js b/src/content/Sync.js
index c0bcd61..00f75a4 100644
--- a/src/content/Sync.js
+++ b/src/content/Sync.js
@@ -47,6 +47,8 @@ com.gContactSync.Sync = {
   mContactsToDelete: [],
   /** New contacts to add to Google */
   mContactsToAdd:    [],
+  /** Contacts whose photos need to be written */
+  mContactsToUploadPhoto: [],
   /** Contacts to update */
   mContactsToUpdate: [],
   /** Groups to delete */
@@ -442,12 +444,12 @@ com.gContactSync.Sync = {
       com.gContactSync.Sync.finish("Max Contacts too low...resynchronizing", true);
       return;
     }
-    com.gContactSync.Sync.mContactsToAdd    = [];
+    com.gContactSync.Sync.mContactsToAdd = [];
+    com.gContactSync.Sync.mContactsToUploadPhoto = [];
     com.gContactSync.Sync.mContactsToDelete = [];
     com.gContactSync.Sync.mContactsToUpdate = [];
     var gContact,
-     // get the strings outside of the loop so they are only found once
-        gContacts   = {},
+        gContacts = {},
         gContactInfo = {},
         abCardInfo = [];
 
@@ -727,22 +729,15 @@ com.gContactSync.Sync = {
           gcontact = new com.gContactSync.GContact(httpReq.responseXML);
       contact.setValue('GoogleID', gcontact.getID(true));
       contact.update();
-      // if photos are allowed to be uploaded to Google then do so
-      if (com.gContactSync.Preferences.mSyncPrefs.sendPhotos.value) {
-        gcontact.setPhoto(com.gContactSync.Sync.mNewPhotoURI);
-      }
-      // reset the new photo URI variable
-      com.gContactSync.Sync.mNewPhotoURI = null;
-      // NOTE - Google has an undocumented limit on the rate at which photos
-      // can be added.  Add a small wait here.
+      // if photos are allowed to be uploaded to Google then queue the request
       if (com.gContactSync.Preferences.mSyncPrefs.sendPhotos.value &&
-          com.gContactSync.Preferences.mSyncPrefs.newContactPhotoDelay.value > 0) {
-        setTimeout(com.gContactSync.Sync.processAddQueue,
-                   com.gContactSync.Preferences.mSyncPrefs.newContactPhotoDelay.value);
-      } else {
-        com.gContactSync.Sync.delayedProcessQueue(com.gContactSync.Sync.processAddQueue);
+          com.gContactSync.Sync.mNewPhotoURI) {
+        com.gContactSync.Sync.mContactsToUploadPhoto.push({abCard: com.gContactSync.ContactConverter.mCurrentCard,
+                                                          gContact: gcontact,
+                                                          uri: com.gContactSync.Sync.mNewPhotoURI});
       }
-    }
+      com.gContactSync.Sync.delayedProcessQueue(com.gContactSync.Sync.processAddQueue);
+    };
     httpReq.mOnCreated = onCreated;
     httpReq.mOnError   = function contactCreatedError(httpReq) {
       com.gContactSync.LOGGER.LOG_ERROR('Error while adding contact',
@@ -755,26 +750,21 @@ com.gContactSync.Sync = {
   },
   /**
    * Updates all cards to Google included in the mContactsToUpdate array one at
-   * a time to avoid timing conflicts.  Calls
-   * com.gContactSync.Sync.syncNextUser() when done.
+   * a time to avoid timing conflicts.
    */
   processUpdateQueue: function Sync_processUpdateQueue() {
+
     var ab = com.gContactSync.Sync.mCurrentAb;
-    if (!com.gContactSync.Sync.mContactsToUpdate
-        || com.gContactSync.Sync.mContactsToUpdate.length == 0
-        || ab.mPrefs.readOnly == "true") {
-      if (com.gContactSync.Sync.mAddressBooks[com.gContactSync.Sync.mIndex]) {
-        var delay = com.gContactSync.Preferences.mSyncPrefs.accountDelay.value;
-        com.gContactSync.LOGGER.LOG("**About to wait " + delay +
-                                    " ms before synchronizing the next account**");
-        com.gContactSync.Overlay.setStatusBarText(com.gContactSync.StringBundle.getStr("waiting"));
-        setTimeout(com.gContactSync.Sync.syncNextUser, delay);
-      }
-      else {
-        com.gContactSync.Sync.syncNextUser();
-      }
+
+    if (!com.gContactSync.Sync.mContactsToUpdate ||
+        (com.gContactSync.Sync.mContactsToUpdate.length === 0) ||
+        (ab.mPrefs.readOnly === "true")) {
+
+      com.gContactSync.LOGGER.LOG("***Uploading contact photos to Google***");
+      com.gContactSync.Sync.processUpdatePhotoQueue();
       return;
     }
+
     com.gContactSync.Overlay.setStatusBarText(com.gContactSync.StringBundle.getStr("updating") + " " +
                                               com.gContactSync.Sync.mContactsToUpdate.length + " " +
                                               com.gContactSync.StringBundle.getStr("remaining"));
@@ -792,8 +782,11 @@ com.gContactSync.Sync = {
     }
 
     var string = com.gContactSync.serialize(gContact.xml);
-    if (com.gContactSync.Preferences.mSyncPrefs.verboseLog.value)
+    if (com.gContactSync.Preferences.mSyncPrefs.verboseLog.value) {
       com.gContactSync.LOGGER.LOG(" * XML of contact being updated:\n" + string + "\n");
+    }
+    com.gContactSync.Sync.mNewPhotoURI = com.gContactSync.Preferences.mSyncPrefs.sendPhotos.value ?
+                                         gContact.mNewPhotoURI : null;
     var httpReq = new com.gContactSync.GHttpRequest("update",
                                                     com.gContactSync.Sync.mCurrentAuthToken,
                                                     editURL,
@@ -801,6 +794,16 @@ com.gContactSync.Sync = {
                                                     com.gContactSync.Sync.mCurrentUsername);
     httpReq.addHeaderItem("If-Match", "*");
     httpReq.mOnSuccess = function processUpdateSuccess(httpReq) {
+
+      // if photos are allowed to be uploaded to Google then queue the request
+      if (com.gContactSync.Preferences.mSyncPrefs.sendPhotos.value &&
+          com.gContactSync.Sync.mNewPhotoURI) {
+
+        var gcontact = new com.gContactSync.GContact(httpReq.responseXML);
+        com.gContactSync.Sync.mContactsToUploadPhoto.push({abCard: com.gContactSync.ContactConverter.mCurrentCard,
+                                                          gContact: gcontact,
+                                                          uri: com.gContactSync.Sync.mNewPhotoURI});
+      }
       com.gContactSync.Sync.delayedProcessQueue(com.gContactSync.Sync.processUpdateQueue);
     };
     httpReq.mOnError   = function processUpdateError(httpReq) {
@@ -813,6 +816,38 @@ com.gContactSync.Sync = {
     httpReq.send();
   },
   /**
+   * Uploads new and updated photos to Google.
+   * Calls com.gContactSync.Sync.syncNextUser() when done.
+   */
+  processUpdatePhotoQueue: function Sync_processUpdatePhotoQueue() {
+
+    var ab = com.gContactSync.Sync.mCurrentAb;
+
+    if (!com.gContactSync.Sync.mContactsToUploadPhoto ||
+        (com.gContactSync.Sync.mContactsToUploadPhoto.length === 0) ||
+        (ab.mPrefs.readOnly === "true")) {
+
+      if (com.gContactSync.Sync.mAddressBooks[com.gContactSync.Sync.mIndex]) {
+        var delay = com.gContactSync.Preferences.mSyncPrefs.accountDelay.value;
+        com.gContactSync.LOGGER.LOG("**About to wait " + delay +
+                                    " ms before synchronizing the next account**");
+        com.gContactSync.Overlay.setStatusBarText(com.gContactSync.StringBundle.getStr("waiting"));
+        setTimeout(com.gContactSync.Sync.syncNextUser, delay);
+      } else {
+        com.gContactSync.Sync.syncNextUser();
+      }
+      return;
+    }
+
+    com.gContactSync.Overlay.setStatusBarText(com.gContactSync.StringBundle.getStr("uploadingPhotos") + " " +
+                                              com.gContactSync.Sync.mContactsToAdd.length + " " +
+                                              com.gContactSync.StringBundle.getStr("remaining"));
+    var obj = com.gContactSync.Sync.mContactsToUploadPhoto.shift();
+    com.gContactSync.LOGGER.LOG("\n" + obj.abCard.getName());
+    obj.gContact.uploadPhoto(obj.uri);
+    com.gContactSync.Sync.delayedProcessQueue(com.gContactSync.Sync.processUpdatePhotoQueue);
+  },
+  /**
    * Syncs all contact groups with mailing lists.
    * @param aAtom {XML} The ATOM/XML feed of Groups.
    */
diff --git a/src/locale/en-US/gcontactsync.properties b/src/locale/en-US/gcontactsync.properties
index 0a4d73d..7b84606 100644
--- a/src/locale/en-US/gcontactsync.properties
+++ b/src/locale/en-US/gcontactsync.properties
@@ -20,6 +20,7 @@ waiting=Waiting to synchronize the next account...
 deleting=Deleting contacts from Google:
 updating=Updating contacts from Google:
 adding=Adding contacts to Google:
+uploadingPhotos=Uploading photos to Google:
 remaining=remaining.
 pleaseAuth=Please login before trying to sync contacts.
 offlineStatusText=Unable to sync contacts while offline.

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-mozext/gcontactsync.git



More information about the Pkg-mozext-commits mailing list