Skip to content

Commit 80c608f

Browse files
authored
Enhance IS-12 support (#440)
* Tidy up * Remove unnecessary resource (receiver) type check * Add helper functions to insert and erase control protocol resources * Add comment * Clear local resources after moved to the model
1 parent a3ca89a commit 80c608f

File tree

6 files changed

+122
-82
lines changed

6 files changed

+122
-82
lines changed

Development/nmos-cpp-node/node_implementation.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -285,8 +285,9 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr
285285
{
286286
if (nmos::details::wait_for(model.shutdown_condition, lock, bst::chrono::milliseconds(milliseconds), [&] { return model.shutdown; })) return false;
287287

288+
const auto is_control_protocol_resource = [&resource]() { return nmos::types::all_nc.end() != std::find(nmos::types::all_nc.begin(), nmos::types::all_nc.end(), resource.type); };
288289
const std::pair<nmos::id, nmos::type> id_type{ resource.id, resource.type };
289-
const bool success = insert_resource(resources, std::move(resource)).second;
290+
const bool success = is_control_protocol_resource() ? insert_control_protocol_resource(resources, std::move(resource)).second : insert_resource(resources, std::move(resource)).second;
290291

291292
if (success)
292293
slog::log<slog::severities::info>(gate, SLOG_FLF) << "Updated model with " << id_type;
@@ -312,6 +313,7 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr
312313
insert_resources(resources, resource_);
313314
if (!insert_resource_after(milliseconds, resources, std::move(resource_), gate)) throw node_implementation_init_exception();
314315
}
316+
resource.resources.clear();
315317
};
316318

317319
auto& resources = model.control_protocol_resources;

Development/nmos/control_protocol_utils.cpp

Lines changed: 106 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -174,37 +174,37 @@ namespace nmos
174174
if (datatype_constraints.is_null())
175175
{
176176
auto primitive_validation = [](const nc_name& name, const web::json::value& value)
177+
{
178+
auto is_int16 = [](int32_t value)
179+
{
180+
return value >= (std::numeric_limits<int16_t>::min)()
181+
&& value <= (std::numeric_limits<int16_t>::max)();
182+
};
183+
auto is_uint16 = [](uint32_t value)
177184
{
178-
auto is_int16 = [](int32_t value)
179-
{
180-
return value >= (std::numeric_limits<int16_t>::min)()
181-
&& value <= (std::numeric_limits<int16_t>::max)();
182-
};
183-
auto is_uint16 = [](uint32_t value)
184-
{
185-
return value >= (std::numeric_limits<uint16_t>::min)()
186-
&& value <= (std::numeric_limits<uint16_t>::max)();
187-
};
188-
auto is_float32 = [](double value)
189-
{
190-
return value >= (std::numeric_limits<float_t>::lowest)()
191-
&& value <= (std::numeric_limits<float_t>::max)();
192-
};
193-
194-
if (U("NcBoolean") == name) { return value.is_boolean(); }
195-
if (U("NcInt16") == name && value.is_number()) { return is_int16(value.as_number().to_int32()); }
196-
if (U("NcInt32") == name && value.is_number()) { return value.as_number().is_int32(); }
197-
if (U("NcInt64") == name && value.is_number()) { return value.as_number().is_int64(); }
198-
if (U("NcUint16") == name && value.is_number()) { return is_uint16(value.as_number().to_uint32()); }
199-
if (U("NcUint32") == name && value.is_number()) { return value.as_number().is_uint32(); }
200-
if (U("NcUint64") == name && value.is_number()) { return value.as_number().is_uint64(); }
201-
if (U("NcFloat32") == name && value.is_number()) { return is_float32(value.as_number().to_double()); }
202-
if (U("NcFloat64") == name && value.is_number()) { return !value.as_number().is_integral(); }
203-
if (U("NcString") == name) { return value.is_string(); }
204-
205-
// invalid primitive type
206-
return false;
185+
return value >= (std::numeric_limits<uint16_t>::min)()
186+
&& value <= (std::numeric_limits<uint16_t>::max)();
207187
};
188+
auto is_float32 = [](double value)
189+
{
190+
return value >= (std::numeric_limits<float_t>::lowest)()
191+
&& value <= (std::numeric_limits<float_t>::max)();
192+
};
193+
194+
if (U("NcBoolean") == name) { return value.is_boolean(); }
195+
if (U("NcInt16") == name && value.is_number()) { return is_int16(value.as_number().to_int32()); }
196+
if (U("NcInt32") == name && value.is_number()) { return value.as_number().is_int32(); }
197+
if (U("NcInt64") == name && value.is_number()) { return value.as_number().is_int64(); }
198+
if (U("NcUint16") == name && value.is_number()) { return is_uint16(value.as_number().to_uint32()); }
199+
if (U("NcUint32") == name && value.is_number()) { return value.as_number().is_uint32(); }
200+
if (U("NcUint64") == name && value.is_number()) { return value.as_number().is_uint64(); }
201+
if (U("NcFloat32") == name && value.is_number()) { return is_float32(value.as_number().to_double()); }
202+
if (U("NcFloat64") == name && value.is_number()) { return !value.as_number().is_integral(); }
203+
if (U("NcString") == name) { return value.is_string(); }
204+
205+
// invalid primitive type
206+
return false;
207+
};
208208

209209
// do primitive type constraints validation
210210
const auto& name = nmos::fields::nc::name(params.datatype_descriptor);
@@ -551,13 +551,31 @@ namespace nmos
551551
web::json::push_back(parent[nmos::fields::nc::members],
552552
details::make_nc_block_member_descriptor(nmos::fields::description(child), nmos::fields::nc::role(child), nmos::fields::nc::oid(child), nmos::fields::nc::constant_oid(child), details::parse_nc_class_id(nmos::fields::nc::class_id(child)), nmos::fields::nc::user_label(child), nmos::fields::nc::oid(parent)));
553553

554+
// add to temporary storage until they are moved to the model resources
554555
nc_block_resource.resources.push_back(resource);
555556
}
556557

