diff --git a/Makefile.am b/Makefile.am index 8fbd3985..cec98dde 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,4 +1,5 @@ SUBDIRS = src EXTRA_DIST= \ - autogen.sh + autogen.sh \ + scripts/checks.m4 diff --git a/src/core/Makefile.am b/src/core/Makefile.am index aeec64d9..969134f2 100644 --- a/src/core/Makefile.am +++ b/src/core/Makefile.am @@ -5,6 +5,8 @@ libsub_core_a_SOURCES = \ curl_get.h \ curl_stack.cc \ curl_stack.h \ + hash_queue.cc \ + hash_queue.h \ http_queue.cc \ http_queue.h \ download.cc \ diff --git a/src/core/download.h b/src/core/download.h index 560afef0..a429ce37 100644 --- a/src/core/download.h +++ b/src/core/download.h @@ -19,10 +19,9 @@ public: void open() { m_download.open(); } void close() { m_download.close(); } + void start() { m_download.start(); } void stop() { m_download.stop(); } - void hash_check(bool resume = false) { m_download.hash_check(resume); } - bool operator == (const std::string& str) { return str == m_download.get_hash(); } private: diff --git a/src/core/download_list.cc b/src/core/download_list.cc index 5d0fc64f..72a37adb 100644 --- a/src/core/download_list.cc +++ b/src/core/download_list.cc @@ -17,8 +17,6 @@ DownloadList::insert(std::istream* str) { iterator itr = Base::insert(end(), Download()); itr->set_download(d); - itr->get_download().signal_hash_done(sigc::bind(sigc::mem_fun(*this, &DownloadList::receive_hash_done), - itr->get_hash())); return itr; } @@ -32,14 +30,4 @@ DownloadList::erase(iterator itr) { Base::erase(itr); } -void -DownloadList::receive_hash_done(const std::string& str) { - iterator itr = std::find(begin(), end(), str); - - if (itr == end()) - throw torrent::client_error("DownloadList received hash check done, but couldn't find the download"); - - itr->get_download().start(); -} - } diff --git a/src/core/download_list.h b/src/core/download_list.h index aef08afc..6f7fa67f 100644 --- a/src/core/download_list.h +++ b/src/core/download_list.h @@ -26,9 +26,6 @@ public: iterator insert(std::istream* str); void erase(iterator itr); - -private: - void receive_hash_done(const std::string& str); }; } diff --git a/src/core/hash_queue.cc b/src/core/hash_queue.cc new file mode 100644 index 00000000..cb01173c --- /dev/null +++ b/src/core/hash_queue.cc @@ -0,0 +1,68 @@ +#include "config.h" + +#include +#include +#include + +#include "download.h" +#include "functional.h" +#include "hash_queue.h" + +namespace core { + +void +HashQueue::insert(Download* d, Slot s) { + if (std::find_if(begin(), end(), func::equal(d, std::mem_fun(&HashQueueNode::get_download))) != end()) + throw std::logic_error("core::HashQueue::insert(...) received a Download that is already queued"); + + if (d->get_download().is_hash_checked()) { + s(); + return; + } + + iterator itr = Base::insert(end(), new HashQueueNode(d, s)); + + (*itr)->set_connection(d->get_download().signal_hash_done(sigc::bind(sigc::mem_fun(*this, &HashQueue::receive_hash_done), itr))); + + fill_queue(); +} + +void +HashQueue::remove(Download* d) { + iterator itr = std::find_if(begin(), end(), func::equal(d, std::mem_fun(&HashQueueNode::get_download))); + + if (itr == end()) + return; + + if ((*itr)->get_download()->get_download().is_hash_checking()) + // What do we do if we're already checking? + ; + + delete *itr; + Base::erase(itr); + + fill_queue(); +} + +void +HashQueue::receive_hash_done(Base::iterator itr) { + Slot s = (*itr)->get_slot(); + + delete *itr; + Base::erase(itr); + + s(); +} + +void +HashQueue::fill_queue() { + if (empty() || front()->get_download()->get_download().is_hash_checking()) + return; + + if (front()->get_download()->get_download().is_hash_checked()) + throw std::logic_error("core::HashQueue::fill_queue() encountered a checked hash"); + + front()->get_download()->get_download().hash_check(); +} + +} diff --git a/src/core/hash_queue.h b/src/core/hash_queue.h new file mode 100644 index 00000000..16db01a7 --- /dev/null +++ b/src/core/hash_queue.h @@ -0,0 +1,65 @@ +#ifndef RTORRENT_CORE_HASH_QUEUE_H +#define RTORRENT_CORE_HASH_QUEUE_H + +#include +#include +#include + +namespace core { + +class Download; + +class HashQueueNode; + +class HashQueue : private std::list { +public: + typedef std::list Base; + typedef sigc::slot0 Slot; + + using Base::iterator; + using Base::const_iterator; + using Base::reverse_iterator; + using Base::const_reverse_iterator; + + using Base::begin; + using Base::end; + using Base::rbegin; + using Base::rend; + + using Base::front; + using Base::back; + + using Base::empty; + using Base::size; + + // Should it be safe to try inserting already present/checked downloads? + void insert(Download* d, Slot s); + + // It's safe to try to remove downloads not in the queue. + void remove(Download* d); + +private: + void receive_hash_done(Base::iterator itr); + + void fill_queue(); +}; + +class HashQueueNode { +public: + HashQueueNode(Download* d, HashQueue::Slot s) : m_download(d), m_slot(s) {} + ~HashQueueNode() { m_connection.disconnect(); } + + Download* get_download() { return m_download; } + HashQueue::Slot get_slot() { return m_slot; } + + void set_connection(sigc::connection c) { m_connection = c; } + +private: + Download* m_download; + HashQueue::Slot m_slot; + sigc::connection m_connection; +}; + +} + +#endif diff --git a/src/core/manager.cc b/src/core/manager.cc index 12863f7d..7baaf891 100644 --- a/src/core/manager.cc +++ b/src/core/manager.cc @@ -19,6 +19,21 @@ Manager::insert(const std::string& uri) { create_http(uri); } +void +Manager::start(Download* d) { + if (d->get_download().is_active()) + return; + + if (d->get_download().is_open()) { + d->start(); + + } else { + d->open(); + + m_hashQueue.insert(d, sigc::mem_fun(*d, &Download::start)); + } +} + void Manager::create_file(const std::string& uri) { DownloadList::iterator itr = m_downloadList.end(); @@ -28,8 +43,7 @@ Manager::create_file(const std::string& uri) { itr = m_downloadList.insert(&f); - itr->open(); - itr->hash_check(); + start(&*itr); } catch (torrent::local_error& e) { // What to do? Keep in list for now. @@ -51,8 +65,7 @@ Manager::receive_http_done(torrent::Http* http) { try { itr = m_downloadList.insert(http->get_stream()); - itr->open(); - itr->hash_check(); + start(&*itr); } catch (torrent::local_error& e) { // What to do? Keep in list for now. diff --git a/src/core/manager.h b/src/core/manager.h index c483f903..b856de51 100644 --- a/src/core/manager.h +++ b/src/core/manager.h @@ -2,6 +2,7 @@ #define RTORRENT_CORE_MANAGER_H #include "download_list.h" +#include "hash_queue.h" #include "http_queue.h" namespace core { @@ -12,10 +13,13 @@ public: typedef sigc::slot0 SlotFailed; DownloadList& get_download_list() { return m_downloadList; } + HashQueue& get_hash_queue() { return m_hashQueue; } HttpQueue& get_http_queue() { return m_httpQueue; } void insert(const std::string& uri); + void start(Download* d); + private: void receive_http_done(torrent::Http* http); @@ -23,6 +27,7 @@ private: void create_http(const std::string& uri); DownloadList m_downloadList; + HashQueue m_hashQueue; HttpQueue m_httpQueue; };