Skip to content

Commit

Permalink
Prepare the way for being able to host e.g. Node API and Connection A…
Browse files Browse the repository at this point in the history
…PI, or Registration API and Query API, together on the same port.

(cherry picked from commit 761c4fd8852620013edd28f00a1d17bcce409eab)
  • Loading branch information
garethsb committed Nov 8, 2018
1 parent 40dc2bb commit ae6a3e0
Show file tree
Hide file tree
Showing 13 changed files with 90 additions and 59 deletions.
8 changes: 4 additions & 4 deletions Development/nmos-cpp-node/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,13 +107,13 @@ int main(int argc, char* argv[])

web::http::experimental::listener::api_router settings_api = nmos::experimental::make_settings_api(node_model, level, gate);
web::http::experimental::listener::http_listener settings_listener(web::http::experimental::listener::make_listener_uri(nmos::experimental::fields::settings_port(node_model.settings)));
nmos::support_api(settings_listener, settings_api);
nmos::support_api(settings_listener, settings_api, gate);

// Configure the Logging API

web::http::experimental::listener::api_router logging_api = nmos::experimental::make_logging_api(log_model, gate);
web::http::experimental::listener::http_listener logging_listener(web::http::experimental::listener::make_listener_uri(nmos::experimental::fields::logging_port(node_model.settings)));
nmos::support_api(logging_listener, logging_api);
nmos::support_api(logging_listener, logging_api, gate);

// Configure the NMOS APIs

Expand All @@ -125,7 +125,7 @@ int main(int argc, char* argv[])
nmos::node_api_target_handler target_handler = nmos::make_node_api_target_handler(node_model, gate);
web::http::experimental::listener::api_router node_api = nmos::make_node_api(node_model, target_handler, gate);
web::http::experimental::listener::http_listener node_listener(web::http::experimental::listener::make_listener_uri(nmos::fields::node_port(node_model.settings)), listener_config);
nmos::support_api(node_listener, node_api);
nmos::support_api(node_listener, node_api, gate);

// set up the node resources
auto node_resources = nmos::details::make_thread_guard([&] { nmos::experimental::node_resources_thread(node_model, gate); }, [&] { node_model.controlled_shutdown(); });
Expand All @@ -134,7 +134,7 @@ int main(int argc, char* argv[])

web::http::experimental::listener::api_router connection_api = nmos::make_connection_api(node_model, gate);
web::http::experimental::listener::http_listener connection_listener(web::http::experimental::listener::make_listener_uri(nmos::fields::connection_port(node_model.settings)), listener_config);
nmos::support_api(connection_listener, connection_api);
nmos::support_api(connection_listener, connection_api, gate);

slog::log<slog::severities::info>(gate, SLOG_FLF) << "Preparing for connections";

Expand Down
14 changes: 7 additions & 7 deletions Development/nmos-cpp-registry/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,19 +111,19 @@ int main(int argc, char* argv[])

web::http::experimental::listener::api_router mdns_api = nmos::experimental::make_mdns_api(registry_model, gate);
web::http::experimental::listener::http_listener mdns_listener(web::http::experimental::listener::make_listener_uri(nmos::experimental::fields::mdns_port(registry_model.settings)));
nmos::support_api(mdns_listener, mdns_api);
nmos::support_api(mdns_listener, mdns_api, gate);

// Configure the Settings API

web::http::experimental::listener::api_router settings_api = nmos::experimental::make_settings_api(registry_model, level, gate);
web::http::experimental::listener::http_listener settings_listener(web::http::experimental::listener::make_listener_uri(nmos::experimental::fields::settings_port(registry_model.settings)));
nmos::support_api(settings_listener, settings_api);
nmos::support_api(settings_listener, settings_api, gate);

// Configure the Logging API

web::http::experimental::listener::api_router logging_api = nmos::experimental::make_logging_api(log_model, gate);
web::http::experimental::listener::http_listener logging_listener(web::http::experimental::listener::make_listener_uri(nmos::experimental::fields::logging_port(registry_model.settings)));
nmos::support_api(logging_listener, logging_api);
nmos::support_api(logging_listener, logging_api, gate);

// Configure the NMOS APIs

Expand All @@ -134,7 +134,7 @@ int main(int argc, char* argv[])

web::http::experimental::listener::api_router query_api = nmos::make_query_api(registry_model, gate);
web::http::experimental::listener::http_listener query_listener(web::http::experimental::listener::make_listener_uri(nmos::fields::query_port(registry_model.settings)), listener_config);
nmos::support_api(query_listener, query_api);
nmos::support_api(query_listener, query_api, gate);

