source: Dev/branches/rest-dojo-ui/client/dojox/cometd/timesync.js @ 274

Last change on this file since 274 was 256, checked in by hendrikvanantwerpen, 13 years ago

Reworked project structure based on REST interaction and Dojo library. As
soon as this is stable, the old jQueryUI branch can be removed (it's
kept for reference).

File size: 5.0 KB
Line 
1dojo.provide("dojox.cometd.timesync");
2dojo.require("dojox.cometd._base");
3
4/**
5 * this file provides the time synchronization extension to cometd.
6 * Timesync allows the client and server to exchange time information on every
7 * handshake and connect message so that the client may calculate an approximate
8 * offset from it's own clock epoch to that of the server.
9 *
10 * With each handshake or connect, the extension sends timestamps within the
11 * ext field like: <code>{ext:{timesync:{tc:12345567890,l:23,o:4567},...},...}</code>
12 * where:<ul>
13 *  <li>tc is the client timestamp in ms since 1970 of when the message was sent.
14 *  <li>l is the network lag that the client has calculated.
15 *  <li>o is the clock offset that the client has calculated.
16 * </ul>
17 * The accuracy of the offset and lag may be calculated with tc-now-l-o,
18 * which should be zero if the calculated offset and lag are perfectly
19 * accurate.
20 * <p>
21 * A cometd server that supports timesync, should respond only if the
22 * measured accuracy value is greater than accuracy target. The response
23 * will be an ext field like: <code>{ext:{timesync:{tc:12345567890,ts:1234567900,p:123,a:3},...},...}</code>
24 * where:<ul>
25 *  <li>tc is the client timestamp of when the message was sent,
26 *  <li>ts is the server timestamp of when the message was received
27 *  <li>p is the poll duration in ms - ie the time the server took before sending the response.
28 *  <li>a is the measured accuracy of the calculated offset and lag sent by the client
29 * </ul>
30 *
31 * On receipt of the response, the client is able to use current time to determine
32 * the total trip time, from which p is subtracted to determine an approximate
33 * two way network traversal time. The measured accuracy is used to adjust the assumption
34 * that the network is symmetric for traversal time, so: <ul>
35 * <li>lag = (now-tc-p)/2-a
36 * <li>offset = ts-tc-lag
37 * </ul>
38 *
39 * In order to smooth over any transient fluctuations, the extension keeps a sliding
40 * average of the offsets received. By default this is over 10 messages, but this can
41 * be changed with the dojox.cometd.timesync._window element.
42 */
43dojox.cometd.timesync = new function(){
44        this._window = 10;              // The window size for the sliding average of offset samples.
45        this._lags = [];                // The samples used to calculate the average lag.
46        this._offsets = [];             // The samples used to calculate the average offset.
47        this.lag=0;                             // The calculated network lag from client to server
48        this.offset = 0;                // The offset in ms between the clients clock and the servers clock.
49        this.samples = 0;               // The number of samples used to calculate the offset. If 0, the offset is not valid.
50       
51        this.getServerTime = function(){ // return: long
52                // Summary:
53                //      Calculate the current time on the server
54                //
55                return new Date().getTime()+this.offset;
56        }
57       
58        this.getServerDate = function(){ // return: Date
59                // Summary:
60                //      Calculate the current time on the server
61                //
62                return new Date(this.getServerTime());
63        }
64       
65        this.setTimeout = function(/*function*/call, /*long|Date*/atTimeOrDate){
66                // Summary:
67                //      Set a timeout function relative to server time
68                // call:
69                //      the function to call when the timeout occurs
70                // atTimeOrTime:
71                //      a long timestamp or a Date representing the server time at
72                //      which the timeout should occur.
73               
74                var ts = (atTimeOrDate instanceof Date) ? atTimeOrDate.getTime() : (0 + atTimeOrDate);
75                var tc = ts - this.offset;
76                var interval = tc - new Date().getTime();
77                if(interval <= 0){
78                        interval = 1;
79                }
80                return setTimeout(call,interval);
81        }
82
83        this._in = function(/*Object*/msg){
84                // Summary:
85                //      Handle incoming messages for the timesync extension.
86                // description:
87                //      Look for ext:{timesync:{}} field and calculate offset if present.
88                // msg:
89                //      The incoming bayeux message
90               
91                var channel = msg.channel;
92                if(channel && channel.indexOf('/meta/') == 0){
93                        if(msg.ext && msg.ext.timesync){
94                                var sync = msg.ext.timesync;
95                                var now = new Date().getTime();
96                                var l=(now-sync.tc-sync.p)/2-sync.a;
97                                var o=sync.ts-sync.tc-l;
98                               
99                                this._lags.push(l);
100                                this._offsets.push(o);
101                                if(this._offsets.length > this._window){
102                                        this._offsets.shift();
103                                        this._lags.shift();
104                                }
105                                this.samples++;
106                                l=0;
107                                o=0;
108                                for(var i in this._offsets){
109                                        l+=this._lags[i];
110                                        o+=this._offsets[i];
111                                }
112                                this.offset = parseInt((o / this._offsets.length).toFixed());
113                                this.lag = parseInt((l / this._lags.length).toFixed());
114                               
115                        }
116                }
117                return msg;
118        }
119
120        this._out = function(msg){
121                // Summary:
122                //      Handle outgoing messages for the timesync extension.
123                // description:
124                //      Look for handshake and connect messages and add the ext:{timesync:{}} fields
125                // msg:
126                //      The outgoing bayeux message
127               
128                var channel = msg.channel;
129                if(channel && channel.indexOf('/meta/') == 0){
130                        var now = new Date().getTime();
131                        if(!msg.ext){
132                                msg.ext = {};
133                        }
134                        msg.ext.timesync = {tc:now,l:this.lag,o:this.offset};
135                }
136                return msg;
137        }
138};
139
140dojox.cometd._extendInList.push(dojo.hitch(dojox.cometd.timesync, "_in"));
141dojox.cometd._extendOutList.push(dojo.hitch(dojox.cometd.timesync, "_out"));
Note: See TracBrowser for help on using the repository browser.