Index: netlog_viewer/bandwidth_view.js |
diff --git a/netlog_viewer/bandwidth_view.js b/netlog_viewer/bandwidth_view.js |
new file mode 100644 |
index 0000000000000000000000000000000000000000..2fd604cdc3114d0b3d1e47b8eac13f67f0ccb0ca |
--- /dev/null |
+++ b/netlog_viewer/bandwidth_view.js |
@@ -0,0 +1,364 @@ |
+// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+/** This view displays summary statistics on bandwidth usage. */ |
+var BandwidthView = (function() { |
+ 'use strict'; |
+ |
+ // We inherit from DivView. |
+ var superClass = DivView; |
+ |
+ /** |
+ * @constructor |
+ */ |
+ function BandwidthView() { |
+ assertFirstConstructorCall(BandwidthView); |
+ |
+ // Call superclass's constructor. |
+ superClass.call(this, BandwidthView.MAIN_BOX_ID); |
+ |
+ g_browser.addSessionNetworkStatsObserver(this, true); |
+ g_browser.addHistoricNetworkStatsObserver(this, true); |
+ |
+ // Register to receive data reduction proxy info. |
+ g_browser.addDataReductionProxyInfoObserver(this, true); |
+ |
+ // Register to receive bad proxy info. |
+ g_browser.addBadProxiesObserver(this, true); |
+ |
+ this.sessionNetworkStats_ = null; |
+ this.historicNetworkStats_ = null; |
+ } |
+ |
+ BandwidthView.TAB_ID = 'tab-handle-bandwidth'; |
+ BandwidthView.TAB_NAME = 'Bandwidth'; |
+ BandwidthView.TAB_HASH = '#bandwidth'; |
+ |
+ // IDs for special HTML elements in bandwidth_view.html |
+ BandwidthView.MAIN_BOX_ID = 'bandwidth-view-tab-content'; |
+ BandwidthView.ENABLED_ID = 'data-reduction-proxy-enabled'; |
+ BandwidthView.PROXY_CONFIG_ID = 'data-reduction-proxy-config'; |
+ BandwidthView.PROBE_STATUS_ID = 'data-reduction-proxy-probe-status'; |
+ BandwidthView.BYPASS_STATE_CONTAINER_ID = |
+ 'data-reduction-proxy-bypass-state-container'; |
+ BandwidthView.BYPASS_STATE_ID = 'data-reduction-proxy-bypass-state-details'; |
+ BandwidthView.EVENTS_TBODY_ID = 'data-reduction-proxy-view-events-tbody'; |
+ BandwidthView.EVENTS_UL = 'data-reduction-proxy-view-events-list'; |
+ BandwidthView.STATS_BOX_ID = 'bandwidth-stats-table'; |
+ BandwidthView.SAVINGS_TBODY_ID = 'bandwidth-savings-tbody'; |
+ |
+ cr.addSingletonGetter(BandwidthView); |
+ |
+ BandwidthView.prototype = { |
+ // Inherit the superclass's methods. |
+ __proto__: superClass.prototype, |
+ |
+ data_reduction_proxy_config_: null, |
+ last_bypass_: null, |
+ bad_proxy_config_: null, |
+ |
+ onLoadLogFinish: function(data) { |
+ return this.onBadProxiesChanged(data.badProxies) && |
+ this.onDataReductionProxyInfoChanged(data.dataReductionProxyInfo) && |
+ (this.onSessionNetworkStatsChanged(data.sessionNetworkStats) || |
+ this.onHistoricNetworkStatsChanged(data.historicNetworkStats)); |
+ }, |
+ |
+ /** |
+ * Retains information on bandwidth usage this session. |
+ */ |
+ onSessionNetworkStatsChanged: function(sessionNetworkStats) { |
+ this.sessionNetworkStats_ = sessionNetworkStats; |
+ return this.updateBandwidthUsageTable_(); |
+ }, |
+ |
+ /** |
+ * Displays information on bandwidth usage this session and over the |
+ * browser's lifetime. |
+ */ |
+ onHistoricNetworkStatsChanged: function(historicNetworkStats) { |
+ this.historicNetworkStats_ = historicNetworkStats; |
+ return this.updateBandwidthUsageTable_(); |
+ }, |
+ |
+ /** |
+ * Updates the UI based on receiving changes in information about the |
+ * data reduction proxy summary. |
+ */ |
+ onDataReductionProxyInfoChanged: function(info) { |
+ $(BandwidthView.EVENTS_TBODY_ID).innerHTML = ''; |
+ |
+ if (!info) |
+ return false; |
+ |
+ if (info.enabled) { |
+ $(BandwidthView.ENABLED_ID).innerText = 'Enabled'; |
+ $(BandwidthView.PROBE_STATUS_ID).innerText = |
+ info.probe != null ? info.probe : 'N/A'; |
+ this.last_bypass_ = info.last_bypass; |
+ this.data_reduction_proxy_config_ = info.proxy_config.params; |
+ } else { |
+ $(BandwidthView.ENABLED_ID).innerText = 'Disabled'; |
+ $(BandwidthView.PROBE_STATUS_ID).innerText = 'N/A'; |
+ this.data_reduction_proxy_config_ = null; |
+ } |
+ |
+ this.updateDataReductionProxyConfig_(); |
+ |
+ for (var eventIndex = info.events.length - 1; eventIndex >= 0; |
+ --eventIndex) { |
+ var event = info.events[eventIndex]; |
+ var headerRow = addNode($(BandwidthView.EVENTS_TBODY_ID), 'tr'); |
+ var detailsRow = addNode($(BandwidthView.EVENTS_TBODY_ID), 'tr'); |
+ |
+ var timeCell = addNode(headerRow, 'td'); |
+ var actionCell = addNode(headerRow, 'td'); |
+ var detailsCell = addNode(detailsRow, 'td'); |
+ detailsCell.colSpan = 2; |
+ detailsCell.className = 'data-reduction-proxy-view-events-details'; |
+ var eventTime = timeutil.convertTimeTicksToDate(event.time); |
+ timeutil.addNodeWithDate(timeCell, eventTime); |
+ this.buildEventRow_(event, actionCell, detailsCell); |
+ } |
+ |
+ return true; |
+ }, |
+ |
+ /** |
+ * Updates the UI based on receiving changes in information about bad |
+ * proxy servers. |
+ */ |
+ onBadProxiesChanged: function(badProxies) { |
+ if (!badProxies) |
+ return false; |
+ |
+ var newBadProxies = []; |
+ if (badProxies.length == 0) { |
+ this.last_bypass_ = null; |
+ } else { |
+ for (var i = 0; i < badProxies.length; ++i) { |
+ var entry = badProxies[i]; |
+ newBadProxies[entry.proxy_uri] = entry.bad_until; |
+ } |
+ } |
+ this.bad_proxy_config_ = newBadProxies; |
+ this.updateDataReductionProxyConfig_(); |
+ |
+ return true; |
+ }, |
+ |
+ /** |
+ * Update the bandwidth usage table. Returns false on failure. |
+ */ |
+ updateBandwidthUsageTable_: function() { |
+ var sessionNetworkStats = this.sessionNetworkStats_; |
+ var historicNetworkStats = this.historicNetworkStats_; |
+ if (!sessionNetworkStats || !historicNetworkStats) |
+ return false; |
+ |
+ var sessionOriginal = sessionNetworkStats.session_original_content_length; |
+ var sessionReceived = sessionNetworkStats.session_received_content_length; |
+ var historicOriginal = |
+ historicNetworkStats.historic_original_content_length; |
+ var historicReceived = |
+ historicNetworkStats.historic_received_content_length; |
+ |
+ var rows = []; |
+ rows.push({ |
+ title: 'Original (KB)', |
+ sessionValue: bytesToRoundedKilobytes_(sessionOriginal), |
+ historicValue: bytesToRoundedKilobytes_(historicOriginal) |
+ }); |
+ rows.push({ |
+ title: 'Received (KB)', |
+ sessionValue: bytesToRoundedKilobytes_(sessionReceived), |
+ historicValue: bytesToRoundedKilobytes_(historicReceived) |
+ }); |
+ rows.push({ |
+ title: 'Savings (KB)', |
+ sessionValue: |
+ bytesToRoundedKilobytes_(sessionOriginal - sessionReceived), |
+ historicValue: |
+ bytesToRoundedKilobytes_(historicOriginal - historicReceived) |
+ }); |
+ rows.push({ |
+ title: 'Savings (%)', |
+ sessionValue: getPercentSavings_(sessionOriginal, sessionReceived), |
+ historicValue: getPercentSavings_(historicOriginal, |
+ historicReceived) |
+ }); |
+ |
+ var tbody = $(BandwidthView.SAVINGS_TBODY_ID); |
+ tbody.innerHTML = ''; |
+ |
+ // Fill in the bandwidth savings table. |
+ for (var i = 0; i < rows.length; ++i) { |
+ var r = rows[i]; |
+ var tr = addNode(tbody, 'tr'); |
+ |
+ addNodeWithText(tr, 'td', r.title); |
+ addNodeWithText(tr, 'td', r.sessionValue); |
+ addNodeWithText(tr, 'td', r.historicValue); |
+ } |
+ |
+ return true; |
+ }, |
+ |
+ /** |
+ * Renders a Data Reduction Proxy event into the event tbody |
+ */ |
+ buildEventRow_: function(event, actionCell, detailsCell) { |
+ if (event.type == EventType.DATA_REDUCTION_PROXY_ENABLED && |
+ event.params.enabled == 0) { |
+ addTextNode(actionCell, 'DISABLED'); |
+ } else { |
+ var actionText = |
+ EventTypeNames[event.type].replace('DATA_REDUCTION_PROXY_', ''); |
+ if (event.phase == EventPhase.PHASE_BEGIN || |
+ event.phase == EventPhase.PHASE_END) { |
+ actionText = actionText + ' (' + |
+ getKeyWithValue(EventPhase, event.phase) |
+ .replace('PHASE_', '') + ')'; |
+ } |
+ |
+ addTextNode(actionCell, actionText); |
+ this.createEventTable_(event.params, detailsCell); |
+ } |
+ }, |
+ |
+ /** |
+ * Updates the data reduction proxy summary block. |
+ */ |
+ updateDataReductionProxyConfig_: function() { |
+ $(BandwidthView.PROXY_CONFIG_ID).innerHTML = ''; |
+ $(BandwidthView.BYPASS_STATE_ID).innerHTML = ''; |
+ setNodeDisplay($(BandwidthView.BYPASS_STATE_CONTAINER_ID), false); |
+ |
+ if (this.data_reduction_proxy_config_) { |
+ var hasBypassedProxy = false; |
+ var now = timeutil.getCurrentTimeTicks(); |
+ |
+ if (this.last_bypass_ && |
+ this.hasTimePassedLogTime_(+this.last_bypass_.params.expiration)) { |
+ // Best effort on iterating the config to search for a bad proxy. |
+ // A server could exist in a string member of |
+ // data_reduction_proxy_config_ or within an array of servers in an |
+ // array member of data_reduction_proxy_config_. As such, search |
+ // through all string members and string arrays. |
+ for (var key in this.data_reduction_proxy_config_) { |
+ var value = this.data_reduction_proxy_config_[key]; |
+ if (typeof value == 'string') { |
+ if (this.isMarkedAsBad_(value)) { |
+ hasBypassedProxy = true; |
+ break; |
+ } |
+ } else if (value instanceof Array) { |
+ for (var index = 1; index < value.length; index++) { |
+ if (this.isMarkedAsBad_(value[index])) { |
+ hasBypassedProxy = true; |
+ } |
+ } |
+ |
+ if (hasBypassedProxy) { |
+ break; |
+ } |
+ } |
+ } |
+ } |
+ |
+ if (hasBypassedProxy) { |
+ this.createEventTable_(this.last_bypass_.params, |
+ $(BandwidthView.BYPASS_STATE_ID)); |
+ } |
+ |
+ this.createEventTable_(this.data_reduction_proxy_config_, |
+ $(BandwidthView.PROXY_CONFIG_ID)); |
+ setNodeDisplay($(BandwidthView.BYPASS_STATE_CONTAINER_ID), |
+ hasBypassedProxy); |
+ } |
+ }, |
+ |
+ /** |
+ * Checks to see if a proxy server is in marked as bad. |
+ */ |
+ isMarkedAsBad_: function(proxy) { |
+ for (var entry in this.bad_proxy_config_) { |
+ if (entry == proxy && |
+ this.hasTimePassedLogTime_(this.bad_proxy_config_[entry])) { |
+ return true; |
+ } |
+ } |
+ |
+ return false; |
+ }, |
+ |
+ /** |
+ * Checks to see if a given time in ticks has passed the time of the |
+ * the log. For real time viewing, this is "now", but for loaded logs, it |
+ * is the time at which the logs were taken. |
+ */ |
+ hasTimePassedLogTime_: function(timeTicks) { |
+ var logTime; |
+ if (MainView.isViewingLoadedLog() && ClientInfo.numericDate) { |
+ logTime = ClientInfo.numericDate; |
+ } else { |
+ logTime = timeutil.getCurrentTime(); |
+ } |
+ |
+ return timeutil.convertTimeTicksToTime(timeTicks) > logTime; |
+ }, |
+ |
+ /** |
+ * Creates a table of the object obj. Certain keys are special cased for |
+ * ease of readability. |
+ */ |
+ createEventTable_: function(obj, parentNode) { |
+ if (Object.keys(obj).length > 0) { |
+ var tableNode = addNode(parentNode, 'table'); |
+ tableNode.className = 'borderless-table'; |
+ for (var key in obj) { |
+ var value = obj[key]; |
+ if (value != null && value.toString() != '') { |
+ if (key == 'net_error') { |
+ if (value == 0) { |
+ value = 'OK'; |
+ } else { |
+ value = netErrorToString(value); |
+ } |
+ } else if (key == 'bypass_type') { |
+ value = getKeyWithValue(DataReductionProxyBypassEventType, value); |
+ } else if (key == 'bypass_action_type') { |
+ value = getKeyWithValue(DataReductionProxyBypassActionType, |
+ value); |
+ } else if (key == 'expiration') { |
+ value = timeutil.convertTimeTicksToDate(value); |
+ } |
+ var tableRow = addNode(tableNode, 'tr'); |
+ addNodeWithText(tableRow, 'td', key); |
+ addNodeWithText(tableRow, 'td', value); |
+ } |
+ } |
+ } |
+ } |
+ }; |
+ |
+ /** |
+ * Converts bytes to kilobytes rounded to one decimal place. |
+ */ |
+ function bytesToRoundedKilobytes_(val) { |
+ return (val / 1024).toFixed(1); |
+ } |
+ |
+ /** |
+ * Returns bandwidth savings as a percent rounded to one decimal place. |
+ */ |
+ function getPercentSavings_(original, received) { |
+ if (original > 0) { |
+ return ((original - received) * 100 / original).toFixed(1); |
+ } |
+ return '0.0'; |
+ } |
+ |
+ return BandwidthView; |
+})(); |