1 diff --git a/src/command_download.cc b/src/command_download.cc
2 index 6043662..9afd9b0 100644
3 --- a/src/command_download.cc
4 +++ b/src/command_download.cc
6 #include <torrent/data/file.h>
7 #include <torrent/data/file_list.h>
8 #include <torrent/peer/connection_list.h>
9 +#include <torrent/peer/peer_info.h>
10 #include <torrent/peer/peer_list.h>
12 #include "core/download.h"
13 #include "core/download_store.h"
14 #include "core/manager.h"
15 #include "rpc/command_variable.h"
16 +#include "rpc/parse.h"
20 @@ -170,6 +172,120 @@ apply_d_delete_tied(core::Download* download) {
21 rpc::call_command("d.set_tied_to_file", std::string(), rpc::make_target(download));
25 +apply_d_snub_leechers(core::Download* download, const torrent::Object& rawArgs) {
26 + if (!download->is_open() || download->is_done() || rpc::call_command_value("d.get_ignore_commands", rpc::make_target(download)) != 0)
27 + return torrent::Object();
29 + const torrent::Object::list_type& args = rawArgs.as_list();
31 + if (args.size() < 3)
32 + throw torrent::input_error("Too few arguments.");
34 + torrent::Object::list_type::const_iterator argItr = args.begin();
35 + uint64_t snub_ratio = rpc::convert_to_value(*argItr++);
36 + uint64_t unsnub_ratio = rpc::convert_to_value(*argItr++);
37 + uint64_t min_transfer = rpc::convert_to_value(*argItr++);
39 + for (torrent::ConnectionList::iterator itr = download->download()->connection_list()->begin(); itr != download->download()->connection_list()->end(); ++itr) {
40 +#if LIBTORRENT_FRIENDS
41 + if (((*itr)->bitfield() && (*itr)->bitfield()->is_all_set()) || (*itr)->peer_info()->is_friend())
43 + if (((*itr)->bitfield() && (*itr)->bitfield()->is_all_set()))
47 + uint64_t up = (*itr)->up_rate()->total();
48 + uint64_t down = (*itr)->down_rate()->total();
50 + if ((*itr)->is_snubbed()) {
51 + if (down * unsnub_ratio >= std::max<uint64_t>(up, min_transfer))
52 + (*itr)->set_snubbed(false);
54 + } else if (up > min_transfer && down * snub_ratio < up) {
55 + (*itr)->set_snubbed(true);
59 + return torrent::Object();
63 +apply_d_ban_slow_peers(core::Download* download, const torrent::Object& rawArgs) {
64 + if (!download->is_open() || download->is_done() || rpc::call_command_value("d.get_ignore_commands", rpc::make_target(download)) != 0)
65 + return torrent::Object();
67 + const torrent::Object::list_type& args = rawArgs.as_list();
69 + if (args.size() < 4)
70 + throw torrent::input_error("Too few arguments.");
72 + torrent::ConnectionList* clist = download->download()->connection_list();
73 + int extraPeers = clist->size() - clist->min_size();
74 + if (extraPeers <= 0)
75 + return torrent::Object();
77 + torrent::Object::list_type::const_iterator argItrStart = args.begin();
78 + int extraSeeds = download->download()->peers_complete() - rpc::convert_to_value(*argItrStart++);
79 + uint32_t minRate = rpc::convert_to_value(*argItrStart++);
81 + for (torrent::ConnectionList::iterator itr = clist->begin(); extraPeers > 0 && itr != clist->end(); ++itr) {
82 +#if LIBTORRENT_FRIENDS
83 + if ((*itr)->peer_info()->is_friend())
87 + bool isSeed = (*itr)->bitfield() && (*itr)->bitfield()->is_all_set();
88 + if (isSeed && extraSeeds <= 0)
91 + int64_t down = (*itr)->down_rate()->total();
92 + uint32_t rate = (*itr)->down_rate()->rate();
94 + for (torrent::Object::list_type::const_iterator argItr = argItrStart; argItr != args.end(); ++argItr) {
95 + if (rate >= minRate || down >= rpc::convert_to_value(*argItr++))
98 + if (cachedTime.seconds() - (*itr)->peer_info()->last_connection() < rpc::convert_to_value(*argItr) * 60)
101 + (*itr)->set_banned();
103 + extraSeeds -= isSeed;
109 + // Need to go by indices because erasing may invalidate iterators.
110 + for (size_t pId = 0; pId < clist->size(); )
111 + if ((*(clist->begin() + pId))->is_banned())
112 + download->connection_list()->erase(*(clist->begin() + pId), 0);
116 + return torrent::Object();
120 +apply_d_unban_peers(core::Download* download) {
121 + torrent::PeerList* list = download->download()->peer_list();
123 + for (torrent::PeerList::const_iterator itr = list->begin(); itr != list->end(); ++itr)
124 + if (itr->second->is_banned())
125 + itr->second->set_unbanned();
129 +apply_d_unsnub_peers(core::Download* download) {
130 + if (!download->is_open())
133 + for (torrent::ConnectionList::iterator itr = download->download()->connection_list()->begin(); itr != download->download()->connection_list()->end(); ++itr)
134 + if ((*itr)->is_snubbed())
135 + (*itr)->set_snubbed(false);
139 apply_d_connection_type(core::Download* download, const std::string& name) {
140 torrent::Download::ConnectionType connType;
141 @@ -580,6 +696,11 @@ initialize_command_download() {
142 ADD_CD_LIST("delete_link", rak::bind_ptr_fn(&apply_d_change_link, 1));
143 ADD_CD_V_VOID("delete_tied", &apply_d_delete_tied);
145 + ADD_CD_LIST("ban_slow_peers", rak::ptr_fn(&apply_d_ban_slow_peers));
146 + ADD_CD_LIST("snub_leechers", rak::ptr_fn(&apply_d_snub_leechers));
147 + ADD_CD_V_VOID("unban_peers", &apply_d_unban_peers);
148 + ADD_CD_V_VOID("unsnub_peers", &apply_d_unsnub_peers);
150 CMD_FUNC_SINGLE("d.start", "d.set_hashing_failed=0 ;view.set_visible=started");
151 CMD_FUNC_SINGLE("d.stop", "view.set_visible=stopped");
152 CMD_FUNC_SINGLE("d.try_start", "branch=\"or={d.get_hashing_failed=,d.get_ignore_commands=}\",{},{view.set_visible=started}");
153 diff --git a/src/command_events.cc b/src/command_events.cc
154 index b25dfbc..a0250d9 100644
155 --- a/src/command_events.cc
156 +++ b/src/command_events.cc
158 #include <rak/path.h>
159 #include <rak/string_manip.h>
160 #include <sigc++/adaptors/bind.h>
161 +#include <torrent/peer/connection_list.h>
162 +#include <torrent/peer/peer_info.h>
163 #include <torrent/rate.h>
164 #include <torrent/hash_string.h>
166 @@ -276,6 +278,31 @@ apply_close_low_diskspace(int64_t arg) {
167 control->core()->push_log("Closed torrents due to low diskspace.");
170 +// Should call the d.* commands via RPC, but there doesn't seem to be a way to
171 +// pass variable-sized argument lists, so call the functions directly for now.
172 +torrent::Object apply_d_snub_leechers(core::Download*, const torrent::Object&);
173 +torrent::Object apply_d_ban_slow_peers(core::Download*, const torrent::Object&);
176 +apply_snub_leechers(const torrent::Object& rawArgs) {
177 + for (core::Manager::DListItr ditr = control->core()->download_list()->begin(); ditr != control->core()->download_list()->end(); ditr++) {
178 + if ((*ditr)->is_open() && !(*ditr)->is_done() && rpc::call_command_value("d.get_ignore_commands", rpc::make_target(*ditr)) == 0)
179 + apply_d_snub_leechers(*ditr, rawArgs);
182 + return torrent::Object();
186 +apply_ban_slow_peers(const torrent::Object& rawArgs) {
187 + for (core::Manager::DListItr ditr = control->core()->download_list()->begin(); ditr != control->core()->download_list()->end(); ditr++) {
188 + if ((*ditr)->is_open() && !(*ditr)->is_done() && rpc::call_command_value("d.get_ignore_commands", rpc::make_target(*ditr)) == 0)
189 + apply_d_ban_slow_peers(*ditr, rawArgs);
192 + return torrent::Object();
196 apply_download_list(const torrent::Object& rawArgs) {
197 const torrent::Object::list_type& args = rawArgs.as_list();
198 @@ -369,6 +396,8 @@ initialize_command_events() {
199 ADD_COMMAND_LIST("on_finished", rak::bind_ptr_fn(&apply_on_state_change, "event.download.finished"));
201 ADD_COMMAND_STRING("on_ratio", rak::ptr_fn(&apply_on_ratio));
202 + ADD_COMMAND_LIST("snub_leechers", rak::ptr_fn(&apply_snub_leechers));
203 + ADD_COMMAND_LIST("ban_slow_peers", rak::ptr_fn(&apply_ban_slow_peers));
205 ADD_COMMAND_VOID("start_tied", &apply_start_tied);
206 ADD_COMMAND_VOID("stop_untied", &apply_stop_untied);
207 diff --git a/src/command_helpers.h b/src/command_helpers.h
208 index a807b5f..cda29d8 100644
209 --- a/src/command_helpers.h
210 +++ b/src/command_helpers.h
211 @@ -54,7 +54,7 @@ namespace rpc {
212 #define COMMAND_DOWNLOAD_SLOTS_SIZE 150
213 #define COMMAND_FILE_SLOTS_SIZE 30
214 #define COMMAND_FILE_ITR_SLOTS_SIZE 10
215 -#define COMMAND_PEER_SLOTS_SIZE 20
216 +#define COMMAND_PEER_SLOTS_SIZE 30
217 #define COMMAND_TRACKER_SLOTS_SIZE 15
218 #define COMMAND_ANY_SLOTS_SIZE 50