From 7ef9d38df965f73e6d2faea39606f93d822acc49 Mon Sep 17 00:00:00 2001 From: Robert Brenick Date: Thu, 4 Dec 2025 12:56:24 +0100 Subject: [PATCH] Updates to RESTBridge --- atos/modules/RESTBridge/src/restbridge.cpp | 91 +++++++++++----------- atos_interfaces | 2 +- docker-compose-bridge.yml | 1 + docs/Usage/Modules/RESTBridge.md | 47 +++++++++++ mkdocs.yml | 1 + 5 files changed, 96 insertions(+), 46 deletions(-) create mode 100644 docs/Usage/Modules/RESTBridge.md diff --git a/atos/modules/RESTBridge/src/restbridge.cpp b/atos/modules/RESTBridge/src/restbridge.cpp index 5c263fb79..523ebda8e 100644 --- a/atos/modules/RESTBridge/src/restbridge.cpp +++ b/atos/modules/RESTBridge/src/restbridge.cpp @@ -4,62 +4,63 @@ using namespace ROSChannels; using namespace std::chrono_literals; using namespace std::placeholders; -RESTBridge::RESTBridge() - : Module(moduleName), - customCommandActionMsgSub( - *this, std::bind(&RESTBridge::onCustomCommandAction, this, _1)) { - curl_global_init(CURL_GLOBAL_ALL); - curl_handle = curl_easy_init(); +RESTBridge::RESTBridge() : + Module(moduleName), + customCommandActionMsgSub(*this, std::bind(&RESTBridge::onCustomCommandAction, this, _1)) { + curl_global_init(CURL_GLOBAL_ALL); + curl_handle = curl_easy_init(); } RESTBridge::~RESTBridge() { - curl_easy_cleanup(curl_handle); - curl_global_cleanup(); + curl_easy_cleanup(curl_handle); + curl_global_cleanup(); } -void RESTBridge::onCustomCommandAction( - const atos_interfaces::msg::CustomCommandAction::SharedPtr msg) { - if (msg->type == atos_interfaces::msg::CustomCommandAction::POST_JSON) { - RCLCPP_INFO(get_logger(), "Received POST_JSON command: %s", - msg->content.c_str()); - json jsonData = parseJsonData(msg->content); - POST(jsonData["endpoint"].get(), jsonData["data"]); - } +void RESTBridge::onCustomCommandAction(const atos_interfaces::msg::CustomCommandAction::SharedPtr msg) { + if (msg->type == atos_interfaces::msg::CustomCommandAction::POST) { + RCLCPP_INFO(get_logger(), "Received POST command: %s", msg->content.c_str()); + json jsonData = parseJsonData(msg->content); + POST(jsonData["endpoint"].get(), jsonData["data"]); + } } -json RESTBridge::parseJsonData(std::string &msg) { - // Parse the message and return the REST API message - std::replace(msg.begin(), msg.end(), '\'', - '\"'); // Replace single quotes with double quotes to be able to - // parse the message - json j = json::parse(msg); - return j; +json RESTBridge::parseJsonData(std::string& msg) { + // Parse the message and return the REST API message + std::replace(msg.begin(), + msg.end(), + '\'', + '\"'); // Replace single quotes with double quotes to be able to + // parse the message + json j = json::parse(msg); + return j; } -void RESTBridge::POST(const std::string &endpoint, const json &data) { - // Send A POST request to the specified endpoint with the specified data, Use - // hardcoded headers for now - CURLcode res; +void RESTBridge::POST(const std::string& endpoint, const json& data) { + // Send A POST request to the specified endpoint with the specified data, Use + // hardcoded headers for now + CURLcode res; - if (curl_handle) { - std::string json_str = data.dump(); // Store the JSON string - const char *json_data = json_str.c_str(); // Get the C-string pointer - curl_easy_setopt(curl_handle, CURLOPT_URL, endpoint.c_str()); - curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDS, json_data); + if (curl_handle) { + std::string json_str = data.dump(); // Store the JSON string + const char* json_data = json_str.c_str(); // Get the C-string pointer + curl_easy_setopt(curl_handle, CURLOPT_URL, endpoint.c_str()); + curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDS, json_data); - struct curl_slist *headers = NULL; - headers = curl_slist_append(headers, "Accept: application/json"); - headers = curl_slist_append(headers, "Content-Type: application/json"); - headers = curl_slist_append(headers, "charset: utf-8"); - curl_easy_setopt(curl_handle, CURLOPT_HTTPHEADER, headers); + struct curl_slist* headers = NULL; + headers = curl_slist_append(headers, "Accept: application/json"); + headers = curl_slist_append(headers, "Content-Type: application/json"); + headers = curl_slist_append(headers, "charset: utf-8"); + curl_easy_setopt(curl_handle, CURLOPT_HTTPHEADER, headers); - // Perform the request, res will get the return code - res = curl_easy_perform(curl_handle); + // Perform the request, res will get the return code + res = curl_easy_perform(curl_handle); - // Check for errors - if (res != CURLE_OK) { - RCLCPP_ERROR(get_logger(), "curl_easy_perform() failed: %s\n", - curl_easy_strerror(res)); - } - } + // Check for errors + if (res != CURLE_OK) { + RCLCPP_ERROR(get_logger(), "curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); + } + curl_slist_free_all(headers); + } else { + RCLCPP_ERROR(get_logger(), "curl_handle is NULL, cannot send POST request"); + } } diff --git a/atos_interfaces b/atos_interfaces index 341eef356..f75c6abba 160000 --- a/atos_interfaces +++ b/atos_interfaces @@ -1 +1 @@ -Subproject commit 341eef356f63eb7be7741fec2c27c92f63ccc0ce +Subproject commit f75c6abba03c5dcd589752e4a60ed44393e413cd diff --git a/docker-compose-bridge.yml b/docker-compose-bridge.yml index 2ce2cd6b5..79fc37b52 100644 --- a/docker-compose-bridge.yml +++ b/docker-compose-bridge.yml @@ -27,6 +27,7 @@ services: - "443:443" - "9090:9090" - "8765:8765" + - "8000:8000" command: bash -c "source /root/atos_ws/install/setup.sh ; ros2 launch atos launch_basic.py insecure:=True" foxglove-studio: image: ghcr.io/foxglove/studio:1.76 diff --git a/docs/Usage/Modules/RESTBridge.md b/docs/Usage/Modules/RESTBridge.md new file mode 100644 index 000000000..c3b614c9e --- /dev/null +++ b/docs/Usage/Modules/RESTBridge.md @@ -0,0 +1,47 @@ +# RESTBridge + +## About the module +RESTBridge is a module that allows you to send HTTP requests to a REST API through ATOS. The module utilize OpenScenario CustomCommandActions to specify the type of request (Currently POST and DELETE are supported) and the content of the request. + +## Example OpenScenario + +```xml + + + + {"endpoint": "http://web_server/set_some_value", "data": {"some_key": "some_value"}} + + + + + + + + + + + + + + + + + + + + + +``` + +### CustomCommandAction + +type: POST or DELETE +data field: + +```json +{ + "endpoint": "http://web_server/set_some_value", # Required. The endpoint to send the request to. + "data": {"some_key": "some_value"} # Optional. The data to send in the request. +} +``` + diff --git a/mkdocs.yml b/mkdocs.yml index 8265a5673..585b74f5c 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -28,6 +28,7 @@ nav: - "Usage/Modules/IntegrationTesting.md" - "Usage/Modules/JournalControl.md" - "Usage/Modules/MQTTBridge.md" + - "Usage/Modules/RESTBridge.md" - "Usage/Modules/OSIAdapter.md" - "Usage/Modules/ObjectControl.md" - "Usage/Modules/PointcloudPublisher.md"