.. _program_listing_file_foxglove_src_server.cpp: Program Listing for File server.cpp =================================== |exhale_lsh| :ref:`Return to documentation for file ` (``foxglove/src/server.cpp``) .. |exhale_lsh| unicode:: U+021B0 .. UPWARDS ARROW WITH TIP LEFTWARDS .. code-block:: cpp #include #include #include #include #include namespace foxglove { FoxgloveResult WebSocketServer::create( WebSocketServerOptions&& options // NOLINT(cppcoreguidelines-rvalue-reference-param-not-moved) ) { foxglove_internal_register_cpp_wrapper(); bool has_any_callbacks = options.callbacks.onSubscribe || options.callbacks.onUnsubscribe || options.callbacks.onClientAdvertise || options.callbacks.onMessageData || options.callbacks.onClientUnadvertise || options.callbacks.onGetParameters || options.callbacks.onSetParameters || options.callbacks.onParametersSubscribe || options.callbacks.onParametersUnsubscribe || options.callbacks.onConnectionGraphSubscribe || options.callbacks.onConnectionGraphUnsubscribe; std::unique_ptr callbacks; std::unique_ptr fetch_asset; foxglove_server_callbacks c_callbacks = {}; if (has_any_callbacks) { callbacks = std::make_unique(std::move(options.callbacks)); c_callbacks.context = callbacks.get(); if (callbacks->onSubscribe) { c_callbacks.on_subscribe = [](const void* context, uint64_t channel_id) { try { (static_cast(context))->onSubscribe(channel_id); } catch (const std::exception& exc) { warn() << "onSubscribe callback failed: " << exc.what(); } }; } if (callbacks->onUnsubscribe) { c_callbacks.on_unsubscribe = [](const void* context, uint64_t channel_id) { try { (static_cast(context))->onUnsubscribe(channel_id); } catch (const std::exception& exc) { warn() << "onUnsubscribe callback failed: " << exc.what(); } }; } if (callbacks->onClientAdvertise) { c_callbacks.on_client_advertise = [](const void* context, uint32_t client_id, const foxglove_client_channel* channel) { ClientChannel cpp_channel = { channel->id, channel->topic, channel->encoding, channel->schema_name, channel->schema_encoding == nullptr ? std::string_view{} : channel->schema_encoding, reinterpret_cast(channel->schema), channel->schema_len }; try { (static_cast(context)) ->onClientAdvertise(client_id, cpp_channel); } catch (const std::exception& exc) { warn() << "onClientAdvertise callback failed: " << exc.what(); } }; } if (callbacks->onMessageData) { c_callbacks.on_message_data = []( const void* context, // NOLINTNEXTLINE(bugprone-easily-swappable-parameters) uint32_t client_id, uint32_t client_channel_id, const uint8_t* payload, size_t payload_len ) { try { (static_cast(context)) ->onMessageData( client_id, client_channel_id, reinterpret_cast(payload), payload_len ); } catch (const std::exception& exc) { warn() << "onMessageData callback failed: " << exc.what(); } }; } if (callbacks->onClientUnadvertise) { c_callbacks.on_client_unadvertise = // NOLINTNEXTLINE(bugprone-easily-swappable-parameters) [](uint32_t client_id, uint32_t client_channel_id, const void* context) { try { (static_cast(context)) ->onClientUnadvertise(client_id, client_channel_id); } catch (const std::exception& exc) { warn() << "onClientUnadvertise callback failed: " << exc.what(); } }; } if (callbacks->onGetParameters) { c_callbacks.on_get_parameters = []( const void* context, uint32_t client_id, // NOLINTNEXTLINE(bugprone-easily-swappable-parameters) const struct foxglove_string* c_request_id, const struct foxglove_string* c_param_names, size_t param_names_len ) -> foxglove_parameter_array* { std::optional request_id; if (c_request_id != nullptr) { request_id.emplace(c_request_id->data, c_request_id->len); } std::vector param_names; if (c_param_names != nullptr) { param_names.reserve(param_names_len); for (size_t i = 0; i < param_names_len; ++i) { param_names.emplace_back(c_param_names[i].data, c_param_names[i].len); } } std::vector params; try { params = (static_cast(context)) ->onGetParameters(client_id, request_id, param_names); } catch (const std::exception& exc) { warn() << "onGetParameters callback failed: " << exc.what(); } auto array = ParameterArray(std::move(params)); return array.release(); }; } if (callbacks->onSetParameters) { c_callbacks.on_set_parameters = []( const void* context, uint32_t client_id, const struct foxglove_string* c_request_id, const foxglove_parameter_array* c_params ) -> foxglove_parameter_array* { std::optional request_id; if (c_request_id != nullptr) { request_id.emplace(c_request_id->data, c_request_id->len); } if (c_params == nullptr) { // Should not happen; the C implementation never passes a null pointer. return nullptr; } std::vector params; try { params = (static_cast(context)) ->onSetParameters(client_id, request_id, ParameterArrayView(c_params).parameters()); } catch (const std::exception& exc) { warn() << "onSetParameters callback failed: " << exc.what(); } auto array = ParameterArray(std::move(params)); return array.release(); }; } if (callbacks->onParametersSubscribe) { c_callbacks.on_parameters_subscribe = [](const void* context, const struct foxglove_string* c_names, size_t names_len) { std::vector names; names.reserve(names_len); for (size_t i = 0; i < names_len; ++i) { names.emplace_back(c_names[i].data, c_names[i].len); } try { (static_cast(context))->onParametersSubscribe(names); } catch (const std::exception& exc) { warn() << "onParametersSubscribe callback failed: " << exc.what(); } }; } if (callbacks->onParametersUnsubscribe) { c_callbacks.on_parameters_unsubscribe = [](const void* context, const struct foxglove_string* c_names, size_t names_len) { std::vector names; names.reserve(names_len); for (size_t i = 0; i < names_len; ++i) { names.emplace_back(c_names[i].data, c_names[i].len); } try { (static_cast(context))->onParametersUnsubscribe(names); } catch (const std::exception& exc) { warn() << "onParametersUnsubscribe callback failed: " << exc.what(); } }; } if (callbacks->onConnectionGraphSubscribe) { c_callbacks.on_connection_graph_subscribe = [](const void* context) { try { (static_cast(context))->onConnectionGraphSubscribe(); } catch (const std::exception& exc) { warn() << "onConnectionGraphSubscribe callback failed: " << exc.what(); } }; } if (callbacks->onConnectionGraphUnsubscribe) { c_callbacks.on_connection_graph_unsubscribe = [](const void* context) { try { (static_cast(context))->onConnectionGraphUnsubscribe(); } catch (const std::exception& exc) { warn() << "onConnectionGraphUnsubscribe callback failed: " << exc.what(); } }; } } foxglove_server_options c_options = {}; c_options.context = options.context.getInner(); c_options.name = {options.name.c_str(), options.name.length()}; c_options.host = {options.host.c_str(), options.host.length()}; c_options.port = options.port; c_options.callbacks = has_any_callbacks ? &c_callbacks : nullptr; c_options.capabilities = static_cast>(options.capabilities); std::vector supported_encodings; supported_encodings.reserve(options.supported_encodings.size()); for (const auto& encoding : options.supported_encodings) { supported_encodings.push_back({encoding.c_str(), encoding.length()}); } c_options.supported_encodings = supported_encodings.data(); c_options.supported_encodings_count = supported_encodings.size(); if (options.fetch_asset) { fetch_asset = std::make_unique(options.fetch_asset); c_options.fetch_asset_context = fetch_asset.get(); c_options.fetch_asset = []( const void* context, const struct foxglove_string* c_uri, struct foxglove_fetch_asset_responder* c_responder ) { try { const auto* handler = static_cast(context); std::string_view uri{c_uri->data, c_uri->len}; FetchAssetResponder responder(c_responder); (*handler)(uri, std::move(responder)); } catch (const std::exception& exc) { warn() << "Fetch asset callback failed: " << exc.what(); } }; } foxglove_websocket_server* server = nullptr; foxglove_error error = foxglove_server_start(&c_options, &server); if (error != foxglove_error::FOXGLOVE_ERROR_OK || server == nullptr) { return foxglove::unexpected(static_cast(error)); } return WebSocketServer(server, std::move(callbacks), std::move(fetch_asset)); } WebSocketServer::WebSocketServer( foxglove_websocket_server* server, std::unique_ptr callbacks, std::unique_ptr fetch_asset ) : callbacks_(std::move(callbacks)) , fetch_asset_(std::move(fetch_asset)) , impl_(server, foxglove_server_stop) {} FoxgloveError WebSocketServer::stop() { foxglove_error error = foxglove_server_stop(impl_.release()); return FoxgloveError(error); } uint16_t WebSocketServer::port() const { return foxglove_server_get_port(impl_.get()); } void WebSocketServer::broadcastTime(uint64_t timestamp_nanos) const noexcept { foxglove_server_broadcast_time(impl_.get(), timestamp_nanos); } FoxgloveError WebSocketServer::clearSession(std::optional session_id ) const noexcept { auto c_session_id = session_id ? std::optional{{session_id->data(), session_id->size()}} : std::nullopt; auto error = foxglove_server_clear_session(impl_.get(), c_session_id ? &*c_session_id : nullptr); return FoxgloveError(error); } // NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved) FoxgloveError WebSocketServer::addService(Service&& service) const noexcept { auto error = foxglove_server_add_service(impl_.get(), service.release()); return FoxgloveError(error); } FoxgloveError WebSocketServer::removeService(std::string_view name) const noexcept { auto error = foxglove_server_remove_service(impl_.get(), {name.data(), name.length()}); return FoxgloveError(error); } void WebSocketServer::publishParameterValues(std::vector&& params) { ParameterArray array(std::move(params)); foxglove_server_publish_parameter_values(impl_.get(), array.release()); } void WebSocketServer::publishConnectionGraph(ConnectionGraph& graph) { foxglove_server_publish_connection_graph(impl_.get(), graph.impl_.get()); } FoxgloveError WebSocketServer::publishStatus( WebSocketServerStatusLevel level, std::string_view message, std::optional id ) const noexcept { auto c_id = id ? std::optional{{id->data(), id->size()}} : std::nullopt; auto error = foxglove_server_publish_status( impl_.get(), static_cast(level), {message.data(), message.size()}, c_id ? &*c_id : nullptr ); return FoxgloveError(error); } FoxgloveError WebSocketServer::removeStatus(const std::vector& ids) const { std::vector c_ids; c_ids.reserve(ids.size()); for (const auto& id : ids) { c_ids.push_back({id.data(), id.size()}); } auto error = foxglove_server_remove_status(impl_.get(), c_ids.data(), c_ids.size()); return FoxgloveError(error); } } // namespace foxglove