@@ -39,46 +39,125 @@ class NodeRpcClient
3939 NodeRpcClient& operator =(NodeRpcClient&&) = delete ;
4040 NodeRpcClient& operator =(const NodeRpcClient&) = delete ;
4141
42- // / Defines the result type of the RPC client raw response .
42+ // / Defines the result type of the RPC client raw call .
4343 // /
44- // / On success, the result is a raw data buffer, its size, and extra metadata.
44+ // / On success, the result is a raw response data buffer, its size, and extra metadata.
4545 // / On failure, the result is an SDK error.
4646 // /
47- struct RawResponse final
47+ struct RawCall final
4848 {
4949 struct Success
5050 {
51- OwnedMutablePayload payload ;
51+ OwnedMutablePayload raw_response ;
5252 CyphalPriority priority;
5353 CyphalNodeId server_node_id;
5454 };
5555 using Failure = Error;
5656 using Result = cetl::variant<Success, Failure>;
5757 };
58- // / Sends raw RPC request .
58+ // / Sends raw RPC call .
5959 // /
60- // / The client-side (the SDK) will forward the raw data to the corresponding Cyphal network service client
60+ // / The client-side (the SDK) will forward the raw request data to the corresponding Cyphal network service client
6161 // / on the server-side (the daemon). The raw data is forwarded as is, without any interpretation or validation.
6262 // /
63- // / Note, only one request can be active at a time (per rpc client).
63+ // / Note, only one call can be active at a time (per rpc client).
6464 // / In the case of multiple "concurrent" operations, only the last one will report the response result.
6565 // / Any previous still existing operations will be "stalled" and never complete.
6666 // /
67- // / @param raw_payload The raw request data to be sent.
67+ // / @param raw_request The raw request data to be sent.
6868 // / @param request_timeout The maximum time to keep the raw request as valid in the Cyphal network.
6969 // / @param response_timeout The maximum time to wait for reply from the Cyphal node.
7070 // / @return An execution sender which emits the async result of the operation.
7171 // /
72- virtual SenderOf<RawResponse ::Result>::Ptr rawRequest (OwnedMutablePayload&& raw_payload ,
73- const std::chrono::microseconds request_timeout,
74- const std::chrono::microseconds response_timeout) = 0;
72+ virtual SenderOf<RawCall ::Result>::Ptr rawCall (OwnedMutablePayload&& raw_request ,
73+ const std::chrono::microseconds request_timeout,
74+ const std::chrono::microseconds response_timeout) = 0;
7575
7676 // / Sets priority for request to be issued by this client.
7777 // /
7878 // / The next and following `request` operations will use this priority.
7979 // /
8080 virtual OptError setPriority (const CyphalPriority priority) = 0;
8181
82+ // / Defines the result type of the RPC client call.
83+ // /
84+ // / On success, the result is a deserialized response message, and extra metadata.
85+ // / On failure, the result is an SDK error.
86+ // /
87+ struct Call final
88+ {
89+ template <typename Response>
90+ struct Success
91+ {
92+ Response response;
93+ CyphalPriority priority;
94+ CyphalNodeId server_node_id;
95+ };
96+
97+ using Failure = Error;
98+
99+ template <typename Response>
100+ using Result = cetl::variant<Success<Response>, Failure>;
101+ };
102+ // / Sends RPC call.
103+ // /
104+ // / The client-side (the SDK) will forward the serialized request message to the corresponding Cyphal network
105+ // / service client on the server-side (the daemon).
106+ // /
107+ // / Note, only one call can be active at a time (per rpc client).
108+ // / In the case of multiple "concurrent" operations, only the last one will report the response result.
109+ // / Any previous still existing operations will be "stalled" and never complete.
110+ // /
111+ // / @param memory The memory resource to use for the response deserialization.
112+ // / @param request The request message to be sent.
113+ // / @param request_timeout The maximum time to keep the request as valid in the Cyphal network.
114+ // / @param response_timeout The maximum time to wait for reply from the Cyphal node.
115+ // / @return An execution sender which emits the async result of the operation.
116+ // /
117+ template <typename Response, typename Request>
118+ typename SenderOf<Call::Result<Response>>::Ptr call (cetl::pmr::memory_resource& memory,
119+ const Request& request,
120+ const std::chrono::microseconds request_timeout,
121+ const std::chrono::microseconds response_timeout)
122+ {
123+ using CallResult = Call::Result<Response>;
124+
125+ auto raw_call_sender = detail::tryPerformOnSerialized<RawCall::Result>( //
126+ request,
127+ [this , request_timeout, response_timeout](auto raw_request) {
128+ //
129+ return rawCall (std::move (raw_request), request_timeout, response_timeout);
130+ });
131+
132+ return then<CallResult, RawCall::Result>( //
133+ std::move (raw_call_sender),
134+ [&memory](auto raw_result) -> CallResult {
135+ //
136+ if (const auto * const failure = cetl::get_if<RawCall::Failure>(&raw_result))
137+ {
138+ return *failure;
139+ }
140+ auto called = cetl::get<RawCall::Success>(std::move (raw_result));
141+
142+ // No lint b/c of integration with Nunavut.
143+ // NOLINTNEXTLINE(*-pro-type-reinterpret-cast)
144+ const auto * const raw_payload = reinterpret_cast <const std::uint8_t *>(called.raw_response .data .get ());
145+ Response response{&memory};
146+ const auto deser_result = deserialize (response, {raw_payload, called.raw_response .size });
147+ if (!deser_result)
148+ {
149+ // Invalid message payload.
150+ return Error{Error::Code::InvalidArgument};
151+ }
152+
153+ return Call::Success<Response>{
154+ std::move (response),
155+ called.priority ,
156+ called.server_node_id ,
157+ };
158+ });
159+ }
160+
82161protected:
83162 NodeRpcClient () = default ;
84163
0 commit comments