From c5c9a1ddae1bf87fb270042c55a6174f90e09796 Mon Sep 17 00:00:00 2001 From: rakshasa Date: Tue, 25 Apr 2006 19:33:53 +0000 Subject: [PATCH] * Added the framework for a download scheduler. * Added "state_changed" variable to downloads that returns the last time the download called DownloadList::pause/resume. git-svn-id: svn://rakshasa.no/libtorrent/trunk/rtorrent@674 e378c898-3ddf-0310-93e7-cc216c733640 --- src/control.cc | 6 +- src/control.h | 3 + src/core/Makefile.am | 2 + src/core/download.cc | 9 ++- src/core/download.h | 1 + src/core/download_factory.cc | 56 ++++++++------- src/core/download_factory.h | 2 + src/core/download_list.cc | 4 ++ src/core/scheduler.cc | 106 +++++++++++++++++++++++++++++ src/core/scheduler.h | 82 ++++++++++++++++++++++ src/core/view_manager.cc | 24 +++++-- src/display/utils.cc | 14 +++- src/display/utils.h | 1 + src/display/window_log.cc | 2 +- src/display/window_log_complete.cc | 2 +- src/display/window_peer_info.cc | 31 +++++++-- src/display/window_peer_info.h | 14 ++-- src/main.cc | 7 ++ src/option_handler_rules.cc | 8 +++ src/utils/variable_generic.cc | 10 ++- 20 files changed, 339 insertions(+), 45 deletions(-) create mode 100644 src/core/scheduler.cc create mode 100644 src/core/scheduler.h diff --git a/src/control.cc b/src/control.cc index b543eba1..e946b677 100644 --- a/src/control.cc +++ b/src/control.cc @@ -42,6 +42,7 @@ #include "core/manager.h" #include "core/view_manager.h" +#include "core/scheduler.h" #include "display/canvas.h" #include "display/client_info.h" @@ -72,8 +73,9 @@ Control::Control() : m_tick(0) { - m_core = new core::Manager(); + m_core = new core::Manager(); m_viewManager = new core::ViewManager(&m_core->download_list()); + m_scheduler = new core::Scheduler(&m_core->download_list()); m_inputStdin->slot_pressed(sigc::mem_fun(m_input, &input::Manager::pressed)); @@ -110,6 +112,8 @@ Control::initialize() { m_core->listen_open(); m_core->download_store().enable(m_variables->get_value("session_lock")); + m_scheduler->set_view(*m_viewManager->find_throw("scheduler")); + m_ui->init(this); m_inputStdin->insert(m_core->get_poll_manager()->get_torrent_poll()); diff --git a/src/control.h b/src/control.h index 1140f2b6..9ed723ed 100644 --- a/src/control.h +++ b/src/control.h @@ -50,6 +50,7 @@ namespace ui { namespace core { class Manager; class ViewManager; + class Scheduler; } namespace display { @@ -86,6 +87,7 @@ public: core::Manager* core() { return m_core; } core::ViewManager* view_manager() { return m_viewManager; } + core::Scheduler* scheduler() { return m_scheduler; } ui::Root* ui() { return m_ui; } display::Manager* display() { return m_display; } @@ -115,6 +117,7 @@ private: core::Manager* m_core; core::ViewManager* m_viewManager; + core::Scheduler* m_scheduler; ui::Root* m_ui; display::Manager* m_display; diff --git a/src/core/Makefile.am b/src/core/Makefile.am index b99f85bf..706f660b 100644 --- a/src/core/Makefile.am +++ b/src/core/Makefile.am @@ -28,6 +28,8 @@ libsub_core_a_SOURCES = \ poll_manager_epoll.h \ poll_manager_select.cc \ poll_manager_select.h \ + scheduler.cc \ + scheduler.h \ view_downloads.cc \ view_downloads.h \ view_manager.cc \ diff --git a/src/core/download.cc b/src/core/download.cc index 08a7cdff..75a13986 100644 --- a/src/core/download.cc +++ b/src/core/download.cc @@ -60,8 +60,8 @@ Download::Download(download_type d) : m_chunksFailed(0) { m_connTrackerSucceded = m_download.signal_tracker_succeded(sigc::bind(sigc::mem_fun(*this, &Download::receive_tracker_msg), "")); - m_connTrackerFailed = m_download.signal_tracker_failed(sigc::mem_fun(*this, &Download::receive_tracker_msg)); - m_connStorageError = m_download.signal_storage_error(sigc::mem_fun(*this, &Download::receive_storage_error)); + m_connTrackerFailed = m_download.signal_tracker_failed(sigc::mem_fun(*this, &Download::receive_tracker_msg)); + m_connStorageError = m_download.signal_storage_error(sigc::mem_fun(*this, &Download::receive_storage_error)); m_download.signal_chunk_failed(sigc::mem_fun(*this, &Download::receive_chunk_failed)); @@ -73,6 +73,11 @@ Download::Download(download_type d) : m_variables.insert("state", new utils::VariableObject(bencode(), "rtorrent", "state", torrent::Object::TYPE_STRING)); 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 + // value, it indicates the last time the torrent changed its state, + // resume/pause. + m_variables.insert("state_changed", new utils::VariableObject(bencode(), "rtorrent", "state_changed", torrent::Object::TYPE_VALUE)); + m_variables.insert("directory", new utils::VariableStringSlot(rak::mem_fn(&m_fileList, &torrent::FileList::root_dir), rak::mem_fn(this, &Download::set_root_directory))); diff --git a/src/core/download.h b/src/core/download.h index f645805c..bddadec7 100644 --- a/src/core/download.h +++ b/src/core/download.h @@ -59,6 +59,7 @@ public: ~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(); } void start(); diff --git a/src/core/download_factory.cc b/src/core/download_factory.cc index 89ca38b2..77489bdb 100644 --- a/src/core/download_factory.cc +++ b/src/core/download_factory.cc @@ -164,18 +164,7 @@ DownloadFactory::receive_success() { torrent::Object* rtorrent = &root->get_key("rtorrent"); - if (!rtorrent->has_key_string("state") || - (rtorrent->get_key("state").as_string() != "stopped" && - rtorrent->get_key("state").as_string() != "started")) - rtorrent->insert_key("state", "stopped"); - - if (!rtorrent->has_key_string("tied_to_file")) - rtorrent->insert_key("tied_to_file", std::string()); - - if (rtorrent->has_key_value("priority")) - (*itr)->variable()->set("priority", rtorrent->get_key("priority").as_value() % 4); - else - (*itr)->variable()->set("priority", (int64_t)2); + initialize_rtorrent(*itr, rtorrent); // Move to 'rtorrent'. (*itr)->variable()->set("connection_leech", m_variables.get("connection_leech")); @@ -184,20 +173,9 @@ DownloadFactory::receive_success() { (*itr)->variable()->set("max_peers", control->variable()->get("max_peers")); (*itr)->variable()->set("max_uploads", control->variable()->get("max_uploads")); - if (rtorrent->has_key_value("key")) { - (*itr)->tracker_list()->set_key(rtorrent->get_key("key").as_value()); - - } else { - (*itr)->tracker_list()->set_key(rand() % (std::numeric_limits::max() - 1) + 1); - rtorrent->insert_key("key", (*itr)->tracker_list()->key()); - } - if (!control->variable()->get_value("use_udp_trackers")) (*itr)->enable_udp_trackers(false); - if (rtorrent->has_key_value("total_uploaded")) - (*itr)->download()->up_rate()->set_total(rtorrent->get_key("total_uploaded").as_value()); - if (m_session) { if (!rtorrent->has_key_string("directory")) (*itr)->variable()->set("directory", m_variables.get("directory")); @@ -236,4 +214,36 @@ DownloadFactory::receive_failed(const std::string& msg) { m_slotFinished(); } +void +DownloadFactory::initialize_rtorrent(Download* download, torrent::Object* rtorrent) { + if (!rtorrent->has_key_string("state") || + (rtorrent->get_key("state").as_string() != "stopped" && rtorrent->get_key("state").as_string() != "started")) { + rtorrent->insert_key("state", "stopped"); + rtorrent->insert_key("state_changed", cachedTime.seconds()); + + } else if (!rtorrent->has_key_value("state_changed") || + rtorrent->get_key("state_changed").as_value() > cachedTime.seconds() || rtorrent->get_key("state_changed").as_value() == 0) { + rtorrent->insert_key("state_changed", cachedTime.seconds()); + } + + if (!rtorrent->has_key_string("tied_to_file")) + rtorrent->insert_key("tied_to_file", std::string()); + + if (rtorrent->has_key_value("priority")) + download->variable()->set("priority", rtorrent->get_key("priority").as_value() % 4); + else + download->variable()->set("priority", (int64_t)2); + + if (rtorrent->has_key_value("key")) { + download->tracker_list()->set_key(rtorrent->get_key("key").as_value()); + + } else { + download->tracker_list()->set_key(rand() % (std::numeric_limits::max() - 1) + 1); + rtorrent->insert_key("key", download->tracker_list()->key()); + } + + if (rtorrent->has_key_value("total_uploaded")) + download->download()->up_rate()->set_total(rtorrent->get_key("total_uploaded").as_value()); +} + } diff --git a/src/core/download_factory.h b/src/core/download_factory.h index 6a2c2de0..ac27802c 100644 --- a/src/core/download_factory.h +++ b/src/core/download_factory.h @@ -87,6 +87,8 @@ private: void receive_success(); void receive_failed(const std::string& msg); + void initialize_rtorrent(Download* download, torrent::Object* rtorrent); + Manager* m_manager; std::iostream* m_stream; diff --git a/src/core/download_list.cc b/src/core/download_list.cc index 87de839b..51c192ec 100644 --- a/src/core/download_list.cc +++ b/src/core/download_list.cc @@ -176,6 +176,8 @@ DownloadList::resume(Download* d) { // TODO: This can cause infinit looping? control->core()->hash_queue().insert(d, sigc::bind(sigc::mem_fun(*this, &DownloadList::resume), d)); + d->variable()->set("state_changed", cachedTime.seconds()); + } catch (torrent::local_error& e) { control->core()->push_log(e.what()); } @@ -188,6 +190,8 @@ DownloadList::pause(Download* d) { if (d->download()->is_active()) std::for_each(m_slotMapStop.begin(), m_slotMapStop.end(), download_list_call(d)); + d->variable()->set("state_changed", cachedTime.seconds()); + } catch (torrent::local_error& e) { control->core()->push_log(e.what()); } diff --git a/src/core/scheduler.cc b/src/core/scheduler.cc new file mode 100644 index 00000000..a46c92a0 --- /dev/null +++ b/src/core/scheduler.cc @@ -0,0 +1,106 @@ +// 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 "download.h" +#include "download_list.h" +#include "scheduler.h" +#include "view_downloads.h" + +namespace core { + +// Change to unlimited. +Scheduler::Scheduler(DownloadList* dl) : + m_view(NULL), + m_downloadList(dl), + + m_maxActive(2), + m_cycle(1) { +} + +Scheduler::~Scheduler() { +} + +void +Scheduler::set_view(ViewDownloads* view) { + m_view = view; +} + +Scheduler::size_type +Scheduler::active() const { + return std::count_if(m_view->begin(), m_view->end(), std::mem_fun(&Download::is_active)); +} + +void +Scheduler::update() { + size_type curActive = active(); + // size_type curInactive = m_view->size() - curActive; + + // Hmm... Perhaps we should use a more complex sorting thingie. + m_view->sort(); + + // Just a hack for now, need to take into consideration how many + // inactive we can switch with. + size_type target = m_maxActive - std::min(m_cycle, m_maxActive); + + for (ViewDownloads::iterator itr = m_view->begin(), last = m_view->end(); curActive > target; ++itr) { + if (itr == last) + throw torrent::internal_error("Scheduler::update() loop bork."); + + if ((*itr)->is_active()) { + m_downloadList->pause(*itr); + --curActive; + } + } + + m_view->sort(); + + for (ViewDownloads::iterator itr = m_view->begin(), last = m_view->end(); curActive < m_maxActive; ++itr) { + if (itr == last) + throw torrent::internal_error("Scheduler::update() loop bork."); + + if (!(*itr)->is_active()) { + m_downloadList->resume(*itr); + ++curActive; + } + } +} + +} diff --git a/src/core/scheduler.h b/src/core/scheduler.h new file mode 100644 index 00000000..9ed0b7d2 --- /dev/null +++ b/src/core/scheduler.h @@ -0,0 +1,82 @@ +// 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_SCHEDULER_H +#define RTORRENT_CORE_SCHEDULER_H + +#include +#include +#include + +#include "view_downloads.h" + +namespace core { + +class DownloadList; +class ViewDownloads; + +class Scheduler { +public: + typedef uint32_t size_type; + + static const size_type unlimited = ~size_type(); + + Scheduler(DownloadList* dl); + ~Scheduler(); + + void set_view(ViewDownloads* view); + + size_type max_active() const { return m_maxActive; } + void set_max_active(size_type v) { m_maxActive = v; } + + size_type cycle() const { return m_cycle; } + void set_cycle(size_type v) { m_cycle = v; } + + size_type active() const; + + void update(); + +private: + ViewDownloads* m_view; + DownloadList* m_downloadList; + + size_type m_maxActive; + size_type m_cycle; +}; + +} + +#endif diff --git a/src/core/view_manager.cc b/src/core/view_manager.cc index c31c48d3..e9cbb6fc 100644 --- a/src/core/view_manager.cc +++ b/src/core/view_manager.cc @@ -69,6 +69,19 @@ private: std::string m_value; }; +class ViewSortVariableValue : public ViewSort { +public: + ViewSortVariableValue(const std::string& name) : + m_name(name) {} + + virtual bool less(Download* d1, Download* d2) const { + return d1->variable()->get_value(m_name) < d2->variable()->get_value(m_name); + } + +private: + std::string m_name; +}; + class ViewSortReverse : public ViewSort { public: ViewSortReverse(ViewSort* s) : m_sort(s) {} @@ -87,11 +100,14 @@ ViewManager::ViewManager(DownloadList* dl) : // m_sort["first"] = new ViewSortNot(new ViewSort()); // m_sort["last"] = new ViewSort(); - m_sort["name"] = new ViewSortName(); - m_sort["name_reverse"] = new ViewSortReverse(new ViewSortName()); + m_sort["name"] = new ViewSortName(); + m_sort["name_reverse"] = new ViewSortReverse(new ViewSortName()); - m_sort["started"] = new ViewSortVariable("state", "started"); - m_sort["stopped"] = new ViewSortVariable("state", "stopped"); + m_sort["started"] = new ViewSortVariable("state", "started"); + m_sort["stopped"] = new ViewSortVariable("state", "stopped"); + + m_sort["state_changed"] = new ViewSortVariableValue("state_changed"); + m_sort["state_changed_reverse"] = new ViewSortReverse(new ViewSortVariableValue("state_changed")); } void diff --git a/src/display/utils.cc b/src/display/utils.cc index e51aab47..98bd7091 100644 --- a/src/display/utils.cc +++ b/src/display/utils.cc @@ -55,21 +55,31 @@ namespace display { char* print_string(char* first, char* last, char* str) { + if (first == last) + return first; + // We don't have any nice simple functions for copying strings that // return the end address. - while (first != last && *str != '\0') + while (first + 1 != last && *str != '\0') *(first++) = *(str++); + *first = '\0'; + return first; } char* print_hhmmss(char* first, char* last, time_t t) { + return print_buffer(first, last, "%2d:%02d:%02d", (int)t / 3600, ((int)t / 60) % 60, (int)t % 60); +} + +char* +print_hhmmss_local(char* first, char* last, time_t t) { std::tm *u = std::localtime(&t); if (u == NULL) //return "inv_time"; - throw torrent::internal_error("print_hhmmss(...) failed."); + throw torrent::internal_error("print_hhmmss_local(...) failed."); return print_buffer(first, last, "%2u:%02u:%02u", u->tm_hour, u->tm_min, u->tm_sec); } diff --git a/src/display/utils.h b/src/display/utils.h index 32094fb9..414f97f0 100644 --- a/src/display/utils.h +++ b/src/display/utils.h @@ -59,6 +59,7 @@ namespace display { char* print_string(char* first, char* last, char* str); char* print_hhmmss(char* first, char* last, time_t t); +char* print_hhmmss_local(char* first, char* last, time_t t); char* print_ddhhmm(char* first, char* last, time_t t); char* print_ddmmyyyy(char* first, char* last, time_t t); diff --git a/src/display/window_log.cc b/src/display/window_log.cc index e8cd96a6..220ece09 100644 --- a/src/display/window_log.cc +++ b/src/display/window_log.cc @@ -71,7 +71,7 @@ WindowLog::redraw() { for (core::Log::iterator itr = m_log->begin(), end = find_older(); itr != end && pos < m_canvas->get_height(); ++itr) { char buffer[16]; - print_hhmmss(buffer, buffer + 16, static_cast(itr->first.seconds())); + print_hhmmss_local(buffer, buffer + 16, static_cast(itr->first.seconds())); m_canvas->print(0, pos++, "(%s) %s", buffer, itr->second.c_str()); } diff --git a/src/display/window_log_complete.cc b/src/display/window_log_complete.cc index 02087154..73c854cb 100644 --- a/src/display/window_log_complete.cc +++ b/src/display/window_log_complete.cc @@ -71,7 +71,7 @@ WindowLogComplete::redraw() { for (core::Log::iterator itr = m_log->begin(), e = m_log->end(); itr != e && pos < m_canvas->get_height(); ++itr) { char buffer[16]; - print_hhmmss(buffer, buffer + 16, static_cast(itr->first.seconds())); + print_hhmmss_local(buffer, buffer + 16, static_cast(itr->first.seconds())); m_canvas->print(0, pos++, "(%s) %s", buffer, itr->second.c_str()); } diff --git a/src/display/window_peer_info.cc b/src/display/window_peer_info.cc index 581559d9..bdf7fed0 100644 --- a/src/display/window_peer_info.cc +++ b/src/display/window_peer_info.cc @@ -66,6 +66,9 @@ WindowPeerInfo::redraw() { m_canvas->erase(); int y = 0; + char buffer[256]; + char* position; + torrent::Download* d = m_download->download(); m_canvas->print(0, y++, "Hash: %s", rak::transform_hex(d->info_hash()).c_str()); @@ -75,12 +78,13 @@ WindowPeerInfo::redraw() { d->chunks_total(), d->chunks_size()); - char buffer[32], *position; - position = print_ddmmyyyy(buffer, buffer + 32, static_cast(d->creation_date())); - position = print_string(position, buffer + 32, " "); - position = print_hhmmss(position, buffer + 32, static_cast(d->creation_date())); + y++; - m_canvas->print(0, y++, "Created: %s", buffer); + position = print_date(buffer, buffer + 256, static_cast(d->creation_date())); + m_canvas->print(0, y++, "Created: %s", buffer); + + position = print_timer(buffer, buffer + 256, static_cast(m_download->variable()->get_value("state_changed"))); + m_canvas->print(0, y++, "State Changed: %s", buffer); y++; @@ -140,4 +144,21 @@ WindowPeerInfo::done_percentage(torrent::Peer& p) { return chunks ? (100 * p.chunks_done()) / chunks : 0; } +char* +WindowPeerInfo::print_date(char* buf, char* end, time_t t) { + buf = print_ddmmyyyy(buf, end, t); + buf = print_string(buf, end, " "); + buf = print_hhmmss_local(buf, end, t); + + return buf; +} + +char* +WindowPeerInfo::print_timer(char* buf, char* end, time_t t) { + if (t == 0) + return print_string(buf, end, "--:--:--"); + else + return print_hhmmss(buf, end, cachedTime.seconds() - t); +} + } diff --git a/src/display/window_peer_info.h b/src/display/window_peer_info.h index f0fed99d..756ae353 100644 --- a/src/display/window_peer_info.h +++ b/src/display/window_peer_info.h @@ -37,6 +37,7 @@ #ifndef RTORRENT_DISPLAY_PEER_INFO_H #define RTORRENT_DISPLAY_PEER_INFO_H +#include #include #include @@ -54,15 +55,18 @@ public: WindowPeerInfo(core::Download* d, PList* l, PList::iterator* f); - virtual void redraw(); + virtual void redraw(); private: - int done_percentage(torrent::Peer& p); + int done_percentage(torrent::Peer& p); - core::Download* m_download; + char* print_date(char* buf, char* end, time_t t); + char* print_timer(char* buf, char* end, time_t t); - PList* m_list; - PList::iterator* m_focus; + core::Download* m_download; + + PList* m_list; + PList::iterator* m_focus; }; } diff --git a/src/main.cc b/src/main.cc index a9c7a829..1b379692 100644 --- a/src/main.cc +++ b/src/main.cc @@ -166,6 +166,13 @@ main(int argc, char** argv) { control->variable()->process_command("view_sort_new = main,name"); control->variable()->process_command("view_sort_current = main,name"); + // Changing these will bork the scheduler. + control->variable()->process_command("view_add = scheduler"); + control->variable()->process_command("view_sort_new = scheduler,state_changed"); // add started? + control->variable()->process_command("view_sort_current = scheduler,state_changed"); + +// control->variable()->process_command("schedule = scheduler,10,10,download_scheduler="); + // Move env and go through "try_import". // if (!control->variable()->process_file("~/.rtorrent.rc")) // control->core()->get_log_important().push_front("Could not load \"~/.rtorrent.rc\"."); diff --git a/src/option_handler_rules.cc b/src/option_handler_rules.cc index 2f5cedca..e3b8b6b0 100644 --- a/src/option_handler_rules.cc +++ b/src/option_handler_rules.cc @@ -53,6 +53,7 @@ #include "core/download.h" #include "core/manager.h" +#include "core/scheduler.h" #include "core/view_manager.h" #include "ui/root.h" #include "utils/directory.h" @@ -224,6 +225,11 @@ apply_view_sort_new(Control* control, const std::string& arg) { control->view_manager()->set_sort_new(name, sortArgs); } +void +apply_download_scheduler(core::Scheduler* scheduler, __UNUSED const std::string& arg) { + scheduler->update(); +} + void initialize_option_handler(Control* c) { utils::VariableMap* variables = control->variable(); @@ -284,6 +290,8 @@ initialize_option_handler(Control* c) { 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("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))); diff --git a/src/utils/variable_generic.cc b/src/utils/variable_generic.cc index acc068c8..421987ef 100644 --- a/src/utils/variable_generic.cc +++ b/src/utils/variable_generic.cc @@ -131,13 +131,21 @@ VariableObject::set(const torrent::Object& arg) { break; case torrent::Object::TYPE_STRING: - if (arg.type() == torrent::Object::TYPE_STRING) + if (arg.is_string()) root->insert_key(m_key, arg); else throw torrent::input_error("VariableObject could not convert to string."); break; + case torrent::Object::TYPE_VALUE: + if (arg.is_value()) + root->insert_key(m_key, arg); + else + throw torrent::input_error("VariableObject could not convert to value."); + + break; + default: throw torrent::input_error("VariableObject unsupported type restriction."); }