diff --git a/src/control.cc b/src/control.cc index 5414c0a9..ee7ee751 100644 --- a/src/control.cc +++ b/src/control.cc @@ -41,6 +41,7 @@ #include #include "core/manager.h" +#include "core/download_store.h" #include "core/view_manager.h" #include "core/scheduler.h" @@ -110,7 +111,7 @@ Control::initialize() { m_core->initialize_second(); m_core->listen_open(); - m_core->download_store().enable(m_variables->get_value("session_lock")); + m_core->download_store()->enable(m_variables->get_value("session_lock")); m_scheduler->set_view(*m_viewManager->find_throw("scheduler")); @@ -125,7 +126,7 @@ Control::cleanup() { m_inputStdin->remove(m_core->get_poll_manager()->get_torrent_poll()); - m_core->download_store().disable(); + m_core->download_store()->disable(); m_ui->cleanup(); m_core->cleanup(); diff --git a/src/core/download.cc b/src/core/download.cc index c1e65560..07f9f559 100644 --- a/src/core/download.cc +++ b/src/core/download.cc @@ -70,8 +70,16 @@ Download::Download(download_type d) : m_variables.insert("connection_leech", new utils::VariableAny(connection_type_to_string(download_type::CONNECTION_LEECH))); m_variables.insert("connection_seed", new utils::VariableAny(connection_type_to_string(download_type::CONNECTION_SEED))); + + // 0 - stopped + // 1 - started m_variables.insert("state", new utils::VariableObject(bencode(), "rtorrent", "state", torrent::Object::TYPE_VALUE)); m_variables.insert("complete", new utils::VariableObject(bencode(), "rtorrent", "complete", torrent::Object::TYPE_VALUE)); + + // 0 - Not hashing + // 1 - Normal hashing + // 2 - Download finished, hashing + m_variables.insert("hashing", new utils::VariableObject(bencode(), "rtorrent", "hashing", torrent::Object::TYPE_VALUE)); m_variables.insert("tied_to_file", new utils::VariableObject(bencode(), "rtorrent", "tied_to_file", torrent::Object::TYPE_STRING)); // The "state_changed" variable is required to be a valid unix time diff --git a/src/core/download.h b/src/core/download.h index d0dd4c7f..6c1208c5 100644 --- a/src/core/download.h +++ b/src/core/download.h @@ -55,6 +55,10 @@ public: typedef download_type::ConnectionType connection_type; 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_last = 2; + Download(download_type d); ~Download(); @@ -73,7 +77,9 @@ public: tracker_list_type* tracker_list() { return &m_trackerList; } const std::string& info_hash() const { return m_download.info_hash(); } + const std::string& message() const { return m_message; } + void set_message(const std::string& msg) { m_message = msg; } uint32_t chunks_failed() const { return m_chunksFailed; } diff --git a/src/core/download_factory.cc b/src/core/download_factory.cc index b9d07aa0..b2acf706 100644 --- a/src/core/download_factory.cc +++ b/src/core/download_factory.cc @@ -54,6 +54,7 @@ #include "download.h" #include "download_factory.h" +#include "download_store.h" namespace core { @@ -103,7 +104,7 @@ DownloadFactory::receive_load() { if (std::strncmp(m_uri.c_str(), "http://", 7) == 0) { // Http handling here. m_stream = new std::stringstream; - HttpQueue::iterator itr = m_manager->http_queue().insert(m_uri, m_stream); + HttpQueue::iterator itr = m_manager->http_queue()->insert(m_uri, m_stream); (*itr)->signal_done().slots().push_front(sigc::mem_fun(*this, &DownloadFactory::receive_loaded)); (*itr)->signal_failed().slots().push_front(sigc::mem_fun(*this, &DownloadFactory::receive_failed)); @@ -190,7 +191,10 @@ DownloadFactory::receive_success() { else download->variable()->set("directory", rtorrent->get_key("directory")); - if (download->variable()->get_value("state") == 1) + // This torrent was queued for hashing or hashing when the session + // file was saved. Or it was in a started state. + if (download->variable()->get_value("hashing") != Download::variable_hashing_stopped || + download->variable()->get_value("state") != 0) m_manager->download_list()->resume(download); } else { @@ -203,7 +207,7 @@ DownloadFactory::receive_success() { if (m_start) m_manager->download_list()->start(download); - m_manager->download_store().save(download); + m_manager->download_store()->save(download); } m_slotFinished(); @@ -237,6 +241,9 @@ DownloadFactory::initialize_rtorrent(Download* download, torrent::Object* rtorre if (!rtorrent->has_key_value("complete")) rtorrent->insert_key("complete", (int64_t)0); + if (!rtorrent->has_key_value("hashing")) + rtorrent->insert_key("hashing", Download::variable_hashing_stopped); + if (!rtorrent->has_key_string("tied_to_file")) rtorrent->insert_key("tied_to_file", std::string()); diff --git a/src/core/download_list.cc b/src/core/download_list.cc index 6d2cccba..2757b166 100644 --- a/src/core/download_list.cc +++ b/src/core/download_list.cc @@ -74,6 +74,18 @@ struct download_list_call { Download* m_download; }; +DownloadList::~DownloadList() { + std::for_each(begin(), end(), std::bind1st(std::mem_fun(&DownloadList::close), this)); + std::for_each(begin(), end(), rak::call_delete()); + + base_type::clear(); +} + +void +DownloadList::session_save() { + std::for_each(begin(), end(), std::bind1st(std::mem_fun(&DownloadStore::save), control->core()->download_store())); +} + Download* DownloadList::create(std::istream* str, bool printLog) { torrent::Object* object = new torrent::Object; @@ -113,7 +125,7 @@ DownloadList::insert(Download* download) { } 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 part 2: " + std::string(e.what())); + throw torrent::internal_error("Caught during DownloadList::insert(...): " + std::string(e.what())); } return itr; @@ -131,9 +143,9 @@ DownloadList::erase(iterator itr) { if (itr == end()) throw torrent::internal_error("DownloadList::erase(...) could not find download."); - // Make safe to erase active downloads. - if ((*itr)->download()->is_active()) - throw torrent::internal_error("DownloadList::erase(...) called on an active download."); + close(*itr); + + control->core()->download_store()->remove(*itr); std::for_each(m_slotMapErase.begin(), m_slotMapErase.end(), download_list_call(*itr)); @@ -187,7 +199,14 @@ DownloadList::close_throw(Download* download) { if (download->download()->is_active()) pause(download); + // Save the torrent on close, this covers shutdown and if a torrent + // is manually closed which would clear the progress data. For + // better crash protection, save regulary in addition to this. + // + // Used to be in pause, but this was wrong for rehashing etc. + control->core()->download_store()->save(download); control->core()->hash_queue()->remove(download); + download->download()->close(); std::for_each(m_slotMapClose.begin(), m_slotMapClose.end(), download_list_call(download)); @@ -220,29 +239,44 @@ DownloadList::resume(Download* download) { if (download->download()->is_active()) return; - open_throw(download); - - if (download->download()->is_hash_checked()) { - - if (download->is_done()) - download->set_connection_type(download->variable()->get_string("connection_seed")); - else - download->set_connection_type(download->variable()->get_string("connection_leech")); - - // Update the priority to ensure it has the correct - // seeding/unfinished modifiers. - download->set_priority(download->priority()); - download->download()->start(); - - std::for_each(m_slotMapStart.begin(), m_slotMapStart.end(), download_list_call(download)); - - } else { - // TODO: This can cause infinit looping? - control->core()->hash_queue()->insert(download); - } + // 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()->find(download) != control->core()->hash_queue()->end()) + 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()) { + + // 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); + + control->core()->hash_queue()->insert(download); + return; + } + + if (download->is_done()) + download->set_connection_type(download->variable()->get_string("connection_seed")); + else + download->set_connection_type(download->variable()->get_string("connection_leech")); + + // Update the priority to ensure it has the correct + // seeding/unfinished modifiers. + download->set_priority(download->priority()); + download->download()->start(); + + std::for_each(m_slotMapStart.begin(), m_slotMapStart.end(), download_list_call(download)); + } catch (torrent::local_error& e) { control->core()->push_log(e.what()); } @@ -254,6 +288,10 @@ DownloadList::pause(Download* download) { try { + // Make sure we don't start hash checking a download that we won't + // start. + control->core()->hash_queue()->remove(download); + if (!download->download()->is_active()) return; @@ -266,7 +304,7 @@ DownloadList::pause(Download* download) { // Save the state after all the slots, etc have been called so we // include the modifications they may make. - control->core()->download_store().save(download); + //control->core()->download_store()->save(download); } catch (torrent::local_error& e) { control->core()->push_log(e.what()); @@ -274,10 +312,8 @@ DownloadList::pause(Download* download) { } void -DownloadList::clear() { - std::for_each(begin(), end(), rak::call_delete()); - - base_type::clear(); +DownloadList::save(Download* d) { + } void @@ -286,17 +322,28 @@ DownloadList::check_hash(Download* download) { try { - close_throw(download); - download->download()->hash_resume_clear(); - open_throw(download); - - control->core()->hash_queue()->insert(download); + download->variable()->set("hashing", Download::variable_hashing_started); + check_hash_throw(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); +} + void DownloadList::hash_done(Download* download) { check_contains(download); @@ -313,18 +360,42 @@ DownloadList::hash_done(Download* download) { // confirm all the data, avoiding large BW usage on f.ex. the // ReiserFS bug with >4GB files. - // Use just is_done(), have another if statement inside. - if (download->is_done() && download->variable()->get_value("complete") == 0) { + int64_t hashing = download->variable()->get_value("hashing"); + download->variable()->set("hashing", Download::variable_hashing_stopped); - if (control->variable()->get_value("session_on_completion")) - control->core()->download_store().save(download); + switch (hashing) { + case Download::variable_hashing_started: + // Normal re/hashing. - // Send a "truly finished message from here. - confirm_finished(download); + if (download->is_done()) + download->variable()->set("complete", (int64_t)1); + + if (download->variable()->get_value("state") == 1) + resume(download); + + return; + + case Download::variable_hashing_last: + + if (download->is_done()) { + + confirm_finished(download); + + if (download->variable()->get_value("state") == 1) + resume(download); + + } else { + download->set_message("Hash check on download completion found bad chunks."); + } + + return; + + case Download::variable_hashing_stopped: + default: + // Either an error or someone wrote to the hashing variable... + download->set_message("Hash check completed but the \"hashing\" variable is in an invalid state."); + return; } - - if (download->variable()->get_value("state") == 1) - resume(download); } void @@ -335,13 +406,15 @@ DownloadList::received_finished(Download* download) { // Set some 'checking_finished_thingie' variable to make hash_done // trigger correctly, also so it can bork on missing data. - check_hash(download); + download->variable()->set("hashing", Download::variable_hashing_last); + check_hash_throw(download); } else { confirm_finished(download); } } +// The download must be open when we call this function. void DownloadList::confirm_finished(Download* download) { check_contains(download); @@ -354,6 +427,13 @@ DownloadList::confirm_finished(Download* download) { download->download()->tracker_list().send_completed(); + // Do this before the slots are called in case one of them closes + // the download. + if (!download->is_active() && control->variable()->get_value("session_on_completion") == 1) { + download->download()->hash_resume_save(); + control->core()->download_store()->save(download); + } + std::for_each(m_slotMapFinished.begin(), m_slotMapFinished.end(), download_list_call(download)); } diff --git a/src/core/download_list.h b/src/core/download_list.h index 88d1d269..89218af5 100644 --- a/src/core/download_list.h +++ b/src/core/download_list.h @@ -72,7 +72,9 @@ public: using base_type::empty; using base_type::size; - ~DownloadList() { clear(); } + ~DownloadList(); + + void session_save(); // Might move this to DownloadFactory. Download* create(std::istream* str, bool printLog); @@ -95,7 +97,11 @@ public: void resume(Download* d); void pause(Download* d); + void save(Download* d); + void check_hash(Download* d); + void check_hash_throw(Download* d); + void hash_done(Download* d); slot_map& slot_map_insert() { return m_slotMapInsert; } @@ -129,8 +135,6 @@ public: private: inline void check_contains(Download* d); - void clear(); - void received_finished(Download* d); void confirm_finished(Download* d); diff --git a/src/core/hash_queue.cc b/src/core/hash_queue.cc index 86f3797c..e153e061 100644 --- a/src/core/hash_queue.cc +++ b/src/core/hash_queue.cc @@ -49,8 +49,7 @@ namespace core { void HashQueue::insert(Download* download) { - if (download->download()->is_hash_checking() || - find(download) != end()) + if (download->download()->is_hash_checking() || find(download) != end()) return; if (download->download()->is_hash_checked()) { diff --git a/src/core/manager.cc b/src/core/manager.cc index fe1d6b3d..bf7f0e6b 100644 --- a/src/core/manager.cc +++ b/src/core/manager.cc @@ -59,7 +59,9 @@ #include "curl_get.h" #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" @@ -116,13 +118,19 @@ Manager::Manager() : m_portFirst(6890), m_portLast(6999) { + m_downloadStore = new DownloadStore(); m_downloadList = new DownloadList(); + + m_httpQueue = new HttpQueue(); m_hashQueue = new HashQueue(m_downloadList); } Manager::~Manager() { - delete m_hashQueue; delete m_downloadList; + delete m_hashQueue; + + delete m_downloadStore; + delete m_httpQueue; } void @@ -142,7 +150,7 @@ Manager::initialize_first() { void Manager::initialize_second() { torrent::Http::set_factory(m_pollManager->get_http_stack()->get_http_factory()); - m_httpQueue.slot_factory(m_pollManager->get_http_stack()->get_http_factory()); + m_httpQueue->slot_factory(m_pollManager->get_http_stack()->get_http_factory()); CurlStack::global_init(); @@ -152,8 +160,6 @@ Manager::initialize_second() { m_downloadList->slot_map_insert()["1_connect_storage_log"] = sigc::bind(sigc::ptr_fun(&connect_signal_storage_log), sigc::mem_fun(m_logComplete, &Log::push_front)); m_downloadList->slot_map_insert()["1_connect_tracker_dump"] = sigc::bind(sigc::ptr_fun(&connect_signal_tracker_dump), sigc::ptr_fun(&receive_tracker_dump)); - m_downloadList->slot_map_erase()["1_hash_queue_remove"] = sigc::mem_fun(m_hashQueue, &HashQueue::remove); - m_downloadList->slot_map_erase()["1_store_remove"] = sigc::mem_fun(m_downloadStore, &DownloadStore::remove); m_downloadList->slot_map_erase()["1_delete_tied"] = sigc::ptr_fun(&delete_tied); } diff --git a/src/core/manager.h b/src/core/manager.h index 11b646d1..b5aff40e 100644 --- a/src/core/manager.h +++ b/src/core/manager.h @@ -40,8 +40,6 @@ #include #include "download_list.h" -#include "download_store.h" -#include "http_queue.h" #include "poll_manager.h" #include "log.h" @@ -51,7 +49,9 @@ namespace torrent { namespace core { +class DownloadStore; class HashQueue; +class HttpQueue; class Manager { public: @@ -62,11 +62,12 @@ public: Manager(); ~Manager(); - DownloadStore& download_store() { return m_downloadStore; } - HttpQueue& http_queue() { return m_httpQueue; } DownloadList* download_list() { return m_downloadList; } + DownloadStore* download_store() { return m_downloadStore; } + HashQueue* hash_queue() { return m_hashQueue; } + HttpQueue* http_queue() { return m_httpQueue; } PollManager* get_poll_manager() { return m_pollManager; } Log& get_log_important() { return m_logImportant; } @@ -104,9 +105,9 @@ private: void receive_http_failed(std::string msg); DownloadList* m_downloadList; - DownloadStore m_downloadStore; + DownloadStore* m_downloadStore; HashQueue* m_hashQueue; - HttpQueue m_httpQueue; + HttpQueue* m_httpQueue; PollManager* m_pollManager; Log m_logImportant; diff --git a/src/core/poll_manager.cc b/src/core/poll_manager.cc index 0b6cd184..6e41d10b 100644 --- a/src/core/poll_manager.cc +++ b/src/core/poll_manager.cc @@ -36,8 +36,8 @@ #include "config.h" -#include #include +#include #include "poll_manager.h" @@ -93,8 +93,8 @@ PollManager::~PollManager() { void PollManager::check_error() { - if (errno != EINTR) - throw std::runtime_error("Poll::work(): select error"); + if (rak::error_number::current().value() != rak::error_number::e_intr) + throw std::runtime_error("Poll::work(): " + std::string(rak::error_number::current().c_str())); } } diff --git a/src/main.cc b/src/main.cc index 1a47ad92..8aad6e4b 100644 --- a/src/main.cc +++ b/src/main.cc @@ -50,6 +50,7 @@ #include "core/download.h" #include "core/download_factory.h" +#include "core/download_store.h" #include "core/manager.h" #include "display/canvas.h" #include "display/window.h" @@ -97,7 +98,7 @@ parse_options(Control* c, int argc, char** argv) { void load_session_torrents(Control* c) { // Load session torrents. - std::list l = c->core()->download_store().get_formated_entries().make_list(); + std::list l = c->core()->download_store()->get_formated_entries().make_list(); for (std::list::iterator first = l.begin(), last = l.end(); first != last; ++first) { core::DownloadFactory* f = new core::DownloadFactory(*first, c->core()); @@ -164,8 +165,6 @@ main(int argc, char** argv) { // Currently not doing any sorting on main. control->variable()->process_command("view_add = main"); - control->variable()->process_command("view_sort_new = main"); - control->variable()->process_command("view_sort_current = main"); control->variable()->process_command("view_add = name"); control->variable()->process_command("view_sort_new = name,name"); @@ -192,13 +191,14 @@ main(int argc, char** argv) { control->variable()->process_command("view_sort_current = incomplete,state_changed_reverse"); control->variable()->process_command("schedule = view_main,10,10,view_sort=main,20"); - control->variable()->process_command("schedule = view_name,10,10,view_sort=main,20"); - control->variable()->process_command("schedule = view_started,10,10,view_sort=started,20"); - control->variable()->process_command("schedule = view_stopped,10,10,view_sort=stopped,20"); - control->variable()->process_command("schedule = view_complete,10,10,view_sort=complete,20"); - control->variable()->process_command("schedule = view_incomplete,10,10,view_sort=incomplete,20"); + control->variable()->process_command("schedule = view_name,10,10,view_sort=name,20"); + control->variable()->process_command("schedule = view_started,10,10,view_sort=started,5"); + control->variable()->process_command("schedule = view_stopped,10,10,view_sort=stopped,5"); + control->variable()->process_command("schedule = view_complete,10,10,view_sort=complete,5"); + control->variable()->process_command("schedule = view_incomplete,10,10,view_sort=incomplete,5"); //control->variable()->process_command("schedule = scheduler,10,10,download_scheduler="); + control->variable()->process_command("schedule = session_save,1800,1800,session_save="); // Changing these will bork the (non-existant) scheduler. control->variable()->process_command("view_add = scheduler"); diff --git a/src/option_handler_rules.cc b/src/option_handler_rules.cc index 29260878..f8b2264b 100644 --- a/src/option_handler_rules.cc +++ b/src/option_handler_rules.cc @@ -52,6 +52,7 @@ #include #include "core/download.h" +#include "core/download_store.h" #include "core/manager.h" #include "core/scheduler.h" #include "core/view_manager.h" @@ -97,7 +98,7 @@ apply_load_start(Control* m, const std::string& arg) { } void -apply_stop_untied(Control* m, __UNUSED const std::string& arg) { +apply_stop_untied(Control* m) { core::Manager::DListItr itr = m->core()->download_list()->begin(); while ((itr = std::find_if(itr, m->core()->download_list()->end(), @@ -116,7 +117,7 @@ apply_stop_untied(Control* m, __UNUSED const std::string& arg) { } void -apply_remove_untied(Control* m, __UNUSED const std::string& arg) { +apply_remove_untied(Control* m) { core::Manager::DListItr itr = m->core()->download_list()->begin(); while ((itr = std::find_if(itr, m->core()->download_list()->end(), @@ -272,8 +273,15 @@ apply_view_sort_new(Control* control, const std::string& arg) { } void -apply_download_scheduler(core::Scheduler* scheduler, __UNUSED const std::string& arg) { - scheduler->update(); +apply_import(const std::string& path) { + if (!control->variable()->process_file(path)) + throw torrent::input_error("Could not open option file: " + path); +} + +void +apply_try_import(const std::string& path) { + if (!control->variable()->process_file(path)) + control->core()->push_log("Could not read resource file: " + path); } void @@ -287,10 +295,11 @@ initialize_option_handler(Control* c) { variables->insert("tracker_dump", new utils::VariableAny(std::string())); - variables->insert("session", new utils::VariableStringSlot(rak::mem_fn(&control->core()->download_store(), &core::DownloadStore::path), - rak::mem_fn(&control->core()->download_store(), &core::DownloadStore::set_path))); + variables->insert("session", new utils::VariableStringSlot(rak::mem_fn(control->core()->download_store(), &core::DownloadStore::path), + rak::mem_fn(control->core()->download_store(), &core::DownloadStore::set_path))); variables->insert("session_lock", new utils::VariableBool(true)); variables->insert("session_on_completion", new utils::VariableBool(true)); + variables->insert("session_save", new utils::VariableVoidSlot(rak::mem_fn(c->core()->download_list(), &core::DownloadList::session_save))); variables->insert("connection_leech", new utils::VariableAny("leech")); variables->insert("connection_seed", new utils::VariableAny("seed")); @@ -321,10 +330,8 @@ initialize_option_handler(Control* c) { variables->insert("max_open_sockets", new utils::VariableValueSlot(rak::ptr_fn(&torrent::max_open_sockets), rak::ptr_fn(&torrent::set_max_open_sockets))); variables->insert("print", new utils::VariableStringSlot(rak::value_fn(std::string()), rak::mem_fn(control->core(), &core::Manager::push_log))); - variables->insert("import", new utils::VariableStringSlot(rak::value_fn(std::string()), - rak::mem_fn(control->variable(), &utils::VariableMap::process_file_throw))); - variables->insert("try_import", new utils::VariableStringSlot(rak::value_fn(std::string()), - rak::mem_fn(control->variable(), &utils::VariableMap::process_file_nothrow))); + variables->insert("import", new utils::VariableStringSlot(rak::value_fn(std::string()), rak::ptr_fn(&apply_import))); + variables->insert("try_import", new utils::VariableStringSlot(rak::value_fn(std::string()), rak::ptr_fn(&apply_try_import))); variables->insert("view_add", new utils::VariableStringSlot(rak::value_fn(std::string()), rak::mem_fn(c->view_manager(), &core::ViewManager::insert_throw))); variables->insert("view_filter", new utils::VariableStringSlot(rak::value_fn(std::string()), rak::bind_ptr_fn(&apply_view_filter, c))); @@ -333,12 +340,11 @@ initialize_option_handler(Control* c) { variables->insert("view_sort_new", new utils::VariableStringSlot(rak::value_fn(std::string()), rak::bind_ptr_fn(&apply_view_sort_new, c))); variables->insert("view_sort_current", new utils::VariableStringSlot(rak::value_fn(std::string()), rak::bind_ptr_fn(&apply_view_sort_current, c))); - variables->insert("schedule", new utils::VariableStringSlot(rak::value_fn(std::string()), - rak::mem_fn(c->command_scheduler(), &CommandScheduler::parse))); + variables->insert("schedule", new utils::VariableStringSlot(rak::value_fn(std::string()), rak::mem_fn(c->command_scheduler(), &CommandScheduler::parse))); variables->insert("schedule_remove", new utils::VariableStringSlot(rak::value_fn(std::string()), rak::mem_fn(c->command_scheduler(), &CommandScheduler::erase))); - variables->insert("download_scheduler", new utils::VariableStringSlot(rak::value_fn(std::string()), rak::bind_ptr_fn(&apply_download_scheduler, c->scheduler()))); + variables->insert("download_scheduler", new utils::VariableVoidSlot(rak::mem_fn(control->scheduler(), &core::Scheduler::update))); variables->insert("send_buffer_size", new utils::VariableValueSlot(rak::mem_fn(torrent::connection_manager(), &torrent::ConnectionManager::send_buffer_size), rak::mem_fn(torrent::connection_manager(), &torrent::ConnectionManager::set_send_buffer_size))); @@ -357,8 +363,8 @@ initialize_option_handler(Control* c) { variables->insert("load", new utils::VariableStringSlot(rak::value_fn(std::string()), rak::bind_ptr_fn(&apply_load, c))); variables->insert("load_start", new utils::VariableStringSlot(rak::value_fn(std::string()), rak::bind_ptr_fn(&apply_load_start, c))); - variables->insert("stop_untied", new utils::VariableStringSlot(rak::value_fn(std::string()), rak::bind_ptr_fn(&apply_stop_untied, c))); - variables->insert("remove_untied", new utils::VariableStringSlot(rak::value_fn(std::string()), rak::bind_ptr_fn(&apply_remove_untied, c))); + variables->insert("stop_untied", new utils::VariableVoidSlot(rak::bind_ptr_fn(&apply_stop_untied, c))); + variables->insert("remove_untied", new utils::VariableVoidSlot(rak::bind_ptr_fn(&apply_remove_untied, c))); variables->insert("enable_trackers", new utils::VariableStringSlot(rak::value_fn(std::string()), rak::bind_ptr_fn(&apply_enable_trackers, c))); variables->insert("encoding_list", new utils::VariableStringSlot(rak::value_fn(std::string()), rak::bind_ptr_fn(&apply_encoding_list, c))); diff --git a/src/ui/download_list.cc b/src/ui/download_list.cc index 309423d1..79dcc6a3 100644 --- a/src/ui/download_list.cc +++ b/src/ui/download_list.cc @@ -76,7 +76,7 @@ DownloadList::DownloadList(Control* c) : m_window(c->display()->end()), m_windowTitle(new WTitle("rTorrent " VERSION " - libTorrent " + std::string(torrent::version()))), - m_windowHttpQueue(new WHttp(&c->core()->http_queue())), + m_windowHttpQueue(new WHttp(c->core()->http_queue())), m_uiDownload(NULL), diff --git a/src/utils/variable_generic.cc b/src/utils/variable_generic.cc index 421987ef..ae0a06d0 100644 --- a/src/utils/variable_generic.cc +++ b/src/utils/variable_generic.cc @@ -155,6 +155,16 @@ VariableObject::set(const torrent::Object& arg) { // New and prettified. // +const torrent::Object& +VariableVoidSlot::get() { + return m_cache; +} + +void +VariableVoidSlot::set(const torrent::Object& arg) { + m_slotSet(); +} + const torrent::Object& VariableValueSlot::get() { m_cache = m_slotGet() / m_unit; diff --git a/src/utils/variable_generic.h b/src/utils/variable_generic.h index 60919da1..e1558cad 100644 --- a/src/utils/variable_generic.h +++ b/src/utils/variable_generic.h @@ -102,6 +102,26 @@ private: // New and pretty. // +class VariableVoidSlot : public Variable { +public: + typedef rak::function0 slot_set_type; + + VariableVoidSlot(slot_set_type::base_type* slotSet) { + m_slotSet.set(slotSet); + } + + virtual const torrent::Object& get(); + virtual void set(const torrent::Object& arg); + +private: + slot_set_type m_slotSet; + + // Store the cache here to avoid unnessesary copying and such. This + // should not result in any unresonable memory usage since few + // strings will be very large. + torrent::Object m_cache; +}; + class VariableValueSlot : public Variable { public: typedef rak::function0 slot_get_type; @@ -160,7 +180,6 @@ private: torrent::Object m_cache; }; - } #endif diff --git a/src/utils/variable_map.cc b/src/utils/variable_map.cc index 2b5fe2a8..c764f5c4 100644 --- a/src/utils/variable_map.cc +++ b/src/utils/variable_map.cc @@ -198,15 +198,4 @@ VariableMap::process_file(const std::string& path) { return true; } -void -VariableMap::process_file_throw(const std::string& path) { - if (!process_file(path)) - throw torrent::input_error("Could not open option file: " + path); -} - -void -VariableMap::process_file_nothrow(const std::string& path) { - process_file(path); -} - } diff --git a/src/utils/variable_map.h b/src/utils/variable_map.h index b088a58c..4c479936 100644 --- a/src/utils/variable_map.h +++ b/src/utils/variable_map.h @@ -77,8 +77,6 @@ public: void process_command(const std::string& command); void process_stream(std::istream* str); bool process_file(const std::string& path); - void process_file_throw(const std::string& path); - void process_file_nothrow(const std::string& path); private: VariableMap(const VariableMap&);