* Allow inlining functions in commands with parantheses, e.g:

print = (convert.time,(system.time))
  schedule2 = test_print_2,2,2,((print,"current ",((convert.time,((system.time))))))

  Multiple parantheses need to be used in schedule to ensure the command doesn't get evaluated at the time of calling schedule.


git-svn-id: svn://rakshasa.no/libtorrent/trunk/rtorrent@1191 e378c898-3ddf-0310-93e7-cc216c733640
This commit is contained in:
rakshasa
2011-02-12 12:20:09 +00:00
parent 5691233bf1
commit 7b2fae35d5
12 changed files with 198 additions and 24 deletions
+50 -1
View File
@@ -57,6 +57,55 @@ system_method_generate_command(torrent::Object::list_const_iterator first, torre
return command;
}
void
system_method_generate_command2(torrent::Object* object, torrent::Object::list_const_iterator first, torrent::Object::list_const_iterator last) {
if (first == last) {
// TODO: Use empty object.
*object = "";
return;
}
if (first->is_string()) {
std::string command;
while (first != last) {
if (!command.empty())
command += " ;";
command += (first++)->as_string();
}
*object = command;
return;
}
if (first + 1 == last) {
if (!first->is_dict_key())
throw torrent::input_error("New command of wrong type.");
*object = *first;
uint32_t flags = object->flags() & torrent::Object::mask_function;
object->unset_flags(torrent::Object::mask_function);
object->set_flags((flags >> 1) & torrent::Object::mask_function);
} else {
*object = torrent::Object::create_list();
while (first != last) {
if (!first->is_dict_key())
throw torrent::input_error("New command of wrong type.");
object->as_list().push_back(*first++);
uint32_t flags = object->as_list().back().flags() & torrent::Object::mask_function;
object->as_list().back().unset_flags(torrent::Object::mask_function);
object->as_list().back().set_flags((flags >> 1) & torrent::Object::mask_function);
}
}
}
// torrent::Object
// system_method_insert_function(const torrent::Object::list_type& args, int flags) {
@@ -86,7 +135,7 @@ system_method_insert_object(const torrent::Object::list_type& args, int flags) {
value = itrArgs != args.end() ? rpc::convert_to_string(*itrArgs) : "";
break;
case rpc::object_storage::flag_function_type:
value = itrArgs != args.end() ? system_method_generate_command(itrArgs, args.end()) : "";
system_method_generate_command2(&value, itrArgs, args.end());
break;
case rpc::object_storage::flag_multi_type:
break;
+1 -2
View File
@@ -186,9 +186,8 @@ apply_schedule(const torrent::Object::list_type& args) {
const std::string& arg1 = (itr++)->as_string();
const std::string& arg2 = (itr++)->as_string();
const std::string& arg3 = (itr++)->as_string();
const std::string& arg4 = (itr++)->as_string();
control->command_scheduler()->parse(arg1, arg2, arg3, arg4);
control->command_scheduler()->parse(arg1, arg2, arg3, *itr);
return torrent::Object();
}
+10 -9
View File
@@ -212,9 +212,10 @@ main(int argc, char** argv) {
// "method.insert = test.value2,value,6\n"
// "method.insert = test.string,string,6\n"
// "method.insert = test.bool,bool,true\n"
// "method.insert = test.bool,bool,true\n"
"method.insert = test.method.simple,simple,\"print=simple_test_,$argument.0=\"\n"
// "method.insert.simple = test.method.simple,((print,simple_test_,$argument.0=))\n"
// "method.insert.simple = test.method.double,((print,simple_test_,$argument.0=)),\"print=simple_test_,$argument.1=\"\n"
"method.insert = event.download.inserted,multi\n"
"method.insert = event.download.inserted_new,multi\n"
@@ -239,8 +240,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.insert = group.insert_persistent_view,simple|const,"
"view.add=$argument.0=,view.persistent=$argument.0=,\"group.insert=$argument.0=,$argument.0=\"\n"
"method.insert.c_simple = group.insert_persistent_view,"
"((view.add,((argument.0)))),((view.persistent,((argument.0)))),((group.insert,((argument.0)),((argument.0))))\n"
// Allow setting 'group2.view' as constant, so that we can't
// modify the value. And look into the possibility of making
@@ -302,12 +303,12 @@ main(int argc, char** argv) {
"view.sort_new = seeding,less=d.state_changed=\n"
"view.sort_current = seeding,less=d.state_changed=\n"
"schedule2 = view.main,10,10,\"view.sort=main,20\"\n"
"schedule2 = view.name,10,10,\"view.sort=name,20\"\n"
"schedule2 = view.main,10,10,((view.sort,main,20))\n"
"schedule2 = view.name,10,10,((view.sort,name,20))\n"
"schedule2 = session_save,1200,1200,session.save=\n"
"schedule2 = low_diskspace,5,60,close_low_diskspace=500M\n"
"schedule2 = prune_file_status,3600,86400,system.file_status_cache.prune=\n"
"schedule2 = session_save,1200,1200,((session.save))\n"
"schedule2 = low_diskspace,5,60,((close_low_diskspace,500M))\n"
"schedule2 = prune_file_status,3600,86400,((system.file_status_cache.prune))\n"
"protocol.encryption.set=allow_incoming,prefer_plaintext,enable_retry\n"
);
+24 -3
View File
@@ -97,7 +97,22 @@ CommandScheduler::call_item(value_type item) {
// removed.
try {
rpc::parse_command_multiple_std(item->command());
if (item->command().is_string()) {
rpc::parse_command_multiple_std(item->command().as_string());
} else if (item->command().is_dict_key()) {
// This can/should be optimized...
torrent::Object tmp_command = item->command();
// Unquote the root function object so 'parse_command_execute'
// doesn't end up calling it.
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(rpc::make_target(), &tmp_command);
rpc::commands.call_command(tmp_command.as_dict_key().c_str(), tmp_command.as_dict_obj());
}
} catch (torrent::input_error& e) {
if (m_slotErrorMessage.is_valid())
@@ -119,13 +134,19 @@ CommandScheduler::call_item(value_type item) {
}
void
CommandScheduler::parse(const std::string& key, const std::string& bufAbsolute, const std::string& bufInterval, const std::string& command) {
CommandScheduler::parse(const std::string& key,
const std::string& bufAbsolute,
const std::string& bufInterval,
const torrent::Object& command) {
if (!command.is_string() && !command.is_dict_key())
throw torrent::bencode_error("Invalid type passed to command scheduler.");
uint32_t absolute = parse_absolute(bufAbsolute.c_str());
uint32_t interval = parse_interval(bufInterval.c_str());
CommandSchedulerItem* item = *insert(key);
item->set_command(command);
item->command() = command;
item->set_interval(interval);
item->enable((cachedTime + rak::timer::from_seconds(absolute)).round_seconds());
+6 -1
View File
@@ -42,6 +42,10 @@
#include <inttypes.h>
#include <rak/functional_fun.h>
namespace torrent {
class Object;
}
namespace rpc {
class CommandSchedulerItem;
@@ -71,7 +75,8 @@ public:
void erase(iterator itr);
void erase_str(const std::string& key) { erase(find(key)); }
void parse(const std::string& key, const std::string& bufAbsolute, const std::string& bufInterval, const std::string& command);
void parse(const std::string& key, const std::string& bufAbsolute,
const std::string& bufInterval, const torrent::Object& command);
static uint32_t parse_absolute(const char* str);
static uint32_t parse_interval(const char* str);
+4 -4
View File
@@ -39,6 +39,8 @@
#include "globals.h"
#include <torrent/object.h>
namespace rpc {
class CommandSchedulerItem {
@@ -54,9 +56,7 @@ public:
void disable();
const std::string& key() const { return m_key; }
const std::string& command() const { return m_command; }
void set_command(const std::string& s) { m_command = s; }
torrent::Object& command() { return m_command; }
// 'interval()' should in the future return some more dynamic values.
uint32_t interval() const { return m_interval; }
@@ -72,7 +72,7 @@ private:
void operator = (const CommandSchedulerItem&);
std::string m_key;
std::string m_command;
torrent::Object m_command;
uint32_t m_interval;
rak::timer m_timeScheduled;
+4 -3
View File
@@ -62,13 +62,14 @@ object_storage::insert(const char* key_data, uint32_t key_size, const torrent::O
// Check for size > key_size.
// Check for empty string.
bool use_raw = false;
torrent::Object object;
switch (flags & mask_type) {
case flag_bool_type: object = !!convert_to_value(rawObject); break;
case flag_value_type: object = convert_to_value(rawObject); break;
case flag_string_type: object = convert_to_string(rawObject); break;
case flag_function_type: object = convert_to_string(rawObject); break;
case flag_function_type: use_raw = true; break;
case flag_multi_type: object = torrent::Object::create_map(); break;
}
@@ -81,7 +82,7 @@ object_storage::insert(const char* key_data, uint32_t key_size, const torrent::O
throw torrent::input_error("Key already exists in object_storage.");
result.first->second.flags = flags;
result.first->second.object = object;
result.first->second.object = use_raw ? rawObject : object;
return result.first;
}
@@ -147,7 +148,7 @@ object_storage::call_function(const torrent::raw_string& key, target_type target
switch (itr->second.flags & mask_type) {
case flag_function_type:
return command_function_call_str(itr->second.object.as_string(), target, object);
return command_function_call_object(itr->second.object, target, object);
case flag_multi_type:
return command_function_multi_call(itr->second.object.as_map(), target, object);
default:
+37
View File
@@ -181,6 +181,43 @@ parse_object(const char* first, const char* last, torrent::Object* dest, bool (*
return ++first;
} else if (*first == '(') {
int32_t depth = 1;
while (first + 1 != last && *(first + 1) == '(') {
first++;
depth++;
}
if (depth > 3)
throw torrent::input_error("Max 3 parantheses per object allowed.");
*dest = torrent::Object::create_dict_key();
dest->set_flags(torrent::Object::flag_function << (depth - 1));
first = parse_string(first + 1, last, &dest->as_dict_key(), &parse_is_delim_func);
first = parse_skip_wspace(first, last);
if (first == last || !parse_is_delim_func(*first))
throw torrent::input_error("Could not find closing ')'.");
if (*first == ',') {
// This will always create a list even for single argument functions...
dest->as_dict_obj() = torrent::Object::create_list();
first = parse_list(first + 1, last, &dest->as_dict_obj(), &parse_is_delim_func);
first = parse_skip_wspace(first, last);
}
while (depth != 0 && first != last && *first == ')') {
first++;
depth--;
}
if (depth != 0)
throw torrent::input_error("Parantheses mismatch.");
return first;
} else {
*dest = std::string();
+1
View File
@@ -64,6 +64,7 @@ inline bool parse_is_delim_list(const char c) { return parse_is_seperator(c)
inline bool parse_is_delim_command(const char c) { return parse_is_seperator(c) || c == ';' || std::isspace(c); }
// inline bool parse_is_delim_block(const char c) { return c == ';' || c == '}'; }
inline bool parse_is_delim_block(const char c) { return parse_is_seperator(c) || c == '}'; }
inline bool parse_is_delim_func(const char c) { return parse_is_seperator(c) || c == ')'; }
const char* parse_skip_wspace(const char* first);
const char* parse_skip_wspace(const char* first, const char* last);
+55 -1
View File
@@ -93,7 +93,19 @@ parse_command_execute(target_type target, torrent::Object* object) {
parse_command_execute(target, &*itr);
}
} else if (*object->as_string().c_str() == '$') {
} else if (object->is_dict_key()) {
parse_command_execute(target, &object->as_dict_obj());
if (object->flags() & torrent::Object::flag_function) {
*object = rpc::commands.call_command(object->as_dict_key().c_str(), object->as_dict_obj(), target);
} else {
uint32_t flags = object->flags() & torrent::Object::mask_function;
object->unset_flags(torrent::Object::mask_function);
object->set_flags((flags >> 1) & torrent::Object::mask_function);
}
} else if (object->is_string() && *object->as_string().c_str() == '$') {
const std::string& str = object->as_string();
*object = parse_command(target, str.c_str() + 1, str.c_str() + str.size()).first;
@@ -252,6 +264,48 @@ command_function_call(const torrent::raw_string& cmd, target_type target, const
}
}
const torrent::Object
command_function_call_object(const torrent::Object& cmd, target_type target, const torrent::Object& args) {
rpc::command_base::stack_type stack;
torrent::Object* last_stack;
if (args.is_list())
last_stack = rpc::command_base::push_stack(args.as_list(), &stack);
else if (args.type() != torrent::Object::TYPE_NONE)
last_stack = rpc::command_base::push_stack(&args, &args + 1, &stack);
else
last_stack = rpc::command_base::push_stack(NULL, NULL, &stack);
try {
torrent::Object result;
if (cmd.is_string()) {
result = parse_command_multiple(target, cmd.as_string().c_str(), cmd.as_string().c_str() + cmd.as_string().size());
} else if (cmd.is_list()){
for (torrent::Object::list_const_iterator first = cmd.as_list().begin(), last = cmd.as_list().end(); first != last; first++) {
torrent::Object tmp_cmd = *first;
rpc::parse_command_execute(target, &tmp_cmd);
result = rpc::commands.call_command(tmp_cmd.as_dict_key().c_str(), tmp_cmd.as_dict_obj());
}
} 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());
}
rpc::command_base::pop_stack(&stack, last_stack);
return result;
} catch (torrent::bencode_error& e) {
rpc::command_base::pop_stack(&stack, last_stack);
throw e;
}
}
const torrent::Object
command_function_multi_call(const torrent::Object::map_type& cmd, target_type target, const torrent::Object& args) {
rpc::command_base::stack_type stack;
+4
View File
@@ -62,6 +62,8 @@ typedef std::pair<torrent::Object, const char*> parse_command_type;
parse_command_type parse_command(target_type target, const char* first, const char* last);
torrent::Object parse_command_multiple(target_type target, const char* first, const char* last);
void parse_command_execute(target_type target, torrent::Object* object);
// Make this take care of lists too.
parse_command_type parse_command_object(target_type target, const torrent::Object& object);
@@ -130,6 +132,8 @@ call_command_d_range(const char* key, core::Download* download, torrent::Object:
const torrent::Object
command_function_call(const torrent::raw_string& cmd, target_type target, const torrent::Object& args);
const torrent::Object
command_function_call_object(const torrent::Object& cmd, target_type target, const torrent::Object& args);
const torrent::Object
command_function_multi_call(const torrent::Object::map_type& cmd, target_type target, const torrent::Object& args);
inline const torrent::Object
+2
View File
@@ -56,6 +56,8 @@ ThreadWorker::ThreadWorker() {
}
ThreadWorker::~ThreadWorker() {
if (m_safe.scgi)
m_safe.scgi->deactivate();
}
void