test_client.cpp
Go to the documentation of this file.
1 #include <chrono>
2 
3 #define ASIO_STANDALONE
4 #include <websocketpp/config/asio_client.hpp>
5 
9 
10 namespace foxglove {
11 
12 constexpr auto DEFAULT_TIMEOUT = std::chrono::seconds(5);
13 
14 std::vector<uint8_t> connectClientAndReceiveMsg(const std::string& uri,
15  const std::string& topic_name) {
16  // Set up text message handler to resolve the promise when the topic is advertised
18  std::promise<nlohmann::json> channelPromise;
19  auto channelFuture = channelPromise.get_future();
20  wsClient.setTextMessageHandler([&topic_name, &channelPromise](const std::string& payload) {
21  const auto msg = nlohmann::json::parse(payload);
22  const auto& op = msg.at("op").get<std::string>();
23  if (op == "advertise") {
24  for (const auto& channel : msg.at("channels")) {
25  if (topic_name == channel.at("topic")) {
26  channelPromise.set_value(channel);
27  }
28  }
29  }
30  });
31 
32  // Connect the client and wait for the channel future
33  if (std::future_status::ready != wsClient.connect(uri).wait_for(DEFAULT_TIMEOUT)) {
34  throw std::runtime_error("Client failed to connect");
35  } else if (std::future_status::ready != channelFuture.wait_for(DEFAULT_TIMEOUT)) {
36  throw std::runtime_error("Client failed to receive channel");
37  }
38 
39  // Set up binary message handler to resolve when a binary message has been received
40  std::promise<std::vector<uint8_t>> msgPromise;
41  auto msgFuture = msgPromise.get_future();
42  wsClient.setBinaryMessageHandler([&msgPromise](const uint8_t* data, size_t dataLength) {
43  const size_t offset = 1 + 4 + 8;
44  std::vector<uint8_t> dataCopy(dataLength - offset);
45  std::memcpy(dataCopy.data(), data + offset, dataLength - offset);
46  msgPromise.set_value(std::move(dataCopy));
47  });
48 
49  // Subscribe to the channel that corresponds to the topic
50  const auto channelId = channelFuture.get().at("id").get<foxglove::ChannelId>();
51  wsClient.subscribe({{1, channelId}});
52 
53  // Wait until we have received a binary message
54  if (std::future_status::ready != msgFuture.wait_for(DEFAULT_TIMEOUT)) {
55  throw std::runtime_error("Client failed to receive message");
56  }
57  return msgFuture.get();
58 }
59 
60 std::future<std::vector<Parameter>> waitForParameters(std::shared_ptr<ClientInterface> client,
61  const std::string& requestId) {
62  auto promise = std::make_shared<std::promise<std::vector<Parameter>>>();
63  auto future = promise->get_future();
64 
65  client->setTextMessageHandler(
66  [promise = std::move(promise), requestId](const std::string& payload) {
67  const auto msg = nlohmann::json::parse(payload);
68  const auto& op = msg["op"].get<std::string>();
69  const auto id = msg.value("id", "");
70 
71  if (op == "parameterValues" && (requestId.empty() || requestId == id)) {
72  const auto parameters = msg["parameters"].get<std::vector<Parameter>>();
73  promise->set_value(std::move(parameters));
74  }
75  });
76 
77  return future;
78 }
79 
80 std::future<ServiceResponse> waitForServiceResponse(std::shared_ptr<ClientInterface> client) {
81  auto promise = std::make_shared<std::promise<ServiceResponse>>();
82  auto future = promise->get_future();
83 
84  client->setBinaryMessageHandler(
85  [promise = std::move(promise)](const uint8_t* data, size_t dataLength) mutable {
86  if (static_cast<BinaryOpcode>(data[0]) != BinaryOpcode::SERVICE_CALL_RESPONSE) {
87  return;
88  }
89 
91  response.read(data + 1, dataLength - 1);
92  promise->set_value(response);
93  });
94  return future;
95 }
96 
97 std::future<Service> waitForService(std::shared_ptr<ClientInterface> client,
98  const std::string& serviceName) {
99  auto promise = std::make_shared<std::promise<Service>>();
100  auto future = promise->get_future();
101 
102  client->setTextMessageHandler(
103  [promise = std::move(promise), serviceName](const std::string& payload) mutable {
104  const auto msg = nlohmann::json::parse(payload);
105  const auto& op = msg["op"].get<std::string>();
106 
107  if (op == "advertiseServices") {
108  const auto services = msg["services"].get<std::vector<Service>>();
109  for (const auto& service : services) {
110  if (service.name == serviceName) {
111  promise->set_value(service);
112  break;
113  }
114  }
115  }
116  });
117 
118  return future;
119 }
120 
121 // Explicit template instantiation
123 
124 } // namespace foxglove
constexpr auto DEFAULT_TIMEOUT
Definition: test_client.cpp:12
void subscribe(const std::vector< std::pair< SubscriptionId, ChannelId >> &subscriptions) override
void setBinaryMessageHandler(BinaryMessageHandler handler) override
void read(const uint8_t *data, size_t size)
std::future< Service > waitForService(std::shared_ptr< ClientInterface > client, const std::string &serviceName)
Definition: test_client.cpp:97
uint32_t ChannelId
Definition: common.hpp:25
void connect(const std::string &uri, std::function< void(websocketpp::connection_hdl)> onOpenHandler, std::function< void(websocketpp::connection_hdl)> onCloseHandler=nullptr) override
std::vector< uint8_t > connectClientAndReceiveMsg(const std::string &uri, const std::string &topic_name)
Definition: test_client.cpp:14
void setTextMessageHandler(TextMessageHandler handler) override
std::future< ServiceResponse > waitForServiceResponse(std::shared_ptr< ClientInterface > client)
Definition: test_client.cpp:80
const std::string response
std::future< std::vector< Parameter > > waitForParameters(std::shared_ptr< ClientInterface > client, const std::string &requestId=std::string())
Definition: test_client.cpp:60


foxglove_bridge
Author(s): Foxglove
autogenerated on Mon Jul 3 2023 02:12:22