forked from Kistler-Group/sdbus-cpp
feat: add support for std::future-based async calls
This commit is contained in:
@ -1066,11 +1066,11 @@ For a real example of a server-side asynchronous D-Bus method, please look at sd
|
|||||||
Asynchronous client-side methods
|
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
|
### 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++
|
```c++
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
@ -1115,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.
|
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
|
### 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++
|
```c++
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
@ -1152,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.
|
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
|
### 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):
|
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):
|
||||||
|
@ -34,6 +34,7 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
#include <future>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
// Forward declarations
|
// Forward declarations
|
||||||
@ -195,6 +196,10 @@ namespace sdbus {
|
|||||||
AsyncMethodInvoker& withTimeout(const std::chrono::duration<_Rep, _Period>& timeout);
|
AsyncMethodInvoker& withTimeout(const std::chrono::duration<_Rep, _Period>& timeout);
|
||||||
template <typename... _Args> AsyncMethodInvoker& withArguments(_Args&&... args);
|
template <typename... _Args> AsyncMethodInvoker& withArguments(_Args&&... args);
|
||||||
template <typename _Function> PendingAsyncCall uponReplyInvoke(_Function&& callback);
|
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:
|
private:
|
||||||
IProxy& proxy_;
|
IProxy& proxy_;
|
||||||
|
@ -610,6 +610,29 @@ namespace sdbus {
|
|||||||
return proxy_.callMethod(method_, std::move(asyncReplyHandler), timeout_);
|
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 ***/
|
/*** SignalSubscriber ***/
|
||||||
/*** ---------------- ***/
|
/*** ---------------- ***/
|
||||||
|
@ -28,10 +28,12 @@
|
|||||||
#define SDBUS_CXX_IPROXY_H_
|
#define SDBUS_CXX_IPROXY_H_
|
||||||
|
|
||||||
#include <sdbus-c++/ConvenienceApiClasses.h>
|
#include <sdbus-c++/ConvenienceApiClasses.h>
|
||||||
|
#include <sdbus-c++/TypeTraits.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
#include <future>
|
||||||
|
|
||||||
// Forward declarations
|
// Forward declarations
|
||||||
namespace sdbus {
|
namespace sdbus {
|
||||||
@ -322,6 +324,33 @@ namespace sdbus {
|
|||||||
* @return A pointer to the currently processed D-Bus message
|
* @return A pointer to the currently processed D-Bus message
|
||||||
*/
|
*/
|
||||||
virtual const Message* getCurrentlyProcessedMessage() const = 0;
|
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());
|
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)
|
inline MethodInvoker IProxy::callMethod(const std::string& methodName)
|
||||||
{
|
{
|
||||||
return MethodInvoker(*this, methodName);
|
return MethodInvoker(*this, methodName);
|
||||||
@ -412,11 +450,6 @@ namespace sdbus {
|
|||||||
return PropertySetter(*this, propertyName);
|
return PropertySetter(*this, propertyName);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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{};
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* @brief Creates a proxy object for a specific remote D-Bus object
|
* @brief Creates a proxy object for a specific remote D-Bus object
|
||||||
*
|
*
|
||||||
|
@ -81,6 +81,13 @@ namespace sdbus {
|
|||||||
// Tag denoting the assumption that the caller has already obtained fd ownership
|
// Tag denoting the assumption that the caller has already obtained fd ownership
|
||||||
struct adopt_fd_t { explicit adopt_fd_t() = default; };
|
struct adopt_fd_t { explicit adopt_fd_t() = default; };
|
||||||
inline constexpr adopt_fd_t adopt_fd{};
|
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 specializations for getting D-Bus signatures from C++ types
|
||||||
template <typename _T>
|
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
|
namespace detail
|
||||||
{
|
{
|
||||||
template <class _Function, class _Tuple, typename... _Args, std::size_t... _I>
|
template <class _Function, class _Tuple, typename... _Args, std::size_t... _I>
|
||||||
|
@ -131,6 +131,29 @@ PendingAsyncCall Proxy::callMethod(const MethodCall& message, async_reply_handle
|
|||||||
return {weakData};
|
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)
|
MethodReply Proxy::sendMethodCallMessageAndWaitForReply(const MethodCall& message, uint64_t timeout)
|
||||||
{
|
{
|
||||||
/*thread_local*/ SyncCallReplyData syncCallReplyData;
|
/*thread_local*/ SyncCallReplyData syncCallReplyData;
|
||||||
|
@ -58,6 +58,8 @@ namespace sdbus::internal {
|
|||||||
MethodCall createMethodCall(const std::string& interfaceName, const std::string& methodName) override;
|
MethodCall createMethodCall(const std::string& interfaceName, const std::string& methodName) override;
|
||||||
MethodReply callMethod(const MethodCall& message, uint64_t timeout) override;
|
MethodReply callMethod(const MethodCall& message, uint64_t timeout) override;
|
||||||
PendingAsyncCall callMethod(const MethodCall& message, async_reply_handler asyncReplyCallback, 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
|
void registerSignalHandler( const std::string& interfaceName
|
||||||
, const std::string& signalName
|
, const std::string& signalName
|
||||||
|
@ -161,6 +161,24 @@ TEST_F(SdbusTestObject, InvokesMethodAsynchronouslyOnClientSide)
|
|||||||
ASSERT_THAT(future.get(), Eq(100));
|
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)
|
TEST_F(SdbusTestObject, AnswersThatAsyncCallIsPendingIfItIsInProgress)
|
||||||
{
|
{
|
||||||
m_proxy->installDoOperationClientSideAsyncReplyHandler([&](uint32_t /*res*/, const sdbus::Error* /*err*/){});
|
m_proxy->installDoOperationClientSideAsyncReplyHandler([&](uint32_t /*res*/, const sdbus::Error* /*err*/){});
|
||||||
@ -222,7 +240,7 @@ TEST_F(SdbusTestObject, SupportsAsyncCallCopyAssignment)
|
|||||||
ASSERT_TRUE(call.isPending());
|
ASSERT_TRUE(call.isPending());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(SdbusTestObject, InvokesErroneousMethodAsynchronouslyOnClientSide)
|
TEST_F(SdbusTestObject, ReturnsNonnullErrorWhenAsynchronousMethodCallFails)
|
||||||
{
|
{
|
||||||
std::promise<uint32_t> promise;
|
std::promise<uint32_t> promise;
|
||||||
auto future = promise.get_future();
|
auto future = promise.get_future();
|
||||||
@ -238,3 +256,10 @@ TEST_F(SdbusTestObject, InvokesErroneousMethodAsynchronouslyOnClientSide)
|
|||||||
|
|
||||||
ASSERT_THROW(future.get(), sdbus::Error);
|
ASSERT_THROW(future.get(), sdbus::Error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(SdbusTestObject, ThrowsErrorWhenClientSideAsynchronousMethodCallWithFutureFails)
|
||||||
|
{
|
||||||
|
auto future = m_proxy->doErroneousOperationClientSideAsync(sdbus::with_future);
|
||||||
|
|
||||||
|
ASSERT_THROW(future.get(), sdbus::Error);
|
||||||
|
}
|
||||||
|
@ -123,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()
|
void TestProxy::doErroneousOperationClientSideAsync()
|
||||||
{
|
{
|
||||||
getProxy().callMethodAsync("throwError")
|
getProxy().callMethodAsync("throwError")
|
||||||
@ -133,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)
|
void TestProxy::doOperationClientSideAsyncWithTimeout(const std::chrono::microseconds &timeout, uint32_t param)
|
||||||
{
|
{
|
||||||
using namespace std::chrono_literals;
|
using namespace std::chrono_literals;
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
#include <thread>
|
#include <thread>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
#include <future>
|
||||||
|
|
||||||
namespace sdbus { namespace test {
|
namespace sdbus { namespace test {
|
||||||
|
|
||||||
@ -94,6 +95,9 @@ public:
|
|||||||
void installDoOperationClientSideAsyncReplyHandler(std::function<void(uint32_t res, const sdbus::Error* err)> handler);
|
void installDoOperationClientSideAsyncReplyHandler(std::function<void(uint32_t res, const sdbus::Error* err)> handler);
|
||||||
uint32_t doOperationWithTimeout(const std::chrono::microseconds &timeout, uint32_t param);
|
uint32_t doOperationWithTimeout(const std::chrono::microseconds &timeout, uint32_t param);
|
||||||
sdbus::PendingAsyncCall doOperationClientSideAsync(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 doErroneousOperationClientSideAsync();
|
||||||
void doOperationClientSideAsyncWithTimeout(const std::chrono::microseconds &timeout, uint32_t param);
|
void doOperationClientSideAsyncWithTimeout(const std::chrono::microseconds &timeout, uint32_t param);
|
||||||
int32_t callNonexistentMethod();
|
int32_t callNonexistentMethod();
|
||||||
|
Reference in New Issue
Block a user