10 import collections |
10 import collections |
11 import contextlib |
11 import contextlib |
12 import copy |
12 import copy |
13 import os |
13 import os |
14 |
14 |
15 from PyQt6.QtCore import QFileInfo, QPoint, Qt, QTimer, pyqtSlot |
15 from PyQt6.QtCore import QFileInfo, QLocale, QPoint, Qt, QTimer, pyqtSlot |
16 from PyQt6.QtGui import QBrush, QColor, QFont, QTextCursor |
16 from PyQt6.QtGui import QBrush, QColor, QFont, QTextCursor |
17 from PyQt6.QtWidgets import QDialog, QMenu, QWidget |
17 from PyQt6.QtWidgets import QDialog, QMenu, QWidget |
18 |
18 |
19 from eric7 import Utilities |
19 from eric7 import Utilities |
20 |
20 |
243 prefix + "load/publish/received": self.loadPublishReceivedLabel, |
243 prefix + "load/publish/received": self.loadPublishReceivedLabel, |
244 prefix + "load/publish/dropped": self.loadPublishDroppedLabel, |
244 prefix + "load/publish/dropped": self.loadPublishDroppedLabel, |
245 prefix + "load/connections": self.loadConnectionsLabel, |
245 prefix + "load/connections": self.loadConnectionsLabel, |
246 prefix + "load/sockets": self.loadSocketsLabel, |
246 prefix + "load/sockets": self.loadSocketsLabel, |
247 } |
247 } |
|
248 self.__statusFormatMapping = { |
|
249 # broker |
|
250 prefix + "version": None, |
|
251 prefix + "timestamp": None, |
|
252 prefix + "uptime": self.__formatUptime, |
|
253 prefix + "subscriptions/count": self.__formatInt, |
|
254 # clients |
|
255 prefix + "clients/connected": self.__formatInt, |
|
256 prefix + "clients/disconnected": self.__formatInt, |
|
257 prefix + "clients/expired": self.__formatInt, |
|
258 prefix + "clients/maximum": self.__formatInt, |
|
259 prefix + "clients/total": self.__formatInt, |
|
260 # messages |
|
261 prefix + "messages/sent": self.__formatInt, |
|
262 prefix + "messages/received": self.__formatInt, |
|
263 prefix + "messages/stored": self.__formatInt, |
|
264 prefix + "store/messages/count": self.__formatInt, |
|
265 prefix + "messages/inflight": self.__formatInt, |
|
266 prefix + "retained messages/count": self.__formatInt, |
|
267 # publish messages |
|
268 prefix + "publish/messages/sent": self.__formatInt, |
|
269 prefix + "publish/messages/received": self.__formatInt, |
|
270 prefix + "publish/messages/dropped": self.__formatInt, |
|
271 # traffic |
|
272 prefix + "bytes/sent": self.__formatData, |
|
273 prefix + "bytes/received": self.__formatData, |
|
274 # load |
|
275 prefix + "load/bytes/sent": self.__formatFloat, |
|
276 prefix + "load/bytes/received": self.__formatFloat, |
|
277 prefix + "load/messages/sent": self.__formatFloat, |
|
278 prefix + "load/messages/received": self.__formatFloat, |
|
279 prefix + "load/publish/sent": self.__formatFloat, |
|
280 prefix + "load/publish/received": self.__formatFloat, |
|
281 prefix + "load/publish/dropped": self.__formatFloat, |
|
282 prefix + "load/connections": self.__formatFloat, |
|
283 prefix + "load/sockets": self.__formatFloat, |
|
284 } |
248 |
285 |
249 self.__statusLoadValues = collections.defaultdict(self.__loadDefaultDictFactory) |
286 self.__statusLoadValues = collections.defaultdict(self.__loadDefaultDictFactory) |
|
287 self.__statusLocale = QLocale() |
250 |
288 |
251 def __createClient(self, clientId="", cleanSession=None, protocol=None): |
289 def __createClient(self, clientId="", cleanSession=None, protocol=None): |
252 """ |
290 """ |
253 Private method to instantiate a MQTT client for a given protocol. |
291 Private method to instantiate a MQTT client for a given protocol. |
254 |
292 |
644 def on_brokerConnectionOptionsButton_clicked(self): |
682 def on_brokerConnectionOptionsButton_clicked(self): |
645 """ |
683 """ |
646 Private slot to show a dialog to modify connection options or a |
684 Private slot to show a dialog to modify connection options or a |
647 dialog to edit connection profiles. |
685 dialog to edit connection profiles. |
648 """ |
686 """ |
|
687 from .MqttConnectionProfilesDialog import MqttConnectionProfilesDialog |
|
688 from .MqttConnectionOptionsDialog import MqttConnectionOptionsDialog |
|
689 |
649 if self.__connectionModeProfile: |
690 if self.__connectionModeProfile: |
650 from .MqttConnectionProfilesDialog import MqttConnectionProfilesDialog |
|
651 |
|
652 profileName = self.profileComboBox.currentText() |
691 profileName = self.profileComboBox.currentText() |
653 dlg = MqttConnectionProfilesDialog( |
692 dlg = MqttConnectionProfilesDialog( |
654 self.__plugin.getPreferences("BrokerProfiles"), |
693 self.__plugin.getPreferences("BrokerProfiles"), |
655 currentProfile=profileName, |
694 currentProfile=profileName, |
656 parent=self, |
695 parent=self, |
658 if dlg.exec() == QDialog.DialogCode.Accepted: |
697 if dlg.exec() == QDialog.DialogCode.Accepted: |
659 profilesDict = dlg.getProfiles() |
698 profilesDict = dlg.getProfiles() |
660 self.__plugin.setPreferences("BrokerProfiles", profilesDict) |
699 self.__plugin.setPreferences("BrokerProfiles", profilesDict) |
661 self.__populateProfileComboBox() |
700 self.__populateProfileComboBox() |
662 else: |
701 else: |
663 from .MqttConnectionOptionsDialog import MqttConnectionOptionsDialog |
|
664 |
|
665 dlg = MqttConnectionOptionsDialog(self.__connectionOptions, parent=self) |
702 dlg = MqttConnectionOptionsDialog(self.__connectionOptions, parent=self) |
666 if dlg.exec() == QDialog.DialogCode.Accepted: |
703 if dlg.exec() == QDialog.DialogCode.Accepted: |
667 self.__connectionOptions = dlg.getConnectionOptions() |
704 self.__connectionOptions = dlg.getConnectionOptions() |
668 if self.__connectionOptions["TlsEnable"]: |
705 if self.__connectionOptions["TlsEnable"]: |
669 port = self.brokerPortComboBox.currentText().strip() |
706 port = self.brokerPortComboBox.currentText().strip() |
1274 if topic.startswith(MqttMonitorWidget.BrokerStatusTopicLoadPrefix): |
1311 if topic.startswith(MqttMonitorWidget.BrokerStatusTopicLoadPrefix): |
1275 self.__handleBrokerLoadStatusMessage(topic, payloadStr) |
1312 self.__handleBrokerLoadStatusMessage(topic, payloadStr) |
1276 else: |
1313 else: |
1277 with contextlib.suppress(KeyError): |
1314 with contextlib.suppress(KeyError): |
1278 label = self.__statusLabelMapping[topic] |
1315 label = self.__statusLabelMapping[topic] |
1279 label.setText(payloadStr) |
1316 label.setText(self.__formatBrokerStatusValue(topic, payloadStr)) |
1280 |
1317 |
1281 def __handleBrokerLoadStatusMessage(self, topic, payloadStr): |
1318 def __handleBrokerLoadStatusMessage(self, topic, payloadStr): |
1282 """ |
1319 """ |
1283 Private method to append a received message to the output. |
1320 Private method to append a received message to the output. |
1284 |
1321 |
1293 |
1330 |
1294 with contextlib.suppress(KeyError): |
1331 with contextlib.suppress(KeyError): |
1295 label = self.__statusLabelMapping[subtopic] |
1332 label = self.__statusLabelMapping[subtopic] |
1296 label.setText( |
1333 label.setText( |
1297 "{0} / {1} / {2}".format( |
1334 "{0} / {1} / {2}".format( |
1298 self.__statusLoadValues[subtopic]["1min"], |
1335 self.__formatBrokerStatusValue( |
1299 self.__statusLoadValues[subtopic]["5min"], |
1336 subtopic, self.__statusLoadValues[subtopic]["1min"] |
1300 self.__statusLoadValues[subtopic]["15min"], |
1337 ), |
1301 ) |
1338 self.__formatBrokerStatusValue( |
1302 ) |
1339 subtopic, self.__statusLoadValues[subtopic]["5min"] |
|
1340 ), |
|
1341 self.__formatBrokerStatusValue( |
|
1342 subtopic, self.__statusLoadValues[subtopic]["15min"] |
|
1343 ), |
|
1344 ) |
|
1345 ) |
|
1346 |
|
1347 def __formatBrokerStatusValue(self, topic, value): |
|
1348 """ |
|
1349 Private method to format the value reported for a topic. |
|
1350 |
|
1351 @param topic topic name |
|
1352 @type str |
|
1353 @param value value of the topic |
|
1354 @type str |
|
1355 @return reformatted value string |
|
1356 @rtype str |
|
1357 """ |
|
1358 try: |
|
1359 formatFunc = self.__statusFormatMapping[topic] |
|
1360 if formatFunc is None: |
|
1361 return value |
|
1362 else: |
|
1363 return formatFunc(value) |
|
1364 except KeyError: |
|
1365 return value |
1303 |
1366 |
1304 def __clearBrokerStatusLabels(self): |
1367 def __clearBrokerStatusLabels(self): |
1305 """ |
1368 """ |
1306 Private method to clear the broker status labels. |
1369 Private method to clear the broker status labels. |
1307 """ |
1370 """ |
1506 properties = self.__plugin.getPreferences(preferencesKey) |
1569 properties = self.__plugin.getPreferences(preferencesKey) |
1507 dlg = MqttUserPropertiesEditorDialog(header, properties.get(key, []), self) |
1570 dlg = MqttUserPropertiesEditorDialog(header, properties.get(key, []), self) |
1508 if dlg.exec() == QDialog.DialogCode.Accepted: |
1571 if dlg.exec() == QDialog.DialogCode.Accepted: |
1509 properties[key] = dlg.getProperties() |
1572 properties[key] = dlg.getProperties() |
1510 self.__plugin.setPreferences(preferencesKey, properties) |
1573 self.__plugin.setPreferences(preferencesKey, properties) |
|
1574 |
|
1575 ####################################################################### |
|
1576 ## some helper methods below |
|
1577 ####################################################################### |
|
1578 |
|
1579 def __formatInt(self, valStr): |
|
1580 """ |
|
1581 Private method to format the uptime string. |
|
1582 |
|
1583 @param valStr string to be formatted |
|
1584 @type str |
|
1585 @return formatted string |
|
1586 @rtype str |
|
1587 """ |
|
1588 try: |
|
1589 val = int(valStr) |
|
1590 return self.__statusLocale.toString(val) |
|
1591 except ValueError: |
|
1592 return valStr |
|
1593 |
|
1594 def __formatFloat(self, valStr): |
|
1595 """ |
|
1596 Private method to format the uptime string. |
|
1597 |
|
1598 @param valStr string to be formatted |
|
1599 @type str |
|
1600 @return formatted string |
|
1601 @rtype str |
|
1602 """ |
|
1603 try: |
|
1604 val = float(valStr) |
|
1605 return self.__statusLocale.toString(val) |
|
1606 except ValueError: |
|
1607 return valStr |
|
1608 |
|
1609 def __formatUptime(self, valStr): |
|
1610 """ |
|
1611 Private method to format the uptime string. |
|
1612 |
|
1613 @param valStr string to be formatted |
|
1614 @type str |
|
1615 @return formatted string |
|
1616 @rtype str |
|
1617 """ |
|
1618 val, *suffix = valStr.split() |
|
1619 try: |
|
1620 val = int(val) |
|
1621 vloc = self.__statusLocale.toString(val) |
|
1622 if suffix: |
|
1623 return f"{vloc} {' '.join(suffix)}" |
|
1624 else: |
|
1625 return vloc |
|
1626 except ValueError: |
|
1627 return valStr |
|
1628 |
|
1629 def __formatData(self, valStr): |
|
1630 """ |
|
1631 Private method to format the uptime string. |
|
1632 |
|
1633 @param valStr string to be formatted |
|
1634 @type str |
|
1635 @return formatted string |
|
1636 @rtype str |
|
1637 """ |
|
1638 try: |
|
1639 size = int(valStr) |
|
1640 if size < 1024: |
|
1641 return self.tr("{0} Bytes").format( |
|
1642 self.__statusLocale.toString(size, "f", 2) |
|
1643 ) |
|
1644 elif size < 1024 * 1024: |
|
1645 size /= 1024 |
|
1646 return self.tr("{0} KiB").format( |
|
1647 self.__statusLocale.toString(size, "f", 2) |
|
1648 ) |
|
1649 elif size < 1024 * 1024 * 1024: |
|
1650 size /= 1024 * 1024 |
|
1651 return self.tr("{0} MiB").format( |
|
1652 self.__statusLocale.toString(size, "f", 2) |
|
1653 ) |
|
1654 elif size < 1024 * 1024 * 1024 * 1024: |
|
1655 size /= 1024 * 1024 * 1024 |
|
1656 return self.tr("{0} GiB").format( |
|
1657 self.__statusLocale.toString(size, "f", 2) |
|
1658 ) |
|
1659 else: |
|
1660 size /= 1024 * 1024 * 1024 * 1024 |
|
1661 return self.tr("{0} TiB").format( |
|
1662 self.__statusLocale.toString(size, "f", 2) |
|
1663 ) |
|
1664 except ValueError: |
|
1665 return valStr |