// "Source ID of the Query API instance issuing the data Grain"
// See https://github.com/AMWA-TV/nmos-discovery-registration/blob/v1.2/APIs/schemas/queryapi-subscriptions-websocket.json
Expand All @@ -154,13 +154,13 @@ int main(int argc, char* argv[])

web::http::experimental::listener::api_router registration_api = nmos::make_registration_api(registry_model, gate);
web::http::experimental::listener::http_listener registration_listener(web::http::experimental::listener::make_listener_uri(nmos::fields::registration_port(registry_model.settings)), listener_config);
nmos::support_api(registration_listener, registration_api);
nmos::support_api(registration_listener, registration_api, gate);

// Configure the Node API

web::http::experimental::listener::api_router node_api = nmos::make_node_api(registry_model, {}, gate);
web::http::experimental::listener::http_listener node_listener(web::http::experimental::listener::make_listener_uri(nmos::fields::node_port(registry_model.settings)), listener_config);
nmos::support_api(node_listener, node_api);
nmos::support_api(node_listener, node_api, gate);

// set up the node resources
auto & self_resources = registry_model.node_resources;
Expand All @@ -175,7 +175,7 @@ int main(int argc, char* argv[])
const utility::string_t admin_filesystem_root = U("./admin");
web::http::experimental::listener::api_router admin_ui = nmos::experimental::make_admin_ui(admin_filesystem_root, gate);
web::http::experimental::listener::http_listener admin_listener(web::http::experimental::listener::make_listener_uri(nmos::experimental::fields::admin_port(registry_model.settings)));
nmos::support_api(admin_listener, admin_ui);
nmos::support_api(admin_listener, admin_ui, gate);

// Configure the mDNS advertisements for our APIs

Expand Down
4 changes: 1 addition & 3 deletions Development/nmos/admin_ui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ namespace nmos

admin_ui.support(U("/?"), methods::GET, [](http_request, http_response res, const string_t&, const route_parameters&)
{
set_reply(res, status_codes::OK, value_of({ JU("admin/") }));
set_reply(res, status_codes::OK, nmos::make_sub_routes_body({ U("admin/") }, res));
return pplx::task_from_result(true);
});

Expand All @@ -45,8 +45,6 @@ namespace nmos

admin_ui.mount(U("/") + nmos::experimental::patterns::admin_ui.pattern, web::http::methods::GET, nmos::experimental::make_filesystem_route(filesystem_root, nmos::experimental::make_relative_path_content_type_validator(valid_extensions), gate));

nmos::add_api_finally_handler(admin_ui, gate);

return admin_ui;
}
}
Expand Down
40 changes: 39 additions & 1 deletion Development/nmos/api_utils.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "nmos/api_utils.h"

#include <set>
#include <boost/algorithm/string/trim.hpp>
#include "nmos/slog.h"

Expand Down Expand Up @@ -66,6 +67,7 @@ namespace nmos
}
}

// add the NMOS-specified CORS response headers
web::http::http_response& add_cors_preflight_headers(const web::http::http_request& req, web::http::http_response& res)
{
// NMOS specification says "all NMOS APIs MUST implement valid CORS HTTP headers in responses"
Expand Down Expand Up @@ -98,6 +100,7 @@ namespace nmos
return res;
}

// add the NMOS-specified CORS response headers
web::http::http_response& add_cors_headers(web::http::http_response& res)
{
// Indicate that any Origin is allowed
Expand Down Expand Up @@ -154,6 +157,29 @@ namespace nmos
return details::resourceTypes_from_type.at(type);
}

// construct a standard NMOS "child resources" response, sorting the specified sub-routes lexicographically
// and optionally merging with ones from an existing response
// see https://github.com/AMWA-TV/nmos-discovery-registration/blob/v1.2/docs/2.0.%20APIs.md#api-paths
web::json::value make_sub_routes_body(std::initializer_list<utility::string_t> sub_routes, web::http::http_response res)
{
using namespace web::http::experimental::listener::api_router_using_declarations;

std::set<utility::string_t> sorted_unique(sub_routes);

if (res.body())
{
auto body = res.extract_json().get();

for (auto& element : body.as_array())
{
sorted_unique.insert(element.as_string());
}
}

return web::json::value_from_elements(sorted_unique);
}

// construct a standard NMOS error response, using the default reason phrase if no user error information is specified
web::json::value make_error_response_body(web::http::status_code code, const utility::string_t& error, const utility::string_t& debug)
{
web::json::value result = web::json::value::object(true);
Expand All @@ -165,6 +191,7 @@ namespace nmos

namespace details
{
// make handler to set appropriate response headers, and error response body if indicated
web::http::experimental::listener::route_handler make_api_finally_handler(slog::base_gate& gate)
{
using namespace web::http::experimental::listener::api_router_using_declarations;
Expand Down Expand Up @@ -227,6 +254,7 @@ namespace nmos
}
}

// add handler to set appropriate response headers, and error response body if indicated - call this only after adding all others!
void add_api_finally_handler(web::http::experimental::listener::api_router& api, slog::base_gate& gate)
{
using namespace web::http::experimental::listener::api_router_using_declarations;
Expand Down Expand Up @@ -279,9 +307,19 @@ namespace nmos
});
}

