From 1e206cb1c46a8d18881c47009a9de9806f1d37fa Mon Sep 17 00:00:00 2001 From: rakshasa Date: Sun, 5 Jun 2011 07:11:59 +0000 Subject: [PATCH] * Cleanup of command handling. * Added 'd.timestamp.finished' that is set when a downloading torrent completes. For torrents that only seed it remains '0'. * Added 'elapsed.{less,greater}' for checking the time elapsed since a time is less/greater, and it also returns false in all cases where the time is '0'. * Fixed a bug that would cause hash checking to block exessively in some cases. git-svn-id: svn://rakshasa.no/libtorrent/trunk/rtorrent@1233 e378c898-3ddf-0310-93e7-cc216c733640 --- doc/log_stats.plot | 20 ++++++++++++++------ src/command_download.cc | 9 +++++++-- src/command_dynamic.cc | 11 ++++++++--- src/command_ui.cc | 28 ++++++++++++++++++++++++++++ src/core/download_factory.cc | 2 ++ src/core/download_list.cc | 5 +++-- src/main.cc | 4 +++- src/rpc/object_storage.cc | 5 ++++- src/rpc/object_storage.h | 12 ++++++++++-- src/rpc/parse_commands.cc | 33 +++++++++++++++++++++++++++++---- 10 files changed, 108 insertions(+), 21 deletions(-) diff --git a/doc/log_stats.plot b/doc/log_stats.plot index 1d8eeaca..70c65abc 100644 --- a/doc/log_stats.plot +++ b/doc/log_stats.plot @@ -31,13 +31,21 @@ gnuplot << EOF # # Choke groups: # -# file.append = (cat,/foo/choke_group_stats.,(system.pid)),"timestamp", -# "\"leech up unchoked\"","\"leech up queued\"","\"leech up rate\"","\"leech down unchoked\"","\"leech down queued\"","\"leech down rate\"","\"leech torrents\"", -# "\"seed up unchoked\"","\"seed up queued\"","\"seed up rate\"","\"seed down unchoked\"","\"seed down queued\"","\"seed down rate\"","\"seed torrents\"" +# file.append = (cat,/foo/choke_group_stats.,(system.pid)),"timestamp",\ +# "\"default up unchoked\"","\"default up queued\"","\"default up rate\"",\ +# "\"default down unchoked\"","\"default down queued\"","\"default down rate\"","\"default torrents\"",\ +# "\"leech up unchoked\"","\"leech up queued\"","\"leech up rate\"",\ +# "\"leech down unchoked\"","\"leech down queued\"","\"leech down rate\"","\"leech torrents\"",\ +# "\"seed boost up unchoked\"","\"seed boost up queued\"","\"seed boost up rate\"",\ +# "\"seed boost down unchoked\"","\"seed boost down queued\"","\"seed boost down rate\"","\"seed boost torrents\"",\ +# "\"seed up unchoked\"","\"seed up queued\"","\"seed up rate\"",\ +# "\"seed down unchoked\"","\"seed down queued\"","\"seed down rate\"","\"seed torrents\"" # -# schedule = log_choke_group_stats,5,10,((file.append,((cat,/foo/choke_group_stats.,((system.pid)))),((system.time_seconds)), -# ((choke_group.up.unchoked,0)),((choke_group.up.queued,0)),((choke_group.up.rate,0)),((choke_group.down.unchoked,0)),((choke_group.down.queued,0)),((choke_group.down.rate,0)),((choke_group.size,0)), -# ((choke_group.up.unchoked,1)),((choke_group.up.queued,1)),((choke_group.up.rate,1)),((choke_group.down.unchoked,1)),((choke_group.down.queued,1)),((choke_group.down.rate,1)),((choke_group.size,1)))) +# schedule = log_choke_group_stats,5,10,((file.append,((cat,/foo/choke_group_stats.,((system.pid)))),((system.time_seconds)),\ +# ((choke_group.up.unchoked,0)),((choke_group.up.queued,0)),((choke_group.up.rate,0)),((choke_group.down.unchoked,0)),((choke_group.down.queued,0)),((choke_group.down.rate,0)),((choke_group.size,0)),\ +# ((choke_group.up.unchoked,1)),((choke_group.up.queued,1)),((choke_group.up.rate,1)),((choke_group.down.unchoked,1)),((choke_group.down.queued,1)),((choke_group.down.rate,1)),((choke_group.size,1)),\ +# ((choke_group.up.unchoked,2)),((choke_group.up.queued,2)),((choke_group.up.rate,2)),((choke_group.down.unchoked,2)),((choke_group.down.queued,2)),((choke_group.down.rate,2)),((choke_group.size,2)),\ +# ((choke_group.up.unchoked,3)),((choke_group.up.queued,3)),((choke_group.up.rate,3)),((choke_group.down.unchoked,3)),((choke_group.down.queued,3)),((choke_group.down.rate,3)),((choke_group.size,3)) )) # # Mincore stats: # diff --git a/src/command_download.cc b/src/command_download.cc index ed98c62b..6b5f9d90 100644 --- a/src/command_download.cc +++ b/src/command_download.cc @@ -654,8 +654,10 @@ initialize_command_download() { // 0 - stopped // 1 - started - CMD2_DL_VAR_VALUE("d.state", "rtorrent", "state"); - CMD2_DL_VAR_VALUE("d.complete", "rtorrent", "complete"); + CMD2_DL_VAR_VALUE("d.state", "rtorrent", "state"); + CMD2_DL_VAR_VALUE("d.complete", "rtorrent", "complete"); + + CMD2_FUNC_SINGLE ("d.incomplete", "not=(d.complete)"); // 0 off // 1 scheduled, being controlled by a download scheduler. Includes a priority. @@ -684,6 +686,8 @@ initialize_command_download() { CMD2_DL_VAR_VALUE("d.state_counter", "rtorrent", "state_counter"); CMD2_DL_VAR_VALUE_PUBLIC("d.ignore_commands", "rtorrent", "ignore_commands"); + CMD2_DL_VAR_VALUE("d.timestamp.finished", "rtorrent", "timestamp.finished"); + CMD2_DL ("d.connection_current", std::bind(&torrent::option_as_string, torrent::OPTION_CONNECTION_TYPE, CMD2_ON_DL(connection_type))); CMD2_DL_STRING("d.connection_current.set", std::bind(&apply_d_connection_type, std::placeholders::_1, std::placeholders::_2)); @@ -748,6 +752,7 @@ initialize_command_download() { CMD2_DL ("d.completed_chunks", CMD2_ON_FL(completed_chunks)); CMD2_DL ("d.left_bytes", CMD2_ON_FL(left_bytes)); + CMD2_DL_V ("d.tracker_announce", std::bind(&torrent::TrackerList::manual_request, CMD2_BIND_TL, false)); CMD2_DL ("d.tracker_numwant", std::bind(&torrent::TrackerList::numwant, CMD2_BIND_TL)); CMD2_DL_VALUE_V ("d.tracker_numwant.set", std::bind(&torrent::TrackerList::set_numwant, CMD2_BIND_TL, std::placeholders::_2)); CMD2_DL ("d.tracker_focus", std::bind(&torrent::TrackerList::focus_index, CMD2_BIND_TL)); diff --git a/src/command_dynamic.cc b/src/command_dynamic.cc index f3cef370..b7f9aa48 100644 --- a/src/command_dynamic.cc +++ b/src/command_dynamic.cc @@ -394,10 +394,15 @@ system_method_set_key(const torrent::Object::list_type& args) { const std::string& key = (itrArgs++)->as_string(); const std::string& cmd_key = (itrArgs++)->as_string(); - if (itrArgs != args.end()) - control->object_storage()->set_str_multi_key(key, cmd_key, system_method_generate_command(itrArgs, args.end())); - else + if (itrArgs == args.end()) { control->object_storage()->erase_str_multi_key(key, cmd_key); + return torrent::Object(); + } + + if (itrArgs->is_dict_key()) + control->object_storage()->set_str_multi_key_obj(key.c_str(), cmd_key, *itrArgs); + else + control->object_storage()->set_str_multi_key(key, cmd_key, system_method_generate_command(itrArgs, args.end())); return torrent::Object(); } diff --git a/src/command_ui.cc b/src/command_ui.cc index 5c00b4af..a5975d66 100644 --- a/src/command_ui.cc +++ b/src/command_ui.cc @@ -404,6 +404,8 @@ apply_if(rpc::target_type target, const torrent::Object& rawArgs, int flags) { if (flags & 0x1 && itr->is_string()) conditional = &(tmp = rpc::parse_command(target, itr->as_string().c_str(), itr->as_string().c_str() + itr->as_string().size()).first); + else if (flags & 0x1 && itr->is_dict_key()) + conditional = &(tmp = rpc::commands.call_command(itr->as_dict_key().c_str(), itr->as_dict_obj(), target)); else conditional = &*itr; @@ -437,6 +439,9 @@ apply_if(rpc::target_type target, const torrent::Object& rawArgs, int flags) { if (flags & 0x1 && itr->is_string()) { return rpc::parse_command(target, itr->as_string().c_str(), itr->as_string().c_str() + itr->as_string().size()).first; + } else if (flags & 0x1 && itr->is_dict_key()) { + return rpc::commands.call_command(itr->as_dict_key().c_str(), itr->as_dict_obj(), target); + } else if (flags & 0x1 && itr->is_list()) { // Move this into a special function or something. Also, might be // nice to have a parse_command function that takes list @@ -512,6 +517,26 @@ cmd_view_set_not_visible(core::Download* download, const torrent::Object::string return torrent::Object(); } +torrent::Object +apply_elapsed_less(const torrent::Object::list_type& args) { + if (args.size() != 2) + throw torrent::input_error("Wrong argument count."); + + int64_t start_time = rpc::convert_to_value(args.front()); + + return (int64_t)(start_time != 0 && rak::timer::current_seconds() - start_time < rpc::convert_to_value(args.back())); +} + +torrent::Object +apply_elapsed_greater(const torrent::Object::list_type& args) { + if (args.size() != 2) + throw torrent::input_error("Wrong argument count."); + + int64_t start_time = rpc::convert_to_value(args.front()); + + return (int64_t)(start_time != 0 && rak::timer::current_seconds() - start_time > rpc::convert_to_value(args.back())); +} + void initialize_command_ui() { CMD2_VAR_STRING("keys.layout", "qwerty"); @@ -573,4 +598,7 @@ initialize_command_ui() { CMD2_ANY_VALUE("convert.mb", std::bind(&apply_to_mb, std::placeholders::_2)); CMD2_ANY_VALUE("convert.xb", std::bind(&apply_to_xb, std::placeholders::_2)); CMD2_ANY_VALUE("convert.throttle", std::bind(&apply_to_throttle, std::placeholders::_2)); + + CMD2_ANY_LIST ("elapsed.less", std::bind(&apply_elapsed_less, std::placeholders::_2)); + CMD2_ANY_LIST ("elapsed.greater", std::bind(&apply_elapsed_greater, std::placeholders::_2)); } diff --git a/src/core/download_factory.cc b/src/core/download_factory.cc index 0fa2035a..cfc22972 100644 --- a/src/core/download_factory.cc +++ b/src/core/download_factory.cc @@ -368,6 +368,8 @@ DownloadFactory::initialize_rtorrent(Download* download, torrent::Object* rtorre rtorrent->insert_preserve_copy("complete", (int64_t)0); rtorrent->insert_preserve_copy("hashing", (int64_t)Download::variable_hashing_stopped); + rtorrent->insert_preserve_copy("timestamp.finished", (int64_t)0); + rtorrent->insert_preserve_copy("tied_to_file", ""); rtorrent->insert_key("loaded_file", m_isFile ? m_uri : std::string()); diff --git a/src/core/download_list.cc b/src/core/download_list.cc index e5806aae..faa5e585 100644 --- a/src/core/download_list.cc +++ b/src/core/download_list.cc @@ -533,8 +533,9 @@ DownloadList::hash_done(Download* download) { control->core()->push_log("Hash check on download completion found bad chunks, consider using \"safe_sync\"."); rpc::commands.call_catch("event.download.hash_final_failed", rpc::make_target(download), torrent::Object(), "Download event action failed: "); } - - break; + + // TODO: Should we skip the 'hash_done' event here? + return; case Download::variable_hashing_stopped: default: diff --git a/src/main.cc b/src/main.cc index 8fbb5d37..2c2c4263 100644 --- a/src/main.cc +++ b/src/main.cc @@ -242,6 +242,8 @@ main(int argc, char** argv) { "method.set_key = event.download.erased, !_download_list, ui.unfocus_download=\n" "method.set_key = event.download.erased, ~_delete_tied, d.delete_tied=\n" + "method.set_key = event.download.finished, !_timestamp, ((d.timestamp.finished.set, ((system.time)) ))\n" + "method.insert.c_simple = group.insert_persistent_view," "((view.add,((argument.0)))),((view.persistent,((argument.0)))),((group.insert,((argument.0)),((argument.0))))\n" @@ -298,7 +300,7 @@ main(int argc, char** argv) { "view.add = hashing\n" "view.filter = hashing,((d.hashing))\n" "view.filter_on = hashing,event.download.hash_queued,event.download.hash_removed," - "event.download.hash_done,event.download.hash_failed,event.download.hash_final_failed\n" + "event.download.hash_done,event.download.hash_failed,event.download.hash_final_failed,event.download.finished\n" // "view.sort_new = hashing,less=d.state_changed=\n" // "view.sort_current = hashing,less=d.state_changed=\n" diff --git a/src/rpc/object_storage.cc b/src/rpc/object_storage.cc index a9f013e1..03e27e9f 100644 --- a/src/rpc/object_storage.cc +++ b/src/rpc/object_storage.cc @@ -205,7 +205,10 @@ object_storage::erase_multi_key(const torrent::raw_string& key, const std::strin } void -object_storage::set_multi_key(const torrent::raw_string& key, const std::string& cmd_key, const std::string& object) { +object_storage::set_multi_key_obj(const torrent::raw_string& key, const std::string& cmd_key, const torrent::Object& object) { + if (!object.is_string() && !object.is_dict_key()) + throw torrent::input_error("Object is wrong type."); + local_iterator itr = find_local(key); if (itr == end(0) || (itr->second.flags & mask_type) != flag_multi_type) diff --git a/src/rpc/object_storage.h b/src/rpc/object_storage.h index 9c50be86..40ae9277 100644 --- a/src/rpc/object_storage.h +++ b/src/rpc/object_storage.h @@ -150,11 +150,14 @@ public: // Multi-command function: bool has_multi_key(const torrent::raw_string& key, const std::string& cmd_key); void erase_multi_key(const torrent::raw_string& key, const std::string& cmd_key); - void set_multi_key(const torrent::raw_string& key, const std::string& cmd_key, const std::string& object); + void set_multi_key_obj(const torrent::raw_string& key, const std::string& cmd_key, const torrent::Object& object); + + void set_multi_key(const torrent::raw_string& key, const std::string& cmd_key, const std::string& object) { set_multi_key_obj(key, cmd_key, object); } bool has_str_multi_key(const std::string& key, const std::string& cmd_key); void erase_str_multi_key(const std::string& key, const std::string& cmd_key); void set_str_multi_key(const std::string& key, const std::string& cmd_key, const std::string& object); + void set_str_multi_key_obj(const std::string& key, const std::string& cmd_key, const torrent::Object& object); torrent::Object::list_type rlookup_list(const std::string& cmd_key); torrent::Object rlookup_obj_list(const std::string& cmd_key) { return torrent::Object::from_list(rlookup_list(cmd_key)); } @@ -241,7 +244,12 @@ object_storage::erase_str_multi_key(const std::string& key, const std::string& c inline void object_storage::set_str_multi_key(const std::string& key, const std::string& cmd_key, const std::string& object) { - return set_multi_key(torrent::raw_string::from_string(key), cmd_key, object); + return set_multi_key_obj(torrent::raw_string::from_string(key), cmd_key, object); +} + +inline void +object_storage::set_str_multi_key_obj(const std::string& key, const std::string& cmd_key, const torrent::Object& object) { + return set_multi_key_obj(torrent::raw_string::from_string(key), cmd_key, object); } } diff --git a/src/rpc/parse_commands.cc b/src/rpc/parse_commands.cc index 60765733..f8a125a9 100644 --- a/src/rpc/parse_commands.cc +++ b/src/rpc/parse_commands.cc @@ -295,10 +295,18 @@ command_function_call_object(const torrent::Object& cmd, target_type target, con } } else { - torrent::Object tmp_cmd = cmd; - - rpc::parse_command_execute(target, &tmp_cmd); - result = rpc::commands.call_command(tmp_cmd.as_dict_key().c_str(), tmp_cmd.as_dict_obj()); + torrent::Object tmp_command = cmd; + + // Unquote the root function object so 'parse_command_execute' + // doesn't end up calling it. + // + // TODO: Only call this if mask_function is set? + uint32_t flags = tmp_command.flags() & torrent::Object::mask_function; + tmp_command.unset_flags(torrent::Object::mask_function); + tmp_command.set_flags((flags >> 1) & torrent::Object::mask_function); + + rpc::parse_command_execute(target, &tmp_command); + rpc::commands.call_command(tmp_command.as_dict_key().c_str(), tmp_command.as_dict_obj(), target); } rpc::command_base::pop_stack(&stack, last_stack); @@ -324,6 +332,23 @@ command_function_multi_call(const torrent::Object::map_type& cmd, target_type ta try { for (torrent::Object::map_const_iterator itr = cmd.begin(), last = cmd.end(); itr != last; itr++) { + if (itr->second.is_dict_key()) { + // This can/should be optimized... + torrent::Object tmp_command = itr->second; + + // Unquote the root function object so 'parse_command_execute' + // doesn't end up calling it. + // + // TODO: Only call this if mask_function is set? + uint32_t flags = tmp_command.flags() & torrent::Object::mask_function; + tmp_command.unset_flags(torrent::Object::mask_function); + tmp_command.set_flags((flags >> 1) & torrent::Object::mask_function); + + rpc::parse_command_execute(target, &tmp_command); + rpc::commands.call_command(tmp_command.as_dict_key().c_str(), tmp_command.as_dict_obj(), target); + continue; + } + const std::string& cmd_str = itr->second.as_string(); parse_command_multiple(target, cmd_str.c_str(), cmd_str.c_str() + cmd_str.size()); }