1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
6 * @fileoverview Queue of pending requests from an origin.
12 * Represents a queued request. Once given a token, call complete() once the
13 * request is processed (or dropped.)
16 function QueuedRequestToken() {}
18 /** Completes (or cancels) this queued request. */
19 QueuedRequestToken
.prototype.complete = function() {};
22 * @param {!RequestQueue} queue The queue for this request.
23 * @param {number} id An id for this request.
24 * @param {function(QueuedRequestToken)} beginCb Called when work may begin on
26 * @param {RequestToken} opt_prev Previous request in the same queue.
27 * @param {RequestToken} opt_next Next request in the same queue.
29 * @implements {QueuedRequestToken}
31 function RequestToken(queue
, id
, beginCb
, opt_prev
, opt_next
) {
32 /** @private {!RequestQueue} */
34 /** @private {number} */
36 /** @type {function(QueuedRequestToken)} */
37 this.beginCb
= beginCb
;
38 /** @type {RequestToken} */
40 /** @type {RequestToken} */
42 /** @private {boolean} */
43 this.completed_
= false;
46 /** Completes (or cancels) this queued request. */
47 RequestToken
.prototype.complete = function() {
48 if (this.completed_
) {
49 // Either the caller called us more than once, or the timer is firing.
50 // Either way, nothing more to do here.
53 this.completed_
= true;
54 this.queue_
.complete(this);
57 /** @return {boolean} Whether this token has already completed. */
58 RequestToken
.prototype.completed = function() {
59 return this.completed_
;
63 * @param {!SystemTimer} sysTimer A system timer implementation.
66 function RequestQueue(sysTimer
) {
67 /** @private {!SystemTimer} */
68 this.sysTimer_
= sysTimer
;
69 /** @private {RequestToken} */
71 /** @private {RequestToken} */
73 /** @private {number} */
78 * Inserts this token into the queue.
79 * @param {RequestToken} token Queue token
82 RequestQueue
.prototype.insertToken_ = function(token
) {
83 console
.log(UTIL_fmt('token ' + this.id_
+ ' inserted'));
84 if (this.head_
=== null) {
88 if (!this.tail_
) throw 'Non-empty list missing tail';
89 this.tail_
.next
= token
;
90 token
.prev
= this.tail_
;
96 * Removes this token from the queue.
97 * @param {RequestToken} token Queue token
100 RequestQueue
.prototype.removeToken_ = function(token
) {
102 token
.next
.prev
= token
.prev
;
105 token
.prev
.next
= token
.next
;
107 if (this.head_
=== token
&& this.tail_
=== token
) {
108 this.head_
= this.tail_
= null;
110 if (this.head_
=== token
) {
111 this.head_
= token
.next
;
112 this.head_
.prev
= null;
114 if (this.tail_
=== token
) {
115 this.tail_
= token
.prev
;
116 this.tail_
.next
= null;
119 token
.prev
= token
.next
= null;
123 * Completes this token's request, and begins the next queued request, if one
125 * @param {RequestToken} token Queue token
127 RequestQueue
.prototype.complete = function(token
) {
128 console
.log(UTIL_fmt('token ' + this.id_
+ ' completed'));
129 var next
= token
.next
;
130 this.removeToken_(token
);
136 /** @return {boolean} Whether this queue is empty. */
137 RequestQueue
.prototype.empty = function() {
138 return this.head_
=== null;
142 * Queues this request, and, if it's the first request, begins work on it.
143 * @param {function(QueuedRequestToken)} beginCb Called when work begins on this
145 * @param {Countdown} timer Countdown timer
146 * @return {QueuedRequestToken} A token for the request.
148 RequestQueue
.prototype.queueRequest = function(beginCb
, timer
) {
149 var startNow
= this.empty();
150 var token
= new RequestToken(this, ++this.id_
, beginCb
);
151 // Clone the timer to set a callback on it, which will ensure complete() is
152 // eventually called, even if the caller never gets around to it.
153 timer
.clone(token
.complete
.bind(token
));
154 this.insertToken_(token
);
156 this.sysTimer_
.setTimeout(function() {
157 if (!token
.completed()) {
158 token
.beginCb(token
);
166 * @param {!SystemTimer} sysTimer A system timer implementation.
169 function OriginKeyedRequestQueue(sysTimer
) {
170 /** @private {!SystemTimer} */
171 this.sysTimer_
= sysTimer
;
172 /** @private {Object<string, !RequestQueue>} */
177 * Queues this request, and, if it's the first request, begins work on it.
178 * @param {string} appId Application Id
179 * @param {string} origin Request origin
180 * @param {function(QueuedRequestToken)} beginCb Called when work begins on this
182 * @param {Countdown} timer Countdown timer
183 * @return {QueuedRequestToken} A token for the request.
185 OriginKeyedRequestQueue
.prototype.queueRequest
=
186 function(appId
, origin
, beginCb
, timer
) {
187 var key
= appId
+ ' ' + origin
;
188 if (!this.requests_
.hasOwnProperty(key
)) {
189 this.requests_
[key
] = new RequestQueue(this.sysTimer_
);
191 var queue
= this.requests_
[key
];
192 return queue
.queueRequest(beginCb
, timer
);