📄 cometda.js
字号:
//AdapterRegistry.js
dojo.AdapterRegistry = function(/*Boolean?*/ returnWrappers){
this.pairs = [];
this.returnWrappers = returnWrappers || false;
};
dojo.extend(dojo.AdapterRegistry, {
register: function(/*String*/ name, /*Function*/ check, /*Function*/ wrap, /*Boolean?*/ directReturn, /*Boolean?*/ override){
this.pairs[((override) ? "unshift" : "push")]([name, check, wrap, directReturn]);
},
match: function(/* ... */){
for(var i = 0; i < this.pairs.length; i++){
var pair = this.pairs[i];
if(pair[1].apply(this, arguments)){
if((pair[3])||(this.returnWrappers)){
return pair[2];
}else{
return pair[2].apply(this, arguments);
}
}
}
throw new Error("No match found");
},
unregister: function(name){
for(var i = 0; i < this.pairs.length; i++){
var pair = this.pairs[i];
if(pair[0] == name){
this.pairs.splice(i, 1);
return true;
}
}
return false;
}
});
//_base.js
dojox.cometd = {
Connection: function(prefix){
dojo.mixin(this, {
"DISCONNECTED": "DISCONNECTED", // _initialized==false && _connected==false
"CONNECTING": "CONNECTING", // _initialized==true && _connected==false (handshake sent)
"CONNECTED": "CONNECTED", // _initialized==true && _connected==true (first successful connect)
"DISCONNECTING": "DISCONNECING", // _initialized==false && _connected==true (disconnect sent)
prefix: prefix,
_initialized: false,
_connected: false,
_polling: false,
_handshook: false,
expectedNetworkDelay: 10000, // expected max network delay
connectTimeout: 0, // If set, used as ms to wait for a connect response and sent as the advised timeout
version: "1.0",
minimumVersion: "0.9",
clientId: null,
messageId: 0,
batch: 0,
_isXD: false,
handshakeReturn: null,
currentTransport: null,
url: null,
lastMessage: null,
_messageQ: [],
handleAs: "json",
_advice: {},
_backoffInterval: 0,
_backoffIncrement: 1000,
_backoffMax: 60000,
_deferredSubscribes: {},
_deferredUnsubscribes: {},
_subscriptions: [],
_extendInList: [], // List of functions invoked before delivering messages
_extendOutList: [] // List of functions invoked before sending messages
});
this.state = function() {
return this._initialized ?
(this._connected ? "CONNECTED" : "CONNECTING") :
(this._connected ? "DISCONNECTING" : "DISCONNECTED");
};
this.init = function( /*String*/ root,
/*Object?*/ props,
/*Object?*/ bargs){ // return: dojo.Deferred
// try to select an XD-capable transport
props = props || {};
// go ask the short bus server what we can support
props.version = this.version;
props.minimumVersion = this.minimumVersion;
props.channel = "/meta/handshake";
props.id = "" + this.messageId++;
this.url = root || dojo.config["cometdRoot"];
if(!this.url){
throw "no cometd root";
return null;
}
var regexp = "^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?$";
var parts = ("" + window.location).match(new RegExp(regexp));
if(parts[4]){
var tmp = parts[4].split(":");
var thisHost = tmp[0];
var thisPort = tmp[1]||"80"; // FIXME: match 443
parts = this.url.match(new RegExp(regexp));
if(parts[4]){
tmp = parts[4].split(":");
var urlHost = tmp[0];
var urlPort = tmp[1]||"80";
this._isXD = ((urlHost != thisHost)||(urlPort != thisPort));
}
}
if(!this._isXD){
props.supportedConnectionTypes = dojo.map(dojox.cometd.connectionTypes.pairs, "return item[0]");
}
props = this._extendOut(props);
var bindArgs = {
url: this.url,
handleAs: this.handleAs,
content: { "message": dojo.toJson([props]) },
load: dojo.hitch(this,function(msg){
this._backon();
this._finishInit(msg);
}),
error: dojo.hitch(this,function(e){
this._backoff();
this._finishInit([{}]);
}),
timeout: this.expectedNetworkDelay
};
if(bargs){
dojo.mixin(bindArgs, bargs);
}
this._props = props;
for(var tname in this._subscriptions){
for(var sub in this._subscriptions[tname]){
if(this._subscriptions[tname][sub].topic){
dojo.unsubscribe(this._subscriptions[tname][sub].topic);
}
}
}
this._messageQ = [];
this._subscriptions = [];
this._initialized = true;
this.batch = 0;
this.startBatch();
var r;
// if xdomain, then we assume jsonp for handshake
if(this._isXD){
bindArgs.callbackParamName = "jsonp";
r = dojo.io.script.get(bindArgs);
}else{
r = dojo.xhrPost(bindArgs);
}
return r;
};
this.publish = function(/*String*/ channel, /*Object*/ data, /*Object?*/ props){
var message = {
data: data,
channel: channel
};
if(props){
dojo.mixin(message, props);
}
this._sendMessage(message);
};
this.subscribe = function( /*String */ channel,
/*Object */ objOrFunc,
/*String */ funcName,
/*Object?*/ props){ // return: dojo.Deferred
props = props||{};
if(objOrFunc){
var tname = prefix + channel;
var subs = this._subscriptions[tname];
if(!subs || subs.length == 0){
subs = [];
props.channel = "/meta/subscribe";
props.subscription = channel;
this._sendMessage(props);
var _ds = this._deferredSubscribes;
if(_ds[channel]){
_ds[channel].cancel();
delete _ds[channel];
}
_ds[channel] = new dojo.Deferred();
}
for(var i in subs){
if(subs[i].objOrFunc === objOrFunc && (!subs[i].funcName&&!funcName||subs[i].funcName==funcName) ){
return null;
}
}
var topic = dojo.subscribe(tname, objOrFunc, funcName);
subs.push({
topic: topic,
objOrFunc: objOrFunc,
funcName: funcName
});
this._subscriptions[tname] = subs;
}
var ret = this._deferredSubscribes[channel] || {};
ret.args = dojo._toArray(arguments);
return ret; // dojo.Deferred
};
this.unsubscribe = function( /*String*/ channel,
/*Object?*/ objOrFunc,
/*String?*/ funcName,
/*Object?*/ props){
if(
(arguments.length == 1) &&
(!dojo.isString(channel)) &&
(channel.args)
){
// it's a subscription handle, unroll
return this.unsubscribe.apply(this, channel.args);
}
var tname = prefix + channel;
var subs = this._subscriptions[tname];
if(!subs || subs.length==0){
return null;
}
var s=0;
for(var i in subs){
var sb = subs[i];
if((!objOrFunc) ||
(
sb.objOrFunc===objOrFunc &&
(!sb.funcName && !funcName || sb.funcName==funcName)
)
){
dojo.unsubscribe(subs[i].topic);
delete subs[i];
}else{
s++;
}
}
if(s == 0){
props = props || {};
props.channel = "/meta/unsubscribe";
props.subscription = channel;
delete this._subscriptions[tname];
this._sendMessage(props);
this._deferredUnsubscribes[channel] = new dojo.Deferred();
if(this._deferredSubscribes[channel]){
this._deferredSubscribes[channel].cancel();
delete this._deferredSubscribes[channel];
}
}
return this._deferredUnsubscribes[channel]; // dojo.Deferred
};
this.disconnect = function(){
for(var tname in this._subscriptions){
for(var sub in this._subscriptions[tname]){
if(this._subscriptions[tname][sub].topic){
dojo.unsubscribe(this._subscriptions[tname][sub].topic);
}
}
}
this._subscriptions = [];
this._messageQ = [];
if(this._initialized && this.currentTransport){
this._initialized=false;
this.currentTransport.disconnect();
}
if(!this._polling) {
this._connected=false;
this._publishMeta("connect",false);
}
this._initialized=false;
this._handshook=false;
this._publishMeta("disconnect",true);
};
this.subscribed = function( /*String*/channel, /*Object*/message){ }
this.unsubscribed = function(/*String*/channel, /*Object*/message){ }
// private methods (TODO name all with leading _)
this.tunnelInit = function(childLocation, childDomain){
};
this.tunnelCollapse = function(){
};
this._backoff = function(){
if(!this._advice){
this._advice={reconnect:"retry",interval:0};
}else if(!this._advice.interval){
this._advice.interval = 0;
}
if(this._backoffInterval < this._backoffMax){
this._backoffInterval += this._backoffIncrement;
}
}
this._backon = function(){
this._backoffInterval=0;
}
this._interval = function(){
var i = this._backoffInterval + (this._advice ? (this._advice.interval ? this._advice.interval : 0) : 0);
if (i>0){
}
return i;
}
this._publishMeta = function(action,successful,props){
try {
var meta = {cometd:this,action:action,successful:successful,state:this.state()};
if (props){
dojo.mixin(meta, props);
}
dojo.publish(this.prefix + "/meta", [meta]);
} catch(e) {
}
}
this._finishInit = function(data){
// summary:
// Handle the handshake return from the server and initialize
// connection if all is OK
data = data[0];
this.handshakeReturn = data;
// remember any advice
if(data["advice"]){
this._advice = data.advice;
}
var successful = data.successful ? data.successful : false;
// check version
if(data.version < this.minimumVersion){
if (console.log)
successful=false;
this._advice.reconnect="none";
}
if(successful){
this.currentTransport = dojox.cometd.connectionTypes.match(
data.supportedConnectionTypes,
data.version,
this._isXD
);
var transport = this.currentTransport;
// initialize the transport
transport._cometd = this;
transport.version = data.version;
this.clientId = data.clientId;
this.tunnelInit = transport.tunnelInit && dojo.hitch(transport, "tunnelInit");
this.tunnelCollapse = transport.tunnelCollapse && dojo.hitch(transport, "tunnelCollapse");
transport.startup(data);
}
this._publishMeta("handshake",successful,{reestablish: successful && this._handshook});
if(successful){
this._handshook=true;
}else{
// If there is a problem
// follow advice
if(!this._advice || this._advice["reconnect"] != "none"){
setTimeout(dojo.hitch(this, "init", this.url, this._props), this._interval());
}
}
}
// FIXME: lots of repeated code...why?
this._extendIn = function(message){
// summary: Handle extensions for inbound messages
dojo.forEach(dojox.cometd._extendInList, function(f){
message = f(message) || message;
});
return message;
}
this._extendOut = function(message){
// summary: Handle extensions for inbound messages
dojo.forEach(dojox.cometd._extendOutList, function(f){
message = f(message) || message;
});
return message;
}
this.deliver = function(messages){
dojo.forEach(messages, this._deliver, this);
return messages;
}
this._deliver = function(message){
// dipatch events along the specified path
message = this._extendIn(message);
if(!message["channel"]){
if(message["success"] !== true){
return;
}
}
this.lastMessage = message;
if(message.advice){
this._advice = message.advice; // TODO maybe merge?
}
// check to see if we got a /meta channel message that we care about
var deferred=null;
if( (message["channel"]) &&
(message.channel.length > 5) &&
(message.channel.substr(0, 5) == "/meta")){
// check for various meta topic actions that we need to respond to
switch(message.channel){
case "/meta/connect":
if(message.successful && !this._connected){
this._connected = this._initialized;
this.endBatch();
}else if(!this._initialized){
this._connected = false; // finish disconnect
}
if(this._initialized){
this._publishMeta("connect",message.successful);
}
break;
case "/meta/subscribe":
deferred = this._deferredSubscribes[message.subscription];
try
{
if(!message.successful){
if(deferred){
deferred.errback(new Error(message.error));
deferred.callback();
}
this.currentTransport.cancelConnect();
return;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -