diff --git a/libretroshare/src/ft/ftserver.cc b/libretroshare/src/ft/ftserver.cc index 044380e81..49c476607 100644 --- a/libretroshare/src/ft/ftserver.cc +++ b/libretroshare/src/ft/ftserver.cc @@ -71,7 +71,8 @@ ftServer::ftServer(p3PeerMgr *pm, p3ServiceControl *sc) mPeerMgr(pm), mServiceCtrl(sc), mFileDatabase(NULL), mFtController(NULL), mFtExtra(NULL), - mFtDataplex(NULL), mFtSearch(NULL), srvMutex("ftServer") + mFtDataplex(NULL), mFtSearch(NULL), srvMutex("ftServer"), + mSearchCallbacksMapMutex("ftServer callbacks map") { addSerialType(new RsFileTransferSerialiser()) ; } @@ -1630,6 +1631,7 @@ int ftServer::tick() mFtDataplex->deleteUnusedServers() ; mFtDataplex->handlePendingCrcRequests() ; mFtDataplex->dispatchReceivedChunkCheckSum() ; + cleanTimedOutSearches(); } return moreToTick; @@ -1822,9 +1824,21 @@ int ftServer::handleIncoming() void ftServer::receiveSearchResult(RsTurtleFTSearchResultItem *item) { - // @Gio: add your thing here + bool hasCallback = false; - RsServer::notify()->notifyTurtleSearchResult(item->request_id,item->result) ; + { + RS_STACK_MUTEX(mSearchCallbacksMapMutex); + auto cbpt = mSearchCallbacksMap.find(item->request_id); + if(cbpt != mSearchCallbacksMap.end()) + { + hasCallback = true; + cbpt->second.first(item->result); + } + } // end RS_STACK_MUTEX(mSearchCallbacksMapMutex); + + if(!hasCallback) + RsServer::notify()->notifyTurtleSearchResult( + item->request_id, item->result ); } /***************************** CONFIG ****************************/ @@ -1839,3 +1853,38 @@ bool ftServer::addConfiguration(p3ConfigMgr *cfgmgr) return true; } +bool ftServer::turtleSearchRequest( + const std::string& matchString, + const std::function& results)>& multiCallback, + std::time_t maxWait ) +{ + if(matchString.empty()) + { + std::cerr << __PRETTY_FUNCTION__ << " match string can't be empty!" + << std::endl; + return false; + } + + TurtleRequestId sId = turtleSearch(matchString); + + RS_STACK_MUTEX(mSearchCallbacksMapMutex); + mSearchCallbacksMap.emplace( + sId, + std::make_pair( + multiCallback, + std::chrono::system_clock::now() + + std::chrono::seconds(maxWait) ) ); + + return true; +} + +void ftServer::cleanTimedOutSearches() +{ + RS_STACK_MUTEX(mSearchCallbacksMapMutex); + auto now = std::chrono::system_clock::now(); + for( auto cbpt = mSearchCallbacksMap.begin(); + cbpt != mSearchCallbacksMap.end(); ) + if(cbpt->second.second <= now) + cbpt = mSearchCallbacksMap.erase(cbpt); + else ++cbpt; +} diff --git a/libretroshare/src/ft/ftserver.h b/libretroshare/src/ft/ftserver.h index f79ffe8b5..5745d3d2b 100644 --- a/libretroshare/src/ft/ftserver.h +++ b/libretroshare/src/ft/ftserver.h @@ -39,6 +39,8 @@ #include #include #include +#include +#include #include "ft/ftdata.h" #include "turtle/turtleclientservice.h" @@ -143,6 +145,12 @@ public: virtual void setFilePermDirectDL(uint32_t perm) ; virtual uint32_t filePermDirectDL() ; + /// @see RsFiles + virtual bool turtleSearchRequest( + const std::string& matchString, + const std::function& results)>& multiCallback, + std::time_t maxWait = 300 ); + virtual TurtleSearchRequestId turtleSearch(const std::string& string_to_match) ; virtual TurtleSearchRequestId turtleSearch(const RsRegularExpression::LinearizedExpression& expr) ; @@ -313,6 +321,18 @@ private: std::map mEncryptedHashes ; // This map is such that sha1(it->second) = it->first std::map mEncryptedPeerIds ; // This map holds the hash to be used with each peer id std::map > mUploadLimitMap ; + + /** Store search callbacks with timeout*/ + std::map< + TurtleRequestId, + std::pair< + std::function& results)>, + std::chrono::system_clock::time_point > + > mSearchCallbacksMap; + RsMutex mSearchCallbacksMapMutex; + + /// Cleanup mSearchCallbacksMap + void cleanTimedOutSearches(); }; diff --git a/libretroshare/src/retroshare/rsfiles.h b/libretroshare/src/retroshare/rsfiles.h index 4fca503a7..b7bbe728f 100644 --- a/libretroshare/src/retroshare/rsfiles.h +++ b/libretroshare/src/retroshare/rsfiles.h @@ -24,6 +24,8 @@ #include #include #include +#include +#include #include "rstypes.h" #include "serialiser/rsserializable.h" @@ -315,8 +317,24 @@ public: virtual uint32_t getMaxUploadSlotsPerFriend()=0; virtual void setFilePermDirectDL(uint32_t perm)=0; virtual uint32_t filePermDirectDL()=0; - virtual TurtleRequestId turtleSearch(const std::string& string_to_match) =0; - virtual TurtleRequestId turtleSearch(const RsRegularExpression::LinearizedExpression& expr) =0; + + /** + * @brief Request remote files search + * @jsonapi{development} + * @param[in] matchString string to look for in the search + * @param multiCallback function that will be called each time a search + * result is received + * @param[in] maxWait maximum wait time in seconds for search results + * @return false on error, true otherwise + */ + virtual bool turtleSearchRequest( + const std::string& matchString, + const std::function& results)>& multiCallback, + std::time_t maxWait = 300 ) = 0; + + virtual TurtleRequestId turtleSearch(const std::string& string_to_match) = 0; + virtual TurtleRequestId turtleSearch( + const RsRegularExpression::LinearizedExpression& expr) = 0; /*** * Control of Downloads Priority. diff --git a/libretroshare/src/retroshare/rsturtle.h b/libretroshare/src/retroshare/rsturtle.h index c183e454c..6f5ac469c 100644 --- a/libretroshare/src/retroshare/rsturtle.h +++ b/libretroshare/src/retroshare/rsturtle.h @@ -38,30 +38,33 @@ class RsTurtle; /** * Pointer to global instance of RsTurtle service implementation - * @jsonapi{development} */ extern RsTurtle* rsTurtle; typedef uint32_t TurtleRequestId ; typedef RsPeerId TurtleVirtualPeerId; -// This is the structure used to send back results of the turtle search -// to the notifyBase class, or send info to the GUI. - -struct TurtleFileInfo //: RsSerializable +/** + * This is the structure used to send back results of the turtle search, + * to other peers, to the notifyBase class, to the search caller or to the GUI. + */ +struct TurtleFileInfo : RsSerializable { - RsFileHash hash; - std::string name; - uint64_t size; -/* + uint64_t size; /// File size + RsFileHash hash; /// File hash + std::string name; /// File name + /// @see RsSerializable::serial_process void serial_process( RsGenericSerializer::SerializeJob j, RsGenericSerializer::SerializeContext& ctx ) { - RS_SERIAL_PROCESS(hash); - RS_SERIAL_PROCESS(name); RS_SERIAL_PROCESS(size); - }*/ + RS_SERIAL_PROCESS(hash); + + // Use String TLV serial process for retrocompatibility + RsTypeSerializer::serial_process( + j, ctx, TLV_TYPE_STR_NAME, name, "name" ); + } }; struct TurtleTunnelRequestDisplayInfo diff --git a/libretroshare/src/turtle/rsturtleitem.cc b/libretroshare/src/turtle/rsturtleitem.cc index 3c51f7c29..7b5717eae 100644 --- a/libretroshare/src/turtle/rsturtleitem.cc +++ b/libretroshare/src/turtle/rsturtleitem.cc @@ -216,55 +216,6 @@ RsTurtleSearchResultItem *RsTurtleGenericSearchResultItem::duplicate() const return sr ; } -template<> uint32_t RsTypeSerializer::serial_size(const TurtleFileInfo& i) -{ - uint32_t s = 0 ; - - s += 8 ; // size - s += i.hash.SIZE_IN_BYTES ; - s += GetTlvStringSize(i.name) ; - - return s; -} - -template<> bool RsTypeSerializer::deserialize(const uint8_t data[],uint32_t size,uint32_t& offset,TurtleFileInfo& i) -{ - uint32_t saved_offset = offset ; - bool ok = true ; - - ok &= getRawUInt64(data, size, &offset, &i.size); // file size - ok &= i.hash.deserialise(data, size, offset); // file hash - ok &= GetTlvString(data, size, &offset, TLV_TYPE_STR_NAME, i.name); // file name - - if(!ok) - offset = saved_offset ; - - return ok; -} - -template<> bool RsTypeSerializer::serialize(uint8_t data[],uint32_t size,uint32_t& offset,const TurtleFileInfo& i) -{ - uint32_t saved_offset = offset ; - bool ok = true ; - - ok &= setRawUInt64(data, size, &offset, i.size); // file size - ok &= i.hash.serialise(data, size, offset); // file hash - ok &= SetTlvString(data, size, &offset, TLV_TYPE_STR_NAME, i.name); // file name - - if(!ok) - offset = saved_offset ; - - return ok; -} - -template<> void RsTypeSerializer::print_data(const std::string& n, const TurtleFileInfo& i) -{ - std::cerr << " [FileInfo ] " << n << " size=" << i.size << " hash=" << i.hash << ", name=" << i.name << std::endl; -} - -RS_TYPE_SERIALIZER_TO_JSON_NOT_IMPLEMENTED_DEF(TurtleFileInfo) -RS_TYPE_SERIALIZER_FROM_JSON_NOT_IMPLEMENTED_DEF(TurtleFileInfo) - void RsTurtleOpenTunnelItem::serial_process(RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx) { RsTypeSerializer::serial_process (j,ctx,file_hash ,"file_hash") ;