forked from Kistler-Group/sdbus-cpp
Compare commits
20 Commits
v1.2.0
...
fix/static
Author | SHA1 | Date | |
---|---|---|---|
41f93b23e9 | |||
cebc1c860b | |||
c39bc637b8 | |||
737f04abc7 | |||
3a56113422 | |||
f332f46087 | |||
c9e157e3e1 | |||
8ca3fdd5ce | |||
55c306ce05 | |||
6c5e72326c | |||
8bbeeeb4ce | |||
7a09e9bcc8 | |||
c812d03bc7 | |||
e7d4e07926 | |||
031f4687ca | |||
aeae79003a | |||
74d849d933 | |||
f336811fc7 | |||
35bffd0f25 | |||
e33a890ce7 |
23
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
23
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior.
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Real (buggy) behavior**
|
||||
A clear and concise description of what really happened in contrast to your expectation.
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here, like version of sdbus-c++ library, version of systemd used, OS used.
|
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
30
.github/workflows/ci.yml
vendored
30
.github/workflows/ci.yml
vendored
@ -12,7 +12,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-18.04, ubuntu-20.04]
|
||||
os: [ubuntu-18.04, ubuntu-20.04, ubuntu-22.04]
|
||||
compiler: [g++, clang]
|
||||
build: [shared-libsystemd]
|
||||
include:
|
||||
@ -20,7 +20,7 @@ jobs:
|
||||
compiler: g++
|
||||
build: embedded-static-libsystemd
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- name: install-libsystemd-toolchain
|
||||
if: matrix.build == 'embedded-static-libsystemd'
|
||||
run: |
|
||||
@ -39,33 +39,37 @@ jobs:
|
||||
sudo update-alternatives --install /usr/bin/cc cc /usr/bin/clang 10
|
||||
sudo update-alternatives --remove-all c++
|
||||
sudo update-alternatives --install /usr/bin/c++ c++ /usr/bin/clang++ 10
|
||||
- name: configure-debug
|
||||
if: matrix.build == 'shared-libsystemd' && matrix.os == 'ubuntu-18.04'
|
||||
- name: install-googletest
|
||||
if: matrix.os == 'ubuntu-22.04' # On older ubuntus the libgmock-dev package is either unavailable or has faulty pkg-config file
|
||||
run: |
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_FLAGS="-O0 -g -W -Wextra -Wall -Wnon-virtual-dtor -Werror" -DBUILD_TESTS=ON -DENABLE_PERF_TESTS=ON -DENABLE_STRESS_TESTS=ON -DBUILD_CODE_GEN=ON ..
|
||||
- name: configure-release
|
||||
sudo apt-get install -y libgmock-dev
|
||||
- name: configure-debug
|
||||
if: matrix.build == 'shared-libsystemd' && matrix.os == 'ubuntu-20.04'
|
||||
run: |
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_CXX_FLAGS="-O3 -DNDEBUG -W -Wextra -Wall -Wnon-virtual-dtor -Werror" -DBUILD_TESTS=ON -DENABLE_PERF_TESTS=ON -DENABLE_STRESS_TESTS=ON -DBUILD_CODE_GEN=ON ..
|
||||
cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_FLAGS="-O0 -g -W -Wextra -Wall -Wnon-virtual-dtor -Werror" -DCMAKE_VERBOSE_MAKEFILE=ON -DBUILD_TESTS=ON -DENABLE_PERF_TESTS=ON -DENABLE_STRESS_TESTS=ON -DBUILD_CODE_GEN=ON ..
|
||||
- name: configure-release
|
||||
if: matrix.build == 'shared-libsystemd' && (matrix.os == 'ubuntu-18.04' || matrix.os == 'ubuntu-22.04')
|
||||
run: |
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_CXX_FLAGS="-O3 -DNDEBUG -W -Wextra -Wall -Wnon-virtual-dtor -Werror" -DCMAKE_VERBOSE_MAKEFILE=ON -DBUILD_TESTS=ON -DENABLE_PERF_TESTS=ON -DENABLE_STRESS_TESTS=ON -DBUILD_CODE_GEN=ON ..
|
||||
- name: configure-with-embedded-libsystemd
|
||||
if: matrix.build == 'embedded-static-libsystemd'
|
||||
run: |
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTS=ON -DENABLE_PERF_TESTS=ON -DENABLE_STRESS_TESTS=ON -DBUILD_CODE_GEN=ON -DBUILD_LIBSYSTEMD=ON -DLIBSYSTEMD_VERSION=244 ..
|
||||
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_VERBOSE_MAKEFILE=ON -DBUILD_TESTS=ON -DENABLE_PERF_TESTS=ON -DENABLE_STRESS_TESTS=ON -DBUILD_CODE_GEN=ON -DBUILD_LIBSYSTEMD=ON -DLIBSYSTEMD_VERSION=244 ..
|
||||
- name: make
|
||||
run: |
|
||||
cd build
|
||||
cmake --build . -j2
|
||||
cmake --build . -j4
|
||||
- name: verify
|
||||
run: |
|
||||
cd build
|
||||
sudo cmake --build . --target install
|
||||
ctest
|
||||
ctest --output-on-failure
|
||||
- name: pack
|
||||
if: matrix.build == 'shared-libsystemd' && matrix.os == 'ubuntu-20.04'
|
||||
run: |
|
||||
@ -73,7 +77,7 @@ jobs:
|
||||
cpack -G DEB
|
||||
- name: 'Upload Artifact'
|
||||
if: matrix.build == 'shared-libsystemd' && matrix.os == 'ubuntu-20.04' && matrix.compiler == 'g++'
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: "debian-packages-${{ matrix.os }}-${{ matrix.compiler }}"
|
||||
path: |
|
||||
|
@ -89,7 +89,7 @@ set(SDBUSCPP_SRCS ${SDBUSCPP_CPP_SRCS} ${SDBUSCPP_HDR_SRCS} ${SDBUSCPP_PUBLIC_HD
|
||||
# GENERAL COMPILER CONFIGURATION
|
||||
#-------------------------------
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
|
||||
#----------------------------------
|
||||
# LIBRARY BUILD INFORMATION
|
||||
@ -140,7 +140,7 @@ endif()
|
||||
install(TARGETS ${EXPORT_SET}
|
||||
EXPORT sdbus-c++-targets
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT runtime
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT runtime
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT runtime NAMELINK_COMPONENT dev
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT dev
|
||||
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${SDBUSCPP_INCLUDE_SUBDIR} COMPONENT dev)
|
||||
|
||||
@ -210,6 +210,11 @@ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/cmake/sdbus-c++-config.cmake
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/sdbus-c++
|
||||
COMPONENT dev)
|
||||
|
||||
if(BUILD_SHARED_LIBS AND (BUILD_LIBSYSTEMD OR Systemd_LINK_LIBRARIES MATCHES "/libsystemd\.a(;|$)"))
|
||||
set(PKGCONFIG_REQS ".private")
|
||||
else()
|
||||
set(PKGCONFIG_REQS "")
|
||||
endif()
|
||||
configure_file(pkgconfig/sdbus-c++.pc.in pkgconfig/sdbus-c++.pc @ONLY)
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/pkgconfig/sdbus-c++.pc
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig COMPONENT dev)
|
||||
|
@ -97,7 +97,7 @@ References/documentation
|
||||
|
||||
* [Using sdbus-c++](docs/using-sdbus-c++.md) - *the* main, comprehensive tutorial on sdbus-c++
|
||||
* [Systemd and dbus configuration](docs/systemd-dbus-config.md)
|
||||
* [D-Bus Specification](https://dbus.freedesktop.org/docs/dbus-specification.html)
|
||||
* [D-Bus Specification](https://dbus.freedesktop.org/doc/dbus-specification.html)
|
||||
* [sd-bus Overview](http://0pointer.net/blog/the-new-sd-bus-api-of-systemd.html)
|
||||
|
||||
Contributing
|
||||
|
@ -46,7 +46,7 @@ ExternalProject_Add(LibsystemdBuildProject
|
||||
GIT_SHALLOW 1
|
||||
UPDATE_COMMAND ""
|
||||
CONFIGURE_COMMAND ${CMAKE_COMMAND} -E remove <BINARY_DIR>/*
|
||||
COMMAND ${MESON} --prefix=<INSTALL_DIR> --buildtype=${LIBSYSTEMD_BUILD_TYPE} -Dstatic-libsystemd=pic -Dselinux=false <SOURCE_DIR> <BINARY_DIR> ${LIBSYSTEMD_EXTRA_CONFIG_OPTS}
|
||||
COMMAND ${MESON} --prefix=<INSTALL_DIR> --buildtype=${LIBSYSTEMD_BUILD_TYPE} -Drootprefix=<INSTALL_DIR> -Dstatic-libsystemd=pic -Dselinux=false <SOURCE_DIR> <BINARY_DIR> ${LIBSYSTEMD_EXTRA_CONFIG_OPTS}
|
||||
BUILD_COMMAND ${BUILD_VERSION_H}
|
||||
COMMAND ${NINJA} -C <BINARY_DIR> libsystemd.a
|
||||
BUILD_ALWAYS 0
|
||||
|
@ -162,7 +162,7 @@ FULL_PATH_NAMES = YES
|
||||
# will be relative from the directory where doxygen is started.
|
||||
# This tag requires that the tag FULL_PATH_NAMES is set to YES.
|
||||
|
||||
STRIP_FROM_PATH =
|
||||
STRIP_FROM_PATH = @PROJECT_SOURCE_DIR@ @PROJECT_BINARY_DIR@
|
||||
|
||||
# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
|
||||
# path mentioned in the documentation of a class, which tells the reader which
|
||||
|
@ -41,7 +41,7 @@ Typical default D-Bus configuration does not allow to register services except e
|
||||
<busconfig>
|
||||
<policy user="root">
|
||||
<allow own="org.sdbuscpp.concatenator"/>
|
||||
<allow send_destination="org.sdbuscpp"/>
|
||||
<allow send_destination="org.sdbuscpp.concatenator"/>
|
||||
<allow send_interface="org.sdbuscpp.concatenator"/>
|
||||
</policy>
|
||||
</busconfig>
|
||||
|
@ -19,8 +19,9 @@ Using sdbus-c++ library
|
||||
14. [Asynchronous client-side methods](#asynchronous-client-side-methods)
|
||||
15. [Using D-Bus properties](#using-d-bus-properties)
|
||||
16. [Standard D-Bus interfaces](#standard-d-bus-interfaces)
|
||||
17. [Support for match rules](#support-for-match-rules)
|
||||
18. [Conclusion](#conclusion)
|
||||
17. [Using D-Bus Types](#using-d-bus-types)
|
||||
18. [Support for match rules](#support-for-match-rules)
|
||||
19. [Conclusion](#conclusion)
|
||||
|
||||
Introduction
|
||||
------------
|
||||
@ -410,19 +411,23 @@ On the **server** side, we generally need to create D-Bus objects and publish th
|
||||
* or in a non-blocking async way, through `enterEventLoopAsync()`,
|
||||
* or, when we have our own implementation of an event loop (e.g. we are using sd-event event loop), we can ask the connection for its underlying fd, I/O events and timeouts through `getEventLoopPollData()` and use that data in our event loop mechanism.
|
||||
|
||||
The object takes the D-Bus connection as a reference in its constructor. This is the only way to wire connection and object together. We must make sure the connection exists as long as objects using it exist.
|
||||
|
||||
Of course, at any time before or after running the event loop on the connection, we can create and "hook", as well as remove, objects and proxies upon that connection.
|
||||
|
||||
#### Using D-Bus connections on the client side
|
||||
|
||||
On the **client** side we have more options when creating D-Bus proxies. That corresponds to three overloads of the `createProxy()` factory:
|
||||
On the **client** side we likewise need a connection -- just that unlike on the server side, we don't need to request a unique bus name on it. We have more options here when creating a proxy:
|
||||
|
||||
* In case we (the application) already maintain a D-Bus connection, e.g. because we a D-Bus service anyway, the simple and typical approach is to create proxy upon that connection. The proxy will share the connection with others. So we pass connection reference to proxy factory. With this approach we must of course ensure that the connection exists as long as the proxy exists.
|
||||
* Pass an already existing connection as a reference. This is the typical approach when the application already maintains a D-Bus connection (maybe it provide D-Bus API on it, and/or it already has some proxies hooked on it). The proxy will share the connection with others. With this approach we must of course ensure that the connection exists as long as the proxy exists.
|
||||
|
||||
* Or -- and this is typical when we have a simple D-Bus client application -- we have another option: we let proxy maintain its own connection (and an associated thread):
|
||||
* Or -- and this is typical when we have a simple D-Bus client application -- we have another option: we let the proxy maintain its own connection (and potentially an associated event loop thread, see below):
|
||||
|
||||
* We either create the connection ourselves and `std::move` it to the proxy object factory. The proxy becomes an owner of this connection, and will run the event loop on that connection. This had the advantage that we may choose the type of connection (system, session, remote).
|
||||
|
||||
* Or we don't bother about any connection at all when creating a proxy (the factory overload with no connection parameter). Under the hood, the proxy creates its own *system bus* connection, creates a separate thread and runs an event loop in it. This is **the simplest approach** for non-complex D-Bus clients. For more complex ones, with big number of proxies, this hurts scalability but may improve concurrency (see discussion higher above), so we should make a conscious choice.
|
||||
* Or we don't bother about any connection at all when creating a proxy (the factory overload with no connection parameter). Under the hood, the proxy creates its own *system bus* connection, creates a separate thread and runs an event loop in it. Quite **simple**, but as you can see, this hurts scalability in case of many proxies, as each would spawn and maintain its own event loop thread (see discussion higher above). But we don't necessarily need an event loop thread, in case our proxy doesn't need to listen to signals or async method call replies. Read on.
|
||||
|
||||
It's also possible in this case to instruct the proxy to **not spawn an event loop thread** for its connection. There are many situations that we want to quickly create a proxy, carry out one or a few (synchronous) D-Bus calls, and let go of proxy. We call them light-weight proxies. For that purpose, spawning a new event loop thread comes with time and resource penalty, for nothing. To create such **a light-weight proxy**, use the factory/constructor overload with `dont_run_event_loop_thread_t`. All in above two bullet sub-points holds; the proxy just won't spawn a thread with an event loop in it. Note that such a proxy can be used only for synchronous D-Bus calls; it may not receive signals or async call replies.
|
||||
|
||||
#### Stopping I/O event loops graciously
|
||||
|
||||
@ -604,7 +609,7 @@ sdbus-c++ ships with the native stub generator tool called `sdbus-c++-xml2cpp`.
|
||||
The generator tool takes D-Bus XML IDL description of D-Bus interfaces on its input, and can be instructed to generate one or both of these: an adaptor header file for use on the server side, and a proxy header file for use on the client side. Like this:
|
||||
|
||||
```bash
|
||||
sdbus-c++-xml2cpp database-bindings.xml --adaptor=database-server-glue.h --proxy=database-client-glue.h
|
||||
sdbus-c++-xml2cpp concatenator-bindings.xml --adaptor=concatenator-server-glue.h --proxy=concatenator-client-glue.h
|
||||
```
|
||||
|
||||
The adaptor header file contains classes that can be used to implement interfaces described in the IDL (these classes represent object interfaces). The proxy header file contains classes that can be used to make calls to remote objects (these classes represent remote object interfaces).
|
||||
@ -630,12 +635,14 @@ As an example, let's look at an XML description of our Concatenator's interfaces
|
||||
</node>
|
||||
```
|
||||
|
||||
After running this through the stubs generator, we get the stub code that is described in the following two subsections.
|
||||
After running this through the code generator, we get the generated code that is described in the following two subsections.
|
||||
|
||||
### concatenator-server-glue.h
|
||||
|
||||
For each interface in the XML IDL file the generator creates one class that represents it. The class is de facto an interface which shall be implemented by the class inheriting it. The class' constructor takes care of registering all methods, signals and properties. For each D-Bus method there is a pure virtual member function. These pure virtual functions must be implemented in the child class. For each signal, there is a public function member that emits this signal.
|
||||
|
||||
Generated adaptor classes support move semantics. They are moveable but not copyable.
|
||||
|
||||
```cpp
|
||||
/*
|
||||
* This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT!
|
||||
@ -658,25 +665,30 @@ public:
|
||||
|
||||
protected:
|
||||
Concatenator_adaptor(sdbus::IObject& object)
|
||||
: object_(object)
|
||||
: object_(&object)
|
||||
{
|
||||
object_.registerMethod("concatenate").onInterface(INTERFACE_NAME).withInputParamNames("numbers", "separator").withOutputParamNames("concatenatedString").implementedAs([this](const std::vector<int32_t>& numbers, const std::string& separator){ return this->concatenate(numbers, separator); });
|
||||
object_.registerSignal("concatenated").onInterface(INTERFACE_NAME).withParameters<std::string>("concatenatedString");
|
||||
object_->registerMethod("concatenate").onInterface(INTERFACE_NAME).withInputParamNames("numbers", "separator").withOutputParamNames("concatenatedString").implementedAs([this](const std::vector<int32_t>& numbers, const std::string& separator){ return this->concatenate(numbers, separator); });
|
||||
object_->registerSignal("concatenated").onInterface(INTERFACE_NAME).withParameters<std::string>("concatenatedString");
|
||||
}
|
||||
|
||||
Concatenator_adaptor(const Concatenator_adaptor&) = delete;
|
||||
Concatenator_adaptor& operator=(const Concatenator_adaptor&) = delete;
|
||||
Concatenator_adaptor(Concatenator_adaptor&&) = default;
|
||||
Concatenator_adaptor& operator=(Concatenator_adaptor&&) = default;
|
||||
|
||||
~Concatenator_adaptor() = default;
|
||||
|
||||
public:
|
||||
void emitConcatenated(const std::string& concatenatedString)
|
||||
{
|
||||
object_.emitSignal("concatenated").onInterface(INTERFACE_NAME).withArguments(concatenatedString);
|
||||
object_->emitSignal("concatenated").onInterface(INTERFACE_NAME).withArguments(concatenatedString);
|
||||
}
|
||||
|
||||
private:
|
||||
virtual std::string concatenate(const std::vector<int32_t>& numbers, const std::string& separator) = 0;
|
||||
|
||||
private:
|
||||
sdbus::IObject& object_;
|
||||
sdbus::IObject* object_;
|
||||
};
|
||||
|
||||
}} // namespaces
|
||||
@ -686,7 +698,9 @@ private:
|
||||
|
||||
### concatenator-client-glue.h
|
||||
|
||||
Analogously to the adaptor classes described above, there is one class generated for one interface in the XML IDL file. The class is de facto a proxy to the concrete single interface of a remote object. For each D-Bus signal there is a pure virtual member function whose body must be provided in a child class. For each method, there is a public function member that calls the method remotely.
|
||||
Analogously to the adaptor classes described above, there is one proxy class generated for one interface in the XML IDL file. The class is de facto a proxy to the concrete single interface of a remote object. For each D-Bus signal there is a pure virtual member function whose body must be provided in a child class. For each method, there is a public function member that calls the method remotely.
|
||||
|
||||
Generated proxy classes support move semantics. They are moveable but not copyable.
|
||||
|
||||
```cpp
|
||||
/*
|
||||
@ -710,11 +724,16 @@ public:
|
||||
|
||||
protected:
|
||||
Concatenator_proxy(sdbus::IProxy& proxy)
|
||||
: proxy_(proxy)
|
||||
: proxy_(&proxy)
|
||||
{
|
||||
proxy_.uponSignal("concatenated").onInterface(INTERFACE_NAME).call([this](const std::string& concatenatedString){ this->onConcatenated(concatenatedString); });
|
||||
proxy_->uponSignal("concatenated").onInterface(INTERFACE_NAME).call([this](const std::string& concatenatedString){ this->onConcatenated(concatenatedString); });
|
||||
}
|
||||
|
||||
Concatenator_proxy(const Concatenator_proxy&) = delete;
|
||||
Concatenator_proxy& operator=(const Concatenator_proxy&) = delete;
|
||||
Concatenator_proxy(Concatenator_proxy&&) = default;
|
||||
Concatenator_proxy& operator=(Concatenator_proxy&&) = default;
|
||||
|
||||
~Concatenator_proxy() = default;
|
||||
|
||||
virtual void onConcatenated(const std::string& concatenatedString) = 0;
|
||||
@ -723,12 +742,12 @@ public:
|
||||
std::string concatenate(const std::vector<int32_t>& numbers, const std::string& separator)
|
||||
{
|
||||
std::string result;
|
||||
proxy_.callMethod("concatenate").onInterface(INTERFACE_NAME).withArguments(numbers, separator).storeResultsTo(result);
|
||||
proxy_->callMethod("concatenate").onInterface(INTERFACE_NAME).withArguments(numbers, separator).storeResultsTo(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
sdbus::IProxy& proxy_;
|
||||
sdbus::IProxy* proxy_;
|
||||
};
|
||||
|
||||
}} // namespaces
|
||||
@ -1047,11 +1066,11 @@ For a real example of a server-side asynchronous D-Bus method, please look at sd
|
||||
Asynchronous client-side methods
|
||||
--------------------------------
|
||||
|
||||
sdbus-c++ also supports asynchronous approach at the client (the proxy) side. With this approach, we can issue a D-Bus method call without blocking current thread's execution while waiting for the reply. We go on doing other things, and when the reply comes, a given callback is invoked within the context of the D-Bus dispatcher thread.
|
||||
sdbus-c++ also supports asynchronous approach at the client (the proxy) side. With this approach, we can issue a D-Bus method call without blocking current thread's execution while waiting for the reply. We go on doing other things, and when the reply comes, either a given callback handler will be invoked within the context of the event loop thread, or a future object returned by the async call will be set the returned value.6
|
||||
|
||||
### Lower-level API
|
||||
|
||||
Considering the Concatenator example based on lower-level API, if we wanted to call `concatenate` in an async way, we'd have to pass a callback to the proxy when issuing the call, and that callback gets invoked when the reply arrives:
|
||||
Considering the Concatenator example based on lower-level API, if we wanted to call `concatenate` in an async way, we have two options: We either pass a callback to the proxy when issuing the call, and that callback gets invoked when the reply arrives:
|
||||
|
||||
```c++
|
||||
int main(int argc, char *argv[])
|
||||
@ -1096,9 +1115,34 @@ int main(int argc, char *argv[])
|
||||
|
||||
The callback is a void-returning function taking two arguments: a reference to the reply message, and a pointer to the prospective `sdbus::Error` instance. Zero `Error` pointer means that no D-Bus error occurred while making the call, and the reply message contains valid reply. Non-zero `Error` pointer, however, points to the valid `Error` instance, meaning that an error occurred. Error name and message can then be read out by the client from that instance.
|
||||
|
||||
There is also an overload of this `IProxy::callMethod()` function taking method call timeout argument.
|
||||
|
||||
Another option is to use `std::future`-based overload of the `IProxy::callMethod()` function. A future object will be returned which will later, when the reply arrives, be set to contain the returned reply message. Or if the call returns an error, `sdbus::Error` will be thrown by `std::future::get()`.
|
||||
|
||||
```c++
|
||||
...
|
||||
// Invoke concatenate on given interface of the object
|
||||
{
|
||||
auto method = concatenatorProxy->createMethodCall(interfaceName, "concatenate");
|
||||
method << numbers << separator;
|
||||
auto future = concatenatorProxy->callMethod(method, sdbus::with_future);
|
||||
try
|
||||
{
|
||||
auto reply = future.get(); // This will throw if call ends with an error
|
||||
std::string result;
|
||||
reply >> result;
|
||||
std::cout << "Got concatenate result: " << result << std::endl;
|
||||
}
|
||||
catch (const sdbus::Error& e)
|
||||
{
|
||||
std::cerr << "Got concatenate error " << e.getName() << " with message " << e.getMessage() << std::endl;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Convenience API
|
||||
|
||||
On the convenience API level, the call statement starts with `callMethodAsync()`, and ends with `uponReplyInvoke()` that takes a callback handler. The callback is a void-returning function that takes at least one argument: pointer to the `sdbus::Error` instance. All subsequent arguments shall exactly reflect the D-Bus method output arguments. A concatenator example:
|
||||
On the convenience API level, the call statement starts with `callMethodAsync()`, and one option is to finish the statement with `uponReplyInvoke()` that takes a callback handler. The callback is a void-returning function that takes at least one argument: pointer to the `sdbus::Error` instance. All subsequent arguments shall exactly reflect the D-Bus method output arguments. A concatenator example:
|
||||
|
||||
```c++
|
||||
int main(int argc, char *argv[])
|
||||
@ -1133,6 +1177,25 @@ int main(int argc, char *argv[])
|
||||
|
||||
When the `Error` pointer is zero, it means that no D-Bus error occurred while making the call, and subsequent arguments are valid D-Bus method return values. Non-zero `Error` pointer, however, points to the valid `Error` instance, meaning that an error occurred during the call (and subsequent arguments are simply default-constructed). Error name and message can then be read out by the client from `Error` instance.
|
||||
|
||||
Another option is to finish the async call statement with `getResultAsFuture()`, which is a template function which takes the list of types returned by the D-Bus method (empty list in case of `void`-returning method) which returns a `std::future` object, which will later, when the reply arrives, be set to contain the return value(s). Or if the call returns an error, `sdbus::Error` will be thrown by `std::future::get()`.
|
||||
|
||||
The future object will contain void for a void-returning D-Bus method, a single type for a single value returning D-Bus method, and a `std::tuple` to hold multiple return values of a D-Bus method.
|
||||
|
||||
```c++
|
||||
...
|
||||
auto future = concatenatorProxy->callMethodAsync("concatenate").onInterface(interfaceName).withArguments(numbers, separator).getResultAsFuture<std::string>();
|
||||
try
|
||||
{
|
||||
auto concatenatedString = future.get(); // This waits for the reply
|
||||
std::cout << "Got concatenate result: " << concatenatedString << std::endl;
|
||||
}
|
||||
catch (const sdbus::Error& e)
|
||||
{
|
||||
std::cerr << "Got concatenate error " << e.getName() << " with message " << e.getMessage() << std::endl;
|
||||
}
|
||||
...
|
||||
```
|
||||
|
||||
### Marking client-side async methods in the IDL
|
||||
|
||||
sdbus-c++ stub generator can generate stub code for client-side async methods. We just need to annotate the method with `org.freedesktop.DBus.Method.Async`. The annotation element value must be either `client` (async on the client-side only) or `clientserver` (async method on both client- and server-side):
|
||||
@ -1216,9 +1279,9 @@ class PropertyProvider_adaptor
|
||||
|
||||
public:
|
||||
PropertyProvider_adaptor(sdbus::IObject& object)
|
||||
: object_(object)
|
||||
: object_(&object)
|
||||
{
|
||||
object_.registerProperty("status").onInterface(INTERFACE_NAME).withGetter([this](){ return this->status(); }).withSetter([this](const uint32_t& value){ this->status(value); });
|
||||
object_->registerProperty("status").onInterface(INTERFACE_NAME).withGetter([this](){ return this->status(); }).withSetter([this](const uint32_t& value){ this->status(value); });
|
||||
}
|
||||
|
||||
~PropertyProvider_adaptor() = default;
|
||||
@ -1245,13 +1308,13 @@ public:
|
||||
// getting the property value
|
||||
uint32_t status()
|
||||
{
|
||||
return object_.getProperty("status").onInterface(INTERFACE_NAME);
|
||||
return object_->getProperty("status").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
// setting the property value
|
||||
void status(const uint32_t& value)
|
||||
{
|
||||
object_.setProperty("status").onInterface(INTERFACE_NAME).toValue(value);
|
||||
object_->setProperty("status").onInterface(INTERFACE_NAME).toValue(value);
|
||||
}
|
||||
|
||||
/*...*/
|
||||
@ -1280,6 +1343,47 @@ Note that signals of afore-mentioned standard D-Bus interfaces are not emitted b
|
||||
|
||||
Working examples of using standard D-Bus interfaces can be found in [sdbus-c++ integration tests](/tests/integrationtests/DBusStandardInterfacesTests.cpp) or the [examples](/examples) directory.
|
||||
|
||||
Using D-Bus Types
|
||||
-----------------
|
||||
|
||||
For many D-Bus interactions dealing with D-Bus types is necessary. For that, sdbus-c++ provides many predefined D-Bus types. The table below shows which C++ type corresponds to which D-Bus type.
|
||||
|
||||
|
||||
| Category | Code | Code ASCII | Conventional Name | C++ Type |
|
||||
|---------------------|-------------|------------|--------------------|---------------------------------|
|
||||
| reserved | 0 | NUL | INVALID | - |
|
||||
| fixed, basic | 121 | y | BYTE | `uint8_t` |
|
||||
| fixed, basic | 98 | b | BOOLEAN | `bool` |
|
||||
| fixed, basic | 110 | n | INT16 | `int16_t` |
|
||||
| fixed, basic | 113 | q | UINT16 | `uint16_t` |
|
||||
| fixed, basic | 105 | i | INT32 | `int32_t` |
|
||||
| fixed, basic | 117 | u | UINT32 | `uint32_t` |
|
||||
| fixed, basic | 120 | x | INT64 | `int64_t` |
|
||||
| fixed, basic | 116 | t | UINT64 | `uint64_t` |
|
||||
| fixed, basic | 100 | d | DOUBLE | `double` |
|
||||
| string-like, basic | 115 | s | STRING | `const char*`, `std::string` |
|
||||
| string-like, basic | 111 | o | OBJECT_PATH | `sdbus::ObjectPath` |
|
||||
| string-like, basic | 103 | g | SIGNATURE | `sdbus::Signature` |
|
||||
| container | 97 | a | ARRAY | `std::vector<T>` (if used as an array followed by a single complete type T), or `std::map<T1, T2>` (if used as an array of dict entries) |
|
||||
| container | 114,40,41 | r() | STRUCT | `sdbus::Struct<T1, T2, ...>` variadic class template |
|
||||
| container | 118 | v | VARIANT | `sdbus::Variant` |
|
||||
| container | 101,123,125 | e{} | DICT_ENTRY | - |
|
||||
| fixed, basic | 104 | h | UNIX_FD | `sdbus::UnixFd` |
|
||||
| reserved | 109 | m | (reserved) | - |
|
||||
| reserved | 42 | * | (reserved) | - |
|
||||
| reserved | 63 | ? | (reserved) | - |
|
||||
| reserved | 64,38,94 | @&^ | (reserved) | - |
|
||||
|
||||
A few examples:
|
||||
|
||||
* The D-Bus signature of an output argument of method `GetManagedObjects()` on standard interface `org.freedesktop.DBus.ObjectManager` is `a{oa{sa{sv}}}`. For this the corresponding C++ method return type is: `std::map<sdbus::ObjectPath, std::map<std::string, std::map<std::string, sdbus::Variant>>>`.
|
||||
* Or an input argument of method `InterfacesRemoved` on that interface has signature `as`. Ths corresponds to the C++ parameter of type `std::vector<std::string>`.
|
||||
* Or a D-Bus signature `a(bdh)` corresponds to the array of D-Bus structures: `std::vector<sdbus::Struct<bool, double, sdbus::UnixFd>>`.
|
||||
|
||||
To see how C++ types are mapped to D-Bus types (including container types) in sdbus-c++, have a look at individual [specializations of `sdbus::signature_of` class template](https://github.com/Kistler-Group/sdbus-cpp/blob/master/include/sdbus-c%2B%2B/TypeTraits.h#L87) in TypeTraits.h header file. For more examples of type mappings, look into [TypeTraits unit tests](https://github.com/Kistler-Group/sdbus-cpp/blob/master/tests/unittests/TypeTraits_test.cpp#L62).
|
||||
|
||||
For more information on basic D-Bus types, D-Bus container types, and D-Bus type system in general, make sure to consult the [D-Bus specification](https://dbus.freedesktop.org/doc/dbus-specification.html#type-system).
|
||||
|
||||
Support for match rules
|
||||
-----------------------
|
||||
|
||||
|
@ -141,6 +141,11 @@ namespace sdbus {
|
||||
|
||||
protected:
|
||||
using base_type = AdaptorInterfaces;
|
||||
|
||||
AdaptorInterfaces(const AdaptorInterfaces&) = delete;
|
||||
AdaptorInterfaces& operator=(const AdaptorInterfaces&) = delete;
|
||||
AdaptorInterfaces(AdaptorInterfaces&&) = default;
|
||||
AdaptorInterfaces& operator=(AdaptorInterfaces&&) = default;
|
||||
~AdaptorInterfaces() = default;
|
||||
};
|
||||
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include <vector>
|
||||
#include <type_traits>
|
||||
#include <chrono>
|
||||
#include <future>
|
||||
#include <cstdint>
|
||||
|
||||
// Forward declarations
|
||||
@ -195,6 +196,10 @@ namespace sdbus {
|
||||
AsyncMethodInvoker& withTimeout(const std::chrono::duration<_Rep, _Period>& timeout);
|
||||
template <typename... _Args> AsyncMethodInvoker& withArguments(_Args&&... args);
|
||||
template <typename _Function> PendingAsyncCall uponReplyInvoke(_Function&& callback);
|
||||
// Returned future will be std::future<void> for no (void) D-Bus method return value
|
||||
// or std::future<T> for single D-Bus method return value
|
||||
// or std::future<std::tuple<...>> for multiple method return values
|
||||
template <typename... _Args> std::future<future_return_t<_Args...>> getResultAsFuture();
|
||||
|
||||
private:
|
||||
IProxy& proxy_;
|
||||
|
@ -610,6 +610,29 @@ namespace sdbus {
|
||||
return proxy_.callMethod(method_, std::move(asyncReplyHandler), timeout_);
|
||||
}
|
||||
|
||||
template <typename... _Args>
|
||||
std::future<future_return_t<_Args...>> AsyncMethodInvoker::getResultAsFuture()
|
||||
{
|
||||
auto promise = std::make_shared<std::promise<future_return_t<_Args...>>>();
|
||||
auto future = promise->get_future();
|
||||
|
||||
uponReplyInvoke([promise = std::move(promise)](const Error* error, _Args... args)
|
||||
{
|
||||
if (error == nullptr)
|
||||
if constexpr (!std::is_void_v<future_return_t<_Args...>>)
|
||||
promise->set_value({std::move(args)...});
|
||||
else
|
||||
promise->set_value();
|
||||
else
|
||||
promise->set_exception(std::make_exception_ptr(*error));
|
||||
});
|
||||
|
||||
// Will be std::future<void> for no D-Bus method return value
|
||||
// or std::future<T> for single D-Bus method return value
|
||||
// or std::future<std::tuple<...>> for multiple method return values
|
||||
return future;
|
||||
}
|
||||
|
||||
/*** ---------------- ***/
|
||||
/*** SignalSubscriber ***/
|
||||
/*** ---------------- ***/
|
||||
|
@ -293,7 +293,6 @@ namespace sdbus {
|
||||
*
|
||||
* @param[in] match Match expression to filter incoming D-Bus message
|
||||
* @param[in] callback Callback handler to be called upon incoming D-Bus message matching the rule
|
||||
* @param[in] Floating slot tag
|
||||
*
|
||||
* The method installs a floating match rule for messages received on the specified bus connection.
|
||||
* Floating means that the bus connection object owns the match rule, i.e. lifetime of the match rule
|
||||
@ -314,21 +313,21 @@ namespace sdbus {
|
||||
[[deprecated("This function has been replaced by enterEventLoop()")]] void enterProcessingLoop();
|
||||
|
||||
/*!
|
||||
* @copydoc IConnection::enterProcessingLoopAsync()
|
||||
* @copydoc IConnection::enterEventLoopAsync()
|
||||
*
|
||||
* @deprecated This function has been replaced by enterEventLoopAsync()
|
||||
*/
|
||||
[[deprecated("This function has been replaced by enterEventLoopAsync()")]] void enterProcessingLoopAsync();
|
||||
|
||||
/*!
|
||||
* @copydoc IConnection::leaveProcessingLoop()
|
||||
* @copydoc IConnection::leaveEventLoop()
|
||||
*
|
||||
* @deprecated This function has been replaced by leaveEventLoop()
|
||||
*/
|
||||
[[deprecated("This function has been replaced by leaveEventLoop()")]] void leaveProcessingLoop();
|
||||
|
||||
/*!
|
||||
* @copydoc IConnection::getProcessLoopPollData()
|
||||
* @copydoc IConnection::getEventLoopPollData()
|
||||
*
|
||||
* @deprecated This function has been replaced by getEventLoopPollData()
|
||||
*/
|
||||
|
@ -28,10 +28,12 @@
|
||||
#define SDBUS_CXX_IPROXY_H_
|
||||
|
||||
#include <sdbus-c++/ConvenienceApiClasses.h>
|
||||
#include <sdbus-c++/TypeTraits.h>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
#include <chrono>
|
||||
#include <future>
|
||||
|
||||
// Forward declarations
|
||||
namespace sdbus {
|
||||
@ -322,6 +324,33 @@ namespace sdbus {
|
||||
* @return A pointer to the currently processed D-Bus message
|
||||
*/
|
||||
virtual const Message* getCurrentlyProcessedMessage() const = 0;
|
||||
|
||||
/*!
|
||||
* @brief Calls method on the proxied D-Bus object asynchronously
|
||||
*
|
||||
* @param[in] message Message representing an async method call
|
||||
* @param[in] asyncReplyCallback Handler for the async reply
|
||||
* @param[in] timeout Timeout for dbus call in microseconds
|
||||
* @return Cookie for the the pending asynchronous call
|
||||
*
|
||||
* The call is non-blocking. It doesn't wait for the reply. Once the reply arrives,
|
||||
* the provided async reply handler will get invoked from the context of the connection
|
||||
* I/O event loop thread.
|
||||
*
|
||||
* Note: To avoid messing with messages, use higher-level API defined below.
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
virtual std::future<MethodReply> callMethod(const MethodCall& message, with_future_t) = 0;
|
||||
virtual std::future<MethodReply> callMethod(const MethodCall& message, uint64_t timeout, with_future_t) = 0;
|
||||
|
||||
/*!
|
||||
* @copydoc IProxy::callMethod(const MethodCall&,uint64_t,with_future_t)
|
||||
*/
|
||||
template <typename _Rep, typename _Period>
|
||||
std::future<MethodReply> callMethod( const MethodCall& message
|
||||
, const std::chrono::duration<_Rep, _Period>& timeout
|
||||
, with_future_t );
|
||||
};
|
||||
|
||||
/********************************************//**
|
||||
@ -382,6 +411,15 @@ namespace sdbus {
|
||||
return callMethod(message, std::move(asyncReplyCallback), microsecs.count());
|
||||
}
|
||||
|
||||
template <typename _Rep, typename _Period>
|
||||
inline std::future<MethodReply> IProxy::callMethod( const MethodCall& message
|
||||
, const std::chrono::duration<_Rep, _Period>& timeout
|
||||
, with_future_t )
|
||||
{
|
||||
auto microsecs = std::chrono::duration_cast<std::chrono::microseconds>(timeout);
|
||||
return callMethod(message, microsecs.count(), with_future);
|
||||
}
|
||||
|
||||
inline MethodInvoker IProxy::callMethod(const std::string& methodName)
|
||||
{
|
||||
return MethodInvoker(*this, methodName);
|
||||
@ -458,6 +496,30 @@ namespace sdbus {
|
||||
, std::string destination
|
||||
, std::string objectPath );
|
||||
|
||||
/*!
|
||||
* @brief Creates a proxy object for a specific remote D-Bus object
|
||||
*
|
||||
* @param[in] connection D-Bus connection to be used by the proxy object
|
||||
* @param[in] destination Bus name that provides the remote D-Bus object
|
||||
* @param[in] objectPath Path of the remote D-Bus object
|
||||
* @return Pointer to the object proxy instance
|
||||
*
|
||||
* The provided connection will be used by the proxy to issue calls against the object.
|
||||
* The Object proxy becomes an exclusive owner of this connection, but will not start an event loop
|
||||
* thread on this connection. This is cheap construction and is suitable for short-lived proxies
|
||||
* created just to execute simple synchronous D-Bus calls and then destroyed. Such blocking request-reply
|
||||
* calls will work without an event loop (but signals, async calls, etc. won't).
|
||||
*
|
||||
* Code example:
|
||||
* @code
|
||||
* auto proxy = sdbus::createProxy(std::move(connection), "com.kistler.foo", "/com/kistler/foo", sdbus::dont_run_event_loop_thread);
|
||||
* @endcode
|
||||
*/
|
||||
[[nodiscard]] std::unique_ptr<sdbus::IProxy> createProxy( std::unique_ptr<sdbus::IConnection>&& connection
|
||||
, std::string destination
|
||||
, std::string objectPath
|
||||
, dont_run_event_loop_thread_t );
|
||||
|
||||
/*!
|
||||
* @brief Creates a proxy object for a specific remote D-Bus object
|
||||
*
|
||||
@ -466,7 +528,7 @@ namespace sdbus {
|
||||
* @return Pointer to the object proxy instance
|
||||
*
|
||||
* No D-Bus connection is provided here, so the object proxy will create and manage
|
||||
* his own connection, and will automatically start a procesing loop upon that connection
|
||||
* his own connection, and will automatically start an event loop upon that connection
|
||||
* in a separate internal thread. Handlers for incoming signals and asynchronous
|
||||
* method replies will be executed in the context of that thread.
|
||||
*
|
||||
@ -478,6 +540,28 @@ namespace sdbus {
|
||||
[[nodiscard]] std::unique_ptr<sdbus::IProxy> createProxy( std::string destination
|
||||
, std::string objectPath );
|
||||
|
||||
/*!
|
||||
* @brief Creates a proxy object for a specific remote D-Bus object
|
||||
*
|
||||
* @param[in] destination Bus name that provides the remote D-Bus object
|
||||
* @param[in] objectPath Path of the remote D-Bus object
|
||||
* @return Pointer to the object proxy instance
|
||||
*
|
||||
* No D-Bus connection is provided here, so the object proxy will create and manage
|
||||
* his own connection, but it will not start an event loop thread. This is cheap
|
||||
* construction and is suitable for short-lived proxies created just to execute simple
|
||||
* synchronous D-Bus calls and then destroyed. Such blocking request-reply calls
|
||||
* will work without an event loop (but signals, async calls, etc. won't).
|
||||
*
|
||||
* Code example:
|
||||
* @code
|
||||
* auto proxy = sdbus::createProxy("com.kistler.foo", "/com/kistler/foo", sdbus::dont_run_event_loop_thread );
|
||||
* @endcode
|
||||
*/
|
||||
[[nodiscard]] std::unique_ptr<sdbus::IProxy> createProxy( std::string destination
|
||||
, std::string objectPath
|
||||
, dont_run_event_loop_thread_t );
|
||||
|
||||
}
|
||||
|
||||
#include <sdbus-c++/ConvenienceApiClasses.inl>
|
||||
|
@ -109,6 +109,21 @@ namespace sdbus {
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Creates native-like proxy object instance
|
||||
*
|
||||
* @param[in] destination Bus name that provides a D-Bus object
|
||||
* @param[in] objectPath Path of the D-Bus object
|
||||
*
|
||||
* This constructor overload creates a proxy that manages its own D-Bus connection(s).
|
||||
* For more information on its behavior, consult @ref createProxy(std::string,std::string,sdbus::dont_run_event_loop_thread_t)
|
||||
*/
|
||||
ProxyInterfaces(std::string destination, std::string objectPath, dont_run_event_loop_thread_t)
|
||||
: ProxyObjectHolder(createProxy(std::move(destination), std::move(objectPath), dont_run_event_loop_thread))
|
||||
, _Interfaces(getProxy())...
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Creates native-like proxy object instance
|
||||
*
|
||||
@ -141,6 +156,22 @@ namespace sdbus {
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Creates native-like proxy object instance
|
||||
*
|
||||
* @param[in] connection D-Bus connection to be used by the proxy object
|
||||
* @param[in] destination Bus name that provides a D-Bus object
|
||||
* @param[in] objectPath Path of the D-Bus object
|
||||
*
|
||||
* The proxy created this way becomes an owner of the connection.
|
||||
* For more information on its behavior, consult @ref createProxy(std::unique_ptr<sdbus::IConnection>&&,std::string,std::string,sdbus::dont_run_event_loop_thread_t)
|
||||
*/
|
||||
ProxyInterfaces(std::unique_ptr<sdbus::IConnection>&& connection, std::string destination, std::string objectPath, dont_run_event_loop_thread_t)
|
||||
: ProxyObjectHolder(createProxy(std::move(connection), std::move(destination), std::move(objectPath), dont_run_event_loop_thread))
|
||||
, _Interfaces(getProxy())...
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Finishes proxy registration and makes the proxy ready for use
|
||||
*
|
||||
@ -175,6 +206,11 @@ namespace sdbus {
|
||||
|
||||
protected:
|
||||
using base_type = ProxyInterfaces;
|
||||
|
||||
ProxyInterfaces(const ProxyInterfaces&) = delete;
|
||||
ProxyInterfaces& operator=(const ProxyInterfaces&) = delete;
|
||||
ProxyInterfaces(ProxyInterfaces&&) = default;
|
||||
ProxyInterfaces& operator=(ProxyInterfaces&&) = default;
|
||||
~ProxyInterfaces() = default;
|
||||
};
|
||||
|
||||
|
@ -43,27 +43,32 @@ namespace sdbus {
|
||||
|
||||
protected:
|
||||
Peer_proxy(sdbus::IProxy& proxy)
|
||||
: proxy_(proxy)
|
||||
: proxy_(&proxy)
|
||||
{
|
||||
}
|
||||
|
||||
Peer_proxy(const Peer_proxy&) = delete;
|
||||
Peer_proxy& operator=(const Peer_proxy&) = delete;
|
||||
Peer_proxy(Peer_proxy&&) = default;
|
||||
Peer_proxy& operator=(Peer_proxy&&) = default;
|
||||
|
||||
~Peer_proxy() = default;
|
||||
|
||||
public:
|
||||
void Ping()
|
||||
{
|
||||
proxy_.callMethod("Ping").onInterface(INTERFACE_NAME);
|
||||
proxy_->callMethod("Ping").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
std::string GetMachineId()
|
||||
{
|
||||
std::string machineUUID;
|
||||
proxy_.callMethod("GetMachineId").onInterface(INTERFACE_NAME).storeResultsTo(machineUUID);
|
||||
proxy_->callMethod("GetMachineId").onInterface(INTERFACE_NAME).storeResultsTo(machineUUID);
|
||||
return machineUUID;
|
||||
}
|
||||
|
||||
private:
|
||||
sdbus::IProxy& proxy_;
|
||||
sdbus::IProxy* proxy_;
|
||||
};
|
||||
|
||||
// Proxy for introspection
|
||||
@ -73,22 +78,27 @@ namespace sdbus {
|
||||
|
||||
protected:
|
||||
Introspectable_proxy(sdbus::IProxy& proxy)
|
||||
: proxy_(proxy)
|
||||
: proxy_(&proxy)
|
||||
{
|
||||
}
|
||||
|
||||
Introspectable_proxy(const Introspectable_proxy&) = delete;
|
||||
Introspectable_proxy& operator=(const Introspectable_proxy&) = delete;
|
||||
Introspectable_proxy(Introspectable_proxy&&) = default;
|
||||
Introspectable_proxy& operator=(Introspectable_proxy&&) = default;
|
||||
|
||||
~Introspectable_proxy() = default;
|
||||
|
||||
public:
|
||||
std::string Introspect()
|
||||
{
|
||||
std::string xml;
|
||||
proxy_.callMethod("Introspect").onInterface(INTERFACE_NAME).storeResultsTo(xml);
|
||||
proxy_->callMethod("Introspect").onInterface(INTERFACE_NAME).storeResultsTo(xml);
|
||||
return xml;
|
||||
}
|
||||
|
||||
private:
|
||||
sdbus::IProxy& proxy_;
|
||||
sdbus::IProxy* proxy_;
|
||||
};
|
||||
|
||||
// Proxy for properties
|
||||
@ -98,10 +108,10 @@ namespace sdbus {
|
||||
|
||||
protected:
|
||||
Properties_proxy(sdbus::IProxy& proxy)
|
||||
: proxy_(proxy)
|
||||
: proxy_(&proxy)
|
||||
{
|
||||
proxy_
|
||||
.uponSignal("PropertiesChanged")
|
||||
->uponSignal("PropertiesChanged")
|
||||
.onInterface(INTERFACE_NAME)
|
||||
.call([this]( const std::string& interfaceName
|
||||
, const std::map<std::string, sdbus::Variant>& changedProperties
|
||||
@ -111,6 +121,11 @@ namespace sdbus {
|
||||
});
|
||||
}
|
||||
|
||||
Properties_proxy(const Properties_proxy&) = delete;
|
||||
Properties_proxy& operator=(const Properties_proxy&) = delete;
|
||||
Properties_proxy(Properties_proxy&&) = default;
|
||||
Properties_proxy& operator=(Properties_proxy&&) = default;
|
||||
|
||||
~Properties_proxy() = default;
|
||||
|
||||
virtual void onPropertiesChanged( const std::string& interfaceName
|
||||
@ -120,23 +135,23 @@ namespace sdbus {
|
||||
public:
|
||||
sdbus::Variant Get(const std::string& interfaceName, const std::string& propertyName)
|
||||
{
|
||||
return proxy_.getProperty(propertyName).onInterface(interfaceName);
|
||||
return proxy_->getProperty(propertyName).onInterface(interfaceName);
|
||||
}
|
||||
|
||||
void Set(const std::string& interfaceName, const std::string& propertyName, const sdbus::Variant& value)
|
||||
{
|
||||
proxy_.setProperty(propertyName).onInterface(interfaceName).toValue(value);
|
||||
proxy_->setProperty(propertyName).onInterface(interfaceName).toValue(value);
|
||||
}
|
||||
|
||||
std::map<std::string, sdbus::Variant> GetAll(const std::string& interfaceName)
|
||||
{
|
||||
std::map<std::string, sdbus::Variant> props;
|
||||
proxy_.callMethod("GetAll").onInterface(INTERFACE_NAME).withArguments(interfaceName).storeResultsTo(props);
|
||||
proxy_->callMethod("GetAll").onInterface(INTERFACE_NAME).withArguments(interfaceName).storeResultsTo(props);
|
||||
return props;
|
||||
}
|
||||
|
||||
private:
|
||||
sdbus::IProxy& proxy_;
|
||||
sdbus::IProxy* proxy_;
|
||||
};
|
||||
|
||||
// Proxy for object manager
|
||||
@ -146,10 +161,10 @@ namespace sdbus {
|
||||
|
||||
protected:
|
||||
ObjectManager_proxy(sdbus::IProxy& proxy)
|
||||
: proxy_(proxy)
|
||||
: proxy_(&proxy)
|
||||
{
|
||||
proxy_
|
||||
.uponSignal("InterfacesAdded")
|
||||
->uponSignal("InterfacesAdded")
|
||||
.onInterface(INTERFACE_NAME)
|
||||
.call([this]( const sdbus::ObjectPath& objectPath
|
||||
, const std::map<std::string, std::map<std::string, sdbus::Variant>>& interfacesAndProperties )
|
||||
@ -157,8 +172,7 @@ namespace sdbus {
|
||||
this->onInterfacesAdded(objectPath, interfacesAndProperties);
|
||||
});
|
||||
|
||||
proxy_
|
||||
.uponSignal("InterfacesRemoved")
|
||||
proxy_->uponSignal("InterfacesRemoved")
|
||||
.onInterface(INTERFACE_NAME)
|
||||
.call([this]( const sdbus::ObjectPath& objectPath
|
||||
, const std::vector<std::string>& interfaces )
|
||||
@ -167,6 +181,11 @@ namespace sdbus {
|
||||
});
|
||||
}
|
||||
|
||||
ObjectManager_proxy(const ObjectManager_proxy&) = delete;
|
||||
ObjectManager_proxy& operator=(const ObjectManager_proxy&) = delete;
|
||||
ObjectManager_proxy(ObjectManager_proxy&&) = default;
|
||||
ObjectManager_proxy& operator=(ObjectManager_proxy&&) = default;
|
||||
|
||||
~ObjectManager_proxy() = default;
|
||||
|
||||
virtual void onInterfacesAdded( const sdbus::ObjectPath& objectPath
|
||||
@ -178,12 +197,12 @@ namespace sdbus {
|
||||
std::map<sdbus::ObjectPath, std::map<std::string, std::map<std::string, sdbus::Variant>>> GetManagedObjects()
|
||||
{
|
||||
std::map<sdbus::ObjectPath, std::map<std::string, std::map<std::string, sdbus::Variant>>> objectsInterfacesAndProperties;
|
||||
proxy_.callMethod("GetManagedObjects").onInterface(INTERFACE_NAME).storeResultsTo(objectsInterfacesAndProperties);
|
||||
proxy_->callMethod("GetManagedObjects").onInterface(INTERFACE_NAME).storeResultsTo(objectsInterfacesAndProperties);
|
||||
return objectsInterfacesAndProperties;
|
||||
}
|
||||
|
||||
private:
|
||||
sdbus::IProxy& proxy_;
|
||||
sdbus::IProxy* proxy_;
|
||||
};
|
||||
|
||||
// Adaptors for the above-listed standard D-Bus interfaces are not necessary because the functionality
|
||||
@ -197,25 +216,30 @@ namespace sdbus {
|
||||
|
||||
protected:
|
||||
Properties_adaptor(sdbus::IObject& object)
|
||||
: object_(object)
|
||||
: object_(&object)
|
||||
{
|
||||
}
|
||||
|
||||
Properties_adaptor(const Properties_adaptor&) = delete;
|
||||
Properties_adaptor& operator=(const Properties_adaptor&) = delete;
|
||||
Properties_adaptor(Properties_adaptor&&) = default;
|
||||
Properties_adaptor& operator=(Properties_adaptor&&) = default;
|
||||
|
||||
~Properties_adaptor() = default;
|
||||
|
||||
public:
|
||||
void emitPropertiesChangedSignal(const std::string& interfaceName, const std::vector<std::string>& properties)
|
||||
{
|
||||
object_.emitPropertiesChangedSignal(interfaceName, properties);
|
||||
object_->emitPropertiesChangedSignal(interfaceName, properties);
|
||||
}
|
||||
|
||||
void emitPropertiesChangedSignal(const std::string& interfaceName)
|
||||
{
|
||||
object_.emitPropertiesChangedSignal(interfaceName);
|
||||
object_->emitPropertiesChangedSignal(interfaceName);
|
||||
}
|
||||
|
||||
private:
|
||||
sdbus::IObject& object_;
|
||||
sdbus::IObject* object_;
|
||||
};
|
||||
|
||||
/*!
|
||||
@ -234,15 +258,20 @@ namespace sdbus {
|
||||
|
||||
protected:
|
||||
explicit ObjectManager_adaptor(sdbus::IObject& object)
|
||||
: object_(object)
|
||||
: object_(&object)
|
||||
{
|
||||
object_.addObjectManager();
|
||||
object_->addObjectManager();
|
||||
}
|
||||
|
||||
ObjectManager_adaptor(const ObjectManager_adaptor&) = delete;
|
||||
ObjectManager_adaptor& operator=(const ObjectManager_adaptor&) = delete;
|
||||
ObjectManager_adaptor(ObjectManager_adaptor&&) = default;
|
||||
ObjectManager_adaptor& operator=(ObjectManager_adaptor&&) = default;
|
||||
|
||||
~ObjectManager_adaptor() = default;
|
||||
|
||||
private:
|
||||
sdbus::IObject& object_;
|
||||
sdbus::IObject* object_;
|
||||
};
|
||||
|
||||
/*!
|
||||
@ -259,10 +288,16 @@ namespace sdbus {
|
||||
class ManagedObject_adaptor
|
||||
{
|
||||
protected:
|
||||
explicit ManagedObject_adaptor(sdbus::IObject& object) : object_(object)
|
||||
explicit ManagedObject_adaptor(sdbus::IObject& object)
|
||||
: object_(&object)
|
||||
{
|
||||
}
|
||||
|
||||
ManagedObject_adaptor(const ManagedObject_adaptor&) = delete;
|
||||
ManagedObject_adaptor& operator=(const ManagedObject_adaptor&) = delete;
|
||||
ManagedObject_adaptor(ManagedObject_adaptor&&) = default;
|
||||
ManagedObject_adaptor& operator=(ManagedObject_adaptor&&) = default;
|
||||
|
||||
~ManagedObject_adaptor() = default;
|
||||
|
||||
public:
|
||||
@ -273,7 +308,7 @@ namespace sdbus {
|
||||
*/
|
||||
void emitInterfacesAddedSignal()
|
||||
{
|
||||
object_.emitInterfacesAddedSignal();
|
||||
object_->emitInterfacesAddedSignal();
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -283,7 +318,7 @@ namespace sdbus {
|
||||
*/
|
||||
void emitInterfacesAddedSignal(const std::vector<std::string>& interfaces)
|
||||
{
|
||||
object_.emitInterfacesAddedSignal(interfaces);
|
||||
object_->emitInterfacesAddedSignal(interfaces);
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -293,7 +328,7 @@ namespace sdbus {
|
||||
*/
|
||||
void emitInterfacesRemovedSignal()
|
||||
{
|
||||
object_.emitInterfacesRemovedSignal();
|
||||
object_->emitInterfacesRemovedSignal();
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -303,11 +338,11 @@ namespace sdbus {
|
||||
*/
|
||||
void emitInterfacesRemovedSignal(const std::vector<std::string>& interfaces)
|
||||
{
|
||||
object_.emitInterfacesRemovedSignal(interfaces);
|
||||
object_->emitInterfacesRemovedSignal(interfaces);
|
||||
}
|
||||
|
||||
private:
|
||||
sdbus::IObject& object_;
|
||||
sdbus::IObject* object_;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -81,6 +81,13 @@ namespace sdbus {
|
||||
// Tag denoting the assumption that the caller has already obtained fd ownership
|
||||
struct adopt_fd_t { explicit adopt_fd_t() = default; };
|
||||
inline constexpr adopt_fd_t adopt_fd{};
|
||||
// Tag specifying that the proxy shall not run an event loop thread on its D-Bus connection.
|
||||
// Such proxies are typically created to carry out a simple synchronous D-Bus call(s) and then are destroyed.
|
||||
struct dont_run_event_loop_thread_t { explicit dont_run_event_loop_thread_t() = default; };
|
||||
inline constexpr dont_run_event_loop_thread_t dont_run_event_loop_thread{};
|
||||
// Tag denoting an asynchronous call that returns std::future as a handle
|
||||
struct with_future_t { explicit with_future_t() = default; };
|
||||
inline constexpr with_future_t with_future{};
|
||||
|
||||
// Template specializations for getting D-Bus signatures from C++ types
|
||||
template <typename _T>
|
||||
@ -540,6 +547,26 @@ namespace sdbus {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <typename... _Args> struct future_return
|
||||
{
|
||||
typedef std::tuple<_Args...> type;
|
||||
};
|
||||
|
||||
template <> struct future_return<>
|
||||
{
|
||||
typedef void type;
|
||||
};
|
||||
|
||||
template <typename _Type> struct future_return<_Type>
|
||||
{
|
||||
typedef _Type type;
|
||||
};
|
||||
|
||||
template <typename... _Args>
|
||||
using future_return_t = typename future_return<_Args...>::type;
|
||||
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template <class _Function, class _Tuple, typename... _Args, std::size_t... _I>
|
||||
|
@ -5,7 +5,7 @@ includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@
|
||||
|
||||
Name: @PROJECT_NAME@
|
||||
Description: C++ library on top of sd-bus, a systemd D-Bus library
|
||||
Requires: libsystemd
|
||||
Requires@PKGCONFIG_REQS@: libsystemd
|
||||
Version: @SDBUSCPP_VERSION@
|
||||
Libs: -L${libdir} -l@PROJECT_NAME@
|
||||
Cflags: -I${includedir}
|
||||
|
@ -33,6 +33,8 @@
|
||||
#include "ScopeGuard.h"
|
||||
#include <systemd/sd-bus.h>
|
||||
#include <cassert>
|
||||
#include <mutex>
|
||||
#include <atomic>
|
||||
|
||||
namespace sdbus {
|
||||
|
||||
@ -862,15 +864,70 @@ void Signal::setDestination(const std::string& destination)
|
||||
SDBUS_THROW_ERROR_IF(r < 0, "Failed to set signal destination", -r);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
// Pseudo-connection lifetime handling. In standard cases, we could do with simply function-local static pseudo
|
||||
// connection instance below. However, it may happen that client's sdbus-c++ objects outlive this static connection
|
||||
// instance (because they are used in global application objects that were created before this connection, and thus
|
||||
// are destroyed later). This by itself sounds like a smell in client's application design, but it is downright bad
|
||||
// in sdbus-c++ because it has no control over when client's dependent statics get destroyed. A "Phoenix" pattern
|
||||
// (see Modern C++ Design - Generic Programming and Design Patterns Applied, by Andrei Alexandrescu) is applied to fix
|
||||
// this by re-creating the connection again in such cases and keeping it alive until the next exit handler is invoked.
|
||||
// The pattern is combined with double-checked locking pattern to ensure safe re-creation across threads/CPU cores.
|
||||
// Another common solution is global sdbus-c++ startup/shutdown functions, but that would be an intrusive change.
|
||||
|
||||
// Working notes (TODO: please remove)
|
||||
// https://preshing.com/20130930/double-checked-locking-is-fixed-in-cpp11/
|
||||
// https://preshing.com/20140709/the-purpose-of-memory_order_consume-in-cpp11/
|
||||
|
||||
constinit std::atomic<sdbus::internal::IConnection*> pseudoConnectionPtr;
|
||||
constinit std::mutex pseudoConnectionMutex;
|
||||
|
||||
std::unique_ptr<sdbus::internal::IConnection, void(*)(sdbus::internal::IConnection*)> createPseudoConnection()
|
||||
{
|
||||
auto deleter = [](sdbus::internal::IConnection* con)
|
||||
{
|
||||
delete con;
|
||||
pseudoConnectionPtr.store(nullptr, std::memory_order_release);
|
||||
};
|
||||
|
||||
auto pseudoConnection = internal::createPseudoConnection();
|
||||
pseudoConnectionPtr.store(pseudoConnection.get(), std::memory_order_release);
|
||||
return {pseudoConnection.release(), std::move(deleter)};
|
||||
}
|
||||
|
||||
sdbus::internal::IConnection& getPseudoConnectionInstance()
|
||||
{
|
||||
static auto pseudoConnection = createPseudoConnection();
|
||||
|
||||
if (pseudoConnectionPtr.load(std::memory_order_consume) == nullptr)
|
||||
{
|
||||
// The connection has been destroyed already (we are in exit handlers).
|
||||
// Double-checked locking pattern is used to re-create the connection in a thread-safe manner.
|
||||
std::lock_guard lock(pseudoConnectionMutex);
|
||||
if (pseudoConnectionPtr.load(std::memory_order_consume) == nullptr)
|
||||
{
|
||||
pseudoConnection = createPseudoConnection(); // Phoenix rising from the ashes
|
||||
atexit([]() { pseudoConnection.~unique_ptr(); }); // We have to manually take care of deleting the phoenix
|
||||
pseudoConnectionPtr.store(pseudoConnection.get(), std::memory_order_release);
|
||||
}
|
||||
}
|
||||
|
||||
assert(pseudoConnection != nullptr);
|
||||
|
||||
return *pseudoConnectionPtr.load(std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
PlainMessage createPlainMessage()
|
||||
{
|
||||
//static auto connection = internal::createConnection();
|
||||
// Let's create a pseudo connection -- one that does not really connect to the real bus.
|
||||
// This is a bit of a hack, but it enables use to work with D-Bus message locally without
|
||||
// the need of D-Bus daemon. This is especially useful in unit tests of both sdbus-c++ and client code.
|
||||
// Additionally, it's light-weight and fast solution.
|
||||
static auto connection = internal::createPseudoConnection();
|
||||
return connection->createPlainMessage();
|
||||
auto& connection = getPseudoConnectionInstance();
|
||||
return connection.createPlainMessage();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -66,6 +66,21 @@ Proxy::Proxy( std::unique_ptr<sdbus::internal::IConnection>&& connection
|
||||
connection_->enterEventLoopAsync();
|
||||
}
|
||||
|
||||
Proxy::Proxy( std::unique_ptr<sdbus::internal::IConnection>&& connection
|
||||
, std::string destination
|
||||
, std::string objectPath
|
||||
, dont_run_event_loop_thread_t )
|
||||
: connection_(std::move(connection))
|
||||
, destination_(std::move(destination))
|
||||
, objectPath_(std::move(objectPath))
|
||||
{
|
||||
SDBUS_CHECK_SERVICE_NAME(destination_);
|
||||
SDBUS_CHECK_OBJECT_PATH(objectPath_);
|
||||
|
||||
// Even though the connection is ours only, we don't start an event loop thread.
|
||||
// This proxy is meant to be created, used for simple synchronous D-Bus call(s) and then dismissed.
|
||||
}
|
||||
|
||||
MethodCall Proxy::createMethodCall(const std::string& interfaceName, const std::string& methodName)
|
||||
{
|
||||
return connection_->createMethodCall(destination_, objectPath_, interfaceName, methodName);
|
||||
@ -110,12 +125,34 @@ PendingAsyncCall Proxy::callMethod(const MethodCall& message, async_reply_handle
|
||||
|
||||
callData->slot = message.send(callback, callData.get(), timeout);
|
||||
|
||||
auto slotPtr = callData->slot.get();
|
||||
pendingAsyncCalls_.addCall(slotPtr, std::move(callData));
|
||||
pendingAsyncCalls_.addCall(std::move(callData));
|
||||
|
||||
return {weakData};
|
||||
}
|
||||
|
||||
std::future<MethodReply> Proxy::callMethod(const MethodCall& message, with_future_t)
|
||||
{
|
||||
return Proxy::callMethod(message, {}, with_future);
|
||||
}
|
||||
|
||||
std::future<MethodReply> Proxy::callMethod(const MethodCall& message, uint64_t timeout, with_future_t)
|
||||
{
|
||||
auto promise = std::make_shared<std::promise<MethodReply>>();
|
||||
auto future = promise->get_future();
|
||||
|
||||
async_reply_handler asyncReplyCallback = [promise = std::move(promise)](MethodReply& reply, const Error* error) noexcept
|
||||
{
|
||||
if (error == nullptr)
|
||||
promise->set_value(reply); // TODO: std::move? Can't move now because currently processed message. TODO: Refactor
|
||||
else
|
||||
promise->set_exception(std::make_exception_ptr(*error));
|
||||
};
|
||||
|
||||
(void)Proxy::callMethod(message, std::move(asyncReplyCallback), timeout);
|
||||
|
||||
return future;
|
||||
}
|
||||
|
||||
MethodReply Proxy::sendMethodCallMessageAndWaitForReply(const MethodCall& message, uint64_t timeout)
|
||||
{
|
||||
/*thread_local*/ SyncCallReplyData syncCallReplyData;
|
||||
@ -238,7 +275,6 @@ int Proxy::sdbus_async_reply_handler(sd_bus_message *sdbusMessage, void *userDat
|
||||
assert(asyncCallData != nullptr);
|
||||
assert(asyncCallData->callback);
|
||||
auto& proxy = asyncCallData->proxy;
|
||||
auto slot = asyncCallData->slot.get();
|
||||
|
||||
// We are removing the CallData item at the complete scope exit, after the callback has been invoked.
|
||||
// We can't do it earlier (before callback invocation for example), because CallBack data (slot release)
|
||||
@ -246,8 +282,7 @@ int Proxy::sdbus_async_reply_handler(sd_bus_message *sdbusMessage, void *userDat
|
||||
SCOPE_EXIT
|
||||
{
|
||||
// Remove call meta-data if it's a real async call (a sync call done in terms of async has slot == nullptr)
|
||||
if (slot)
|
||||
proxy.pendingAsyncCalls_.removeCall(slot);
|
||||
proxy.pendingAsyncCalls_.removeCall(asyncCallData);
|
||||
};
|
||||
|
||||
auto message = Message::Factory::create<MethodReply>(sdbusMessage, &proxy.connection_->getSdBusInterface());
|
||||
@ -319,7 +354,7 @@ void PendingAsyncCall::cancel()
|
||||
if (auto ptr = callData_.lock(); ptr != nullptr)
|
||||
{
|
||||
auto* callData = static_cast<internal::Proxy::AsyncCalls::CallData*>(ptr.get());
|
||||
callData->proxy.pendingAsyncCalls_.removeCall(callData->slot.get());
|
||||
callData->proxy.pendingAsyncCalls_.removeCall(callData);
|
||||
|
||||
// At this point, the callData item is being deleted, leading to the release of the
|
||||
// sd-bus slot pointer. This release locks the global sd-bus mutex. If the async
|
||||
@ -363,6 +398,22 @@ std::unique_ptr<sdbus::IProxy> createProxy( std::unique_ptr<IConnection>&& conne
|
||||
, std::move(objectPath) );
|
||||
}
|
||||
|
||||
std::unique_ptr<sdbus::IProxy> createProxy( std::unique_ptr<IConnection>&& connection
|
||||
, std::string destination
|
||||
, std::string objectPath
|
||||
, dont_run_event_loop_thread_t )
|
||||
{
|
||||
auto* sdbusConnection = dynamic_cast<sdbus::internal::IConnection*>(connection.get());
|
||||
SDBUS_THROW_ERROR_IF(!sdbusConnection, "Connection is not a real sdbus-c++ connection", EINVAL);
|
||||
|
||||
connection.release();
|
||||
|
||||
return std::make_unique<sdbus::internal::Proxy>( std::unique_ptr<sdbus::internal::IConnection>(sdbusConnection)
|
||||
, std::move(destination)
|
||||
, std::move(objectPath)
|
||||
, dont_run_event_loop_thread );
|
||||
}
|
||||
|
||||
std::unique_ptr<sdbus::IProxy> createProxy( std::string destination
|
||||
, std::string objectPath )
|
||||
{
|
||||
@ -376,4 +427,19 @@ std::unique_ptr<sdbus::IProxy> createProxy( std::string destination
|
||||
, std::move(objectPath) );
|
||||
}
|
||||
|
||||
std::unique_ptr<sdbus::IProxy> createProxy( std::string destination
|
||||
, std::string objectPath
|
||||
, dont_run_event_loop_thread_t )
|
||||
{
|
||||
auto connection = sdbus::createConnection();
|
||||
|
||||
auto sdbusConnection = std::unique_ptr<sdbus::internal::IConnection>(dynamic_cast<sdbus::internal::IConnection*>(connection.release()));
|
||||
assert(sdbusConnection != nullptr);
|
||||
|
||||
return std::make_unique<sdbus::internal::Proxy>( std::move(sdbusConnection)
|
||||
, std::move(destination)
|
||||
, std::move(objectPath)
|
||||
, dont_run_event_loop_thread );
|
||||
}
|
||||
|
||||
}
|
||||
|
23
src/Proxy.h
23
src/Proxy.h
@ -33,7 +33,7 @@
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
#include <deque>
|
||||
#include <mutex>
|
||||
#include <atomic>
|
||||
#include <condition_variable>
|
||||
@ -50,10 +50,16 @@ namespace sdbus::internal {
|
||||
Proxy( std::unique_ptr<sdbus::internal::IConnection>&& connection
|
||||
, std::string destination
|
||||
, std::string objectPath );
|
||||
Proxy( std::unique_ptr<sdbus::internal::IConnection>&& connection
|
||||
, std::string destination
|
||||
, std::string objectPath
|
||||
, dont_run_event_loop_thread_t );
|
||||
|
||||
MethodCall createMethodCall(const std::string& interfaceName, const std::string& methodName) override;
|
||||
MethodReply callMethod(const MethodCall& message, uint64_t timeout) override;
|
||||
PendingAsyncCall callMethod(const MethodCall& message, async_reply_handler asyncReplyCallback, uint64_t timeout) override;
|
||||
std::future<MethodReply> callMethod(const MethodCall& message, with_future_t) override;
|
||||
std::future<MethodReply> callMethod(const MethodCall& message, uint64_t timeout, with_future_t) override;
|
||||
|
||||
void registerSignalHandler( const std::string& interfaceName
|
||||
, const std::string& signalName
|
||||
@ -132,6 +138,7 @@ namespace sdbus::internal {
|
||||
Proxy& proxy;
|
||||
async_reply_handler callback;
|
||||
Slot slot;
|
||||
bool finished { false };
|
||||
};
|
||||
|
||||
~AsyncCalls()
|
||||
@ -139,18 +146,20 @@ namespace sdbus::internal {
|
||||
clear();
|
||||
}
|
||||
|
||||
bool addCall(void* slot, std::shared_ptr<CallData> asyncCallData)
|
||||
void addCall(std::shared_ptr<CallData> asyncCallData)
|
||||
{
|
||||
std::lock_guard lock(mutex_);
|
||||
return calls_.emplace(slot, std::move(asyncCallData)).second;
|
||||
if (!asyncCallData->finished) // The call may have finished in the mean time
|
||||
calls_.emplace_back(std::move(asyncCallData));
|
||||
}
|
||||
|
||||
void removeCall(void* slot)
|
||||
void removeCall(CallData* data)
|
||||
{
|
||||
std::unique_lock lock(mutex_);
|
||||
if (auto it = calls_.find(slot); it != calls_.end())
|
||||
data->finished = true;
|
||||
if (auto it = std::find_if(calls_.begin(), calls_.end(), [data](auto const& entry){ return entry.get() == data; }); it != calls_.end())
|
||||
{
|
||||
auto callData = std::move(it->second);
|
||||
auto callData = std::move(*it);
|
||||
calls_.erase(it);
|
||||
lock.unlock();
|
||||
|
||||
@ -176,7 +185,7 @@ namespace sdbus::internal {
|
||||
|
||||
private:
|
||||
std::mutex mutex_;
|
||||
std::unordered_map<void*, std::shared_ptr<CallData>> calls_;
|
||||
std::deque<std::shared_ptr<CallData>> calls_;
|
||||
} pendingAsyncCalls_;
|
||||
|
||||
std::atomic<const Message*> m_CurrentlyProcessedMessage{nullptr};
|
||||
|
@ -55,18 +55,17 @@
|
||||
// return; // exiting scope normally
|
||||
// }
|
||||
|
||||
#define SCOPE_EXIT \
|
||||
auto ANONYMOUS_VARIABLE(SCOPE_EXIT_STATE) \
|
||||
= ::skybase::utils::detail::ScopeGuardOnExit() + [&]() \
|
||||
#define SCOPE_EXIT \
|
||||
auto ANONYMOUS_VARIABLE(SCOPE_EXIT_STATE) \
|
||||
= ::sdbus::internal::detail::ScopeGuardOnExit() + [&]() \
|
||||
/**/
|
||||
|
||||
#define SCOPE_EXIT_NAMED(NAME) \
|
||||
auto NAME \
|
||||
= ::skybase::utils::detail::ScopeGuardOnExit() + [&]() \
|
||||
#define SCOPE_EXIT_NAMED(NAME) \
|
||||
auto NAME \
|
||||
= ::sdbus::internal::detail::ScopeGuardOnExit() + [&]() \
|
||||
/**/
|
||||
|
||||
namespace skybase {
|
||||
namespace utils {
|
||||
namespace sdbus::internal {
|
||||
|
||||
template <class _Fun>
|
||||
class ScopeGuard
|
||||
@ -114,7 +113,7 @@ namespace utils {
|
||||
}
|
||||
}
|
||||
|
||||
}}
|
||||
}
|
||||
|
||||
#define CONCATENATE_IMPL(s1, s2) s1##s2
|
||||
#define CONCATENATE(s1, s2) CONCATENATE_IMPL(s1, s2)
|
||||
|
@ -48,7 +48,14 @@ int SdBus::sd_bus_send(sd_bus *bus, sd_bus_message *m, uint64_t *cookie)
|
||||
{
|
||||
std::lock_guard lock(sdbusMutex_);
|
||||
|
||||
return ::sd_bus_send(bus, m, cookie);
|
||||
auto r = ::sd_bus_send(bus, m, cookie);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
// Make sure long messages are not only stored in outgoing queues but also really sent out
|
||||
::sd_bus_flush(bus != nullptr ? bus : ::sd_bus_message_get_bus(m));
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int SdBus::sd_bus_call(sd_bus *bus, sd_bus_message *m, uint64_t usec, sd_bus_error *ret_error, sd_bus_message **reply)
|
||||
@ -62,7 +69,14 @@ int SdBus::sd_bus_call_async(sd_bus *bus, sd_bus_slot **slot, sd_bus_message *m,
|
||||
{
|
||||
std::lock_guard lock(sdbusMutex_);
|
||||
|
||||
return ::sd_bus_call_async(bus, slot, m, callback, userdata, usec);
|
||||
auto r = ::sd_bus_call_async(bus, slot, m, callback, userdata, usec);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
// Make sure long messages are not only stored in outgoing queues but also really sent out
|
||||
::sd_bus_flush(bus != nullptr ? bus : ::sd_bus_message_get_bus(m));
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int SdBus::sd_bus_message_new(sd_bus *bus, sd_bus_message **m, uint8_t type)
|
||||
|
@ -161,6 +161,24 @@ TEST_F(SdbusTestObject, InvokesMethodAsynchronouslyOnClientSide)
|
||||
ASSERT_THAT(future.get(), Eq(100));
|
||||
}
|
||||
|
||||
TEST_F(SdbusTestObject, InvokesMethodAsynchronouslyOnClientSideWithFuture)
|
||||
{
|
||||
auto future = m_proxy->doOperationClientSideAsync(100, sdbus::with_future);
|
||||
|
||||
ASSERT_THAT(future.get(), Eq(100));
|
||||
}
|
||||
|
||||
TEST_F(SdbusTestObject, InvokesMethodAsynchronouslyOnClientSideWithFutureOnBasicAPILevel)
|
||||
{
|
||||
auto future = m_proxy->doOperationClientSideAsyncOnBasicAPILevel(100);
|
||||
|
||||
auto methodReply = future.get();
|
||||
uint32_t returnValue{};
|
||||
methodReply >> returnValue;
|
||||
|
||||
ASSERT_THAT(returnValue, Eq(100));
|
||||
}
|
||||
|
||||
TEST_F(SdbusTestObject, AnswersThatAsyncCallIsPendingIfItIsInProgress)
|
||||
{
|
||||
m_proxy->installDoOperationClientSideAsyncReplyHandler([&](uint32_t /*res*/, const sdbus::Error* /*err*/){});
|
||||
@ -222,7 +240,7 @@ TEST_F(SdbusTestObject, SupportsAsyncCallCopyAssignment)
|
||||
ASSERT_TRUE(call.isPending());
|
||||
}
|
||||
|
||||
TEST_F(SdbusTestObject, InvokesErroneousMethodAsynchronouslyOnClientSide)
|
||||
TEST_F(SdbusTestObject, ReturnsNonnullErrorWhenAsynchronousMethodCallFails)
|
||||
{
|
||||
std::promise<uint32_t> promise;
|
||||
auto future = promise.get_future();
|
||||
@ -238,3 +256,10 @@ TEST_F(SdbusTestObject, InvokesErroneousMethodAsynchronouslyOnClientSide)
|
||||
|
||||
ASSERT_THROW(future.get(), sdbus::Error);
|
||||
}
|
||||
|
||||
TEST_F(SdbusTestObject, ThrowsErrorWhenClientSideAsynchronousMethodCallWithFutureFails)
|
||||
{
|
||||
auto future = m_proxy->doErroneousOperationClientSideAsync(sdbus::with_future);
|
||||
|
||||
ASSERT_THROW(future.get(), sdbus::Error);
|
||||
}
|
||||
|
@ -38,6 +38,7 @@
|
||||
#include <fstream>
|
||||
#include <future>
|
||||
#include <unistd.h>
|
||||
#include <variant>
|
||||
|
||||
using ::testing::ElementsAre;
|
||||
using ::testing::Eq;
|
||||
@ -59,6 +60,18 @@ TEST(AdaptorAndProxy, CanBeConstructedSuccesfully)
|
||||
ASSERT_NO_THROW(TestProxy proxy(BUS_NAME, OBJECT_PATH));
|
||||
}
|
||||
|
||||
TEST(AProxy, SupportsMoveSemantics)
|
||||
{
|
||||
static_assert(std::is_move_constructible_v<DummyTestProxy>);
|
||||
static_assert(std::is_move_assignable_v<DummyTestProxy>);
|
||||
}
|
||||
|
||||
TEST(AnAdaptor, SupportsMoveSemantics)
|
||||
{
|
||||
static_assert(std::is_move_constructible_v<DummyTestAdaptor>);
|
||||
static_assert(std::is_move_assignable_v<DummyTestAdaptor>);
|
||||
}
|
||||
|
||||
TEST_F(AConnection, WillCallCallbackHandlerForIncomingMessageMatchingMatchRule)
|
||||
{
|
||||
auto matchRule = "sender='" + BUS_NAME + "',path='" + OBJECT_PATH + "'";
|
||||
@ -103,7 +116,8 @@ TEST_F(AConnection, CanAddFloatingMatchRule)
|
||||
};
|
||||
con->addMatch(matchRule, std::move(callback), sdbus::floating_slot);
|
||||
m_adaptor->emitSimpleSignal();
|
||||
assert(waitUntil(matchingMessageReceived, 2s));
|
||||
[[maybe_unused]] auto gotMessage = waitUntil(matchingMessageReceived, 2s);
|
||||
assert(gotMessage);
|
||||
matchingMessageReceived = false;
|
||||
|
||||
con.reset();
|
||||
|
@ -272,3 +272,12 @@ TEST_F(SdbusTestObject, CannotSetGeneralMethodTimeoutWithLibsystemdVersionLessTh
|
||||
ASSERT_THROW(s_adaptorConnection->getMethodCallTimeout(), sdbus::Error);
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST_F(SdbusTestObject, CanCallMethodSynchronouslyWithoutAnEventLoopThread)
|
||||
{
|
||||
auto proxy = std::make_unique<TestProxy>(BUS_NAME, OBJECT_PATH, sdbus::dont_run_event_loop_thread);
|
||||
|
||||
auto multiplyRes = proxy->multiply(INT64_VALUE, DOUBLE_VALUE);
|
||||
|
||||
ASSERT_THAT(multiplyRes, Eq(INT64_VALUE * DOUBLE_VALUE));
|
||||
}
|
||||
|
@ -89,6 +89,18 @@ TEST_F(SdbusTestObject, EmitsSignalWithMapSuccesfully)
|
||||
ASSERT_THAT(m_proxy->m_mapFromSignal[1], Eq("one"));
|
||||
}
|
||||
|
||||
TEST_F(SdbusTestObject, EmitsSignalWithLargeMapSuccesfully)
|
||||
{
|
||||
std::map<int32_t, std::string> largeMap;
|
||||
for (int32_t i = 0; i < 20'000; ++i)
|
||||
largeMap.emplace(i, "This is string nr. " + std::to_string(i+1));
|
||||
m_adaptor->emitSignalWithMap(largeMap);
|
||||
|
||||
ASSERT_TRUE(waitUntil(m_proxy->m_gotSignalWithMap));
|
||||
ASSERT_THAT(m_proxy->m_mapFromSignal[0], Eq("This is string nr. 1"));
|
||||
ASSERT_THAT(m_proxy->m_mapFromSignal[1], Eq("This is string nr. 2"));
|
||||
}
|
||||
|
||||
TEST_F(SdbusTestObject, EmitsSignalWithVariantSuccesfully)
|
||||
{
|
||||
double d = 3.14;
|
||||
|
@ -201,7 +201,13 @@ TEST_F(SdbusTestObject, EmitsInterfacesAddedSignalForAllObjectInterfaces)
|
||||
, const std::map<std::string, std::map<std::string, sdbus::Variant>>& interfacesAndProperties )
|
||||
{
|
||||
EXPECT_THAT(objectPath, Eq(OBJECT_PATH));
|
||||
#if LIBSYSTEMD_VERSION<=250
|
||||
EXPECT_THAT(interfacesAndProperties, SizeIs(5)); // INTERFACE_NAME + 4 standard interfaces
|
||||
#else
|
||||
// Since systemd v251, ObjectManager standard interface is not listed among the interfaces
|
||||
// if the object does not have object manager functionality explicitly enabled.
|
||||
EXPECT_THAT(interfacesAndProperties, SizeIs(4)); // INTERFACE_NAME + 3 standard interfaces
|
||||
#endif
|
||||
#if LIBSYSTEMD_VERSION<=244
|
||||
// Up to sd-bus v244, all properties are added to the list, i.e. `state', `action', and `blocking' in this case.
|
||||
EXPECT_THAT(interfacesAndProperties.at(INTERFACE_NAME), SizeIs(3));
|
||||
@ -248,7 +254,13 @@ TEST_F(SdbusTestObject, EmitsInterfacesRemovedSignalForAllObjectInterfaces)
|
||||
, const std::vector<std::string>& interfaces )
|
||||
{
|
||||
EXPECT_THAT(objectPath, Eq(OBJECT_PATH));
|
||||
#if LIBSYSTEMD_VERSION<=250
|
||||
ASSERT_THAT(interfaces, SizeIs(5)); // INTERFACE_NAME + 4 standard interfaces
|
||||
#else
|
||||
// Since systemd v251, ObjectManager standard interface is not listed among the interfaces
|
||||
// if the object does not have object manager functionality explicitly enabled.
|
||||
ASSERT_THAT(interfaces, SizeIs(4)); // INTERFACE_NAME + 3 standard interfaces
|
||||
#endif
|
||||
signalReceived = true;
|
||||
};
|
||||
|
||||
|
@ -109,6 +109,43 @@ public: // for tests
|
||||
std::string m_propertySetSender;
|
||||
};
|
||||
|
||||
class DummyTestAdaptor final : public sdbus::AdaptorInterfaces< org::sdbuscpp::integrationtests_adaptor
|
||||
, sdbus::Properties_adaptor
|
||||
, sdbus::ManagedObject_adaptor >
|
||||
{
|
||||
public:
|
||||
DummyTestAdaptor(sdbus::IConnection& connection, const std::string& path) : AdaptorInterfaces(connection, path) {}
|
||||
|
||||
protected:
|
||||
void noArgNoReturn() override {}
|
||||
int32_t getInt() override { return {}; }
|
||||
std::tuple<uint32_t, std::string> getTuple() override { return {}; }
|
||||
double multiply(const int64_t&, const double&) override { return {}; }
|
||||
void multiplyWithNoReply(const int64_t&, const double&) override {}
|
||||
std::vector<int16_t> getInts16FromStruct(const sdbus::Struct<uint8_t, int16_t, double, std::string, std::vector<int16_t>>&) override { return {}; }
|
||||
sdbus::Variant processVariant(const sdbus::Variant&) override { return {}; }
|
||||
std::map<int32_t, sdbus::Variant> getMapOfVariants(const std::vector<int32_t>&, const sdbus::Struct<sdbus::Variant, sdbus::Variant>&) override { return {}; }
|
||||
sdbus::Struct<std::string, sdbus::Struct<std::map<int32_t, int32_t>>> getStructInStruct() override { return {}; }
|
||||
int32_t sumStructItems(const sdbus::Struct<uint8_t, uint16_t>&, const sdbus::Struct<int32_t, int64_t>&) override { return {}; }
|
||||
uint32_t sumVectorItems(const std::vector<uint16_t>&, const std::vector<uint64_t>&) override { return {}; }
|
||||
uint32_t doOperation(const uint32_t&) override { return {}; }
|
||||
void doOperationAsync(sdbus::Result<uint32_t>&&, uint32_t) override {}
|
||||
sdbus::Signature getSignature() override { return {}; }
|
||||
sdbus::ObjectPath getObjPath() override { return {}; }
|
||||
sdbus::UnixFd getUnixFd() override { return {}; }
|
||||
std::map<uint64_t, sdbus::Struct<std::map<uint8_t, std::vector<sdbus::Struct<sdbus::ObjectPath, bool, sdbus::Variant, std::map<int32_t, std::string>>>>, sdbus::Signature, std::string>> getComplex() override { return {}; }
|
||||
void throwError() override {}
|
||||
void throwErrorWithNoReply() override {}
|
||||
void doPrivilegedStuff() override {}
|
||||
void emitTwoSimpleSignals() override {}
|
||||
|
||||
uint32_t action() override { return {}; }
|
||||
void action(const uint32_t&) override {}
|
||||
bool blocking() override { return {}; }
|
||||
void blocking(const bool&) override {}
|
||||
std::string state() override { return {}; }
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif /* INTEGRATIONTESTS_TESTADAPTOR_H_ */
|
||||
|
@ -39,6 +39,13 @@ TestProxy::TestProxy(std::string destination, std::string objectPath)
|
||||
registerProxy();
|
||||
}
|
||||
|
||||
TestProxy::TestProxy(std::string destination, std::string objectPath, dont_run_event_loop_thread_t)
|
||||
: ProxyInterfaces(std::move(destination), std::move(objectPath), dont_run_event_loop_thread)
|
||||
{
|
||||
// It doesn't make sense to register any signals here since proxy upon a D-Bus connection with no event loop thread
|
||||
// will not receive any incoming messages except replies to synchronous D-Bus calls.
|
||||
}
|
||||
|
||||
TestProxy::TestProxy(sdbus::IConnection& connection, std::string destination, std::string objectPath)
|
||||
: ProxyInterfaces(connection, std::move(destination), std::move(objectPath))
|
||||
{
|
||||
@ -116,6 +123,22 @@ sdbus::PendingAsyncCall TestProxy::doOperationClientSideAsync(uint32_t param)
|
||||
});
|
||||
}
|
||||
|
||||
std::future<uint32_t> TestProxy::doOperationClientSideAsync(uint32_t param, with_future_t)
|
||||
{
|
||||
return getProxy().callMethodAsync("doOperation")
|
||||
.onInterface(sdbus::test::INTERFACE_NAME)
|
||||
.withArguments(param)
|
||||
.getResultAsFuture<uint32_t>();
|
||||
}
|
||||
|
||||
std::future<MethodReply> TestProxy::doOperationClientSideAsyncOnBasicAPILevel(uint32_t param)
|
||||
{
|
||||
auto methodCall = getProxy().createMethodCall(sdbus::test::INTERFACE_NAME, "doOperation");
|
||||
methodCall << param;
|
||||
|
||||
return getProxy().callMethod(methodCall, sdbus::with_future);
|
||||
}
|
||||
|
||||
void TestProxy::doErroneousOperationClientSideAsync()
|
||||
{
|
||||
getProxy().callMethodAsync("throwError")
|
||||
@ -126,6 +149,13 @@ void TestProxy::doErroneousOperationClientSideAsync()
|
||||
});
|
||||
}
|
||||
|
||||
std::future<void> TestProxy::doErroneousOperationClientSideAsync(with_future_t)
|
||||
{
|
||||
return getProxy().callMethodAsync("throwError")
|
||||
.onInterface(sdbus::test::INTERFACE_NAME)
|
||||
.getResultAsFuture<>();;
|
||||
}
|
||||
|
||||
void TestProxy::doOperationClientSideAsyncWithTimeout(const std::chrono::microseconds &timeout, uint32_t param)
|
||||
{
|
||||
using namespace std::chrono_literals;
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
#include <atomic>
|
||||
#include <future>
|
||||
|
||||
namespace sdbus { namespace test {
|
||||
|
||||
@ -73,6 +74,7 @@ class TestProxy final : public sdbus::ProxyInterfaces< org::sdbuscpp::integratio
|
||||
{
|
||||
public:
|
||||
TestProxy(std::string destination, std::string objectPath);
|
||||
TestProxy(std::string destination, std::string objectPath, dont_run_event_loop_thread_t);
|
||||
TestProxy(sdbus::IConnection& connection, std::string destination, std::string objectPath);
|
||||
~TestProxy();
|
||||
|
||||
@ -93,6 +95,9 @@ public:
|
||||
void installDoOperationClientSideAsyncReplyHandler(std::function<void(uint32_t res, const sdbus::Error* err)> handler);
|
||||
uint32_t doOperationWithTimeout(const std::chrono::microseconds &timeout, uint32_t param);
|
||||
sdbus::PendingAsyncCall doOperationClientSideAsync(uint32_t param);
|
||||
std::future<uint32_t> doOperationClientSideAsync(uint32_t param, with_future_t);
|
||||
std::future<MethodReply> doOperationClientSideAsyncOnBasicAPILevel(uint32_t param);
|
||||
std::future<void> doErroneousOperationClientSideAsync(with_future_t);
|
||||
void doErroneousOperationClientSideAsync();
|
||||
void doOperationClientSideAsyncWithTimeout(const std::chrono::microseconds &timeout, uint32_t param);
|
||||
int32_t callNonexistentMethod();
|
||||
@ -117,6 +122,29 @@ public: // for tests
|
||||
std::string m_signalMemberName;
|
||||
};
|
||||
|
||||
class DummyTestProxy final : public sdbus::ProxyInterfaces< org::sdbuscpp::integrationtests_proxy
|
||||
, sdbus::Peer_proxy
|
||||
, sdbus::Introspectable_proxy
|
||||
, sdbus::Properties_proxy >
|
||||
{
|
||||
public:
|
||||
DummyTestProxy(std::string destination, std::string objectPath)
|
||||
: ProxyInterfaces(destination, objectPath)
|
||||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
void onSimpleSignal() override {}
|
||||
void onSignalWithMap(const std::map<int32_t, std::string>&) override {}
|
||||
void onSignalWithVariant(const sdbus::Variant&) override {}
|
||||
|
||||
void onSignalWithoutRegistration(const sdbus::Struct<std::string, sdbus::Struct<sdbus::Signature>>&) {}
|
||||
void onDoOperationReply(uint32_t, const sdbus::Error*) {}
|
||||
|
||||
// Signals of standard D-Bus interfaces
|
||||
void onPropertiesChanged( const std::string&, const std::map<std::string, sdbus::Variant>&, const std::vector<std::string>& ) override {}
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif /* SDBUS_CPP_INTEGRATIONTESTS_TESTPROXY_H_ */
|
||||
|
@ -20,54 +20,59 @@ public:
|
||||
|
||||
protected:
|
||||
integrationtests_adaptor(sdbus::IObject& object)
|
||||
: object_(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).withOutputParamNames("anInt").implementedAs([this](){ return this->getInt(); });
|
||||
object_.registerMethod("getTuple").onInterface(INTERFACE_NAME).withOutputParamNames("arg0", "arg1").implementedAs([this](){ return this->getTuple(); });
|
||||
object_.registerMethod("multiply").onInterface(INTERFACE_NAME).withInputParamNames("a", "b").withOutputParamNames("result").implementedAs([this](const int64_t& a, const double& b){ return this->multiply(a, b); });
|
||||
object_.registerMethod("multiplyWithNoReply").onInterface(INTERFACE_NAME).withInputParamNames("a", "b").implementedAs([this](const int64_t& a, const double& b){ return this->multiplyWithNoReply(a, b); }).markAsDeprecated().withNoReply();
|
||||
object_.registerMethod("getInts16FromStruct").onInterface(INTERFACE_NAME).withInputParamNames("arg0").withOutputParamNames("arg0").implementedAs([this](const sdbus::Struct<uint8_t, int16_t, double, std::string, std::vector<int16_t>>& arg0){ return this->getInts16FromStruct(arg0); });
|
||||
object_.registerMethod("processVariant").onInterface(INTERFACE_NAME).withInputParamNames("variant").withOutputParamNames("result").implementedAs([this](const sdbus::Variant& variant){ return this->processVariant(variant); });
|
||||
object_.registerMethod("getMapOfVariants").onInterface(INTERFACE_NAME).withInputParamNames("x", "y").withOutputParamNames("aMapOfVariants").implementedAs([this](const std::vector<int32_t>& x, const sdbus::Struct<sdbus::Variant, sdbus::Variant>& y){ return this->getMapOfVariants(x, y); });
|
||||
object_.registerMethod("getStructInStruct").onInterface(INTERFACE_NAME).withOutputParamNames("aMapOfVariants").implementedAs([this](){ return this->getStructInStruct(); });
|
||||
object_.registerMethod("sumStructItems").onInterface(INTERFACE_NAME).withInputParamNames("arg0", "arg1").withOutputParamNames("arg0").implementedAs([this](const sdbus::Struct<uint8_t, uint16_t>& arg0, const sdbus::Struct<int32_t, int64_t>& arg1){ return this->sumStructItems(arg0, arg1); });
|
||||
object_.registerMethod("sumVectorItems").onInterface(INTERFACE_NAME).withInputParamNames("arg0", "arg1").withOutputParamNames("arg0").implementedAs([this](const std::vector<uint16_t>& arg0, const std::vector<uint64_t>& arg1){ return this->sumVectorItems(arg0, arg1); });
|
||||
object_.registerMethod("doOperation").onInterface(INTERFACE_NAME).withInputParamNames("arg0").withOutputParamNames("arg0").implementedAs([this](const uint32_t& arg0){ return this->doOperation(arg0); });
|
||||
object_.registerMethod("doOperationAsync").onInterface(INTERFACE_NAME).withInputParamNames("arg0").withOutputParamNames("arg0").implementedAs([this](sdbus::Result<uint32_t>&& result, uint32_t arg0){ this->doOperationAsync(std::move(result), std::move(arg0)); });
|
||||
object_.registerMethod("getSignature").onInterface(INTERFACE_NAME).withOutputParamNames("arg0").implementedAs([this](){ return this->getSignature(); });
|
||||
object_.registerMethod("getObjPath").onInterface(INTERFACE_NAME).withOutputParamNames("arg0").implementedAs([this](){ return this->getObjPath(); });
|
||||
object_.registerMethod("getUnixFd").onInterface(INTERFACE_NAME).withOutputParamNames("arg0").implementedAs([this](){ return this->getUnixFd(); });
|
||||
object_.registerMethod("getComplex").onInterface(INTERFACE_NAME).withOutputParamNames("arg0").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](){ return this->throwErrorWithNoReply(); }).withNoReply();
|
||||
object_.registerMethod("doPrivilegedStuff").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->doPrivilegedStuff(); }).markAsPrivileged();
|
||||
object_.registerMethod("emitTwoSimpleSignals").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->emitTwoSimpleSignals(); });
|
||||
object_.registerSignal("simpleSignal").onInterface(INTERFACE_NAME).markAsDeprecated();
|
||||
object_.registerSignal("signalWithMap").onInterface(INTERFACE_NAME).withParameters<std::map<int32_t, std::string>>("aMap");
|
||||
object_.registerSignal("signalWithVariant").onInterface(INTERFACE_NAME).withParameters<sdbus::Variant>("aVariant");
|
||||
object_.registerProperty("action").onInterface(INTERFACE_NAME).withGetter([this](){ return this->action(); }).withSetter([this](const uint32_t& value){ this->action(value); }).withUpdateBehavior(sdbus::Flags::EMITS_INVALIDATION_SIGNAL);
|
||||
object_.registerProperty("blocking").onInterface(INTERFACE_NAME).withGetter([this](){ return this->blocking(); }).withSetter([this](const bool& value){ this->blocking(value); });
|
||||
object_.registerProperty("state").onInterface(INTERFACE_NAME).withGetter([this](){ return this->state(); }).markAsDeprecated().withUpdateBehavior(sdbus::Flags::CONST_PROPERTY_VALUE);
|
||||
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).withOutputParamNames("anInt").implementedAs([this](){ return this->getInt(); });
|
||||
object_->registerMethod("getTuple").onInterface(INTERFACE_NAME).withOutputParamNames("arg0", "arg1").implementedAs([this](){ return this->getTuple(); });
|
||||
object_->registerMethod("multiply").onInterface(INTERFACE_NAME).withInputParamNames("a", "b").withOutputParamNames("result").implementedAs([this](const int64_t& a, const double& b){ return this->multiply(a, b); });
|
||||
object_->registerMethod("multiplyWithNoReply").onInterface(INTERFACE_NAME).withInputParamNames("a", "b").implementedAs([this](const int64_t& a, const double& b){ return this->multiplyWithNoReply(a, b); }).markAsDeprecated().withNoReply();
|
||||
object_->registerMethod("getInts16FromStruct").onInterface(INTERFACE_NAME).withInputParamNames("arg0").withOutputParamNames("arg0").implementedAs([this](const sdbus::Struct<uint8_t, int16_t, double, std::string, std::vector<int16_t>>& arg0){ return this->getInts16FromStruct(arg0); });
|
||||
object_->registerMethod("processVariant").onInterface(INTERFACE_NAME).withInputParamNames("variant").withOutputParamNames("result").implementedAs([this](const sdbus::Variant& variant){ return this->processVariant(variant); });
|
||||
object_->registerMethod("getMapOfVariants").onInterface(INTERFACE_NAME).withInputParamNames("x", "y").withOutputParamNames("aMapOfVariants").implementedAs([this](const std::vector<int32_t>& x, const sdbus::Struct<sdbus::Variant, sdbus::Variant>& y){ return this->getMapOfVariants(x, y); });
|
||||
object_->registerMethod("getStructInStruct").onInterface(INTERFACE_NAME).withOutputParamNames("aMapOfVariants").implementedAs([this](){ return this->getStructInStruct(); });
|
||||
object_->registerMethod("sumStructItems").onInterface(INTERFACE_NAME).withInputParamNames("arg0", "arg1").withOutputParamNames("arg0").implementedAs([this](const sdbus::Struct<uint8_t, uint16_t>& arg0, const sdbus::Struct<int32_t, int64_t>& arg1){ return this->sumStructItems(arg0, arg1); });
|
||||
object_->registerMethod("sumVectorItems").onInterface(INTERFACE_NAME).withInputParamNames("arg0", "arg1").withOutputParamNames("arg0").implementedAs([this](const std::vector<uint16_t>& arg0, const std::vector<uint64_t>& arg1){ return this->sumVectorItems(arg0, arg1); });
|
||||
object_->registerMethod("doOperation").onInterface(INTERFACE_NAME).withInputParamNames("arg0").withOutputParamNames("arg0").implementedAs([this](const uint32_t& arg0){ return this->doOperation(arg0); });
|
||||
object_->registerMethod("doOperationAsync").onInterface(INTERFACE_NAME).withInputParamNames("arg0").withOutputParamNames("arg0").implementedAs([this](sdbus::Result<uint32_t>&& result, uint32_t arg0){ this->doOperationAsync(std::move(result), std::move(arg0)); });
|
||||
object_->registerMethod("getSignature").onInterface(INTERFACE_NAME).withOutputParamNames("arg0").implementedAs([this](){ return this->getSignature(); });
|
||||
object_->registerMethod("getObjPath").onInterface(INTERFACE_NAME).withOutputParamNames("arg0").implementedAs([this](){ return this->getObjPath(); });
|
||||
object_->registerMethod("getUnixFd").onInterface(INTERFACE_NAME).withOutputParamNames("arg0").implementedAs([this](){ return this->getUnixFd(); });
|
||||
object_->registerMethod("getComplex").onInterface(INTERFACE_NAME).withOutputParamNames("arg0").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](){ return this->throwErrorWithNoReply(); }).withNoReply();
|
||||
object_->registerMethod("doPrivilegedStuff").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->doPrivilegedStuff(); }).markAsPrivileged();
|
||||
object_->registerMethod("emitTwoSimpleSignals").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->emitTwoSimpleSignals(); });
|
||||
object_->registerSignal("simpleSignal").onInterface(INTERFACE_NAME).markAsDeprecated();
|
||||
object_->registerSignal("signalWithMap").onInterface(INTERFACE_NAME).withParameters<std::map<int32_t, std::string>>("aMap");
|
||||
object_->registerSignal("signalWithVariant").onInterface(INTERFACE_NAME).withParameters<sdbus::Variant>("aVariant");
|
||||
object_->registerProperty("action").onInterface(INTERFACE_NAME).withGetter([this](){ return this->action(); }).withSetter([this](const uint32_t& value){ this->action(value); }).withUpdateBehavior(sdbus::Flags::EMITS_INVALIDATION_SIGNAL);
|
||||
object_->registerProperty("blocking").onInterface(INTERFACE_NAME).withGetter([this](){ return this->blocking(); }).withSetter([this](const bool& value){ this->blocking(value); });
|
||||
object_->registerProperty("state").onInterface(INTERFACE_NAME).withGetter([this](){ return this->state(); }).markAsDeprecated().withUpdateBehavior(sdbus::Flags::CONST_PROPERTY_VALUE);
|
||||
}
|
||||
|
||||
integrationtests_adaptor(const integrationtests_adaptor&) = delete;
|
||||
integrationtests_adaptor& operator=(const integrationtests_adaptor&) = delete;
|
||||
integrationtests_adaptor(integrationtests_adaptor&&) = default;
|
||||
integrationtests_adaptor& operator=(integrationtests_adaptor&&) = default;
|
||||
|
||||
~integrationtests_adaptor() = default;
|
||||
|
||||
public:
|
||||
void emitSimpleSignal()
|
||||
{
|
||||
object_.emitSignal("simpleSignal").onInterface(INTERFACE_NAME);
|
||||
object_->emitSignal("simpleSignal").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
void emitSignalWithMap(const std::map<int32_t, std::string>& aMap)
|
||||
{
|
||||
object_.emitSignal("signalWithMap").onInterface(INTERFACE_NAME).withArguments(aMap);
|
||||
object_->emitSignal("signalWithMap").onInterface(INTERFACE_NAME).withArguments(aMap);
|
||||
}
|
||||
|
||||
void emitSignalWithVariant(const sdbus::Variant& aVariant)
|
||||
{
|
||||
object_.emitSignal("signalWithVariant").onInterface(INTERFACE_NAME).withArguments(aVariant);
|
||||
object_->emitSignal("signalWithVariant").onInterface(INTERFACE_NAME).withArguments(aVariant);
|
||||
}
|
||||
|
||||
private:
|
||||
@ -101,7 +106,7 @@ private:
|
||||
virtual std::string state() = 0;
|
||||
|
||||
private:
|
||||
sdbus::IObject& object_;
|
||||
sdbus::IObject* object_;
|
||||
};
|
||||
|
||||
}} // namespaces
|
||||
|
@ -20,13 +20,18 @@ public:
|
||||
|
||||
protected:
|
||||
integrationtests_proxy(sdbus::IProxy& proxy)
|
||||
: proxy_(proxy)
|
||||
: proxy_(&proxy)
|
||||
{
|
||||
proxy_.uponSignal("simpleSignal").onInterface(INTERFACE_NAME).call([this](){ this->onSimpleSignal(); });
|
||||
proxy_.uponSignal("signalWithMap").onInterface(INTERFACE_NAME).call([this](const std::map<int32_t, std::string>& aMap){ this->onSignalWithMap(aMap); });
|
||||
proxy_.uponSignal("signalWithVariant").onInterface(INTERFACE_NAME).call([this](const sdbus::Variant& aVariant){ this->onSignalWithVariant(aVariant); });
|
||||
proxy_->uponSignal("simpleSignal").onInterface(INTERFACE_NAME).call([this](){ this->onSimpleSignal(); });
|
||||
proxy_->uponSignal("signalWithMap").onInterface(INTERFACE_NAME).call([this](const std::map<int32_t, std::string>& aMap){ this->onSignalWithMap(aMap); });
|
||||
proxy_->uponSignal("signalWithVariant").onInterface(INTERFACE_NAME).call([this](const sdbus::Variant& aVariant){ this->onSignalWithVariant(aVariant); });
|
||||
}
|
||||
|
||||
integrationtests_proxy(const integrationtests_proxy&) = delete;
|
||||
integrationtests_proxy& operator=(const integrationtests_proxy&) = delete;
|
||||
integrationtests_proxy(integrationtests_proxy&&) = default;
|
||||
integrationtests_proxy& operator=(integrationtests_proxy&&) = default;
|
||||
|
||||
~integrationtests_proxy() = default;
|
||||
|
||||
virtual void onSimpleSignal() = 0;
|
||||
@ -36,178 +41,178 @@ protected:
|
||||
public:
|
||||
void noArgNoReturn()
|
||||
{
|
||||
proxy_.callMethod("noArgNoReturn").onInterface(INTERFACE_NAME);
|
||||
proxy_->callMethod("noArgNoReturn").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
int32_t getInt()
|
||||
{
|
||||
int32_t result;
|
||||
proxy_.callMethod("getInt").onInterface(INTERFACE_NAME).storeResultsTo(result);
|
||||
proxy_->callMethod("getInt").onInterface(INTERFACE_NAME).storeResultsTo(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::tuple<uint32_t, std::string> getTuple()
|
||||
{
|
||||
std::tuple<uint32_t, std::string> result;
|
||||
proxy_.callMethod("getTuple").onInterface(INTERFACE_NAME).storeResultsTo(result);
|
||||
proxy_->callMethod("getTuple").onInterface(INTERFACE_NAME).storeResultsTo(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
double multiply(const int64_t& a, const double& b)
|
||||
{
|
||||
double result;
|
||||
proxy_.callMethod("multiply").onInterface(INTERFACE_NAME).withArguments(a, b).storeResultsTo(result);
|
||||
proxy_->callMethod("multiply").onInterface(INTERFACE_NAME).withArguments(a, b).storeResultsTo(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
void multiplyWithNoReply(const int64_t& a, const double& b)
|
||||
{
|
||||
proxy_.callMethod("multiplyWithNoReply").onInterface(INTERFACE_NAME).withArguments(a, b).dontExpectReply();
|
||||
proxy_->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>>& arg0)
|
||||
{
|
||||
std::vector<int16_t> result;
|
||||
proxy_.callMethod("getInts16FromStruct").onInterface(INTERFACE_NAME).withArguments(arg0).storeResultsTo(result);
|
||||
proxy_->callMethod("getInts16FromStruct").onInterface(INTERFACE_NAME).withArguments(arg0).storeResultsTo(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
sdbus::Variant processVariant(const sdbus::Variant& variant)
|
||||
{
|
||||
sdbus::Variant result;
|
||||
proxy_.callMethod("processVariant").onInterface(INTERFACE_NAME).withArguments(variant).storeResultsTo(result);
|
||||
proxy_->callMethod("processVariant").onInterface(INTERFACE_NAME).withArguments(variant).storeResultsTo(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::map<int32_t, sdbus::Variant> getMapOfVariants(const std::vector<int32_t>& x, const sdbus::Struct<sdbus::Variant, sdbus::Variant>& y)
|
||||
{
|
||||
std::map<int32_t, sdbus::Variant> result;
|
||||
proxy_.callMethod("getMapOfVariants").onInterface(INTERFACE_NAME).withArguments(x, y).storeResultsTo(result);
|
||||
proxy_->callMethod("getMapOfVariants").onInterface(INTERFACE_NAME).withArguments(x, y).storeResultsTo(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
sdbus::Struct<std::string, sdbus::Struct<std::map<int32_t, int32_t>>> getStructInStruct()
|
||||
{
|
||||
sdbus::Struct<std::string, sdbus::Struct<std::map<int32_t, int32_t>>> result;
|
||||
proxy_.callMethod("getStructInStruct").onInterface(INTERFACE_NAME).storeResultsTo(result);
|
||||
proxy_->callMethod("getStructInStruct").onInterface(INTERFACE_NAME).storeResultsTo(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
int32_t sumStructItems(const sdbus::Struct<uint8_t, uint16_t>& arg0, const sdbus::Struct<int32_t, int64_t>& arg1)
|
||||
{
|
||||
int32_t result;
|
||||
proxy_.callMethod("sumStructItems").onInterface(INTERFACE_NAME).withArguments(arg0, arg1).storeResultsTo(result);
|
||||
proxy_->callMethod("sumStructItems").onInterface(INTERFACE_NAME).withArguments(arg0, arg1).storeResultsTo(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
uint32_t sumVectorItems(const std::vector<uint16_t>& arg0, const std::vector<uint64_t>& arg1)
|
||||
{
|
||||
uint32_t result;
|
||||
proxy_.callMethod("sumVectorItems").onInterface(INTERFACE_NAME).withArguments(arg0, arg1).storeResultsTo(result);
|
||||
proxy_->callMethod("sumVectorItems").onInterface(INTERFACE_NAME).withArguments(arg0, arg1).storeResultsTo(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
uint32_t doOperation(const uint32_t& arg0)
|
||||
{
|
||||
uint32_t result;
|
||||
proxy_.callMethod("doOperation").onInterface(INTERFACE_NAME).withArguments(arg0).storeResultsTo(result);
|
||||
proxy_->callMethod("doOperation").onInterface(INTERFACE_NAME).withArguments(arg0).storeResultsTo(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
uint32_t doOperationAsync(const uint32_t& arg0)
|
||||
{
|
||||
uint32_t result;
|
||||
proxy_.callMethod("doOperationAsync").onInterface(INTERFACE_NAME).withArguments(arg0).storeResultsTo(result);
|
||||
proxy_->callMethod("doOperationAsync").onInterface(INTERFACE_NAME).withArguments(arg0).storeResultsTo(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
sdbus::Signature getSignature()
|
||||
{
|
||||
sdbus::Signature result;
|
||||
proxy_.callMethod("getSignature").onInterface(INTERFACE_NAME).storeResultsTo(result);
|
||||
proxy_->callMethod("getSignature").onInterface(INTERFACE_NAME).storeResultsTo(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
sdbus::ObjectPath getObjPath()
|
||||
{
|
||||
sdbus::ObjectPath result;
|
||||
proxy_.callMethod("getObjPath").onInterface(INTERFACE_NAME).storeResultsTo(result);
|
||||
proxy_->callMethod("getObjPath").onInterface(INTERFACE_NAME).storeResultsTo(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
sdbus::UnixFd getUnixFd()
|
||||
{
|
||||
sdbus::UnixFd result;
|
||||
proxy_.callMethod("getUnixFd").onInterface(INTERFACE_NAME).storeResultsTo(result);
|
||||
proxy_->callMethod("getUnixFd").onInterface(INTERFACE_NAME).storeResultsTo(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::map<uint64_t, sdbus::Struct<std::map<uint8_t, std::vector<sdbus::Struct<sdbus::ObjectPath, bool, sdbus::Variant, std::map<int32_t, std::string>>>>, sdbus::Signature, std::string>> getComplex()
|
||||
{
|
||||
std::map<uint64_t, sdbus::Struct<std::map<uint8_t, std::vector<sdbus::Struct<sdbus::ObjectPath, bool, sdbus::Variant, std::map<int32_t, std::string>>>>, sdbus::Signature, std::string>> result;
|
||||
proxy_.callMethod("getComplex").onInterface(INTERFACE_NAME).storeResultsTo(result);
|
||||
proxy_->callMethod("getComplex").onInterface(INTERFACE_NAME).storeResultsTo(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
void throwError()
|
||||
{
|
||||
proxy_.callMethod("throwError").onInterface(INTERFACE_NAME);
|
||||
proxy_->callMethod("throwError").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
void throwErrorWithNoReply()
|
||||
{
|
||||
proxy_.callMethod("throwErrorWithNoReply").onInterface(INTERFACE_NAME).dontExpectReply();
|
||||
proxy_->callMethod("throwErrorWithNoReply").onInterface(INTERFACE_NAME).dontExpectReply();
|
||||
}
|
||||
|
||||
void doPrivilegedStuff()
|
||||
{
|
||||
proxy_.callMethod("doPrivilegedStuff").onInterface(INTERFACE_NAME);
|
||||
proxy_->callMethod("doPrivilegedStuff").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
void emitTwoSimpleSignals()
|
||||
{
|
||||
proxy_.callMethod("emitTwoSimpleSignals").onInterface(INTERFACE_NAME);
|
||||
proxy_->callMethod("emitTwoSimpleSignals").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
void unregisterSimpleSignalHandler()
|
||||
{
|
||||
proxy_.muteSignal("simpleSignal").onInterface(INTERFACE_NAME);
|
||||
proxy_->muteSignal("simpleSignal").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
void reRegisterSimpleSignalHandler()
|
||||
{
|
||||
proxy_.uponSignal("simpleSignal").onInterface(INTERFACE_NAME).call([this](){ this->onSimpleSignal(); });
|
||||
proxy_.finishRegistration();
|
||||
proxy_->uponSignal("simpleSignal").onInterface(INTERFACE_NAME).call([this](){ this->onSimpleSignal(); });
|
||||
proxy_->finishRegistration();
|
||||
}
|
||||
|
||||
public:
|
||||
uint32_t action()
|
||||
{
|
||||
return proxy_.getProperty("action").onInterface(INTERFACE_NAME);
|
||||
return proxy_->getProperty("action").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
void action(const uint32_t& value)
|
||||
{
|
||||
proxy_.setProperty("action").onInterface(INTERFACE_NAME).toValue(value);
|
||||
proxy_->setProperty("action").onInterface(INTERFACE_NAME).toValue(value);
|
||||
}
|
||||
|
||||
bool blocking()
|
||||
{
|
||||
return proxy_.getProperty("blocking").onInterface(INTERFACE_NAME);
|
||||
return proxy_->getProperty("blocking").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
void blocking(const bool& value)
|
||||
{
|
||||
proxy_.setProperty("blocking").onInterface(INTERFACE_NAME).toValue(value);
|
||||
proxy_->setProperty("blocking").onInterface(INTERFACE_NAME).toValue(value);
|
||||
}
|
||||
|
||||
std::string state()
|
||||
{
|
||||
return proxy_.getProperty("state").onInterface(INTERFACE_NAME);
|
||||
return proxy_->getProperty("state").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
private:
|
||||
sdbus::IProxy& proxy_;
|
||||
sdbus::IProxy* proxy_;
|
||||
};
|
||||
|
||||
}} // namespaces
|
||||
|
@ -20,19 +20,24 @@ public:
|
||||
|
||||
protected:
|
||||
perftests_adaptor(sdbus::IObject& object)
|
||||
: object_(object)
|
||||
: object_(&object)
|
||||
{
|
||||
object_.registerMethod("sendDataSignals").onInterface(INTERFACE_NAME).withInputParamNames("numberOfSignals", "signalMsgSize").implementedAs([this](const uint32_t& numberOfSignals, const uint32_t& signalMsgSize){ return this->sendDataSignals(numberOfSignals, signalMsgSize); });
|
||||
object_.registerMethod("concatenateTwoStrings").onInterface(INTERFACE_NAME).withInputParamNames("string1", "string2").withOutputParamNames("result").implementedAs([this](const std::string& string1, const std::string& string2){ return this->concatenateTwoStrings(string1, string2); });
|
||||
object_.registerSignal("dataSignal").onInterface(INTERFACE_NAME).withParameters<std::string>("data");
|
||||
object_->registerMethod("sendDataSignals").onInterface(INTERFACE_NAME).withInputParamNames("numberOfSignals", "signalMsgSize").implementedAs([this](const uint32_t& numberOfSignals, const uint32_t& signalMsgSize){ return this->sendDataSignals(numberOfSignals, signalMsgSize); });
|
||||
object_->registerMethod("concatenateTwoStrings").onInterface(INTERFACE_NAME).withInputParamNames("string1", "string2").withOutputParamNames("result").implementedAs([this](const std::string& string1, const std::string& string2){ return this->concatenateTwoStrings(string1, string2); });
|
||||
object_->registerSignal("dataSignal").onInterface(INTERFACE_NAME).withParameters<std::string>("data");
|
||||
}
|
||||
|
||||
perftests_adaptor(const perftests_adaptor&) = delete;
|
||||
perftests_adaptor& operator=(const perftests_adaptor&) = delete;
|
||||
perftests_adaptor(perftests_adaptor&&) = default;
|
||||
perftests_adaptor& operator=(perftests_adaptor&&) = default;
|
||||
|
||||
~perftests_adaptor() = default;
|
||||
|
||||
public:
|
||||
void emitDataSignal(const std::string& data)
|
||||
{
|
||||
object_.emitSignal("dataSignal").onInterface(INTERFACE_NAME).withArguments(data);
|
||||
object_->emitSignal("dataSignal").onInterface(INTERFACE_NAME).withArguments(data);
|
||||
}
|
||||
|
||||
private:
|
||||
@ -40,7 +45,7 @@ private:
|
||||
virtual std::string concatenateTwoStrings(const std::string& string1, const std::string& string2) = 0;
|
||||
|
||||
private:
|
||||
sdbus::IObject& object_;
|
||||
sdbus::IObject* object_;
|
||||
};
|
||||
|
||||
}} // namespaces
|
||||
|
@ -20,11 +20,16 @@ public:
|
||||
|
||||
protected:
|
||||
perftests_proxy(sdbus::IProxy& proxy)
|
||||
: proxy_(proxy)
|
||||
: proxy_(&proxy)
|
||||
{
|
||||
proxy_.uponSignal("dataSignal").onInterface(INTERFACE_NAME).call([this](const std::string& data){ this->onDataSignal(data); });
|
||||
proxy_->uponSignal("dataSignal").onInterface(INTERFACE_NAME).call([this](const std::string& data){ this->onDataSignal(data); });
|
||||
}
|
||||
|
||||
perftests_proxy(const perftests_proxy&) = delete;
|
||||
perftests_proxy& operator=(const perftests_proxy&) = delete;
|
||||
perftests_proxy(perftests_proxy&&) = default;
|
||||
perftests_proxy& operator=(perftests_proxy&&) = default;
|
||||
|
||||
~perftests_proxy() = default;
|
||||
|
||||
virtual void onDataSignal(const std::string& data) = 0;
|
||||
@ -32,18 +37,18 @@ protected:
|
||||
public:
|
||||
void sendDataSignals(const uint32_t& numberOfSignals, const uint32_t& signalMsgSize)
|
||||
{
|
||||
proxy_.callMethod("sendDataSignals").onInterface(INTERFACE_NAME).withArguments(numberOfSignals, signalMsgSize);
|
||||
proxy_->callMethod("sendDataSignals").onInterface(INTERFACE_NAME).withArguments(numberOfSignals, signalMsgSize);
|
||||
}
|
||||
|
||||
std::string concatenateTwoStrings(const std::string& string1, const std::string& string2)
|
||||
{
|
||||
std::string result;
|
||||
proxy_.callMethod("concatenateTwoStrings").onInterface(INTERFACE_NAME).withArguments(string1, string2).storeResultsTo(result);
|
||||
proxy_->callMethod("concatenateTwoStrings").onInterface(INTERFACE_NAME).withArguments(string1, string2).storeResultsTo(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
sdbus::IProxy& proxy_;
|
||||
sdbus::IProxy* proxy_;
|
||||
};
|
||||
|
||||
}} // namespaces
|
||||
|
@ -22,18 +22,23 @@ public:
|
||||
|
||||
protected:
|
||||
thermometer_adaptor(sdbus::IObject& object)
|
||||
: object_(object)
|
||||
: object_(&object)
|
||||
{
|
||||
object_.registerMethod("getCurrentTemperature").onInterface(INTERFACE_NAME).withOutputParamNames("result").implementedAs([this](){ return this->getCurrentTemperature(); });
|
||||
object_->registerMethod("getCurrentTemperature").onInterface(INTERFACE_NAME).withOutputParamNames("result").implementedAs([this](){ return this->getCurrentTemperature(); });
|
||||
}
|
||||
|
||||
thermometer_adaptor(const thermometer_adaptor&) = delete;
|
||||
thermometer_adaptor& operator=(const thermometer_adaptor&) = delete;
|
||||
thermometer_adaptor(thermometer_adaptor&&) = default;
|
||||
thermometer_adaptor& operator=(thermometer_adaptor&&) = default;
|
||||
|
||||
~thermometer_adaptor() = default;
|
||||
|
||||
private:
|
||||
virtual uint32_t getCurrentTemperature() = 0;
|
||||
|
||||
private:
|
||||
sdbus::IObject& object_;
|
||||
sdbus::IObject* object_;
|
||||
};
|
||||
|
||||
}}}} // namespaces
|
||||
|
@ -22,22 +22,27 @@ public:
|
||||
|
||||
protected:
|
||||
thermometer_proxy(sdbus::IProxy& proxy)
|
||||
: proxy_(proxy)
|
||||
: proxy_(&proxy)
|
||||
{
|
||||
}
|
||||
|
||||
thermometer_proxy(const thermometer_proxy&) = delete;
|
||||
thermometer_proxy& operator=(const thermometer_proxy&) = delete;
|
||||
thermometer_proxy(thermometer_proxy&&) = default;
|
||||
thermometer_proxy& operator=(thermometer_proxy&&) = default;
|
||||
|
||||
~thermometer_proxy() = default;
|
||||
|
||||
public:
|
||||
uint32_t getCurrentTemperature()
|
||||
{
|
||||
uint32_t result;
|
||||
proxy_.callMethod("getCurrentTemperature").onInterface(INTERFACE_NAME).storeResultsTo(result);
|
||||
proxy_->callMethod("getCurrentTemperature").onInterface(INTERFACE_NAME).storeResultsTo(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
sdbus::IProxy& proxy_;
|
||||
sdbus::IProxy* proxy_;
|
||||
};
|
||||
|
||||
}}}} // namespaces
|
||||
|
@ -21,25 +21,30 @@ public:
|
||||
|
||||
protected:
|
||||
concatenator_adaptor(sdbus::IObject& object)
|
||||
: object_(object)
|
||||
: object_(&object)
|
||||
{
|
||||
object_.registerMethod("concatenate").onInterface(INTERFACE_NAME).withInputParamNames("params").withOutputParamNames("result").implementedAs([this](sdbus::Result<std::string>&& result, std::map<std::string, sdbus::Variant> params){ this->concatenate(std::move(result), std::move(params)); });
|
||||
object_.registerSignal("concatenatedSignal").onInterface(INTERFACE_NAME).withParameters<std::string>("concatenatedString");
|
||||
object_->registerMethod("concatenate").onInterface(INTERFACE_NAME).withInputParamNames("params").withOutputParamNames("result").implementedAs([this](sdbus::Result<std::string>&& result, std::map<std::string, sdbus::Variant> params){ this->concatenate(std::move(result), std::move(params)); });
|
||||
object_->registerSignal("concatenatedSignal").onInterface(INTERFACE_NAME).withParameters<std::string>("concatenatedString");
|
||||
}
|
||||
|
||||
concatenator_adaptor(const concatenator_adaptor&) = delete;
|
||||
concatenator_adaptor& operator=(const concatenator_adaptor&) = delete;
|
||||
concatenator_adaptor(concatenator_adaptor&&) = default;
|
||||
concatenator_adaptor& operator=(concatenator_adaptor&&) = default;
|
||||
|
||||
~concatenator_adaptor() = default;
|
||||
|
||||
public:
|
||||
void emitConcatenatedSignal(const std::string& concatenatedString)
|
||||
{
|
||||
object_.emitSignal("concatenatedSignal").onInterface(INTERFACE_NAME).withArguments(concatenatedString);
|
||||
object_->emitSignal("concatenatedSignal").onInterface(INTERFACE_NAME).withArguments(concatenatedString);
|
||||
}
|
||||
|
||||
private:
|
||||
virtual void concatenate(sdbus::Result<std::string>&& result, std::map<std::string, sdbus::Variant> params) = 0;
|
||||
|
||||
private:
|
||||
sdbus::IObject& object_;
|
||||
sdbus::IObject* object_;
|
||||
};
|
||||
|
||||
}}} // namespaces
|
||||
|
@ -21,11 +21,16 @@ public:
|
||||
|
||||
protected:
|
||||
concatenator_proxy(sdbus::IProxy& proxy)
|
||||
: proxy_(proxy)
|
||||
: proxy_(&proxy)
|
||||
{
|
||||
proxy_.uponSignal("concatenatedSignal").onInterface(INTERFACE_NAME).call([this](const std::string& concatenatedString){ this->onConcatenatedSignal(concatenatedString); });
|
||||
proxy_->uponSignal("concatenatedSignal").onInterface(INTERFACE_NAME).call([this](const std::string& concatenatedString){ this->onConcatenatedSignal(concatenatedString); });
|
||||
}
|
||||
|
||||
concatenator_proxy(const concatenator_proxy&) = delete;
|
||||
concatenator_proxy& operator=(const concatenator_proxy&) = delete;
|
||||
concatenator_proxy(concatenator_proxy&&) = default;
|
||||
concatenator_proxy& operator=(concatenator_proxy&&) = default;
|
||||
|
||||
~concatenator_proxy() = default;
|
||||
|
||||
virtual void onConcatenatedSignal(const std::string& concatenatedString) = 0;
|
||||
@ -35,11 +40,11 @@ protected:
|
||||
public:
|
||||
sdbus::PendingAsyncCall concatenate(const std::map<std::string, sdbus::Variant>& params)
|
||||
{
|
||||
return proxy_.callMethodAsync("concatenate").onInterface(INTERFACE_NAME).withArguments(params).uponReplyInvoke([this](const sdbus::Error* error, const std::string& result){ this->onConcatenateReply(result, error); });
|
||||
return proxy_->callMethodAsync("concatenate").onInterface(INTERFACE_NAME).withArguments(params).uponReplyInvoke([this](const sdbus::Error* error, const std::string& result){ this->onConcatenateReply(result, error); });
|
||||
}
|
||||
|
||||
private:
|
||||
sdbus::IProxy& proxy_;
|
||||
sdbus::IProxy* proxy_;
|
||||
};
|
||||
|
||||
}}} // namespaces
|
||||
|
@ -22,18 +22,23 @@ public:
|
||||
|
||||
protected:
|
||||
thermometer_adaptor(sdbus::IObject& object)
|
||||
: object_(object)
|
||||
: object_(&object)
|
||||
{
|
||||
object_.registerMethod("getCurrentTemperature").onInterface(INTERFACE_NAME).withOutputParamNames("result").implementedAs([this](){ return this->getCurrentTemperature(); });
|
||||
object_->registerMethod("getCurrentTemperature").onInterface(INTERFACE_NAME).withOutputParamNames("result").implementedAs([this](){ return this->getCurrentTemperature(); });
|
||||
}
|
||||
|
||||
thermometer_adaptor(const thermometer_adaptor&) = delete;
|
||||
thermometer_adaptor& operator=(const thermometer_adaptor&) = delete;
|
||||
thermometer_adaptor(thermometer_adaptor&&) = default;
|
||||
thermometer_adaptor& operator=(thermometer_adaptor&&) = default;
|
||||
|
||||
~thermometer_adaptor() = default;
|
||||
|
||||
private:
|
||||
virtual uint32_t getCurrentTemperature() = 0;
|
||||
|
||||
private:
|
||||
sdbus::IObject& object_;
|
||||
sdbus::IObject* object_;
|
||||
};
|
||||
|
||||
}}}} // namespaces
|
||||
@ -51,12 +56,17 @@ public:
|
||||
|
||||
protected:
|
||||
factory_adaptor(sdbus::IObject& object)
|
||||
: object_(object)
|
||||
: object_(&object)
|
||||
{
|
||||
object_.registerMethod("createDelegateObject").onInterface(INTERFACE_NAME).withOutputParamNames("delegate").implementedAs([this](sdbus::Result<sdbus::ObjectPath>&& result){ this->createDelegateObject(std::move(result)); });
|
||||
object_.registerMethod("destroyDelegateObject").onInterface(INTERFACE_NAME).withInputParamNames("delegate").implementedAs([this](sdbus::Result<>&& result, sdbus::ObjectPath delegate){ this->destroyDelegateObject(std::move(result), std::move(delegate)); }).withNoReply();
|
||||
object_->registerMethod("createDelegateObject").onInterface(INTERFACE_NAME).withOutputParamNames("delegate").implementedAs([this](sdbus::Result<sdbus::ObjectPath>&& result){ this->createDelegateObject(std::move(result)); });
|
||||
object_->registerMethod("destroyDelegateObject").onInterface(INTERFACE_NAME).withInputParamNames("delegate").implementedAs([this](sdbus::Result<>&& result, sdbus::ObjectPath delegate){ this->destroyDelegateObject(std::move(result), std::move(delegate)); }).withNoReply();
|
||||
}
|
||||
|
||||
factory_adaptor(const factory_adaptor&) = delete;
|
||||
factory_adaptor& operator=(const factory_adaptor&) = delete;
|
||||
factory_adaptor(factory_adaptor&&) = default;
|
||||
factory_adaptor& operator=(factory_adaptor&&) = default;
|
||||
|
||||
~factory_adaptor() = default;
|
||||
|
||||
private:
|
||||
@ -64,7 +74,7 @@ private:
|
||||
virtual void destroyDelegateObject(sdbus::Result<>&& result, sdbus::ObjectPath delegate) = 0;
|
||||
|
||||
private:
|
||||
sdbus::IObject& object_;
|
||||
sdbus::IObject* object_;
|
||||
};
|
||||
|
||||
}}}}} // namespaces
|
||||
|
@ -22,22 +22,27 @@ public:
|
||||
|
||||
protected:
|
||||
thermometer_proxy(sdbus::IProxy& proxy)
|
||||
: proxy_(proxy)
|
||||
: proxy_(&proxy)
|
||||
{
|
||||
}
|
||||
|
||||
thermometer_proxy(const thermometer_proxy&) = delete;
|
||||
thermometer_proxy& operator=(const thermometer_proxy&) = delete;
|
||||
thermometer_proxy(thermometer_proxy&&) = default;
|
||||
thermometer_proxy& operator=(thermometer_proxy&&) = default;
|
||||
|
||||
~thermometer_proxy() = default;
|
||||
|
||||
public:
|
||||
uint32_t getCurrentTemperature()
|
||||
{
|
||||
uint32_t result;
|
||||
proxy_.callMethod("getCurrentTemperature").onInterface(INTERFACE_NAME).storeResultsTo(result);
|
||||
proxy_->callMethod("getCurrentTemperature").onInterface(INTERFACE_NAME).storeResultsTo(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
sdbus::IProxy& proxy_;
|
||||
sdbus::IProxy* proxy_;
|
||||
};
|
||||
|
||||
}}}} // namespaces
|
||||
@ -55,27 +60,32 @@ public:
|
||||
|
||||
protected:
|
||||
factory_proxy(sdbus::IProxy& proxy)
|
||||
: proxy_(proxy)
|
||||
: proxy_(&proxy)
|
||||
{
|
||||
}
|
||||
|
||||
factory_proxy(const factory_proxy&) = delete;
|
||||
factory_proxy& operator=(const factory_proxy&) = delete;
|
||||
factory_proxy(factory_proxy&&) = default;
|
||||
factory_proxy& operator=(factory_proxy&&) = default;
|
||||
|
||||
~factory_proxy() = default;
|
||||
|
||||
public:
|
||||
sdbus::ObjectPath createDelegateObject()
|
||||
{
|
||||
sdbus::ObjectPath result;
|
||||
proxy_.callMethod("createDelegateObject").onInterface(INTERFACE_NAME).storeResultsTo(result);
|
||||
proxy_->callMethod("createDelegateObject").onInterface(INTERFACE_NAME).storeResultsTo(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
void destroyDelegateObject(const sdbus::ObjectPath& delegate)
|
||||
{
|
||||
proxy_.callMethod("destroyDelegateObject").onInterface(INTERFACE_NAME).withArguments(delegate).dontExpectReply();
|
||||
proxy_->callMethod("destroyDelegateObject").onInterface(INTERFACE_NAME).withArguments(delegate).dontExpectReply();
|
||||
}
|
||||
|
||||
private:
|
||||
sdbus::IProxy& proxy_;
|
||||
sdbus::IProxy* proxy_;
|
||||
};
|
||||
|
||||
}}}}} // namespaces
|
||||
|
@ -26,6 +26,26 @@
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
|
||||
#include "sdbus-c++/sdbus-c++.h"
|
||||
|
||||
// There are some data races reported thread sanitizer in unit/intg tests. TODO: investigate, it looks like this example is not well written:
|
||||
class Global
|
||||
{
|
||||
public:
|
||||
~Global()
|
||||
{
|
||||
std::thread t([]() {
|
||||
sdbus::Variant v((int) 5);
|
||||
printf("%d\n", v.get<int>());
|
||||
});
|
||||
t.detach();
|
||||
}
|
||||
};
|
||||
|
||||
Global g1;
|
||||
Global g2;
|
||||
Global g3;
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
::testing::InitGoogleMock(&argc, argv);
|
||||
|
@ -85,7 +85,7 @@ std::string AdaptorGenerator::processInterface(Node& interface) const
|
||||
<< tab << "static constexpr const char* INTERFACE_NAME = \"" << ifaceName << "\";" << endl << endl
|
||||
<< "protected:" << endl
|
||||
<< tab << className << "(sdbus::IObject& object)" << endl
|
||||
<< tab << tab << ": object_(object)" << endl;
|
||||
<< tab << tab << ": object_(&object)" << endl;
|
||||
|
||||
Nodes methods = interface["method"];
|
||||
Nodes signals = interface["signal"];
|
||||
@ -111,7 +111,7 @@ std::string AdaptorGenerator::processInterface(Node& interface) const
|
||||
if(!annotationRegistration.empty())
|
||||
{
|
||||
std::stringstream str;
|
||||
str << tab << tab << "object_.setInterfaceFlags(INTERFACE_NAME)" << annotationRegistration << ";" << endl;
|
||||
str << tab << tab << "object_->setInterfaceFlags(INTERFACE_NAME)" << annotationRegistration << ";" << endl;
|
||||
annotationRegistration = str.str();
|
||||
}
|
||||
|
||||
@ -131,6 +131,12 @@ std::string AdaptorGenerator::processInterface(Node& interface) const
|
||||
<< propertyRegistration
|
||||
<< tab << "}" << endl << endl;
|
||||
|
||||
// Rule of Five
|
||||
body << tab << className << "(const " << className << "&) = delete;" << endl;
|
||||
body << tab << className << "& operator=(const " << className << "&) = delete;" << endl;
|
||||
body << tab << className << "(" << className << "&&) = default;" << endl;
|
||||
body << tab << className << "& operator=(" << className << "&&) = default;" << endl << endl;
|
||||
|
||||
body << tab << "~" << className << "() = default;" << endl << endl;
|
||||
|
||||
if (!signalMethods.empty())
|
||||
@ -149,7 +155,7 @@ std::string AdaptorGenerator::processInterface(Node& interface) const
|
||||
}
|
||||
|
||||
body << "private:" << endl
|
||||
<< tab << "sdbus::IObject& object_;" << endl
|
||||
<< tab << "sdbus::IObject* object_;" << endl
|
||||
<< "};" << endl << endl
|
||||
<< std::string(namespacesCount, '}') << " // namespaces" << endl << endl;
|
||||
|
||||
@ -211,7 +217,7 @@ std::tuple<std::string, std::string> AdaptorGenerator::processMethods(const Node
|
||||
|
||||
using namespace std::string_literals;
|
||||
|
||||
registrationSS << tab << tab << "object_.registerMethod(\""
|
||||
registrationSS << tab << tab << "object_->registerMethod(\""
|
||||
<< methodName << "\")"
|
||||
<< ".onInterface(INTERFACE_NAME)"
|
||||
<< (!argStringsStr.empty() ? (".withInputParamNames(" + argStringsStr + ")") : "")
|
||||
@ -267,7 +273,7 @@ std::tuple<std::string, std::string> AdaptorGenerator::processSignals(const Node
|
||||
std::tie(argStr, argTypeStr, typeStr, argStringsStr) = argsToNamesAndTypes(args);
|
||||
|
||||
signalRegistrationSS << tab << tab
|
||||
<< "object_.registerSignal(\"" << name << "\")"
|
||||
<< "object_->registerSignal(\"" << name << "\")"
|
||||
".onInterface(INTERFACE_NAME)";
|
||||
|
||||
if (args.size() > 0)
|
||||
@ -284,7 +290,7 @@ std::tuple<std::string, std::string> AdaptorGenerator::processSignals(const Node
|
||||
|
||||
signalMethodSS << tab << "void emit" << nameWithCapFirstLetter << "(" << argTypeStr << ")" << endl
|
||||
<< tab << "{" << endl
|
||||
<< tab << tab << "object_.emitSignal(\"" << name << "\")"
|
||||
<< tab << tab << "object_->emitSignal(\"" << name << "\")"
|
||||
".onInterface(INTERFACE_NAME)";
|
||||
|
||||
if (!argStr.empty())
|
||||
@ -333,7 +339,7 @@ std::tuple<std::string, std::string> AdaptorGenerator::processProperties(const N
|
||||
<< "Option '" << annotationName << "' not allowed or supported in this context! Option ignored..." << std::endl;
|
||||
}
|
||||
|
||||
registrationSS << tab << tab << "object_.registerProperty(\""
|
||||
registrationSS << tab << tab << "object_->registerProperty(\""
|
||||
<< propertyName << "\")"
|
||||
<< ".onInterface(INTERFACE_NAME)";
|
||||
|
||||
|
@ -84,7 +84,7 @@ std::string ProxyGenerator::processInterface(Node& interface) const
|
||||
<< tab << "static constexpr const char* INTERFACE_NAME = \"" << ifaceName << "\";" << endl << endl
|
||||
<< "protected:" << endl
|
||||
<< tab << className << "(sdbus::IProxy& proxy)" << endl
|
||||
<< tab << tab << ": proxy_(proxy)" << endl;
|
||||
<< tab << tab << ": proxy_(&proxy)" << endl;
|
||||
|
||||
Nodes methods = interface["method"];
|
||||
Nodes signals = interface["signal"];
|
||||
@ -97,6 +97,12 @@ std::string ProxyGenerator::processInterface(Node& interface) const
|
||||
<< registration
|
||||
<< tab << "}" << endl << endl;
|
||||
|
||||
// Rule of Five
|
||||
body << tab << className << "(const " << className << "&) = delete;" << endl;
|
||||
body << tab << className << "& operator=(const " << className << "&) = delete;" << endl;
|
||||
body << tab << className << "(" << className << "&&) = default;" << endl;
|
||||
body << tab << className << "& operator=(" << className << "&&) = default;" << endl << endl;
|
||||
|
||||
body << tab << "~" << className << "() = default;" << endl << endl;
|
||||
|
||||
if (!declaration.empty())
|
||||
@ -122,7 +128,7 @@ std::string ProxyGenerator::processInterface(Node& interface) const
|
||||
}
|
||||
|
||||
body << "private:" << endl
|
||||
<< tab << "sdbus::IProxy& proxy_;" << endl
|
||||
<< tab << "sdbus::IProxy* proxy_;" << endl
|
||||
<< "};" << endl << endl
|
||||
<< std::string(namespacesCount, '}') << " // namespaces" << endl << endl;
|
||||
|
||||
@ -200,7 +206,7 @@ std::tuple<std::string, std::string> ProxyGenerator::processMethods(const Nodes&
|
||||
}
|
||||
|
||||
definitionSS << tab << tab << (async && !dontExpectReply ? "return " : "")
|
||||
<< "proxy_.callMethod" << (async ? "Async" : "") << "(\"" << name << "\").onInterface(INTERFACE_NAME)";
|
||||
<< "proxy_->callMethod" << (async ? "Async" : "") << "(\"" << name << "\").onInterface(INTERFACE_NAME)";
|
||||
|
||||
if (!timeoutValue.empty())
|
||||
{
|
||||
@ -257,7 +263,7 @@ std::tuple<std::string, std::string> ProxyGenerator::processSignals(const Nodes&
|
||||
std::tie(argStr, argTypeStr, std::ignore, std::ignore) = argsToNamesAndTypes(args);
|
||||
|
||||
registrationSS << tab << tab << "proxy_"
|
||||
".uponSignal(\"" << name << "\")"
|
||||
"->uponSignal(\"" << name << "\")"
|
||||
".onInterface(INTERFACE_NAME)"
|
||||
".call([this](" << argTypeStr << ")"
|
||||
"{ this->on" << nameBigFirst << "(" << argStr << "); });" << endl;
|
||||
@ -286,7 +292,7 @@ std::string ProxyGenerator::processProperties(const Nodes& properties) const
|
||||
{
|
||||
propertySS << tab << propertyType << " " << propertyNameSafe << "()" << endl
|
||||
<< tab << "{" << endl;
|
||||
propertySS << tab << tab << "return proxy_.getProperty(\"" << propertyName << "\")"
|
||||
propertySS << tab << tab << "return proxy_->getProperty(\"" << propertyName << "\")"
|
||||
".onInterface(INTERFACE_NAME)";
|
||||
propertySS << ";" << endl << tab << "}" << endl << endl;
|
||||
}
|
||||
@ -295,7 +301,7 @@ std::string ProxyGenerator::processProperties(const Nodes& properties) const
|
||||
{
|
||||
propertySS << tab << "void " << propertyNameSafe << "(" << propertyTypeArg << ")" << endl
|
||||
<< tab << "{" << endl;
|
||||
propertySS << tab << tab << "proxy_.setProperty(\"" << propertyName << "\")"
|
||||
propertySS << tab << tab << "proxy_->setProperty(\"" << propertyName << "\")"
|
||||
".onInterface(INTERFACE_NAME)"
|
||||
".toValue(" << propertyArg << ")";
|
||||
propertySS << ";" << endl << tab << "}" << endl << endl;
|
||||
|
Reference in New Issue
Block a user