@@ -13,18 +13,6 @@ auto vamp_protocol::page_command_path(vamp_protocol::page_command command) -> st
|
||||
return vamp_protocol::remote_next_path;
|
||||
}
|
||||
|
||||
auto vamp_protocol::page_command_legacy_path(vamp_protocol::page_command command) -> std::char_t const * {
|
||||
switch (command) {
|
||||
case vamp_protocol::page_command::PREVIOUS:
|
||||
return vamp_protocol::previous_page_path;
|
||||
case vamp_protocol::page_command::NEXT:
|
||||
return vamp_protocol::next_page_path;
|
||||
case vamp_protocol::page_command::SELECT:
|
||||
return vamp_protocol::remote_select_path;
|
||||
}
|
||||
return vamp_protocol::next_page_path;
|
||||
}
|
||||
|
||||
auto vamp_protocol::page_command_name(vamp_protocol::page_command command) -> std::char_t const * {
|
||||
switch (command) {
|
||||
case vamp_protocol::page_command::PREVIOUS:
|
||||
|
||||
+25
-81
@@ -1,4 +1,3 @@
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <expected>
|
||||
#include <string>
|
||||
@@ -6,9 +5,7 @@
|
||||
#include <utility>
|
||||
|
||||
#include <boost/json/object.hpp>
|
||||
#include <boost/json/parse.hpp>
|
||||
#include <boost/json/value.hpp>
|
||||
#include <boost/system/error_code.hpp>
|
||||
|
||||
#include <vamp_zero/config.hpp>
|
||||
#include <vamp_zero/errors.hpp>
|
||||
@@ -22,93 +19,49 @@ constexpr auto json_options = modulus::json_config::options{
|
||||
.not_found_code = static_cast<std::int32_t>(vamp_zero::error_code::NOT_FOUND),
|
||||
};
|
||||
|
||||
constexpr auto field_options = modulus::json_config::options{
|
||||
.category = "product-vamp",
|
||||
.invalid_argument_code = static_cast<std::int32_t>(vamp_zero::error_code::INVALID_ARGUMENT),
|
||||
.not_found_code = static_cast<std::int32_t>(vamp_zero::error_code::NOT_FOUND),
|
||||
};
|
||||
|
||||
auto invalid(std::string message) -> modulus::error {
|
||||
return vamp_zero::make_error(vamp_zero::error_code::INVALID_ARGUMENT, std::move(message));
|
||||
}
|
||||
|
||||
auto require_object(boost::json::value const &value, std::string_view name) -> std::expected<boost::json::object const *, modulus::error> {
|
||||
if (!value.is_object()) {
|
||||
return std::unexpected(invalid(std::string{name} + " must be an object"));
|
||||
}
|
||||
return &value.as_object();
|
||||
}
|
||||
|
||||
auto optional_object(boost::json::object const &object, std::string_view field) -> std::expected<boost::json::object const *, modulus::error> {
|
||||
auto found = object.find(field);
|
||||
if (found == object.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
return require_object(found->value(), field);
|
||||
return modulus::json_config::require_object(found->value(), field, field_options);
|
||||
}
|
||||
|
||||
auto optional_string(boost::json::object const &object, std::string_view field, std::string fallback) -> std::expected<std::string, modulus::error> {
|
||||
auto found = object.find(field);
|
||||
if (found == object.end()) {
|
||||
return fallback;
|
||||
}
|
||||
if (!found->value().is_string()) {
|
||||
return std::unexpected(invalid(std::string{field} + " must be a string"));
|
||||
}
|
||||
auto value = std::string{found->value().as_string()};
|
||||
if (value.empty()) {
|
||||
auto value = modulus::json_config::optional_string_field(object, field, std::move(fallback), field_options);
|
||||
if (value && value->empty() && object.contains(field)) {
|
||||
return std::unexpected(invalid(std::string{field} + " must not be empty"));
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
auto optional_bool(boost::json::object const &object, std::string_view field, std::bool_t fallback) -> std::expected<std::bool_t, modulus::error> {
|
||||
auto found = object.find(field);
|
||||
if (found == object.end()) {
|
||||
return fallback;
|
||||
}
|
||||
if (!found->value().is_bool()) {
|
||||
return std::unexpected(invalid(std::string{field} + " must be a boolean"));
|
||||
}
|
||||
return found->value().as_bool();
|
||||
}
|
||||
|
||||
auto optional_uint32(boost::json::object const &object, std::string_view field, std::uint32_t fallback, std::uint32_t min_value, std::uint32_t max_value) -> std::expected<std::uint32_t, modulus::error> {
|
||||
auto found = object.find(field);
|
||||
if (found == object.end()) {
|
||||
return fallback;
|
||||
auto value = modulus::json_config::optional_uint64_field(object, field, fallback, max_value, field_options);
|
||||
if (!value) {
|
||||
return std::unexpected(value.error());
|
||||
}
|
||||
auto value = std::uint64_t{};
|
||||
if (found->value().is_uint64()) {
|
||||
value = found->value().as_uint64();
|
||||
} else if (found->value().is_int64()) {
|
||||
auto signed_value = found->value().as_int64();
|
||||
if (signed_value < 0) {
|
||||
return std::unexpected(invalid(std::string{field} + " must not be negative"));
|
||||
}
|
||||
value = static_cast<std::uint64_t>(signed_value);
|
||||
} else {
|
||||
return std::unexpected(invalid(std::string{field} + " must be an integer"));
|
||||
}
|
||||
if (value < min_value || value > max_value) {
|
||||
if (*value < min_value) {
|
||||
return std::unexpected(invalid(std::string{field} + " is out of range"));
|
||||
}
|
||||
return static_cast<std::uint32_t>(value);
|
||||
return static_cast<std::uint32_t>(*value);
|
||||
}
|
||||
|
||||
auto optional_float(boost::json::object const &object, std::string_view field, std::float32_t fallback, std::float32_t min_value, std::float32_t max_value) -> std::expected<std::float32_t, modulus::error> {
|
||||
auto found = object.find(field);
|
||||
if (found == object.end()) {
|
||||
return fallback;
|
||||
auto value = modulus::json_config::optional_float64_field(object, field, fallback, min_value, max_value, field_options);
|
||||
if (!value) {
|
||||
return std::unexpected(value.error());
|
||||
}
|
||||
auto value = std::float64_t{};
|
||||
if (found->value().is_double()) {
|
||||
value = found->value().as_double();
|
||||
} else if (found->value().is_uint64()) {
|
||||
value = static_cast<std::float64_t>(found->value().as_uint64());
|
||||
} else if (found->value().is_int64()) {
|
||||
value = static_cast<std::float64_t>(found->value().as_int64());
|
||||
} else {
|
||||
return std::unexpected(invalid(std::string{field} + " must be a number"));
|
||||
}
|
||||
if (!std::isfinite(value) || value < min_value || value > max_value) {
|
||||
return std::unexpected(invalid(std::string{field} + " is out of range"));
|
||||
}
|
||||
return static_cast<std::float32_t>(value);
|
||||
return static_cast<std::float32_t>(*value);
|
||||
}
|
||||
|
||||
auto parse_runtime(boost::json::object const &root, vamp_zero::runtime_config fallback) -> std::expected<vamp_zero::runtime_config, modulus::error> {
|
||||
@@ -119,8 +72,8 @@ auto parse_runtime(boost::json::object const &root, vamp_zero::runtime_config fa
|
||||
if (*object == nullptr) {
|
||||
return fallback;
|
||||
}
|
||||
auto headless = optional_bool(**object, "headless", fallback.headless);
|
||||
auto exit_after_startup = optional_bool(**object, "exit_after_startup", fallback.exit_after_startup);
|
||||
auto headless = modulus::json_config::optional_bool_field(**object, "headless", fallback.headless, field_options);
|
||||
auto exit_after_startup = modulus::json_config::optional_bool_field(**object, "exit_after_startup", fallback.exit_after_startup, field_options);
|
||||
auto assets_path = optional_string(**object, "assets_path", fallback.assets_path);
|
||||
auto heartbeat_path = optional_string(**object, "heartbeat_path", fallback.heartbeat_path);
|
||||
if (!headless) {
|
||||
@@ -218,21 +171,12 @@ auto parse_audio(boost::json::object const &root, vamp_zero::audio_config fallba
|
||||
if (*object == nullptr) {
|
||||
return fallback;
|
||||
}
|
||||
auto enabled = optional_bool(**object, "enabled", fallback.enabled);
|
||||
auto playback_enabled = optional_bool(**object, "playback_enabled", fallback.playback_enabled);
|
||||
auto legacy_track = optional_bool(**object, "track_enabled", fallback.playback_enabled);
|
||||
if (!legacy_track) {
|
||||
return std::unexpected(legacy_track.error());
|
||||
}
|
||||
if ((*object)->if_contains("track_enabled")) {
|
||||
if ((*object)->if_contains("playback_enabled") && playback_enabled && *playback_enabled != *legacy_track) {
|
||||
return std::unexpected(invalid("audio.playback_enabled contradicts legacy track_enabled"));
|
||||
}
|
||||
if (!(*object)->if_contains("playback_enabled")) {
|
||||
playback_enabled = legacy_track;
|
||||
}
|
||||
return std::unexpected(invalid("audio.track_enabled is no longer supported; use audio.playback_enabled"));
|
||||
}
|
||||
auto metronome_enabled = optional_bool(**object, "metronome_enabled", fallback.metronome_enabled);
|
||||
auto enabled = modulus::json_config::optional_bool_field(**object, "enabled", fallback.enabled, field_options);
|
||||
auto playback_enabled = modulus::json_config::optional_bool_field(**object, "playback_enabled", fallback.playback_enabled, field_options);
|
||||
auto metronome_enabled = modulus::json_config::optional_bool_field(**object, "metronome_enabled", fallback.metronome_enabled, field_options);
|
||||
auto metronome_bpm = optional_uint32(**object, "metronome_bpm", fallback.metronome_bpm, 1U, 400U);
|
||||
auto metronome_min_bpm = optional_uint32(**object, "metronome_min_bpm", fallback.metronome_min_bpm, 1U, 400U);
|
||||
auto metronome_max_bpm = optional_uint32(**object, "metronome_max_bpm", fallback.metronome_max_bpm, 1U, 400U);
|
||||
@@ -293,7 +237,7 @@ auto parse_audio(boost::json::object const &root, vamp_zero::audio_config fallba
|
||||
}
|
||||
|
||||
auto vamp_zero::parse_config(boost::json::value const &value) -> std::expected<vamp_zero::config, modulus::error> {
|
||||
auto root = require_object(value, "Product Vamp config root");
|
||||
auto root = modulus::json_config::require_object(value, "Product Vamp config root", field_options);
|
||||
if (!root) {
|
||||
return std::unexpected(root.error());
|
||||
}
|
||||
|
||||
@@ -196,13 +196,5 @@ auto vamp_zero::make_router(vamp_zero::control_state &state) -> ligo::service_ro
|
||||
auto updated = state.apply(vamp_protocol::page_command::SELECT);
|
||||
co_return remote_response(updated);
|
||||
});
|
||||
router.add_route("POST", vamp_protocol::next_page_path, [&state](ligo::request_context, boost::json::value) -> boost::asio::awaitable<std::expected<boost::json::value, modulus::error>> {
|
||||
auto updated = state.apply(vamp_protocol::page_command::NEXT);
|
||||
co_return vamp_zero::portal_status_json(state.config(), updated);
|
||||
});
|
||||
router.add_route("POST", vamp_protocol::previous_page_path, [&state](ligo::request_context, boost::json::value) -> boost::asio::awaitable<std::expected<boost::json::value, modulus::error>> {
|
||||
auto updated = state.apply(vamp_protocol::page_command::PREVIOUS);
|
||||
co_return vamp_zero::portal_status_json(state.config(), updated);
|
||||
});
|
||||
return router;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user