Skip to content

Commit 72a3962

Browse files
committed
first draft of RPC client SDK
1 parent 921dfcb commit 72a3962

File tree

12 files changed

+531
-37
lines changed

12 files changed

+531
-37
lines changed

docs/svc_design.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -375,7 +375,7 @@ sequenceDiagram
375375
uavcan.primitive.Empty.1.0 empty
376376
RawRpcClientCreate.0.1 create
377377
RawRpcClientConfig.0.1 config
378-
RawRpcClientSend.0.1 send
378+
RawRpcClientCall.0.1 call
379379
@sealed
380380
---
381381
@union
@@ -396,7 +396,7 @@ uint16 server_node_id
396396
uint8[<=1] priority
397397
@extent 32 * 8
398398
```
399-
- `RawRpcClientSend.0.1.dsdl`
399+
- `RawRpcClientCall.0.1.dsdl`
400400
```
401401
uint64 request_timeout_us
402402
uint64 response_timeout_us
@@ -426,7 +426,7 @@ sequenceDiagram
426426
RawRpcClient --)+ RawRpcClientService: Route{ChMsg{}}<br/>RawRpcClient.Request_0_1{Create{service_id, extent, srv_node_id}}
427427
RawRpcClient ->>- User : return
428428
429-
RawRpcClientService ->> CyServiceClient: client = create.makeClient(srv_node_id, service_id, extent)
429+
RawRpcClientService ->> CyServiceClient: client = makeClient(srv_node_id, service_id, extent)
430430
activate RawRpcClient
431431
alt success
432432
RawRpcClientService --) RawRpcClient: Route{ChMsg{}}<br/>RawRpcClient.Response_0_1{empty}
@@ -447,11 +447,11 @@ sequenceDiagram
447447
Note over RawRpcClient, RawRpcClientService: Making a request
448448
User ->>+ RpcClient: request<Msg>(msg, timeouts)
449449
RpcClient ->> RpcClient: rawRequest(raw_payload, timeouts)
450-
RpcClient --)+ RawRpcClientService: Route{ChMsg{}}<br/>RawRpcClient.Request_0_1{Send{payload_size, timeouts}}<br/>raw_payload
450+
RpcClient --)+ RawRpcClientService: Route{ChMsg{}}<br/>RawRpcClient.Request_0_1{Call{payload_size, timeouts}}<br/>raw_payload
451451
RpcClient ->>- User: return
452452
RawRpcClientService ->>+ CyServiceClient: promise = client.request(raw_payload, timeouts)
453453
CyServiceClient --) NodeX: SvcRequest<service_id>{}
454-
Note left of NodeX: Cyphal network servers(s)<br/>receive the service request.
454+
Note left of NodeX: A cyphal network server<br/>receive the service request.
455455
CyServiceClient ->>- RawRpcClientService: promise
456456
opt if error
457457
RawRpcClientService --)+ RpcClient: Route{ChMsg{}}<br/>RawRpcClient.Response_0_1{request_error}

include/ocvsmd/sdk/daemon.hpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "file_server.hpp"
1212
#include "node_command_client.hpp"
1313
#include "node_pub_sub.hpp"
14+
#include "node_rpc_client.hpp"
1415
#include "node_registry_client.hpp"
1516

1617
#include <cetl/cetl.hpp>
@@ -126,6 +127,32 @@ class Daemon
126127
virtual SenderOf<MakeSubscriber::Result>::Ptr makeSubscriber(const CyphalPortId subject_id,
127128
const std::size_t extent_bytes) = 0;
128129

