1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
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"));
}
|