- Add scheduled OpenWiki regeneration and pull-request workflow - Refresh generated wiki metadata, navigation, and source documentation - Add Doxygen configuration and ignore generated documentation output - Publish OpenWiki guidance for Codex and Claude agents TG-3 #ready-for-test
7.0 KiB
type, title, description, tags
| type | title | description | tags | ||||||
|---|---|---|---|---|---|---|---|---|---|
| API | C API for Unity Integration | C API surface for embedding the RPC server in Unity or other native consumers — lifecycle functions, rpc_string memory management, method registration, and the test API for handler testing. |
|
C API for Unity Integration
The C API allows Unity (or any C/C++ consumer) to embed the RPC server as a shared library, register custom RPC handlers as C function pointers, and manage the server lifecycle without touching C++ directly.
Unity C# design spec: For the complete Unity-side implementation guide — including
rpc_stringownership rules, IL2CPP callback pinning, main-thread dispatcher design, and shutdown ordering — see docs/unity-integration.md. The C API described here is the C++ side of the interface; the C# side is the Unity project's responsibility.
Two C API surfaces exist:
| API | Header | Library | Purpose |
|---|---|---|---|
| Server API | include/server_api.h |
libcloud_point_rpc |
Start/stop the TCP server, register RPC methods |
| Test API | include/test_api.h |
test_cloud_point |
Internal test harness: register methods, schedule calls, auto-call loop |
Both APIs use the rpc_string type and callback_t function pointer typedef.
Export macros
include/export.h defines CRPC_EXPORT. On Windows, it resolves to __declspec(dllexport) when CRPC_SERVER_API_EXPORT is defined (set in src/meson.build) and __declspec(dllimport) otherwise. On GCC/Clang, it uses __attribute__((visibility("default"))). This allows the same headers to be used when building the library and when consuming it.
rpc_string
Defined in include/cloud_point_rpc/rpc_server.hpp inside an extern "C" block:
struct rpc_string {
std::string s; // C++ std::string, but the struct is C-ABI compatible
};
Although the struct contains a std::string, it is allocated and managed by the library. Consumers interact with it through opaque pointers and accessor functions:
| Function | Description |
|---|---|
crpc_str_create(data, size) |
Allocate a new rpc_string with the given data. Tracked by internal GC. |
crpc_str_destroy(ptr) |
Manually free a rpc_string. |
crpc_str_get_data(ptr) |
Get the raw C string pointer. |
crpc_str_get_size(ptr) |
Get the string length. |
Garbage collector
src/server_api.cpp maintains a static std::list<std::unique_ptr<rpc_string>> gc protected by gc_mtx. All crpc_str_create allocations are tracked in this list. crpc_deinit() clears the entire list. crpc_str_destroy removes a specific entry. This prevents memory leaks if Unity forgets to call destroy, though manual destruction is recommended to avoid excessive memory usage.
Important
:
rpc_stringpointers returned from callbacks are owned by the library's GC. Do notfree()them — usecrpc_str_destroy().
Server API (server_api.h)
Lifecycle
// Initialize and start the server from a config file
crpc_init("config.yaml");
// Or initialize with an explicit address (no config file needed)
crpc_init_with_address("127.0.0.1", 9095);
// ... register methods and serve ...
// Stop server and free all GC-tracked rpc_strings
crpc_deinit();
crpc_init(config_path)— Loads YAML config viaConfigLoader, creates aTcpServerwith the configured IP/port, and starts it. Initializes Google Logging if not already initialized. See Architecture → Config.crpc_init_with_address(ip, port)— Same but without a config file. Used when the consumer wants to set the address directly.crpc_deinit()— Stops the server (resets theTcpServerunique_ptr) and clears therpc_stringGC list.
Registering methods
rpc_string* my_handler(rpc_string* params_json) {
// params_json->s contains the JSON params as a string
// Build your result (JSON or raw string)
return crpc_str_create("{\"key\":\"value\"}", 15);
}
rpc_string method_name;
method_name.s = "my-method";
crpc_add_method(my_handler, &method_name);
callback_tisrpc_string* (*)(rpc_string*)— a C function pointer.- The callback receives the JSON
paramsobject serialized as a string inrpc_string->s. - The callback returns a
rpc_string*whose string is parsed as JSON if possible, or used as a raw string in theresultfield. See RPC Protocol → Handler registration. crpc_add_methodis guarded byserver_mtxand registers the callback on the globalRpcServer.
Global state
server_api.cpp uses file-level statics: rpc_server (the global RpcServer), server (the TcpServer unique_ptr), gc (the string GC list), and two mutexes (gc_mtx, server_mtx). This means only one server instance is supported per process.
Test API (test_api.h)
The test API is built into a separate shared library (test_cloud_point) and provides a TestThread class (in src/test_api.cpp) that runs a background std::jthread for testing registered methods without a real TCP connection.
Lifecycle
crpc_test_init(); // Start the test thread + Google Logging
// ... register methods, schedule calls ...
crpc_test_deinit(); // Stop thread, call crpc_deinit(), reset state
Methods
| Function | Description |
|---|---|
crpc_test_add_method(cb, name) |
Register a method on the test RpcServer. Duplicates are ignored. |
crpc_test_remove_method(name) |
Remove a registered method. Returns 0 on success, -1 if not found. |
crpc_test_schedule_call(name) |
Enqueue a one-shot call to the named method (processed by the test thread). |
crpc_test_change_duration(ms) |
Set the auto-call sleep interval (default 50ms). |
crpc_test_duration() |
Get the current sleep interval. |
crpc_test_auto_call(state) |
Enable (1) or disable (0) auto-calling registered methods on each sleep cycle. |
Test thread behavior
The TestThread::routine() loop:
- If there are queued one-shot calls, process them (build a JSON-RPC request and call
server.process()). - If auto-call is enabled and methods exist, call the next method in round-robin order.
- If auto-call is enabled and the queue is empty, wait on a condition variable for the configured duration (or until stop is requested).
- Stop when
jthreadstop is requested viacrpc_test_deinit().
Note
: The test API does not start a TCP server. It processes JSON-RPC requests directly through
RpcServer::process(), logging results. It is designed for testing handler registration and callback behavior in C, as demonstrated intests/test_c_api.cppandtests/test_c_api_edge_cases.cpp.
Source references
include/server_api.h— Server C API declarationssrc/server_api.cpp— Server C API implementation,rpc_stringGCinclude/test_api.h— Test C API declarationssrc/test_api.cpp—TestThreadimplementation and test C APIinclude/export.h—CRPC_EXPORTmacroinclude/cloud_point_rpc/rpc_server.hpp—rpc_stringstruct andcallback_ttypedef