2 * Copyright (c) 2010 the original author or authors.
\r
4 * Licensed under the Apache License, Version 2.0 (the "License");
\r
5 * you may not use this file except in compliance with the License.
\r
6 * You may obtain a copy of the License at
\r
8 * http://www.apache.org/licenses/LICENSE-2.0
\r
10 * Unless required by applicable law or agreed to in writing, software
\r
11 * distributed under the License is distributed on an "AS IS" BASIS,
\r
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
\r
13 * See the License for the specific language governing permissions and
\r
14 * limitations under the License.
\r
19 function bind(org_cometd)
\r
22 * With each handshake or connect, the extension sends timestamps within the
\r
23 * ext field like: <code>{ext:{timesync:{tc:12345567890,l:23,o:4567},...},...}</code>
\r
25 * <li>tc is the client timestamp in ms since 1970 of when the message was sent.
\r
26 * <li>l is the network lag that the client has calculated.
\r
27 * <li>o is the clock offset that the client has calculated.
\r
31 * A cometd server that supports timesync, can respond with an ext
\r
32 * field like: <code>{ext:{timesync:{tc:12345567890,ts:1234567900,p:123,a:3},...},...}</code>
\r
34 * <li>tc is the client timestamp of when the message was sent,
\r
35 * <li>ts is the server timestamp of when the message was received
\r
36 * <li>p is the poll duration in ms - ie the time the server took before sending the response.
\r
37 * <li>a is the measured accuracy of the calculated offset and lag sent by the client
\r
41 * The relationship between tc, ts & l is given by <code>ts=tc+o+l</code> (the
\r
42 * time the server received the messsage is the client time plus the offset plus the
\r
43 * network lag). Thus the accuracy of the o and l settings can be determined with
\r
44 * <code>a=(tc+o+l)-ts</code>.
\r
47 * When the client has received the response, it can make a more accurate estimate
\r
48 * of the lag as <code>l2=(now-tc-p)/2</code> (assuming symmetric lag).
\r
49 * A new offset can then be calculated with the relationship on the client
\r
50 * that <code>ts=tc+o2+l2</code>, thus <code>o2=ts-tc-l2</code>.
\r
53 * Since the client also receives the a value calculated on the server, it
\r
54 * should be possible to analyse this and compensate for some asymmetry
\r
55 * in the lag. But the current client does not do this.
\r
58 * @param configuration
\r
60 return org_cometd.TimeSyncExtension = function(configuration)
\r
63 var _maxSamples = configuration && configuration.maxSamples || 10;
\r
69 function _debug(text, args)
\r
71 _cometd._debug(text, args);
\r
74 this.registered = function(name, cometd)
\r
77 _debug('TimeSyncExtension: executing registration callback');
\r
80 this.unregistered = function()
\r
82 _debug('TimeSyncExtension: executing unregistration callback');
\r
88 this.incoming = function(message)
\r
90 var channel = message.channel;
\r
91 if (channel && channel.indexOf('/meta/') === 0)
\r
93 if (message.ext && message.ext.timesync)
\r
95 var timesync = message.ext.timesync;
\r
96 _debug('TimeSyncExtension: server sent timesync', timesync);
\r
98 var now = new Date().getTime();
\r
99 var l2 = (now - timesync.tc - timesync.p) / 2;
\r
100 var o2 = timesync.ts - timesync.tc - l2;
\r
104 if (_offsets.length > _maxSamples)
\r
110 var samples = _offsets.length;
\r
112 var offsetsSum = 0;
\r
113 for (var i = 0; i < samples; ++i)
\r
115 lagsSum += _lags[i];
\r
116 offsetsSum += _offsets[i];
\r
118 _lag = parseInt((lagsSum / samples).toFixed());
\r
119 _offset = parseInt((offsetsSum / samples).toFixed());
\r
120 _debug('TimeSyncExtension: network lag', _lag, 'ms, time offset with server', _offset, 'ms', _lag, _offset);
\r
126 this.outgoing = function(message)
\r
128 var channel = message.channel;
\r
129 if (channel && channel.indexOf('/meta/') === 0)
\r
135 message.ext.timesync = {
\r
136 tc: new Date().getTime(),
\r
140 _debug('TimeSyncExtension: client sending timesync', org_cometd.JSON.toJSON(message.ext.timesync));
\r
146 * Get the estimated offset in ms from the clients clock to the
\r
147 * servers clock. The server time is the client time plus the offset.
\r
149 this.getTimeOffset = function()
\r
155 * Get an array of multiple offset samples used to calculate
\r
158 this.getTimeOffsetSamples = function()
\r
164 * Get the estimated network lag in ms from the client to the server.
\r
166 this.getNetworkLag = function()
\r
172 * Get the estimated server time in ms since the epoch.
\r
174 this.getServerTime = function()
\r
176 return new Date().getTime() + _offset;
\r
181 * Get the estimated server time as a Date object
\r
183 this.getServerDate = function()
\r
185 return new Date(this.getServerTime());
\r
189 * Set a timeout to expire at given time on the server.
\r
190 * @param callback The function to call when the timer expires
\r
191 * @param atServerTimeOrDate a js Time or Date object representing the
\r
192 * server time at which the timeout should expire
\r
194 this.setTimeout = function(callback, atServerTimeOrDate)
\r
196 var ts = (atServerTimeOrDate instanceof Date) ? atServerTimeOrDate.getTime() : (0 + atServerTimeOrDate);
\r
197 var tc = ts - _offset;
\r
198 var interval = tc - new Date().getTime();
\r
203 return org_cometd.Utils.setTimeout(_cometd, callback, interval);
\r
208 if (typeof define === 'function' && define.amd)
\r
210 define(['org/cometd'], bind);
\r