- Author:
- David Nickerson <david.nickerson@gmail.com>
- Date:
- 2021-09-17 15:50:49+12:00
- Desc:
- tweak html formatting
- Permanent Source URI:
- https://models.fieldml.org/workspace/a1/rawfile/1b3862589abf79ae9119ee0b5e99a8b785d762e1/dojo-presentation/js/dojo/dojox/cometd/timesync.js
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: {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"));