558+
// insert a control protocol resource
559+
std::pair<resources::iterator, bool> insert_control_protocol_resource(resources& resources, resource&& resource)
560+
{
561+
// set the creation and update timestamps, before inserting the resource
562+
resource.updated = resource.created = nmos::strictly_increasing_update(resources);
563+
564+
auto result = resources.insert(std::move(resource));
565+
// replacement of a deleted or expired resource is also allowed
566+
// (currently, with no further checks on api_version, type, etc.)
567+
if (!result.second && !result.first->has_data())
568+
{
569+
// if the insertion was banned, resource has not been moved from
570+
result.second = resources.replace(result.first, std::move(resource));
571+
}
572+
return result;
573+
}
574+
557575
// modify a control protocol resource, and insert notification event to all subscriptions
558576
bool modify_control_protocol_resource(resources& resources, const id& id, std::function<void(resource&)> modifier, const web::json::value& notification_event)
559577
{
560-
// note, model write lock should aleady be applied by the outer function, so access to control_protocol_resources is OK...
578+
// note, model write lock should already be applied by the outer function, so access to control_protocol_resources is OK...
561579

562580
auto found = resources.find(id);
563581
if (resources.end() == found || !found->has_data()) return false;
@@ -589,7 +607,6 @@ namespace nmos
589607
if (result)
590608
{
591609
auto& modified = *found;
592-
593610
insert_notification_events(resources, modified.version, modified.downgrade_version, modified.type, pre, modified.data, notification_event);
594611
}
595612

@@ -601,6 +618,20 @@ namespace nmos
601618
return result;
602619
}
603620

