diff options
Diffstat (limited to 'js/dojo/dojox/cometd/timesync.js')
| -rw-r--r-- | js/dojo/dojox/cometd/timesync.js | 146 |
1 files changed, 146 insertions, 0 deletions
diff --git a/js/dojo/dojox/cometd/timesync.js b/js/dojo/dojox/cometd/timesync.js new file mode 100644 index 0000000..586f65d --- /dev/null +++ b/js/dojo/dojox/cometd/timesync.js @@ -0,0 +1,146 @@ +//>>built +// wrapped by build app +define("dojox/cometd/timesync", ["dijit","dojo","dojox","dojo/require!dojox/cometd/_base"], function(dijit,dojo,dojox){ +dojo.provide("dojox.cometd.timesync"); +dojo.require("dojox.cometd._base"); + +/** + * 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: <code>{ext:{timesync:{tc:12345567890,l:23,o:4567},...},...}</code> + * where:<ul> + * <li>tc is the client timestamp in ms since 1970 of when the message was sent. + * <li>l is the network lag that the client has calculated. + * <li>o is the clock offset that the client has calculated. + * </ul> + * The accuracy of the offset and lag may be calculated with tc-now-l-o, + * which should be zero if the calculated offset and lag are perfectly + * accurate. + * <p> + * A cometd server that supports timesync, should respond only if the + * measured accuracy value is greater than accuracy target. The response + * will be an ext field like: <code>{ext:{timesync:{tc:12345567890,ts:1234567900,p:123,a:3},...},...}</code> + * where:<ul> + * <li>tc is the client timestamp of when the message was sent, + * <li>ts is the server timestamp of when the message was received + * <li>p is the poll duration in ms - ie the time the server took before sending the response. + * <li>a is the measured accuracy of the calculated offset and lag sent by the client + * </ul> + * + * 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 measured accuracy is used to adjust the assumption + * that the network is symmetric for traversal time, so: <ul> + * <li>lag = (now-tc-p)/2-a + * <li>offset = ts-tc-lag + * </ul> + * + * 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._lags = []; // The samples used to calculate the average lag. + this._offsets = []; // The samples used to calculate the average offset. + this.lag=0; // The calculated network lag from client to server + this.offset = 0; // The offset in ms between the clients clock and the servers clock. + 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(); + var l=(now-sync.tc-sync.p)/2-sync.a; + var o=sync.ts-sync.tc-l; + + this._lags.push(l); + this._offsets.push(o); + if(this._offsets.length > this._window){ + this._offsets.shift(); + this._lags.shift(); + } + this.samples++; + l=0; + o=0; + for(var i in this._offsets){ + l+=this._lags[i]; + o+=this._offsets[i]; + } + this.offset = parseInt((o / this._offsets.length).toFixed()); + this.lag = parseInt((l / this._lags.length).toFixed()); + + } + } + 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,l:this.lag,o:this.offset}; + } + return msg; + } +}; + +dojox.cometd._extendInList.push(dojo.hitch(dojox.cometd.timesync, "_in")); +dojox.cometd._extendOutList.push(dojo.hitch(dojox.cometd.timesync, "_out")); + +}); |
