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.
5 /** @suppress {duplicate} */
6 var remoting = remoting || {};
12 remoting.TelemetryEventWriter = function() {};
16 WRITE: 'remoting.TelemetryEventWriter.write'
20 * @param {base.Ipc} ipc
21 * @param {remoting.XhrEventWriter} eventWriter
23 * @implements {base.Disposable}
25 remoting.TelemetryEventWriter.Service = function(ipc, eventWriter) {
27 this.eventWriter_ = eventWriter;
30 /** @private {base.Disposables} */
31 this.eventHooks_ = new base.Disposables();
34 this.sessionMonitor_ = new SessionMonitor(this.eventWriter_);
37 /** @return {Promise} */
38 remoting.TelemetryEventWriter.Service.prototype.init = function() {
39 /** @this {remoting.TelemetryEventWriter.Service} */
42 new base.DomEventHook(window, 'online',
43 this.eventWriter_.flush.bind(this.eventWriter_),
45 new base.ChromeEventHook(chrome.runtime.onSuspend,
46 this.onSuspend_.bind(this)));
48 this.ipc_.register(IpcNames.WRITE, this.write.bind(this));
49 this.eventWriter_.flush();
51 // Only listen for new incoming requests after we have loaded the pending
52 // ones. This will ensure that we always process the requests in order.
53 return this.eventWriter_.loadPendingRequests().then(init.bind(this));
56 remoting.TelemetryEventWriter.Service.prototype.dispose = function() {
57 this.ipc_.unregister(IpcNames.WRITE);
58 base.dispose(this.eventHooks_);
59 this.eventHooks_ = null;
63 * Unbind any sessions that are associated with |windowId|.
64 * @param {string} windowId
66 remoting.TelemetryEventWriter.Service.prototype.unbindSession =
68 this.sessionMonitor_.unbindSession(windowId);
72 * @param {string} windowId The source window id of the IPC.
73 * @param {!Object} event The event to be written to the server.
75 remoting.TelemetryEventWriter.Service.prototype.write =
76 function(windowId, event) {
77 this.sessionMonitor_.trackSessionStateChanges(windowId, event);
78 this.eventWriter_.write(event);
84 remoting.TelemetryEventWriter.Service.prototype.onSuspend_ = function() {
85 this.eventWriter_.writeToStorage();
88 /** @return {remoting.TelemetryEventWriter.Service} */
89 remoting.TelemetryEventWriter.Service.create = function() {
90 return new remoting.TelemetryEventWriter.Service(
91 base.Ipc.getInstance(),
92 new remoting.XhrEventWriter(
93 remoting.settings.TELEMETRY_API_BASE_URL,
95 'pending-log-requests'));
98 remoting.TelemetryEventWriter.Client = function() {};
101 * @param {!Object} event
102 * @return {Promise} A promise that resolves when the log message is sent to the
105 remoting.TelemetryEventWriter.Client.write = function(event) {
106 return base.Ipc.invoke(IpcNames.WRITE, chrome.app.window.current().id, event);
113 * @param {remoting.ChromotingEvent} event
115 function SessionInfo(event) {
117 this.timestamp = Date.now();
121 * When a window is closed using the context menu, the foreground page doesn't
122 * have a chance to intercept the close event.
123 * This class keeps track of all foreground windows with ongoing sessions, so
124 * that we can report session termination when they are closed.
126 * @param {remoting.XhrEventWriter} eventWriter
129 var SessionMonitor = function(eventWriter) {
131 this.eventWriter_ = eventWriter;
132 /** @private {Map<string, SessionInfo>} */
133 this.sessionMap_ = new Map();
137 * @param {string} windowId
138 * @param {Object} entry
140 SessionMonitor.prototype.trackSessionStateChanges = function(windowId, entry) {
141 var event = /** @type {remoting.ChromotingEvent} */ (base.deepCopy(entry));
143 if (event.type !== remoting.ChromotingEvent.Type.SESSION_STATE) {
147 if (remoting.ChromotingEvent.isEndOfSession(event)) {
148 this.sessionMap_.delete(windowId);
150 this.sessionMap_.set(windowId, new SessionInfo(event));
155 * Unbinds a session with |windowId| and log any close events if necessary.
156 * @param {string} windowId
158 SessionMonitor.prototype.unbindSession = function(windowId) {
159 if (this.sessionMap_.has(windowId)) {
160 var sessionInfo = this.sessionMap_.get(windowId);
161 console.assert(sessionInfo !== undefined);
162 inferSessionEndEvent(/** @type {SessionInfo} */ (sessionInfo));
163 this.eventWriter_.write(/** @type {Object} */ (sessionInfo.event));
164 this.sessionMap_.delete(windowId);
169 * @param {SessionInfo} sessionInfo
171 function inferSessionEndEvent(sessionInfo) {
172 var event = sessionInfo.event;
173 var SessionState = remoting.ChromotingEvent.SessionState;
175 switch (event.session_state) {
176 case SessionState.INITIALIZING:
177 case SessionState.CONNECTING:
178 case SessionState.AUTHENTICATED:
179 event.session_state = SessionState.CONNECTION_CANCELED;
182 event.session_state = SessionState.CLOSED;
184 var elapsed = (Date.now() - sessionInfo.timestamp) / 1000.0;
185 event.session_duration += elapsed;