moved code into separate directories

git-svn-id: http://svn.code.sf.net/p/retroshare/code/trunk@7244 b45a01b8-16f6-495d-af2f-9b41ad6348cc
This commit is contained in:
csoler 2014-04-06 08:10:14 +00:00
parent 44a1f6f6f3
commit 1e0ea41b4a
24 changed files with 263 additions and 19 deletions

View file

@ -0,0 +1,55 @@
#include <QFrame>
#include <QObject>
#include "NetworkSimulatorGUI.h"
#include "NetworkViewer.h"
#include "TurtleRouterStatistics.h"
NetworkSimulatorGUI::NetworkSimulatorGUI(Network& net)
{
setupUi(this) ;
tickTimerId = 0 ;
QVBoxLayout *layout = new QVBoxLayout(networkViewFrame) ;
layout->addWidget(_viewer = new NetworkViewer(networkViewFrame,net)) ;
QObject::connect(_viewer,SIGNAL(nodeSelected(int)),this,SLOT(updateSelectedNode(int))) ;
QObject::connect(flow_CB,SIGNAL(toggled(bool)),this,SLOT(toggleNetworkTraffic(bool))) ;
QVBoxLayout *layout2 = new QVBoxLayout(inspectorFrame) ;
layout2->addWidget(_turtle_router_statistics = new TurtleRouterStatistics() ) ;
}
void NetworkSimulatorGUI::updateSelectedNode(int node_id)
{
_turtle_router_statistics->setTurtleRouter( _viewer->network().node(node_id).turtle_service() ) ;
}
void NetworkSimulatorGUI::toggleNetworkTraffic(bool b)
{
if(!b && tickTimerId > 0)
{
killTimer(tickTimerId) ;
tickTimerId = 0 ;
return ;
}
if(b && tickTimerId == 0)
{
tickTimerId = startTimer(1000) ;
return ;
}
std::cerr << "ERROR !!" << std::endl;
}
void NetworkSimulatorGUI::timerEvent(QTimerEvent *event)
{
Q_UNUSED(event) ;
std::cerr << "timer event!" << std::endl;
_viewer->network().tick() ;
}

View file

@ -0,0 +1,26 @@
#include "ui_NetworkSimulatorGUI.h"
class TurtleRouterStatistics ;
class NetworkViewer ;
class Network ;
class NetworkSimulatorGUI: public QMainWindow, public Ui::NetworkSimulatorGUI
{
Q_OBJECT
public:
NetworkSimulatorGUI(Network& net) ;
public slots:
void updateSelectedNode(int) ;
void toggleNetworkTraffic(bool) ;
virtual void timerEvent(QTimerEvent *e) ;
private:
NetworkViewer *_viewer ;
TurtleRouterStatistics *_turtle_router_statistics ;
int tickTimerId ;
};

View file

@ -0,0 +1,106 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>NetworkSimulatorGUI</class>
<widget class="QMainWindow" name="NetworkSimulatorGUI">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>901</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QFrame" name="networkViewFrame">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QCheckBox" name="flow_CB">
<property name="text">
<string>flow</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</item>
<item>
<widget class="QFrame" name="inspectorFrame">
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>901</width>
<height>25</height>
</rect>
</property>
<widget class="QMenu" name="menuFile">
<property name="title">
<string>File</string>
</property>
<addaction name="actionLoad_network"/>
<addaction name="actionSave_network"/>
</widget>
<addaction name="menuFile"/>
</widget>
<widget class="QStatusBar" name="statusbar"/>
<action name="actionLoad_network">
<property name="text">
<string>Load network</string>
</property>
</action>
<action name="actionSave_network">
<property name="text">
<string>Save network</string>
</property>
</action>
</widget>
<resources/>
<connections/>
</ui>

View file