130+
/// Defines the result type of the RPC client creation.
131+
///
132+
/// On success, the result is a smart pointer to an RPC client with the required parameters.
133+
/// On failure, the result is an SDK error.
134+
///
135+
struct MakeRpcClient final
136+
{
137+
using Success = NodeRpcClient::Ptr;
138+
using Failure = Error;
139+
using Result = cetl::variant<Success, Failure>;
140+
};
141+
/// Makes a new RPC client for the specified remote service and node ids.
142+
///
143+
/// The server-side (the daemon) of SDK will create the corresponding Cyphal network service client,
144+
/// use it to send requests, and forward replies to the client-side of SDK.
145+
/// See also `RpcClient` docs for how to issue RPC calls.
146+
///
147+
/// @param service_id The service ID to send requests to.
148+
/// @param server_node_id The ID of the target server node.
149+
/// @param extent_bytes The "extent" size of responses (see Cyphal spec).
150+
/// @return An execution sender which emits the async result of the operation.
151+
///
152+
virtual SenderOf<MakeRpcClient::Result>::Ptr makeRpcClient(const CyphalPortId service_id,
153+
const CyphalNodeId server_node_id,
154+
const std::size_t extent_bytes) = 0;
155+
129156
protected:
130157
Daemon() = default;
131158

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
//
2+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
// SPDX-License-Identifier: MIT
4+
//
5+
6+
#ifndef OCVSMD_SDK_NODE_RPC_CLIENT_HPP_INCLUDED
7+
#define OCVSMD_SDK_NODE_RPC_CLIENT_HPP_INCLUDED
8+
9+
#include "defines.hpp"
10+
#include "execution.hpp"
11+
12+
#include <cetl/pf17/cetlpf.hpp>
13+
14+
#include <chrono>
15+
#include <memory>
16+
17+
namespace ocvsmd
18+
{
19+
namespace sdk
20+
{
21+
22+
/// Defines the interface of RPC Client to a Cyphal network node.
23+
///
24+
class NodeRpcClient
25+
{
26+
public:
27+
/// Defines a smart pointer type for the interface.
28+
///
29+
/// It's made "shared" b/c execution sender (see `request` method) implicitly
30+
/// holds reference to its client.
31+
///
32+
using Ptr = std::shared_ptr<NodeRpcClient>;
33+
34+
virtual ~NodeRpcClient() = default;
35+
36+
// No copy/move semantics.
37+
NodeRpcClient(NodeRpcClient&&) = delete;
38+
NodeRpcClient(const NodeRpcClient&) = delete;
39+
NodeRpcClient& operator=(NodeRpcClient&&) = delete;
40+
NodeRpcClient& operator=(const NodeRpcClient&) = delete;
41+
42+
/// Defines the result type of the RPC client raw response.
43+
///
44+
/// On success, the result is a raw data buffer, its size, and extra metadata.
45+
/// On failure, the result is an SDK error.
46+
///
47+
struct RawResponse final
48+
{
49+
struct Success
50+
{
51+
OwnedMutablePayload payload;
52+
CyphalPriority priority;
53+
CyphalNodeId server_node_id;
54+
};
55+
using Failure = Error;
56+
using Result = cetl::variant<Success, Failure>;
57+
};
58+
/// Sends raw RPC request.
59+
///
60+
/// The client-side (the SDK) will forward the raw data to the corresponding Cyphal network service client
61+
/// on the server-side (the daemon). The raw data is forwarded as is, without any interpretation or validation.
62+
///
63+
/// Note, only one request can be active at a time (per rpc client).
64+
/// In the case of multiple "concurrent" operations, only the last one will report the response result.
65+
/// Any previous still existing operations will be "stalled" and never complete.
66+
///
67+
/// @param raw_payload The raw request data to be sent.
68+
/// @param request_timeout The maximum time to keep the raw request as valid in the Cyphal network.
69+
/// @param response_timeout The maximum time to wait for reply from the Cyphal node.
70+
/// @return An execution sender which emits the async result of the operation.
71+
///
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;
75+
76+
/// Sets priority for request to be issued by this client.
77+
///
78+
/// The next and following `request` operations will use this priority.
79+
///
80+
virtual OptError setPriority(const CyphalPriority priority) = 0;
81+
82+
protected:
83+
NodeRpcClient() = default;
84+
85+
}; // NodeRpcClient
86+
87+
} // namespace sdk
88+
} // namespace ocvsmd
89+
90+
#endif // OCVSMD_SDK_NODE_RPC_CLIENT_HPP_INCLUDED

