From 30776c95e360a6499bb5aac02ccbd20bd942acba Mon Sep 17 00:00:00 2001 From: ConnorC432 Date: Thu, 19 Mar 2026 17:56:03 +0000 Subject: [PATCH 1/7] suppress sleep on linux using dbus inhibitor lock --- SerialPrograms/CMakeLists.txt | 7 +- .../Environment/SystemSleep.cpp | 2 + .../Environment/SystemSleep_Linux.tpp | 165 ++++++++++++++++++ SerialPrograms/cmake/SourceFiles.cmake | 1 + 4 files changed, 174 insertions(+), 1 deletion(-) create mode 100644 SerialPrograms/Source/CommonFramework/Environment/SystemSleep_Linux.tpp diff --git a/SerialPrograms/CMakeLists.txt b/SerialPrograms/CMakeLists.txt index ec74150758..595a52916a 100644 --- a/SerialPrograms/CMakeLists.txt +++ b/SerialPrograms/CMakeLists.txt @@ -395,7 +395,7 @@ else() # macOS and Linux if(NOT IS_DIRECTORY ${EXTRACTED_ONNX_PATH}) message(STATUS "ONNX_ROOT_PATH not found. Downloading ONNX Runtime v${ONNXRUNTIME_VERSION}...") - + # logic for downloading... set(DOWNLOAD_LOCATION "${CMAKE_BINARY_DIR}/${ONNXRUNTIME_TGZ_NAME}") file(DOWNLOAD @@ -447,6 +447,11 @@ else() # macOS and Linux else() message(FATAL_ERROR "Could not find ONNX Runtime headers or library.") endif() + + # Systemd DBus Library + find_package(sdbus-c++ REQUIRED) + target_link_libraries(SerialProgramsLib PRIVATE sdbus-c++) + target_link_libraries(SerialPrograms PRIVATE sdbus-c++) endif() # end Linux # Find OpenCV diff --git a/SerialPrograms/Source/CommonFramework/Environment/SystemSleep.cpp b/SerialPrograms/Source/CommonFramework/Environment/SystemSleep.cpp index b679e936c3..3988946c81 100644 --- a/SerialPrograms/Source/CommonFramework/Environment/SystemSleep.cpp +++ b/SerialPrograms/Source/CommonFramework/Environment/SystemSleep.cpp @@ -11,6 +11,8 @@ #include "SystemSleep_Windows.tpp" #elif __APPLE__ #include "SystemSleep_Apple.tpp" +#elif __linux__ +#include "SystemSleep_Linux.tpp" #else namespace PokemonAutomation{ SystemSleepController& SystemSleepController::instance(){ diff --git a/SerialPrograms/Source/CommonFramework/Environment/SystemSleep_Linux.tpp b/SerialPrograms/Source/CommonFramework/Environment/SystemSleep_Linux.tpp new file mode 100644 index 0000000000..a6940957ed --- /dev/null +++ b/SerialPrograms/Source/CommonFramework/Environment/SystemSleep_Linux.tpp @@ -0,0 +1,165 @@ +/* OS Sleep (Linux) + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#include +#include "Common/Cpp/Concurrency/ConditionVariable.h" +#include "Common/Cpp/Concurrency/AsyncTask.h" +#include "Common/Cpp/Concurrency/ThreadPool.h" +#include "CommonFramework/Logging/Logger.h" +#include "CommonFramework/Tools/GlobalThreadPools.h" +#include "SystemSleep.h" + +namespace PokemonAutomation{ + + +class LinuxSleepController final : public SystemSleepController{ +public: + LinuxSleepController() + : m_screen_on_requests(0) + , m_no_sleep_requests(0) + , m_stopping(false) + , m_thread(GlobalThreadPools::unlimited_normal().dispatch_now_blocking( + [this]{ thread_loop(); }) + ) + {} + virtual ~LinuxSleepController(){ + stop(); + } + virtual void stop() noexcept override{ + if (!m_thread){ + return; + } + { + std::lock_guard lg(m_lock); + m_stopping = true; + } + m_cv.notify_all(); + m_thread.wait_and_ignore_exceptions(); + m_inhibit_fd.reset(); + if (m_state.load(std::memory_order_relaxed) != SleepSuppress::NONE){ + try{ + global_logger_tagged().log( + "Destroying LinuxSleepController with active requests...", + COLOR_RED + ); + }catch (...){} + } + } + + virtual void push_screen_on() override{ + std::lock_guard lg(m_lock); + m_screen_on_requests++; + m_cv.notify_all(); + } + virtual void pop_screen_on() override{ + std::lock_guard lg(m_lock); + m_screen_on_requests--; + m_cv.notify_all(); + } + virtual void push_no_sleep() override{ + std::lock_guard lg(m_lock); + m_no_sleep_requests++; + m_cv.notify_all(); + } + virtual void pop_no_sleep() override{ + std::lock_guard lg(m_lock); + m_no_sleep_requests--; + m_cv.notify_all(); + } + +private: + void thread_loop() + { + auto connection = sdbus::createSystemBusConnection(); + auto proxy = sdbus::createProxy( + *connection, + sdbus::BusName{"org.freedesktop.login1"}, + sdbus::ObjectPath{"/org/freedesktop/login1"} + ); + + while (true) + { + std::unique_lock lg(m_lock); + if (m_stopping) + { + return; + } + + SleepSuppress before_state = m_state.load(std::memory_order_relaxed); + SleepSuppress after_state = SleepSuppress::NONE; + + bool need_inhibit = false; + std::string what; + if (m_no_sleep_requests > 0) + { + need_inhibit = true; + what = "sleep"; + after_state = SleepSuppress::NO_SLEEP; + } + else if (m_screen_on_requests > 0) + { + need_inhibit = true; + what = "idle"; + after_state = SleepSuppress::SCREEN_ON; + } + if (need_inhibit && !m_inhibit_fd) + { + try + { + sdbus::UnixFd fd; + proxy->callMethod("Inhibit") + .onInterface("org.freedesktop.login1.Manager") + .withArguments(what, "PokemonAutomation", "Keeping system awake", "block") + .storeResultsTo(fd); + m_inhibit_fd = std::make_unique(std::move(fd)); + + global_logger_tagged().log("Acquired sleep inhibitor", COLOR_BLUE); + } + + catch (const sdbus::Error &e) + { + global_logger_tagged().log(std::string("DBus error: ") + e.what(), COLOR_RED); + } + } + else if (!need_inhibit && m_inhibit_fd) + { + m_inhibit_fd.reset(); + global_logger_tagged().log("Released sleep inhibitor", COLOR_BLUE); + } + + if (before_state != after_state) + { + m_state.store(after_state, std::memory_order_release); + notify_listeners(after_state); + } + + m_cv.wait(lg); + } + } + +private: + size_t m_screen_on_requests = 0; + size_t m_no_sleep_requests = 0; + + bool m_stopping; + ConditionVariable m_cv; + AsyncTask m_thread; + + std::unique_ptr m_inhibit_fd; +}; + + +SystemSleepController& SystemSleepController::instance(){ + static LinuxSleepController controller; + return controller; +} + + + + + + +} diff --git a/SerialPrograms/cmake/SourceFiles.cmake b/SerialPrograms/cmake/SourceFiles.cmake index 846f06ef95..5890df225c 100644 --- a/SerialPrograms/cmake/SourceFiles.cmake +++ b/SerialPrograms/cmake/SourceFiles.cmake @@ -364,6 +364,7 @@ file(GLOB LIBRARY_SOURCES Source/CommonFramework/Environment/SystemSleep.cpp Source/CommonFramework/Environment/SystemSleep.h Source/CommonFramework/Environment/SystemSleep_Apple.tpp + Source/CommonFramework/Environment/SystemSleep_Linux.tpp Source/CommonFramework/Environment/SystemSleep_Windows.tpp Source/CommonFramework/ErrorReports/ErrorReports.cpp Source/CommonFramework/ErrorReports/ErrorReports.h From be3d26cb3c3443b506a4b23f57eae680174bcc13 Mon Sep 17 00:00:00 2001 From: pifopi Date: Fri, 20 Mar 2026 12:27:57 +0100 Subject: [PATCH 2/7] Install libsdbus-c++-dev --- .github/workflows/cpp-ci-serial-programs-base.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cpp-ci-serial-programs-base.yml b/.github/workflows/cpp-ci-serial-programs-base.yml index 09d52a5ba1..f15abcff3e 100644 --- a/.github/workflows/cpp-ci-serial-programs-base.yml +++ b/.github/workflows/cpp-ci-serial-programs-base.yml @@ -64,7 +64,7 @@ jobs: cd Arduino-Source sudo apt update sudo apt upgrade - sudo apt install clang-tools libopencv-dev + sudo apt install clang-tools libopencv-dev libsdbus-c++-dev sudo apt install ./3rdPartyBinaries/libdpp-10.0.28-linux-x64.deb From 64c1c1d3f0b2e312a4d4c2795c566f4d483481fe Mon Sep 17 00:00:00 2001 From: ConnorC432 Date: Fri, 20 Mar 2026 13:26:01 +0000 Subject: [PATCH 3/7] use bundled libsdbus-c++ library --- .../include/sdbus-c++/AdaptorInterfaces.h | 152 +++ .../include/sdbus-c++/ConvenienceApiClasses.h | 290 ++++++ .../sdbus-c++/ConvenienceApiClasses.inl | 718 +++++++++++++ 3rdParty/sdbus-cpp/include/sdbus-c++/Error.h | 106 ++ 3rdParty/sdbus-cpp/include/sdbus-c++/Flags.h | 99 ++ .../sdbus-cpp/include/sdbus-c++/IConnection.h | 584 +++++++++++ .../sdbus-cpp/include/sdbus-c++/IObject.h | 484 +++++++++ 3rdParty/sdbus-cpp/include/sdbus-c++/IProxy.h | 981 ++++++++++++++++++ .../sdbus-cpp/include/sdbus-c++/Message.h | 782 ++++++++++++++ .../include/sdbus-c++/MethodResult.h | 93 ++ .../include/sdbus-c++/ProxyInterfaces.h | 217 ++++ .../include/sdbus-c++/StandardInterfaces.h | 530 ++++++++++ .../sdbus-cpp/include/sdbus-c++/TypeTraits.h | 702 +++++++++++++ 3rdParty/sdbus-cpp/include/sdbus-c++/Types.h | 597 +++++++++++ .../sdbus-cpp/include/sdbus-c++/VTableItems.h | 112 ++ .../include/sdbus-c++/VTableItems.inl | 301 ++++++ .../sdbus-cpp/include/sdbus-c++/sdbus-c++.h | 38 + .../sdbus-c++/sdbus-c++-config-version.cmake | 65 ++ .../cmake/sdbus-c++/sdbus-c++-config.cmake | 28 + .../sdbus-c++/sdbus-c++-targets-release.cmake | 19 + .../cmake/sdbus-c++/sdbus-c++-targets.cmake | 114 ++ 3rdParty/sdbus-cpp/lib/libsdbus-c++.a | Bin 0 -> 764160 bytes 3rdParty/sdbus-cpp/lib/pkgconfig/sdbus-c++.pc | 11 + SerialPrograms/CMakeLists.txt | 21 +- 24 files changed, 7041 insertions(+), 3 deletions(-) create mode 100644 3rdParty/sdbus-cpp/include/sdbus-c++/AdaptorInterfaces.h create mode 100644 3rdParty/sdbus-cpp/include/sdbus-c++/ConvenienceApiClasses.h create mode 100644 3rdParty/sdbus-cpp/include/sdbus-c++/ConvenienceApiClasses.inl create mode 100644 3rdParty/sdbus-cpp/include/sdbus-c++/Error.h create mode 100644 3rdParty/sdbus-cpp/include/sdbus-c++/Flags.h create mode 100644 3rdParty/sdbus-cpp/include/sdbus-c++/IConnection.h create mode 100644 3rdParty/sdbus-cpp/include/sdbus-c++/IObject.h create mode 100644 3rdParty/sdbus-cpp/include/sdbus-c++/IProxy.h create mode 100644 3rdParty/sdbus-cpp/include/sdbus-c++/Message.h create mode 100644 3rdParty/sdbus-cpp/include/sdbus-c++/MethodResult.h create mode 100644 3rdParty/sdbus-cpp/include/sdbus-c++/ProxyInterfaces.h create mode 100644 3rdParty/sdbus-cpp/include/sdbus-c++/StandardInterfaces.h create mode 100644 3rdParty/sdbus-cpp/include/sdbus-c++/TypeTraits.h create mode 100644 3rdParty/sdbus-cpp/include/sdbus-c++/Types.h create mode 100644 3rdParty/sdbus-cpp/include/sdbus-c++/VTableItems.h create mode 100644 3rdParty/sdbus-cpp/include/sdbus-c++/VTableItems.inl create mode 100644 3rdParty/sdbus-cpp/include/sdbus-c++/sdbus-c++.h create mode 100644 3rdParty/sdbus-cpp/lib/cmake/sdbus-c++/sdbus-c++-config-version.cmake create mode 100644 3rdParty/sdbus-cpp/lib/cmake/sdbus-c++/sdbus-c++-config.cmake create mode 100644 3rdParty/sdbus-cpp/lib/cmake/sdbus-c++/sdbus-c++-targets-release.cmake create mode 100644 3rdParty/sdbus-cpp/lib/cmake/sdbus-c++/sdbus-c++-targets.cmake create mode 100644 3rdParty/sdbus-cpp/lib/libsdbus-c++.a create mode 100644 3rdParty/sdbus-cpp/lib/pkgconfig/sdbus-c++.pc diff --git a/3rdParty/sdbus-cpp/include/sdbus-c++/AdaptorInterfaces.h b/3rdParty/sdbus-cpp/include/sdbus-c++/AdaptorInterfaces.h new file mode 100644 index 0000000000..550a0959f7 --- /dev/null +++ b/3rdParty/sdbus-cpp/include/sdbus-c++/AdaptorInterfaces.h @@ -0,0 +1,152 @@ +/** + * (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland + * (C) 2016 - 2024 Stanislav Angelovic + * + * @file AdaptorInterfaces.h + * + * Created on: Nov 8, 2016 + * Project: sdbus-c++ + * Description: High-level D-Bus IPC C++ library based on sd-bus + * + * This file is part of sdbus-c++. + * + * sdbus-c++ is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 of the License, or + * (at your option) any later version. + * + * sdbus-c++ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with sdbus-c++. If not, see . + */ + +#ifndef SDBUS_CXX_ADAPTORINTERFACES_H_ +#define SDBUS_CXX_ADAPTORINTERFACES_H_ + +#include +#include +#include +#include + +// Forward declarations +namespace sdbus { + class IConnection; +} + +namespace sdbus { + + /********************************************//** + * @class ObjectHolder + * + * ObjectHolder is a helper that simply owns and provides + * access to an object to other classes in the inheritance + * hierarchy of an object based on generated interface classes. + * + ***********************************************/ + class ObjectHolder + { + protected: + ObjectHolder(std::unique_ptr&& object) + : object_(std::move(object)) + { + } + + const IObject& getObject() const + { + assert(object_ != nullptr); + return *object_; + } + + IObject& getObject() + { + assert(object_ != nullptr); + return *object_; + } + + private: + std::unique_ptr object_; + }; + + /********************************************//** + * @class AdaptorInterfaces + * + * AdaptorInterfaces is a helper template class that joins all interface classes of a remote + * D-Bus object generated by sdbus-c++-xml2cpp to be used on the server (the adaptor) side, + * including some auxiliary classes. AdaptorInterfaces is the class that native-like object + * implementation classes written by users should inherit from and implement all pure virtual + * methods. So the _Interfaces template parameter is a list of sdbus-c++-xml2cpp-generated + * adaptor-side interface classes representing interfaces (with methods, signals and properties) + * of the D-Bus object. + * + * In the final adaptor class inherited from AdaptorInterfaces, one needs to make sure: + * 1. to call `registerAdaptor();` in the class constructor, and, conversely, + * 2. to call `unregisterAdaptor();` in the class destructor, + * so that the object API vtable is registered and unregistered at the proper time. + * + ***********************************************/ + template + class AdaptorInterfaces + : protected ObjectHolder + , public _Interfaces... + { + public: + /*! + * @brief Creates object instance + * + * @param[in] connection D-Bus connection where the object will publish itself + * @param[in] objectPath Path of the D-Bus object + * + * For more information, consult @ref createObject(sdbus::IConnection&,std::string) + */ + AdaptorInterfaces(IConnection& connection, ObjectPath objectPath) + : ObjectHolder(createObject(connection, std::move(objectPath))) + , _Interfaces(getObject())... + { + } + + /*! + * @brief Adds object vtable (i.e. D-Bus API) definitions for all interfaces it implements + * + * This function must be called in the constructor of the final adaptor class that implements AdaptorInterfaces. + * + * See also @ref IObject::addVTable() + */ + void registerAdaptor() + { + (_Interfaces::registerAdaptor(), ...); + } + + /*! + * @brief Unregisters adaptors's API and removes it from the bus + * + * This function must be called in the destructor of the final adaptor class that implements AdaptorInterfaces. + * + * For more information, see underlying @ref IObject::unregister() + */ + void unregisterAdaptor() + { + getObject().unregister(); + } + + /*! + * @brief Returns reference to the underlying IObject instance + */ + using ObjectHolder::getObject; + + protected: + using base_type = AdaptorInterfaces; + + AdaptorInterfaces(const AdaptorInterfaces&) = delete; + AdaptorInterfaces& operator=(const AdaptorInterfaces&) = delete; + AdaptorInterfaces(AdaptorInterfaces&&) = delete; + AdaptorInterfaces& operator=(AdaptorInterfaces&&) = delete; + ~AdaptorInterfaces() = default; + }; + +} + +#endif /* SDBUS_CXX_ADAPTORINTERFACES_H_ */ diff --git a/3rdParty/sdbus-cpp/include/sdbus-c++/ConvenienceApiClasses.h b/3rdParty/sdbus-cpp/include/sdbus-c++/ConvenienceApiClasses.h new file mode 100644 index 0000000000..d644ab8ebe --- /dev/null +++ b/3rdParty/sdbus-cpp/include/sdbus-c++/ConvenienceApiClasses.h @@ -0,0 +1,290 @@ +/** + * (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland + * (C) 2016 - 2024 Stanislav Angelovic + * + * @file ConvenienceApiClasses.h + * + * Created on: Jan 19, 2017 + * Project: sdbus-c++ + * Description: High-level D-Bus IPC C++ library based on sd-bus + * + * This file is part of sdbus-c++. + * + * sdbus-c++ is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 of the License, or + * (at your option) any later version. + * + * sdbus-c++ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with sdbus-c++. If not, see . + */ + +#ifndef SDBUS_CXX_CONVENIENCEAPICLASSES_H_ +#define SDBUS_CXX_CONVENIENCEAPICLASSES_H_ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +// Forward declarations +namespace sdbus { + class IObject; + class IProxy; + class Error; + class PendingAsyncCall; +} + +namespace sdbus { + + class VTableAdder + { + public: + void forInterface(InterfaceName interfaceName); + void forInterface(std::string interfaceName); + [[nodiscard]] Slot forInterface(InterfaceName interfaceName, return_slot_t); + [[nodiscard]] Slot forInterface(std::string interfaceName, return_slot_t); + + private: + friend IObject; + VTableAdder(IObject& object, std::vector vtable); + + private: + IObject& object_; + std::vector vtable_; + }; + + class SignalEmitter + { + public: + SignalEmitter& onInterface(const InterfaceName& interfaceName); + SignalEmitter& onInterface(const std::string& interfaceName); + SignalEmitter& onInterface(const char* interfaceName); + template void withArguments(_Args&&... args); + + SignalEmitter(SignalEmitter&& other) = default; + ~SignalEmitter() noexcept(false); + + private: + friend IObject; + SignalEmitter(IObject& object, const SignalName& signalName); + SignalEmitter(IObject& object, const char* signalName); + + private: + IObject& object_; + const char* signalName_; + Signal signal_; + int exceptions_{}; // Number of active exceptions when SignalEmitter is constructed + }; + + class MethodInvoker + { + public: + MethodInvoker& onInterface(const InterfaceName& interfaceName); + MethodInvoker& onInterface(const std::string& interfaceName); + MethodInvoker& onInterface(const char* interfaceName); + MethodInvoker& withTimeout(uint64_t usec); + template + MethodInvoker& withTimeout(const std::chrono::duration<_Rep, _Period>& timeout); + template MethodInvoker& withArguments(_Args&&... args); + template void storeResultsTo(_Args&... args); + void dontExpectReply(); + + MethodInvoker(MethodInvoker&& other) = default; + ~MethodInvoker() noexcept(false); + + private: + friend IProxy; + MethodInvoker(IProxy& proxy, const MethodName& methodName); + MethodInvoker(IProxy& proxy, const char* methodName); + + private: + IProxy& proxy_; + const char* methodName_; + uint64_t timeout_{}; + MethodCall method_; + int exceptions_{}; // Number of active exceptions when MethodInvoker is constructed + bool methodCalled_{}; + }; + + class AsyncMethodInvoker + { + public: + AsyncMethodInvoker& onInterface(const InterfaceName& interfaceName); + AsyncMethodInvoker& onInterface(const std::string& interfaceName); + AsyncMethodInvoker& onInterface(const char* interfaceName); + AsyncMethodInvoker& withTimeout(uint64_t usec); + template + AsyncMethodInvoker& withTimeout(const std::chrono::duration<_Rep, _Period>& timeout); + template AsyncMethodInvoker& withArguments(_Args&&... args); + template PendingAsyncCall uponReplyInvoke(_Function&& callback); + template [[nodiscard]] Slot uponReplyInvoke(_Function&& callback, return_slot_t); + // Returned future will be std::future for no (void) D-Bus method return value + // or std::future for single D-Bus method return value + // or std::future> for multiple method return values + template std::future> getResultAsFuture(); + + private: + friend IProxy; + AsyncMethodInvoker(IProxy& proxy, const MethodName& methodName); + AsyncMethodInvoker(IProxy& proxy, const char* methodName); + template async_reply_handler makeAsyncReplyHandler(_Function&& callback); + + private: + IProxy& proxy_; + const char* methodName_; + uint64_t timeout_{}; + MethodCall method_; + }; + + class SignalSubscriber + { + public: + SignalSubscriber& onInterface(const InterfaceName& interfaceName); + SignalSubscriber& onInterface(const std::string& interfaceName); + SignalSubscriber& onInterface(const char* interfaceName); + template void call(_Function&& callback); + template [[nodiscard]] Slot call(_Function&& callback, return_slot_t); + + private: + friend IProxy; + SignalSubscriber(IProxy& proxy, const SignalName& signalName); + SignalSubscriber(IProxy& proxy, const char* signalName); + template signal_handler makeSignalHandler(_Function&& callback); + + private: + IProxy& proxy_; + const char* signalName_; + const char* interfaceName_{}; + }; + + class PropertyGetter + { + public: + Variant onInterface(std::string_view interfaceName); + + private: + friend IProxy; + PropertyGetter(IProxy& proxy, std::string_view propertyName); + + static constexpr const char* DBUS_PROPERTIES_INTERFACE_NAME = "org.freedesktop.DBus.Properties"; + + private: + IProxy& proxy_; + std::string_view propertyName_; + }; + + class AsyncPropertyGetter + { + public: + AsyncPropertyGetter& onInterface(std::string_view interfaceName); + template PendingAsyncCall uponReplyInvoke(_Function&& callback); + template [[nodiscard]] Slot uponReplyInvoke(_Function&& callback, return_slot_t); + std::future getResultAsFuture(); + + private: + friend IProxy; + AsyncPropertyGetter(IProxy& proxy, std::string_view propertyName); + + static constexpr const char* DBUS_PROPERTIES_INTERFACE_NAME = "org.freedesktop.DBus.Properties"; + + private: + IProxy& proxy_; + std::string_view propertyName_; + std::string_view interfaceName_; + }; + + class PropertySetter + { + public: + PropertySetter& onInterface(std::string_view interfaceName); + template void toValue(const _Value& value); + template void toValue(const _Value& value, dont_expect_reply_t); + void toValue(const Variant& value); + void toValue(const Variant& value, dont_expect_reply_t); + + private: + friend IProxy; + PropertySetter(IProxy& proxy, std::string_view propertyName); + + static constexpr const char* DBUS_PROPERTIES_INTERFACE_NAME = "org.freedesktop.DBus.Properties"; + + private: + IProxy& proxy_; + std::string_view propertyName_; + std::string_view interfaceName_; + }; + + class AsyncPropertySetter + { + public: + AsyncPropertySetter& onInterface(std::string_view interfaceName); + template AsyncPropertySetter& toValue(_Value&& value); + AsyncPropertySetter& toValue(Variant value); + template PendingAsyncCall uponReplyInvoke(_Function&& callback); + template [[nodiscard]] Slot uponReplyInvoke(_Function&& callback, return_slot_t); + std::future getResultAsFuture(); + + private: + friend IProxy; + AsyncPropertySetter(IProxy& proxy, std::string_view propertyName); + + static constexpr const char* DBUS_PROPERTIES_INTERFACE_NAME = "org.freedesktop.DBus.Properties"; + + private: + IProxy& proxy_; + std::string_view propertyName_; + std::string_view interfaceName_; + Variant value_; + }; + + class AllPropertiesGetter + { + public: + std::map onInterface(std::string_view interfaceName); + + private: + friend IProxy; + AllPropertiesGetter(IProxy& proxy); + + static constexpr const char* DBUS_PROPERTIES_INTERFACE_NAME = "org.freedesktop.DBus.Properties"; + + private: + IProxy& proxy_; + }; + + class AsyncAllPropertiesGetter + { + public: + AsyncAllPropertiesGetter& onInterface(std::string_view interfaceName); + template PendingAsyncCall uponReplyInvoke(_Function&& callback); + template [[nodiscard]] Slot uponReplyInvoke(_Function&& callback, return_slot_t); + std::future> getResultAsFuture(); + + private: + friend IProxy; + AsyncAllPropertiesGetter(IProxy& proxy); + + static constexpr const char* DBUS_PROPERTIES_INTERFACE_NAME = "org.freedesktop.DBus.Properties"; + + private: + IProxy& proxy_; + std::string_view interfaceName_; + }; + +} // namespace sdbus + +#endif /* SDBUS_CXX_CONVENIENCEAPICLASSES_H_ */ diff --git a/3rdParty/sdbus-cpp/include/sdbus-c++/ConvenienceApiClasses.inl b/3rdParty/sdbus-cpp/include/sdbus-c++/ConvenienceApiClasses.inl new file mode 100644 index 0000000000..4be40a9fb5 --- /dev/null +++ b/3rdParty/sdbus-cpp/include/sdbus-c++/ConvenienceApiClasses.inl @@ -0,0 +1,718 @@ +/** + * (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland + * (C) 2016 - 2024 Stanislav Angelovic + * + * @file ConvenienceApiClasses.inl + * + * Created on: Dec 19, 2016 + * Project: sdbus-c++ + * Description: High-level D-Bus IPC C++ library based on sd-bus + * + * This file is part of sdbus-c++. + * + * sdbus-c++ is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 of the License, or + * (at your option) any later version. + * + * sdbus-c++ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with sdbus-c++. If not, see . + */ + +#ifndef SDBUS_CPP_CONVENIENCEAPICLASSES_INL_ +#define SDBUS_CPP_CONVENIENCEAPICLASSES_INL_ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace sdbus { + + /*** ------------- ***/ + /*** VTableAdder ***/ + /*** ------------- ***/ + + inline VTableAdder::VTableAdder(IObject& object, std::vector vtable) + : object_(object) + , vtable_(std::move(vtable)) + { + } + + inline void VTableAdder::forInterface(InterfaceName interfaceName) + { + object_.addVTable(std::move(interfaceName), std::move(vtable_)); + } + + inline void VTableAdder::forInterface(std::string interfaceName) + { + forInterface(InterfaceName{std::move(interfaceName)}); + } + + [[nodiscard]] inline Slot VTableAdder::forInterface(InterfaceName interfaceName, return_slot_t) + { + return object_.addVTable(std::move(interfaceName), std::move(vtable_), return_slot); + } + + [[nodiscard]] inline Slot VTableAdder::forInterface(std::string interfaceName, return_slot_t) + { + return forInterface(InterfaceName{std::move(interfaceName)}, return_slot); + } + + /*** ------------- ***/ + /*** SignalEmitter ***/ + /*** ------------- ***/ + + inline SignalEmitter::SignalEmitter(IObject& object, const SignalName& signalName) + : SignalEmitter(object, signalName.c_str()) + { + } + + inline SignalEmitter::SignalEmitter(IObject& object, const char* signalName) + : object_(object) + , signalName_(signalName) + , exceptions_(std::uncaught_exceptions()) + { + } + + inline SignalEmitter::~SignalEmitter() noexcept(false) // since C++11, destructors must + { // explicitly be allowed to throw + // Don't emit the signal if SignalEmitter threw an exception in one of its methods + if (std::uncaught_exceptions() != exceptions_) + return; + + // emitSignal() can throw. But as the SignalEmitter shall always be used as an unnamed, + // temporary object, i.e. not as a stack-allocated object, the double-exception situation + // shall never happen. I.e. it should not happen that this destructor is directly called + // in the stack-unwinding process of another flying exception (which would lead to immediate + // termination). It can be called indirectly in the destructor of another object, but that's + // fine and safe provided that the caller catches exceptions thrown from here. + // Therefore, we can allow emitSignal() to throw even if we are in the destructor. + // Bottomline is, to be on the safe side, the caller must take care of catching and reacting + // to the exception thrown from here if the caller is a destructor itself. + object_.emitSignal(signal_); + } + + inline SignalEmitter& SignalEmitter::onInterface(const InterfaceName& interfaceName) + { + return onInterface(interfaceName.c_str()); + } + + inline SignalEmitter& SignalEmitter::onInterface(const std::string& interfaceName) + { + return onInterface(interfaceName.c_str()); + } + + inline SignalEmitter& SignalEmitter::onInterface(const char* interfaceName) + { + signal_ = object_.createSignal(interfaceName, signalName_); + + return *this; + } + + template + inline void SignalEmitter::withArguments(_Args&&... args) + { + assert(signal_.isValid()); // onInterface() must be placed/called prior to withArguments() + + detail::serialize_pack(signal_, std::forward<_Args>(args)...); + } + + /*** ------------- ***/ + /*** MethodInvoker ***/ + /*** ------------- ***/ + + inline MethodInvoker::MethodInvoker(IProxy& proxy, const MethodName& methodName) + : MethodInvoker(proxy, methodName.c_str()) + { + } + + inline MethodInvoker::MethodInvoker(IProxy& proxy, const char* methodName) + : proxy_(proxy) + , methodName_(methodName) + , exceptions_(std::uncaught_exceptions()) + { + } + + inline MethodInvoker::~MethodInvoker() noexcept(false) // since C++11, destructors must + { // explicitly be allowed to throw + // Don't call the method if it has been called already or if MethodInvoker + // threw an exception in one of its methods + if (methodCalled_ || std::uncaught_exceptions() != exceptions_) + return; + + // callMethod() can throw. But as the MethodInvoker shall always be used as an unnamed, + // temporary object, i.e. not as a stack-allocated object, the double-exception situation + // shall never happen. I.e. it should not happen that this destructor is directly called + // in the stack-unwinding process of another flying exception (which would lead to immediate + // termination). It can be called indirectly in the destructor of another object, but that's + // fine and safe provided that the caller catches exceptions thrown from here. + // Therefore, we can allow callMethod() to throw even if we are in the destructor. + // Bottomline is, to be on the safe side, the caller must take care of catching and reacting + // to the exception thrown from here if the caller is a destructor itself. + proxy_.callMethod(method_, timeout_); + } + + inline MethodInvoker& MethodInvoker::onInterface(const InterfaceName& interfaceName) + { + return onInterface(interfaceName.c_str()); + } + + inline MethodInvoker& MethodInvoker::onInterface(const std::string& interfaceName) + { + return onInterface(interfaceName.c_str()); + } + + inline MethodInvoker& MethodInvoker::onInterface(const char* interfaceName) + { + method_ = proxy_.createMethodCall(interfaceName, methodName_); + + return *this; + } + + inline MethodInvoker& MethodInvoker::withTimeout(uint64_t usec) + { + timeout_ = usec; + + return *this; + } + + template + inline MethodInvoker& MethodInvoker::withTimeout(const std::chrono::duration<_Rep, _Period>& timeout) + { + auto microsecs = std::chrono::duration_cast(timeout); + return withTimeout(microsecs.count()); + } + + template + inline MethodInvoker& MethodInvoker::withArguments(_Args&&... args) + { + assert(method_.isValid()); // onInterface() must be placed/called prior to this function + + detail::serialize_pack(method_, std::forward<_Args>(args)...); + + return *this; + } + + template + inline void MethodInvoker::storeResultsTo(_Args&... args) + { + assert(method_.isValid()); // onInterface() must be placed/called prior to this function + + auto reply = proxy_.callMethod(method_, timeout_); + methodCalled_ = true; + + detail::deserialize_pack(reply, args...); + } + + inline void MethodInvoker::dontExpectReply() + { + assert(method_.isValid()); // onInterface() must be placed/called prior to this function + + method_.dontExpectReply(); + } + + /*** ------------------ ***/ + /*** AsyncMethodInvoker ***/ + /*** ------------------ ***/ + + inline AsyncMethodInvoker::AsyncMethodInvoker(IProxy& proxy, const MethodName& methodName) + : AsyncMethodInvoker(proxy, methodName.c_str()) + { + } + + inline AsyncMethodInvoker::AsyncMethodInvoker(IProxy& proxy, const char* methodName) + : proxy_(proxy) + , methodName_(methodName) + { + } + + inline AsyncMethodInvoker& AsyncMethodInvoker::onInterface(const InterfaceName& interfaceName) + { + return onInterface(interfaceName.c_str()); + } + + inline AsyncMethodInvoker& AsyncMethodInvoker::onInterface(const std::string& interfaceName) + { + return onInterface(interfaceName.c_str()); + } + + inline AsyncMethodInvoker& AsyncMethodInvoker::onInterface(const char* interfaceName) + { + method_ = proxy_.createMethodCall(interfaceName, methodName_); + + return *this; + } + + inline AsyncMethodInvoker& AsyncMethodInvoker::withTimeout(uint64_t usec) + { + timeout_ = usec; + + return *this; + } + + template + inline AsyncMethodInvoker& AsyncMethodInvoker::withTimeout(const std::chrono::duration<_Rep, _Period>& timeout) + { + auto microsecs = std::chrono::duration_cast(timeout); + return withTimeout(microsecs.count()); + } + + template + inline AsyncMethodInvoker& AsyncMethodInvoker::withArguments(_Args&&... args) + { + assert(method_.isValid()); // onInterface() must be placed/called prior to this function + + detail::serialize_pack(method_, std::forward<_Args>(args)...); + + return *this; + } + + template + PendingAsyncCall AsyncMethodInvoker::uponReplyInvoke(_Function&& callback) + { + assert(method_.isValid()); // onInterface() must be placed/called prior to this function + + return proxy_.callMethodAsync(method_, makeAsyncReplyHandler(std::forward<_Function>(callback)), timeout_); + } + + template + [[nodiscard]] Slot AsyncMethodInvoker::uponReplyInvoke(_Function&& callback, return_slot_t) + { + assert(method_.isValid()); // onInterface() must be placed/called prior to this function + + return proxy_.callMethodAsync( method_ + , makeAsyncReplyHandler(std::forward<_Function>(callback)) + , timeout_ + , return_slot ); + } + + template + inline async_reply_handler AsyncMethodInvoker::makeAsyncReplyHandler(_Function&& callback) + { + return [callback = std::forward<_Function>(callback)](MethodReply reply, std::optional error) + { + // Create a tuple of callback input arguments' types, which will be used + // as a storage for the argument values deserialized from the message. + tuple_of_function_input_arg_types_t<_Function> args; + + // Deserialize input arguments from the message into the tuple (if no error occurred). + if (!error) + { + try + { + reply >> args; + } + catch (const Error& e) + { + // Pass message deserialization exceptions to the client via callback error parameter, + // instead of propagating them up the message loop call stack. + sdbus::apply(callback, e, args); + return; + } + } + + // Invoke callback with input arguments from the tuple. + sdbus::apply(callback, std::move(error), args); + }; + } + + template + std::future> AsyncMethodInvoker::getResultAsFuture() + { + auto promise = std::make_shared>>(); + auto future = promise->get_future(); + + uponReplyInvoke([promise = std::move(promise)](std::optional error, _Args... args) + { + if (!error) + if constexpr (!std::is_void_v>) + promise->set_value({std::move(args)...}); + else + promise->set_value(); + else + promise->set_exception(std::make_exception_ptr(*std::move(error))); + }); + + // Will be std::future for no D-Bus method return value + // or std::future for single D-Bus method return value + // or std::future> for multiple method return values + return future; + } + + /*** ---------------- ***/ + /*** SignalSubscriber ***/ + /*** ---------------- ***/ + + inline SignalSubscriber::SignalSubscriber(IProxy& proxy, const SignalName& signalName) + : SignalSubscriber(proxy, signalName.c_str()) + { + } + + inline SignalSubscriber::SignalSubscriber(IProxy& proxy, const char* signalName) + : proxy_(proxy) + , signalName_(signalName) + { + } + + inline SignalSubscriber& SignalSubscriber::onInterface(const InterfaceName& interfaceName) + { + return onInterface(interfaceName.c_str()); + } + + inline SignalSubscriber& SignalSubscriber::onInterface(const std::string& interfaceName) + { + return onInterface(interfaceName.c_str()); + } + + inline SignalSubscriber& SignalSubscriber::onInterface(const char* interfaceName) + { + interfaceName_ = std::move(interfaceName); + + return *this; + } + + template + inline void SignalSubscriber::call(_Function&& callback) + { + assert(interfaceName_ != nullptr); // onInterface() must be placed/called prior to this function + + proxy_.registerSignalHandler( interfaceName_ + , signalName_ + , makeSignalHandler(std::forward<_Function>(callback)) ); + } + + template + [[nodiscard]] inline Slot SignalSubscriber::call(_Function&& callback, return_slot_t) + { + assert(interfaceName_ != nullptr); // onInterface() must be placed/called prior to this function + + return proxy_.registerSignalHandler( interfaceName_ + , signalName_ + , makeSignalHandler(std::forward<_Function>(callback)) + , return_slot ); + } + + template + inline signal_handler SignalSubscriber::makeSignalHandler(_Function&& callback) + { + return [callback = std::forward<_Function>(callback)](Signal signal) + { + // Create a tuple of callback input arguments' types, which will be used + // as a storage for the argument values deserialized from the signal message. + tuple_of_function_input_arg_types_t<_Function> signalArgs; + + // The signal handler can take pure signal parameters only, or an additional `std::optional` as its first + // parameter. In the former case, if the deserialization fails (e.g. due to signature mismatch), + // the failure is ignored (and signal simply dropped). In the latter case, the deserialization failure + // will be communicated to the client's signal handler as a valid Error object inside the std::optional parameter. + if constexpr (has_error_param_v<_Function>) + { + // Deserialize input arguments from the signal message into the tuple + try + { + signal >> signalArgs; + } + catch (const sdbus::Error& e) + { + // Pass message deserialization exceptions to the client via callback error parameter, + // instead of propagating them up the message loop call stack. + sdbus::apply(callback, e, signalArgs); + return; + } + + // Invoke callback with no error and input arguments from the tuple. + sdbus::apply(callback, {}, signalArgs); + } + else + { + // Deserialize input arguments from the signal message into the tuple + signal >> signalArgs; + + // Invoke callback with input arguments from the tuple. + sdbus::apply(callback, signalArgs); + } + }; + } + + /*** -------------- ***/ + /*** PropertyGetter ***/ + /*** -------------- ***/ + + inline PropertyGetter::PropertyGetter(IProxy& proxy, std::string_view propertyName) + : proxy_(proxy) + , propertyName_(std::move(propertyName)) + { + } + + inline Variant PropertyGetter::onInterface(std::string_view interfaceName) + { + Variant var; + proxy_.callMethod("Get") + .onInterface(DBUS_PROPERTIES_INTERFACE_NAME) + .withArguments(interfaceName, propertyName_) + .storeResultsTo(var); + return var; + } + + /*** ------------------- ***/ + /*** AsyncPropertyGetter ***/ + /*** ------------------- ***/ + + inline AsyncPropertyGetter::AsyncPropertyGetter(IProxy& proxy, std::string_view propertyName) + : proxy_(proxy) + , propertyName_(std::move(propertyName)) + { + } + + inline AsyncPropertyGetter& AsyncPropertyGetter::onInterface(std::string_view interfaceName) + { + interfaceName_ = std::move(interfaceName); + + return *this; + } + + template + PendingAsyncCall AsyncPropertyGetter::uponReplyInvoke(_Function&& callback) + { + static_assert( std::is_invocable_r_v, Variant> + , "Property get callback function must accept std::optional and property value as Variant" ); + + assert(!interfaceName_.empty()); // onInterface() must be placed/called prior to this function + + return proxy_.callMethodAsync("Get") + .onInterface(DBUS_PROPERTIES_INTERFACE_NAME) + .withArguments(interfaceName_, propertyName_) + .uponReplyInvoke(std::forward<_Function>(callback)); + } + + template + [[nodiscard]] Slot AsyncPropertyGetter::uponReplyInvoke(_Function&& callback, return_slot_t) + { + static_assert( std::is_invocable_r_v, Variant> + , "Property get callback function must accept std::optional and property value as Variant" ); + + assert(!interfaceName_.empty()); // onInterface() must be placed/called prior to this function + + return proxy_.callMethodAsync("Get") + .onInterface(DBUS_PROPERTIES_INTERFACE_NAME) + .withArguments(interfaceName_, propertyName_) + .uponReplyInvoke(std::forward<_Function>(callback), return_slot); + } + + inline std::future AsyncPropertyGetter::getResultAsFuture() + { + assert(!interfaceName_.empty()); // onInterface() must be placed/called prior to this function + + return proxy_.callMethodAsync("Get") + .onInterface(DBUS_PROPERTIES_INTERFACE_NAME) + .withArguments(interfaceName_, propertyName_) + .getResultAsFuture(); + } + + /*** -------------- ***/ + /*** PropertySetter ***/ + /*** -------------- ***/ + + inline PropertySetter::PropertySetter(IProxy& proxy, std::string_view propertyName) + : proxy_(proxy) + , propertyName_(std::move(propertyName)) + { + } + + inline PropertySetter& PropertySetter::onInterface(std::string_view interfaceName) + { + interfaceName_ = std::move(interfaceName); + + return *this; + } + + template + inline void PropertySetter::toValue(const _Value& value) + { + PropertySetter::toValue(Variant{value}); + } + + template + inline void PropertySetter::toValue(const _Value& value, dont_expect_reply_t) + { + PropertySetter::toValue(Variant{value}, dont_expect_reply); + } + + inline void PropertySetter::toValue(const Variant& value) + { + assert(!interfaceName_.empty()); // onInterface() must be placed/called prior to this function + + proxy_.callMethod("Set") + .onInterface(DBUS_PROPERTIES_INTERFACE_NAME) + .withArguments(interfaceName_, propertyName_, value); + } + + inline void PropertySetter::toValue(const Variant& value, dont_expect_reply_t) + { + assert(!interfaceName_.empty()); // onInterface() must be placed/called prior to this function + + proxy_.callMethod("Set") + .onInterface(DBUS_PROPERTIES_INTERFACE_NAME) + .withArguments(interfaceName_, propertyName_, value) + .dontExpectReply(); + } + + /*** ------------------- ***/ + /*** AsyncPropertySetter ***/ + /*** ------------------- ***/ + + inline AsyncPropertySetter::AsyncPropertySetter(IProxy& proxy, std::string_view propertyName) + : proxy_(proxy) + , propertyName_(propertyName) + { + } + + inline AsyncPropertySetter& AsyncPropertySetter::onInterface(std::string_view interfaceName) + { + interfaceName_ = std::move(interfaceName); + + return *this; + } + + template + inline AsyncPropertySetter& AsyncPropertySetter::toValue(_Value&& value) + { + return AsyncPropertySetter::toValue(Variant{std::forward<_Value>(value)}); + } + + inline AsyncPropertySetter& AsyncPropertySetter::toValue(Variant value) + { + value_ = std::move(value); + + return *this; + } + + template + PendingAsyncCall AsyncPropertySetter::uponReplyInvoke(_Function&& callback) + { + static_assert( std::is_invocable_r_v> + , "Property set callback function must accept std::optional only" ); + + assert(!interfaceName_.empty()); // onInterface() must be placed/called prior to this function + + return proxy_.callMethodAsync("Set") + .onInterface(DBUS_PROPERTIES_INTERFACE_NAME) + .withArguments(interfaceName_, propertyName_, std::move(value_)) + .uponReplyInvoke(std::forward<_Function>(callback)); + } + + template + [[nodiscard]] Slot AsyncPropertySetter::uponReplyInvoke(_Function&& callback, return_slot_t) + { + static_assert( std::is_invocable_r_v> + , "Property set callback function must accept std::optional only" ); + + assert(!interfaceName_.empty()); // onInterface() must be placed/called prior to this function + + return proxy_.callMethodAsync("Set") + .onInterface(DBUS_PROPERTIES_INTERFACE_NAME) + .withArguments(interfaceName_, propertyName_, std::move(value_)) + .uponReplyInvoke(std::forward<_Function>(callback), return_slot); + } + + inline std::future AsyncPropertySetter::getResultAsFuture() + { + assert(!interfaceName_.empty()); // onInterface() must be placed/called prior to this function + + return proxy_.callMethodAsync("Set") + .onInterface(DBUS_PROPERTIES_INTERFACE_NAME) + .withArguments(interfaceName_, propertyName_, std::move(value_)) + .getResultAsFuture<>(); + } + + /*** ------------------- ***/ + /*** AllPropertiesGetter ***/ + /*** ------------------- ***/ + + inline AllPropertiesGetter::AllPropertiesGetter(IProxy& proxy) + : proxy_(proxy) + { + } + + inline std::map AllPropertiesGetter::onInterface(std::string_view interfaceName) + { + std::map props; + proxy_.callMethod("GetAll") + .onInterface(DBUS_PROPERTIES_INTERFACE_NAME) + .withArguments(std::move(interfaceName)) + .storeResultsTo(props); + return props; + } + + /*** ------------------------ ***/ + /*** AsyncAllPropertiesGetter ***/ + /*** ------------------------ ***/ + + inline AsyncAllPropertiesGetter::AsyncAllPropertiesGetter(IProxy& proxy) + : proxy_(proxy) + { + } + + inline AsyncAllPropertiesGetter& AsyncAllPropertiesGetter::onInterface(std::string_view interfaceName) + { + interfaceName_ = std::move(interfaceName); + + return *this; + } + + template + PendingAsyncCall AsyncAllPropertiesGetter::uponReplyInvoke(_Function&& callback) + { + static_assert( std::is_invocable_r_v, std::map> + , "All properties get callback function must accept std::optional and a map of property names to their values" ); + + assert(!interfaceName_.empty()); // onInterface() must be placed/called prior to this function + + return proxy_.callMethodAsync("GetAll") + .onInterface(DBUS_PROPERTIES_INTERFACE_NAME) + .withArguments(interfaceName_) + .uponReplyInvoke(std::forward<_Function>(callback)); + } + + template + [[nodiscard]] Slot AsyncAllPropertiesGetter::uponReplyInvoke(_Function&& callback, return_slot_t) + { + static_assert( std::is_invocable_r_v, std::map> + , "All properties get callback function must accept std::optional and a map of property names to their values" ); + + assert(!interfaceName_.empty()); // onInterface() must be placed/called prior to this function + + return proxy_.callMethodAsync("GetAll") + .onInterface(DBUS_PROPERTIES_INTERFACE_NAME) + .withArguments(interfaceName_) + .uponReplyInvoke(std::forward<_Function>(callback), return_slot); + } + + inline std::future> AsyncAllPropertiesGetter::getResultAsFuture() + { + assert(!interfaceName_.empty()); // onInterface() must be placed/called prior to this function + + return proxy_.callMethodAsync("GetAll") + .onInterface(DBUS_PROPERTIES_INTERFACE_NAME) + .withArguments(interfaceName_) + .getResultAsFuture>(); + } + +} // namespace sdbus + +#endif /* SDBUS_CPP_CONVENIENCEAPICLASSES_INL_ */ diff --git a/3rdParty/sdbus-cpp/include/sdbus-c++/Error.h b/3rdParty/sdbus-cpp/include/sdbus-c++/Error.h new file mode 100644 index 0000000000..4f6e2e9d8e --- /dev/null +++ b/3rdParty/sdbus-cpp/include/sdbus-c++/Error.h @@ -0,0 +1,106 @@ +/** + * (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland + * (C) 2016 - 2024 Stanislav Angelovic + * + * @file Error.h + * + * Created on: Nov 8, 2016 + * Project: sdbus-c++ + * Description: High-level D-Bus IPC C++ library based on sd-bus + * + * This file is part of sdbus-c++. + * + * sdbus-c++ is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 of the License, or + * (at your option) any later version. + * + * sdbus-c++ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with sdbus-c++. If not, see . + */ + +#ifndef SDBUS_CXX_ERROR_H_ +#define SDBUS_CXX_ERROR_H_ + +#include +#include +#include + +namespace sdbus { + + /********************************************//** + * @class Error + * + * Represents a common sdbus-c++ exception. + * + ***********************************************/ + class Error + : public std::runtime_error + { + public: + // Strong type representing the D-Bus error name + class Name : public std::string + { + public: + Name() = default; + explicit Name(std::string value) + : std::string(std::move(value)) + {} + explicit Name(const char* value) + : std::string(value) + {} + + using std::string::operator=; + }; + + explicit Error(Name name, const char* message = nullptr) + : Error(std::move(name), std::string(message ? message : "")) + { + } + + Error(Name name, std::string message) + : std::runtime_error(!message.empty() ? "[" + name + "] " + message : "[" + name + "]") + , name_(std::move(name)) + , message_(std::move(message)) + { + } + + [[nodiscard]] const Name& getName() const + { + return name_; + } + + [[nodiscard]] const std::string& getMessage() const + { + return message_; + } + + [[nodiscard]] bool isValid() const + { + return !getName().empty(); + } + + private: + Name name_; + std::string message_; + }; + + Error createError(int errNo, std::string customMsg = {}); + + inline const Error::Name SDBUSCPP_ERROR_NAME{"org.sdbuscpp.Error"}; +} + +#define SDBUS_THROW_ERROR(_MSG, _ERRNO) \ + throw sdbus::createError((_ERRNO), (_MSG)) \ + /**/ + +#define SDBUS_THROW_ERROR_IF(_COND, _MSG, _ERRNO) \ + if (!(_COND)) ; else SDBUS_THROW_ERROR((_MSG), (_ERRNO)) \ + /**/ + +#endif /* SDBUS_CXX_ERROR_H_ */ diff --git a/3rdParty/sdbus-cpp/include/sdbus-c++/Flags.h b/3rdParty/sdbus-cpp/include/sdbus-c++/Flags.h new file mode 100644 index 0000000000..d85a4aa51d --- /dev/null +++ b/3rdParty/sdbus-cpp/include/sdbus-c++/Flags.h @@ -0,0 +1,99 @@ +/** + * (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland + * (C) 2016 - 2024 Stanislav Angelovic + * + * @file Flags.h + * + * Created on: Dec 31, 2018 + * Project: sdbus-c++ + * Description: High-level D-Bus IPC C++ library based on sd-bus + * + * This file is part of sdbus-c++. + * + * sdbus-c++ is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 of the License, or + * (at your option) any later version. + * + * sdbus-c++ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with sdbus-c++. If not, see . + */ + +#ifndef SDBUS_CXX_FLAGS_H_ +#define SDBUS_CXX_FLAGS_H_ + +#include +#include + +namespace sdbus { + + // D-Bus interface, method, signal or property flags + class Flags + { + public: + enum GeneralFlags : uint8_t + { DEPRECATED = 0 + , METHOD_NO_REPLY = 1 + , PRIVILEGED = 2 + }; + + enum PropertyUpdateBehaviorFlags : uint8_t + { EMITS_CHANGE_SIGNAL = 3 + , EMITS_INVALIDATION_SIGNAL = 4 + , EMITS_NO_SIGNAL = 5 + , CONST_PROPERTY_VALUE = 6 + }; + + enum : uint8_t + { FLAG_COUNT = 7 + }; + + Flags() + { + // EMITS_CHANGE_SIGNAL is on by default + flags_.set(EMITS_CHANGE_SIGNAL, true); + } + + void set(GeneralFlags flag, bool value = true) + { + flags_.set(flag, value); + } + + void set(PropertyUpdateBehaviorFlags flag, bool value = true) + { + flags_.set(EMITS_CHANGE_SIGNAL, false); + flags_.set(EMITS_INVALIDATION_SIGNAL, false); + flags_.set(EMITS_NO_SIGNAL, false); + flags_.set(CONST_PROPERTY_VALUE, false); + + flags_.set(flag, value); + } + + [[nodiscard]] bool test(GeneralFlags flag) const + { + return flags_.test(flag); + } + + [[nodiscard]] bool test(PropertyUpdateBehaviorFlags flag) const + { + return flags_.test(flag); + } + + [[nodiscard]] uint64_t toSdBusInterfaceFlags() const; + [[nodiscard]] uint64_t toSdBusMethodFlags() const; + [[nodiscard]] uint64_t toSdBusSignalFlags() const; + [[nodiscard]] uint64_t toSdBusPropertyFlags() const; + [[nodiscard]] uint64_t toSdBusWritablePropertyFlags() const; + + private: + std::bitset flags_; + }; + +} + +#endif /* SDBUS_CXX_FLAGS_H_ */ diff --git a/3rdParty/sdbus-cpp/include/sdbus-c++/IConnection.h b/3rdParty/sdbus-cpp/include/sdbus-c++/IConnection.h new file mode 100644 index 0000000000..42caa76b4b --- /dev/null +++ b/3rdParty/sdbus-cpp/include/sdbus-c++/IConnection.h @@ -0,0 +1,584 @@ +/** + * (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland + * (C) 2016 - 2024 Stanislav Angelovic + * + * @file IConnection.h + * + * Created on: Nov 8, 2016 + * Project: sdbus-c++ + * Description: High-level D-Bus IPC C++ library based on sd-bus + * + * This file is part of sdbus-c++. + * + * sdbus-c++ is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 of the License, or + * (at your option) any later version. + * + * sdbus-c++ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with sdbus-c++. If not, see . + */ + +#ifndef SDBUS_CXX_ICONNECTION_H_ +#define SDBUS_CXX_ICONNECTION_H_ + +#include + +#include +#include +#include +#include +#include + +// Forward declarations +struct sd_bus; +struct sd_event; +namespace sdbus { + class Message; + class ObjectPath; + class BusName; + using ServiceName = BusName; +} + +namespace sdbus { + + /********************************************//** + * @class IConnection + * + * An interface to D-Bus bus connection. Incorporates implementation + * of both synchronous and asynchronous D-Bus I/O event loop. + * + * All methods throw sdbus::Error in case of failure. All methods in + * this class are thread-aware, but not thread-safe. + * + ***********************************************/ + class IConnection + { + public: + struct PollData; + + virtual ~IConnection() = default; + + /*! + * @brief Enters I/O event loop on this bus connection + * + * The incoming D-Bus messages are processed in the loop. The method + * blocks indefinitely, until unblocked through leaveEventLoop(). + * + * @throws sdbus::Error in case of failure + */ + virtual void enterEventLoop() = 0; + + /*! + * @brief Enters I/O event loop on this bus connection in a separate thread + * + * The same as enterEventLoop, except that it doesn't block + * because it runs the loop in a separate, internally managed thread. + */ + virtual void enterEventLoopAsync() = 0; + + /*! + * @brief Leaves the I/O event loop running on this bus connection + * + * This causes the loop to exit and frees the thread serving the loop + * + * @throws sdbus::Error in case of failure + */ + virtual void leaveEventLoop() = 0; + + /*! + * @brief Attaches the bus connection to an sd-event event loop + * + * @param[in] event sd-event event loop object + * @param[in] priority Specified priority + * + * @throws sdbus::Error in case of failure + * + * See `man sd_bus_attach_event'. + */ + virtual void attachSdEventLoop(sd_event *event, int priority = 0) = 0; + + /*! + * @brief Detaches the bus connection from an sd-event event loop + * + * @throws sdbus::Error in case of failure + */ + virtual void detachSdEventLoop() = 0; + + /*! + * @brief Gets current sd-event event loop for the bus connection + * + * @return Pointer to event loop object if attached, nullptr otherwise + */ + virtual sd_event *getSdEventLoop() = 0; + + /*! + * @brief Returns fd's, I/O events and timeout data to be used in an external event loop + * + * This function is useful to hook up a bus connection object with an + * external (like GMainLoop, boost::asio, etc.) or manual event loop + * involving poll() or a similar I/O polling call. + * + * Before **each** invocation of the I/O polling call, this function + * should be invoked. Returned PollData::fd file descriptor should + * be polled for the events indicated by PollData::events, and the I/O + * call should block for that up to the returned PollData::timeout. + * + * Additionally, returned PollData::eventFd should be polled for POLLIN + * events. + * + * After each I/O polling call the bus connection needs to process + * incoming or outgoing data, by invoking processPendingEvent(). + * + * Note that the returned timeout should be considered only a maximum + * sleeping time. It is permissible (and even expected) that shorter + * timeouts are used by the calling program, in case other event sources + * are polled in the same event loop. Note that the returned time-value + * is absolute, based of CLOCK_MONOTONIC and specified in microseconds. + * Use PollData::getPollTimeout() to have the timeout value converted + * in a form that can be passed to poll(2). + * + * The bus connection conveniently integrates sd-event event loop. + * To attach the bus connection to an sd-event event loop, use + * attachSdEventLoop() function. + * + * @throws sdbus::Error in case of failure + */ + [[nodiscard]] virtual PollData getEventLoopPollData() const = 0; + + /*! + * @brief Processes a pending event + * + * @returns True if an event was processed, false if no operations were pending + * + * This function drives the D-Bus connection. It processes pending I/O events. + * Queued outgoing messages (or parts thereof) are sent out. Queued incoming + * messages are dispatched to registered callbacks. Timeouts are recalculated. + * + * It returns false when no operations were pending and true if a message was + * processed. When false is returned the caller should synchronously poll for + * I/O events before calling into processPendingEvent() again. + * Don't forget to call getEventLoopPollData() each time before the next poll. + * + * You don't need to directly call this method or getEventLoopPollData() method + * when using convenient, internal bus connection event loops through + * enterEventLoop() or enterEventLoopAsync() calls, or when the bus is + * connected to an sd-event event loop through attachSdEventLoop(). + * It is invoked automatically when necessary. + * + * @throws sdbus::Error in case of failure + */ + virtual bool processPendingEvent() = 0; + + /*! + * @brief Provides access to the currently processed D-Bus message + * + * This method provides access to the currently processed incoming D-Bus message. + * "Currently processed" means that the registered callback handler(s) for that message + * are being invoked. This method is meant to be called from within a callback handler + * (e.g. from a D-Bus signal handler, or async method reply handler, etc.). In such a case it is + * guaranteed to return a valid D-Bus message instance for which the handler is called. + * If called from other contexts/threads, it may return a valid or invalid message, depending + * on whether a message was processed or not at the time of the call. + * + * @return Currently processed D-Bus message + */ + [[nodiscard]] virtual Message getCurrentlyProcessedMessage() const = 0; + + /*! + * @brief Sets general method call timeout + * + * @param[in] timeout Timeout value in microseconds + * + * General method call timeout is used for all method calls upon this connection. + * Method call-specific timeout overrides this general setting. + * + * Supported by libsystemd>=v240. + * + * @throws sdbus::Error in case of failure + */ + virtual void setMethodCallTimeout(uint64_t timeout) = 0; + + /*! + * @copydoc IConnection::setMethodCallTimeout(uint64_t) + */ + template + void setMethodCallTimeout(const std::chrono::duration<_Rep, _Period>& timeout); + + /*! + * @brief Gets general method call timeout + * + * @return Timeout value in microseconds + * + * Supported by libsystemd>=v240. + * + * @throws sdbus::Error in case of failure + */ + [[nodiscard]] virtual uint64_t getMethodCallTimeout() const = 0; + + /*! + * @brief Adds an ObjectManager at the specified D-Bus object path + * @param[in] objectPath Object path at which the ObjectManager interface shall be installed + * + * Creates an ObjectManager interface at the specified object path on + * the connection. This is a convenient way to interrogate a connection + * to see what objects it has. + * + * This call creates a floating registration. The ObjectManager will + * be there for the object path until the connection is destroyed. + * + * Another, recommended way to add object managers is directly through IObject API. + * + * @throws sdbus::Error in case of failure + */ + virtual void addObjectManager(const ObjectPath& objectPath) = 0; + + /*! + * @brief Adds an ObjectManager at the specified D-Bus object path + * @param[in] objectPath Object path at which the ObjectManager interface shall be installed + * @return Slot handle owning the registration + * + * Creates an ObjectManager interface at the specified object path on + * the connection. This is a convenient way to interrogate a connection + * to see what objects it has. + * + * This call returns an owning slot. The lifetime of the ObjectManager + * interface is bound to the lifetime of the returned slot instance. + * + * Another, recommended way to add object managers is directly through IObject API. + * + * @throws sdbus::Error in case of failure + */ + [[nodiscard]] virtual Slot addObjectManager(const ObjectPath& objectPath, return_slot_t) = 0; + + /*! + * @brief Installs a floating match rule for messages received on this bus connection + * + * @param[in] match Match expression to filter incoming D-Bus message + * @param[in] callback Callback handler to be called upon processing an inbound D-Bus message matching the rule + * + * The method installs a match rule for messages received on the specified bus connection. + * The syntax of the match rule expression passed in match is described in the D-Bus specification. + * The specified handler function callback is called for each incoming message matching the specified + * expression. The match is installed synchronously when connected to a bus broker, i.e. the call + * sends a control message requesting the match to be added to the broker and waits until the broker + * confirms the match has been installed successfully. + * + * The method installs a floating match rule for messages received on the specified bus connection. + * Floating means that the bus connection object owns the match rule, i.e. lifetime of the match rule + * is bound to the lifetime of the bus connection. + * + * For more information, consult `man sd_bus_add_match`. + * + * @throws sdbus::Error in case of failure + */ + virtual void addMatch(const std::string& match, message_handler callback) = 0; + + /*! + * @brief Installs a match rule for messages received on this bus connection + * + * @param[in] match Match expression to filter incoming D-Bus message + * @param[in] callback Callback handler to be called upon processing an inbound D-Bus message matching the rule + * @return RAII-style slot handle representing the ownership of the subscription + * + * The method installs a match rule for messages received on the specified bus connection. + * The syntax of the match rule expression passed in match is described in the D-Bus specification. + * The specified handler function callback is called for each incoming message matching the specified + * expression. The match is installed synchronously when connected to a bus broker, i.e. the call + * sends a control message requesting the match to be added to the broker and waits until the broker + * confirms the match has been installed successfully. + * + * The lifetime of the match rule is bound to the lifetime of the returned slot instance. Destroying + * the slot instance implies uninstalling of the match rule from the bus connection. + * + * For more information, consult `man sd_bus_add_match`. + * + * @throws sdbus::Error in case of failure + */ + [[nodiscard]] virtual Slot addMatch(const std::string& match, message_handler callback, return_slot_t) = 0; + + /*! + * @brief Asynchronously installs a floating match rule for messages received on this bus connection + * + * @param[in] match Match expression to filter incoming D-Bus message + * @param[in] callback Callback handler to be called upon processing an inbound D-Bus message matching the rule + * @param[in] installCallback Callback handler to be called upon processing an inbound D-Bus message matching the rule + * + * This method operates the same as `addMatch()` above, just that it installs the match rule asynchronously, + * in a non-blocking fashion. A request is sent to the broker, but the call does not wait for a response. + * The `installCallback' callable is called when the response is later received, with the response message + * from the broker as parameter. If it's an empty function object, a default implementation is used that + * terminates the bus connection should installing the match fail. + * + * The method installs a floating match rule for messages received on the specified bus connection. + * Floating means that the bus connection object owns the match rule, i.e. lifetime of the match rule + * is bound to the lifetime of the bus connection. + * + * For more information, consult `man sd_bus_add_match_async`. + * + * @throws sdbus::Error in case of failure + */ + virtual void addMatchAsync(const std::string& match, message_handler callback, message_handler installCallback) = 0; + + /*! + * @brief Asynchronously installs a match rule for messages received on this bus connection + * + * @param[in] match Match expression to filter incoming D-Bus message + * @param[in] callback Callback handler to be called upon processing an inbound D-Bus message matching the rule + * @param[in] installCallback Callback handler to be called upon processing an inbound D-Bus message matching the rule + * @return RAII-style slot handle representing the ownership of the subscription + * + * This method operates the same as `addMatch()` above, just that it installs the match rule asynchronously, + * in a non-blocking fashion. A request is sent to the broker, but the call does not wait for a response. + * The `installCallback' callable is called when the response is later received, with the response message + * from the broker as parameter. If it's an empty function object, a default implementation is used that + * terminates the bus connection should installing the match fail. + * + * The lifetime of the match rule is bound to the lifetime of the returned slot instance. Destroying + * the slot instance implies the uninstalling of the match rule from the bus connection. + * + * For more information, consult `man sd_bus_add_match_async`. + * + * @throws sdbus::Error in case of failure + */ + [[nodiscard]] virtual Slot addMatchAsync( const std::string& match + , message_handler callback + , message_handler installCallback + , return_slot_t ) = 0; + + /*! + * @brief Retrieves the unique name of a connection. E.g. ":1.xx" + * + * @throws sdbus::Error in case of failure + */ + [[nodiscard]] virtual BusName getUniqueName() const = 0; + + /*! + * @brief Requests a well-known D-Bus service name on a bus + * + * @param[in] name Name to request + * + * @throws sdbus::Error in case of failure + */ + virtual void requestName(const ServiceName& name) = 0; + + /*! + * @brief Releases an acquired well-known D-Bus service name on a bus + * + * @param[in] name Name to release + * + * @throws sdbus::Error in case of failure + */ + virtual void releaseName(const ServiceName& name) = 0; + + /*! + * @struct PollData + * + * Carries poll data needed for integration with external event loop implementations. + * + * See getEventLoopPollData() for more info. + */ + struct PollData + { + /*! + * The read fd to be monitored by the event loop. + */ + int fd; + + /*! + * The events to use for poll(2) alongside fd. + */ + short int events; + + /*! + * Absolute timeout value in microseconds, based of CLOCK_MONOTONIC. + * + * Call getPollTimeout() to get timeout recalculated to relative timeout that can be passed to poll(2). + */ + std::chrono::microseconds timeout; + + /*! + * An additional event fd to be monitored by the event loop for POLLIN events. + */ + int eventFd; + + /*! + * Returns the timeout as relative value from now. + * + * Returned value is std::chrono::microseconds::max() if the timeout is indefinite. + * + * @return Relative timeout as a time duration + */ + [[nodiscard]] std::chrono::microseconds getRelativeTimeout() const; + + /*! + * Returns relative timeout in the form which can be passed as argument 'timeout' to poll(2) + * + * @return -1 if the timeout is indefinite. 0 if the poll(2) shouldn't block. + * An integer in milliseconds otherwise. + */ + [[nodiscard]] int getPollTimeout() const; + }; + }; + + template + inline void IConnection::setMethodCallTimeout(const std::chrono::duration<_Rep, _Period>& timeout) + { + auto microsecs = std::chrono::duration_cast(timeout); + return setMethodCallTimeout(microsecs.count()); + } + + /*! + * @brief Creates/opens D-Bus session bus connection when in a user context, and a system bus connection, otherwise. + * + * @return Connection instance + * + * @throws sdbus::Error in case of failure + */ + [[nodiscard]] std::unique_ptr createBusConnection(); + + /*! + * @brief Creates/opens D-Bus session bus connection with a name when in a user context, and a system bus connection with a name, otherwise. + * + * @param[in] name Name to request on the connection after its opening + * @return Connection instance + * + * @throws sdbus::Error in case of failure + */ + [[nodiscard]] std::unique_ptr createBusConnection(const ServiceName& name); + + /*! + * @brief Creates/opens D-Bus system bus connection + * + * @return Connection instance + * + * @throws sdbus::Error in case of failure + */ + [[nodiscard]] std::unique_ptr createSystemBusConnection(); + + /*! + * @brief Creates/opens D-Bus system bus connection with a name + * + * @param[in] name Name to request on the connection after its opening + * @return Connection instance + * + * @throws sdbus::Error in case of failure + */ + [[nodiscard]] std::unique_ptr createSystemBusConnection(const ServiceName& name); + + /*! + * @brief Creates/opens D-Bus session bus connection + * + * @return Connection instance + * + * @throws sdbus::Error in case of failure + */ + [[nodiscard]] std::unique_ptr createSessionBusConnection(); + + /*! + * @brief Creates/opens D-Bus session bus connection with a name + * + * @param[in] name Name to request on the connection after its opening + * @return Connection instance + * + * @throws sdbus::Error in case of failure + */ + [[nodiscard]] std::unique_ptr createSessionBusConnection(const ServiceName& name); + + /*! + * @brief Creates/opens D-Bus session bus connection at a custom address + * + * @param[in] address ";"-separated list of addresses of bus brokers to try to connect + * @return Connection instance + * + * @throws sdbus::Error in case of failure + * + * Consult manual pages for `sd_bus_set_address` of the underlying sd-bus library for more information. + */ + [[nodiscard]] std::unique_ptr createSessionBusConnectionWithAddress(const std::string& address); + + /*! + * @brief Creates/opens D-Bus system connection on a remote host using ssh + * + * @param[in] host Name of the host to connect + * @return Connection instance + * + * @throws sdbus::Error in case of failure + */ + [[nodiscard]] std::unique_ptr createRemoteSystemBusConnection(const std::string& host); + + /*! + * @brief Opens direct D-Bus connection at a custom address + * + * @param[in] address ";"-separated list of addresses of bus brokers to try to connect to + * @return Connection instance + * + * @throws sdbus::Error in case of failure + */ + [[nodiscard]] std::unique_ptr createDirectBusConnection(const std::string& address); + + /*! + * @brief Opens direct D-Bus connection at the given file descriptor + * + * @param[in] fd File descriptor used to communicate directly from/to a D-Bus server + * @return Connection instance + * + * The underlying sdbus-c++ connection instance takes over ownership of fd, so the caller can let it go. + * If, however, the call throws an exception, the ownership of fd remains with the caller. + * + * @throws sdbus::Error in case of failure + */ + [[nodiscard]] std::unique_ptr createDirectBusConnection(int fd); + + /*! + * @brief Opens direct D-Bus connection at fd as a server + * + * @param[in] fd File descriptor to use for server DBus connection + * @return Server connection instance + * + * This creates a new, custom bus object in server mode. One can then call createDirectBusConnection() + * on client side to connect to this bus. + * + * The underlying sdbus-c++ connection instance takes over ownership of fd, so the caller can let it go. + * If, however, the call throws an exception, the ownership of fd remains with the caller. + * + * @throws sdbus::Error in case of failure + */ + [[nodiscard]] std::unique_ptr createServerBus(int fd); + + /*! + * @brief Creates sdbus-c++ bus connection representation out of underlying sd_bus instance + * + * @param[in] bus File descriptor to use for server DBus connection + * @return Connection instance + * + * This functions is helpful in cases where clients need a custom, tweaked configuration of their + * bus object. Since sdbus-c++ does not provide C++ API for all bus connection configuration + * functions of the underlying sd-bus library, clients can use these sd-bus functions themselves + * to create and configure their sd_bus object, and create sdbus-c++ IConnection on top of it. + * + * The IConnection instance assumes unique ownership of the provided bus object. The bus object + * must have been started by the client before this call. + * The bus object will get flushed, closed, and unreffed when the IConnection instance is destroyed. + * + * @throws sdbus::Error in case of failure + * + * Code example: + * @code + * sd_bus* bus{}; + * ::sd_bus_new(&bus); + * ::sd_bus_set_address(bus, address); + * ::sd_bus_set_anonymous(bus, true); + * ::sd_bus_start(bus); + * auto con = sdbus::createBusConnection(bus); // IConnection consumes sd_bus object + * @endcode + */ + [[nodiscard]] std::unique_ptr createBusConnection(sd_bus *bus); +} + +#endif /* SDBUS_CXX_ICONNECTION_H_ */ diff --git a/3rdParty/sdbus-cpp/include/sdbus-c++/IObject.h b/3rdParty/sdbus-cpp/include/sdbus-c++/IObject.h new file mode 100644 index 0000000000..21953bcc13 --- /dev/null +++ b/3rdParty/sdbus-cpp/include/sdbus-c++/IObject.h @@ -0,0 +1,484 @@ +/** + * (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland + * (C) 2016 - 2024 Stanislav Angelovic + * + * @file IObject.h + * + * Created on: Nov 8, 2016 + * Project: sdbus-c++ + * Description: High-level D-Bus IPC C++ library based on sd-bus + * + * This file is part of sdbus-c++. + * + * sdbus-c++ is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 of the License, or + * (at your option) any later version. + * + * sdbus-c++ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with sdbus-c++. If not, see . + */ + +#ifndef SDBUS_CXX_IOBJECT_H_ +#define SDBUS_CXX_IOBJECT_H_ + +#include +#include +#include +#include + +#include +#include +#include +#include + +// Forward declarations +namespace sdbus { + class Signal; + class IConnection; + class ObjectPath; +} + +namespace sdbus { + + /********************************************//** + * @class IObject + * + * IObject class represents a D-Bus object instance identified by a specific object path. + * D-Bus object provides its interfaces, methods, signals and properties on a bus + * identified by a specific bus name. + * + * All IObject member methods throw @c sdbus::Error in case of D-Bus or sdbus-c++ error. + * The IObject class has been designed as thread-aware. However, the operation of + * creating and sending asynchronous method replies, as well as creating and emitting + * signals, is thread-safe by design. + * + ***********************************************/ + class IObject + { + public: // High-level, convenience API + virtual ~IObject() = default; + + /*! + * @brief Adds a declaration of methods, properties and signals of the object at a given interface + * + * @param[in] vtable Individual instances of VTable item structures stored in a vector + * @return VTableAdder high-level helper class + * + * This method is used to declare attributes for the object under the given interface. + * Parameter `vtable' represents a vtable definition that may contain method declarations + * (using MethodVTableItem struct), property declarations (using PropertyVTableItem + * struct), signal declarations (using SignalVTableItem struct), or global interface + * flags (using InterfaceFlagsVTableItem struct). + * + * An interface can have any number of vtables attached to it. + * + * Consult manual pages for the underlying `sd_bus_add_object_vtable` function for more information. + * + * The method can be called at any time during object's lifetime. + * + * When called like `addVTable(vtable).forInterface(interface)`, then an internal registration + * slot is created for that vtable and its lifetime is tied to the lifetime of the Object instance. + * When called like `addVTable(items...).forInterface(interface, sdbus::return_slot)`, then an internal + * registration slot is created for the vtable and is returned to the caller. Keeping the slot means + * keep the registration "alive". Destroying the slot means that the vtable is not needed anymore, + * and the vtable gets removed from the object. This allows for "dynamic" object API where vtables + * can be added or removed by the user at runtime. + * + * The function provides strong exception guarantee. The state of the object remains + * unmodified in face of an exception. + * + * @throws sdbus::Error in case of failure + */ + [[nodiscard]] VTableAdder addVTable(std::vector vtable); + + /*! + * @brief Adds a declaration of methods, properties and signals of the object at a given interface + * + * @param[in] items Individual instances of VTable item structures + * @return VTableAdder high-level helper class + * + * This method is used to declare attributes for the object under the given interface. + * Parameter pack contains vtable definition that may contain method declarations + * (using MethodVTableItem struct), property declarations (using PropertyVTableItem + * struct), signal declarations (using SignalVTableItem struct), or global interface + * flags (using InterfaceFlagsVTableItem struct). + * + * An interface can have any number of vtables attached to it. + * + * Consult manual pages for the underlying `sd_bus_add_object_vtable` function for more information. + * + * The method can be called at any time during object's lifetime. + * + * When called like `addVTable(items...).forInterface(interface)`, then an internal registration + * slot is created for that vtable and its lifetime is tied to the lifetime of the Object instance. + * When called like `addVTable(items...).forInterface(interface, sdbus::return_slot)`, then an internal + * registration slot is created for the vtable and is returned to the caller. Keeping the slot means + * keep the registration "alive". Destroying the slot means that the vtable is not needed anymore, + * and the vtable gets removed from the object. This allows for "dynamic" object API where vtables + * can be added or removed by the user at runtime. + * + * The function provides strong exception guarantee. The state of the object remains + * unmodified in face of an exception. + * + * @throws sdbus::Error in case of failure + */ + template < typename... VTableItems + , typename = std::enable_if_t<(is_one_of_variants_types> && ...)> > + [[nodiscard]] VTableAdder addVTable(VTableItems&&... items); + + /*! + * @brief Emits signal on D-Bus + * + * @param[in] signalName Name of the signal + * @return A helper object for convenient emission of signals + * + * This is a high-level, convenience way of emitting D-Bus signals that abstracts + * from the D-Bus message concept. Signal arguments are automatically serialized + * in a message and D-Bus signatures automatically deduced from the provided native arguments. + * + * Example of use: + * @code + * int arg1 = ...; + * double arg2 = ...; + * SignalName fooSignal{"fooSignal"}; + * object_.emitSignal(fooSignal).onInterface("com.kistler.foo").withArguments(arg1, arg2); + * @endcode + * + * @throws sdbus::Error in case of failure + */ + [[nodiscard]] SignalEmitter emitSignal(const SignalName& signalName); + + /*! + * @copydoc IObject::emitSignal(const SignalName&) + */ + [[nodiscard]] SignalEmitter emitSignal(const std::string& signalName); + + /*! + * @copydoc IObject::emitSignal(const SignalName&) + */ + [[nodiscard]] SignalEmitter emitSignal(const char* signalName); + + /*! + * @brief Emits PropertyChanged signal for specified properties under a given interface of this object path + * + * @param[in] interfaceName Name of an interface that properties belong to + * @param[in] propNames Names of properties that will be included in the PropertiesChanged signal + * + * @throws sdbus::Error in case of failure + */ + virtual void emitPropertiesChangedSignal(const InterfaceName& interfaceName, const std::vector& propNames) = 0; + + /*! + * @copydoc IObject::emitPropertiesChangedSignal(const InterfaceName&,const std::vector&) + */ + virtual void emitPropertiesChangedSignal(const char* interfaceName, const std::vector& propNames) = 0; + + /*! + * @brief Emits PropertyChanged signal for all properties on a given interface of this object path + * + * @param[in] interfaceName Name of an interface + * + * @throws sdbus::Error in case of failure + */ + virtual void emitPropertiesChangedSignal(const InterfaceName& interfaceName) = 0; + + /*! + * @copydoc IObject::emitPropertiesChangedSignal(const InterfaceName&) + */ + virtual void emitPropertiesChangedSignal(const char* interfaceName) = 0; + + /*! + * @brief Emits InterfacesAdded signal on this object path + * + * This emits an InterfacesAdded signal on this object path, by iterating all registered + * interfaces on the path. All properties are queried and included in the signal. + * This call is equivalent to emitInterfacesAddedSignal() with an explicit list of + * registered interfaces. However, unlike emitInterfacesAddedSignal(interfaces), this + * call can figure out the list of supported interfaces itself. Furthermore, it properly + * adds the builtin org.freedesktop.DBus.* interfaces. + * + * @throws sdbus::Error in case of failure + */ + virtual void emitInterfacesAddedSignal() = 0; + + /*! + * @brief Emits InterfacesAdded signal on this object path + * + * This emits an InterfacesAdded signal on this object path with explicitly provided list + * of registered interfaces. Since v2.0, sdbus-c++ supports dynamically addable/removable + * object interfaces and their vtables, so this method now makes more sense. + * + * @throws sdbus::Error in case of failure + */ + virtual void emitInterfacesAddedSignal(const std::vector& interfaces) = 0; + + /*! + * @brief Emits InterfacesRemoved signal on this object path + * + * This is like sd_bus_emit_object_added(), but emits an InterfacesRemoved signal on this + * object path. This only includes any registered interfaces but skips the properties. + * This function shall be called (just) before destroying the object. + * + * @throws sdbus::Error in case of failure + */ + virtual void emitInterfacesRemovedSignal() = 0; + + /*! + * @brief Emits InterfacesRemoved signal on this object path + * + * This emits an InterfacesRemoved signal on the given path with explicitly provided list + * of registered interfaces. Since v2.0, sdbus-c++ supports dynamically addable/removable + * object interfaces and their vtables, so this method now makes more sense. + * + * @throws sdbus::Error in case of failure + */ + virtual void emitInterfacesRemovedSignal(const std::vector& interfaces) = 0; + + /*! + * @brief Adds an ObjectManager interface at the path of this D-Bus object + * + * Creates an ObjectManager interface at the specified object path on + * the connection. This is a convenient way to interrogate a connection + * to see what objects it has. + * + * This call creates a so-called floating registration. This means that + * the ObjectManager interface stays there for the lifetime of the object. + * + * @throws sdbus::Error in case of failure + */ + virtual void addObjectManager() = 0; + + /*! + * @brief Adds an ObjectManager interface at the path of this D-Bus object + * + * @return Slot handle owning the registration + * + * Creates an ObjectManager interface at the specified object path on + * the connection. This is a convenient way to interrogate a connection + * to see what objects it has. + * + * The lifetime of the ObjectManager interface is bound to the lifetime + * of the returned slot instance. + * + * @throws sdbus::Error in case of failure + */ + [[nodiscard]] virtual Slot addObjectManager(return_slot_t) = 0; + + /*! + * @brief Provides D-Bus connection used by the object + * + * @return Reference to the D-Bus connection + */ + [[nodiscard]] virtual sdbus::IConnection& getConnection() const = 0; + + /*! + * @brief Returns object path of the underlying DBus object + */ + [[nodiscard]] virtual const ObjectPath& getObjectPath() const = 0; + + /*! + * @brief Provides access to the currently processed D-Bus message + * + * This method provides access to the currently processed incoming D-Bus message. + * "Currently processed" means that the registered callback handler(s) for that message + * are being invoked. This method is meant to be called from within a callback handler + * (e.g. from a D-Bus signal handler, or async method reply handler, etc.). In such a case it is + * guaranteed to return a valid D-Bus message instance for which the handler is called. + * If called from other contexts/threads, it may return a valid or invalid message, depending + * on whether a message was processed or not at the time of the call. + * + * @return Currently processed D-Bus message + */ + [[nodiscard]] virtual Message getCurrentlyProcessedMessage() const = 0; + + /*! + * @brief Unregisters object's API and removes object from the bus + * + * This method unregisters the object, its interfaces, methods, signals and properties + * from the bus. Unregistration is done automatically also in object's destructor. This + * method makes sense if, in the process of object removal, we need to make sure that + * callbacks are unregistered explicitly before the final destruction of the object instance. + * + * @throws sdbus::Error in case of failure + */ + virtual void unregister() = 0; + + public: // Lower-level, message-based API + /*! + * @brief Adds a declaration of methods, properties and signals of the object at a given interface + * + * @param[in] interfaceName Name of an interface the the vtable is registered for + * @param[in] items Individual instances of VTable item structures + * + * This method is used to declare attributes for the object under the given interface. + * Parameter `items' represents a vtable definition that may contain method declarations + * (using MethodVTableItem struct), property declarations (using PropertyVTableItem + * struct), signal declarations (using SignalVTableItem struct), or global interface + * flags (using InterfaceFlagsVTableItem struct). + * + * An interface can have any number of vtables attached to it. + * + * Consult manual pages for the underlying `sd_bus_add_object_vtable` function for more information. + * + * The method can be called at any time during object's lifetime. For each vtable an internal + * registration slot is created and its lifetime is tied to the lifetime of the Object instance. + * + * The function provides strong exception guarantee. The state of the object remains + * unmodified in face of an exception. + * + * @throws sdbus::Error in case of failure + */ + template < typename... VTableItems + , typename = std::enable_if_t<(is_one_of_variants_types> && ...)> > + void addVTable(InterfaceName interfaceName, VTableItems&&... items); + + /*! + * @brief Adds a declaration of methods, properties and signals of the object at a given interface + * + * @param[in] interfaceName Name of an interface the the vtable is registered for + * @param[in] vtable A list of individual descriptions in the form of VTable item instances + * + * This method is used to declare attributes for the object under the given interface. + * The `vtable' parameter may contain method declarations (using MethodVTableItem struct), + * property declarations (using PropertyVTableItem struct), signal declarations (using + * SignalVTableItem struct), or global interface flags (using InterfaceFlagsVTableItem struct). + * + * An interface can have any number of vtables attached to it. + * + * Consult manual pages for the underlying `sd_bus_add_object_vtable` function for more information. + * + * The method can be called at any time during object's lifetime. For each vtable an internal + * registration slot is created and its lifetime is tied to the lifetime of the Object instance. + * + * The function provides strong exception guarantee. The state of the object remains + * unmodified in face of an exception. + * + * @throws sdbus::Error in case of failure + */ + virtual void addVTable(InterfaceName interfaceName, std::vector vtable) = 0; + + /*! + * @brief Adds a declaration of methods, properties and signals of the object at a given interface + * + * @param[in] interfaceName Name of an interface the the vtable is registered for + * @param[in] vtable A list of individual descriptions in the form of VTable item instances + * + * This method is used to declare attributes for the object under the given interface. + * The `vtable' parameter may contain method declarations (using MethodVTableItem struct), + * property declarations (using PropertyVTableItem struct), signal declarations (using + * SignalVTableItem struct), or global interface flags (using InterfaceFlagsVTableItem struct). + * + * An interface can have any number of vtables attached to it. + * + * Consult manual pages for the underlying `sd_bus_add_object_vtable` function for more information. + * + * The method can be called at any time during object's lifetime. For each vtable an internal + * registration slot is created and is returned to the caller. The returned slot should be destroyed + * when the vtable is not needed anymore. This allows for "dynamic" object API where vtables + * can be added or removed by the user at runtime. + * + * The function provides strong exception guarantee. The state of the object remains + * unmodified in face of an exception. + * + * @throws sdbus::Error in case of failure + */ + [[nodiscard]] virtual Slot addVTable(InterfaceName interfaceName, std::vector vtable, return_slot_t) = 0; + + /*! + * @brief Creates a signal message + * + * @param[in] interfaceName Name of an interface that the signal belongs under + * @param[in] signalName Name of the signal + * @return A signal message + * + * Serialize signal arguments into the returned message and emit the signal by passing + * the message with serialized arguments to the @c emitSignal function. + * Alternatively, use higher-level API @c emitSignal(const std::string& signalName) defined below. + * + * @throws sdbus::Error in case of failure + */ + [[nodiscard]] virtual Signal createSignal(const InterfaceName& interfaceName, const SignalName& signalName) const = 0; + + /*! + * @brief Emits signal for this object path + * + * @param[in] message Signal message to be sent out + * + * Note: To avoid messing with messages, use higher-level API defined below. + * + * @throws sdbus::Error in case of failure + */ + virtual void emitSignal(const sdbus::Signal& message) = 0; + + protected: // Internal API for efficiency reasons used by high-level API helper classes + friend SignalEmitter; + + [[nodiscard]] virtual Signal createSignal(const char* interfaceName, const char* signalName) const = 0; + }; + + // Out-of-line member definitions + + inline SignalEmitter IObject::emitSignal(const SignalName& signalName) + { + return SignalEmitter(*this, signalName); + } + + inline SignalEmitter IObject::emitSignal(const std::string& signalName) + { + return SignalEmitter(*this, signalName.c_str()); + } + + inline SignalEmitter IObject::emitSignal(const char* signalName) + { + return SignalEmitter(*this, signalName); + } + + template + void IObject::addVTable(InterfaceName interfaceName, VTableItems&&... items) + { + addVTable(std::move(interfaceName), {std::forward(items)...}); + } + + template + VTableAdder IObject::addVTable(VTableItems&&... items) + { + return addVTable(std::vector{std::forward(items)...}); + } + + inline VTableAdder IObject::addVTable(std::vector vtable) + { + return VTableAdder(*this, std::move(vtable)); + } + + /*! + * @brief Creates instance representing a D-Bus object + * + * @param[in] connection D-Bus connection to be used by the object + * @param[in] objectPath Path of the D-Bus object + * @return Pointer to the object representation instance + * + * The provided connection will be used by the object to export methods, + * issue signals and provide properties. + * + * Creating a D-Bus object instance is (thread-)safe even upon the connection + * which is already running its I/O event loop. + * + * Code example: + * @code + * auto proxy = sdbus::createObject(connection, "/com/kistler/foo"); + * @endcode + */ + [[nodiscard]] std::unique_ptr createObject(sdbus::IConnection& connection, ObjectPath objectPath); + +} + +#include +#include + +#endif /* SDBUS_CXX_IOBJECT_H_ */ diff --git a/3rdParty/sdbus-cpp/include/sdbus-c++/IProxy.h b/3rdParty/sdbus-cpp/include/sdbus-c++/IProxy.h new file mode 100644 index 0000000000..5c21191a20 --- /dev/null +++ b/3rdParty/sdbus-cpp/include/sdbus-c++/IProxy.h @@ -0,0 +1,981 @@ +/** + * (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland + * (C) 2016 - 2024 Stanislav Angelovic + * + * @file IProxy.h + * + * Created on: Nov 8, 2016 + * Project: sdbus-c++ + * Description: High-level D-Bus IPC C++ library based on sd-bus + * + * This file is part of sdbus-c++. + * + * sdbus-c++ is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 of the License, or + * (at your option) any later version. + * + * sdbus-c++ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with sdbus-c++. If not, see . + */ + +#ifndef SDBUS_CXX_IPROXY_H_ +#define SDBUS_CXX_IPROXY_H_ + +#include +#include + +#include +#include +#include +#include +#include +#include + +// Forward declarations +namespace sdbus { + class MethodCall; + class MethodReply; + class IConnection; + class ObjectPath; + class PendingAsyncCall; + namespace internal { + class Proxy; + } +} + +namespace sdbus { + + /********************************************//** + * @class IProxy + * + * IProxy class represents a proxy object, which is a convenient local object created + * to represent a remote D-Bus object in another process. + * The proxy enables calling methods on remote objects, receiving signals from remote + * objects, and getting/setting properties of remote objects. + * + * All IProxy member methods throw @c sdbus::Error in case of D-Bus or sdbus-c++ error. + * The IProxy class has been designed as thread-aware. However, the operation of + * creating and sending method calls (both synchronously and asynchronously) is + * thread-safe by design. + * + ***********************************************/ + class IProxy + { + public: // High-level, convenience API + virtual ~IProxy() = default; + + /*! + * @brief Calls method on the D-Bus object + * + * @param[in] methodName Name of the method + * @return A helper object for convenient invocation of the method + * + * This is a high-level, convenience way of calling D-Bus methods that abstracts + * from the D-Bus message concept. Method arguments/return value are automatically (de)serialized + * in a message and D-Bus signatures automatically deduced from the provided native arguments + * and return values. + * + * Example of use: + * @code + * int result, a = ..., b = ...; + * MethodName multiply{"multiply"}; + * object_.callMethod(multiply).onInterface(INTERFACE_NAME).withArguments(a, b).storeResultsTo(result); + * @endcode + * + * @throws sdbus::Error in case of failure + */ + [[nodiscard]] MethodInvoker callMethod(const MethodName& methodName); + + /*! + * @copydoc IProxy::callMethod(const MethodName&) + */ + [[nodiscard]] MethodInvoker callMethod(const std::string& methodName); + + /*! + * @copydoc IProxy::callMethod(const MethodName&) + */ + [[nodiscard]] MethodInvoker callMethod(const char* methodName); + + /*! + * @brief Calls method on the D-Bus object asynchronously + * + * @param[in] methodName Name of the method + * @return A helper object for convenient asynchronous invocation of the method + * + * This is a high-level, convenience way of calling D-Bus methods that abstracts + * from the D-Bus message concept. Method arguments/return value are automatically (de)serialized + * in a message and D-Bus signatures automatically deduced from the provided native arguments + * and return values. + * + * Example of use: + * @code + * int a = ..., b = ...; + * MethodName multiply{"multiply"}; + * object_.callMethodAsync(multiply).onInterface(INTERFACE_NAME).withArguments(a, b).uponReplyInvoke([](int result) + * { + * std::cout << "Got result of multiplying " << a << " and " << b << ": " << result << std::endl; + * }); + * @endcode + * + * @throws sdbus::Error in case of failure + */ + [[nodiscard]] AsyncMethodInvoker callMethodAsync(const MethodName& methodName); + + /*! + * @copydoc IProxy::callMethodAsync(const MethodName&) + */ + [[nodiscard]] AsyncMethodInvoker callMethodAsync(const std::string& methodName); + + /*! + * @copydoc IProxy::callMethodAsync(const MethodName&) + */ + [[nodiscard]] AsyncMethodInvoker callMethodAsync(const char* methodName); + + /*! + * @brief Registers signal handler for a given signal of the D-Bus object + * + * @param[in] signalName Name of the signal + * @return A helper object for convenient registration of the signal handler + * + * This is a high-level, convenience way of registering to D-Bus signals that abstracts + * from the D-Bus message concept. Signal arguments are automatically serialized + * in a message and D-Bus signatures automatically deduced from the parameters + * of the provided native signal callback. + * + * A signal can be subscribed to and unsubscribed from at any time during proxy + * lifetime. The subscription is active immediately after the call. + * + * Example of use: + * @code + * object_.uponSignal("stateChanged").onInterface("com.kistler.foo").call([this](int arg1, double arg2){ this->onStateChanged(arg1, arg2); }); + * sdbus::InterfaceName foo{"com.kistler.foo"}; + * sdbus::SignalName levelChanged{"levelChanged"}; + * object_.uponSignal(levelChanged).onInterface(foo).call([this](uint16_t level){ this->onLevelChanged(level); }); + * @endcode + * + * @throws sdbus::Error in case of failure + */ + [[nodiscard]] SignalSubscriber uponSignal(const SignalName& signalName); + + /*! + * @copydoc IProxy::uponSignal(const SignalName&) + */ + [[nodiscard]] SignalSubscriber uponSignal(const std::string& signalName); + + /*! + * @copydoc IProxy::uponSignal(const SignalName&) + */ + [[nodiscard]] SignalSubscriber uponSignal(const char* signalName); + + /*! + * @brief Gets value of a property of the D-Bus object + * + * @param[in] propertyName Name of the property + * @return A helper object for convenient getting of property value + * + * This is a high-level, convenience way of reading D-Bus property values that abstracts + * from the D-Bus message concept. sdbus::Variant is returned which shall then be converted + * to the real property type (implicit conversion is supported). + * + * Example of use: + * @code + * int state = object.getProperty("state").onInterface("com.kistler.foo"); + * sdbus::InterfaceName foo{"com.kistler.foo"}; + * sdbus::PropertyName level{"level"}; + * int level = object.getProperty(level).onInterface(foo); + * @endcode + * + * @throws sdbus::Error in case of failure + */ + [[nodiscard]] PropertyGetter getProperty(const PropertyName& propertyName); + + /*! + * @copydoc IProxy::getProperty(const PropertyName&) + */ + [[nodiscard]] PropertyGetter getProperty(std::string_view propertyName); + + /*! + * @brief Gets value of a property of the D-Bus object asynchronously + * + * @param[in] propertyName Name of the property + * @return A helper object for convenient asynchronous getting of property value + * + * This is a high-level, convenience way of reading D-Bus property values that abstracts + * from the D-Bus message concept. + * + * Example of use: + * @code + * std::future state = object.getPropertyAsync("state").onInterface("com.kistler.foo").getResultAsFuture(); + * auto callback = [](std::optional err, const sdbus::Variant& value){ ... }; + * object.getPropertyAsync("state").onInterface("com.kistler.foo").uponReplyInvoke(std::move(callback)); + * @endcode + * + * @throws sdbus::Error in case of failure + */ + [[nodiscard]] AsyncPropertyGetter getPropertyAsync(const PropertyName& propertyName); + + /*! + * @copydoc IProxy::getPropertyAsync(const PropertyName&) + */ + [[nodiscard]] AsyncPropertyGetter getPropertyAsync(std::string_view propertyName); + + /*! + * @brief Sets value of a property of the D-Bus object + * + * @param[in] propertyName Name of the property + * @return A helper object for convenient setting of property value + * + * This is a high-level, convenience way of writing D-Bus property values that abstracts + * from the D-Bus message concept. + * Setting property value with NoReply flag is also supported. + * + * Example of use: + * @code + * int state = ...; + * object_.setProperty("state").onInterface("com.kistler.foo").toValue(state); + * // Or we can just send the set message call without waiting for the reply + * object_.setProperty("state").onInterface("com.kistler.foo").toValue(state, dont_expect_reply); + * @endcode + * + * @throws sdbus::Error in case of failure + */ + [[nodiscard]] PropertySetter setProperty(const PropertyName& propertyName); + + /*! + * @copydoc IProxy::setProperty(const PropertyName&) + */ + [[nodiscard]] PropertySetter setProperty(std::string_view propertyName); + + /*! + * @brief Sets value of a property of the D-Bus object asynchronously + * + * @param[in] propertyName Name of the property + * @return A helper object for convenient asynchronous setting of property value + * + * This is a high-level, convenience way of writing D-Bus property values that abstracts + * from the D-Bus message concept. + * + * Example of use: + * @code + * int state = ...; + * // We can wait until the set operation finishes by waiting on the future + * std::future res = object_.setPropertyAsync("state").onInterface("com.kistler.foo").toValue(state).getResultAsFuture(); + * @endcode + * + * @throws sdbus::Error in case of failure + */ + [[nodiscard]] AsyncPropertySetter setPropertyAsync(const PropertyName& propertyName); + + /*! + * @copydoc IProxy::setPropertyAsync(const PropertyName&) + */ + [[nodiscard]] AsyncPropertySetter setPropertyAsync(std::string_view propertyName); + + /*! + * @brief Gets values of all properties of the D-Bus object + * + * @return A helper object for convenient getting of properties' values + * + * This is a high-level, convenience way of reading D-Bus properties' values that abstracts + * from the D-Bus message concept. + * + * Example of use: + * @code + * auto props = object.getAllProperties().onInterface("com.kistler.foo"); + * @endcode + * + * @throws sdbus::Error in case of failure + */ + [[nodiscard]] AllPropertiesGetter getAllProperties(); + + /*! + * @brief Gets values of all properties of the D-Bus object asynchronously + * + * @return A helper object for convenient asynchronous getting of properties' values + * + * This is a high-level, convenience way of reading D-Bus properties' values that abstracts + * from the D-Bus message concept. + * + * Example of use: + * @code + * auto callback = [](std::optional err, const std::map>& properties){ ... }; + * auto props = object.getAllPropertiesAsync().onInterface("com.kistler.foo").uponReplyInvoke(std::move(callback)); + * @endcode + * + * @throws sdbus::Error in case of failure + */ + [[nodiscard]] AsyncAllPropertiesGetter getAllPropertiesAsync(); + + /*! + * @brief Provides D-Bus connection used by the proxy + * + * @return Reference to the D-Bus connection + */ + [[nodiscard]] virtual sdbus::IConnection& getConnection() const = 0; + + /*! + * @brief Returns object path of the underlying DBus object + */ + [[nodiscard]] virtual const ObjectPath& getObjectPath() const = 0; + + /*! + * @brief Provides access to the currently processed D-Bus message + * + * This method provides access to the currently processed incoming D-Bus message. + * "Currently processed" means that the registered callback handler(s) for that message + * are being invoked. This method is meant to be called from within a callback handler + * (e.g. from a D-Bus signal handler, or async method reply handler, etc.). In such a case it is + * guaranteed to return a valid D-Bus message instance for which the handler is called. + * If called from other contexts/threads, it may return a valid or invalid message, depending + * on whether a message was processed or not at the time of the call. + * + * @return Currently processed D-Bus message + */ + [[nodiscard]] virtual Message getCurrentlyProcessedMessage() const = 0; + + /*! + * @brief Unregisters proxy's signal handlers and stops receiving replies to pending async calls + * + * Unregistration is done automatically also in proxy's destructor. This method makes + * sense if, in the process of proxy removal, we need to make sure that callbacks + * are unregistered explicitly before the final destruction of the proxy instance. + * + * @throws sdbus::Error in case of failure + */ + virtual void unregister() = 0; + + public: // Lower-level, message-based API + /*! + * @brief Creates a method call message + * + * @param[in] interfaceName Name of an interface that provides a given method + * @param[in] methodName Name of the method + * @return A method call message + * + * Serialize method arguments into the returned message and invoke the method by passing + * the message with serialized arguments to the @c callMethod function. + * Alternatively, use higher-level API @c callMethod(const std::string& methodName) defined below. + * + * @throws sdbus::Error in case of failure + */ + [[nodiscard]] virtual MethodCall createMethodCall(const InterfaceName& interfaceName, const MethodName& methodName) const = 0; + + /*! + * @brief Calls method on the remote D-Bus object + * + * @param[in] message Message representing a method call + * @return A method reply message + * + * The call does not block if the method call has dont-expect-reply flag set. In that case, + * the call returns immediately and the return value is an empty, invalid method reply. + * + * The call blocks otherwise, waiting for the remote peer to send back a reply or an error, + * or until the call times out. + * + * While blocking, other concurrent operations (in other threads) on the underlying bus + * connection are stalled until the call returns. This is not an issue in vast majority of + * (simple, single-threaded) applications. In asynchronous, multi-threaded designs involving + * shared bus connections, this may be an issue. It is advised to instead use an asynchronous + * callMethod() function overload, which does not block the bus connection, or do the synchronous + * call from another Proxy instance created just before the call and then destroyed (which is + * anyway quite a typical approach in D-Bus implementations). Such proxy instance must have + * its own bus connection. So-called light-weight proxies (ones running without an event loop thread) + * tag are designed for exactly that purpose. + * + * The default D-Bus method call timeout is used. See IConnection::getMethodCallTimeout(). + * + * Note: To avoid messing with messages, use API on a higher level of abstraction defined below. + * + * @throws sdbus::Error in case of failure (also in case the remote function returned an error) + */ + virtual MethodReply callMethod(const MethodCall& message) = 0; + + /*! + * @brief Calls method on the remote D-Bus object + * + * @param[in] message Message representing a method call + * @param[in] timeout Method call timeout (in microseconds) + * @return A method reply message + * + * The call does not block if the method call has dont-expect-reply flag set. In that case, + * the call returns immediately and the return value is an empty, invalid method reply. + * + * The call blocks otherwise, waiting for the remote peer to send back a reply or an error, + * or until the call times out. + * + * While blocking, other concurrent operations (in other threads) on the underlying bus + * connection are stalled until the call returns. This is not an issue in vast majority of + * (simple, single-threaded) applications. In asynchronous, multi-threaded designs involving + * shared bus connections, this may be an issue. It is advised to instead use an asynchronous + * callMethod() function overload, which does not block the bus connection, or do the synchronous + * call from another Proxy instance created just before the call and then destroyed (which is + * anyway quite a typical approach in D-Bus implementations). Such proxy instance must have + * its own bus connection. So-called light-weight proxies (ones running without an event loop thread) + * tag are designed for exactly that purpose. + * + * If timeout is zero, the default D-Bus method call timeout is used. See IConnection::getMethodCallTimeout(). + * + * Note: To avoid messing with messages, use API on a higher level of abstraction defined below. + * + * @throws sdbus::Error in case of failure (also in case the remote function returned an error) + */ + virtual MethodReply callMethod(const MethodCall& message, uint64_t timeout) = 0; + + /*! + * @copydoc IProxy::callMethod(const MethodCall&,uint64_t) + */ + template + MethodReply callMethod(const MethodCall& message, const std::chrono::duration<_Rep, _Period>& timeout); + + /*! + * @brief Calls method on the D-Bus object asynchronously + * + * @param[in] message Message representing an async method call + * @param[in] asyncReplyCallback Handler for the async reply + * @return Observing handle for the the pending asynchronous call + * + * This is a callback-based way of asynchronously calling a remote D-Bus method. + * + * The call itself is non-blocking. It doesn't wait for the reply. Once the reply arrives, + * the provided async reply handler will get invoked from the context of the bus + * connection I/O event loop thread. + * + * An non-owning, observing async call handle is returned that can be used to query call status or cancel the call. + * + * The default D-Bus method call timeout is used. See IConnection::getMethodCallTimeout(). + * + * Note: To avoid messing with messages, use API on a higher level of abstraction defined below. + * + * @throws sdbus::Error in case of failure + */ + virtual PendingAsyncCall callMethodAsync(const MethodCall& message, async_reply_handler asyncReplyCallback) = 0; + + /*! + * @brief Calls method on the D-Bus object asynchronously + * + * @param[in] message Message representing an async method call + * @param[in] asyncReplyCallback Handler for the async reply + * @return RAII-style slot handle representing the ownership of the async call + * + * This is a callback-based way of asynchronously calling a remote D-Bus method. + * + * The call itself is non-blocking. It doesn't wait for the reply. Once the reply arrives, + * the provided async reply handler will get invoked from the context of the bus + * connection I/O event loop thread. + * + * A slot (an owning handle) is returned for the async call. Lifetime of the call is bound to the lifetime of the slot. + * The slot can be used to cancel the method call at a later time by simply destroying it. + * + * The default D-Bus method call timeout is used. See IConnection::getMethodCallTimeout(). + * + * Note: To avoid messing with messages, use API on a higher level of abstraction defined below. + * + * @throws sdbus::Error in case of failure + */ + [[nodiscard]] virtual Slot callMethodAsync( const MethodCall& message + , async_reply_handler asyncReplyCallback + , return_slot_t ) = 0; + + /*! + * @brief Calls method on the D-Bus object asynchronously, with custom timeout + * + * @param[in] message Message representing an async method call + * @param[in] asyncReplyCallback Handler for the async reply + * @param[in] timeout Method call timeout (in microseconds) + * @return Observing handle for the the pending asynchronous call + * + * This is a callback-based way of asynchronously calling a remote D-Bus method. + * + * The call itself is non-blocking. It doesn't wait for the reply. Once the reply arrives, + * the provided async reply handler will get invoked from the context of the bus + * connection I/O event loop thread. + * + * An non-owning, observing async call handle is returned that can be used to query call status or cancel the call. + * + * If timeout is zero, the default D-Bus method call timeout is used. See IConnection::getMethodCallTimeout(). + * + * Note: To avoid messing with messages, use API on a higher level of abstraction defined below. + * + * @throws sdbus::Error in case of failure + */ + virtual PendingAsyncCall callMethodAsync( const MethodCall& message + , async_reply_handler asyncReplyCallback + , uint64_t timeout ) = 0; + + /*! + * @brief Calls method on the D-Bus object asynchronously, with custom timeout + * + * @param[in] message Message representing an async method call + * @param[in] asyncReplyCallback Handler for the async reply + * @param[in] timeout Method call timeout (in microseconds) + * @return RAII-style slot handle representing the ownership of the async call + * + * This is a callback-based way of asynchronously calling a remote D-Bus method. + * + * The call itself is non-blocking. It doesn't wait for the reply. Once the reply arrives, + * the provided async reply handler will get invoked from the context of the bus + * connection I/O event loop thread. + * + * A slot (an owning handle) is returned for the async call. Lifetime of the call is bound to the lifetime of the slot. + * The slot can be used to cancel the method call at a later time by simply destroying it. + * + * If timeout is zero, the default D-Bus method call timeout is used. See IConnection::getMethodCallTimeout(). + * + * Note: To avoid messing with messages, use API on a higher level of abstraction defined below. + * + * @throws sdbus::Error in case of failure + */ + [[nodiscard]] virtual Slot callMethodAsync( const MethodCall& message + , async_reply_handler asyncReplyCallback + , uint64_t timeout + , return_slot_t ) = 0; + + /*! + * @copydoc IProxy::callMethod(const MethodCall&,async_reply_handler,uint64_t) + */ + template + PendingAsyncCall callMethodAsync( const MethodCall& message + , async_reply_handler asyncReplyCallback + , const std::chrono::duration<_Rep, _Period>& timeout ); + + /*! + * @copydoc IProxy::callMethod(const MethodCall&,async_reply_handler,uint64_t,return_slot_t) + */ + template + [[nodiscard]] Slot callMethodAsync( const MethodCall& message + , async_reply_handler asyncReplyCallback + , const std::chrono::duration<_Rep, _Period>& timeout + , return_slot_t ); + + /*! + * @brief Calls method on the D-Bus object asynchronously + * + * @param[in] message Message representing an async method call + * @param[in] Tag denoting a std::future-based overload + * @return Future object providing access to the future method reply message + * + * This is a std::future-based way of asynchronously calling a remote D-Bus method. + * + * The call itself is non-blocking. It doesn't wait for the reply. Once the reply arrives, + * the provided future object will be set to contain the reply (or sdbus::Error + * in case the remote method threw an exception). + * + * The default D-Bus method call timeout is used. See IConnection::getMethodCallTimeout(). + * + * Note: To avoid messing with messages, use higher-level API defined below. + * + * @throws sdbus::Error in case of failure + */ + virtual std::future callMethodAsync(const MethodCall& message, with_future_t) = 0; + + /*! + * @brief Calls method on the D-Bus object asynchronously, with custom timeout + * + * @param[in] message Message representing an async method call + * @param[in] timeout Method call timeout + * @param[in] Tag denoting a std::future-based overload + * @return Future object providing access to the future method reply message + * + * This is a std::future-based way of asynchronously calling a remote D-Bus method. + * + * The call itself is non-blocking. It doesn't wait for the reply. Once the reply arrives, + * the provided future object will be set to contain the reply (or sdbus::Error + * in case the remote method threw an exception, or the call timed out). + * + * If timeout is zero, the default D-Bus method call timeout is used. See IConnection::getMethodCallTimeout(). + * + * Note: To avoid messing with messages, use higher-level API defined below. + * + * @throws sdbus::Error in case of failure + */ + virtual std::future callMethodAsync( const MethodCall& message + , uint64_t timeout + , with_future_t ) = 0; + + /*! + * @copydoc IProxy::callMethod(const MethodCall&,uint64_t,with_future_t) + */ + template + std::future callMethodAsync( const MethodCall& message + , const std::chrono::duration<_Rep, _Period>& timeout + , with_future_t ); + + /*! + * @brief Registers a handler for the desired signal emitted by the D-Bus object + * + * @param[in] interfaceName Name of an interface that the signal belongs to + * @param[in] signalName Name of the signal + * @param[in] signalHandler Callback that implements the body of the signal handler + * + * A signal can be subscribed to at any time during proxy lifetime. The subscription + * is active immediately after the call, and stays active for the entire lifetime + * of the Proxy object. + * + * To be able to unsubscribe from the signal at a later time, use the registerSignalHandler() + * overload with request_slot tag. + * + * @throws sdbus::Error in case of failure + */ + virtual void registerSignalHandler( const InterfaceName& interfaceName + , const SignalName& signalName + , signal_handler signalHandler ) = 0; + + /*! + * @brief Registers a handler for the desired signal emitted by the D-Bus object + * + * @param[in] interfaceName Name of an interface that the signal belongs to + * @param[in] signalName Name of the signal + * @param[in] signalHandler Callback that implements the body of the signal handler + * + * @return RAII-style slot handle representing the ownership of the subscription + * + * A signal can be subscribed to and unsubscribed from at any time during proxy + * lifetime. The subscription is active immediately after the call. The lifetime + * of the subscription is bound to the lifetime of the slot object. The subscription + * is unregistered by letting go of the slot object. + * + * @throws sdbus::Error in case of failure + */ + [[nodiscard]] virtual Slot registerSignalHandler( const InterfaceName& interfaceName + , const SignalName& signalName + , signal_handler signalHandler + , return_slot_t ) = 0; + + protected: // Internal API for efficiency reasons used by high-level API helper classes + friend MethodInvoker; + friend AsyncMethodInvoker; + friend SignalSubscriber; + + [[nodiscard]] virtual MethodCall createMethodCall(const char* interfaceName, const char* methodName) const = 0; + virtual void registerSignalHandler( const char* interfaceName + , const char* signalName + , signal_handler signalHandler ) = 0; + [[nodiscard]] virtual Slot registerSignalHandler( const char* interfaceName + , const char* signalName + , signal_handler signalHandler + , return_slot_t ) = 0; + }; + + /********************************************//** + * @class PendingAsyncCall + * + * PendingAsyncCall represents a simple handle type to cancel the delivery + * of the asynchronous D-Bus call result to the application. + * + * The handle is lifetime-independent from the originating Proxy object. + * It's safe to call its methods even after the Proxy has gone. + * + ***********************************************/ + class PendingAsyncCall + { + public: + PendingAsyncCall() = default; + + /*! + * @brief Cancels the delivery of the pending asynchronous call result + * + * This function effectively removes the callback handler registered to the + * async D-Bus method call result delivery. Does nothing if the call was + * completed already, or if the originating Proxy object has gone meanwhile. + */ + void cancel(); + + /*! + * @brief Answers whether the asynchronous call is still pending + * + * @return True if the call is pending, false if the call has been fully completed + * + * Pending call in this context means a call whose results have not arrived, or + * have arrived and are currently being processed by the callback handler. + */ + [[nodiscard]] bool isPending() const; + + private: + friend internal::Proxy; + PendingAsyncCall(std::weak_ptr callInfo); + + private: + std::weak_ptr callInfo_; + }; + + // Out-of-line member definitions + + template + inline MethodReply IProxy::callMethod(const MethodCall& message, const std::chrono::duration<_Rep, _Period>& timeout) + { + auto microsecs = std::chrono::duration_cast(timeout); + return callMethod(message, microsecs.count()); + } + + template + inline PendingAsyncCall IProxy::callMethodAsync( const MethodCall& message + , async_reply_handler asyncReplyCallback + , const std::chrono::duration<_Rep, _Period>& timeout ) + { + auto microsecs = std::chrono::duration_cast(timeout); + return callMethodAsync(message, std::move(asyncReplyCallback), microsecs.count()); + } + + template + inline Slot IProxy::callMethodAsync( const MethodCall& message + , async_reply_handler asyncReplyCallback + , const std::chrono::duration<_Rep, _Period>& timeout + , return_slot_t ) + { + auto microsecs = std::chrono::duration_cast(timeout); + return callMethodAsync(message, std::move(asyncReplyCallback), microsecs.count(), return_slot); + } + + template + inline std::future IProxy::callMethodAsync( const MethodCall& message + , const std::chrono::duration<_Rep, _Period>& timeout + , with_future_t ) + { + auto microsecs = std::chrono::duration_cast(timeout); + return callMethodAsync(message, microsecs.count(), with_future); + } + + inline MethodInvoker IProxy::callMethod(const MethodName& methodName) + { + return MethodInvoker(*this, methodName); + } + + inline MethodInvoker IProxy::callMethod(const std::string& methodName) + { + return MethodInvoker(*this, methodName.c_str()); + } + + inline MethodInvoker IProxy::callMethod(const char* methodName) + { + return MethodInvoker(*this, methodName); + } + + inline AsyncMethodInvoker IProxy::callMethodAsync(const MethodName& methodName) + { + return AsyncMethodInvoker(*this, methodName); + } + + inline AsyncMethodInvoker IProxy::callMethodAsync(const std::string& methodName) + { + return AsyncMethodInvoker(*this, methodName.c_str()); + } + + inline AsyncMethodInvoker IProxy::callMethodAsync(const char* methodName) + { + return AsyncMethodInvoker(*this, methodName); + } + + inline SignalSubscriber IProxy::uponSignal(const SignalName& signalName) + { + return SignalSubscriber(*this, signalName); + } + + inline SignalSubscriber IProxy::uponSignal(const std::string& signalName) + { + return SignalSubscriber(*this, signalName.c_str()); + } + + inline SignalSubscriber IProxy::uponSignal(const char* signalName) + { + return SignalSubscriber(*this, signalName); + } + + inline PropertyGetter IProxy::getProperty(const PropertyName& propertyName) + { + return PropertyGetter(*this, propertyName); + } + + inline PropertyGetter IProxy::getProperty(std::string_view propertyName) + { + return PropertyGetter(*this, std::move(propertyName)); + } + + inline AsyncPropertyGetter IProxy::getPropertyAsync(const PropertyName& propertyName) + { + return AsyncPropertyGetter(*this, propertyName); + } + + inline AsyncPropertyGetter IProxy::getPropertyAsync(std::string_view propertyName) + { + return AsyncPropertyGetter(*this, std::move(propertyName)); + } + + inline PropertySetter IProxy::setProperty(const PropertyName& propertyName) + { + return PropertySetter(*this, propertyName); + } + + inline PropertySetter IProxy::setProperty(std::string_view propertyName) + { + return PropertySetter(*this, std::move(propertyName)); + } + + inline AsyncPropertySetter IProxy::setPropertyAsync(const PropertyName& propertyName) + { + return AsyncPropertySetter(*this, propertyName); + } + + inline AsyncPropertySetter IProxy::setPropertyAsync(std::string_view propertyName) + { + return AsyncPropertySetter(*this, std::move(propertyName)); + } + + inline AllPropertiesGetter IProxy::getAllProperties() + { + return AllPropertiesGetter(*this); + } + + inline AsyncAllPropertiesGetter IProxy::getAllPropertiesAsync() + { + return AsyncAllPropertiesGetter(*this); + } + + /*! + * @brief Creates a proxy object for a specific remote D-Bus object + * + * @param[in] connection D-Bus connection to be used by the proxy object + * @param[in] destination Bus name that provides the remote D-Bus object + * @param[in] objectPath Path of the remote D-Bus object + * @return Pointer to the proxy object instance + * + * The provided connection will be used by the proxy to issue calls against the object, + * and signals, if any, will be subscribed to on this connection. The caller still + * remains the owner of the connection (the proxy just keeps a reference to it), and + * should make sure that an I/O event loop is running on that connection, so the proxy + * may receive incoming signals and asynchronous method replies. + * + * The destination parameter may be an empty string (useful e.g. in case of direct + * D-Bus connections to a custom server bus). + * + * Code example: + * @code + * auto proxy = sdbus::createProxy(connection, "com.kistler.foo", "/com/kistler/foo"); + * @endcode + */ + [[nodiscard]] std::unique_ptr createProxy( sdbus::IConnection& connection + , ServiceName destination + , ObjectPath objectPath ); + + /*! + * @brief Creates a proxy object for a specific remote D-Bus object + * + * @param[in] connection D-Bus connection to be used by the proxy object + * @param[in] destination Bus name that provides the remote D-Bus object + * @param[in] objectPath Path of the remote D-Bus object + * @return Pointer to the object proxy instance + * + * The provided connection will be used by the proxy to issue calls against the object, + * and signals, if any, will be subscribed to on this connection. The Object proxy becomes + * an exclusive owner of this connection, and will automatically start a procesing loop + * upon that connection in a separate internal thread. Handlers for incoming signals and + * asynchronous method replies will be executed in the context of that thread. + * + * The destination parameter may be an empty string (useful e.g. in case of direct + * D-Bus connections to a custom server bus). + * + * Code example: + * @code + * auto proxy = sdbus::createProxy(std::move(connection), "com.kistler.foo", "/com/kistler/foo"); + * @endcode + */ + [[nodiscard]] std::unique_ptr createProxy( std::unique_ptr&& connection + , ServiceName destination + , ObjectPath objectPath ); + + /*! + * @brief Creates a light-weight proxy object for a specific remote D-Bus object + * + * @param[in] connection D-Bus connection to be used by the proxy object + * @param[in] destination Bus name that provides the remote D-Bus object + * @param[in] objectPath Path of the remote D-Bus object + * @return Pointer to the object proxy instance + * + * The provided connection will be used by the proxy to issue calls against the object. + * The Object proxy becomes an exclusive owner of this connection, but will not start + * an event loop thread on this connection. This is cheap construction and is suitable + * for short-lived proxies created just to execute simple synchronous D-Bus calls and + * then destroyed. Such blocking request-reply calls will work without an event loop + * (but signals, async calls, etc. won't). + * + * The destination parameter may be an empty string (useful e.g. in case of direct + * D-Bus connections to a custom server bus). + * + * Code example: + * @code + * auto proxy = sdbus::createProxy(std::move(connection), "com.kistler.foo", "/com/kistler/foo", sdbus::dont_run_event_loop_thread); + * @endcode + */ + [[nodiscard]] std::unique_ptr createProxy( std::unique_ptr&& connection + , ServiceName destination + , ObjectPath objectPath + , dont_run_event_loop_thread_t ); + + /*! + * @brief Creates a light-weight proxy object for a specific remote D-Bus object + * + * Does the same thing as createProxy(std::unique_ptr&&, ServiceName, ObjectPath, dont_run_event_loop_thread_t); + */ + [[nodiscard]] std::unique_ptr createLightWeightProxy( std::unique_ptr&& connection + , ServiceName destination + , ObjectPath objectPath ); + + /*! + * @brief Creates a proxy object for a specific remote D-Bus object + * + * @param[in] destination Bus name that provides the remote D-Bus object + * @param[in] objectPath Path of the remote D-Bus object + * @return Pointer to the object proxy instance + * + * No D-Bus connection is provided here, so the object proxy will create and manage + * his own connection, and will automatically start an event loop upon that connection + * in a separate internal thread. Handlers for incoming signals and asynchronous + * method replies will be executed in the context of that thread. + * + * Code example: + * @code + * auto proxy = sdbus::createProxy("com.kistler.foo", "/com/kistler/foo"); + * @endcode + */ + [[nodiscard]] std::unique_ptr createProxy( ServiceName destination + , ObjectPath objectPath ); + + /*! + * @brief Creates a light-weight proxy object for a specific remote D-Bus object + * + * @param[in] destination Bus name that provides the remote D-Bus object + * @param[in] objectPath Path of the remote D-Bus object + * @return Pointer to the object proxy instance + * + * No D-Bus connection is provided here, so the object proxy will create and manage + * his own connection, but it will not start an event loop thread. This is cheap + * construction and is suitable for short-lived proxies created just to execute simple + * synchronous D-Bus calls and then destroyed. Such blocking request-reply calls + * will work without an event loop (but signals, async calls, etc. won't). + * + * Code example: + * @code + * auto proxy = sdbus::createProxy("com.kistler.foo", "/com/kistler/foo", sdbus::dont_run_event_loop_thread ); + * @endcode + */ + [[nodiscard]] std::unique_ptr createProxy( ServiceName destination + , ObjectPath objectPath + , dont_run_event_loop_thread_t ); + + /*! + * @brief Creates a light-weight proxy object for a specific remote D-Bus object + * + * Does the same thing as createProxy(ServiceName, ObjectPath, dont_run_event_loop_thread_t); + */ + [[nodiscard]] std::unique_ptr createLightWeightProxy(ServiceName destination, ObjectPath objectPath); + +} + +#include + +#endif /* SDBUS_CXX_IPROXY_H_ */ diff --git a/3rdParty/sdbus-cpp/include/sdbus-c++/Message.h b/3rdParty/sdbus-cpp/include/sdbus-c++/Message.h new file mode 100644 index 0000000000..4be8d85898 --- /dev/null +++ b/3rdParty/sdbus-cpp/include/sdbus-c++/Message.h @@ -0,0 +1,782 @@ +/** + * (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland + * (C) 2016 - 2024 Stanislav Angelovic + * + * @file Message.h + * + * Created on: Nov 9, 2016 + * Project: sdbus-c++ + * Description: High-level D-Bus IPC C++ library based on sd-bus + * + * This file is part of sdbus-c++. + * + * sdbus-c++ is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 of the License, or + * (at your option) any later version. + * + * sdbus-c++ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with sdbus-c++. If not, see . + */ + +#ifndef SDBUS_CXX_MESSAGE_H_ +#define SDBUS_CXX_MESSAGE_H_ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#ifdef __has_include +# if __has_include() +# include +# endif +#endif +#include +#include +#include +#include +#include +#include + +// Forward declarations +namespace sdbus { + class Variant; + class ObjectPath; + class Signature; + template class Struct; + class UnixFd; + class MethodReply; + namespace internal { + class IConnection; + } +} + +namespace sdbus { + + /********************************************//** + * @class Message + * + * Message represents a D-Bus message, which can be either method call message, + * method reply message, signal message, or a plain message. + * + * Serialization and deserialization functions are provided for types supported + * by D-Bus. + * + * You mostly don't need to work with this class directly if you use high-level + * APIs of @c IObject and @c IProxy. + * + ***********************************************/ + class [[nodiscard]] Message + { + public: + Message(const Message&) noexcept; + Message& operator=(const Message&) noexcept; + Message(Message&& other) noexcept; + Message& operator=(Message&& other) noexcept; + ~Message(); + + Message& operator<<(bool item); + Message& operator<<(int16_t item); + Message& operator<<(int32_t item); + Message& operator<<(int64_t item); + Message& operator<<(uint8_t item); + Message& operator<<(uint16_t item); + Message& operator<<(uint32_t item); + Message& operator<<(uint64_t item); + Message& operator<<(double item); + Message& operator<<(const char *item); + Message& operator<<(const std::string &item); + Message& operator<<(std::string_view item); + Message& operator<<(const Variant &item); + template + Message& operator<<(const std::variant& value); + Message& operator<<(const ObjectPath &item); + Message& operator<<(const Signature &item); + Message& operator<<(const UnixFd &item); + template + Message& operator<<(const std::vector<_Element, _Allocator>& items); + template + Message& operator<<(const std::array<_Element, _Size>& items); +#ifdef __cpp_lib_span + template + Message& operator<<(const std::span<_Element, _Extent>& items); +#endif + template >> + Message& operator<<(const _Enum& item); + template + Message& operator<<(const DictEntry<_Key, _Value>& value); + template + Message& operator<<(const std::map<_Key, _Value, _Compare, _Allocator>& items); + template + Message& operator<<(const std::unordered_map<_Key, _Value, _Hash, _KeyEqual, _Allocator>& items); + template + Message& operator<<(const Struct<_ValueTypes...>& item); + template + Message& operator<<(const std::tuple<_ValueTypes...>& item); + + Message& operator>>(bool& item); + Message& operator>>(int16_t& item); + Message& operator>>(int32_t& item); + Message& operator>>(int64_t& item); + Message& operator>>(uint8_t& item); + Message& operator>>(uint16_t& item); + Message& operator>>(uint32_t& item); + Message& operator>>(uint64_t& item); + Message& operator>>(double& item); + Message& operator>>(char*& item); + Message& operator>>(std::string &item); + Message& operator>>(Variant &item); + template + Message& operator>>(std::variant& value); + Message& operator>>(ObjectPath &item); + Message& operator>>(Signature &item); + Message& operator>>(UnixFd &item); + template + Message& operator>>(std::vector<_Element, _Allocator>& items); + template + Message& operator>>(std::array<_Element, _Size>& items); +#ifdef __cpp_lib_span + template + Message& operator>>(std::span<_Element, _Extent>& items); +#endif + template >> + Message& operator>>(_Enum& item); + template + Message& operator>>(DictEntry<_Key, _Value>& value); + template + Message& operator>>(std::map<_Key, _Value, _Compare, _Allocator>& items); + template + Message& operator>>(std::unordered_map<_Key, _Value, _Hash, _KeyEqual, _Allocator>& items); + template + Message& operator>>(Struct<_ValueTypes...>& item); + template + Message& operator>>(std::tuple<_ValueTypes...>& item); + + template + Message& openContainer(); + Message& openContainer(const char* signature); + Message& closeContainer(); + template + Message& openDictEntry(); + Message& openDictEntry(const char* signature); + Message& closeDictEntry(); + template + Message& openVariant(); + Message& openVariant(const char* signature); + Message& closeVariant(); + template + Message& openStruct(); + Message& openStruct(const char* signature); + Message& closeStruct(); + + template + Message& enterContainer(); + Message& enterContainer(const char* signature); + Message& exitContainer(); + template + Message& enterDictEntry(); + Message& enterDictEntry(const char* signature); + Message& exitDictEntry(); + template + Message& enterVariant(); + Message& enterVariant(const char* signature); + Message& exitVariant(); + template + Message& enterStruct(); + Message& enterStruct(const char* signature); + Message& exitStruct(); + + Message& appendArray(char type, const void *ptr, size_t size); + Message& readArray(char type, const void **ptr, size_t *size); + + template + Message& serializeDictionary(const _Callback& callback); + template + Message& serializeDictionary(const std::initializer_list>& dictEntries); + template + Message& deserializeDictionary(const _Callback& callback); + + explicit operator bool() const; + void clearFlags(); + + const char* getInterfaceName() const; + const char* getMemberName() const; + const char* getSender() const; + const char* getPath() const; + const char* getDestination() const; + uint64_t getCookie() const; + std::pair peekType() const; + bool isValid() const; + bool isEmpty() const; + bool isAtEnd(bool complete) const; + + void copyTo(Message& destination, bool complete) const; + void seal(); + void rewind(bool complete); + + pid_t getCredsPid() const; + uid_t getCredsUid() const; + uid_t getCredsEuid() const; + gid_t getCredsGid() const; + gid_t getCredsEgid() const; + std::vector getCredsSupplementaryGids() const; + std::string getSELinuxContext() const; + + class Factory; + + private: + template + void serializeArray(const _Array& items); + template + void deserializeArray(_Array& items); + template + void deserializeArrayFast(_Array& items); + template + void deserializeArrayFast(std::vector<_Element, _Allocator>& items); + template + void deserializeArraySlow(_Array& items); + template + void deserializeArraySlow(std::vector<_Element, _Allocator>& items); + + protected: + Message() = default; + explicit Message(internal::IConnection* connection) noexcept; + Message(void *msg, internal::IConnection* connection) noexcept; + Message(void *msg, internal::IConnection* connection, adopt_message_t) noexcept; + + friend Factory; + + protected: + void* msg_{}; + internal::IConnection* connection_{}; + mutable bool ok_{true}; + }; + + class MethodCall : public Message + { + using Message::Message; + friend Factory; + + public: + MethodCall() = default; + + MethodReply send(uint64_t timeout) const; + [[nodiscard]] Slot send(void* callback, void* userData, uint64_t timeout, return_slot_t) const; + + MethodReply createReply() const; + MethodReply createErrorReply(const sdbus::Error& error) const; + + void dontExpectReply(); + bool doesntExpectReply() const; + + protected: + MethodCall(void *msg, internal::IConnection* connection, adopt_message_t) noexcept; + + private: + MethodReply sendWithReply(uint64_t timeout = 0) const; + MethodReply sendWithNoReply() const; + }; + + class MethodReply : public Message + { + using Message::Message; + friend Factory; + + public: + MethodReply() = default; + void send() const; + uint64_t getReplyCookie() const; + }; + + class Signal : public Message + { + using Message::Message; + friend Factory; + + public: + Signal() = default; + void setDestination(const std::string& destination); + void setDestination(const char* destination); + void send() const; + }; + + class PropertySetCall : public Message + { + using Message::Message; + friend Factory; + + public: + PropertySetCall() = default; + }; + + class PropertyGetReply : public Message + { + using Message::Message; + friend Factory; + + public: + PropertyGetReply() = default; + }; + + // Represents any of the above message types, or just a message that serves as a container for data + class PlainMessage : public Message + { + using Message::Message; + friend Factory; + + public: + PlainMessage() = default; + }; + + PlainMessage createPlainMessage(); + + template + inline Message& Message::operator<<(const std::variant& value) + { + std::visit([this](const auto& inner) + { + openVariant(); + *this << inner; + closeVariant(); + }, value); + + return *this; + } + + template + inline Message& Message::operator<<(const std::vector<_Element, _Allocator>& items) + { + serializeArray(items); + + return *this; + } + + template + inline Message& Message::operator<<(const std::array<_Element, _Size>& items) + { + serializeArray(items); + + return *this; + } + +#ifdef __cpp_lib_span + template + inline Message& Message::operator<<(const std::span<_Element, _Extent>& items) + { + serializeArray(items); + + return *this; + } +#endif + + template + inline Message& Message::operator<<(const _Enum &item) + { + return operator<<(static_cast>(item)); + } + + template + inline void Message::serializeArray(const _Array& items) + { + using ElementType = typename _Array::value_type; + + // Use faster, one-step serialization of contiguous array of elements of trivial D-Bus types except bool, + // otherwise use step-by-step serialization of individual elements. + if constexpr (signature_of::is_trivial_dbus_type && !std::is_same_v) + { + constexpr auto signature = as_null_terminated(signature_of_v); + appendArray(*signature.data(), items.data(), items.size() * sizeof(ElementType)); + } + else + { + openContainer(); + + for (const auto& item : items) + *this << item; + + closeContainer(); + } + } + + template + inline Message& Message::operator<<(const DictEntry<_Key, _Value>& value) + { + openDictEntry<_Key, _Value>(); + *this << value.first; + *this << value.second; + closeDictEntry(); + + return *this; + } + + template + inline Message& Message::operator<<(const std::map<_Key, _Value, _Compare, _Allocator>& items) + { + serializeDictionary<_Key, _Value>([&items](Message& msg){ for (const auto& item : items) msg << item; }); + + return *this; + } + + template + inline Message& Message::operator<<(const std::unordered_map<_Key, _Value, _Hash, _KeyEqual, _Allocator>& items) + { + serializeDictionary<_Key, _Value>([&items](Message& msg){ for (const auto& item : items) msg << item; }); + + return *this; + } + + template + inline Message& Message::serializeDictionary(const std::initializer_list>& items) + { + serializeDictionary<_Key, _Value>([&](Message& msg){ for (const auto& item : items) msg << item; }); + + return *this; + } + + template + inline Message& Message::serializeDictionary(const _Callback& callback) + { + openContainer>(); + callback(*this); + closeContainer(); + + return *this; + } + + namespace detail + { + template + void serialize_pack(Message& msg, _Args&&... args) + { + (void)(msg << ... << args); + } + + template + void serialize_tuple( Message& msg + , const _Tuple& t + , std::index_sequence<_Is...>) + { + serialize_pack(msg, std::get<_Is>(t)...); + } + } + + template + inline Message& Message::operator<<(const Struct<_ValueTypes...>& item) + { + openStruct<_ValueTypes...>(); + detail::serialize_tuple(*this, item, std::index_sequence_for<_ValueTypes...>{}); + closeStruct(); + + return *this; + } + + template + inline Message& Message::operator<<(const std::tuple<_ValueTypes...>& item) + { + detail::serialize_tuple(*this, item, std::index_sequence_for<_ValueTypes...>{}); + return *this; + } + + namespace detail + { + template + bool deserialize_variant(Message& msg, std::variant<_Elements...>& value, const char* signature) + { + constexpr auto elemSignature = as_null_terminated(sdbus::signature_of_v<_Element>); + if (std::strcmp(signature, elemSignature.data()) != 0) + return false; + + _Element temp; + msg.enterVariant(signature); + msg >> temp; + msg.exitVariant(); + value = std::move(temp); + return true; + } + } + + template + inline Message& Message::operator>>(std::variant& value) + { + auto [type, contents] = peekType(); + bool result = (detail::deserialize_variant(*this, value, contents) || ...); + SDBUS_THROW_ERROR_IF(!result, "Failed to deserialize variant: signature did not match any of the variant types", EINVAL); + return *this; + } + + template + inline Message& Message::operator>>(std::vector<_Element, _Allocator>& items) + { + deserializeArray(items); + + return *this; + } + + template + inline Message& Message::operator>>(std::array<_Element, _Size>& items) + { + deserializeArray(items); + + return *this; + } + +#ifdef __cpp_lib_span + template + inline Message& Message::operator>>(std::span<_Element, _Extent>& items) + { + deserializeArray(items); + + return *this; + } +#endif + + template + inline Message& Message::operator>>(_Enum& item) + { + std::underlying_type_t<_Enum> val; + *this >> val; + item = static_cast<_Enum>(val); + return *this; + } + + template + inline void Message::deserializeArray(_Array& items) + { + using ElementType = typename _Array::value_type; + + // Use faster, one-step deserialization of contiguous array of elements of trivial D-Bus types except bool, + // otherwise use step-by-step deserialization of individual elements. + if constexpr (signature_of::is_trivial_dbus_type && !std::is_same_v) + { + deserializeArrayFast(items); + } + else + { + deserializeArraySlow(items); + } + } + + template + inline void Message::deserializeArrayFast(_Array& items) + { + using ElementType = typename _Array::value_type; + + size_t arraySize{}; + const ElementType* arrayPtr{}; + + constexpr auto signature = as_null_terminated(sdbus::signature_of_v); + readArray(*signature.data(), (const void**)&arrayPtr, &arraySize); + + size_t elementsInMsg = arraySize / sizeof(ElementType); + bool notEnoughSpace = items.size() < elementsInMsg; + SDBUS_THROW_ERROR_IF(notEnoughSpace, "Failed to deserialize array: not enough space in destination sequence", EINVAL); + + std::copy_n(arrayPtr, elementsInMsg, items.begin()); + } + + template + void Message::deserializeArrayFast(std::vector<_Element, _Allocator>& items) + { + size_t arraySize{}; + const _Element* arrayPtr{}; + + constexpr auto signature = as_null_terminated(sdbus::signature_of_v<_Element>); + readArray(*signature.data(), (const void**)&arrayPtr, &arraySize); + + items.insert(items.end(), arrayPtr, arrayPtr + (arraySize / sizeof(_Element))); + } + + template + inline void Message::deserializeArraySlow(_Array& items) + { + using ElementType = typename _Array::value_type; + + if(!enterContainer()) + return; + + for (auto& elem : items) + if (!(*this >> elem)) + break; // Keep the rest in the destination sequence untouched + + SDBUS_THROW_ERROR_IF(!isAtEnd(false), "Failed to deserialize array: not enough space in destination sequence", EINVAL); + + clearFlags(); + + exitContainer(); + } + + template + void Message::deserializeArraySlow(std::vector<_Element, _Allocator>& items) + { + if(!enterContainer<_Element>()) + return; + + while (true) + { + _Element elem; + if (*this >> elem) + items.emplace_back(std::move(elem)); + else + break; + } + + clearFlags(); + + exitContainer(); + } + + template + inline Message& Message::operator>>(DictEntry<_Key, _Value>& value) + { + if (!enterDictEntry<_Key, _Value>()) + return *this; + *this >> value.first >> value.second; + exitDictEntry(); + + return *this; + } + + template + inline Message& Message::operator>>(std::map<_Key, _Value, _Compare, _Allocator>& items) + { + deserializeDictionary<_Key, _Value>([&items](auto dictEntry){ items.insert(std::move(dictEntry)); }); + + return *this; + } + + template + inline Message& Message::operator>>(std::unordered_map<_Key, _Value, _Hash, _KeyEqual, _Allocator>& items) + { + deserializeDictionary<_Key, _Value>([&items](auto dictEntry){ items.insert(std::move(dictEntry)); }); + + return *this; + } + + template + inline Message& Message::deserializeDictionary(const _Callback& callback) + { + if (!enterContainer>()) + return *this; + + while (true) + { + DictEntry<_Key, _Value> dictEntry; + *this >> dictEntry; + if (!*this) + break; + callback(std::move(dictEntry)); + } + clearFlags(); + + exitContainer(); + + return *this; + } + + namespace detail + { + template + void deserialize_pack(Message& msg, _Args&... args) + { + (void)(msg >> ... >> args); + } + + template + void deserialize_tuple( Message& msg + , _Tuple& t + , std::index_sequence<_Is...> ) + { + deserialize_pack(msg, std::get<_Is>(t)...); + } + } + + template + inline Message& Message::operator>>(Struct<_ValueTypes...>& item) + { + if (!enterStruct<_ValueTypes...>()) + return *this; + + detail::deserialize_tuple(*this, item, std::index_sequence_for<_ValueTypes...>{}); + + exitStruct(); + + return *this; + } + + template + inline Message& Message::operator>>(std::tuple<_ValueTypes...>& item) + { + detail::deserialize_tuple(*this, item, std::index_sequence_for<_ValueTypes...>{}); + return *this; + } + + template + inline Message& Message::openContainer() + { + constexpr auto signature = as_null_terminated(signature_of_v<_ElementType>); + return openContainer(signature.data()); + } + + template + inline Message& Message::openDictEntry() + { + constexpr auto signature = as_null_terminated(signature_of_v>); + return openDictEntry(signature.data()); + } + + template + inline Message& Message::openVariant() + { + constexpr auto signature = as_null_terminated(signature_of_v<_ValueType>); + return openVariant(signature.data()); + } + + template + inline Message& Message::openStruct() + { + constexpr auto signature = as_null_terminated(signature_of_v>); + return openStruct(signature.data()); + } + + template + inline Message& Message::enterContainer() + { + constexpr auto signature = as_null_terminated(signature_of_v<_ElementType>); + return enterContainer(signature.data()); + } + + template + inline Message& Message::enterDictEntry() + { + constexpr auto signature = as_null_terminated(signature_of_v>); + return enterDictEntry(signature.data()); + } + + template + inline Message& Message::enterVariant() + { + constexpr auto signature = as_null_terminated(signature_of_v<_ValueType>); + return enterVariant(signature.data()); + } + + template + inline Message& Message::enterStruct() + { + constexpr auto signature = as_null_terminated(signature_of_v>); + return enterStruct(signature.data()); + } + +} + +#endif /* SDBUS_CXX_MESSAGE_H_ */ diff --git a/3rdParty/sdbus-cpp/include/sdbus-c++/MethodResult.h b/3rdParty/sdbus-cpp/include/sdbus-c++/MethodResult.h new file mode 100644 index 0000000000..d6f8540f01 --- /dev/null +++ b/3rdParty/sdbus-cpp/include/sdbus-c++/MethodResult.h @@ -0,0 +1,93 @@ +/** + * (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland + * (C) 2016 - 2024 Stanislav Angelovic + * + * @file MethodResult.h + * + * Created on: Nov 8, 2016 + * Project: sdbus-c++ + * Description: High-level D-Bus IPC C++ library based on sd-bus + * + * This file is part of sdbus-c++. + * + * sdbus-c++ is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 of the License, or + * (at your option) any later version. + * + * sdbus-c++ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with sdbus-c++. If not, see . + */ + +#ifndef SDBUS_CXX_METHODRESULT_H_ +#define SDBUS_CXX_METHODRESULT_H_ + +#include + +#include + +// Forward declarations +namespace sdbus { + class Error; +} + +namespace sdbus { + + /********************************************//** + * @class Result + * + * Represents result of an asynchronous server-side method. + * An instance is provided to the method and shall be set + * by the method to either method return value or an error. + * + ***********************************************/ + template + class Result + { + public: + Result() = default; + Result(MethodCall call); + + Result(const Result&) = delete; + Result& operator=(const Result&) = delete; + + Result(Result&& other) = default; + Result& operator=(Result&& other) = default; + + void returnResults(const _Results&... results) const; + void returnError(const Error& error) const; + + private: + MethodCall call_; + }; + + template + inline Result<_Results...>::Result(MethodCall call) + : call_(std::move(call)) + { + } + + template + inline void Result<_Results...>::returnResults(const _Results&... results) const + { + assert(call_.isValid()); + auto reply = call_.createReply(); + (void)(reply << ... << results); + reply.send(); + } + + template + inline void Result<_Results...>::returnError(const Error& error) const + { + auto reply = call_.createErrorReply(error); + reply.send(); + } + +} + +#endif /* SDBUS_CXX_METHODRESULT_H_ */ diff --git a/3rdParty/sdbus-cpp/include/sdbus-c++/ProxyInterfaces.h b/3rdParty/sdbus-cpp/include/sdbus-c++/ProxyInterfaces.h new file mode 100644 index 0000000000..72f25c6be4 --- /dev/null +++ b/3rdParty/sdbus-cpp/include/sdbus-c++/ProxyInterfaces.h @@ -0,0 +1,217 @@ +/** + * (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland + * (C) 2016 - 2024 Stanislav Angelovic + * + * @file ProxyInterfaces.h + * + * Created on: Apr 8, 2019 + * Project: sdbus-c++ + * Description: High-level D-Bus IPC C++ library based on sd-bus + * + * This file is part of sdbus-c++. + * + * sdbus-c++ is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 of the License, or + * (at your option) any later version. + * + * sdbus-c++ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with sdbus-c++. If not, see . + */ + +#ifndef SDBUS_CXX_PROXYINTERFACES_H_ +#define SDBUS_CXX_PROXYINTERFACES_H_ + +#include +#include +#include +#include + +// Forward declarations +namespace sdbus { + class IConnection; +} + +namespace sdbus { + + /********************************************//** + * @class ProxyObjectHolder + * + * ProxyObjectHolder is a helper that simply owns and provides + * access to a proxy object to other classes in the inheritance + * hierarchy of a native-like proxy object based on generated + * interface classes. + * + ***********************************************/ + class ProxyObjectHolder + { + protected: + ProxyObjectHolder(std::unique_ptr&& proxy) + : proxy_(std::move(proxy)) + { + assert(proxy_ != nullptr); + } + + const IProxy& getProxy() const + { + assert(proxy_ != nullptr); + return *proxy_; + } + + IProxy& getProxy() + { + assert(proxy_ != nullptr); + return *proxy_; + } + + private: + std::unique_ptr proxy_; + }; + + /********************************************//** + * @class ProxyInterfaces + * + * ProxyInterfaces is a helper template class that joins all interface classes of a remote + * D-Bus object generated by sdbus-c++-xml2cpp to be used on the client (the proxy) side, + * including some auxiliary classes. ProxyInterfaces is the class that native-like proxy + * implementation classes written by users should inherit from and implement all pure virtual + * methods. So the _Interfaces template parameter is a list of sdbus-c++-xml2cpp-generated + * proxy-side interface classes representing interfaces of the corresponding remote D-Bus object. + * + * In the final adaptor class inherited from ProxyInterfaces, one needs to make sure: + * 1. to call `registerProxy();` in the class constructor, and, conversely, + * 2. to call `unregisterProxy();` in the class destructor, + * so that the signals are subscribed to and unsubscribed from at a proper time. + * + ***********************************************/ + template + class ProxyInterfaces + : protected ProxyObjectHolder + , public _Interfaces... + { + public: + /*! + * @brief Creates native-like proxy object instance + * + * @param[in] destination Bus name that provides a D-Bus object + * @param[in] objectPath Path of the D-Bus object + * + * This constructor overload creates a proxy that manages its own D-Bus connection(s). + * For more information on its behavior, consult @ref createProxy(std::string,std::string) + */ + ProxyInterfaces(ServiceName destination, ObjectPath objectPath) + : ProxyObjectHolder(createProxy(std::move(destination), std::move(objectPath))) + , _Interfaces(getProxy())... + { + } + + /*! + * @brief Creates native-like proxy object instance + * + * @param[in] destination Bus name that provides a D-Bus object + * @param[in] objectPath Path of the D-Bus object + * + * This constructor overload creates a proxy that manages its own D-Bus connection(s). + * For more information on its behavior, consult @ref createProxy(std::string,std::string,sdbus::dont_run_event_loop_thread_t) + */ + ProxyInterfaces(ServiceName destination, ObjectPath objectPath, dont_run_event_loop_thread_t) + : ProxyObjectHolder(createProxy(std::move(destination), std::move(objectPath), dont_run_event_loop_thread)) + , _Interfaces(getProxy())... + { + } + + /*! + * @brief Creates native-like proxy object instance + * + * @param[in] connection D-Bus connection to be used by the proxy object + * @param[in] destination Bus name that provides a D-Bus object + * @param[in] objectPath Path of the D-Bus object + * + * The proxy created this way just references a D-Bus connection owned and managed by the user. + * For more information on its behavior, consult @ref createProxy(IConnection&,std::string,std::string) + */ + ProxyInterfaces(IConnection& connection, ServiceName destination, ObjectPath objectPath) + : ProxyObjectHolder(createProxy(connection, std::move(destination), std::move(objectPath))) + , _Interfaces(getProxy())... + { + } + + /*! + * @brief Creates native-like proxy object instance + * + * @param[in] connection D-Bus connection to be used by the proxy object + * @param[in] destination Bus name that provides a D-Bus object + * @param[in] objectPath Path of the D-Bus object + * + * The proxy created this way becomes an owner of the connection. + * For more information on its behavior, consult @ref createProxy(std::unique_ptr&&,std::string,std::string) + */ + ProxyInterfaces(std::unique_ptr&& connection, ServiceName destination, ObjectPath objectPath) + : ProxyObjectHolder(createProxy(std::move(connection), std::move(destination), std::move(objectPath))) + , _Interfaces(getProxy())... + { + } + + /*! + * @brief Creates native-like proxy object instance + * + * @param[in] connection D-Bus connection to be used by the proxy object + * @param[in] destination Bus name that provides a D-Bus object + * @param[in] objectPath Path of the D-Bus object + * + * The proxy created this way becomes an owner of the connection. + * For more information on its behavior, consult @ref createProxy(std::unique_ptr&&,std::string,std::string,sdbus::dont_run_event_loop_thread_t) + */ + ProxyInterfaces(std::unique_ptr&& connection, ServiceName destination, ObjectPath objectPath, dont_run_event_loop_thread_t) + : ProxyObjectHolder(createProxy(std::move(connection), std::move(destination), std::move(objectPath), dont_run_event_loop_thread)) + , _Interfaces(getProxy())... + { + } + + /*! + * @brief Registers handlers for D-Bus signals of the remote object + * + * This function must be called in the constructor of the final proxy class that implements ProxyInterfaces. + * + * See also @ref IProxy::registerSignalHandler() + */ + void registerProxy() + { + (_Interfaces::registerProxy(), ...); + } + + /*! + * @brief Unregisters the proxy so it no more receives signals and async call replies + * + * This function must be called in the destructor of the final proxy class that implements ProxyInterfaces. + * + * See underlying @ref IProxy::unregister() + */ + void unregisterProxy() + { + getProxy().unregister(); + } + + /*! + * @brief Returns reference to the underlying IProxy instance + */ + using ProxyObjectHolder::getProxy; + + protected: + using base_type = ProxyInterfaces; + + ProxyInterfaces(const ProxyInterfaces&) = delete; + ProxyInterfaces& operator=(const ProxyInterfaces&) = delete; + ProxyInterfaces(ProxyInterfaces&&) = delete; + ProxyInterfaces& operator=(ProxyInterfaces&&) = delete; + ~ProxyInterfaces() = default; + }; + +} + +#endif /* SDBUS_CXX_INTERFACES_H_ */ diff --git a/3rdParty/sdbus-cpp/include/sdbus-c++/StandardInterfaces.h b/3rdParty/sdbus-cpp/include/sdbus-c++/StandardInterfaces.h new file mode 100644 index 0000000000..83007b0ec9 --- /dev/null +++ b/3rdParty/sdbus-cpp/include/sdbus-c++/StandardInterfaces.h @@ -0,0 +1,530 @@ +/** + * (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland + * (C) 2016 - 2024 Stanislav Angelovic + * + * @file StandardInterfaces.h + * + * Created on: Dec 13, 2016 + * Project: sdbus-c++ + * Description: High-level D-Bus IPC C++ library based on sd-bus + * + * This file is part of sdbus-c++. + * + * sdbus-c++ is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 of the License, or + * (at your option) any later version. + * + * sdbus-c++ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with sdbus-c++. If not, see . + */ + +#ifndef SDBUS_CXX_STANDARDINTERFACES_H_ +#define SDBUS_CXX_STANDARDINTERFACES_H_ + +#include +#include +#include +#include +#include +#include +#include + +namespace sdbus { + + // Proxy for peer + class Peer_proxy + { + static inline const char* INTERFACE_NAME = "org.freedesktop.DBus.Peer"; + + protected: + Peer_proxy(sdbus::IProxy& proxy) + : m_proxy(proxy) + { + } + + Peer_proxy(const Peer_proxy&) = delete; + Peer_proxy& operator=(const Peer_proxy&) = delete; + Peer_proxy(Peer_proxy&&) = delete; + Peer_proxy& operator=(Peer_proxy&&) = delete; + + ~Peer_proxy() = default; + + void registerProxy() + { + } + + public: + void Ping() + { + m_proxy.callMethod("Ping").onInterface(INTERFACE_NAME); + } + + std::string GetMachineId() + { + std::string machineUUID; + m_proxy.callMethod("GetMachineId").onInterface(INTERFACE_NAME).storeResultsTo(machineUUID); + return machineUUID; + } + + private: + sdbus::IProxy& m_proxy; + }; + + // Proxy for introspection + class Introspectable_proxy + { + static inline const char* INTERFACE_NAME = "org.freedesktop.DBus.Introspectable"; + + protected: + Introspectable_proxy(sdbus::IProxy& proxy) + : m_proxy(proxy) + { + } + + Introspectable_proxy(const Introspectable_proxy&) = delete; + Introspectable_proxy& operator=(const Introspectable_proxy&) = delete; + Introspectable_proxy(Introspectable_proxy&&) = delete; + Introspectable_proxy& operator=(Introspectable_proxy&&) = delete; + + ~Introspectable_proxy() = default; + + void registerProxy() + { + } + + public: + std::string Introspect() + { + std::string xml; + m_proxy.callMethod("Introspect").onInterface(INTERFACE_NAME).storeResultsTo(xml); + return xml; + } + + private: + sdbus::IProxy& m_proxy; + }; + + // Proxy for properties + class Properties_proxy + { + static inline const char* INTERFACE_NAME = "org.freedesktop.DBus.Properties"; + + protected: + Properties_proxy(sdbus::IProxy& proxy) + : m_proxy(proxy) + { + } + + Properties_proxy(const Properties_proxy&) = delete; + Properties_proxy& operator=(const Properties_proxy&) = delete; + Properties_proxy(Properties_proxy&&) = delete; + Properties_proxy& operator=(Properties_proxy&&) = delete; + + ~Properties_proxy() = default; + + void registerProxy() + { + m_proxy + .uponSignal("PropertiesChanged") + .onInterface(INTERFACE_NAME) + .call([this]( const InterfaceName& interfaceName + , const std::map& changedProperties + , const std::vector& invalidatedProperties ) + { + this->onPropertiesChanged(interfaceName, changedProperties, invalidatedProperties); + }); + } + + virtual void onPropertiesChanged( const InterfaceName& interfaceName + , const std::map& changedProperties + , const std::vector& invalidatedProperties ) = 0; + + public: + sdbus::Variant Get(const InterfaceName& interfaceName, const PropertyName& propertyName) + { + return m_proxy.getProperty(propertyName).onInterface(interfaceName); + } + + sdbus::Variant Get(std::string_view interfaceName, std::string_view propertyName) + { + return m_proxy.getProperty(propertyName).onInterface(interfaceName); + } + + template + PendingAsyncCall GetAsync(const InterfaceName& interfaceName, const PropertyName& propertyName, _Function&& callback) + { + return m_proxy.getPropertyAsync(propertyName).onInterface(interfaceName).uponReplyInvoke(std::forward<_Function>(callback)); + } + + template + [[nodiscard]] Slot GetAsync(const InterfaceName& interfaceName, const PropertyName& propertyName, _Function&& callback, return_slot_t) + { + return m_proxy.getPropertyAsync(propertyName).onInterface(interfaceName).uponReplyInvoke(std::forward<_Function>(callback), return_slot); + } + + std::future GetAsync(const InterfaceName& interfaceName, const PropertyName& propertyName, with_future_t) + { + return m_proxy.getPropertyAsync(propertyName).onInterface(interfaceName).getResultAsFuture(); + } + + template + PendingAsyncCall GetAsync(std::string_view interfaceName, std::string_view propertyName, _Function&& callback) + { + return m_proxy.getPropertyAsync(propertyName).onInterface(interfaceName).uponReplyInvoke(std::forward<_Function>(callback)); + } + + template + [[nodiscard]] Slot GetAsync(std::string_view interfaceName, std::string_view propertyName, _Function&& callback, return_slot_t) + { + return m_proxy.getPropertyAsync(propertyName).onInterface(interfaceName).uponReplyInvoke(std::forward<_Function>(callback), return_slot); + } + + std::future GetAsync(std::string_view interfaceName, std::string_view propertyName, with_future_t) + { + return m_proxy.getPropertyAsync(propertyName).onInterface(interfaceName).getResultAsFuture(); + } + + void Set(const InterfaceName& interfaceName, const PropertyName& propertyName, const sdbus::Variant& value) + { + m_proxy.setProperty(propertyName).onInterface(interfaceName).toValue(value); + } + + void Set(std::string_view interfaceName, const std::string_view propertyName, const sdbus::Variant& value) + { + m_proxy.setProperty(propertyName).onInterface(interfaceName).toValue(value); + } + + void Set(const InterfaceName& interfaceName, const PropertyName& propertyName, const sdbus::Variant& value, dont_expect_reply_t) + { + m_proxy.setProperty(propertyName).onInterface(interfaceName).toValue(value, dont_expect_reply); + } + + void Set(std::string_view interfaceName, const std::string_view propertyName, const sdbus::Variant& value, dont_expect_reply_t) + { + m_proxy.setProperty(propertyName).onInterface(interfaceName).toValue(value, dont_expect_reply); + } + + template + PendingAsyncCall SetAsync(const InterfaceName& interfaceName, const PropertyName& propertyName, const sdbus::Variant& value, _Function&& callback) + { + return m_proxy.setPropertyAsync(propertyName).onInterface(interfaceName).toValue(value).uponReplyInvoke(std::forward<_Function>(callback)); + } + + template + [[nodiscard]] Slot SetAsync(const InterfaceName& interfaceName, const PropertyName& propertyName, const sdbus::Variant& value, _Function&& callback, return_slot_t) + { + return m_proxy.setPropertyAsync(propertyName).onInterface(interfaceName).toValue(value).uponReplyInvoke(std::forward<_Function>(callback), return_slot); + } + + std::future SetAsync(const InterfaceName& interfaceName, const PropertyName& propertyName, const sdbus::Variant& value, with_future_t) + { + return m_proxy.setPropertyAsync(propertyName).onInterface(interfaceName).toValue(value).getResultAsFuture(); + } + + template + PendingAsyncCall SetAsync(std::string_view interfaceName, std::string_view propertyName, const sdbus::Variant& value, _Function&& callback) + { + return m_proxy.setPropertyAsync(propertyName).onInterface(interfaceName).toValue(value).uponReplyInvoke(std::forward<_Function>(callback)); + } + + template + [[nodiscard]] Slot SetAsync(std::string_view interfaceName, std::string_view propertyName, const sdbus::Variant& value, _Function&& callback, return_slot_t) + { + return m_proxy.setPropertyAsync(propertyName).onInterface(interfaceName).toValue(value).uponReplyInvoke(std::forward<_Function>(callback), return_slot); + } + + std::future SetAsync(std::string_view interfaceName, std::string_view propertyName, const sdbus::Variant& value, with_future_t) + { + return m_proxy.setPropertyAsync(propertyName).onInterface(interfaceName).toValue(value).getResultAsFuture(); + } + + std::map GetAll(const InterfaceName& interfaceName) + { + return m_proxy.getAllProperties().onInterface(interfaceName); + } + + std::map GetAll(std::string_view interfaceName) + { + return m_proxy.getAllProperties().onInterface(interfaceName); + } + + template + PendingAsyncCall GetAllAsync(const InterfaceName& interfaceName, _Function&& callback) + { + return m_proxy.getAllPropertiesAsync().onInterface(interfaceName).uponReplyInvoke(std::forward<_Function>(callback)); + } + + template + [[nodiscard]] Slot GetAllAsync(const InterfaceName& interfaceName, _Function&& callback, return_slot_t) + { + return m_proxy.getAllPropertiesAsync().onInterface(interfaceName).uponReplyInvoke(std::forward<_Function>(callback), return_slot); + } + + std::future> GetAllAsync(const InterfaceName& interfaceName, with_future_t) + { + return m_proxy.getAllPropertiesAsync().onInterface(interfaceName).getResultAsFuture(); + } + + template + PendingAsyncCall GetAllAsync(std::string_view interfaceName, _Function&& callback) + { + return m_proxy.getAllPropertiesAsync().onInterface(interfaceName).uponReplyInvoke(std::forward<_Function>(callback)); + } + + template + [[nodiscard]] Slot GetAllAsync(std::string_view interfaceName, _Function&& callback, return_slot_t) + { + return m_proxy.getAllPropertiesAsync().onInterface(interfaceName).uponReplyInvoke(std::forward<_Function>(callback), return_slot); + } + + std::future> GetAllAsync(std::string_view interfaceName, with_future_t) + { + return m_proxy.getAllPropertiesAsync().onInterface(interfaceName).getResultAsFuture(); + } + + private: + sdbus::IProxy& m_proxy; + }; + + // Proxy for object manager + class ObjectManager_proxy + { + static inline const char* INTERFACE_NAME = "org.freedesktop.DBus.ObjectManager"; + + protected: + ObjectManager_proxy(sdbus::IProxy& proxy) + : m_proxy(proxy) + { + } + + ObjectManager_proxy(const ObjectManager_proxy&) = delete; + ObjectManager_proxy& operator=(const ObjectManager_proxy&) = delete; + ObjectManager_proxy(ObjectManager_proxy&&) = delete; + ObjectManager_proxy& operator=(ObjectManager_proxy&&) = delete; + + ~ObjectManager_proxy() = default; + + void registerProxy() + { + m_proxy + .uponSignal("InterfacesAdded") + .onInterface(INTERFACE_NAME) + .call([this]( const sdbus::ObjectPath& objectPath + , const std::map>& interfacesAndProperties ) + { + this->onInterfacesAdded(objectPath, interfacesAndProperties); + }); + + m_proxy + .uponSignal("InterfacesRemoved") + .onInterface(INTERFACE_NAME) + .call([this]( const sdbus::ObjectPath& objectPath + , const std::vector& interfaces ) + { + this->onInterfacesRemoved(objectPath, interfaces); + }); + } + + virtual void onInterfacesAdded( const sdbus::ObjectPath& objectPath + , const std::map>& interfacesAndProperties) = 0; + virtual void onInterfacesRemoved( const sdbus::ObjectPath& objectPath + , const std::vector& interfaces) = 0; + + public: + std::map>> GetManagedObjects() + { + std::map>> objectsInterfacesAndProperties; + m_proxy.callMethod("GetManagedObjects").onInterface(INTERFACE_NAME).storeResultsTo(objectsInterfacesAndProperties); + return objectsInterfacesAndProperties; + } + + template + PendingAsyncCall GetManagedObjectsAsync(_Function&& callback) + { + return m_proxy.callMethodAsync("GetManagedObjects").onInterface(INTERFACE_NAME).uponReplyInvoke(std::forward<_Function>(callback)); + } + + template + [[nodiscard]] Slot GetManagedObjectsAsync(_Function&& callback, return_slot_t) + { + return m_proxy.callMethodAsync("GetManagedObjects").onInterface(INTERFACE_NAME).uponReplyInvoke(std::forward<_Function>(callback), return_slot); + } + + std::future>>> GetManagedObjectsAsync(with_future_t) + { + return m_proxy.callMethodAsync("GetManagedObjects").onInterface(INTERFACE_NAME).getResultAsFuture>>>(); + } + + private: + sdbus::IProxy& m_proxy; + }; + + // Adaptors for the above-listed standard D-Bus interfaces are not necessary because the functionality + // is provided by underlying libsystemd implementation. The exception is Properties_adaptor, + // ObjectManager_adaptor and ManagedObject_adaptor, which provide convenience functionality to emit signals. + + // Adaptor for properties + class Properties_adaptor + { + static inline const char* INTERFACE_NAME = "org.freedesktop.DBus.Properties"; + + protected: + Properties_adaptor(sdbus::IObject& object) : m_object(object) + { + } + + Properties_adaptor(const Properties_adaptor&) = delete; + Properties_adaptor& operator=(const Properties_adaptor&) = delete; + Properties_adaptor(Properties_adaptor&&) = delete; + Properties_adaptor& operator=(Properties_adaptor&&) = delete; + + ~Properties_adaptor() = default; + + void registerAdaptor() + { + } + + public: + void emitPropertiesChangedSignal(const InterfaceName& interfaceName, const std::vector& properties) + { + m_object.emitPropertiesChangedSignal(interfaceName, properties); + } + + void emitPropertiesChangedSignal(const char* interfaceName, const std::vector& properties) + { + m_object.emitPropertiesChangedSignal(interfaceName, properties); + } + + void emitPropertiesChangedSignal(const InterfaceName& interfaceName) + { + m_object.emitPropertiesChangedSignal(interfaceName); + } + + void emitPropertiesChangedSignal(const char* interfaceName) + { + m_object.emitPropertiesChangedSignal(interfaceName); + } + + private: + sdbus::IObject& m_object; + }; + + /*! + * @brief Object Manager Convenience Adaptor + * + * Adding this class as _Interfaces.. template parameter of class AdaptorInterfaces + * implements the *GetManagedObjects()* method of the [org.freedesktop.DBus.ObjectManager.GetManagedObjects](https://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-objectmanager) + * interface. + * + * Note that there can be multiple object managers in a path hierarchy. InterfacesAdded/InterfacesRemoved + * signals are sent from the closest object manager at either the same path or the closest parent path of an object. + */ + class ObjectManager_adaptor + { + static inline const char* INTERFACE_NAME = "org.freedesktop.DBus.ObjectManager"; + + protected: + explicit ObjectManager_adaptor(sdbus::IObject& object) : m_object(object) + { + } + + ObjectManager_adaptor(const ObjectManager_adaptor&) = delete; + ObjectManager_adaptor& operator=(const ObjectManager_adaptor&) = delete; + ObjectManager_adaptor(ObjectManager_adaptor&&) = delete; + ObjectManager_adaptor& operator=(ObjectManager_adaptor&&) = delete; + + ~ObjectManager_adaptor() = default; + + void registerAdaptor() + { + m_object.addObjectManager(); + } + + private: + sdbus::IObject& m_object; + }; + + /*! + * @brief Managed Object Convenience Adaptor + * + * Adding this class as _Interfaces.. template parameter of class AdaptorInterfaces + * will extend the resulting object adaptor with emitInterfacesAddedSignal()/emitInterfacesRemovedSignal() + * according to org.freedesktop.DBus.ObjectManager.InterfacesAdded/.InterfacesRemoved. + * + * Note that objects which implement this adaptor require an object manager (e.g via ObjectManager_adaptor) to be + * instantiated on one of it's parent object paths or the same path. InterfacesAdded/InterfacesRemoved + * signals are sent from the closest object manager at either the same path or the closest parent path of an object. + */ + class ManagedObject_adaptor + { + protected: + explicit ManagedObject_adaptor(sdbus::IObject& object) + : m_object(object) + { + } + + ManagedObject_adaptor(const ManagedObject_adaptor&) = delete; + ManagedObject_adaptor& operator=(const ManagedObject_adaptor&) = delete; + ManagedObject_adaptor(ManagedObject_adaptor&&) = delete; + ManagedObject_adaptor& operator=(ManagedObject_adaptor&&) = delete; + + ~ManagedObject_adaptor() = default; + + void registerAdaptor() + { + } + + public: + /*! + * @brief Emits InterfacesAdded signal for this object path + * + * See IObject::emitInterfacesAddedSignal(). + */ + void emitInterfacesAddedSignal() + { + m_object.emitInterfacesAddedSignal(); + } + + /*! + * @brief Emits InterfacesAdded signal for this object path + * + * See IObject::emitInterfacesAddedSignal(). + */ + void emitInterfacesAddedSignal(const std::vector& interfaces) + { + m_object.emitInterfacesAddedSignal(interfaces); + } + + /*! + * @brief Emits InterfacesRemoved signal for this object path + * + * See IObject::emitInterfacesRemovedSignal(). + */ + void emitInterfacesRemovedSignal() + { + m_object.emitInterfacesRemovedSignal(); + } + + /*! + * @brief Emits InterfacesRemoved signal for this object path + * + * See IObject::emitInterfacesRemovedSignal(). + */ + void emitInterfacesRemovedSignal(const std::vector& interfaces) + { + m_object.emitInterfacesRemovedSignal(interfaces); + } + + private: + sdbus::IObject& m_object; + }; + +} + +#endif /* SDBUS_CXX_STANDARDINTERFACES_H_ */ diff --git a/3rdParty/sdbus-cpp/include/sdbus-c++/TypeTraits.h b/3rdParty/sdbus-cpp/include/sdbus-c++/TypeTraits.h new file mode 100644 index 0000000000..e9143fa640 --- /dev/null +++ b/3rdParty/sdbus-cpp/include/sdbus-c++/TypeTraits.h @@ -0,0 +1,702 @@ +/** + * (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland + * (C) 2016 - 2024 Stanislav Angelovic + * + * @file TypeTraits.h + * + * Created on: Nov 9, 2016 + * Project: sdbus-c++ + * Description: High-level D-Bus IPC C++ library based on sd-bus + * + * This file is part of sdbus-c++. + * + * sdbus-c++ is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 of the License, or + * (at your option) any later version. + * + * sdbus-c++ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with sdbus-c++. If not, see . + */ + +#ifndef SDBUS_CXX_TYPETRAITS_H_ +#define SDBUS_CXX_TYPETRAITS_H_ + +#include + +#include +#include +#include +#include +#include +#include +#ifdef __has_include +# if __has_include() +# include +# endif +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +// Forward declarations +namespace sdbus { + class Variant; + template class Struct; + class ObjectPath; + class Signature; + class UnixFd; + template using DictEntry = std::pair<_T1, _T2>; + class BusName; + class InterfaceName; + class MemberName; + class MethodCall; + class MethodReply; + class Signal; + class Message; + class PropertySetCall; + class PropertyGetReply; + template class Result; + class Error; + template struct signature_of; +} + +namespace sdbus { + + // Callbacks from sdbus-c++ + using method_callback = std::function; + using async_reply_handler = std::function error)>; + using signal_handler = std::function; + using message_handler = std::function; + using property_set_callback = std::function; + using property_get_callback = std::function; + + // Type-erased RAII-style handle to callbacks/subscriptions registered to sdbus-c++ + using Slot = std::unique_ptr>; + + // Tag specifying that an owning handle (so-called slot) of the logical resource shall be provided to the client + struct return_slot_t { explicit return_slot_t() = default; }; + inline constexpr return_slot_t return_slot{}; + // Tag specifying that the library shall own the slot resulting from the call of the function (so-called floating slot) + struct floating_slot_t { explicit floating_slot_t() = default; }; + inline constexpr floating_slot_t floating_slot{}; + // Tag denoting the assumption that the caller has already obtained message ownership + struct adopt_message_t { explicit adopt_message_t() = default; }; + inline constexpr adopt_message_t adopt_message{}; + // Tag denoting the assumption that the caller has already obtained fd ownership + struct adopt_fd_t { explicit adopt_fd_t() = default; }; + inline constexpr adopt_fd_t adopt_fd{}; + // Tag specifying that the proxy shall not run an event loop thread on its D-Bus connection. + // Such proxies are typically created to carry out a simple synchronous D-Bus call(s) and then are destroyed. + struct dont_run_event_loop_thread_t { explicit dont_run_event_loop_thread_t() = default; }; + inline constexpr dont_run_event_loop_thread_t dont_run_event_loop_thread{}; + // Tag denoting an asynchronous call that returns std::future as a handle + struct with_future_t { explicit with_future_t() = default; }; + inline constexpr with_future_t with_future{}; + // Tag denoting a call where the reply shouldn't be waited for + struct dont_expect_reply_t { explicit dont_expect_reply_t() = default; }; + inline constexpr dont_expect_reply_t dont_expect_reply{}; + // Tag denoting that the variant shall embed the other variant as its value, instead of creating a copy + struct embed_variant_t { explicit embed_variant_t() = default; }; + inline constexpr embed_variant_t embed_variant{}; + + // Helper for static assert + template constexpr bool always_false = false; + + // Helper operator+ for concatenation of `std::array`s + template + constexpr std::array<_T, _N1 + _N2> operator+(std::array<_T, _N1> lhs, std::array<_T, _N2> rhs); + + // Template specializations for getting D-Bus signatures from C++ types + template + constexpr auto signature_of_v = signature_of<_T>::value; + + template + struct signature_of + { + static constexpr bool is_valid = false; + static constexpr bool is_trivial_dbus_type = false; + + static constexpr void* value = [] + { + // See using-sdbus-c++.md, section "Extending sdbus-c++ type system", + // on how to teach sdbus-c++ about your custom types + static_assert(always_false<_T>, "Unsupported D-Bus type (specialize `signature_of` for your custom types)"); + }; + }; + + template + struct signature_of : signature_of<_T> + {}; + + template + struct signature_of : signature_of<_T> + {}; + + template + struct signature_of : signature_of<_T> + {}; + + template + struct signature_of<_T&> : signature_of<_T> + {}; + + template + struct signature_of<_T&&> : signature_of<_T> + {}; + + template <> + struct signature_of + { + static constexpr std::array value{}; + static constexpr bool is_valid = true; + static constexpr bool is_trivial_dbus_type = false; + }; + + template <> + struct signature_of + { + static constexpr std::array value{'b'}; + static constexpr bool is_valid = true; + static constexpr bool is_trivial_dbus_type = true; + }; + + template <> + struct signature_of + { + static constexpr std::array value{'y'}; + static constexpr bool is_valid = true; + static constexpr bool is_trivial_dbus_type = true; + }; + + template <> + struct signature_of + { + static constexpr std::array value{'n'}; + static constexpr bool is_valid = true; + static constexpr bool is_trivial_dbus_type = true; + }; + + template <> + struct signature_of + { + static constexpr std::array value{'q'}; + static constexpr bool is_valid = true; + static constexpr bool is_trivial_dbus_type = true; + }; + + template <> + struct signature_of + { + static constexpr std::array value{'i'}; + static constexpr bool is_valid = true; + static constexpr bool is_trivial_dbus_type = true; + }; + + template <> + struct signature_of + { + static constexpr std::array value{'u'}; + static constexpr bool is_valid = true; + static constexpr bool is_trivial_dbus_type = true; + }; + + template <> + struct signature_of + { + static constexpr std::array value{'x'}; + static constexpr bool is_valid = true; + static constexpr bool is_trivial_dbus_type = true; + }; + + template <> + struct signature_of + { + static constexpr std::array value{'t'}; + static constexpr bool is_valid = true; + static constexpr bool is_trivial_dbus_type = true; + }; + + template <> + struct signature_of + { + static constexpr std::array value{'d'}; + static constexpr bool is_valid = true; + static constexpr bool is_trivial_dbus_type = true; + }; + + template <> + struct signature_of + { + static constexpr std::array value{'s'}; + static constexpr bool is_valid = true; + static constexpr bool is_trivial_dbus_type = false; + }; + + template <> + struct signature_of : signature_of + {}; + + template <> + struct signature_of : signature_of + {}; + + template <> + struct signature_of : signature_of + {}; + + template + struct signature_of : signature_of + {}; + + template + struct signature_of : signature_of + {}; + + template <> + struct signature_of : signature_of + {}; + + template <> + struct signature_of : signature_of + {}; + + template <> + struct signature_of : signature_of + {}; + + template + struct signature_of> + { + static constexpr std::array contents = (signature_of_v<_ValueTypes> + ...); + static constexpr std::array value = std::array{'('} + contents + std::array{')'}; + static constexpr char type_value{'r'}; /* Not actually used in signatures on D-Bus, see specs */ + static constexpr bool is_valid = true; + static constexpr bool is_trivial_dbus_type = false; + }; + + template <> + struct signature_of + { + static constexpr std::array value{'v'}; + static constexpr bool is_valid = true; + static constexpr bool is_trivial_dbus_type = false; + }; + + template + struct signature_of> : signature_of + {}; + + template <> + struct signature_of + { + static constexpr std::array value{'o'}; + static constexpr bool is_valid = true; + static constexpr bool is_trivial_dbus_type = false; + }; + + template <> + struct signature_of + { + static constexpr std::array value{'g'}; + static constexpr bool is_valid = true; + static constexpr bool is_trivial_dbus_type = false; + }; + + template <> + struct signature_of + { + static constexpr std::array value{'h'}; + static constexpr bool is_valid = true; + static constexpr bool is_trivial_dbus_type = false; + }; + + template + struct signature_of> + { + static constexpr std::array value = std::array{'{'} + signature_of_v> + std::array{'}'}; + static constexpr char type_value{'e'}; /* Not actually used in signatures on D-Bus, see specs */ + static constexpr bool is_valid = true; + static constexpr bool is_trivial_dbus_type = false; + }; + + template + struct signature_of> + { + static constexpr std::array value = std::array{'a'} + signature_of_v<_Element>; + static constexpr bool is_valid = true; + static constexpr bool is_trivial_dbus_type = false; + }; + + template + struct signature_of> : signature_of> + { + }; + +#ifdef __cpp_lib_span + template + struct signature_of> : signature_of> + { + }; +#endif + + template // is_const_v and is_volatile_v to avoid ambiguity conflicts with const and volatile specializations of signature_of + struct signature_of<_Enum, typename std::enable_if_t && !std::is_const_v<_Enum> && !std::is_volatile_v<_Enum>>> + : signature_of> + {}; + + template + struct signature_of> + { + static constexpr std::array value = std::array{'a'} + signature_of_v>; + static constexpr bool is_valid = true; + static constexpr bool is_trivial_dbus_type = false; + }; + + template + struct signature_of> + : signature_of> + { + }; + + template + struct signature_of> // A simple concatenation of signatures of _Types + { + static constexpr std::array value = (std::array{} + ... + signature_of_v<_Types>); + static constexpr bool is_valid = false; + static constexpr bool is_trivial_dbus_type = false; + }; + + // To simplify conversions of arrays to C strings + template + constexpr auto as_null_terminated(std::array<_T, _N> arr) + { + return arr + std::array<_T, 1>{0}; + } + + // Function traits implementation inspired by (c) kennytm, + // https://github.com/kennytm/utils/blob/master/traits.hpp + template + struct function_traits : function_traits + {}; + + template + struct function_traits : function_traits<_Type> + {}; + + template + struct function_traits<_Type&> : function_traits<_Type> + {}; + + template + struct function_traits_base + { + typedef _ReturnType result_type; + typedef std::tuple<_Args...> arguments_type; + typedef std::tuple...> decayed_arguments_type; + + typedef _ReturnType function_type(_Args...); + + static constexpr std::size_t arity = sizeof...(_Args); + +// template +// struct arg; +// +// template +// struct arg<_Idx, std::enable_if_t<(_Idx < arity)>> +// { +// typedef std::tuple_element_t<_Idx, arguments_type> type; +// }; +// +// template +// struct arg<_Idx, std::enable_if_t> +// { +// typedef void type; +// }; + + template + struct arg + { + typedef std::tuple_element_t<_Idx, std::tuple<_Args...>> type; + }; + + template + using arg_t = typename arg<_Idx>::type; + }; + + template + struct function_traits<_ReturnType(_Args...)> : function_traits_base<_ReturnType, _Args...> + { + static constexpr bool is_async = false; + static constexpr bool has_error_param = false; + }; + + template + struct function_traits, _Args...)> : function_traits_base + { + static constexpr bool has_error_param = true; + }; + + template + struct function_traits, _Args...)> : function_traits_base, _Args...> + { + static constexpr bool is_async = true; + using async_result_t = Result<_Results...>; + }; + + template + struct function_traits&&, _Args...)> : function_traits_base, _Args...> + { + static constexpr bool is_async = true; + using async_result_t = Result<_Results...>; + }; + + template + struct function_traits<_ReturnType(*)(_Args...)> : function_traits<_ReturnType(_Args...)> + {}; + + template + struct function_traits<_ReturnType(_ClassType::*)(_Args...)> : function_traits<_ReturnType(_Args...)> + { + typedef _ClassType& owner_type; + }; + + template + struct function_traits<_ReturnType(_ClassType::*)(_Args...) const> : function_traits<_ReturnType(_Args...)> + { + typedef const _ClassType& owner_type; + }; + + template + struct function_traits<_ReturnType(_ClassType::*)(_Args...) volatile> : function_traits<_ReturnType(_Args...)> + { + typedef volatile _ClassType& owner_type; + }; + + template + struct function_traits<_ReturnType(_ClassType::*)(_Args...) const volatile> : function_traits<_ReturnType(_Args...)> + { + typedef const volatile _ClassType& owner_type; + }; + + template + struct function_traits> : function_traits + {}; + + template + constexpr auto is_async_method_v = function_traits<_Function>::is_async; + + template + constexpr auto has_error_param_v = function_traits<_Function>::has_error_param; + + template + using function_arguments_t = typename function_traits<_FunctionType>::arguments_type; + + template + using function_argument_t = typename function_traits<_FunctionType>::template arg_t<_Idx>; + + template + constexpr auto function_argument_count_v = function_traits<_FunctionType>::arity; + + template + using function_result_t = typename function_traits<_FunctionType>::result_type; + + template + struct tuple_of_function_input_arg_types + { + typedef typename function_traits<_Function>::decayed_arguments_type type; + }; + + template + using tuple_of_function_input_arg_types_t = typename tuple_of_function_input_arg_types<_Function>::type; + + template + struct tuple_of_function_output_arg_types + { + typedef typename function_traits<_Function>::result_type type; + }; + + template + using tuple_of_function_output_arg_types_t = typename tuple_of_function_output_arg_types<_Function>::type; + + template + struct signature_of_function_input_arguments : signature_of> + { + static std::string value_as_string() + { + constexpr auto signature = as_null_terminated(signature_of_v>); + return signature.data(); + } + }; + + template + inline auto signature_of_function_input_arguments_v = signature_of_function_input_arguments<_Function>::value_as_string(); + + template + struct signature_of_function_output_arguments : signature_of> + { + static std::string value_as_string() + { + constexpr auto signature = as_null_terminated(signature_of_v>); + return signature.data(); + } + }; + + template + inline auto signature_of_function_output_arguments_v = signature_of_function_output_arguments<_Function>::value_as_string(); + + // std::future stuff for return values of async calls + template struct future_return + { + typedef std::tuple<_Args...> type; + }; + + template <> struct future_return<> + { + typedef void type; + }; + + template struct future_return<_Type> + { + typedef _Type type; + }; + + template + using future_return_t = typename future_return<_Args...>::type; + + // Credit: Piotr Skotnicki (https://stackoverflow.com/a/57639506) + template + constexpr bool is_one_of_variants_types = false; + + template + constexpr bool is_one_of_variants_types, _QueriedType> + = (std::is_same_v<_QueriedType, _VariantTypes> || ...); + + // Wrapper (tag) denoting we want to serialize user-defined struct + // into a D-Bus message as a dictionary of strings to variants. + template + struct as_dictionary + { + explicit as_dictionary(const _Struct& s) : m_struct(s) {} + const _Struct& m_struct; + }; + + template + const _Type& as_dictionary_if_struct(const _Type& object) + { + return object; // identity in case _Type is not struct (user-defined structs shall provide an overload) + } + + // By default, the dict-as-struct deserialization strategy is strict. + // Strict means that every key of the deserialized dictionary must have its counterpart member in the struct, otherwise an exception is thrown. + // Relaxed means that a key that does not have a matching struct member is silently ignored. + // The behavior can be overridden for user-defined struct by specializing this variable template. + template + constexpr auto strict_dict_as_struct_deserialization_v = true; + + // By default, the struct-as-dict serialization strategy is single-level only (as opposed to nested). + // Single-level means that only the specific struct is serialized as a dictionary, serializing members that are structs always as structs. + // Nested means that the struct *and* its members that are structs are all serialized as a dictionary. If nested strategy is also + // defined for the nested struct, then the same behavior applies for that struct, recursively. + // The behavior can be overridden for user-defined struct by specializing this variable template. + template + constexpr auto nested_struct_as_dict_serialization_v = false; + + namespace detail + { + template + constexpr decltype(auto) apply_impl( _Function&& f + , Result<_Args...>&& r + , _Tuple&& t + , std::index_sequence<_I...> ) + { + return std::forward<_Function>(f)(std::move(r), std::get<_I>(std::forward<_Tuple>(t))...); + } + + template + decltype(auto) apply_impl( _Function&& f + , std::optional e + , _Tuple&& t + , std::index_sequence<_I...> ) + { + return std::forward<_Function>(f)(std::move(e), std::get<_I>(std::forward<_Tuple>(t))...); + } + + // For non-void returning functions, apply_impl simply returns function return value (a tuple of values). + // For void-returning functions, apply_impl returns an empty tuple. + template + constexpr decltype(auto) apply_impl( _Function&& f + , _Tuple&& t + , std::index_sequence<_I...> ) + { + if constexpr (!std::is_void_v>) + return std::forward<_Function>(f)(std::get<_I>(std::forward<_Tuple>(t))...); + else + return std::forward<_Function>(f)(std::get<_I>(std::forward<_Tuple>(t))...), std::tuple<>{}; + } + } + + // Convert tuple `t' of values into a list of arguments + // and invoke function `f' with those arguments. + template + constexpr decltype(auto) apply(_Function&& f, _Tuple&& t) + { + return detail::apply_impl( std::forward<_Function>(f) + , std::forward<_Tuple>(t) + , std::make_index_sequence>::value>{} ); + } + + // Convert tuple `t' of values into a list of arguments + // and invoke function `f' with those arguments. + template + constexpr decltype(auto) apply(_Function&& f, Result<_Args...>&& r, _Tuple&& t) + { + return detail::apply_impl( std::forward<_Function>(f) + , std::move(r) + , std::forward<_Tuple>(t) + , std::make_index_sequence>::value>{} ); + } + + // Convert tuple `t' of values into a list of arguments + // and invoke function `f' with those arguments. + template + decltype(auto) apply(_Function&& f, std::optional e, _Tuple&& t) + { + return detail::apply_impl( std::forward<_Function>(f) + , std::move(e) + , std::forward<_Tuple>(t) + , std::make_index_sequence>::value>{} ); + } + + // Convenient concatenation of arrays + template + constexpr std::array<_T, _N1 + _N2> operator+(std::array<_T, _N1> lhs, std::array<_T, _N2> rhs) + { + std::array<_T, _N1 + _N2> result{}; + std::size_t index = 0; + + for (auto& el : lhs) { + result[index] = std::move(el); + ++index; + } + for (auto& el : rhs) { + result[index] = std::move(el); + ++index; + } + + return result; + } + +} + +#endif /* SDBUS_CXX_TYPETRAITS_H_ */ diff --git a/3rdParty/sdbus-cpp/include/sdbus-c++/Types.h b/3rdParty/sdbus-cpp/include/sdbus-c++/Types.h new file mode 100644 index 0000000000..b75e3faa1f --- /dev/null +++ b/3rdParty/sdbus-cpp/include/sdbus-c++/Types.h @@ -0,0 +1,597 @@ +/** + * (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland + * (C) 2016 - 2024 Stanislav Angelovic + * + * @file Types.h + * + * Created on: Nov 23, 2016 + * Project: sdbus-c++ + * Description: High-level D-Bus IPC C++ library based on sd-bus + * + * This file is part of sdbus-c++. + * + * sdbus-c++ is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 of the License, or + * (at your option) any later version. + * + * sdbus-c++ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with sdbus-c++. If not, see . + */ + +#ifndef SDBUS_CXX_TYPES_H_ +#define SDBUS_CXX_TYPES_H_ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace sdbus { + + /********************************************//** + * @class Variant + * + * Variant can hold value of any D-Bus-supported type. + * + * Note: Even though thread-aware, Variant objects are not thread-safe. + * Some const methods are conceptually const, but not physically const, + * thus are not thread-safe. This is by design: normally, clients + * should process a single Variant object in a single thread at a time. + * Otherwise they need to take care of synchronization by themselves. + * + ***********************************************/ + class Variant + { + public: + Variant(); + + template + explicit Variant(const _ValueType& value) : Variant() + { + msg_.openVariant<_ValueType>(); + msg_ << value; + msg_.closeVariant(); + msg_.seal(); + } + + Variant(const Variant& value, embed_variant_t) : Variant() + { + msg_.openVariant(); + msg_ << value; + msg_.closeVariant(); + msg_.seal(); + } + + template + explicit Variant(const as_dictionary<_Struct>& value) : Variant() + { + msg_.openVariant>(); + msg_ << as_dictionary(value.m_struct); + msg_.closeVariant(); + msg_.seal(); + } + + template + Variant(const std::variant<_Elements...>& value) + : Variant() + { + msg_ << value; + msg_.seal(); + } + + template + _ValueType get() const + { + msg_.rewind(false); + + msg_.enterVariant<_ValueType>(); + _ValueType val; + msg_ >> val; + msg_.exitVariant(); + return val; + } + + // Only allow conversion operator for true D-Bus type representations in C++ + template ::is_valid>> + explicit operator _ValueType() const + { + return get<_ValueType>(); + } + + template + operator std::variant<_Elements...>() const + { + std::variant<_Elements...> result; + msg_.rewind(false); + msg_ >> result; + return result; + } + + template + bool containsValueOfType() const + { + constexpr auto signature = as_null_terminated(signature_of_v<_Type>); + return std::strcmp(signature.data(), peekValueType()) == 0; + } + + bool isEmpty() const; + + void serializeTo(Message& msg) const; + void deserializeFrom(Message& msg); + const char* peekValueType() const; + + private: + mutable PlainMessage msg_{}; + }; + + /********************************************//** + * @class Struct + * + * Representation of struct D-Bus type + * + * Struct implements tuple protocol, i.e. it's a tuple-like class. + * It can be used with std::get<>(), std::tuple_element, + * std::tuple_size and in structured bindings. + * + ***********************************************/ + template + class Struct + : public std::tuple<_ValueTypes...> + { + public: + using std::tuple<_ValueTypes...>::tuple; + + Struct() = default; + + explicit Struct(const std::tuple<_ValueTypes...>& t) + : std::tuple<_ValueTypes...>(t) + { + } + + template + auto& get() + { + return std::get<_I>(*this); + } + + template + const auto& get() const + { + return std::get<_I>(*this); + } + }; + + template + Struct(_Elements...) -> Struct<_Elements...>; + + template + constexpr Struct...> + make_struct(_Elements&&... args) + { + typedef Struct...> result_type; + return result_type(std::forward<_Elements>(args)...); + } + + /********************************************//** + * @class ObjectPath + * + * Strong type representing the D-Bus object path + * + ***********************************************/ + class ObjectPath : public std::string + { + public: + ObjectPath() = default; + explicit ObjectPath(std::string value) + : std::string(std::move(value)) + {} + explicit ObjectPath(const char* value) + : std::string(value) + {} + + using std::string::operator=; + }; + + /********************************************//** + * @class BusName + * + * Strong type representing the D-Bus bus/service/connection name + * + ***********************************************/ + class BusName : public std::string + { + public: + BusName() = default; + explicit BusName(std::string value) + : std::string(std::move(value)) + {} + explicit BusName(const char* value) + : std::string(value) + {} + + using std::string::operator=; + }; + + using ServiceName = BusName; + using ConnectionName = BusName; + + /********************************************//** + * @class InterfaceName + * + * Strong type representing the D-Bus interface name + * + ***********************************************/ + class InterfaceName : public std::string + { + public: + InterfaceName() = default; + explicit InterfaceName(std::string value) + : std::string(std::move(value)) + {} + explicit InterfaceName(const char* value) + : std::string(value) + {} + + using std::string::operator=; + }; + + /********************************************//** + * @class MemberName + * + * Strong type representing the D-Bus member name + * + ***********************************************/ + class MemberName : public std::string + { + public: + MemberName() = default; + explicit MemberName(std::string value) + : std::string(std::move(value)) + {} + explicit MemberName(const char* value) + : std::string(value) + {} + + using std::string::operator=; + }; + + using MethodName = MemberName; + using SignalName = MemberName; + using PropertyName = MemberName; + + /********************************************//** + * @class Signature + * + * Strong type representing the D-Bus object path + * + ***********************************************/ + class Signature : public std::string + { + public: + Signature() = default; + explicit Signature(std::string value) + : std::string(std::move(value)) + {} + explicit Signature(const char* value) + : std::string(value) + {} + + using std::string::operator=; + }; + + /********************************************//** + * @struct UnixFd + * + * UnixFd is a representation of file descriptor D-Bus type that owns + * the underlying fd, provides access to it, and closes the fd when + * the UnixFd goes out of scope. + * + * UnixFd can be default constructed (owning invalid fd), or constructed from + * an explicitly provided fd by either duplicating or adopting that fd as-is. + * + ***********************************************/ + class UnixFd + { + public: + UnixFd() = default; + + explicit UnixFd(int fd) + : fd_(checkedDup(fd)) + { + } + + UnixFd(int fd, adopt_fd_t) + : fd_(fd) + { + } + + UnixFd(const UnixFd& other) + { + *this = other; + } + + UnixFd& operator=(const UnixFd& other) + { + if (this == &other) + { + return *this; + } + close(); + fd_ = checkedDup(other.fd_); + return *this; + } + + UnixFd(UnixFd&& other) + { + *this = std::move(other); + } + + UnixFd& operator=(UnixFd&& other) + { + if (this == &other) + { + return *this; + } + close(); + fd_ = std::exchange(other.fd_, -1); + return *this; + } + + ~UnixFd() + { + close(); + } + + [[nodiscard]] int get() const + { + return fd_; + } + + void reset(int fd = -1) + { + *this = UnixFd{fd}; + } + + void reset(int fd, adopt_fd_t) + { + *this = UnixFd{fd, adopt_fd}; + } + + int release() + { + return std::exchange(fd_, -1); + } + + [[nodiscard]] bool isValid() const + { + return fd_ >= 0; + } + + private: + /// Closes file descriptor, but does not set it to -1. + void close(); + + /// Returns negative argument unchanged. + /// Otherwise, call ::dup and throw on failure. + static int checkedDup(int fd); + + int fd_ = -1; + }; + + /********************************************//** + * @typedef DictEntry + * + * DictEntry is implemented as std::pair, a standard + * value_type in STL(-like) associative containers. + * + ***********************************************/ + template + using DictEntry = std::pair<_T1, _T2>; + +} + +// Making sdbus::Struct implement the tuple-protocol, i.e. be a tuple-like type +template +struct std::tuple_element<_I, sdbus::Struct<_ValueTypes...>> + : std::tuple_element<_I, std::tuple<_ValueTypes...>> +{}; +template +struct std::tuple_size> + : std::tuple_size> +{}; + +/********************************************//** + * @name SDBUSCPP_REGISTER_STRUCT + * + * A convenient way to extend sdbus-c++ type system with user-defined structs. + * + * The macro teaches sdbus-c++ to recognize the user-defined struct + * as a valid C++ representation of a D-Bus Struct type, and enables + * clients to use their struct conveniently instead of the (too + * generic and less expressive) `sdbus::Struct<...>` in sdbus-c++ API. + * + * It also enables to serialize a user-defined struct as an a{sv} dictionary, + * and to deserialize an a{sv} dictionary into the user-defined struct. + * + * The first argument is the struct type name and the remaining arguments + * are names of struct members. Members must be of types supported by + * sdbus-c++ (or of user-defined types that sdbus-c++ was taught to support). + * Members can be other structs (nesting is supported). + * The macro must be placed in the global namespace. + * + * For example, given the user-defined struct `ABC`: + * + * namespace foo { + * struct ABC + * { + * int number; + * std::string name; + * std::vector data; + * }; + * } + * + * one can teach sdbus-c++ about the contents of this struct simply with: + * + * SDBUSCPP_REGISTER_STRUCT(foo::ABC, number, name, data); + * + * Up to 16 struct members are supported by the macro. + * + ***********************************************/ +#define SDBUSCPP_REGISTER_STRUCT(STRUCT, ...) \ + namespace sdbus { \ + static_assert(SDBUSCPP_PP_NARG(__VA_ARGS__) <= 16, \ + "Not more than 16 struct members are supported, please open an issue if you need more"); \ + \ + template <> \ + struct signature_of \ + : signature_of> \ + {}; \ + \ + inline auto as_dictionary_if_struct(const STRUCT& object) \ + { \ + return as_dictionary(object); \ + } \ + \ + inline sdbus::Message& operator<<(sdbus::Message& msg, const STRUCT& items) \ + { \ + return msg << sdbus::Struct{std::forward_as_tuple(SDBUSCPP_STRUCT_MEMBERS(items, __VA_ARGS__))}; \ + } \ + \ + inline Message& operator<<(Message& msg, const as_dictionary& s) \ + { \ + if constexpr (!nested_struct_as_dict_serialization_v) \ + return msg.serializeDictionary({SDBUSCPP_STRUCT_MEMBERS_AS_DICT_ENTRIES(s.m_struct, __VA_ARGS__)}); \ + else \ + return msg.serializeDictionary({SDBUSCPP_STRUCT_MEMBERS_AS_NESTED_DICT_ENTRIES(s.m_struct, __VA_ARGS__)}); \ + } \ + \ + inline Message& operator>>(Message& msg, STRUCT& s) \ + { \ + /* First, try to deserialize as a struct */ \ + if (msg.peekType().first == signature_of::type_value) \ + { \ + Struct sdbusStruct{std::forward_as_tuple(SDBUSCPP_STRUCT_MEMBERS(s, __VA_ARGS__))}; \ + return msg >> sdbusStruct; \ + } \ + \ + /* Otherwise try to deserialize as a dictionary of strings to variants */ \ + \ + return msg.deserializeDictionary([&s](const auto& dictEntry) \ + { \ + const std::string& key = dictEntry.first; /* Intentionally not using structured bindings */ \ + const Variant& value = dictEntry.second; \ + \ + using namespace std::string_literals; \ + /* This also handles members which are structs serialized as dict of strings to variants, recursively */ \ + SDBUSCPP_FIND_AND_DESERIALIZE_STRUCT_MEMBERS(s, __VA_ARGS__) \ + SDBUS_THROW_ERROR_IF( strict_dict_as_struct_deserialization_v \ + , ("Failed to deserialize struct from a dictionary: could not find field '"s += key) += "' in struct 'my::Struct'" \ + , EINVAL ); \ + }); \ + } \ + } \ + /**/ + +/********************************************//** + * @name SDBUSCPP_ENABLE_RELAXED_DICT2STRUCT_DESERIALIZATION + * + * Enables relaxed deserialization of an a{sv} dictionary into a user-defined struct STRUCT. + * + * The default (strict) deserialization mode is that if there are entries in the dictionary + * which do not have a corresponding field in the struct, an exception is thrown. + * In the relaxed mode, such entries are silently skipped. + * + * The macro can only be used in combination with SDBUSCPP_REGISTER_STRUCT macro, + * and must be placed before SDBUSCPP_REGISTER_STRUCT macro. + ***********************************************/ +#define SDBUSCPP_ENABLE_RELAXED_DICT2STRUCT_DESERIALIZATION(STRUCT) \ + template <> \ + constexpr auto sdbus::strict_dict_as_struct_deserialization_v = false; \ + /**/ + +/********************************************//** + * @name SDBUSCPP_ENABLE_NESTED_STRUCT2DICT_SERIALIZATION + * + * Enables nested serialization of user-defined struct STRUCT as an a{sv} dictionary. + * + * By default, STRUCT fields which are structs themselves are serialized as D-Bus structs. + * This macro tells sdbus-c++ to also serialize nested structs, in a recursive fashion, + * as a{sv} dictionaries. + * + * The macro can only be used in combination with SDBUSCPP_REGISTER_STRUCT macro, + * and must be placed before SDBUSCPP_REGISTER_STRUCT macro. + ***********************************************/ +#define SDBUSCPP_ENABLE_NESTED_STRUCT2DICT_SERIALIZATION(STRUCT) \ + template <> \ + constexpr auto sdbus::nested_struct_as_dict_serialization_v = true \ + /**/ + +/*! + * @cond SDBUSCPP_INTERNAL + * + * Internal helper preprocessor facilities + */ +#define SDBUSCPP_STRUCT_MEMBERS(STRUCT, ...) \ + SDBUSCPP_PP_CAT(SDBUSCPP_FOR_EACH_, SDBUSCPP_PP_NARG(__VA_ARGS__))(SDBUSCPP_STRUCT_MEMBER, SDBUSCPP_PP_COMMA, STRUCT, __VA_ARGS__) \ + /**/ +#define SDBUSCPP_STRUCT_MEMBER(STRUCT, MEMBER) STRUCT.MEMBER + +#define SDBUSCPP_STRUCT_MEMBER_TYPES(STRUCT, ...) \ + SDBUSCPP_PP_CAT(SDBUSCPP_FOR_EACH_, SDBUSCPP_PP_NARG(__VA_ARGS__))(SDBUSCPP_STRUCT_MEMBER_TYPE, SDBUSCPP_PP_COMMA, STRUCT, __VA_ARGS__) \ + /**/ +#define SDBUSCPP_STRUCT_MEMBER_TYPE(STRUCT, MEMBER) decltype(STRUCT::MEMBER) + +#define SDBUSCPP_STRUCT_MEMBERS_AS_DICT_ENTRIES(STRUCT, ...) \ + SDBUSCPP_PP_CAT(SDBUSCPP_FOR_EACH_, SDBUSCPP_PP_NARG(__VA_ARGS__))(SDBUSCPP_STRUCT_MEMBER_AS_DICT_ENTRY, SDBUSCPP_PP_COMMA, STRUCT, __VA_ARGS__) \ + /**/ +#define SDBUSCPP_STRUCT_MEMBER_AS_DICT_ENTRY(STRUCT, MEMBER) {#MEMBER, Variant{STRUCT.MEMBER}} + +#define SDBUSCPP_STRUCT_MEMBERS_AS_NESTED_DICT_ENTRIES(STRUCT, ...) \ + SDBUSCPP_PP_CAT(SDBUSCPP_FOR_EACH_, SDBUSCPP_PP_NARG(__VA_ARGS__))(SDBUSCPP_STRUCT_MEMBER_AS_NESTED_DICT_ENTRY, SDBUSCPP_PP_COMMA, STRUCT, __VA_ARGS__) \ + /**/ +#define SDBUSCPP_STRUCT_MEMBER_AS_NESTED_DICT_ENTRY(STRUCT, MEMBER) {#MEMBER, Variant{as_dictionary_if_struct(STRUCT.MEMBER)}} + +#define SDBUSCPP_FIND_AND_DESERIALIZE_STRUCT_MEMBERS(STRUCT, ...) \ + SDBUSCPP_PP_CAT(SDBUSCPP_FOR_EACH_, SDBUSCPP_PP_NARG(__VA_ARGS__))(SDBUSCPP_FIND_AND_DESERIALIZE_STRUCT_MEMBER, SDBUSCPP_PP_SPACE, STRUCT, __VA_ARGS__) \ + /**/ +#define SDBUSCPP_FIND_AND_DESERIALIZE_STRUCT_MEMBER(STRUCT, MEMBER) if (key == #MEMBER) STRUCT.MEMBER = value.get(); else + +#define SDBUSCPP_FOR_EACH_1(M, D, S, M1) M(S, M1) +#define SDBUSCPP_FOR_EACH_2(M, D, S, M1, M2) M(S, M1) D M(S, M2) +#define SDBUSCPP_FOR_EACH_3(M, D, S, M1, M2, M3) M(S, M1) D M(S, M2) D M(S, M3) +#define SDBUSCPP_FOR_EACH_4(M, D, S, M1, M2, M3, M4) M(S, M1) D M(S, M2) D M(S, M3) D M(S, M4) +#define SDBUSCPP_FOR_EACH_5(M, D, S, M1, M2, M3, M4, M5) M(S, M1) D M(S, M2) D M(S, M3) D M(S, M4) D M(S, M5) +#define SDBUSCPP_FOR_EACH_6(M, D, S, M1, M2, M3, M4, M5, M6) M(S, M1) D M(S, M2) D M(S, M3) D M(S, M4) D M(S, M5) D M(S, M6) +#define SDBUSCPP_FOR_EACH_7(M, D, S, M1, M2, M3, M4, M5, M6, M7) M(S, M1) D M(S, M2) D M(S, M3) D M(S, M4) D M(S, M5) D M(S, M6) D M(S, M7) +#define SDBUSCPP_FOR_EACH_8(M, D, S, M1, M2, M3, M4, M5, M6, M7, M8) M(S, M1) D M(S, M2) D M(S, M3) D M(S, M4) D M(S, M5) D M(S, M6) D M(S, M7) D M(S, M8) +#define SDBUSCPP_FOR_EACH_9(M, D, S, M1, M2, M3, M4, M5, M6, M7, M8, M9) M(S, M1) D M(S, M2) D M(S, M3) D M(S, M4) D M(S, M5) D M(S, M6) D M(S, M7) D M(S, M8) D M(S, M9) +#define SDBUSCPP_FOR_EACH_10(M, D, S, M1, M2, M3, M4, M5, M6, M7, M8, M9, M10) M(S, M1) D M(S, M2) D M(S, M3) D M(S, M4) D M(S, M5) D M(S, M6) D M(S, M7) D M(S, M8) D M(S, M9) D M(S, M10) +#define SDBUSCPP_FOR_EACH_11(M, D, S, M1, M2, M3, M4, M5, M6, M7, M8, M9, M10, M11) M(S, M1) D M(S, M2) D M(S, M3) D M(S, M4) D M(S, M5) D M(S, M6) D M(S, M7) D M(S, M8) D M(S, M9) D M(S, M10) D M(S, M11) +#define SDBUSCPP_FOR_EACH_12(M, D, S, M1, M2, M3, M4, M5, M6, M7, M8, M9, M10, M11, M12) M(S, M1) D M(S, M2) D M(S, M3) D M(S, M4) D M(S, M5) D M(S, M6) D M(S, M7) D M(S, M8) D M(S, M9) D M(S, M10) D M(S, M11) D M(S, M12) +#define SDBUSCPP_FOR_EACH_13(M, D, S, M1, M2, M3, M4, M5, M6, M7, M8, M9, M10, M11, M12, M13) M(S, M1) D M(S, M2) D M(S, M3) D M(S, M4) D M(S, M5) D M(S, M6) D M(S, M7) D M(S, M8) D M(S, M9) D M(S, M10) D M(S, M11) D M(S, M12) D M(S, M13) +#define SDBUSCPP_FOR_EACH_14(M, D, S, M1, M2, M3, M4, M5, M6, M7, M8, M9, M10, M11, M12, M13, M14) M(S, M1) D M(S, M2) D M(S, M3) D M(S, M4) D M(S, M5) D M(S, M6) D M(S, M7) D M(S, M8) D M(S, M9) D M(S, M10) D M(S, M11) D M(S, M12) D M(S, M13) D M(S, M14) +#define SDBUSCPP_FOR_EACH_15(M, D, S, M1, M2, M3, M4, M5, M6, M7, M8, M9, M10, M11, M12, M13, M14, M15) M(S, M1) D M(S, M2) D M(S, M3) D M(S, M4) D M(S, M5) D M(S, M6) D M(S, M7) D M(S, M8) D M(S, M9) D M(S, M10) D M(S, M11) D M(S, M12) D M(S, M13) D M(S, M14) D M(S, M15) +#define SDBUSCPP_FOR_EACH_16(M, D, S, M1, M2, M3, M4, M5, M6, M7, M8, M9, M10, M11, M12, M13, M14, M15, M16) M(S, M1) D M(S, M2) D M(S, M3) D M(S, M4) D M(S, M5) D M(S, M6) D M(S, M7) D M(S, M8) D M(S, M9) D M(S, M10) D M(S, M11) D M(S, M12) D M(S, M13) D M(S, M14) D M(S, M15) D M(S, M16) + +#define SDBUSCPP_PP_CAT(X, Y) SDBUSCPP_PP_CAT_IMPL(X, Y) +#define SDBUSCPP_PP_CAT_IMPL(X, Y) X##Y +#define SDBUSCPP_PP_NARG(...) SDBUSCPP_PP_NARG_IMPL(__VA_ARGS__, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) +#define SDBUSCPP_PP_NARG_IMPL(_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, _N, ...) _N + +#define SDBUSCPP_PP_COMMA , +#define SDBUSCPP_PP_SPACE + +#endif /* SDBUS_CXX_TYPES_H_ */ diff --git a/3rdParty/sdbus-cpp/include/sdbus-c++/VTableItems.h b/3rdParty/sdbus-cpp/include/sdbus-c++/VTableItems.h new file mode 100644 index 0000000000..019a57b82d --- /dev/null +++ b/3rdParty/sdbus-cpp/include/sdbus-c++/VTableItems.h @@ -0,0 +1,112 @@ +/** + * (C) 2016 - 2024 Stanislav Angelovic + * + * @file VTableItems.h + * + * Created on: Dec 14, 2023 + * Project: sdbus-c++ + * Description: High-level D-Bus IPC C++ library based on sd-bus + * + * This file is part of sdbus-c++. + * + * sdbus-c++ is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 of the License, or + * (at your option) any later version. + * + * sdbus-c++ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with sdbus-c++. If not, see . + */ + +#ifndef SDBUS_CXX_VTABLEITEMS_H_ +#define SDBUS_CXX_VTABLEITEMS_H_ + +#include +#include +#include + +#include +#include +#include + +namespace sdbus { + + struct MethodVTableItem + { + template MethodVTableItem& implementedAs(_Function&& callback); + MethodVTableItem& withInputParamNames(std::vector names); + template MethodVTableItem& withInputParamNames(_String... names); + MethodVTableItem& withOutputParamNames(std::vector names); + template MethodVTableItem& withOutputParamNames(_String... names); + MethodVTableItem& markAsDeprecated(); + MethodVTableItem& markAsPrivileged(); + MethodVTableItem& withNoReply(); + + MethodName name; + Signature inputSignature; + std::vector inputParamNames; + Signature outputSignature; + std::vector outputParamNames; + method_callback callbackHandler; + Flags flags; + }; + + MethodVTableItem registerMethod(MethodName methodName); + MethodVTableItem registerMethod(std::string methodName); + + struct SignalVTableItem + { + template SignalVTableItem& withParameters(); + template SignalVTableItem& withParameters(std::vector names); + template SignalVTableItem& withParameters(_String... names); + SignalVTableItem& markAsDeprecated(); + + SignalName name; + Signature signature; + std::vector paramNames; + Flags flags; + }; + + SignalVTableItem registerSignal(SignalName signalName); + SignalVTableItem registerSignal(std::string signalName); + + struct PropertyVTableItem + { + template PropertyVTableItem& withGetter(_Function&& callback); + template PropertyVTableItem& withSetter(_Function&& callback); + PropertyVTableItem& markAsDeprecated(); + PropertyVTableItem& markAsPrivileged(); + PropertyVTableItem& withUpdateBehavior(Flags::PropertyUpdateBehaviorFlags behavior); + + PropertyName name; + Signature signature; + property_get_callback getter; + property_set_callback setter; + Flags flags; + }; + + PropertyVTableItem registerProperty(PropertyName propertyName); + PropertyVTableItem registerProperty(std::string propertyName); + + struct InterfaceFlagsVTableItem + { + InterfaceFlagsVTableItem& markAsDeprecated(); + InterfaceFlagsVTableItem& markAsPrivileged(); + InterfaceFlagsVTableItem& withNoReplyMethods(); + InterfaceFlagsVTableItem& withPropertyUpdateBehavior(Flags::PropertyUpdateBehaviorFlags behavior); + + Flags flags; + }; + + InterfaceFlagsVTableItem setInterfaceFlags(); + + using VTableItem = std::variant; + +} // namespace sdbus + +#endif /* SDBUS_CXX_VTABLEITEMS_H_ */ diff --git a/3rdParty/sdbus-cpp/include/sdbus-c++/VTableItems.inl b/3rdParty/sdbus-cpp/include/sdbus-c++/VTableItems.inl new file mode 100644 index 0000000000..127006dfef --- /dev/null +++ b/3rdParty/sdbus-cpp/include/sdbus-c++/VTableItems.inl @@ -0,0 +1,301 @@ +/** + * (C) 2016 - 2024 Stanislav Angelovic + * + * @file VTableItems.inl + * + * Created on: Dec 14, 2023 + * Project: sdbus-c++ + * Description: High-level D-Bus IPC C++ library based on sd-bus + * + * This file is part of sdbus-c++. + * + * sdbus-c++ is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 of the License, or + * (at your option) any later version. + * + * sdbus-c++ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with sdbus-c++. If not, see . + */ + +#ifndef SDBUS_CPP_VTABLEITEMS_INL_ +#define SDBUS_CPP_VTABLEITEMS_INL_ + +#include +#include + +#include +#include +#include + +namespace sdbus { + + /*** -------------------- ***/ + /*** Method VTable Item ***/ + /*** -------------------- ***/ + + template + MethodVTableItem& MethodVTableItem::implementedAs(_Function&& callback) + { + inputSignature = signature_of_function_input_arguments_v<_Function>; + outputSignature = signature_of_function_output_arguments_v<_Function>; + callbackHandler = [callback = std::forward<_Function>(callback)](MethodCall call) + { + // Create a tuple of callback input arguments' types, which will be used + // as a storage for the argument values deserialized from the message. + tuple_of_function_input_arg_types_t<_Function> inputArgs; + + // Deserialize input arguments from the message into the tuple. + call >> inputArgs; + + if constexpr (!is_async_method_v<_Function>) + { + // Invoke callback with input arguments from the tuple. + auto ret = sdbus::apply(callback, inputArgs); + + // Store output arguments to the reply message and send it back. + auto reply = call.createReply(); + reply << ret; + reply.send(); + } + else + { + // Invoke callback with input arguments from the tuple and with result object to be set later + using AsyncResult = typename function_traits<_Function>::async_result_t; + sdbus::apply(callback, AsyncResult{std::move(call)}, std::move(inputArgs)); + } + }; + + return *this; + } + + inline MethodVTableItem& MethodVTableItem::withInputParamNames(std::vector names) + { + inputParamNames = std::move(names); + + return *this; + } + + template + inline MethodVTableItem& MethodVTableItem::withInputParamNames(_String... names) + { + static_assert(std::conjunction_v...>, "Parameter names must be (convertible to) strings"); + + return withInputParamNames({names...}); + } + + inline MethodVTableItem& MethodVTableItem::withOutputParamNames(std::vector names) + { + outputParamNames = std::move(names); + + return *this; + } + + template + inline MethodVTableItem& MethodVTableItem::withOutputParamNames(_String... names) + { + static_assert(std::conjunction_v...>, "Parameter names must be (convertible to) strings"); + + return withOutputParamNames({names...}); + } + + inline MethodVTableItem& MethodVTableItem::markAsDeprecated() + { + flags.set(Flags::DEPRECATED); + + return *this; + } + + inline MethodVTableItem& MethodVTableItem::markAsPrivileged() + { + flags.set(Flags::PRIVILEGED); + + return *this; + } + + inline MethodVTableItem& MethodVTableItem::withNoReply() + { + flags.set(Flags::METHOD_NO_REPLY); + + return *this; + } + + inline MethodVTableItem registerMethod(MethodName methodName) + { + return {std::move(methodName), {}, {}, {}, {}, {}, {}}; + } + + inline MethodVTableItem registerMethod(std::string methodName) + { + return registerMethod(MethodName{std::move(methodName)}); + } + + /*** -------------------- ***/ + /*** Signal VTable Item ***/ + /*** -------------------- ***/ + + template + inline SignalVTableItem& SignalVTableItem::withParameters() + { + signature = signature_of_function_input_arguments_v; + + return *this; + } + + template + inline SignalVTableItem& SignalVTableItem::withParameters(std::vector names) + { + paramNames = std::move(names); + + return withParameters<_Args...>(); + } + + template + inline SignalVTableItem& SignalVTableItem::withParameters(_String... names) + { + static_assert(std::conjunction_v...>, "Parameter names must be (convertible to) strings"); + static_assert(sizeof...(_Args) == sizeof...(_String), "Numbers of signal parameters and their names don't match"); + + return withParameters<_Args...>({names...}); + } + + inline SignalVTableItem& SignalVTableItem::markAsDeprecated() + { + flags.set(Flags::DEPRECATED); + + return *this; + } + + inline SignalVTableItem registerSignal(SignalName signalName) + { + return {std::move(signalName), {}, {}, {}}; + } + + inline SignalVTableItem registerSignal(std::string signalName) + { + return registerSignal(SignalName{std::move(signalName)}); + } + + /*** -------------------- ***/ + /*** Property VTable Item ***/ + /*** -------------------- ***/ + + template + inline PropertyVTableItem& PropertyVTableItem::withGetter(_Function&& callback) + { + static_assert(function_argument_count_v<_Function> == 0, "Property getter function must not take any arguments"); + static_assert(!std::is_void>::value, "Property getter function must return property value"); + + if (signature.empty()) + signature = signature_of_function_output_arguments_v<_Function>; + + getter = [callback = std::forward<_Function>(callback)](PropertyGetReply& reply) + { + // Get the propety value and serialize it into the pre-constructed reply message + reply << callback(); + }; + + return *this; + } + + template + inline PropertyVTableItem& PropertyVTableItem::withSetter(_Function&& callback) + { + static_assert(function_argument_count_v<_Function> == 1, "Property setter function must take one parameter - the property value"); + static_assert(std::is_void>::value, "Property setter function must not return any value"); + + if (signature.empty()) + signature = signature_of_function_input_arguments_v<_Function>; + + setter = [callback = std::forward<_Function>(callback)](PropertySetCall call) + { + // Default-construct property value + using property_type = function_argument_t<_Function, 0>; + std::decay_t property; + + // Deserialize property value from the incoming call message + call >> property; + + // Invoke setter with the value + callback(property); + }; + + return *this; + } + + inline PropertyVTableItem& PropertyVTableItem::markAsDeprecated() + { + flags.set(Flags::DEPRECATED); + + return *this; + } + + inline PropertyVTableItem& PropertyVTableItem::markAsPrivileged() + { + flags.set(Flags::PRIVILEGED); + + return *this; + } + + inline PropertyVTableItem& PropertyVTableItem::withUpdateBehavior(Flags::PropertyUpdateBehaviorFlags behavior) + { + flags.set(behavior); + + return *this; + } + + inline PropertyVTableItem registerProperty(PropertyName propertyName) + { + return {std::move(propertyName), {}, {}, {}, {}}; + } + + inline PropertyVTableItem registerProperty(std::string propertyName) + { + return registerProperty(PropertyName{std::move(propertyName)}); + } + + /*** --------------------------- ***/ + /*** Interface Flags VTable Item ***/ + /*** --------------------------- ***/ + + inline InterfaceFlagsVTableItem& InterfaceFlagsVTableItem::markAsDeprecated() + { + flags.set(Flags::DEPRECATED); + + return *this; + } + + inline InterfaceFlagsVTableItem& InterfaceFlagsVTableItem::markAsPrivileged() + { + flags.set(Flags::PRIVILEGED); + + return *this; + } + + inline InterfaceFlagsVTableItem& InterfaceFlagsVTableItem::withNoReplyMethods() + { + flags.set(Flags::METHOD_NO_REPLY); + + return *this; + } + + inline InterfaceFlagsVTableItem& InterfaceFlagsVTableItem::withPropertyUpdateBehavior(Flags::PropertyUpdateBehaviorFlags behavior) + { + flags.set(behavior); + + return *this; + } + + inline InterfaceFlagsVTableItem setInterfaceFlags() + { + return {}; + } + +} // namespace sdbus + +#endif /* SDBUS_CPP_VTABLEITEMS_INL_ */ diff --git a/3rdParty/sdbus-cpp/include/sdbus-c++/sdbus-c++.h b/3rdParty/sdbus-cpp/include/sdbus-c++/sdbus-c++.h new file mode 100644 index 0000000000..8bc3fe69d4 --- /dev/null +++ b/3rdParty/sdbus-cpp/include/sdbus-c++/sdbus-c++.h @@ -0,0 +1,38 @@ +/** + * (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland + * (C) 2016 - 2024 Stanislav Angelovic + * + * @file sdbus-c++.h + * + * Created on: Jan 19, 2017 + * Project: sdbus-c++ + * Description: High-level D-Bus IPC C++ library based on sd-bus + * + * This file is part of sdbus-c++. + * + * sdbus-c++ is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 of the License, or + * (at your option) any later version. + * + * sdbus-c++ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with sdbus-c++. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include diff --git a/3rdParty/sdbus-cpp/lib/cmake/sdbus-c++/sdbus-c++-config-version.cmake b/3rdParty/sdbus-cpp/lib/cmake/sdbus-c++/sdbus-c++-config-version.cmake new file mode 100644 index 0000000000..a9711194e3 --- /dev/null +++ b/3rdParty/sdbus-cpp/lib/cmake/sdbus-c++/sdbus-c++-config-version.cmake @@ -0,0 +1,65 @@ +# This is a basic version file for the Config-mode of find_package(). +# It is used by write_basic_package_version_file() as input file for configure_file() +# to create a version-file which can be installed along a config.cmake file. +# +# The created file sets PACKAGE_VERSION_EXACT if the current version string and +# the requested version string are exactly the same and it sets +# PACKAGE_VERSION_COMPATIBLE if the current version is >= requested version, +# but only if the requested major version is the same as the current one. +# The variable CVF_VERSION must be set before calling configure_file(). + + +set(PACKAGE_VERSION "2.2.1") + +if(PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION) + set(PACKAGE_VERSION_COMPATIBLE FALSE) +else() + + if("2.2.1" MATCHES "^([0-9]+)\\.") + set(CVF_VERSION_MAJOR "${CMAKE_MATCH_1}") + if(NOT CVF_VERSION_MAJOR VERSION_EQUAL 0) + string(REGEX REPLACE "^0+" "" CVF_VERSION_MAJOR "${CVF_VERSION_MAJOR}") + endif() + else() + set(CVF_VERSION_MAJOR "2.2.1") + endif() + + if(PACKAGE_FIND_VERSION_RANGE) + # both endpoints of the range must have the expected major version + math (EXPR CVF_VERSION_MAJOR_NEXT "${CVF_VERSION_MAJOR} + 1") + if (NOT PACKAGE_FIND_VERSION_MIN_MAJOR STREQUAL CVF_VERSION_MAJOR + OR ((PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "INCLUDE" AND NOT PACKAGE_FIND_VERSION_MAX_MAJOR STREQUAL CVF_VERSION_MAJOR) + OR (PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "EXCLUDE" AND NOT PACKAGE_FIND_VERSION_MAX VERSION_LESS_EQUAL CVF_VERSION_MAJOR_NEXT))) + set(PACKAGE_VERSION_COMPATIBLE FALSE) + elseif(PACKAGE_FIND_VERSION_MIN_MAJOR STREQUAL CVF_VERSION_MAJOR + AND ((PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "INCLUDE" AND PACKAGE_VERSION VERSION_LESS_EQUAL PACKAGE_FIND_VERSION_MAX) + OR (PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "EXCLUDE" AND PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION_MAX))) + set(PACKAGE_VERSION_COMPATIBLE TRUE) + else() + set(PACKAGE_VERSION_COMPATIBLE FALSE) + endif() + else() + if(PACKAGE_FIND_VERSION_MAJOR STREQUAL CVF_VERSION_MAJOR) + set(PACKAGE_VERSION_COMPATIBLE TRUE) + else() + set(PACKAGE_VERSION_COMPATIBLE FALSE) + endif() + + if(PACKAGE_FIND_VERSION STREQUAL PACKAGE_VERSION) + set(PACKAGE_VERSION_EXACT TRUE) + endif() + endif() +endif() + + +# if the installed or the using project don't have CMAKE_SIZEOF_VOID_P set, ignore it: +if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "" OR "8" STREQUAL "") + return() +endif() + +# check that the installed version has the same 32/64bit-ness as the one which is currently searching: +if(NOT CMAKE_SIZEOF_VOID_P STREQUAL "8") + math(EXPR installedBits "8 * 8") + set(PACKAGE_VERSION "${PACKAGE_VERSION} (${installedBits}bit)") + set(PACKAGE_VERSION_UNSUITABLE TRUE) +endif() diff --git a/3rdParty/sdbus-cpp/lib/cmake/sdbus-c++/sdbus-c++-config.cmake b/3rdParty/sdbus-cpp/lib/cmake/sdbus-c++/sdbus-c++-config.cmake new file mode 100644 index 0000000000..a3a9a5f805 --- /dev/null +++ b/3rdParty/sdbus-cpp/lib/cmake/sdbus-c++/sdbus-c++-config.cmake @@ -0,0 +1,28 @@ + +####### Expanded from @PACKAGE_INIT@ by configure_package_config_file() ####### +####### Any changes to this file will be overwritten by the next CMake run #### +####### The input file was sdbus-c++-config.cmake.in ######## + +get_filename_component(PACKAGE_PREFIX_DIR "${CMAKE_CURRENT_LIST_DIR}/../../../" ABSOLUTE) + +macro(set_and_check _var _file) + set(${_var} "${_file}") + if(NOT EXISTS "${_file}") + message(FATAL_ERROR "File or directory ${_file} referenced by variable ${_var} does not exist !") + endif() +endmacro() + +macro(check_required_components _NAME) + foreach(comp ${${_NAME}_FIND_COMPONENTS}) + if(NOT ${_NAME}_${comp}_FOUND) + if(${_NAME}_FIND_REQUIRED_${comp}) + set(${_NAME}_FOUND FALSE) + endif() + endif() + endforeach() +endmacro() + +#################################################################################### + +include("${CMAKE_CURRENT_LIST_DIR}/sdbus-c++-targets.cmake") +check_required_components("sdbus-c++") diff --git a/3rdParty/sdbus-cpp/lib/cmake/sdbus-c++/sdbus-c++-targets-release.cmake b/3rdParty/sdbus-cpp/lib/cmake/sdbus-c++/sdbus-c++-targets-release.cmake new file mode 100644 index 0000000000..d21aa91bdc --- /dev/null +++ b/3rdParty/sdbus-cpp/lib/cmake/sdbus-c++/sdbus-c++-targets-release.cmake @@ -0,0 +1,19 @@ +#---------------------------------------------------------------- +# Generated CMake target import file for configuration "Release". +#---------------------------------------------------------------- + +# Commands may need to know the format version. +set(CMAKE_IMPORT_FILE_VERSION 1) + +# Import target "SDBusCpp::sdbus-c++" for configuration "Release" +set_property(TARGET SDBusCpp::sdbus-c++ APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE) +set_target_properties(SDBusCpp::sdbus-c++ PROPERTIES + IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "C;CXX" + IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/lib/libsdbus-c++.a" + ) + +list(APPEND _cmake_import_check_targets SDBusCpp::sdbus-c++ ) +list(APPEND _cmake_import_check_files_for_SDBusCpp::sdbus-c++ "${_IMPORT_PREFIX}/lib/libsdbus-c++.a" ) + +# Commands beyond this point should not need to know the version. +set(CMAKE_IMPORT_FILE_VERSION) diff --git a/3rdParty/sdbus-cpp/lib/cmake/sdbus-c++/sdbus-c++-targets.cmake b/3rdParty/sdbus-cpp/lib/cmake/sdbus-c++/sdbus-c++-targets.cmake new file mode 100644 index 0000000000..aeb772a44e --- /dev/null +++ b/3rdParty/sdbus-cpp/lib/cmake/sdbus-c++/sdbus-c++-targets.cmake @@ -0,0 +1,114 @@ +# Generated by CMake + +if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" LESS 2.8) + message(FATAL_ERROR "CMake >= 3.0.0 required") +endif() +if(CMAKE_VERSION VERSION_LESS "3.0.0") + message(FATAL_ERROR "CMake >= 3.0.0 required") +endif() +cmake_policy(PUSH) +cmake_policy(VERSION 3.0.0...4.1) +#---------------------------------------------------------------- +# Generated CMake target import file. +#---------------------------------------------------------------- + +# Commands may need to know the format version. +set(CMAKE_IMPORT_FILE_VERSION 1) + +# Protect against multiple inclusion, which would fail when already imported targets are added once more. +set(_cmake_targets_defined "") +set(_cmake_targets_not_defined "") +set(_cmake_expected_targets "") +foreach(_cmake_expected_target IN ITEMS SDBusCpp::sdbus-c++ SDBusCpp::sdbus-c++-objlib) + list(APPEND _cmake_expected_targets "${_cmake_expected_target}") + if(TARGET "${_cmake_expected_target}") + list(APPEND _cmake_targets_defined "${_cmake_expected_target}") + else() + list(APPEND _cmake_targets_not_defined "${_cmake_expected_target}") + endif() +endforeach() +unset(_cmake_expected_target) +if(_cmake_targets_defined STREQUAL _cmake_expected_targets) + unset(_cmake_targets_defined) + unset(_cmake_targets_not_defined) + unset(_cmake_expected_targets) + unset(CMAKE_IMPORT_FILE_VERSION) + cmake_policy(POP) + return() +endif() +if(NOT _cmake_targets_defined STREQUAL "") + string(REPLACE ";" ", " _cmake_targets_defined_text "${_cmake_targets_defined}") + string(REPLACE ";" ", " _cmake_targets_not_defined_text "${_cmake_targets_not_defined}") + message(FATAL_ERROR "Some (but not all) targets in this export set were already defined.\nTargets Defined: ${_cmake_targets_defined_text}\nTargets not yet defined: ${_cmake_targets_not_defined_text}\n") +endif() +unset(_cmake_targets_defined) +unset(_cmake_targets_not_defined) +unset(_cmake_expected_targets) + + +# Compute the installation prefix relative to this file. +get_filename_component(_IMPORT_PREFIX "${CMAKE_CURRENT_LIST_FILE}" PATH) +get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH) +get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH) +get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH) +if(_IMPORT_PREFIX STREQUAL "/") + set(_IMPORT_PREFIX "") +endif() + +# Create imported target SDBusCpp::sdbus-c++ +add_library(SDBusCpp::sdbus-c++ STATIC IMPORTED) + +set_target_properties(SDBusCpp::sdbus-c++ PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${_IMPORT_PREFIX}/include" + INTERFACE_LINK_LIBRARIES "\$" +) + +# Create imported target SDBusCpp::sdbus-c++-objlib +add_library(SDBusCpp::sdbus-c++-objlib INTERFACE IMPORTED) + +set_target_properties(SDBusCpp::sdbus-c++-objlib PROPERTIES + INTERFACE_LINK_LIBRARIES "PkgConfig::Systemd;Threads::Threads" +) + +# Load information for each installed configuration. +file(GLOB _cmake_config_files "${CMAKE_CURRENT_LIST_DIR}/sdbus-c++-targets-*.cmake") +foreach(_cmake_config_file IN LISTS _cmake_config_files) + include("${_cmake_config_file}") +endforeach() +unset(_cmake_config_file) +unset(_cmake_config_files) + +# Cleanup temporary variables. +set(_IMPORT_PREFIX) + +# Loop over all imported files and verify that they actually exist +foreach(_cmake_target IN LISTS _cmake_import_check_targets) + if(CMAKE_VERSION VERSION_LESS "3.28" + OR NOT DEFINED _cmake_import_check_xcframework_for_${_cmake_target} + OR NOT IS_DIRECTORY "${_cmake_import_check_xcframework_for_${_cmake_target}}") + foreach(_cmake_file IN LISTS "_cmake_import_check_files_for_${_cmake_target}") + if(NOT EXISTS "${_cmake_file}") + message(FATAL_ERROR "The imported target \"${_cmake_target}\" references the file + \"${_cmake_file}\" +but this file does not exist. Possible reasons include: +* The file was deleted, renamed, or moved to another location. +* An install or uninstall procedure did not complete successfully. +* The installation package was faulty and contained + \"${CMAKE_CURRENT_LIST_FILE}\" +but not all the files it references. +") + endif() + endforeach() + endif() + unset(_cmake_file) + unset("_cmake_import_check_files_for_${_cmake_target}") +endforeach() +unset(_cmake_target) +unset(_cmake_import_check_targets) + +# This file does not depend on other imported targets which have +# been exported from the same project but in a separate export set. + +# Commands beyond this point should not need to know the version. +set(CMAKE_IMPORT_FILE_VERSION) +cmake_policy(POP) diff --git a/3rdParty/sdbus-cpp/lib/libsdbus-c++.a b/3rdParty/sdbus-cpp/lib/libsdbus-c++.a new file mode 100644 index 0000000000000000000000000000000000000000..3e8cd171efbd24726c0a33df1ed2c322655b43f2 GIT binary patch literal 764160 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 =M6ozyU;gg#!vE_K*XiL+|NL|GMCQZeYmbN{W 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®M~Po#y!@3YXGWh?_*t(|xRy)!ZGMcvuOwl^jK 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 2.2.1 not found, using bundled library") + target_include_directories(SerialProgramsLib PRIVATE + ${REPO_ROOT_DIR}/3rdParty/sdbus-cpp/include + ) + target_link_libraries(SerialProgramsLib PRIVATE + ${REPO_ROOT_DIR}/3rdParty/sdbus-cpp/lib/libsdbus-c++.a + systemd + ) + endif() endif() # end Linux # Find OpenCV From 92dacbab7d7d742deb619a0660edb78fc296da40 Mon Sep 17 00:00:00 2001 From: ConnorC432 Date: Fri, 20 Mar 2026 14:42:54 +0000 Subject: [PATCH 4/7] sdbus-c++ overload wrapper --- .../Environment/SystemSleep_Linux.tpp | 44 ++++++++++++++++--- 1 file changed, 39 insertions(+), 5 deletions(-) diff --git a/SerialPrograms/Source/CommonFramework/Environment/SystemSleep_Linux.tpp b/SerialPrograms/Source/CommonFramework/Environment/SystemSleep_Linux.tpp index a6940957ed..21ebbcaee8 100644 --- a/SerialPrograms/Source/CommonFramework/Environment/SystemSleep_Linux.tpp +++ b/SerialPrograms/Source/CommonFramework/Environment/SystemSleep_Linux.tpp @@ -15,6 +15,44 @@ namespace PokemonAutomation{ +// Strong typing overload +template +auto make_login1_proxy(Connection& connection, int) + -> decltype(sdbus::createProxy( + connection, + sdbus::BusName{"org.freedesktop.login1"}, + sdbus::ObjectPath{"/org/freedesktop/login1"} + )) +{ + return sdbus::createProxy( + connection, + sdbus::BusName{"org.freedesktop.login1"}, + sdbus::ObjectPath{"/org/freedesktop/login1"} + ); +} + +// Fallback overload +template +auto make_login1_proxy(Connection& connection, long) + -> decltype(sdbus::createProxy( + connection, + "org.freedesktop.login1", + "/org/freedesktop/login1" + )) +{ + return sdbus::createProxy( + connection, + "org.freedesktop.login1", + "/org/freedesktop/login1" + ); +} + +template +auto make_login1_proxy(Connection& connection) +{ + return make_login1_proxy(connection, 0); +} + class LinuxSleepController final : public SystemSleepController{ public: LinuxSleepController() @@ -74,11 +112,7 @@ private: void thread_loop() { auto connection = sdbus::createSystemBusConnection(); - auto proxy = sdbus::createProxy( - *connection, - sdbus::BusName{"org.freedesktop.login1"}, - sdbus::ObjectPath{"/org/freedesktop/login1"} - ); + auto proxy = make_login1_proxy(*connection); while (true) { From 52e3bf2e4a4fe5e75c96f758a6a863a6d341048e Mon Sep 17 00:00:00 2001 From: ConnorC432 Date: Fri, 20 Mar 2026 14:54:34 +0000 Subject: [PATCH 5/7] workflow libsystemd-dev --- .github/workflows/cpp-ci-serial-programs-base.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cpp-ci-serial-programs-base.yml b/.github/workflows/cpp-ci-serial-programs-base.yml index f15abcff3e..4666ed4b96 100644 --- a/.github/workflows/cpp-ci-serial-programs-base.yml +++ b/.github/workflows/cpp-ci-serial-programs-base.yml @@ -64,7 +64,7 @@ jobs: cd Arduino-Source sudo apt update sudo apt upgrade - sudo apt install clang-tools libopencv-dev libsdbus-c++-dev + sudo apt install clang-tools libopencv-dev libsdbus-c++-dev libsystemd-dev sudo apt install ./3rdPartyBinaries/libdpp-10.0.28-linux-x64.deb From 368a5bd8c78336b00b032ab90400835e4bac7c34 Mon Sep 17 00:00:00 2001 From: ConnorC432 Date: Fri, 20 Mar 2026 17:13:13 +0000 Subject: [PATCH 6/7] always use bundled sdbus-c++ --- .../workflows/cpp-ci-serial-programs-base.yml | 2 +- SerialPrograms/CMakeLists.txt | 26 ++++++------------- 2 files changed, 9 insertions(+), 19 deletions(-) diff --git a/.github/workflows/cpp-ci-serial-programs-base.yml b/.github/workflows/cpp-ci-serial-programs-base.yml index 4666ed4b96..d467c9db0b 100644 --- a/.github/workflows/cpp-ci-serial-programs-base.yml +++ b/.github/workflows/cpp-ci-serial-programs-base.yml @@ -64,7 +64,7 @@ jobs: cd Arduino-Source sudo apt update sudo apt upgrade - sudo apt install clang-tools libopencv-dev libsdbus-c++-dev libsystemd-dev + sudo apt install clang-tools libopencv-dev libsystemd-dev sudo apt install ./3rdPartyBinaries/libdpp-10.0.28-linux-x64.deb diff --git a/SerialPrograms/CMakeLists.txt b/SerialPrograms/CMakeLists.txt index 553fb6587f..1245b2af0a 100644 --- a/SerialPrograms/CMakeLists.txt +++ b/SerialPrograms/CMakeLists.txt @@ -449,24 +449,14 @@ else() # macOS and Linux endif() # Systemd DBus Library - find_package(sdbus-c++ 2.2.1 QUIET) - - if(TARGET sdbus-c++ AND sdbus-c++_VERSION VERSION_GREATER_EQUAL 2.2.1) - # Use System-installed library - message(STATUS "Using system-installed sdbus-c++ v${sdbus-c++_VERSION}") - target_link_libraries(SerialProgramsLib PRIVATE sdbus-c++) - target_link_libraries(SerialPrograms PRIVATE sdbus-c++) - else() - # Use bundled library - message(STATUS "sdbus-c++ >= 2.2.1 not found, using bundled library") - target_include_directories(SerialProgramsLib PRIVATE - ${REPO_ROOT_DIR}/3rdParty/sdbus-cpp/include - ) - target_link_libraries(SerialProgramsLib PRIVATE - ${REPO_ROOT_DIR}/3rdParty/sdbus-cpp/lib/libsdbus-c++.a - systemd - ) - endif() + message(STATUS "Using bundled sdbus-c++ library.") + target_include_directories(SerialProgramsLib PRIVATE + ${REPO_ROOT_DIR}/3rdParty/sdbus-cpp/include + ) + target_link_libraries(SerialProgramsLib PRIVATE + ${REPO_ROOT_DIR}/3rdParty/sdbus-cpp/lib/libsdbus-c++.a + systemd #sdbus-c++ relies on libsystemd, almost all distros should have this + ) endif() # end Linux # Find OpenCV From 94976467ea75f90a1882cad29456ca64fd340e6f Mon Sep 17 00:00:00 2001 From: ConnorC432 Date: Fri, 20 Mar 2026 17:20:06 +0000 Subject: [PATCH 7/7] Revert "sdbus-c++ overload wrapper" This reverts commit 92dacbab7d7d742deb619a0660edb78fc296da40. --- .../Environment/SystemSleep_Linux.tpp | 44 +++---------------- 1 file changed, 5 insertions(+), 39 deletions(-) diff --git a/SerialPrograms/Source/CommonFramework/Environment/SystemSleep_Linux.tpp b/SerialPrograms/Source/CommonFramework/Environment/SystemSleep_Linux.tpp index 21ebbcaee8..a6940957ed 100644 --- a/SerialPrograms/Source/CommonFramework/Environment/SystemSleep_Linux.tpp +++ b/SerialPrograms/Source/CommonFramework/Environment/SystemSleep_Linux.tpp @@ -15,44 +15,6 @@ namespace PokemonAutomation{ -// Strong typing overload -template -auto make_login1_proxy(Connection& connection, int) - -> decltype(sdbus::createProxy( - connection, - sdbus::BusName{"org.freedesktop.login1"}, - sdbus::ObjectPath{"/org/freedesktop/login1"} - )) -{ - return sdbus::createProxy( - connection, - sdbus::BusName{"org.freedesktop.login1"}, - sdbus::ObjectPath{"/org/freedesktop/login1"} - ); -} - -// Fallback overload -template -auto make_login1_proxy(Connection& connection, long) - -> decltype(sdbus::createProxy( - connection, - "org.freedesktop.login1", - "/org/freedesktop/login1" - )) -{ - return sdbus::createProxy( - connection, - "org.freedesktop.login1", - "/org/freedesktop/login1" - ); -} - -template -auto make_login1_proxy(Connection& connection) -{ - return make_login1_proxy(connection, 0); -} - class LinuxSleepController final : public SystemSleepController{ public: LinuxSleepController() @@ -112,7 +74,11 @@ private: void thread_loop() { auto connection = sdbus::createSystemBusConnection(); - auto proxy = make_login1_proxy(*connection); + auto proxy = sdbus::createProxy( + *connection, + sdbus::BusName{"org.freedesktop.login1"}, + sdbus::ObjectPath{"/org/freedesktop/login1"} + ); while (true) {