@ -0,0 +1,602 @@
#include <QMouseEvent>
#include <QMenu>
#include <QAction>
#include <retroshare/rsids.h>
#include "Network.h"
#include "NetworkViewer.h"
NetworkViewer::NetworkViewer(QWidget *parent,Network&net)
: QGLViewer(parent),_network(net) , timerId(0)
{
_current_selected_node = -1 ;
_current_displayed_node = -1 ;
_current_acted_node = -1 ;
_dragging = false ;
_nodes_need_recomputing = true ;
_node_coords.resize(net.n_nodes()) ;
_node_speeds.resize(net.n_nodes()) ;
for(int i=0;i<_node_coords.size();++i)
{
_node_coords[i].x = drand48()*width()*5;
_node_coords[i].y = drand48()*height()*5 ;
_node_speeds[i].x = 0 ;
_node_speeds[i].y = 0 ;
}
timerId = startTimer(1000/25) ;
connect(this,SIGNAL(customContextMenuRequested(QPoint)),this,SLOT(contextMenu(QPoint)));
action_ManageHash = new QAction(QString("Manage new random hash"),this) ;
QObject::connect(action_ManageHash,SIGNAL(triggered()),this,SLOT(actionManageHash())) ;
setMouseTracking(true) ;
}
void NetworkViewer::draw()
{
glDisable(GL_DEPTH_TEST) ;
glClear(GL_COLOR_BUFFER_BIT) ;
// for now, view is fixed.
glMatrixMode(GL_MODELVIEW) ;
glPushMatrix() ;
glLoadIdentity() ;
glMatrixMode(GL_PROJECTION) ;
glPushMatrix() ;
glLoadIdentity() ;
glOrtho(0,width(),0,height(),1,-1) ;
glEnable(GL_BLEND) ;
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA) ;
// Now, draw all edges
std::set<int> tunnel_nodes ;
glEnable(GL_LINE_SMOOTH) ;
glBegin(GL_LINES) ;
for(uint32_t i=0;i<_network.n_nodes();++i)
{
PeerNode::NodeTrafficInfo traffic_info ;
_network.node(i).getTrafficInfo(traffic_info) ;
const std::set<uint32_t>& neighs( _network.neighbors(i) ) ;
for(std::set<uint32_t>::const_iterator it(neighs.begin());it!=neighs.end();++it)
{
if(traffic_info.local_src.find(_network.node(*it).id().toStdString())!=traffic_info.local_src.end() || traffic_info.local_dst.find(_network.node(*it).id().toStdString())!=traffic_info.local_dst.end())
{
glColor3f(0.9f,0.4f,0.2f) ;
tunnel_nodes.insert(i) ;
tunnel_nodes.insert(*it) ;
}
else
glColor3f(0.4f,0.4f,0.4f) ;
if( i < *it )
{
glVertex2f(_node_coords[ i].x, _node_coords[ i].y) ;
glVertex2f(_node_coords[*it].x, _node_coords[*it].y) ;
}
}
}
glEnd() ;
// Draw all nodes.
//
glEnable(GL_POINT_SMOOTH) ;
glPointSize(20.0f) ;
glBegin(GL_POINTS) ;
if(_current_selected_node > -1)
{
glColor4f(1.0f,0.2f,0.1f,0.7f) ;
glVertex2f(_node_coords[_current_selected_node].x, _node_coords[_current_selected_node].y) ;
}
glEnd() ;
glPointSize(10.0f) ;
glBegin(GL_POINTS) ;
for(uint32_t i=0;i<_network.n_nodes();++i)
{
float r = 0.8 ;
float g = 0.8 ;
float b = 0.8 ;
if(!_network.node(i).providedHashes().empty())
r *= 2.0, g /= 2.0, b /= 2.0f ;
if(!_network.node(i).managedHashes().empty())
g *= 2.0, b /= 2.0, r /= 2.0f ;
if(tunnel_nodes.find(i) != tunnel_nodes.end() && r==0.8f && g==0.8f && b==0.8f)
r = 0.9f, g=0.4f,b=0.2f ;
glColor3f(r,g,b) ;
glVertex2f(_node_coords[i].x, _node_coords[i].y) ;
}
glEnd() ;
// Draw info about current node under mouse.
//
if(_current_displayed_node > -1)
{
const PeerNode& node(_network.node(_current_displayed_node)) ;
int offset = 0 ;
int text_height = 15 ;
drawText(10+_node_coords[_current_displayed_node].x,offset + height()-_node_coords[_current_displayed_node].y, "Node id = " + QString::fromStdString(node.id().toStdString())) ;
offset += text_height ;
for(std::set<TurtleFileHash>::const_iterator it(node.providedHashes().begin());it!=node.providedHashes().end();++it)
{
drawText(10+_node_coords[_current_displayed_node].x,offset + height()-_node_coords[_current_displayed_node].y, "Server for hash " + QString::fromStdString((*it).toStdString()) );
offset += text_height ;
}
for(std::set<TurtleFileHash>::const_iterator it(node.managedHashes().begin());it!=node.managedHashes().end();++it)
{
drawText(10+_node_coords[_current_displayed_node].x,offset + height()-_node_coords[_current_displayed_node].y, "Client for hash " + QString::fromStdString((*it).toStdString()) ) ;
offset += text_height ;
}
}
glMatrixMode(GL_MODELVIEW) ;
glPopMatrix() ;
glMatrixMode(GL_PROJECTION) ;
glPopMatrix() ;
}
#define SWAP(a,b) tempr=(a);(a)=(b);(b)=tempr
void fourn(double data[],unsigned long nn[],unsigned long ndim,int isign)
{
int i1,i2,i3,i2rev,i3rev,ip1,ip2,ip3,ifp1,ifp2;
int ibit,idim,k1,k2,n,nprev,nrem,ntot;
double tempi,tempr;
double theta,wi,wpi,wpr,wr,wtemp;
ntot=1;
for (idim=1;idim<=(long)ndim;idim++)
ntot *= nn[idim];
nprev=1;
for (idim=ndim;idim>=1;idim--) {
n=nn[idim];
nrem=ntot/(n*nprev);
ip1=nprev << 1;
ip2=ip1*n;
ip3=ip2*nrem;
i2rev=1;
for (i2=1;i2<=ip2;i2+=ip1) {
if (i2 < i2rev) {
for (i1=i2;i1<=i2+ip1-2;i1+=2) {
for (i3=i1;i3<=ip3;i3+=ip2) {
i3rev=i2rev+i3-i2;
SWAP(data[i3],data[i3rev]);
SWAP(data[i3+1],data[i3rev+1]);
}
}
}
ibit=ip2 >> 1;
while (ibit >= ip1 && i2rev > ibit) {
i2rev -= ibit;
ibit >>= 1;
}
i2rev += ibit;
}
ifp1=ip1;
while (ifp1 < ip2) {
ifp2=ifp1 << 1;
theta=isign*6.28318530717959/(ifp2/ip1);
wtemp=sin(0.5*theta);
wpr = -2.0*wtemp*wtemp;
wpi=sin(theta);
wr=1.0;
wi=0.0;
for (i3=1;i3<=ifp1;i3+=ip1) {
for (i1=i3;i1<=i3+ip1-2;i1+=2) {
for (i2=i1;i2<=ip3;i2+=ifp2) {
k1=i2;
k2=k1+ifp1;
tempr=wr*data[k2]-wi*data[k2+1];
tempi=wr*data[k2+1]+wi*data[k2];
data[k2]=data[k1]-tempr;
data[k2+1]=data[k1+1]-tempi;
data[k1] += tempr;
data[k1+1] += tempi;
}
}
wr=(wtemp=wr)*wpr-wi*wpi+wr;
wi=wi*wpr+wtemp*wpi+wi;
}
ifp1=ifp2;
}
nprev *= n;
}
}
#undef SWAP
static void convolveWithGaussian(double *forceMap,int S,int /*s*/)
{
static double *bf = NULL ;
if(bf == NULL)
{
bf = new double[S*S*2] ;
for(int i=0;i<S;++i)
for(int j=0;j<S;++j)
{
int x = (i<S/2)?i:(S-i) ;
int y = (j<S/2)?j:(S-j) ;
// int l=2*(x*x+y*y);
bf[2*(i+S*j)] = log(sqrtf(0.1 + x*x+y*y)); // linear -> derivative is constant
bf[2*(i+S*j)+1] = 0 ;
}
unsigned long nn[2] = {S,S};
fourn(&bf[-1],&nn[-1],2,1) ;
}
unsigned long nn[2] = {S,S};
fourn(&forceMap[-1],&nn[-1],2,1) ;
for(int i=0;i<S;++i)
for(int j=0;j<S;++j)
{
float a = forceMap[2*(i+S*j)]*bf[2*(i+S*j)] - forceMap[2*(i+S*j)+1]*bf[2*(i+S*j)+1] ;
float b = forceMap[2*(i+S*j)]*bf[2*(i+S*j)+1] + forceMap[2*(i+S*j)+1]*bf[2*(i+S*j)] ;
forceMap[2*(i+S*j)] = a ;
forceMap[2*(i+S*j)+1] = b ;
}
fourn(&forceMap[-1],&nn[-1],2,-1) ;
for(int i=0;i<S*S*2;++i)
forceMap[i] /= S*S;
}
void NetworkViewer::timerEvent(QTimerEvent *event)
{
Q_UNUSED(event);
if(!isVisible())
return ;
if(_nodes_need_recomputing)
{
std::cerr << "Updating forces..."<< std::endl;
static const int S = 256 ;
static double *forceMap = new double[2*S*S] ;
memset(forceMap,0,2*S*S*sizeof(double)) ;
for(uint32_t k=0;k<_network.n_nodes();++k)
{
float x = S*_node_coords[k].x/width() ;
float y = S*_node_coords[k].y/height() ;
int i=(int)floor(x) ;
int j=(int)floor(y) ;
float di = x-i ;
float dj = y-j ;
if( i>=0 && i<S-1 && j>=0 && j<S-1)
{
forceMap[2*(i +S*(j ))] += (1-di)*(1-dj) ;
forceMap[2*(i+1+S*(j ))] += di *(1-dj) ;
forceMap[2*(i +S*(j+1))] += (1-di)*dj ;
forceMap[2*(i+1+S*(j+1))] += di *dj ;
}
}
// compute convolution with 1/omega kernel.
//
convolveWithGaussian(forceMap,S,20) ;
static float speedf=1.0f;
std::vector<NodeCoord> new_coords(_node_coords) ;
for(uint32_t i=0;i<_network.n_nodes();++i)
if(i != _current_selected_node || !_dragging)
{
float x = _node_coords[i].x ;
float y = _node_coords[i].y ;
calculateForces(i,forceMap,S,S,x,y,speedf,new_coords[i].x,new_coords[i].y);
}
bool itemsMoved = false;
for(uint32_t i=0;i<_node_coords.size();++i)
{
if( fabsf(_node_coords[i].x - new_coords[i].x) > 1.0 || fabsf(_node_coords[i].y - new_coords[i].y) > 1.0)
itemsMoved = true;
//std::cerr << "Old i = " << _node_coords[i].x << ", new = " << new_coords[i].x << std::endl;
_node_coords[i] = new_coords[i] ;
}
if (!itemsMoved) {
// killTimer(timerId);
//#ifdef DEBUG_ELASTIC
std::cerr << "Killing timr" << std::endl ;
_nodes_need_recomputing = false ;
//#endif
timerId = 0;
}
else
{
updateGL() ;
usleep(2000) ;
}
}
else
updateGL() ;
}
void NetworkViewer::mouseMoveEvent(QMouseEvent *e)
{
if(_dragging && _current_selected_node >= 0)
{
_node_coords[_current_selected_node].x = e->x() ;
_node_coords[_current_selected_node].y = height() - e->y() ;
_nodes_need_recomputing = true ;
updateGL() ;
}
float x = e->x() ;
float y = height()-e->y() ;
_current_displayed_node = -1 ;
for(uint32_t i=0;i<_node_coords.size();++i)
if( pow(_node_coords[i].x-x,2)+pow(_node_coords[i].y-y,2) < 5*5)
{
_current_displayed_node = i;
break ;
}
}
void NetworkViewer::mouseReleaseEvent(QMouseEvent *e)
{
_dragging = false ;
}
void NetworkViewer::mousePressEvent(QMouseEvent *e)
{
float x = e->x() ;
float y = height() - e->y() ;
// find which node is selected
for(uint32_t i=0;i<_node_coords.size();++i)
if( pow(_node_coords[i].x - x,2)+pow(_node_coords[i].y - y,2) < 10*10 )
{
if(e->button() == Qt::LeftButton)
{
_current_selected_node = i ;
_dragging = true ;
updateGL() ;
emit nodeSelected(i) ;
return ;
}
if(e->button() == Qt::RightButton)
{
_current_acted_node = i ;
emit customContextMenuRequested(QPoint(e->x(),e->y())) ;
return ;
}
}
_dragging = false ;
_current_selected_node = -1 ;
}
void NetworkViewer::calculateForces(const Network::NodeId& node_id,const double *map,int W,int H,float x,float y,float /*speedf*/,float& new_x, float& new_y)
{
#ifdef A_FAIRE
if (mouseGrabberItem() == this)
{
new_x = x ;
new_y = y ;
return;
}
#endif
// Sum up all forces pushing this item away
qreal xforce = 0;
qreal yforce = 0;
float dei=0.0f ;
float dej=0.0f ;
static float *e = NULL ;
static const int KS = 5 ;
if(e == NULL)
{
e = new float[(2*KS+1)*(2*KS+1)] ;
for(int i=-KS;i<=KS;++i)
for(int j=-KS;j<=KS;++j)
e[i+KS+(2*KS+1)*(j+KS)] = exp( -(i*i+j*j)/30.0 ) ; // can be precomputed
}
for(int i=-KS;i<=KS;++i)
for(int j=-KS;j<=KS;++j)
{
int X = std::min(W-1,std::max(0,(int)rint(x/(float)width()*W))) ;
int Y = std::min(H-1,std::max(0,(int)rint(y/(float)height()*H))) ;
float val = map[2*((i+X+W)%W + W*((j+Y+H)%H))] ;
dei += i * e[i+KS+(2*KS+1)*(j+KS)] * val ;
dej += j * e[i+KS+(2*KS+1)*(j+KS)] * val ;
}
xforce = REPULSION_FACTOR * dei/25.0;
yforce = REPULSION_FACTOR * dej/25.0;
// Now subtract all forces pulling items together
//
const std::set<Network::NodeId>& neighbs(_network.neighbors(node_id)) ;
double weight = neighbs.size() + 1 ;
for(std::set<Network::NodeId>::const_iterator it(neighbs.begin());it!=neighbs.end();++it)
{
NodeCoord pos;
double w2 ; // This factor makes the edge length depend on connectivity, so clusters of friends tend to stay in the
// same location.
//
pos.x = _node_coords[*it].x - x ; //mapFromItem(edge->destNode(), 0, 0);
pos.y = _node_coords[*it].y - y ; //mapFromItem(edge->destNode(), 0, 0);
w2 = sqrtf(std::min(neighbs.size(),_network.neighbors(*it).size())) ;
float dist = sqrtf(pos.x*pos.x + pos.y*pos.y) ;
float val = dist - NODE_DISTANCE * w2 ;
xforce += 0.01*pos.x * val / weight;
yforce += 0.01*pos.y * val / weight;
}
xforce -= FRICTION_FACTOR * _node_speeds[node_id].x ;
yforce -= FRICTION_FACTOR * _node_speeds[node_id].y ;
// This term drags nodes away from the sides.
//
if(x < 15) xforce += 100.0/(x+0.1) ;
if(y < 15) yforce += 100.0/(y+0.1) ;
if(x > width()-15) xforce -= 100.0/(width()-x+0.1) ;
if(y > height()-15) yforce -= 100.0/(height()-y+0.1) ;
// now time filter:
_node_speeds[node_id].x += xforce / MASS_FACTOR;
_node_speeds[node_id].y += yforce / MASS_FACTOR;
if(_node_speeds[node_id].x > 10) _node_speeds[node_id].x = 10.0f ;
if(_node_speeds[node_id].y > 10) _node_speeds[node_id].y = 10.0f ;
if(_node_speeds[node_id].x <-10) _node_speeds[node_id].x =-10.0f ;
if(_node_speeds[node_id].y <-10) _node_speeds[node_id].y =-10.0f ;
new_x = x + _node_speeds[node_id].x ;
new_y = y + _node_speeds[node_id].y ;
new_x = std::min(std::max(new_x, 10.0f), width() - 10.0f);
new_y = std::min(std::max(new_y, 10.0f), height() - 10.0f);
}
void NetworkViewer::contextMenu(QPoint p)
{
std::cerr << "Context menu request at point " << p.x() << " " << p.y() << std::endl;
QMenu contextMnu ;//= ui.msgText->createStandardContextMenu(matrix.map(point));
contextMnu.addAction(action_ManageHash);
if(_current_acted_node == -1)
return ;
std::cerr << "acting on node " << _network.node(_current_acted_node).id() << std::endl;
// make a list of hashes provided by all nodes except this one
std::set<TurtleFileHash> managed_hashes ;
std::set<TurtleFileHash> provided_hashes ;
for(uint32_t i=0;i<_network.n_nodes();++i)
if(i != _current_acted_node)
{
managed_hashes.insert( _network.node(i).managedHashes().begin(), _network.node(i).managedHashes().end()) ;
provided_hashes.insert( _network.node(i).providedHashes().begin(), _network.node(i).providedHashes().end()) ;
}
if(!managed_hashes.empty())
{
QMenu *Mnu2 = contextMnu.addMenu("Provide hash") ;
for(std::set<TurtleFileHash>::const_iterator it(managed_hashes.begin());it!=managed_hashes.end();++it)
{
QAction* provide_hash_action = new QAction(QString::fromStdString((*it).toStdString()), Mnu2);
connect(provide_hash_action, SIGNAL(triggered()), this, SLOT(actionProvideHash()));
Mnu2->addAction(provide_hash_action);
}
}
if(!provided_hashes.empty())
{
QMenu *Mnu2 = contextMnu.addMenu("Manage hash") ;
for(std::set<TurtleFileHash>::const_iterator it(provided_hashes.begin());it!=provided_hashes.end();++it)
{
QAction* manage_hash_action = new QAction(QString::fromStdString((*it).toStdString()), Mnu2);
connect(manage_hash_action, SIGNAL(triggered()), this, SLOT(actionManageHash()));
Mnu2->addAction(manage_hash_action);
}
}
contextMnu.exec(mapToGlobal(p));
}
void NetworkViewer::actionManageHash()
{
if(_current_acted_node < 0)
return ;
RsFileHash hash ;
if(qobject_cast<QAction*>(sender())->text().length() == 40) //data().toString().toStdString();
{
hash = RsFileHash(qobject_cast<QAction*>(sender())->text().toStdString()) ;
std::cerr << "Managing existing hash " << hash << std::endl;
}
else
{
std::cerr << "Managing random hash..." << std::endl;
hash = RsFileHash::random() ;
}
std::cerr << " current node = " << _current_acted_node << std::endl ;
std::cerr << " adding random hash = " << hash << std::endl;
_network.node(_current_acted_node).manageFileHash(hash) ;
updateGL() ;
}
void NetworkViewer::actionProvideHash()
{
QString hash = qobject_cast<QAction*>(sender())->text() ;//data().toString().toStdString();
if(_current_acted_node < 0)
return ;
std::cerr << "Providing hash " << hash.toStdString() << std::endl;
_network.node(_current_acted_node).provideFileHash(RsFileHash(hash.toStdString())) ;
updateGL() ;
}

