diff --git a/libretroshare/src/retroshare/rsturtle.h b/libretroshare/src/retroshare/rsturtle.h index 2194bfaaf..ebe3a9b1f 100644 --- a/libretroshare/src/retroshare/rsturtle.h +++ b/libretroshare/src/retroshare/rsturtle.h @@ -26,6 +26,8 @@ * */ +#pragma once + #include #include #include @@ -39,7 +41,7 @@ extern RsTurtle *rsTurtle ; typedef uint32_t TurtleRequestId ; // This is the structure used to send back results of the turtle search -// to the notifyBase class. +// to the notifyBase class, or send info to the GUI. struct TurtleFileInfo { @@ -48,6 +50,14 @@ struct TurtleFileInfo uint64_t size ; }; +struct TurtleRequestDisplayInfo +{ + uint32_t request_id ; // Id of the request + std::string source_peer_id ; // Peer that relayed the request + uint32_t age ; // Age in seconds + uint32_t depth ; // Depth of the request. Might be altered. +}; + // Interface class for turtle hopping. // // This class mainly interacts with the turtle router, that is responsible @@ -61,7 +71,7 @@ class RsTurtle public: enum FileSharingStrategy { SHARE_ENTIRE_NETWORK, SHARE_FRIENDS_ONLY } ; - RsTurtle() { _sharing_strategy = SHARE_ENTIRE_NETWORK ;} + RsTurtle() {} virtual ~RsTurtle() {} // Lauches a search request through the pipes, and immediately returns @@ -71,6 +81,11 @@ class RsTurtle virtual TurtleRequestId turtleSearch(const std::string& match_string) = 0 ; virtual TurtleRequestId turtleSearch(const LinearizedExpression& expr) = 0 ; + // Sets the file sharing strategy. It concerns all local files. It would + // be better to handle this for each file, of course. + + void setFileSharingStrategy(FileSharingStrategy f) { _sharing_strategy = f ; } + // Initiates tunnel handling for the given file hash. tunnels. Launches // an exception if an error occurs during the initialization process. The // turtle router itself does not initiate downloads, it only maintains @@ -84,18 +99,13 @@ class RsTurtle // virtual void stopMonitoringFileTunnels(const std::string& file_hash) = 0 ; - // Sets the file sharing strategy. It concerns all local files. It would - // be better to handle this for each file, of course. - - void setFileSharingStrategy(FileSharingStrategy f) { _sharing_strategy = f ; } - // Get info from the turtle router. I use std strings to hide the internal structs. virtual void getInfo(std::vector >&,std::vector >&, - std::vector >&,std::vector >&) const = 0; + std::vector&,std::vector&) const = 0; // Convenience function. virtual bool isTurtlePeer(const std::string& peer_id) const = 0 ; - + protected: FileSharingStrategy _sharing_strategy ; }; diff --git a/libretroshare/src/turtle/p3turtle.cc b/libretroshare/src/turtle/p3turtle.cc index c5992a01a..159ba3fda 100644 --- a/libretroshare/src/turtle/p3turtle.cc +++ b/libretroshare/src/turtle/p3turtle.cc @@ -2040,8 +2040,8 @@ static std::string printNumber(uint64_t num,bool hex=false) void p3turtle::getInfo( std::vector >& hashes_info, std::vector >& tunnels_info, - std::vector >& search_reqs_info, - std::vector >& tunnel_reqs_info) const + std::vector& search_reqs_info, + std::vector& tunnel_reqs_info) const { RsStackMutex stack(mTurtleMtx); /********** STACK LOCKED MTX ******/ @@ -2091,35 +2091,28 @@ void p3turtle::getInfo( std::vector >& hashes_info, for(std::map::const_iterator it(_search_requests_origins.begin());it!=_search_requests_origins.end();++it) { - search_reqs_info.push_back(std::vector()) ; - std::vector& search_req(search_reqs_info.back()) ; + TurtleRequestDisplayInfo info ; - search_req.push_back(printNumber(it->first,true)) ; + info.request_id = it->first ; + info.source_peer_id = it->second.origin ; + info.age = now - it->second.time_stamp ; + info.depth = it->second.depth ; - RsPeerDetails sslDetails; - if(rsPeers->getPeerDetails(it->second.origin,sslDetails)) - search_req.push_back(sslDetails.name + " - " + sslDetails.location) ; - else - search_req.push_back(it->second.origin) ; - - search_req.push_back(printNumber(now - it->second.time_stamp) + " secs ago") ; + search_reqs_info.push_back(info) ; } tunnel_reqs_info.clear(); for(std::map::const_iterator it(_tunnel_requests_origins.begin());it!=_tunnel_requests_origins.end();++it) { - tunnel_reqs_info.push_back(std::vector()) ; - std::vector& tunnel_req(tunnel_reqs_info.back()) ; + TurtleRequestDisplayInfo info ; - tunnel_req.push_back(printNumber(it->first,true)) ; - RsPeerDetails sslDetails; - if(rsPeers->getPeerDetails(it->second.origin,sslDetails)) - tunnel_req.push_back(sslDetails.name + " - " + sslDetails.location) ; - else - tunnel_req.push_back(it->second.origin) ; + info.request_id = it->first ; + info.source_peer_id = it->second.origin ; + info.age = now - it->second.time_stamp ; + info.depth = it->second.depth ; - tunnel_req.push_back(printNumber(now - it->second.time_stamp) + " secs ago") ; + tunnel_reqs_info.push_back(info) ; } } diff --git a/libretroshare/src/turtle/p3turtle.h b/libretroshare/src/turtle/p3turtle.h index 202f28951..e31e561fe 100644 --- a/libretroshare/src/turtle/p3turtle.h +++ b/libretroshare/src/turtle/p3turtle.h @@ -244,8 +244,8 @@ class p3turtle: public p3Service, /*public pqiMonitor,*/ public RsTurtle,/* publ /// get info about tunnels virtual void getInfo(std::vector >&, std::vector >&, - std::vector >&, - std::vector >&) const ; + std::vector&, + std::vector&) const ; #ifdef TO_REMOVE /************* from pqiMonitor *******************/ diff --git a/retroshare-gui/src/gui/FileTransferInfoWidget.cpp b/retroshare-gui/src/gui/FileTransferInfoWidget.cpp index f002e9b0a..d79d7e1a2 100644 --- a/retroshare-gui/src/gui/FileTransferInfoWidget.cpp +++ b/retroshare-gui/src/gui/FileTransferInfoWidget.cpp @@ -75,8 +75,8 @@ void FileTransferInfoWidget::updateDisplay() //std::cout << "got details for file " << nfo.fname << std::endl ; - pixmap = QPixmap(size()); - pixmap.fill(this, 0, 0); +// pixmap = QPixmap(size()); +// pixmap.fill(this, 0, 0); pixmap = QPixmap(maxWidth, maxHeight); pixmap.fill(this, 0, 0); setFixedHeight(maxHeight); diff --git a/retroshare-gui/src/gui/TurtleRouterDialog.cpp b/retroshare-gui/src/gui/TurtleRouterDialog.cpp index c67b004cd..1c542d103 100644 --- a/retroshare-gui/src/gui/TurtleRouterDialog.cpp +++ b/retroshare-gui/src/gui/TurtleRouterDialog.cpp @@ -1,10 +1,104 @@ #include #include +#include #include +#include #include "TurtleRouterDialog.h" +#include +#include static const int MAX_TUNNEL_REQUESTS_DISPLAY = 10 ; +class TRHistogram +{ + public: + TRHistogram(const std::vector& info) :_infos(info) {} + + QColor colorScale(float f) + { + 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 cellx = 6 ; + static const int celly = 10 ; + + 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 > hits ; + std::map >::iterator it ; + + int max_hits = 1; + for(uint32_t i=0;i<_infos.size();++i) + { + std::vector& h(hits[_infos[i].source_peer_id]) ; + + if(h.size() <= _infos[i].age) + h.resize(MaxTime,0) ; + + if(_infos[i].age < h.size()) + { + h[_infos[i].age]++ ; + if(h[_infos[i].age] > max_hits) + max_hits = h[_infos[i].age] ; + } + } + + int p=0 ; + + for(it=hits.begin();it!=hits.end();++it,++p) + { + int total = 0 ; + + for(int i=0;ifillRect(ox+i*cellx,oy+p*celly,cellx,celly,colorScale(it->second[i]/(float)max_hits)) ; + total += it->second[i] ; + } + + painter->setPen(QColor::fromRgb(0,0,0)) ; + painter->drawText(ox+(MaxTime+1)*cellx,oy+(p+1)*celly,TurtleRouterDialog::getPeerName(it->first)) ; + painter->drawText(ox+(MaxTime+1)*cellx+80,oy+(p+1)*celly,"("+QString::number(total)+")") ; + } + + painter->drawRect(ox,oy,MaxTime*cellx,p*celly) ; + + for(int i=0;idrawText(ox+i*cellx,oy+(p+1)*celly+4,QString::number(i)) ; + + oy += (p+1)*celly+4 ; + + painter->drawText(ox,oy+celly,QObject::tr("(Age in seconds)")); + oy += 3*celly ; + + // now, draw a scale + + for(int i=0;i<=10;++i) + { + painter->fillRect(ox+i*(cellx+40),oy,cellx,celly,colorScale(i/10.0f)) ; + painter->setPen(QColor::fromRgb(0,0,0)) ; + painter->drawRect(ox+i*(cellx+40),oy,cellx,celly) ; + painter->drawText(ox+i*(cellx+40)+cellx+4,oy+celly,QString::number((int)(max_hits*i/10.0))) ; + } + + oy += celly*2 ; + + ox = save_ox ; + } + + private: + const std::vector& _infos ; +}; + TurtleRouterDialog::TurtleRouterDialog(QWidget *parent) : RsAutoUpdatePage(2000,parent) { @@ -26,17 +120,47 @@ TurtleRouterDialog::TurtleRouterDialog(QWidget *parent) _f2f_TW->insertTopLevelItem(n++,top_level_t_requests) ; top_level_hashes.clear() ; + + QVBoxLayout v(_tunnel_statistics_F) ; + v.addWidget( _tst_CW = new TurtleRouterStatisticsWidget() ) ; } void TurtleRouterDialog::updateDisplay() { std::vector > hashes_info ; std::vector > tunnels_info ; - std::vector > search_reqs_info ; - std::vector > tunnel_reqs_info ; + std::vector search_reqs_info ; + std::vector tunnel_reqs_info ; rsTurtle->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) ; +} + +QString TurtleRouterDialog::getPeerName(const std::string& peer_id) +{ + static std::map names ; + + std::map::const_iterator it = names.find(peer_id) ; + + if( it != names.end()) + return it->second ; + else + { + RsPeerDetails detail ; + if(!rsPeers->getPeerDetails(peer_id,detail)) + return "unknown peer"; + + return (names[peer_id] = QString::fromStdString(detail.name)) ; + } +} + +void TurtleRouterDialog::updateTunnelRequests( const std::vector >& hashes_info, + const std::vector >& tunnels_info, + const std::vector& search_reqs_info, + const std::vector& tunnel_reqs_info) +{ // now display this in the QTableWidgets QStringList stl ; @@ -73,7 +197,7 @@ void TurtleRouterDialog::updateDisplay() for(uint i=0;isetText(0, tr("Search requests") + "(" + QString::number(search_reqs_info.size()) + ")" ) ; - int reqs_size = tunnel_reqs_info.size() ; - - for(uint i=0;i= reqs_size || i < MAX_TUNNEL_REQUESTS_DISPLAY) + for(uint i=0;i= tunnel_reqs_info.size() || i < MAX_TUNNEL_REQUESTS_DISPLAY) { - QString str = QString::fromStdString( "Request id: " + tunnel_reqs_info[i][0] + "\t from [" + tunnel_reqs_info[i][1] + "]\t " + tunnel_reqs_info[i][2]) ; + QString str = "Request id: " + QString::number(tunnel_reqs_info[i].request_id,16) + "\t from [" + getPeerName(tunnel_reqs_info[i].source_peer_id) + "]\t " + QString::number(tunnel_reqs_info[i].age)+" secs ago" ; stl.clear() ; stl.push_back(str) ; @@ -148,4 +270,47 @@ QTreeWidgetItem *TurtleRouterDialog::findParentHashItem(const std::string& hash) return items.front() ; } +TurtleRouterStatisticsWidget::TurtleRouterStatisticsWidget(QWidget *parent) + : QWidget(parent) +{ + maxWidth = 200 ; + maxHeight = 100 ; +} + +void TurtleRouterStatisticsWidget::updateTunnelStatistics(const std::vector >& hashes_info, + const std::vector >& tunnels_info, + const std::vector& search_reqs_info, + const std::vector& tunnel_reqs_info) + +{ + QPixmap tmppixmap(maxWidth, maxHeight); + tmppixmap.fill(this, 0, 0); + + QPainter painter(&tmppixmap); + painter.initFrom(this); + + // 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,QObject::tr("Evolution of search requests:")) ; + TRHistogram(tunnel_reqs_info).draw(&painter,ox,oy,QObject::tr("Evolution of tunnel requests:")) ; + + // update the pixmap + pixmap = tmppixmap; +} + +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); +} + diff --git a/retroshare-gui/src/gui/TurtleRouterDialog.h b/retroshare-gui/src/gui/TurtleRouterDialog.h index 931e6436a..955cb163f 100644 --- a/retroshare-gui/src/gui/TurtleRouterDialog.h +++ b/retroshare-gui/src/gui/TurtleRouterDialog.h @@ -1,16 +1,26 @@ #pragma once #include +#include #include "ui_TurtleRouterDialog.h" #include "RsAutoUpdatePage.h" +class TurtleRouterStatisticsWidget ; + class TurtleRouterDialog: public RsAutoUpdatePage, public Ui::TurtleRouterDialogForm { public: TurtleRouterDialog(QWidget *parent = NULL) ; - /** Default Constructor */ + // Cache for peer names. + static QString getPeerName(const std::string& peer_id) ; + private: + void updateTunnelRequests( const std::vector > >&, + const std::vector > >&, + const std::vector&, + const std::vector&) ; + virtual void updateDisplay() ; QTreeWidgetItem *findParentHashItem(const std::string& hash) ; @@ -18,4 +28,25 @@ class TurtleRouterDialog: public RsAutoUpdatePage, public Ui::TurtleRouterDialog QTreeWidgetItem *top_level_unknown_hashes ; QTreeWidgetItem *top_level_s_requests ; QTreeWidgetItem *top_level_t_requests ; + + TurtleRouterStatisticsWidget *_tst_CW ; } ; + +class TurtleRouterStatisticsWidget: public QWidget +{ + public: + TurtleRouterStatisticsWidget(QWidget *parent = NULL) ; + + virtual void paintEvent(QPaintEvent *event) ; + virtual void resizeEvent(QResizeEvent *event); + + void updateTunnelStatistics( const std::vector > >&, + const std::vector > >&, + const std::vector&, + const std::vector&) ; + + private: + QPixmap pixmap ; + int maxWidth,maxHeight ; +}; + diff --git a/retroshare-gui/src/gui/TurtleRouterDialog.ui b/retroshare-gui/src/gui/TurtleRouterDialog.ui index 1c26e77e4..8fa1d1db0 100644 --- a/retroshare-gui/src/gui/TurtleRouterDialog.ui +++ b/retroshare-gui/src/gui/TurtleRouterDialog.ui @@ -7,7 +7,7 @@ 0 0 865 - 553 + 525 @@ -17,17 +17,36 @@ :/images/rstray3.png:/images/rstray3.png - + - - - true + + + Qt::Vertical - - - F2F router information + + + true - + + + F2F router information + + + + + + + 0 + 0 + + + + QFrame::StyledPanel + + + QFrame::Raised + +