Skip to content

Commit 41b6a58

Browse files
Merge pull request #2 from garethsb/validate-settings-schema
Add nmos::validate_node_settings/validate_registry_settings
2 parents 69740cf + b303384 commit 41b6a58

8 files changed

Lines changed: 723 additions & 0 deletions

File tree

Development/cmake/NmosCppTest.cmake

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ set(NMOS_CPP_TEST_NMOS_TEST_SOURCES
6060
nmos/test/query_api_test.cpp
6161
nmos/test/sdp_test_utils.cpp
6262
nmos/test/sdp_utils_test.cpp
63+
nmos/test/settings_test.cpp
6364
nmos/test/slog_test.cpp
6465
nmos/test/system_resources_test.cpp
6566
nmos/test/video_jxsv_test.cpp

Development/nmos-cpp-node/main.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,12 @@ int main(int argc, char* argv[])
6767
}
6868
}
6969

70+
// Validate the standard and example-node-specific settings (before inserting
71+
// run-time defaults, so that errors in user-provided settings are reported with
72+
// the offending key rather than as a bare json_exception via the field accessors)
73+
// (throws web::json::json_exception with the offending key in the message)
74+
validate_node_implementation_settings(node_model.settings);
75+
7076
// Prepare run-time default settings (different than header defaults)
7177

7278
nmos::insert_node_default_settings(node_model.settings);

Development/nmos-cpp-node/node_implementation.cpp

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
#include "node_implementation.h"
22

3+
#include <map>
34
#include <boost/range/adaptor/filtered.hpp>
5+
#include <boost/range/adaptor/map.hpp>
46
#include <boost/range/adaptor/transformed.hpp>
57
#include <boost/range/algorithm/find.hpp>
68
#include <boost/range/algorithm/find_first_of.hpp>
@@ -10,6 +12,7 @@
1012
#include <boost/range/join.hpp>
1113
#include "pplx/pplx_utils.h" // for pplx::complete_after, etc.
1214
#include "cpprest/host_utils.h"
15+
#include "cpprest/json_validator.h"
1316
#ifdef HAVE_LLDP
1417
#include "lldp/lldp_manager.h"
1518
#endif
@@ -2574,6 +2577,88 @@ namespace impl
25742577
{
25752578
web::json::push_back(resource.data[nmos::fields::tags][nmos::fields::group_hint], nmos::make_group_hint({ U("example"), resource.type.name + U(' ') + port.name + utility::conversions::details::to_string_t(index) }));
25762579
}
2580+
2581+
// JSON schema covering the example-node-specific impl::fields::* settings; combined with
2582+
// nmos::validate_node_settings, this covers all the properties this example reads from the
2583+
// settings JSON. additionalProperties is not set to false, so all other (standard) settings
2584+
// pass through unchecked, allowing the two validators to be composed.
2585+
// definitions: aliases (in nmos::details::settings_definitions_schema() source order) first, then local
2586+
static const char* node_settings_schema_text = R"-schema-(
2587+
{
2588+
"$schema": "http://json-schema.org/draft-04/schema#",
2589+
"type": "object",
2590+
"definitions": {
2591+
"nonNegativeInteger": { "$ref": "urn:x-nmos-cpp:schemas:defs#/definitions/nonNegativeInteger" },
2592+
"positiveInteger": { "$ref": "urn:x-nmos-cpp:schemas:defs#/definitions/positiveInteger" },
2593+
"rational": { "$ref": "urn:x-nmos-cpp:schemas:defs#/definitions/rational" },
2594+
"tags": { "$ref": "urn:x-nmos-cpp:schemas:defs#/definitions/tags" },
2595+
"uuid": { "$ref": "urn:x-nmos-cpp:schemas:defs#/definitions/uuid" },
2596+
"interlaceMode": { "$ref": "urn:x-nmos-cpp:schemas:defs#/definitions/interlaceMode" },
2597+
"colorspace": { "$ref": "urn:x-nmos-cpp:schemas:defs#/definitions/colorspace" },
2598+
"transferCharacteristic": { "$ref": "urn:x-nmos-cpp:schemas:defs#/definitions/transferCharacteristic" },
2599+
"colorSampling": { "$ref": "urn:x-nmos-cpp:schemas:defs#/definitions/colorSampling" },
2600+
"portKind": { "type": "string", "enum": ["v", "a", "d", "m", "t", "b", "s", "c", "xv", "xa", "xd"] }
2601+
},
2602+
"properties": {
2603+
"node_tags": { "$ref": "#/definitions/tags" },
2604+
"device_tags": { "$ref": "#/definitions/tags" },
2605+
2606+
"how_many": { "$ref": "#/definitions/nonNegativeInteger" },
2607+
"activate_senders": { "type": "boolean" },
2608+
2609+
"senders": { "type": "array", "items": { "$ref": "#/definitions/portKind" } },
2610+
"receivers": { "type": "array", "items": { "$ref": "#/definitions/portKind" } },
2611+
2612+
"frame_rate": { "$ref": "#/definitions/rational" },
2613+
"frame_width": { "$ref": "#/definitions/positiveInteger" },
2614+
"frame_height": { "$ref": "#/definitions/positiveInteger" },
2615+
2616+
"interlace_mode": { "$ref": "#/definitions/interlaceMode" },
2617+
2618+
"colorspace": { "$ref": "#/definitions/colorspace" },
2619+
"transfer_characteristic": { "$ref": "#/definitions/transferCharacteristic" },
2620+
"color_sampling": { "$ref": "#/definitions/colorSampling" },
2621+
"component_depth": { "$ref": "#/definitions/positiveInteger" },
2622+
"video_type": { "type": "string", "pattern": "^video\\/[^\\s\\/]+$" },
2623+
"mxl_video_type": { "type": "string", "enum": ["video/v210", "video/v210a"] },
2624+
2625+
"channel_count": { "$ref": "#/definitions/positiveInteger" },
2626+
2627+
"smpte2022_7": { "type": "boolean" },
2628+
"simulate_status_monitor_activity": { "type": "boolean" },
2629+
2630+
"mxl_domain_id": { "$ref": "#/definitions/uuid" }
2631+
}
2632+
}
2633+
)-schema-";
2634+
2635+
const std::pair<web::uri, web::json::value>& node_settings_schema()
2636+
{
2637+
static const std::pair<web::uri, web::json::value> instance{
2638+
web::uri{ U("urn:x-nmos-cpp:schemas:node-settings") },
2639+
web::json::value::parse(node_settings_schema_text)
2640+
};
2641+
return instance;
2642+
}
2643+
2644+
}
2645+
2646+
void validate_node_implementation_settings(const nmos::settings& settings)
2647+
{
2648+
// delegate validation of the standard properties (see nmos/settings.h)
2649+
nmos::validate_node_settings(settings);
2650+
2651+
// validate the example node-specific impl::fields::* properties
2652+
static const std::map<web::uri, web::json::value> known{
2653+
impl::node_settings_schema(),
2654+
nmos::details::settings_definitions_schema()
2655+
};
2656+
static const web::json::experimental::json_validator validator
2657+
{
2658+
[](const web::uri& wanted) { return known.at(wanted); },
2659+
boost::copy_range<std::vector<web::uri>>(known | boost::adaptors::map_keys)
2660+
};
2661+
validator.validate(settings, impl::node_settings_schema().first);
25772662
}
25782663

