Skip to content
Merged
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 Development/cmake/NmosCppTest.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ set(NMOS_CPP_TEST_NMOS_TEST_SOURCES
nmos/test/query_api_test.cpp
nmos/test/sdp_test_utils.cpp
nmos/test/sdp_utils_test.cpp
nmos/test/settings_test.cpp
nmos/test/slog_test.cpp
nmos/test/system_resources_test.cpp
nmos/test/video_jxsv_test.cpp
Expand Down
6 changes: 6 additions & 0 deletions Development/nmos-cpp-node/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,12 @@ int main(int argc, char* argv[])
}
}

// Validate the standard and example-node-specific settings (before inserting
// run-time defaults, so that errors in user-provided settings are reported with
// the offending key rather than as a bare json_exception via the field accessors)
// (throws web::json::json_exception with the offending key in the message)
validate_node_implementation_settings(node_model.settings);

// Prepare run-time default settings (different than header defaults)

nmos::insert_node_default_settings(node_model.settings);
Expand Down
85 changes: 85 additions & 0 deletions Development/nmos-cpp-node/node_implementation.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#include "node_implementation.h"

#include <map>
#include <boost/range/adaptor/filtered.hpp>
#include <boost/range/adaptor/map.hpp>
#include <boost/range/adaptor/transformed.hpp>
#include <boost/range/algorithm/find.hpp>
#include <boost/range/algorithm/find_first_of.hpp>
Expand All @@ -10,6 +12,7 @@
#include <boost/range/join.hpp>
#include "pplx/pplx_utils.h" // for pplx::complete_after, etc.
#include "cpprest/host_utils.h"
#include "cpprest/json_validator.h"
#ifdef HAVE_LLDP
#include "lldp/lldp_manager.h"
#endif
Expand Down Expand Up @@ -2574,6 +2577,88 @@ namespace impl
{
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) }));
}

// JSON schema covering the example-node-specific impl::fields::* settings; combined with
// nmos::validate_node_settings, this covers all the properties this example reads from the
// settings JSON. additionalProperties is not set to false, so all other (standard) settings
// pass through unchecked, allowing the two validators to be composed.
// definitions: aliases (in nmos::details::settings_definitions_schema() source order) first, then local
static const char* node_settings_schema_text = R"-schema-(
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"definitions": {
"nonNegativeInteger": { "$ref": "urn:x-nmos-cpp:schemas:defs#/definitions/nonNegativeInteger" },
"positiveInteger": { "$ref": "urn:x-nmos-cpp:schemas:defs#/definitions/positiveInteger" },
"rational": { "$ref": "urn:x-nmos-cpp:schemas:defs#/definitions/rational" },
"tags": { "$ref": "urn:x-nmos-cpp:schemas:defs#/definitions/tags" },
"uuid": { "$ref": "urn:x-nmos-cpp:schemas:defs#/definitions/uuid" },
"interlaceMode": { "$ref": "urn:x-nmos-cpp:schemas:defs#/definitions/interlaceMode" },
"colorspace": { "$ref": "urn:x-nmos-cpp:schemas:defs#/definitions/colorspace" },
"transferCharacteristic": { "$ref": "urn:x-nmos-cpp:schemas:defs#/definitions/transferCharacteristic" },
"colorSampling": { "$ref": "urn:x-nmos-cpp:schemas:defs#/definitions/colorSampling" },
"portKind": { "type": "string", "enum": ["v", "a", "d", "m", "t", "b", "s", "c", "xv", "xa", "xd"] }
},
"properties": {
"node_tags": { "$ref": "#/definitions/tags" },
"device_tags": { "$ref": "#/definitions/tags" },

"how_many": { "$ref": "#/definitions/nonNegativeInteger" },
"activate_senders": { "type": "boolean" },

"senders": { "type": "array", "items": { "$ref": "#/definitions/portKind" } },
"receivers": { "type": "array", "items": { "$ref": "#/definitions/portKind" } },

"frame_rate": { "$ref": "#/definitions/rational" },
"frame_width": { "$ref": "#/definitions/positiveInteger" },
"frame_height": { "$ref": "#/definitions/positiveInteger" },

"interlace_mode": { "$ref": "#/definitions/interlaceMode" },

"colorspace": { "$ref": "#/definitions/colorspace" },
"transfer_characteristic": { "$ref": "#/definitions/transferCharacteristic" },
"color_sampling": { "$ref": "#/definitions/colorSampling" },
"component_depth": { "$ref": "#/definitions/positiveInteger" },
"video_type": { "type": "string", "pattern": "^video\\/[^\\s\\/]+$" },
"mxl_video_type": { "type": "string", "enum": ["video/v210", "video/v210a"] },

"channel_count": { "$ref": "#/definitions/positiveInteger" },

"smpte2022_7": { "type": "boolean" },
"simulate_status_monitor_activity": { "type": "boolean" },

"mxl_domain_id": { "$ref": "#/definitions/uuid" }
}
}
)-schema-";

const std::pair<web::uri, web::json::value>& node_settings_schema()
{
static const std::pair<web::uri, web::json::value> instance{
web::uri{ U("urn:x-nmos-cpp:schemas:node-settings") },
web::json::value::parse(node_settings_schema_text)
};
return instance;
}

}

void validate_node_implementation_settings(const nmos::settings& settings)
{
// delegate validation of the standard properties (see nmos/settings.h)
nmos::validate_node_settings(settings);

// validate the example node-specific impl::fields::* properties
static const std::map<web::uri, web::json::value> known{
impl::node_settings_schema(),
nmos::details::settings_definitions_schema()
};
static const web::json::experimental::json_validator validator
{
[](const web::uri& wanted) { return known.at(wanted); },
boost::copy_range<std::vector<web::uri>>(known | boost::adaptors::map_keys)
};
validator.validate(settings, impl::node_settings_schema().first);
}

// This constructs all the callbacks used to integrate the example device-specific underlying implementation
Expand Down
9 changes: 9 additions & 0 deletions Development/nmos-cpp-node/node_implementation.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#ifndef NMOS_CPP_NODE_NODE_IMPLEMENTATION_H
#define NMOS_CPP_NODE_NODE_IMPLEMENTATION_H

#include "nmos/settings.h"

namespace slog
{
class base_gate;
Expand All @@ -17,6 +19,13 @@ namespace nmos
}
}

// Validates settings for the example node, including both the standard properties (via
// nmos::validate_node_settings) and the additional impl::fields::* settings defined in
// node_implementation.cpp.
// Throws web::json::json_exception, with a message including the offending key (and where
// appropriate the actual value), for incorrect types and out-of-range or unrecognised values.
void validate_node_implementation_settings(const nmos::settings& settings);

// This is an example of how to integrate the nmos-cpp library with a device-specific underlying implementation.
// It constructs and inserts a node resource and some sub-resources into the model, based on the model settings,
// starts background tasks to emit regular events from the temperature event source, and then waits for shutdown.
Expand Down
6 changes: 6 additions & 0 deletions Development/nmos-cpp-registry/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,12 @@ int main(int argc, char* argv[])
}
}

// Validate the standard settings (before inserting run-time defaults, so that
// errors in user-provided settings are reported with the offending key rather
// than as a bare json_exception via the field accessors)
// (throws web::json::json_exception with the offending key in the message)
nmos::validate_registry_settings(registry_model.settings);

// Prepare run-time default settings (different than header defaults)

nmos::insert_registry_default_settings(registry_model.settings);
Expand Down
Loading
Loading