* Add support for any number of custom download values identified by string keys.

d.set_custom=key,value
  d.get_custom=key (returns "" if not set)
  d.get_custom_throw=key (returns error if not set)

* With this patch, rtorrent will detect and complain about .torrent files with broken bencode representation (e.g. where the order of dictionary keys is not lexicographic).

* Choose a different poll type using the RTORRENT_POLL env. variable (if it's implemented), probably only useful as RTORRENT_POLL=select.

* Add the commands execute_capture and execute_capture_nothrow that work like their other counterparts but return the OUTPUT (stdout) of the given command.

  Note that the output is not modified in any way, in particular a trailing newline is NOT removed. To work around this, have the command write its output without it e.g. using echo -n. Also note that with execute_capture_nothrow there is no way to check if the command failed.

  Example usage: d.set_custom4=$execute_capture=handler.sh

* When logging peer communication errors, show IP and peer ID to help debugging.

All patches above by Josef Drexler.


git-svn-id: svn://rakshasa.no/libtorrent/trunk/rtorrent@1088 e378c898-3ddf-0310-93e7-cc216c733640
This commit is contained in:
rakshasa
2009-05-13 09:39:00 +00:00
parent 6753b45627
commit 3c670a7add
6 changed files with 113 additions and 11 deletions
+40
View File
@@ -252,6 +252,42 @@ retrieve_d_local_id_html(core::Download* download) {
return torrent::Object(rak::copy_escape_html(hashString->begin(), hashString->end()));
}
torrent::Object
apply_d_custom(core::Download* download, const torrent::Object& rawArgs) {
torrent::Object::list_const_iterator itr = rawArgs.as_list().begin();
if (itr == rawArgs.as_list().end())
throw torrent::bencode_error("Missing key argument.");
const std::string& key = itr->as_string();
if (++itr == rawArgs.as_list().end())
throw torrent::bencode_error("Missing value argument.");
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
retrieve_d_custom(core::Download* download, const std::string& key) {
try {
return download->bencode()->get_key("rtorrent").get_key("custom").get_key_string(key);
} catch (torrent::bencode_error& e) {
return std::string();
}
}
torrent::Object
retrieve_d_custom_throw(core::Download* download, const std::string& key) {
try {
return download->bencode()->get_key("rtorrent").get_key("custom").get_key_string(key);
} catch (torrent::bencode_error& e) {
throw torrent::input_error("No such custom value.");
}
}
// Just a helper function atm.
torrent::Object
cmd_d_initialize_logs(core::Download* download) {
@@ -560,6 +596,10 @@ initialize_command_download() {
ADD_CD_VARIABLE_STRING_PUBLIC("custom4", "rtorrent", "custom4");
ADD_CD_VARIABLE_STRING_PUBLIC("custom5", "rtorrent", "custom5");
ADD_CD_SLOT_PUBLIC("d.set_custom", call_list, rak::ptr_fn(&apply_d_custom), "i:", "");
ADD_CD_SLOT_PUBLIC("d.get_custom", call_string, rpc::object_string_fn<core::Download*>(std::ptr_fun(&retrieve_d_custom)), "s:s", "");
ADD_CD_SLOT_PUBLIC("d.get_custom_throw", call_string, rpc::object_string_fn<core::Download*>(std::ptr_fun(&retrieve_d_custom_throw)), "s:s", "");
// 0 - stopped
// 1 - started
ADD_CD_VARIABLE_VALUE("state", "rtorrent", "state");
+2
View File
@@ -204,6 +204,8 @@ initialize_command_local() {
ADD_COMMAND_LIST("execute_nothrow", rak::bind2_mem_fn(&rpc::execFile, &rpc::ExecFile::execute_object, rpc::ExecFile::flag_expand_tilde));
ADD_COMMAND_LIST("execute_raw", rak::bind2_mem_fn(&rpc::execFile, &rpc::ExecFile::execute_object, rpc::ExecFile::flag_throw));
ADD_COMMAND_LIST("execute_raw_nothrow", rak::bind2_mem_fn(&rpc::execFile, &rpc::ExecFile::execute_object, 0));
ADD_COMMAND_LIST("execute_capture", rak::bind2_mem_fn(&rpc::execFile, &rpc::ExecFile::execute_object, rpc::ExecFile::flag_throw | rpc::ExecFile::flag_expand_tilde | rpc::ExecFile::flag_capture));
ADD_COMMAND_LIST("execute_capture_nothrow", rak::bind2_mem_fn(&rpc::execFile, &rpc::ExecFile::execute_object, rpc::ExecFile::flag_expand_tilde | rpc::ExecFile::flag_capture));
ADD_COMMAND_STRING_UN("execute_log", std::ptr_fun(&apply_execute_log));
+17 -1
View File
@@ -187,7 +187,23 @@ Manager::set_hashing_view(View* v) {
void
Manager::initialize_first() {
if ((m_pollManager = PollManagerEPoll::create(sysconf(_SC_OPEN_MAX))) != NULL)
const char* poll = getenv("RTORRENT_POLL");
if (poll != NULL) {
if (!strcmp(poll, "epoll"))
m_pollManager = PollManagerEPoll::create(sysconf(_SC_OPEN_MAX));
else if (!strcmp(poll, "kqueue"))
m_pollManager = PollManagerKQueue::create(sysconf(_SC_OPEN_MAX));
else if (!strcmp(poll, "select"))
m_pollManager = PollManagerSelect::create(sysconf(_SC_OPEN_MAX));
if (m_pollManager == NULL)
m_logImportant.push_front(std::string("Cannot enable '") + poll + "' based polling.");
}
if (m_pollManager != NULL)
m_logImportant.push_front(std::string("Using '") + poll + "' based polling.");
else if ((m_pollManager = PollManagerEPoll::create(sysconf(_SC_OPEN_MAX))) != NULL)
m_logImportant.push_front("Using 'epoll' based polling.");
else if ((m_pollManager = PollManagerKQueue::create(sysconf(_SC_OPEN_MAX))) != NULL)
+2 -2
View File
@@ -199,8 +199,8 @@ main(int argc, char** argv) {
"system.method.set_key = event.download.inserted_new, 1_prepare, \"branch=d.get_state=,view.set_visible=started,view.set_visible=stopped ;d.save_session=\"\n"
"system.method.set_key = event.download.inserted_session, 1_prepare, \"branch=d.get_state=,view.set_visible=started,view.set_visible=stopped\"\n"
"system.method.set_key = event.download.erased, 0_download_list, ui.unfocus_download=\n"
"system.method.set_key = event.download.erased, 9_delete_tied, d.delete_tied=\n"
"system.method.set_key = event.download.erased, !_download_list, ui.unfocus_download=\n"
"system.method.set_key = event.download.erased, ~_delete_tied, d.delete_tied=\n"
"system.method.insert = ratio.enable, simple|static|const,group.seeding.ratio.enable=\n"
"system.method.insert = ratio.disable,simple|static|const,group.seeding.ratio.disable=\n"
+49 -7
View File
@@ -36,6 +36,7 @@
#include "config.h"
#include <fcntl.h>
#include <string>
#include <unistd.h>
#include <rak/error_number.h>
@@ -51,7 +52,7 @@ namespace rpc {
// Close m_logFd.
int
ExecFile::execute(const char* file, char* const* argv) {
ExecFile::execute(const char* file, char* const* argv, int flags) {
// Write the execued command and its parameters to the log fd.
if (m_logFd != -1) {
for (char* const* itr = argv; *itr != NULL; itr++) {
@@ -66,20 +67,38 @@ ExecFile::execute(const char* file, char* const* argv) {
write(m_logFd, "\n---\n", sizeof("\n---\n"));
}
int pipeFd[2];
if ((flags & flag_capture) && pipe(pipeFd))
throw torrent::input_error("ExecFile::execute(...) Pipe creation failed.");
pid_t childPid = fork();
if (childPid == -1)
throw torrent::input_error("ExecFile::execute(...) Fork failed.");
if (childPid == 0) {
::close(0);
::close(1);
::close(2);
int devNull = open("/dev/null", O_RDWR);
if (devNull != -1)
dup2(devNull, 0);
else
::close(0);
if (m_logFd != -1) {
if (flags & flag_capture)
dup2(pipeFd[1], 1);
else if (m_logFd != -1)
dup2(m_logFd, 1);
else if (devNull != -1)
dup2(devNull, 1);
else
::close(1);
if (m_logFd != -1)
dup2(m_logFd, 2);
}
else if (devNull != -1)
dup2(devNull, 2);
else
::close(2);
// Close all fd's.
for (int i = 3, last = sysconf(_SC_OPEN_MAX); i != last; i++)
@@ -90,6 +109,26 @@ ExecFile::execute(const char* file, char* const* argv) {
_exit(result);
} else {
if (flags & flag_capture) {
m_capture = std::string();
::close(pipeFd[1]);
char buffer[4096];
ssize_t length;
do {
length = read(pipeFd[0], buffer, sizeof(buffer));
if (length > 0)
m_capture += std::string(buffer, length);
} while (length > 0);
if (m_logFd != -1) {
write(m_logFd, "Captured output:\n", sizeof("Captured output:\n"));
write(m_logFd, m_capture.data(), m_capture.length());
}
}
int status;
int wpid = waitpid(childPid, &status, 0);
@@ -143,11 +182,14 @@ ExecFile::execute_object(const torrent::Object& rawArgs, int flags) {
*argsCurrent = NULL;
int status = execute(argsBuffer[0], argsBuffer);
int status = execute(argsBuffer[0], argsBuffer, flags);
if ((flags & flag_throw) && status != 0)
throw torrent::input_error("Bad return code.");
if (flags & flag_capture)
return m_capture;
return torrent::Object((int64_t)status);
}
+3 -1
View File
@@ -48,18 +48,20 @@ public:
static const int flag_expand_tilde = 0x1;
static const int flag_throw = 0x2;
static const int flag_capture = 0x4;
ExecFile() : m_logFd(-1) {}
int log_fd() const { return m_logFd; }
void set_log_fd(int fd) { m_logFd = fd; }
int execute(const char* file, char* const* argv);
int execute(const char* file, char* const* argv, int flags);
torrent::Object execute_object(const torrent::Object& rawArgs, int flags);
private:
int m_logFd;
std::string m_capture;
};
}