View file

@ -0,0 +1,79 @@
#include <QPoint>
#include <QGLViewer/qglviewer.h>
// The network simulator GUI has the following functionalities:
//
// 1 - show the network graph
// * the graph should spread in space automatically. We should use the code from the NetworkView for that.
// * each edge will be drawn with a color that displays used bandwidth along the edge, or TR sent to the edge, etc.
// * individual tunnels should be shown, in order to see what shape they have
//
// 2 - show info about each node. One needs a node widget that gets updated with whatever is to be read from the current node
//
// 3 - buttons to re-initiate a new network, or reset the network.
//
// 4 - buttons to inject information into the network:
// * shared files in some nodes. Should be handled by derivign the component that the turtle router accesses for local searches.
// * file requests in other nodes. Eazy: one just needs to ask the turtle router of the node to handle the hash.
//
// 5 - perturbate the network
// * change the load of each node, and the delay when forwarding requests.
//
#include "Network.h"
class NetworkViewer: public QGLViewer
{
Q_OBJECT
public:
NetworkViewer(QWidget *parent,Network& network) ;
virtual void draw() ;
virtual void keyPressEvent(QKeyEvent *) {}
virtual void mousePressEvent(QMouseEvent *) ;
virtual void mouseReleaseEvent(QMouseEvent *) ;
virtual void mouseMoveEvent(QMouseEvent *) ;
const Network& network() const { return _network ; }
Network& network() { return _network ; }
signals:
void nodeSelected(int) ;
public slots:
void timerEvent(QTimerEvent *) ;
void contextMenu(QPoint) ;
void actionManageHash() ;
void actionProvideHash() ;
private:
void calculateForces(const Network::NodeId& node_id,const double *map,int W,int H,float x,float y,float /*speedf*/,float& new_x, float& new_y) ;
typedef struct
{
float x ;
float y ;
} NodeCoord ;
Network& _network ;
std::vector<NodeCoord> _node_coords ;
std::vector<NodeCoord> _node_speeds ;
static const float MASS_FACTOR = 10 ;
static const float FRICTION_FACTOR = 15.8 ;
static const float REPULSION_FACTOR = 8 ;
static const float NODE_DISTANCE = 30.0 ;
int timerId ;
int _current_selected_node ;
int _current_displayed_node ;
int _current_acted_node ;
bool _dragging ;
bool _nodes_need_recomputing ;
QAction *action_ManageHash ;
QAction *action_ProvideHash ;
};

