From 2173d8e61f6c1de19a51bd2387e2ff4e455f65a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Tue, 4 Sep 2018 21:02:30 +0200 Subject: [PATCH] Improve monitor and implement server statistics --- .../authentication/aws/awsauthenticator.cpp | 2 + .../dummy/dummyauthenticator.cpp | 2 + libnymea-remoteproxy/engine.cpp | 40 +++++++++++++- libnymea-remoteproxy/engine.h | 10 ++++ libnymea-remoteproxy/monitorserver.cpp | 44 ++++------------ libnymea-remoteproxy/monitorserver.h | 5 +- libnymea-remoteproxy/proxyclient.cpp | 31 +++++++++++ libnymea-remoteproxy/proxyclient.h | 14 +++++ libnymea-remoteproxy/proxyserver.cpp | 15 ++++++ libnymea-remoteproxy/proxyserver.h | 6 +++ monitor/terminalwindow.cpp | 52 +++++++++++++------ monitor/terminalwindow.h | 2 + 12 files changed, 168 insertions(+), 55 deletions(-) diff --git a/libnymea-remoteproxy/authentication/aws/awsauthenticator.cpp b/libnymea-remoteproxy/authentication/aws/awsauthenticator.cpp index eb737db..a04c53c 100644 --- a/libnymea-remoteproxy/authentication/aws/awsauthenticator.cpp +++ b/libnymea-remoteproxy/authentication/aws/awsauthenticator.cpp @@ -56,6 +56,8 @@ void AwsAuthenticator::onAuthenticationProcessFinished(Authenticator::Authentica qCDebug(dcAuthentication()) << name() << reply->proxyClient() << "finished with error" << error; } + reply->proxyClient()->setUserName(userInformation.email()); + setReplyError(reply, error); setReplyFinished(reply); } diff --git a/libnymea-remoteproxy/authentication/dummy/dummyauthenticator.cpp b/libnymea-remoteproxy/authentication/dummy/dummyauthenticator.cpp index 4d08ccb..ef73ce5 100644 --- a/libnymea-remoteproxy/authentication/dummy/dummyauthenticator.cpp +++ b/libnymea-remoteproxy/authentication/dummy/dummyauthenticator.cpp @@ -43,6 +43,8 @@ AuthenticationReply *DummyAuthenticator::authenticate(ProxyClient *proxyClient) qCWarning(dcAuthentication()) << "Attention: This authenticator will always succeed! This is a security risk and was explicitly enabled!"; AuthenticationReply *reply = createAuthenticationReply(proxyClient, this); + proxyClient->setUserName("dummy@example.com"); + setReplyError(reply, AuthenticationErrorNoError); setReplyFinished(reply); return reply; diff --git a/libnymea-remoteproxy/engine.cpp b/libnymea-remoteproxy/engine.cpp index 5f3013c..e369371 100644 --- a/libnymea-remoteproxy/engine.cpp +++ b/libnymea-remoteproxy/engine.cpp @@ -157,7 +157,13 @@ MonitorServer *Engine::monitorServer() const Engine::Engine(QObject *parent) : QObject(parent) { + m_lastTimeStamp = QDateTime::currentDateTime().toMSecsSinceEpoch(); + m_timer = new QTimer(this); + m_timer->setSingleShot(false); + m_timer->setInterval(50); + + connect(m_timer, &QTimer::timeout, this, &Engine::onTimerTick); } Engine::~Engine() @@ -165,6 +171,31 @@ Engine::~Engine() stop(); } +QVariantMap Engine::createServerStatistic() +{ + QVariantMap monitorData; + monitorData.insert("serverName", m_configuration->serverName()); + monitorData.insert("serverVersion", SERVER_VERSION_STRING); + monitorData.insert("apiVersion", API_VERSION_STRING); + monitorData.insert("proxyStatistic", proxyServer()->currentStatistics()); + return monitorData; +} + +void Engine::onTimerTick() +{ + qint64 timestamp = QDateTime::currentDateTime().toMSecsSinceEpoch(); + qint64 deltaTime = timestamp - m_lastTimeStamp; + m_lastTimeStamp = timestamp; + + m_currentTimeCounter += deltaTime; + if (m_currentTimeCounter >= 1000) { + // One second passed, do second tick + m_proxyServer->tick(); + m_monitorServer->updateClients(createServerStatistic()); + m_currentTimeCounter = 0; + } +} + void Engine::clean() { if (m_monitorServer) { @@ -195,9 +226,14 @@ void Engine::setRunning(bool running) if (m_running == running) return; - //qCDebug(dcEngine()) << "----------------------------------------------------------"; qCDebug(dcEngine()) << "Engine is" << (running ? "now running." : "not running any more."); - //qCDebug(dcEngine()) << "----------------------------------------------------------"; + + if (running) { + m_timer->start(); + } else { + m_timer->stop(); + } + m_running = running; emit runningChanged(m_running); } diff --git a/libnymea-remoteproxy/engine.h b/libnymea-remoteproxy/engine.h index d81d03f..d6d19fe 100644 --- a/libnymea-remoteproxy/engine.h +++ b/libnymea-remoteproxy/engine.h @@ -23,7 +23,9 @@ #define ENGINE_H #include +#include #include +#include #include #include @@ -66,6 +68,11 @@ private: ~Engine(); static Engine *s_instance; + QTimer *m_timer = nullptr; + qint64 m_lastTimeStamp = 0; + int m_currentTimeCounter = 0; + qint64 m_runTime = 0; + bool m_running = false; bool m_developerMode = false; @@ -75,10 +82,13 @@ private: WebSocketServer *m_webSocketServer = nullptr; MonitorServer *m_monitorServer = nullptr; + QVariantMap createServerStatistic(); + signals: void runningChanged(bool running); private slots: + void onTimerTick(); void clean(); void setRunning(bool running); diff --git a/libnymea-remoteproxy/monitorserver.cpp b/libnymea-remoteproxy/monitorserver.cpp index efa66f7..ceb572e 100644 --- a/libnymea-remoteproxy/monitorserver.cpp +++ b/libnymea-remoteproxy/monitorserver.cpp @@ -32,10 +32,7 @@ MonitorServer::MonitorServer(const QString &serverName, QObject *parent) : QObject(parent), m_serverName(serverName) { - m_timer = new QTimer(this); - m_timer->setInterval(1000); - m_timer->setSingleShot(false); - connect(m_timer, &QTimer::timeout, this, &MonitorServer::onTimeout); + } MonitorServer::~MonitorServer() @@ -51,36 +48,12 @@ bool MonitorServer::running() const return m_server->isListening(); } -QVariantMap MonitorServer::createMonitorData() -{ - QVariantMap monitorData; - monitorData.insert("serverName", Engine::instance()->configuration()->serverName()); - monitorData.insert("serverVersion", SERVER_VERSION_STRING); - monitorData.insert("apiVersion", API_VERSION_STRING); - monitorData.insert("proxyStatistic", Engine::instance()->proxyServer()->currentStatistics()); - return monitorData; -} - void MonitorServer::sendMonitorData(QLocalSocket *clientConnection, const QVariantMap &dataMap) { clientConnection->write(QJsonDocument::fromVariant(dataMap).toJson(QJsonDocument::Compact) + '\n'); clientConnection->flush(); } -void MonitorServer::onTimeout() -{ - // If no client left or no server running, stop the timer - if (m_clients.isEmpty() || !m_server) - m_timer->stop(); - - QVariantMap dataMap = createMonitorData(); - - // Send each monitor the current data - foreach (QLocalSocket *clientConnection, m_clients) { - sendMonitorData(clientConnection, dataMap); - } -} - void MonitorServer::onMonitorConnected() { QLocalSocket *clientConnection = m_server->nextPendingConnection(); @@ -89,12 +62,6 @@ void MonitorServer::onMonitorConnected() m_clients.append(clientConnection); qCDebug(dcMonitorServer()) << "New monitor connected."; - - if (!m_timer->isActive()) { - // Send the data right the way - onTimeout(); - m_timer->start(); - } } void MonitorServer::onMonitorDisconnected() @@ -131,7 +98,6 @@ void MonitorServer::startServer() void MonitorServer::stopServer() { - m_timer->stop(); if (!m_server) return; @@ -145,4 +111,12 @@ void MonitorServer::stopServer() m_server = nullptr; } +void MonitorServer::updateClients(const QVariantMap &dataMap) +{ + // Send each monitor the current data + foreach (QLocalSocket *clientConnection, m_clients) { + sendMonitorData(clientConnection, dataMap); + } +} + } diff --git a/libnymea-remoteproxy/monitorserver.h b/libnymea-remoteproxy/monitorserver.h index e65b6bb..2a0def0 100644 --- a/libnymea-remoteproxy/monitorserver.h +++ b/libnymea-remoteproxy/monitorserver.h @@ -41,20 +41,19 @@ public: private: QString m_serverName; QLocalServer *m_server = nullptr; - QTimer *m_timer = nullptr; QList m_clients; - QVariantMap createMonitorData(); void sendMonitorData(QLocalSocket *clientConnection, const QVariantMap &dataMap); private slots: - void onTimeout(); void onMonitorConnected(); void onMonitorDisconnected(); public slots: void startServer(); void stopServer(); + + void updateClients(const QVariantMap &dataMap); }; } diff --git a/libnymea-remoteproxy/proxyclient.cpp b/libnymea-remoteproxy/proxyclient.cpp index 81bbf08..ed9c854 100644 --- a/libnymea-remoteproxy/proxyclient.cpp +++ b/libnymea-remoteproxy/proxyclient.cpp @@ -88,6 +88,16 @@ void ProxyClient::setTunnelConnected(bool isTunnelConnected) } } +QString ProxyClient::userName() const +{ + return m_userName; +} + +void ProxyClient::setUserName(const QString &userName) +{ + m_userName = userName; +} + TransportInterface *ProxyClient::interface() const { return m_interface; @@ -133,6 +143,26 @@ void ProxyClient::setNonce(const QString &nonce) m_nonce = nonce; } +quint64 ProxyClient::rxDataCount() const +{ + return m_rxDataCount; +} + +void ProxyClient::addRxDataCount(int dataCount) +{ + m_rxDataCount += static_cast(dataCount); +} + +quint64 ProxyClient::txDataCount() const +{ + return m_txDataCount; +} + +void ProxyClient::addTxDataCount(int dataCount) +{ + m_txDataCount += static_cast(dataCount); +} + void ProxyClient::sendData(const QByteArray &data) { if (!m_interface) @@ -157,6 +187,7 @@ QDebug operator<<(QDebug debug, ProxyClient *proxyClient) } debug.nospace() << proxyClient->interface()->serverName(); debug.nospace() << ", " << proxyClient->clientId().toString(); + debug.nospace() << ", " << proxyClient->userName(); debug.nospace() << ", " << proxyClient->peerAddress().toString(); debug.nospace() << ", " << proxyClient->creationTimeString() << ") "; return debug; diff --git a/libnymea-remoteproxy/proxyclient.h b/libnymea-remoteproxy/proxyclient.h index 665562f..d09783e 100644 --- a/libnymea-remoteproxy/proxyclient.h +++ b/libnymea-remoteproxy/proxyclient.h @@ -51,6 +51,9 @@ public: bool isTunnelConnected() const; void setTunnelConnected(bool isTunnelConnected); + QString userName() const; + void setUserName(const QString &userName); + TransportInterface *interface() const; // Properties from auth request @@ -66,6 +69,12 @@ public: QString nonce() const; void setNonce(const QString &nonce); + quint64 rxDataCount() const; + void addRxDataCount(int dataCount); + + quint64 txDataCount() const; + void addTxDataCount(int dataCount); + // Actions for this client void sendData(const QByteArray &data); void killConnection(const QString &reason); @@ -86,6 +95,11 @@ private: QString m_token; QString m_nonce; + QString m_userName; + + quint64 m_rxDataCount = 0; + quint64 m_txDataCount = 0; + signals: void authenticated(); void tunnelConnected(); diff --git a/libnymea-remoteproxy/proxyserver.cpp b/libnymea-remoteproxy/proxyserver.cpp index f839d9b..9feae99 100644 --- a/libnymea-remoteproxy/proxyserver.cpp +++ b/libnymea-remoteproxy/proxyserver.cpp @@ -65,6 +65,7 @@ QVariantMap ProxyServer::currentStatistics() QVariantMap statisticsMap; statisticsMap.insert("clientCount", m_proxyClients.count()); statisticsMap.insert("tunnelCount", m_tunnels.count()); + statisticsMap.insert("troughput", m_troughput); // Create client list QVariantList clientList; @@ -76,7 +77,10 @@ QVariantMap ProxyServer::currentStatistics() clientMap.insert("authenticated", client->isAuthenticated()); clientMap.insert("tunnelConnected", client->isTunnelConnected()); clientMap.insert("name", client->name()); + clientMap.insert("userName", client->userName()); clientMap.insert("uuid", client->uuid()); + clientMap.insert("rxDataCount", client->rxDataCount()); + clientMap.insert("txDataCount", client->txDataCount()); clientList.append(clientMap); } statisticsMap.insert("clients", clientList); @@ -242,6 +246,11 @@ void ProxyServer::onClientDataAvailable(const QUuid &clientId, const QByteArray Q_ASSERT_X(remoteClient, "ProxyServer", "Tunnel existing but not tunnel client available"); Q_ASSERT_X(m_tunnels.contains(proxyClient->token()), "ProxyServer", "Tunnel connect but not existing"); + // Calculate server statisitcs + m_troughputCounter += data.count(); + proxyClient->addRxDataCount(data.count()); + remoteClient->addTxDataCount(data.count()); + qCDebug(dcProxyServerTraffic()) << "Pipe tunnel data:"; qCDebug(dcProxyServerTraffic()) << " --> from" << proxyClient; qCDebug(dcProxyServerTraffic()) << " --> to" << remoteClient; @@ -338,4 +347,10 @@ void ProxyServer::stopServer() setRunning(false); } +void ProxyServer::tick() +{ + m_troughput = m_troughputCounter; + m_troughputCounter = 0; +} + } diff --git a/libnymea-remoteproxy/proxyserver.h b/libnymea-remoteproxy/proxyserver.h index 9fb83aa..416b793 100644 --- a/libnymea-remoteproxy/proxyserver.h +++ b/libnymea-remoteproxy/proxyserver.h @@ -63,6 +63,10 @@ private: // Token, Tunnel QHash m_tunnels; + // Statistic measurments + int m_troughput = 0; + int m_troughputCounter = 0; + void setRunning(bool running); ProxyClient *getRemoteClient(ProxyClient *proxyClient); @@ -84,6 +88,8 @@ public slots: void startServer(); void stopServer(); + void tick(); + }; } diff --git a/monitor/terminalwindow.cpp b/monitor/terminalwindow.cpp index 6787a4a..1f4205f 100644 --- a/monitor/terminalwindow.cpp +++ b/monitor/terminalwindow.cpp @@ -105,6 +105,22 @@ QString TerminalWindow::getDurationString(uint timestamp) return res.sprintf("%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; @@ -146,12 +162,13 @@ void TerminalWindow::drawWindowBorder(WINDOW *window) void TerminalWindow::paintHeader() { - QString headerString = QString(" Server: %1 %2 | API version %3 | Clients: %4 | Tunnels %5 | %6 ") + QString headerString = QString(" Server: %1 %2 | API version %3 | Clients: %4 | Tunnels %5 | %6 | %7 ") .arg(m_dataMap.value("serverName", "-").toString()) .arg(m_dataMap.value("serverVersion", "-").toString()) .arg(m_dataMap.value("apiVersion", "-").toString()) .arg(m_dataMap.value("proxyStatistic").toMap().value("clientCount", 0).toInt()) .arg(m_dataMap.value("proxyStatistic").toMap().value("tunnelCount", 0).toInt()) + .arg(humanReadableTraffic(m_dataMap.value("proxyStatistic").toMap().value("troughput", 0).toInt()) + " / s", - 13) .arg((m_view == ViewClients ? "-- Clients --" : "-- Tunnels --")); int delta = m_terminalSizeX - headerString.count(); @@ -164,7 +181,6 @@ void TerminalWindow::paintHeader() wattron(m_headerWindow, A_BOLD | COLOR_PAIR(1)); mvwprintw(m_headerWindow, 1, 2, convertString(headerString)); wattroff(m_headerWindow, A_BOLD | COLOR_PAIR(1)); - drawWindowBorder(m_headerWindow); } void TerminalWindow::paintContentClients() @@ -179,11 +195,15 @@ void TerminalWindow::paintContentClients() uint timeStamp = clientMap.value("timestamp").toUInt(); QString clientConnectionTime = QDateTime::fromTime_t(timeStamp).toString("dd.MM.yyyy hh:mm:ss"); - QString clientPrint = QString("%1 | %2 | %3 | %4 | %5 | %6 | %7") + int rxDataCountBytes = clientMap.value("rxDataCount").toInt(); + int txDataCountBytes = clientMap.value("txDataCount").toInt(); + + QString clientPrint = QString("%1 | %2 | %3 | RX: %4 | TX: %5 | %6 | %7 | %8") .arg(clientConnectionTime) .arg(clientMap.value("duration").toString()) .arg(clientMap.value("address").toString(), - 16) - .arg(clientMap.value("uuid").toString()) + .arg(humanReadableTraffic(rxDataCountBytes), - 10) + .arg(humanReadableTraffic(txDataCountBytes), - 10) .arg((clientMap.value("authenticated").toBool() ? "A" : "-")) .arg((clientMap.value("tunnelConnected").toBool() ? "T" : "-")) .arg(clientMap.value("name").toString(), -30); @@ -192,8 +212,6 @@ void TerminalWindow::paintContentClients() i++; } - // Draw borders - drawWindowBorder(m_contentWindow); } void TerminalWindow::paintContentTunnels() @@ -209,21 +227,21 @@ void TerminalWindow::paintContentTunnels() uint timeStamp = tunnelMap.value("timestamp").toUInt(); QString tunnelConnectionTime = QDateTime::fromTime_t(timeStamp).toString("dd.MM.yyyy hh:mm:ss"); - QString tunnelPrint = QString("%1 | %2 %3 %4 %5 %6") + + QString tunnelPrint = QString("%1 | %2 | %3 | %4 | %5 (%6) <---> %7 (%8)") .arg(tunnelConnectionTime) - .arg(clientOne.value("address").toString(), - 16) + .arg(getDurationString(timeStamp)) + .arg(humanReadableTraffic(clientOne.value("rxDataCount").toInt() + clientOne.value("txDataCount").toInt()), - 10) + .arg(clientOne.value("userName").toString()) .arg(clientOne.value("name").toString()) - .arg(" <---> ") - .arg(clientTwo.value("address").toString(), - 16) + .arg(clientOne.value("address").toString()) .arg(clientTwo.value("name").toString()) + .arg(clientTwo.value("address").toString()) ; mvwprintw(m_contentWindow, i, 2, convertString(tunnelPrint)); i++; } - - // Draw borders - drawWindowBorder(m_contentWindow); } void TerminalWindow::eventLoop() @@ -232,7 +250,7 @@ void TerminalWindow::eventLoop() werase(m_headerWindow); werase(m_contentWindow); - resizeWindow(); + resizeWindow(); int keyInteger = getch(); switch (keyInteger) { @@ -268,9 +286,13 @@ void TerminalWindow::eventLoop() break; } + // Draw borders + drawWindowBorder(m_headerWindow); + drawWindowBorder(m_contentWindow); + wrefresh(m_headerWindow); wrefresh(m_contentWindow); - //refresh(); + refresh(); // Reinvoke the method for the next event loop run //QMetaObject::invokeMethod(this, "eventLoop", Qt::QueuedConnection); diff --git a/monitor/terminalwindow.h b/monitor/terminalwindow.h index aa59c8d..109347d 100644 --- a/monitor/terminalwindow.h +++ b/monitor/terminalwindow.h @@ -59,6 +59,8 @@ private: const char *convertString(const QString &string); QString getDurationString(uint timestamp); + QString humanReadableTraffic(int bytes); + // content paint methods void resizeWindow(); void drawWindowBorder(WINDOW *window);