blob: 45b3069f0b68bf52836618458a9475466abf9979 [file] [log] [blame] [raw]
/*
* nload
* real time monitor for network traffic
* Copyright (C) 2001 - 2018 by Roland Riegel <feedback@roland-riegel.de>
*
* This program 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; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "deviceview.h"
#include "device.h"
#include "graph.h"
#include "setting.h"
#include "settingstore.h"
#include "stringutils.h"
#include "window.h"
#include <algorithm>
#include <iomanip>
#include <sstream>
using namespace std;
DeviceView::DeviceView(Device* device)
: m_deviceNumber(0), m_totalNumberOfDevices(0), m_device(device)
{
}
DeviceView::~DeviceView()
{
}
void DeviceView::update()
{
if(m_device->exists())
{
const Statistics& statistics = m_device->getStatistics();
m_deviceGraphIn.update(statistics.getDataInPerSecond());
m_deviceGraphOut.update(statistics.getDataOutPerSecond());
}
else
{
m_deviceGraphIn.resetTrafficData();
m_deviceGraphOut.resetTrafficData();
}
}
// print the device's data
void DeviceView::print(Window& window)
{
int width = window.getWidth();
int height = window.getHeight();
// print header
if(height > 2)
{
string deviceName = m_device->getName();
string ipv4 = m_device->getIpV4Address();
if(m_device->exists())
{
if(!ipv4.empty())
window.print() << "Device " << deviceName << " [" << ipv4 << "] (" << (m_deviceNumber + 1) << "/" << m_totalNumberOfDevices << "):" << endl;
else
window.print() << "Device " << deviceName << " (" << (m_deviceNumber + 1) << "/" << m_totalNumberOfDevices << "):" << endl;
window.print() << string(width, '=');
}
else
{
// if device does not exist print warning message
window.print() << "Device " << deviceName << " (" << (m_deviceNumber + 1) << "/" << m_totalNumberOfDevices << "): does not exist" << endl;
window.print() << string(width, '=') << endl;
// and exit
return;
}
}
if(width < 25 || height < 8)
{
window.print() << "Please enlarge console for viewing device information." << endl;
return;
}
// format statistics
vector<string> statLinesIn;
vector<string> statLinesOut;
generateStatisticsIn(statLinesIn);
generateStatisticsOut(statLinesOut);
size_t statLineInMaxLength = max_element(statLinesIn.begin(), statLinesIn.end(), sizeLess())->size();
size_t statLineOutMaxLength = max_element(statLinesOut.begin(), statLinesOut.end(), sizeLess())->size();
int statLineMaxLength = statLineInMaxLength > statLineOutMaxLength ? statLineInMaxLength : statLineOutMaxLength;
// if graphs should be hidden ...
if(SettingStore::get("MultipleDevices"))
{
window.print() << "Incoming:";
window.print(width / 2) << "Outgoing:" << endl;
int statusY = window.getY();
printStatistics(window, statLinesIn, 0, statusY);
printStatistics(window, statLinesOut, width / 2, statusY);
window.print() << endl;
}
// ... or not
else
{
// calculate layout
int lines = height - window.getY();
int linesForIn = (lines + 1) / 2;
int linesForOut = lines - linesForIn;
int dirInY = window.getY();
int dirOutY = dirInY + linesForIn;
int statisticsX = width - statLineMaxLength - 1;
statisticsX -= statisticsX % 5;
if(linesForOut <= 5)
{
linesForIn = lines;
linesForOut = 0;
dirOutY = height;
}
// calculate deflection of graphs
unsigned long long maxDeflectionIn = (unsigned long long) SettingStore::get("BarMaxIn") * 1024 / 8;
unsigned long long maxDeflectionOut = (unsigned long long) SettingStore::get("BarMaxOut") * 1024 / 8;
if(maxDeflectionIn < 1)
maxDeflectionIn = roundUpMaxDeflection(m_deviceGraphIn.calcMaxDeflection());
if(maxDeflectionOut < 1)
maxDeflectionOut = roundUpMaxDeflection(m_deviceGraphOut.calcMaxDeflection());
// print incoming data
if(linesForIn > 5)
{
window.print(0, dirInY) << "Incoming (100% @ " << formatTrafficValue(maxDeflectionIn, 0) << "):" << endl;
if(statisticsX > 1)
{
m_deviceGraphIn.setNumOfBars(statisticsX - 1);
m_deviceGraphIn.setHeightOfBars(linesForIn - 1);
m_deviceGraphIn.setMaxDeflection(maxDeflectionIn);
m_deviceGraphIn.print(window, 0, dirInY + 1);
}
if(width > statLineMaxLength)
printStatistics(window, statLinesIn, statisticsX, dirInY + linesForIn - 5);
}
// print outgoing data
if(linesForOut > 5)
{
window.print(0, dirOutY) << "Outgoing (100% @ " << formatTrafficValue(maxDeflectionOut, 0) << "):" << endl;
if(statisticsX > 1)
{
m_deviceGraphOut.setNumOfBars(statisticsX - 1);
m_deviceGraphOut.setHeightOfBars(linesForOut - 1);
m_deviceGraphOut.setMaxDeflection(maxDeflectionOut);
m_deviceGraphOut.print(window, 0, dirOutY + 1);
}
if(width > statLineMaxLength)
printStatistics(window, statLinesOut, statisticsX, dirOutY + linesForOut - 5);
}
}
}
// set the number identifying the device (for display only)
void DeviceView::setDeviceNumber(int deviceNumber)
{
m_deviceNumber = deviceNumber;
}
// set the total number of shown devices (for display only)
void DeviceView::setTotalNumberOfDevices(int totalNumberOfDevices)
{
m_totalNumberOfDevices = totalNumberOfDevices;
}
unsigned long long DeviceView::roundUpMaxDeflection(unsigned long long value)
{
unsigned long long rounded = 2 * 1024; // 2 kByte/s
while (rounded < value)
{
if((rounded << 1) < rounded)
return value;
rounded <<= 1;
}
return rounded;
}
string DeviceView::formatTrafficValue(unsigned long value, int precision)
{
Statistics::dataUnit trafficFormat = (Statistics::dataUnit) ((int) SettingStore::get("TrafficFormat"));
string unitString = Statistics::getUnitString(trafficFormat, value);
float unitFactor = Statistics::getUnitFactor(trafficFormat, value);
ostringstream oss;
oss << fixed << setprecision(precision) << ((float) value / unitFactor) << " " << unitString << "/s";
return oss.str();
}
string DeviceView::formatDataValue(unsigned long long value, int precision)
{
Statistics::dataUnit dataFormat = (Statistics::dataUnit) ((int) SettingStore::get("DataFormat"));
string unitString = Statistics::getUnitString(dataFormat, value);
float unitFactor = Statistics::getUnitFactor(dataFormat, value);
ostringstream oss;
oss << fixed << setprecision(precision) << ((float) value / unitFactor) << " " << unitString << endl;
return oss.str();
}
void DeviceView::generateStatisticsIn(vector<string>& statisticLines)
{
const Statistics& statistics = m_device->getStatistics();
statisticLines.push_back("Cur: " + formatTrafficValue(statistics.getDataInPerSecond(), 2));
statisticLines.push_back("Avg: " + formatTrafficValue(statistics.getDataInAverage(), 2));
statisticLines.push_back("Min: " + formatTrafficValue(statistics.getDataInMin(), 2));
statisticLines.push_back("Max: " + formatTrafficValue(statistics.getDataInMax(), 2));
statisticLines.push_back("Ttl: " + formatDataValue(statistics.getDataInTotal(), 2));
}
void DeviceView::generateStatisticsOut(vector<string>& statisticLines)
{
const Statistics& statistics = m_device->getStatistics();
statisticLines.push_back("Cur: " + formatTrafficValue(statistics.getDataOutPerSecond(), 2));
statisticLines.push_back("Avg: " + formatTrafficValue(statistics.getDataOutAverage(), 2));
statisticLines.push_back("Min: " + formatTrafficValue(statistics.getDataOutMin(), 2));
statisticLines.push_back("Max: " + formatTrafficValue(statistics.getDataOutMax(), 2));
statisticLines.push_back("Ttl: " + formatDataValue(statistics.getDataOutTotal(), 2));
}
void DeviceView::printStatistics(Window& window, const vector<string>& statisticLines, int x, int y)
{
for(vector<string>::const_iterator itLine = statisticLines.begin(); itLine != statisticLines.end(); ++itLine)
{
window.print(x, y++) << *itLine;
}
}