View file

@ -0,0 +1,47 @@
#include <QTimer>
#include "RsAutoUpdatePage.h"
bool RsAutoUpdatePage::_locked = false ;
RsAutoUpdatePage::RsAutoUpdatePage(int ms_update_period, QWidget *parent, Qt::WindowFlags flags)
: QWidget(parent, flags)
{
_timer = new QTimer ;
_timer->setInterval(ms_update_period);
_timer->setSingleShot(true);
QObject::connect(_timer,SIGNAL(timeout()),this,SLOT(timerUpdate())) ;
_timer->start() ;
}
RsAutoUpdatePage::~RsAutoUpdatePage()
{
if(_timer != NULL)
delete _timer ;
_timer = NULL ;
}
void RsAutoUpdatePage::showEvent(QShowEvent */*event*/)
{
//std::cout << "RsAutoUpdatePage::showEvent() In show event !!" << std::endl ;
if(!_locked)
updateDisplay();
}
void RsAutoUpdatePage::timerUpdate()
{
// only update when the widget is visible.
//
if(_locked == false && isVisible()) {
updateDisplay();
update() ; // Qt flush
}
_timer->start() ;
}
void RsAutoUpdatePage::lockAllEvents() { _locked = true ; }
void RsAutoUpdatePage::unlockAllEvents() { _locked = false ; }
bool RsAutoUpdatePage::eventsLocked() { return _locked ; }

