summaryrefslogtreecommitdiffstats
path: root/common/src/main/webapp/thirdparty/cometd/cometd/TimeSyncExtension.js
diff options
context:
space:
mode:
Diffstat (limited to 'common/src/main/webapp/thirdparty/cometd/cometd/TimeSyncExtension.js')
-rw-r--r--common/src/main/webapp/thirdparty/cometd/cometd/TimeSyncExtension.js216
1 files changed, 216 insertions, 0 deletions
diff --git a/common/src/main/webapp/thirdparty/cometd/cometd/TimeSyncExtension.js b/common/src/main/webapp/thirdparty/cometd/cometd/TimeSyncExtension.js
new file mode 100644
index 0000000..5063298
--- /dev/null
+++ b/common/src/main/webapp/thirdparty/cometd/cometd/TimeSyncExtension.js
@@ -0,0 +1,216 @@
+/*
+ * Copyright (c) 2010 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+(function()
+{
+ function bind(org_cometd)
+ {
+ /**
+ * 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>
+ *
+ * <p>
+ * A cometd server that supports timesync, can respond with 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>
+ *
+ * <p>
+ * The relationship between tc, ts & l is given by <code>ts=tc+o+l</code> (the
+ * time the server received the messsage is the client time plus the offset plus the
+ * network lag). Thus the accuracy of the o and l settings can be determined with
+ * <code>a=(tc+o+l)-ts</code>.
+ * </p>
+ * <p>
+ * When the client has received the response, it can make a more accurate estimate
+ * of the lag as <code>l2=(now-tc-p)/2</code> (assuming symmetric lag).
+ * A new offset can then be calculated with the relationship on the client
+ * that <code>ts=tc+o2+l2</code>, thus <code>o2=ts-tc-l2</code>.
+ * </p>
+ * <p>
+ * Since the client also receives the a value calculated on the server, it
+ * should be possible to analyse this and compensate for some asymmetry
+ * in the lag. But the current client does not do this.
+ * </p>
+ *
+ * @param configuration
+ */
+ return org_cometd.TimeSyncExtension = function(configuration)
+ {
+ var _cometd;
+ var _maxSamples = configuration && configuration.maxSamples || 10;
+ var _lags = [];
+ var _offsets = [];
+ var _lag = 0;
+ var _offset = 0;
+
+ function _debug(text, args)
+ {
+ _cometd._debug(text, args);
+ }
+
+ this.registered = function(name, cometd)
+ {
+ _cometd = cometd;
+ _debug('TimeSyncExtension: executing registration callback');
+ };
+
+ this.unregistered = function()
+ {
+ _debug('TimeSyncExtension: executing unregistration callback');
+ _cometd = null;
+ _lags = [];
+ _offsets = [];
+ };
+
+ this.incoming = function(message)
+ {
+ var channel = message.channel;
+ if (channel && channel.indexOf('/meta/') === 0)
+ {
+ if (message.ext && message.ext.timesync)
+ {
+ var timesync = message.ext.timesync;
+ _debug('TimeSyncExtension: server sent timesync', timesync);
+
+ var now = new Date().getTime();
+ var l2 = (now - timesync.tc - timesync.p) / 2;
+ var o2 = timesync.ts - timesync.tc - l2;
+
+ _lags.push(l2);
+ _offsets.push(o2);
+ if (_offsets.length > _maxSamples)
+ {
+ _offsets.shift();
+ _lags.shift();
+ }
+
+ var samples = _offsets.length;
+ var lagsSum = 0;
+ var offsetsSum = 0;
+ for (var i = 0; i < samples; ++i)
+ {
+ lagsSum += _lags[i];
+ offsetsSum += _offsets[i];
+ }
+ _lag = parseInt((lagsSum / samples).toFixed());
+ _offset = parseInt((offsetsSum / samples).toFixed());
+ _debug('TimeSyncExtension: network lag', _lag, 'ms, time offset with server', _offset, 'ms', _lag, _offset);
+ }
+ }
+ return message;
+ };
+
+ this.outgoing = function(message)
+ {
+ var channel = message.channel;
+ if (channel && channel.indexOf('/meta/') === 0)
+ {
+ if (!message.ext)
+ {
+ message.ext = {};
+ }
+ message.ext.timesync = {
+ tc: new Date().getTime(),
+ l: _lag,
+ o: _offset
+ };
+ _debug('TimeSyncExtension: client sending timesync', org_cometd.JSON.toJSON(message.ext.timesync));
+ }
+ return message;
+ };
+
+ /**
+ * Get the estimated offset in ms from the clients clock to the
+ * servers clock. The server time is the client time plus the offset.
+ */
+ this.getTimeOffset = function()
+ {
+ return _offset;
+ };
+
+ /**
+ * Get an array of multiple offset samples used to calculate
+ * the offset.
+ */
+ this.getTimeOffsetSamples = function()
+ {
+ return _offsets;
+ };
+
+ /**
+ * Get the estimated network lag in ms from the client to the server.
+ */
+ this.getNetworkLag = function()
+ {
+ return _lag;
+ };
+
+ /**
+ * Get the estimated server time in ms since the epoch.
+ */
+ this.getServerTime = function()
+ {
+ return new Date().getTime() + _offset;
+ };
+
+ /**
+ *
+ * Get the estimated server time as a Date object
+ */
+ this.getServerDate = function()
+ {
+ return new Date(this.getServerTime());
+ };
+
+ /**
+ * Set a timeout to expire at given time on the server.
+ * @param callback The function to call when the timer expires
+ * @param atServerTimeOrDate a js Time or Date object representing the
+ * server time at which the timeout should expire
+ */
+ this.setTimeout = function(callback, atServerTimeOrDate)
+ {
+ var ts = (atServerTimeOrDate instanceof Date) ? atServerTimeOrDate.getTime() : (0 + atServerTimeOrDate);
+ var tc = ts - _offset;
+ var interval = tc - new Date().getTime();
+ if (interval <= 0)
+ {
+ interval = 1;
+ }
+ return org_cometd.Utils.setTimeout(_cometd, callback, interval);
+ };
+ };
+ }
+
+ if (typeof define === 'function' && define.amd)
+ {
+ define(['org/cometd'], bind);
+ }
+ else
+ {
+ bind(org.cometd);
+ }
+})();