Skip to content

Fixed LUA compilaition issue. #1435

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 31, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 66 additions & 30 deletions src/rpc/lua.cc
Original file line number Diff line number Diff line change
Expand Up @@ -86,19 +86,28 @@ int
LuaEngine::lua_rtorrent_call(lua_State* l_state) {
auto method = lua_tostring(l_state, 1);
lua_remove(l_state, 1);
torrent::Object object;
rpc::target_type target = rpc::make_target();
;

rpc::CommandMap::iterator itr = rpc::commands.find(std::string(method).c_str());

if (itr == rpc::commands.end()) {
throw torrent::input_error("method not found: " + std::string(method));
}
object = lua_callstack_to_object(l_state, itr->second.m_flags, &target);

auto target = rpc::make_target();
auto deleter = std::function<void()>();

auto object = lua_callstack_to_object(l_state, itr->second.m_flags, &target, &deleter);

try {
const auto& result = rpc::commands.call_command(itr, object, target);

object_to_lua(l_state, result);
deleter();

return 1;

} catch (torrent::base_error& e) {
deleter();
throw luaL_error(l_state, e.what());
}
}
Expand All @@ -107,27 +116,33 @@ int
LuaEngine::lua_init_module(lua_State* l_state) {
// Should this throw if it fails to find the file?
auto lua_file = search_lua_path(l_state);

if (!lua_file.empty()) {
check_lua_status(l_state, luaL_loadfile(l_state, lua_file.c_str()));
}

lua_createtable(l_state, 0, 1);
// Assign functions
lua_pushliteral(l_state, "call");
lua_pushcfunction(l_state, LuaEngine::lua_rtorrent_call);
lua_settable(l_state, -3);

if (!lua_file.empty()) {
check_lua_status(l_state, lua_pcall(l_state, 1, 1, 0));
}

return 1;
}

