* Fixed more redirected commands.

* Cleaned up the Command stack implementation.

* Added framework for object_storage class that will hold variables and user-defined command lists.


git-svn-id: svn://rakshasa.no/libtorrent/trunk/rtorrent@1162 e378c898-3ddf-0310-93e7-cc216c733640
This commit is contained in:
rakshasa
2010-04-11 14:19:27 +00:00
parent 856228da3d
commit 74bae32243
15 changed files with 276 additions and 140 deletions
+30 -17
View File
@@ -109,10 +109,22 @@ system_method_insert(const torrent::Object::list_type& args) {
rpc::commands.insert_type(create_new_key<0>(rawKey, ""), command, slot, flags, NULL, NULL);
} else if (options.find("simple") != std::string::npos) {
rpc::Command::any_slot slot = &rpc::CommandFunction::call;
rpc::Command* command = new rpc::CommandFunction(system_method_generate_command(++itrArgs, args.end()));
rpc::command_base* command = new rpc::command_base();
rpc::commands.insert_type(create_new_key<0>(rawKey, ""), command, slot, flags, NULL, NULL);
command->set_function<rpc::command_base_is_type
<rpc::command_base_call
<rpc::target_type> >::type>(std::tr1::bind(&rpc::command_function_call_str,
system_method_generate_command(++itrArgs, args.end()),
std::tr1::placeholders::_1,
std::tr1::placeholders::_2));
rpc::commands.insert_type(create_new_key<0>(rawKey, ""), command, &rpc::command_base_call<rpc::target_type>,
flags, NULL, NULL);
// rpc::Command::any_slot slot = &rpc::CommandFunction::call;
// rpc::Command* command = new rpc::CommandFunction(system_method_generate_command(++itrArgs, args.end()));
// rpc::commands.insert_type(create_new_key<0>(rawKey, ""), command, slot, flags, NULL, NULL);
} else if (options.find("value") != std::string::npos ||
options.find("bool") != std::string::npos ||
@@ -197,29 +209,30 @@ system_method_redirect(const torrent::Object::list_type& args) {
torrent::Object
system_method_get(const torrent::Object::string_type& args) {
rpc::CommandFunction* function;
rpc::CommandMap::iterator itr = rpc::commands.find(args.c_str());
// rpc::CommandFunction* function;
// rpc::CommandMap::iterator itr = rpc::commands.find(args.c_str());
if (itr == rpc::commands.end() ||
(function = dynamic_cast<rpc::CommandFunction*>(itr->second.m_variable)) == NULL)
throw torrent::input_error("Command not modifiable or wrong type.");
// if (itr == rpc::commands.end() ||
// (function = dynamic_cast<rpc::CommandFunction*>(itr->second.m_variable)) == NULL)
// throw torrent::input_error("Command not modifiable or wrong type.");
return torrent::Object(function->command());
// return torrent::Object(function->command());
return torrent::Object();
}
torrent::Object
system_method_set(const torrent::Object::list_type& args) {
if (args.empty())
throw torrent::input_error("Invalid argument count.");
// 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());
// rpc::CommandFunction* function;
// rpc::CommandMap::iterator itr = rpc::commands.find(args.front().as_string().c_str());
if (itr == rpc::commands.end() || !rpc::commands.is_modifiable(itr) ||
(function = dynamic_cast<rpc::CommandFunction*>(itr->second.m_variable)) == NULL)
throw torrent::input_error("Command not modifiable or wrong type.");
// if (itr == rpc::commands.end() || !rpc::commands.is_modifiable(itr) ||
// (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()));
// function->set_command(system_method_generate_command(++args.begin(), args.end()));
return torrent::Object();
}
+1 -1
View File
@@ -341,5 +341,5 @@ initialize_command_events() {
CMD2_ANY_VALUE ("close_low_diskspace", std::tr1::bind(&apply_close_low_diskspace, std::tr1::placeholders::_2));
CMD2_ANY_LIST ("download_list", std::tr1::bind(&apply_download_list, std::tr1::placeholders::_2));
CMD2_ANY_LIST ("d.multicall", std::tr1::bind(&d_multicall, std::tr1::placeholders::_2));
CMD2_ANY_LIST ("d.multicall2", std::tr1::bind(&d_multicall, std::tr1::placeholders::_2));
}
+4 -5
View File
@@ -71,12 +71,11 @@ void initialize_commands();
rpc::commands.insert_type(key, commandNewSlotItr++, &rpc::function, \
rpc::CommandMap::flag_dont_delete, NULL, NULL);
// #define CMD2_ANY(key, slot) CMD2_A_FUNCTION(key, command_base_call_any, slot, "i:", "")
#define CMD2_ANY(key, slot) CMD2_A_FUNCTION(key, command_base_call<rpc::target_type>, slot, "i:", "")
#define CMD2_ANY(key, slot) CMD2_A_FUNCTION(key, command_base_call<rpc::target_type>, slot, "i:", "")
#define CMD2_ANY_P(key, slot) CMD2_A_FUNCTION_PRIVATE(key, command_base_call<rpc::target_type>, slot, "i:", "")
#define CMD2_ANY_V(key, slot) CMD2_A_FUNCTION(key, command_base_call_list<rpc::target_type>, object_convert_void(slot), "i:", "")
#define CMD2_ANY_L(key, slot) CMD2_A_FUNCTION(key, command_base_call_list<rpc::target_type>, slot, "A:", "")
#define CMD2_ANY_P(key, slot) CMD2_A_FUNCTION_PRIVATE(key, command_base_call<rpc::target_type>, slot, "i:", "")
#define CMD2_ANY_V(key, slot) CMD2_A_FUNCTION(key, command_base_call_list<rpc::target_type>, object_convert_void(slot), "i:", "")
#define CMD2_ANY_L(key, slot) CMD2_A_FUNCTION(key, command_base_call_list<rpc::target_type>, slot, "A:", "")
#define CMD2_ANY_VALUE(key, slot) CMD2_A_FUNCTION(key, command_base_call_value<rpc::target_type>, slot, "i:i", "")
#define CMD2_ANY_VALUE_V(key, slot) CMD2_A_FUNCTION(key, command_base_call_value<rpc::target_type>, object_convert_void(slot), "i:i", "")
+2 -2
View File
@@ -240,8 +240,8 @@ initialize_command_local() {
CMD2_ANY("execute_capture", std::tr1::bind(&rpc::ExecFile::execute_object, &rpc::execFile, std::tr1::placeholders::_2, rpc::ExecFile::flag_throw | rpc::ExecFile::flag_expand_tilde | rpc::ExecFile::flag_capture));
CMD2_ANY("execute_capture_nothrow", std::tr1::bind(&rpc::ExecFile::execute_object, &rpc::execFile, std::tr1::placeholders::_2, rpc::ExecFile::flag_expand_tilde | rpc::ExecFile::flag_capture));
CMD2_ANY_STRING("log.execute", std::tr1::bind(&apply_log, std::tr1::placeholders::_2, 0));
CMD2_ANY_STRING("log.xmlrpc", std::tr1::bind(&apply_log, std::tr1::placeholders::_2, 1));
CMD2_ANY_STRING ("log.execute", std::tr1::bind(&apply_log, std::tr1::placeholders::_2, 0));
CMD2_ANY_STRING_V("log.xmlrpc", std::tr1::bind(&ThreadWorker::set_xmlrpc_log, worker_thread, std::tr1::placeholders::_2));
// TODO: Convert to new command types:
*rpc::Command::argument(0) = "placeholder.0";
+3
View File
@@ -611,6 +611,9 @@ main(int argc, char** argv) {
CMD2_REDIRECT ("view_sort_current", "view.sort_current");
CMD2_REDIRECT ("view_sort_new", "view.sort_new");
// Rename these to avoid conflicts with old style.
CMD2_REDIRECT_GENERIC("d.multicall", "d.multicall2");
// Functions that might not get depracted as they are nice for
// configuration files, and thus might do with just some
// cleanup.
+2
View File
@@ -19,6 +19,8 @@ libsub_rpc_a_SOURCES = \
command_new_slot.h \
exec_file.cc \
exec_file.h \
object_storage.cc \
object_storage.h \
parse.cc \
parse.h \
parse_commands.cc \
+1
View File
@@ -157,6 +157,7 @@ public:
static torrent::Object* stack_end() { return current_stack.end(); }
static torrent::Object* push_stack(const torrent::Object::list_type& args, stack_type* stack);
static torrent::Object* push_stack(const torrent::Object* first_arg, const torrent::Object* last_arg, stack_type* stack);
static void pop_stack(stack_type* stack, torrent::Object* last_stack);
protected:
+20 -94
View File
@@ -49,105 +49,39 @@ namespace rpc {
// Temp until it can be moved somewhere better...
const torrent::Object
command_function_call(const torrent::raw_string& cmd, target_type target, const torrent::Object& args) {
char* buffer[sizeof(torrent::Object) * Command::max_arguments];
torrent::Object* stack = (torrent::Object*)buffer;
torrent::Object* first = (torrent::Object*)buffer;
rpc::Command::stack_type stack;
torrent::Object* last_stack;
if (args.is_list()) {
// Do nothing for now.
for (torrent::Object::list_const_iterator itr = args.as_list().begin(), last = args.as_list().end();
itr != last && first != stack + Command::max_arguments;
itr++, first++) {
new (first) torrent::Object(*itr);
first->swap(*Command::argument(std::distance(stack, first)));
}
} else if (args.type() != torrent::Object::TYPE_NONE) {
new (first) torrent::Object(args);
(first++)->swap(*Command::argument(0));
}
if (args.is_list())
last_stack = rpc::Command::push_stack(args.as_list(), &stack);
else if (args.type() != torrent::Object::TYPE_NONE)
last_stack = rpc::Command::push_stack(&args, &args + 1, &stack);
else
last_stack = rpc::Command::push_stack(NULL, NULL, &stack);
try {
torrent::Object result = parse_command_multiple(target, cmd.begin(), cmd.end());
while (first-- != stack) {
first->swap(*Command::argument(std::distance(stack, first)));
first->~Object();
}
rpc::Command::pop_stack(&stack, last_stack);
return result;
} catch (torrent::bencode_error& e) {
while (first-- != stack) {
first->swap(*Command::argument(std::distance(stack, first)));
first->~Object();
}
throw e;
}
}
const torrent::Object
CommandFunction::call(Command* rawCommand, target_type target, const torrent::Object& args) {
char* buffer[sizeof(torrent::Object) * Command::max_arguments];
torrent::Object* stack = (torrent::Object*)buffer;
torrent::Object* first = (torrent::Object*)buffer;
if (args.is_list()) {
// Do nothing for now.
for (torrent::Object::list_const_iterator itr = args.as_list().begin(), last = args.as_list().end();
itr != last && first != stack + Command::max_arguments;
itr++, first++) {
new (first) torrent::Object(*itr);
first->swap(*argument(std::distance(stack, first)));
}
} else if (args.type() != torrent::Object::TYPE_NONE) {
new (first) torrent::Object(args);
(first++)->swap(*argument(0));
}
CommandFunction* command = reinterpret_cast<CommandFunction*>(rawCommand);
try {
torrent::Object result = parse_command_multiple(target, command->m_command.c_str(), command->m_command.c_str() + command->m_command.size());
while (first-- != stack) {
first->swap(*argument(std::distance(stack, first)));
first->~Object();
}
return result;
} catch (torrent::bencode_error& e) {
while (first-- != stack) {
first->swap(*Command::argument(std::distance(stack, first)));
first->~Object();
}
rpc::Command::pop_stack(&stack, last_stack);
throw e;
}
}
const torrent::Object
CommandFunctionList::call(Command* rawCommand, target_type target, const torrent::Object& args) {
char* buffer[sizeof(torrent::Object) * Command::max_arguments];
torrent::Object* stack = (torrent::Object*)buffer;
torrent::Object* first = (torrent::Object*)buffer;
rpc::Command::stack_type stack;
torrent::Object* last_stack;
if (args.is_list()) {
// Do nothing for now.
for (torrent::Object::list_const_iterator itr = args.as_list().begin(), last = args.as_list().end();
itr != last && first != stack + Command::max_arguments;
itr++, first++) {
new (first) torrent::Object(*itr);
first->swap(*argument(std::distance(stack, first)));
}
} else if (args.type() != torrent::Object::TYPE_NONE) {
new (first) torrent::Object(args);
(first++)->swap(*argument(0));
}
if (args.is_list())
last_stack = rpc::Command::push_stack(args.as_list(), &stack);
else if (args.type() != torrent::Object::TYPE_NONE)
last_stack = rpc::Command::push_stack(&args, &args + 1, &stack);
else
last_stack = rpc::Command::push_stack(NULL, NULL, &stack);
CommandFunctionList* command = reinterpret_cast<CommandFunctionList*>(rawCommand);
@@ -156,19 +90,11 @@ CommandFunctionList::call(Command* rawCommand, target_type target, const torrent
parse_command_multiple(target, itr->second.c_str(), itr->second.c_str() + itr->second.size());
} catch (torrent::bencode_error& e) {
while (first-- != stack) {
first->swap(*Command::argument(std::distance(stack, first)));
first->~Object();
}
rpc::Command::pop_stack(&stack, last_stack);
throw e;
}
while (first-- != stack) {
first->swap(*argument(std::distance(stack, first)));
first->~Object();
}
rpc::Command::pop_stack(&stack, last_stack);
return torrent::Object();
}
+5 -14
View File
@@ -47,20 +47,6 @@
namespace rpc {
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; }
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;
};
class CommandFunctionList : public Command,
private std::vector<std::pair<std::string, std::string> > {
public:
@@ -86,6 +72,11 @@ public:
const torrent::Object
command_function_call(const torrent::raw_string& cmd, target_type target, const torrent::Object& args);
inline const torrent::Object
command_function_call_str(const std::string& cmd, target_type target, const torrent::Object& args) {
return command_function_call(torrent::raw_string::from_string(cmd), target, args);
}
}
#endif
+10 -4
View File
@@ -77,18 +77,24 @@ get_target_cast<torrent::File*>(target_type target, int type) {
}
inline torrent::Object*
Command::push_stack(const torrent::Object::list_type& args, stack_type* stack) {
Command::push_stack(const torrent::Object* first_arg, const torrent::Object* last_arg, stack_type* stack) {
unsigned int idx = 0;
for (torrent::Object::list_const_iterator itr = args.begin(), last = args.end();
itr != last && idx < Command::max_arguments; itr++, idx++) {
new (&(*stack)[idx]) torrent::Object(*itr);
while (first_arg != last_arg && idx < Command::max_arguments) {
new (&(*stack)[idx]) torrent::Object(*first_arg++);
(*stack)[idx].swap(*Command::argument(idx));
idx++;
}
return stack->begin() + idx;
}
inline torrent::Object*
Command::push_stack(const torrent::Object::list_type& args, stack_type* stack) {
return push_stack(args.data(), args.data() + args.size(), stack);
}
inline void
Command::pop_stack(stack_type* stack, torrent::Object* last_stack) {
while (last_stack-- != stack->begin()) {
+43
View File
@@ -0,0 +1,43 @@
// rTorrent - BitTorrent client
// Copyright (C) 2005-2007, Jari Sundell
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// In addition, as a special exception, the copyright holders give
// permission to link the code of portions of this program with the
// OpenSSL library under certain conditions as described in each
// individual source file, and distribute linked combinations
// including the two.
//
// You must obey the GNU General Public License in all respects for
// all of the code used other than OpenSSL. If you modify file(s)
// with this exception, you may extend this exception to your version
// of the file(s), but you are not obligated to do so. If you do not
// wish to do so, delete this exception statement from your version.
// If you delete this exception statement from all source files in the
// program, then also delete it here.
//
// Contact: Jari Sundell <jaris@ifi.uio.no>
//
// Skomakerveien 33
// 3185 Skoppum, NORWAY
#include "config.h"
#include "object_storage.h"
namespace rpc {
}
+93
View File
@@ -0,0 +1,93 @@
// rTorrent - BitTorrent client
// Copyright (C) 2005-2007, Jari Sundell
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// In addition, as a special exception, the copyright holders give
// permission to link the code of portions of this program with the
// OpenSSL library under certain conditions as described in each
// individual source file, and distribute linked combinations
// including the two.
//
// You must obey the GNU General Public License in all respects for
// all of the code used other than OpenSSL. If you modify file(s)
// with this exception, you may extend this exception to your version
// of the file(s), but you are not obligated to do so. If you do not
// wish to do so, delete this exception statement from your version.
// If you delete this exception statement from all source files in the
// program, then also delete it here.
//
// Contact: Jari Sundell <jaris@ifi.uio.no>
//
// Skomakerveien 33
// 3185 Skoppum, NORWAY
// The object_storage type is responsible for storing variables,
// commands, command lists and other types encoded in torrent::Object
// format.
#ifndef RTORRENT_RPC_OBJECT_STORAGE_H
#define RTORRENT_RPC_OBJECT_STORAGE_H
#include <cstring>
#include <tr1/unordered_set>
#include <torrent/object.h>
namespace rpc {
// The key size should be such that the value type size which includes
// the next-pointer.
struct object_storage_node_internal {
torrent::Object object;
char key[0];
};
struct object_storage_node : public object_storage_node_internal {
// TODO: Use the size of the unordered_map::value_type with a struct {}.
static const size_t key_size = 128 - sizeof(object_storage_node_internal) - sizeof(void*);
};
struct hash_object_storage_node {
inline std::size_t operator () (const object_storage_node& p);
};
bool operator == (const object_storage_node& left, const object_storage_node& right) { return std::strcmp(left.key, right.key) == 0; }
bool operator != (const object_storage_node& left, const object_storage_node& right) { return std::strcmp(left.key, right.key) != 0; }
bool operator < (const object_storage_node& left, const object_storage_node& right) { return std::strcmp(left.key, right.key) < 0; }
bool operator <= (const object_storage_node& left, const object_storage_node& right) { return std::strcmp(left.key, right.key) <= 0; }
bool operator > (const object_storage_node& left, const object_storage_node& right) { return std::strcmp(left.key, right.key) > 0; }
bool operator >= (const object_storage_node& left, const object_storage_node& right) { return std::strcmp(left.key, right.key) >= 0; }
class object_storage : private std::tr1::unordered_set<object_storage_node, hash_object_storage_node> {
typedef std::tr1::unordered_set<object_storage_node, hash_object_storage_node> base_type;
using base_type::iterator;
};
inline std::size_t
hash_object_storage_node::operator () (const object_storage_node& p) {
std::size_t result = 0;
const char* first = p.key;
while (*first != '\0')
result = (result * 131) + *first++;
return result;
}
}
#endif
+8 -1
View File
@@ -229,8 +229,15 @@ SCgiTask::receive_write(const char* buffer, uint32_t length) {
m_bufferSize = length + headerSize;
std::memcpy(m_buffer + headerSize, buffer, length);
event_write();
if (m_parent->log_fd() >= 0) {
// Clean up logging, this is just plain ugly...
// write(m_logFd, "\n---\n", sizeof("\n---\n"));
write(m_parent->log_fd(), m_buffer, m_bufferSize);
write(m_parent->log_fd(), "\n---\n", sizeof("\n---\n"));
}
event_write();
return true;
}
+44
View File
@@ -40,7 +40,10 @@
#include "globals.h"
#include "control.h"
#include <fcntl.h>
#include <unistd.h>
#include <cassert>
#include <rak/path.h>
#include <torrent/exceptions.h>
#include "core/manager.h"
@@ -67,6 +70,8 @@ ThreadWorker::set_scgi(rpc::SCgi* scgi) {
if (!__sync_bool_compare_and_swap(&m_safe.scgi, NULL, scgi))
return false;
change_xmlrpc_log();
// The xmlrpc process call requires a global lock.
// m_safe.scgi->set_slot_process(rak::mem_fn(&rpc::xmlrpc, &rpc::XmlRpc::process));
@@ -77,6 +82,13 @@ ThreadWorker::set_scgi(rpc::SCgi* scgi) {
return true;
}
void
ThreadWorker::set_xmlrpc_log(const std::string& filename) {
m_xmlrpcLog = filename;
queue_item((thread_base_func)&msg_change_xmlrpc_log);
}
void
ThreadWorker::start_scgi(ThreadBase* baseThread) {
ThreadWorker* thread = (ThreadWorker*)baseThread;
@@ -95,6 +107,38 @@ ThreadWorker::start_log_counter(ThreadBase* baseThread) {
priority_queue_insert(&thread->m_taskScheduler, &thread->m_taskTouchLog, cachedTime);
}
void
ThreadWorker::msg_change_xmlrpc_log(ThreadBase* baseThread) {
ThreadWorker* thread = (ThreadWorker*)baseThread;
acquire_global_lock();
thread->change_xmlrpc_log();
release_global_lock();
}
void
ThreadWorker::change_xmlrpc_log() {
if (scgi() == NULL)
return;
if (scgi()->log_fd() != -1)
::close(scgi()->log_fd());
if (m_xmlrpcLog.empty()) {
control->core()->push_log("Closed XMLRPC log.");
return;
}
scgi()->set_log_fd(open(rak::path_expand(m_xmlrpcLog).c_str(), O_WRONLY | O_APPEND | O_CREAT, 0644));
if (scgi()->log_fd() == -1) {
control->core()->push_log_std("Could not open XMLRPC log file '" + m_xmlrpcLog + "'.");
return;
}
control->core()->push_log_std("Logging XMLRPC events to '" + m_xmlrpcLog + "'.");
}
void
ThreadWorker::task_touch_log() {
priority_queue_insert(&m_taskScheduler, &m_taskTouchLog, cachedTime + rak::timer::from_seconds(1));
+10 -2
View File
@@ -58,13 +58,16 @@ public:
rpc::SCgi* scgi() { return m_safe.scgi; }
bool set_scgi(rpc::SCgi* scgi);
void set_xmlrpc_log(const std::string& filename);
static void start_scgi(ThreadBase* thread);
static void start_log_counter(ThreadBase* thread);
static void msg_change_xmlrpc_log(ThreadBase* thread);
private:
void task_touch_log();
rak::priority_item m_taskTouchLog;
void change_xmlrpc_log();
struct lt_cacheline_aligned safe_type {
safe_type() : scgi(NULL) {}
@@ -72,7 +75,12 @@ private:
rpc::SCgi* scgi;
};
safe_type m_safe;
rak::priority_item m_taskTouchLog;
safe_type m_safe;
// The following types shall only be modified while holding the
// global lock.
std::string m_xmlrpcLog;
};
#endif