Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / remoting / webapp / base / js / session_logger.js
blob3bd7069e88962a7a56ac454c4b60a3bddbbdac94
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
6 /** @suppress {duplicate} */
7 var remoting = remoting || {};
9 (function() {
11 'use strict';
13 /**
14  * This class defines a remoting.Logger implementation that generates
15  * log entries in the format of remoting.ChromotingEvent.
16  *
17  * @param {remoting.ChromotingEvent.Role} role
18  * @param {function(!Object)} writeLogEntry
19  *
20  * @constructor
21  * @implements {remoting.Logger}
22  */
23 remoting.SessionLogger = function(role, writeLogEntry) {
24   /** @private */
25   this.role_ = role;
26   /** @private */
27   this.writeLogEntry_ = writeLogEntry;
28   /** @private */
29   this.statsAccumulator_ = new remoting.StatsAccumulator();
30   /** @private */
31   this.sessionId_ = '';
32   /** @private */
33   this.sessionIdGenerationTime_ = 0;
34   /** @private */
35   this.sessionStartTime_ = new Date().getTime();
36   /** @private {remoting.ChromotingEvent.ConnectionType} */
37   this.connectionType_;
38   /** @private */
39   this.authTotalTime_ = 0;
40   /** @private */
41   this.hostVersion_ = '';
42   /** @private */
43   this.mode_ = remoting.ChromotingEvent.Mode.ME2ME;
45   this.setSessionId_();
48 /** @override {remoting.Logger} */
49 remoting.SessionLogger.prototype.setAuthTotalTime = function(totalTime) {
50   this.authTotalTime_ = totalTime;
53 /** @override {remoting.Logger} */
54 remoting.SessionLogger.prototype.setHostVersion = function(hostVersion) {
55   this.hostVersion_ = hostVersion;
58 /** @override {remoting.Logger} */
59 remoting.SessionLogger.prototype.setConnectionType = function(connectionType) {
60   this.connectionType_ = toConnectionType(connectionType);
63 /** @override {remoting.Logger} */
64 remoting.SessionLogger.prototype.setLogEntryMode = function(mode) {
65   this.mode_ = mode;
68 /** @override {remoting.Logger} */
69 remoting.SessionLogger.prototype.getSessionId = function() {
70   return this.sessionId_;
73 /** @override {remoting.Logger} */
74 remoting.SessionLogger.prototype.logSignalStrategyProgress =
75     function(strategyType, progress) {
76   this.maybeExpireSessionId_();
77   var entry = new remoting.ChromotingEvent(
78       remoting.ChromotingEvent.Type.SIGNAL_STRATEGY_PROGRESS);
79   entry.signal_strategy_type = toSignalStrategyType(strategyType);
80   entry.signal_strategy_progress = toSignalStrategyProgress(progress);
82   this.fillEvent_(entry);
83   this.log_(entry);
86 /** @override {remoting.Logger} */
87 remoting.SessionLogger.prototype.logClientSessionStateChange =
88     function(state, connectionError) {
89   this.maybeExpireSessionId_();
90   // Log the session state change.
91   var entry = this.makeSessionStateChange_(state, connectionError);
92   this.log_(entry);
93   // Don't accumulate connection statistics across state changes.
94   this.logAccumulatedStatistics_();
95   this.statsAccumulator_.empty();
98 /** @override {remoting.Logger} */
99 remoting.SessionLogger.prototype.logStatistics = function(stats) {
100   this.maybeExpireSessionId_();
101   // Store the statistics.
102   this.statsAccumulator_.add(stats);
103   // Send statistics to the server if they've been accumulating for at least
104   // 60 seconds.
105   if (this.statsAccumulator_.getTimeSinceFirstValue() >=
106       remoting.Logger.CONNECTION_STATS_ACCUMULATE_TIME) {
107     this.logAccumulatedStatistics_();
108   }
112  * @param {remoting.ClientSession.State} state
113  * @param {remoting.Error} error
114  * @return {remoting.ChromotingEvent}
115  * @private
116  */
117 remoting.SessionLogger.prototype.makeSessionStateChange_ =
118     function(state, error) {
119   var entry = new remoting.ChromotingEvent(
120       remoting.ChromotingEvent.Type.SESSION_STATE);
121   entry.connection_error = toConnectionError(error);
122   entry.session_state = toSessionState(state);
123   this.fillEvent_(entry);
124   return entry;
128  * @return {remoting.ChromotingEvent}
129  * @private
130  */
131 remoting.SessionLogger.prototype.makeSessionIdNew_ = function() {
132   var entry = new remoting.ChromotingEvent(
133       remoting.ChromotingEvent.Type.SESSION_ID_NEW);
134   this.fillEvent_(entry);
135   return entry;
139  * @return {remoting.ChromotingEvent}
140  * @private
141  */
142 remoting.SessionLogger.prototype.makeSessionIdOld_ = function() {
143   var entry = new remoting.ChromotingEvent(
144       remoting.ChromotingEvent.Type.SESSION_ID_OLD);
145   this.fillEvent_(entry);
146   return entry;
150  * @return {remoting.ChromotingEvent}
151  * @private
152  */
153 remoting.SessionLogger.prototype.makeStats_ = function() {
154   var perfStats = this.statsAccumulator_.getPerfStats();
155   if (Boolean(perfStats)) {
156     var entry = new remoting.ChromotingEvent(
157         remoting.ChromotingEvent.Type.CONNECTION_STATISTICS);
158     this.fillEvent_(entry);
159     entry.video_bandwidth = perfStats.videoBandwidth;
160     entry.capture_latency = perfStats.captureLatency;
161     entry.encode_latency = perfStats.encodeLatency;
162     entry.decode_latency = perfStats.decodeLatency;
163     entry.render_latency = perfStats.renderLatency;
164     entry.roundtrip_latency = perfStats.roundtripLatency;
165     return entry;
166   }
167   return null;
171  * Moves connection statistics from the accumulator to the log server.
173  * If all the statistics are zero, then the accumulator is still emptied,
174  * but the statistics are not sent to the log server.
176  * @private
177  */
178 remoting.SessionLogger.prototype.logAccumulatedStatistics_ = function() {
179   var entry = this.makeStats_();
180   if (entry) {
181     this.log_(entry);
182   }
183   this.statsAccumulator_.empty();
187  * @param {remoting.ChromotingEvent} entry
188  * @private
189  */
190 remoting.SessionLogger.prototype.fillEvent_ = function(entry) {
191   entry.session_id = this.sessionId_;
192   entry.mode = this.mode_;
193   entry.role = this.role_;
194   var sessionDurationInSeconds =
195       (new Date().getTime() - this.sessionStartTime_ -
196           this.authTotalTime_) / 1000.0;
197   entry.session_duration = sessionDurationInSeconds;
198   if (Boolean(this.connectionType_)) {
199     entry.connection_type = this.connectionType_;
200   }
201   entry.host_version = this.hostVersion_;
205  * Sends a log entry to the server.
206  * @param {remoting.ChromotingEvent} entry
207  * @private
208  */
209 remoting.SessionLogger.prototype.log_ = function(entry) {
210   this.writeLogEntry_(/** @type {!Object} */ (base.deepCopy(entry)));
214  * Sets the session ID to a random string.
215  * @private
216  */
217 remoting.SessionLogger.prototype.setSessionId_ = function() {
218   var random = new Uint8Array(20);
219   window.crypto.getRandomValues(random);
220   this.sessionId_ = window.btoa(String.fromCharCode.apply(null, random));
221   this.sessionIdGenerationTime_ = new Date().getTime();
225  * Clears the session ID.
227  * @private
228  */
229 remoting.SessionLogger.prototype.clearSessionId_ = function() {
230   this.sessionId_ = '';
231   this.sessionIdGenerationTime_ = 0;
235  * Sets a new session ID, if the current session ID has reached its maximum age.
237  * This method also logs the old and new session IDs to the server, in separate
238  * log entries.
240  * @private
241  */
242 remoting.SessionLogger.prototype.maybeExpireSessionId_ = function() {
243   if ((this.sessionId_ !== '') &&
244       (new Date().getTime() - this.sessionIdGenerationTime_ >=
245       remoting.Logger.MAX_SESSION_ID_AGE)) {
246     // Log the old session ID.
247     var entry = this.makeSessionIdOld_();
248     this.log_(entry);
249     // Generate a new session ID.
250     this.setSessionId_();
251     // Log the new session ID.
252     entry = this.makeSessionIdNew_();
253     this.log_(entry);
254   }
258  * TODO(kelvinp): Consolidate the two enums (crbug.com/504200)
259  * @param {remoting.ClientSession.State} state
260  * @return {remoting.ChromotingEvent.SessionState}
261  */
262 function toSessionState(state) {
263   var SessionState = remoting.ChromotingEvent.SessionState;
264   switch(state) {
265     case remoting.ClientSession.State.UNKNOWN:
266       return SessionState.UNKNOWN;
267     case remoting.ClientSession.State.INITIALIZING:
268       return SessionState.INITIALIZING;
269     case remoting.ClientSession.State.CONNECTING:
270       return SessionState.CONNECTING;
271     case remoting.ClientSession.State.AUTHENTICATED:
272       return SessionState.AUTHENTICATED;
273     case remoting.ClientSession.State.CONNECTED:
274       return SessionState.CONNECTED;
275     case remoting.ClientSession.State.CLOSED:
276       return SessionState.CLOSED;
277     case remoting.ClientSession.State.FAILED:
278       return SessionState.CONNECTION_FAILED;
279     case remoting.ClientSession.State.CONNECTION_DROPPED:
280       return SessionState.CONNECTION_DROPPED;
281     case remoting.ClientSession.State.CONNECTION_CANCELED:
282       return SessionState.CONNECTION_CANCELED;
283     default:
284       throw new Error('Unknown session state : ' + state);
285   }
289  * @param {remoting.Error} error
290  * @return {remoting.ChromotingEvent.ConnectionError}
291  */
292 function toConnectionError(error) {
293   var ConnectionError = remoting.ChromotingEvent.ConnectionError;
294   switch (error.getTag()) {
295     case remoting.Error.Tag.NONE:
296       return ConnectionError.NONE;
297     case remoting.Error.Tag.INVALID_ACCESS_CODE:
298       return ConnectionError.INVALID_ACCESS_CODE;
299     case remoting.Error.Tag.MISSING_PLUGIN:
300       return ConnectionError.MISSING_PLUGIN;
301     case remoting.Error.Tag.AUTHENTICATION_FAILED:
302       return ConnectionError.AUTHENTICATION_FAILED;
303     case remoting.Error.Tag.HOST_IS_OFFLINE:
304       return ConnectionError.HOST_OFFLINE;
305     case remoting.Error.Tag.INCOMPATIBLE_PROTOCOL:
306       return ConnectionError.INCOMPATIBLE_PROTOCOL;
307     case remoting.Error.Tag.BAD_PLUGIN_VERSION:
308       return ConnectionError.ERROR_BAD_PLUGIN_VERSION;
309     case remoting.Error.Tag.NETWORK_FAILURE:
310       return ConnectionError.NETWORK_FAILURE;
311     case remoting.Error.Tag.HOST_OVERLOAD:
312       return ConnectionError.HOST_OVERLOAD;
313     case remoting.Error.Tag.P2P_FAILURE:
314       return ConnectionError.P2P_FAILURE;
315     case remoting.Error.Tag.CLIENT_SUSPENDED:
316       return ConnectionError.CLIENT_SUSPENDED;
317     case remoting.Error.Tag.UNEXPECTED:
318       return ConnectionError.UNEXPECTED;
319     default:
320       throw new Error('Unknown error Tag : ' + error.getTag());
321   }
325  * @param {remoting.SignalStrategy.Type} type
326  * @return {remoting.ChromotingEvent.SignalStrategyType}
327  */
328 function toSignalStrategyType(type) {
329   switch (type) {
330     case remoting.SignalStrategy.Type.XMPP:
331       return remoting.ChromotingEvent.SignalStrategyType.XMPP;
332     case remoting.SignalStrategy.Type.WCS:
333       return remoting.ChromotingEvent.SignalStrategyType.WCS;
334     default:
335       throw new Error('Unknown signal strategy type : ' + type);
336   }
340  * @param {remoting.FallbackSignalStrategy.Progress} progress
341  * @return {remoting.ChromotingEvent.SignalStrategyProgress}
342  */
343 function toSignalStrategyProgress(progress) {
344   var Progress = remoting.FallbackSignalStrategy.Progress;
345   switch (progress) {
346     case Progress.SUCCEEDED:
347       return remoting.ChromotingEvent.SignalStrategyProgress.SUCCEEDED;
348     case Progress.FAILED:
349       return remoting.ChromotingEvent.SignalStrategyProgress.FAILED;
350     case Progress.TIMED_OUT:
351       return remoting.ChromotingEvent.SignalStrategyProgress.TIMED_OUT;
352     case Progress.SUCCEEDED_LATE:
353       return remoting.ChromotingEvent.SignalStrategyProgress.SUCCEEDED_LATE;
354     case Progress.FAILED_LATE:
355       return remoting.ChromotingEvent.SignalStrategyProgress.FAILED_LATE;
356     default:
357       throw new Error('Unknown signal strategy progress :=' + progress);
358   }
362  * @param {string} type
363  * @return {remoting.ChromotingEvent.ConnectionType}
364  */
365 function toConnectionType(type) {
366   switch (type) {
367     case 'direct':
368       return remoting.ChromotingEvent.ConnectionType.DIRECT;
369     case 'stun':
370       return remoting.ChromotingEvent.ConnectionType.STUN;
371     case 'relay':
372       return remoting.ChromotingEvent.ConnectionType.RELAY;
373     default:
374       throw new Error('Unknown ConnectionType :=' + type);
375   }
378 })();