Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / resources / cryptotoken / requestqueue.js
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.
4
5 /**
6  * @fileoverview Queue of pending requests from an origin.
7  */
8 'use strict';
9
10 /**
11  * Represents a queued request. Once given a token, call complete() once the
12  * request is processed (or dropped.)
13  * @interface
14  */
15 function QueuedRequestToken() {}
16
17 /** Completes (or cancels) this queued request. */
18 QueuedRequestToken.prototype.complete = function() {};
19
20 /**
21  * @param {!RequestQueue} queue The queue for this request.
22  * @param {function(QueuedRequestToken)} beginCb Called when work may begin on
23  *     this request.
24  * @param {RequestToken} opt_prev Previous request in the same queue.
25  * @param {RequestToken} opt_next Next request in the same queue.
26  * @constructor
27  * @implements {QueuedRequestToken}
28  */
29 function RequestToken(queue, beginCb, opt_prev, opt_next) {
30   /** @private {!RequestQueue} */
31   this.queue_ = queue;
32   /** @type {function(QueuedRequestToken)} */
33   this.beginCb = beginCb;
34   /** @type {RequestToken} */
35   this.prev = null;
36   /** @type {RequestToken} */
37   this.next = null;
38   /** @private {boolean} */
39   this.completed_ = false;
40 }
41
42 /** Completes (or cancels) this queued request. */
43 RequestToken.prototype.complete = function() {
44   if (this.completed_) {
45     // Either the caller called us more than once, or the timer is firing.
46     // Either way, nothing more to do here.
47     return;
48   }
49   this.completed_ = true;
50   this.queue_.complete(this);
51 };
52
53 /** @return {boolean} Whether this token has already completed. */
54 RequestToken.prototype.completed = function() {
55   return this.completed_;
56 };
57
58 /**
59  * @constructor
60  */
61 function RequestQueue() {
62   /** @private {RequestToken} */
63   this.head_ = null;
64   /** @private {RequestToken} */
65   this.tail_ = null;
66 }
67
68 /**
69  * Inserts this token into the queue.
70  * @param {RequestToken} token Queue token
71  * @private
72  */
73 RequestQueue.prototype.insertToken_ = function(token) {
74   if (this.head_ === null) {
75     this.head_ = token;
76     this.tail_ = token;
77   } else {
78     if (!this.tail_) throw 'Non-empty list missing tail';
79     this.tail_.next = token;
80     token.prev = this.tail_;
81     this.tail_ = token;
82   }
83 };
84
85 /**
86  * Removes this token from the queue.
87  * @param {RequestToken} token Queue token
88  * @private
89  */
90 RequestQueue.prototype.removeToken_ = function(token) {
91   if (token.next) {
92     token.next.prev = token.prev;
93   }
94   if (token.prev) {
95     token.prev.next = token.next;
96   }
97   if (this.head_ === token && this.tail_ === token) {
98     this.head_ = this.tail_ = null;
99   } else {
100     if (this.head_ === token) {
101       this.head_ = token.next;
102       this.head_.prev = null;
103     }
104     if (this.tail_ === token) {
105       this.tail_ = token.prev;
106       this.tail_.next = null;
107     }
108   }
109   token.prev = token.next = null;
110 };
111
112 /**
113  * Completes this token's request, and begins the next queued request, if one
114  * exists.
115  * @param {RequestToken} token Queue token
116  */
117 RequestQueue.prototype.complete = function(token) {
118   var next = token.next;
119   this.removeToken_(token);
120   if (next) {
121     next.beginCb(next);
122   }
123 };
124
125 /** @return {boolean} Whether this queue is empty. */
126 RequestQueue.prototype.empty = function() {
127   return this.head_ === null;
128 };
129
130 /**
131  * Queues this request, and, if it's the first request, begins work on it.
132  * @param {function(QueuedRequestToken)} beginCb Called when work begins on this
133  *     request.
134  * @param {Countdown} timer Countdown timer
135  * @return {QueuedRequestToken} A token for the request.
136  */
137 RequestQueue.prototype.queueRequest = function(beginCb, timer) {
138   var startNow = this.empty();
139   var token = new RequestToken(this, beginCb);
140   // Clone the timer to set a callback on it, which will ensure complete() is
141   // eventually called, even if the caller never gets around to it.
142   timer.clone(token.complete.bind(token));
143   this.insertToken_(token);
144   if (startNow) {
145     window.setTimeout(function() {
146       if (!token.completed()) {
147         token.beginCb(token);
148       }
149     }, 0);
150   }
151   return token;
152 };
153
154 /**
155  * @constructor
156  */
157 function OriginKeyedRequestQueue() {
158   /** @private {Object.<string, !RequestQueue>} */
159   this.requests_ = {};
160 }
161
162 /**
163  * Queues this request, and, if it's the first request, begins work on it.
164  * @param {string} appId Application Id
165  * @param {string} origin Request origin
166  * @param {function(QueuedRequestToken)} beginCb Called when work begins on this
167  *     request.
168  * @param {Countdown} timer Countdown timer
169  * @return {QueuedRequestToken} A token for the request.
170  */
171 OriginKeyedRequestQueue.prototype.queueRequest =
172     function(appId, origin, beginCb, timer) {
173   var key = appId + origin;
174   if (!this.requests_.hasOwnProperty(key)) {
175     this.requests_[key] = new RequestQueue();
176   }
177   var queue = this.requests_[key];
178   return queue.queueRequest(beginCb, timer);
179 };