1// Copyright (c) 2012 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. 4 5var SourceTracker = (function() { 6 'use strict'; 7 8 /** 9 * This class keeps track of all NetLog events, grouped into per-source 10 * streams. It receives events from EventsTracker, and passes 11 * them on to all its observers. 12 * 13 * @constructor 14 */ 15 function SourceTracker() { 16 assertFirstConstructorCall(SourceTracker); 17 18 // Observers that only want to receive lists of updated SourceEntries. 19 this.sourceEntryObservers_ = []; 20 21 // True when cookies and authentication information should be removed from 22 // displayed events. When true, such information should be hidden from 23 // all pages. 24 this.privacyStripping_ = true; 25 26 // True when times should be displayed as milliseconds since the first 27 // event, as opposed to milliseconds since January 1, 1970. 28 this.useRelativeTimes_ = true; 29 30 this.clearEntries_(); 31 32 EventsTracker.getInstance().addLogEntryObserver(this); 33 } 34 35 cr.addSingletonGetter(SourceTracker); 36 37 SourceTracker.prototype = { 38 /** 39 * Clears all log entries and SourceEntries and related state. 40 */ 41 clearEntries_: function() { 42 // Used for sorting entries with automatically assigned IDs. 43 this.maxReceivedSourceId_ = 0; 44 45 // Next unique id to be assigned to a log entry without a source. 46 // Needed to identify associated GUI elements, etc. 47 this.nextSourcelessEventId_ = -1; 48 49 // Ordered list of log entries. Needed to maintain original order when 50 // generating log dumps 51 this.capturedEvents_ = []; 52 53 this.sourceEntries_ = {}; 54 }, 55 56 /** 57 * Returns a list of all SourceEntries. 58 */ 59 getAllSourceEntries: function() { 60 return this.sourceEntries_; 61 }, 62 63 /** 64 * Returns the description of the specified SourceEntry, or an empty string 65 * if it doesn't exist. 66 */ 67 getDescription: function(id) { 68 var entry = this.getSourceEntry(id); 69 if (entry) 70 return entry.getDescription(); 71 return ''; 72 }, 73 74 /** 75 * Returns the specified SourceEntry. 76 */ 77 getSourceEntry: function(id) { 78 return this.sourceEntries_[id]; 79 }, 80 81 /** 82 * Sends each entry to all observers and updates |capturedEvents_|. 83 * Also assigns unique ids to log entries without a source. 84 */ 85 onReceivedLogEntries: function(logEntries) { 86 // List source entries with new log entries. Sorted chronologically, by 87 // first new log entry. 88 var updatedSourceEntries = []; 89 90 var updatedSourceEntryIdMap = {}; 91 92 for (var e = 0; e < logEntries.length; ++e) { 93 var logEntry = logEntries[e]; 94 95 // Assign unique ID, if needed. 96 // TODO(mmenke): Remove this, and all other code to handle 0 source 97 // IDs when M19 hits stable. 98 if (logEntry.source.id == 0) { 99 logEntry.source.id = this.nextSourcelessEventId_; 100 --this.nextSourcelessEventId_; 101 } else if (this.maxReceivedSourceId_ < logEntry.source.id) { 102 this.maxReceivedSourceId_ = logEntry.source.id; 103 } 104 105 // Create/update SourceEntry object. 106 var sourceEntry = this.sourceEntries_[logEntry.source.id]; 107 if (!sourceEntry) { 108 sourceEntry = new SourceEntry(logEntry, this.maxReceivedSourceId_); 109 this.sourceEntries_[logEntry.source.id] = sourceEntry; 110 } else { 111 sourceEntry.update(logEntry); 112 } 113 114 // Add to updated SourceEntry list, if not already in it. 115 if (!updatedSourceEntryIdMap[logEntry.source.id]) { 116 updatedSourceEntryIdMap[logEntry.source.id] = sourceEntry; 117 updatedSourceEntries.push(sourceEntry); 118 } 119 } 120 121 this.capturedEvents_ = this.capturedEvents_.concat(logEntries); 122 for (var i = 0; i < this.sourceEntryObservers_.length; ++i) { 123 this.sourceEntryObservers_[i].onSourceEntriesUpdated( 124 updatedSourceEntries); 125 } 126 }, 127 128 /** 129 * Called when all log events have been deleted. 130 */ 131 onAllLogEntriesDeleted: function() { 132 this.clearEntries_(); 133 for (var i = 0; i < this.sourceEntryObservers_.length; ++i) 134 this.sourceEntryObservers_[i].onAllSourceEntriesDeleted(); 135 }, 136 137 /** 138 * Sets the value of |privacyStripping_| and informs log observers 139 * of the change. 140 */ 141 setPrivacyStripping: function(privacyStripping) { 142 this.privacyStripping_ = privacyStripping; 143 for (var i = 0; i < this.sourceEntryObservers_.length; ++i) { 144 if (this.sourceEntryObservers_[i].onPrivacyStrippingChanged) 145 this.sourceEntryObservers_[i].onPrivacyStrippingChanged(); 146 } 147 }, 148 149 /** 150 * Returns whether or not cookies and authentication information should be 151 * displayed for events that contain them. 152 */ 153 getPrivacyStripping: function() { 154 return this.privacyStripping_; 155 }, 156 157 /** 158 * Sets the value of |useRelativeTimes_| and informs log observers 159 * of the change. 160 */ 161 setUseRelativeTimes: function(useRelativeTimes) { 162 this.useRelativeTimes_ = useRelativeTimes; 163 for (var i = 0; i < this.sourceEntryObservers_.length; ++i) { 164 if (this.sourceEntryObservers_[i].onUseRelativeTimesChanged) 165 this.sourceEntryObservers_[i].onUseRelativeTimesChanged(); 166 } 167 }, 168 169 /** 170 * Returns true if times should be displayed as milliseconds since the first 171 * event. 172 */ 173 getUseRelativeTimes: function() { 174 return this.useRelativeTimes_; 175 }, 176 177 /** 178 * Adds a listener of SourceEntries. |observer| will be called back when 179 * SourceEntries are added or modified, source entries are deleted, or 180 * privacy stripping changes: 181 * 182 * observer.onSourceEntriesUpdated(sourceEntries) 183 * observer.onAllSourceEntriesDeleted() 184 * observer.onPrivacyStrippingChanged() 185 */ 186 addSourceEntryObserver: function(observer) { 187 this.sourceEntryObservers_.push(observer); 188 } 189 }; 190 191 return SourceTracker; 192})(); 193