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} */
38 /** @private {remoting.ChromotingEvent.SessionEntryPoint} */
40 /** @private {remoting.ChromotingEvent.SessionState} */
41 this.previousSessionState_
;
43 this.authTotalTime_
= 0;
45 this.hostVersion_
= '';
48 this.mode_
= remoting
.ChromotingEvent
.Mode
.ME2ME
;
54 * @param {remoting.ChromotingEvent.SessionEntryPoint} entryPoint
56 remoting
.SessionLogger
.prototype.setEntryPoint = function(entryPoint
) {
57 this.entryPoint_
= entryPoint
;
60 /** @override {remoting.Logger} */
61 remoting
.SessionLogger
.prototype.setAuthTotalTime = function(totalTime
) {
62 this.authTotalTime_
= totalTime
;
65 /** @override {remoting.Logger} */
66 remoting
.SessionLogger
.prototype.setHostVersion = function(hostVersion
) {
67 this.hostVersion_
= hostVersion
;
70 /** @override {remoting.Logger} */
71 remoting
.SessionLogger
.prototype.setConnectionType = function(connectionType
) {
72 this.connectionType_
= toConnectionType(connectionType
);
75 /** @override {remoting.Logger} */
76 remoting
.SessionLogger
.prototype.setLogEntryMode = function(mode
) {
80 /** @override {remoting.Logger} */
81 remoting
.SessionLogger
.prototype.getSessionId = function() {
82 return this.sessionId_
;
85 /** @override {remoting.Logger} */
86 remoting
.SessionLogger
.prototype.logSignalStrategyProgress
=
87 function(strategyType
, progress
) {
88 this.maybeExpireSessionId_();
89 var entry
= new remoting
.ChromotingEvent(
90 remoting
.ChromotingEvent
.Type
.SIGNAL_STRATEGY_PROGRESS
);
91 entry
.signal_strategy_type
= toSignalStrategyType(strategyType
);
92 entry
.signal_strategy_progress
= toSignalStrategyProgress(progress
);
94 this.fillEvent_(entry
);
98 /** @override {remoting.Logger} */
99 remoting
.SessionLogger
.prototype.logClientSessionStateChange = function(
100 state
, connectionError
, xmppError
) {
101 this.logSessionStateChange(
102 toSessionState(state
),
103 toConnectionError(connectionError
),
108 * @param {remoting.ChromotingEvent.SessionState} state
109 * @param {remoting.ChromotingEvent.ConnectionError} error
110 * @param {remoting.ChromotingEvent.XmppError=} opt_XmppError
112 remoting
.SessionLogger
.prototype.logSessionStateChange = function(
113 state
, error
, opt_XmppError
) {
114 this.maybeExpireSessionId_();
116 var entry
= this.makeSessionStateChange_(
118 /** @type {?remoting.ChromotingEvent.XmppError} */ (opt_XmppError
));
119 entry
.previous_session_state
= this.previousSessionState_
;
120 this.previousSessionState_
= state
;
124 // Don't accumulate connection statistics across state changes.
125 this.logAccumulatedStatistics_();
126 this.statsAccumulator_
.empty();
129 /** @override {remoting.Logger} */
130 remoting
.SessionLogger
.prototype.logStatistics = function(stats
) {
131 this.maybeExpireSessionId_();
132 // Store the statistics.
133 this.statsAccumulator_
.add(stats
);
134 // Send statistics to the server if they've been accumulating for at least
136 if (this.statsAccumulator_
.getTimeSinceFirstValue() >=
137 remoting
.Logger
.CONNECTION_STATS_ACCUMULATE_TIME
) {
138 this.logAccumulatedStatistics_();
143 * @param {remoting.ChromotingEvent.SessionState} state
144 * @param {remoting.ChromotingEvent.ConnectionError} error
145 * @param {?remoting.ChromotingEvent.XmppError} xmppError
146 * @return {remoting.ChromotingEvent}
149 remoting
.SessionLogger
.prototype.makeSessionStateChange_
=
150 function(state
, error
, xmppError
) {
151 var entry
= new remoting
.ChromotingEvent(
152 remoting
.ChromotingEvent
.Type
.SESSION_STATE
);
153 entry
.connection_error
= error
;
154 entry
.session_state
= state
;
156 if (Boolean(xmppError
)) {
157 entry
.xmpp_error
= xmppError
;
160 this.fillEvent_(entry
);
165 * @return {remoting.ChromotingEvent}
168 remoting
.SessionLogger
.prototype.makeSessionIdNew_ = function() {
169 var entry
= new remoting
.ChromotingEvent(
170 remoting
.ChromotingEvent
.Type
.SESSION_ID_NEW
);
171 this.fillEvent_(entry
);
176 * @return {remoting.ChromotingEvent}
179 remoting
.SessionLogger
.prototype.makeSessionIdOld_ = function() {
180 var entry
= new remoting
.ChromotingEvent(
181 remoting
.ChromotingEvent
.Type
.SESSION_ID_OLD
);
182 this.fillEvent_(entry
);
187 * @return {remoting.ChromotingEvent}
190 remoting
.SessionLogger
.prototype.makeStats_ = function() {
191 var perfStats
= this.statsAccumulator_
.getPerfStats();
192 if (Boolean(perfStats
)) {
193 var entry
= new remoting
.ChromotingEvent(
194 remoting
.ChromotingEvent
.Type
.CONNECTION_STATISTICS
);
195 this.fillEvent_(entry
);
196 entry
.video_bandwidth
= perfStats
.videoBandwidth
;
197 entry
.capture_latency
= perfStats
.captureLatency
;
198 entry
.encode_latency
= perfStats
.encodeLatency
;
199 entry
.decode_latency
= perfStats
.decodeLatency
;
200 entry
.render_latency
= perfStats
.renderLatency
;
201 entry
.roundtrip_latency
= perfStats
.roundtripLatency
;
208 * Moves connection statistics from the accumulator to the log server.
210 * If all the statistics are zero, then the accumulator is still emptied,
211 * but the statistics are not sent to the log server.
215 remoting
.SessionLogger
.prototype.logAccumulatedStatistics_ = function() {
216 var entry
= this.makeStats_();
220 this.statsAccumulator_
.empty();
224 * @param {remoting.ChromotingEvent} entry
227 remoting
.SessionLogger
.prototype.fillEvent_ = function(entry
) {
228 entry
.session_id
= this.sessionId_
;
229 entry
.mode
= this.mode_
;
230 entry
.role
= this.role_
;
231 entry
.session_entry_point
= this.entryPoint_
;
232 var sessionDurationInSeconds
=
233 (new Date().getTime() - this.sessionStartTime_
-
234 this.authTotalTime_
) / 1000.0;
235 entry
.session_duration
= sessionDurationInSeconds
;
236 if (Boolean(this.connectionType_
)) {
237 entry
.connection_type
= this.connectionType_
;
239 entry
.host_version
= this.hostVersion_
;
243 * Sends a log entry to the server.
244 * @param {remoting.ChromotingEvent} entry
247 remoting
.SessionLogger
.prototype.log_ = function(entry
) {
248 this.writeLogEntry_(/** @type {!Object} */ (base
.deepCopy(entry
)));
252 * Sets the session ID to a random string.
255 remoting
.SessionLogger
.prototype.setSessionId_ = function() {
256 var random
= new Uint8Array(20);
257 window
.crypto
.getRandomValues(random
);
258 this.sessionId_
= window
.btoa(String
.fromCharCode
.apply(null, random
));
259 this.sessionIdGenerationTime_
= new Date().getTime();
263 * Clears the session ID.
267 remoting
.SessionLogger
.prototype.clearSessionId_ = function() {
268 this.sessionId_
= '';
269 this.sessionIdGenerationTime_
= 0;
273 * Sets a new session ID, if the current session ID has reached its maximum age.
275 * This method also logs the old and new session IDs to the server, in separate
280 remoting
.SessionLogger
.prototype.maybeExpireSessionId_ = function() {
281 if ((this.sessionId_
!== '') &&
282 (new Date().getTime() - this.sessionIdGenerationTime_
>=
283 remoting
.Logger
.MAX_SESSION_ID_AGE
)) {
284 // Log the old session ID.
285 var entry
= this.makeSessionIdOld_();
287 // Generate a new session ID.
288 this.setSessionId_();
289 // Log the new session ID.
290 entry
= this.makeSessionIdNew_();
295 /** @return {remoting.SessionLogger} */
296 remoting
.SessionLogger
.createForClient = function() {
297 return new remoting
.SessionLogger(remoting
.ChromotingEvent
.Role
.CLIENT
,
298 remoting
.TelemetryEventWriter
.Client
.write
);
302 * TODO(kelvinp): Consolidate the two enums (crbug.com/504200)
303 * @param {remoting.ClientSession.State} state
304 * @return {remoting.ChromotingEvent.SessionState}
306 function toSessionState(state
) {
307 var SessionState
= remoting
.ChromotingEvent
.SessionState
;
309 case remoting
.ClientSession
.State
.UNKNOWN
:
310 return SessionState
.UNKNOWN
;
311 case remoting
.ClientSession
.State
.INITIALIZING
:
312 return SessionState
.INITIALIZING
;
313 case remoting
.ClientSession
.State
.CONNECTING
:
314 return SessionState
.CONNECTING
;
315 case remoting
.ClientSession
.State
.AUTHENTICATED
:
316 return SessionState
.AUTHENTICATED
;
317 case remoting
.ClientSession
.State
.CONNECTED
:
318 return SessionState
.CONNECTED
;
319 case remoting
.ClientSession
.State
.CLOSED
:
320 return SessionState
.CLOSED
;
321 case remoting
.ClientSession
.State
.FAILED
:
322 return SessionState
.CONNECTION_FAILED
;
323 case remoting
.ClientSession
.State
.CONNECTION_DROPPED
:
324 return SessionState
.CONNECTION_DROPPED
;
325 case remoting
.ClientSession
.State
.CONNECTION_CANCELED
:
326 return SessionState
.CONNECTION_CANCELED
;
328 throw new Error('Unknown session state : ' + state
);
333 * @param {remoting.Error} error
334 * @return {remoting.ChromotingEvent.ConnectionError}
336 function toConnectionError(error
) {
337 var ConnectionError
= remoting
.ChromotingEvent
.ConnectionError
;
338 switch (error
.getTag()) {
339 case remoting
.Error
.Tag
.NONE
:
340 return ConnectionError
.NONE
;
341 case remoting
.Error
.Tag
.INVALID_ACCESS_CODE
:
342 return ConnectionError
.INVALID_ACCESS_CODE
;
343 case remoting
.Error
.Tag
.MISSING_PLUGIN
:
344 return ConnectionError
.MISSING_PLUGIN
;
345 case remoting
.Error
.Tag
.AUTHENTICATION_FAILED
:
346 return ConnectionError
.AUTHENTICATION_FAILED
;
347 case remoting
.Error
.Tag
.HOST_IS_OFFLINE
:
348 return ConnectionError
.HOST_OFFLINE
;
349 case remoting
.Error
.Tag
.INCOMPATIBLE_PROTOCOL
:
350 return ConnectionError
.INCOMPATIBLE_PROTOCOL
;
351 case remoting
.Error
.Tag
.BAD_PLUGIN_VERSION
:
352 return ConnectionError
.ERROR_BAD_PLUGIN_VERSION
;
353 case remoting
.Error
.Tag
.NETWORK_FAILURE
:
354 return ConnectionError
.NETWORK_FAILURE
;
355 case remoting
.Error
.Tag
.HOST_OVERLOAD
:
356 return ConnectionError
.HOST_OVERLOAD
;
357 case remoting
.Error
.Tag
.P2P_FAILURE
:
358 return ConnectionError
.P2P_FAILURE
;
359 case remoting
.Error
.Tag
.CLIENT_SUSPENDED
:
360 return ConnectionError
.CLIENT_SUSPENDED
;
361 case remoting
.Error
.Tag
.UNEXPECTED
:
362 return ConnectionError
.UNEXPECTED
;
364 throw new Error('Unknown error Tag : ' + error
.getTag());
369 * @param {remoting.SignalStrategy.Type} type
370 * @return {remoting.ChromotingEvent.SignalStrategyType}
372 function toSignalStrategyType(type
) {
374 case remoting
.SignalStrategy
.Type
.XMPP
:
375 return remoting
.ChromotingEvent
.SignalStrategyType
.XMPP
;
376 case remoting
.SignalStrategy
.Type
.WCS
:
377 return remoting
.ChromotingEvent
.SignalStrategyType
.WCS
;
379 throw new Error('Unknown signal strategy type : ' + type
);
384 * @param {remoting.FallbackSignalStrategy.Progress} progress
385 * @return {remoting.ChromotingEvent.SignalStrategyProgress}
387 function toSignalStrategyProgress(progress
) {
388 var Progress
= remoting
.FallbackSignalStrategy
.Progress
;
390 case Progress
.SUCCEEDED
:
391 return remoting
.ChromotingEvent
.SignalStrategyProgress
.SUCCEEDED
;
392 case Progress
.FAILED
:
393 return remoting
.ChromotingEvent
.SignalStrategyProgress
.FAILED
;
394 case Progress
.TIMED_OUT
:
395 return remoting
.ChromotingEvent
.SignalStrategyProgress
.TIMED_OUT
;
396 case Progress
.SUCCEEDED_LATE
:
397 return remoting
.ChromotingEvent
.SignalStrategyProgress
.SUCCEEDED_LATE
;
398 case Progress
.FAILED_LATE
:
399 return remoting
.ChromotingEvent
.SignalStrategyProgress
.FAILED_LATE
;
401 throw new Error('Unknown signal strategy progress :=' + progress
);
406 * @param {string} type
407 * @return {remoting.ChromotingEvent.ConnectionType}
409 function toConnectionType(type
) {
412 return remoting
.ChromotingEvent
.ConnectionType
.DIRECT
;
414 return remoting
.ChromotingEvent
.ConnectionType
.STUN
;
416 return remoting
.ChromotingEvent
.ConnectionType
.RELAY
;
418 throw new Error('Unknown ConnectionType :=' + type
);