-
Notifications
You must be signed in to change notification settings - Fork 62
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement ws-protocol's fetchAsset
specification
#232
Changes from all commits
8c02db3
903579e
38efea3
849a104
9a206a0
ad437ba
16cba13
33e8549
f0efd85
aa6ca52
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,7 +17,6 @@ | |
"/usr/include" | ||
] | ||
}, | ||
"defines": ["ASIO_STANDALONE"], | ||
"cppStandard": "c++17" | ||
} | ||
], | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -69,6 +69,7 @@ const std::unordered_map<std::string, std::string> CAPABILITY_BY_CLIENT_OPERATIO | |
{"unsubscribeParameterUpdates", CAPABILITY_PARAMETERS_SUBSCRIBE}, | ||
{"subscribeConnectionGraph", CAPABILITY_CONNECTION_GRAPH}, | ||
{"unsubscribeConnectionGraph", CAPABILITY_CONNECTION_GRAPH}, | ||
{"fetchAsset", CAPABILITY_ASSETS}, | ||
}; | ||
|
||
/// Map of required capability by client operation (binary). | ||
|
@@ -131,6 +132,7 @@ class Server final : public ServerInterface<ConnHandle> { | |
void sendServiceResponse(ConnHandle clientHandle, const ServiceResponse& response) override; | ||
void updateConnectionGraph(const MapOfSets& publishedTopics, const MapOfSets& subscribedTopics, | ||
const MapOfSets& advertisedServices) override; | ||
void sendFetchAssetResponse(ConnHandle clientHandle, const FetchAssetResponse& response) override; | ||
|
||
uint16_t getPort() override; | ||
std::string remoteEndpointString(ConnHandle clientHandle) override; | ||
|
@@ -622,6 +624,7 @@ inline void Server<ServerConfiguration>::handleTextMessage(ConnHandle hdl, Messa | |
constexpr auto UNSUBSCRIBE_PARAMETER_UPDATES = Integer("unsubscribeParameterUpdates"); | ||
constexpr auto SUBSCRIBE_CONNECTION_GRAPH = Integer("subscribeConnectionGraph"); | ||
constexpr auto UNSUBSCRIBE_CONNECTION_GRAPH = Integer("unsubscribeConnectionGraph"); | ||
constexpr auto FETCH_ASSET = Integer("fetchAsset"); | ||
|
||
switch (Integer(op)) { | ||
case SUBSCRIBE: { | ||
|
@@ -906,6 +909,22 @@ inline void Server<ServerConfiguration>::handleTextMessage(ConnHandle hdl, Messa | |
"Client was not subscribed to connection graph updates"); | ||
} | ||
} break; | ||
case FETCH_ASSET: { | ||
if (!_handlers.fetchAssetHandler) { | ||
return; | ||
} | ||
|
||
const auto uri = payload.at("uri").get<std::string>(); | ||
const auto requestId = payload.at("requestId").get<uint32_t>(); | ||
|
||
try { | ||
_handlers.fetchAssetHandler(uri, requestId, hdl); | ||
} catch (const std::exception& e) { | ||
sendStatusAndLogMsg(hdl, StatusLevel::Error, e.what()); | ||
} catch (...) { | ||
sendStatusAndLogMsg(hdl, StatusLevel::Error, op + ": Failed to execute handler"); | ||
} | ||
} break; | ||
default: { | ||
sendStatusAndLogMsg(hdl, StatusLevel::Error, "Unrecognized client opcode \"" + op + "\""); | ||
} break; | ||
|
@@ -1371,4 +1390,38 @@ inline bool Server<ServerConfiguration>::hasCapability(const std::string& capabi | |
_options.capabilities.end(); | ||
} | ||
|
||
template <typename ServerConfiguration> | ||
inline void Server<ServerConfiguration>::sendFetchAssetResponse( | ||
ConnHandle clientHandle, const FetchAssetResponse& response) { | ||
std::error_code ec; | ||
const auto con = _server.get_con_from_hdl(clientHandle, ec); | ||
if (ec || !con) { | ||
return; | ||
} | ||
|
||
const size_t errMsgSize = | ||
response.status == FetchAssetStatus::Error ? response.errorMessage.size() : 0ul; | ||
const size_t dataSize = response.status == FetchAssetStatus::Success ? response.data.size() : 0ul; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. do we need to similarly check if status==Error before adding |
||
const size_t messageSize = 1 + 4 + 1 + 4 + errMsgSize + dataSize; | ||
|
||
auto message = con->get_message(OpCode::BINARY, messageSize); | ||
|
||
const auto op = BinaryOpcode::FETCH_ASSET_RESPONSE; | ||
message->append_payload(&op, 1); | ||
|
||
std::array<uint8_t, 4> uint32Data; | ||
foxglove::WriteUint32LE(uint32Data.data(), response.requestId); | ||
message->append_payload(uint32Data.data(), uint32Data.size()); | ||
|
||
const uint8_t status = static_cast<uint8_t>(response.status); | ||
message->append_payload(&status, 1); | ||
|
||
foxglove::WriteUint32LE(uint32Data.data(), response.errorMessage.size()); | ||
message->append_payload(uint32Data.data(), uint32Data.size()); | ||
message->append_payload(response.errorMessage.data(), errMsgSize); | ||
|
||
message->append_payload(response.data.data(), dataSize); | ||
con->send(message); | ||
} | ||
|
||
} // namespace foxglove |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,5 @@ | ||
#include <chrono> | ||
|
||
#define ASIO_STANDALONE | ||
#include <websocketpp/config/asio_client.hpp> | ||
|
||
#include <foxglove_bridge/serialization.hpp> | ||
|
@@ -132,7 +131,35 @@ std::future<Channel> waitForChannel(std::shared_ptr<ClientInterface> client, | |
} | ||
} | ||
}); | ||
return future; | ||
} | ||
|
||
std::future<FetchAssetResponse> waitForFetchAssetResponse(std::shared_ptr<ClientInterface> client) { | ||
auto promise = std::make_shared<std::promise<FetchAssetResponse>>(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: is make_shared required? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You left a similar comment here: #239 (comment) Will create an issue to keep track of this |
||
auto future = promise->get_future(); | ||
|
||
client->setBinaryMessageHandler( | ||
[promise = std::move(promise)](const uint8_t* data, size_t dataLength) mutable { | ||
if (static_cast<BinaryOpcode>(data[0]) != BinaryOpcode::FETCH_ASSET_RESPONSE) { | ||
return; | ||
} | ||
|
||
foxglove::FetchAssetResponse response; | ||
size_t offset = 1; | ||
response.requestId = ReadUint32LE(data + offset); | ||
offset += 4; | ||
response.status = static_cast<foxglove::FetchAssetStatus>(data[offset]); | ||
offset += 1; | ||
const size_t errorMsgLength = static_cast<size_t>(ReadUint32LE(data + offset)); | ||
offset += 4; | ||
response.errorMessage = | ||
std::string(reinterpret_cast<const char*>(data + offset), errorMsgLength); | ||
offset += errorMsgLength; | ||
const auto payloadLength = dataLength - offset; | ||
response.data.resize(payloadLength); | ||
std::memcpy(response.data.data(), data + offset, payloadLength); | ||
promise->set_value(response); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: maybe std::move(response)? |
||
}); | ||
return future; | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what happens if these are missing or the wrong type? if an exception is thrown here, will it be caught somewhere?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, any exception that is not handled in the operation handler would be caught here:
ros-foxglove-bridge/foxglove_bridge_base/include/foxglove_bridge/websocket_server.hpp
Lines 560 to 571 in 9a206a0