621+
// erase a control protocol resource
622+
resources::size_type erase_control_protocol_resource(resources& resources, const id& id)
623+
{
624+
// hmm, may be also erasing all it's member blocks?
625+
resources::size_type count = 0;
626+
auto found = resources.find(id);
627+
if (resources.end() != found && found->has_data())
628+
{
629+
resources.erase(found);
630+
++count;
631+
}
632+
return count;
633+
}
634+
604635
// find the control protocol resource which is assoicated with the given IS-04/IS-05/IS-08 resource id
605636
resources::const_iterator find_control_protocol_resource(resources& resources, type type, const id& resource_id)
606637
{
@@ -613,8 +644,7 @@ namespace nmos
613644
auto found_tp = std::find_if(tps.begin(), tps.end(), [resource_id](const web::json::value& touchpoint)
614645
{
615646
auto& resource = nmos::fields::nc::resource(touchpoint);
616-
return (resource_id == nmos::fields::nc::id(resource).as_string()
617-
&& nmos::ncp_nmos_resource_types::receiver.name == nmos::fields::nc::resource_type(resource));
647+
return (resource_id == nmos::fields::nc::id(resource).as_string());
618648
});
619649
return (tps.end() != found_tp);
620650
}
@@ -638,4 +668,47 @@ namespace nmos
638668
details::method_parameter_constraints_validation(arguments.at(name), constraints, { nmos::details::get_datatype_descriptor(type_name, get_control_protocol_datatype_descriptor), get_control_protocol_datatype_descriptor });
639669
}
640670
}
671+
672+
// insert 'value changed', 'sequence item added', 'sequence item changed' or 'sequence item removed' notification events into all grains whose subscriptions match the specified version, type and "pre" or "post" values
673+
// this is used for the IS-12 propertry changed event
674+
void insert_notification_events(nmos::resources& resources, const nmos::api_version& version, const nmos::api_version& downgrade_version, const nmos::type& type, const web::json::value& pre, const web::json::value& post, const web::json::value& event)
675+
{
676+
using web::json::value;
677+
678+
if (pre == post) return;
679+
680+
auto& by_type = resources.get<tags::type>();
681+
const auto subscriptions = by_type.equal_range(details::has_data(nmos::types::subscription));
682+
683+
for (auto it = subscriptions.first; subscriptions.second != it; ++it)
684+
{
685+
// for each subscription
686+
const auto& subscription = *it;
687+
688+
// check whether the resource_path matches the resource type and the query parameters match either the "pre" or "post" resource
689+
690+
const auto resource_path = nmos::fields::resource_path(subscription.data);
691+
const resource_query match(subscription.version, resource_path, nmos::fields::params(subscription.data));
692+
693+
const bool pre_match = match(version, downgrade_version, type, pre, resources);
694+
const bool post_match = match(version, downgrade_version, type, post, resources);
695+
696+
if (!pre_match && !post_match) continue;
697+
698+
// add the event to the grain for each websocket connection to this subscription
699+
700+
for (const auto& id : subscription.sub_resources)
701+
{
702+
auto grain = find_resource(resources, { id, nmos::types::grain });
703+
if (resources.end() == grain) continue; // check websocket connection is still open
704+
705+
resources.modify(grain, [&resources, &event](nmos::resource& grain)
706+
{
707+
auto& events = nmos::fields::message_grain_data(grain.data);
708+
web::json::push_back(events, event);
709+
grain.updated = strictly_increasing_update(resources);
710+
});
711+
}
712+
}
713+
}
641714
}

Development/nmos/control_protocol_utils.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,14 +71,23 @@ namespace nmos
7171
// push control protocol resource into other control protocol NcBlock resource
7272
void push_back(control_protocol_resource& nc_block_resource, const control_protocol_resource& resource);
7373

74+
// insert a control protocol resource
75+
std::pair<resources::iterator, bool> insert_control_protocol_resource(resources& resources, resource&& resource);
76+
7477
// modify a control protocol resource, and insert notification event to all subscriptions
7578
bool modify_control_protocol_resource(resources& resources, const id& id, std::function<void(resource&)> modifier, const web::json::value& notification_event);
7679

80+
// erase a control protocol resource
81+
resources::size_type erase_control_protocol_resource(resources& resources, const id& id);
82+
7783
// find the control protocol resource which is assoicated with the given IS-04/IS-05/IS-08 resource id
7884
resources::const_iterator find_control_protocol_resource(resources& resources, type type, const id& id);
7985

8086
// method parameters constraints validation, may throw nmos::control_protocol_exception
8187
void method_parameters_contraints_validation(const web::json::value& arguments, const web::json::value& nc_method_descriptor, get_control_protocol_datatype_descriptor_handler get_control_protocol_datatype_descriptor);
88+
89+
// insert 'value changed', 'sequence item added', 'sequence item changed' or 'sequence item removed' notification events into all grains whose subscriptions match the specified version, type and "pre" or "post" values
90+
void insert_notification_events(resources& resources, const api_version& version, const api_version& downgrade_version, const type& type, const web::json::value& pre, const web::json::value& post, const web::json::value& event);
8291
}
8392

