Skip to content

Commit

Permalink
Fix non-standard class's method handing
Browse files Browse the repository at this point in the history
  • Loading branch information
lo-simon committed Nov 7, 2023
1 parent cbedf53 commit d21ca75
Show file tree
Hide file tree
Showing 10 changed files with 55 additions and 60 deletions.
2 changes: 1 addition & 1 deletion Development/nmos-cpp-node/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ int main(int argc, char* argv[])
{
node_implementation.on_get_control_class(nmos::make_get_control_protocol_class_handler(control_protocol_state));
node_implementation.on_get_control_datatype(nmos::make_get_control_protocol_datatype_handler(control_protocol_state));
node_implementation.on_get_control_protocol_methods(nmos::make_get_control_protocol_methods_handler(control_protocol_state));
node_implementation.on_get_control_protocol_method(nmos::make_get_control_protocol_method_handler(control_protocol_state));
}

// Set up the node server
Expand Down
12 changes: 9 additions & 3 deletions Development/nmos-cpp-node/node_implementation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1002,12 +1002,16 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr

auto example_method_with_no_args = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, slog::base_gate& gate)
{
// note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK...

slog::log<slog::severities::more_info>(gate, SLOG_FLF) << "Executing the example method with no arguments";

return nmos::make_control_protocol_message_response(handle, { nmos::nc_method_status::ok });
};
auto example_method_with_simple_args = [&](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, slog::base_gate& gate)
auto example_method_with_simple_args = [enum_arg, string_arg, number_arg, boolean_arg, make_string_example_argument_constraints, make_number_example_argument_constraints](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, slog::base_gate& gate)
{
// note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK...

slog::log<slog::severities::more_info>(gate, SLOG_FLF) << "Executing the example method with simple arguments:"
<< " enum_arg: "
<< enum_arg(arguments).to_int32()
Expand All @@ -1028,16 +1032,18 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr

return nmos::make_control_protocol_message_response(handle, { nmos::nc_method_status::ok });
};
auto example_method_with_object_args = [&](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, slog::base_gate& gate)
auto example_method_with_object_args = [obj_arg](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, slog::base_gate& gate)
{
// note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK...

slog::log<slog::severities::more_info>(gate, SLOG_FLF) << "Executing the example method with object argument:"
<< " obj_arg: "
<< obj_arg(arguments).serialize();

return nmos::make_control_protocol_message_response(handle, { nmos::nc_method_status::ok });
};
// Example control class methods
std::vector<std::pair<web::json::value, nmos::experimental::method>> example_control_methods =
std::vector<std::pair<web::json::value, nmos::experimental::method_handler>> example_control_methods =
{
{ nmos::experimental::make_control_class_method(U("Example method with no arguments"), { 3, 1 }, U("MethodNoArgs"), U("NcMethodResult"), {}, false), example_method_with_no_args },
{ nmos::experimental::make_control_class_method(U("Example method with simple arguments"), { 3, 2 }, U("MethodSimpleArgs"), U("NcMethodResult"),
Expand Down
26 changes: 18 additions & 8 deletions Development/nmos/control_protocol_handlers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,21 +38,31 @@ namespace nmos
};
}

get_control_protocol_methods_handler make_get_control_protocol_methods_handler(experimental::control_protocol_state& control_protocol_state)
get_control_protocol_method_handler make_get_control_protocol_method_handler(experimental::control_protocol_state& control_protocol_state)
{
return [&]()
return [&](const nc_class_id& class_id_, const nc_method_id& method_id)
{
std::map<nmos::nc_class_id, experimental::methods> methods;
auto class_id = class_id_;

auto lock = control_protocol_state.read_lock();
auto get_control_protocol_class = make_get_control_protocol_class_handler(control_protocol_state);

auto& control_classes = control_protocol_state.control_classes;
auto lock = control_protocol_state.read_lock();

for (const auto& control_class : control_classes)
while (!class_id.empty())
{
methods[control_class.first] = control_class.second.method_handlers;
const auto& control_class = get_control_protocol_class(class_id);
auto& methods = control_class.method_handlers;

auto method_found = methods.find(method_id);
if (methods.end() != method_found)
{
return method_found->second;
}

class_id.pop_back();
}
return methods;

return experimental::method_handler(nullptr);
};
}

Expand Down
12 changes: 8 additions & 4 deletions Development/nmos/control_protocol_handlers.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,23 +35,27 @@ namespace nmos
namespace experimental
{
// method handler defnition
typedef std::function<web::json::value(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler get_control_protocol_datatype, slog::base_gate& gate)> method;
typedef std::function<web::json::value(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler get_control_protocol_datatype, slog::base_gate& gate)> method_handler;
// methods defnition
typedef std::map<nmos::nc_method_id, method> methods; // method_id vs method handler
typedef std::map<nmos::nc_method_id, method_handler> methods; // method_id vs method handler
}

// callback to retrieve all the method handlers
// this callback should not throw exceptions
typedef std::function<std::map<nmos::nc_class_id, experimental::methods>()> get_control_protocol_methods_handler;

// callback to retrieve a specific method handler
// this callback should not throw exceptions
typedef std::function<experimental::method_handler(const nc_class_id& class_id, const nc_method_id& method_id)> get_control_protocol_method_handler;

// construct callback to retrieve a specific control protocol class
get_control_protocol_class_handler make_get_control_protocol_class_handler(experimental::control_protocol_state& control_protocol_state);

// construct callback to retrieve a specific datatype
get_control_protocol_datatype_handler make_get_control_protocol_datatype_handler(experimental::control_protocol_state& control_protocol_state);

// construct callback to retrieve all method handlers
get_control_protocol_methods_handler make_get_control_protocol_methods_handler(experimental::control_protocol_state& control_protocol_state);
// construct callback to retrieve a specific method handler
get_control_protocol_method_handler make_get_control_protocol_method_handler(experimental::control_protocol_state& control_protocol_state);

// a control_protocol_connection_activation_handler is a notification that the active parameters for the specified (IS-05) sender/connection_sender or receiver/connection_receiver have changed
// this callback should not throw exceptions
Expand Down
12 changes: 6 additions & 6 deletions Development/nmos/control_protocol_state.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ namespace nmos
{
// create control class
// where
// properties: vector of NcPropertyDescriptor which can be constructed using make_control_class_property
// methods: vector of NcMethodDescriptor which can be constructed using make_nc_method_descriptor and the assoicated method handler
// properties: vector of NcPropertyDescriptor can be constructed using make_control_class_property
// methods: vector of NcMethodDescriptor can be constructed using make_nc_method_descriptor and the assoicated method handler
// events: vector of NcEventDescriptor can be constructed using make_nc_event_descriptor
control_class make_control_class(const utility::string_t& description, const nc_class_id& class_id, const nc_name& name, const web::json::value& fixed_role, const std::vector<web::json::value>& properties_, const std::vector<std::pair<web::json::value, nmos::experimental::method>>& methods_, const std::vector<web::json::value>& events_)
control_class make_control_class(const utility::string_t& description, const nc_class_id& class_id, const nc_name& name, const web::json::value& fixed_role, const std::vector<web::json::value>& properties_, const std::vector<std::pair<web::json::value, nmos::experimental::method_handler>>& methods_, const std::vector<web::json::value>& events_)
{
using web::json::value;

Expand All @@ -38,7 +38,7 @@ namespace nmos
// properties: vector of NcPropertyDescriptor which can be constructed using make_control_class_property
// methods: vector of NcMethodDescriptor which can be constructed using make_nc_method_descriptor and the assoicated method handler
// events: vector of NcEventDescriptor can be constructed using make_nc_event_descriptor
control_class make_control_class(const utility::string_t& description, const nc_class_id& class_id, const nc_name& name, const utility::string_t& fixed_role, const std::vector<web::json::value>& properties, const std::vector<std::pair<web::json::value, nmos::experimental::method>>& methods, const std::vector<web::json::value>& events)
control_class make_control_class(const utility::string_t& description, const nc_class_id& class_id, const nc_name& name, const utility::string_t& fixed_role, const std::vector<web::json::value>& properties, const std::vector<std::pair<web::json::value, nmos::experimental::method_handler>>& methods, const std::vector<web::json::value>& events)
{
using web::json::value;

Expand All @@ -49,7 +49,7 @@ namespace nmos
// properties: vector of NcPropertyDescriptor which can be constructed using make_control_class_property
// methods: vector of NcMethodDescriptor which can be constructed using make_nc_method_descriptor and the assoicated method handler
// events: vector of NcEventDescriptor can be constructed using make_nc_event_descriptor
control_class make_control_class(const utility::string_t& description, const nc_class_id& class_id, const nc_name& name, const std::vector<web::json::value>& properties, const std::vector<std::pair<web::json::value, nmos::experimental::method>>& methods, const std::vector<web::json::value>& events)
control_class make_control_class(const utility::string_t& description, const nc_class_id& class_id, const nc_name& name, const std::vector<web::json::value>& properties, const std::vector<std::pair<web::json::value, nmos::experimental::method_handler>>& methods, const std::vector<web::json::value>& events)
{
using web::json::value;

Expand Down Expand Up @@ -100,7 +100,7 @@ namespace nmos

auto to_methods_vector = [](const web::json::value& method_data_array, const nmos::experimental::methods& method_handlers)
{
std::vector<std::pair<web::json::value, nmos::experimental::method>> methods;
std::vector<std::pair<web::json::value, nmos::experimental::method_handler>> methods;

if (!method_data_array.is_null())
{
Expand Down
4 changes: 2 additions & 2 deletions Development/nmos/control_protocol_state.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,9 @@ namespace nmos
bool is_read_only = false, bool is_nullable = false, bool is_sequence = false, bool is_deprecated = false, const web::json::value& constraints = web::json::value::null());

// create control class with fixed role
control_class make_control_class(const utility::string_t& description, const nc_class_id& class_id, const nc_name& name, const utility::string_t& fixed_role, const std::vector<web::json::value>& properties = {}, const std::vector<std::pair<web::json::value, nmos::experimental::method>>& methods = {}, const std::vector<web::json::value>& events = {});
control_class make_control_class(const utility::string_t& description, const nc_class_id& class_id, const nc_name& name, const utility::string_t& fixed_role, const std::vector<web::json::value>& properties = {}, const std::vector<std::pair<web::json::value, nmos::experimental::method_handler>>& methods = {}, const std::vector<web::json::value>& events = {});
// create control class with no fixed role
control_class make_control_class(const utility::string_t& description, const nc_class_id& class_id, const nc_name& name, const std::vector<web::json::value>& properties = {}, const std::vector<std::pair<web::json::value, nmos::experimental::method>>& methods = {}, const std::vector<web::json::value>& events = {});
control_class make_control_class(const utility::string_t& description, const nc_class_id& class_id, const nc_name& name, const std::vector<web::json::value>& properties = {}, const std::vector<std::pair<web::json::value, nmos::experimental::method_handler>>& methods = {}, const std::vector<web::json::value>& events = {});
}
}

Expand Down
31 changes: 3 additions & 28 deletions Development/nmos/control_protocol_ws_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,29 +45,6 @@ namespace nmos
{
controlprotocol_validator().validate(request_data, experimental::make_controlprotocolapi_subscription_message_schema_uri(version));
}

nmos::experimental::method find_method(const nc_method_id& method_id, const nc_class_id& class_id_, const std::map<nmos::nc_class_id, experimental::methods>& methods)
{
auto class_id = class_id_;

while (!class_id.empty())
{
auto class_id_methods_found = methods.find(class_id);

if (methods.end() != class_id_methods_found)
{
auto& method_id_methods = class_id_methods_found->second;
auto method_found = method_id_methods.find(method_id);
if (method_id_methods.end() != method_found)
{
return method_found->second;
}
}
class_id.pop_back();
}

return nullptr;
}
}

// IS-12 Control Protocol WebSocket API
Expand Down Expand Up @@ -206,14 +183,12 @@ namespace nmos
};
}

web::websockets::experimental::listener::message_handler make_control_protocol_ws_message_handler(nmos::node_model& model, nmos::websockets& websockets, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, nmos::get_control_protocol_methods_handler get_control_protocol_methods, slog::base_gate& gate_)
web::websockets::experimental::listener::message_handler make_control_protocol_ws_message_handler(nmos::node_model& model, nmos::websockets& websockets, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, nmos::get_control_protocol_method_handler get_control_protocol_method, slog::base_gate& gate_)
{
using web::json::value;
using web::json::value_of;

auto methods = get_control_protocol_methods();

return [&model, &websockets, get_control_protocol_class, get_control_protocol_datatype, methods, &gate_](const web::uri& connection_uri, const web::websockets::experimental::listener::connection_id& connection_id, const web::websockets::websocket_incoming_message& msg_)
return [&model, &websockets, get_control_protocol_class, get_control_protocol_datatype, get_control_protocol_method, &gate_](const web::uri& connection_uri, const web::websockets::experimental::listener::connection_id& connection_id, const web::websockets::websocket_incoming_message& msg_)
{
nmos::ws_api_gate gate(gate_, connection_uri);

Expand Down Expand Up @@ -276,7 +251,7 @@ namespace nmos
const auto& class_id = nmos::details::parse_nc_class_id(nmos::fields::nc::class_id(resource->data));

// find the relevent method handler to execute
auto method = details::find_method(method_id, class_id, methods);
auto method = get_control_protocol_method(class_id, method_id);
if (method)
{
// execute the relevant method handler, then accumulating up their response to reponses
Expand Down
Loading

0 comments on commit d21ca75

Please sign in to comment.