Extend monitor and add test script for connections

This commit is contained in:
Simon Stürz 2022-01-11 09:01:54 +01:00
parent 97514a9504
commit 1ca3119995
8 changed files with 242 additions and 42 deletions

View File

@ -56,7 +56,9 @@ bool MonitorServer::running() const
void MonitorServer::sendMonitorData(QLocalSocket *clientConnection, const QVariantMap &dataMap)
{
clientConnection->write(QJsonDocument::fromVariant(dataMap).toJson(QJsonDocument::Compact) + '\n');
QByteArray data = QJsonDocument::fromVariant(dataMap).toJson(QJsonDocument::Indented) + '\n';
qCDebug(dcMonitorServer()) << "Sending monitor data" << qUtf8Printable(data);
clientConnection->write(data);
clientConnection->flush();
}

View File

@ -201,6 +201,7 @@ QVariantMap TunnelProxyServer::currentStatistics()
statisticsMap.insert("totalClientCount", m_proxyClients.count());
statisticsMap.insert("serverConnectionsCount", m_tunnelProxyServerConnections.count());
statisticsMap.insert("clientConnectionsCount", m_tunnelProxyClientConnections.count());
statisticsMap.insert("troughput", m_troughput);
QVariantList tunnelConnections;
foreach (TunnelProxyServerConnection *serverConnection, m_tunnelProxyServerConnections) {
@ -210,6 +211,9 @@ QVariantMap TunnelProxyServer::currentStatistics()
serverMap.insert("timestamp", serverConnection->transportClient()->creationTime());
serverMap.insert("name", serverConnection->transportClient()->name());
serverMap.insert("serverUuid", serverConnection->transportClient()->uuid());
serverMap.insert("rxDataCount", serverConnection->transportClient()->rxDataCount());
serverMap.insert("txDataCount", serverConnection->transportClient()->txDataCount());
QVariantList clientList;
foreach (TunnelProxyClientConnection *clientConnection, serverConnection->clientConnections()) {
QVariantMap clientMap;
@ -218,9 +222,12 @@ QVariantMap TunnelProxyServer::currentStatistics()
clientMap.insert("timestamp", clientConnection->transportClient()->creationTime());
clientMap.insert("name", clientConnection->transportClient()->name());
clientMap.insert("clientUuid", clientConnection->transportClient()->uuid());
clientMap.insert("rxDataCount", clientConnection->transportClient()->rxDataCount());
clientMap.insert("txDataCount", clientConnection->transportClient()->txDataCount());
clientList.append(clientMap);
}
serverMap.insert("clientConnections", clientList);
tunnelConnections.append(serverMap);
}
statisticsMap.insert("tunnelConnections", tunnelConnections);
@ -248,7 +255,8 @@ void TunnelProxyServer::stopServer()
void TunnelProxyServer::tick()
{
m_troughput = m_troughputCounter;
m_troughputCounter = 0;
}
void TunnelProxyServer::onClientConnected(const QUuid &clientId, const QHostAddress &address)
@ -337,7 +345,7 @@ void TunnelProxyServer::onClientDataAvailable(const QUuid &clientId, const QByte
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)));
m_troughputCounter += data.count();
} else if (tunnelProxyClient->type() == TunnelProxyClient::TypeServer) {
// Data coming from a connected server connection
if (tunnelProxyClient->slipEnabled()) {
@ -368,6 +376,7 @@ 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();
}
}
} else {

View File

@ -95,6 +95,9 @@ private:
QHash<QUuid, TunnelProxyServerConnection *> m_tunnelProxyServerConnections; // server uuid, object
QHash<QUuid, TunnelProxyClientConnection *> m_tunnelProxyClientConnections; // client uuid, object
// Statistic measurments
int m_troughput = 0;
int m_troughputCounter = 0;
};
}

View File

@ -48,7 +48,7 @@ int main(int argc, char *argv[])
parser.setApplicationDescription(QString("\nThe nymea remote proxy monitor allowes to monitor the live server activity on the a local instance.\n\n"
"Server version: %1\n"
"API version: %2\n\n"
"Copyright %3 2021 nymea GmbH <developer@nymea.io>\n")
"Copyright %3 2022 nymea GmbH <developer@nymea.io>\n")
.arg(SERVER_VERSION_STRING)
.arg(API_VERSION_STRING)
.arg(QChar(0xA9)));

View File

