forked from Kistler-Group/sdbus-cpp
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0b27f222c4 | ||
|
|
58895d2730 | ||
|
|
d957948274 | ||
|
|
47fad7dd63 | ||
|
|
7378cea833 | ||
|
|
2526546432 | ||
|
|
9c0e98c580 | ||
|
|
2c78e08d19 | ||
|
|
97372155a6 | ||
|
|
1def4e247a | ||
|
|
d764afec93 | ||
|
|
eb58d2fa52 | ||
|
|
a6bb8c070e | ||
|
|
108c33faac | ||
|
|
ec06462713 | ||
|
|
234145cade | ||
|
|
e971f95bad |
@@ -1,35 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>sdbus-cpp</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.cdt.autotools.core.genmakebuilderV2</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.cdt.managedbuilder.core.genmakebuilder</name>
|
||||
<triggers>clean,full,incremental,</triggers>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder</name>
|
||||
<triggers>full,incremental,</triggers>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.cdt.core.cnature</nature>
|
||||
<nature>org.eclipse.cdt.core.ccnature</nature>
|
||||
<nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature>
|
||||
<nature>org.eclipse.cdt.managedbuilder.core.ScannerConfigNature</nature>
|
||||
<nature>org.yocto.sdk.ide.YoctoSDKNature</nature>
|
||||
<nature>org.eclipse.cdt.autotools.core.autotoolsNatureV2</nature>
|
||||
<nature>org.yocto.sdk.ide.YoctoSDKAutotoolsNature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
Executable
+146
@@ -0,0 +1,146 @@
|
||||
#-------------------------------
|
||||
# PROJECT INFORMATION
|
||||
#-------------------------------
|
||||
|
||||
cmake_minimum_required(VERSION 3.8)
|
||||
|
||||
project(sdbus-c++ VERSION 0.4.1 LANGUAGES C CXX)
|
||||
|
||||
include(GNUInstallDirs) # Installation directories for `install` command and pkgconfig file
|
||||
|
||||
#-------------------------------
|
||||
# PERFORMING CHECKS
|
||||
#-------------------------------
|
||||
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(SYSTEMD REQUIRED libsystemd>=236)
|
||||
|
||||
#-------------------------------
|
||||
# SOURCE FILES CONFIGURATION
|
||||
#-------------------------------
|
||||
|
||||
set(SDBUSCPP_SOURCE_DIR ${CMAKE_SOURCE_DIR}/src)
|
||||
set(SDBUSCPP_INCLUDE_SUBDIR sdbus-c++)
|
||||
set(SDBUSCPP_INCLUDE_DIR ${CMAKE_SOURCE_DIR}/include/${SDBUSCPP_INCLUDE_SUBDIR})
|
||||
|
||||
set(SDBUSCPP_CPP_SRCS
|
||||
${SDBUSCPP_SOURCE_DIR}/Connection.cpp
|
||||
${SDBUSCPP_SOURCE_DIR}/ConvenienceClasses.cpp
|
||||
${SDBUSCPP_SOURCE_DIR}/Error.cpp
|
||||
${SDBUSCPP_SOURCE_DIR}/Message.cpp
|
||||
${SDBUSCPP_SOURCE_DIR}/MethodResult.cpp
|
||||
${SDBUSCPP_SOURCE_DIR}/Object.cpp
|
||||
${SDBUSCPP_SOURCE_DIR}/ObjectProxy.cpp
|
||||
${SDBUSCPP_SOURCE_DIR}/Types.cpp
|
||||
${SDBUSCPP_SOURCE_DIR}/Flags.cpp
|
||||
${SDBUSCPP_SOURCE_DIR}/VTableUtils.c)
|
||||
|
||||
set(SDBUSCPP_HDR_SRCS
|
||||
${SDBUSCPP_SOURCE_DIR}/Connection.h
|
||||
${SDBUSCPP_SOURCE_DIR}/IConnection.h
|
||||
${SDBUSCPP_SOURCE_DIR}/MessageUtils.h
|
||||
${SDBUSCPP_SOURCE_DIR}/Object.h
|
||||
${SDBUSCPP_SOURCE_DIR}/ObjectProxy.h
|
||||
${SDBUSCPP_SOURCE_DIR}/ScopeGuard.h
|
||||
${SDBUSCPP_SOURCE_DIR}/VTableUtils.h)
|
||||
|
||||
set(SDBUSCPP_PUBLIC_HDRS
|
||||
${SDBUSCPP_INCLUDE_DIR}/ConvenienceClasses.h
|
||||
${SDBUSCPP_INCLUDE_DIR}/ConvenienceClasses.inl
|
||||
${SDBUSCPP_INCLUDE_DIR}/Error.h
|
||||
${SDBUSCPP_INCLUDE_DIR}/IConnection.h
|
||||
${SDBUSCPP_INCLUDE_DIR}/Interfaces.h
|
||||
${SDBUSCPP_INCLUDE_DIR}/Introspection.h
|
||||
${SDBUSCPP_INCLUDE_DIR}/IObject.h
|
||||
${SDBUSCPP_INCLUDE_DIR}/IObjectProxy.h
|
||||
${SDBUSCPP_INCLUDE_DIR}/Message.h
|
||||
${SDBUSCPP_INCLUDE_DIR}/MethodResult.h
|
||||
${SDBUSCPP_INCLUDE_DIR}/sdbus-c++.h
|
||||
${SDBUSCPP_INCLUDE_DIR}/Types.h
|
||||
${SDBUSCPP_INCLUDE_DIR}/TypeTraits.h
|
||||
${SDBUSCPP_INCLUDE_DIR}/Flags.h)
|
||||
|
||||
set(SDBUSCPP_SRCS ${SDBUSCPP_CPP_SRCS} ${SDBUSCPP_HDR_SRCS} ${SDBUSCPP_PUBLIC_HDRS})
|
||||
|
||||
#-------------------------------
|
||||
# GENERAL COMPILER CONFIGURATION
|
||||
#-------------------------------
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
include_directories("${CMAKE_SOURCE_DIR}/include")
|
||||
include_directories("${CMAKE_SOURCE_DIR}/src")
|
||||
|
||||
#----------------------------------
|
||||
# LIBRARY BUILD INFORMATION
|
||||
#----------------------------------
|
||||
|
||||
set(SDBUSCPP_VERSION_MAJOR "${PROJECT_VERSION_MAJOR}")
|
||||
set(SDBUSCPP_VERSION "${PROJECT_VERSION}")
|
||||
|
||||
# We are building in two steps: first objects, then link them into a library,
|
||||
# and that's because we need object files since unit tests link against them.
|
||||
add_library(sdbuscppobjects OBJECT ${SDBUSCPP_SRCS})
|
||||
target_include_directories(sdbuscppobjects PUBLIC ${SYSTEMD_INCLUDE_DIRS})
|
||||
target_compile_definitions(sdbuscppobjects PRIVATE BUILDLIB=1)
|
||||
set_target_properties(sdbuscppobjects PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
add_library(sdbus-c++ SHARED $<TARGET_OBJECTS:sdbuscppobjects>)
|
||||
set_target_properties(sdbus-c++
|
||||
PROPERTIES
|
||||
PUBLIC_HEADER "${SDBUSCPP_PUBLIC_HDRS}"
|
||||
VERSION "${SDBUSCPP_VERSION}"
|
||||
SOVERSION "${SDBUSCPP_VERSION_MAJOR}"
|
||||
OUTPUT_NAME "sdbus-c++")
|
||||
target_link_libraries(sdbus-c++ ${SYSTEMD_LIBRARIES})
|
||||
|
||||
#----------------------------------
|
||||
# INSTALLATION
|
||||
#----------------------------------
|
||||
|
||||
install(TARGETS sdbus-c++
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT libraries
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT libraries
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT static_libraries
|
||||
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${SDBUSCPP_INCLUDE_SUBDIR} COMPONENT dev)
|
||||
|
||||
#----------------------------------
|
||||
# TESTS
|
||||
#----------------------------------
|
||||
|
||||
option(ENABLE_TESTS "Build and install tests (default ON)" ON)
|
||||
|
||||
if(ENABLE_TESTS)
|
||||
enable_testing()
|
||||
add_subdirectory("${CMAKE_SOURCE_DIR}/test")
|
||||
endif()
|
||||
|
||||
#----------------------------------
|
||||
# UTILS
|
||||
#----------------------------------
|
||||
|
||||
option(BUILD_CODE_GEN "Build and install interface stub code generator (default OFF)" OFF)
|
||||
|
||||
if(BUILD_CODE_GEN)
|
||||
add_subdirectory("${CMAKE_SOURCE_DIR}/stub-generator")
|
||||
endif()
|
||||
|
||||
#----------------------------------
|
||||
# DOCUMENTATION
|
||||
#----------------------------------
|
||||
|
||||
# TODO Build doxygen
|
||||
|
||||
#----------------------------------
|
||||
# CMAKE CONFIG & PACKAGE CONFIG
|
||||
#----------------------------------
|
||||
|
||||
set(SDBUSCPP_CONFIG_INSTALL_DIR ${CMAKE_INSTALL_LIBDIR}/cmake/sdbus-c++)
|
||||
|
||||
configure_file(sdbus-c++-config.cmake.in sdbus-c++-config.cmake @ONLY)
|
||||
install(FILES ${CMAKE_BINARY_DIR}/sdbus-c++-config.cmake DESTINATION ${SDBUSCPP_CONFIG_INSTALL_DIR} COMPONENT dev)
|
||||
|
||||
configure_file(sdbus-c++-config-version.cmake.in sdbus-c++-config-version.cmake @ONLY)
|
||||
install(FILES ${CMAKE_BINARY_DIR}/sdbus-c++-config-version.cmake DESTINATION ${SDBUSCPP_CONFIG_INSTALL_DIR} COMPONENT dev)
|
||||
|
||||
configure_file(sdbus-c++.pc.in sdbus-c++.pc @ONLY)
|
||||
install(FILES ${CMAKE_BINARY_DIR}/sdbus-c++.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig COMPONENT dev)
|
||||
@@ -26,3 +26,18 @@ v0.3.0
|
||||
|
||||
v0.3.1
|
||||
- Fixed hogging the CPU by server with async methods (issue #15)
|
||||
|
||||
v0.3.2
|
||||
- Switched from autotools to CMake build system
|
||||
|
||||
v0.3.3
|
||||
- Minor fixes in tutorial examples
|
||||
- Add comment on threading traits of Variant and its const methods
|
||||
- Fix broken invariant of const Variant::peekValueType() method
|
||||
|
||||
v0.4.0
|
||||
- Introduce support and implementation of common D-Bus annotations
|
||||
- Remove hard-coded warning-related compiler options from the build system
|
||||
|
||||
v0.4.1
|
||||
- Change constexpr member into a getter method to be compatible across odr-usage rules of various compiler versions
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
Building:
|
||||
$ ./autogen.sh ${CONFIGURE_FLAGS}
|
||||
$ mkdir build
|
||||
$ cd build
|
||||
$ cmake .. ${CONFIGURE_FLAGS_IF_NECESSARY}
|
||||
$ make
|
||||
|
||||
Installing:
|
||||
|
||||
-22
@@ -1,22 +0,0 @@
|
||||
EXTRA_DIST = autogen.sh
|
||||
SUBDIRS = include src test
|
||||
|
||||
DISTCHECK_CONFIGURE_FLAGS=
|
||||
|
||||
pkgconfigdir = $(libdir)/pkgconfig
|
||||
pkgconfig_DATA = sdbus-c++.pc
|
||||
|
||||
CLEANFILES = *~ *.lo *.la
|
||||
|
||||
MOSTLYCLEANFILES = *.o
|
||||
|
||||
DISTCLEANFILES = \
|
||||
*libtool* \
|
||||
aclocal.m4 \
|
||||
compile config.* configure \
|
||||
depcomp install-sh \
|
||||
ltmain.sh \
|
||||
Makefile Makefile.in \
|
||||
missing \
|
||||
stamp-h1 \
|
||||
sdbus-c++.pc
|
||||
@@ -6,20 +6,26 @@ sdbus-c++ is a C++ API library for D-Bus IPC, based on sd-bus implementation.
|
||||
Building and installing the library
|
||||
-----------------------------------
|
||||
|
||||
The library is built using CMake:
|
||||
|
||||
```bash
|
||||
$ ./autogen.sh ${CONFIGURE_FLAGS}
|
||||
$ mkdir build
|
||||
$ cd build
|
||||
$ cmake .. ${CONFIGURE_FLAGS_IF_NECESSARY}
|
||||
$ make
|
||||
$ sudo make install
|
||||
```
|
||||
|
||||
Use `--disable-tests` flag when configuring to disable building unit and integration tests for the library.
|
||||
By default, the library builds its unit and integration tests. That incorporates downloading and building static libraries of Google Test. Use `-DENABLE_TESTS=OFF` configure flag if you want to disable building the tests.
|
||||
|
||||
By default, the library doesn't build the code generator for adaptor and proxy interfaces. Use `-DBUILD_CODE_GEN=ON` flag to also build the code generator.
|
||||
|
||||
Dependencies
|
||||
------------
|
||||
|
||||
* `C++17` - the library uses C++17 `std::uncaught_exceptions()` feature. When building sdbus-c++ manually, make sure you use a compiler that supports that feature.
|
||||
* `libsystemd` - systemd library containing sd-bus implementation. Systemd v236 at least is needed for sdbus-c++ to compile.
|
||||
* `googletest` - google unit testing framework, only necessary when building tests
|
||||
* `googletest` - google unit testing framework, only necessary when building tests, will be downloaded and built automatically
|
||||
|
||||
Licensing
|
||||
---------
|
||||
@@ -41,4 +47,4 @@ Contributions that increase the library quality, functionality, or fix issues ar
|
||||
Contact
|
||||
-------
|
||||
|
||||
stanislav.angelovic[at]kistler.com
|
||||
https://github.com/Kistler-Group/sdbus-cpp
|
||||
|
||||
-10
@@ -1,10 +0,0 @@
|
||||
#! /bin/sh
|
||||
[ -e config.cache ] && rm -f config.cache
|
||||
|
||||
libtoolize --automake
|
||||
aclocal ${OECORE_ACLOCAL_OPTS}
|
||||
autoconf
|
||||
autoheader
|
||||
automake -a
|
||||
./configure $@
|
||||
exit
|
||||
@@ -1,62 +0,0 @@
|
||||
AC_PREREQ(2.61)
|
||||
|
||||
# package version number (not shared library version)
|
||||
# odd micro numbers indicate in-progress development
|
||||
# even micro numbers indicate released versions
|
||||
m4_define(sdbus_cpp_version_major, 0)
|
||||
m4_define(sdbus_cpp_version_minor, 3)
|
||||
m4_define(sdbus_cpp_version_micro, 1)
|
||||
|
||||
m4_define([sdbus_cpp_version],
|
||||
[sdbus_cpp_version_major.sdbus_cpp_version_minor.sdbus_cpp_version_micro])
|
||||
m4_define([sdbus_cpp_api_version],
|
||||
[sdbus_cpp_version_major.sdbus_cpp_version_minor])
|
||||
|
||||
AC_INIT(libsdbus-c++, sdbus_cpp_version)
|
||||
AM_INIT_AUTOMAKE
|
||||
AC_CONFIG_HEADERS(config.h)
|
||||
|
||||
# Checks for programs.
|
||||
AC_PROG_LIBTOOL
|
||||
AC_PROG_CXX
|
||||
AC_PROG_CC
|
||||
AC_PROG_INSTALL
|
||||
|
||||
# enable pkg-config
|
||||
PKG_PROG_PKG_CONFIG
|
||||
|
||||
PKG_CHECK_MODULES(SYSTEMD, [libsystemd >= 236],,
|
||||
AC_MSG_ERROR([You need the libsystemd library (version 236 or newer)]
|
||||
[https://www.freedesktop.org/wiki/Software/systemd/])
|
||||
)
|
||||
|
||||
# Checks for library functions.
|
||||
#AC_CHECK_FUNCS([memset])
|
||||
|
||||
AC_SUBST(libsdbus_cpp_CFLAGS)
|
||||
AC_SUBST(libsdbus_cpp_LIBS)
|
||||
|
||||
AC_ARG_ENABLE([tests],
|
||||
[AS_HELP_STRING([--enable-tests],
|
||||
[build and install tests @<:@default=yes@:>@])],
|
||||
[],
|
||||
[enable_tests=yes])
|
||||
AM_CONDITIONAL([ENABLE_TESTS], [test x$enable_tests = xyes])
|
||||
|
||||
#icondir=${datadir}/icons/hicolor/32x32/apps
|
||||
#AC_SUBST(icondir)
|
||||
|
||||
AC_OUTPUT([
|
||||
Makefile
|
||||
include/Makefile
|
||||
src/Makefile
|
||||
test/Makefile
|
||||
sdbus-c++.pc
|
||||
])
|
||||
|
||||
echo ""
|
||||
echo " sdbus-cpp $VERSION"
|
||||
echo " ====================="
|
||||
echo ""
|
||||
echo " To build the project, run \"make\""
|
||||
echo ""
|
||||
+18
-17
@@ -29,21 +29,19 @@ method calls, signals and properties. There is room for additions and improvemen
|
||||
Integrating sdbus-c++ into your project
|
||||
---------------------------------------
|
||||
|
||||
The library build system is based on Autotools. The library supports `pkg-config`, so integrating it into your autotools project
|
||||
is a two step process.
|
||||
The library build system is based on CMake. The library provides a config file, so integrating it into your CMake project is rather straight-forward:
|
||||
|
||||
1. Add `PKG_CHECK_MODULES` macro into your `configure.ac`:
|
||||
```bash
|
||||
PKG_CHECK_MODULES(SDBUSCPP, [sdbus-c++ >= 0.1],,
|
||||
AC_MSG_ERROR([You need the sdbus-c++ library (version 0.1 or better)]
|
||||
[http://www.kistler.com/])
|
||||
)
|
||||
find_package(sdbus-c++ REQUIRED)
|
||||
```
|
||||
|
||||
2. Update `*_CFLAGS` and `*_LDFLAGS` in Makefiles of modules that use *sdbus-c++*, for example like this:
|
||||
The library also supports `pkg-config`, so it easily be integrated into e.g. an Autotools project:
|
||||
|
||||
```bash
|
||||
AM_CXXFLAGS = -std=c++17 -pedantic -W -Wall @SDBUSCPP_CFLAGS@ ...
|
||||
AM_LDFLAGS = @SDBUSCPP_LIBS@ ...
|
||||
PKG_CHECK_MODULES(SDBUSCPP, [sdbus-c++ >= 0.4],,
|
||||
AC_MSG_ERROR([You need the sdbus-c++ library (version 0.4 or newer)]
|
||||
[http://www.kistler.com/])
|
||||
)
|
||||
```
|
||||
|
||||
Note: sdbus-c++ library depends on C++17, since it uses C++17 `std::uncaught_exceptions()` feature. When building sdbus-c++ manually, make sure you use a compiler that supports that feature. To use the library, make sure you have a C++ standard library that supports the feature. The feature is supported by e.g. gcc >= 6, and clang >= 3.7.
|
||||
@@ -211,9 +209,9 @@ void onConcatenated(sdbus::Signal& signal)
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// Create proxy object for the concatenator object on the server side. Since we don't pass
|
||||
// the D-Bus connection object to the proxy constructor, the proxy will internally create
|
||||
// its own connection to the system bus.
|
||||
// Create proxy object for the concatenator object on the server side. Since here
|
||||
// we are creating the proxy instance without passing connection to it, the proxy
|
||||
// will create its own connection automatically, and it will be system bus connection.
|
||||
const char* destinationName = "org.sdbuscpp.concatenator";
|
||||
const char* objectPath = "/org/sdbuscpp/concatenator";
|
||||
auto concatenatorProxy = sdbus::createObjectProxy(destinationName, objectPath);
|
||||
@@ -258,9 +256,9 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
```
|
||||
|
||||
The object proxy is created without explicitly providing a D-Bus connection as an argument in its factory function. In that case, the proxy
|
||||
will create its own connection to the *system* bus and listen to signals on it in a separate thread. That means the `onConcatenated` method is invoked always
|
||||
in the context of a thread different from the main thread.
|
||||
The object proxy can be created by either explicitly passing the connection object to it, or without the connection object. In the former case, we have the freedom of creating our own connection (to either system bus or to session bus) and then we can just move that connection object as the first argument of the proxy factory. The latter option is more convenient (no messing with connection for proxy), the proxy will create and manage its own connection, but the limitation is that it will be the connection to the **system** bus only.
|
||||
|
||||
If there are callbacks for signals, proxy will start listening to the signals upon the connection in a separate thread. That means the `onConcatenated` method is invoked always in the context of a thread different from the main thread.
|
||||
|
||||
Implementing the Concatenator example using convenience sdbus-c++ API layer
|
||||
---------------------------------------------------------------------------
|
||||
@@ -357,7 +355,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
// Let's subscribe for the 'concatenated' signals
|
||||
const char* interfaceName = "org.sdbuscpp.Concatenator";
|
||||
concatenatorProxy->uponSignal("concatenated").onInterface(interfaceName).call([this](const std::string& str){ onConcatenated(str); });
|
||||
concatenatorProxy->uponSignal("concatenated").onInterface(interfaceName).call([](const std::string& str){ onConcatenated(str); });
|
||||
concatenatorProxy->finishRegistration();
|
||||
|
||||
std::vector<int> numbers = {1, 2, 3};
|
||||
@@ -630,10 +628,13 @@ protected:
|
||||
};
|
||||
```
|
||||
|
||||
In the above example, a proxy is created that creates and maintains its own system bus connection. However, there are `ProxyInterfaces` class template constructor overloads that also take the connection from the user as the first parameter, and pass that connection over to the underlying proxy. The connection instance is used for all D-Bus proxy interfaces listed in the `ProxyInterfaces` template parameter list.
|
||||
|
||||
Now let's use this proxy to make remote calls and listen to signals in a real application.
|
||||
|
||||
```cpp
|
||||
#include "ConcatenatorProxy.h"
|
||||
#include <unistd.h>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
|
||||
# Distribution
|
||||
# Headers will be installed to $(includedir)/sdbus-c++ directory
|
||||
|
||||
HEADER_DIR = sdbus-c++
|
||||
libsdbuscppdir = $(includedir)/$(HEADER_DIR)
|
||||
libsdbuscpp_HEADERS = \
|
||||
$(HEADER_DIR)/ConvenienceClasses.h \
|
||||
$(HEADER_DIR)/ConvenienceClasses.inl \
|
||||
$(HEADER_DIR)/Error.h \
|
||||
$(HEADER_DIR)/IConnection.h \
|
||||
$(HEADER_DIR)/Interfaces.h \
|
||||
$(HEADER_DIR)/Introspection.h \
|
||||
$(HEADER_DIR)/IObject.h \
|
||||
$(HEADER_DIR)/IObjectProxy.h \
|
||||
$(HEADER_DIR)/Message.h \
|
||||
$(HEADER_DIR)/MethodResult.h \
|
||||
$(HEADER_DIR)/Types.h \
|
||||
$(HEADER_DIR)/TypeTraits.h \
|
||||
$(HEADER_DIR)/sdbus-c++.h
|
||||
|
||||
EXTRA_DIST = ($libsdbuscpp_HEADERS)
|
||||
|
||||
DISTCLEANFILES = Makefile Makefile.in
|
||||
@@ -28,6 +28,7 @@
|
||||
|
||||
#include <sdbus-c++/Message.h>
|
||||
#include <sdbus-c++/TypeTraits.h>
|
||||
#include <sdbus-c++/Flags.h>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
@@ -44,16 +45,29 @@ namespace sdbus {
|
||||
{
|
||||
public:
|
||||
MethodRegistrator(IObject& object, const std::string& methodName);
|
||||
MethodRegistrator(MethodRegistrator&& other) = default;
|
||||
MethodRegistrator& operator=(MethodRegistrator&& other) = default;
|
||||
~MethodRegistrator() noexcept(false);
|
||||
|
||||
MethodRegistrator& onInterface(const std::string& interfaceName);
|
||||
template <typename _Function>
|
||||
std::enable_if_t<!is_async_method_v<_Function>> implementedAs(_Function&& callback);
|
||||
std::enable_if_t<!is_async_method_v<_Function>, MethodRegistrator&> implementedAs(_Function&& callback);
|
||||
template <typename _Function>
|
||||
std::enable_if_t<is_async_method_v<_Function>> implementedAs(_Function&& callback);
|
||||
std::enable_if_t<is_async_method_v<_Function>, MethodRegistrator&> implementedAs(_Function&& callback);
|
||||
MethodRegistrator& markAsDeprecated();
|
||||
MethodRegistrator& markAsPrivileged();
|
||||
MethodRegistrator& withNoReply();
|
||||
|
||||
private:
|
||||
IObject& object_;
|
||||
const std::string& methodName_;
|
||||
std::string interfaceName_;
|
||||
std::string inputSignature_;
|
||||
std::string outputSignature_;
|
||||
method_callback syncCallback_;
|
||||
async_method_callback asyncCallback_;
|
||||
Flags flags_;
|
||||
int exceptions_{}; // Number of active exceptions when SignalRegistrator is constructed
|
||||
};
|
||||
|
||||
class SignalRegistrator
|
||||
@@ -63,14 +77,17 @@ namespace sdbus {
|
||||
SignalRegistrator(SignalRegistrator&& other) = default;
|
||||
SignalRegistrator& operator=(SignalRegistrator&& other) = default;
|
||||
~SignalRegistrator() noexcept(false);
|
||||
|
||||
SignalRegistrator& onInterface(std::string interfaceName);
|
||||
template <typename... _Args> void withParameters();
|
||||
template <typename... _Args> SignalRegistrator& withParameters();
|
||||
SignalRegistrator& markAsDeprecated();
|
||||
|
||||
private:
|
||||
IObject& object_;
|
||||
const std::string& signalName_;
|
||||
std::string interfaceName_;
|
||||
std::string signalSignature_;
|
||||
Flags flags_;
|
||||
int exceptions_{}; // Number of active exceptions when SignalRegistrator is constructed
|
||||
};
|
||||
|
||||
@@ -81,9 +98,13 @@ namespace sdbus {
|
||||
PropertyRegistrator(PropertyRegistrator&& other) = default;
|
||||
PropertyRegistrator& operator=(PropertyRegistrator&& other) = default;
|
||||
~PropertyRegistrator() noexcept(false);
|
||||
|
||||
PropertyRegistrator& onInterface(const std::string& interfaceName);
|
||||
template <typename _Function> PropertyRegistrator& withGetter(_Function&& callback);
|
||||
template <typename _Function> PropertyRegistrator& withSetter(_Function&& callback);
|
||||
PropertyRegistrator& markAsDeprecated();
|
||||
PropertyRegistrator& markAsPrivileged();
|
||||
PropertyRegistrator& withUpdateBehavior(Flags::PropertyUpdateBehaviorFlags behavior);
|
||||
|
||||
private:
|
||||
IObject& object_;
|
||||
@@ -92,9 +113,30 @@ namespace sdbus {
|
||||
std::string propertySignature_;
|
||||
property_get_callback getter_;
|
||||
property_set_callback setter_;
|
||||
Flags flags_;
|
||||
int exceptions_{}; // Number of active exceptions when PropertyRegistrator is constructed
|
||||
};
|
||||
|
||||
class InterfaceFlagsSetter
|
||||
{
|
||||
public:
|
||||
InterfaceFlagsSetter(IObject& object, const std::string& interfaceName);
|
||||
InterfaceFlagsSetter(InterfaceFlagsSetter&& other) = default;
|
||||
InterfaceFlagsSetter& operator=(InterfaceFlagsSetter&& other) = default;
|
||||
~InterfaceFlagsSetter() noexcept(false);
|
||||
|
||||
InterfaceFlagsSetter& markAsDeprecated();
|
||||
InterfaceFlagsSetter& markAsPrivileged();
|
||||
InterfaceFlagsSetter& withNoReplyMethods();
|
||||
InterfaceFlagsSetter& withPropertyUpdateBehavior(Flags::PropertyUpdateBehaviorFlags behavior);
|
||||
|
||||
private:
|
||||
IObject& object_;
|
||||
const std::string& interfaceName_;
|
||||
Flags flags_;
|
||||
int exceptions_{}; // Number of active exceptions when InterfaceFlagsSetter is constructed
|
||||
};
|
||||
|
||||
class SignalEmitter
|
||||
{
|
||||
public:
|
||||
@@ -123,6 +165,7 @@ namespace sdbus {
|
||||
MethodInvoker& onInterface(const std::string& interfaceName);
|
||||
template <typename... _Args> MethodInvoker& withArguments(_Args&&... args);
|
||||
template <typename... _Args> void storeResultsTo(_Args&... args);
|
||||
void dontExpectReply();
|
||||
|
||||
private:
|
||||
IObjectProxy& objectProxy_;
|
||||
|
||||
@@ -39,12 +39,41 @@
|
||||
|
||||
namespace sdbus {
|
||||
|
||||
// Moved into the library to isolate from C++17 dependency
|
||||
/*
|
||||
inline MethodRegistrator::MethodRegistrator(IObject& object, const std::string& methodName)
|
||||
: object_(object)
|
||||
, methodName_(methodName)
|
||||
, exceptions_(std::uncaught_exceptions()) // Needs C++17
|
||||
{
|
||||
}
|
||||
|
||||
inline MethodRegistrator::~MethodRegistrator() noexcept(false) // since C++11, destructors must
|
||||
{ // explicitly be allowed to throw
|
||||
// Don't register the method if MethodRegistrator threw an exception in one of its methods
|
||||
if (std::uncaught_exceptions() != exceptions_)
|
||||
return;
|
||||
|
||||
SDBUS_THROW_ERROR_IF(interfaceName_.empty(), "DBus interface not specified when registering a DBus method", EINVAL);
|
||||
|
||||
// registerMethod() can throw. But as the MethodRegistrator 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 registerMethod() 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.
|
||||
if (syncCallback_)
|
||||
object_.registerMethod(interfaceName_, methodName_, inputSignature_, outputSignature_, std::move(syncCallback_));
|
||||
else if(asyncCallback_)
|
||||
object_.registerMethod(interfaceName_, methodName_, inputSignature_, outputSignature_, std::move(asyncCallback_));
|
||||
else
|
||||
SDBUS_THROW_ERROR("Method handler not specified when registering a DBus method", EINVAL);
|
||||
}
|
||||
*/
|
||||
|
||||
inline MethodRegistrator& MethodRegistrator::onInterface(const std::string& interfaceName)
|
||||
{
|
||||
interfaceName_ = interfaceName;
|
||||
@@ -53,15 +82,11 @@ namespace sdbus {
|
||||
}
|
||||
|
||||
template <typename _Function>
|
||||
inline std::enable_if_t<!is_async_method_v<_Function>> MethodRegistrator::implementedAs(_Function&& callback)
|
||||
inline std::enable_if_t<!is_async_method_v<_Function>, MethodRegistrator&> MethodRegistrator::implementedAs(_Function&& callback)
|
||||
{
|
||||
SDBUS_THROW_ERROR_IF(interfaceName_.empty(), "DBus interface not specified when registering a DBus method", EINVAL);
|
||||
|
||||
object_.registerMethod( interfaceName_
|
||||
, methodName_
|
||||
, signature_of_function_input_arguments<_Function>::str()
|
||||
, signature_of_function_output_arguments<_Function>::str()
|
||||
, [callback = std::forward<_Function>(callback)](MethodCall& msg, MethodReply& reply)
|
||||
inputSignature_ = signature_of_function_input_arguments<_Function>::str();
|
||||
outputSignature_ = signature_of_function_output_arguments<_Function>::str();
|
||||
syncCallback_ = [callback = std::forward<_Function>(callback)](MethodCall& msg, MethodReply& reply)
|
||||
{
|
||||
// Create a tuple of callback input arguments' types, which will be used
|
||||
// as a storage for the argument values deserialized from the message.
|
||||
@@ -78,19 +103,17 @@ namespace sdbus {
|
||||
// The return value is stored to the reply message.
|
||||
// In case of void functions, ret is an empty tuple and thus nothing is stored.
|
||||
reply << ret;
|
||||
});
|
||||
};
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename _Function>
|
||||
inline std::enable_if_t<is_async_method_v<_Function>> MethodRegistrator::implementedAs(_Function&& callback)
|
||||
inline std::enable_if_t<is_async_method_v<_Function>, MethodRegistrator&> MethodRegistrator::implementedAs(_Function&& callback)
|
||||
{
|
||||
SDBUS_THROW_ERROR_IF(interfaceName_.empty(), "DBus interface not specified when registering a DBus method", EINVAL);
|
||||
|
||||
object_.registerMethod( interfaceName_
|
||||
, methodName_
|
||||
, signature_of_function_input_arguments<_Function>::str()
|
||||
, signature_of_function_output_arguments<_Function>::str() //signature_of<last_function_argument_t<_Function>>::str() // because last argument contains output types
|
||||
, [callback = std::forward<_Function>(callback)](MethodCall& msg, MethodResult result)
|
||||
inputSignature_ = signature_of_function_input_arguments<_Function>::str();
|
||||
outputSignature_ = signature_of_function_output_arguments<_Function>::str();
|
||||
asyncCallback_ = [callback = std::forward<_Function>(callback)](MethodCall& msg, MethodResult result)
|
||||
{
|
||||
// Create a tuple of callback input arguments' types, which will be used
|
||||
// as a storage for the argument values deserialized from the message.
|
||||
@@ -102,9 +125,33 @@ namespace sdbus {
|
||||
|
||||
// Invoke callback with input arguments from the tuple.
|
||||
sdbus::apply(callback, std::move(result), inputArgs); // TODO: Use std::apply when switching to full C++17 support
|
||||
});
|
||||
};
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline MethodRegistrator& MethodRegistrator::markAsDeprecated()
|
||||
{
|
||||
flags_.set(Flags::DEPRECATED);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline MethodRegistrator& MethodRegistrator::markAsPrivileged()
|
||||
{
|
||||
flags_.set(Flags::PRIVILEGED);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline MethodRegistrator& MethodRegistrator::withNoReply()
|
||||
{
|
||||
flags_.set(Flags::METHOD_NO_REPLY);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
// Moved into the library to isolate from C++17 dependency
|
||||
/*
|
||||
inline SignalRegistrator::SignalRegistrator(IObject& object, std::string signalName)
|
||||
@@ -144,9 +191,18 @@ namespace sdbus {
|
||||
}
|
||||
|
||||
template <typename... _Args>
|
||||
inline void SignalRegistrator::withParameters()
|
||||
inline SignalRegistrator& SignalRegistrator::withParameters()
|
||||
{
|
||||
signalSignature_ = signature_of_function_input_arguments<void(_Args...)>::str();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline SignalRegistrator& SignalRegistrator::markAsDeprecated()
|
||||
{
|
||||
flags_.set(Flags::DEPRECATED);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
@@ -234,6 +290,87 @@ namespace sdbus {
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline PropertyRegistrator& PropertyRegistrator::markAsDeprecated()
|
||||
{
|
||||
flags_.set(Flags::DEPRECATED);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline PropertyRegistrator& PropertyRegistrator::markAsPrivileged()
|
||||
{
|
||||
flags_.set(Flags::PRIVILEGED);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline PropertyRegistrator& PropertyRegistrator::withUpdateBehavior(Flags::PropertyUpdateBehaviorFlags behavior)
|
||||
{
|
||||
flags_.set(behavior);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
// Moved into the library to isolate from C++17 dependency
|
||||
/*
|
||||
inline InterfaceFlagsSetter::InterfaceFlagsSetter(IObject& object, const std::string& interfaceName)
|
||||
: object_(object)
|
||||
, interfaceName_(interfaceName)
|
||||
, exceptions_(std::uncaught_exceptions())
|
||||
{
|
||||
}
|
||||
|
||||
inline InterfaceFlagsSetter::~InterfaceFlagsSetter() noexcept(false) // since C++11, destructors must
|
||||
{ // explicitly be allowed to throw
|
||||
// Don't set any flags if InterfaceFlagsSetter threw an exception in one of its methods
|
||||
if (std::uncaught_exceptions() != exceptions_)
|
||||
return;
|
||||
|
||||
SDBUS_THROW_ERROR_IF(interfaceName_.empty(), "DBus interface not specified when setting its flags", EINVAL);
|
||||
|
||||
// setInterfaceFlags() can throw. But as the InterfaceFlagsSetter 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 setInterfaceFlags() 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_.setInterfaceFlags( std::move(interfaceName_)
|
||||
, std::move(flags_) );
|
||||
}
|
||||
*/
|
||||
|
||||
inline InterfaceFlagsSetter& InterfaceFlagsSetter::markAsDeprecated()
|
||||
{
|
||||
flags_.set(Flags::DEPRECATED);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline InterfaceFlagsSetter& InterfaceFlagsSetter::markAsPrivileged()
|
||||
{
|
||||
flags_.set(Flags::PRIVILEGED);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline InterfaceFlagsSetter& InterfaceFlagsSetter::withNoReplyMethods()
|
||||
{
|
||||
flags_.set(Flags::METHOD_NO_REPLY);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline InterfaceFlagsSetter& InterfaceFlagsSetter::withPropertyUpdateBehavior(Flags::PropertyUpdateBehaviorFlags behavior)
|
||||
{
|
||||
flags_.set(behavior);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
// Moved into the library to isolate from C++17 dependency
|
||||
/*
|
||||
@@ -342,6 +479,13 @@ namespace sdbus {
|
||||
detail::deserialize_pack(reply, args...);
|
||||
}
|
||||
|
||||
inline void MethodInvoker::dontExpectReply()
|
||||
{
|
||||
SDBUS_THROW_ERROR_IF(!method_.isValid(), "DBus interface not specified when calling a DBus method", EINVAL);
|
||||
|
||||
method_.dontExpectReply();
|
||||
}
|
||||
|
||||
|
||||
inline SignalSubscriber::SignalSubscriber(IObjectProxy& objectProxy, const std::string& signalName)
|
||||
: objectProxy_(objectProxy)
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
/**
|
||||
* (C) 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
*
|
||||
* @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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef SDBUS_CXX_FLAGS_H_
|
||||
#define SDBUS_CXX_FLAGS_H_
|
||||
|
||||
#include <bitset>
|
||||
#include <cstdint>
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
bool test(GeneralFlags flag) const
|
||||
{
|
||||
return flags_.test(flag);
|
||||
}
|
||||
|
||||
bool test(PropertyUpdateBehaviorFlags flag) const
|
||||
{
|
||||
return flags_.test(flag);
|
||||
}
|
||||
|
||||
uint64_t toSdBusInterfaceFlags() const;
|
||||
uint64_t toSdBusMethodFlags() const;
|
||||
uint64_t toSdBusSignalFlags() const;
|
||||
uint64_t toSdBusPropertyFlags() const;
|
||||
uint64_t toSdBusWritablePropertyFlags() const;
|
||||
|
||||
private:
|
||||
std::bitset<FLAG_COUNT> flags_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* SDBUS_CXX_FLAGS_H_ */
|
||||
@@ -28,6 +28,7 @@
|
||||
|
||||
#include <sdbus-c++/ConvenienceClasses.h>
|
||||
#include <sdbus-c++/TypeTraits.h>
|
||||
#include <sdbus-c++/Flags.h>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
@@ -61,6 +62,7 @@ namespace sdbus {
|
||||
* @param[in] inputSignature D-Bus signature of method input parameters
|
||||
* @param[in] outputSignature D-Bus signature of method output parameters
|
||||
* @param[in] methodCallback Callback that implements the body of the method
|
||||
* @param[in] noReply If true, the method isn't expected to send reply
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
@@ -68,7 +70,8 @@ namespace sdbus {
|
||||
, const std::string& methodName
|
||||
, const std::string& inputSignature
|
||||
, const std::string& outputSignature
|
||||
, method_callback methodCallback ) = 0;
|
||||
, method_callback methodCallback
|
||||
, Flags flags = {} ) = 0;
|
||||
|
||||
/*!
|
||||
* @brief Registers method that the object will provide on D-Bus
|
||||
@@ -78,6 +81,7 @@ namespace sdbus {
|
||||
* @param[in] inputSignature D-Bus signature of method input parameters
|
||||
* @param[in] outputSignature D-Bus signature of method output parameters
|
||||
* @param[in] asyncMethodCallback Callback that implements the body of the method
|
||||
* @param[in] noReply If true, the method isn't expected to send reply
|
||||
*
|
||||
* This overload register a method callback that will have a freedom to execute
|
||||
* its body in asynchronous contexts, and send the results from those contexts.
|
||||
@@ -90,7 +94,8 @@ namespace sdbus {
|
||||
, const std::string& methodName
|
||||
, const std::string& inputSignature
|
||||
, const std::string& outputSignature
|
||||
, async_method_callback asyncMethodCallback ) = 0;
|
||||
, async_method_callback asyncMethodCallback
|
||||
, Flags flags = {} ) = 0;
|
||||
|
||||
/*!
|
||||
* @brief Registers signal that the object will emit on D-Bus
|
||||
@@ -103,7 +108,8 @@ namespace sdbus {
|
||||
*/
|
||||
virtual void registerSignal( const std::string& interfaceName
|
||||
, const std::string& signalName
|
||||
, const std::string& signature ) = 0;
|
||||
, const std::string& signature
|
||||
, Flags flags = {} ) = 0;
|
||||
|
||||
/*!
|
||||
* @brief Registers read-only property that the object will provide on D-Bus
|
||||
@@ -118,7 +124,8 @@ namespace sdbus {
|
||||
virtual void registerProperty( const std::string& interfaceName
|
||||
, const std::string& propertyName
|
||||
, const std::string& signature
|
||||
, property_get_callback getCallback ) = 0;
|
||||
, property_get_callback getCallback
|
||||
, Flags flags = {} ) = 0;
|
||||
|
||||
/*!
|
||||
* @brief Registers read/write property that the object will provide on D-Bus
|
||||
@@ -135,7 +142,18 @@ namespace sdbus {
|
||||
, const std::string& propertyName
|
||||
, const std::string& signature
|
||||
, property_get_callback getCallback
|
||||
, property_set_callback setCallback ) = 0;
|
||||
, property_set_callback setCallback
|
||||
, Flags flags = {} ) = 0;
|
||||
|
||||
/*!
|
||||
* @brief Sets flags for a given interface
|
||||
*
|
||||
* @param[in] interfaceName Name of an interface whose flags will be set
|
||||
* @param[in] flags Flags to be set
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
virtual void setInterfaceFlags(const std::string& interfaceName, Flags flags) = 0;
|
||||
|
||||
/*!
|
||||
* @brief Finishes the registration and exports object API on D-Bus
|
||||
@@ -231,6 +249,23 @@ namespace sdbus {
|
||||
*/
|
||||
PropertyRegistrator registerProperty(const std::string& propertyName);
|
||||
|
||||
/*!
|
||||
* @brief Sets flags (annotations) for a given interface
|
||||
*
|
||||
* @param[in] interfaceName Name of an interface whose flags will be set
|
||||
* @return A helper object for convenient setting of Interface flags
|
||||
*
|
||||
* This is a high-level, convenience alternative to the other setInterfaceFlags overload.
|
||||
*
|
||||
* Example of use:
|
||||
* @code
|
||||
* object_.setInterfaceFlags("com.kistler.foo").markAsDeprecated().withPropertyUpdateBehavior(sdbus::Flags::EMITS_NO_SIGNAL);
|
||||
* @endcode
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
InterfaceFlagsSetter setInterfaceFlags(const std::string& interfaceName);
|
||||
|
||||
/*!
|
||||
* @brief Emits signal on D-Bus
|
||||
*
|
||||
@@ -270,6 +305,11 @@ namespace sdbus {
|
||||
return PropertyRegistrator(*this, std::move(propertyName));
|
||||
}
|
||||
|
||||
inline InterfaceFlagsSetter IObject::setInterfaceFlags(const std::string& interfaceName)
|
||||
{
|
||||
return InterfaceFlagsSetter(*this, std::move(interfaceName));
|
||||
}
|
||||
|
||||
inline SignalEmitter IObject::emitSignal(const std::string& signalName)
|
||||
{
|
||||
return SignalEmitter(*this, signalName);
|
||||
|
||||
@@ -72,6 +72,14 @@ namespace sdbus {
|
||||
* @brief Calls method on the proxied D-Bus object
|
||||
*
|
||||
* @param[in] message Message representing a method call
|
||||
* @return A method reply message
|
||||
*
|
||||
* Normally, the call is blocking, i.e. it waits for the remote method to finish with either
|
||||
* a return value or an error.
|
||||
*
|
||||
* If the method call argument is set to not expect reply, the call will not wait for the remote
|
||||
* method to finish, i.e. the call will be non-blocking, and the function will return an empty,
|
||||
* invalid MethodReply object (representing void).
|
||||
*
|
||||
* Note: To avoid messing with messages, use higher-level API defined below.
|
||||
*
|
||||
|
||||
@@ -113,6 +113,13 @@ namespace sdbus {
|
||||
{
|
||||
getObject().finishRegistration();
|
||||
}
|
||||
|
||||
ProxyInterfaces(std::unique_ptr<sdbus::IConnection>&& connection, std::string destination, std::string objectPath)
|
||||
: ObjectHolder<IObjectProxy>(createObjectProxy(std::move(connection), std::move(destination), std::move(objectPath)))
|
||||
, _Interfaces(getObject())...
|
||||
{
|
||||
getObject().finishRegistration();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -155,6 +155,12 @@ namespace sdbus {
|
||||
MethodReply send() const;
|
||||
MethodReply createReply() const;
|
||||
MethodReply createErrorReply(const sdbus::Error& error) const;
|
||||
void dontExpectReply();
|
||||
bool doesntExpectReply() const;
|
||||
|
||||
private:
|
||||
MethodReply sendWithReply() const;
|
||||
MethodReply sendWithNoReply() const;
|
||||
};
|
||||
|
||||
class MethodReply : public Message
|
||||
|
||||
@@ -40,6 +40,12 @@ 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
|
||||
|
||||
Executable
+11
@@ -0,0 +1,11 @@
|
||||
set(PACKAGE_VERSION "@SDBUSCPP_VERSION@")
|
||||
|
||||
# Check whether the requested PACKAGE_FIND_VERSION is compatible
|
||||
if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}")
|
||||
set(PACKAGE_VERSION_COMPATIBLE FALSE)
|
||||
else()
|
||||
set(PACKAGE_VERSION_COMPATIBLE TRUE)
|
||||
if ("${PACKAGE_VERSION}" VERSION_EQUAL "${PACKAGE_FIND_VERSION}")
|
||||
set(PACKAGE_VERSION_EXACT TRUE)
|
||||
endif()
|
||||
endif()
|
||||
Executable
+14
@@ -0,0 +1,14 @@
|
||||
# Config file for the sdbus-c++ package.
|
||||
#
|
||||
# It defines the following variables:
|
||||
# SDBUSCPP_VERSION - version of sdbus-c++
|
||||
# SDBUSCPP_FOUND - set to true
|
||||
# SDBUSCPP_INCLUDE_DIRS - include directories for sdbus-c++
|
||||
# SDBUSCPP_LIBRARY_DIR - library directories for sdbus-c++
|
||||
# SDBUSCPP_LIBRARIES - libraries to link against
|
||||
|
||||
set(SDBUSCPP_VERSION "@SDBUSCPP_VERSION@")
|
||||
set(SDBUSCPP_FOUND "TRUE")
|
||||
set(SDBUSCPP_INCLUDE_DIRS "@CMAKE_INSTALL_FULL_INCLUDEDIR@")
|
||||
set(SDBUSCPP_LIBRARY_DIR "@CMAKE_INSTALL_FULL_LIBDIR@")
|
||||
set(SDBUSCPP_LIBRARIES sdbus-c++)
|
||||
Regular → Executable
+8
-8
@@ -1,11 +1,11 @@
|
||||
prefix=@prefix@
|
||||
exec_prefix=@exec_prefix@
|
||||
libdir=@libdir@
|
||||
includedir=@includedir@
|
||||
prefix=@CMAKE_INSTALL_PREFIX@
|
||||
exec_prefix=@CMAKE_INSTALL_PREFIX@
|
||||
libdir=@CMAKE_INSTALL_FULL_LIBDIR@
|
||||
includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@
|
||||
|
||||
Name: @PACKAGE@
|
||||
Description: C++ bindings library for sd-bus
|
||||
Name: @PROJECT_NAME@
|
||||
Description: C++ library on top of sd-bus, a systemd D-Bus library
|
||||
Requires: libsystemd
|
||||
Version: @VERSION@
|
||||
Libs: -L${libdir} -lsdbus-c++
|
||||
Version: @SDBUSCPP_VERSION@
|
||||
Libs: -L${libdir} -l@PROJECT_NAME@
|
||||
Cflags: -I${includedir}
|
||||
|
||||
@@ -31,6 +31,38 @@
|
||||
|
||||
namespace sdbus {
|
||||
|
||||
MethodRegistrator::MethodRegistrator(IObject& object, const std::string& methodName)
|
||||
: object_(object)
|
||||
, methodName_(methodName)
|
||||
, exceptions_(std::uncaught_exceptions()) // Needs C++17
|
||||
{
|
||||
}
|
||||
|
||||
MethodRegistrator::~MethodRegistrator() noexcept(false) // since C++11, destructors must
|
||||
{ // explicitly be allowed to throw
|
||||
// Don't register the method if MethodRegistrator threw an exception in one of its methods
|
||||
if (std::uncaught_exceptions() != exceptions_)
|
||||
return;
|
||||
|
||||
SDBUS_THROW_ERROR_IF(interfaceName_.empty(), "DBus interface not specified when registering a DBus method", EINVAL);
|
||||
|
||||
// registerMethod() can throw. But as the MethodRegistrator 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 registerMethod() 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.
|
||||
if (syncCallback_)
|
||||
object_.registerMethod(interfaceName_, methodName_, inputSignature_, outputSignature_, std::move(syncCallback_), flags_);
|
||||
else if(asyncCallback_)
|
||||
object_.registerMethod(interfaceName_, methodName_, inputSignature_, outputSignature_, std::move(asyncCallback_), flags_);
|
||||
else
|
||||
SDBUS_THROW_ERROR("Method handler not specified when registering a DBus method", EINVAL);
|
||||
}
|
||||
|
||||
SignalRegistrator::SignalRegistrator(IObject& object, const std::string& signalName)
|
||||
: object_(object)
|
||||
, signalName_(signalName)
|
||||
@@ -55,7 +87,7 @@ SignalRegistrator::~SignalRegistrator() noexcept(false) // since C++11, destruct
|
||||
// Therefore, we can allow registerSignal() 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_.registerSignal(interfaceName_, signalName_, signalSignature_);
|
||||
object_.registerSignal(interfaceName_, signalName_, signalSignature_, flags_);
|
||||
}
|
||||
|
||||
|
||||
@@ -87,7 +119,37 @@ PropertyRegistrator::~PropertyRegistrator() noexcept(false) // since C++11, dest
|
||||
, std::move(propertyName_)
|
||||
, std::move(propertySignature_)
|
||||
, std::move(getter_)
|
||||
, std::move(setter_) );
|
||||
, std::move(setter_)
|
||||
, flags_ );
|
||||
}
|
||||
|
||||
|
||||
InterfaceFlagsSetter::InterfaceFlagsSetter(IObject& object, const std::string& interfaceName)
|
||||
: object_(object)
|
||||
, interfaceName_(interfaceName)
|
||||
, exceptions_(std::uncaught_exceptions())
|
||||
{
|
||||
}
|
||||
|
||||
InterfaceFlagsSetter::~InterfaceFlagsSetter() noexcept(false) // since C++11, destructors must
|
||||
{ // explicitly be allowed to throw
|
||||
// Don't set any flags if InterfaceFlagsSetter threw an exception in one of its methods
|
||||
if (std::uncaught_exceptions() != exceptions_)
|
||||
return;
|
||||
|
||||
SDBUS_THROW_ERROR_IF(interfaceName_.empty(), "DBus interface not specified when setting its flags", EINVAL);
|
||||
|
||||
// setInterfaceFlags() can throw. But as the InterfaceFlagsSetter 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 setInterfaceFlags() 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_.setInterfaceFlags( std::move(interfaceName_)
|
||||
, std::move(flags_) );
|
||||
}
|
||||
|
||||
|
||||
|
||||
+111
@@ -0,0 +1,111 @@
|
||||
/**
|
||||
* (C) 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
*
|
||||
* @file Flags.cpp
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <sdbus-c++/Flags.h>
|
||||
#include <systemd/sd-bus.h>
|
||||
|
||||
namespace sdbus
|
||||
{
|
||||
uint64_t Flags::toSdBusInterfaceFlags() const
|
||||
{
|
||||
uint64_t sdbusFlags{};
|
||||
|
||||
using namespace sdbus;
|
||||
if (flags_.test(Flags::DEPRECATED))
|
||||
sdbusFlags |= SD_BUS_VTABLE_DEPRECATED;
|
||||
if (!flags_.test(Flags::PRIVILEGED))
|
||||
sdbusFlags |= SD_BUS_VTABLE_UNPRIVILEGED;
|
||||
|
||||
if (flags_.test(Flags::EMITS_CHANGE_SIGNAL))
|
||||
sdbusFlags |= SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE;
|
||||
else if (flags_.test(Flags::EMITS_INVALIDATION_SIGNAL))
|
||||
sdbusFlags |= SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION;
|
||||
else if (flags_.test(Flags::CONST_PROPERTY_VALUE))
|
||||
sdbusFlags |= SD_BUS_VTABLE_PROPERTY_CONST;
|
||||
else if (flags_.test(Flags::EMITS_NO_SIGNAL))
|
||||
sdbusFlags |= 0;
|
||||
|
||||
return sdbusFlags;
|
||||
}
|
||||
|
||||
uint64_t Flags::toSdBusMethodFlags() const
|
||||
{
|
||||
uint64_t sdbusFlags{};
|
||||
|
||||
using namespace sdbus;
|
||||
if (flags_.test(Flags::DEPRECATED))
|
||||
sdbusFlags |= SD_BUS_VTABLE_DEPRECATED;
|
||||
if (!flags_.test(Flags::PRIVILEGED))
|
||||
sdbusFlags |= SD_BUS_VTABLE_UNPRIVILEGED;
|
||||
if (flags_.test(Flags::METHOD_NO_REPLY))
|
||||
sdbusFlags |= SD_BUS_VTABLE_METHOD_NO_REPLY;
|
||||
|
||||
return sdbusFlags;
|
||||
}
|
||||
|
||||
uint64_t Flags::toSdBusSignalFlags() const
|
||||
{
|
||||
uint64_t sdbusFlags{};
|
||||
|
||||
using namespace sdbus;
|
||||
if (flags_.test(Flags::DEPRECATED))
|
||||
sdbusFlags |= SD_BUS_VTABLE_DEPRECATED;
|
||||
|
||||
return sdbusFlags;
|
||||
}
|
||||
|
||||
uint64_t Flags::toSdBusPropertyFlags() const
|
||||
{
|
||||
uint64_t sdbusFlags{};
|
||||
|
||||
using namespace sdbus;
|
||||
if (flags_.test(Flags::DEPRECATED))
|
||||
sdbusFlags |= SD_BUS_VTABLE_DEPRECATED;
|
||||
//if (!flags_.test(Flags::PRIVILEGED))
|
||||
// sdbusFlags |= SD_BUS_VTABLE_UNPRIVILEGED;
|
||||
|
||||
if (flags_.test(Flags::EMITS_CHANGE_SIGNAL))
|
||||
sdbusFlags |= SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE;
|
||||
else if (flags_.test(Flags::EMITS_INVALIDATION_SIGNAL))
|
||||
sdbusFlags |= SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION;
|
||||
else if (flags_.test(Flags::CONST_PROPERTY_VALUE))
|
||||
sdbusFlags |= SD_BUS_VTABLE_PROPERTY_CONST;
|
||||
else if (flags_.test(Flags::EMITS_NO_SIGNAL))
|
||||
sdbusFlags |= 0;
|
||||
|
||||
return sdbusFlags;
|
||||
}
|
||||
|
||||
uint64_t Flags::toSdBusWritablePropertyFlags() const
|
||||
{
|
||||
auto sdbusFlags = toSdBusPropertyFlags();
|
||||
|
||||
using namespace sdbus;
|
||||
if (!flags_.test(Flags::PRIVILEGED))
|
||||
sdbusFlags |= SD_BUS_VTABLE_UNPRIVILEGED;
|
||||
|
||||
return sdbusFlags;
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
|
||||
lib_LTLIBRARIES = libsdbus-c++.la
|
||||
|
||||
libsdbus_c___la_SOURCES = \
|
||||
Connection.cpp \
|
||||
ConvenienceClasses.cpp \
|
||||
Message.cpp \
|
||||
MethodResult.cpp \
|
||||
Object.cpp \
|
||||
ObjectProxy.cpp \
|
||||
Types.cpp \
|
||||
Error.cpp \
|
||||
VTableUtils.c
|
||||
|
||||
libsdbus_c___la_LIBADD = @SYSTEMD_LIBS@
|
||||
|
||||
# Setting per-file flags
|
||||
AM_CPPFLAGS = -I$(top_srcdir)/include
|
||||
AM_CXXFLAGS = @libsdbus_cpp_CFLAGS@ @SYSTEMD_CFLAGS@ -std=c++17 -pipe -pedantic -W -Wall
|
||||
AM_LDFLAGS = @libsdbus_cpp_LIBS@ @SYSTEMD_LIBS@
|
||||
|
||||
libsdbus_c___la_LDFLAGS = -version-info 0:0:0
|
||||
|
||||
# Cleaning
|
||||
CLEANFILES = *~ *.lo *.la
|
||||
MOSTLYCLEANFILES = *.o
|
||||
DISTCLEANFILES = Makefile Makefile.in
|
||||
@@ -571,7 +571,28 @@ void* Message::getMsg() const
|
||||
return msg_;
|
||||
}
|
||||
|
||||
void MethodCall::dontExpectReply()
|
||||
{
|
||||
auto r = sd_bus_message_set_expect_reply((sd_bus_message*)getMsg(), 0);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to set the dont-expect-reply flag", -r);
|
||||
}
|
||||
|
||||
bool MethodCall::doesntExpectReply() const
|
||||
{
|
||||
auto r = sd_bus_message_get_expect_reply((sd_bus_message*)getMsg());
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to get the dont-expect-reply flag", -r);
|
||||
return r > 0 ? false : true;
|
||||
}
|
||||
|
||||
MethodReply MethodCall::send() const
|
||||
{
|
||||
if (!doesntExpectReply())
|
||||
return sendWithReply();
|
||||
else
|
||||
return sendWithNoReply();
|
||||
}
|
||||
|
||||
MethodReply MethodCall::sendWithReply() const
|
||||
{
|
||||
sd_bus_message* sdbusReply{};
|
||||
SCOPE_EXIT{ sd_bus_message_unref(sdbusReply); }; // Returned message will become an owner of sdbusReply
|
||||
@@ -590,6 +611,13 @@ MethodReply MethodCall::send() const
|
||||
return MethodReply(sdbusReply);
|
||||
}
|
||||
|
||||
MethodReply MethodCall::sendWithNoReply() const
|
||||
{
|
||||
auto r = sd_bus_send(nullptr, (sd_bus_message*)getMsg(), nullptr);
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to call method with no reply", -r);
|
||||
return MethodReply{}; // No reply
|
||||
}
|
||||
|
||||
MethodReply MethodCall::createReply() const
|
||||
{
|
||||
sd_bus_message *sdbusReply{};
|
||||
|
||||
+32
-15
@@ -28,6 +28,7 @@
|
||||
#include <sdbus-c++/Message.h>
|
||||
#include <sdbus-c++/Error.h>
|
||||
#include <sdbus-c++/MethodResult.h>
|
||||
#include <sdbus-c++/Flags.h>
|
||||
#include "IConnection.h"
|
||||
#include "VTableUtils.h"
|
||||
#include <systemd/sd-bus.h>
|
||||
@@ -45,7 +46,8 @@ void Object::registerMethod( const std::string& interfaceName
|
||||
, const std::string& methodName
|
||||
, const std::string& inputSignature
|
||||
, const std::string& outputSignature
|
||||
, method_callback methodCallback )
|
||||
, method_callback methodCallback
|
||||
, Flags flags )
|
||||
{
|
||||
SDBUS_THROW_ERROR_IF(!methodCallback, "Invalid method callback provided", EINVAL);
|
||||
|
||||
@@ -57,7 +59,7 @@ void Object::registerMethod( const std::string& interfaceName
|
||||
};
|
||||
|
||||
auto& interface = interfaces_[interfaceName];
|
||||
InterfaceData::MethodData methodData{inputSignature, outputSignature, std::move(syncCallback)};
|
||||
InterfaceData::MethodData methodData{inputSignature, outputSignature, std::move(syncCallback), flags};
|
||||
auto inserted = interface.methods_.emplace(methodName, std::move(methodData)).second;
|
||||
|
||||
SDBUS_THROW_ERROR_IF(!inserted, "Failed to register method: method already exists", EINVAL);
|
||||
@@ -67,7 +69,8 @@ void Object::registerMethod( const std::string& interfaceName
|
||||
, const std::string& methodName
|
||||
, const std::string& inputSignature
|
||||
, const std::string& outputSignature
|
||||
, async_method_callback asyncMethodCallback )
|
||||
, async_method_callback asyncMethodCallback
|
||||
, Flags flags )
|
||||
{
|
||||
SDBUS_THROW_ERROR_IF(!asyncMethodCallback, "Invalid method callback provided", EINVAL);
|
||||
|
||||
@@ -78,7 +81,7 @@ void Object::registerMethod( const std::string& interfaceName
|
||||
};
|
||||
|
||||
auto& interface = interfaces_[interfaceName];
|
||||
InterfaceData::MethodData methodData{inputSignature, outputSignature, std::move(asyncCallback)};
|
||||
InterfaceData::MethodData methodData{inputSignature, outputSignature, std::move(asyncCallback), flags};
|
||||
auto inserted = interface.methods_.emplace(methodName, std::move(methodData)).second;
|
||||
|
||||
SDBUS_THROW_ERROR_IF(!inserted, "Failed to register method: method already exists", EINVAL);
|
||||
@@ -86,11 +89,12 @@ void Object::registerMethod( const std::string& interfaceName
|
||||
|
||||
void Object::registerSignal( const std::string& interfaceName
|
||||
, const std::string& signalName
|
||||
, const std::string& signature )
|
||||
, const std::string& signature
|
||||
, Flags flags )
|
||||
{
|
||||
auto& interface = interfaces_[interfaceName];
|
||||
|
||||
InterfaceData::SignalData signalData{signature};
|
||||
InterfaceData::SignalData signalData{signature, flags};
|
||||
auto inserted = interface.signals_.emplace(signalName, std::move(signalData)).second;
|
||||
|
||||
SDBUS_THROW_ERROR_IF(!inserted, "Failed to register signal: signal already exists", EINVAL);
|
||||
@@ -99,31 +103,40 @@ void Object::registerSignal( const std::string& interfaceName
|
||||
void Object::registerProperty( const std::string& interfaceName
|
||||
, const std::string& propertyName
|
||||
, const std::string& signature
|
||||
, property_get_callback getCallback )
|
||||
, property_get_callback getCallback
|
||||
, Flags flags )
|
||||
{
|
||||
registerProperty( interfaceName
|
||||
, propertyName
|
||||
, signature
|
||||
, getCallback
|
||||
, property_set_callback{} );
|
||||
, property_set_callback{}
|
||||
, flags );
|
||||
}
|
||||
|
||||
void Object::registerProperty( const std::string& interfaceName
|
||||
, const std::string& propertyName
|
||||
, const std::string& signature
|
||||
, property_get_callback getCallback
|
||||
, property_set_callback setCallback )
|
||||
, property_set_callback setCallback
|
||||
, Flags flags )
|
||||
{
|
||||
SDBUS_THROW_ERROR_IF(!getCallback && !setCallback, "Invalid property callbacks provided", EINVAL);
|
||||
|
||||
auto& interface = interfaces_[interfaceName];
|
||||
|
||||
InterfaceData::PropertyData propertyData{signature, std::move(getCallback), std::move(setCallback)};
|
||||
InterfaceData::PropertyData propertyData{signature, std::move(getCallback), std::move(setCallback), flags};
|
||||
auto inserted = interface.properties_.emplace(propertyName, std::move(propertyData)).second;
|
||||
|
||||
SDBUS_THROW_ERROR_IF(!inserted, "Failed to register property: property already exists", EINVAL);
|
||||
}
|
||||
|
||||
void Object::setInterfaceFlags(const std::string& interfaceName, Flags flags)
|
||||
{
|
||||
auto& interface = interfaces_[interfaceName];
|
||||
interface.flags_ = flags;
|
||||
}
|
||||
|
||||
void Object::finishRegistration()
|
||||
{
|
||||
for (auto& item : interfaces_)
|
||||
@@ -159,7 +172,7 @@ const std::vector<sd_bus_vtable>& Object::createInterfaceVTable(InterfaceData& i
|
||||
auto& vtable = interfaceData.vtable_;
|
||||
assert(vtable.empty());
|
||||
|
||||
vtable.push_back(createVTableStartItem());
|
||||
vtable.push_back(createVTableStartItem(interfaceData.flags_.toSdBusInterfaceFlags()));
|
||||
registerMethodsToVTable(interfaceData, vtable);
|
||||
registerSignalsToVTable(interfaceData, vtable);
|
||||
registerPropertiesToVTable(interfaceData, vtable);
|
||||
@@ -178,7 +191,8 @@ void Object::registerMethodsToVTable(const InterfaceData& interfaceData, std::ve
|
||||
vtable.push_back(createVTableMethodItem( methodName.c_str()
|
||||
, methodData.inputArgs_.c_str()
|
||||
, methodData.outputArgs_.c_str()
|
||||
, &Object::sdbus_method_callback ));
|
||||
, &Object::sdbus_method_callback
|
||||
, methodData.flags_.toSdBusMethodFlags() ));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -190,7 +204,8 @@ void Object::registerSignalsToVTable(const InterfaceData& interfaceData, std::ve
|
||||
const auto& signalData = item.second;
|
||||
|
||||
vtable.push_back(createVTableSignalItem( signalName.c_str()
|
||||
, signalData.signature_.c_str() ));
|
||||
, signalData.signature_.c_str()
|
||||
, signalData.flags_.toSdBusSignalFlags() ));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -204,12 +219,14 @@ void Object::registerPropertiesToVTable(const InterfaceData& interfaceData, std:
|
||||
if (!propertyData.setCallback_)
|
||||
vtable.push_back(createVTablePropertyItem( propertyName.c_str()
|
||||
, propertyData.signature_.c_str()
|
||||
, &Object::sdbus_property_get_callback ));
|
||||
, &Object::sdbus_property_get_callback
|
||||
, propertyData.flags_.toSdBusPropertyFlags() ));
|
||||
else
|
||||
vtable.push_back(createVTableWritablePropertyItem( propertyName.c_str()
|
||||
, propertyData.signature_.c_str()
|
||||
, &Object::sdbus_property_get_callback
|
||||
, &Object::sdbus_property_set_callback ));
|
||||
, &Object::sdbus_property_set_callback
|
||||
, propertyData.flags_.toSdBusWritablePropertyFlags() ));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+20
-9
@@ -49,28 +49,35 @@ namespace internal {
|
||||
, const std::string& methodName
|
||||
, const std::string& inputSignature
|
||||
, const std::string& outputSignature
|
||||
, method_callback methodCallback ) override;
|
||||
, method_callback methodCallback
|
||||
, Flags flags ) override;
|
||||
|
||||
void registerMethod( const std::string& interfaceName
|
||||
, const std::string& methodName
|
||||
, const std::string& inputSignature
|
||||
, const std::string& outputSignature
|
||||
, async_method_callback asyncMethodCallback ) override;
|
||||
, async_method_callback asyncMethodCallback
|
||||
, Flags flags ) override;
|
||||
|
||||
void registerSignal( const std::string& interfaceName
|
||||
, const std::string& signalName
|
||||
, const std::string& signature ) override;
|
||||
|
||||
void registerProperty( const std::string& interfaceName
|
||||
, const std::string& propertyName
|
||||
, const std::string& signature
|
||||
, property_get_callback getCallback ) override;
|
||||
, const std::string& signature
|
||||
, Flags flags ) override;
|
||||
|
||||
void registerProperty( const std::string& interfaceName
|
||||
, const std::string& propertyName
|
||||
, const std::string& signature
|
||||
, property_get_callback getCallback
|
||||
, property_set_callback setCallback ) override;
|
||||
, Flags flags ) override;
|
||||
|
||||
void registerProperty( const std::string& interfaceName
|
||||
, const std::string& propertyName
|
||||
, const std::string& signature
|
||||
, property_get_callback getCallback
|
||||
, property_set_callback setCallback
|
||||
, Flags flags ) override;
|
||||
|
||||
void setInterfaceFlags(const std::string& interfaceName, Flags flags) override;
|
||||
|
||||
void finishRegistration() override;
|
||||
|
||||
@@ -89,12 +96,14 @@ namespace internal {
|
||||
std::string inputArgs_;
|
||||
std::string outputArgs_;
|
||||
std::function<void(MethodCall&)> callback_;
|
||||
Flags flags_;
|
||||
};
|
||||
std::map<MethodName, MethodData> methods_;
|
||||
using SignalName = std::string;
|
||||
struct SignalData
|
||||
{
|
||||
std::string signature_;
|
||||
Flags flags_;
|
||||
};
|
||||
std::map<SignalName, SignalData> signals_;
|
||||
using PropertyName = std::string;
|
||||
@@ -103,9 +112,11 @@ namespace internal {
|
||||
std::string signature_;
|
||||
property_get_callback getCallback_;
|
||||
property_set_callback setCallback_;
|
||||
Flags flags_;
|
||||
};
|
||||
std::map<PropertyName, PropertyData> properties_;
|
||||
std::vector<sd_bus_vtable> vtable_;
|
||||
Flags flags_;
|
||||
|
||||
std::unique_ptr<void, std::function<void(void*)>> slot_;
|
||||
};
|
||||
|
||||
@@ -51,6 +51,7 @@ void Variant::deserializeFrom(Message& msg)
|
||||
|
||||
std::string Variant::peekValueType() const
|
||||
{
|
||||
msg_.rewind(false);
|
||||
std::string type;
|
||||
std::string contents;
|
||||
msg_.peekType(type, contents);
|
||||
|
||||
+14
-10
@@ -26,42 +26,46 @@
|
||||
#include "VTableUtils.h"
|
||||
#include <systemd/sd-bus.h>
|
||||
|
||||
sd_bus_vtable createVTableStartItem()
|
||||
sd_bus_vtable createVTableStartItem(uint64_t flags)
|
||||
{
|
||||
struct sd_bus_vtable vtableStart = SD_BUS_VTABLE_START(0);
|
||||
struct sd_bus_vtable vtableStart = SD_BUS_VTABLE_START(flags);
|
||||
return vtableStart;
|
||||
}
|
||||
|
||||
sd_bus_vtable createVTableMethodItem( const char *member
|
||||
, const char *signature
|
||||
, const char *result
|
||||
, sd_bus_message_handler_t handler )
|
||||
, sd_bus_message_handler_t handler
|
||||
, uint64_t flags )
|
||||
{
|
||||
struct sd_bus_vtable vtableItem = SD_BUS_METHOD(member, signature, result, handler, SD_BUS_VTABLE_UNPRIVILEGED);
|
||||
struct sd_bus_vtable vtableItem = SD_BUS_METHOD(member, signature, result, handler, flags);
|
||||
return vtableItem;
|
||||
}
|
||||
|
||||
sd_bus_vtable createVTableSignalItem( const char *member
|
||||
, const char *signature )
|
||||
, const char *signature
|
||||
, uint64_t flags )
|
||||
{
|
||||
struct sd_bus_vtable vtableItem = SD_BUS_SIGNAL(member, signature, 0);
|
||||
struct sd_bus_vtable vtableItem = SD_BUS_SIGNAL(member, signature, flags);
|
||||
return vtableItem;
|
||||
}
|
||||
|
||||
sd_bus_vtable createVTablePropertyItem( const char *member
|
||||
, const char *signature
|
||||
, sd_bus_property_get_t getter )
|
||||
, sd_bus_property_get_t getter
|
||||
, uint64_t flags )
|
||||
{
|
||||
struct sd_bus_vtable vtableItem = SD_BUS_PROPERTY(member, signature, getter, 0, 0);
|
||||
struct sd_bus_vtable vtableItem = SD_BUS_PROPERTY(member, signature, getter, 0, flags);
|
||||
return vtableItem;
|
||||
}
|
||||
|
||||
sd_bus_vtable createVTableWritablePropertyItem( const char *member
|
||||
, const char *signature
|
||||
, sd_bus_property_get_t getter
|
||||
, sd_bus_property_set_t setter )
|
||||
, sd_bus_property_set_t setter
|
||||
, uint64_t flags )
|
||||
{
|
||||
struct sd_bus_vtable vtableItem = SD_BUS_WRITABLE_PROPERTY(member, signature, getter, setter, 0, 0);
|
||||
struct sd_bus_vtable vtableItem = SD_BUS_WRITABLE_PROPERTY(member, signature, getter, setter, 0, flags);
|
||||
return vtableItem;
|
||||
}
|
||||
|
||||
|
||||
+10
-5
@@ -27,25 +27,30 @@
|
||||
#define SDBUS_CXX_INTERNAL_VTABLEUTILS_H_
|
||||
|
||||
#include <systemd/sd-bus.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
sd_bus_vtable createVTableStartItem();
|
||||
sd_bus_vtable createVTableStartItem(uint64_t flags);
|
||||
sd_bus_vtable createVTableMethodItem( const char *member
|
||||
, const char *signature
|
||||
, const char *result
|
||||
, sd_bus_message_handler_t handler );
|
||||
, sd_bus_message_handler_t handler
|
||||
, uint64_t flags );
|
||||
sd_bus_vtable createVTableSignalItem( const char *member
|
||||
, const char *signature );
|
||||
, const char *signature
|
||||
, uint64_t flags );
|
||||
sd_bus_vtable createVTablePropertyItem( const char *member
|
||||
, const char *signature
|
||||
, sd_bus_property_get_t getter );
|
||||
, sd_bus_property_get_t getter
|
||||
, uint64_t flags );
|
||||
sd_bus_vtable createVTableWritablePropertyItem( const char *member
|
||||
, const char *signature
|
||||
, sd_bus_property_get_t getter
|
||||
, sd_bus_property_set_t setter );
|
||||
, sd_bus_property_set_t setter
|
||||
, uint64_t flags );
|
||||
sd_bus_vtable createVTableEndItem();
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -89,6 +89,30 @@ std::string AdaptorGenerator::processInterface(Node& interface) const
|
||||
Nodes signals = interface["signal"];
|
||||
Nodes properties = interface["property"];
|
||||
|
||||
auto annotations = getAnnotations(interface);
|
||||
std::string annotationRegistration;
|
||||
for (const auto& annotation : annotations)
|
||||
{
|
||||
const auto& annotationName = annotation.first;
|
||||
const auto& annotationValue = annotation.second;
|
||||
|
||||
if (annotationName == "org.freedesktop.DBus.Deprecated" && annotationValue == "true")
|
||||
annotationRegistration += ".markAsDeprecated()";
|
||||
else if (annotationName == "org.freedesktop.systemd1.Privileged" && annotationValue == "true")
|
||||
annotationRegistration += ".markAsPrivileged()";
|
||||
else if (annotationName == "org.freedesktop.DBus.Property.EmitsChangedSignal")
|
||||
annotationRegistration += ".withPropertyUpdateBehavior(" + propertyAnnotationToFlag(annotationValue) + ")";
|
||||
else
|
||||
std::cerr << "Node: " << ifaceName << ": "
|
||||
<< "Option '" << annotationName << "' not allowed or supported in this context! Option ignored..." << std::endl;
|
||||
}
|
||||
if(!annotationRegistration.empty())
|
||||
{
|
||||
std::stringstream str;
|
||||
str << tab << tab << "object_.setInterfaceFlags(interfaceName)" << annotationRegistration << ";" << endl;
|
||||
annotationRegistration = str.str();
|
||||
}
|
||||
|
||||
std::string methodRegistration, methodDeclaration;
|
||||
std::tie(methodRegistration, methodDeclaration) = processMethods(methods);
|
||||
|
||||
@@ -99,10 +123,11 @@ std::string AdaptorGenerator::processInterface(Node& interface) const
|
||||
std::tie(propertyRegistration, propertyAccessorDeclaration) = processProperties(properties);
|
||||
|
||||
body << tab << "{" << endl
|
||||
<< methodRegistration
|
||||
<< signalRegistration
|
||||
<< propertyRegistration
|
||||
<< tab << "}" << endl << endl;
|
||||
<< annotationRegistration
|
||||
<< methodRegistration
|
||||
<< signalRegistration
|
||||
<< propertyRegistration
|
||||
<< tab << "}" << endl << endl;
|
||||
|
||||
if (!signalMethods.empty())
|
||||
{
|
||||
@@ -136,17 +161,25 @@ std::tuple<std::string, std::string> AdaptorGenerator::processMethods(const Node
|
||||
{
|
||||
auto methodName = method->get("name");
|
||||
|
||||
auto annotations = getAnnotations(*method);
|
||||
bool async{false};
|
||||
Nodes annotations = (*method)["annotation"];
|
||||
|
||||
std::string annotationRegistration;
|
||||
for (const auto& annotation : annotations)
|
||||
{
|
||||
if (annotation->get("name") == "org.freedesktop.DBus.Method.Async"
|
||||
&& (annotation->get("value") == "server" || annotation->get("value") == "clientserver"))
|
||||
{
|
||||
const auto& annotationName = annotation.first;
|
||||
const auto& annotationValue = annotation.second;
|
||||
|
||||
if (annotationName == "org.freedesktop.DBus.Deprecated" && annotationValue == "true")
|
||||
annotationRegistration += ".markAsDeprecated()";
|
||||
else if (annotationName == "org.freedesktop.DBus.Method.NoReply" && annotationValue == "true")
|
||||
annotationRegistration += ".withNoReply()";
|
||||
else if (annotationName == "org.freedesktop.DBus.Method.Async" && (annotationValue == "server" || annotationValue == "clientserver"))
|
||||
async = true;
|
||||
break;
|
||||
}
|
||||
else if (annotationName == "org.freedesktop.systemd1.Privileged" && annotationValue == "true")
|
||||
annotationRegistration += ".markAsPrivileged()";
|
||||
else
|
||||
std::cerr << "Node: " << methodName << ": "
|
||||
<< "Option '" << annotationName << "' not allowed or supported in this context! Option ignored..." << std::endl;
|
||||
}
|
||||
|
||||
Nodes args = (*method)["arg"];
|
||||
@@ -167,7 +200,8 @@ std::tuple<std::string, std::string> AdaptorGenerator::processMethods(const Node
|
||||
<< argTypeStr
|
||||
<< "){ " << (async ? "" : "return ") << "this->" << methodName << "("
|
||||
<< (async ? "std::move(result)"s + (argTypeStr.empty() ? "" : ", ") : "")
|
||||
<< argStr << "); });" << endl;
|
||||
<< argStr << "); })"
|
||||
<< annotationRegistration << ";" << endl;
|
||||
|
||||
declarationSS << tab
|
||||
<< "virtual "
|
||||
@@ -190,6 +224,21 @@ std::tuple<std::string, std::string> AdaptorGenerator::processSignals(const Node
|
||||
for (const auto& signal : signals)
|
||||
{
|
||||
auto name = signal->get("name");
|
||||
|
||||
auto annotations = getAnnotations(*signal);
|
||||
std::string annotationRegistration;
|
||||
for (const auto& annotation : annotations)
|
||||
{
|
||||
const auto& annotationName = annotation.first;
|
||||
const auto& annotationValue = annotation.second;
|
||||
|
||||
if (annotationName == "org.freedesktop.DBus.Deprecated" && annotationValue == "true")
|
||||
annotationRegistration += ".markAsDeprecated()";
|
||||
else
|
||||
std::cerr << "Node: " << name << ": "
|
||||
<< "Option '" << annotationName << "' not allowed or supported in this context! Option ignored..." << std::endl;
|
||||
}
|
||||
|
||||
Nodes args = (*signal)["arg"];
|
||||
|
||||
std::string argStr, argTypeStr, typeStr;;
|
||||
@@ -204,6 +253,7 @@ std::tuple<std::string, std::string> AdaptorGenerator::processSignals(const Node
|
||||
signalRegistrationSS << ".withParameters<" << typeStr << ">()";
|
||||
}
|
||||
|
||||
signalRegistrationSS << annotationRegistration;
|
||||
signalRegistrationSS << ";" << endl;
|
||||
|
||||
signalMethodSS << tab << "void " << name << "(" << argTypeStr << ")" << endl
|
||||
@@ -238,6 +288,24 @@ std::tuple<std::string, std::string> AdaptorGenerator::processProperties(const N
|
||||
auto propertyArg = std::string("value");
|
||||
auto propertyTypeArg = std::string("const ") + propertyType + "& " + propertyArg;
|
||||
|
||||
auto annotations = getAnnotations(*property);
|
||||
std::string annotationRegistration;
|
||||
for (const auto& annotation : annotations)
|
||||
{
|
||||
const auto& annotationName = annotation.first;
|
||||
const auto& annotationValue = annotation.second;
|
||||
|
||||
if (annotationName == "org.freedesktop.DBus.Deprecated" && annotationValue == "true")
|
||||
annotationRegistration += ".markAsDeprecated()";
|
||||
else if (annotationName == "org.freedesktop.DBus.Property.EmitsChangedSignal")
|
||||
annotationRegistration += ".withUpdateBehavior(" + propertyAnnotationToFlag(annotationValue) + ")";
|
||||
else if (annotationName == "org.freedesktop.systemd1.Privileged" && annotationValue == "true")
|
||||
annotationRegistration += ".markAsPrivileged()";
|
||||
else
|
||||
std::cerr << "Node: " << propertyName << ": "
|
||||
<< "Option '" << annotationName << "' not allowed or supported in this context! Option ignored..." << std::endl;
|
||||
}
|
||||
|
||||
registrationSS << tab << tab << "object_.registerProperty(\""
|
||||
<< propertyName << "\")"
|
||||
<< ".onInterface(interfaceName)";
|
||||
@@ -254,6 +322,7 @@ std::tuple<std::string, std::string> AdaptorGenerator::processProperties(const N
|
||||
"{ this->" << propertyName << "(" << propertyArg << "); })";
|
||||
}
|
||||
|
||||
registrationSS << annotationRegistration;
|
||||
registrationSS << ";" << endl;
|
||||
|
||||
if (propertyAccess == "read" || propertyAccess == "readwrite")
|
||||
@@ -264,3 +333,25 @@ std::tuple<std::string, std::string> AdaptorGenerator::processProperties(const N
|
||||
|
||||
return std::make_tuple(registrationSS.str(), declarationSS.str());
|
||||
}
|
||||
|
||||
std::map<std::string, std::string> AdaptorGenerator::getAnnotations( sdbuscpp::xml::Node& node) const
|
||||
{
|
||||
std::map<std::string, std::string> result;
|
||||
|
||||
Nodes annotations = (node)["annotation"];
|
||||
for (const auto& annotation : annotations)
|
||||
{
|
||||
result[annotation->get("name")] = annotation->get("value");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string AdaptorGenerator::propertyAnnotationToFlag(const std::string& annotationValue) const
|
||||
{
|
||||
return annotationValue == "true" ? "sdbus::Flags::EMITS_CHANGE_SIGNAL"
|
||||
: annotationValue == "invalidates" ? "sdbus::Flags::EMITS_INVALIDATION_SIGNAL"
|
||||
: annotationValue == "const" ? "sdbus::Flags::CONST_PROPERTY_VALUE"
|
||||
: annotationValue == "false" ? "sdbus::Flags::EMITS_NO_SIGNAL"
|
||||
: "EMITS_CHANGE_SIGNAL"; // Default
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
|
||||
// STL
|
||||
#include <tuple>
|
||||
#include <set>
|
||||
|
||||
class AdaptorGenerator : public BaseGenerator
|
||||
{
|
||||
@@ -73,6 +74,19 @@ private:
|
||||
*/
|
||||
std::tuple<std::string, std::string> processProperties(const sdbuscpp::xml::Nodes& properties) const;
|
||||
|
||||
/**
|
||||
* Get annotations listed for a given node
|
||||
* @param node
|
||||
* @return map of annotation names to their values
|
||||
*/
|
||||
std::map<std::string, std::string> getAnnotations(sdbuscpp::xml::Node& node) const;
|
||||
|
||||
/**
|
||||
* Get flag for property update behavior annotation value
|
||||
* @param annotationValue
|
||||
* @return flag
|
||||
*/
|
||||
std::string propertyAnnotationToFlag(const std::string& annotationValue) const;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -108,12 +108,21 @@ std::tuple<std::string, std::string, std::string> BaseGenerator::argsToNamesAndT
|
||||
{
|
||||
std::ostringstream argSS, argTypeSS, typeSS;
|
||||
|
||||
bool firstArg{true};
|
||||
for (const auto& arg : args)
|
||||
for (size_t i = 0; i < args.size(); ++i)
|
||||
{
|
||||
if (firstArg) firstArg = false; else { argSS << ", "; argTypeSS << ", "; typeSS << ", "; }
|
||||
auto arg = args.at(i);
|
||||
if (i > 0)
|
||||
{
|
||||
argSS << ", ";
|
||||
argTypeSS << ", ";
|
||||
typeSS << ", ";
|
||||
}
|
||||
|
||||
auto argName = arg->get("name");
|
||||
if (argName.empty())
|
||||
{
|
||||
argName = "arg" + std::to_string(i);
|
||||
}
|
||||
auto type = signature_to_type(arg->get("type"));
|
||||
argSS << argName;
|
||||
argTypeSS << "const " << type << "& " << argName;
|
||||
|
||||
@@ -1,13 +1,52 @@
|
||||
cmake_minimum_required (VERSION 3.4)
|
||||
#-------------------------------
|
||||
# PROJECT INFORMATION
|
||||
#-------------------------------
|
||||
|
||||
add_definitions(-std=c++14)
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
project (sdbuscpp-xml2cpp)
|
||||
project(sdbuscpp-xml2cpp)
|
||||
|
||||
add_executable(${PROJECT_NAME} xml2cpp.cpp xml.cpp generator_utils.cpp BaseGenerator.cpp AdaptorGenerator.cpp ProxyGenerator.cpp)
|
||||
include(GNUInstallDirs)
|
||||
|
||||
find_package (EXPAT REQUIRED)
|
||||
#-------------------------------
|
||||
# PERFORMING CHECKS
|
||||
#-------------------------------
|
||||
|
||||
find_package(EXPAT REQUIRED)
|
||||
|
||||
#-------------------------------
|
||||
# SOURCE FILES CONFIGURATION
|
||||
#-------------------------------
|
||||
|
||||
set(SDBUSCPP_XML2CPP_SRCS
|
||||
xml2cpp.cpp
|
||||
xml.h
|
||||
xml.cpp
|
||||
generator_utils.h
|
||||
generator_utils.cpp
|
||||
BaseGenerator.h
|
||||
BaseGenerator.cpp
|
||||
AdaptorGenerator.h
|
||||
AdaptorGenerator.cpp
|
||||
ProxyGenerator.h
|
||||
ProxyGenerator.cpp)
|
||||
|
||||
#-------------------------------
|
||||
# GENERAL COMPILER CONFIGURATION
|
||||
#-------------------------------
|
||||
|
||||
set(CMAKE_CXX_STANDARD 14)
|
||||
|
||||
#----------------------------------
|
||||
# EXECUTABLE BUILD INFORMATION
|
||||
#----------------------------------
|
||||
|
||||
add_executable(${PROJECT_NAME} ${SDBUSCPP_XML2CPP_SRCS})
|
||||
|
||||
target_link_libraries (${PROJECT_NAME} ${EXPAT_LIBRARIES})
|
||||
|
||||
install(TARGETS ${PROJECT_NAME} EXPORT ${PROJECT_NAME} DESTINATION bin)
|
||||
#----------------------------------
|
||||
# INSTALLATION
|
||||
#----------------------------------
|
||||
|
||||
install(TARGETS ${PROJECT_NAME} EXPORT ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
|
||||
@@ -127,6 +127,24 @@ std::string ProxyGenerator::processMethods(const Nodes& methods) const
|
||||
Nodes inArgs = args.select("direction" , "in");
|
||||
Nodes outArgs = args.select("direction" , "out");
|
||||
|
||||
bool dontExpectReply{false};
|
||||
Nodes annotations = (*method)["annotation"];
|
||||
for (const auto& annotation : annotations)
|
||||
{
|
||||
if (annotation->get("name") == "org.freedesktop.DBus.Method.NoReply"
|
||||
&& annotation->get("value") == "true")
|
||||
{
|
||||
dontExpectReply = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (dontExpectReply && outArgs.size() > 0)
|
||||
{
|
||||
std::cerr << "Function: " << name << ": ";
|
||||
std::cerr << "Option 'org.freedesktop.DBus.Method.NoReply' not allowed for methods with 'out' variables! Option ignored..." << std::endl;
|
||||
dontExpectReply = false;
|
||||
}
|
||||
|
||||
auto retType = outArgsToType(outArgs);
|
||||
std::string argStr, argTypeStr;
|
||||
std::tie(argStr, argTypeStr, std::ignore) = argsToNamesAndTypes(inArgs);
|
||||
@@ -152,6 +170,10 @@ std::string ProxyGenerator::processMethods(const Nodes& methods) const
|
||||
methodSS << ".storeResultsTo(result);" << endl
|
||||
<< tab << tab << "return result";
|
||||
}
|
||||
else if (dontExpectReply)
|
||||
{
|
||||
methodSS << ".dontExpectReply()";
|
||||
}
|
||||
|
||||
methodSS << ";" << endl << tab << "}" << endl << endl;
|
||||
}
|
||||
@@ -159,7 +181,6 @@ std::string ProxyGenerator::processMethods(const Nodes& methods) const
|
||||
return methodSS.str();
|
||||
}
|
||||
|
||||
|
||||
std::tuple<std::string, std::string> ProxyGenerator::processSignals(const Nodes& signals) const
|
||||
{
|
||||
std::ostringstream registrationSS, declarationSS;
|
||||
|
||||
@@ -247,15 +247,15 @@ std::string Document::to_xml() const
|
||||
}
|
||||
|
||||
void Document::Expat::start_doctype_decl_handler(
|
||||
void* data,
|
||||
const XML_Char* name,
|
||||
const XML_Char* sysid,
|
||||
const XML_Char *pubid,
|
||||
int has_internal_subset)
|
||||
void* /*data*/,
|
||||
const XML_Char* /*name*/,
|
||||
const XML_Char* /*sysid*/,
|
||||
const XML_Char */*pubid*/,
|
||||
int /*has_internal_subset*/)
|
||||
{
|
||||
}
|
||||
|
||||
void Document::Expat::end_doctype_decl_handler(void* data)
|
||||
void Document::Expat::end_doctype_decl_handler(void* /*data*/)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -300,7 +300,7 @@ void Document::Expat::character_data_handler(void* data, const XML_Char* chars,
|
||||
nod->cdata = std::string(chars, x, y + 1);
|
||||
}
|
||||
|
||||
void Document::Expat::end_element_handler(void* data, const XML_Char* name)
|
||||
void Document::Expat::end_element_handler(void* data, const XML_Char* /*name*/)
|
||||
{
|
||||
Document* doc = static_cast<Document*>(data);
|
||||
|
||||
|
||||
Executable
+100
@@ -0,0 +1,100 @@
|
||||
#-------------------------------
|
||||
# DOWNLOAD AND BUILD OF GOOGLETEST
|
||||
# https://github.com/google/googletest/blob/master/googletest/README.md#incorporating-into-an-existing-cmake-project
|
||||
#-------------------------------
|
||||
|
||||
configure_file(googletest-download/CMakeLists.txt.in googletest-download/CMakeLists.txt)
|
||||
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" .
|
||||
RESULT_VARIABLE result
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/googletest-download)
|
||||
|
||||
if(result)
|
||||
message(FATAL_ERROR "CMake step for googletest failed: ${result}")
|
||||
endif()
|
||||
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} --build .
|
||||
RESULT_VARIABLE result
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/googletest-download)
|
||||
|
||||
if(result)
|
||||
message(FATAL_ERROR "Build step for googletest failed: ${result}")
|
||||
endif()
|
||||
|
||||
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
|
||||
|
||||
add_subdirectory(${CMAKE_CURRENT_BINARY_DIR}/googletest-src
|
||||
${CMAKE_CURRENT_BINARY_DIR}/googletest-build
|
||||
EXCLUDE_FROM_ALL)
|
||||
|
||||
#-------------------------------
|
||||
# SOURCE FILES CONFIGURATION
|
||||
#-------------------------------
|
||||
|
||||
set(UNITTESTS_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/unittests)
|
||||
set(UNITTESTS_SRCS
|
||||
${UNITTESTS_SOURCE_DIR}/libsdbus-c++_unittests.cpp
|
||||
${UNITTESTS_SOURCE_DIR}/Message_test.cpp
|
||||
${UNITTESTS_SOURCE_DIR}/Types_test.cpp
|
||||
${UNITTESTS_SOURCE_DIR}/TypeTraits_test.cpp)
|
||||
|
||||
set(INTEGRATIONTESTS_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/integrationtests)
|
||||
set(INTEGRATIONTESTS_SRCS
|
||||
${INTEGRATIONTESTS_SOURCE_DIR}/AdaptorAndProxy_test.cpp
|
||||
${INTEGRATIONTESTS_SOURCE_DIR}/Connection_test.cpp
|
||||
${INTEGRATIONTESTS_SOURCE_DIR}/libsdbus-c++_integrationtests.cpp
|
||||
${INTEGRATIONTESTS_SOURCE_DIR}/adaptor-glue.h
|
||||
${INTEGRATIONTESTS_SOURCE_DIR}/defs.h
|
||||
${INTEGRATIONTESTS_SOURCE_DIR}/proxy-glue.h
|
||||
${INTEGRATIONTESTS_SOURCE_DIR}/TestingAdaptor.h
|
||||
${INTEGRATIONTESTS_SOURCE_DIR}/TestingProxy.h)
|
||||
|
||||
#-------------------------------
|
||||
# GENERAL COMPILER CONFIGURATION
|
||||
#-------------------------------
|
||||
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
#----------------------------------
|
||||
# BUILD INFORMATION
|
||||
#----------------------------------
|
||||
|
||||
# Turn off -isystem gcc option that CMake uses for imported
|
||||
# targets even when INTERFACE_INCLUDE_DIRECTORIES is used.
|
||||
set(CMAKE_NO_SYSTEM_FROM_IMPORTED "1")
|
||||
|
||||
add_executable(libsdbus-c++_unittests ${UNITTESTS_SRCS} $<TARGET_OBJECTS:sdbuscppobjects>)
|
||||
target_link_libraries(libsdbus-c++_unittests ${SYSTEMD_LIBRARIES} gmock gmock_main)
|
||||
|
||||
add_executable(libsdbus-c++_integrationtests ${INTEGRATIONTESTS_SRCS})
|
||||
target_link_libraries(libsdbus-c++_integrationtests sdbus-c++ gmock gmock_main)
|
||||
|
||||
#----------------------------------
|
||||
# INSTALLATION
|
||||
#----------------------------------
|
||||
|
||||
install(TARGETS libsdbus-c++_unittests DESTINATION /opt/test/bin)
|
||||
install(TARGETS libsdbus-c++_integrationtests DESTINATION /opt/test/bin)
|
||||
install(FILES ${INTEGRATIONTESTS_SOURCE_DIR}/files/libsdbus-cpp-test.conf DESTINATION ${CMAKE_INSTALL_SYSCONFDIR}/dbus-1/system.d)
|
||||
|
||||
#----------------------------------
|
||||
# RUNNING THE TESTS UPON BUILD
|
||||
#----------------------------------
|
||||
|
||||
if(CMAKE_CROSSCOMPILING)
|
||||
if(NOT DEFINED UNIT_TESTS_RUNNER)
|
||||
set(UNIT_TESTS_RUNNER $ENV{UNIT_TESTS_RUNNER})
|
||||
endif()
|
||||
if(NOT DEFINED TEST_DEVICE_IP)
|
||||
set(TEST_DEVICE_IP $ENV{TEST_DEVICE_IP})
|
||||
endif()
|
||||
|
||||
if(NOT (UNIT_TESTS_RUNNER AND TEST_DEVICE_IP))
|
||||
message(WARNING "UNIT_TESTS_RUNNER and TEST_DEVICE_IP variables must be defined to run tests remotely")
|
||||
endif()
|
||||
add_test(NAME libsdbus-c++_unittests COMMAND ${UNIT_TESTS_RUNNER} --deviceip=${TEST_DEVICE_IP} --testbin=libsdbus-c++_unittests)
|
||||
add_test(NAME libsdbus-c++_integrationtests COMMAND ${UNIT_TESTS_RUNNER} --deviceip=${TEST_DEVICE_IP} --testbin=libsdbus-c++_integrationtests)
|
||||
else()
|
||||
add_test(NAME libsdbus-c++_unittests COMMAND libsdbus-c++_unittests)
|
||||
add_test(NAME libsdbus-c++_integrationtests COMMAND libsdbus-c++_integrationtests)
|
||||
endif()
|
||||
@@ -1,67 +0,0 @@
|
||||
# Defines how to build and install libsdbus-c++ tests
|
||||
|
||||
AUTOMAKE_OPTIONS = subdir-objects
|
||||
|
||||
# Target dirs for test binaries, scripts and files
|
||||
testbindir = /opt/test/bin
|
||||
dbusconfdir = $(sysconfdir)/dbus-1/system.d
|
||||
|
||||
# ENABLE_TESTS is defined by configure when user enables tests during configuration
|
||||
if ENABLE_TESTS
|
||||
testbin_PROGRAMS = libsdbus-c++_unittests libsdbus-c++_integrationtests
|
||||
dbusconf_DATA = integrationtests/files/libsdbus-cpp-test.conf
|
||||
endif
|
||||
|
||||
# Setting per-file flags
|
||||
AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/src
|
||||
AM_CXXFLAGS = @libsdbus_cpp_CFLAGS@ @SYSTEMD_CFLAGS@ -W -Wall -Werror -pedantic -pipe -std=c++17
|
||||
AM_LDFLAGS = @libsdbus_cpp_LIBS@ @SYSTEMD_LIBS@
|
||||
|
||||
CLEANFILES = *~ *.lo *.la
|
||||
MOSTLYCLEANFILES = *.o
|
||||
|
||||
TESTS =
|
||||
|
||||
# Configuration for libsdbus-c++_unittests
|
||||
libsdbus_c___unittests_SOURCES = \
|
||||
unittests/libsdbus-c++_unittests.cpp \
|
||||
unittests/TypeTraits_test.cpp \
|
||||
unittests/Types_test.cpp \
|
||||
unittests/Message_test.cpp
|
||||
|
||||
libsdbus_c___unittests_LDFLAGS = -L$(top_builddir)/src -pthread
|
||||
|
||||
libsdbus_c___unittests_LDADD = \
|
||||
-lsdbus-c++ \
|
||||
@libsdbus_cpp_LIBS@ \
|
||||
@SYSTEMD_LIBS@ \
|
||||
-lgmock
|
||||
|
||||
TESTS += libsdbus-c++_unittests
|
||||
|
||||
# Configuration for libsdbus-c++_integrationtests
|
||||
libsdbus_c___integrationtests_SOURCES = \
|
||||
integrationtests/libsdbus-c++_integrationtests.cpp \
|
||||
integrationtests/Connection_test.cpp \
|
||||
integrationtests/AdaptorAndProxy_test.cpp
|
||||
|
||||
libsdbus_c___integrationtests_LDFLAGS = -L$(top_builddir)/src -pthread
|
||||
|
||||
libsdbus_c___integrationtests_LDADD = \
|
||||
-lsdbus-c++ \
|
||||
@libsdbus_cpp_LIBS@ \
|
||||
@SYSTEMD_LIBS@ \
|
||||
-lgmock
|
||||
|
||||
TESTS += libsdbus-c++_integrationtests
|
||||
|
||||
check_PROGRAMS = libsdbus-c++_unittests libsdbus-c++_integrationtests
|
||||
|
||||
DISTCLEANFILES = Makefile Makefile.in
|
||||
|
||||
# Post-build action: executing tests from the IDE
|
||||
if ENABLE_TESTS
|
||||
all-local: libsdbus-c++_unittests libsdbus-c++_integrationtests
|
||||
if [ "${UNIT_TESTS_RUNNER}" ]; then "${UNIT_TESTS_RUNNER}" --deviceip="${TEST_DEVICE_IP}" --testbin=.libs/libsdbus-c++_unittests; fi; exit 0
|
||||
if [ "${UNIT_TESTS_RUNNER}" ]; then "${UNIT_TESTS_RUNNER}" --deviceip="${TEST_DEVICE_IP}" --testbin=.libs/libsdbus-c++_integrationtests; fi; exit 0
|
||||
endif
|
||||
Executable
+17
@@ -0,0 +1,17 @@
|
||||
# Taken from https://github.com/google/googletest/blob/master/googletest/README.md#incorporating-into-an-existing-cmake-project
|
||||
|
||||
cmake_minimum_required(VERSION 2.8.2)
|
||||
|
||||
project(googletest-download NONE)
|
||||
|
||||
include(ExternalProject)
|
||||
|
||||
ExternalProject_Add(googletest
|
||||
GIT_REPOSITORY https://github.com/google/googletest.git
|
||||
GIT_TAG master
|
||||
SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-src"
|
||||
BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-build"
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND ""
|
||||
TEST_COMMAND "")
|
||||
@@ -41,6 +41,7 @@
|
||||
#include <thread>
|
||||
#include <tuple>
|
||||
#include <chrono>
|
||||
#include <fstream>
|
||||
|
||||
using ::testing::Eq;
|
||||
using ::testing::Gt;
|
||||
@@ -200,6 +201,51 @@ TEST_F(SdbusTestObject, CallsMethodWithComplexTypeSuccesfully)
|
||||
ASSERT_THAT(resComplex.count(0), Eq(1));
|
||||
}
|
||||
|
||||
TEST_F(SdbusTestObject, CallsMultiplyMethodWithNoReplyFlag)
|
||||
{
|
||||
m_proxy->multiplyWithNoReply(INT64_VALUE, DOUBLE_VALUE);
|
||||
|
||||
for (auto i = 0; i < 100; ++i)
|
||||
{
|
||||
if (m_adaptor->wasMultiplyCalled())
|
||||
break;
|
||||
std::this_thread::sleep_for(10ms);
|
||||
}
|
||||
ASSERT_TRUE(m_adaptor->wasMultiplyCalled());
|
||||
ASSERT_THAT(m_adaptor->getMultiplyResult(), Eq(INT64_VALUE * DOUBLE_VALUE));
|
||||
}
|
||||
|
||||
TEST_F(SdbusTestObject, CallsMethodThatThrowsError)
|
||||
{
|
||||
try
|
||||
{
|
||||
m_proxy->throwError();
|
||||
FAIL() << "Expected sdbus::Error exception";
|
||||
}
|
||||
catch (const sdbus::Error& e)
|
||||
{
|
||||
ASSERT_THAT(e.getName(), Eq("org.freedesktop.DBus.Error.AccessDenied"));
|
||||
ASSERT_THAT(e.getMessage(), Eq("A test error occurred (Operation not permitted)"));
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
FAIL() << "Expected sdbus::Error exception";
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(SdbusTestObject, CallsErrorThrowingMethodWithDontExpectReplySet)
|
||||
{
|
||||
ASSERT_NO_THROW(m_proxy->throwErrorWithNoReply());
|
||||
|
||||
for (auto i = 0; i < 100; ++i)
|
||||
{
|
||||
if (m_adaptor->wasThrowErrorCalled())
|
||||
break;
|
||||
std::this_thread::sleep_for(10ms);
|
||||
}
|
||||
ASSERT_TRUE(m_adaptor->wasThrowErrorCalled());
|
||||
}
|
||||
|
||||
TEST_F(SdbusTestObject, DoesServerSideAsynchoronousMethodInParallel)
|
||||
{
|
||||
// Yeah, this is kinda timing-dependent test, but times should be safe...
|
||||
@@ -227,7 +273,6 @@ TEST_F(SdbusTestObject, DoesServerSideAsynchoronousMethodInParallel)
|
||||
|
||||
TEST_F(SdbusTestObject, HandlesCorrectlyABulkOfParallelServerSideAsyncMethods)
|
||||
{
|
||||
std::mutex mtx;
|
||||
std::atomic<size_t> resultCount{};
|
||||
std::atomic<bool> invoke{};
|
||||
std::atomic<int> startedCount{};
|
||||
@@ -331,7 +376,7 @@ TEST_F(SdbusTestObject, ReadsReadPropertySuccesfully)
|
||||
|
||||
TEST_F(SdbusTestObject, WritesAndReadsReadWritePropertySuccesfully)
|
||||
{
|
||||
auto x = 42;
|
||||
uint32_t x = 42;
|
||||
ASSERT_NO_THROW(m_proxy->action(x));
|
||||
ASSERT_THAT(m_proxy->action(), Eq(x));
|
||||
}
|
||||
@@ -346,3 +391,8 @@ TEST_F(SdbusTestObject, CannotReadFromWriteProperty)
|
||||
{
|
||||
ASSERT_THROW(m_proxy->blocking(), sdbus::Error);
|
||||
}
|
||||
|
||||
TEST_F(SdbusTestObject, AnswersXmlApiDescriptionOnIntrospection)
|
||||
{
|
||||
ASSERT_THAT(m_proxy->Introspect(), Eq(m_adaptor->getExpectedXmlApiDescription()));
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "adaptor-glue.h"
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
#include <atomic>
|
||||
|
||||
class TestingAdaptor : public sdbus::Interfaces<testing_adaptor>
|
||||
{
|
||||
@@ -38,6 +39,10 @@ public:
|
||||
|
||||
virtual ~TestingAdaptor() { }
|
||||
|
||||
bool wasMultiplyCalled() const { return m_multiplyCalled; }
|
||||
double getMultiplyResult() const { return m_multiplyResult; }
|
||||
bool wasThrowErrorCalled() const { return m_throwErrorCalled; }
|
||||
|
||||
protected:
|
||||
|
||||
void noArgNoReturn() const { }
|
||||
@@ -48,6 +53,12 @@ protected:
|
||||
|
||||
double multiply(const int64_t& a, const double& b) const { return a * b; }
|
||||
|
||||
void multiplyWithNoReply(const int64_t& a, const double& b) const
|
||||
{
|
||||
m_multiplyResult = a * b;
|
||||
m_multiplyCalled = true;
|
||||
}
|
||||
|
||||
std::vector<int16_t> getInts16FromStruct(const sdbus::Struct<uint8_t, int16_t, double, std::string, std::vector<int16_t>>& x) const
|
||||
{
|
||||
std::vector<int16_t> res{x.get<1>()};
|
||||
@@ -154,6 +165,12 @@ protected:
|
||||
};
|
||||
}
|
||||
|
||||
void throwError() const
|
||||
{
|
||||
m_throwErrorCalled = true;
|
||||
throw sdbus::createError(1, "A test error occurred");
|
||||
}
|
||||
|
||||
std::string state() { return STRING_VALUE; }
|
||||
uint32_t action() { return m_action; }
|
||||
void action(const uint32_t& value) { m_action = value; }
|
||||
@@ -164,6 +181,10 @@ private:
|
||||
uint32_t m_action;
|
||||
bool m_blocking;
|
||||
|
||||
// For dont-expect-reply method call verifications
|
||||
mutable std::atomic<bool> m_multiplyCalled{};
|
||||
mutable double m_multiplyResult{};
|
||||
mutable std::atomic<bool> m_throwErrorCalled{};
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -28,10 +28,10 @@
|
||||
|
||||
#include "proxy-glue.h"
|
||||
|
||||
class TestingProxy : public sdbus::ProxyInterfaces<::testing_proxy>
|
||||
class TestingProxy : public sdbus::ProxyInterfaces<::testing_proxy, sdbus::introspectable_proxy>
|
||||
{
|
||||
public:
|
||||
using sdbus::ProxyInterfaces<::testing_proxy>::ProxyInterfaces;
|
||||
using sdbus::ProxyInterfaces<::testing_proxy, sdbus::introspectable_proxy>::ProxyInterfaces;
|
||||
|
||||
int getSimpleCallCount() const { return m_simpleCallCounter; }
|
||||
std::map<int32_t, std::string> getMap() const { return m_map; }
|
||||
|
||||
@@ -57,11 +57,14 @@ protected:
|
||||
testing_adaptor(sdbus::IObject& object) :
|
||||
object_(object)
|
||||
{
|
||||
object_.setInterfaceFlags(INTERFACE_NAME).markAsDeprecated().withPropertyUpdateBehavior(sdbus::Flags::EMITS_NO_SIGNAL);
|
||||
|
||||
object_.registerMethod("noArgNoReturn").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->noArgNoReturn(); });
|
||||
object_.registerMethod("getInt").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->getInt(); });
|
||||
object_.registerMethod("getTuple").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->getTuple(); });
|
||||
|
||||
object_.registerMethod("multiply").onInterface(INTERFACE_NAME).implementedAs([this](const int64_t& a, const double& b){ return this->multiply(a, b); });
|
||||
object_.registerMethod("multiplyWithNoReply").onInterface(INTERFACE_NAME).implementedAs([this](const int64_t& a, const double& b){ this->multiplyWithNoReply(a, b); }).markAsDeprecated().withNoReply();
|
||||
object_.registerMethod("getInts16FromStruct").onInterface(INTERFACE_NAME).implementedAs([this](
|
||||
const sdbus::Struct<uint8_t, int16_t, double, std::string, std::vector<int16_t>>& x){ return this->getInts16FromStruct(x); });
|
||||
|
||||
@@ -95,15 +98,20 @@ protected:
|
||||
object_.registerMethod("getSignature").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->getSignature(); });
|
||||
object_.registerMethod("getObjectPath").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->getObjectPath(); });
|
||||
|
||||
object_.registerMethod("getComplex").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->getComplex(); });
|
||||
object_.registerMethod("getComplex").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->getComplex(); }).markAsDeprecated();
|
||||
|
||||
object_.registerMethod("throwError").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->throwError(); });
|
||||
object_.registerMethod("throwErrorWithNoReply").onInterface(INTERFACE_NAME).implementedAs([this](){ this->throwError(); }).withNoReply();
|
||||
|
||||
object_.registerMethod("doPrivilegedStuff").onInterface(INTERFACE_NAME).implementedAs([](){}).markAsPrivileged();
|
||||
|
||||
// registration of signals is optional, it is useful because of introspection
|
||||
object_.registerSignal("simpleSignal").onInterface(INTERFACE_NAME);
|
||||
object_.registerSignal("simpleSignal").onInterface(INTERFACE_NAME).markAsDeprecated();
|
||||
object_.registerSignal("signalWithMap").onInterface(INTERFACE_NAME).withParameters<std::map<int32_t, std::string>>();
|
||||
object_.registerSignal("signalWithVariant").onInterface(INTERFACE_NAME).withParameters<sdbus::Variant>();
|
||||
|
||||
object_.registerProperty("state").onInterface(INTERFACE_NAME).withGetter([this](){ return this->state(); });
|
||||
object_.registerProperty("action").onInterface(INTERFACE_NAME).withGetter([this](){ return this->action(); }).withSetter([this](const uint32_t& value){ this->action(value); });
|
||||
object_.registerProperty("state").onInterface(INTERFACE_NAME).withGetter([this](){ return this->state(); }).markAsDeprecated().withUpdateBehavior(sdbus::Flags::CONST_PROPERTY_VALUE);
|
||||
object_.registerProperty("action").onInterface(INTERFACE_NAME).withGetter([this](){ return this->action(); }).withSetter([this](const uint32_t& value){ this->action(value); }).withUpdateBehavior(sdbus::Flags::EMITS_NO_SIGNAL);
|
||||
object_.registerProperty("blocking").onInterface(INTERFACE_NAME)./*withGetter([this](){ return this->blocking(); }).*/withSetter([this](const bool& value){ this->blocking(value); });
|
||||
|
||||
}
|
||||
@@ -143,6 +151,7 @@ protected:
|
||||
virtual int32_t getInt() const = 0;
|
||||
virtual std::tuple<uint32_t, std::string> getTuple() const = 0;
|
||||
virtual double multiply(const int64_t& a, const double& b) const = 0;
|
||||
virtual void multiplyWithNoReply(const int64_t& a, const double& b) const = 0;
|
||||
virtual std::vector<int16_t> getInts16FromStruct(const sdbus::Struct<uint8_t, int16_t, double, std::string, std::vector<int16_t>>& x) const = 0;
|
||||
virtual sdbus::Variant processVariant(sdbus::Variant& v) = 0;
|
||||
virtual std::map<int32_t, sdbus::Variant> getMapOfVariants(const std::vector<int32_t>& x, const sdbus::Struct<sdbus::Variant, sdbus::Variant>& y) const = 0;
|
||||
@@ -154,6 +163,7 @@ protected:
|
||||
virtual sdbus::Signature getSignature() const = 0;
|
||||
virtual sdbus::ObjectPath getObjectPath() const = 0;
|
||||
virtual ComplexType getComplex() const = 0;
|
||||
virtual void throwError() const = 0;
|
||||
|
||||
virtual std::string state() = 0;
|
||||
virtual uint32_t action() = 0;
|
||||
@@ -161,6 +171,142 @@ protected:
|
||||
virtual bool blocking() = 0;
|
||||
virtual void blocking(const bool& value) = 0;
|
||||
|
||||
public: // For testing purposes
|
||||
std::string getExpectedXmlApiDescription()
|
||||
{
|
||||
return
|
||||
R"delimiter(<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
|
||||
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
|
||||
<node>
|
||||
<interface name="org.freedesktop.DBus.Peer">
|
||||
<method name="Ping"/>
|
||||
<method name="GetMachineId">
|
||||
<arg type="s" name="machine_uuid" direction="out"/>
|
||||
</method>
|
||||
</interface>
|
||||
<interface name="org.freedesktop.DBus.Introspectable">
|
||||
<method name="Introspect">
|
||||
<arg name="data" type="s" direction="out"/>
|
||||
</method>
|
||||
</interface>
|
||||
<interface name="org.freedesktop.DBus.Properties">
|
||||
<method name="Get">
|
||||
<arg name="interface" direction="in" type="s"/>
|
||||
<arg name="property" direction="in" type="s"/>
|
||||
<arg name="value" direction="out" type="v"/>
|
||||
</method>
|
||||
<method name="GetAll">
|
||||
<arg name="interface" direction="in" type="s"/>
|
||||
<arg name="properties" direction="out" type="a{sv}"/>
|
||||
</method>
|
||||
<method name="Set">
|
||||
<arg name="interface" direction="in" type="s"/>
|
||||
<arg name="property" direction="in" type="s"/>
|
||||
<arg name="value" direction="in" type="v"/>
|
||||
</method>
|
||||
<signal name="PropertiesChanged">
|
||||
<arg type="s" name="interface"/>
|
||||
<arg type="a{sv}" name="changed_properties"/>
|
||||
<arg type="as" name="invalidated_properties"/>
|
||||
</signal>
|
||||
</interface>
|
||||
<interface name="com.kistler.testsdbuscpp">
|
||||
<annotation name="org.freedesktop.DBus.Deprecated" value="true"/>
|
||||
<method name="doOperationAsync">
|
||||
<arg type="u" direction="in"/>
|
||||
<arg type="u" direction="out"/>
|
||||
</method>
|
||||
<method name="doOperationSync">
|
||||
<arg type="u" direction="in"/>
|
||||
<arg type="u" direction="out"/>
|
||||
</method>
|
||||
<method name="doPrivilegedStuff">
|
||||
<annotation name="org.freedesktop.systemd1.Privileged" value="true"/>
|
||||
</method>
|
||||
<method name="getComplex">
|
||||
<arg type="a{t(a{ya(obva{is})}gs)}" direction="out"/>
|
||||
<annotation name="org.freedesktop.DBus.Deprecated" value="true"/>
|
||||
</method>
|
||||
<method name="getInt">
|
||||
<arg type="i" direction="out"/>
|
||||
</method>
|
||||
<method name="getInts16FromStruct">
|
||||
<arg type="(yndsan)" direction="in"/>
|
||||
<arg type="an" direction="out"/>
|
||||
</method>
|
||||
<method name="getMapOfVariants">
|
||||
<arg type="ai" direction="in"/>
|
||||
<arg type="(vv)" direction="in"/>
|
||||
<arg type="a{iv}" direction="out"/>
|
||||
</method>
|
||||
<method name="getObjectPath">
|
||||
<arg type="o" direction="out"/>
|
||||
</method>
|
||||
<method name="getSignature">
|
||||
<arg type="g" direction="out"/>
|
||||
</method>
|
||||
<method name="getStructInStruct">
|
||||
<arg type="(s(a{ii}))" direction="out"/>
|
||||
</method>
|
||||
<method name="getTuple">
|
||||
<arg type="u" direction="out"/>
|
||||
<arg type="s" direction="out"/>
|
||||
</method>
|
||||
<method name="multiply">
|
||||
<arg type="x" direction="in"/>
|
||||
<arg type="d" direction="in"/>
|
||||
<arg type="d" direction="out"/>
|
||||
</method>
|
||||
<method name="multiplyWithNoReply">
|
||||
<arg type="x" direction="in"/>
|
||||
<arg type="d" direction="in"/>
|
||||
<annotation name="org.freedesktop.DBus.Deprecated" value="true"/>
|
||||
<annotation name="org.freedesktop.DBus.Method.NoReply" value="true"/>
|
||||
</method>
|
||||
<method name="noArgNoReturn">
|
||||
</method>
|
||||
<method name="processVariant">
|
||||
<arg type="v" direction="in"/>
|
||||
<arg type="v" direction="out"/>
|
||||
</method>
|
||||
<method name="sumStructItems">
|
||||
<arg type="(yq)" direction="in"/>
|
||||
<arg type="(ix)" direction="in"/>
|
||||
<arg type="i" direction="out"/>
|
||||
</method>
|
||||
<method name="sumVectorItems">
|
||||
<arg type="aq" direction="in"/>
|
||||
<arg type="at" direction="in"/>
|
||||
<arg type="u" direction="out"/>
|
||||
</method>
|
||||
<method name="throwError">
|
||||
</method>
|
||||
<method name="throwErrorWithNoReply">
|
||||
<annotation name="org.freedesktop.DBus.Method.NoReply" value="true"/>
|
||||
</method>
|
||||
<signal name="signalWithMap">
|
||||
<arg type="a{is}"/>
|
||||
</signal>
|
||||
<signal name="signalWithVariant">
|
||||
<arg type="v"/>
|
||||
</signal>
|
||||
<signal name="simpleSignal">
|
||||
<annotation name="org.freedesktop.DBus.Deprecated" value="true"/>
|
||||
</signal>
|
||||
<property name="action" type="u" access="readwrite">
|
||||
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
|
||||
</property>
|
||||
<property name="blocking" type="b" access="readwrite">
|
||||
</property>
|
||||
<property name="state" type="s" access="read">
|
||||
<annotation name="org.freedesktop.DBus.Deprecated" value="true"/>
|
||||
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
|
||||
</property>
|
||||
</interface>
|
||||
</node>
|
||||
)delimiter";
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -45,7 +45,6 @@ protected:
|
||||
{ this->onSignalWithoutRegistration(s); });
|
||||
}
|
||||
|
||||
|
||||
virtual void onSimpleSignal() = 0;
|
||||
virtual void onSignalWithMap(const std::map<int32_t, std::string>& map) = 0;
|
||||
virtual void onSignalWithVariant(const sdbus::Variant& v) = 0;
|
||||
@@ -78,6 +77,11 @@ public:
|
||||
return result;
|
||||
}
|
||||
|
||||
void multiplyWithNoReply(const int64_t& a, const double& b)
|
||||
{
|
||||
object_.callMethod("multiplyWithNoReply").onInterface(INTERFACE_NAME).withArguments(a, b).dontExpectReply();
|
||||
}
|
||||
|
||||
std::vector<int16_t> getInts16FromStruct(const sdbus::Struct<uint8_t, int16_t, double, std::string, std::vector<int16_t>>& x)
|
||||
{
|
||||
std::vector<int16_t> result;
|
||||
@@ -155,6 +159,16 @@ public:
|
||||
return result;
|
||||
}
|
||||
|
||||
void throwError()
|
||||
{
|
||||
object_.callMethod("throwError").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
void throwErrorWithNoReply()
|
||||
{
|
||||
object_.callMethod("throwErrorWithNoReply").onInterface(INTERFACE_NAME).dontExpectReply();
|
||||
}
|
||||
|
||||
int32_t callNonexistentMethod()
|
||||
{
|
||||
int32_t result;
|
||||
|
||||
Reference in New Issue
Block a user