8493
#endif

Development/nmos/query_utils.cpp

Lines changed: 0 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -577,49 +577,4 @@ namespace nmos
577577
}
578578
}
579579
}
580-
581-
// insert 'value changed', 'sequence item added', 'sequence item changed' or 'sequence item removed' notification events into all grains whose subscriptions match the specified version, type and "pre" or "post" values
582-
// this is used for the IS-12 propertry changed event
583-
void insert_notification_events(nmos::resources& resources, const nmos::api_version& version, const nmos::api_version& downgrade_version, const nmos::type& type, const web::json::value& pre, const web::json::value& post, const web::json::value& event)
584-
{
585-
using web::json::value;
586-
587-
if (pre == post) return;
588-
589-
if (!details::is_queryable_resource(type)) return;
590-
591-
auto& by_type = resources.get<tags::type>();
592-
const auto subscriptions = by_type.equal_range(details::has_data(nmos::types::subscription));
593-
594-
for (auto it = subscriptions.first; subscriptions.second != it; ++it)
595-
{
596-
// for each subscription
597-
const auto& subscription = *it;
598-
599-
// check whether the resource_path matches the resource type and the query parameters match either the "pre" or "post" resource
600-
601-
const auto resource_path = nmos::fields::resource_path(subscription.data);
602-
const resource_query match(subscription.version, resource_path, nmos::fields::params(subscription.data));
603-
604-
const bool pre_match = match(version, downgrade_version, type, pre, resources);
605-
const bool post_match = match(version, downgrade_version, type, post, resources);
606-
607-
if (!pre_match && !post_match) continue;
608-
609-
// add the event to the grain for each websocket connection to this subscription
610-
611-
for (const auto& id : subscription.sub_resources)
612-
{
613-
auto grain = find_resource(resources, { id, nmos::types::grain });
614-
if (resources.end() == grain) continue; // check websocket connection is still open
615-
616-
resources.modify(grain, [&resources, &event](nmos::resource& grain)
617-
{
618-
auto& events = nmos::fields::message_grain_data(grain.data);
619-
web::json::push_back(events, event);
620-
grain.updated = strictly_increasing_update(resources);
621-
});
622-
}
623-
}
624-
}
625580
}

Development/nmos/query_utils.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -114,9 +114,6 @@ namespace nmos
114114
// insert 'added', 'removed' or 'modified' resource events into all grains whose subscriptions match the specified version, type and "pre" or "post" values
115115
void insert_resource_events(nmos::resources& resources, const nmos::api_version& version, const nmos::api_version& downgrade_version, const nmos::type& type, const web::json::value& pre, const web::json::value& post);
116116

117-
// insert 'value changed', 'sequence item added', 'sequence item changed' or 'sequence item removed' notification events into all grains whose subscriptions match the specified version, type and "pre" or "post" values
118-
void insert_notification_events(nmos::resources& resources, const nmos::api_version& version, const nmos::api_version& downgrade_version, const nmos::type& type, const web::json::value& pre, const web::json::value& post, const web::json::value& event);
119-
120117
namespace fields
121118
{
122119
const web::json::field_as_string_or query_rql{ U("query.rql"), {} };

Development/nmos/type.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,10 @@ namespace nmos
4949
const type nc_receiver_monitor{ U("nc_receiver_monitor") };
5050
const type nc_receiver_monitor_protected{ U("nc_receiver_monitor_protected") };
5151
const type nc_ident_beacon{ U("nc_ident_beacon") };
52+
53+
// all Control Protocol resource types
54+
const std::vector<type> all_nc{ nmos::types::nc_block, nmos::types::nc_worker, nmos::types::nc_manager, nmos::types::nc_device_manager, nmos::types::nc_class_manager, nmos::types::nc_receiver_monitor, nmos::types::nc_receiver_monitor_protected, nmos::types::nc_ident_beacon };
55+
5256
}
5357
}
5458

0 commit comments

Comments
 (0)