[BUGFIX] Fix decrementing of AJAX requests in extension scanner 39/58539/5
authorAndreas Fernandez <a.fernandez@scripting-base.de>
Mon, 1 Oct 2018 17:55:00 +0000 (19:55 +0200)
committerStefan Neufeind <typo3.neufeind@speedpartner.de>
Mon, 1 Oct 2018 20:11:30 +0000 (22:11 +0200)
The queueing of AJAX requests in the extension scanner has some flaws
which causes the scanner to refuse another scan request.

The counter of pending requests is now always decremented, not only if
the amount of requests equals the threshold. Also, it's now checked if
there is any item in the request queue before shifting.

Instead of overriding the `success` and `error` callback, only `complete`
is now overridden, as this callback is executed on any return state.

To make the queueing part better maintainable and reusable, the code has
been moved into a separate module.

Resolves: #86523
Related: #86436
Releases: master
Change-Id: Ifa26ad7ce3bd81497c43b8606b902d467bdd1dda
Reviewed-on: https://review.typo3.org/58539
Reviewed-by: Richard Haeser <richard@maxserv.com>
Tested-by: Richard Haeser <richard@maxserv.com>
Reviewed-by: Wouter Wolters <typo3@wouterwolters.nl>
Reviewed-by: Frank Naegler <frank.naegler@typo3.org>
Tested-by: Frank Naegler <frank.naegler@typo3.org>
Reviewed-by: Stefan Neufeind <typo3.neufeind@speedpartner.de>
Tested-by: Stefan Neufeind <typo3.neufeind@speedpartner.de>
typo3/sysext/install/Resources/Public/JavaScript/Modules/AjaxQueue.js [new file with mode: 0644]
typo3/sysext/install/Resources/Public/JavaScript/Modules/ExtensionScanner.js

diff --git a/typo3/sysext/install/Resources/Public/JavaScript/Modules/AjaxQueue.js b/typo3/sysext/install/Resources/Public/JavaScript/Modules/AjaxQueue.js
new file mode 100644 (file)
index 0000000..26e5848
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+/**
+ * Module: TYPO3/CMS/Install/AjaxQueue
+ */
+define(['jquery'], function($) {
+  'use strict';
+
+  return {
+    requestCount: 0,
+    threshold: 10,
+    queue: [],
+
+    add: function(payload) {
+      var oldComplete = payload.complete;
+      var that = this;
+      payload.complete = function(jqXHR, textStatus) {
+        if (that.queue.length > 0 && that.requestCount <= that.threshold) {
+          $.ajax(that.queue.shift()).always(function() {
+            that.decrementRequestCount();
+          });
+        } else {
+          that.decrementRequestCount();
+        }
+
+        if (oldComplete) {
+          oldComplete(jqXHR, textStatus);
+        }
+      };
+
+      if (this.requestCount >= this.threshold) {
+        this.queue.push(payload);
+      } else {
+        this.incrementRequestCount();
+        $.ajax(payload);
+      }
+    },
+
+    incrementRequestCount: function() {
+      this.requestCount++;
+    },
+
+    decrementRequestCount: function() {
+      if (this.requestCount > 0) {
+        this.requestCount--;
+      }
+    },
+  };
+});
index 0e60536..8cf71ca 100644 (file)
@@ -16,8 +16,9 @@
  */
 define(['jquery',
   'TYPO3/CMS/Install/Router',
-  'TYPO3/CMS/Backend/Notification'
-], function($, Router, Notification) {
+  'TYPO3/CMS/Backend/Notification',
+  'TYPO3/CMS/Install/AjaxQueue'
+], function($, Router, Notification, AjaxQueue) {
   'use strict';
 
   return {
@@ -27,10 +28,6 @@ define(['jquery',
     selectorExtensionContainer: '.t3js-extensionScanner-extension',
     selectorNumberOfFiles: '.t3js-extensionScanner-number-of-files',
     selectorScanSingleTrigger: '.t3js-extensionScanner-scan-single',
-    ajaxRequests: 0,
-    ajaxQueue: [],
-    ajaxActive: 0,
-    ajaxMaxConcurrent: 10,
 
     initialize: function(currentModal) {
       var self = this;
@@ -59,38 +56,9 @@ define(['jquery',
       });
     },
 
-    addAjaxCallToQueue: function(obj) {
-      this.ajaxRequests++;
-      var oldSuccess = obj.success;
-      var oldError = obj.error;
-      var that = this;
-      var callback = function() {
-        that.ajaxRequests--;
-        if (that.ajaxActive === that.ajaxMaxConcurrent) {
-          $.ajax(that.ajaxQueue.shift());
-        } else {
-          that.ajaxActive--;
-        }
-      };
-      obj.success = function(resp, xhr, status) {
-        callback();
-        if (oldSuccess) oldSuccess(resp, xhr, status);
-      };
-      obj.error = function(xhr, status, error) {
-        callback();
-        if (oldError) oldError(xhr, status, error);
-      };
-      if (this.ajaxActive === this.ajaxMaxConcurrent) {
-        this.ajaxQueue.push(obj);
-      } else {
-        this.ajaxActive++;
-        $.ajax(obj);
-      }
-    },
-
     getData: function() {
       var modalContent = this.currentModal.find(this.selectorModalBody);
-      this.addAjaxCallToQueue(
+      AjaxQueue.add(
         {
           url: Router.getUrl('extensionScannerGetData'),
           cache: false,
@@ -184,7 +152,7 @@ define(['jquery',
 
       if (numberOfScannedExtensions === numberOfExtensions) {
         Notification.success('Scan finished', 'All extensions have been scanned');
-        this.addAjaxCallToQueue(
+        AjaxQueue.add(
           {
             url: Router.getUrl(),
             method: 'POST',
@@ -241,8 +209,7 @@ define(['jquery',
       $extensionContainer.find('.t3js-extensionScanner-extension-body-ignored-files').empty().text('0');
       $extensionContainer.find('.t3js-extensionScanner-extension-body-ignored-lines').empty().text('0');
       this.setProgressForAll();
-      var that = this;
-      this.addAjaxCallToQueue(
+      AjaxQueue.add(
         {
           url: Router.getUrl(),
           method: 'POST',
@@ -262,7 +229,7 @@ define(['jquery',
                 $extensionContainer.find('.t3js-extensionScanner-extension-body').text('');
                 var doneFiles = 0;
                 data.files.forEach(function(file) {
-                  that.addAjaxCallToQueue(
+                  AjaxQueue.add(
                     {
                       method: 'POST',
                       data: {