View file

@ -0,0 +1,40 @@
#pragma once
#include <QApplication>
#include <QWidget>
// This class implement a basic RS functionality which is that widgets displayign info
// should update regularly. They also should update only when visible, to save CPU time.
//
// Using this class simply needs to derive your widget from RsAutoUpdateWidget
// and oveload the update() function with the actual code that updates the
// widget.
//
class QTimer ;
class RsAutoUpdatePage: public QWidget
{
Q_OBJECT
public:
RsAutoUpdatePage(int ms_update_period = 1000, QWidget *parent = NULL, Qt::WindowFlags flags = 0) ;
virtual ~RsAutoUpdatePage() ;
virtual void updateDisplay() {}
static void lockAllEvents() ;
static void unlockAllEvents() ;
static bool eventsLocked() ;
protected:
virtual void showEvent(QShowEvent *e) ;
private slots:
void timerUpdate() ;
private:
QTimer *_timer ;
static bool _locked ;
};

View file

@ -0,0 +1,318 @@
/****************************************************************
* RetroShare is distributed under the following license:
*
* Copyright (C) 20011, RetroShare Team
*
* 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., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
****************************************************************/
#include <iostream>
#include <QTimer>
#include <QObject>
#include <QPainter>
#include <QStylePainter>
#include <retroshare/rsturtle.h>
#include <retroshare/rspeers.h>
#include "TurtleRouterStatistics.h"
static const int MAX_TUNNEL_REQUESTS_DISPLAY = 10 ;
class TRHistogram
{
public:
TRHistogram(const std::vector<TurtleRequestDisplayInfo >& info) :_infos(info) {}
QColor colorScale(float f)
{
if(f == 0)
return QColor::fromHsv(0,0,192) ;
else
return QColor::fromHsv((int)((1.0-f)*280),200,255) ;
}
virtual void draw(QPainter *painter,int& ox,int& oy,const QString& title)
{
static const int MaxTime = 61 ;
static const int MaxDepth = 8 ;
static const int cellx = 7 ;
static const int celly = 12 ;
int save_ox = ox ;
painter->setPen(QColor::fromRgb(0,0,0)) ;
painter->drawText(2+ox,celly+oy,title) ;
oy+=2+2*celly ;
if(_infos.empty())
return ;
ox += 10 ;
std::map<RsPeerId,std::vector<int> > hits ;
std::map<RsPeerId,std::vector<int> > depths ;
std::map<RsPeerId,std::vector<int> >::iterator it ;
int max_hits = 1;
int max_depth = 1;
for(uint32_t i=0;i<_infos.size();++i)
{
std::vector<int>& h(hits[_infos[i].source_peer_id]) ;
std::vector<int>& g(depths[_infos[i].source_peer_id]) ;
if(h.size() <= _infos[i].age)
h.resize(MaxTime,0) ;
if(g.empty())
g.resize(MaxDepth,0) ;
if(_infos[i].age < h.size())
{
h[_infos[i].age]++ ;
if(h[_infos[i].age] > max_hits)
max_hits = h[_infos[i].age] ;
}
if(_infos[i].depth < g.size())
{
g[_infos[i].depth]++ ;
if(g[_infos[i].depth] > max_depth)
max_depth = g[_infos[i].depth] ;
}
}
int max_bi = std::max(max_hits,max_depth) ;
int p=0 ;
for(it=depths.begin();it!=depths.end();++it,++p)
for(int i=0;i<MaxDepth;++i)
painter->fillRect(ox+MaxTime*cellx+20+i*cellx,oy+p*celly,cellx,celly,colorScale(it->second[i]/(float)max_bi)) ;
painter->setPen(QColor::fromRgb(0,0,0)) ;
painter->drawRect(ox+MaxTime*cellx+20,oy,MaxDepth*cellx,p*celly) ;
for(int i=0;i<MaxTime;i+=5)
painter->drawText(ox+i*cellx,oy+(p+1)*celly+4,QString::number(i)) ;
p=0 ;
int great_total = 0 ;
for(it=hits.begin();it!=hits.end();++it,++p)
{
int total = 0 ;
for(int i=0;i<MaxTime;++i)
{
painter->fillRect(ox+i*cellx,oy+p*celly,cellx,celly,colorScale(it->second[i]/(float)max_bi)) ;
total += it->second[i] ;
}
painter->setPen(QColor::fromRgb(0,0,0)) ;
painter->drawText(ox+MaxDepth*cellx+30+(MaxTime+1)*cellx,oy+(p+1)*celly,TurtleRouterStatistics::getPeerName(it->first)) ;
painter->drawText(ox+MaxDepth*cellx+30+(MaxTime+1)*cellx+120,oy+(p+1)*celly,"("+QString::number(total)+")") ;
great_total += total ;
}
painter->drawRect(ox,oy,MaxTime*cellx,p*celly) ;
for(int i=0;i<MaxTime;i+=5)
painter->drawText(ox+i*cellx,oy+(p+1)*celly+4,QString::number(i)) ;
for(int i=0;i<MaxDepth;i++)
painter->drawText(ox+MaxTime*cellx+20+i*cellx,oy+(p+1)*celly+4,QString::number(i)) ;
painter->setPen(QColor::fromRgb(255,130,80)) ;
painter->drawText(ox+MaxDepth*cellx+30+(MaxTime+1)*cellx+120,oy+(p+1)*celly+4,"("+QString::number(great_total)+")");
oy += (p+1)*celly+6 ;
painter->setPen(QColor::fromRgb(0,0,0)) ;
painter->drawText(ox,oy+celly,"("+QApplication::translate("TurtleRouterStatistics", "Age in seconds")+")");
painter->drawText(ox+MaxTime*cellx+20,oy+celly,"("+QApplication::translate("TurtleRouterStatistics", "Depth")+")");
painter->drawText(ox+MaxDepth*cellx+30+(MaxTime+1)*cellx+120,oy+celly,"("+QApplication::translate("TurtleRouterStatistics", "total")+")");
oy += 3*celly ;
// now, draw a scale
int last_hts = -1 ;
int cellid = 0 ;
for(int i=0;i<=10;++i)
{
int hts = (int)(max_bi*i/10.0) ;
if(hts > last_hts)
{
painter->fillRect(ox+cellid*(cellx+22),oy,cellx,celly,colorScale(i/10.0f)) ;
painter->setPen(QColor::fromRgb(0,0,0)) ;
painter->drawRect(ox+cellid*(cellx+22),oy,cellx,celly) ;
painter->drawText(ox+cellid*(cellx+22)+cellx+4,oy+celly,QString::number(hts)) ;
last_hts = hts ;
++cellid ;
}
}
oy += celly*2 ;
ox = save_ox ;
}
private:
const std::vector<TurtleRequestDisplayInfo>& _infos ;
};
TurtleRouterStatistics::TurtleRouterStatistics(QWidget *parent)
: RsAutoUpdatePage(2000,parent)
{
setupUi(this) ;
_turtle = NULL ;
_tunnel_statistics_F->setWidget( _tst_CW = new TurtleRouterStatisticsWidget() ) ;
_tunnel_statistics_F->setWidgetResizable(true);
_tunnel_statistics_F->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
_tunnel_statistics_F->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
_tunnel_statistics_F->viewport()->setBackgroundRole(QPalette::NoRole);
_tunnel_statistics_F->setFrameStyle(QFrame::NoFrame);
_tunnel_statistics_F->setFocusPolicy(Qt::NoFocus);
}
TurtleRouterStatistics::~TurtleRouterStatistics()
{
}
void TurtleRouterStatistics::updateDisplay()
{
if(_turtle == NULL)
return ;
std::vector<std::vector<std::string> > hashes_info ;
std::vector<std::vector<std::string> > tunnels_info ;
std::vector<TurtleRequestDisplayInfo > search_reqs_info ;
std::vector<TurtleRequestDisplayInfo > tunnel_reqs_info ;
_turtle->getInfo(hashes_info,tunnels_info,search_reqs_info,tunnel_reqs_info) ;
//updateTunnelRequests(hashes_info,tunnels_info,search_reqs_info,tunnel_reqs_info) ;
_tst_CW->updateTunnelStatistics(hashes_info,tunnels_info,search_reqs_info,tunnel_reqs_info,_turtle) ;
_tst_CW->update();
}
QString TurtleRouterStatistics::getPeerName(const RsPeerId& peer_id)
{
static std::map<RsPeerId, QString> names ;
std::map<RsPeerId,QString>::const_iterator it = names.find(peer_id) ;
if( it != names.end())
return it->second ;
else
return (names[peer_id] = QString::fromStdString(peer_id.toStdString())) ;
}
TurtleRouterStatisticsWidget::TurtleRouterStatisticsWidget(QWidget *parent)
: QWidget(parent)
{
maxWidth = 200 ;
maxHeight = 0 ;
}
void TurtleRouterStatisticsWidget::updateTunnelStatistics(const std::vector<std::vector<std::string> >& /*hashes_info*/,
const std::vector<std::vector<std::string> >& /*tunnels_info*/,
const std::vector<TurtleRequestDisplayInfo >& search_reqs_info,
const std::vector<TurtleRequestDisplayInfo >& tunnel_reqs_info,
const RsTurtle *turtle)
{
static const int cellx = 6 ;
static const int celly = 10+4 ;
QPixmap tmppixmap(maxWidth, maxHeight);
tmppixmap.fill(this, 0, 0);
setFixedHeight(maxHeight);
QPainter painter(&tmppixmap);
painter.initFrom(this);
maxHeight = 500 ;
// std::cerr << "Drawing into pixmap of size " << maxWidth << "x" << maxHeight << std::endl;
// draw...
int ox=5,oy=5 ;
TRHistogram(search_reqs_info).draw(&painter,ox,oy,tr("Search requests repartition") + ":") ;
painter.setPen(QColor::fromRgb(70,70,70)) ;
painter.drawLine(0,oy,maxWidth,oy) ;
oy += celly ;
TRHistogram(tunnel_reqs_info).draw(&painter,ox,oy,tr("Tunnel requests repartition") + ":") ;
// now give information about turtle traffic.
//
TurtleTrafficStatisticsInfo info ;
turtle->getTrafficStatistics(info) ;
painter.setPen(QColor::fromRgb(70,70,70)) ;
painter.drawLine(0,oy,maxWidth,oy) ;
oy += celly ;
painter.drawText(ox,oy+celly,tr("Turtle router traffic")+":") ; oy += celly*2 ;
painter.drawText(ox+2*cellx,oy+celly,tr("Tunnel requests Up")+"\t: " + speedString(info.tr_up_Bps) ) ; oy += celly ;
painter.drawText(ox+2*cellx,oy+celly,tr("Tunnel requests Dn")+"\t: " + speedString(info.tr_dn_Bps) ) ; oy += celly ;
painter.drawText(ox+2*cellx,oy+celly,tr("Incoming file data")+"\t: " + speedString(info.data_dn_Bps) ) ; oy += celly ;
painter.drawText(ox+2*cellx,oy+celly,tr("Outgoing file data")+"\t: " + speedString(info.data_up_Bps) ) ; oy += celly ;
painter.drawText(ox+2*cellx,oy+celly,tr("Forwarded data ")+"\t: " + speedString(info.unknown_updn_Bps) ) ; oy += celly ;
QString prob_string ;
for(uint i=0;i<info.forward_probabilities.size();++i)
prob_string += QString::number(info.forward_probabilities[i],'g',2) + " (" + QString::number(i) + ") " ;
painter.drawText(ox+2*cellx,oy+celly,tr("TR Forward probabilities")+"\t: " + prob_string ) ;
oy += celly ;
oy += celly ;
// update the pixmap
//
pixmap = tmppixmap;
maxHeight = oy ;
}
QString TurtleRouterStatisticsWidget::speedString(float f)
{
if(f < 1.0f)
return QString("0 B/s") ;
if(f < 1024.0f)
return QString::number((int)f)+" B/s" ;
return QString::number(f/1024.0,'f',2) + " KB/s";
}
void TurtleRouterStatisticsWidget::paintEvent(QPaintEvent */*event*/)
{
QStylePainter(this).drawPixmap(0, 0, pixmap);
}
void TurtleRouterStatisticsWidget::resizeEvent(QResizeEvent *event)
{
QRect TaskGraphRect = geometry();
maxWidth = TaskGraphRect.width();
maxHeight = TaskGraphRect.height() ;
QWidget::resizeEvent(event);
update();
}

