This example demonstrates a complete RPC server that uses the RPC module
system to organize handlers into modules and dispatch incoming calls. It
combines a vrtql_msg_svr for
networking with a vrtql_rpc_system for
request routing.
#include <string.h>
#include <vws/server.h>
#include <vws/rpc.h>
// Worker thread context holds the RPC system and environment
typedef struct
{
vrtql_rpc_system* system;
vrtql_rpc_env env;
} rpc_ctx;
//----------------------------------------------------------------------
// RPC Handlers: "user" module
//----------------------------------------------------------------------
vrtql_msg* user_login(vrtql_rpc_env* e, vrtql_msg* req)
{
vrtql_msg* reply = vrtql_rpc_reply(req);
cstr username = vrtql_msg_get_header(req, "username");
cstr password = vrtql_msg_get_header(req, "password");
if (username != NULL && password != NULL)
{
// Perform authentication (simplified)
vrtql_msg_set_header(reply, "rc", "0");
vrtql_msg_set_header(reply, "msg", "Authenticated");
vrtql_msg_set_content(reply, "{\"token\":\"abc123\"}");
}
else
{
vrtql_msg_set_header(reply, "rc", "1");
vrtql_msg_set_header(reply, "msg", "Missing credentials");
}
return reply;
}
vrtql_msg* user_info(vrtql_rpc_env* e, vrtql_msg* req)
{
vrtql_msg* reply = vrtql_rpc_reply(req);
vrtql_msg_set_header(reply, "rc", "0");
vrtql_msg_set_content(reply, "{\"name\":\"admin\",\"role\":\"superuser\"}");
return reply;
}
//----------------------------------------------------------------------
// RPC Handlers: "system" module
//----------------------------------------------------------------------
vrtql_msg* system_status(vrtql_rpc_env* e, vrtql_msg* req)
{
vrtql_msg* reply = vrtql_rpc_reply(req);
vrtql_msg_set_header(reply, "rc", "0");
vrtql_msg_set_content(reply, "{\"status\":\"running\"}");
return reply;
}
//----------------------------------------------------------------------
// Server setup
//----------------------------------------------------------------------
// Build the RPC system with all modules
vrtql_rpc_system* build_rpc_system()
{
vrtql_rpc_system* system = vrtql_rpc_system_new();
// User module
vrtql_rpc_module* user = vrtql_rpc_module_new("user");
vrtql_rpc_module_set(user, "login", user_login);
vrtql_rpc_module_set(user, "info", user_info);
vrtql_rpc_system_set(system, user);
// System module
vrtql_rpc_module* sys = vrtql_rpc_module_new("system");
vrtql_rpc_module_set(sys, "status", system_status);
vrtql_rpc_system_set(system, sys);
return system;
}
// Worker thread constructor: each thread gets its own RPC environment
void* worker_ctor(void* data)
{
rpc_ctx* ctx = (rpc_ctx*)malloc(sizeof(rpc_ctx));
ctx->system = (vrtql_rpc_system*)data;
ctx->env.data = NULL;
ctx->env.module = NULL;
return ctx;
}
// Worker thread destructor
void worker_dtor(void* data)
{
rpc_ctx* ctx = (rpc_ctx*)data;
free(ctx);
}
// Message processing: dispatch to RPC system
void process(vws_svr* s, vws_cid_t cid, vrtql_msg* m, void* ctx)
{
vrtql_msg_svr* server = (vrtql_msg_svr*)s;
rpc_ctx* rctx = (rpc_ctx*)ctx;
// Dispatch to RPC system
vrtql_msg* reply = vrtql_rpc_service(rctx->system, &rctx->env, m);
if (reply != NULL)
{
server->send(s, cid, reply, NULL);
}
// Note: m has been freed by vrtql_rpc_service()
}
int main(int argc, const char* argv[])
{
// Build the RPC system
vrtql_rpc_system* system = build_rpc_system();
// Create server
vrtql_msg_svr* server = vrtql_msg_svr_new(10, 0, 0);
server->process = process;
// Worker threads share the RPC system (read-only) but get their
// own environment via worker_ctor
vws_tcp_svr* base = (vws_tcp_svr*)server;
base->worker_ctor = worker_ctor;
base->worker_ctor_data = system;
base->worker_dtor = worker_dtor;
// Run
vrtql_msg_svr_run(server, "127.0.0.1", 8181);
// Cleanup
vrtql_msg_svr_free(server);
vrtql_rpc_system_free(system);
vws_cleanup();
return 0;
}
Clients can call into this server using the client-side RPC API. For
example, to call the user.login function, a client would
create a message with the header "id" set to
"user.login", include the required credentials as headers,
and use vrtql_rpc_exec() or
vrtql_rpc_invoke() to make the
call.