407 lines · 15.0 KB · C++
RawDownload
#include "config.h" #include <memory> #include <torrent/download/resource_manager.h>#include <torrent/download/choke_group.h>#include <torrent/download/choke_queue.h>#include <torrent/utils/log.h>#include <torrent/utils/option_strings.h> #include "ui/root.h"#include "rpc/parse.h"#include "rpc/parse_commands.h" #include "globals.h"#include "control.h"#include "command_helpers.h" // For cg_d_group.#include "core/download.h" #define LT_LOG_SUBSYSTEM(log_fmt, ...)                                  \  lt_log_print_subsystem(torrent::LOG_TORRENT_INFO, "choke_queue", log_fmt, __VA_ARGS__); // A hack to allow testing of the new choke_group API without the// working parts present.#define USE_CHOKE_GROUP 0 #if USE_CHOKE_GROUP int64_tcg_get_index(const torrent::Object& raw_args) {  const torrent::Object& arg = (raw_args.is_list() && !raw_args.as_list().empty()) ? raw_args.as_list().front() : raw_args;   int64_t index = 0;   if (arg.is_string()) {    if (!rpc::parse_whole_value_nothrow(arg.as_string().c_str(), &index))      return torrent::resource_manager()->group_index_of(arg.as_string());   } else {    index = arg.as_value();  }   if (index < 0)    index = (int64_t)torrent::resource_manager()->group_size() + index;   return std::min<uint64_t>(index, torrent::resource_manager()->group_size());} torrent::choke_group*cg_get_group(const torrent::Object& raw_args) {  return torrent::resource_manager()->group_at(cg_get_index(raw_args));} int64_tcg_d_group(core::Download* download) {  return torrent::resource_manager()->entry_at(download->main()).group();} const std::string&cg_d_group_name(core::Download* download) {  return torrent::resource_manager()->group_at(torrent::resource_manager()->entry_at(download->main()).group())->name();} voidcg_d_group_set(core::Download* download, const torrent::Object& arg) {  torrent::resource_manager()->set_group(torrent::resource_manager()->find_throw(download->main()), cg_get_index(arg));} torrent::Objectapply_cg_list() {  torrent::Object::list_type result;   for (torrent::ResourceManager::group_iterator         itr = torrent::resource_manager()->group_begin(),         last = torrent::resource_manager()->group_end(); itr != last; itr++)    result.push_back((*itr)->name());   return torrent::Object::from_list(result);} torrent::Objectapply_cg_insert(const std::string& arg) {  int64_t dummy;   if (rpc::parse_whole_value_nothrow(arg.c_str(), &dummy))    throw torrent::input_error("Cannot use a value string as choke group name.");   torrent::resource_manager()->push_group(arg);   return torrent::Object();} torrent::Objectapply_cg_all_update_balance(bool is_up) {  LT_LOG_SUBSYSTEM("apply update balance: resource_manager is_up:%i", (int)is_up);   for (torrent::ResourceManager::group_iterator         itr = torrent::resource_manager()->group_begin(),         last = torrent::resource_manager()->group_end(); itr != last; itr++) {    if (is_up)      itr->up_queue()->balance();    else      itr->down_queue()->balance();  }   return torrent::Object();} //// The hacked version://#else std::vector<std::unique_ptr<torrent::choke_group>> cg_list_hack; int64_tcg_get_index(const torrent::Object& raw_args) {  const torrent::Object& arg = (raw_args.is_list() && !raw_args.as_list().empty()) ? raw_args.as_list().front() : raw_args;   int64_t index = 0;   if (arg.is_string()) {    if (!rpc::parse_whole_value_nothrow(arg.as_string().c_str(), &index)) {      auto itr = std::find_if(cg_list_hack.begin(), cg_list_hack.end(), [&arg](const auto& cg) { return arg.as_string() == cg->name(); });       if (itr == cg_list_hack.end())        throw torrent::input_error("Choke group not found.");       return std::distance(cg_list_hack.begin(), itr);    }   } else {    index = arg.as_value();  }   if (index < 0)    index = (int64_t)cg_list_hack.size() + index;   if ((size_t)index >= cg_list_hack.size())    throw torrent::input_error("Choke group not found.");   return index;} torrent::choke_group*cg_get_group(const torrent::Object& raw_args) {  int64_t index = cg_get_index(raw_args);   if ((size_t)index >= cg_list_hack.size())    throw torrent::input_error("Choke group not found.");   return cg_list_hack.at(index).get();} int64_t cg_d_group(core::Download* download) { return download->group(); }const std::string& cg_d_group_name(core::Download* download) {  return cg_list_hack.at(download->group())->name();}void    cg_d_group_set(core::Download* download, const torrent::Object& arg) { download->set_group(cg_get_index(arg)); } torrent::Objectapply_cg_list() {  torrent::Object::list_type result;   for (const auto& itr : cg_list_hack)    result.push_back(itr->name());   return torrent::Object::from_list(result);} intcg_get_can_unchoke(torrent::choke_queue* cq) {  return cq->max_unchoked_signed() - (int)cq->size_unchoked();} torrent::Objectapply_cg_insert(const std::string& arg) {  int64_t dummy;   if (rpc::parse_whole_value_nothrow(arg.c_str(), &dummy))    throw torrent::input_error("Cannot use a value string as choke group name.");   if (arg.empty() || std::any_of(cg_list_hack.begin(), cg_list_hack.end(), [&arg](const auto& cg) { return arg == cg->name(); }))    throw torrent::input_error("Duplicate name for choke group.");   cg_list_hack.push_back(std::make_unique<torrent::choke_group>());  cg_list_hack.back()->set_name(arg);   cg_list_hack.back()->up_queue()->set_heuristics(torrent::HEURISTICS_UPLOAD_LEECH);  cg_list_hack.back()->down_queue()->set_heuristics(torrent::HEURISTICS_DOWNLOAD_LEECH);   return torrent::Object();} torrent::Objectapply_cg_index_of(const std::string& arg) {  auto itr = std::find_if(cg_list_hack.begin(), cg_list_hack.end(), [&arg](const auto& cg) { return arg == cg->name(); });   if (itr == cg_list_hack.end())    throw torrent::input_error("Choke group not found.");   return std::distance(cg_list_hack.begin(), itr);} torrent::Objectapply_cg_all_update_balance(bool is_up) {  LT_LOG_SUBSYSTEM("apply update balance: hack is_up:%i", (int)is_up);   for (const auto& itr : cg_list_hack) {    if (is_up)      itr->up_queue()->balance();    else      itr->down_queue()->balance();  }   return torrent::Object();} //// End of choke group hack.//#endif  torrent::Objectapply_cg_max_set(const torrent::Object::list_type& args, bool is_up) {  if (args.size() != 2)    throw torrent::input_error("Incorrect number of arguments.");   int64_t second_arg = 0;  rpc::parse_whole_value(args.back().as_string().c_str(), &second_arg);   if (is_up)    cg_get_group(args.front())->up_queue()->set_max_unchoked(second_arg);  else    cg_get_group(args.front())->down_queue()->set_max_unchoked(second_arg);   return torrent::Object();} torrent::Objectapply_cg_heuristics_set(const torrent::Object::list_type& args, bool is_up) {  if (args.size() != 2)    throw torrent::input_error("Incorrect number of arguments.");   int t = torrent::option_find_string(is_up ? torrent::OPTION_CHOKE_HEURISTICS_UPLOAD : torrent::OPTION_CHOKE_HEURISTICS_DOWNLOAD,                                      args.back().as_string().c_str());   if (is_up)    cg_get_group(args.front())->up_queue()->set_heuristics((torrent::choke_queue::heuristics_enum)t);  else    cg_get_group(args.front())->down_queue()->set_heuristics((torrent::choke_queue::heuristics_enum)t);   return torrent::Object();} torrent::Objectapply_cg_tracker_mode_set(const torrent::Object::list_type& args) {  if (args.size() != 2)    throw torrent::input_error("Incorrect number of arguments.");   int t = torrent::option_find_string(torrent::OPTION_TRACKER_MODE, args.back().as_string().c_str());   cg_get_group(args.front())->set_tracker_mode((torrent::choke_group::tracker_mode_enum)t);   return torrent::Object();} #define CG_GROUP_AT()          std::bind(&cg_get_group, std::placeholders::_2)#define CHOKE_GROUP(direction) std::bind(direction, CG_GROUP_AT()) /* <cg_index> -> '0'..'(choke_group.size)'           -> '-1'..'-(choke_group.size)'           -> '<group_name>' (choke_group.list) -> List of group names.(choke_group.size) -> Number of groups. (choke_group.insert,"group_name") Adds a new group with default settings, use index '-1' to accessing itimmediately afterwards. (choke_group.index_of,"group_name") -> <group_index> Throws if the group name was not found. (choke_group.general.size,<cg_index>) -> <size> Number of torrents in this group. (choke_group.tracker.mode,<cg_index>) -> "tracker_mode"(choke_group.tracker.mode.set,<cg_index>,"tracker_mode") Decide on how aggressive a tracker should be, see'strings.tracker_mode' for list of available options (choke_group.up.rate,<cg_index>) -> <bytes/second>(choke_group.down.rate,<cg_index>) -> <bytes/second> Upload / download rate for the aggregate of all torrents in thisparticular group. (choke_group.up.max,<cg_index>) -> <max_upload_slots>(choke_group.up.max.unlimited,<cg_index>) -> <max_upload_slots>(choke_group.up.max.set,<cg_index>, <max_upload_slots>)(choke_group.down.max,<cg_index>) -> <max_download_slots>(choke_group.down.max.unlimited,<cg_index>) -> <max_download_slots>(choke_group.down.max.set,<cg_index>, <max_download_slots) Number of unchoked upload / download peers regulated on a group basis. (choke_group.up.total,<cg_index>) -> <number of queued and unchoked interested peers>(choke_group.up.queued,<cg_index>) -> <number of queued interested peers>(choke_group.up.unchoked,<cg_index>) -> <number of unchoked uploads>(choke_group.down.total,<cg_index>) -> <number of queued and unchoked interested peers>(choke_group.down.queued,<cg_index>) -> <number of queued interested peers>(choke_group.down.unchoked,<cg_index>) -> <number of unchoked uploads> (choke_group.up.heuristics,<cg_index>) -> "heuristics"(choke_group.up.heuristics.set,<cg_index>,"heuristics")(choke_group.down.heuristics,<cg_index>) -> "heuristics"(choke_group.down.heuristics.set,<cg_index>,"heuristics") Heuristics are used for deciding what peers to choke and unchoke, see'strings.choke_heuristics{,_download,_upload}' for a list of availableoptions. (d.group) -> <choke_group_index>(d.group.name) -> "choke_group_name"(d.group.set,<cg_index>)  */  voidinitialize_command_groups() {  CMD_ANY         ("choke_group.list",                std::bind(&apply_cg_list));  CMD_ANY_STRING  ("choke_group.insert",              std::bind(&apply_cg_insert, std::placeholders::_2)); #if USE_CHOKE_GROUP  CMD_ANY         ("choke_group.size",                std::bind(&torrent::ResourceManager::group_size, torrent::resource_manager()));  CMD_ANY_STRING  ("choke_group.index_of",            std::bind(&torrent::ResourceManager::group_index_of, torrent::resource_manager(), std::placeholders::_2));#else  apply_cg_insert("default");   CMD_ANY         ("choke_group.size",                [](auto, auto) { return (int64_t)cg_list_hack.size(); });  CMD_ANY_STRING  ("choke_group.index_of",            std::bind(&apply_cg_index_of, std::placeholders::_2));#endif   // Commands specific for a group. Supports as the first argument the  // name, the index or a negative index.  CMD_ANY         ("choke_group.general.size",        std::bind(&torrent::choke_group::size, CG_GROUP_AT()));   CMD_ANY         ("choke_group.tracker.mode",        [](auto, auto arg) { return torrent::option_to_str_or_throw(torrent::OPTION_TRACKER_MODE, cg_get_group(arg)->tracker_mode()); });  CMD_ANY_LIST    ("choke_group.tracker.mode.set",    [](auto, auto arg) { return apply_cg_tracker_mode_set(arg); });   CMD_ANY         ("choke_group.all.up.update_balance",   std::bind(&apply_cg_all_update_balance, true));  CMD_ANY         ("choke_group.all.down.update_balance", std::bind(&apply_cg_all_update_balance, false));   CMD_ANY         ("choke_group.up.rate",             std::bind(&torrent::choke_group::up_rate, CG_GROUP_AT()));  CMD_ANY         ("choke_group.down.rate",           std::bind(&torrent::choke_group::down_rate, CG_GROUP_AT()));   CMD_ANY         ("choke_group.up.max.unlimited",    std::bind(&torrent::choke_queue::is_unlimited, CHOKE_GROUP(&torrent::choke_group::up_queue)));  CMD_ANY         ("choke_group.up.max",              std::bind(&torrent::choke_queue::max_unchoked_signed, CHOKE_GROUP(&torrent::choke_group::up_queue)));  CMD_ANY_LIST    ("choke_group.up.max.set",          std::bind(&apply_cg_max_set, std::placeholders::_2, true));   CMD_ANY         ("choke_group.up.total",            std::bind(&torrent::choke_queue::size_total, CHOKE_GROUP(&torrent::choke_group::up_queue)));  CMD_ANY         ("choke_group.up.queued",           std::bind(&torrent::choke_queue::size_queued, CHOKE_GROUP(&torrent::choke_group::up_queue)));  CMD_ANY         ("choke_group.up.unchoked",         std::bind(&torrent::choke_queue::size_unchoked, CHOKE_GROUP(&torrent::choke_group::up_queue)));  CMD_ANY         ("choke_group.up.heuristics",       [](auto, auto arg) { return torrent::option_to_str_or_throw(torrent::OPTION_CHOKE_HEURISTICS, cg_get_group(arg)->up_queue()->heuristics()); });  CMD_ANY_LIST    ("choke_group.up.heuristics.set",   [](auto, auto arg) { return apply_cg_heuristics_set(arg, true); });   CMD_ANY         ("choke_group.down.max.unlimited",  std::bind(&torrent::choke_queue::is_unlimited, CHOKE_GROUP(&torrent::choke_group::down_queue)));  CMD_ANY         ("choke_group.down.max",            std::bind(&torrent::choke_queue::max_unchoked_signed, CHOKE_GROUP(&torrent::choke_group::down_queue)));  CMD_ANY_LIST    ("choke_group.down.max.set",        std::bind(&apply_cg_max_set, std::placeholders::_2, false));   CMD_ANY         ("choke_group.down.total",          std::bind(&torrent::choke_queue::size_total, CHOKE_GROUP(&torrent::choke_group::down_queue)));  CMD_ANY         ("choke_group.down.queued",         std::bind(&torrent::choke_queue::size_queued, CHOKE_GROUP(&torrent::choke_group::down_queue)));  CMD_ANY         ("choke_group.down.unchoked",       std::bind(&torrent::choke_queue::size_unchoked, CHOKE_GROUP(&torrent::choke_group::down_queue)));  CMD_ANY         ("choke_group.down.heuristics",     [](auto, auto arg) { return torrent::option_to_str_or_throw(torrent::OPTION_CHOKE_HEURISTICS, cg_get_group(arg)->down_queue()->heuristics()); });  CMD_ANY_LIST    ("choke_group.down.heuristics.set", [](auto, auto arg) { return apply_cg_heuristics_set(arg, false); });   rpc::rpc.mark_safe("choke_group.list");  rpc::rpc.mark_safe("choke_group.size");  rpc::rpc.mark_safe("choke_group.index_of");  rpc::rpc.mark_safe("choke_group.general.size");  rpc::rpc.mark_safe("choke_group.tracker.mode");  rpc::rpc.mark_safe("choke_group.up.rate");  rpc::rpc.mark_safe("choke_group.down.rate");  rpc::rpc.mark_safe("choke_group.up.max");  rpc::rpc.mark_safe("choke_group.up.max.unlimited");  rpc::rpc.mark_safe("choke_group.up.total");  rpc::rpc.mark_safe("choke_group.up.queued");  rpc::rpc.mark_safe("choke_group.up.unchoked");  rpc::rpc.mark_safe("choke_group.up.heuristics");  rpc::rpc.mark_safe("choke_group.down.max");  rpc::rpc.mark_safe("choke_group.down.max.unlimited");  rpc::rpc.mark_safe("choke_group.down.total");  rpc::rpc.mark_safe("choke_group.down.queued");  rpc::rpc.mark_safe("choke_group.down.unchoked");  rpc::rpc.mark_safe("choke_group.down.heuristics");}