Skip to content

Commit

Permalink
refactor(!): add new jsonrpc client code
Browse files Browse the repository at this point in the history
  • Loading branch information
diegonehab committed Oct 9, 2024
1 parent 283247d commit 6655d0f
Show file tree
Hide file tree
Showing 11 changed files with 364 additions and 156 deletions.
31 changes: 0 additions & 31 deletions src/clua-i-virtual-machine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -401,19 +401,6 @@ static int machine_obj_index_replace_memory_range(lua_State *L) {
return 0;
}

/// \brief This is the machine:destroy() method implementation.
/// \param L Lua state.
static int machine_obj_index_destroy(lua_State *L) {
lua_settop(L, 2);
auto &m = clua_check<clua_managed_cm_ptr<cm_machine>>(L, 1);
const bool keep_machine = lua_toboolean(L, 2);
if (cm_destroy(m.get(), keep_machine) != 0) {
return luaL_error(L, "%s", cm_get_last_error_message());
}
m.release();
return 0;
}

/// \brief This is the machine:snapshot() method implementation.
/// \param L Lua state.
static int machine_obj_index_snapshot(lua_State *L) {
Expand Down Expand Up @@ -530,7 +517,6 @@ static const auto machine_obj_index = cartesi::clua_make_luaL_Reg_array({
{"write_virtual_memory", machine_obj_index_write_virtual_memory},
{"translate_virtual_address", machine_obj_index_translate_virtual_address},
{"replace_memory_range", machine_obj_index_replace_memory_range},
{"destroy", machine_obj_index_destroy},
{"snapshot", machine_obj_index_snapshot},
{"commit", machine_obj_index_commit},
{"rollback", machine_obj_index_rollback},
Expand All @@ -544,27 +530,10 @@ static const auto machine_obj_index = cartesi::clua_make_luaL_Reg_array({
{"log_send_cmio_response", machine_obj_index_log_send_cmio_response},
});

/// \brief This is the machine __close metamethod implementation.
/// \param L Lua state.
static int machine_obj_close(lua_State *L) {
auto &m = clua_check<clua_managed_cm_ptr<cm_machine>>(L, 1);
if (cm_destroy(m.get(), false) != 0) {
return luaL_error(L, "%s", cm_get_last_error_message());
}
m.release();
clua_close<clua_managed_cm_ptr<cm_machine>>(L);
return 0;
}

int clua_i_virtual_machine_init(lua_State *L, int ctxidx) {
if (!clua_typeexists<clua_managed_cm_ptr<cm_machine>>(L, ctxidx)) {
clua_createtype<clua_managed_cm_ptr<cm_machine>>(L, "cartesi machine object", ctxidx);
clua_setmethods<clua_managed_cm_ptr<cm_machine>>(L, machine_obj_index.data(), 0, ctxidx);
// Override __close to actually destroy the machine
static const auto machine_class_meta = cartesi::clua_make_luaL_Reg_array({
{"__close", machine_obj_close},
});
clua_setmetamethods<clua_managed_cm_ptr<cm_machine>>(L, machine_class_meta.data(), 0, ctxidx);
}
return 1;
}
Expand Down
167 changes: 111 additions & 56 deletions src/clua-jsonrpc-machine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,25 +14,27 @@
// with this program (see COPYING). If not, see <https://www.gnu.org/licenses/>.
//

#include <unordered_map>

#include "clua-jsonrpc-machine.h"
#include "clua-machine-util.h"
#include "clua.h"
#include "jsonrpc-machine-c-api.h"

namespace cartesi {

/// \brief Deleter for C api jsonrpc stub
/// \brief Deleter for C api jsonrpc connection
template <>
void clua_delete(cm_jsonrpc_connection *ptr) {
cm_jsonrpc_destroy_connection(ptr);
void clua_delete(cm_jsonrpc_connection *con) {
cm_jsonrpc_release_connection(con);
}

/// \brief This is the machine.get_default_machine_config()
/// static method implementation.
static int jsonrpc_machine_class_get_default_config(lua_State *L) {
const int stubidx = lua_upvalueindex(1);
const int conidx = lua_upvalueindex(1);
const int ctxidx = lua_upvalueindex(2);
auto &managed_jsonrpc_connection = clua_check<clua_managed_cm_ptr<cm_jsonrpc_connection>>(L, stubidx, ctxidx);
auto &managed_jsonrpc_connection = clua_check<clua_managed_cm_ptr<cm_jsonrpc_connection>>(L, conidx, ctxidx);
const char *config = nullptr;
if (cm_jsonrpc_get_default_config(managed_jsonrpc_connection.get(), &config) != 0) {
return luaL_error(L, "%s", cm_get_last_error_message());
Expand All @@ -57,10 +59,10 @@ static int jsonrpc_machine_class_get_reg_address(lua_State *L) {
/// \brief This is the machine.verify_step_uarch()
/// static method implementation.
static int jsonrpc_machine_class_verify_step_uarch(lua_State *L) {
const int stubidx = lua_upvalueindex(1);
const int conidx = lua_upvalueindex(1);
const int ctxidx = lua_upvalueindex(2);
lua_settop(L, 5);
auto &managed_jsonrpc_connection = clua_check<clua_managed_cm_ptr<cm_jsonrpc_connection>>(L, stubidx, ctxidx);
auto &managed_jsonrpc_connection = clua_check<clua_managed_cm_ptr<cm_jsonrpc_connection>>(L, conidx, ctxidx);
const char *log = clua_check_schemed_json_string(L, 2, "AccessLog", ctxidx);
if (!lua_isnil(L, 1) || !lua_isnil(L, 3)) {
cm_hash root_hash{};
Expand All @@ -81,10 +83,10 @@ static int jsonrpc_machine_class_verify_step_uarch(lua_State *L) {
/// \brief This is the machine.verify_reset_uarch()
/// static method implementation.
static int jsonrpc_machine_class_verify_reset_uarch(lua_State *L) {
const int stubidx = lua_upvalueindex(1);
const int conidx = lua_upvalueindex(1);
const int ctxidx = lua_upvalueindex(2);
lua_settop(L, 5);
auto &managed_jsonrpc_connection = clua_check<clua_managed_cm_ptr<cm_jsonrpc_connection>>(L, stubidx, ctxidx);
auto &managed_jsonrpc_connection = clua_check<clua_managed_cm_ptr<cm_jsonrpc_connection>>(L, conidx, ctxidx);
const char *log = clua_check_schemed_json_string(L, 2, "AccessLog", ctxidx);
if (!lua_isnil(L, 1) || !lua_isnil(L, 3)) {
cm_hash root_hash{};
Expand All @@ -105,10 +107,10 @@ static int jsonrpc_machine_class_verify_reset_uarch(lua_State *L) {
/// \brief This is the machine.verify_send_cmio_response()
/// static method implementation.
static int jsonrpc_machine_class_verify_send_cmio_response(lua_State *L) {
const int stubidx = lua_upvalueindex(1);
const int conidx = lua_upvalueindex(1);
const int ctxidx = lua_upvalueindex(2);
lua_settop(L, 6);
auto &managed_jsonrpc_connection = clua_check<clua_managed_cm_ptr<cm_jsonrpc_connection>>(L, stubidx, ctxidx);
auto &managed_jsonrpc_connection = clua_check<clua_managed_cm_ptr<cm_jsonrpc_connection>>(L, conidx, ctxidx);
const uint16_t reason = static_cast<uint16_t>(luaL_checkinteger(L, 1));
size_t length{0};
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
Expand Down Expand Up @@ -151,10 +153,10 @@ static int jsonrpc_machine_tostring(lua_State *L) {
/// \brief This is the cartesi.machine() constructor implementation.
/// \param L Lua state.
static int jsonrpc_machine_ctor(lua_State *L) {
const int stubidx = lua_upvalueindex(1);
const int conidx = lua_upvalueindex(1);
const int ctxidx = lua_upvalueindex(2);
lua_settop(L, 3);
auto &managed_jsonrpc_connection = clua_check<clua_managed_cm_ptr<cm_jsonrpc_connection>>(L, stubidx, ctxidx);
auto &managed_jsonrpc_connection = clua_check<clua_managed_cm_ptr<cm_jsonrpc_connection>>(L, conidx, ctxidx);
auto &managed_machine = clua_push_to(L, clua_managed_cm_ptr<cm_machine>(nullptr), ctxidx);
const char *runtime_config = !lua_isnil(L, 3) ? clua_check_json_string(L, 3, -1, ctxidx) : nullptr;
if (!lua_isstring(L, 2)) {
Expand All @@ -180,7 +182,7 @@ static const auto jsonrpc_machine_class_meta = cartesi::clua_make_luaL_Reg_array
});

/// \brief This is the machine.get_machine() static method implementation.
static int jsonrpc_server_class_get_machine(lua_State *L) {
static int jsonrpc_connection_class_get_machine(lua_State *L) {
lua_settop(L, 1);
auto &managed_jsonrpc_connection =
clua_check<clua_managed_cm_ptr<cm_jsonrpc_connection>>(L, lua_upvalueindex(1), lua_upvalueindex(2));
Expand All @@ -193,10 +195,10 @@ static int jsonrpc_server_class_get_machine(lua_State *L) {
}

/// \brief This is the machine.get_version() static method implementation.
static int jsonrpc_server_class_get_version(lua_State *L) {
const int stubidx = lua_upvalueindex(1);
static int jsonrpc_connection_class_get_version(lua_State *L) {
const int conidx = lua_upvalueindex(1);
const int ctxidx = lua_upvalueindex(2);
auto &managed_jsonrpc_connection = clua_check<clua_managed_cm_ptr<cm_jsonrpc_connection>>(L, stubidx, ctxidx);
auto &managed_jsonrpc_connection = clua_check<clua_managed_cm_ptr<cm_jsonrpc_connection>>(L, conidx, ctxidx);
const char *version = nullptr;
if (cm_jsonrpc_get_version(managed_jsonrpc_connection.get(), &version) != 0) {
return luaL_error(L, "%s", cm_get_last_error_message());
Expand All @@ -205,18 +207,8 @@ static int jsonrpc_server_class_get_version(lua_State *L) {
return 1;
}

/// \brief This is the machine.shutdown() static method implementation.
static int jsonrpc_server_class_shutdown(lua_State *L) {
auto &managed_jsonrpc_connection =
clua_check<clua_managed_cm_ptr<cm_jsonrpc_connection>>(L, lua_upvalueindex(1), lua_upvalueindex(2));
if (cm_jsonrpc_shutdown(managed_jsonrpc_connection.get()) != 0) {
return luaL_error(L, "%s", cm_get_last_error_message());
}
return 0;
}

/// \brief This is the rebind method implementation.
static int jsonrpc_server_class_rebind(lua_State *L) {
static int jsonrpc_connection_class_rebind(lua_State *L) {
auto &managed_jsonrpc_connection =
clua_check<clua_managed_cm_ptr<cm_jsonrpc_connection>>(L, lua_upvalueindex(1), lua_upvalueindex(2));
const char *address = luaL_checkstring(L, 1);
Expand All @@ -233,7 +225,7 @@ static int jsonrpc_server_class_rebind(lua_State *L) {
}

/// \brief This is the fork method implementation.
static int jsonrpc_server_class_fork(lua_State *L) {
static int jsonrpc_connection_class_fork(lua_State *L) {
auto &managed_jsonrpc_connection =
clua_check<clua_managed_cm_ptr<cm_jsonrpc_connection>>(L, lua_upvalueindex(1), lua_upvalueindex(2));
const char *address = nullptr;
Expand All @@ -246,45 +238,108 @@ static int jsonrpc_server_class_fork(lua_State *L) {
return 2;
}

/// \brief JSONRPC server static methods
static const auto jsonrpc_server_static_methods = cartesi::clua_make_luaL_Reg_array({
{"get_machine", jsonrpc_server_class_get_machine},
{"get_version", jsonrpc_server_class_get_version},
{"shutdown", jsonrpc_server_class_shutdown},
{"fork", jsonrpc_server_class_fork},
{"rebind", jsonrpc_server_class_rebind},
/// \brief JSONRPC connection static methods
static const auto jsonrpc_connection_static_methods = cartesi::clua_make_luaL_Reg_array({
{"get_machine", jsonrpc_connection_class_get_machine},
{"get_version", jsonrpc_connection_class_get_version},
{"fork", jsonrpc_connection_class_fork},
{"rebind", jsonrpc_connection_class_rebind},
});

/// \brief This is the jsonrpc.stub() method implementation.
static int mod_stub(lua_State *L) {
const char *remote_address = luaL_checkstring(L, 1);
// Create stub
/// \brief Takes underlying cm_jsonrpc_connection in top of stack and encapsulates it in its Lua interface
static void wrap_jsonrpc_connection(lua_State *L) {
lua_newtable(L); // ccon luacon
lua_newtable(L); // ccon luacon mtab
lua_pushvalue(L, -3); // ccon luacon mtab ccon
lua_pushvalue(L, lua_upvalueindex(1)); // ccon luacon mtab ccon cluactx
luaL_setfuncs(L, jsonrpc_machine_static_methods.data(), 2); // ccon luacon mtab
lua_newtable(L); // ccon luacon mtab mmeta
lua_pushvalue(L, -4); // ccon luacon mtab mmeta ccon
lua_pushvalue(L, lua_upvalueindex(1)); // ccon luacon mtab mmeta ccon cluactx
luaL_setfuncs(L, jsonrpc_machine_class_meta.data(), 2); // ccon luacon mtab mmeta
lua_setmetatable(L, -2); // ccon luacon mtab
lua_setfield(L, -2, "machine"); // ccon luacon
lua_pushvalue(L, -2); // ccon luacon ccon
lua_pushvalue(L, lua_upvalueindex(1)); // ccon luacon ccon cluactx
luaL_setfuncs(L, jsonrpc_connection_static_methods.data(), 2); // ccon luacon
lua_insert(L, -2); // luacon ccon
lua_pop(L, 1); // luacon
}

static cm_jsonrpc_manage check_cm_jsonrpc_manage(lua_State *L, int idx) {
const char *strwhat = luaL_checkstring(L, idx);
if (strcmp(strwhat, "server") == 0) {
return CM_JSONRPC_MANAGE_SERVER;
} else if (strcmp(strwhat, "machine") == 0) {
return CM_JSONRPC_MANAGE_MACHINE;
} else if (strcmp(strwhat, "none") == 0) {
return CM_JSONRPC_MANAGE_NONE;
} else {
luaL_argerror(L, idx, "expected \"server\", \"machine\", or \"none\"");
return CM_JSONRPC_MANAGE_SERVER;
}
}

/// \brief This is the jsonrpc.connect() method implementation.
static int mod_connect(lua_State *L) {
// create and push the underlying cm_jsonrpc_connection
const char *address = luaL_checkstring(L, 1);
auto what = check_cm_jsonrpc_manage(L, 2);
auto &managed_jsonrpc_connection = clua_push_to(L, clua_managed_cm_ptr<cm_jsonrpc_connection>(nullptr));
if (cm_jsonrpc_create_connection(remote_address, &managed_jsonrpc_connection.get()) != 0) {
if (cm_jsonrpc_connect(address, what, &managed_jsonrpc_connection.get()) != 0) {
return luaL_error(L, "%s", cm_get_last_error_message());
}
lua_newtable(L); // stub server
lua_newtable(L); // stub server jsonrpc_machine_class
lua_pushvalue(L, -3); // stub server jsonrpc_machine_class stub
lua_pushvalue(L, lua_upvalueindex(1)); // stub server jsonrpc_machine_class stub cluactx
luaL_setfuncs(L, jsonrpc_machine_static_methods.data(), 2); // stub server jsonrpc_machine_class
lua_newtable(L); // stub server jsonrpc_machine_class meta
lua_pushvalue(L, -4); // stub server jsonrpc_machine_class meta stub
lua_pushvalue(L, lua_upvalueindex(1)); // stub server jsonrpc_machine_class meta stub cluactx
luaL_setfuncs(L, jsonrpc_machine_class_meta.data(), 2); // stub server jsonrpc_machine_class meta
lua_setmetatable(L, -2); // stub server jsonrpc_machine_class
lua_setfield(L, -2, "machine"); // stub server
lua_pushvalue(L, -2); // stub server stub
lua_pushvalue(L, lua_upvalueindex(1)); // stub server stub cluactx
luaL_setfuncs(L, jsonrpc_server_static_methods.data(), 2);
// wrap it into its Lua interface
wrap_jsonrpc_connection(L);
return 1;
}

/// \brief This is the jsonrpc.connect() method implementation.
static int mod_spawn(lua_State *L) {
const char *address = luaL_checkstring(L, 1);
auto what = check_cm_jsonrpc_manage(L, 2);
// create and push the underlying cm_jsonrpc_connection
auto &managed_jsonrpc_connection = clua_push_to(L, clua_managed_cm_ptr<cm_jsonrpc_connection>(nullptr));
const char *bound_address = nullptr;
int32_t pid = 0;
if (cm_jsonrpc_spawn(address, what, &managed_jsonrpc_connection.get(), &bound_address, &pid) != 0) {
return luaL_error(L, "%s", cm_get_last_error_message());
}
// wrap it into its Lua interface
wrap_jsonrpc_connection(L);
lua_pushstring(L, bound_address);
lua_pushinteger(L, pid);
return 3;
}

/// \brief Contents of the jsonrpc module.
static const auto mod = cartesi::clua_make_luaL_Reg_array({
{"stub", mod_stub},
{"connect", mod_connect},
{"spawn", mod_spawn},
});

// jsonrpc.connect()
// return connection object
// jsonrpc.spawn()
// return connection object, bound address, pid
//
// connection object
// machine
// either load or create new machine
// get_machine
// return existing machine object
// get_version
// manage
// rebind
// fork
// __gc/__close call release on connection
//
// machine object
// all methods of normal machine
// get_connection
// destroy?
// __gc/__close call release on connection

int clua_jsonrpc_machine_init(lua_State *L, int ctxidx) {
clua_createnewtype<clua_managed_cm_ptr<unsigned char>>(L, ctxidx);
clua_createnewtype<clua_managed_cm_ptr<std::string>>(L, ctxidx);
Expand Down
2 changes: 1 addition & 1 deletion src/clua-machine-util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ void clua_delete<unsigned char>(unsigned char *ptr) { // NOLINT(readability-non-

template <>
void clua_delete<cm_machine>(cm_machine *ptr) {
cm_destroy(ptr, true); // this call should never fail
cm_destroy(ptr); // this call should never fail
}

template <>
Expand Down
14 changes: 9 additions & 5 deletions src/jsonrpc-connection.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,9 @@
namespace cartesi {

class jsonrpc_connection final {
boost::asio::io_context m_ioc{1}; // The io_context is required for all I/O
boost::beast::tcp_stream m_stream{m_ioc}; // TCP stream for keep alive connections
boost::container::static_vector<std::string, 2> m_address{};

public:
explicit jsonrpc_connection(std::string remote_address);
enum class manage { server, machine, none };
explicit jsonrpc_connection(std::string remote_address, manage what);
jsonrpc_connection(const jsonrpc_connection &other) = delete;
jsonrpc_connection(jsonrpc_connection &&other) noexcept = delete;
jsonrpc_connection &operator=(const jsonrpc_connection &other) = delete;
Expand All @@ -50,7 +47,14 @@ class jsonrpc_connection final {
void snapshot(void);
void commit(void);
void rollback(void);
manage get_what_managed(void) const;

private:
void shutdown(void);
boost::asio::io_context m_ioc{1}; // The io_context is required for all I/O
boost::beast::tcp_stream m_stream{m_ioc}; // TCP stream for keep alive connections
boost::container::static_vector<std::string, 2> m_address{};
manage m_what_managed{manage::server};
};

} // namespace cartesi
Expand Down
Loading

0 comments on commit 6655d0f

Please sign in to comment.