CLIENT GUI Framework
[vnfsdk/refrepo.git] / openo-portal / portal-common / src / main / webapp / common / thirdparty / cometd / cometd / TimeSyncExtension.js
1 /*\r
2  * Copyright (c) 2010 the original author or authors.\r
3  *\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
7  *\r
8  *     http://www.apache.org/licenses/LICENSE-2.0\r
9  *\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
15  */\r
16 \r
17 (function()\r
18 {\r
19     function bind(org_cometd)\r
20     {\r
21         /**\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
24          * where:<ul>\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
28          * </ul>\r
29          *\r
30          * <p>\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
33          * where:<ul>\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
38          * </ul>\r
39          *\r
40          * <p>\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
45          * </p>\r
46          * <p>\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
51          * </p>\r
52          * <p>\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
56          * </p>\r
57          *\r
58          * @param configuration\r
59          */\r
60         return org_cometd.TimeSyncExtension = function(configuration)\r
61         {\r
62             var _cometd;\r
63             var _maxSamples = configuration && configuration.maxSamples || 10;\r
64             var _lags = [];\r
65             var _offsets = [];\r
66             var _lag = 0;\r
67             var _offset = 0;\r
68 \r
69             function _debug(text, args)\r
70             {\r
71                 _cometd._debug(text, args);\r
72             }\r
73 \r
74             this.registered = function(name, cometd)\r
75             {\r
76                 _cometd = cometd;\r
77                 _debug('TimeSyncExtension: executing registration callback');\r
78             };\r
79 \r
80             this.unregistered = function()\r
81             {\r
82                 _debug('TimeSyncExtension: executing unregistration callback');\r
83                 _cometd = null;\r
84                 _lags = [];\r
85                 _offsets = [];\r
86             };\r
87 \r
88             this.incoming = function(message)\r
89             {\r
90                 var channel = message.channel;\r
91                 if (channel && channel.indexOf('/meta/') === 0)\r
92                 {\r
93                     if (message.ext && message.ext.timesync)\r
94                     {\r
95                         var timesync = message.ext.timesync;\r
96                         _debug('TimeSyncExtension: server sent timesync', timesync);\r
97 \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
101 \r
102                         _lags.push(l2);\r
103                         _offsets.push(o2);\r
104                         if (_offsets.length > _maxSamples)\r
105                         {\r
106                             _offsets.shift();\r
107                             _lags.shift();\r
108                         }\r
109 \r
110                         var samples = _offsets.length;\r
111                         var lagsSum = 0;\r
112                         var offsetsSum = 0;\r
113                         for (var i = 0; i < samples; ++i)\r
114                         {\r
115                             lagsSum += _lags[i];\r
116                             offsetsSum += _offsets[i];\r
117                         }\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
121                     }\r
122                 }\r
123                 return message;\r
124             };\r
125 \r
126             this.outgoing = function(message)\r
127             {\r
128                 var channel = message.channel;\r
129                 if (channel && channel.indexOf('/meta/') === 0)\r
130                 {\r
131                     if (!message.ext)\r
132                     {\r
133                         message.ext = {};\r
134                     }\r
135                     message.ext.timesync = {\r
136                         tc: new Date().getTime(),\r
137                         l: _lag,\r
138                         o: _offset\r
139                     };\r
140                     _debug('TimeSyncExtension: client sending timesync', org_cometd.JSON.toJSON(message.ext.timesync));\r
141                 }\r
142                 return message;\r
143             };\r
144 \r
145             /**\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
148              */\r
149             this.getTimeOffset = function()\r
150             {\r
151                 return _offset;\r
152             };\r
153 \r
154             /**\r
155              * Get an array of multiple offset samples used to calculate\r
156              * the offset.\r
157              */\r
158             this.getTimeOffsetSamples = function()\r
159             {\r
160                 return _offsets;\r
161             };\r
162 \r
163             /**\r
164              * Get the estimated network lag in ms from the client to the server.\r
165              */\r
166             this.getNetworkLag = function()\r
167             {\r
168                 return _lag;\r
169             };\r
170 \r
171             /**\r
172              * Get the estimated server time in ms since the epoch.\r
173              */\r
174             this.getServerTime = function()\r
175             {\r
176                 return new Date().getTime() + _offset;\r
177             };\r
178 \r
179             /**\r
180              *\r
181              * Get the estimated server time as a Date object\r
182              */\r
183             this.getServerDate = function()\r
184             {\r
185                 return new Date(this.getServerTime());\r
186             };\r
187 \r
188             /**\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
193              */\r
194             this.setTimeout = function(callback, atServerTimeOrDate)\r
195             {\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
199                 if (interval <= 0)\r
200                 {\r
201                     interval = 1;\r
202                 }\r
203                 return org_cometd.Utils.setTimeout(_cometd, callback, interval);\r
204             };\r
205         };\r
206     }\r
207 \r
208     if (typeof define === 'function' && define.amd)\r
209     {\r
210         define(['org/cometd'], bind);\r
211     }\r
212     else\r
213     {\r
214         bind(org.cometd);\r
215     }\r
216 })();\r