From 8081c7804e12da232cd06aedee7c91995263d643 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Thu, 15 Dec 2022 23:30:23 +0100 Subject: [PATCH] Add monitor non interactive mode and add traffic counter for tunnel proxy --- .../tunnelproxy/tunnelproxyserver.cpp | 9 +- monitor/main.cpp | 15 ++- monitor/monitor.pro | 5 +- monitor/noninteractivemonitor.cpp | 101 ++++++++++++++++++ monitor/noninteractivemonitor.h | 48 +++++++++ monitor/terminalwindow.cpp | 56 +++------- monitor/terminalwindow.h | 3 - monitor/utils.h | 65 +++++++++++ 8 files changed, 253 insertions(+), 49 deletions(-) create mode 100644 monitor/noninteractivemonitor.cpp create mode 100644 monitor/noninteractivemonitor.h create mode 100644 monitor/utils.h diff --git a/libnymea-remoteproxy/tunnelproxy/tunnelproxyserver.cpp b/libnymea-remoteproxy/tunnelproxy/tunnelproxyserver.cpp index 54d6613..252a81b 100644 --- a/libnymea-remoteproxy/tunnelproxy/tunnelproxyserver.cpp +++ b/libnymea-remoteproxy/tunnelproxy/tunnelproxyserver.cpp @@ -328,6 +328,7 @@ void TunnelProxyServer::onClientDataAvailable(const QUuid &clientId, const QByte } qCDebug(dcTunnelProxyServerTraffic()) << "Client data available" << tunnelProxyClient << qUtf8Printable(data); + tunnelProxyClient->addRxDataCount(data.count()); if (tunnelProxyClient->type() == TunnelProxyClient::TypeClient) { // Send the data to the server using slip encoded frame @@ -344,8 +345,11 @@ void TunnelProxyServer::onClientDataAvailable(const QUuid &clientId, const QByte frame.socketAddress = clientConnection->socketAddress(); frame.data = data; qCDebug(dcTunnelProxyServerTraffic()) << "--> Tunnel data to server socket address" << clientConnection->socketAddress() << "to" << clientConnection->serverConnection() << "\n" << data; - clientConnection->serverConnection()->transportClient()->sendData(SlipDataProcessor::serializeData(SlipDataProcessor::buildFrame(frame))); + QByteArray rawData = SlipDataProcessor::serializeData(SlipDataProcessor::buildFrame(frame)); + clientConnection->serverConnection()->transportClient()->sendData(rawData); + clientConnection->serverConnection()->transportClient()->addTxDataCount(rawData.count()); m_troughputCounter += data.count(); + } else if (tunnelProxyClient->type() == TunnelProxyClient::TypeServer) { // Data coming from a connected server connection if (tunnelProxyClient->slipEnabled()) { @@ -376,7 +380,8 @@ void TunnelProxyServer::onClientDataAvailable(const QUuid &clientId, const QByte qCDebug(dcTunnelProxyServerTraffic()) << "--> Tunnel data from server socket" << frame.socketAddress << "to" << clientConnection << "\n" << frame.data; clientConnection->transportClient()->sendData(frame.data); - m_troughputCounter += data.count(); + clientConnection->transportClient()->addTxDataCount(frame.data.count()); + m_troughputCounter += frame.data.count(); } } } else { diff --git a/monitor/main.cpp b/monitor/main.cpp index d2363ed..8e582e7 100644 --- a/monitor/main.cpp +++ b/monitor/main.cpp @@ -1,6 +1,6 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* Copyright 2013 - 2020, nymea GmbH +* Copyright 2013 - 2022, nymea GmbH * Contact: contact@nymea.io * * This file is part of nymea. @@ -33,6 +33,7 @@ #include #include "monitor.h" +#include "noninteractivemonitor.h" #include "../version.h" int main(int argc, char *argv[]) @@ -58,6 +59,10 @@ int main(int argc, char *argv[]) QCommandLineOption socketOption(QStringList() << "s" << "socket", "The socket descriptor for the nymea-remoteproxy monitor socket. Default is /tmp/nymea-remoteproxy-monitor.sock", "socket"); socketOption.setDefaultValue("/tmp/nymea-remoteproxy-monitor.sock"); parser.addOption(socketOption); + + QCommandLineOption noninteractiveOption(QStringList() << "n" << "non-interactive", "Connect to the server, list all data and close the connection. This works only for the tunnelproxy."); + parser.addOption(noninteractiveOption); + parser.process(application); // Check socket file @@ -72,7 +77,13 @@ int main(int argc, char *argv[]) exit(1); } - Monitor monitor(parser.value(socketOption)); + if (parser.isSet(noninteractiveOption)) { + NonInteractiveMonitor *monitor = new NonInteractiveMonitor(parser.value(socketOption)); + Q_UNUSED(monitor); + } else { + Monitor *monitor = new Monitor(parser.value(socketOption)); + Q_UNUSED(monitor); + } return application.exec(); } diff --git a/monitor/monitor.pro b/monitor/monitor.pro index 983cb61..3212436 100644 --- a/monitor/monitor.pro +++ b/monitor/monitor.pro @@ -5,11 +5,14 @@ TEMPLATE = app HEADERS += \ monitorclient.h \ + noninteractivemonitor.h \ terminalwindow.h \ - monitor.h + monitor.h \ + utils.h SOURCES += main.cpp \ monitorclient.cpp \ + noninteractivemonitor.cpp \ terminalwindow.cpp \ monitor.cpp diff --git a/monitor/noninteractivemonitor.cpp b/monitor/noninteractivemonitor.cpp new file mode 100644 index 0000000..4766373 --- /dev/null +++ b/monitor/noninteractivemonitor.cpp @@ -0,0 +1,101 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2022, nymea GmbH +* Contact: contact@nymea.io +* +* This file is part of nymea. +* This project including source code and documentation is protected by copyright law, and +* remains the property of nymea GmbH. All rights, including reproduction, publication, +* editing and translation, are reserved. The use of this project is subject to the terms of a +* license agreement to be concluded with nymea GmbH in accordance with the terms +* of use of nymea GmbH, available under https://nymea.io/license +* +* GNU General Public License Usage +* Alternatively, this project may be redistributed and/or modified under +* the terms of the GNU General Public License as published by the Free Software Foundation, +* GNU version 3. this project is distributed in the hope that it will be useful, but WITHOUT ANY +* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +* PURPOSE. See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this project. +* If not, see . +* +* For any further details and any questions please contact us under contact@nymea.io +* or see our FAQ/Licensing Information on https://nymea.io/license/faq +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "noninteractivemonitor.h" +#include "utils.h" + +#include + +NonInteractiveMonitor::NonInteractiveMonitor(const QString &serverName, QObject *parent) + : QObject{parent} +{ + m_monitorClient = new MonitorClient(serverName, this); + connect(m_monitorClient, &MonitorClient::connected, this, &NonInteractiveMonitor::onConnected); + + m_monitorClient->connectMonitor(); +} + +void NonInteractiveMonitor::onConnected() +{ + connect(m_monitorClient, &MonitorClient::dataReady, this, [](const QVariantMap &dataMap){ + qInfo().noquote() << "---------------------------------------------------------------------"; + qInfo().noquote() << "Server name:" << dataMap.value("serverName", "-").toString(); + qInfo().noquote() << "Server version:" << dataMap.value("serverVersion", "-").toString(); + qInfo().noquote() << "API version:" << dataMap.value("apiVersion", "-").toString(); + qInfo().noquote() << "Total client count:" << dataMap.value("tunnelProxyStatistic").toMap().value("totalClientCount", 0).toInt(); + qInfo().noquote() << "Server connections:" << dataMap.value("tunnelProxyStatistic").toMap().value("serverConnectionsCount", 0).toInt(); + qInfo().noquote() << "Client connections:" << dataMap.value("tunnelProxyStatistic").toMap().value("clientConnectionsCount", 0).toInt(); + qInfo().noquote() << "Data troughput:" << Utils::humanReadableTraffic(dataMap.value("tunnelProxyStatistic").toMap().value("troughput", 0).toInt()) + " / s"; + qInfo().noquote() << "---------------------------------------------------------------------"; + + QVariantMap tunnelProxyMap = dataMap.value("tunnelProxyStatistic").toMap(); + foreach (const QVariant &serverVariant, tunnelProxyMap.value("tunnelConnections").toList()) { + QVariantMap serverMap = serverVariant.toMap(); + QVariantList clientList = serverMap.value("clientConnections").toList(); + + // Server line + QString serverConnectionTime = QDateTime::fromTime_t(serverMap.value("timestamp").toUInt()).toString("dd.MM.yyyy hh:mm:ss"); + QString serverLinePrint; + if (clientList.isEmpty()) { + serverLinePrint.prepend("├──"); + } else { + serverLinePrint.prepend("├┬─"); + } + + serverLinePrint += QString("%1 | %2 RX: %3 TX: %4 | %5") + .arg(serverConnectionTime) + .arg(serverMap.value("address").toString(), - 15) + .arg(Utils::humanReadableTraffic(serverMap.value("rxDataCount").toInt()), - 9) + .arg(Utils::humanReadableTraffic(serverMap.value("txDataCount").toInt()), - 9) + .arg(serverMap.value("name").toString()); + + qInfo().noquote() << serverLinePrint; + + for (int cc = 0; cc < clientList.count(); cc++) { + QVariantMap clientMap = clientList.at(cc).toMap(); + QString clientLinePrint; + if (cc >= clientList.count() - 1) { + clientLinePrint.append("│└─"); + } else { + clientLinePrint.prepend("│├─"); + } + + clientLinePrint += QString("%1 | %2 RX: %3 TX: %4 | %5") + .arg(QDateTime::fromTime_t(clientMap.value("timestamp").toUInt()).toString("dd.MM.yyyy hh:mm:ss")) + .arg(clientMap.value("address").toString(), - 15) + .arg(Utils::humanReadableTraffic(serverMap.value("rxDataCount").toInt()), - 9) + .arg(Utils::humanReadableTraffic(serverMap.value("txDataCount").toInt()), - 9) + .arg(clientMap.value("name").toString(), -30); + + qInfo().noquote() << clientLinePrint; + } + } + + exit(0); + }); + +} diff --git a/monitor/noninteractivemonitor.h b/monitor/noninteractivemonitor.h new file mode 100644 index 0000000..67191e2 --- /dev/null +++ b/monitor/noninteractivemonitor.h @@ -0,0 +1,48 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2022, nymea GmbH +* Contact: contact@nymea.io +* +* This file is part of nymea. +* This project including source code and documentation is protected by copyright law, and +* remains the property of nymea GmbH. All rights, including reproduction, publication, +* editing and translation, are reserved. The use of this project is subject to the terms of a +* license agreement to be concluded with nymea GmbH in accordance with the terms +* of use of nymea GmbH, available under https://nymea.io/license +* +* GNU General Public License Usage +* Alternatively, this project may be redistributed and/or modified under +* the terms of the GNU General Public License as published by the Free Software Foundation, +* GNU version 3. this project is distributed in the hope that it will be useful, but WITHOUT ANY +* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +* PURPOSE. See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this project. +* If not, see . +* +* For any further details and any questions please contact us under contact@nymea.io +* or see our FAQ/Licensing Information on https://nymea.io/license/faq +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef NONINTERACTIVEMONITOR_H +#define NONINTERACTIVEMONITOR_H + +#include +#include "monitorclient.h" + +class NonInteractiveMonitor : public QObject +{ + Q_OBJECT +public: + explicit NonInteractiveMonitor(const QString &serverName, QObject *parent = nullptr); + +private: + MonitorClient *m_monitorClient = nullptr; + +private slots: + void onConnected(); + +}; + +#endif // NONINTERACTIVEMONITOR_H diff --git a/monitor/terminalwindow.cpp b/monitor/terminalwindow.cpp index 76a7063..c959abd 100644 --- a/monitor/terminalwindow.cpp +++ b/monitor/terminalwindow.cpp @@ -26,6 +26,7 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "terminalwindow.h" +#include "utils.h" #include #include @@ -95,33 +96,6 @@ TerminalWindow::~TerminalWindow() cleanup(); } -QString TerminalWindow::getDurationString(uint timestamp) -{ - uint duration = QDateTime::currentDateTimeUtc().toTime_t() - timestamp; - int seconds = static_cast(duration % 60); - duration /= 60; - int minutes = static_cast(duration % 60); - duration /= 60; - int hours = static_cast(duration % 24); - return QString::asprintf("%02d:%02d:%02d", hours, minutes, seconds); -} - -QString TerminalWindow::humanReadableTraffic(int bytes) -{ - double dataCount = bytes; - QStringList list; - list << "KB" << "MB" << "GB" << "TB"; - - QStringListIterator i(list); - QString unit("B"); - - while(dataCount >= 1024.0 && i.hasNext()) { - unit = i.next(); - dataCount /= 1024.0; - } - return QString().setNum(dataCount,'f',2) + " " + unit; -} - void TerminalWindow::resizeWindow() { int terminalSizeX; @@ -196,8 +170,8 @@ void TerminalWindow::paintHeader() .arg(m_dataMap.value("proxyStatistic").toMap().value("total").toMap().value("totalClientCount").toInt()) .arg(m_dataMap.value("proxyStatistic").toMap().value("tunnelCount", 0).toInt()) .arg(m_dataMap.value("proxyStatistic").toMap().value("total").toMap().value("totalTunnelCount").toInt()) - .arg(humanReadableTraffic(m_dataMap.value("proxyStatistic").toMap().value("troughput", 0).toInt()) + " / s", - 13) - .arg(humanReadableTraffic(m_dataMap.value("proxyStatistic").toMap().value("total").toMap().value("totalTraffic").toInt()), - 10) + .arg(Utils::humanReadableTraffic(m_dataMap.value("proxyStatistic").toMap().value("troughput", 0).toInt()) + " / s", - 13) + .arg(Utils::humanReadableTraffic(m_dataMap.value("proxyStatistic").toMap().value("total").toMap().value("totalTraffic").toInt()), - 10) .arg(windowName); break; case ViewTunnels: @@ -210,8 +184,8 @@ void TerminalWindow::paintHeader() .arg(m_dataMap.value("proxyStatistic").toMap().value("total").toMap().value("totalClientCount").toInt()) .arg(m_dataMap.value("proxyStatistic").toMap().value("tunnelCount", 0).toInt()) .arg(m_dataMap.value("proxyStatistic").toMap().value("total").toMap().value("totalTunnelCount").toInt()) - .arg(humanReadableTraffic(m_dataMap.value("proxyStatistic").toMap().value("troughput", 0).toInt()) + " / s", - 13) - .arg(humanReadableTraffic(m_dataMap.value("proxyStatistic").toMap().value("total").toMap().value("totalTraffic").toInt()), - 10) + .arg(Utils::humanReadableTraffic(m_dataMap.value("proxyStatistic").toMap().value("troughput", 0).toInt()) + " / s", - 13) + .arg(Utils::humanReadableTraffic(m_dataMap.value("proxyStatistic").toMap().value("total").toMap().value("totalTraffic").toInt()), - 10) .arg(windowName); break; case ViewTunnelProxy: @@ -223,7 +197,7 @@ void TerminalWindow::paintHeader() .arg(m_dataMap.value("tunnelProxyStatistic").toMap().value("totalClientCount", 0).toInt()) .arg(m_dataMap.value("tunnelProxyStatistic").toMap().value("serverConnectionsCount", 0).toInt()) .arg(m_dataMap.value("tunnelProxyStatistic").toMap().value("clientConnectionsCount", 0).toInt()) - .arg(humanReadableTraffic(m_dataMap.value("tunnelProxyStatistic").toMap().value("troughput", 0).toInt()) + " / s", - 13) + .arg(Utils::humanReadableTraffic(m_dataMap.value("tunnelProxyStatistic").toMap().value("troughput", 0).toInt()) + " / s", - 13) .arg(windowName); break; } @@ -258,8 +232,8 @@ void TerminalWindow::paintContentClients() .arg(clientConnectionTime) .arg(clientMap.value("duration").toString()) .arg(clientMap.value("address").toString(), - 16) - .arg(humanReadableTraffic(rxDataCountBytes), - 10) - .arg(humanReadableTraffic(txDataCountBytes), - 10) + .arg(Utils::humanReadableTraffic(rxDataCountBytes), - 10) + .arg(Utils::humanReadableTraffic(txDataCountBytes), - 10) .arg((clientMap.value("authenticated").toBool() ? "A" : "-")) .arg((clientMap.value("tunnelConnected").toBool() ? "T" : "-")) .arg(clientMap.value("name").toString(), -30); @@ -284,8 +258,8 @@ void TerminalWindow::paintContentTunnels() QString tunnelPrint = QString("%1 | %2 | %3 | %4 | %5 (%6) <---> %7 (%8)") .arg(tunnelConnectionTime) - .arg(getDurationString(timeStamp)) - .arg(humanReadableTraffic(clientOne.value("rxDataCount").toInt() + clientOne.value("txDataCount").toInt()), - 10) + .arg(Utils::getDurationString(timeStamp)) + .arg(Utils::humanReadableTraffic(clientOne.value("rxDataCount").toInt() + clientOne.value("txDataCount").toInt()), - 10) .arg(clientOne.value("userName").toString()) .arg(clientOne.value("name").toString()) .arg(clientOne.value("address").toString()) @@ -312,8 +286,8 @@ void TerminalWindow::paintContentTunnelProxy() QString serverLinePrint = QString("%1 | %2 | RX: %3 | TX: %4 | %5") .arg(serverConnectionTime) .arg(serverMap.value("address").toString(), - 16) - .arg(humanReadableTraffic(rxDataCountBytes), - 10) - .arg(humanReadableTraffic(txDataCountBytes), - 10) + .arg(Utils::humanReadableTraffic(rxDataCountBytes), - 10) + .arg(Utils::humanReadableTraffic(txDataCountBytes), - 10) .arg(serverMap.value("name").toString(), -30); QVariantList clientList = serverMap.value("clientConnections").toList(); @@ -343,8 +317,8 @@ void TerminalWindow::paintContentTunnelProxy() QString clientLinePrint = QString("%1 | %2 | RX: %3 | TX: %4 | %5") .arg(QDateTime::fromTime_t(clientMap.value("timestamp").toUInt()).toString("dd.MM.yyyy hh:mm:ss")) .arg(clientMap.value("address").toString(), - 16) - .arg(humanReadableTraffic(clientMap.value("rxDataCount").toInt()), - 10) - .arg(humanReadableTraffic(clientMap.value("txDataCount").toInt()), - 10) + .arg(Utils::humanReadableTraffic(clientMap.value("rxDataCount").toInt()), - 10) + .arg(Utils::humanReadableTraffic(clientMap.value("txDataCount").toInt()), - 10) .arg(clientMap.value("name").toString(), -30); mvwprintw(m_contentWindow, i, 6, "%s", clientLinePrint.trimmed().toLatin1().constData()); @@ -437,7 +411,7 @@ void TerminalWindow::refreshWindow(const QVariantMap &dataMap) foreach (const QVariant &clientVariant, statisticMap.value("clients").toList()) { QVariantMap clientMap = clientVariant.toMap(); - clientMap.insert("duration", getDurationString(clientMap.value("timestamp").toUInt())); + clientMap.insert("duration", Utils::getDurationString(clientMap.value("timestamp").toUInt())); m_clientHash.insert(clientMap.value("id").toString(), clientMap); } } diff --git a/monitor/terminalwindow.h b/monitor/terminalwindow.h index 87fec51..96509e7 100644 --- a/monitor/terminalwindow.h +++ b/monitor/terminalwindow.h @@ -68,9 +68,6 @@ private: QVariantMap m_dataMap; QHash m_clientHash; - QString getDurationString(uint timestamp); - - QString humanReadableTraffic(int bytes); // content paint methods void resizeWindow(); diff --git a/monitor/utils.h b/monitor/utils.h new file mode 100644 index 0000000..bf080f7 --- /dev/null +++ b/monitor/utils.h @@ -0,0 +1,65 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2022, nymea GmbH +* Contact: contact@nymea.io +* +* This file is part of nymea. +* This project including source code and documentation is protected by copyright law, and +* remains the property of nymea GmbH. All rights, including reproduction, publication, +* editing and translation, are reserved. The use of this project is subject to the terms of a +* license agreement to be concluded with nymea GmbH in accordance with the terms +* of use of nymea GmbH, available under https://nymea.io/license +* +* GNU General Public License Usage +* Alternatively, this project may be redistributed and/or modified under +* the terms of the GNU General Public License as published by the Free Software Foundation, +* GNU version 3. this project is distributed in the hope that it will be useful, but WITHOUT ANY +* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +* PURPOSE. See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this project. +* If not, see . +* +* For any further details and any questions please contact us under contact@nymea.io +* or see our FAQ/Licensing Information on https://nymea.io/license/faq +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef UTILS_H +#define UTILS_H + +#include +#include + +class Utils { + +public: + Utils() = default; + + inline static QString getDurationString(uint timestamp) { + uint duration = QDateTime::currentDateTimeUtc().toTime_t() - timestamp; + int seconds = static_cast(duration % 60); + duration /= 60; + int minutes = static_cast(duration % 60); + duration /= 60; + int hours = static_cast(duration % 24); + return QString::asprintf("%02d:%02d:%02d", hours, minutes, seconds); + } + + inline static QString humanReadableTraffic(int bytes) { + double dataCount = bytes; + QStringList list; + list << "KB" << "MB" << "GB" << "TB"; + + QStringListIterator i(list); + QString unit("B"); + + while(dataCount >= 1024.0 && i.hasNext()) { + unit = i.next(); + dataCount /= 1024.0; + } + return QString().setNum(dataCount,'f',2) + " " + unit; + } +}; + +#endif // UTILS_H