* Use user-modifiable commands instead of slots for the 'on_*' events.

git-svn-id: svn://rakshasa.no/libtorrent/trunk/rtorrent@1070 e378c898-3ddf-0310-93e7-cc216c733640
This commit is contained in:
rakshasa
2008-10-01 14:19:51 +00:00
parent d7c2960d1e
commit 07b9616ef6
13 changed files with 332 additions and 139 deletions
+113 -15
View File
@@ -42,39 +42,74 @@
#include "control.h"
#include "command_helpers.h"
std::string
system_method_generate_command(torrent::Object::list_const_iterator first, torrent::Object::list_const_iterator last) {
std::string command;
while (first != last) {
if (!command.empty())
command += " ;";
command += (first++)->as_string();
}
return command;
}
// system.method.insert <generic> {name, "simple|private|const", ...}
// system.method.insert <generic> {name, "list|private|const"}
//
// Add a new user-defined method called 'name' and any number of
// lines.
torrent::Object
system_method_insert(__UNUSED rpc::target_type target, const torrent::Object& rawArgs) {
const torrent::Object::list_type& args = rawArgs.as_list();
// Allow arbritary number of args, just use what ever necessary in
// order to create a function blob out of them.
if (args.empty() || ++args.begin() == args.end())
throw torrent::input_error("Invalid argument count.");
if (args.empty())
return torrent::Object();
const std::string& rawKey = args.front().as_string();
torrent::Object::list_const_iterator itrArgs = args.begin();
const std::string& rawKey = (itrArgs++)->as_string();
if (rawKey.empty() || rpc::commands.has(rawKey))
throw torrent::input_error("Invalid key.");
std::string command;
rpc::Command* command = NULL;
rpc::Command::any_slot slot = NULL;
int flags = rpc::CommandMap::flag_delete_key | rpc::CommandMap::flag_modifiable | rpc::CommandMap::flag_public_xmlrpc;
for (torrent::Object::list_const_iterator itr = ++args.begin(), last = args.end(); itr != last; itr++) {
if (!command.empty())
command += " ;";
const std::string& options = itrArgs->as_string();
command += itr->as_string();
// Use a | separated list of options here, for non-modifable,
// non-public methods, etc.
if (options.find("list") != std::string::npos) {
// Later, make it possible to add functions here.
slot = &rpc::CommandFunctionList::call;
command = new rpc::CommandFunctionList();
} else if (options.find("simple") != std::string::npos) {
slot = &rpc::CommandFunction::call;
command = new rpc::CommandFunction(system_method_generate_command(++itrArgs, args.end()));
}
if (options.find("private") != std::string::npos)
flags &= ~rpc::CommandMap::flag_public_xmlrpc;
if (options.find("const") != std::string::npos)
flags &= ~rpc::CommandMap::flag_modifiable;
char* key = new char[rawKey.size() + 1];
std::memcpy(key, rawKey.c_str(), rawKey.size() + 1);
rpc::commands.insert_type(key, new rpc::CommandFunction(command), &rpc::CommandFunction::call,
rpc::CommandMap::flag_delete_key | rpc::CommandMap::flag_modifiable | rpc::CommandMap::flag_public_xmlrpc, NULL, NULL);
rpc::commands.insert_type(key, command, slot, flags, NULL, NULL);
return torrent::Object();
}
// system.method.erase <> {name}
//
// Erase a modifiable method called 'name. Trying to remove methods
// that aren't modifiable, e.g. defined by rtorrent or set to
// read-only by the user, will result in an error.
torrent::Object
system_method_erase(__UNUSED rpc::target_type target, const torrent::Object& rawArgs) {
rpc::CommandMap::iterator itr = rpc::commands.find(rawArgs.as_string().c_str());
@@ -90,8 +125,71 @@ system_method_erase(__UNUSED rpc::target_type target, const torrent::Object& raw
return torrent::Object();
}
torrent::Object
system_method_set(__UNUSED rpc::target_type target, const torrent::Object& rawArgs) {
const torrent::Object::list_type& args = rawArgs.as_list();
if (args.empty())
throw torrent::input_error("Invalid argument count.");
rpc::CommandFunction* function;
rpc::CommandMap::iterator itr = rpc::commands.find(args.front().as_string().c_str());
if (itr == rpc::commands.end() || !(itr->second.m_flags & rpc::CommandMap::flag_modifiable) ||
(function = dynamic_cast<rpc::CommandFunction*>(itr->second.m_variable)) == NULL)
throw torrent::input_error("Command not modifiable or wrong type.");
function->set_command(system_method_generate_command(++args.begin(), args.end()));
return torrent::Object();
}
torrent::Object
system_method_set_key(__UNUSED rpc::target_type target, const torrent::Object& rawArgs) {
const torrent::Object::list_type& args = rawArgs.as_list();
if (args.empty() || ++args.begin() == args.end())
throw torrent::input_error("Invalid argument count.");
rpc::CommandFunctionList* function;
rpc::CommandMap::iterator itr = rpc::commands.find(args.front().as_string().c_str());
if (itr == rpc::commands.end() || !(itr->second.m_flags & rpc::CommandMap::flag_modifiable) ||
(function = dynamic_cast<rpc::CommandFunctionList*>(itr->second.m_variable)) == NULL)
throw torrent::input_error("Command not modifiable or wrong type.");
torrent::Object::list_const_iterator itrArgs = ++args.begin();
const std::string& key = (itrArgs++)->as_string();
if (itrArgs != args.end())
function->insert(key, system_method_generate_command(itrArgs, args.end()));
else
function->erase(key);
return torrent::Object();
}
torrent::Object
system_method_has_key(__UNUSED rpc::target_type target, const torrent::Object& rawArgs) {
const torrent::Object::list_type& args = rawArgs.as_list();
if (args.size() != 2)
throw torrent::input_error("Invalid argument count.");
rpc::CommandFunctionList* function;
rpc::CommandMap::iterator itr = rpc::commands.find(args.front().as_string().c_str());
if (itr == rpc::commands.end() ||
(function = dynamic_cast<rpc::CommandFunctionList*>(itr->second.m_variable)) == NULL)
throw torrent::input_error("Command is the wrong type.");
return torrent::Object((int64_t)(function->find(args.back().as_string().c_str()) != function->end()));
}
void
initialize_command_dynamic() {
CMD_G("system.method.insert", rak::ptr_fn(&system_method_insert));
CMD_G("system.method.insert", rak::ptr_fn(&system_method_insert));
CMD_G_STRING("system.method.erase", rak::ptr_fn(&system_method_erase));
CMD_G("system.method.set", rak::ptr_fn(&system_method_set));
CMD_G("system.method.set_key", rak::ptr_fn(&system_method_set_key));
CMD_G("system.method.has_key", rak::ptr_fn(&system_method_has_key));
}
+26 -19
View File
@@ -59,7 +59,7 @@
#include "command_helpers.h"
torrent::Object
apply_on_state_change(core::DownloadList::slot_map* slotMap, const torrent::Object& rawArgs) {
apply_on_state_change(const char* name, const torrent::Object& rawArgs) {
const torrent::Object::list_type& args = rawArgs.as_list();
if (args.size() == 0 || args.size() > 2)
@@ -76,9 +76,18 @@ apply_on_state_change(core::DownloadList::slot_map* slotMap, const torrent::Obje
std::string key = rawKey[0] != '_' ? ("1_state_" + rawKey) : rawKey.substr(1);
if (args.size() == 1)
slotMap->erase(key);
rpc::commands.call("system.method.set_key", rpc::make_target(), rpc::create_object_list(name, key));
else
(*slotMap)[key] = args.back().as_string();
rpc::commands.call("system.method.set_key", rpc::make_target(), rpc::create_object_list(name, key, args.back()));
// Deprecated notice, remove this function in the next minor
// version.
static bool notify = true;
if (notify) {
control->core()->push_log("Deprecated on_* commands, use 'system.method.set_key = event.download.{inserted, erased, ...}, <key>, <command>' instead.");
notify = false;
}
return torrent::Object();
}
@@ -117,8 +126,8 @@ apply_on_ratio(int action, const torrent::Object& rawArgs) {
switch (action) {
// case core::DownloadList::SLOTS_CLOSE: success = downloadList->close_try(current); break;
// case core::DownloadList::SLOTS_STOP: success = downloadList->stop_try(current); break;
case core::DownloadList::SLOTS_CLOSE: rpc::parse_command_single(rpc::make_target(current), "d.try_close="); break;
case core::DownloadList::SLOTS_STOP: rpc::parse_command_single(rpc::make_target(current), "d.try_stop="); break;
case core::DownloadList::D_SLOTS_CLOSE: rpc::parse_command_single(rpc::make_target(current), "d.try_close="); break;
case core::DownloadList::D_SLOTS_STOP: rpc::parse_command_single(rpc::make_target(current), "d.try_stop="); break;
default: success = false; break;
}
@@ -341,26 +350,24 @@ d_multicall(const torrent::Object& rawArgs) {
void
initialize_command_events() {
core::DownloadList* downloadList = control->core()->download_list();
ADD_VARIABLE_BOOL("check_hash", true);
ADD_VARIABLE_BOOL("session_lock", true);
ADD_VARIABLE_BOOL("session_on_completion", true);
ADD_COMMAND_LIST("on_insert", rak::bind_ptr_fn(&apply_on_state_change, &downloadList->slot_map_insert()));
ADD_COMMAND_LIST("on_erase", rak::bind_ptr_fn(&apply_on_state_change, &downloadList->slot_map_erase()));
ADD_COMMAND_LIST("on_open", rak::bind_ptr_fn(&apply_on_state_change, &downloadList->slot_map_open()));
ADD_COMMAND_LIST("on_close", rak::bind_ptr_fn(&apply_on_state_change, &downloadList->slot_map_close()));
ADD_COMMAND_LIST("on_start", rak::bind_ptr_fn(&apply_on_state_change, &downloadList->slot_map_start()));
ADD_COMMAND_LIST("on_stop", rak::bind_ptr_fn(&apply_on_state_change, &downloadList->slot_map_stop()));
ADD_COMMAND_LIST("on_hash_queued", rak::bind_ptr_fn(&apply_on_state_change, &downloadList->slot_map_hash_queued()));
ADD_COMMAND_LIST("on_hash_removed", rak::bind_ptr_fn(&apply_on_state_change, &downloadList->slot_map_hash_removed()));
ADD_COMMAND_LIST("on_hash_done", rak::bind_ptr_fn(&apply_on_state_change, &downloadList->slot_map_hash_done()));
ADD_COMMAND_LIST("on_finished", rak::bind_ptr_fn(&apply_on_state_change, &downloadList->slot_map_finished()));
// Deprecated.
ADD_COMMAND_LIST("on_insert", rak::bind_ptr_fn(&apply_on_state_change, "event.download.inserted"));
ADD_COMMAND_LIST("on_erase" , rak::bind_ptr_fn(&apply_on_state_change, "event.download.erased"));
ADD_COMMAND_LIST("on_open", rak::bind_ptr_fn(&apply_on_state_change, "event.download.opened"));
ADD_COMMAND_LIST("on_close", rak::bind_ptr_fn(&apply_on_state_change, "event.download.closed"));
ADD_COMMAND_LIST("on_start", rak::bind_ptr_fn(&apply_on_state_change, "event.download.resumed"));
ADD_COMMAND_LIST("on_stop", rak::bind_ptr_fn(&apply_on_state_change, "event.download.paused"));
ADD_COMMAND_LIST("on_hash_queued", rak::bind_ptr_fn(&apply_on_state_change, "event.download.hash_queued"));
ADD_COMMAND_LIST("on_hash_removed", rak::bind_ptr_fn(&apply_on_state_change, "event.download.hash_removed"));
ADD_COMMAND_LIST("on_finished", rak::bind_ptr_fn(&apply_on_state_change, "event.download.finished"));
ADD_COMMAND_LIST("stop_on_ratio", rak::bind_ptr_fn(&apply_on_ratio, (int)core::DownloadList::SLOTS_STOP));
ADD_COMMAND_LIST("close_on_ratio", rak::bind_ptr_fn(&apply_on_ratio, (int)core::DownloadList::SLOTS_CLOSE));
ADD_COMMAND_LIST("stop_on_ratio", rak::bind_ptr_fn(&apply_on_ratio, (int)core::DownloadList::D_SLOTS_STOP));
ADD_COMMAND_LIST("close_on_ratio", rak::bind_ptr_fn(&apply_on_ratio, (int)core::DownloadList::D_SLOTS_CLOSE));
ADD_COMMAND_VOID("start_tied", &apply_start_tied);
ADD_COMMAND_VOID("stop_untied", &apply_stop_untied);
+27 -27
View File
@@ -72,19 +72,19 @@ DownloadList::check_contains(Download* d) {
#endif
}
struct download_list_call {
download_list_call(Download* d) : m_download(d) {}
// struct download_list_call {
// download_list_call(Download* d) : m_download(d) {}
void operator () (const DownloadList::slot_map::value_type& s) {
try {
rpc::parse_command_d_multiple_std(m_download, s.second);
} catch (torrent::input_error& e) {
control->core()->push_log((std::string("Download event action failed: ") + e.what()).c_str());
}
}
// void operator () (const DownloadList::slot_map::value_type& s) {
// try {
// rpc::parse_command_d_multiple_std(m_download, s.second);
// } catch (torrent::input_error& e) {
// control->core()->push_log((std::string("Download event action failed: ") + e.what()).c_str());
// }
// }
Download* m_download;
};
// Download* m_download;
// };
void
DownloadList::clear() {
@@ -171,7 +171,7 @@ DownloadList::insert(Download* download) {
std::for_each(control->view_manager()->begin(), control->view_manager()->end(), std::bind2nd(std::mem_fun(&View::insert), download));
std::for_each(control->view_manager()->begin(), control->view_manager()->end(), std::bind2nd(std::mem_fun(&View::filter_download), download));
std::for_each(slot_map_insert().begin(), slot_map_insert().end(), download_list_call(*itr));
rpc::commands.call_catch("event.download.inserted", rpc::make_target(*itr), torrent::Object(), "Download event action failed: ");
} catch (torrent::local_error& e) {
// Should perhaps relax this, just print an error and remove the
@@ -199,7 +199,7 @@ DownloadList::erase(iterator itr) {
control->core()->download_store()->remove(*itr);
std::for_each(slot_map_erase().begin(), slot_map_erase().end(), download_list_call(*itr));
rpc::commands.call_catch("event.download.erased", rpc::make_target(*itr), torrent::Object(), "Download event action failed: ");
std::for_each(control->view_manager()->begin(), control->view_manager()->end(), std::bind2nd(std::mem_fun(&View::erase), *itr));
torrent::download_remove(*(*itr)->download());
@@ -230,8 +230,7 @@ DownloadList::open_throw(Download* download) {
return;
download->download()->open(download->resume_flags());
std::for_each(slot_map_open().begin(), slot_map_open().end(), download_list_call(download));
rpc::commands.call_catch("event.download.opened", rpc::make_target(download), torrent::Object(), "Download event action failed: ");
}
void
@@ -294,8 +293,8 @@ DownloadList::close_throw(Download* download) {
if (!download->is_hash_failed() && rpc::call_command_value("d.get_hashing", rpc::make_target(download)) != Download::variable_hashing_stopped)
throw torrent::internal_error("DownloadList::close_throw(...) called but we're going into a hashing loop.");
std::for_each(slot_map_hash_removed().begin(), slot_map_hash_removed().end(), download_list_call(download));
std::for_each(slot_map_close().begin(), slot_map_close().end(), download_list_call(download));
rpc::commands.call_catch("event.download.hash_removed", rpc::make_target(download), torrent::Object(), "Download event action failed: ");
rpc::commands.call_catch("event.download.closed", rpc::make_target(download), torrent::Object(), "Download event action failed: ");
}
void
@@ -328,7 +327,7 @@ DownloadList::resume(Download* download, int flags) {
if (rpc::call_command_value("d.get_hashing", rpc::make_target(download)) == Download::variable_hashing_stopped)
rpc::call_command("d.set_hashing", Download::variable_hashing_initial, rpc::make_target(download));
std::for_each(slot_map_hash_queued().begin(), slot_map_hash_queued().end(), download_list_call(download));
rpc::commands.call_catch("event.download.hash_queued", rpc::make_target(download), torrent::Object(), "Download event action failed: ");
return;
}
@@ -361,7 +360,7 @@ DownloadList::resume(Download* download, int flags) {
download->set_resume_flags(~uint32_t());
std::for_each(slot_map_start().begin(), slot_map_start().end(), download_list_call(download));
rpc::commands.call_catch("event.download.resumed", rpc::make_target(download), torrent::Object(), "Download event action failed: ");
} catch (torrent::local_error& e) {
control->core()->push_log(e.what());
@@ -384,7 +383,7 @@ DownloadList::pause(Download* download, int flags) {
download->download()->hash_stop();
rpc::call_command_set_value("d.set_hashing", Download::variable_hashing_stopped, rpc::make_target(download));
std::for_each(slot_map_hash_removed().begin(), slot_map_hash_removed().end(), download_list_call(download));
rpc::commands.call_catch("event.download.hash_removed", rpc::make_target(download), torrent::Object(), "Download event action failed: ");
}
if (!download->download()->is_active())
@@ -396,7 +395,7 @@ DownloadList::pause(Download* download, int flags) {
// TODO: This is actually for pause, not stop... And doesn't get
// called when the download isn't active, but was in the 'started'
// view.
std::for_each(slot_map_stop().begin(), slot_map_stop().end(), download_list_call(download));
rpc::commands.call_catch("event.download.paused", rpc::make_target(download), torrent::Object(), "Download event action failed: ");
rpc::call_command("d.set_state_changed", cachedTime.seconds(), rpc::make_target(download));
rpc::call_command("d.set_state_counter", rpc::call_command_value("d.get_state_counter", rpc::make_target(download)), rpc::make_target(download));
@@ -441,7 +440,7 @@ DownloadList::hash_done(Download* download) {
if (!download->is_hash_checked()) {
download->set_hash_failed(true);
std::for_each(slot_map_hash_done().begin(), slot_map_hash_done().end(), download_list_call(download));
rpc::commands.call_catch("event.download.hash_done", rpc::make_target(download), torrent::Object(), "Download event action failed: ");
return;
}
@@ -497,7 +496,7 @@ DownloadList::hash_done(Download* download) {
return;
}
std::for_each(slot_map_hash_done().begin(), slot_map_hash_done().end(), download_list_call(download));
rpc::commands.call_catch("event.download.hash_done", rpc::make_target(download), torrent::Object(), "Download event action failed: ");
}
void
@@ -512,8 +511,9 @@ DownloadList::hash_queue(Download* download, int type) {
if (download->is_open()) {
pause(download, torrent::Download::stop_skip_tracker);
download->download()->close();
std::for_each(slot_map_hash_removed().begin(), slot_map_hash_removed().end(), download_list_call(download));
std::for_each(slot_map_close().begin(), slot_map_close().end(), download_list_call(download));
rpc::commands.call_catch("event.download.hash_removed", rpc::make_target(download), torrent::Object(), "Download event action failed: ");
rpc::commands.call_catch("event.download.closed", rpc::make_target(download), torrent::Object(), "Download event action failed: ");
}
torrent::resume_clear_progress(*download->download(), download->download()->bencode()->get_key("libtorrent_resume"));
@@ -526,7 +526,7 @@ DownloadList::hash_queue(Download* download, int type) {
// If any more stuff is added here, make sure resume etc are still
// correct.
std::for_each(slot_map_hash_queued().begin(), slot_map_hash_queued().end(), download_list_call(download));
rpc::commands.call_catch("event.download.hash_queued", rpc::make_target(download), torrent::Object(), "Download event action failed: ");
}
void
@@ -570,7 +570,7 @@ DownloadList::confirm_finished(Download* download) {
// up/downloaded baseline.
download->download()->tracker_list()->send_completed();
std::for_each(slot_map_finished().begin(), slot_map_finished().end(), download_list_call(download));
rpc::commands.call_catch("event.download.finished", rpc::make_target(download), torrent::Object(), "Download event action failed: ");
if (download->resume_flags() != ~uint32_t())
throw torrent::internal_error("DownloadList::confirm_finished(...) download->resume_flags() != ~uint32_t().");
+25 -55
View File
@@ -60,7 +60,6 @@ class Download;
class DownloadList : private std::list<Download*> {
public:
typedef std::list<Download*> base_type;
typedef std::map<std::string, std::string> slot_map;
using base_type::iterator;
using base_type::const_iterator;
@@ -115,40 +114,35 @@ public:
void check_hash(Download* d);
enum {
SLOTS_INSERT,
SLOTS_ERASE,
SLOTS_OPEN,
SLOTS_CLOSE,
SLOTS_START,
SLOTS_STOP,
SLOTS_HASH_QUEUED,
SLOTS_HASH_REMOVED,
SLOTS_HASH_DONE,
SLOTS_FINISHED,
D_SLOTS_INSERT,
D_SLOTS_ERASE,
D_SLOTS_OPEN,
D_SLOTS_CLOSE,
D_SLOTS_START,
D_SLOTS_STOP,
D_SLOTS_HASH_QUEUED,
D_SLOTS_HASH_REMOVED,
D_SLOTS_HASH_DONE,
D_SLOTS_FINISHED,
SLOTS_MAX_SIZE
};
slot_map& slots(int m) { return m_slotMaps[m]; }
const slot_map& slots(int m) const { return m_slotMaps[m]; }
slot_map* slot_map_begin() { return m_slotMaps; }
const slot_map* slot_map_begin() const { return m_slotMaps; }
slot_map* slot_map_end() { return m_slotMaps + SLOTS_MAX_SIZE; }
const slot_map* slot_map_end() const { return m_slotMaps + SLOTS_MAX_SIZE; }
slot_map& slot_map_insert() { return m_slotMaps[SLOTS_INSERT]; }
const slot_map& slot_map_insert() const { return m_slotMaps[SLOTS_INSERT]; }
slot_map& slot_map_erase() { return m_slotMaps[SLOTS_ERASE]; }
const slot_map& slot_map_erase() const { return m_slotMaps[SLOTS_ERASE]; }
slot_map& slot_map_open() { return m_slotMaps[SLOTS_OPEN]; }
const slot_map& slot_map_open() const { return m_slotMaps[SLOTS_OPEN]; }
slot_map& slot_map_close() { return m_slotMaps[SLOTS_CLOSE]; }
const slot_map& slot_map_close() const { return m_slotMaps[SLOTS_CLOSE]; }
slot_map& slot_map_start() { return m_slotMaps[SLOTS_START]; }
const slot_map& slot_map_start() const { return m_slotMaps[SLOTS_START]; }
slot_map& slot_map_stop() { return m_slotMaps[SLOTS_STOP]; }
const slot_map& slot_map_stop() const { return m_slotMaps[SLOTS_STOP]; }
static const char* slot_name(int m) {
switch(m) {
case D_SLOTS_INSERT: return "event.download.inserted";
case D_SLOTS_ERASE: return "event.download.erased";
case D_SLOTS_OPEN: return "event.download.opened";
case D_SLOTS_CLOSE: return "event.download.closed";
case D_SLOTS_START: return "event.download.resumed";
case D_SLOTS_STOP: return "event.download.paused";
case D_SLOTS_HASH_QUEUED: return "event.download.hash_queued";
case D_SLOTS_HASH_REMOVED: return "event.download.hash_removed";
case D_SLOTS_HASH_DONE: return "event.download.hash_done";
case D_SLOTS_FINISHED: return "event.download.finished";
default: return "BORK";
}
}
// The finished slots will be called when an active download with
// "finished" == 0 performs a hash check which returns a done
@@ -158,28 +152,6 @@ public:
// Also we need to handle cases when a hashing torrent starts up
// after a shutdown.
slot_map& slot_map_hash_queued() { return m_slotMaps[SLOTS_HASH_QUEUED]; }
const slot_map& slot_map_hash_queued() const { return m_slotMaps[SLOTS_HASH_QUEUED]; }
slot_map& slot_map_hash_removed() { return m_slotMaps[SLOTS_HASH_REMOVED]; }
const slot_map& slot_map_hash_removed() const { return m_slotMaps[SLOTS_HASH_REMOVED]; }
slot_map& slot_map_hash_done() { return m_slotMaps[SLOTS_HASH_DONE]; }
const slot_map& slot_map_hash_done() const { return m_slotMaps[SLOTS_HASH_DONE]; }
slot_map& slot_map_finished() { return m_slotMaps[SLOTS_FINISHED]; }
const slot_map& slot_map_finished() const { return m_slotMaps[SLOTS_FINISHED]; }
bool has_slot_insert(const std::string& key) const { return slot_map_insert().find(key) != slot_map_insert().end(); }
bool has_slot_erase(const std::string& key) const { return slot_map_erase().find(key) != slot_map_erase().end(); }
bool has_slot_open(const std::string& key) const { return slot_map_open().find(key) != slot_map_open().end(); }
bool has_slot_close(const std::string& key) const { return slot_map_close().find(key) != slot_map_close().end(); }
bool has_slot_start(const std::string& key) const { return slot_map_start().find(key) != slot_map_start().end(); }
bool has_slot_stop(const std::string& key) const { return slot_map_stop().find(key) != slot_map_stop().end(); }
bool has_slot_hash_queued(const std::string& key) const{ return slot_map_hash_queued().find(key) != slot_map_hash_queued().end(); }
bool has_slot_hash_done(const std::string& key) const { return slot_map_hash_done().find(key) != slot_map_hash_done().end(); }
bool has_slot_finished(const std::string& key) const { return slot_map_finished().find(key) != slot_map_finished().end(); }
static void erase_key(slot_map& sm, const std::string& key) { sm.erase(key); }
private:
DownloadList(const DownloadList&);
void operator = (const DownloadList&);
@@ -191,8 +163,6 @@ private:
void received_finished(Download* d);
void confirm_finished(Download* d);
slot_map m_slotMaps[SLOTS_MAX_SIZE];
};
}
+2 -2
View File
@@ -213,8 +213,8 @@ Manager::initialize_second() {
// Register slots to be called when a download is inserted/erased,
// opened or closed.
m_downloadList->slot_map_insert()["1_connect_logs"] = "d.initialize_logs=";
m_downloadList->slot_map_erase()["9_delete_tied"] = "d.delete_tied=";
rpc::parse_command_single(rpc::make_target(), "system.method.set_key = event.download.inserted, 1_connect_logs, d.initialize_logs=");
rpc::parse_command_single(rpc::make_target(), "system.method.set_key = event.download.erased, 9_delete_tied, d.delete_tied=");
torrent::connection_manager()->set_signal_handshake_log(sigc::mem_fun(this, &Manager::handshake_log));
}
+12 -8
View File
@@ -116,9 +116,10 @@ View::~View() {
if (m_name.empty())
return;
std::for_each(control->core()->download_list()->slot_map_begin(), control->core()->download_list()->slot_map_end(),
rak::bind2nd(std::ptr_fun(&DownloadList::erase_key), "0_view_" + m_name));
for (int i = 0; i < DownloadList::SLOTS_MAX_SIZE; i++)
rpc::commands.call("system.method.set_key", rpc::make_target(),
rpc::create_object_list(control->core()->download_list()->slot_name(i), "0_view_" + m_name));
priority_queue_erase(&taskScheduler, &m_delayChanged);
}
@@ -133,7 +134,8 @@ View::initialize(const std::string& name) {
std::string key = "0_view_" + name;
core::DownloadList* dlist = control->core()->download_list();
if (dlist->has_slot_insert(key) || dlist->has_slot_erase(key))
if (rpc::commands.call("system.method.has_key", rpc::make_target(), rpc::create_object_list("event.download.inserted", key)).as_value() ||
rpc::commands.call("system.method.has_key", rpc::make_target(), rpc::create_object_list("event.download.erased", key)).as_value())
throw torrent::internal_error("View::initialize(...) duplicate key name found in DownloadList.");
m_name = name;
@@ -296,18 +298,20 @@ View::filter_download(core::Download* download) {
void
View::set_filter_on(int event) {
if (event == DownloadList::SLOTS_INSERT || event == DownloadList::SLOTS_ERASE || event >= DownloadList::SLOTS_MAX_SIZE)
if (event == DownloadList::D_SLOTS_INSERT || event == DownloadList::D_SLOTS_ERASE || event >= DownloadList::SLOTS_MAX_SIZE)
throw torrent::internal_error("View::filter_on(...) invalid event.");
control->core()->download_list()->slots(event)["0_view_" + m_name] = "view.filter_download=" + m_name;
rpc::commands.call("system.method.set_key", rpc::make_target(),
rpc::create_object_list(control->core()->download_list()->slot_name(event), "0_view_" + m_name, "view.filter_download=" + m_name));
}
void
View::clear_filter_on() {
// Don't clear insert and erase as these are required to keep the
// View up-to-date with the available downloads.
std::for_each(control->core()->download_list()->slot_map_begin() + DownloadList::SLOTS_OPEN, control->core()->download_list()->slot_map_end(),
rak::bind2nd(std::ptr_fun(&DownloadList::erase_key), "0_view_" + m_name));
for (int i = DownloadList::D_SLOTS_OPEN; i < DownloadList::SLOTS_MAX_SIZE; i++)
rpc::commands.call("system.method.set_key", rpc::make_target(),
rpc::create_object_list(control->core()->download_list()->slot_name(i), "0_view_" + m_name));
}
inline void
+6 -6
View File
@@ -115,22 +115,22 @@ ViewManager::set_filter_on(const std::string& name, const filter_args& args) {
for (filter_args::const_iterator itr = args.begin(); itr != args.end(); ++itr) {
if (*itr == "start")
(*viewItr)->set_filter_on(DownloadList::SLOTS_START);
(*viewItr)->set_filter_on(DownloadList::D_SLOTS_START);
else if (*itr == "stop")
(*viewItr)->set_filter_on(DownloadList::SLOTS_STOP);
(*viewItr)->set_filter_on(DownloadList::D_SLOTS_STOP);
else if (*itr == "hash_queued")
(*viewItr)->set_filter_on(DownloadList::SLOTS_HASH_QUEUED);
(*viewItr)->set_filter_on(DownloadList::D_SLOTS_HASH_QUEUED);
else if (*itr == "hash_removed")
(*viewItr)->set_filter_on(DownloadList::SLOTS_HASH_REMOVED);
(*viewItr)->set_filter_on(DownloadList::D_SLOTS_HASH_REMOVED);
else if (*itr == "hash_done")
(*viewItr)->set_filter_on(DownloadList::SLOTS_HASH_DONE);
(*viewItr)->set_filter_on(DownloadList::D_SLOTS_HASH_DONE);
else if (*itr == "finished")
(*viewItr)->set_filter_on(DownloadList::SLOTS_FINISHED);
(*viewItr)->set_filter_on(DownloadList::D_SLOTS_FINISHED);
else
throw torrent::input_error("Invalid filter on identifier.");
+14 -2
View File
@@ -171,8 +171,20 @@ main(int argc, char** argv) {
// torrent::ConnectionManager* are valid etc.
initialize_commands();
rpc::parse_command_multiple(rpc::make_target(),
// "set_name = $cat={$system.hostname=,:,$system.pid=}\n"
rpc::parse_command_multiple
(rpc::make_target(),
"system.method.insert = event.download.inserted,list\n"
"system.method.insert = event.download.erased,list\n"
"system.method.insert = event.download.opened,list\n"
"system.method.insert = event.download.closed,list\n"
"system.method.insert = event.download.resumed,list\n"
"system.method.insert = event.download.paused,list\n"
"system.method.insert = event.download.finished,list\n"
"system.method.insert = event.download.hash_done,list\n"
"system.method.insert = event.download.hash_removed,list\n"
"system.method.insert = event.download.hash_queued,list\n"
"set_name = \"$cat=$system.hostname=,:,$system.pid=\"\n"
// Currently not doing any sorting on main.
+42
View File
@@ -36,6 +36,10 @@
#include "config.h"
#include <algorithm>
#include <functional>
#include <rak/functional.h>
#include "parse.h"
#include "parse_commands.h"
#include "command_function.h"
@@ -51,4 +55,42 @@ CommandFunction::call(Command* rawCommand, target_type target, const torrent::Ob
return torrent::Object();
}
const torrent::Object
CommandFunctionList::call(Command* rawCommand, target_type target, const torrent::Object& args) {
CommandFunctionList* command = reinterpret_cast<CommandFunctionList*>(rawCommand);
for (base_type::const_iterator itr = command->begin(), last = command->end(); itr != last; itr++)
parse_command_multiple(target, itr->second.c_str(), itr->second.c_str() + itr->second.size());
return torrent::Object();
}
CommandFunctionList::const_iterator
CommandFunctionList::find(const char* key) {
base_type::iterator itr = std::find_if(begin(), end(), rak::greater_equal(key, rak::mem_ref(&base_type::value_type::first)));
if (itr == end() || itr->first != key)
return end();
else
return itr;
}
void
CommandFunctionList::insert(const std::string& key, const std::string& cmd) {
base_type::iterator itr = std::find_if(begin(), end(), rak::greater_equal(key, rak::mem_ref(&base_type::value_type::first)));
if (itr != end() && itr->first == key)
itr->second = cmd;
else
base_type::insert(itr, base_type::value_type(key, cmd));
}
void
CommandFunctionList::erase(const std::string& key) {
base_type::iterator itr = std::find_if(begin(), end(), rak::greater_equal(key, rak::mem_ref(&base_type::value_type::first)));
if (itr != end() && itr->first == key)
base_type::erase(itr);
}
}
+25 -3
View File
@@ -38,6 +38,7 @@
#define RTORRENT_RPC_COMMAND_FUNCTION_H
#include <string>
#include <vector>
#include <limits>
#include <inttypes.h>
#include <torrent/object.h>
@@ -50,14 +51,35 @@ class CommandFunction : public Command {
public:
CommandFunction(const std::string& cmd = std::string()) : m_command(cmd) {}
const std::string& command() const { return m_command; }
void set_command(const std::string& cmd) { m_command = cmd; }
const std::string& command() const { return m_command; }
void set_command(const std::string& cmd) { m_command = cmd; }
static const torrent::Object call(Command* rawCommand, target_type target, const torrent::Object& args);
private:
// TODO: Replace with a delete-me flag and const char*.
std::string m_command;
std::string m_command;
};
class CommandFunctionList : public Command,
private std::vector<std::pair<std::string, std::string> > {
public:
typedef std::vector<std::pair<std::string, std::string> > base_type;
using Command::value_type;
using base_type::iterator;
using base_type::const_iterator;
using base_type::begin;
using base_type::end;
CommandFunctionList() {}
const_iterator find(const char* key);
void insert(const std::string& key, const std::string& cmd);
void erase(const std::string& key);
static const torrent::Object call(Command* rawCommand, target_type target, const torrent::Object& args);
};
}
+15
View File
@@ -41,6 +41,11 @@
#include <torrent/object.h>
#include <torrent/data/file_list_iterator.h>
// Get better logging...
#include "globals.h"
#include "control.h"
#include "core/manager.h"
#include "command.h"
#include "command_map.h"
@@ -99,6 +104,16 @@ CommandMap::erase(iterator itr) {
delete [] key;
}
const CommandMap::mapped_type
CommandMap::call_catch(key_type key, target_type target, const mapped_type& args, const char* err) {
try {
return call_command(key, args, target);
} catch (torrent::input_error& e) {
control->core()->push_log((err + std::string(e.what())).c_str());
return torrent::Object();
}
}
const CommandMap::mapped_type
CommandMap::call_command(key_type key, const mapped_type& arg, target_type target) {
const_iterator itr = base_type::find(key);
+24 -1
View File
@@ -62,7 +62,7 @@ struct command_map_data_type {
int target() const { return m_target; }
Command* m_variable;
Command* m_variable;
union {
Command::cleaned_slot m_genericSlot;
@@ -124,6 +124,9 @@ public:
void insert(key_type key, const command_map_data_type src);
void erase(iterator itr);
const mapped_type call(key_type key, target_type target, const mapped_type& args = mapped_type()) { return call_command(key, args, target); }
const mapped_type call_catch(key_type key, target_type target, const mapped_type& args = mapped_type(), const char* err = "Command failed: ");
const mapped_type call_command (key_type key, const mapped_type& arg, target_type target = target_type((int)Command::target_generic, NULL));
const mapped_type call_command (const_iterator itr, const mapped_type& arg, target_type target = target_type((int)Command::target_generic, NULL));
@@ -151,6 +154,26 @@ inline target_type make_target_pair(T target1, T target2) {
return target_type((int)target_type_id<T, T>::value, target1, target2);
}
// TODO: Helper-functions that really should be in the
// torrent/object.h header.
inline torrent::Object
create_object_list(const torrent::Object& o1, const torrent::Object& o2) {
torrent::Object tmp = torrent::Object::create_list();
tmp.as_list().push_back(o1);
tmp.as_list().push_back(o2);
return tmp;
}
inline torrent::Object
create_object_list(const torrent::Object& o1, const torrent::Object& o2, const torrent::Object& o3) {
torrent::Object tmp = torrent::Object::create_list();
tmp.as_list().push_back(o1);
tmp.as_list().push_back(o2);
tmp.as_list().push_back(o3);
return tmp;
}
}
#endif
+1 -1
View File
@@ -98,7 +98,7 @@ DownloadList::activate(display::Frame* frame, bool focus) {
m_frame = frame;
control->input()->push_back(&m_bindings);
control->core()->download_list()->slot_map_erase()["0_download_list"] = "ui.unfocus_download=";
rpc::commands.call("system.method.set_key", rpc::make_target(), rpc::create_object_list("event.download.erased", "0_download_list", "ui.unfocus_download="));
activate_display(DISPLAY_DOWNLOAD_LIST);
}