]> git.pond.sub.org Git - eow/blobdiff - static/dojo-release-1.1.1/dojox/cometd/timesync.js
add Dojo 1.1.1
[eow] / static / dojo-release-1.1.1 / dojox / cometd / timesync.js
diff --git a/static/dojo-release-1.1.1/dojox/cometd/timesync.js b/static/dojo-release-1.1.1/dojox/cometd/timesync.js
new file mode 100644 (file)
index 0000000..44ef241
--- /dev/null
@@ -0,0 +1,126 @@
+if(!dojo._hasResource["dojox.cometd.timesync"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.cometd.timesync"] = true;
+dojo.provide("dojox.cometd.timesync");
+dojo.require("dojox.cometd");
+
+/**
+ * this file provides the time synchronization extension to cometd.
+ * Timesync allows the client and server to exchange time information on every 
+ * handshake and connect message so that the client may calculate an approximate
+ * offset from it's own clock epoch to that of the server.
+ *
+ * With each handshake or connect, the extension sends timestamps within the 
+ * ext field like: {ext:{timesync:{tc:12345567890},...},...}
+ * where ts is the timestamp in ms since 1970 of when the message was sent.
+ *
+ * A cometd server that supports timesync, should respond with and ext field
+ * like: {ext:{timesync:{tc:12345567890,ts:1234567900,p:123},...},...}
+ * where ts is the timestamp sent by the client, te is the timestamp on the server
+ * of when the message was received and p is the poll duration in ms - ie the
+ * time the server took before sending the response.
+ *
+ * On receipt of the response, the client is able to use current time to determine
+ * the total trip time, from which p is subtracted to determine an approximate
+ * two way network traversal time. The assumption is made that the network is
+ * symmetric for traversal time, so the offset between the two clocks is 
+ * ts-tc-(now-tc-p)/2. In practise networks (and the cometd client/server software)
+ * is never perfectly symmetric, so accuracy is limited by the difference, which 
+ * can be 10s of milliseconds.
+ *
+ * In order to smooth over any transient fluctuations, the extension keeps a sliding
+ * average of the offsets received. By default this is over 10 messages, but this can
+ * be changed with the dojox.cometd.timesync._window element.
+ */
+dojox.cometd.timesync= new function(){
+
+       this._window=10;// The window size for the sliding average of offset samples.
+       this._minWindow=4;// The window size for the sliding average of offset samples.
+       this._offsets=new Array(); // The samples used to calculate the average offset.
+       this.offset=0;  // The offset in ms between the clients clock and the servers clock. Add this to the local
+                       // time epoch to obtain server time.
+       this.samples=0; // The number of samples used to calculate the offset. If 0, the offset is not valid.
+       
+       this.getServerTime=function(){ // return: long
+               // Summary:
+               //      Calculate the current time on the server
+               // 
+               return new Date().getTime()+this.offset;
+       }
+       
+       this.getServerDate=function(){ // return: Date
+               // Summary:
+               //      Calculate the current time on the server
+               // 
+               return new Date(this.getServerTime());
+       }
+       
+       this.setTimeout=function(/*function*/call,/*long|Date*/atTimeOrDate){
+               // Summary:
+               //      Set a timeout function relative to server time
+               // call:
+               //      the function to call when the timeout occurs
+               // atTimeOrTime: 
+               //      a long timestamp or a Date representing the server time at
+               //      which the timeout should occur.
+               
+               var ts=(atTimeOrDate instanceof Date)?atTimeOrDate.getTime():(0+atTimeOrDate);
+               var tc=ts-this.offset;
+               var interval=tc-new Date().getTime();
+               if (interval<=0)
+                       interval=1;
+               return setTimeout(call,interval);
+       }
+
+       this._in=function(/*Object*/msg){
+               // Summary:
+               //      Handle incoming messages for the timesync extension.
+               // description:
+               //      Look for ext:{timesync:{}} field and calculate offset if present.
+               // msg: 
+               //      The incoming bayeux message
+               
+               var channel=msg.channel;
+               if (channel &&  channel.indexOf('/meta/')==0){
+                       if (msg.ext && msg.ext.timesync){
+                               var sync=msg.ext.timesync;
+                               var now=new Date().getTime();
+                               
+                               this._offsets.push(sync.ts-sync.tc-(now-sync.tc-sync.p)/2);
+                               if (this._offsets.length>this._window)
+                                       this._offsets.shift();          
+                               this.samples++;
+                               var total=0;
+                               for (var i in this._offsets)
+                                       total+=this._offsets[i];
+                               this.offset=parseInt((total/this._offsets.length).toFixed());
+                               
+                               if (this.samples<this._minWindow)
+                                       setTimeout(dojox._scopeName + ".cometd.publish('/meta/ping',null)",100);
+                       }
+               }
+               return msg;
+       }
+
+       this._out=function(msg){
+               // Summary:
+               //      Handle outgoing messages for the timesync extension.
+               // description:
+               //      Look for handshake and connect messages and add the ext:{timesync:{}} fields
+               // msg: 
+               //      The outgoing bayeux message
+               
+               var channel=msg.channel;
+               if (channel &&  channel.indexOf('/meta/')==0){
+                       var now=new Date().getTime();
+                       if (!msg.ext)
+                               msg.ext={};
+                       msg.ext.timesync={tc: now};
+               }
+               return msg;
+       }
+};
+
+dojox.cometd._extendInList.push(dojo.hitch(dojox.cometd.timesync,"_in"));
+dojox.cometd._extendOutList.push(dojo.hitch(dojox.cometd.timesync,"_out"));
+
+}