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.