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.
5 /** This view displays summary statistics on bandwidth usage. */
6 var BandwidthView = (function() {
9 // We inherit from DivView.
10 var superClass = DivView;
15 function BandwidthView() {
16 assertFirstConstructorCall(BandwidthView);
18 // Call superclass's constructor.
19 superClass.call(this, BandwidthView.MAIN_BOX_ID);
21 g_browser.addSessionNetworkStatsObserver(this, true);
22 g_browser.addHistoricNetworkStatsObserver(this, true);
24 // Register to receive data reduction proxy info.
25 g_browser.addDataReductionProxyInfoObserver(this, true);
27 // Register to receive bad proxy info.
28 g_browser.addBadProxiesObserver(this, true);
30 this.sessionNetworkStats_ = null;
31 this.historicNetworkStats_ = null;
34 BandwidthView.TAB_ID = 'tab-handle-bandwidth';
35 BandwidthView.TAB_NAME = 'Bandwidth';
36 BandwidthView.TAB_HASH = '#bandwidth';
38 // IDs for special HTML elements in bandwidth_view.html
39 BandwidthView.MAIN_BOX_ID = 'bandwidth-view-tab-content';
40 BandwidthView.ENABLED_ID = 'data-reduction-proxy-enabled';
41 BandwidthView.PRIMARY_PROXY_ID = 'data-reduction-proxy-primary';
42 BandwidthView.SECONDARY_PROXY_ID = 'data-reduction-proxy-secondary';
43 BandwidthView.PROBE_STATUS_ID = 'data-reduction-proxy-probe-status';
44 BandwidthView.BYPASS_STATE_ID = 'data-reduction-proxy-bypass-state';
45 BandwidthView.BYPASS_STATE_CONTAINER_ID =
46 'data-reduction-proxy-bypass-state-container';
47 BandwidthView.EVENTS_TBODY_ID = 'data-reduction-proxy-view-events-tbody';
48 BandwidthView.EVENTS_UL = 'data-reduction-proxy-view-events-list';
49 BandwidthView.STATS_BOX_ID = 'bandwidth-stats-table';
51 cr.addSingletonGetter(BandwidthView);
53 BandwidthView.prototype = {
54 // Inherit the superclass's methods.
55 __proto__: superClass.prototype,
57 data_reduction_proxy_config_: null,
59 bad_proxy_config_: null,
61 onLoadLogFinish: function(data) {
62 return this.onBadProxiesChanged(data.badProxies) &&
63 this.onDataReductionProxyInfoChanged(data.dataReductionProxyInfo) &&
64 (this.onSessionNetworkStatsChanged(data.sessionNetworkStats) ||
65 this.onHistoricNetworkStatsChanged(data.historicNetworkStats));
69 * Retains information on bandwidth usage this session.
71 onSessionNetworkStatsChanged: function(sessionNetworkStats) {
72 this.sessionNetworkStats_ = sessionNetworkStats;
73 return this.updateBandwidthUsageTable_();
77 * Displays information on bandwidth usage this session and over the
80 onHistoricNetworkStatsChanged: function(historicNetworkStats) {
81 this.historicNetworkStats_ = historicNetworkStats;
82 return this.updateBandwidthUsageTable_();
86 * Updates the UI based on receiving changes in information about the
87 * data reduction proxy summary.
89 onDataReductionProxyInfoChanged: function(info) {
90 $(BandwidthView.EVENTS_TBODY_ID).innerHTML = '';
96 $(BandwidthView.ENABLED_ID).innerText = 'Enabled';
97 $(BandwidthView.PROBE_STATUS_ID).innerText =
98 info.probe != null ? info.probe : 'N/A';
99 this.last_bypass_ = info.last_bypass != null ?
100 this.parseBypassEvent_(info.last_bypass) : null;
101 this.data_reduction_proxy_config_ = info.proxy_config.params;
103 $(BandwidthView.ENABLED_ID).innerText = 'Disabled';
104 $(BandwidthView.PROBE_STATUS_ID).innerText = 'N/A';
105 this.data_reduction_proxy_config_ = null;
108 this.updateDataReductionProxyConfig_();
110 for (var eventIndex = info.events.length - 1; eventIndex >= 0;
112 var event = info.events[eventIndex];
113 var headerRow = addNode($(BandwidthView.EVENTS_TBODY_ID), 'tr');
114 var detailsRow = addNode($(BandwidthView.EVENTS_TBODY_ID), 'tr');
116 var timeCell = addNode(headerRow, 'td');
117 var actionCell = addNode(headerRow, 'td');
118 var detailsCell = addNode(detailsRow, 'td');
119 detailsCell.colSpan = 2;
120 detailsCell.className = 'data-reduction-proxy-view-events-details';
121 var eventTime = timeutil.convertTimeTicksToDate(event.time);
122 timeutil.addNodeWithDate(timeCell, eventTime);
124 switch (event.type) {
125 case EventType.DATA_REDUCTION_PROXY_ENABLED:
126 this.buildEnabledRow_(event, actionCell, detailsCell);
128 case EventType.DATA_REDUCTION_PROXY_CANARY_REQUEST:
129 this.buildProbeRow_(event, actionCell, detailsCell);
131 case EventType.DATA_REDUCTION_PROXY_CANARY_RESPONSE_RECEIVED:
132 this.buildProbeResponseRow_(event, actionCell, detailsCell);
134 case EventType.DATA_REDUCTION_PROXY_BYPASS_REQUESTED:
135 this.buildBypassRow_(event, actionCell, detailsCell);
137 case EventType.DATA_REDUCTION_PROXY_FALLBACK:
138 this.buildFallbackRow_(event, actionCell, detailsCell);
147 * Updates the UI based on receiving changes in information about bad
150 onBadProxiesChanged: function(badProxies) {
154 var newBadProxies = [];
155 if (badProxies.length == 0) {
156 this.last_bypass_ = null;
158 for (var i = 0; i < badProxies.length; ++i) {
159 var entry = badProxies[i];
160 newBadProxies[entry.proxy_uri] = entry.bad_until;
163 this.bad_proxy_config_ = newBadProxies;
164 this.updateDataReductionProxyConfig_();
170 * Update the bandwidth usage table. Returns false on failure.
172 updateBandwidthUsageTable_: function() {
173 var sessionNetworkStats = this.sessionNetworkStats_;
174 var historicNetworkStats = this.historicNetworkStats_;
175 if (!sessionNetworkStats || !historicNetworkStats)
178 var sessionOriginal = sessionNetworkStats.session_original_content_length;
179 var sessionReceived = sessionNetworkStats.session_received_content_length;
180 var historicOriginal =
181 historicNetworkStats.historic_original_content_length;
182 var historicReceived =
183 historicNetworkStats.historic_received_content_length;
187 title: 'Original (KB)',
188 sessionValue: bytesToRoundedKilobytes_(sessionOriginal),
189 historicValue: bytesToRoundedKilobytes_(historicOriginal)
192 title: 'Received (KB)',
193 sessionValue: bytesToRoundedKilobytes_(sessionReceived),
194 historicValue: bytesToRoundedKilobytes_(historicReceived)
197 title: 'Savings (KB)',
199 bytesToRoundedKilobytes_(sessionOriginal - sessionReceived),
201 bytesToRoundedKilobytes_(historicOriginal - historicReceived)
204 title: 'Savings (%)',
205 sessionValue: getPercentSavings_(sessionOriginal, sessionReceived),
206 historicValue: getPercentSavings_(historicOriginal,
210 var input = new JsEvalContext({rows: rows});
211 jstProcess(input, $(BandwidthView.STATS_BOX_ID));
216 * Renders a data reduction proxy enabled/disabled event into the event
219 buildEnabledRow_: function(event, actionCell, detailsCell) {
220 if (event.params.enabled == 1) {
221 addTextNode(actionCell, 'Proxy: Enabled');
222 var proxyWrapper = addNode(detailsCell, 'div');
223 addNodeWithText(proxyWrapper, 'div', 'Proxy configuration:');
225 if (event.params.primary_origin != null &&
226 event.params.primary_origin.trim() != '') {
227 var proxyText = 'Primary: ' + event.params.primary_origin;
228 if (event.params.primary_restricted != null &&
229 event.params.primary_restricted) {
230 proxyText += ' (restricted)';
232 addNodeWithText(proxyWrapper, 'div', proxyText);
235 if (event.params.fallback_origin != null &&
236 event.params.fallback_origin.trim() != '') {
237 var proxyText = 'Fallback: ' + event.params.fallback_origin;
238 if (event.params.fallback_restricted != null &&
239 event.params.fallback_restricted) {
240 proxyText += ' (restricted)';
242 addNodeWithText(proxyWrapper, 'div', proxyText);
245 if (event.params.ssl_origin != null &&
246 event.params.ssl_origin.trim() != '') {
247 addNodeWithText(proxyWrapper, 'div',
248 'SSL: ' + event.params.ssl_origin);
251 addTextNode(actionCell, 'Proxy: Disabled');
256 * Renders a Data Reduction Proxy probe request event into the event
259 buildProbeRow_: function(event, actionCell, detailsCell) {
260 if (event.phase == EventPhase.PHASE_BEGIN) {
261 addTextNode(actionCell, 'Probe request sent');
262 addTextNode(detailsCell, 'URL: ' + event.params.url);
263 } else if (event.phase == EventPhase.PHASE_END) {
264 addTextNode(actionCell, 'Probe request completed');
265 if (event.params.net_error == 0) {
266 addTextNode(detailsCell, 'Result: OK');
268 addTextNode(detailsCell,
269 'Result: ' + netErrorToString(event.params.net_error));
275 * Renders a Data Reduction Proxy probe response event into the event
278 buildProbeResponseRow_: function(event, actionCell, detailsCell) {
279 addTextNode(actionCell, 'Probe response received');
283 * Renders a data reduction proxy bypass event into the event tbody.
285 buildBypassRow_: function(event, actionCell, detailsCell) {
286 var parsedBypass = this.parseBypassEvent_(event);
288 addTextNode(actionCell,
289 'Bypass received (' + parsedBypass.bypass_reason + ')');
290 var bypassWrapper = addNode(detailsCell, 'div');
291 addNodeWithText(bypassWrapper, 'div', 'URL: ' + parsedBypass.origin_url);
293 bypassWrapper, 'div',
294 'Bypassed for ' + parsedBypass.bypass_duration_seconds + ' seconds.');
298 * Renders a data reduction proxy fallback event into the event tbody.
300 buildFallbackRow_: function(event, actionCell, detailsCell) {
301 addTextNode(actionCell, 'Proxy fallback');
305 * Parses a data reduction proxy bypass event for use in the summary and
306 * in the event tbody.
308 parseBypassEvent_: function(event) {
310 if (event.params.action != null) {
311 reason = event.params.action;
313 reason = getKeyWithValue(
314 DataReductionProxyBypassEventType, event.params.bypass_type);
318 bypass_reason: reason,
319 origin_url: event.params.url,
320 bypass_duration_seconds: event.params.bypass_duration_seconds,
321 bypass_expiration: event.params.expiration,
328 * Updates the data reduction proxy summary block.
330 updateDataReductionProxyConfig_: function() {
331 $(BandwidthView.PRIMARY_PROXY_ID).innerHTML = '';
332 $(BandwidthView.SECONDARY_PROXY_ID).innerHTML = '';
333 setNodeDisplay($(BandwidthView.BYPASS_STATE_CONTAINER_ID), false);
335 if (this.data_reduction_proxy_config_) {
336 var primaryProxy = '';
337 var secondaryProxy = '';
338 var hasBypassedProxy = false;
339 var now = timeutil.getCurrentTimeTicks();
341 if (this.last_bypass_ &&
342 this.hasTimePassedLogTime_(+this.last_bypass_.bypass_expiration)) {
343 var input = new JsEvalContext(this.last_bypass_);
344 jstProcess(input, $(BandwidthView.BYPASS_STATE_CONTAINER_ID));
346 var input = new JsEvalContext();
347 jstProcess(input, $(BandwidthView.BYPASS_STATE_CONTAINER_ID));
350 if (this.data_reduction_proxy_config_.ssl_origin) {
351 if (this.isMarkedAsBad_(this.data_reduction_proxy_config_.ssl_origin))
352 hasBypassedProxy = true;
354 primaryProxy = 'HTTPS Tunnel: ' + this.buildProxyString_(
355 this.data_reduction_proxy_config_.ssl_origin, false);
358 if (this.data_reduction_proxy_config_.primary_origin) {
359 if (this.isMarkedAsBad_(
360 this.data_reduction_proxy_config_.primary_origin))
361 hasBypassedProxy = true;
363 var proxyString = this.buildProxyString_(
364 this.data_reduction_proxy_config_.primary_origin,
365 this.data_reduction_proxy_config_.primary_restricted);
367 if (primaryProxy == '')
368 primaryProxy = proxyString;
370 secondaryProxy = proxyString;
373 if (this.data_reduction_proxy_config_.fallback_origin) {
374 if (this.isMarkedAsBad_(
375 this.data_reduction_proxy_config_.fallback_origin))
376 hasBypassedProxy = true;
378 var proxyString = this.buildProxyString_(
379 this.data_reduction_proxy_config_.fallback_origin,
380 this.data_reduction_proxy_config_.fallback_restricted);
382 if (primaryProxy == '')
383 primaryProxy = proxyString;
384 else if (secondaryProxy == '')
385 secondaryProxy = proxyString;
388 $(BandwidthView.PRIMARY_PROXY_ID).innerText = primaryProxy;
389 $(BandwidthView.SECONDARY_PROXY_ID).innerText = secondaryProxy;
390 if (hasBypassedProxy)
391 setNodeDisplay($(BandwidthView.BYPASS_STATE_CONTAINER_ID), true);
396 * Takes a data reduction proxy configuration and renders to a friendly
399 buildProxyString_: function(proxy, restricted) {
400 var markedAsBad = this.isMarkedAsBad_(proxy);
401 var proxyString = '';
403 proxyString += proxy + ' (RESTRICTED)';
405 proxyString += proxy;
407 proxyString += ' (BYPASSED)';
409 proxyString += ' (ACTIVE)';
417 * Checks to see if a proxy server is in marked as bad.
419 isMarkedAsBad_: function(proxy) {
420 for (var entry in this.bad_proxy_config_) {
421 if (entry == proxy &&
422 this.hasTimePassedLogTime_(this.bad_proxy_config_[entry])) {
431 * Checks to see if a given time in ticks has passed the time of the
432 * the log. For real time viewing, this is "now", but for loaded logs, it
433 * is the time at which the logs were taken.
435 hasTimePassedLogTime_: function(timeTicks) {
437 if (MainView.isViewingLoadedLog() && ClientInfo.numericDate) {
438 logTime = ClientInfo.numericDate;
440 logTime = timeutil.getCurrentTime();
443 return timeutil.convertTimeTicksToTime(timeTicks) > logTime;
448 * Converts bytes to kilobytes rounded to one decimal place.
450 function bytesToRoundedKilobytes_(val) {
451 return (val / 1024).toFixed(1);
455 * Returns bandwidth savings as a percent rounded to one decimal place.
457 function getPercentSavings_(original, received) {
459 return ((original - received) * 100 / original).toFixed(1);
464 return BandwidthView;