mirror of
https://github.com/rakshasa/rtorrent.git
synced 2026-08-15 22:52:31 +00:00
* 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:
@@ -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());
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user