root / dojox / trunk / cometd / _base.js

Revision 16295, 22.2 kB (checked in by gregw, 13 months ago)

Refs #8160 fixed bug introduced with meta reestablish messages

  • Property svn:eol-style set to native
Line 
1dojo.provide("dojox.cometd._base");
2dojo.require("dojo.AdapterRegistry");
3
4
5/*
6 * this file defines Comet protocol client. Actual message transport is
7 * deferred to one of several connection type implementations. The default is a
8 * long-polling implementation. A single global object named "dojox.cometd" is
9 * used to mediate for these connection types in order to provide a stable
10 * interface.
11 *
12 * extensions modules may be loaded (eg "dojox.cometd.timestamp", that use
13 * the cometd._extendInList and cometd._extendOutList fields to provide functions
14 * that extend and handling incoming and outgoing messages.
15 *
16 * By default the long-polling and callback-polling transports will be required.
17 * If specific or alternative transports are required, then they can be directly
18 * loaded. For example dojo.require('dojox.cometd.longPollTransportJsonEncoded')
19 * will load cometd with only the json encoded variant of the long polling transport.
20 */
21
22dojox.cometd = {
23        Connection: function(prefix){ // This constructor is stored as dojox.cometd.Connection
24                // summary
25                // This constructor is used to create new cometd connections. Generally, you should use
26                // one cometd connection for each server you connect to. A default connection instance is
27                // created at dojox.cometd.
28                // To connect to a new server you can create an instance like:
29                // var cometd = new dojox.cometd.Connection("/otherServer");
30                // cometd.init("http://otherServer.com/cometd");
31                //
32                // prefix is the prefix for all the events that are published in the Dojo pub/sub system.
33                // You must include this prefix, and it should start with a slash like "/myprefix".
34               
35                // cometd states:
36                // unconnected, handshaking, connecting, connected, disconnected
37                dojo.mixin(this, {
38                prefix: prefix,
39                        _status: "unconnected",
40                        _handshook: false,
41                        _initialized: false,
42                        _polling: false,
43               
44                        expectedNetworkDelay: 10000, // expected max network delay
45                        connectTimeout: 0,               // If set, used as ms to wait for a connect response and sent as the advised timeout
46               
47                        version:        "1.0",
48                        minimumVersion: "0.9",
49                        clientId: null,
50                        messageId: 0,
51                        batch: 0,
52               
53                        _isXD: false,
54                        handshakeReturn: null,
55                        currentTransport: null,
56                        url: null,
57                        lastMessage: null,
58                        _messageQ: [],
59                        handleAs: "json",
60                        _advice: {},
61                        _backoffInterval: 0,
62                        _backoffIncrement: 1000,
63                        _backoffMax: 60000,
64                        _deferredSubscribes: {},
65                        _deferredUnsubscribes: {},
66                        _subscriptions: [],
67                        _extendInList: [],      // List of functions invoked before delivering messages
68                        _extendOutList: []      // List of functions invoked before sending messages
69                       
70                });
71       
72                this.state = function() {
73                         return this._status;
74                }
75       
76                this.init = function(   /*String*/      root,
77                                        /*Object?*/ props,
78                                        /*Object?*/ bargs){     // return: dojo.Deferred
79                        //      summary:
80                        //              Initialize the cometd implementation of the Bayeux protocol
81                        //      description:
82                        //              Initialize the cometd implementation of the Bayeux protocol by
83                        //              sending a handshake message. The cometd state will be changed to CONNECTING
84                        //              until a handshake response is received and the first successful connect message
85                        //              has returned.
86                        //              The protocol state changes may be monitored
87                        //              by subscribing to the dojo topic "/prefix/meta" (typically "/cometd/meta") where
88                        //              events are published in the form
89                        //                 {cometd:this,action:"handshake",successful:true,state:this.state()}
90                        //      root:
91                        //              The URL of the cometd server. If the root is absolute, the host
92                        //              is examined to determine if xd transport is needed. Otherwise the
93                        //              same domain is assumed.
94                        //      props:
95                        //              An optional object that is used as the basis of the handshake message
96                        //      bargs:
97                        //              An optional object of bind args mixed in with the send of the handshake
98                        //      example:
99                        //      |       dojox.cometd.init("/cometd");
100                        //      |       dojox.cometd.init("http://xdHost/cometd",{ext:{user:"fred",pwd:"secret"}});
101       
102                        // FIXME: if the root isn't from the same host, we should automatically
103                        // try to select an XD-capable transport
104                        props = props || {};
105                        // go ask the short bus server what we can support
106                        props.version = this.version;
107                        props.minimumVersion = this.minimumVersion;
108                        props.channel = "/meta/handshake";
109                        props.id = "" + this.messageId++;
110       
111                        this.url = root || dojo.config["cometdRoot"];
112                        if(!this.url){
113                                throw "no cometd root";
114                                return null;
115                        }
116       
117                        // Are we x-domain? borrowed from dojo.uri.Uri in lieu of fixed host and port properties
118                        var regexp = "^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?$";
119                        var parts = ("" + window.location).match(new RegExp(regexp));
120                        if(parts[4]){
121                                var tmp = parts[4].split(":");
122                                var thisHost = tmp[0];
123                                var thisPort = tmp[1]||"80"; // FIXME: match 443
124       
125                                parts = this.url.match(new RegExp(regexp));
126                                if(parts[4]){
127                                        tmp = parts[4].split(":");
128                                        var urlHost = tmp[0];
129                                        var urlPort = tmp[1]||"80";
130                                        this._isXD = ((urlHost != thisHost)||(urlPort != thisPort));
131                                }
132                        }
133       
134                        if(!this._isXD){
135                                props.supportedConnectionTypes = dojo.map(dojox.cometd.connectionTypes.pairs, "return item[0]");
136                        }
137       
138                        props = this._extendOut(props);
139       
140                        var bindArgs = {
141                                url: this.url,
142                                handleAs: this.handleAs,
143                                content: { "message": dojo.toJson([props]) },
144                                load: dojo.hitch(this,function(msg){
145                                        this._backon();
146                                        this._finishInit(msg);
147                                }),
148                                error: dojo.hitch(this,function(e){
149                                        this._backoff();
150                                        this._finishInit(e);
151                                }),
152                                timeout: this.expectedNetworkDelay
153                        };
154       
155                        if(bargs){
156                                dojo.mixin(bindArgs, bargs);
157                        }
158                        this._props = props;
159                        for(var tname in this._subscriptions){
160                                for(var sub in this._subscriptions[tname]){
161                                        if(this._subscriptions[tname][sub].topic){
162                                                dojo.unsubscribe(this._subscriptions[tname][sub].topic);
163                                        }
164                                }
165                        }
166                        this._messageQ = [];
167                        this._subscriptions = [];
168                        this._initialized = true;
169                        this._status = "handshaking";
170                        this.batch = 0;
171                        this.startBatch();
172                       
173                        var r;
174                        // if xdomain, then we assume jsonp for handshake
175                        if(this._isXD){
176                                bindArgs.callbackParamName = "jsonp";
177                                r = dojo.io.script.get(bindArgs);
178                        }else{
179                                r = dojo.xhrPost(bindArgs);
180                        }
181                        return r;
182                }
183               
184                this.publish = function(/*String*/ channel, /*Object*/ data, /*Object?*/ props){
185                        // summary:
186                        //              publishes the passed message to the cometd server for delivery
187                        //              on the specified topic
188                        // channel:
189                        //              the destination channel for the message
190                        // data:
191                        //              a JSON object containing the message "payload"
192                        // properties:
193                        //              Optional. Other meta-data to be mixed into the top-level of the
194                        //              message
195                        var message = {
196                                data: data,
197                                channel: channel
198                        };
199                        if(props){
200                                dojo.mixin(message, props);
201                        }
202                        this._sendMessage(message);
203                }
204       
205               
206                this.subscribe = function(      /*String */     channel,
207                                                /*Object */     objOrFunc,
208                                                /*String */     funcName,
209                                                /*Object?*/ props){ // return: dojo.Deferred
210                        //      summary:
211                        //              inform the server of this client's interest in channel
212                        //      description:
213                        //              `dojox.cometd.subscribe()` handles all the hard work of telling
214                        //              the server that we want to be notified when events are
215                        //              published on a particular topic. `subscribe` accepts a function
216                        //              to handle messages and returns a `dojo.Deferred` object which
217                        //              has an extra property added to it which makes it suitable for
218                        //              passing to `dojox.cometd.unsubscribe()` as a "subscription
219                        //              handle" (much like the handle object that `dojo.connect()`
220                        //              produces and which `dojo.disconnect()` expects).
221                        //             
222                        //              Note that of a subscription is registered before a connection
223                        //              with the server is established, events sent before the
224                        //              connection is established will not be delivered to this client.
225                        //              The deferred object which `subscribe` returns will callback
226                        //              when the server successfuly acknolwedges receipt of our
227                        //              "subscribe" request.
228                        //      channel:
229                        //              name of the cometd channel to subscribe to
230                        //      objOrFunc:
231                        //              an object scope for funcName or the name or reference to a
232                        //              function to be called when messages are delivered to the
233                        //              channel
234                        //      funcName:
235                        //              the second half of the objOrFunc/funcName pair for identifying
236                        //              a callback function to notifiy upon channel message delivery
237                        //      example:
238                        //              Simple subscribe use-case
239                        //      |       dojox.cometd.init("http://myserver.com:8080/cometd");
240                        //      |       // log out all incoming messages on /foo/bar
241                        //      |       dojox.cometd.subscribe("/foo/bar", console, "debug");
242                        //      example:
243                        //              Subscribe before connection is initialized
244                        //      |       dojox.cometd.subscribe("/foo/bar", console, "debug");
245                        //      |       dojox.cometd.init("http://myserver.com:8080/cometd");
246                        //      example:
247                        //              Subscribe an unsubscribe
248                        //      |       dojox.cometd.init("http://myserver.com:8080/cometd");
249                        //      |       var h = dojox.cometd.subscribe("/foo/bar", console, "debug");
250                        //      |       dojox.cometd.unsubscribe(h);
251                        //      example:
252                        //              Listen for successful subscription:
253                        //      |       dojox.cometd.init("http://myserver.com:8080/cometd");
254                        //      |       var h = dojox.cometd.subscribe("/foo/bar", console, "debug");
255                        //      |       h.addCallback(function(){
256                        //      |               console.debug("subscription to /foo/bar established");
257                        //      |       });
258       
259                        props = props||{};
260                        if(objOrFunc){
261                                var tname = prefix + channel;
262                                var subs = this._subscriptions[tname];
263                                if(!subs || subs.length == 0){
264                                        subs = [];
265                                        props.channel = "/meta/subscribe";
266                                        props.subscription = channel;
267                                        this._sendMessage(props);
268                                       
269                                        var _ds = this._deferredSubscribes;
270                                        if(_ds[channel]){
271                                                _ds[channel].cancel();
272                                                delete _ds[channel];
273                                        }
274                                        _ds[channel] = new dojo.Deferred();
275                                }
276                               
277                                for(var i in subs){
278                                        if(subs[i].objOrFunc === objOrFunc && (!subs[i].funcName&&!funcName||subs[i].funcName==funcName) ){
279                                                return null;
280                                        }
281                                }
282                               
283                                var topic = dojo.subscribe(tname, objOrFunc, funcName);
284                                subs.push({ 
285                                        topic: topic, 
286                                        objOrFunc: objOrFunc, 
287                                        funcName: funcName
288                                });
289                                this._subscriptions[tname] = subs;
290                        }
291                        var ret = this._deferredSubscribes[channel] || {};
292                        ret.args = dojo._toArray(arguments);
293                        return ret; // dojo.Deferred
294                }
295       
296                this.unsubscribe = function(    /*String*/      channel,
297                                                /*Object?*/ objOrFunc,
298                                                /*String?*/ funcName,
299                                                /*Object?*/ props){
300                        // summary:
301                        //              inform the server of this client's disinterest in channel
302                        // channel:
303                        //              name of the cometd channel to unsubscribe from
304                        // objOrFunc:
305                        //              an object scope for funcName or the name or reference to a
306                        //              function to be called when messages are delivered to the
307                        //              channel. If null then all subscribers to the channel are unsubscribed.
308                        // funcName:
309                        //              the second half of the objOrFunc/funcName pair for identifying
310                        //              a callback function to notifiy upon channel message delivery
311       
312                        if(
313                                (arguments.length == 1) &&
314                                (!dojo.isString(channel)) &&
315                                (channel.args)
316                        ){
317                                // it's a subscription handle, unroll
318                                return this.unsubscribe.apply(this, channel.args);
319                        }
320                       
321                        var tname = prefix + channel;
322                        var subs = this._subscriptions[tname];
323                        if(!subs || subs.length==0){
324                                return null;
325                        }
326       
327                        var s=0;
328                        for(var i in subs){
329                                var sb = subs[i];
330                                if((!objOrFunc) ||
331                                        (
332                                                sb.objOrFunc===objOrFunc &&
333                                                (!sb.funcName && !funcName || sb.funcName==funcName)
334                                        )
335                                ){
336                                        dojo.unsubscribe(subs[i].topic);
337                                        delete subs[i];
338                                }else{
339                                        s++;
340                                }
341                        }
342                       
343                        if(s == 0){
344                                props = props || {};
345                                props.channel = "/meta/unsubscribe";
346                                props.subscription = channel;
347                                delete this._subscriptions[tname];
348                                this._sendMessage(props);
349                                this._deferredUnsubscribes[channel] = new dojo.Deferred();
350                                if(this._deferredSubscribes[channel]){
351                                        this._deferredSubscribes[channel].cancel();
352                                        delete this._deferredSubscribes[channel];
353                                }
354                        }
355                        return this._deferredUnsubscribes[channel]; // dojo.Deferred
356                }
357               
358               
359                this.disconnect = function(){
360                        //      summary:
361                        //              Disconnect from the server.
362                        //      description:
363                        //              Disconnect from the server by sending a disconnect message
364                        //      example:
365                        //      |       dojox.cometd.disconnect();
366       
367                        for(var tname in this._subscriptions){
368                                for(var sub in this._subscriptions[tname]){
369                                        if(this._subscriptions[tname][sub].topic){
370                                                dojo.unsubscribe(this._subscriptions[tname][sub].topic);
371                                        }
372                                }
373                        }
374                        this._subscriptions = [];
375                        this._messageQ = [];
376                        if(this._initialized && this.currentTransport){
377                                this._initialized=false;
378                                this.currentTransport.disconnect();
379                        }
380                        if(!this._polling) {
381                                this._publishMeta("connect",false);
382                        }
383                        this._initialized=false;
384                        this._handshook=false;
385                        this._status = "disconnected"; //should be disconnecting, but we ignore the reply to this message
386                        this._publishMeta("disconnect",true);
387                }
388       
389               
390                // public extension points
391               
392                this.subscribed = function(     /*String*/channel, /*Object*/message){ }
393       
394                this.unsubscribed = function(/*String*/channel, /*Object*/message){ }
395       
396       
397                // private methods (TODO name all with leading _)
398       
399                this.tunnelInit = function(childLocation, childDomain){
400                        // placeholder - replaced by _finishInit
401                }
402               
403                this.tunnelCollapse = function(){
404                        // placeholder - replaced by _finishInit
405                }
406               
407                this._backoff = function(){
408                        if(!this._advice){
409                                this._advice={reconnect:"retry",interval:0};
410                        }else if(!this._advice.interval){
411                                this._advice.interval = 0;
412                        }
413                       
414                        if(this._backoffInterval < this._backoffMax){
415                                this._backoffInterval += this._backoffIncrement;
416                        }
417                }
418               
419                this._backon = function(){
420                        this._backoffInterval=0;
421                }
422       
423                this._interval = function(){
424                        var i = this._backoffInterval + (this._advice ? (this._advice.interval ? this._advice.interval : 0) : 0);
425                        if (i>0){
426                                console.log("Retry in interval+backoff=" + this._advice.interval + "+" + this._backoffInterval+"="+i+"ms");
427                        }
428                        return i;
429                }
430               
431                this._publishMeta = function(action,successful,props){
432                        try {
433                                var meta = {cometd:this,action:action,successful:successful,state:this.state()};
434                                if (props){
435                                        dojo.mixin(meta, props);
436                                }
437                                dojo.publish(this.prefix + "/meta", [meta]);
438                        } catch(e) {
439                                console.log(e);
440                        }
441                }
442       
443                this._finishInit = function(data){
444                        //      summary:
445                        //              Handle the handshake return from the server and initialize
446                        //              connection if all is OK
447
448                        if(this._status!="handshaking") {return;}
449
450
451                        var wasHandshook = this._handshook;
452                        var successful = false; 
453                        var metaMsg = {};
454
455                        if (data instanceof Error) {
456                                dojo.mixin(metaMsg,{
457                                        reestablish:false,
458                                        failure: true,
459                                        error: data,
460                                        advice: this._advice
461                                });
462                        } else {
463                                data = data[0];
464                                data = this._extendIn(data);
465                                this.handshakeReturn = data;
466                                // remember any advice
467                                if(data["advice"]){
468                                        this._advice = data.advice;
469                                }
470
471                                successful = data.successful ? data.successful : false;
472
473                                // check version
474                                if(data.version < this.minimumVersion){
475                                        if (console.log)
476                                                console.log("cometd protocol version mismatch. We wanted", this.minimumVersion, "but got", data.version);
477                                        successful=false;
478                                        this._advice.reconnect="none";
479                                }
480                                dojo.mixin(metaMsg,{reestablish: successful && wasHandshook, response:data});
481                        } 
482
483                        this._publishMeta("handshake",successful,metaMsg);
484                        //in the meta listeners, disconnect() may have been called, so recheck it now to
485                        //prevent resends or continuing with initializing the protocol
486                        if(this._status!="handshaking") {return;}
487
488                        // If all OK
489                        if(successful){
490                                this._status = "connecting";
491                                this._handshook = true;
492                                // pick a transport
493                                this.currentTransport = dojox.cometd.connectionTypes.match(
494                                        data.supportedConnectionTypes,
495                                        data.version,
496                                        this._isXD
497                                );
498                                var transport = this.currentTransport;
499                                // initialize the transport
500                                transport._cometd = this;
501                                transport.version = data.version;
502                                this.clientId = data.clientId;
503                                this.tunnelInit = transport.tunnelInit && dojo.hitch(transport, "tunnelInit");
504                                this.tunnelCollapse = transport.tunnelCollapse && dojo.hitch(transport, "tunnelCollapse");
505                                transport.startup(data);
506                        }else{
507                                // If there is a problem follow advice
508                                if(!this._advice || this._advice["reconnect"] != "none"){
509                                        setTimeout(dojo.hitch(this, "init", this.url, this._props), this._interval());
510                                }
511                        }
512                }
513       
514                // FIXME: lots of repeated code...why?
515                this._extendIn = function(message){
516                        // summary: Handle extensions for inbound messages
517                        dojo.forEach(dojox.cometd._extendInList, function(f){
518                                message = f(message) || message;
519                        });
520                        return message;
521                }
522       
523                this._extendOut = function(message){
524                        // summary: Handle extensions for inbound messages
525                        dojo.forEach(dojox.cometd._extendOutList, function(f){
526                                message = f(message) || message;
527                        });
528                        return message;
529                }
530       
531                this.deliver = function(messages){
532                        dojo.forEach(messages, this._deliver, this);
533                        return messages;
534                }
535       
536                this._deliver = function(message){
537                        // dipatch events along the specified path
538                       
539                        message = this._extendIn(message);
540       
541                        if(!message["channel"]){
542                                if(message["success"] !== true){
543                                        return;
544                                }
545                        }
546                        this.lastMessage = message;
547       
548                        if(message.advice){
549                                this._advice = message.advice; // TODO maybe merge?
550                        }
551       
552                        // check to see if we got a /meta channel message that we care about
553                        var deferred=null;
554                        if(     (message["channel"]) &&
555                                (message.channel.length > 5) &&
556                                (message.channel.substr(0, 5) == "/meta")){
557                                // check for various meta topic actions that we need to respond to
558                                switch(message.channel){
559                                        case "/meta/connect":
560                                                var metaMsg = {response: message};
561                                                if(message.successful) {
562                                                        if (this._status != "connected"){
563                                                                this._status = "connected";
564                                                                this.endBatch();
565                                                        }
566                                                }
567 
568                                                if(this._initialized){
569                                                        this._publishMeta("connect",message.successful, metaMsg);
570                                                }
571                                                break;
572                                        case "/meta/subscribe":
573                                                deferred = this._deferredSubscribes[message.subscription];
574                                                try
575                                                {
576                                                        if(!message.successful){
577                                                                if(deferred){
578                                                                        deferred.errback(new Error(message.error));
579                                                                }
580                                                                this.currentTransport.cancelConnect();
581                                                                return;
582                                                        }
583                                                        if(deferred){
584                                                                deferred.callback(true);
585                                                        }
586                                                        this.subscribed(message.subscription, message);
587                                                } catch(e)      {
588                                                        log.warn(e);
589                                                }
590                                                break;
591                                        case "/meta/unsubscribe":
592                                                deferred = this._deferredUnsubscribes[message.subscription];
593                                                try
594                                                {
595                                                        if(!message.successful){
596                                                                if(deferred){
597                                                                        deferred.errback(new Error(message.error));
598                                                                }
599                                                                this.currentTransport.cancelConnect();
600                                                                return;
601                                                        }
602                                                        if(deferred){
603                                                                deferred.callback(true);
604                                                        }
605                                                        this.unsubscribed(message.subscription, message);
606                                                } catch(e)      {
607                                                        log.warn(e);
608                                                }
609                                                break;
610                                        default:
611                                                if(message.successful && !message.successful){
612                                                        this.currentTransport.cancelConnect();
613                                                        return;
614                                                }
615                                }
616                        }
617                       
618                        // send the message down for processing by the transport
619                        this.currentTransport.deliver(message);
620       
621                        if(message.data){
622                                // dispatch the message to any locally subscribed listeners
623                                try{
624                                        var messages = [message];
625       
626                                        // Determine target topic
627                                        var tname = prefix + message.channel;
628       
629                                        // Deliver to globs that apply to target topic
630                                        var tnameParts = message.channel.split("/");
631                                        var tnameGlob = prefix;
632                                        for (var i = 1; i < tnameParts.length - 1; i++){
633                                                dojo.publish(tnameGlob + "/**", messages);
634                                                tnameGlob += "/" + tnameParts[i];
635                                        }
636                                        dojo.publish(tnameGlob + "/**", messages);
637                                        dojo.publish(tnameGlob + "/*", messages);
638               
639                                        // deliver to target topic
640                                        dojo.publish(tname,messages);
641                                }catch(e){
642                                        console.log(e);
643                                }
644                        }
645                }
646       
647                this._sendMessage = function(/* object */ message){
648                        if(this.currentTransport && !this.batch){
649                                return this.currentTransport.sendMessages([message]);
650                        }else{
651                                this._messageQ.push(message);
652                                return null;
653                        }
654                }
655       
656                this.startBatch = function(){
657                        this.batch++;
658                }
659       
660                this.endBatch = function(){
661                        if(--this.batch <= 0 && this.currentTransport && this._status == "connected"){
662                                this.batch = 0;
663                                var messages = this._messageQ;
664                                this._messageQ = [];
665                                if(messages.length > 0){
666                                        this.currentTransport.sendMessages(messages);
667                                }
668                        }
669                }
670               
671                this._onUnload = function(){
672                        // make this the last of the onUnload method
673                        dojo.addOnUnload(dojox.cometd, "disconnect");
674                }
675       
676                this._connectTimeout = function(){
677                        // summary: Return the connect timeout in ms, calculated as the minimum of the advised timeout
678                        // and the configured timeout. Else 0 to indicate no client side timeout
679                        var advised=0;
680                        if(this._advice && this._advice.timeout && this.expectedNetworkDelay > 0){
681                                advised = this._advice.timeout + this.expectedNetworkDelay;
682                        }
683                       
684                        if(this.connectTimeout > 0 && this.connectTimeout < advised){
685                                return this.connectTimeout;
686                        }
687                       
688                        return advised;
689                }
690        },
691        // connectionTypes are shared by all cometd Connection.
692        connectionTypes : new dojo.AdapterRegistry(true)
693}
694
695// create the default instance
696dojox.cometd.Connection.call(dojox.cometd,"/cometd"); 
697
698/*
699
700FIXME: TODOC: this info should be part of the relevant functions and/or overview so
701the parser can find it.
702
703transport objects MUST expose the following methods:
704        - check
705        - startup
706        - sendMessages
707        - deliver
708        - disconnect
709optional, standard but transport dependent methods are:
710        - tunnelCollapse
711        - tunnelInit
712
713Transports SHOULD be namespaced under the cometd object and transports MUST
714register themselves with cometd.connectionTypes
715
716here's a stub transport defintion:
717
718cometd.blahTransport = new function(){
719        this._connectionType="my-polling";
720        this._cometd=null;
721        this.lastTimestamp = null;
722
723        this.check = function(types, version, xdomain){
724                // summary:
725                //              determines whether or not this transport is suitable given a
726                //              list of transport types that the server supports
727                return dojo.inArray(types, "blah");
728        }
729
730        this.startup = function(){
731                if(dojox.cometd._polling){ return; }
732                // FIXME: fill in startup routine here
733                dojox.cometd._polling = true;
734        }
735
736        this.sendMessages = function(message){
737                // FIXME: fill in message array sending logic
738        }
739
740        this.deliver = function(message){
741        }
742
743        this.disconnect = function(){
744                // send orderly disconnect message
745        }
746
747        this.cancelConnect = function(){
748                // cancel the current connection
749        }
750}
751cometd.connectionTypes.register("blah", cometd.blahTransport.check, cometd.blahTransport);
752*/
753
754dojo.addOnUnload(dojox.cometd, "_onUnload");
Note: See TracBrowser for help on using the browser.