View file

@ -0,0 +1,74 @@
/****************************************************************
* RetroShare is distributed under the following license:
*
* Copyright (C) 20011, RetroShare Team
*
* 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., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
****************************************************************/
#pragma once
#include <QPoint>
#include <retroshare/rsturtle.h>
#include "ui_TurtleRouterStatistics.h"
#include "RsAutoUpdatePage.h"
class TurtleRouterStatisticsWidget ;
class TurtleRouterStatistics: public RsAutoUpdatePage, public Ui::TurtleRouterStatistics
{
Q_OBJECT
public:
TurtleRouterStatistics(QWidget *parent = NULL) ;
~TurtleRouterStatistics();
// Cache for peer names.
static QString getPeerName(const RsPeerId& peer_id) ;
void setTurtleRouter(const RsTurtle *turtle) { _turtle = turtle ; }
private:
virtual void updateDisplay() ;
TurtleRouterStatisticsWidget *_tst_CW ;
const RsTurtle *_turtle ;
} ;
class TurtleRouterStatisticsWidget: public QWidget
{
Q_OBJECT
public:
TurtleRouterStatisticsWidget(QWidget *parent = NULL) ;
virtual void paintEvent(QPaintEvent *event) ;
virtual void resizeEvent(QResizeEvent *event);
void updateTunnelStatistics( const std::vector<std::vector<std::basic_string<char> > >&,
const std::vector<std::vector<std::basic_string<char> > >&,
const std::vector<TurtleRequestDisplayInfo >&,
const std::vector<TurtleRequestDisplayInfo >&,
const RsTurtle *turtle) ;
private:
static QString speedString(float f) ;
QPixmap pixmap ;
int maxWidth,maxHeight ;
};

