All checks were successful
Verification / Is-Buildable (push) Successful in 3m8s
:Release Notes: - :Detailed Notes: - :Testing Performed: - was not verified, to be fair :D :QA Notes: - generated by glm-5.2 :Issues Addressed: TG-3
166 lines
4.9 KiB
Markdown
166 lines
4.9 KiB
Markdown
# RPC Protocol
|
||
|
||
## JSON-RPC 2.0
|
||
|
||
The server implements **JSON-RPC 2.0** over TCP with length-prefixed framing (see [Architecture → Wire framing](architecture.md#wire-framing)).
|
||
|
||
Batch requests are not supported — only single request objects are processed.
|
||
|
||
### Request format
|
||
|
||
```json
|
||
{
|
||
"jsonrpc": "2.0",
|
||
"method": "<method_name>",
|
||
"params": {},
|
||
"id": <integer|string>
|
||
}
|
||
```
|
||
|
||
The `params` field is accepted but currently ignored by all implemented methods. The `id` field is required; requests without it receive a `-32600 Invalid Request` error.
|
||
|
||
### Success response
|
||
|
||
```json
|
||
{
|
||
"jsonrpc": "2.0",
|
||
"result": <method_specific_result>,
|
||
"id": <matching_request_id>
|
||
}
|
||
```
|
||
|
||
### Error response
|
||
|
||
```json
|
||
{
|
||
"jsonrpc": "2.0",
|
||
"error": {
|
||
"code": <integer>,
|
||
"message": "<string>"
|
||
},
|
||
"id": <matching_request_id>
|
||
}
|
||
```
|
||
|
||
### Error codes
|
||
|
||
| Code | Meaning | When |
|
||
|---|---|---|
|
||
| `-32700` | Parse error | Request is not valid JSON |
|
||
| `-32600` | Invalid Request | Missing `jsonrpc`, `method`, or `id` fields, or `jsonrpc != "2.0"` |
|
||
| `-32601` | Method not found | No handler registered for the requested method name |
|
||
| `-32000` | Server error | Handler threw an exception |
|
||
|
||
> **Known issue**: Non-object JSON (arrays, strings, numbers, null) causes a `nlohmann::json::type_error` instead of a clean `-32600` response. See `tests/test_rpc_edge_cases.cpp`.
|
||
|
||
Source: `src/rpc_server.cpp` — `RpcServer::process()` and `create_error()`.
|
||
|
||
## Methods
|
||
|
||
### `get-intrinsic-params`
|
||
|
||
Retrieves intrinsic camera parameters as a flat 3×3 matrix (row-major, 9 doubles).
|
||
|
||
**Request:**
|
||
```json
|
||
{"jsonrpc": "2.0", "method": "get-intrinsic-params", "id": 1}
|
||
```
|
||
|
||
**Response:**
|
||
```json
|
||
{"jsonrpc": "2.0", "result": <base64-encoded-array>, "id": 1}
|
||
```
|
||
|
||
Result type: `vector<double>` (size 9), Base64-encoded.
|
||
|
||
### `get-extrinsic-params`
|
||
|
||
Retrieves extrinsic camera parameters as a flat 4×4 matrix (row-major, 16 doubles).
|
||
|
||
**Request:**
|
||
```json
|
||
{"jsonrpc": "2.0", "method": "get-extrinsic-params", "id": 2}
|
||
```
|
||
|
||
**Response:**
|
||
```json
|
||
{"jsonrpc": "2.0", "result": <base64-encoded-array>, "id": 2}
|
||
```
|
||
|
||
Result type: `vector<double>` (size 16), Base64-encoded.
|
||
|
||
### `get-cloud-point`
|
||
|
||
Retrieves the current field-of-view point cloud.
|
||
|
||
**Request:**
|
||
```json
|
||
{"jsonrpc": "2.0", "method": "get-cloud-point", "id": 3}
|
||
```
|
||
|
||
**Response:**
|
||
```json
|
||
{"jsonrpc": "2.0", "result": {"width": int, "height": int, "data": <base64-encoded-array>}, "id": 3}
|
||
```
|
||
|
||
Result type: `matrix WxH` (list of `[x, y, z]` points), Base64-encoded.
|
||
|
||
> **Note**: The standalone mock server (`server_main.cpp`) returns these as raw JSON arrays (not Base64-encoded) via `Service`. The Base64 encoding is expected to be implemented on the Unity side per `API.md`.
|
||
|
||
## Handler registration
|
||
|
||
Handlers are registered with `RpcServer::register_method()`. Two forms exist:
|
||
|
||
### C++ handler
|
||
|
||
```cpp
|
||
rpc_server.register_method("get-intrinsic-params", [&](const json& params) {
|
||
return service.get_intrinsic_params(); // returns vector<double>
|
||
});
|
||
```
|
||
|
||
The handler returns `std::variant<nlohmann::json, std::string>`. If a `json` is returned, it is placed directly in the `result` field. If a `std::string` is returned, it is placed as-is.
|
||
|
||
### C callback handler
|
||
|
||
```cpp
|
||
rpc_string* my_callback(rpc_string* params_json) {
|
||
// params_json->s contains the JSON params as a string
|
||
// return a result string (JSON or raw)
|
||
return crpc_str_create("result_data", 11);
|
||
}
|
||
|
||
rpc_server.register_method("my-method", my_callback);
|
||
```
|
||
|
||
The C callback receives the JSON `params` as a string in `rpc_string->s`. The return value's string is parsed as JSON if possible; otherwise it is used as a raw string in the `result` field.
|
||
|
||
Source: `src/rpc_server.cpp` — `register_method(name, callback_t)` overload.
|
||
|
||
## Base64 encoding
|
||
|
||
`include/cloud_point_rpc/rpc_coder.hpp`, `src/rpc_coder.cpp`
|
||
|
||
- `Base64RPCCoder` implements the `IRPCCoder` interface with `encode()` and `decode()` methods.
|
||
- Uses the [aklomp/base64](https://github.com/aklomp/base64) library (Meson wrap `subprojects/aklomp-base64.wrap`).
|
||
- `encode(vector<char>) → string` and `decode(string) → vector<char>`.
|
||
- Includes overflow protection: throws `std::length_error` if input exceeds safe size limits.
|
||
|
||
> Per `API.md`, Base64 encoding/decoding of camera data is expected to be done on the **Unity side**. The `Base64RPCCoder` class is available for C++ consumers but is not used by the mock server's response path.
|
||
|
||
## Client-side usage
|
||
|
||
`include/cloud_point_rpc/rpc_client.hpp`
|
||
|
||
`RpcClient` wraps `jsonrpccxx::JsonRpcClient` and provides typed access:
|
||
|
||
```cpp
|
||
score::TCPConnector connector(ip, port);
|
||
score::RpcClient client(connector);
|
||
|
||
auto intrinsic = client.get_intrinsic_params(); // vector<double>
|
||
auto extrinsic = client.get_extrinsic_params(); // vector<double>
|
||
auto cloud = client.get_cloud_point(); // vector<vector<double>>
|
||
```
|
||
|
||
The interactive CLI (`src/cli.cpp`) and `minimal_client` (`src/minimal_client.cpp`) demonstrate client usage. |