forked from sony/nmos-cpp
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsystem_api.cpp
187 lines (150 loc) · 7.98 KB
/
system_api.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
#include "nmos/system_api.h"
#include "cpprest/json_validator.h"
#include "nmos/api_utils.h"
#include "nmos/json_schema.h"
#include "nmos/log_manip.h"
#include "nmos/model.h"
namespace nmos
{
inline web::http::experimental::listener::api_router make_unmounted_system_api(nmos::registry_model& model, slog::base_gate& gate);
web::http::experimental::listener::api_router make_system_api(nmos::registry_model& model, slog::base_gate& gate)
{
using namespace web::http::experimental::listener::api_router_using_declarations;
api_router system_api;
system_api.support(U("/?"), methods::GET, [](http_request, http_response res, const string_t&, const route_parameters&)
{
set_reply(res, status_codes::OK, nmos::make_sub_routes_body({ U("x-nmos/") }, res));
return pplx::task_from_result(true);
});
system_api.support(U("/x-nmos/?"), methods::GET, [](http_request, http_response res, const string_t&, const route_parameters&)
{
set_reply(res, status_codes::OK, nmos::make_sub_routes_body({ U("system/") }, res));
return pplx::task_from_result(true);
});
const std::set<api_version> versions{ { 1, 0 } };
system_api.support(U("/x-nmos/") + nmos::patterns::system_api.pattern + U("/?"), methods::GET, [versions](http_request, http_response res, const string_t&, const route_parameters&)
{
set_reply(res, status_codes::OK, nmos::make_sub_routes_body(nmos::make_api_version_sub_routes(versions), res));
return pplx::task_from_result(true);
});
system_api.mount(U("/x-nmos/") + nmos::patterns::system_api.pattern + U("/") + nmos::patterns::version.pattern, make_unmounted_system_api(model, gate));
return system_api;
}
inline web::http::experimental::listener::api_router make_unmounted_system_api(nmos::registry_model& model, slog::base_gate& gate_)
{
using namespace web::http::experimental::listener::api_router_using_declarations;
api_router system_api;
// check for supported API version
const std::set<api_version> versions{ { 1, 0 } };
system_api.support(U(".*"), details::make_api_version_handler(versions, gate_));
system_api.support(U("/?"), methods::GET, [](http_request, http_response res, const string_t&, const route_parameters&)
{
set_reply(res, status_codes::OK, nmos::make_sub_routes_body({ U("global/") }, res));
return pplx::task_from_result(true);
});
system_api.support(U("/global/?"), methods::GET, [&model, &gate_](http_request req, http_response res, const string_t&, const route_parameters& parameters)
{
nmos::api_gate gate(gate_, req, parameters);
auto lock = model.read_lock();
if (model.system_global_resource.has_data())
{
set_reply(res, status_codes::OK, model.system_global_resource.data);
}
else
{
slog::log<slog::severities::error>(gate, SLOG_FLF) << "System global resource not configured!";
set_reply(res, status_codes::InternalError); // rather than Not Found, since the System API doesn't allow a 404 response
}
return pplx::task_from_result(true);
});
const web::json::experimental::json_validator validator
{
nmos::experimental::load_json_schema,
{ experimental::make_systemapi_global_schema_uri({ 1, 0 }) }
};
// experimental extension, to allow the global configuration resource to be replaced
system_api.support(U("/global/?"), methods::PUT, [&model, validator, &gate_](http_request req, http_response res, const string_t&, const route_parameters& parameters)
{
nmos::api_gate gate(gate_, req, parameters);
return details::extract_json(req, gate).then([&model, &validator, req, res, parameters, gate](value body) mutable
{
auto lock = model.write_lock();
const nmos::api_version version = nmos::parse_api_version(parameters.at(nmos::patterns::version.name));
// Validate JSON syntax according to the schema
const bool allow_invalid_resources = nmos::fields::allow_invalid_resources(model.settings);
if (!allow_invalid_resources)
{
validator.validate(body, experimental::make_systemapi_global_schema_uri(version));
}
else
{
try
{
validator.validate(body, experimental::make_systemapi_global_schema_uri(version));
}
catch (const web::json::json_exception& e)
{
slog::log<slog::severities::warning>(gate, SLOG_FLF) << "JSON error: " << e.what();
}
}
const auto& data = body;
model.system_global_resource = { version, types::global, data, true };
// notify anyone who cares...
model.notify();
set_reply(res, status_codes::Created, data);
return true;
});
});
// experimental extension, to allow the global configuration resource to be modified
system_api.support(U("/global/?"), methods::PATCH, [&model, validator, &gate_](http_request req, http_response res, const string_t&, const route_parameters& parameters)
{
nmos::api_gate gate(gate_, req, parameters);
return details::extract_json(req, gate).then([&model, &validator, req, res, parameters, gate](value body) mutable
{
auto lock = model.write_lock();
const nmos::api_version version = nmos::parse_api_version(parameters.at(nmos::patterns::version.name));
if (model.system_global_resource.has_data()) // and version is the same?
{
// Merge the updates
auto patched = model.system_global_resource.data;
web::json::merge_patch(patched, body, true);
// Validate JSON syntax according to the schema
const bool allow_invalid_resources = nmos::fields::allow_invalid_resources(model.settings);
if (!allow_invalid_resources)
{
validator.validate(patched, experimental::make_systemapi_global_schema_uri(version));
}
else
{
try
{
validator.validate(patched, experimental::make_systemapi_global_schema_uri(version));
}
catch (const web::json::json_exception& e)
{
slog::log<slog::severities::warning>(gate, SLOG_FLF) << "JSON error: " << e.what();
}
}
if (model.system_global_resource.id == nmos::fields::id(patched))
{
model.system_global_resource.data = patched;
// notify anyone who cares...
model.notify();
set_reply(res, status_codes::OK, patched);
}
else
{
set_error_reply(res, status_codes::BadRequest, U("Bad Request; cannot modify resource id with a PATCH request"));
}
}
else
{
slog::log<slog::severities::error>(gate, SLOG_FLF) << "System global resource not configured!";
set_reply(res, status_codes::InternalError); // rather than Not Found, since the System API doesn't allow a 404 response
}
return true;
});
});
return system_api;
}
}