From 7744ecacca1f2c1237c465f7b4dfa998623d717d Mon Sep 17 00:00:00 2001 From: "Jonathan Thorpe (Sony)" Date: Mon, 22 Apr 2024 13:31:24 +0100 Subject: [PATCH 1/9] Add properties endpoint (cherry picked from commit 8265d1a934f7fd80043f87214fc8e182deed4e97) (cherry picked from commit b78c25f5f91d8a80c9f335a26c4f7f782028ab18) --- Development/nmos/api_utils.h | 3 ++- Development/nmos/configuration_api.cpp | 11 +++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/Development/nmos/api_utils.h b/Development/nmos/api_utils.h index 3ca03b28..3c240412 100644 --- a/Development/nmos/api_utils.h +++ b/Development/nmos/api_utils.h @@ -91,7 +91,8 @@ namespace nmos // Configuration API const route_pattern rolePath = make_route_pattern(U("rolePath"), U("root|root\\.[a-zA-Z0-9\\-_\\.]+")); - + const route_pattern propertyId = make_route_pattern(U("propertyId"), U("^[0-9]+p[0-9]+")); + // Common patterns const route_pattern resourceId = make_route_pattern(U("resourceId"), U("[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}")); } diff --git a/Development/nmos/configuration_api.cpp b/Development/nmos/configuration_api.cpp index 1b92e864..95a19caf 100644 --- a/Development/nmos/configuration_api.cpp +++ b/Development/nmos/configuration_api.cpp @@ -410,6 +410,17 @@ namespace nmos return pplx::task_from_result(true); }); + + configuration_api.support(U("/rolePaths/") + nmos::patterns::rolePath.pattern + U("/properties/") + nmos::patterns::propertyId.pattern + U("/?"), methods::GET, [&model, get_control_protocol_class_descriptor, &gate_](http_request req, http_response res, const string_t& route_path, const route_parameters& parameters) + { + const string_t property_id = parameters.at(nmos::patterns::propertyId.name); + set_error_reply(res, status_codes::NotFound, U("Not Found; ") + property_id); + + return pplx::task_from_result(true); + }); + return configuration_api; } + + } From 5adef6ac7a670a8f4fc58c51652629c22a50b700 Mon Sep 17 00:00:00 2001 From: "Jonathan Thorpe (Sony)" Date: Wed, 24 Apr 2024 17:35:42 +0100 Subject: [PATCH 2/9] Update propertyId regular expression (cherry picked from commit 90598171bc0cba3d819a36b7030cea4a2358c6d0) --- Development/nmos/api_utils.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Development/nmos/api_utils.h b/Development/nmos/api_utils.h index 3c240412..4345d5df 100644 --- a/Development/nmos/api_utils.h +++ b/Development/nmos/api_utils.h @@ -91,7 +91,7 @@ namespace nmos // Configuration API const route_pattern rolePath = make_route_pattern(U("rolePath"), U("root|root\\.[a-zA-Z0-9\\-_\\.]+")); - const route_pattern propertyId = make_route_pattern(U("propertyId"), U("^[0-9]+p[0-9]+")); + const route_pattern propertyId = make_route_pattern(U("propertyId"), U("[0-9]+p[0-9]+")); // Common patterns const route_pattern resourceId = make_route_pattern(U("resourceId"), U("[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}")); From a4f6591dd4a9b58139b6c0e350bb4c08cc6d5083 Mon Sep 17 00:00:00 2001 From: "Jonathan Thorpe (Sony)" Date: Fri, 26 Apr 2024 12:01:50 +0100 Subject: [PATCH 3/9] added /rolePaths/{rolePath}/property/{propertyId}/value and /rolePaths/{rolePath}/property/{propertyId}/descriptor enpoints rolePath/{rolePath/properties/{proportyId}/value endpoint --- Development/nmos/configuration_api.cpp | 111 +++++++++++++++++++++++-- 1 file changed, 106 insertions(+), 5 deletions(-) diff --git a/Development/nmos/configuration_api.cpp b/Development/nmos/configuration_api.cpp index 95a19caf..8c00368f 100644 --- a/Development/nmos/configuration_api.cpp +++ b/Development/nmos/configuration_api.cpp @@ -4,8 +4,10 @@ #include //#include "cpprest/json_validator.h" #include "nmos/api_utils.h" +#include "nmos/control_protocol_methods.h" #include "nmos/control_protocol_resource.h" #include "nmos/control_protocol_state.h" +#include "nmos/control_protocol_typedefs.h" #include "nmos/control_protocol_utils.h" #include "nmos/is14_versions.h" //#include "nmos/json_schema.h" @@ -199,6 +201,15 @@ namespace nmos return get_nc_object(resources, role_path_segments); } + + nc_property_id parse_formatted_property_id(const utility::string_t& property_id) + { + const utility::string_t::size_type delimiter = property_id.find('p'); + utility::string_t level = std::string::npos != delimiter ? property_id.substr(0, delimiter) : L"0"; + utility::string_t index = std::string::npos != delimiter ? property_id.substr(delimiter + 1) : L"0"; + // JRT Hmmmm, what to do if the property_id is not of a form we recognise + return { uint16_t(web::json::value::parse(level).as_integer()), uint16_t(web::json::value::parse(index).as_integer()) }; + } } inline web::http::experimental::listener::api_router make_unmounted_configuration_api(nmos::node_model& model, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, slog::base_gate& gate_) @@ -244,7 +255,7 @@ namespace nmos configuration_api.support(U("/rolePaths/") + nmos::patterns::rolePath.pattern + U("/?"), methods::GET, [&model, &gate_](http_request req, http_response res, const string_t& route_path, const route_parameters& parameters) { - const string_t role_path = parameters.at(nmos::patterns::rolePath.name); + const utility::string_t role_path = parameters.at(nmos::patterns::rolePath.name); auto lock = model.read_lock(); auto& resources = model.control_protocol_resources; @@ -309,7 +320,7 @@ namespace nmos configuration_api.support(U("/rolePaths/") + nmos::patterns::rolePath.pattern + U("/methods/?"), methods::GET, [&model, get_control_protocol_class_descriptor, &gate_](http_request req, http_response res, const string_t& route_path, const route_parameters& parameters) { - const string_t role_path = parameters.at(nmos::patterns::rolePath.name); + const utility::string_t role_path = parameters.at(nmos::patterns::rolePath.name); auto lock = model.read_lock(); auto& resources = model.control_protocol_resources; @@ -410,11 +421,101 @@ namespace nmos return pplx::task_from_result(true); }); - configuration_api.support(U("/rolePaths/") + nmos::patterns::rolePath.pattern + U("/properties/") + nmos::patterns::propertyId.pattern + U("/?"), methods::GET, [&model, get_control_protocol_class_descriptor, &gate_](http_request req, http_response res, const string_t& route_path, const route_parameters& parameters) { - const string_t property_id = parameters.at(nmos::patterns::propertyId.name); - set_error_reply(res, status_codes::NotFound, U("Not Found; ") + property_id); + const utility::string_t property_id = parameters.at(nmos::patterns::propertyId.name); + const utility::string_t role_path = parameters.at(nmos::patterns::rolePath.name); + + auto lock = model.read_lock(); + auto& resources = model.control_protocol_resources; + + const auto& nc_object = details::get_nc_object(resources, role_path); + if (!nc_object.is_null()) + { + //// find the relevant nc_property_descriptor + const auto& property_descriptor = find_property_descriptor(details::parse_formatted_property_id(property_id), details::parse_nc_class_id(nmos::fields::nc::class_id(nc_object)), get_control_protocol_class_descriptor); + if (property_descriptor.is_null()) + { + set_error_reply(res, status_codes::NotFound, U("Not Found; ") + property_id); + } + else + { + set_reply(res, status_codes::OK, nmos::make_sub_routes_body({ U("descriptor/"), U("value/") }, req, res)); + } + } + else + { + set_error_reply(res, status_codes::NotFound, U("Not Found; ") + role_path); + } + + return pplx::task_from_result(true); + }); + + configuration_api.support(U("/rolePaths/") + nmos::patterns::rolePath.pattern + U("/properties/") + nmos::patterns::propertyId.pattern + U("/descriptor/?"), methods::GET, [&model, get_control_protocol_class_descriptor, &gate_](http_request req, http_response res, const string_t& route_path, const route_parameters& parameters) + { + const utility::string_t property_id = parameters.at(nmos::patterns::propertyId.name); + const utility::string_t role_path = parameters.at(nmos::patterns::rolePath.name); + + web::json::value property_value{}; + + auto lock = model.read_lock(); + auto& resources = model.control_protocol_resources; + + const auto& nc_object = details::get_nc_object(resources, role_path); + if (!nc_object.is_null()) + { + //// find the relevant nc_property_descriptor + const auto& property_descriptor = find_property_descriptor(details::parse_formatted_property_id(property_id), details::parse_nc_class_id(nmos::fields::nc::class_id(nc_object)), get_control_protocol_class_descriptor); + if (property_descriptor.is_null()) + { + set_error_reply(res, status_codes::NotFound, U("Not Found; ") + property_id); + } + else + { + set_reply(res, status_codes::OK, property_descriptor); + } + } + else + { + set_error_reply(res, status_codes::NotFound, U("Not Found; ") + role_path); + } + + return pplx::task_from_result(true); + }); + + configuration_api.support(U("/rolePaths/") + nmos::patterns::rolePath.pattern + U("/properties/") + nmos::patterns::propertyId.pattern + U("/value/?"), methods::GET, [&model, get_control_protocol_class_descriptor, &gate_](http_request req, http_response res, const string_t& route_path, const route_parameters& parameters) + { + const utility::string_t property_id = parameters.at(nmos::patterns::propertyId.name); + const utility::string_t role_path = parameters.at(nmos::patterns::rolePath.name); + + web::json::value property_value{}; + + auto lock = model.read_lock(); + auto& resources = model.control_protocol_resources; + + const auto& nc_object = details::get_nc_object(resources, role_path); + if (!nc_object.is_null()) + { + //// find the relevant nc_property_descriptor + const auto& property_descriptor = find_property_descriptor(details::parse_formatted_property_id(property_id), details::parse_nc_class_id(nmos::fields::nc::class_id(nc_object)), get_control_protocol_class_descriptor); + if (property_descriptor.is_null()) + { + set_error_reply(res, status_codes::NotFound, U("Not Found; ") + property_id); + } + else + { + web::json::value response = web::json::value_of({ + { nmos::fields::nc::status, nmos::fields::nc::is_deprecated(property_descriptor) ? nmos::nc_method_status::property_deprecated : nmos::nc_method_status::ok }, + { nmos::fields::nc::value, nc_object.at(nmos::fields::nc::name(property_descriptor)) } + }); + + set_reply(res, status_codes::OK, response); + } + } + else + { + set_error_reply(res, status_codes::NotFound, U("Not Found; ") + role_path); + } return pplx::task_from_result(true); }); From 6788b1f9432087e7022da54ff4e22c61e7a41691 Mon Sep 17 00:00:00 2001 From: "Jonathan Thorpe (Sony)" Date: Fri, 26 Apr 2024 12:33:56 +0100 Subject: [PATCH 4/9] Fixed property id parsing --- Development/nmos/configuration_api.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Development/nmos/configuration_api.cpp b/Development/nmos/configuration_api.cpp index 8c00368f..9798e784 100644 --- a/Development/nmos/configuration_api.cpp +++ b/Development/nmos/configuration_api.cpp @@ -204,10 +204,10 @@ namespace nmos nc_property_id parse_formatted_property_id(const utility::string_t& property_id) { + // Assume that property_id is in form "p" as validated by the propertyId regular expression pattern const utility::string_t::size_type delimiter = property_id.find('p'); - utility::string_t level = std::string::npos != delimiter ? property_id.substr(0, delimiter) : L"0"; - utility::string_t index = std::string::npos != delimiter ? property_id.substr(delimiter + 1) : L"0"; - // JRT Hmmmm, what to do if the property_id is not of a form we recognise + utility::string_t level = property_id.substr(0, delimiter); + utility::string_t index = property_id.substr(delimiter + 1); return { uint16_t(web::json::value::parse(level).as_integer()), uint16_t(web::json::value::parse(index).as_integer()) }; } } From e9306f2f79cdacbb4139a955090eb470c89e340f Mon Sep 17 00:00:00 2001 From: "Jonathan Thorpe (Sony)" Date: Fri, 26 Apr 2024 14:57:42 +0100 Subject: [PATCH 5/9] Expose make_nc_method_result utility function --- Development/nmos/control_protocol_resource.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Development/nmos/control_protocol_resource.h b/Development/nmos/control_protocol_resource.h index a0354226..c43d8297 100644 --- a/Development/nmos/control_protocol_resource.h +++ b/Development/nmos/control_protocol_resource.h @@ -40,6 +40,9 @@ namespace nmos namespace details { + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncmethodresult + web::json::value make_nc_method_result(const nc_method_result& method_result, const web::json::value& value); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncelementid web::json::value make_nc_element_id(const nc_element_id& element_id); nc_element_id parse_nc_element_id(const web::json::value& element_id); From f0016404baaacb5ff344ceb65abc838634cfa60d Mon Sep 17 00:00:00 2001 From: "Jonathan Thorpe (Sony)" Date: Fri, 26 Apr 2024 14:58:05 +0100 Subject: [PATCH 6/9] Refactor method result creation --- Development/nmos/configuration_api.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/Development/nmos/configuration_api.cpp b/Development/nmos/configuration_api.cpp index 9798e784..f1f1356c 100644 --- a/Development/nmos/configuration_api.cpp +++ b/Development/nmos/configuration_api.cpp @@ -504,12 +504,9 @@ namespace nmos } else { - web::json::value response = web::json::value_of({ - { nmos::fields::nc::status, nmos::fields::nc::is_deprecated(property_descriptor) ? nmos::nc_method_status::property_deprecated : nmos::nc_method_status::ok }, - { nmos::fields::nc::value, nc_object.at(nmos::fields::nc::name(property_descriptor)) } - }); + web::json::value method_result = details::make_nc_method_result({ nmos::fields::nc::is_deprecated(property_descriptor) ? nmos::nc_method_status::property_deprecated : nmos::nc_method_status::ok }, nc_object.at(nmos::fields::nc::name(property_descriptor))); - set_reply(res, status_codes::OK, response); + set_reply(res, status_codes::OK, method_result); } } else From c1d3c10e93d9c4079ce359a34124cfda6700a595 Mon Sep 17 00:00:00 2001 From: "Jonathan Thorpe (Sony)" Date: Fri, 26 Apr 2024 16:30:08 +0100 Subject: [PATCH 7/9] Fix descriptor endpoints to return NcMethodResult objects instead of raw descriptors --- Development/nmos/configuration_api.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Development/nmos/configuration_api.cpp b/Development/nmos/configuration_api.cpp index f1f1356c..870eab42 100644 --- a/Development/nmos/configuration_api.cpp +++ b/Development/nmos/configuration_api.cpp @@ -410,7 +410,8 @@ namespace nmos ? details::make_nc_class_descriptor(description, class_id, name, property_descriptors, method_descriptors, event_descriptors) : details::make_nc_class_descriptor(description, class_id, name, fixed_role.as_string(), property_descriptors, method_descriptors, event_descriptors); - set_reply(res, status_codes::OK, class_descriptor); + web::json::value method_result = details::make_nc_method_result({ nmos::nc_method_status::ok }, class_descriptor); + set_reply(res, status_codes::OK, method_result); } } else @@ -472,7 +473,8 @@ namespace nmos } else { - set_reply(res, status_codes::OK, property_descriptor); + web::json::value method_result = details::make_nc_method_result({ nmos::nc_method_status::ok }, property_descriptor); + set_reply(res, status_codes::OK, method_result); } } else From 014cb37c6767722dfcd7dc9eb05e2d7a055e61d5 Mon Sep 17 00:00:00 2001 From: lo-simon Date: Mon, 29 Apr 2024 08:18:09 +0100 Subject: [PATCH 8/9] Tidy up --- Development/nmos/configuration_api.cpp | 56 +++++++++++--------------- 1 file changed, 23 insertions(+), 33 deletions(-) diff --git a/Development/nmos/configuration_api.cpp b/Development/nmos/configuration_api.cpp index 870eab42..13d9b6c6 100644 --- a/Development/nmos/configuration_api.cpp +++ b/Development/nmos/configuration_api.cpp @@ -228,10 +228,8 @@ namespace nmos return pplx::task_from_result(true); }); - configuration_api.support(U("/rolePaths/?"), methods::GET, [&model](http_request req, http_response res, const string_t& route_path, const route_parameters& parameters) + configuration_api.support(U("/rolePaths/?"), methods::GET, [&model](http_request req, http_response res, const string_t&, const route_parameters&) { - using web::json::value; - auto lock = model.read_lock(); auto& resources = model.control_protocol_resources; @@ -253,9 +251,9 @@ namespace nmos return pplx::task_from_result(true); }); - configuration_api.support(U("/rolePaths/") + nmos::patterns::rolePath.pattern + U("/?"), methods::GET, [&model, &gate_](http_request req, http_response res, const string_t& route_path, const route_parameters& parameters) + configuration_api.support(U("/rolePaths/") + nmos::patterns::rolePath.pattern + U("/?"), methods::GET, [&model, &gate_](http_request req, http_response res, const string_t&, const route_parameters& parameters) { - const utility::string_t role_path = parameters.at(nmos::patterns::rolePath.name); + const auto role_path = parameters.at(nmos::patterns::rolePath.name); auto lock = model.read_lock(); auto& resources = model.control_protocol_resources; @@ -272,9 +270,9 @@ namespace nmos return pplx::task_from_result(true); }); - configuration_api.support(U("/rolePaths/") + nmos::patterns::rolePath.pattern + U("/properties/?"), methods::GET, [&model, get_control_protocol_class_descriptor, &gate_](http_request req, http_response res, const string_t& route_path, const route_parameters& parameters) + configuration_api.support(U("/rolePaths/") + nmos::patterns::rolePath.pattern + U("/properties/?"), methods::GET, [&model, get_control_protocol_class_descriptor, &gate_](http_request req, http_response res, const string_t&, const route_parameters& parameters) { - const string_t role_path = parameters.at(nmos::patterns::rolePath.name); + const auto role_path = parameters.at(nmos::patterns::rolePath.name); auto lock = model.read_lock(); auto& resources = model.control_protocol_resources; @@ -318,9 +316,9 @@ namespace nmos return pplx::task_from_result(true); }); - configuration_api.support(U("/rolePaths/") + nmos::patterns::rolePath.pattern + U("/methods/?"), methods::GET, [&model, get_control_protocol_class_descriptor, &gate_](http_request req, http_response res, const string_t& route_path, const route_parameters& parameters) + configuration_api.support(U("/rolePaths/") + nmos::patterns::rolePath.pattern + U("/methods/?"), methods::GET, [&model, get_control_protocol_class_descriptor, &gate_](http_request req, http_response res, const string_t&, const route_parameters& parameters) { - const utility::string_t role_path = parameters.at(nmos::patterns::rolePath.name); + const auto role_path = parameters.at(nmos::patterns::rolePath.name); auto lock = model.read_lock(); auto& resources = model.control_protocol_resources; @@ -330,7 +328,7 @@ namespace nmos { std::set methods_routes; - nc_class_id class_id = nmos::details::parse_nc_class_id(nmos::fields::nc::class_id(nc_object)); + auto class_id = nmos::details::parse_nc_class_id(nmos::fields::nc::class_id(nc_object)); while (!class_id.empty()) { const auto& control_class = get_control_protocol_class_descriptor(class_id); @@ -366,11 +364,9 @@ namespace nmos return pplx::task_from_result(true); }); - configuration_api.support(U("/rolePaths/") + nmos::patterns::rolePath.pattern + U("/descriptor/?"), methods::GET, [&model, get_control_protocol_class_descriptor, &gate_](http_request req, http_response res, const string_t& route_path, const route_parameters& parameters) + configuration_api.support(U("/rolePaths/") + nmos::patterns::rolePath.pattern + U("/descriptor/?"), methods::GET, [&model, get_control_protocol_class_descriptor, &gate_](http_request req, http_response res, const string_t&, const route_parameters& parameters) { - using web::json::value_from_elements; - - const string_t role_path = parameters.at(nmos::patterns::rolePath.name); + const auto role_path = parameters.at(nmos::patterns::rolePath.name); auto lock = model.read_lock(); auto& resources = model.control_protocol_resources; @@ -410,7 +406,7 @@ namespace nmos ? details::make_nc_class_descriptor(description, class_id, name, property_descriptors, method_descriptors, event_descriptors) : details::make_nc_class_descriptor(description, class_id, name, fixed_role.as_string(), property_descriptors, method_descriptors, event_descriptors); - web::json::value method_result = details::make_nc_method_result({ nmos::nc_method_status::ok }, class_descriptor); + auto method_result = details::make_nc_method_result({ nmos::nc_method_status::ok }, class_descriptor); set_reply(res, status_codes::OK, method_result); } } @@ -422,10 +418,10 @@ namespace nmos return pplx::task_from_result(true); }); - configuration_api.support(U("/rolePaths/") + nmos::patterns::rolePath.pattern + U("/properties/") + nmos::patterns::propertyId.pattern + U("/?"), methods::GET, [&model, get_control_protocol_class_descriptor, &gate_](http_request req, http_response res, const string_t& route_path, const route_parameters& parameters) + configuration_api.support(U("/rolePaths/") + nmos::patterns::rolePath.pattern + U("/properties/") + nmos::patterns::propertyId.pattern + U("/?"), methods::GET, [&model, get_control_protocol_class_descriptor, &gate_](http_request req, http_response res, const string_t&, const route_parameters& parameters) { - const utility::string_t property_id = parameters.at(nmos::patterns::propertyId.name); - const utility::string_t role_path = parameters.at(nmos::patterns::rolePath.name); + const auto property_id = parameters.at(nmos::patterns::propertyId.name); + const auto role_path = parameters.at(nmos::patterns::rolePath.name); auto lock = model.read_lock(); auto& resources = model.control_protocol_resources; @@ -433,7 +429,7 @@ namespace nmos const auto& nc_object = details::get_nc_object(resources, role_path); if (!nc_object.is_null()) { - //// find the relevant nc_property_descriptor + // find the relevant nc_property_descriptor const auto& property_descriptor = find_property_descriptor(details::parse_formatted_property_id(property_id), details::parse_nc_class_id(nmos::fields::nc::class_id(nc_object)), get_control_protocol_class_descriptor); if (property_descriptor.is_null()) { @@ -452,12 +448,10 @@ namespace nmos return pplx::task_from_result(true); }); - configuration_api.support(U("/rolePaths/") + nmos::patterns::rolePath.pattern + U("/properties/") + nmos::patterns::propertyId.pattern + U("/descriptor/?"), methods::GET, [&model, get_control_protocol_class_descriptor, &gate_](http_request req, http_response res, const string_t& route_path, const route_parameters& parameters) + configuration_api.support(U("/rolePaths/") + nmos::patterns::rolePath.pattern + U("/properties/") + nmos::patterns::propertyId.pattern + U("/descriptor/?"), methods::GET, [&model, get_control_protocol_class_descriptor, &gate_](http_request req, http_response res, const string_t&, const route_parameters& parameters) { - const utility::string_t property_id = parameters.at(nmos::patterns::propertyId.name); - const utility::string_t role_path = parameters.at(nmos::patterns::rolePath.name); - - web::json::value property_value{}; + const auto property_id = parameters.at(nmos::patterns::propertyId.name); + const auto role_path = parameters.at(nmos::patterns::rolePath.name); auto lock = model.read_lock(); auto& resources = model.control_protocol_resources; @@ -465,7 +459,7 @@ namespace nmos const auto& nc_object = details::get_nc_object(resources, role_path); if (!nc_object.is_null()) { - //// find the relevant nc_property_descriptor + // find the relevant nc_property_descriptor const auto& property_descriptor = find_property_descriptor(details::parse_formatted_property_id(property_id), details::parse_nc_class_id(nmos::fields::nc::class_id(nc_object)), get_control_protocol_class_descriptor); if (property_descriptor.is_null()) { @@ -485,12 +479,10 @@ namespace nmos return pplx::task_from_result(true); }); - configuration_api.support(U("/rolePaths/") + nmos::patterns::rolePath.pattern + U("/properties/") + nmos::patterns::propertyId.pattern + U("/value/?"), methods::GET, [&model, get_control_protocol_class_descriptor, &gate_](http_request req, http_response res, const string_t& route_path, const route_parameters& parameters) + configuration_api.support(U("/rolePaths/") + nmos::patterns::rolePath.pattern + U("/properties/") + nmos::patterns::propertyId.pattern + U("/value/?"), methods::GET, [&model, get_control_protocol_class_descriptor, &gate_](http_request req, http_response res, const string_t&, const route_parameters& parameters) { - const utility::string_t property_id = parameters.at(nmos::patterns::propertyId.name); - const utility::string_t role_path = parameters.at(nmos::patterns::rolePath.name); - - web::json::value property_value{}; + const auto property_id = parameters.at(nmos::patterns::propertyId.name); + const auto role_path = parameters.at(nmos::patterns::rolePath.name); auto lock = model.read_lock(); auto& resources = model.control_protocol_resources; @@ -498,7 +490,7 @@ namespace nmos const auto& nc_object = details::get_nc_object(resources, role_path); if (!nc_object.is_null()) { - //// find the relevant nc_property_descriptor + // find the relevant nc_property_descriptor const auto& property_descriptor = find_property_descriptor(details::parse_formatted_property_id(property_id), details::parse_nc_class_id(nmos::fields::nc::class_id(nc_object)), get_control_protocol_class_descriptor); if (property_descriptor.is_null()) { @@ -521,6 +513,4 @@ namespace nmos return configuration_api; } - - } From 514468f4fae9c4797379163d543a0de9e6f6bd4b Mon Sep 17 00:00:00 2001 From: lo-simon Date: Mon, 29 Apr 2024 09:04:35 +0100 Subject: [PATCH 9/9] Add common functions and rename get_nc_object to get_nc_resource --- Development/nmos/configuration_api.cpp | 92 +++++++++++++++----------- 1 file changed, 54 insertions(+), 38 deletions(-) diff --git a/Development/nmos/configuration_api.cpp b/Development/nmos/configuration_api.cpp index 13d9b6c6..56bea7ef 100644 --- a/Development/nmos/configuration_api.cpp +++ b/Development/nmos/configuration_api.cpp @@ -161,7 +161,7 @@ namespace nmos return web::json::value{}; } - web::json::value get_nc_object(const resources& resources, std::list& role_path_segments) + web::json::value get_nc_resource(const resources& resources, std::list& role_path_segments) { auto resource = nmos::find_resource(resources, utility::s2us(std::to_string(nmos::root_block_oid))); if (resources.end() != resource) @@ -193,23 +193,50 @@ namespace nmos return web::json::value{}; } - web::json::value get_nc_object(const resources& resources, const utility::string_t& role_path) + web::json::value get_nc_resource(const resources& resources, const utility::string_t& role_path) { // tokenize the role_path with the '.' delimiter std::list role_path_segments; boost::algorithm::split(role_path_segments, role_path, [](utility::char_t c) { return '.' == c; }); - return get_nc_object(resources, role_path_segments); + return get_nc_resource(resources, role_path_segments); } nc_property_id parse_formatted_property_id(const utility::string_t& property_id) { // Assume that property_id is in form "p" as validated by the propertyId regular expression pattern const utility::string_t::size_type delimiter = property_id.find('p'); - utility::string_t level = property_id.substr(0, delimiter); - utility::string_t index = property_id.substr(delimiter + 1); + auto level = property_id.substr(0, delimiter); + auto index = property_id.substr(delimiter + 1); return { uint16_t(web::json::value::parse(level).as_integer()), uint16_t(web::json::value::parse(index).as_integer()) }; } + + // format nc_property_id to the form of "p" + utility::string_t make_formatted_property_id(const web::json::value& property_descriptor) + { + auto property_id = nmos::fields::nc::id(property_descriptor); + utility::ostringstream_t os; + os << nmos::fields::nc::level(property_id) << 'p' << nmos::fields::nc::index(property_id); + return os.str(); + } + + nc_method_id parse_formatted_method_id(const utility::string_t& method_id) + { + // Assume that method_id is in form "m" as validated by the methodId regular expression pattern + const utility::string_t::size_type delimiter = method_id.find('m'); + auto level = method_id.substr(0, delimiter); + auto index = method_id.substr(delimiter + 1); + return { uint16_t(web::json::value::parse(level).as_integer()), uint16_t(web::json::value::parse(index).as_integer()) }; + } + + // format nc_method_id to the form of "m" + utility::string_t make_formatted_method_id(const web::json::value& method_descriptor) + { + auto method_id = nmos::fields::nc::id(method_descriptor); + utility::ostringstream_t os; + os << nmos::fields::nc::level(method_id) << 'm' << nmos::fields::nc::index(method_id); + return os.str(); + } } inline web::http::experimental::listener::api_router make_unmounted_configuration_api(nmos::node_model& model, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, slog::base_gate& gate_) @@ -258,7 +285,7 @@ namespace nmos auto lock = model.read_lock(); auto& resources = model.control_protocol_resources; - if (!details::get_nc_object(resources, role_path).is_null()) + if (!details::get_nc_resource(resources, role_path).is_null()) { set_reply(res, status_codes::OK, nmos::make_sub_routes_body({ U("bulkProperties/"), U("descriptor/"), U("methods/"), U("properties/") }, req, res)); } @@ -277,12 +304,12 @@ namespace nmos auto lock = model.read_lock(); auto& resources = model.control_protocol_resources; - const auto& nc_object = details::get_nc_object(resources, role_path); - if (!nc_object.is_null()) + const auto& resource = details::get_nc_resource(resources, role_path); + if (!resource.is_null()) { std::set properties_routes; - auto class_id = nmos::details::parse_nc_class_id(nmos::fields::nc::class_id(nc_object)); + auto class_id = nmos::details::parse_nc_class_id(nmos::fields::nc::class_id(resource)); while (!class_id.empty()) { const auto& control_class = get_control_protocol_class_descriptor(class_id); @@ -290,15 +317,7 @@ namespace nmos auto properties_route = boost::copy_range>(property_descriptors | boost::adaptors::transformed([](const web::json::value& property_descriptor) { - auto make_property_id = [](const web::json::value& property_descriptor) - { - auto property_id = nmos::fields::nc::id(property_descriptor); - utility::ostringstream_t os; - os << nmos::fields::nc::level(property_id) << 'p' << nmos::fields::nc::index(property_id); - return os.str(); - }; - - return make_property_id(property_descriptor) + U("/"); + return details::make_formatted_property_id(property_descriptor) + U("/"); })); properties_routes.insert(properties_route.begin(), properties_route.end()); @@ -323,12 +342,12 @@ namespace nmos auto lock = model.read_lock(); auto& resources = model.control_protocol_resources; - const auto& nc_object = details::get_nc_object(resources, role_path); - if (!nc_object.is_null()) + const auto& resource = details::get_nc_resource(resources, role_path); + if (!resource.is_null()) { std::set methods_routes; - auto class_id = nmos::details::parse_nc_class_id(nmos::fields::nc::class_id(nc_object)); + auto class_id = nmos::details::parse_nc_class_id(nmos::fields::nc::class_id(resource)); while (!class_id.empty()) { const auto& control_class = get_control_protocol_class_descriptor(class_id); @@ -340,10 +359,7 @@ namespace nmos { // method tuple definition described in control_protocol_handlers.h auto& nc_method_descriptor = std::get<0>(method); - auto method_id = nmos::fields::nc::id(nc_method_descriptor); - utility::ostringstream_t os; - os << nmos::fields::nc::level(method_id) << 'm' << nmos::fields::nc::index(method_id); - return os.str(); + return details::make_formatted_method_id(nc_method_descriptor); }; return make_method_id(method) + U("/"); @@ -371,10 +387,10 @@ namespace nmos auto lock = model.read_lock(); auto& resources = model.control_protocol_resources; - const auto& nc_object = details::get_nc_object(resources, role_path); - if (!nc_object.is_null()) + const auto& resource = details::get_nc_resource(resources, role_path); + if (!resource.is_null()) { - nc_class_id class_id = nmos::details::parse_nc_class_id(nmos::fields::nc::class_id(nc_object)); + nc_class_id class_id = nmos::details::parse_nc_class_id(nmos::fields::nc::class_id(resource)); if (!class_id.empty()) { @@ -426,11 +442,11 @@ namespace nmos auto lock = model.read_lock(); auto& resources = model.control_protocol_resources; - const auto& nc_object = details::get_nc_object(resources, role_path); - if (!nc_object.is_null()) + const auto& resource = details::get_nc_resource(resources, role_path); + if (!resource.is_null()) { // find the relevant nc_property_descriptor - const auto& property_descriptor = find_property_descriptor(details::parse_formatted_property_id(property_id), details::parse_nc_class_id(nmos::fields::nc::class_id(nc_object)), get_control_protocol_class_descriptor); + const auto& property_descriptor = find_property_descriptor(details::parse_formatted_property_id(property_id), details::parse_nc_class_id(nmos::fields::nc::class_id(resource)), get_control_protocol_class_descriptor); if (property_descriptor.is_null()) { set_error_reply(res, status_codes::NotFound, U("Not Found; ") + property_id); @@ -456,11 +472,11 @@ namespace nmos auto lock = model.read_lock(); auto& resources = model.control_protocol_resources; - const auto& nc_object = details::get_nc_object(resources, role_path); - if (!nc_object.is_null()) + const auto& resource = details::get_nc_resource(resources, role_path); + if (!resource.is_null()) { // find the relevant nc_property_descriptor - const auto& property_descriptor = find_property_descriptor(details::parse_formatted_property_id(property_id), details::parse_nc_class_id(nmos::fields::nc::class_id(nc_object)), get_control_protocol_class_descriptor); + const auto& property_descriptor = find_property_descriptor(details::parse_formatted_property_id(property_id), details::parse_nc_class_id(nmos::fields::nc::class_id(resource)), get_control_protocol_class_descriptor); if (property_descriptor.is_null()) { set_error_reply(res, status_codes::NotFound, U("Not Found; ") + property_id); @@ -487,18 +503,18 @@ namespace nmos auto lock = model.read_lock(); auto& resources = model.control_protocol_resources; - const auto& nc_object = details::get_nc_object(resources, role_path); - if (!nc_object.is_null()) + const auto& resource = details::get_nc_resource(resources, role_path); + if (!resource.is_null()) { // find the relevant nc_property_descriptor - const auto& property_descriptor = find_property_descriptor(details::parse_formatted_property_id(property_id), details::parse_nc_class_id(nmos::fields::nc::class_id(nc_object)), get_control_protocol_class_descriptor); + const auto& property_descriptor = find_property_descriptor(details::parse_formatted_property_id(property_id), details::parse_nc_class_id(nmos::fields::nc::class_id(resource)), get_control_protocol_class_descriptor); if (property_descriptor.is_null()) { set_error_reply(res, status_codes::NotFound, U("Not Found; ") + property_id); } else { - web::json::value method_result = details::make_nc_method_result({ nmos::fields::nc::is_deprecated(property_descriptor) ? nmos::nc_method_status::property_deprecated : nmos::nc_method_status::ok }, nc_object.at(nmos::fields::nc::name(property_descriptor))); + web::json::value method_result = details::make_nc_method_result({ nmos::fields::nc::is_deprecated(property_descriptor) ? nmos::nc_method_status::property_deprecated : nmos::nc_method_status::ok }, resource.at(nmos::fields::nc::name(property_descriptor))); set_reply(res, status_codes::OK, method_result); }