void
object_to_target(const torrent::Object& obj, int call_flags, rpc::target_type* target) {
object_to_target(const torrent::Object& obj, int call_flags, rpc::target_type* target, std::function<void()>* deleter) {
if (!obj.is_string()) {
throw torrent::input_error("invalid parameters: target must be a string");
}

std::string target_string = obj.as_string();
bool require_index = (call_flags & (CommandMap::flag_tracker_target | CommandMap::flag_file_target));

if (target_string.empty() && !require_index) {
return;
}
Expand All @@ -141,16 +156,20 @@ object_to_target(const torrent::Object& obj, int call_flags, rpc::target_type* t
std::string hash;
std::string index;
const auto& delim_pos = target_string.find_first_of(':', 40);

if (delim_pos == target_string.npos || delim_pos + 2 >= target_string.size()) {
if (require_index) {
throw torrent::input_error("invalid parameters: no index");
}

hash = target_string;

} else {
hash = target_string.substr(0, delim_pos);
type = target_string[delim_pos + 1];
index = target_string.substr(delim_pos + 2);
}

core::Download* download = rpc.slot_find_download()(hash.c_str());

if (download == nullptr)
Expand All @@ -161,22 +180,32 @@ object_to_target(const torrent::Object& obj, int call_flags, rpc::target_type* t
case 'd':
*target = rpc::make_target(download);
break;

case 'f':
*target = rpc::make_target(command_base::target_file, rpc.slot_find_file()(download, std::stoi(std::string(index))));
break;

case 't':
*target =
rpc::make_target(command_base::target_tracker, rpc.slot_find_tracker()(download, std::stoi(std::string(index))));
{
auto tracker = new torrent::tracker::Tracker(rpc.slot_find_tracker()(download, std::stoi(std::string(index))));

*deleter = [tracker]() { delete tracker; };
*target = rpc::make_target(command_base::target_tracker, target);
}
break;
case 'p': {
if (index.size() < 40) {
throw torrent::input_error("Not a hash string.");

case 'p':
{
if (index.size() < 40) {
throw torrent::input_error("Not a hash string.");
}

torrent::HashString hash;
torrent::hash_string_from_hex_c_str(index.c_str(), hash);
*target = rpc::make_target(command_base::target_peer, rpc.slot_find_peer()(download, hash));
}
torrent::HashString hash;
torrent::hash_string_from_hex_c_str(index.c_str(), hash);
*target = rpc::make_target(command_base::target_peer, rpc.slot_find_peer()(download, hash));
break;
}

default:
throw torrent::input_error("invalid parameters: unexpected target type");
}
Expand Down Expand Up @@ -291,52 +320,59 @@ lua_to_object(lua_State* l_state) {
}

torrent::Object
lua_callstack_to_object(lua_State* l_state, int command_flags, rpc::target_type* target) {
torrent::Object object;
lua_callstack_to_object(lua_State* l_state, int command_flags, rpc::target_type* target, std::function<void()>* deleter) {
if (lua_gettop(l_state) == 0) {
return torrent::Object();
}

if (!lua_isstring(l_state, 1)) {
throw torrent::input_error("invalid parameters: target must be a string");
}
object_to_target(torrent::Object(lua_tostring(l_state, 1)), command_flags, target);

object_to_target(torrent::Object(lua_tostring(l_state, 1)), command_flags, target, deleter);

// start from the second argument since the first is the target
lua_remove(l_state, 1);

if (lua_gettop(l_state) == 0) {
if (lua_gettop(l_state) == 0)
return torrent::Object();
} else {
torrent::Object result = torrent::Object::create_list();
torrent::Object::list_type& list_ref = result.as_list();
while (lua_gettop(l_state) != 0) {
list_ref.insert(list_ref.begin(), lua_to_object(l_state));
lua_remove(l_state, -1);
}
return result;

torrent::Object result = torrent::Object::create_list();
torrent::Object::list_type& list_ref = result.as_list();

while (lua_gettop(l_state) != 0) {
list_ref.insert(list_ref.begin(), lua_to_object(l_state));
lua_remove(l_state, -1);
}

return object;
return result;
}

int
lua_rtorrent_call(lua_State* l_state) {
torrent::Object object;
rpc::target_type target = rpc::make_target();
auto method = lua_tostring(l_state, 1);
lua_remove(l_state, 1);

rpc::CommandMap::iterator itr = rpc::commands.find(method);
if (itr == rpc::commands.end()) {
throw torrent::input_error("method not found: " + std::string(method));
}
object = lua_callstack_to_object(l_state, itr->second.m_flags, &target);

auto target = rpc::make_target();
auto deleter = std::function<void()>();

auto object = lua_callstack_to_object(l_state, itr->second.m_flags, &target, &deleter);

try {
const auto& result = rpc::commands.call_command(itr, object, target);

object_to_lua(l_state, result);
deleter();

return 1;

} catch (torrent::base_error& e) {
deleter();
throw luaL_error(l_state, e.what());
}
}
Expand Down
6 changes: 5 additions & 1 deletion src/rpc/lua.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class LuaEngine {

LuaEngine();
~LuaEngine();

#ifdef HAVE_LUA
// lua_CFunctions
static int lua_init_module(lua_State* l_state);
Expand All @@ -29,15 +30,18 @@ class LuaEngine {
lua_State* m_luaState;
#endif
};

torrent::Object execute_lua(LuaEngine* engine, rpc::target_type target, const torrent::Object& raw_args, int flags);

#ifdef HAVE_LUA

int rtorrent_call(lua_State* l_state);
void init_rtorrent_module(lua_State* l_state);
void object_to_lua(lua_State* l_state, torrent::Object const& object);
void check_lua_status(lua_State* l_state, int status);
torrent::Object lua_to_object(lua_State* l_state);
torrent::Object lua_callstack_to_object(lua_State* l_state, int command_flags, rpc::target_type* target);
torrent::Object lua_callstack_to_object(lua_State* l_state, int command_flags, rpc::target_type* target, std::function<void()>* deleter);

#endif

} // namespace rpc
Expand Down