diff options
Diffstat (limited to 'lisp/url/url-queue.el')
| -rw-r--r-- | lisp/url/url-queue.el | 61 |
1 files changed, 53 insertions, 8 deletions
diff --git a/lisp/url/url-queue.el b/lisp/url/url-queue.el index 534c94b4d52..9dfee485918 100644 --- a/lisp/url/url-queue.el +++ b/lisp/url/url-queue.el | |||
| @@ -30,6 +30,7 @@ | |||
| 30 | 30 | ||
| 31 | (eval-when-compile (require 'cl)) | 31 | (eval-when-compile (require 'cl)) |
| 32 | (require 'browse-url) | 32 | (require 'browse-url) |
| 33 | (require 'url-parse) | ||
| 33 | 34 | ||
| 34 | (defcustom url-queue-parallel-processes 6 | 35 | (defcustom url-queue-parallel-processes 6 |
| 35 | "The number of concurrent processes." | 36 | "The number of concurrent processes." |
| @@ -49,21 +50,47 @@ | |||
| 49 | 50 | ||
| 50 | (defstruct url-queue | 51 | (defstruct url-queue |
| 51 | url callback cbargs silentp | 52 | url callback cbargs silentp |
| 52 | buffer start-time) | 53 | buffer start-time pre-triggered |
| 54 | inhibit-cookiesp) | ||
| 53 | 55 | ||
| 54 | ;;;###autoload | 56 | ;;;###autoload |
| 55 | (defun url-queue-retrieve (url callback &optional cbargs silent) | 57 | (defun url-queue-retrieve (url callback &optional cbargs silent inhibit-cookies) |
| 56 | "Retrieve URL asynchronously and call CALLBACK with CBARGS when finished. | 58 | "Retrieve URL asynchronously and call CALLBACK with CBARGS when finished. |
| 57 | Like `url-retrieve' (which see for details of the arguments), but | 59 | This is like `url-retrieve' (which see for details of the arguments), |
| 58 | controls the level of parallelism via the | 60 | but with limits on the degree of parallelism. The variable |
| 59 | `url-queue-parallel-processes' variable." | 61 | `url-queue-parallel-processes' sets the number of concurrent processes. |
| 62 | The variable `url-queue-timeout' sets a timeout." | ||
| 60 | (setq url-queue | 63 | (setq url-queue |
| 61 | (append url-queue | 64 | (append url-queue |
| 62 | (list (make-url-queue :url url | 65 | (list (make-url-queue :url url |
| 63 | :callback callback | 66 | :callback callback |
| 64 | :cbargs cbargs | 67 | :cbargs cbargs |
| 65 | :silentp silent)))) | 68 | :silentp silent |
| 66 | (url-queue-run-queue)) | 69 | :inhibit-cookiesp inhibit-cookies)))) |
| 70 | (url-queue-setup-runners)) | ||
| 71 | |||
| 72 | ;; To ensure asynch behaviour, we start the required number of queue | ||
| 73 | ;; runners from `run-with-idle-timer'. So we're basically going | ||
| 74 | ;; through the queue in two ways: 1) synchronously when a program | ||
| 75 | ;; calls `url-queue-retrieve' (which will then start the required | ||
| 76 | ;; number of queue runners), and 2) at the exit of each job, which | ||
| 77 | ;; will then not start any further threads, but just reuse the | ||
| 78 | ;; previous "slot". | ||
| 79 | |||
| 80 | (defun url-queue-setup-runners () | ||
| 81 | (let ((running 0) | ||
| 82 | waiting) | ||
| 83 | (dolist (entry url-queue) | ||
| 84 | (cond | ||
| 85 | ((or (url-queue-start-time entry) | ||
| 86 | (url-queue-pre-triggered entry)) | ||
| 87 | (incf running)) | ||
| 88 | ((not waiting) | ||
| 89 | (setq waiting entry)))) | ||
| 90 | (when (and waiting | ||
| 91 | (< running url-queue-parallel-processes)) | ||
| 92 | (setf (url-queue-pre-triggered waiting) t) | ||
| 93 | (run-with-idle-timer 0.01 nil 'url-queue-run-queue)))) | ||
| 67 | 94 | ||
| 68 | (defun url-queue-run-queue () | 95 | (defun url-queue-run-queue () |
| 69 | (url-queue-prune-old-entries) | 96 | (url-queue-prune-old-entries) |
| @@ -81,16 +108,34 @@ controls the level of parallelism via the | |||
| 81 | (url-queue-start-retrieve waiting)))) | 108 | (url-queue-start-retrieve waiting)))) |
| 82 | 109 | ||
| 83 | (defun url-queue-callback-function (status job) | 110 | (defun url-queue-callback-function (status job) |
| 111 | (when (and (eq (car status) :error) | ||
| 112 | (eq (cadr (cadr status)) 'connection-failed)) | ||
| 113 | ;; If we get a connection error, then flush all other jobs from | ||
| 114 | ;; the host from the queue. This particularly makes sense if the | ||
| 115 | ;; error really is a DNS resolver issue, which happens | ||
| 116 | ;; synchronously and totally halts Emacs. | ||
| 117 | (url-queue-remove-jobs-from-host | ||
| 118 | (plist-get (nthcdr 3 (cadr status)) :host))) | ||
| 84 | (setq url-queue (delq job url-queue)) | 119 | (setq url-queue (delq job url-queue)) |
| 85 | (url-queue-run-queue) | 120 | (url-queue-run-queue) |
| 86 | (apply (url-queue-callback job) (cons status (url-queue-cbargs job)))) | 121 | (apply (url-queue-callback job) (cons status (url-queue-cbargs job)))) |
| 87 | 122 | ||
| 123 | (defun url-queue-remove-jobs-from-host (host) | ||
| 124 | (let ((jobs nil)) | ||
| 125 | (dolist (job url-queue) | ||
| 126 | (when (equal (url-host (url-generic-parse-url (url-queue-url job))) | ||
| 127 | host) | ||
| 128 | (push job jobs))) | ||
| 129 | (dolist (job jobs) | ||
| 130 | (setq url-queue (delq job url-queue))))) | ||
| 131 | |||
| 88 | (defun url-queue-start-retrieve (job) | 132 | (defun url-queue-start-retrieve (job) |
| 89 | (setf (url-queue-buffer job) | 133 | (setf (url-queue-buffer job) |
| 90 | (ignore-errors | 134 | (ignore-errors |
| 91 | (url-retrieve (url-queue-url job) | 135 | (url-retrieve (url-queue-url job) |
| 92 | #'url-queue-callback-function (list job) | 136 | #'url-queue-callback-function (list job) |
| 93 | (url-queue-silentp job))))) | 137 | (url-queue-silentp job) |
| 138 | (url-queue-inhibit-cookiesp job))))) | ||
| 94 | 139 | ||
| 95 | (defun url-queue-prune-old-entries () | 140 | (defun url-queue-prune-old-entries () |
| 96 | (let (dead-jobs) | 141 | (let (dead-jobs) |