src/common/dsdl/ocvsmd/common/svc/relay/RawRpcClient.0.1.dsdl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
uavcan.primitive.Empty.1.0 empty
44
RawRpcClientCreate.0.1 create
55
RawRpcClientConfig.0.1 config
6-
RawRpcClientSend.0.1 send
6+
RawRpcClientCall.0.1 call
77

88
@sealed
99

src/common/dsdl/ocvsmd/common/svc/relay/RawRpcClientSend.0.1.dsdl renamed to src/common/dsdl/ocvsmd/common/svc/relay/RawRpcClientCall.0.1.dsdl

File renamed without changes.

src/daemon/engine/svc/relay/raw_rpc_client_service.cpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ class RawRpcClientServiceImpl final
128128
private:
129129
using RawRpcClientCreate = common::svc::relay::RawRpcClientCreate_0_1;
130130
using RawRpcClientConfig = common::svc::relay::RawRpcClientConfig_0_1;
131-
using RawRpcClientSend = common::svc::relay::RawRpcClientSend_0_1;
131+
using RawRpcClientCall = common::svc::relay::RawRpcClientCall_0_1;
132132

133133
using CyPayloadFragment = libcyphal::transport::PayloadFragment;
134134
using CyRawSvcClient = libcyphal::presentation::RawServiceClient;
@@ -155,9 +155,9 @@ class RawRpcClientServiceImpl final
155155
//
156156
handleInputEvent(config);
157157
},
158-
[this, payload](const RawRpcClientSend& send) {
158+
[this, payload](const RawRpcClientCall& call) {
159159
//
160-
handleInputEvent(send, payload);
160+
handleInputEvent(call, payload);
161161
},
162162
[](const RawRpcClientCreate&) {},
163163
[](const uavcan::primitive::Empty_1_0&) {}),
@@ -189,7 +189,7 @@ class RawRpcClientServiceImpl final
189189
}
190190
}
191191

192-
void handleInputEvent(const common::svc::relay::RawRpcClientSend_0_1& send, const common::io::Payload payload)
192+
void handleInputEvent(const common::svc::relay::RawRpcClientCall_0_1& call, const common::io::Payload payload)
193193
{
194194
CETL_DEBUG_ASSERT(cy_raw_svc_client_, "");
195195
if (!cy_raw_svc_client_)
@@ -200,13 +200,13 @@ class RawRpcClientServiceImpl final
200200

201201
const auto now = service_.context_.executor.now();
202202
const auto request_deadline = now + std::chrono::duration_cast<libcyphal::Duration>( //
203-
std::chrono::microseconds{send.request_timeout_us});
203+
std::chrono::microseconds{call.request_timeout_us});
204204
const auto response_deadline = now + std::chrono::duration_cast<libcyphal::Duration>(
205-
std::chrono::microseconds{send.response_timeout_us});
205+
std::chrono::microseconds{call.response_timeout_us});
206206

207207
// The tail of the payload is the raw message data.
208208
//
209-
const auto raw_msg_payload = payload.subspan(payload.size() - send.payload_size);
209+
const auto raw_msg_payload = payload.subspan(payload.size() - call.payload_size);
210210
std::array<CyPayloadFragment, 1> fragments{{{raw_msg_payload.data(), raw_msg_payload.size()}}};
211211

