From d308be58b31c57e85a47be8e9fc75ed878d29546 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Thu, 23 Aug 2018 10:02:08 +0200 Subject: [PATCH] Update monitor behaviour --- monitor/main.cpp | 14 ++++- monitor/monitor.cpp | 20 ++++++- monitor/monitor.h | 4 ++ monitor/monitorclient.cpp | 10 ++++ monitor/monitorclient.h | 4 ++ monitor/terminalwindow.cpp | 120 +++++++++++++++++++++++++++---------- monitor/terminalwindow.h | 3 + nymea-remoteproxy.pri | 2 +- 8 files changed, 139 insertions(+), 38 deletions(-) diff --git a/monitor/main.cpp b/monitor/main.cpp index 80e95c8..ff837f0 100644 --- a/monitor/main.cpp +++ b/monitor/main.cpp @@ -20,6 +20,7 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include +#include #include #include #include @@ -50,9 +51,20 @@ 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); - parser.process(application); + // Check socket file + QFileInfo fileInfo(parser.value(socketOption)); + if (!fileInfo.exists()) { + qWarning() << "Could not find socket descriptor" << fileInfo.canonicalFilePath(); + exit(1); + } + + if (!fileInfo.isReadable()) { + qWarning() << "Could not open socket descriptor" << fileInfo.canonicalFilePath(); + exit(1); + } + Monitor monitor(parser.value(socketOption)); return application.exec(); diff --git a/monitor/monitor.cpp b/monitor/monitor.cpp index ad20952..3e3b825 100644 --- a/monitor/monitor.cpp +++ b/monitor/monitor.cpp @@ -23,10 +23,24 @@ Monitor::Monitor(const QString &serverName, QObject *parent) : QObject(parent) { - m_terminal = new TerminalWindow(this); m_monitorClient = new MonitorClient(serverName, this); - - connect(m_monitorClient, &MonitorClient::dataReady, m_terminal, &TerminalWindow::refreshWindow); + connect(m_monitorClient, &MonitorClient::connected, this, &Monitor::onConnected); + connect(m_monitorClient, &MonitorClient::disconnected, this, &Monitor::onDisconnected); m_monitorClient->connectMonitor(); } + +void Monitor::onConnected() +{ + m_terminal = new TerminalWindow(this); + connect(m_monitorClient, &MonitorClient::dataReady, m_terminal, &TerminalWindow::refreshWindow); +} + +void Monitor::onDisconnected() +{ + if (!m_terminal) + return; + + m_terminal->deleteLater(); + m_terminal = nullptr; +} diff --git a/monitor/monitor.h b/monitor/monitor.h index ae93ff1..5d8f058 100644 --- a/monitor/monitor.h +++ b/monitor/monitor.h @@ -37,6 +37,10 @@ private: TerminalWindow *m_terminal = nullptr; MonitorClient *m_monitorClient = nullptr; +private slots: + void onConnected(); + void onDisconnected(); + }; #endif // MONITOR_H diff --git a/monitor/monitorclient.cpp b/monitor/monitorclient.cpp index 8da8313..f9034f3 100644 --- a/monitor/monitorclient.cpp +++ b/monitor/monitorclient.cpp @@ -32,16 +32,19 @@ MonitorClient::MonitorClient(const QString &serverName, QObject *parent) : connect(m_socket, &QLocalSocket::connected, this, &MonitorClient::onConnected); connect(m_socket, &QLocalSocket::disconnected, this, &MonitorClient::onDisconnected); connect(m_socket, &QLocalSocket::readyRead, this, &MonitorClient::onReadyRead); + connect(m_socket, SIGNAL(error(QLocalSocket::LocalSocketError)), this, SLOT(onErrorOccured(QLocalSocket::LocalSocketError))); } void MonitorClient::onConnected() { qDebug() << "Monitor connected to" << m_serverName; + emit connected(); } void MonitorClient::onDisconnected() { qDebug() << "Monitor disconnected from" << m_serverName; + emit disconnected(); } void MonitorClient::onReadyRead() @@ -62,6 +65,13 @@ void MonitorClient::onReadyRead() emit dataReady(dataMap); } +void MonitorClient::onErrorOccured(QLocalSocket::LocalSocketError socketError) +{ + Q_UNUSED(socketError) + qWarning() << "Local socket error occured" << m_socket->errorString(); + exit(1); +} + void MonitorClient::connectMonitor() { m_socket->connectToServer(m_serverName, QLocalSocket::ReadOnly); diff --git a/monitor/monitorclient.h b/monitor/monitorclient.h index ac8aede..7a49214 100644 --- a/monitor/monitorclient.h +++ b/monitor/monitorclient.h @@ -36,13 +36,17 @@ public: private: QString m_serverName; QLocalSocket *m_socket = nullptr; + signals: + void connected(); + void disconnected(); void dataReady(const QVariantMap &data); private slots: void onConnected(); void onDisconnected(); void onReadyRead(); + void onErrorOccured(QLocalSocket::LocalSocketError socketError); public slots: void connectMonitor(); diff --git a/monitor/terminalwindow.cpp b/monitor/terminalwindow.cpp index d5ac489..c7e1601 100644 --- a/monitor/terminalwindow.cpp +++ b/monitor/terminalwindow.cpp @@ -21,6 +21,7 @@ #include "terminalwindow.h" +#include #include #include #include @@ -30,40 +31,48 @@ TerminalWindow::TerminalWindow(QObject *parent) : { // Create main window m_mainWindow = initscr(); - start_color(); - init_pair(1, COLOR_BLACK, COLOR_GREEN); - init_pair(2, COLOR_BLACK, COLOR_RED); + // Enable colors if available + if (has_colors()) { + start_color(); + init_pair(1, COLOR_BLACK, COLOR_GREEN); + init_pair(2, COLOR_BLACK, COLOR_RED); + } // Configure behaviour cbreak(); noecho(); + nonl();; + nodelay(stdscr, TRUE); curs_set(FALSE); - //clear(); + clear(); keypad(m_mainWindow, true); nodelay(m_mainWindow, true); - getmaxyx(stdscr, m_terminalSizeY, m_terminalSizeX); + getmaxyx(m_mainWindow, m_terminalSizeY, m_terminalSizeX); + wrefresh(m_mainWindow); // Create header and content window m_headerWindow = newwin(m_headerHeight, m_terminalSizeX, 0, 0); m_contentWindow = newwin(m_terminalSizeY - m_headerHeight, m_terminalSizeX, m_headerHeight, 0); // Draw borders - wclear(m_headerWindow); - wclear(m_contentWindow); + werase(m_headerWindow); + werase(m_contentWindow); + drawWindowBorder(m_headerWindow); + drawWindowBorder(m_contentWindow); - mvwprintw(m_headerWindow, 1, 2, convertString("Connecting...")); - - box(m_headerWindow, 0 , 0); - box(m_contentWindow, 0 , 0); + //box(m_headerWindow, 0 , 0); + //box(m_contentWindow, 0 , 0); // Refresh windows wrefresh(m_headerWindow); wrefresh(m_contentWindow); refresh(); + + eventLoop(); } TerminalWindow::~TerminalWindow() @@ -80,6 +89,18 @@ const char *TerminalWindow::convertString(const QString &string) return reinterpret_cast(string.toLatin1().data()); } +QString TerminalWindow::getDurationString(uint timestamp) +{ + uint duration = QDateTime::currentDateTime().toTime_t() - timestamp; + QString res; + int seconds = static_cast(duration % 60); + duration /= 60; + int minutes = static_cast(duration % 60); + duration /= 60; + int hours = static_cast(duration % 24); + return res.sprintf("%02d:%02d:%02d", hours, minutes, seconds); +} + void TerminalWindow::resizeWindow() { int terminalSizeX; @@ -93,30 +114,61 @@ void TerminalWindow::resizeWindow() } } +void TerminalWindow::drawWindowBorder(WINDOW *window) +{ + int x, y, i; + getmaxyx(window, y, x); + + // corners + mvwprintw(window, 0, 0, "+"); + mvwprintw(window, y - 1, 0, "+"); + mvwprintw(window, 0, x - 1, "+"); + mvwprintw(window, y - 1, x - 1, "+"); + + // sides + for (i = 1; i < (y - 1); i++) { + mvwprintw(window, i, 0, "|"); + mvwprintw(window, i, x - 1, "|"); + } + + // top and bottom + for (i = 1; i < (x - 1); i++) { + mvwprintw(window, 0, i, "-"); + mvwprintw(window, y - 1, i, "-"); + } +} + void TerminalWindow::paintHeader() { - 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").toInt()) - .arg(m_dataMap.value("proxyStatistic").toMap().value("tunnelCount").toInt()) - .arg((m_view == ViewClients ? "Clients" : "Tunnels")) - .arg("", m_terminalSizeX, ' '); + QString headerString = QString(" Server: %1 %2 | API version %3 | Clients: %4 | Tunnels %5 | %6 ") + .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((m_view == ViewClients ? "-- Clients --" : "-- Tunnels --")); + + int delta = m_terminalSizeX - headerString.count(); + + // Fill string for background color + for (int i = 0; i < delta; i++) + headerString.append(" "); wclear(m_headerWindow); wattron(m_headerWindow, A_BOLD | COLOR_PAIR(1)); mvwprintw(m_headerWindow, 1, 2, convertString(headerString)); wattroff(m_headerWindow, A_BOLD | COLOR_PAIR(1)); - box(m_headerWindow, 0 , 0); + drawWindowBorder(m_headerWindow); wrefresh(m_headerWindow); } void TerminalWindow::paintContentClients() { - int i = 1; + if (m_clientHash.isEmpty()) + return; + int i = 1; wclear(m_contentWindow); foreach (const QVariant &clientVariant, m_clientHash.values()) { QVariantMap clientMap = clientVariant.toMap(); @@ -124,20 +176,21 @@ 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 |") + QString clientPrint = QString("%1 | %2 | %3 | %4 | %5 | %6 | %7") .arg(clientConnectionTime) + .arg(clientMap.value("duration").toString()) .arg(clientMap.value("address").toString()) .arg(clientMap.value("uuid").toString()) - .arg(clientMap.value("name").toString(), -30) - .arg((clientMap.value("authenticated").toBool() ? "auth" : "no auth"), -9) - .arg((clientMap.value("tunnelConnected").toBool() ? "<--->" : " | ")); + .arg((clientMap.value("authenticated").toBool() ? "A" : "-")) + .arg((clientMap.value("tunnelConnected").toBool() ? "T" : "-")) + .arg(clientMap.value("name").toString(), -30); - mvwprintw(m_contentWindow, i, 2, convertString(clientPrint)); + mvwprintw(m_contentWindow, i, 2, convertString(clientPrint.trimmed())); i++; } // Draw borders - box(m_contentWindow, 0 , 0); + drawWindowBorder(m_contentWindow); wrefresh(m_contentWindow); } @@ -159,7 +212,7 @@ void TerminalWindow::paintContentTunnels() .arg(tunnelConnectionTime) .arg(clientOne.value("address").toString()) .arg(clientOne.value("name").toString()) - .arg("<--->", 10) + .arg(" <---> ") .arg(clientTwo.value("address").toString()) .arg(clientTwo.value("name").toString()) ; @@ -169,7 +222,7 @@ void TerminalWindow::paintContentTunnels() } // Draw borders - box(m_contentWindow, 0 , 0); + drawWindowBorder(m_contentWindow); wrefresh(m_contentWindow); } @@ -191,6 +244,7 @@ void TerminalWindow::eventLoop() delwin(m_contentWindow); delwin(m_mainWindow); endwin(); + qDebug() << "Closing window monitor. Have a nice day!"; exit(0); break; default: @@ -213,10 +267,10 @@ void TerminalWindow::eventLoop() refresh(); // Reinvoke the method for the next event loop run - QMetaObject::invokeMethod(this, "eventLoop", Qt::QueuedConnection); + //QMetaObject::invokeMethod(this, "eventLoop", Qt::QueuedConnection); + QTimer::singleShot(50, this, &TerminalWindow::eventLoop); } - void TerminalWindow::refreshWindow(const QVariantMap &dataMap) { m_dataMap = dataMap; @@ -224,11 +278,11 @@ void TerminalWindow::refreshWindow(const QVariantMap &dataMap) QVariantMap statisticMap = m_dataMap.value("proxyStatistic").toMap(); m_clientHash.clear(); + foreach (const QVariant &clientVariant, statisticMap.value("clients").toList()) { QVariantMap clientMap = clientVariant.toMap(); + clientMap.insert("duration", getDurationString(clientMap.value("timestamp").toUInt())); m_clientHash.insert(clientMap.value("id").toString(), clientMap); } - - eventLoop(); } diff --git a/monitor/terminalwindow.h b/monitor/terminalwindow.h index fe59c54..aa59c8d 100644 --- a/monitor/terminalwindow.h +++ b/monitor/terminalwindow.h @@ -23,6 +23,7 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +#include #include #include @@ -56,9 +57,11 @@ private: QHash m_clientHash; const char *convertString(const QString &string); + QString getDurationString(uint timestamp); // content paint methods void resizeWindow(); + void drawWindowBorder(WINDOW *window); void paintHeader(); void paintContentClients(); void paintContentTunnels(); diff --git a/nymea-remoteproxy.pri b/nymea-remoteproxy.pri index 9059f94..5cc0877 100644 --- a/nymea-remoteproxy.pri +++ b/nymea-remoteproxy.pri @@ -23,7 +23,7 @@ ccache { QMAKE_CXX = ccache g++ } -coverage { +coverage {< # Note: this works only if you build in the source dir OBJECTS_DIR = MOC_DIR =