analyzers/src/watch/user_gui.cpp (167 lines of code) (raw):
//------------------------------------------------------------------------------
// Author: Vitali Adamenka
// Description: Source for UserGui.
// Copyright (c) 2015 EPAM Systems. All Rights Reserved.
//------------------------------------------------------------------------------
/*
This file is part of Nfstrace.
Nfstrace is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, version 2 of the License.
Nfstrace 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 Nfstrace. If not, see <http://www.gnu.org/licenses/>.
*/
//------------------------------------------------------------------------------
#include <algorithm>
#include <exception>
#include <iostream>
#include <stdexcept>
#include <system_error>
#include <unistd.h>
#include <api/plugin_api.h>
#include "nc_windows/header_window.h"
#include "nc_windows/main_window.h"
#include "nc_windows/statistics_window.h"
#include "user_gui.h"
//-----------------------------------------------------------------------------
namespace
{
const int SCROLL_UP = 1;
const int SCROLL_DOWN = -1;
const int MSEC = 1000000;
}
//------------------------------------------------------------------------------
void UserGUI::run()
{
try
{
// prepare for select
fd_set rfds;
MainWindow mainWindow;
HeaderWindow headerWindow(mainWindow);
StatisticsWindow statisticsWindow(mainWindow, _statisticsContainers);
/* Watch stdin (fd 0) to see when it has input. */
FD_ZERO(&rfds);
FD_SET(STDIN_FILENO, &rfds);
/* Set wait time. */
struct timeval tv = getTimeval();
uint16_t key = 0;
std::vector<std::size_t> tmp;
statisticsWindow.updateProtocol(_activeProtocol);
while(_running.test_and_set())
{
if(_shouldResize)
{
mainWindow.resize();
headerWindow.resize(mainWindow);
statisticsWindow.resize(mainWindow);
statisticsWindow.updateProtocol(_activeProtocol);
_shouldResize = false;
}
if(_running.test_and_set())
{
std::unique_lock<std::mutex> lck(_statisticsDeltaMutex);
tmp = _statisticsContainers.at(_activeProtocol);
}
headerWindow.update();
statisticsWindow.update(tmp);
mainWindow.update();
if(select(STDIN_FILENO + 1, &rfds, nullptr, nullptr, &tv) == -1)
{
break;
}
else
{
key = mainWindow.inputKeys();
if(key == KEY_LEFT || key == KEY_RIGHT)
{
auto it = find_if(_allProtocols.begin(), _allProtocols.end(), [&](std::string s) {
return !(s.compare(_activeProtocol->getProtocolName()));
});
if(it != _allProtocols.end())
{
if(key == KEY_LEFT)
{
if(it + 1 == _allProtocols.end())
it = _allProtocols.begin();
else
++it;
}
else if(key == KEY_RIGHT)
{
if(it == _allProtocols.begin())
it = _allProtocols.end() - 1;
else
--it;
}
auto a = find_if(_statisticsContainers.begin(), _statisticsContainers.end(), [&](std::pair<AbstractProtocol*, std::vector<std::size_t>> p) {
return !(p.first->getProtocolName().compare(*it));
});
if(a != _statisticsContainers.end())
{
_activeProtocol = a->first;
statisticsWindow.setProtocol(_activeProtocol);
statisticsWindow.resize(mainWindow);
{
std::unique_lock<std::mutex> lck(_statisticsDeltaMutex);
tmp = a->second;
}
statisticsWindow.update(tmp);
}
}
}
else if(key == KEY_UP)
{
statisticsWindow.scrollContent(SCROLL_UP);
statisticsWindow.update(tmp);
}
else if(key == KEY_DOWN)
{
statisticsWindow.scrollContent(SCROLL_DOWN);
statisticsWindow.update(tmp);
}
}
tv = getTimeval();
}
}
catch(std::runtime_error& e)
{
std::cerr << "Watch plugin error: " << e.what();
}
}
timeval UserGUI::getTimeval() const
{
struct timeval tv;
tv.tv_sec = _refresh_delta / MSEC;
tv.tv_usec = _refresh_delta % MSEC;
return tv;
}
UserGUI::UserGUI(const char* opts, std::vector<AbstractProtocol*>& data)
: _refresh_delta{900000}
, _shouldResize{false}
, _running{ATOMIC_FLAG_INIT}
, _activeProtocol(nullptr)
{
try
{
if(opts != nullptr && *opts != '\0')
{
_refresh_delta = std::stoul(opts);
}
for(auto it = data.begin(); it != data.end(); ++it)
{
_allProtocols.push_back((*it)->getProtocolName());
_statisticsContainers.insert(std::make_pair<AbstractProtocol*, std::vector<std::size_t>>((AbstractProtocol * &&)(*it), std::vector<std::size_t>((*it)->getAmount(), 0)));
}
if(_activeProtocol == nullptr && !data.empty())
{
_activeProtocol = data.back();
}
}
catch(std::exception& e)
{
throw std::runtime_error{std::string{"Error in plugin options processing. OPTS: "} + opts + std::string(" Error: ") + e.what()};
}
_running.test_and_set();
_guiThread = std::thread(&UserGUI::run, this);
}
UserGUI::~UserGUI()
{
_running.clear();
_guiThread.join();
}
void UserGUI::update(AbstractProtocol* p, std::vector<std::size_t>& d)
{
std::vector<std::size_t>::iterator it;
std::vector<std::size_t>::iterator st;
std::unique_lock<std::mutex> lck(_statisticsDeltaMutex);
for(it = (_statisticsContainers.at(p)).begin(), st = d.begin(); it != (_statisticsContainers.at(p)).end() && st != d.end(); ++it, ++st)
{
(*it) += (*st);
}
}
void UserGUI::enableUpdate()
{
_shouldResize = true;
}
//------------------------------------------------------------------------------