diff --git a/libretroshare/src/file_sharing/p3filelists.cc b/libretroshare/src/file_sharing/p3filelists.cc index c7b659a85..9a2663991 100644 --- a/libretroshare/src/file_sharing/p3filelists.cc +++ b/libretroshare/src/file_sharing/p3filelists.cc @@ -192,7 +192,7 @@ int p3FileDatabase::tick() mRemoteDirectories[i]->print(); #endif - locked_recursSweepRemoteDirectory(mRemoteDirectories[i],mRemoteDirectories[i]->root()) ; + locked_recursSweepRemoteDirectory(mRemoteDirectories[i],mRemoteDirectories[i]->root(),0) ; } mRemoteDirectories[i]->checkSave() ; @@ -549,6 +549,30 @@ bool p3FileDatabase::convertEntryIndexToPointer(const EntryIndex& e, uint32_t fi return true; } +void p3FileDatabase::requestDirUpdate(void *ref) +{ + uint32_t fi; + DirectoryStorage::EntryIndex e ; + + convertPointerToEntryIndex(ref,e,fi); + + if(fi == 0) + return ; // not updating current directory (should we?) + + time_t recurs_max_modf_TS_remote_time,local_update_TS; + + std::cerr << "Trying to force sync of entry ndex " << e << " to friend " << mRemoteDirectories[fi-1]->peerId() << std::endl; + + if(!mRemoteDirectories[fi-1]->getDirUpdateTS(e,recurs_max_modf_TS_remote_time,local_update_TS)) + { + std::cerr << " (EE) Cannot get max known recurs modf time!" << std::endl; + return ; + } + + if(generateAndSendSyncRequest(mRemoteDirectories[fi-1],e,recurs_max_modf_TS_remote_time)) + P3FILELISTS_DEBUG() << " Succeed." << std::endl; +} + // This function converts a pointer into directory details, to be used by the AbstractItemModel for browsing the files. int p3FileDatabase::RequestDirDetails(void *ref, DirDetails& d, FileSearchFlags flags) const @@ -1035,20 +1059,24 @@ void p3FileDatabase::handleDirSyncResponse(RsFileListsSyncResponseItem *item) } } -void p3FileDatabase::locked_recursSweepRemoteDirectory(RemoteDirectoryStorage *rds,DirectoryStorage::EntryIndex e) +void p3FileDatabase::locked_recursSweepRemoteDirectory(RemoteDirectoryStorage *rds,DirectoryStorage::EntryIndex e,int depth) { time_t now = time(NULL) ; + std::string indent(2*depth,' ') ; + // if not up to date, request update, and return (content is not certified, so no need to recurs yet). // if up to date, return, because TS is about the last modif TS below, so no need to recurs either. // get the info for this entry + P3FILELISTS_DEBUG() << "currently at entry index " << e << std::endl; + time_t recurs_max_modf_TS_remote_time,local_update_TS; if(!rds->getDirUpdateTS(e,recurs_max_modf_TS_remote_time,local_update_TS)) { - std::cerr << "(EE) lockec_recursSweepRemoteDirectory(): cannot get update TS for directory with index " << e << ". This is a consistency bug." << std::endl; + std::cerr << " (EE) lockec_recursSweepRemoteDirectory(): cannot get update TS for directory with index " << e << ". This is a consistency bug." << std::endl; return; } @@ -1056,73 +1084,89 @@ void p3FileDatabase::locked_recursSweepRemoteDirectory(RemoteDirectoryStorage *r if(now > local_update_TS + DELAY_BETWEEN_REMOTE_DIRECTORY_SYNC_REQ) // we need to compare local times only. We cannot compare local (now) with remote time. { - // check if a request already exists and is not too old either: no need to re-ask. + if(generateAndSendSyncRequest(rds,e,recurs_max_modf_TS_remote_time)) + P3FILELISTS_DEBUG() << " Asking for sync of directory " << e << " to peer " << rds->peerId() << " because it's " << (now - local_update_TS) << " secs old since last check." << std::endl; - DirSyncRequestId sync_req_id = makeDirSyncReqId(rds->peerId(),e) ; + // Dont recurs into sub-directories, since we dont know yet were to go. - std::map::iterator it = mPendingSyncRequests.find(sync_req_id) ; - - if(it != mPendingSyncRequests.end()) - { - P3FILELISTS_DEBUG() << "Not asking for sync of directory " << e << " to friend " << rds->peerId() << " because a recent pending request still exists." << std::endl; - return ; - } - - P3FILELISTS_DEBUG() << "Asking for sync of directory " << e << " to peer " << rds->peerId() << " because it's " << (now - local_update_TS) << " secs old since last check." << std::endl; - - RsFileListsSyncRequestItem *item = new RsFileListsSyncRequestItem ; - - if(!rds->getDirHashFromIndex(e,item->entry_hash) ) - { - std::cerr << "(EE) cannot find hash for entry index " << e << ". This is very unexpected." << std::endl; - return; - } - - item->flags = RsFileListsItem::FLAGS_SYNC_REQUEST ; - item->request_id = sync_req_id ; - item->last_known_recurs_modf_TS = recurs_max_modf_TS_remote_time ; - item->PeerId(rds->peerId()) ; - - DirSyncRequestData data ; - - data.request_TS = now ; - data.peer_id = item->PeerId(); - data.flags = item->flags; - - std::cerr << "Pushing req in pending list with peer id " << data.peer_id << std::endl; - - mPendingSyncRequests[sync_req_id] = data ; - - sendItem(item) ; // at end! Because item is destroyed by the process. - - // Dont recurs into sub-directories, since we dont know yet were to go. - - //return ; + //return ; } for(DirectoryStorage::DirIterator it(rds,e);it;++it) - locked_recursSweepRemoteDirectory(rds,*it); + locked_recursSweepRemoteDirectory(rds,*it,depth+1); } -p3FileDatabase::DirSyncRequestId p3FileDatabase::makeDirSyncReqId(const RsPeerId& peer_id,DirectoryStorage::EntryIndex e) +p3FileDatabase::DirSyncRequestId p3FileDatabase::makeDirSyncReqId(const RsPeerId& peer_id,const RsFileHash& hash) { -#warning needs to be improved. It's quite likely that random_bias and then e can be bruteforced from the result of this function static uint64_t random_bias = RSRandom::random_u64(); - uint64_t r = e ; + uint64_t r = 0 ; - // This is kind of arbitrary. The important thing is that the same ID needs to be generated every time for a given (peer_id,e) pair, in a way - // that cannot be brute-forced or reverse-engineered, which explains the random bias. + // This is kind of arbitrary. The important thing is that the same ID needs to be generated every time for a given (peer_id,entry index) pair, in a way + // that cannot be brute-forced or reverse-engineered, which explains the random bias and the usage of the hash, that is itself random. for(uint32_t i=0;igetDirHashFromIndex(e,entry_hash) ) + { + std::cerr << " (EE) cannot find hash for entry index " << e << ". This is very unexpected." << std::endl; + return false; + } + + // check if a request already exists and is not too old either: no need to re-ask. + + DirSyncRequestId sync_req_id = makeDirSyncReqId(rds->peerId(),entry_hash) ; + + std::map::iterator it = mPendingSyncRequests.find(sync_req_id) ; + + if(it != mPendingSyncRequests.end()) + { + P3FILELISTS_DEBUG() << " Not asking for sync of directory " << e << " to friend " << rds->peerId() << " because a recent pending request still exists." << std::endl; + return false ; + } + + RsFileListsSyncRequestItem *item = new RsFileListsSyncRequestItem ; + + item->entry_hash = entry_hash ; + item->flags = RsFileListsItem::FLAGS_SYNC_REQUEST ; + item->request_id = sync_req_id ; + item->last_known_recurs_modf_TS = max_known_recurs_modf_time ; + item->PeerId(rds->peerId()) ; + + DirSyncRequestData data ; + + data.request_TS = now ; + data.peer_id = item->PeerId(); + data.flags = item->flags; + + std::cerr << " Pushing req in pending list with peer id " << data.peer_id << std::endl; + + mPendingSyncRequests[sync_req_id] = data ; + + sendItem(item) ; // at end! Because item is destroyed by the process. + + return true; +} + + diff --git a/libretroshare/src/file_sharing/p3filelists.h b/libretroshare/src/file_sharing/p3filelists.h index ec5f1b517..8861ed26d 100644 --- a/libretroshare/src/file_sharing/p3filelists.h +++ b/libretroshare/src/file_sharing/p3filelists.h @@ -92,6 +92,7 @@ class p3FileDatabase: public p3Service, public p3Config, public ftSearch //, pub // void * here is the type expected by the abstract model index from Qt. It gets turned into a DirectoryStorage::EntryIndex internally. + void requestDirUpdate(void *ref) ; // triggers an update. Used when browsing. int RequestDirDetails(void *, DirDetails&, FileSearchFlags) const ; uint32_t getType(void *) const ; @@ -142,7 +143,15 @@ class p3FileDatabase: public p3Service, public p3Config, public ftSearch //, pub typedef uint64_t DirSyncRequestId ; - static DirSyncRequestId makeDirSyncReqId(const RsPeerId& peer_id,DirectoryStorage::EntryIndex e) ; + static DirSyncRequestId makeDirSyncReqId(const RsPeerId& peer_id, const RsFileHash &hash) ; + + /*! + * \brief generateAndSendSyncRequest + * \param rds Remote directory storage for the request + * \param e Entry index to update + * \return true if the request is correctly sent. + */ + bool generateAndSendSyncRequest(RemoteDirectoryStorage *rds,const DirectoryStorage::EntryIndex& e,time_t max_known_recurs_modf_time); // File sync request queues. The fast one is used for online browsing when friends are connected. // The slow one is used for background update of file lists. @@ -185,7 +194,7 @@ class p3FileDatabase: public p3Service, public p3Config, public ftSearch //, pub time_t mLastRemoteDirSweepTS ; // TS for friend list update std::map mPendingSyncRequests ; // pending requests, waiting for an answer - void locked_recursSweepRemoteDirectory(RemoteDirectoryStorage *rds,DirectoryStorage::EntryIndex e); + void locked_recursSweepRemoteDirectory(RemoteDirectoryStorage *rds, DirectoryStorage::EntryIndex e, int depth); // We use a shared file cache as well, to avoid re-hashing files with known modification TS and equal name. // diff --git a/libretroshare/src/ft/ftserver.cc b/libretroshare/src/ft/ftserver.cc index 1268ea831..4b4d4c1e3 100644 --- a/libretroshare/src/ft/ftserver.cc +++ b/libretroshare/src/ft/ftserver.cc @@ -345,7 +345,12 @@ bool ftServer::FileDownloadChunksDetails(const RsFileHash& hash,FileChunksInfo& return mFtController->getFileDownloadChunksDetails(hash,info); } - /* Directory Handling */ +void ftServer::requestDirUpdate(void *ref) +{ + mFileDatabase->requestDirUpdate(ref) ; +} + + /* Directory Handling */ void ftServer::setDownloadDirectory(std::string path) { mFtController->setDownloadDirectory(path); diff --git a/libretroshare/src/ft/ftserver.h b/libretroshare/src/ft/ftserver.h index 4e5ae3a61..da1deb009 100644 --- a/libretroshare/src/ft/ftserver.h +++ b/libretroshare/src/ft/ftserver.h @@ -199,6 +199,7 @@ public: /*** * Directory Handling ***/ + virtual void requestDirUpdate(void *ref) ; // triggers the update of the given reference. Used when browsing. virtual void setDownloadDirectory(std::string path); virtual void setPartialsDirectory(std::string path); virtual std::string getDownloadDirectory(); diff --git a/libretroshare/src/retroshare/rsfiles.h b/libretroshare/src/retroshare/rsfiles.h index cf1bfc157..d49324933 100644 --- a/libretroshare/src/retroshare/rsfiles.h +++ b/libretroshare/src/retroshare/rsfiles.h @@ -205,6 +205,8 @@ class RsFiles /*** * Directory Control ***/ + virtual void requestDirUpdate(void *ref) =0 ; // triggers the update of the given reference. Used when browsing. + virtual void setDownloadDirectory(std::string path) = 0; virtual void setPartialsDirectory(std::string path) = 0; virtual std::string getDownloadDirectory() = 0; diff --git a/retroshare-gui/src/gui/RemoteDirModel.cpp b/retroshare-gui/src/gui/RemoteDirModel.cpp index eb5800867..2153f255d 100644 --- a/retroshare-gui/src/gui/RemoteDirModel.cpp +++ b/retroshare-gui/src/gui/RemoteDirModel.cpp @@ -80,6 +80,11 @@ void RetroshareDirModel::treeStyle() peerIcon = QIcon(":/images/user/identity16.png"); } +void TreeStyle_RDM::updateRef(const QModelIndex& indx) const +{ + rsFiles->requestDirUpdate(indx.internalPointer()) ; +} + bool TreeStyle_RDM::hasChildren(const QModelIndex &parent) const { diff --git a/retroshare-gui/src/gui/RemoteDirModel.h b/retroshare-gui/src/gui/RemoteDirModel.h index 062a49a43..54f60ffad 100644 --- a/retroshare-gui/src/gui/RemoteDirModel.h +++ b/retroshare-gui/src/gui/RemoteDirModel.h @@ -78,6 +78,8 @@ class RetroshareDirModel : public QAbstractItemModel bool requestDirDetails(void *ref, bool remote,DirDetails& d) const; virtual void update() {} + virtual void updateRef(const QModelIndex&) const =0; + public: virtual QMimeData * mimeData ( const QModelIndexList & indexes ) const; virtual QStringList mimeTypes () const; @@ -167,7 +169,9 @@ class TreeStyle_RDM: public RetroshareDirModel virtual ~TreeStyle_RDM() ; protected: - /* These are all overloaded Virtual Functions */ + virtual void updateRef(const QModelIndex&) const ; + + /* These are all overloaded Virtual Functions */ virtual int rowCount(const QModelIndex &parent = QModelIndex()) const; virtual int columnCount(const QModelIndex &parent = QModelIndex()) const; @@ -203,7 +207,8 @@ class FlatStyle_RDM: public RetroshareDirModel void updateRefs() ; protected: - virtual void postMods(); + virtual void updateRef(const QModelIndex&) const {} + virtual void postMods(); virtual int rowCount(const QModelIndex &parent = QModelIndex()) const; virtual int columnCount(const QModelIndex &parent = QModelIndex()) const; diff --git a/retroshare-gui/src/gui/SharedFilesDialog.cpp b/retroshare-gui/src/gui/SharedFilesDialog.cpp index a0864839a..aaaa79284 100644 --- a/retroshare-gui/src/gui/SharedFilesDialog.cpp +++ b/retroshare-gui/src/gui/SharedFilesDialog.cpp @@ -228,6 +228,7 @@ RemoteSharedFilesDialog::RemoteSharedFilesDialog(QWidget *parent) ui.checkButton->hide() ; connect(ui.downloadButton, SIGNAL(clicked()), this, SLOT(downloadRemoteSelected())); + connect(ui.dirTreeView, SIGNAL( expanded(const QModelIndex & ) ), this, SLOT( expanded(const QModelIndex & ) ) ); // load settings processSettings(true); @@ -366,7 +367,6 @@ void SharedFilesDialog::changeCurrentViewModel(int viewTypeIndex) } // connect( ui.dirTreeView, SIGNAL( collapsed(const QModelIndex & ) ), this, SLOT( collapsed(const QModelIndex & ) ) ); -// connect( ui.dirTreeView, SIGNAL( expanded(const QModelIndex & ) ), this, SLOT( expanded(const QModelIndex & ) ) ); ui.dirTreeView->setModel(proxyModel); ui.dirTreeView->update(); @@ -517,6 +517,13 @@ QModelIndexList SharedFilesDialog::getSelected() return proxyList ; } +void RemoteSharedFilesDialog::expanded(const QModelIndex& indx) +{ + std::cerr << "Expanding at " << indx.row() << " and " << indx.column() << " ref=" << indx.internalPointer() << ", pointer at 1: " << proxyModel->mapToSource(indx).internalPointer() << std::endl; + + model->updateRef(proxyModel->mapToSource(indx)) ; +} + void RemoteSharedFilesDialog::downloadRemoteSelected() { /* call back to the model (which does all the interfacing? */ diff --git a/retroshare-gui/src/gui/SharedFilesDialog.h b/retroshare-gui/src/gui/SharedFilesDialog.h index 9b7387224..594df6fab 100644 --- a/retroshare-gui/src/gui/SharedFilesDialog.h +++ b/retroshare-gui/src/gui/SharedFilesDialog.h @@ -196,6 +196,7 @@ class RemoteSharedFilesDialog : public SharedFilesDialog private slots: void downloadRemoteSelected(); + void expanded(const QModelIndex& indx); }; #endif