Changeset 2738

Show
Ignore:
Timestamp:
03/02/06 00:41:31 (3 years ago)
Author:
madcat
Message:

Support for global searching.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • hydranode/hncore/ed2k/clientlist.cpp

    r2706 r2738  
    813813                        ServerList::instance().handleGlobStatRes(packet, from); 
    814814                        break; 
     815                case OP_GLOBSEARCHRES: 
     816                        ServerList::instance().handleGlobSearchRes( 
     817                                packet, from 
     818                        ); 
     819                        break; 
    815820                default: 
    816821                        logDebug( 
  • hydranode/hncore/ed2k/ed2ksearch.cpp

    r2613 r2738  
    2929#include <hncore/fileslist.h> 
    3030#include <hncore/sharedfile.h> 
     31#include <boost/lexical_cast.hpp> 
    3132 
    3233namespace Donkey { 
     
    7576} 
    7677 
     78std::string ED2KSearchResult::identifier() const { 
     79        return m_hash.toString() + boost::lexical_cast<std::string>(getSize()); 
     80} 
     81 
    7782} // end namespace Donkey 
  • hydranode/hncore/ed2k/ed2ksearch.h

    r2613 r2738  
    5252         */ 
    5353        virtual void download(); 
     54 
     55        /** 
     56         * @returns unique identifier (hash + size combo) for this result 
     57         */ 
     58        virtual std::string identifier() const; 
    5459private: 
    5560        Hash<ED2KHash> m_hash; 
  • hydranode/hncore/ed2k/opcodes.h

    r2617 r2738  
    206206        OP_GLOBGETSOURCES2  = 0x94,  //!< cnt*[<hash>hash<u32>size] 
    207207        OP_GLOBFOUNDSOURCES = 0x9b,  //!< <hash>hash<u8>cnt*[<u32>id<u16>port] 
    208  
     208        OP_GLOBSEARCHREQ    = 0x98,  //!< search tree 
     209        OP_GLOBSEARCHRES    = 0x99,  //!< results 
    209210        OP_GLOBSTATREQ      = 0x96,  //!< <u32>challenge 
    210211        //! <u32>challenge<u32>users<u32>files<u32>maxusers<u32>softlimit 
  • hydranode/hncore/ed2k/packets.cpp

    r2667 r2738  
    397397        Utils::StopWatch stopwatch; 
    398398        uint32_t cnt2 = count; // used for later debug msg 
     399 
    399400        while (count-- && i) { 
    400                 Hash<ED2KHash> h(Utils::getVal<std::string>(i, 16)); 
    401                 (void)Utils::getVal<uint32_t>(i); // id - ignored 
    402                 (void)Utils::getVal<uint16_t>(i); // port - ignored 
    403                 uint32_t tagCount = Utils::getVal<uint32_t>(i); 
    404                 std::string name; 
    405                 uint32_t size = 0; 
    406                 uint32_t sources = 0; 
    407                 uint32_t completesrc = 0; 
    408                 std::string codec; 
    409                 uint32_t bitrate = 0; 
    410                 uint32_t len = 0; 
    411                 uint32_t lastSeen = 0; 
    412                 uint8_t  rating = 0; 
    413                 while (tagCount-- && i) { 
    414                         Tag t(i); 
    415                         switch (t.getOpcode()) { 
    416                                 case CT_FILENAME: 
    417                                         name = t.getStr(); 
    418                                         break; 
    419                                 case CT_FILESIZE: 
    420                                         size = t.getInt(); 
    421                                         break; 
    422                                 case CT_SOURCES: 
    423                                         sources = t.getInt(); 
    424                                         break; 
    425                                 case CT_COMPLSRC: 
    426                                         completesrc = t.getInt(); 
    427                                         break; 
    428                                 case CT_MEDIA_CODEC: 
    429                                         codec = t.getStr(); 
    430                                         break; 
    431                                 case CT_MEDIA_BITRATE: 
    432                                         bitrate = t.getInt(); 
    433                                         break; 
    434                                 case CT_MEDIA_LENGTH: 
    435                                         len = t.getInt(); 
    436                                         break; 
    437                                 case CT_LASTSEENCOMPL: 
    438                                         lastSeen = t.getInt(); 
    439                                         break; 
    440                                 case CT_FILERATING: 
    441                                         rating = t.getInt(); 
    442                                         break; 
    443                                 default: 
    444                                         if (t.getName() == "bitrate") { 
    445                                                 bitrate = t.getInt(); 
    446                                         } else if (t.getName() == "length") { 
    447                                                 /** 
    448                                                  * TODO: Convert str-tag LEN 
    449                                                  *       into integer-len 
    450                                                  */ 
    451                                         } 
    452                                         warnUnHandled("SearchResult", t); 
    453                                         break; 
    454                         } 
    455                 } 
    456                 boost::shared_ptr<ED2KSearchResult> f; 
    457  
    458                 // Note - ignoring ID/Port values. 
    459                 f.reset(new ED2KSearchResult(h, name, size)); 
    460                 f->addSources(sources); 
    461                 f->addComplete(completesrc); 
    462                 f->addRating(rating); 
    463                 if (codec.size() || bitrate || len) { 
    464                         f->getStrd().reset(new StreamData(codec, bitrate, len)); 
    465                 } 
    466  
    467                 m_results.push_back(f); 
     401                readResult(i); 
    468402        } 
    469403 
     
    474408                ) % cnt2 % stopwatch 
    475409        ); 
     410} 
     411 
     412// protected default constructor for usage by GlobSearchRes class 
     413SearchResult::SearchResult() {} 
     414 
     415void SearchResult::readResult(std::istream &i) { 
     416        Hash<ED2KHash> h(Utils::getVal<std::string>(i, 16)); 
     417        (void)Utils::getVal<uint32_t>(i); // id - ignored 
     418        (void)Utils::getVal<uint16_t>(i); // port - ignored 
     419        uint32_t tagCount = Utils::getVal<uint32_t>(i); 
     420        std::string name; 
     421        uint32_t size = 0; 
     422        uint32_t sources = 0; 
     423        uint32_t completesrc = 0; 
     424        std::string codec; 
     425        uint32_t bitrate = 0; 
     426        uint32_t len = 0; 
     427        uint32_t lastSeen = 0; 
     428        uint8_t  rating = 0; 
     429        while (tagCount-- && i) { 
     430                Tag t(i); 
     431                switch (t.getOpcode()) { 
     432                        case CT_FILENAME: 
     433                                name = t.getStr(); 
     434                                break; 
     435                        case CT_FILESIZE: 
     436                                size = t.getInt(); 
     437                                break; 
     438                        case CT_SOURCES: 
     439                                sources = t.getInt(); 
     440                                break; 
     441                        case CT_COMPLSRC: 
     442                                completesrc = t.getInt(); 
     443                                break; 
     444                        case CT_MEDIA_CODEC: 
     445                                codec = t.getStr(); 
     446                                break; 
     447                        case CT_MEDIA_BITRATE: 
     448                                bitrate = t.getInt(); 
     449                                break; 
     450                        case CT_MEDIA_LENGTH: 
     451                                len = t.getInt(); 
     452                                break; 
     453                        case CT_LASTSEENCOMPL: 
     454                                lastSeen = t.getInt(); 
     455                                break; 
     456                        case CT_FILERATING: 
     457                                rating = t.getInt(); 
     458                                break; 
     459                        default: 
     460                                if (t.getName() == "bitrate") { 
     461                                        bitrate = t.getInt(); 
     462                                } else if (t.getName() == "length") { 
     463                                        /** 
     464                                         * TODO: Convert str-tag LEN 
     465                                         *       into integer-len 
     466                                         */ 
     467                                } 
     468                                warnUnHandled("SearchResult", t); 
     469                                break; 
     470                } 
     471        } 
     472        boost::shared_ptr<ED2KSearchResult> f; 
     473 
     474        // Note - ignoring ID/Port values. 
     475        f.reset(new ED2KSearchResult(h, name, size)); 
     476        f->addSources(sources); 
     477        f->addComplete(completesrc); 
     478        f->addRating(rating); 
     479        if (codec.size() || bitrate || len) { 
     480                f->getStrd().reset(new StreamData(codec, bitrate, len)); 
     481        } 
     482 
     483        m_results.push_back(f); 
    476484} 
    477485 
     
    579587        } catch (std::exception &) {} // safe to ignore 
    580588} 
     589 
     590// GlobSearchReq class 
     591// ------------------- 
     592GlobSearchReq::GlobSearchReq(SearchPtr data, uint8_t proto) 
     593: Search(data, proto) {} 
     594 
     595GlobSearchReq::operator std::string() { 
     596        std::string tmp(*static_cast<Search*>(this)); 
     597        tmp.erase(1, 4); // no size field in udp packets 
     598        tmp[1] = OP_GLOBSEARCHREQ; 
     599        return tmp; // makePacket is called by Search class already 
     600} 
     601 
     602// GlobSearchRes class 
     603// ------------------- 
     604GlobSearchRes::GlobSearchRes(std::istream &i) : SearchResult() { 
     605        while (i) { 
     606                readResult(i); 
     607                if (i.peek() == PR_ED2K) { 
     608                        (void)Utils::getVal<uint8_t>(i); 
     609                } else { 
     610                        i.seekg(-1, std::ios::cur); 
     611                        break; 
     612                } 
     613                if (i.peek() == OP_GLOBSEARCHRES) { 
     614                        (void)Utils::getVal<uint8_t>(i); 
     615                } else { 
     616                        i.seekg(-2, std::ios::cur); 
     617                        break; 
     618                } 
     619        } 
     620        if (!i.eof()) { 
     621                logDebug(boost::format( 
     622                        "Extra bytes at the end of GlobSearchRes packet: %s" 
     623                ) % Utils::hexDump( 
     624                        dynamic_cast<std::istringstream&>(i).str().substr( 
     625                                i.tellg() 
     626                        ) 
     627                )); 
     628        } 
     629} 
     630 
    581631 
    582632                      /*************************/ 
  • hydranode/hncore/ed2k/packets.h

    r2613 r2738  
    323323                return m_results.at(num); 
    324324        } 
     325protected: 
     326        SearchResult(); 
     327 
     328        //! Reads one result from stream 
     329        void readResult(std::istream &i); 
    325330private: 
    326331        std::vector<boost::shared_ptr<ED2KSearchResult> > m_results; 
     
    462467        uint32_t m_udpFlags;    //!< UDP flags 
    463468        uint32_t m_lowIdUsers;  //!< Number of online LowId users 
     469}; 
     470 
     471/** 
     472 * Global search request, sent via UDP socket to servers; format is 
     473 * same as with Search packet, except for different opcode. 
     474 * 
     475 * Usage: Client -> Server (UDP) 
     476 */ 
     477class GlobSearchReq : public Search { 
     478public: 
     479        GlobSearchReq(SearchPtr data, uint8_t proto = PR_ED2K); 
     480        operator std::string(); 
     481}; 
     482 
     483/** 
     484 * Response to GlobSearchReq packet, sent by servers via UDP; format is 
     485 * same as SearchResult packet, except for different opcode. 
     486 */ 
     487class GlobSearchRes : public SearchResult { 
     488public: 
     489        GlobSearchRes(std::istream &i); 
    464490}; 
    465491 
  • hydranode/hncore/ed2k/server.cpp

    r2613 r2738  
    3838m_addr(addr), m_failedCount(), m_preference(), m_ping(), m_lastPing(), 
    3939m_maxUsers(), m_softLimit(), m_hardLimit(), m_udpFlags(), m_users(), m_files(), 
    40 m_lowIdUsers(), m_lastUdpQuery(), m_pingInProgress(), m_challenge() { 
     40m_lowIdUsers(), m_lastUdpQuery(), m_pingInProgress(), m_challenge(), 
     41m_globSearch()  { 
    4142        // Sanity checking 
    4243        CHECK_THROW_MSG(addr.getAddr(), "Server IP may not be null."); 
     
    4445 
    4546        setName(m_addr.getStr()); 
     47 
     48        // mark all servers udp-search capable initially, so when starting 
     49        // with empty server list, it's still possible to perform searches 
     50        m_udpFlags &= FL_GETFILES;  
    4651} 
    4752 
     
    5358m_failedCount(), m_preference(), m_ping(), m_lastPing(), m_maxUsers(), 
    5459m_softLimit(), m_hardLimit(), m_udpFlags(), m_users(), m_files(), 
    55 m_lowIdUsers(), m_lastUdpQuery(), m_pingInProgress(), m_challenge() { 
     60m_lowIdUsers(), m_lastUdpQuery(), m_pingInProgress(), m_challenge(), 
     61m_globSearch()  { 
    5662        m_addr.setAddr(Utils::getVal<uint32_t>(i)); 
    5763        m_addr.setPort(Utils::getVal<uint16_t>(i)); 
  • hydranode/hncore/ed2k/server.h

    r2613 r2738  
    2828#include <hnbase/ipv4addr.h> 
    2929#include <hnbase/object.h> 
     30#include <hncore/fwd.h> 
    3031#include <hncore/ed2k/fwd.h> 
    3132 
     
    8485        bool        pingInProgress()        const { return m_pingInProgress; } 
    8586        uint32_t    getChallenge()          const { return m_challenge;      } 
     87        SearchPtr   currentSearch()         const { return m_globSearch;     } 
    8688 
    8789        //! ED2K Server UDP port is always TCP + 4 
     
    8991        bool supportsGetSources() const { return m_udpFlags & FL_GETSOURCES; } 
    9092        bool supportsGetFiles()   const { return m_udpFlags & FL_GETFILES;   } 
     93        bool supportsUdpSearch()  const { return m_udpFlags & FL_GETFILES;   } 
    9194        //@} 
    9295 
     
    116119 
    117120        void setLastUdpQuery(uint64_t time)   { m_lastUdpQuery = time; } 
    118         void setPingInProgress(bool v)        { m_pingInProgress = v; } 
    119         void setChallenge(uint32_t c)         { m_challenge = c; } 
     121        void setPingInProgress(bool v)        { m_pingInProgress = v;  } 
     122        void setChallenge(uint32_t c)         { m_challenge = c;       } 
     123        void setCurrentSearch(SearchPtr p)    { m_globSearch = p;      } 
    120124        //@} 
    121125private: 
     
    158162        std::vector<uint16_t> m_auxPorts; //!< Auxiliary ports 
    159163 
    160         uint64_t m_lastUdpQuery;     //!< Time of last UDP query 
    161         bool m_pingInProgress;       //!< UDP Ping is in progress 
    162         uint32_t m_challenge;        //!< Last UDP query challenge 
     164        uint64_t  m_lastUdpQuery;    //!< Time of last UDP query 
     165        bool      m_pingInProgress;  //!< UDP Ping is in progress 
     166        uint32_t  m_challenge;       //!< Last UDP query challenge 
     167        SearchPtr m_globSearch;      //!< Current search, if any 
    163168        //@} 
    164169 
  • hydranode/hncore/ed2k/serverlist.cpp

    r2707 r2738  
    7272}; 
    7373 
     74//! Server UDP Addr extractor functor 
     75struct ServerUAddrExtractor { 
     76        typedef IPV4Address result_type; 
     77        result_type operator()(const Server *const s) const { 
     78                return IPV4Address(s->getAddr().getIp(), s->getUdpPort()); 
     79        } 
     80}; 
     81 
    7482//! last udp query time extractor functor 
    7583struct QueryTimeExtractor { 
     
    8795        boost::multi_index::ordered_non_unique<ServerAddrExtractor>, 
    8896        boost::multi_index::ordered_non_unique<ServerNameExtractor>, 
    89         boost::multi_index::ordered_non_unique<QueryTimeExtractor> 
     97        boost::multi_index::ordered_non_unique<QueryTimeExtractor>, 
     98        boost::multi_index::ordered_non_unique<ServerUAddrExtractor> 
    9099> {}; 
    91100struct MIServerList : boost::multi_index_container< 
     
    99108        QTIter(const T &t) : MIServerList::nth_index<3>::type::iterator(t) {} 
    100109}; 
     110typedef MIServerList::nth_index<4>::type::iterator UAddrIter; 
    101111 
    102112} // namespace Detail 
     
    455465        logTrace(TRACE, "[ed2k] ServerList::performSearch"); 
    456466 
    457         if (m_status != ST_CONNECTED || !m_serverSocket) { 
    458                 logError( 
    459                         "Unable to perform a search at this time: not " 
    460                         "connected to a server." 
    461                 ); 
    462                 if (m_status != ST_CONNECTING) { 
    463                         connect(); 
    464                 } 
    465         } else { 
     467        // local server search only if we'r currently connected 
     468        if (m_serverSocket && m_status == ST_CONNECTED) { 
    466469                *m_serverSocket << ED2KPacket::Search(search); 
    467470                m_curSearch = search; 
    468471        } 
     472 
     473        // global search 
     474        std::vector<Server*> tmp; 
     475        std::copy(m_list->begin(), m_list->end(), std::back_inserter(tmp)); 
     476        std::random_shuffle(tmp.begin(), tmp.end()); 
     477        boost::shared_ptr<std::list<Server*> > list(new std::list<Server*>); 
     478        std::copy(tmp.begin(), tmp.end(), std::back_inserter(*list)); 
     479        Utils::timedCallback( 
     480                boost::bind(&ServerList::doGlobSearch, this, search, list), 0 
     481        ); 
     482        std::string keywords; 
     483        for (uint32_t i = 0; i < search->getTermCount(); ++i) { 
     484                keywords += search->getTerm(i); 
     485                if (i + 1 < search->getTermCount()) { 
     486                        keywords += " "; 
     487                } 
     488        } 
     489        logMsg( 
     490                boost::format( 
     491                        "eDonkey2000: Search started with keywords '%s'." 
     492                ) % keywords 
     493        ); 
    469494} 
    470495 
     
    784809                ) % e.what() 
    785810        ); 
    786 
    787 MSVC_ONLY(;) 
     811} MSVC_ONLY(;) 
    788812 
    789813void ServerList::handleGlobStatRes(std::istringstream &i, IPV4Address from) try{ 
     
    849873                ) % e.what() 
    850874        ); 
    851 
    852 MSVC_ONLY(;) 
     875} MSVC_ONLY(;) 
     876 
     877void ServerList::handleGlobSearchRes(std::istringstream &i, IPV4Address from) 
     878try { 
     879        logTrace(TRACE, 
     880                boost::format("Received GlobSearchRes from %s") % from 
     881        ); 
     882 
     883        ED2KPacket::GlobSearchRes p(i); 
     884        UAddrIter it(m_list->get<4>().find(from)); 
     885 
     886        if (it != m_list->get<4>().end() && (*it)->currentSearch()) { 
     887                // search stopped - ignore these results 
     888                if (!(*it)->currentSearch()->isRunning()) { 
     889                        return; 
     890                } 
     891                for (size_t i = 0; i < p.getCount(); ++i) { 
     892                        (*it)->currentSearch()->addResult(p.getResult(i)); 
     893                } 
     894                (*it)->currentSearch()->notifyResults(); 
     895                // Server::m_globSearch is reset from timed callback 
     896        } else { 
     897                logDebug( 
     898                        boost::format( 
     899                                "Received search results from unknown " 
     900                                "server %s" 
     901                        ) % from 
     902                ); 
     903        } 
     904} catch (std::exception &e) { 
     905        logError( 
     906                boost::format("Handling GlobSearchRes packet from %s: %s")  
     907                % from % e.what() 
     908        ); 
     909        logError("Packet contents: " + Utils::hexDump(i.str())); 
     910} MSVC_ONLY(;) 
    853911 
    854912void ServerList::queryNextServer() { 
     
    11651223} 
    11661224 
     1225void ServerList::doGlobSearch( 
     1226        SearchPtr search, boost::shared_ptr<std::list<Server*> > srv 
     1227) { 
     1228        CHECK_RET(srv); 
     1229        if (!search->isRunning() || !m_list->size() || !srv->size()) { 
     1230                return; 
     1231        } 
     1232        uint32_t callback = 500; // default 500ms delay 
     1233        size_t loopCnt = srv->size(); 
     1234 
     1235        while (srv->size() && loopCnt--) { 
     1236                if (m_list->find(srv->front()) == m_list->end()) { 
     1237                        srv->pop_front(); 
     1238                } else if (srv->front()->currentSearch()) { 
     1239                        srv->push_back(srv->front()); 
     1240                        srv->pop_front(); 
     1241                } else if (!srv->front()->supportsUdpSearch()) { 
     1242                        srv->pop_front(); 
     1243                } 
     1244        } 
     1245        if (srv->size() && srv->front()->currentSearch()) { 
     1246                logTrace(TRACE, 
     1247                        "No valid servers found for global search, " 
     1248                        "retrying in 5 seconds." 
     1249                ); 
     1250                callback = 5000; 
     1251        } else if (srv->size()) { 
     1252                ED2KPacket::GlobSearchReq packet(search); 
     1253                IPV4Address to( 
     1254                        srv->front()->getAddr().getIp(),  
     1255                        srv->front()->getUdpPort() 
     1256                ); 
     1257                Client::getUdpSocket()->send(packet, to); 
     1258                srv->front()->setCurrentSearch(search); 
     1259                Utils::timedCallback( 
     1260                        boost::bind( 
     1261                                &Server::setCurrentSearch, 
     1262                                srv->front(), SearchPtr() 
     1263                        ), 10000    // 10sec timeout 
     1264                ); 
     1265                srv->pop_front(); 
     1266                logTrace(TRACE, 
     1267                        boost::format("Sent global search request to %s") % to 
     1268                ); 
     1269        } 
     1270        if (srv->size()) { 
     1271                Utils::timedCallback( 
     1272                        boost::bind( 
     1273                                &ServerList::doGlobSearch, this, 
     1274                                search, srv 
     1275                        ), callback 
     1276                ); 
     1277        } else { 
     1278                std::string keywords; 
     1279                for (uint32_t i = 0; i < search->getTermCount(); ++i) { 
     1280                        keywords += search->getTerm(i); 
     1281                        if (i + 1 < search->getTermCount()) { 
     1282                                keywords += " "; 
     1283                        } 
     1284                } 
     1285                logMsg( 
     1286                        boost::format( 
     1287                                "eDonkey2000: Global search " 
     1288                                "with keywords '%s' ended." 
     1289                        ) % keywords 
     1290                ); 
     1291        } 
     1292} 
     1293 
    11671294} // end namespace Donkey 
  • hydranode/hncore/ed2k/serverlist.h

    r2613 r2738  
    245245         */ 
    246246        void onUdpData(ED2KUDPSocket *sock, SocketEvent evt); 
     247 
     248        /** 
     249         * Sends global UDP search query to next server in list. 
     250         */ 
     251        void doGlobSearch( 
     252                SearchPtr search, 
     253                boost::shared_ptr<std::list<Detail::Server*> > srv 
     254        ); 
    247255public: 
    248256        //! @name Packet handlers 
     
    256264        void onPacket(const ED2KPacket::CallbackReq &p); 
    257265        void onPacket(const ED2KPacket::FoundSources  &p); 
    258         //@} 
    259266 
    260267        /** 
     
    273280         */ 
    274281        void handleGlobStatRes(std::istringstream &i, IPV4Address from); 
     282 
     283        /** 
     284         * Handles GlobSearchRes packet from UDP servers 
     285         * 
     286         * @param i      Input stream to read packet from 
     287         * @param from   The server that sent this data 
     288         */ 
     289        void handleGlobSearchRes(std::istringstream &i, IPV4Address from); 
     290        //@} 
    275291 
    276292        //! @name Various operations 
  • hydranode/hncore/hnsh/shellcommands.cpp

    r2669 r2738  
    8585        m_commands["search"]  = bind(&ShellCommands::cmdSearch, this, _1); 
    8686        m_commands["vr"]      = bind(&ShellCommands::cmdViewResults, this, _1); 
     87        m_commands["ss"]      = bind(&ShellCommands::cmdStopSearch, this, _1); 
    8788        m_commands["download"]  = bind(&ShellCommands::cmdDownload, this, _1); 
    8889        m_commands["vd"]     = bind(&ShellCommands::cmdListDownloads, this, _1); 
     
    99100        m_commands["hs"]   = bind(&ShellCommands::cmdShowHasherStats, this, _1); 
    100101        m_commands["history"] = bind(&ShellCommands::cmdShowHistory, this, _1); 
    101         m_commands["ss"]      = bind(&ShellCommands::cmdSchedStats, this, _1); 
     102        m_commands["scs"]     = bind(&ShellCommands::cmdSchedStats, this, _1); 
    102103        m_commands["ifs"]     = bind(&ShellCommands::cmdFilterStats, this, _1); 
    103104#if !defined(NDEBUG) && !defined(NTRACE) 
     
    426427        } 
    427428 
    428         SearchPtr search(new Search()); 
     429        if (m_currentSearch) { 
     430                m_currentSearch->stop(); 
     431        } 
     432        m_currentSearch.reset(new Search); 
    429433 
    430434        // Parse arguments 
     
    451455                                boost::format("Adding search term '%s'.") % *i 
    452456                        ); 
    453                         search->addTerm(*i); 
     457                        m_currentSearch->addTerm(*i); 
    454458                } 
    455459        } 
     
    460464                if ((*i).first == "minsize") { 
    461465                        uint64_t mz = lexical_cast<uint64_t>((*i).second); 
    462                         search->setMinSize(mz); 
     466                        m_currentSearch->setMinSize(mz); 
    463467                } else if ((*i).first == "maxsize") { 
    464468                        uint64_t mz = lexical_cast<uint64_t>((*i).second); 
    465                         search->setMaxSize(mz); 
     469                        m_currentSearch->setMaxSize(mz); 
    466470                } else if ((*i).first == "type") { 
    467                         search->setType(helperStrToType((*i).second)); 
     471                        m_currentSearch->setType(helperStrToType((*i).second)); 
    468472                } else { 
    469473                        boost::format fmt("Unknown argument: '%s'"); 
     
    483487                        (*i).first 
    484488                ); 
     489                m_currentSearch.reset(); 
    485490                return false; 
    486491        } 
    487492 
    488493        // Parsing is done, check if everything we need is in place 
    489         if (!search->getTermCount()) { 
     494        if (!m_currentSearch->getTermCount()) { 
    490495                setError("please specify a term to search for"); 
     496                m_currentSearch.reset(); 
    491497                return false; 
    492498        } 
    493499 
    494500        m_searchResults.clear(); 
    495         search->addResultHandler( 
     501        m_currentSearch->addResultHandler( 
    496502                boost::bind(&ShellCommands::helperOnSearchEvent, this, _1) 
    497503        ); 
    498504 
    499505        logMsg("Initialising new search."); 
    500         search->run(); 
     506        m_currentSearch->run(); 
    501507 
    502508        return true; 
     
    886892        *m_socket << "cd            Change directory."          << Socket::Endl; 
    887893        *m_socket << "uname         Show Hydranode version."    << Socket::Endl; 
    888         //*m_socket << "history       List command history"     << Socket::Endl; 
    889894        *m_socket << "search        Search for files."          << Socket::Endl; 
     895        *m_socket << "ss            Stop current search."       << Socket::Endl; 
    890896        *m_socket << "vr [pred]     View search results."       << Socket::Endl; 
    891897        *m_socket << "download      Download a search result or link."; 
     
    899905        *m_socket << "addsource     Add a source to download."  << Socket::Endl; 
    900906        *m_socket << "hs            View Hasher Statistics."    << Socket::Endl; 
    901         *m_socket << "ss            View Scheduler Statistics." << Socket::Endl; 
     907        *m_socket << "scs           View Scheduler Statistics." << Socket::Endl; 
    902908        *m_socket << "ifs           View IPFilter Statistics."  << Socket::Endl; 
    903909        *m_socket << "log [on/off]  Enable/Disable log printing."<<Socket::Endl; 
     
    14101416        } 
    14111417        sortResults(pred); 
    1412         printSearchResults(); 
     1418        printSearchResults(true); 
    14131419        return true; 
    14141420} 
     
    14631469        fmt % Utils::bytesToString(avgUp) % Utils::bytesToString(avgDown); 
    14641470        *m_socket << fmt.str() << Socket::Endl; 
     1471        return true; 
     1472} 
     1473 
     1474bool ShellCommands::cmdStopSearch(Tokenizer) { 
     1475        if (m_currentSearch) { 
     1476                m_currentSearch->stop(); 
     1477                m_currentSearch.reset(); 
     1478        } else { 
     1479                *m_socket << "'ss': Stops current active search."; 
     1480                *m_socket << Socket::Endl; 
     1481        } 
    14651482        return true; 
    14661483} 
     
    16241641 
    16251642void ShellCommands::helperOnSearchEvent(SearchPtr search) try { 
    1626         CHECK_THROW(search->getResultCount() >= m_searchResults.size()); 
    1627  
    16281643        if (!search->getResultCount()) { 
    1629                 *m_socket << "\rReceived 0 results from server." <<Socket::Endl; 
    1630                 m_parent->setPrompt(); 
    16311644                return; 
    16321645        } 
     
    16371650        } 
    16381651 
    1639         sortResults( 
    1640                 Prefs::instance().read<std::string>("/SearchSortOrder", "rsrc") 
    1641         ); 
    1642  
    1643         printSearchResults(); 
     1652        sortResults("src"); 
     1653        printSearchResults(false); 
    16441654 
    16451655        m_parent->setPrompt(); 
     
    16501660 
    16511661 
    1652 void ShellCommands::printSearchResults() { 
     1662void ShellCommands::printSearchResults(bool printAll) { 
    16531663        CHECK_THROW(m_socket); 
    16541664        if (!m_searchResults.size()) { 
     
    16561666        } 
    16571667 
    1658         *m_socket << Socket::Endl; 
    1659         *m_socket << "   #   Size Src(Compl) Rating Filename"; 
    1660         *m_socket << Socket::Endl; 
    1661  
    1662         boost::format fmt("%3d) %10s %4d(%d) %3d %|30t|%s"); 
    1663         for (uint32_t i = 0; i < m_searchResults.size(); ++i) { 
     1668        uint32_t toPrint = m_parent->getHeight() - 2; 
     1669        if (m_searchResults.size() < toPrint) { 
     1670                toPrint = m_searchResults.size(); 
     1671                uint16_t emptyLines = m_parent->getHeight() - 2 - toPrint; 
     1672                // clear screen 
     1673                *m_socket << "\33[H"; 
     1674                for (uint32_t i = 1; i < m_parent->getHeight(); ++i) { 
     1675                        *m_socket << std::string(m_parent->getWidth(), ' '); 
     1676                        *m_socket << Socket::Endl; 
     1677                } 
     1678                *m_socket << "\33[H"; 
     1679                // navigate to correct position 
     1680                while (emptyLines--) { 
     1681                        *m_socket << Socket::Endl; 
     1682                } 
     1683        } else if (m_searchResults.size() > toPrint) { 
     1684                toPrint -= 2;    // 2-line Notice line in the end 
     1685        } 
     1686         
     1687        *m_socket << "\r   #   Size Src(Compl) Rating Filename" << Socket::Endl; 
     1688 
     1689        boost::format fmt("%3d) %10s %4d(%d) %|27t|%3d %|30t|%s"); 
     1690        for (uint32_t i = 0; i < toPrint; ++i) { 
    16641691                SearchResultPtr sr(m_searchResults[i]); 
    16651692 
    16661693                fmt % i % Utils::bytesToString(sr->getSize()); 
    16671694                fmt % sr->getSources() % sr->getComplete(); 
    1668                 fmt % static_cast<int>(sr->getRating()) % sr->getName(); 
    1669  
     1695                fmt % static_cast<int>(sr->getRating()); 
     1696 
     1697                // can't truncate name if screen width is <31 
     1698                if (m_parent->getWidth() <= 31) { 
     1699                        fmt % sr->getName(); 
     1700                } 
     1701                // truncate name to fit on screen single line 
     1702                if (sr->getName().size() > m_parent->getWidth() - 31u) { 
     1703                        std::string tmp( 
     1704                                sr->getName().substr( 
     1705                                        0, m_parent->getWidth() - 40 
     1706                                ) 
     1707                        ); 
     1708                        tmp += "[...]" + sr->getName().substr( 
     1709                                sr->getName().size() - 4 
     1710                        ); 
     1711                        fmt % tmp; 
     1712                } else { 
     1713                        fmt % sr->getName(); 
     1714                } 
    16701715                *m_socket << fmt.str() << Socket::Endl; 
     1716        } 
     1717        if (toPrint < m_searchResults.size()) { 
     1718                *m_socket <<  
     1719                "  => Notice: Only the most popular results are printed. "; 
     1720                *m_socket << Socket::Endl; 
     1721                *m_socket << "  => To view all results, type 'vr'."; 
     1722                *m_socket << " To stop searching, type 'ss'."; 
     1723                *m_socket << Socket::Endl; 
    16711724        } 
    16721725} 
  • hydranode/hncore/hnsh/shellcommands.h

    r2656 r2738  
    198198        bool cmdMemStats(Tokenizer); 
    199199 
     200        //! Stops current search 
     201        bool cmdStopSearch(Tokenizer); 
     202 
    200203        //! Print one client 
    201204    &