212212
auto cy_req_result = cy_raw_svc_client_->request(request_deadline,

src/sdk/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ add_library(ocvsmd_sdk
2929
svc/file_server/pop_root_client.cpp
3030
svc/file_server/push_root_client.cpp
3131
svc/relay/raw_publisher_client.cpp
32+
svc/relay/raw_rpc_client.cpp
3233
svc/relay/raw_subscriber_client.cpp
3334
)
3435
target_link_libraries(ocvsmd_sdk

src/sdk/daemon.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
#include "svc/client_helpers.hpp"
1717
#include "svc/relay/raw_publisher_client.hpp"
1818
#include "svc/relay/raw_publisher_spec.hpp"
19+
#include "svc/relay/raw_rpc_client.hpp"
20+
#include "svc/relay/raw_rpc_client_spec.hpp"
1921
#include "svc/relay/raw_subscriber_client.hpp"
2022
#include "svc/relay/raw_subscriber_spec.hpp"
2123

@@ -135,6 +137,29 @@ class DaemonImpl final : public Daemon
135137
logger_);
136138
}
137139

140+
SenderOf<MakeRpcClient::Result>::Ptr makeRpcClient( //
141+
const CyphalPortId service_id, // NOLINT bugprone-easily-swappable-parameters
142+
const CyphalNodeId server_node_id,
143+
const std::size_t extent_bytes) override
144+
{
145+
using RawRpcClient = svc::relay::RawRpcClient;
146+
using Request = common::svc::relay::RawRpcClientSpec::Request;
147+
148+
logger_->trace("Making sender of `makeRawSubscriber()`.");
149+
150+
Request request{&memory_};
151+
auto& create_req = request.set_create();
152+
create_req.service_id = service_id;
153+
create_req.server_node_id = server_node_id;
154+
create_req.extent_size = extent_bytes;
155+
auto svc_client = RawRpcClient::make({memory_, *ipc_router_}, request);
156+
157+
return std::make_unique<svc::AsSender<MakeRpcClient::Result, decltype(svc_client)>>( //
158+
"Daemon::makeRpcClient",
159+
std::move(svc_client),
160+
logger_);
161+
}
162+
138163
private:
139164
cetl::pmr::memory_resource& memory_;
140165
libcyphal::IExecutor& executor_;

src/sdk/svc/relay/raw_publisher_client.cpp

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
#include "raw_publisher_client.hpp"
77

8+
#include "common_helpers.hpp"
89
#include "logging.hpp"
910
#include "ocvsmd/sdk/execution.hpp"
1011
#include "ocvsmd/sdk/node_pub_sub.hpp"
@@ -140,14 +141,14 @@ class RawPublisherClientImpl final : public RawPublisherClient
140141
}
141142

142143
private:
143-
using SocketBuffer = common::io::SocketBuffer;
144-
using PublishRequest = Spec::Request::_traits_::TypeOf::publish;
145-
using PublishResponse = Spec::Response::_traits_::TypeOf::publish_error;
144+
using SocketBuffer = common::io::SocketBuffer;
145+
using PublishRequest = Spec::Request::_traits_::TypeOf::publish;
146+
using PublishErrorResponse = Spec::Response::_traits_::TypeOf::publish_error;
146147

147148
struct Published
148149
{
149150
PublishRequest request;
150-
OwnedMutablePayload payload; // NOLINT(*-avoid-c-arrays)
151+
OwnedMutablePayload payload;
151152
};
152153

153154
void handleEvent(const Channel::Input& input)
@@ -168,15 +169,15 @@ class RawPublisherClientImpl final : public RawPublisherClient
168169
{
169170
context_.logger->debug("Publisher::handleEvent({}).", completed);
170171
completion_error_ = completed.opt_error.value_or(Error{Error::Code::Canceled});
171-
notifyPublished(completion_error_);
172+
notifyReceived(completion_error_);
172173
}
173174

174-
void handleInputEvent(const PublishResponse& publish_error) const
175+
void handleInputEvent(const PublishErrorResponse& publish_error) const
175176
{
176-
notifyPublished(dsdlErrorToOptError(publish_error));
177+
notifyReceived(dsdlErrorToOptError(publish_error));
177178
}
178179

179-
void notifyPublished(const OptError opt_error) const
180+
void notifyReceived(const OptError opt_error) const
180181
{
181182
if (receiver_)
182183
{

0 commit comments

Comments
 (0)