View file

@ -0,0 +1,55 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>TurtleRouterStatistics</class>
<widget class="QWidget" name="TurtleRouterStatistics">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>611</width>
<height>408</height>
</rect>
</property>
<property name="windowTitle">
<string>Router Statistics</string>
</property>
<property name="windowIcon">
<iconset resource="images.qrc">
<normaloff>:/images/rstray3.png</normaloff>:/images/rstray3.png</iconset>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QSplitter" name="splitter">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<widget class="QScrollArea" name="_tunnel_statistics_F">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="widgetResizable">
<bool>true</bool>
</property>
<widget class="QWidget" name="scrollAreaWidgetContents">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>593</width>
<height>390</height>
</rect>
</property>
</widget>
</widget>
</widget>
</item>
</layout>
</widget>
<resources>
<include location="images.qrc"/>
</resources>
<connections/>
</ui>

View file

@ -0,0 +1,19 @@
TEMPLATE = app
CONFIG *= qt qglviewer
QT *= xml opengl
INCLUDEPATH *= ../.. ..
TARGET = NetworkSim
DESTDIR = bin
SOURCES = main.cpp NetworkViewer.cpp NetworkSimulatorGUI.cpp \
TurtleRouterStatistics.cpp RsAutoUpdatePage.cpp
HEADERS = NetworkViewer.h NetworkSimulatorGUI.h \
TurtleRouterStatistics.h RsAutoUpdatePage.h
FORMS = NetworkSimulatorGUI.ui TurtleRouterStatistics.ui
LIBS *= ../../../lib/libretroshare.a ../../../../../libbitdht/src/lib/libbitdht.a ../../../../../../lib/sqlcipher/.libs/libsqlcipher.a ../../../../../openpgpsdk/src/lib/libops.a -lgnome-keyring -lupnp -lssl -lcrypto -lbz2 -lixml