25792664
// This constructs all the callbacks used to integrate the example device-specific underlying implementation

Development/nmos-cpp-node/node_implementation.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
#ifndef NMOS_CPP_NODE_NODE_IMPLEMENTATION_H
22
#define NMOS_CPP_NODE_NODE_IMPLEMENTATION_H
33

4+
#include "nmos/settings.h"
5+
46
namespace slog
57
{
68
class base_gate;
@@ -17,6 +19,13 @@ namespace nmos
1719
}
1820
}
1921

22+
// Validates settings for the example node, including both the standard properties (via
23+
// nmos::validate_node_settings) and the additional impl::fields::* settings defined in
24+
// node_implementation.cpp.
25+
// Throws web::json::json_exception, with a message including the offending key (and where
26+
// appropriate the actual value), for incorrect types and out-of-range or unrecognised values.
27+
void validate_node_implementation_settings(const nmos::settings& settings);
28+
2029
// This is an example of how to integrate the nmos-cpp library with a device-specific underlying implementation.
2130
// It constructs and inserts a node resource and some sub-resources into the model, based on the model settings,
2231
// starts background tasks to emit regular events from the temperature event source, and then waits for shutdown.

Development/nmos-cpp-registry/main.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,12 @@ int main(int argc, char* argv[])
6060
}
6161
}
6262

63+
// Validate the standard settings (before inserting run-time defaults, so that
64+
// errors in user-provided settings are reported with the offending key rather
65+
// than as a bare json_exception via the field accessors)
66+
// (throws web::json::json_exception with the offending key in the message)
67+
nmos::validate_registry_settings(registry_model.settings);
68+
6369
// Prepare run-time default settings (different than header defaults)
6470

6571
nmos::insert_registry_default_settings(registry_model.settings);

0 commit comments

Comments
 (0)