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 || {};
14 * This class defines a remoting.Logger implementation that generates
15 * log entries in the format of remoting.ChromotingEvent.
17 * @param {remoting.ChromotingEvent.Role} role
18 * @param {function(!Object)} writeLogEntry
21 * @implements {remoting.Logger}
23 remoting.SessionLogger = function(role, writeLogEntry) {
27 this.writeLogEntry_ = writeLogEntry;
29 this.statsAccumulator_ = new remoting.StatsAccumulator();
33 this.sessionIdGenerationTime_ = 0;
35 this.sessionStartTime_ = new Date().getTime();
36 /** @private {remoting.ChromotingEvent.ConnectionType} */
39 this.authTotalTime_ = 0;
41 this.hostVersion_ = '';
43 this.mode_ = remoting.ChromotingEvent.Mode.ME2ME;
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) {
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);
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);
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
105 if (this.statsAccumulator_.getTimeSinceFirstValue() >=
106 remoting.Logger.CONNECTION_STATS_ACCUMULATE_TIME) {
107 this.logAccumulatedStatistics_();
112 * @param {remoting.ClientSession.State} state
113 * @param {remoting.Error} error
114 * @return {remoting.ChromotingEvent}
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);
128 * @return {remoting.ChromotingEvent}
131 remoting.SessionLogger.prototype.makeSessionIdNew_ = function() {
132 var entry = new remoting.ChromotingEvent(
133 remoting.ChromotingEvent.Type.SESSION_ID_NEW);
134 this.fillEvent_(entry);
139 * @return {remoting.ChromotingEvent}
142 remoting.SessionLogger.prototype.makeSessionIdOld_ = function() {
143 var entry = new remoting.ChromotingEvent(
144 remoting.ChromotingEvent.Type.SESSION_ID_OLD);
145 this.fillEvent_(entry);
150 * @return {remoting.ChromotingEvent}
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;
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.
178 remoting.SessionLogger.prototype.logAccumulatedStatistics_ = function() {
179 var entry = this.makeStats_();
183 this.statsAccumulator_.empty();
187 * @param {remoting.ChromotingEvent} entry
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_;
201 entry.host_version = this.hostVersion_;
205 * Sends a log entry to the server.
206 * @param {remoting.ChromotingEvent} entry
209 remoting.SessionLogger.prototype.log_ = function(entry) {
210 this.writeLogEntry_(/** @type {!Object} */ (base.deepCopy(entry)));
214 * Sets the session ID to a random string.
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.
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
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_();
249 // Generate a new session ID.
250 this.setSessionId_();
251 // Log the new session ID.
252 entry = this.makeSessionIdNew_();
258 * TODO(kelvinp): Consolidate the two enums (crbug.com/504200)
259 * @param {remoting.ClientSession.State} state
260 * @return {remoting.ChromotingEvent.SessionState}
262 function toSessionState(state) {
263 var SessionState = remoting.ChromotingEvent.SessionState;
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;
284 throw new Error('Unknown session state : ' + state);
289 * @param {remoting.Error} error
290 * @return {remoting.ChromotingEvent.ConnectionError}
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;
320 throw new Error('Unknown error Tag : ' + error.getTag());
325 * @param {remoting.SignalStrategy.Type} type
326 * @return {remoting.ChromotingEvent.SignalStrategyType}
328 function toSignalStrategyType(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;
335 throw new Error('Unknown signal strategy type : ' + type);
340 * @param {remoting.FallbackSignalStrategy.Progress} progress
341 * @return {remoting.ChromotingEvent.SignalStrategyProgress}
343 function toSignalStrategyProgress(progress) {
344 var Progress = remoting.FallbackSignalStrategy.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;
357 throw new Error('Unknown signal strategy progress :=' + progress);
362 * @param {string} type
363 * @return {remoting.ChromotingEvent.ConnectionType}
365 function toConnectionType(type) {
368 return remoting.ChromotingEvent.ConnectionType.DIRECT;
370 return remoting.ChromotingEvent.ConnectionType.STUN;
372 return remoting.ChromotingEvent.ConnectionType.RELAY;
374 throw new Error('Unknown ConnectionType :=' + type);