summarylogtreecommitdiffstats
path: root/command_pyroscope.cc
diff options
context:
space:
mode:
authorxsmile2018-07-02 22:51:10 +0200
committerxsmile2018-07-02 22:51:10 +0200
commite9b4bfa9b8b176e8b291fe8115e59242e302a6a2 (patch)
tree8d6e021191cf5cf695f4d3beec9cc142f0d043c4 /command_pyroscope.cc
parentd1e56fd0fdfbe3d8d7c8c2bfc20b8f800ceb66e5 (diff)
downloadaur-e9b4bfa9b8b176e8b291fe8115e59242e302a6a2.tar.gz
update
Diffstat (limited to 'command_pyroscope.cc')
-rw-r--r--command_pyroscope.cc345
1 files changed, 330 insertions, 15 deletions
diff --git a/command_pyroscope.cc b/command_pyroscope.cc
index e432cffe6473..80fa52b54f0b 100644
--- a/command_pyroscope.cc
+++ b/command_pyroscope.cc
@@ -180,16 +180,19 @@ torrent::Object apply_random(rpc::target_type target, const torrent::Object::lis
torrent::Tracker* get_active_tracker(torrent::Download* item) {
torrent::TrackerList* tl = item->tracker_list();
torrent::Tracker* tracker = 0;
+ torrent::Tracker* fallback = 0;
for (size_t trkidx = 0; trkidx < tl->size(); trkidx++) {
tracker = tl->at(trkidx);
- if (tracker->is_usable() && tracker->type() == torrent::Tracker::TRACKER_HTTP
- && tracker->scrape_complete() + tracker->scrape_incomplete() > 0) {
- break;
+ if (tracker->is_usable() && tracker->type() == torrent::Tracker::TRACKER_HTTP) {
+ if (!fallback) fallback = tracker;
+ if (tracker->scrape_complete() || tracker->scrape_incomplete()) {
+ break;
+ }
}
tracker = 0;
}
- if (!tracker && tl->size()) tracker = tl->at(0);
+ if (!tracker && tl->size()) tracker = fallback ? fallback : tl->at(0);
return tracker;
}
@@ -497,6 +500,11 @@ torrent::Object cmd_import_return(rpc::target_type target, const torrent::Object
}
+torrent::Object cmd_do(rpc::target_type target, const torrent::Object& args) {
+ return rpc::call_object(args, target);
+}
+
+
torrent::Object retrieve_d_custom_if_z(core::Download* download, const torrent::Object::list_type& args) {
torrent::Object::list_const_iterator itr = args.begin();
if (itr == args.end())
@@ -508,13 +516,53 @@ torrent::Object retrieve_d_custom_if_z(core::Download* download, const torrent::
throw torrent::bencode_error("d.custom.if_z: Missing default argument.");
try {
- return download->bencode()->get_key("rtorrent").get_key("custom").get_key_string(key);
+ const std::string& val = download->bencode()->get_key("rtorrent").get_key("custom").get_key_string(key);
+ return val.empty() ? itr->as_string() : val;
} catch (torrent::bencode_error& e) {
return itr->as_string();
}
}
+torrent::Object cmd_d_custom_set_if_z(core::Download* download, const torrent::Object::list_type& args) {
+ torrent::Object::list_const_iterator itr = args.begin();
+ if (itr == args.end())
+ throw torrent::bencode_error("d.custom.set_if_z: Missing key argument.");
+ const std::string& key = (itr++)->as_string();
+ if (key.empty())
+ throw torrent::bencode_error("d.custom.set_if_z: Empty key argument.");
+ if (itr == args.end())
+ throw torrent::bencode_error("d.custom.set_if_z: Missing value argument.");
+
+ bool set_it = false;
+ try {
+ const std::string& val = download->bencode()->get_key("rtorrent").get_key("custom").get_key_string(key);
+ set_it = val.empty();
+ } catch (torrent::bencode_error& e) {
+ set_it = true;
+ }
+ if (set_it)
+ download->bencode()->get_key("rtorrent").
+ insert_preserve_copy("custom", torrent::Object::create_map()).first->second.
+ insert_key(key, itr->as_string());
+
+ return torrent::Object();
+}
+
+
+torrent::Object cmd_d_custom_erase(core::Download* download, const torrent::Object::list_type& args) {
+ for (torrent::Object::list_type::const_iterator itr = args.begin(), last = args.end(); itr != last; itr++) {
+ const std::string& key = itr->as_string();
+ if (key.empty())
+ throw torrent::bencode_error("d.custom.erase: Empty key argument.");
+
+ download->bencode()->get_key("rtorrent").get_key("custom").erase_key(key);
+ }
+
+ return torrent::Object();
+}
+
+
torrent::Object retrieve_d_custom_map(core::Download* download, bool keys_only, const torrent::Object::list_type& args) {
if (args.begin() != args.end())
throw torrent::bencode_error("d.custom.keys/items takes no arguments.");
@@ -531,6 +579,44 @@ torrent::Object retrieve_d_custom_map(core::Download* download, bool keys_only,
}
+torrent::Object cmd_d_custom_toggle(core::Download* download, const std::string& key) {
+ bool result = true;
+ try {
+ const std::string& strval = download->bencode()->get_key("rtorrent").get_key("custom").get_key_string(key);
+ if (!strval.empty()) {
+ char* junk = 0;
+ long number = strtol(strval.c_str(), &junk, 10);
+ while (std::isspace(*junk)) ++junk;
+ result = !*junk && number == 0;
+ }
+ } catch (torrent::bencode_error& e) {
+ // true
+ }
+
+ download->bencode()->get_key("rtorrent").
+ insert_preserve_copy("custom", torrent::Object::create_map()).first->second.
+ insert_key(key, result ? "1" : "0");
+ return (int64_t) (result ? 1 : 0);
+}
+
+
+torrent::Object retrieve_d_custom_as_value(core::Download* download, const std::string& key) {
+ try {
+ const std::string& strval = download->bencode()->get_key("rtorrent").get_key("custom").get_key_string(key);
+ if (strval.empty())
+ return (int64_t) 0;
+
+ char* junk = 0;
+ long result = strtol(strval.c_str(), &junk, 10);
+ if (*junk)
+ throw torrent::input_error("d.custom.as_value(" + key + "): junk at end of '" + strval + "'!");
+ return (int64_t) result;
+ } catch (torrent::bencode_error& e) {
+ return (int64_t) 0;
+ }
+}
+
+
torrent::Object
d_multicall_filtered(const torrent::Object::list_type& args) {
if (args.size() < 2)
@@ -539,12 +625,7 @@ d_multicall_filtered(const torrent::Object::list_type& args) {
// Find the given view
core::ViewManager* viewManager = control->view_manager();
- core::ViewManager::iterator viewItr;
-
- if (!arg->as_string().empty())
- viewItr = viewManager->find(arg->as_string());
- else
- viewItr = viewManager->find("default");
+ core::ViewManager::iterator viewItr = viewManager->find(arg->as_string().empty() ? "default" : arg->as_string());
if (viewItr == viewManager->end())
throw torrent::input_error("Could not find view '" + arg->as_string() + "'.");
@@ -594,15 +675,39 @@ torrent::Object cmd_throttle_names() {
}
-static const std::string& string_get_first_arg(const char* name, const torrent::Object::list_type& args) {
- if (args.size() < 1) {
- throw torrent::input_error("string." + std::string(name) + " needs a string argument!");
+// Get length of an UTF8-encoded std::string
+size_t u8_length(const std::string& text) {
+ // Take total length and subtract number of non-leading multi-bytes
+ return text.length() - count_if(text.begin(), text.end(),
+ [](char c)->bool { return (c & 0xC0) == 0x80; });
+}
+
+
+// Chop off an UTF-8 string
+std::string u8_chop(const std::string& text, size_t glyphs) {
+ std::mbstate_t mbs = std::mbstate_t();
+ size_t bytes = 0, skip;
+ const char* pos = text.c_str();
+
+ while (*pos && glyphs-- > 0 && (skip = std::mbrlen(pos, text.length() - bytes, &mbs)) > 0) {
+ pos += skip;
+ bytes += skip;
}
+
+ return bytes < text.length() ? text.substr(0, bytes) : text;
+}
+
+
+static const std::string& string_get_first_arg(const char* name, const torrent::Object::list_type& args) {
torrent::Object::list_const_iterator itr = args.begin();
+ if (args.size() < 1 || !itr->is_string()) {
+ throw torrent::input_error("string." + std::string(name) + " needs a string argument.0!");
+ }
return itr->as_string();
}
+// get a numeric arg from a string or value, advancing the passed iterator
static int64_t string_get_value_arg(const char* name, torrent::Object::list_const_iterator& itr) {
int64_t result = 0;
if (itr->is_string()) {
@@ -637,6 +742,147 @@ torrent::Object cmd_string_len(rpc::target_type target, const torrent::Object::l
}
+torrent::Object cmd_string_join(rpc::target_type target, const torrent::Object::list_type& args) {
+ std::string delim = string_get_first_arg("join", args);
+ std::string result;
+ torrent::Object::list_const_iterator first = args.begin() + 1, last = args.end();
+
+ for (torrent::Object::list_const_iterator itr = first; itr != last; ++itr) {
+ if (itr != first) result += delim;
+ rpc::print_object_std(&result, &*itr, 0);
+ }
+
+ return result;
+}
+
+
+torrent::Object cmd_string_strip(int where, const torrent::Object::list_type& args) {
+ std::string text = string_get_first_arg("[lr]strip", args);
+ torrent::Object::list_const_iterator first = args.begin() + 1, last = args.end();
+
+ if (args.size() == 1) {
+ // Strip whitespace
+ if (where <= 0) {
+ text.erase(text.begin(),
+ std::find_if(text.begin(), text.end(),
+ std::not1(std::ptr_fun<int, int>(std::isspace))));
+ }
+ if (where >= 0) {
+ text.erase(std::find_if(text.rbegin(), text.rend(),
+ std::not1(std::ptr_fun<int, int>(std::isspace))).base(),
+ text.end());
+ }
+ } else {
+ size_t lpos = 0, rpos = text.length();
+ bool changed;
+ do {
+ changed = false;
+ for (torrent::Object::list_const_iterator itr = first; itr != last; ++itr) {
+ const std::string& strippable = itr->as_string();
+ if (strippable.empty()) continue;
+
+ bool found;
+ do {
+ found = false;
+
+ if (where <= 0) {
+ if (0 == strncmp(text.c_str() + lpos, strippable.c_str(), strippable.length())) {
+ lpos += strippable.length();
+ changed = found = true;
+ }
+ }
+ if (where >= 0 && lpos <= rpos - strippable.length()) {
+ if (0 == strncmp(text.c_str() + rpos - strippable.length(), strippable.c_str(), strippable.length())) {
+ rpos -= strippable.length();
+ changed = found = true;
+ }
+ }
+ } while (found && lpos < rpos);
+ }
+ } while (changed && lpos < rpos);
+ text = lpos < rpos ? text.substr(lpos, rpos - lpos) : "";
+ }
+
+ return text;
+}
+
+
+torrent::Object cmd_string_pad(bool at_end, const torrent::Object::list_type& args) {
+ std::string text;
+ if (args.size() > 0 && args.begin()->is_value()) {
+ char buf[65];
+ snprintf(buf, sizeof(buf), "%ld", (long)args.begin()->as_value());
+ text = buf;
+ } else {
+ text = string_get_first_arg("[lr]pad", args);
+ }
+
+ torrent::Object::list_const_iterator itr = args.begin() + 1;
+ int64_t pad_len = 0;
+ std::string filler;
+ if (itr != args.end()) pad_len = string_get_value_arg("[lr]pad(pad_len)", itr);
+ if (itr != args.end()) filler = (itr++)->as_string();
+ if (pad_len < 0)
+ throw torrent::input_error("string.[lr]pad: Invalid negative padding length!");
+ if (filler.empty()) filler = " ";
+ size_t text_len = u8_length(text), filler_len = u8_length(filler);
+
+ if (size_t(pad_len) > text_len) {
+ std::string pad;
+ size_t count = size_t(pad_len) - text_len;
+
+ if (filler.length() == 1) { // optimize the common case
+ pad.insert(0, count, filler.at(0));
+ } else while (count > 0) {
+ if (count >= filler_len) {
+ pad += filler;
+ count -= filler_len;
+ } else {
+ pad += u8_chop(filler, count);
+ count = 0;
+ }
+ }
+
+ return at_end ? text + pad : pad + text;
+ }
+
+ return text;
+}
+
+
+torrent::Object cmd_string_split(rpc::target_type target, const torrent::Object::list_type& args) {
+ const std::string text = string_get_first_arg("split", args);
+ if (args.size() != 2 || !args.rbegin()->is_string()) {
+ throw torrent::input_error("string.split needs a string argument.1!");
+ }
+ const std::string delim = args.rbegin()->as_string();
+ torrent::Object result = torrent::Object::create_list();
+ torrent::Object::list_type& resultList = result.as_list();
+
+ if (delim.length()) {
+ size_t pos = 0, next = 0;
+
+ while ((next = text.find(delim, pos)) != std::string::npos) {
+ resultList.push_back(text.substr(pos, next - pos));
+ pos = next + delim.length();
+ }
+ resultList.push_back(text.substr(pos));
+ } else {
+ std::mbstate_t mbs = std::mbstate_t();
+ const char* cpos = text.c_str();
+ int bytes = 0, skip;
+
+ while (*cpos && (skip = std::mbrlen(cpos, text.length() - bytes, &mbs)) > 0) {
+ resultList.push_back(std::string(cpos, skip));
+ cpos += skip;
+ bytes += skip;
+ }
+ }
+
+ return result;
+}
+
+
torrent::Object cmd_string_substr(rpc::target_type target, const torrent::Object::list_type& args) {
const std::string text = string_get_first_arg("substr", args);
@@ -756,6 +1002,36 @@ torrent::Object cmd_string_replace(rpc::target_type target, const torrent::Objec
}
+torrent::Object cmd_string_compare(int mode, const torrent::Object::list_type& args) {
+ const char* opnames[] = {"equals", "startswith", "endswith"};
+ if (args.size() < 2) {
+ throw torrent::input_error("string." + std::string(opnames[mode]) + " takes at least two arguments!");
+ }
+
+ std::string value = string_get_first_arg(opnames[mode], args);
+ torrent::Object::list_const_iterator first = args.begin() + 1, last = args.end();
+
+ for (torrent::Object::list_const_iterator itr = first; itr != last; ++itr) {
+ const std::string& cmp = itr->as_string();
+ switch (mode) {
+ case 0:
+ if (value == cmp) return (int64_t) 1;
+ break;
+ case 1:
+ if (value.substr(0, cmp.length()) == cmp) return (int64_t) 1;
+ break;
+ case 2:
+ if (value.length() >= cmp.length() && value.substr(value.length() - cmp.length()) == cmp) return (int64_t) 1;
+ break;
+ default:
+ throw torrent::input_error("string comparison: internal error (unknown mode)");
+ }
+ }
+
+ return (int64_t) 0;
+}
+
+
torrent::Object cmd_array_at(rpc::target_type target, const torrent::Object::list_type& args) {
if (args.size() != 2) {
throw torrent::input_error("array.at takes at exactly two arguments!");
@@ -820,6 +1096,20 @@ torrent::Object cmd_system_has_methods(bool filter_public) {
}
+torrent::Object cmd_system_client_version_as_value() {
+ int64_t result = 0;
+ const char* pos = PACKAGE_VERSION;
+
+ while (*pos) {
+ result = 100 * result + strtol(pos, (char**)&pos, 10);
+ if (*pos && *pos != '.')
+ throw torrent::input_error("INTERNAL ERROR: Bad version " PACKAGE_VERSION);
+ if (*pos) ++pos;
+ }
+ return result;
+}
+
+
torrent::Object cmd_value(rpc::target_type target, const torrent::Object::list_type& args) {
if (args.size() < 1) {
throw torrent::input_error("'value' takes at least a number argument!");
@@ -1005,20 +1295,34 @@ void initialize_command_pyroscope() {
*/
#if RT_HEX_VERSION <= 0x000906
- // these are merged into 0.9.7+ mainline! (well, maybe, PRs are ignored)
+ // these are merged into 0.9.7+ mainline!
CMD2_ANY_STRING("system.env", _cxxstd_::bind(&cmd_system_env, _cxxstd_::placeholders::_2));
CMD2_ANY("ui.current_view", _cxxstd_::bind(&cmd_ui_current_view));
+#endif
+
+#if RT_HEX_VERSION <= 0x000907
+ // these are merged into 0.9.8+ mainline! (well, maybe, PRs are mostly ignored)
CMD2_ANY_LIST("system.random", &apply_random);
CMD2_ANY_LIST("d.multicall.filtered", _cxxstd_::bind(&d_multicall_filtered, _cxxstd_::placeholders::_2));
#endif
// string.* group
CMD2_ANY_LIST("string.len", &cmd_string_len);
+ CMD2_ANY_LIST("string.join", &cmd_string_join);
+ CMD2_ANY_LIST("string.split", &cmd_string_split);
CMD2_ANY_LIST("string.substr", &cmd_string_substr);
CMD2_ANY_LIST("string.contains", &cmd_string_contains);
CMD2_ANY_LIST("string.contains_i", &cmd_string_contains_i);
CMD2_ANY_LIST("string.map", &cmd_string_map);
CMD2_ANY_LIST("string.replace", &cmd_string_replace);
+ CMD2_ANY_LIST("string.equals", std::bind(&cmd_string_compare, 0, std::placeholders::_2));
+ CMD2_ANY_LIST("string.startswith", std::bind(&cmd_string_compare, 1, std::placeholders::_2));
+ CMD2_ANY_LIST("string.endswith", std::bind(&cmd_string_compare, 2, std::placeholders::_2));
+ CMD2_ANY_LIST("string.strip", std::bind(&cmd_string_strip, 0, std::placeholders::_2));
+ CMD2_ANY_LIST("string.lstrip", std::bind(&cmd_string_strip, -1, std::placeholders::_2));
+ CMD2_ANY_LIST("string.rstrip", std::bind(&cmd_string_strip, 1, std::placeholders::_2));
+ CMD2_ANY_LIST("string.lpad", std::bind(&cmd_string_pad, false, std::placeholders::_2));
+ CMD2_ANY_LIST("string.rpad", std::bind(&cmd_string_pad, true, std::placeholders::_2));
// array.* group
CMD2_ANY_LIST("array.at", &cmd_array_at);
@@ -1047,14 +1351,23 @@ void initialize_command_pyroscope() {
CMD2_ANY("system.has.list", _cxxstd_::bind(&cmd_system_has_list));
CMD2_ANY("system.has.private_methods", _cxxstd_::bind(&cmd_system_has_methods, false));
CMD2_ANY("system.has.public_methods", _cxxstd_::bind(&cmd_system_has_methods, true));
+ CMD2_ANY("system.client_version.as_value", _cxxstd_::bind(&cmd_system_client_version_as_value));
// d.custom.* extensions
CMD2_DL_LIST("d.custom.if_z", _cxxstd_::bind(&retrieve_d_custom_if_z,
_cxxstd_::placeholders::_1, _cxxstd_::placeholders::_2));
+ CMD2_DL_LIST("d.custom.set_if_z", _cxxstd_::bind(&cmd_d_custom_set_if_z,
+ _cxxstd_::placeholders::_1, _cxxstd_::placeholders::_2));
+ CMD2_DL_LIST("d.custom.erase", _cxxstd_::bind(&cmd_d_custom_erase,
+ _cxxstd_::placeholders::_1, _cxxstd_::placeholders::_2));
CMD2_DL_LIST("d.custom.keys", _cxxstd_::bind(&retrieve_d_custom_map,
_cxxstd_::placeholders::_1, true, _cxxstd_::placeholders::_2));
CMD2_DL_LIST("d.custom.items", _cxxstd_::bind(&retrieve_d_custom_map,
_cxxstd_::placeholders::_1, false, _cxxstd_::placeholders::_2));
+ CMD2_DL_STRING("d.custom.toggle", _cxxstd_::bind(&cmd_d_custom_toggle,
+ _cxxstd_::placeholders::_1, _cxxstd_::placeholders::_2));
+ CMD2_DL_STRING("d.custom.as_value", _cxxstd_::bind(&retrieve_d_custom_as_value,
+ _cxxstd_::placeholders::_1, _cxxstd_::placeholders::_2));
// Misc commands
CMD2_ANY_LIST("value", &cmd_value);
@@ -1069,6 +1382,7 @@ void initialize_command_pyroscope() {
CMD2_ANY_STRING("log.messages", _cxxstd_::bind(&cmd_log_messages, _cxxstd_::placeholders::_2));
CMD2_ANY_P("import.return", &cmd_import_return);
+ CMD2_ANY("do", _cxxstd_::bind(&cmd_do, _cxxstd_::placeholders::_1, _cxxstd_::placeholders::_2));
CMD2_DL("d.is_meta", _cxxstd_::bind(&torrent::DownloadInfo::is_meta_download,
_cxxstd_::bind(&core::Download::info, _cxxstd_::placeholders::_1)));
@@ -1078,4 +1392,5 @@ void initialize_command_pyroscope() {
add_capability("colors"); // not monochrome
add_capability("canvas_v2"); // new PS 1.1 canvas with fully dynamic columns
add_capability("collapsed-views"); // pre-collapsed views
+ add_capability("fixed-log-xmlrpc-close");
}