From d4706da4d5acec455fd47c3607255380adac58e8 Mon Sep 17 00:00:00 2001 From: rakshasa Date: Sat, 13 May 2006 00:18:50 +0000 Subject: [PATCH] * Removed core::HashQueue, using the "hashing" view and a function in core::Manager instead. * Added a new :rtorrent:hashing state so we can distinguish between initial hashing and manual rehashes. The former is cleared if the download is paused. * Added a hash failed flag to core::Download. This is used to skip entries in the hashing view that either failed to open or are in the process of being erased from DownloadList. * torrent::Bitfield::unset was incrementing, rather than decrementing, the m_set counter. * Replaced all torrent::internal_error's in rtorrent with torrent::client_error. * ^D now checks :rtorrent:state to decide whetever to stop or erase a download. Downloads queued for hashing will now stop rather than be deleted. git-svn-id: svn://rakshasa.no/libtorrent/trunk/rtorrent@688 e378c898-3ddf-0310-93e7-cc216c733640 --- src/command_scheduler.cc | 6 +- src/command_scheduler_item.cc | 4 +- src/control.cc | 1 + src/core/Makefile.am | 2 - src/core/download.cc | 2 + src/core/download.h | 16 +++- src/core/download_list.cc | 122 ++++++++++++++------------- src/core/download_list.h | 6 +- src/core/hash_queue.cc | 125 ---------------------------- src/core/hash_queue.h | 109 ------------------------ src/core/manager.cc | 43 +++++++++- src/core/manager.h | 11 ++- src/core/scheduler.cc | 4 +- src/core/view.cc | 16 ++-- src/core/view.h | 3 +- src/core/view_manager.cc | 3 +- src/display/utils.cc | 14 ++-- src/display/window_download_list.cc | 2 +- src/ui/download_list.cc | 6 +- src/ui/element_file_list.cc | 12 +-- src/ui/element_tracker_list.cc | 14 ++-- src/utils/variable_map.cc | 2 +- 22 files changed, 177 insertions(+), 346 deletions(-) delete mode 100644 src/core/hash_queue.cc delete mode 100644 src/core/hash_queue.h diff --git a/src/command_scheduler.cc b/src/command_scheduler.cc index 1f0daba0..0c6e7f4b 100644 --- a/src/command_scheduler.cc +++ b/src/command_scheduler.cc @@ -85,10 +85,10 @@ CommandScheduler::erase(iterator itr) { void CommandScheduler::call_item(value_type item) { if (item->is_queued()) - throw torrent::internal_error("CommandScheduler::call_item(...) called but item is still queued."); + throw torrent::client_error("CommandScheduler::call_item(...) called but item is still queued."); if (std::find(begin(), end(), item) == end()) - throw torrent::internal_error("CommandScheduler::call_item(...) called but the item isn't in the scheduler."); + throw torrent::client_error("CommandScheduler::call_item(...) called but the item isn't in the scheduler."); // Remove the item before calling the command if it should be // removed. @@ -110,7 +110,7 @@ CommandScheduler::call_item(value_type item) { } if (next <= cachedTime) - throw torrent::internal_error("CommandScheduler::call_item(...) tried to schedule a zero interval item."); + throw torrent::client_error("CommandScheduler::call_item(...) tried to schedule a zero interval item."); item->enable(next); } diff --git a/src/command_scheduler_item.cc b/src/command_scheduler_item.cc index 6e46a5db..30e85f49 100644 --- a/src/command_scheduler_item.cc +++ b/src/command_scheduler_item.cc @@ -47,7 +47,7 @@ CommandSchedulerItem::~CommandSchedulerItem() { void CommandSchedulerItem::enable(rak::timer t) { if (t == rak::timer()) - throw torrent::internal_error("CommandSchedulerItem::enable() t == rak::timer()."); + throw torrent::client_error("CommandSchedulerItem::enable() t == rak::timer()."); if (is_queued()) disable(); @@ -71,7 +71,7 @@ CommandSchedulerItem::next_time_scheduled() const { return rak::timer(); if (m_timeScheduled == rak::timer()) - throw torrent::internal_error("CommandSchedulerItem::next_time_scheduled() m_timeScheduled == rak::timer()."); + throw torrent::client_error("CommandSchedulerItem::next_time_scheduled() m_timeScheduled == rak::timer()."); rak::timer next = m_timeScheduled; diff --git a/src/control.cc b/src/control.cc index ee7ee751..03cc45de 100644 --- a/src/control.cc +++ b/src/control.cc @@ -113,6 +113,7 @@ Control::initialize() { m_core->listen_open(); m_core->download_store()->enable(m_variables->get_value("session_lock")); + m_core->set_hashing_view(*m_viewManager->find_throw("hashing")); m_scheduler->set_view(*m_viewManager->find_throw("scheduler")); m_ui->init(this); diff --git a/src/core/Makefile.am b/src/core/Makefile.am index fcb4f9b1..7eedc08b 100644 --- a/src/core/Makefile.am +++ b/src/core/Makefile.am @@ -14,8 +14,6 @@ libsub_core_a_SOURCES = \ download_slot_map.h \ download_store.cc \ download_store.h \ - hash_queue.cc \ - hash_queue.h \ http_queue.cc \ http_queue.h \ log.cc \ diff --git a/src/core/download.cc b/src/core/download.cc index 07f9f559..c98ff0c5 100644 --- a/src/core/download.cc +++ b/src/core/download.cc @@ -57,6 +57,8 @@ Download::Download(download_type d) : m_fileList(d.file_list()), m_trackerList(d.tracker_list()), + m_hashFailed(false), + m_chunksFailed(0) { m_connTrackerSucceded = m_download.signal_tracker_succeded(sigc::bind(sigc::mem_fun(*this, &Download::receive_tracker_msg), "")); diff --git a/src/core/download.h b/src/core/download.h index 6c1208c5..b30e257f 100644 --- a/src/core/download.h +++ b/src/core/download.h @@ -56,15 +56,25 @@ public: typedef utils::VariableMap variable_map_type; static const int64_t variable_hashing_stopped = 0; - static const int64_t variable_hashing_started = 1; + static const int64_t variable_hashing_initial = 1; static const int64_t variable_hashing_last = 2; + static const int64_t variable_hashing_rehash = 3; Download(download_type d); ~Download(); bool is_open() const { return m_download.is_open(); } bool is_active() const { return m_download.is_active(); } - inline bool is_done() const { return m_download.chunks_done() == m_download.chunks_total(); } + bool is_done() const { return m_download.chunks_done() == m_download.chunks_total(); } + + // FIXME: Fixed a bug in libtorrent that caused is_hash_checked to + // return true when the torrent is closed. Remove this redundant + // test in the next milestone. + bool is_hash_checked() const { return m_download.is_open() && m_download.is_hash_checked(); } + bool is_hash_checking() const { return m_download.is_hash_checking(); } + + bool is_hash_failed() const { return m_hashFailed; } + void set_hash_failed(bool v) { m_hashFailed = v; } variable_map_type* variable() { return &m_variables; } std::string variable_string(const std::string& key) { return m_variables.get_string(key); } @@ -127,6 +137,8 @@ private: file_list_type m_fileList; tracker_list_type m_trackerList; + bool m_hashFailed; + std::string m_message; uint32_t m_chunksFailed; diff --git a/src/core/download_list.cc b/src/core/download_list.cc index 47223b61..3858e628 100644 --- a/src/core/download_list.cc +++ b/src/core/download_list.cc @@ -47,7 +47,6 @@ #include "rak/functional.h" #include "globals.h" -#include "hash_queue.h" #include "manager.h" #include "download.h" @@ -60,7 +59,7 @@ inline void DownloadList::check_contains(Download* d) { #ifdef USE_EXTRA_DEBUG if (std::find(begin(), end(), d) == end()) - throw torrent::internal_error("DownloadList::check_contains(...) failed."); + throw torrent::client_error("DownloadList::check_contains(...) failed."); #endif } @@ -121,12 +120,14 @@ DownloadList::insert(Download* download) { try { (*itr)->download()->signal_download_done(sigc::bind(sigc::mem_fun(*this, &DownloadList::received_finished), download)); + (*itr)->download()->signal_hash_done(sigc::bind(sigc::mem_fun(*this, &DownloadList::hash_done), download)); + std::for_each(slot_map_insert().begin(), slot_map_insert().end(), download_list_call(*itr)); } catch (torrent::local_error& e) { // Should perhaps relax this, just print an error and remove the // downloads? - throw torrent::internal_error("Caught during DownloadList::insert(...): " + std::string(e.what())); + throw torrent::client_error("Caught during DownloadList::insert(...): " + std::string(e.what())); } return itr; @@ -142,7 +143,10 @@ DownloadList::erase(Download* download) { DownloadList::iterator DownloadList::erase(iterator itr) { if (itr == end()) - throw torrent::internal_error("DownloadList::erase(...) could not find download."); + throw torrent::client_error("DownloadList::erase(...) could not find download."); + + // Makes sure close doesn't restart hashing of this download. + (*itr)->set_hash_failed(true); close(*itr); @@ -199,10 +203,12 @@ void DownloadList::close_throw(Download* download) { check_contains(download); - if (!download->download()->is_open()) + if (!download->is_open()) return; - if (download->download()->is_active()) + // When pause gets called it will clear the initial hash checking. + + if (download->is_active()) pause(download); // Save the torrent on close, this covers shutdown and if a torrent @@ -214,18 +220,32 @@ DownloadList::close_throw(Download* download) { // Reconsider this save. Should be done explicitly when shutting down. //control->core()->download_store()->save(download); - if (control->core()->hash_queue()->is_queued(download)) { - control->core()->hash_queue()->remove(download); - download->download()->close(); + // FIXME: Urgh, need to do something sane when closing a download + // that has been queued for hashing. ATM just close the torrent and + // call the hash_removed slots. This might open and restart the + // hashing of this torrent. - // Hash removed slot must be called after close as we can't atm - // stop already started hash checks except through close. - std::for_each(slot_map_hash_removed().begin(), slot_map_hash_removed().end(), download_list_call(download)); +// if (download->is_hash_checking()) { +// download->download()->close(); - } else { - download->download()->close(); - } +// // Hash removed slot must be called after close as we can't atm +// // stop already started hash checks except through close. +// std::for_each(slot_map_hash_removed().begin(), slot_map_hash_removed().end(), download_list_call(download)); +// } else { +// download->download()->close(); +// } + + // But this isn't correct either, i think... ATM do the borking + // thing, the hash queue won't be updated. Need to properly handle + // erasing a download. + + // Propably should do its own thingie in erase rather than calling + // close. + + download->download()->close(); + + std::for_each(slot_map_hash_removed().begin(), slot_map_hash_removed().end(), download_list_call(download)); std::for_each(slot_map_close().begin(), slot_map_close().end(), download_list_call(download)); } @@ -256,34 +276,27 @@ DownloadList::resume(Download* download) { if (download->download()->is_active()) return; - // Properly escape when resume get's called during hashing. The - // 'state' is changed by the call to DownloadList::start so it - // will automagically start afterwards. - if (control->core()->hash_queue()->is_queued(download)) - return; - - download->variable()->set("state_changed", cachedTime.seconds()); - - open_throw(download); - // Manual or end-of-download rehashing clears the resume data so // we can just start the hashing again without clearing it again. // // It is also assumed the is_hash_checked flag gets cleared when // 'hashing' was set. - if (!download->download()->is_hash_checked()) { + if (!download->is_hash_checked()) { + download->set_hash_failed(false); // Set 'hashing' to started if hashing wasn't started, else keep // the old value. if (download->variable()->get_value("hashing") == Download::variable_hashing_stopped) - download->variable()->set("hashing", Download::variable_hashing_started); + download->variable()->set("hashing", Download::variable_hashing_initial); - control->core()->hash_queue()->insert(download); std::for_each(slot_map_hash_queued().begin(), slot_map_hash_queued().end(), download_list_call(download)); - return; } + download->variable()->set("state_changed", cachedTime.seconds()); + + open_throw(download); + if (download->is_done()) { download->set_connection_type(download->variable()->get_string("connection_seed")); } else { @@ -314,11 +327,10 @@ DownloadList::pause(Download* download) { try { - if (control->core()->hash_queue()->is_queued(download)) { - control->core()->hash_queue()->remove(download); + // Don't stop if we're doing the final hashing. + if (download->variable()->get_value("hashing") == Download::variable_hashing_initial) { + download->variable()->set("hashing", Download::variable_hashing_stopped); - // Hash removed slot must be called after close as we can't atm - // stop already started hash checks except through close. std::for_each(slot_map_hash_removed().begin(), slot_map_hash_removed().end(), download_list_call(download)); } @@ -347,37 +359,20 @@ DownloadList::check_hash(Download* download) { try { - download->variable()->set("hashing", Download::variable_hashing_started); - check_hash_throw(download); + download->variable()->set("hashing", Download::variable_hashing_rehash); + hash_clear(download); } catch (torrent::local_error& e) { control->core()->push_log(e.what()); } } -// Throw in addition to not setting 'hashing'. -void -DownloadList::check_hash_throw(Download* download) { - check_contains(download); - - close_throw(download); - download->download()->hash_resume_clear(); - open_throw(download); - - // If any more stuff is added here, make sure resume etc are still - // correct. - control->core()->hash_queue()->insert(download); - std::for_each(slot_map_hash_queued().begin(), slot_map_hash_queued().end(), download_list_call(download)); -} - void DownloadList::hash_done(Download* download) { check_contains(download); - if (!download->download()->is_hash_checked() || - download->download()->is_hash_checking() || - download->download()->is_active()) - throw torrent::internal_error("DownloadList::hash_done(...) download in invalid state."); + if (!download->is_hash_checked() || download->is_hash_checking() || download->is_active()) + throw torrent::client_error("DownloadList::hash_done(...) download in invalid state."); // Need to find some sane conditional here. Can we check the total // downloaded to ensure something was transferred, thus we didn't @@ -392,7 +387,8 @@ DownloadList::hash_done(Download* download) { download->variable()->set("hashing", Download::variable_hashing_stopped); switch (hashing) { - case Download::variable_hashing_started: + case Download::variable_hashing_initial: + case Download::variable_hashing_rehash: // Normal re/hashing. if (download->is_done()) @@ -432,6 +428,20 @@ DownloadList::hash_done(Download* download) { std::for_each(slot_map_hash_done().begin(), slot_map_hash_done().end(), download_list_call(download)); } +void +DownloadList::hash_clear(Download* download) { + check_contains(download); + + close_throw(download); + download->download()->hash_resume_clear(); + + download->set_hash_failed(false); + + // If any more stuff is added here, make sure resume etc are still + // correct. + std::for_each(slot_map_hash_queued().begin(), slot_map_hash_queued().end(), download_list_call(download)); +} + void DownloadList::received_finished(Download* download) { check_contains(download); @@ -441,7 +451,7 @@ DownloadList::received_finished(Download* download) { // trigger correctly, also so it can bork on missing data. download->variable()->set("hashing", Download::variable_hashing_last); - check_hash_throw(download); + hash_clear(download); } else { confirm_finished(download); diff --git a/src/core/download_list.h b/src/core/download_list.h index 2e9b5842..52d4e068 100644 --- a/src/core/download_list.h +++ b/src/core/download_list.h @@ -100,9 +100,6 @@ public: void pause(Download* d); void check_hash(Download* d); - void check_hash_throw(Download* d); - - void hash_done(Download* d); enum { SLOTS_INSERT, @@ -171,6 +168,9 @@ public: static void erase_key(slot_map& sm, const std::string& key) { sm.erase(key); } private: + void hash_done(Download* d); + void hash_clear(Download* d); + inline void check_contains(Download* d); void received_finished(Download* d); diff --git a/src/core/hash_queue.cc b/src/core/hash_queue.cc deleted file mode 100644 index ca187d42..00000000 --- a/src/core/hash_queue.cc +++ /dev/null @@ -1,125 +0,0 @@ -// rTorrent - BitTorrent client -// Copyright (C) 2005-2006, Jari Sundell -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either version 2 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -// In addition, as a special exception, the copyright holders give -// permission to link the code of portions of this program with the -// OpenSSL library under certain conditions as described in each -// individual source file, and distribute linked combinations -// including the two. -// -// You must obey the GNU General Public License in all respects for -// all of the code used other than OpenSSL. If you modify file(s) -// with this exception, you may extend this exception to your version -// of the file(s), but you are not obligated to do so. If you do not -// wish to do so, delete this exception statement from your version. -// If you delete this exception statement from all source files in the -// program, then also delete it here. -// -// Contact: Jari Sundell -// -// Skomakerveien 33 -// 3185 Skoppum, NORWAY - -#include "config.h" - -#include -#include -#include - -#include "download.h" -#include "download_list.h" -#include "rak/functional.h" -#include "hash_queue.h" - -namespace core { - -bool -HashQueue::is_queued(Download* download) const { - return - download->download()->is_hash_checking() || - std::find_if(begin(), end(), rak::equal(download, std::mem_fun(&HashQueueNode::download))) != end(); -} - -void -HashQueue::insert(Download* download) { - if (download->download()->is_hash_checking() || find(download) != end()) - return; - - if (download->download()->is_hash_checked()) { - m_downloadList->hash_done(download); - return; - } - - if (find(download) != end()) - throw torrent::internal_error("HashQueue::insert(...) download already in queue."); - - iterator itr = Base::insert(end(), new HashQueueNode(download)); - - (*itr)->set_connection(download->download()->signal_hash_done(sigc::bind(sigc::mem_fun(*this, &HashQueue::receive_hash_done), download))); - - fill_queue(); -} - -void -HashQueue::remove(Download* d) { - iterator itr = find(d); - - if (itr == end()) - return; - - // We don't do anything if we're already checking, just disconnect. -// if ((*itr)->download()->download()->is_hash_checking()) { -// // What do we do if we're already checking? -// } - - delete *itr; - Base::erase(itr); - - fill_queue(); -} - -HashQueue::iterator -HashQueue::find(Download* d) { - return std::find_if(begin(), end(), rak::equal(d, std::mem_fun(&HashQueueNode::download))); -} - -void -HashQueue::receive_hash_done(Download* d) { - iterator itr = find(d); - - if (itr == end()) - return; - - delete *itr; - Base::erase(itr); - - m_downloadList->hash_done(d); - fill_queue(); -} - -void -HashQueue::fill_queue() { - if (empty() || front()->download()->download()->is_hash_checking()) - return; - - if (front()->download()->download()->is_hash_checked()) - throw std::logic_error("core::HashQueue::fill_queue() encountered a checked hash"); - - front()->download()->download()->hash_check(); -} - -} diff --git a/src/core/hash_queue.h b/src/core/hash_queue.h deleted file mode 100644 index 89a90e75..00000000 --- a/src/core/hash_queue.h +++ /dev/null @@ -1,109 +0,0 @@ -// rTorrent - BitTorrent client -// Copyright (C) 2005-2006, Jari Sundell -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either version 2 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -// In addition, as a special exception, the copyright holders give -// permission to link the code of portions of this program with the -// OpenSSL library under certain conditions as described in each -// individual source file, and distribute linked combinations -// including the two. -// -// You must obey the GNU General Public License in all respects for -// all of the code used other than OpenSSL. If you modify file(s) -// with this exception, you may extend this exception to your version -// of the file(s), but you are not obligated to do so. If you do not -// wish to do so, delete this exception statement from your version. -// If you delete this exception statement from all source files in the -// program, then also delete it here. -// -// Contact: Jari Sundell -// -// Skomakerveien 33 -// 3185 Skoppum, NORWAY - -#ifndef RTORRENT_CORE_HASH_QUEUE_H -#define RTORRENT_CORE_HASH_QUEUE_H - -#include -#include -#include - -namespace core { - -class Download; -class DownloadList; - -class HashQueueNode; - -class HashQueue : private std::list { -public: - typedef std::list Base; - - 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; - - // Replace 'dl' with a slot. - HashQueue(DownloadList* dl) : m_downloadList(dl) {} - - bool is_queued(Download* download) const; - - void insert(Download* d); - - // It's safe to try to remove downloads not in the queue. The hash - // checking is not stopped if it has already started. - void remove(Download* d); - - iterator find(Download* d); - -private: - void receive_hash_done(Download* d); - - void fill_queue(); - - DownloadList* m_downloadList; -}; - -class HashQueueNode { -public: - HashQueueNode(Download* d) : m_download(d) {} - ~HashQueueNode() { disconnect(); } - - void disconnect() { m_connection.disconnect(); } - Download* download() { return m_download; } - - void set_connection(sigc::connection c) { m_connection = c; } - -private: - Download* m_download; - sigc::connection m_connection; -}; - -} - -#endif diff --git a/src/core/manager.cc b/src/core/manager.cc index 68b03872..7a5992b1 100644 --- a/src/core/manager.cc +++ b/src/core/manager.cc @@ -60,11 +60,11 @@ #include "download.h" #include "download_factory.h" #include "download_store.h" -#include "hash_queue.h" #include "http_queue.h" #include "manager.h" #include "poll_manager_epoll.h" #include "poll_manager_select.h" +#include "view.h" namespace core { @@ -114,6 +114,8 @@ delete_tied(Download* d) { } Manager::Manager() : + m_hashingView(NULL), + m_pollManager(NULL), m_portFirst(6890), m_portLast(6999) { @@ -122,17 +124,24 @@ Manager::Manager() : m_downloadList = new DownloadList(); m_httpQueue = new HttpQueue(); - m_hashQueue = new HashQueue(m_downloadList); } Manager::~Manager() { delete m_downloadList; - delete m_hashQueue; delete m_downloadStore; delete m_httpQueue; } +void +Manager::set_hashing_view(View* v) { + if (v == NULL || m_hashingView != NULL) + throw torrent::client_error("Manager::set_hashing_view(...) received NULL or is already set."); + + m_hashingView = v; + v->signal_changed().connect(sigc::mem_fun(this, &Manager::receive_hashing_changed)); +} + void Manager::initialize_first() { if ((m_pollManager = PollManagerEPoll::create(sysconf(_SC_OPEN_MAX))) != NULL) @@ -360,4 +369,32 @@ Manager::try_create_download_expand(const std::string& uri, bool start, bool pri try_create_download(uri, start, printLog, tied); } +// DownloadList's hashing related functions don't actually start the +// hashing, it only reacts to events. This functions checks the +// hashing view and starts hashing if nessesary. +void +Manager::receive_hashing_changed() { + if (m_hashingView->empty_visible() || + std::find_if(m_hashingView->begin_visible(), m_hashingView->end_visible(), std::mem_fun(&Download::is_hash_checking)) != m_hashingView->end_visible()) + return; + + for (View::iterator itr = m_hashingView->begin_visible(), last = m_hashingView->end_visible(); itr != last; ++itr) { + + try { + + if ((*itr)->is_hash_checked()) + throw torrent::client_error("core::Manager::receive_hashing_changed() hash already checked."); + + m_downloadList->open_throw(*itr); + (*itr)->download()->hash_check(); + + return; + + } catch (torrent::local_error& e) { + (*itr)->set_hash_failed(true); + push_log(e.what()); + } + } +} + } diff --git a/src/core/manager.h b/src/core/manager.h index 8f7ad891..a7644cf2 100644 --- a/src/core/manager.h +++ b/src/core/manager.h @@ -50,8 +50,8 @@ namespace torrent { namespace core { class DownloadStore; -class HashQueue; class HttpQueue; +class View; class Manager { public: @@ -65,9 +65,11 @@ public: DownloadList* download_list() { return m_downloadList; } DownloadStore* download_store() { return m_downloadStore; } - HashQueue* hash_queue() { return m_hashQueue; } HttpQueue* http_queue() { return m_httpQueue; } + View* hashing_view() { return m_hashingView; } + void set_hashing_view(View* v); + PollManager* get_poll_manager() { return m_pollManager; } Log& get_log_important() { return m_logImportant; } Log& get_log_complete() { return m_logComplete; } @@ -103,11 +105,14 @@ private: void receive_http_failed(std::string msg); + void receive_hashing_changed(); + DownloadList* m_downloadList; DownloadStore* m_downloadStore; - HashQueue* m_hashQueue; HttpQueue* m_httpQueue; + View* m_hashingView; + PollManager* m_pollManager; Log m_logImportant; Log m_logComplete; diff --git a/src/core/scheduler.cc b/src/core/scheduler.cc index 086b4482..e7b6901d 100644 --- a/src/core/scheduler.cc +++ b/src/core/scheduler.cc @@ -82,7 +82,7 @@ Scheduler::update() { for (View::iterator itr = m_view->begin_visible(), last = m_view->end_visible(); curActive > target; ++itr) { if (itr == last) - throw torrent::internal_error("Scheduler::update() loop bork."); + throw torrent::client_error("Scheduler::update() loop bork."); if ((*itr)->is_active()) { m_downloadList->pause(*itr); @@ -94,7 +94,7 @@ Scheduler::update() { for (View::iterator itr = m_view->begin_visible(), last = m_view->end_visible(); curActive < m_maxActive; ++itr) { if (itr == last) - throw torrent::internal_error("Scheduler::update() loop bork."); + throw torrent::client_error("Scheduler::update() loop bork."); if (!(*itr)->is_active()) { m_downloadList->resume(*itr); diff --git a/src/core/view.cc b/src/core/view.cc index 6a7e2ad3..0a00e3e7 100644 --- a/src/core/view.cc +++ b/src/core/view.cc @@ -60,15 +60,15 @@ View::~View() { void View::initialize(const std::string& name, core::DownloadList* dlist) { if (!m_name.empty()) - throw torrent::internal_error("View::initialize(...) called on an already initialized view."); + throw torrent::client_error("View::initialize(...) called on an already initialized view."); if (name.empty()) - throw torrent::internal_error("View::initialize(...) called with an empty name."); + throw torrent::client_error("View::initialize(...) called with an empty name."); std::string key = "0_view_" + name; if (dlist->has_slot_insert(key) || dlist->has_slot_erase(key)) - throw torrent::internal_error("View::initialize(...) duplicate key name found in DownloadList."); + throw torrent::client_error("View::initialize(...) duplicate key name found in DownloadList."); m_name = name; m_list = dlist; @@ -167,7 +167,7 @@ View::filter() { void View::set_filter_on(int event) { if (event == DownloadList::SLOTS_INSERT || event == DownloadList::SLOTS_ERASE || event >= DownloadList::SLOTS_MAX_SIZE) - throw torrent::internal_error("View::filter_on(...) invalid event."); + throw torrent::client_error("View::filter_on(...) invalid event."); m_list->slots(event)["0_view_" + m_name] = sigc::bind(sigc::mem_fun(this, &View::received), event); } @@ -193,7 +193,7 @@ View::insert_visible(Download* d) { inline void View::erase(iterator itr) { if (itr == end_filtered()) - throw torrent::internal_error("View::erase_visible(...) iterator out of range."); + throw torrent::client_error("View::erase_visible(...) iterator out of range."); m_size -= (itr < end_visible()); m_focus -= (m_focus > position(itr)); @@ -209,7 +209,7 @@ View::received(core::Download* download, int event) { case DownloadList::SLOTS_INSERT: if (itr != base_type::end()) - throw torrent::internal_error("View::received(..., SLOTS_INSERT) already inserted."); + throw torrent::client_error("View::received(..., SLOTS_INSERT) already inserted."); if (view_downloads_filter(m_filter)(download)) insert_visible(download); @@ -217,7 +217,7 @@ View::received(core::Download* download, int event) { base_type::insert(end_filtered(), download); if (m_focus > m_size) - throw torrent::internal_error("View::received(...) m_focus > m_size."); + throw torrent::client_error("View::received(...) m_focus > m_size."); break; @@ -227,7 +227,7 @@ View::received(core::Download* download, int event) { default: if (itr == end_filtered()) - throw torrent::internal_error("View::received(..., SLOTS_*) could not find download."); + throw torrent::client_error("View::received(..., SLOTS_*) could not find download."); if (view_downloads_filter(m_filter)(download)) { diff --git a/src/core/view.h b/src/core/view.h index 60de88e6..229f7d42 100644 --- a/src/core/view.h +++ b/src/core/view.h @@ -85,7 +85,8 @@ public: const std::string& name() const { return m_name; } - bool empty() const { return m_size == 0; } + bool empty_visible() const { return m_size == 0; } + size_type size() const { return m_size; } // Perhaps this should be renamed? diff --git a/src/core/view_manager.cc b/src/core/view_manager.cc index 1a223dfd..bcbe51d4 100644 --- a/src/core/view_manager.cc +++ b/src/core/view_manager.cc @@ -44,7 +44,6 @@ #include "download.h" #include "download_list.h" -#include "hash_queue.h" #include "manager.h" #include "view.h" #include "view_manager.h" @@ -162,7 +161,7 @@ ViewManager::clear() { ViewManager::iterator ViewManager::insert(const std::string& name) { if (find(name) != end()) - throw torrent::internal_error("ViewManager::insert(...) name already inserted."); + throw torrent::client_error("ViewManager::insert(...) name already inserted."); View* view = new View(); view->initialize(name, m_list); diff --git a/src/display/utils.cc b/src/display/utils.cc index 98bd7091..6961d621 100644 --- a/src/display/utils.cc +++ b/src/display/utils.cc @@ -79,7 +79,7 @@ print_hhmmss_local(char* first, char* last, time_t t) { if (u == NULL) //return "inv_time"; - throw torrent::internal_error("print_hhmmss_local(...) failed."); + throw torrent::client_error("print_hhmmss_local(...) failed."); return print_buffer(first, last, "%2u:%02u:%02u", u->tm_hour, u->tm_min, u->tm_sec); } @@ -98,7 +98,7 @@ print_ddmmyyyy(char* first, char* last, time_t t) { if (u == NULL) //return "inv_time"; - throw torrent::internal_error("print_ddmmyyyy(...) failed."); + throw torrent::client_error("print_ddmmyyyy(...) failed."); return print_buffer(first, last, "%02u/%02u/%04u", u->tm_mday, (u->tm_mon + 1), (1900 + u->tm_year)); } @@ -154,17 +154,17 @@ print_download_info(char* first, char* last, core::Download* d) { first = print_buffer(first, last, " [%s]", core::Download::priority_to_string(d->priority())); if (first > last) - throw torrent::internal_error("print_download_info(...) wrote past end of the buffer."); + throw torrent::client_error("print_download_info(...) wrote past end of the buffer."); return first; } char* print_download_status(char* first, char* last, core::Download* d) { - if (!d->download()->is_active()) + if (!d->is_active()) first = print_buffer(first, last, "Inactive: "); - if (d->download()->is_hash_checking()) { + if (d->is_hash_checking()) { first = print_buffer(first, last, "Checking hash [%2i%%]", (d->download()->chunks_hashed() * 100) / d->download()->chunks_total()); @@ -182,7 +182,7 @@ print_download_status(char* first, char* last, core::Download* d) { } if (first > last) - throw torrent::internal_error("print_download_status(...) wrote past end of the buffer."); + throw torrent::client_error("print_download_status(...) wrote past end of the buffer."); return first; } @@ -233,7 +233,7 @@ print_status_info(char* first, char* last) { } if (first > last) - throw torrent::internal_error("print_status_info(...) wrote past end of the buffer."); + throw torrent::client_error("print_status_info(...) wrote past end of the buffer."); if (!rak::socket_address::cast_from(torrent::connection_manager()->bind_address())->is_address_any()) { first = print_buffer(first, last, " [Bind "); diff --git a/src/display/window_download_list.cc b/src/display/window_download_list.cc index cdad86bc..562ed84e 100644 --- a/src/display/window_download_list.cc +++ b/src/display/window_download_list.cc @@ -73,7 +73,7 @@ WindowDownloadList::redraw() { m_canvas->print(0, 0, "%s", ("[View: " + m_view->name() + "]").c_str()); - if (m_view->empty() || m_canvas->get_width() < 5 || m_canvas->get_height() < 2) + if (m_view->empty_visible() || m_canvas->get_width() < 5 || m_canvas->get_height() < 2) return; typedef std::pair Range; diff --git a/src/ui/download_list.cc b/src/ui/download_list.cc index 5dd2b0b4..09a43bde 100644 --- a/src/ui/download_list.cc +++ b/src/ui/download_list.cc @@ -90,7 +90,7 @@ DownloadList::DownloadList(Control* c) : receive_change_view("main"); if (m_view == NULL) - throw torrent::internal_error("View \"main\" must be present to initialize the main display."); + throw torrent::client_error("View \"main\" must be present to initialize the main display."); m_taskUpdate.set_slot(rak::mem_fn(this, &DownloadList::task_update)), @@ -209,7 +209,7 @@ DownloadList::receive_stop_download() { if (m_view->focus() == m_view->end_visible()) return; - if ((*m_view->focus())->download()->is_active()) + if ((*m_view->focus())->variable()->get_value("state") == 1) m_control->core()->download_list()->stop(*m_view->focus()); else m_control->core()->download_list()->erase(*m_view->focus()); @@ -391,7 +391,7 @@ DownloadList::receive_change_view(const std::string& name) { ElementDownloadList* ui = dynamic_cast(m_uiArray[DISPLAY_DOWNLOAD_LIST]); if (ui == NULL) - throw torrent::internal_error("DownloadList::receive_change_view(...) could not cast ui."); + throw torrent::client_error("DownloadList::receive_change_view(...) could not cast ui."); ui->set_view(m_view); } diff --git a/src/ui/element_file_list.cc b/src/ui/element_file_list.cc index 1ae6ed6a..1735fd97 100644 --- a/src/ui/element_file_list.cc +++ b/src/ui/element_file_list.cc @@ -61,7 +61,7 @@ ElementFileList::ElementFileList(core::Download* d) : void ElementFileList::activate(Control* c, MItr mItr) { if (m_window != NULL) - throw torrent::internal_error("ui::ElementFileList::activate(...) called on an object in the wrong state"); + throw torrent::client_error("ui::ElementFileList::activate(...) called on an object in the wrong state"); c->input()->push_front(&m_bindings); @@ -71,7 +71,7 @@ ElementFileList::activate(Control* c, MItr mItr) { void ElementFileList::disable(Control* c) { if (m_window == NULL) - throw torrent::internal_error("ui::ElementFileList::disable(...) called on an object in the wrong state"); + throw torrent::client_error("ui::ElementFileList::disable(...) called on an object in the wrong state"); c->input()->erase(&m_bindings); @@ -82,7 +82,7 @@ ElementFileList::disable(Control* c) { void ElementFileList::receive_next() { if (m_window == NULL) - throw torrent::internal_error("ui::ElementFileList::receive_next(...) called on a disabled object"); + throw torrent::client_error("ui::ElementFileList::receive_next(...) called on a disabled object"); if (++m_focus >= m_download->download()->file_list().size()) m_focus = 0; @@ -93,7 +93,7 @@ ElementFileList::receive_next() { void ElementFileList::receive_prev() { if (m_window == NULL) - throw torrent::internal_error("ui::ElementFileList::receive_prev(...) called on a disabled object"); + throw torrent::client_error("ui::ElementFileList::receive_prev(...) called on a disabled object"); torrent::FileList fl = m_download->download()->file_list(); @@ -111,7 +111,7 @@ ElementFileList::receive_prev() { void ElementFileList::receive_priority() { if (m_window == NULL) - throw torrent::internal_error("ui::ElementFileList::receive_prev(...) called on a disabled object"); + throw torrent::client_error("ui::ElementFileList::receive_prev(...) called on a disabled object"); torrent::FileList fl = m_download->download()->file_list(); @@ -129,7 +129,7 @@ ElementFileList::receive_priority() { void ElementFileList::receive_change_all() { if (m_window == NULL) - throw torrent::internal_error("ui::ElementFileList::receive_prev(...) called on a disabled object"); + throw torrent::client_error("ui::ElementFileList::receive_prev(...) called on a disabled object"); torrent::FileList fl = m_download->download()->file_list(); diff --git a/src/ui/element_tracker_list.cc b/src/ui/element_tracker_list.cc index aeae5242..d2ed1b68 100644 --- a/src/ui/element_tracker_list.cc +++ b/src/ui/element_tracker_list.cc @@ -62,7 +62,7 @@ ElementTrackerList::ElementTrackerList(core::Download* d) : void ElementTrackerList::activate(Control* c, MItr mItr) { if (m_window != NULL) - throw torrent::internal_error("ui::ElementTrackerList::activate(...) called on an object in the wrong state"); + throw torrent::client_error("ui::ElementTrackerList::activate(...) called on an object in the wrong state"); c->input()->push_front(&m_bindings); @@ -72,7 +72,7 @@ ElementTrackerList::activate(Control* c, MItr mItr) { void ElementTrackerList::disable(Control* c) { if (m_window == NULL) - throw torrent::internal_error("ui::ElementTrackerList::disable(...) called on an object in the wrong state"); + throw torrent::client_error("ui::ElementTrackerList::disable(...) called on an object in the wrong state"); c->input()->erase(&m_bindings); @@ -83,7 +83,7 @@ ElementTrackerList::disable(Control* c) { void ElementTrackerList::receive_disable() { if (m_window == NULL) - throw torrent::internal_error("ui::ElementTrackerList::receive_disable(...) called on a disabled object"); + throw torrent::client_error("ui::ElementTrackerList::receive_disable(...) called on a disabled object"); torrent::Tracker t = m_download->download()->tracker_list().get(m_focus); @@ -98,7 +98,7 @@ ElementTrackerList::receive_disable() { void ElementTrackerList::receive_next() { if (m_window == NULL) - throw torrent::internal_error("ui::ElementTrackerList::receive_next(...) called on a disabled object"); + throw torrent::client_error("ui::ElementTrackerList::receive_next(...) called on a disabled object"); if (++m_focus >= m_download->download()->tracker_list().size()) m_focus = 0; @@ -109,7 +109,7 @@ ElementTrackerList::receive_next() { void ElementTrackerList::receive_prev() { if (m_window == NULL) - throw torrent::internal_error("ui::ElementTrackerList::receive_prev(...) called on a disabled object"); + throw torrent::client_error("ui::ElementTrackerList::receive_prev(...) called on a disabled object"); if (m_download->download()->tracker_list().size() == 0) return; @@ -125,12 +125,12 @@ ElementTrackerList::receive_prev() { void ElementTrackerList::receive_cycle_group() { if (m_window == NULL) - throw torrent::internal_error("ui::ElementTrackerList::receive_group_cycle(...) called on a disabled object"); + throw torrent::client_error("ui::ElementTrackerList::receive_group_cycle(...) called on a disabled object"); torrent::TrackerList tl = m_download->download()->tracker_list(); if (m_focus >= tl.size()) - throw torrent::internal_error("ui::ElementTrackerList::receive_group_cycle(...) called with an invalid focus"); + throw torrent::client_error("ui::ElementTrackerList::receive_group_cycle(...) called with an invalid focus"); tl.cycle_group(tl.get(m_focus).group()); diff --git a/src/utils/variable_map.cc b/src/utils/variable_map.cc index c764f5c4..28033067 100644 --- a/src/utils/variable_map.cc +++ b/src/utils/variable_map.cc @@ -59,7 +59,7 @@ VariableMap::insert(const std::string& key, Variable* v) { iterator itr = base_type::find(key); if (itr != base_type::end()) - throw torrent::internal_error("VariableMap::insert(...) tried to insert an already existing key."); + throw torrent::client_error("VariableMap::insert(...) tried to insert an already existing key."); base_type::insert(itr, value_type(key, v)); }