@ -35,6 +35,9 @@
TerminalWindow::TerminalWindow(QObject *parent) :
QObject(parent)
{
// Init view tabs
m_tabs << ViewClients << ViewTunnels << ViewTunnelProxy;
// Create main window
m_mainWindow = initscr();
@ -71,7 +74,9 @@ TerminalWindow::TerminalWindow(QObject *parent) :
// Draw borders
drawWindowBorder(m_headerWindow);
drawWindowBorder(m_contentWindow);
//drawWindowBorder(m_contentWindow);
scrollok(m_contentWindow, true);
//box(m_headerWindow, 0 , 0);
//box(m_contentWindow, 0 , 0);
@ -87,11 +92,7 @@ TerminalWindow::TerminalWindow(QObject *parent) :
TerminalWindow::~TerminalWindow()
{
clear();
delwin(m_headerWindow);
delwin(m_contentWindow);
delwin(m_mainWindow);
endwin();
cleanup();
}
const char *TerminalWindow::convertString(const QString &string)
@ -165,19 +166,72 @@ void TerminalWindow::drawWindowBorder(WINDOW *window)
}
}
void TerminalWindow::moveTabRight()
{
int currentIndex = m_tabs.indexOf(m_view);
if (currentIndex + 1 >= m_tabs.count()) {
m_view = m_tabs.at(0);
} else {
m_view = m_tabs.at( currentIndex + 1);
}
}
void TerminalWindow::moveTabLeft()
{
int currentIndex = m_tabs.indexOf(m_view);
if (currentIndex - 1 < 0) {
m_view = m_tabs.at(m_tabs.count() - 1);
} else {
m_view = m_tabs.at( currentIndex - 1);
}
}
void TerminalWindow::paintHeader()
{
QString headerString = QString(" Server: %1 (%2) | API: %3 | Clients: %4, %5 | Tunnels: %6, %7 | %8 | %9 | %10")
.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("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((m_view == ViewClients ? "-- Clients --" : "-- Tunnels --"));
QString windowName;
QString headerString;
switch (m_view) {
case ViewClients:
windowName = "-- Clients --";
headerString = QString(" Server: %1 (%2) | API: %3 | Clients: %4, %5 | Tunnels: %6, %7 | %8 | %9 | %10")
.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("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(windowName);
break;
case ViewTunnels:
windowName = "-- Tunnels --";
headerString = QString(" Server: %1 (%2) | API: %3 | Clients: %4, %5 | Tunnels: %6, %7 | %8 | %9 | %10")
.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("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(windowName);
break;
case ViewTunnelProxy:
windowName = "-- TunnelProxy --";
headerString = QString(" Server: %1 (%2) | API: %3 | Total: %4 | Servers: %5 | Clients: %6 | %7 | %8")
.arg(m_dataMap.value("serverName", "-").toString())
.arg(m_dataMap.value("serverVersion", "-").toString())
.arg(m_dataMap.value("apiVersion", "-").toString())
.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(windowName);
break;
}
int delta = m_terminalSizeX - headerString.count();
@ -185,10 +239,9 @@ void TerminalWindow::paintHeader()
for (int i = 0; i < delta; i++)
headerString.append(" ");
wattron(m_headerWindow, A_BOLD | COLOR_PAIR(1));
//wattron(m_headerWindow, A_BOLD | COLOR_PAIR(1));
mvwprintw(m_headerWindow, 1, 2, convertString(headerString));
wattroff(m_headerWindow, A_BOLD | COLOR_PAIR(1));
//wattroff(m_headerWindow, A_BOLD | COLOR_PAIR(1));
}
void TerminalWindow::paintContentClients()
@ -219,7 +272,6 @@ void TerminalWindow::paintContentClients()
mvwprintw(m_contentWindow, i, 2, convertString(clientPrint.trimmed()));
i++;
}
}
void TerminalWindow::paintContentTunnels()
@ -235,7 +287,6 @@ 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) <---> %7 (%8)")
.arg(tunnelConnectionTime)
.arg(getDurationString(timeStamp))
@ -252,9 +303,73 @@ void TerminalWindow::paintContentTunnels()
}
}
void TerminalWindow::paintContentTunnelProxy()
{
QVariantMap tunnelProxyMap = m_dataMap.value("tunnelProxyStatistic").toMap();
int i = 1;
foreach (const QVariant &serverVariant, tunnelProxyMap.value("tunnelConnections").toList()) {
QVariantMap serverMap = serverVariant.toMap();
uint timeStamp = serverMap.value("timestamp").toUInt();
QString serverConnectionTime = QDateTime::fromTime_t(timeStamp).toString("dd.MM.yyyy hh:mm:ss");
int rxDataCountBytes = serverMap.value("rxDataCount").toInt();
int txDataCountBytes = serverMap.value("txDataCount").toInt();
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(serverMap.value("name").toString(), -30);
QVariantList clientList = serverMap.value("clientConnections").toList();
mvwaddch(m_contentWindow, i, 2, ACS_LTEE);
mvwaddch(m_contentWindow, i, 3, ACS_HLINE);
if (clientList.isEmpty()) {
mvwaddch(m_contentWindow, i, 4, ACS_HLINE);
} else {
mvwaddch(m_contentWindow, i, 4, ACS_TTEE);
}
mvwaddch(m_contentWindow, i, 5, ACS_HLINE);
mvwprintw(m_contentWindow, i, 6, convertString(serverLinePrint.trimmed()));
i++;
for (int cc = 0; cc < clientList.count(); cc++) {
QVariantMap clientMap = clientList.at(cc).toMap();
mvwaddch(m_contentWindow, i, 2, ACS_VLINE);
if (cc >= clientList.count() - 1) {
mvwaddch(m_contentWindow, i, 4, ACS_LLCORNER);
} else {
mvwaddch(m_contentWindow, i, 4, ACS_LTEE);
}
mvwaddch(m_contentWindow, i, 5, ACS_HLINE);
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(clientMap.value("name").toString(), -30);
mvwprintw(m_contentWindow, i, 6, convertString(clientLinePrint.trimmed()));
i++;
}
}
}
void TerminalWindow::cleanup()
{
clear();
delwin(m_headerWindow);
delwin(m_contentWindow);
delwin(m_mainWindow);
endwin();
}
void TerminalWindow::eventLoop()
{
werase(m_headerWindow);
werase(m_contentWindow);
@ -263,17 +378,13 @@ void TerminalWindow::eventLoop()
int keyInteger = getch();
switch (keyInteger) {
case KEY_LEFT:
m_view = ViewClients;
moveTabLeft();
break;
case KEY_RIGHT:
m_view = ViewTunnels;
moveTabRight();
break;
case 27: // Esc
clear();
delwin(m_headerWindow);
delwin(m_contentWindow);
delwin(m_mainWindow);
endwin();
cleanup();
qDebug() << "Closing window monitor. Have a nice day!";
exit(0);
break;
@ -292,11 +403,25 @@ void TerminalWindow::eventLoop()
case ViewTunnels:
paintContentTunnels();
break;
case ViewTunnelProxy:
paintContentTunnelProxy();
break;
}
switch (keyInteger) {
case KEY_DOWN:
scroll(m_contentWindow);
scrl(1);
break;
case KEY_UP:
scroll(m_contentWindow);
scrl(-1);
break;
}
// Draw borders
drawWindowBorder(m_headerWindow);
drawWindowBorder(m_contentWindow);
//drawWindowBorder(m_contentWindow);
wrefresh(m_headerWindow);
wrefresh(m_contentWindow);

View File

@ -41,7 +41,8 @@ public:
enum View {
ViewClients,
ViewTunnels
ViewTunnels,
ViewTunnelProxy
};
Q_ENUM(View)
@ -58,6 +59,11 @@ private:
int m_terminalSizeY = 0;
View m_view = ViewClients;
int m_tunnelProxyScollIndex = 0;
// Tabs
QList<View> m_tabs;
QVariantMap m_dataMap;
QHash<QString, QVariantMap> m_clientHash;
@ -70,11 +76,15 @@ private:
// content paint methods
void resizeWindow();
void drawWindowBorder(WINDOW *window);
void moveTabRight();
void moveTabLeft();
void paintHeader();
void paintContentClients();
void paintContentTunnels();
void paintContentTunnelProxy();
signals:
void cleanup();
private slots:
void eventLoop();

View File

@ -55,10 +55,6 @@ static void catchUnixSignals(const std::vector<int>& quitSignals, const std::vec
case SIGHUP:
qCDebug(dcApplication()) << "Cought SIGHUP quit signal...";
break;
case SIGSEGV: {
qCDebug(dcApplication()) << "Cought SIGSEGV signal. Segmentation fault!";
exit(1);
}
default:
break;
}
@ -82,5 +78,5 @@ static void catchUnixSignals(const std::vector<int>& quitSignals, const std::vec
RemoteProxyServerApplication::RemoteProxyServerApplication(int &argc, char **argv) :
QCoreApplication(argc, argv)
{
catchUnixSignals({SIGQUIT, SIGINT, SIGTERM, SIGHUP, SIGSEGV});
catchUnixSignals({SIGQUIT, SIGINT, SIGTERM, SIGHUP});
}

View File

@ -0,0 +1,55 @@
#!/bin/bash
CHILD_PROCESSES=()
SERVER_URL=tcp://127.0.0.1:2213
# Start server: Arguments: serverName serverUuid
function createServer() {
echo "--> Create server"
nymea-remoteproxy-tunnelclient -s -n "$1" --uuid "$2" -u $SERVER_URL -i & CHILD_PROCESSES+=("$!")
}
# Create client: Arguments: clientName serverUuid
function createClient() {
echo "--> Create client"
nymea-remoteproxy-tunnelclient -c -n "$1" --server-uuid "$2" -u $SERVER_URL -i & CHILD_PROCESSES+=("$!")
}
# Arguments: client count
function createTunnelConnections() {
local serverUuid=$(uuidgen)
createServer "Test server $serverUuid " $serverUuid
sleep 0.5
i=1
while [[ $i -lt $1 ]] ; do
createClient "Test client $i" $serverUuid
((i += 1))
#sleep 0.5
done
}
function cleanup {
echo "Cleanup"
kill "${CHILD_PROCESSES[@]}"
}
trap cleanup EXIT
createTunnelConnections 5
createTunnelConnections 3
createTunnelConnections 9
createTunnelConnections 6
createTunnelConnections 4
createTunnelConnections 3
createTunnelConnections 2
createTunnelConnections 1
createTunnelConnections 3
createTunnelConnections 2
createTunnelConnections 1
createTunnelConnections 8
sleep 300