void support_api(web::http::experimental::listener::http_listener& listener, web::http::experimental::listener::api_router& api)
// modify the specified API to handle all requests (including CORS preflight requests via "OPTIONS") and attach it to the specified listener - captures api by reference!
void support_api(web::http::experimental::listener::http_listener& listener, web::http::experimental::listener::api_router& api, slog::base_gate& gate)
{
add_api_finally_handler(api, gate);
listener.support(std::ref(api));
listener.support(web::http::methods::OPTIONS, std::ref(api)); // to handle CORS preflight requests
}

// construct an http_listener on the specified port, using the specified API to handle all requests
web::http::experimental::listener::http_listener make_api_listener(int port, web::http::experimental::listener::api_router& api, web::http::experimental::listener::http_listener_config config, slog::base_gate& gate)
{
web::http::experimental::listener::http_listener api_listener(web::http::experimental::listener::make_listener_uri(port), std::move(config));
nmos::support_api(api_listener, api, gate);
return api_listener;
}
}
13 changes: 11 additions & 2 deletions Development/nmos/api_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,14 +64,23 @@ namespace nmos

// Other utility functions for generating NMOS response headers and body

// construct a standard NMOS "child resources" response, sorting the specified sub-routes lexicographically
// and merging with ones from an existing response
// see https://github.com/AMWA-TV/nmos-discovery-registration/blob/v1.2/docs/2.0.%20APIs.md#api-paths
web::json::value make_sub_routes_body(std::initializer_list<utility::string_t> sub_routes, web::http::http_response res);

// construct a standard NMOS error response, using the default reason phrase if no user error information is specified
web::json::value make_error_response_body(web::http::status_code code, const utility::string_t& error = {}, const utility::string_t& debug = {});

// add handler to set appropriate response headers, and error response body if indicated - call this only after adding all others!
void add_api_finally_handler(web::http::experimental::listener::api_router& api, slog::base_gate& gate);

// use an API to handle all requests (including CORS preflight requests via "OPTIONS") - captures api by reference!
void support_api(web::http::experimental::listener::http_listener& listener, web::http::experimental::listener::api_router& api);
// modify the specified API to handle all requests (including CORS preflight requests via "OPTIONS") and attach it to the specified listener - captures api by reference!
void support_api(web::http::experimental::listener::http_listener& listener, web::http::experimental::listener::api_router& api, slog::base_gate& gate);

// construct an http_listener on the specified port, modifying the specified API to handle all requests
// (including CORS preflight requests via "OPTIONS") - captures api by reference!
web::http::experimental::listener::http_listener make_api_listener(int port, web::http::experimental::listener::api_router& api, web::http::experimental::listener::http_listener_config config, slog::base_gate& gate);

namespace details
{
Expand Down
18 changes: 8 additions & 10 deletions Development/nmos/connection_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,26 +23,24 @@ namespace nmos

connection_api.support(U("/?"), methods::GET, [](http_request, http_response res, const string_t&, const route_parameters&)
{
set_reply(res, status_codes::OK, value_of({ JU("x-nmos/") }));
set_reply(res, status_codes::OK, nmos::make_sub_routes_body({ U("x-nmos/") }, res));
return pplx::task_from_result(true);
});

connection_api.support(U("/x-nmos/?"), methods::GET, [](http_request, http_response res, const string_t&, const route_parameters&)
{
set_reply(res, status_codes::OK, value_of({ JU("connection/") }));
set_reply(res, status_codes::OK, nmos::make_sub_routes_body({ U("connection/") }, res));
return pplx::task_from_result(true);
});

connection_api.support(U("/x-nmos/") + nmos::patterns::connection_api.pattern + U("/?"), methods::GET, [](http_request, http_response res, const string_t&, const route_parameters&)
{
set_reply(res, status_codes::OK, value_of({ JU("v1.0/") }));
set_reply(res, status_codes::OK, nmos::make_sub_routes_body({ U("v1.0/") }, res));
return pplx::task_from_result(true);
});

connection_api.mount(U("/x-nmos/") + nmos::patterns::connection_api.pattern + U("/") + nmos::patterns::is05_version.pattern, make_unmounted_connection_api(model, gate));

nmos::add_api_finally_handler(connection_api, gate);

return connection_api;
}

