networkstatus.py
1 """ 2 Network status tab widget definition. 3 """ 4 5 import time 6 7 from PyQt4 import QtCore, QtGui 8 9 import l10n 10 import network.stats 11 import state 12 from . import widgets 13 from network import connectionpool, knownnodes 14 from .retranslateui import RetranslateMixin 15 from tr import _translate 16 from .uisignaler import UISignaler 17 18 19 class NetworkStatus(QtGui.QWidget, RetranslateMixin): 20 """Network status tab""" 21 def __init__(self, parent=None): 22 super(NetworkStatus, self).__init__(parent) 23 widgets.load('networkstatus.ui', self) 24 25 header = self.tableWidgetConnectionCount.horizontalHeader() 26 header.setResizeMode(QtGui.QHeaderView.ResizeToContents) 27 28 # Somehow this value was 5 when I tested 29 if header.sortIndicatorSection() > 4: 30 header.setSortIndicator(0, QtCore.Qt.AscendingOrder) 31 32 self.startup = time.localtime() 33 34 self.UISignalThread = UISignaler.get() 35 # pylint: disable=no-member 36 QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL( 37 "updateNumberOfMessagesProcessed()"), self.updateNumberOfMessagesProcessed) 38 QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL( 39 "updateNumberOfPubkeysProcessed()"), self.updateNumberOfPubkeysProcessed) 40 QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL( 41 "updateNumberOfBroadcastsProcessed()"), self.updateNumberOfBroadcastsProcessed) 42 QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL( 43 "updateNetworkStatusTab(PyQt_PyObject,PyQt_PyObject,PyQt_PyObject)"), self.updateNetworkStatusTab) 44 45 self.timer = QtCore.QTimer() 46 47 QtCore.QObject.connect(self.timer, QtCore.SIGNAL("timeout()"), self.runEveryTwoSeconds) 48 # pylint: enable=no-member 49 50 def startUpdate(self): 51 """Start a timer to update counters every 2 seconds""" 52 state.Inventory.numberOfInventoryLookupsPerformed = 0 53 self.runEveryTwoSeconds() 54 self.timer.start(2000) # milliseconds 55 56 def stopUpdate(self): 57 """Stop counter update timer""" 58 self.timer.stop() 59 60 def formatBytes(self, num): 61 """Format bytes nicely (SI prefixes)""" 62 # pylint: disable=no-self-use 63 for x in [ 64 _translate( 65 "networkstatus", 66 "byte(s)", 67 None, 68 QtCore.QCoreApplication.CodecForTr, 69 num), 70 "kB", 71 "MB", 72 "GB", 73 ]: 74 if num < 1000.0: 75 return "%3.0f %s" % (num, x) 76 num /= 1000.0 77 return "%3.0f %s" % (num, 'TB') 78 79 def formatByteRate(self, num): 80 """Format transfer speed in kB/s""" 81 # pylint: disable=no-self-use 82 num /= 1000 83 return "%4.0f kB" % num 84 85 def updateNumberOfObjectsToBeSynced(self): 86 """Update the counter for number of objects to be synced""" 87 self.labelSyncStatus.setText( 88 _translate( 89 "networkstatus", 90 "Object(s) to be synced: %n", 91 None, 92 QtCore.QCoreApplication.CodecForTr, 93 network.stats.pendingDownload() 94 + network.stats.pendingUpload())) 95 96 def updateNumberOfMessagesProcessed(self): 97 """Update the counter for number of processed messages""" 98 self.updateNumberOfObjectsToBeSynced() 99 self.labelMessageCount.setText( 100 _translate( 101 "networkstatus", 102 "Processed %n person-to-person message(s).", 103 None, 104 QtCore.QCoreApplication.CodecForTr, 105 state.numberOfMessagesProcessed)) 106 107 def updateNumberOfBroadcastsProcessed(self): 108 """Update the counter for the number of processed broadcasts""" 109 self.updateNumberOfObjectsToBeSynced() 110 self.labelBroadcastCount.setText( 111 _translate( 112 "networkstatus", 113 "Processed %n broadcast message(s).", 114 None, 115 QtCore.QCoreApplication.CodecForTr, 116 state.numberOfBroadcastsProcessed)) 117 118 def updateNumberOfPubkeysProcessed(self): 119 """Update the counter for the number of processed pubkeys""" 120 self.updateNumberOfObjectsToBeSynced() 121 self.labelPubkeyCount.setText( 122 _translate( 123 "networkstatus", 124 "Processed %n public key(s).", 125 None, 126 QtCore.QCoreApplication.CodecForTr, 127 state.numberOfPubkeysProcessed)) 128 129 def updateNumberOfBytes(self): 130 """ 131 This function is run every two seconds, so we divide the rate of bytes 132 sent and received by 2. 133 """ 134 self.labelBytesRecvCount.setText( 135 _translate( 136 "networkstatus", 137 "Down: %1/s Total: %2").arg( 138 self.formatByteRate(network.stats.downloadSpeed()), 139 self.formatBytes(network.stats.receivedBytes()))) 140 self.labelBytesSentCount.setText( 141 _translate( 142 "networkstatus", "Up: %1/s Total: %2").arg( 143 self.formatByteRate(network.stats.uploadSpeed()), 144 self.formatBytes(network.stats.sentBytes()))) 145 146 def updateNetworkStatusTab(self, outbound, add, destination): 147 """Add or remove an entry to the list of connected peers""" 148 # pylint: disable=too-many-branches,undefined-variable 149 if outbound: 150 try: 151 c = connectionpool.pool.outboundConnections[destination] 152 except KeyError: 153 if add: 154 return 155 else: 156 try: 157 c = connectionpool.pool.inboundConnections[destination] 158 except KeyError: 159 try: 160 c = connectionpool.pool.inboundConnections[destination.host] 161 except KeyError: 162 if add: 163 return 164 165 self.tableWidgetConnectionCount.setUpdatesEnabled(False) 166 self.tableWidgetConnectionCount.setSortingEnabled(False) 167 168 if add: 169 self.tableWidgetConnectionCount.insertRow(0) 170 self.tableWidgetConnectionCount.setItem( 171 0, 0, 172 QtGui.QTableWidgetItem("%s:%i" % (destination.host, destination.port)) 173 ) 174 self.tableWidgetConnectionCount.setItem( 175 0, 2, 176 QtGui.QTableWidgetItem("%s" % (c.userAgent)) 177 ) 178 self.tableWidgetConnectionCount.setItem( 179 0, 3, 180 QtGui.QTableWidgetItem("%s" % (c.tlsVersion)) 181 ) 182 self.tableWidgetConnectionCount.setItem( 183 0, 4, 184 QtGui.QTableWidgetItem("%s" % (",".join(map(str, c.streams)))) 185 ) 186 try: 187 # .. todo:: FIXME: hard coded stream no 188 rating = "%.1f" % (knownnodes.knownNodes[1][destination]['rating']) 189 except KeyError: 190 rating = "-" 191 self.tableWidgetConnectionCount.setItem( 192 0, 1, 193 QtGui.QTableWidgetItem("%s" % (rating)) 194 ) 195 brush = QtGui.QBrush( 196 QtGui.QColor("yellow" if outbound else "green"), 197 QtCore.Qt.SolidPattern) 198 for j in range(1): 199 self.tableWidgetConnectionCount.item(0, j).setBackground(brush) 200 self.tableWidgetConnectionCount.item(0, j).setForeground( 201 QtGui.QBrush(QtGui.QColor("black"), QtCore.Qt.SolidPattern)) 202 self.tableWidgetConnectionCount.item(0, 0).setData(QtCore.Qt.UserRole, destination) 203 self.tableWidgetConnectionCount.item(0, 1).setData(QtCore.Qt.UserRole, outbound) 204 else: 205 if not connectionpool.pool.inboundConnections: 206 self.window().setStatusIcon('yellow') 207 for i in range(self.tableWidgetConnectionCount.rowCount()): 208 if self.tableWidgetConnectionCount.item(i, 0).data(QtCore.Qt.UserRole).toPyObject() != destination: 209 continue 210 if self.tableWidgetConnectionCount.item(i, 1).data(QtCore.Qt.UserRole).toPyObject() == outbound: 211 self.tableWidgetConnectionCount.removeRow(i) 212 break 213 214 self.tableWidgetConnectionCount.setUpdatesEnabled(True) 215 self.tableWidgetConnectionCount.setSortingEnabled(True) 216 self.labelTotalConnections.setText( 217 _translate( 218 "networkstatus", "Total Connections: %1").arg( 219 str(self.tableWidgetConnectionCount.rowCount()))) 220 # FYI: The 'singlelistener' thread sets the icon color to green when it 221 # receives an incoming connection, meaning that the user's firewall is 222 # configured correctly. 223 if self.tableWidgetConnectionCount.rowCount() and state.statusIconColor == 'red': 224 self.window().setStatusIcon('yellow') 225 elif self.tableWidgetConnectionCount.rowCount() == 0 and state.statusIconColor != "red": 226 self.window().setStatusIcon('red') 227 228 # timer driven 229 def runEveryTwoSeconds(self): 230 """Updates counters, runs every 2 seconds if the timer is running""" 231 self.labelLookupsPerSecond.setText(_translate("networkstatus", "Inventory lookups per second: %1").arg( 232 str(state.Inventory.numberOfInventoryLookupsPerformed / 2))) 233 state.Inventory.numberOfInventoryLookupsPerformed = 0 234 self.updateNumberOfBytes() 235 self.updateNumberOfObjectsToBeSynced() 236 237 def retranslateUi(self): 238 """Conventional Qt Designer method for dynamic l10n""" 239 super(NetworkStatus, self).retranslateUi() 240 self.labelTotalConnections.setText( 241 _translate( 242 "networkstatus", "Total Connections: %1").arg( 243 str(self.tableWidgetConnectionCount.rowCount()))) 244 self.labelStartupTime.setText(_translate( 245 "networkstatus", "Since startup on %1" 246 ).arg(l10n.formatTimestamp(self.startup))) 247 self.updateNumberOfMessagesProcessed() 248 self.updateNumberOfBroadcastsProcessed() 249 self.updateNumberOfPubkeysProcessed()