From 8f3499fd921091871ea56109d9cf90e1b91a2a2c Mon Sep 17 00:00:00 2001
From: Joseph McGuire <joseph.p.mcguire@googlemail.com>
Date: Wed, 19 Oct 2011 15:43:20 +0100
Subject: [PATCH] Added support for Queue API so that requests for short urls can be optionally queued and processed by a background process [#1313274]

---
 shorten.admin.inc |   15 ++++++-
 shorten.install   |    3 +-
 shorten.module    |  119 ++++++++++++++++++++++++++++++++++++++++++----------
 3 files changed, 112 insertions(+), 25 deletions(-)

diff --git a/shorten.admin.inc b/shorten.admin.inc
index c4e705d..7450fb6 100644
--- a/shorten.admin.inc
+++ b/shorten.admin.inc
@@ -87,6 +87,19 @@ function shorten_admin($form_state) {
       '#description' => t('Allow users to choose which service to use in the Shorten URLs block and page.'),
     );
   }
+  $queue_module_url = 'http://drupal.org/project/drupal_queue';
+  $form['shorten_workflow'] = array(
+    '#type' => 'radios',
+    '#title' => t('When to process'),
+    '#description' => t('The default is to request short URLs when a page is rendered which can slow down the time it take to deliver a page. If you have the Queue API module enabled then you can also queue request to process at a later time.'),
+    '#options' => array(
+      'render' => t('Request while the page is rendered.'),
+      'queue' => t('Queue requests to fetch at a later time. Requires <a href="@queue_module_url">Queue API</a>.', array('@queue_module_url' => $queue_module_url)),
+    ),
+    '#default_value' => module_exists('drupal_queue') ? variable_get('shorten_workflow', 'render') : 'render',
+    '#disabled' => module_exists('drupal_queue') ? FALSE : TRUE,
+  );
+
   if (module_exists('token')) {
     $form['shorten_generate_token'] = array(
       '#type' => 'checkbox',
@@ -258,4 +271,4 @@ function shorten_keys($form_state) {
     '#default_value' => variable_get('shorten_redirec', ''),
   );
   return system_settings_form($form);
-}
\ No newline at end of file
+}
diff --git a/shorten.install b/shorten.install
index ddf5a2e..a74525f 100644
--- a/shorten.install
+++ b/shorten.install
@@ -47,6 +47,7 @@ function shorten_uninstall() {
   variable_del('shorten_service_backup');
   variable_del('shorten_invisible_services');
   variable_del('shorten_cache_fail_duration');
+  variable_del('shorten_workflow');
 }
 
 /**
@@ -96,4 +97,4 @@ function shorten_update_6102() {
     variable_set('shorten_service_backup', 'Drupal ShortURL module');
   }
   return array();
-}
\ No newline at end of file
+}
diff --git a/shorten.module b/shorten.module
index 6f88dfc..f887be0 100644
--- a/shorten.module
+++ b/shorten.module
@@ -109,6 +109,17 @@ function shorten_flush_caches() {
 }
 
 /**
+ * Implementation of hook_cron_queue_info().
+ */
+function shorten_cron_queue_info() {
+  $queues['shorten'] = array(
+    'worker callback' => 'shorten_url_cron_queue',
+    'time' => variable_get('shorten_timeout', 3),
+  );
+  return $queues;
+}
+
+/**
  * Retrieves and beautifies the abbreviated URL.
  * This is the main API function of this module.
  *
@@ -118,22 +129,87 @@ function shorten_flush_caches() {
  * @param $service
  *   The service to use to abbreviate the URL.
  *   For services available by default, see shorten_shorten_service().
+ *
  * @return
  *   An abbreviated URL.
  */