View file

@ -0,0 +1,58 @@
#include <fenv.h>
#include "Network.h"
#include "NetworkSimulatorGUI.h"
#include "MonitoredRsPeers.h"
#include <QApplication>
#include <util/argstream.h>
int main(int argc, char *argv[])
{
feenableexcept(FE_INVALID) ;
feenableexcept(FE_DIVBYZERO) ;
#ifndef DEBUG
try
{
#endif
argstream as(argc,argv) ;
bool show_gui = false;
int nb_nodes = 20 ;
float connexion_probability = 0.2 ;
as >> option('i',"gui",show_gui,"show gui (vs. do the pipeline automatically)")
>> parameter('n',"nodes",nb_nodes,"number of nodes in the network",false)
>> parameter('p',"connexion probability",connexion_probability,"probability that two nodes are connected (exponential law)",false)
>> help() ;
as.defaultErrorHandling() ;
// 2 - call the full pipeline
Network network ;
network.initRandom(nb_nodes,connexion_probability) ;
rsPeers = new MonitoredRsPeers(network) ;
if(show_gui)
{
QApplication app(argc,argv) ;
NetworkSimulatorGUI pgui(network);
pgui.show() ;
return app.exec() ;
}
return 0 ;
#ifndef DEBUG
}
catch(std::exception& e)
{
std::cerr << "Unhandled exception: " << e.what() << std::endl;
return 1 ;
}
#endif
}