diff --git a/src/Makefile.am b/src/Makefile.am index 6b8b4892..3560a343 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -19,6 +19,8 @@ rtorrent_LDADD = \ rtorrent_SOURCES = \ command_events.cc \ command_events.h \ + command_helpers.cc \ + command_helpers.h \ command_ui.cc \ command_ui.h \ command_scheduler.cc \ diff --git a/src/command_events.cc b/src/command_events.cc index 3ea05b16..a8ce8187 100644 --- a/src/command_events.cc +++ b/src/command_events.cc @@ -37,15 +37,17 @@ #include "config.h" #include +#include +#include "core/download.h" #include "core/download_list.h" #include "core/manager.h" #include "utils/command_slot.h" #include "utils/parse.h" -#include "utils/variable_map.h" #include "globals.h" #include "control.h" +#include "command_helpers.h" void apply_on_state_change(core::DownloadList::slot_map* slotMap, const torrent::Object& rawArgs) { @@ -66,8 +68,39 @@ apply_on_state_change(core::DownloadList::slot_map* slotMap, const torrent::Obje utils::convert_list_to_command(++args.begin(), args.end())); } -#define ADD_COMMAND_SLOT(key, function, slot) \ -variables->insert(key, new utils::CommandSlot(slot), &utils::CommandSlot::function); +void +apply_stop_on_ratio(const torrent::Object& rawArgs) { + const torrent::Object::list_type& args = rawArgs.as_list(); + + if (args.empty()) + throw torrent::input_error("Too few arguments."); + + torrent::Object::list_type::const_iterator argItr = args.begin(); + + // first argument: minimum ratio to reach + // second argument: minimum upload amount to reach [optional] + // third argument: maximum ratio to reach [optional] + int64_t minRatio = utils::convert_to_value(*argItr++); + int64_t minUpload = argItr != args.end() ? utils::convert_to_value(*argItr++) : 0; + int64_t maxRatio = argItr != args.end() ? utils::convert_to_value(*argItr++) : 0; + + core::DownloadList* downloadList = control->core()->download_list(); + core::Manager::DListItr itr = downloadList->begin(); + + while ((itr = std::find_if(itr, downloadList->end(), std::mem_fun(&core::Download::is_seeding))) + != downloadList->end()) { + int64_t totalDone = (*itr)->download()->bytes_done(); + int64_t totalUpload = (*itr)->download()->up_rate()->total(); + + if ((totalUpload >= minUpload && totalUpload * 100 >= totalDone * minRatio) || + (maxRatio > 0 && totalUpload * 100 > totalDone * maxRatio)) { + downloadList->stop_try(*itr); + (*itr)->set("ignore_commands", (int64_t)1); + } + + ++itr; + } +} void initialize_command_events() { @@ -84,4 +117,6 @@ initialize_command_events() { ADD_COMMAND_SLOT("on_hash_removed", call_list, rak::bind_ptr_fn(&apply_on_state_change, &downloadList->slot_map_hash_removed())); ADD_COMMAND_SLOT("on_hash_done", call_list, rak::bind_ptr_fn(&apply_on_state_change, &downloadList->slot_map_hash_done())); ADD_COMMAND_SLOT("on_finished", call_list, rak::bind_ptr_fn(&apply_on_state_change, &downloadList->slot_map_finished())); + + ADD_COMMAND_SLOT("stop_on_ratio", call_list, rak::ptr_fn(&apply_stop_on_ratio)); } diff --git a/src/command_helpers.cc b/src/command_helpers.cc new file mode 100644 index 00000000..dceaa443 --- /dev/null +++ b/src/command_helpers.cc @@ -0,0 +1,77 @@ +// rTorrent - BitTorrent client +// Copyright (C) 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 "utils/command_slot.h" +#include "utils/command_variable.h" + +#include "globals.h" +#include "control.h" +#include "command_helpers.h" + +utils::CommandSlot commandSlots[COMMAND_SLOTS_SIZE]; +utils::CommandSlot* commandSlotsItr = commandSlots; +utils::CommandVariable commandVariables[COMMAND_VARIABLES_SIZE]; +utils::CommandVariable* commandVariablesItr = commandVariables; + +void +initialize_commands() { + initialize_variables(); + initialize_download_variables(); + initialize_command_events(); + initialize_command_ui(); + + if (commandSlotsItr != commandSlots + COMMAND_SLOTS_SIZE || + commandVariablesItr != commandVariables + COMMAND_VARIABLES_SIZE) + throw torrent::internal_error("initialize_commands() static command array size mismatch."); +} + +void +add_variable(const char* getKey, const char* setKey, const char* defaultSetKey, + utils::VariableMap::generic_slot getSlot, utils::VariableMap::generic_slot setSlot, + const torrent::Object& defaultObject) { + utils::CommandVariable* variable = commandVariablesItr++; + variable->set_variable(defaultObject); + + control->variable()->insert(getKey, variable, getSlot, utils::VariableMap::flag_dont_delete); + control->variable()->insert(setKey, variable, setSlot, utils::VariableMap::flag_dont_delete); + + if (defaultSetKey) + control->variable()->insert(defaultSetKey, variable, setSlot, utils::VariableMap::flag_dont_delete); +} diff --git a/src/command_helpers.h b/src/command_helpers.h new file mode 100644 index 00000000..ef81ee6b --- /dev/null +++ b/src/command_helpers.h @@ -0,0 +1,82 @@ +// rTorrent - BitTorrent client +// Copyright (C) 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_UTILS_COMMAND_HELPERS_H +#define RTORRENT_UTILS_COMMAND_HELPERS_H + +#include "utils/variable_map.h" + +namespace utils { + class CommandSlot; + class CommandVariable; +} + +// By using a static array we avoid allocating the variables on the +// heap. This should reduce memory use and improve cache locality. +#define COMMAND_SLOTS_SIZE 18 +#define COMMAND_VARIABLES_SIZE 23 + +extern utils::CommandSlot commandSlots[COMMAND_SLOTS_SIZE]; +extern utils::CommandSlot* commandSlotsItr; +extern utils::CommandVariable commandVariables[COMMAND_VARIABLES_SIZE]; +extern utils::CommandVariable* commandVariablesItr; + +void initialize_variables(); +void initialize_download_variables(); +void initialize_command_events(); +void initialize_command_ui(); + +void initialize_commands(); + +void +add_variable(const char* getKey, const char* setKey, const char* defaultSetKey, + utils::VariableMap::generic_slot getSlot, utils::VariableMap::generic_slot setSlot, + const torrent::Object& defaultObject); + +#define ADD_VARIABLE_BOOL(key, defaultValue) \ +add_variable("get_" key, "set_" key, key, &utils::CommandVariable::get_bool, &utils::CommandVariable::set_bool, (int64_t)defaultValue); + +#define ADD_VARIABLE_VALUE(key, defaultValue) \ +add_variable("get_" key, "set_" key, key, &utils::CommandVariable::get_value, &utils::CommandVariable::set_value, (int64_t)defaultValue); + +#define ADD_VARIABLE_STRING(key, defaultValue) \ +add_variable("get_" key, "set_" key, key, &utils::CommandVariable::get_string, &utils::CommandVariable::set_string, std::string(defaultValue)); + +#define ADD_COMMAND_SLOT(key, function, slot) \ + commandSlotsItr->set_slot(slot); \ + variables->insert(key, commandSlotsItr++, &utils::CommandSlot::function, utils::VariableMap::flag_dont_delete); + +#endif diff --git a/src/command_ui.cc b/src/command_ui.cc index ca0b2b3f..53e5ce02 100644 --- a/src/command_ui.cc +++ b/src/command_ui.cc @@ -44,10 +44,10 @@ #include "core/view_manager.h" #include "utils/command_slot.h" #include "utils/parse.h" -#include "utils/variable_map.h" #include "globals.h" #include "control.h" +#include "command_helpers.h" typedef void (core::ViewManager::*view_filter_slot)(const std::string&, const core::ViewManager::sort_args&); @@ -91,9 +91,6 @@ apply_view_sort(const torrent::Object& rawArgs) { control->view_manager()->sort(name, value); } -#define ADD_COMMAND_SLOT(key, function, slot) \ -variables->insert(key, new utils::CommandSlot(slot), &utils::CommandSlot::function); - void initialize_command_ui() { utils::VariableMap* variables = control->variable(); diff --git a/src/main.cc b/src/main.cc index 361c0e63..a9b33155 100644 --- a/src/main.cc +++ b/src/main.cc @@ -71,6 +71,7 @@ void do_panic(int signum); void print_help(); +void initialize_commands(); int parse_options(Control* c, int argc, char** argv) { @@ -163,10 +164,7 @@ main(int argc, char** argv) { // Initialize option handlers after libtorrent to ensure // torrent::ConnectionManager* are valid etc. - initialize_variables(); - initialize_download_variables(); - initialize_command_events(); - initialize_command_ui(); + initialize_commands(); control->variable()->process_multiple ( diff --git a/src/option_handler_rules.cc b/src/option_handler_rules.cc index cf1ce454..239ac799 100644 --- a/src/option_handler_rules.cc +++ b/src/option_handler_rules.cc @@ -78,6 +78,7 @@ #include "control.h" #include "option_handler_rules.h" #include "command_scheduler.h" +#include "command_helpers.h" namespace core { extern void @@ -182,38 +183,6 @@ apply_close_low_diskspace(int64_t arg) { } } -void -apply_stop_on_ratio(const torrent::Object& rawArgs) { - const torrent::Object::list_type& args = rawArgs.as_list(); - - if (args.empty()) - throw torrent::input_error("Too few arguments."); - - torrent::Object::list_type::const_iterator argItr = args.begin(); - - // first argument: minimum ratio to reach - // second argument: minimum upload amount to reach [optional] - // third argument: maximum ratio to reach [optional] - int64_t minRatio = utils::convert_to_value(*argItr++); - int64_t minUpload = argItr != args.end() ? utils::convert_to_value(*argItr++) : 0; - int64_t maxRatio = argItr != args.end() ? utils::convert_to_value(*argItr++) : 0; - - core::Manager::DListItr itr = control->core()->download_list()->begin(); - - while ((itr = std::find_if(itr, control->core()->download_list()->end(), std::mem_fun(&core::Download::is_seeding))) != control->core()->download_list()->end()) { - int64_t totalUpload = (*itr)->download()->up_rate()->total(); - int64_t totalDone = (*itr)->download()->bytes_done(); - - if ((totalUpload >= minUpload && totalUpload * 100 >= totalDone * minRatio) || - (maxRatio > 0 && totalUpload * 100 > totalDone * maxRatio)) { - control->core()->download_list()->stop_try(*itr); - (*itr)->set("ignore_commands", (int64_t)1); - } - - ++itr; - } -} - void apply_encoding_list(const std::string& arg) { torrent::encoding_list()->push_back(arg); @@ -337,31 +306,6 @@ apply_schedule(const torrent::Object& rawArgs) { control->command_scheduler()->parse(arg1, arg2, arg3, utils::convert_list_to_command(itr, args.end())); } -void -add_variable(const char* getKey, const char* setKey, const char* defaultSetKey, - utils::VariableMap::generic_slot getSlot, utils::VariableMap::generic_slot setSlot, - const torrent::Object& defaultObject) { - utils::Variable* variable = new utils::CommandVariable(defaultObject); - - control->variable()->insert(getKey, variable, getSlot); - control->variable()->insert(setKey, variable, setSlot, utils::VariableMap::flag_dont_delete); - - if (defaultSetKey) - control->variable()->insert(defaultSetKey, variable, setSlot, utils::VariableMap::flag_dont_delete); -} - -#define ADD_VARIABLE_BOOL(key, defaultValue) \ -add_variable("get_" key, "set_" key, key, &utils::CommandVariable::get_bool, &utils::CommandVariable::set_bool, (int64_t)defaultValue); - -#define ADD_VARIABLE_VALUE(key, defaultValue) \ -add_variable("get_" key, "set_" key, key, &utils::CommandVariable::get_value, &utils::CommandVariable::set_value, (int64_t)defaultValue); - -#define ADD_VARIABLE_STRING(key, defaultValue) \ -add_variable("get_" key, "set_" key, key, &utils::CommandVariable::get_string, &utils::CommandVariable::set_string, std::string(defaultValue)); - -#define ADD_COMMAND_SLOT(key, function, slot) \ -variables->insert(key, new utils::CommandSlot(slot), &utils::CommandSlot::function); - void initialize_variables() { utils::VariableMap* variables = control->variable(); @@ -430,7 +374,6 @@ initialize_variables() { variables->insert("try_import", new utils::VariableStringSlot(NULL, rak::ptr_fn(&apply_try_import))); ADD_COMMAND_SLOT("schedule", call_list, rak::ptr_fn(&apply_schedule)); -// variables->insert("schedule", new utils::VariableListSlot(rak::ptr_fn(&apply_schedule))); variables->insert("schedule_remove", new utils::VariableStringSlot(NULL, rak::mem_fn(control->command_scheduler(), &CommandScheduler::erase))); variables->insert("download_scheduler", new utils::VariableVoidSlot(rak::mem_fn(control->scheduler(), &core::Scheduler::update))); @@ -487,14 +430,11 @@ initialize_variables() { variables->insert("remove_untied", new utils::VariableVoidSlot(rak::ptr_fn(&apply_remove_untied))); variables->insert("close_low_diskspace", new utils::VariableValueSlot(rak::value_fn(int64_t()), rak::ptr_fn(&apply_close_low_diskspace))); - ADD_COMMAND_SLOT("stop_on_ratio", call_list, rak::ptr_fn(&apply_stop_on_ratio)); -// variables->insert("stop_on_ratio", new utils::VariableListSlot(rak::ptr_fn(&apply_stop_on_ratio))); variables->insert("enable_trackers", new utils::VariableStringSlot(NULL, rak::ptr_fn(&apply_enable_trackers))); variables->insert("encoding_list", new utils::VariableStringSlot(NULL, rak::ptr_fn(&apply_encoding_list))); ADD_COMMAND_SLOT("encryption", call_list, rak::ptr_fn(&apply_encryption)); -// variables->insert("encryption", new utils::VariableListSlot(rak::ptr_fn(&apply_encryption))); // Move to command_ui.cc. variables->insert("print", new utils::VariableStringSlot(NULL, rak::mem_fn(control->core(), &core::Manager::push_log))); diff --git a/src/utils/command_slot.h b/src/utils/command_slot.h index a0ad8134..55a758d5 100644 --- a/src/utils/command_slot.h +++ b/src/utils/command_slot.h @@ -47,6 +47,10 @@ namespace utils { +// The CommandSlot class uses union instead of creating multiple +// derived classes so that it is possible to create an array +// containing different slot types. + class CommandSlot : public Variable { public: // For now, only return void. @@ -57,10 +61,14 @@ public: // m_slotSet.set(slotSet); // } - CommandSlot(slot_type::base_type* slotSet) { - m_slot.set(slotSet); + CommandSlot() {} + + CommandSlot(slot_type::base_type* s) { + m_slot.set(s); } + void set_slot(slot_type::base_type* s) { m_slot.set(s); } + static const torrent::Object& call_list(Variable* rawVariable, const torrent::Object& args); // static const torrent::Object& get_list(Variable* rawVariable, const torrent::Object& args); diff --git a/src/utils/command_variable.h b/src/utils/command_variable.h index 4b6c1c69..6c8a208d 100644 --- a/src/utils/command_variable.h +++ b/src/utils/command_variable.h @@ -50,6 +50,9 @@ class CommandVariable : public Variable { public: CommandVariable(const torrent::Object& v = torrent::Object()) : m_variable(v) {} + const torrent::Object& variable() const { return m_variable; } + void set_variable(const torrent::Object& var) { m_variable = var; } + static const torrent::Object& set_bool(Variable* rawVariable, const torrent::Object& args); static const torrent::Object& get_bool(Variable* rawVariable, const torrent::Object& args);