📄 _base.js
字号:
if(!dojo._hasResource["dojox.cometd._base"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.dojo._hasResource["dojox.cometd._base"] = true;dojo.provide("dojox.cometd._base");dojo.require("dojo.AdapterRegistry");dojo.require("dojo.io.script");/* * this file defines Comet protocol client. Actual message transport is * deferred to one of several connection type implementations. The default is a * long-polling implementation. A single global object named "dojox.cometd" is * used to mediate for these connection types in order to provide a stable * interface. * * extensions modules may be loaded (eg "dojox.cometd.timestamp", that use * the cometd._extendInList and cometd._extendOutList fields to provide functions * that extend and handling incoming and outgoing messages. */dojox.cometd = new function(){ // cometd states: // alex; OMG, these "constants" need to die. Java truly is a degenerative disease. this.DISCONNECTED = "DISCONNECTED"; // _initialized==false && _connected==false this.CONNECTING = "CONNECTING"; // _initialized==true && _connected==false (handshake sent) this.CONNECTED = "CONNECTED"; // _initialized==true && _connected==true (first successful connect) this.DISCONNECTING = "DISCONNECING"; // _initialized==false && _connected==true (disconnect sent) this._initialized = false; this._connected = false; this._polling = false; this.expectedNetworkDelay = 5000; // expected max network delay this.connectTimeout = 0; // If set, used as ms to wait for a connect response and sent as the advised timeout this.connectionTypes = new dojo.AdapterRegistry(true); this.version = "1.0"; this.minimumVersion = "0.9"; this.clientId = null; this.messageId = 0; this.batch = 0; this._isXD = false; this.handshakeReturn = null; this.currentTransport = null; this.url = null; this.lastMessage = null; this._messageQ = []; this.handleAs = "json-comment-optional"; this._advice = {}; this._backoffInterval = 0; this._backoffIncrement = 1000; this._backoffMax = 60000; this._deferredSubscribes = {}; this._deferredUnsubscribes = {}; this._subscriptions = []; this._extendInList = []; // List of functions invoked before delivering messages this._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 // summary: // Initialize the cometd implementation of the Bayeux protocol // description: // Initialize the cometd implementation of the Bayeux protocol by // sending a handshake message. The cometd state will be changed to CONNECTING // until a handshake response is received and the first successful connect message // has returned. // The protocol state changes may be monitored // by subscribing to the dojo topic "/cometd/meta" where events are // published in the form {cometd:this,action:"handshake",successful:true,state:this.state()} // root: // The URL of the cometd server. If the root is absolute, the host // is examined to determine if xd transport is needed. Otherwise the // same domain is assumed. // props: // An optional object that is used as the basis of the handshake message // bargs: // An optional object of bind args mixed in with the send of the handshake // example: // | dojox.cometd.init("/cometd"); // | dojox.cometd.init("http://xdHost/cometd",{ext:{user:"fred",pwd:"secret"}}); // FIXME: if the root isn't from the same host, we should automatically // 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){ console.debug("no cometd root specified in djConfig and no root passed"); return null; } // Are we x-domain? borrowed from dojo.uri.Uri in lieu of fixed host and port properties 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){ if(props.ext){ if(props.ext["json-comment-filtered"]!==true && props.ext["json-comment-filtered"]!==false){ props.ext["json-comment-filtered"] = true; } }else{ props.ext = { "json-comment-filtered": true }; } props.supportedConnectionTypes = dojo.map(this.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){ console.debug("handshake error!:",e); this._backoff(); this._finishInit([{}]); }) }; 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); } dojo.publish("/cometd/meta", [ { cometd: this, action: "handshake", successful: true, state: this.state() } ]); return r; } this.publish = function(/*String*/ channel, /*Object*/ data, /*Object?*/ props){ // summary: // publishes the passed message to the cometd server for delivery // on the specified topic // channel: // the destination channel for the message // data: // a JSON object containing the message "payload" // properties: // Optional. Other meta-data to be mixed into the top-level of the // message 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 // summary: // inform the server of this client's interest in channel // description: // `dojox.cometd.subscribe()` handles all the hard work of telling // the server that we want to be notified when events are // published on a particular topic. `subscribe` accepts a function // to handle messages and returns a `dojo.Deferred` object which // has an extra property added to it which makes it suitable for // passing to `dojox.cometd.unsubscribe()` as a "subscription // handle" (much like the handle object that `dojo.connect()` // produces and which `dojo.disconnect()` expects). // // Note that of a subscription is registered before a connection // with the server is established, events sent before the // connection is established will not be delivered to this client. // The deferred object which `subscribe` returns will callback // when the server successfuly acknolwedges receipt of our // "subscribe" request. // channel: // name of the cometd channel to subscribe to // objOrFunc: // an object scope for funcName or the name or reference to a // function to be called when messages are delivered to the // channel // funcName: // the second half of the objOrFunc/funcName pair for identifying // a callback function to notifiy upon channel message delivery // example: // Simple subscribe use-case // | dojox.cometd.init("http://myserver.com:8080/cometd"); // | // log out all incoming messages on /foo/bar // | dojox.cometd.subscribe("/foo/bar", console, "debug"); // example: // Subscribe before connection is initialized // | dojox.cometd.subscribe("/foo/bar", console, "debug"); // | dojox.cometd.init("http://myserver.com:8080/cometd"); // example: // Subscribe an unsubscribe // | dojox.cometd.init("http://myserver.com:8080/cometd"); // | var h = dojox.cometd.subscribe("/foo/bar", console, "debug"); // | dojox.cometd.unsubscribe(h); // example: // Listen for successful subscription: // | dojox.cometd.init("http://myserver.com:8080/cometd"); // | var h = dojox.cometd.subscribe("/foo/bar", console, "debug"); // | h.addCallback(function(){ // | console.debug("subscription to /foo/bar established"); // | }); props = props||{}; if(objOrFunc){ var tname = "/cometd"+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){ // summary: // inform the server of this client's disinterest in channel // channel: // name of the cometd channel to unsubscribe from // objOrFunc: // an object scope for funcName or the name or reference to a // function to be called when messages are delivered to the // channel. If null then all subscribers to the channel are unsubscribed. // funcName: // the second half of the objOrFunc/funcName pair for identifying // a callback function to notifiy upon channel message delivery if( (arguments.length == 1) && (!dojo.isString(channel)) && (channel.args) ){ // it's a subscription handle, unroll return this.unsubscribe.apply(this, channel.args); } var tname = "/cometd"+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(){ // summary: // Disconnect from the server. // description: // Disconnect from the server by sending a disconnect message // example: // | dojox.cometd.disconnect(); 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; dojo.publish("/cometd/meta", [{cometd:this,action:"connect",successful:false,state:this.state()}]); } this._initialized=false; dojo.publish("/cometd/meta", [{cometd:this,action:"disconnect",successful:true,state:this.state()}]); } // public extension points 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){ // placeholder - replaced by _finishInit } this.tunnelCollapse = function(){ // placeholder - replaced by _finishInit } 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) console.debug("Retry in interval+backoff="+this._advice.interval+"+"+this._backoffInterval+"="+i+"ms"); return i; } 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){ console.debug("cometd protocol version mismatch. We wanted", this.minimumVersion, "but got", data.version); successful=false; this._advice.reconnect="none"; } // If all OK if(successful){ // pick a transport this.currentTransport = this.connectionTypes.match( data.supportedConnectionTypes, data.version, this._isXD ); // initialize the transport this.currentTransport._cometd = this; this.currentTransport.version = data.version; this.clientId = data.clientId; this.tunnelInit = dojo.hitch(this.currentTransport, "tunnelInit"); this.tunnelCollapse = dojo.hitch(this.currentTransport, "tunnelCollapse"); this.currentTransport.startup(data); } dojo.publish("/cometd/meta", [{cometd:this,action:"handshook",successful:successful,state:this.state()}]);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -