Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions _codeql_detected_source_root
74 changes: 74 additions & 0 deletions src/mtconnect/sink/rest_sink/rest_service.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@

#include <regex>

#include <nlohmann/json.hpp>

#include "error.hpp"
#include "mtconnect/configuration/config_options.hpp"
#include "mtconnect/entity/xml_parser.hpp"
Expand Down Expand Up @@ -118,6 +120,7 @@ namespace mtconnect {
createAssetRoutings();
createProbeRoutings();
createPutObservationRoutings();
createConfigRoutings();
createFileRoutings();
m_server->addCommands();

Expand Down Expand Up @@ -435,6 +438,77 @@ namespace mtconnect {
session->writeResponse(std::move(response));
}

void RestService::createConfigRoutings()
{
using namespace rest_sink;
using json = nlohmann::json;

auto handler = [this](SessionPtr session, const RequestPtr request) -> bool {
// Build JSON response with agent configuration
json config;

for (const auto& [key, value] : m_options)
{
// Handle different variant types
std::visit([&config, &key](auto&& arg) {
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, std::monostate>)
{
config[key] = nullptr;
}
else if constexpr (std::is_same_v<T, bool>)
{
config[key] = arg;
}
else if constexpr (std::is_same_v<T, int>)
{
config[key] = arg;
}
else if constexpr (std::is_same_v<T, double>)
{
config[key] = arg;
}
else if constexpr (std::is_same_v<T, std::string>)
{
config[key] = arg;
}
else if constexpr (std::is_same_v<T, Seconds>)
{
config[key] = arg.count();
}
else if constexpr (std::is_same_v<T, Milliseconds>)
{
config[key] = arg.count();
}
else if constexpr (std::is_same_v<T, StringList>)
{
config[key] = arg;
}
else
{
// If compilation fails here, a new type has been added to ConfigOption
// and needs to be handled above
[]<bool flag = false>()
{
static_assert(flag, "Unhandled type in ConfigOption variant");
}();
}
}, value);
}

ResponsePtr response = make_unique<Response>(
rest_sink::status::ok, config.dump(), "application/json");
respond(session, std::move(response), request->m_requestId);
return true;
};

m_server
->addRouting({boost::beast::http::verb::get, "/config", handler})
.document("Agent configuration request",
"Returns the current agent configuration as JSON")
.command("config");
}

void RestService::createFileRoutings()
{
using namespace rest_sink;
Expand Down
2 changes: 2 additions & 0 deletions src/mtconnect/sink/rest_sink/rest_service.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,8 @@ namespace mtconnect {

void createAssetRoutings();

void createConfigRoutings();

// Current Data Collection
std::string fetchCurrentData(const printer::Printer *printer, const FilterSetOpt &filterSet,
const std::optional<SequenceNumber_t> &at, bool pretty = false,
Expand Down
28 changes: 28 additions & 0 deletions test_package/agent_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
#include <stdexcept>
#include <thread>

#include <nlohmann/json.hpp>

#include "agent_test_helper.hpp"
#include "mtconnect/agent.hpp"
#include "mtconnect/asset/file_asset.hpp"
Expand Down Expand Up @@ -2622,3 +2624,29 @@ TEST_F(AgentTest, should_initialize_observaton_to_initial_value_when_available)
ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:PartCount", "0");
}
}

TEST_F(AgentTest, should_return_agent_configuration)
{
m_agentTestHelper->createAgent("/samples/test_config.xml", 8, 4, "2.6", 4, false);

// Test the /config endpoint
auto session = m_agentTestHelper->m_server->createSession(m_agentTestHelper->m_context);
auto request = make_unique<Request>("/config", boost::beast::http::verb::get);

auto routing = m_agentTestHelper->m_server->getRouting(request->m_path, request->m_verb);
ASSERT_TRUE(routing);

routing->m_handler(session, std::move(request));

// Verify response is JSON
ASSERT_EQ(session->m_mimeType, "application/json");
ASSERT_EQ(session->m_code, boost::beast::http::status::ok);

// Parse JSON response
auto json = nlohmann::json::parse(session->m_body);

// Verify key configuration values are present
ASSERT_TRUE(json.contains("Port"));
ASSERT_TRUE(json.contains("BufferSize"));
ASSERT_TRUE(json.contains("SchemaVersion"));
}