Projects
domecam:swift
domecam
Log In
Username
Password
We truncated the diff of some files because they were too big. If you want to see the full diff for every file,
click here
.
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
Expand all
Collapse all
Changes of Revision 32
View file
domecam.changes
Changed
@@ -1,4 +1,10 @@ ------------------------------------------------------------------- +Mon Dec 18 12:54:53 UTC 2023 - Matwey V. Kornilov <matwey@sai.msu.ru> + +- Version 0.1.18 +- Add domecam-replayd package + +------------------------------------------------------------------- Wed Nov 1 16:43:29 UTC 2023 - Matwey V. Kornilov <matwey@sai.msu.ru> - Version 0.1.17
View file
domecam.spec
Changed
@@ -57,6 +57,16 @@ %description -n domecamd This package contains the daemon for routine operation DomeCam equipment. +%package -n domecam-replayd +Summary: DomeCam replay daemon +Group: Productivity/Scientific/Astronomy +Requires(post): systemd +%systemd_requires +%sysusers_requires + +%description -n domecam-replayd +This package contains the daemon for DomeCam measurements replaying. + %prep %setup -q @@ -75,12 +85,15 @@ mkdir -p %{buildroot}%{_unitdir} install -m 0644 ./domecamd.service %{buildroot}%{_unitdir}/ +install -m 0644 ./domecam-replayd.service %{buildroot}%{_unitdir}/ mkdir -p %{buildroot}%{_sbindir} ln -s /usr/sbin/service %{buildroot}%{_sbindir}/rcdomecamd +ln -s /usr/sbin/service %{buildroot}%{_sbindir}/rcdomecam-replayd mkdir -p %{buildroot}%{_sysconfdir} install -m 0644 ./doc/example/domecamd.conf %{buildroot}%{_sysconfdir}/ +install -m 0644 ./doc/example/domecam-replayd.conf %{buildroot}%{_sysconfdir}/ %check %ctest @@ -97,6 +110,18 @@ %postun -n domecamd %service_del_postun domecamd.service +%pre -n domecam-replayd +%service_add_pre domecam-replayd.service + +%preun -n domecam-replayd +%service_del_preun domecam-replayd.service + +%post -n domecam-replayd +%service_add_post domecam-replayd.service + +%postun -n domecam-replayd +%service_del_postun domecam-replayd.service + %files %defattr(-,root,root) %license LICENSE.txt @@ -115,4 +140,12 @@ %{_sbindir}/rcdomecamd %attr(0755, domecamd, domecamd) %dir %{_localstatedir}/lib/domecamd +%files -n domecam-replayd +%license LICENSE.txt +%defattr(-,root,root) +%config(noreplace) %{_sysconfdir}/domecam-replayd.conf +%{_bindir}/domecam-replayd +%{_unitdir}/domecam-replayd.service +%{_sbindir}/rcdomecam-replayd + %changelog
View file
_service
Changed
@@ -3,7 +3,7 @@ <param name="url">http://curl.sai.msu.ru/hg/home/matwey/domecam/</param> <param name="scm">hg</param> <param name="versionformat">{latesttag}</param> - <param name="revision">0.1.17</param> + <param name="revision">0.1.18</param> </service> <service name="tar" mode="buildtime" /> <service name="recompress" mode="buildtime">
View file
domecam-0.1.17.obscpio/.hgtags -> domecam-0.1.18.obscpio/.hgtags
Changed
@@ -15,3 +15,4 @@ 8655a50fea3e634a2b099c77882009e08fd22ca1 0.1.14 4ca4898b0732dc93583b391358c621c74fd575bf 0.1.15 ee7ef40e4a1d664c5e36cc223e5dec42a81f2a95 0.1.16 +d1a0b26dcf61c5fb7db5c6e97ec89f6b62b91e00 0.1.17
View file
domecam-0.1.17.obscpio/CMakeLists.txt -> domecam-0.1.18.obscpio/CMakeLists.txt
Changed
@@ -1,9 +1,10 @@ cmake_minimum_required (VERSION 3.5) -project(domecam LANGUAGES C CXX VERSION 0.1.17) +project(domecam LANGUAGES C CXX VERSION 0.1.18) -option(BUILD_DOMECAMD "build domecamd" ON) -option(BUILD_DOMECAM_PROC "build domecam-proc" ON) -option(BUILD_TEST "build test" ON) +option(BUILD_DOMECAMD "build domecamd" ON) +option(BUILD_DOMECAM_PROC "build domecam-proc" ON) +option(BUILD_DOMECAM_REPLAYD "build domecam-replayd" ON) +option(BUILD_TEST "build test" ON) set(CMAKE_CXX_STANDARD 17) @@ -68,3 +69,6 @@ if(BUILD_DOMECAM_PROC) add_subdirectory(exe/domecam-proc) endif() +if(BUILD_DOMECAM_REPLAYD) +add_subdirectory(exe/domecam-replayd) +endif()
View file
domecam-0.1.18.obscpio/doc/example/domecam-replayd.conf
Added
@@ -0,0 +1,3 @@ +{ + "amqp_uri": "amqp://domecam-replayd:domecam-replayd@192.168.15.111/domecam-test" +}
View file
domecam-0.1.18.obscpio/domecam-replayd.service
Added
@@ -0,0 +1,26 @@ +Unit +Description=DomeCam replay daemon +After=syslog.target network.target +StartLimitIntervalSec=10min +StartLimitBurst=10 + +Service +Type=simple +StandardOutput=journal +StandardError=journal +Restart=always +RestartSec=30 +ExecStart=/usr/bin/domecam-replayd +PrivateDevices=true +ProtectClock=true +ProtectControlGroups=true +ProtectHome=true +ProtectHostname=true +ProtectKernelLogs=true +ProtectKernelModules=true +ProtectKernelTunables=true +ProtectSystem=strict +RestrictRealtime=true + +Install +WantedBy=multi-user.target
View file
domecam-0.1.18.obscpio/exe/domecam-replayd
Added
+(directory)
View file
domecam-0.1.18.obscpio/exe/domecam-replayd/CMakeLists.txt
Added
@@ -0,0 +1,31 @@ +cmake_minimum_required (VERSION 3.5) + +set(CMAKE_CXX_STANDARD 17) + +include(GNUInstallDirs) + +# CheckIPOSupported module is available since 3.9 +# VERSION_GREATER_EQUAL is available since 3.7 +if(NOT (CMAKE_VERSION VERSION_LESS "3.9.0")) + # check_ipo_supported() returns an error when CMP0069 is OLD + cmake_policy(SET CMP0069 NEW) + + include(CheckIPOSupported) + check_ipo_supported(RESULT HAS_LTO_SUPPORT) +endif() + +find_package(amqpcpp) + +if(TARGET amqpcpp) + file(GLOB_RECURSE DOMECAM_REPLAYD_SOURCES *.cpp) + add_executable(domecam-replayd-exe ${DOMECAM_REPLAYD_SOURCES}) + set_target_properties(domecam-replayd-exe PROPERTIES OUTPUT_NAME domecam-replayd) + target_link_libraries(domecam-replayd-exe domecam amqpcpp) + if(HAS_LTO_SUPPORT) + set_property(TARGET domecam-replayd-exe PROPERTY INTERPROCEDURAL_OPTIMIZATION True) + endif(HAS_LTO_SUPPORT) + + install(TARGETS domecam-replayd-exe DESTINATION ${CMAKE_INSTALL_BINDIR}) +else() + message(WARNING "libamqpcpp not found, so domecam-replayd disabled") +endif()
View file
domecam-0.1.18.obscpio/exe/domecam-replayd/consumer.cpp
Added
@@ -0,0 +1,267 @@ +/* + * SPDX-License-Identifier: GPL-3.0-or-later + * + * Copyright (C) 2017-2023 Matwey V. Kornilov <matwey.kornilov@gmail.com> + */ + +#include <chrono> +#include <exception> +#include <functional> +#include <sstream> +#include <stdexcept> +#include <string> +#include <variant> + +#include <error.h> +#include <exe/domecam-replayd/consumer.h> +#include <io.h> + + +struct task { + std::unique_ptr<replay_executor> executor_; + std::string source_; +}; + +struct domecam_replayd_request_ping { +}; + +struct domecam_replayd_request_run { + std::vector<task> tasks_; +}; + +using domecam_replayd_request = std::variant<domecam_replayd_request_ping, domecam_replayd_request_run>; + +struct domecam_replayd_response_error { + std::exception_ptr reason_; +}; + +struct domecam_replayd_response_pong { +}; + +struct domecam_replayd_response_run { + std::exception_ptr reason_; + std::vector<executor_result> results_; +}; + +task tag_invoke(boost::json::value_to_tag<task>, const boost::json::value& jv) { + using boost::json::value_to; + + const auto& obj = jv.as_object(); + + return task{ + value_to<std::unique_ptr<replay_executor>>(obj.at("executor")), + value_to<std::string>(obj.at("source"))}; +} + +domecam_replayd_request tag_invoke(boost::json::value_to_tag<domecam_replayd_request>, const boost::json::value& jv) { + using boost::json::value_to; + + const auto& obj = jv.as_object(); + const auto& type = obj.at("type").as_string(); + + if (type == "ping") { + return domecam_replayd_request_ping{}; + } else if (type == "run") { + return domecam_replayd_request_run{value_to<std::vector<task>>(obj.at("tasks"))}; + } + + throw std::runtime_error(std::string("Unknown request type ") + type.c_str()); +} + +boost::json::value error_to_value(const std::exception_ptr& p) { + boost::json::value jv; + + try { + std::rethrow_exception(p); + } catch (const std::exception& e) { + jv = { + {"reason", e.what()}}; + } catch (...) { + jv = { + {"reason", "unknown"}}; + } + + return jv; +} + +void tag_invoke(boost::json::value_from_tag, boost::json::value& jv, const domecam_replayd_response_pong&) { + jv = { + {"status", "pong"}}; +} + +void tag_invoke(boost::json::value_from_tag, boost::json::value& jv, const domecam_replayd_response_run& r) { + using boost::json::value_from; + + jv = { + {"status", r.reason_ ? "error" : "ok"}}; + + auto& obj = jv.as_object(); + + if (r.reason_) { + obj"error" = error_to_value(r.reason_); + } + + obj"results" = value_from(r.results_); +} + +void tag_invoke(boost::json::value_from_tag, boost::json::value& jv, const domecam_replayd_response_error& r) { + jv = { + {"status", "error"}, + {"error", error_to_value(r.reason_)}}; +} + + +consumer::consumer(boost::asio::io_context& io_context, const std::string& uri): + io_context_{io_context}, + amqp_handler_{io_context_}, + connection_{&amqp_handler_, AMQP::Address{uri}}, + channel_{&connection_} { + + channel_.onError(this (const char* message) { + std::cerr << "Cannot create AMQP channel: " << message << std::endl; + + this->io_context().stop(); + }); + channel_.onReady(std::bind(&consumer::on_channel_ready, this)); +} + +void consumer::declare_exchange(const char* exchange, AMQP::ExchangeType type, const AMQP::SuccessCallback& callback) { + channel_.declareExchange(exchange, type).onError(this (const char* message) { + std::cerr << "Cannot declare AMQP exchange: " << message << std::endl; + + this->io_context().stop(); + }).onSuccess(callback); +} + +void consumer::declare_queue_request() { + using std::placeholders::_1; + using std::placeholders::_2; + using std::placeholders::_3; + + AMQP::Table args; + args.set("x-dead-letter-exchange", exchange_dlx); + + channel_.declareQueue(queue_request, AMQP::durable, args).onSuccess( + std::bind(&consumer::on_queue_success, this, _1, _2, _3) + ).onError(this (const char* message) { + std::cerr << "Cannot declare AMQP queue: " << message << std::endl; + + this->io_context().stop(); + }); +} + +void consumer::set_qos() { + using std::placeholders::_1; + using std::placeholders::_2; + using std::placeholders::_3; + + constexpr std::uint16_t prefetch_count = 1; + + channel_.setQos(prefetch_count).onSuccess( + std::bind(&consumer::on_qos_success, this) + ).onError(this (const char* message) { + std::cerr << "Cannot set QoS: " << message << std::endl; + + this->io_context().stop(); + }); +} + +void consumer::consume_queue_request() { + using std::placeholders::_1; + using std::placeholders::_2; + using std::placeholders::_3; + + channel_.consume(queue_request).onReceived( + std::bind(&consumer::on_received, this, _1, _2, _3) + ).onError(this (const char* message) { + std::cerr << "Cannot consume from AMQP queue: " << message << std::endl; + + this->io_context().stop(); + }); +} + +void consumer::handle_request(const AMQP::Message& message, std::uint64_t deliveryTag) { + const auto correlation_id = message.hasCorrelationID() ? std::make_optional(message.correlationID()) : std::nullopt; + const auto reply_to = message.hasReplyTo() ? std::make_optional(message.replyTo()) : std::nullopt; + + struct request_visitor { + consumer& consumer_; + const std::optional<std::string>& correlation_id_; + const std::optional<std::string>& reply_to_; + + void operator() (const domecam_replayd_request_ping& r) const { + if (reply_to_) { + consumer_.reply(domecam_replayd_response_pong{}, *reply_to_, correlation_id_); + } + } + + void operator() (domecam_replayd_request_run& r) const { + std::exception_ptr reason;
View file
domecam-0.1.18.obscpio/exe/domecam-replayd/main.cpp
Added
@@ -0,0 +1,81 @@ +/* + * SPDX-License-Identifier: GPL-3.0-or-later + * + * Copyright (C) 2017-2023 Matwey V. Kornilov <matwey.kornilov@gmail.com> + */ + +#include <iostream> +#include <thread> + +#include <boost/asio/io_service.hpp> +#include <boost/asio/signal_set.hpp> + +#include <amqpcpp.h> +#include <amqpcpp/libboostasio.h> + +#include <application.h> +#include <io.h> +#include <exe/domecam-replayd/consumer.h> + + +struct domecam_replayd_context { + std::string amqp_uri_; +}; + +domecam_replayd_context tag_invoke(boost::json::value_to_tag<domecam_replayd_context>, const boost::json::value& jv) { + using boost::json::value_to; + + const auto& obj = jv.as_object(); + + return domecam_replayd_context{ + value_to<std::string>(obj.at("amqp_uri"))}; +} + +class application: public abstract_application { +public: + application(); + ~application() override; +protected: + int do_run(const boost::program_options::variables_map& va) override; +public: + static const char config_opt; +private: + boost::asio::io_context io_context_; + boost::asio::signal_set signal_set_; +}; + +const char application::config_opt = "config"; + +application::application(): + abstract_application(), + io_context_(std::thread::hardware_concurrency()), + signal_set_{io_context_, SIGINT, SIGTERM} { + + namespace po = boost::program_options; + + opts_.add_options() + (config_opt, po::value<std::string>()->default_value("/etc/domecam-replayd.conf"), "configuration file") + ; + + signal_set_.async_wait(this (const boost::system::error_code& error, int signal_number) { + std::cerr << "Got signal " << signal_number << ", terminating..." << std::endl; + + io_context_.stop(); + }); +} + +application::~application() = default; + +int application::do_run(const boost::program_options::variables_map& va) { + auto ctx = load_json<domecam_replayd_context>(boost::filesystem::path{vaconfig_opt.as<std::string>()}); + consumer cmr{io_context_, ctx.amqp_uri_}; + + io_context_.run(); + + return 0; +} + +int main(int argc, char** argv) { + application app; + return app.run(argc, argv); +}
View file
domecam-0.1.18.obscpio/include/exe/domecam-replayd
Added
+(directory)
View file
domecam-0.1.18.obscpio/include/exe/domecam-replayd/consumer.h
Added
@@ -0,0 +1,57 @@ +/* + * SPDX-License-Identifier: GPL-3.0-or-later + * + * Copyright (C) 2017-2023 Matwey V. Kornilov <matwey.kornilov@gmail.com> + */ + +#ifndef _EXE_DOMECAM_REPLAYD_CONSUMER_H +#define _EXE_DOMECAM_REPLAYD_CONSUMER_H + +#include <cstdint> +#include <optional> +#include <stdexcept> +#include <string> + +#include <boost/asio/io_service.hpp> + +#include <amqpcpp.h> +#include <amqpcpp/libboostasio.h> + + +class consumer { +public: + consumer(boost::asio::io_context& io_context, const std::string& uri); + virtual ~consumer() = default; + + inline boost::asio::io_context& io_context() { + return io_context_; + } +private: + void declare_exchange(const char* exchange, AMQP::ExchangeType type, const AMQP::SuccessCallback& callback); + void declare_queue_request(); + void consume_queue_request(); + void set_qos(); + void handle_request(const AMQP::Message& message, std::uint64_t deliveryTag); + + template<class T> + void reply(const T& x, const std::string& routing_key, const std::optional<std::string>& correlation_id, const std::string& exchange = std::string()); + void reply(const std::string& body, const std::string& routing_key, const std::optional<std::string>& correlation_id, const std::string& exchange = std::string()); + + void on_channel_ready(); + void on_exchange_dlx_success(); + void on_queue_success(const std::string& /*name*/, std::uint32_t /*messagecount*/, std::uint32_t /*consumercount*/); + void on_qos_success(); + void on_received(const AMQP::Message& message, std::uint64_t deliveryTag, bool /*redelivered*/); + +private: + boost::asio::io_context& io_context_; + AMQP::LibBoostAsioHandler amqp_handler_; + AMQP::TcpConnection connection_; + AMQP::TcpChannel channel_; + +public: + constexpr static const char exchange_dlx = "domecam.dlx"; + constexpr static const char queue_request = "domecam.domecam-replayd.request"; +}; + +#endif // _EXE_DOMECAM_REPLAYD_CONSUMER_H
View file
domecam-0.1.17.obscpio/include/executorfwd.h -> domecam-0.1.18.obscpio/include/executorfwd.h
Changed
@@ -93,6 +93,13 @@ template<template<class> class Runner, class Executor, class ResultType = void> class runner_visitor; public: + replay_executor(); + replay_executor(const replay_executor&) = delete; + replay_executor(replay_executor&&) = delete; + replay_executor& operator=(const replay_executor&) = delete; + replay_executor& operator=(replay_executor&&) = delete; + virtual ~replay_executor() = default; + virtual executor_result run(const fits::variant_image& vi) const = 0; };
View file
domecam-0.1.17.obscpio/include/io.h -> domecam-0.1.18.obscpio/include/io.h
Changed
@@ -11,6 +11,8 @@ #include <memory> #include <variant> +#include <boost/version.hpp> + #include <camera_settings.h> #include <carriage.h> #include <iofwd.h> @@ -51,9 +53,18 @@ abstract_carriage::direction tag_invoke(boost::json::value_to_tag<abstract_carriage::direction>, const boost::json::value& jv); std::unique_ptr<executor> tag_invoke(boost::json::value_to_tag<std::unique_ptr<executor>>, const boost::json::value& jv); +std::unique_ptr<replay_executor> tag_invoke(boost::json::value_to_tag<std::unique_ptr<replay_executor>>, const boost::json::value& jv); +#if BOOST_VERSION >= 108100 +boost::json::result<optional_camera_settings::auto_tag> tag_invoke(boost::json::try_value_to_tag<optional_camera_settings::auto_tag>, const boost::json::value& jv); +#else optional_camera_settings::packet_size_type tag_invoke(boost::json::value_to_tag<optional_camera_settings::packet_size_type>, const boost::json::value& jv); -camera_settings::region_type tag_invoke(boost::json::value_to_tag<camera_settings::region_type>, const boost::json::value& jv); +#endif optional_camera_settings::region_type tag_invoke(boost::json::value_to_tag<optional_camera_settings::region_type>, const boost::json::value& jv); +#if BOOST_VERSION >= 108100 +boost::json::result<optional_camera_settings::full_tag> tag_invoke(boost::json::try_value_to_tag<optional_camera_settings::full_tag>, const boost::json::value& jv); +#else +camera_settings::region_type tag_invoke(boost::json::value_to_tag<camera_settings::region_type>, const boost::json::value& jv); +#endif optional_camera_settings tag_invoke(boost::json::value_to_tag<optional_camera_settings>, const boost::json::value& jv); camera tag_invoke(boost::json::value_to_tag<camera>, const boost::json::value& jv);
View file
domecam-0.1.17.obscpio/src/executorfwd.cpp -> domecam-0.1.18.obscpio/src/executorfwd.cpp
Changed
@@ -15,6 +15,9 @@ executor::executor() = default; +replay_executor::replay_executor() = default; + + camera_executor::source_mixin::source_mixin(const camera_executor& e, camera& c): ::source_mixin<source_type>(c, e.frames_number_, std::chrono::seconds(5), 20) {}
View file
domecam-0.1.17.obscpio/src/io.cpp -> domecam-0.1.18.obscpio/src/io.cpp
Changed
@@ -129,16 +129,111 @@ throw std::runtime_error(std::string("Unknown executor type ") + type.c_str()); } +std::unique_ptr<replay_executor> tag_invoke(boost::json::value_to_tag<std::unique_ptr<replay_executor>>, const boost::json::value& jv) { + using boost::json::value_to; + + const auto& obj = jv.as_object(); + const auto& type = obj.at("type").as_string(); + + if (type == "mean_raw") { + return std::unique_ptr<replay_executor>{new mean_raw_replay_executor{ + value_to<std::string>(obj.at("filename"))}}; + } else if (type == "grad") { + return std::unique_ptr<replay_executor>{new grad_replay_executor{ + value_to<std::string>(obj.at("filename"))}}; + } else if (type == "binary") { + return std::unique_ptr<replay_executor>{new binary_replay_executor{ + value_to<std::string>(obj.at("filename"))}}; + } else if (type == "pupil" || type == "edge" || type == "pupil_mask" || type == "mean_pupil_mask") { + const auto samples_number = load<std::size_t>(obj.if_contains("samples_number")).value_or(60); + const auto force_initial = load<bool>(obj.if_contains("force_initial")).value_or(true); + + if (type == "pupil") { + return std::unique_ptr<replay_executor>{new pupil_replay_executor{ + samples_number, + force_initial}}; + } else if (type == "edge") { + const auto loss_factor = value_to<float>(obj.at("loss_factor")); + + return std::unique_ptr<replay_executor>{new edge_replay_executor{ + samples_number, + force_initial, + loss_factor}}; + } else if (type == "pupil_mask") { + return std::unique_ptr<replay_executor>{new pupil_mask_replay_executor{ + value_to<std::string>(obj.at("filename")), + samples_number, + force_initial}}; + } else if (type == "mean_pupil_mask") { + return std::unique_ptr<replay_executor>{new mean_pupil_mask_replay_executor{ + value_to<std::string>(obj.at("filename")), + samples_number}}; + } + } else if (type == "clean" || type == "normalized_clean" || type == "relative_clean" || type == "acf") { + const auto& filename = value_to<std::string>(obj.at("filename")); + const auto& bias_filename = value_to<std::string>(obj.at("bias_filename")); + const auto& mask_filename = value_to<std::string>(obj.at("mask_filename")); + + if (type == "clean") { + return std::unique_ptr<replay_executor>{new clean_replay_executor{ + filename, + bias_filename, + mask_filename}}; + } else if (type == "normalized_clean") { + return std::unique_ptr<replay_executor>{new normalized_clean_replay_executor{ + filename, + bias_filename, + mask_filename}}; + } else if (type == "relative_clean" || type == "acf") { + const auto& pupil_filename = value_to<std::string>(obj.at("pupil_filename")); + + if (type == "relative_clean") { + return std::unique_ptr<replay_executor>{new relative_clean_replay_executor{ + filename, + bias_filename, + pupil_filename, + mask_filename}}; + } else if (type == "acf") { + const auto grid_size = value_to<std::size_t>(obj.at("grid_size")); + + return std::unique_ptr<replay_executor>{new acf_replay_executor{filename, + bias_filename, + pupil_filename, + mask_filename, + grid_size}}; + } + } + } + + throw std::runtime_error(std::string("Unknown executor type ") + type.c_str()); +} + +#if BOOST_VERSION >= 108100 + +boost::json::result<optional_camera_settings::auto_tag> tag_invoke(boost::json::try_value_to_tag<optional_camera_settings::auto_tag>, const boost::json::value& jv) { + using boost::json::make_error_code; + + if (const auto str = jv.if_string(); str && *str == "auto") { + return optional_camera_settings::auto_tag{}; + } + + return make_error_code(boost::json::error::syntax); +} + +#else + optional_camera_settings::packet_size_type tag_invoke(boost::json::value_to_tag<optional_camera_settings::packet_size_type>, const boost::json::value& jv) { using boost::json::value_to; - if (jv.is_string() && jv.get_string() == "auto") { + if (const auto str = jv.if_string(); str && *str == "auto") { return optional_camera_settings::auto_tag{}; } return value_to<camera_settings::packet_size_type>(jv); } +#endif + camera_settings::region_type tag_invoke(boost::json::value_to_tag<camera_settings::region_type>, const boost::json::value& jv) { using boost::json::value_to; @@ -149,16 +244,32 @@ value_to<std::array<std::int32_t, 2>>(obj.at("size"))}; } +#if BOOST_VERSION >= 108100 + +boost::json::result<optional_camera_settings::full_tag> tag_invoke(boost::json::try_value_to_tag<optional_camera_settings::full_tag>, const boost::json::value& jv) { + using boost::json::make_error_code; + + if (const auto str = jv.if_string(); str && *str == "full") { + return optional_camera_settings::full_tag{}; + } + + return make_error_code(boost::json::error::syntax); +} + +#else + optional_camera_settings::region_type tag_invoke(boost::json::value_to_tag<optional_camera_settings::region_type>, const boost::json::value& jv) { using boost::json::value_to; - if (jv.is_string() && jv.get_string() == "full") { + if (const auto str = jv.if_string(); str && *str == "full") { return optional_camera_settings::full_tag{}; } return value_to<camera_settings::region_type>(jv); } +#endif + optional_camera_settings tag_invoke(boost::json::value_to_tag<optional_camera_settings>, const boost::json::value& jv) { using boost::json::value_to;
View file
domecam.obsinfo
Changed
@@ -1,3 +1,3 @@ name: domecam -version: 0.1.17 -mtime: 1698856173 +version: 0.1.18 +mtime: 1702903872
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.