-function shorten_url($original = '', $service = '') {
+function shorten_url($original = '', $service = '', $options = array()) {
+
+  $default_options = array(
+    'use queue' => TRUE,
+    'check cache' => TRUE,
+  );
+  $options = array_merge($default_options, $options);
+
   if (!$original) {
     $original = url($_GET['q'], array('absolute' => TRUE, 'alias' => !variable_get('shorten_use_alias', 1)));
   }
   if (!$service) {
     $service = variable_get('shorten_service', 'is.gd');
   }
-  //First try to retrieve a value from the cache.
-  $cached = cache_get($original, 'cache_shorten');
-  if (!empty($cached->data) && time() < $cached->expire) {
-    return $cached->data;
+
+  if ($options['check cache']) {
+    $cached = cache_get($original, 'cache_shorten');
+    if (!empty($cached->data)) {
+      return $cached->data;
+    }
   }
-  //We don't have anything cached for this URL, so try the primary service (or the one explicitly requested in the $service parameter).
+
+  // If queueing requests is supported and enabled then create an item and
+  // cache the original to avoid multiple queue items being created.
+  if ($options['use queue'] && variable_get('shorten_workflow', 'render') == 'queue' && module_exists('drupal_queue')) {
+    _shorten_queue_item($original, $service);
+    cache_set($original, $original, 'cache_shorten', CACHE_TEMPORARY);
+    return $original;
+  }
+
+  // There was no suitable cache and the queue is not being used so now we can
+  // request the short URL and cache the results.
+  if ($url = _shorten_url($original, $service)) {
+    $cache_duration = variable_get('shorten_cache_duration', 1814400);
+    $expire = is_numeric($cache_duration) ? (time() + $cache_duration) : CACHE_PERMANENT;
+  }
+  else {
+    // The URL failed to be shortened so cache the original for a short time.
+    $cache_duration = variable_get('shorten_cache_fail_duration', 1800);
+    $expire = time() + $cache_duration;
+    $url = $original;
+  }
+  cache_set($original, $url, 'cache_shorten', $expire);
+
+  // Announce that we have a new short URL and return it.
+  module_invoke_all('shorten_create', $original, $url, $service);
+  return $url;
+}
+
+/**
+ * Helper function to create a shorten Queue API item.
+ */
+function _shorten_queue_item($original, $service) {
+  $queue = DrupalQueue::get('shorten');
+  $item = array(
+    'original' => $original,
+    'service' => $service,
+  );
+  $queue->createItem($item);
+}
+
+/**
+ * Helper function to call the shortening service.
+ *
+ * Method also check a secondary service if the first fails.
+ *
+ * @param $original
+ *   The URL of the page for which to create the abbreviated URL.  If not passed
+ *   uses the current page.
+ * @param $service
+ *   The service to use to abbreviate the URL.
+ *   For services available by default, see shorten_shorten_service().
+ *
+ * @return
+ *   An abbreviated URL or FALSE if one could not be generated.
+ */
+function _shorten_url($original, $service) {
   $services = module_invoke_all('shorten_service');
   if (isset($services[$service])) {
     $url = _shorten_get_url($original, $services[$service], $service);
@@ -144,9 +220,9 @@ function shorten_url($original = '', $service = '') {
     if (isset($services[$service])) {
       $url = _shorten_get_url($original, $services[$service], $service);
     }
-    //If the secondary service fails, use the original URL.
+    //If the secondary service fails return FALSE.
     if (!$url) {
-      $url = $original;
+      return FALSE;
     }
   }
   $url = trim($url); //Redundant for most services.
@@ -165,20 +241,6 @@ function shorten_url($original = '', $service = '') {
       }
     }
   }
-  //Cache the result for a limited time.
-  $cache_duration = variable_get('shorten_cache_duration', 1814400);
-  if ($url == $original) {
-    $expire = time() + variable_get('shorten_cache_fail_duration', 1800);
-  }
-  elseif (is_numeric($cache_duration)) {
-    $expire = time() + $cache_duration;
-  }
-  else {
-    $expire = CACHE_PERMANENT;
-  }
-  cache_set($original, $url, 'cache_shorten', $expire);
-  //Announce that we have a new short URL and return it.
-  module_invoke_all('shorten_create', $original, $url, $service);
   return $url;
 }
 
@@ -242,6 +304,17 @@ function _shorten_get_url($original, $api, $service) {
 }
 
 /**
+ * Queue API Worker.
+ */
+function shorten_url_cron_queue($item) {
+  $options = array(
+    'use queue' => FALSE,
+    'check cache' => FALSE,
+  );
+  shorten_url($item['original'], $item['service'], $options);
+}
+
+/**
  * Implementation of hook_shorten_service().
  */
 function shorten_shorten_service() {
@@ -670,4 +743,4 @@ function shorten_token_values($type, $data = NULL, $options = array()) {
       'url' => shorten_url(url('node/'. $data->nid, array('absolute' => TRUE, 'alias' => variable_get('shorten_use_alias', 1)))),
     );
   }
-}
\ No newline at end of file
+}
-- 
1.7.4.1