Expand Down Expand Up @@ -728,13 +726,13 @@ namespace nmos

connection_api.support(U("/?"), methods::GET, [](http_request, http_response res, const string_t&, const route_parameters&)
{
set_reply(res, status_codes::OK, value_of({ JU("bulk/"), JU("single/") }));
set_reply(res, status_codes::OK, nmos::make_sub_routes_body({ U("bulk/"), U("single/") }, res));
return pplx::task_from_result(true);
});

connection_api.support(U("/bulk/?"), methods::GET, [](http_request, http_response res, const string_t&, const route_parameters&)
{
set_reply(res, status_codes::OK, value_of({ JU("senders/"), JU("receivers/") }));
set_reply(res, status_codes::OK, nmos::make_sub_routes_body({ U("senders/"), U("receivers/") }, res));
return pplx::task_from_result(true);
});

Expand Down Expand Up @@ -885,7 +883,7 @@ namespace nmos

connection_api.support(U("/single/?"), methods::GET, [](http_request, http_response res, const string_t&, const route_parameters&)
{
set_reply(res, status_codes::OK, value_of({ JU("senders/"), JU("receivers/") }));
set_reply(res, status_codes::OK, nmos::make_sub_routes_body({ U("senders/"), U("receivers/") }, res));
return pplx::task_from_result(true);
});

Expand Down Expand Up @@ -924,11 +922,11 @@ namespace nmos
{
if (nmos::types::sender == resource->type)
{
set_reply(res, status_codes::OK, value_of({ JU("constraints/"), JU("staged/"), JU("active/"), JU("transportfile/") }));
set_reply(res, status_codes::OK, nmos::make_sub_routes_body({ U("constraints/"), U("staged/"), U("active/"), U("transportfile/") }, res));
}
else // if (nmos::types::receiver == resource->type)
{
set_reply(res, status_codes::OK, value_of({ JU("constraints/"), JU("staged/"), JU("active/") }));
set_reply(res, status_codes::OK, nmos::make_sub_routes_body({ U("constraints/"), U("staged/"), U("active/") }, res));
}
}
else
Expand Down
8 changes: 3 additions & 5 deletions Development/nmos/logging_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,18 @@ namespace nmos

logging_api.support(U("/?"), methods::GET, [](http_request, http_response res, const string_t&, const route_parameters&)
{
set_reply(res, status_codes::OK, value_of({ value(U("log/")) }));
set_reply(res, status_codes::OK, nmos::make_sub_routes_body({ U("log/") }, res));
return pplx::task_from_result(true);
});

logging_api.support(U("/log/?"), methods::GET, [](http_request, http_response res, const string_t&, const route_parameters&)
{
set_reply(res, status_codes::OK, value_of({ value(U("v1.0/")) }));
set_reply(res, status_codes::OK, nmos::make_sub_routes_body({ U("v1.0/") }, res));
return pplx::task_from_result(true);
});

logging_api.mount(U("/log/v1.0"), make_unmounted_logging_api(model, gate));

nmos::add_api_finally_handler(logging_api, gate);

return logging_api;
}

Expand Down Expand Up @@ -300,7 +298,7 @@ namespace nmos

logging_api.support(U("/?"), methods::GET, [](http_request, http_response res, const string_t&, const route_parameters&)
{
set_reply(res, status_codes::OK, value_of({ value(U("events/")) }));
set_reply(res, status_codes::OK, nmos::make_sub_routes_body({ U("events/") }, res));
return pplx::task_from_result(true);
});

Expand Down
6 changes: 2 additions & 4 deletions Development/nmos/mdns_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,18 @@ namespace nmos

mdns_api.support(U("/?"), methods::GET, [](http_request, http_response res, const string_t&, const route_parameters&)
{
set_reply(res, status_codes::OK, value_of({ value(U("x-dns-sd/")) }));
set_reply(res, status_codes::OK, nmos::make_sub_routes_body({ U("x-dns-sd/") }, res));
return pplx::task_from_result(true);
});

mdns_api.support(U("/x-dns-sd/?"), methods::GET, [](http_request, http_response res, const string_t&, const route_parameters&)
{
set_reply(res, status_codes::OK, value_of({ value(U("v1.0/")) }));
set_reply(res, status_codes::OK, nmos::make_sub_routes_body({ U("v1.0/") }, res));
return pplx::task_from_result(true);
});

mdns_api.mount(U("/x-dns-sd/v1.0"), make_unmounted_mdns_api(model, gate));

nmos::add_api_finally_handler(mdns_api, gate);

return mdns_api;
}

Expand Down
Loading

0 comments on commit ae6a3e0

Please sign in to comment.