📄 jquery.cometd.js
字号:
/**
* Copyright 2008 Mort Bay Consulting Pty. Ltd.
* Dual licensed under the Apache License 2.0 and the MIT license.
* ----------------------------------------------------------------------------
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http: *www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ----------------------------------------------------------------------------
* Licensed under the MIT license;
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
* ----------------------------------------------------------------------------
* $Revision$ $Date$
*/
(function($)
{
/**
* The constructor for a Comet object.
* There is a default Comet instance already created at the variable <code>$.cometd</code>,
* and hence that can be used to start a comet conversation with a server.
* In the rare case a page needs more than one comet conversation, a new instance can be
* created via:
* <pre>
* var url2 = ...;
* var cometd2 = new $.Cometd();
* cometd2.init(url2);
* </pre>
*/
$.Cometd = function(name)
{
var _name = name || 'default';
var _logPriorities = { debug: 1, info: 2, warn: 3, error: 4 };
var _logLevel = 'info';
var _url;
var _xd = false;
var _transport;
var _status = 'disconnected';
var _messageId = 0;
var _clientId = null;
var _batch = 0;
var _messageQueue = [];
var _listeners = {};
var _backoff = 0;
var _backoffIncrement = 1000;
var _maxBackoff = 60000;
var _scheduledSend = null;
var _extensions = [];
var _advice = {};
var _handshakeProps;
/**
* Returns the name assigned to this Comet object, or the string 'default'
* if no name has been explicitely passed as parameter to the constructor.
*/
this.getName = function()
{
return _name;
};
/**
* Configures the initial comet communication with the comet server.
* @param cometURL the URL of the comet server
*/
this.configure = function(cometURL)
{
_configure(cometURL);
};
function _configure(cometURL)
{
_url = cometURL;
_debug('Initializing comet with url: {}', _url);
// Check immediately if we're cross domain
// If cross domain, the handshake must not send the long polling transport type
var urlParts = /(^https?:)?(\/\/(([^:\/\?#]+)(:(\d+))?))?([^\?#]*)/.exec(cometURL);
if (urlParts[3]) _xd = urlParts[3] != location.host;
// Temporary setup a transport to send the initial handshake
// The transport may be changed as a result of handshake
if (_xd)
_transport = newCallbackPollingTransport();
else
_transport = newLongPollingTransport();
_debug('Initial transport is {}', _transport.getType());
}
/**
* Configures and establishes the comet communication with the comet server
* via a handshake and a subsequent connect.
* @param cometURL the URL of the comet server
* @param handshakeProps an object to be merged with the handshake message
* @see #configure(cometURL)
* @see #handshake(handshakeProps)
*/
this.init = function(cometURL, handshakeProps)
{
_configure(cometURL);
_handshake(handshakeProps);
};
/**
* Establishes the comet communication with the comet server
* via a handshake and a subsequent connect.
* @param handshakeProps an object to be merged with the handshake message
*/
this.handshake = function(handshakeProps)
{
_handshake(handshakeProps);
};
/**
* Disconnects from the comet server.
* @param disconnectProps an object to be merged with the disconnect message
*/
this.disconnect = function(disconnectProps)
{
var bayeuxMessage = {
channel: '/meta/disconnect'
};
var message = $.extend({}, disconnectProps, bayeuxMessage);
// Deliver immediately
// The handshake and connect mechanism make use of startBatch(), and in case
// of a failed handshake the disconnect would not be delivered if using _send().
_setStatus('disconnecting');
_deliver([message], false);
};
/**
* Marks the start of a batch of application messages to be sent to the server
* in a single request, obtaining a single response containing (possibly) many
* application reply messages.
* Messages are held in a queue and not sent until {@link #endBatch()} is called.
* If startBatch() is called multiple times, then an equal number of endBatch()
* calls must be made to close and send the batch of messages.
* @see #endBatch()
*/
this.startBatch = function()
{
_startBatch();
};
/**
* Marks the end of a batch of application messages to be sent to the server
* in a single request.
* @see #startBatch()
*/
this.endBatch = function()
{
_endBatch(true);
};
/**
* Subscribes to the given channel, performing the given callback in the given scope
* when a message for the channel arrives.
* @param channel the channel to subscribe to
* @param scope the scope of the callback
* @param callback the callback to call when a message is delivered to the channel
* @param subscribeProps an object to be merged with the subscribe message
* @return the subscription handle to be passed to {@link #unsubscribe(object)}
*/
this.subscribe = function(channel, scope, callback, subscribeProps)
{
var subscription = this.addListener(channel, scope, callback);
// Send the subscription message after the subscription registration to avoid
// races where the server would deliver a message to the subscribers, but here
// on the client the subscription has not been added yet to the data structures
var bayeuxMessage = {
channel: '/meta/subscribe',
subscription: channel
};
var message = $.extend({}, subscribeProps, bayeuxMessage);
_send(message);
return subscription;
};
/**
* Unsubscribes the subscription obtained with a call to {@link #subscribe(string, object, function)}.
* @param subscription the subscription to unsubscribe.
*/
this.unsubscribe = function(subscription, unsubscribeProps)
{
// Remove the local listener before sending the message
// This ensures that if the server fails, this client does not get notifications
this.removeListener(subscription);
var bayeuxMessage = {
channel: '/meta/unsubscribe',
subscription: subscription[0]
};
var message = $.extend({}, unsubscribeProps, bayeuxMessage);
_send(message);
};
/**
* Publishes a message on the given channel, containing the given content.
* @param channel the channel to publish the message to
* @param content the content of the message
* @param publishProps an object to be merged with the publish message
*/
this.publish = function(channel, content, publishProps)
{
var bayeuxMessage = {
channel: channel,
data: content
};
var message = $.extend({}, publishProps, bayeuxMessage);
_send(message);
};
/**
* Adds a listener for bayeux messages, performing the given callback in the given scope
* when a message for the given channel arrives.
* @param channel the channel the listener is interested to
* @param scope the scope of the callback
* @param callback the callback to call when a message is delivered to the channel
* @returns the subscription handle to be passed to {@link #removeListener(object)}
* @see #removeListener(object)
*/
this.addListener = function(channel, scope, callback)
{
// The data structure is a map<channel, subscription[]>, where each subscription
// holds the callback to be called and its scope.
// Normalize arguments
if (!callback)
{
callback = scope;
scope = undefined;
}
var subscription = {
scope: scope,
callback: callback
};
var subscriptions = _listeners[channel];
if (!subscriptions)
{
subscriptions = [];
_listeners[channel] = subscriptions;
}
// Pushing onto an array appends at the end and returns the id associated with the element increased by 1.
// Note that if:
// a.push('a'); var hb=a.push('b'); delete a[hb-1]; var hc=a.push('c');
// then:
// hc==3, a.join()=='a',,'c', a.length==3
var subscriptionIndex = subscriptions.push(subscription) - 1;
_debug('Added listener: channel \'{}\', callback \'{}\', index {}', channel, callback.name, subscriptionIndex);
// The subscription to allow removal of the listener is made of the channel and the index
return [channel, subscriptionIndex];
};
/**
* Removes the subscription obtained with a call to {@link #addListener(string, object, function)}.
* @param subscription the subscription to unsubscribe.
*/
this.removeListener = function(subscription)
{
var subscriptions = _listeners[subscription[0]];
if (subscriptions)
{
delete subscriptions[subscription[1]];
_debug('Removed listener: channel \'{}\', index {}', subscription[0], subscription[1]);
}
};
/**
* Removes all listeners registered with {@link #addListener(channel, scope, callback)} or
* {@link #subscribe(channel, scope, callback)}.
*/
this.clearListeners = function()
{
_listeners = {};
};
/**
* Returns a string representing the status of the bayeux communication with the comet server.
*/
this.getStatus = function()
{
return _status;
};
/**
* Sets the backoff period used to increase the backoff time when retrying an unsuccessful or failed message.
* Default value is 1 second, which means if there is a persistent failure the retries will happen
* after 1 second, then after 2 seconds, then after 3 seconds, etc. So for example with 15 seconds of
* elapsed time, there will be 5 retries (at 1, 3, 6, 10 and 15 seconds elapsed).
* @param period the backoff period to set
* @see #getBackoffIncrement()
*/
this.setBackoffIncrement = function(period)
{
_backoffIncrement = period;
};
/**
* Returns the backoff period used to increase the backoff time when retrying an unsuccessful or failed message.
* @see #setBackoffIncrement(period)
*/
this.getBackoffIncrement = function()
{
return _backoffIncrement;
};
/**
* Returns the backoff period to wait before retrying an unsuccessful or failed message.
*/
this.getBackoffPeriod = function()
{
return _backoff;
};
/**
* Sets the log level for console logging.
* Valid values are the strings 'error', 'warn', 'info' and 'debug', from
* less verbose to more verbose.
* @param level the log level string
*/
this.setLogLevel = function(level)
{
_logLevel = level;
};
/**
* Registers an extension whose callbacks are called for every incoming message
* (that comes from the server to this client implementation) and for every
* outgoing message (that originates from this client implementation for the
* server).
* The format of the extension object is the following:
* <pre>
* {
* incoming: function(message) { ... },
* outgoing: function(message) { ... }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -