1
/* Copyright 2009 Canonical Ltd. This software is licensed under the
2
* GNU Affero General Public License version 3 (see the file LICENSE).
4
* The Launchpad Longpoll module provides the functionnality to deal
5
* with longpolling on the JavaScript side.
7
* The module method setupLongPollManager is called in every template and
8
* the long poll machinery will only be started if LP.cache.longpoll
11
* Usually the only thing you will want to do to use the long polling feature
12
* is to make sure LP.cache.longpoll is populated and then create Javascript
13
* handlers for the events which will be fired.
14
* You also might create handlers for the generic long polling events
18
YUI.add('lp.app.longpoll', function(Y) {
20
var namespace = Y.namespace('lp.app.longpoll');
22
// Event fired when the long polling request starts.
23
namespace.longpoll_start_event = 'lp.app.longpoll.start';
25
// Event fired each time the long polling request fails (to connect or
26
// to parse the returned result).
27
namespace.longpoll_fail_event = 'lp.app.longpoll.failure';
29
// Event fired when the delay between each failed connection is set to
30
// a long delay (after MAX_SHORT_DELAY_FAILED_ATTEMPTS failed attempts).
31
namespace.longpoll_longdelay = 'lp.app.longpoll.longdelay';
33
// Event fired when the delay between each failed connection is set back
35
namespace.longpoll_shortdelay = 'lp.app.longpoll.shortdelay';
37
namespace._manager = null;
39
// After MAX_SHORT_DELAY_FAILED_ATTEMPTS failed connections (real failed
40
// connections or connection getting an invalid return) separated
41
// by SHORT_DELAY (millisec), wait LONG_DELAY (millisec) between
42
// each failed connection.
43
namespace.MAX_SHORT_DELAY_FAILED_ATTEMPTS = 5;
44
namespace.SHORT_DELAY = 1000;
45
namespace.LONG_DELAY = 3*60*1000;
49
* A Long Poll Manager creates and manages a long polling connexion
50
* to the server to fetch events. This class is not directly used
51
* but managed through 'setupLongPollManager' which creates and
52
* initialises a singleton LongPollManager.
54
* @class LongPollManager
56
function LongPollManager(config) {
57
LongPollManager.superclass.constructor.apply(this, arguments);
60
LongPollManager.NAME = "longPollManager";
62
Y.extend(LongPollManager, Y.Base, {
63
initializer : function(cfg) {
64
this._started = false;
65
this._failed_attempts = 0;
70
setConnectionInfos : function(key, uri) {
75
_io : function (uri, config) {
79
successPoll : function (id, response) {
81
var data = Y.JSON.parse(response.responseText);
82
var event_key = data.event_key;
83
var event_data = data.event_data;
84
Y.fire(event_key, event_data);
88
Y.fire(namespace.longpoll_fail_event, e);
93
failurePoll : function () {
94
Y.fire(namespace.longpoll_fail_event);
98
* Return the delay (milliseconds) to wait before trying to reconnect
99
* again after a failed connection.
101
* The rationale here is that:
102
* 1. We should not try to reconnect instantaneously after a failed
104
* 2. After a certain number of failed connections, we should set the
105
* delay between two failed connection to a bigger number because
106
* the server may be having problems.
110
_pollDelay : function() {
111
this._failed_attempts = this._failed_attempts + 1;
112
if (this._failed_attempts >=
113
namespace.MAX_SHORT_DELAY_FAILED_ATTEMPTS) {
114
Y.fire(namespace.longpoll_longdelay);
115
return namespace.LONG_DELAY;
118
return namespace.SHORT_DELAY;
123
* Relaunch a connection to the server after a successful or
124
* a failed connection.
127
* @param {Boolean} failed: whether or not the previous connection
130
repoll : function(failed) {
132
if (this._failed_attempts >=
133
namespace.MAX_SHORT_DELAY_FAILED_ATTEMPTS) {
134
Y.fire(namespace.longpoll_shortdelay);
136
this._failed_attempts = 0;
142
var delay = this._pollDelay();
144
Y.later(delay, this, this.poll);
155
failure: function() {
159
success: function(id, response) {
160
var res = that.successPoll(id, response);
165
this._sequence = this._sequence + 1;
166
var queue_uri = this.uri +
167
"?uuid=" + this.key +
168
"&sequence=" + this._sequence;
169
if (!this._started) {
170
Y.fire(namespace.longpoll_start_event);
171
this._started = true;
173
this._io(queue_uri, config);
177
namespace.LongPollManager = LongPollManager;
179
namespace.getLongPollManager = function() {
180
if (!Y.Lang.isValue(namespace._manager)) {
181
namespace._manager = new namespace.LongPollManager();
183
return namespace._manager;
186
namespace.setupLongPollManager = function() {
187
if (Y.Lang.isValue(LP.cache.longpoll)) {
188
var key = LP.cache.longpoll.key;
189
var uri = LP.cache.longpoll.uri;
190
var longpollmanager = namespace.getLongPollManager();
191
longpollmanager.setConnectionInfos(key, uri);
192
longpollmanager.poll();
193
return longpollmanager;
197
}, "0.1", {"requires":["base", "event", "lang", "json", "io"]});