14#include <AUI/Common/AObject.h>
15#include <AUI/Traits/concepts.h>
16#include <AUI/Util/APimpl.h>
17#include <AUI/Util/ARaiiHelper.h>
18#include "AUI/Common/AException.h"
27 using std::string::string;
34 concept convertible =
requires(T t) {
41 explicit Unknown(
const DBusMessageIter& mIter) : mIter(mIter) {}
43 template<convertible T>
46 template<convertible T>
50 DBusMessageIter mIter;
53 using VariantImpl = std::variant<
70 using VariantImpl::variant;
71 Variant(): VariantImpl(std::nullopt) {}
75 concept convertible_or_void = convertible<T> || std::is_void_v<T>;
78 template<convertible T>
79 void iter_append(DBusMessageIter* iter,
const T& value) {
82 template<convertible T>
83 T iter_get(DBusMessageIter* iter) {
84 return converter<T>::iter_get(iter);
87 template<convertible T>
89 return aui::dbus::iter_get<T>(&mIter);
92 template<convertible T>
93 bool Unknown::as(T& v) {
94 if (
auto got = dbus_message_iter_get_arg_type(&mIter); got != converter<T>::signature[0]) {
98 v = aui::dbus::iter_get<T>(&mIter);
104 template<
typename T,
char dbusType = DBUS_TYPE_INVALID>
106 static inline std::string signature = fmt::format(
"{}", dbusType);
108 static void iter_append(DBusMessageIter* iter,
const T& t) {
109 dbus_message_iter_append_basic(iter, dbusType, &t);
111 static T iter_get(DBusMessageIter* iter) {
112 if (
auto got = dbus_message_iter_get_arg_type(iter); got != dbusType) {
113 throw AException(
"type error: expected '{:c}', got '{:c}'"_format(dbusType, got));
116 dbus_message_iter_get_basic(iter, &t);
123 static inline std::string signature = DBUS_TYPE_INVALID_AS_STRING;
125 static void iter_append(DBusMessageIter* iter, std::nullopt_t) {
127 dbus_message_iter_append_basic(iter, DBUS_TYPE_INVALID, &v);
130 static auto iter_get(DBusMessageIter* iter) {
131 if (
auto got = dbus_message_iter_get_arg_type(iter); got != DBUS_TYPE_INVALID) {
132 throw AException(
"type error: expected '{:c}', got '{:c}'"_format(DBUS_TYPE_INVALID, got));
148 static inline std::string signature = DBUS_TYPE_BOOLEAN_AS_STRING;
150 static void iter_append(DBusMessageIter* iter,
const bool& t) {
153 static bool iter_get(DBusMessageIter* iter) {
159 static void iter_append(DBusMessageIter* iter,
const std::string& t) {
162 static std::string iter_get(DBusMessageIter* iter) {
168 static void iter_append(DBusMessageIter* iter,
const AString& t) {
171 static AString iter_get(DBusMessageIter* iter) {
177 static void iter_append(DBusMessageIter* iter,
const ObjectPath& t) {
178 super::iter_append(iter, t.c_str());
181 static ObjectPath iter_get(DBusMessageIter* iter) {
182 return super::iter_get(iter);
188 template<convertible T>
192 static void iter_append(DBusMessageIter* iter,
const AVector<T>& t) {
195 if (!dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, s, &sub)) {
196 throw AException(
"dbus_message_iter_open_container failed");
199 dbus_message_iter_close_container(iter, &sub);
202 for (
const auto& v : t) {
203 aui::dbus::iter_append(&sub, v);
206 static AVector<T> iter_get(DBusMessageIter* iter) {
207 if (
auto got = dbus_message_iter_get_arg_type(iter); got != DBUS_TYPE_ARRAY) {
208 throw AException(
"type error: array expected, got '{:c}'"_format(got));
211 dbus_message_iter_recurse(iter, &sub);
215 result << aui::dbus::iter_get<T>(&sub);
216 if (!dbus_message_iter_next(&sub))
break;
223 template<convertible K, convertible V>
227 static void iter_append(DBusMessageIter* iter,
const AMap<K, V>& t) {
230 throw AException(
"dbus_message_iter_open_container failed");
233 dbus_message_iter_close_container(iter, &sub);
236 for (
const auto&[k, v] : t) {
237 DBusMessageIter item;
238 dbus_message_iter_open_container(&sub, DBUS_TYPE_DICT_ENTRY,
nullptr, &item);
240 dbus_message_iter_close_container(&sub, &item);
243 aui::dbus::iter_append(&item, k);
244 aui::dbus::iter_append(&item, v);
247 static AMap<K, V> iter_get(DBusMessageIter* iter) {
248 if (
auto got = dbus_message_iter_get_arg_type(iter); got != DBUS_TYPE_ARRAY) {
249 throw AException(
"type error: array expected, got '{:c}'"_format(got));
252 dbus_message_iter_recurse(iter, &sub);
256 AUI_ASSERT(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_DICT_ENTRY);
257 DBusMessageIter item;
258 dbus_message_iter_recurse(&sub, &item);
259 auto k = aui::dbus::iter_get<K>(&item);
260 if (!dbus_message_iter_next(&item)) {
263 auto v = aui::dbus::iter_get<V>(&item);
265 if (!dbus_message_iter_next(&sub))
break;
272 template<convertible... Types>
276 static void iter_append(DBusMessageIter* iter,
const std::tuple<Types...>& t) {
277 if (
auto got = dbus_message_iter_get_arg_type(iter); got != DBUS_TYPE_STRUCT) {
278 throw AException(
"type error: struct expected, got '{:c}'"_format(got));
282 dbus_message_iter_recurse(iter, &sub);
284 std::apply([&](
const auto&...
args){
285 (..., aui::dbus::iter_append(&sub,
args));
289 static std::tuple<Types...> iter_get(DBusMessageIter* iter) {
290 if (
auto got = dbus_message_iter_get_arg_type(iter); got != DBUS_TYPE_STRUCT) {
291 throw AException(
"type error: struct expected, got '{:c}'"_format(got));
295 dbus_message_iter_recurse(iter, &sub);
298 return aui::tuple_visitor<std::tuple<Types...>>::for_each_make_tuple([&]<
typename T>() {
302 auto v = aui::dbus::iter_get<T>(&sub);
303 hasNext = dbus_message_iter_next(&sub);
311 static inline std::string signature =
"v";
313 static void iter_append(DBusMessageIter* iter,
const Variant& t);
315 static Variant iter_get(DBusMessageIter* iter);
320 static inline std::string signature =
"";
322 static void iter_append(DBusMessageIter* iter,
const Unknown& t) {
327 static Unknown iter_get(DBusMessageIter* iter);
342 using AException::AException;
345 static ADBus& inst();
347 template<aui::dbus::convertible_or_void Return = void, aui::dbus::convertible... Args>
348 Return callBlocking(
const AString& bus,
352 const Args&...
args) {
359 auto formatError = [&](
const AString& info) {
360 return "unable to invoke {};{};{};{}: {}"_format(bus, path, interface, method, info);
367 DBusMessageIter dbusArgs;
368 dbus_message_iter_init_append(msg.get(), &dbusArgs);
370 aui::parameter_pack::for_each([&](
const auto& v) {
371 aui::dbus::iter_append(&dbusArgs, v);
375 DBusPendingCall* pending;
376 if (!dbus_connection_send_with_reply(mConnection, msg.get(), &pending, -1)) {
377 throw ADBus::Exception(formatError(
"dbus_connection_send_with_reply failed"));
380 }(), dbus_pending_call_unref);
383 dbus_pending_call_block(pending.get());
386 msg.reset(dbus_pending_call_steal_reply(pending.get()));
388 if (dbus_message_get_type(msg.get()) == DBUS_MESSAGE_TYPE_ERROR) {
389 if (
auto e = dbus_message_get_error_name(msg.get())) {
395 if constexpr (!std::is_void_v<Return>) {
396 if (!dbus_message_iter_init(msg.get(), &dbusArgs)) {
399 return aui::dbus::iter_get<Return>(&dbusArgs);
403 template<aui::not_overloaded_lambda Callback>
405 return addListener([
object = std::move(
object),
408 callback = std::forward<Callback>(callback)](DBusMessage* msg) {
409 if (dbus_message_is_signal(msg, DBUS_INTERFACE_LOCAL,
"Disconnected")) {
410 return DBUS_HANDLER_RESULT_HANDLED;
413 if (!dbus_message_is_signal(msg, interface.c_str(), signal.c_str())) {
414 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
417 if (
object != std::string_view(dbus_message_get_path(msg))) {
418 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
422 if constexpr (std::tuple_size_v<argz> > 0) {
423 DBusMessageIter dbusArgs;
424 if (!dbus_message_iter_init(msg, &dbusArgs)) {
433 auto v = aui::dbus::iter_get<T>(&dbusArgs);
434 hasNext = dbus_message_iter_next(&dbusArgs);
438 std::apply(callback, std::move(
args));
444 return DBUS_HANDLER_RESULT_HANDLED;
448 void processMessages();
451 struct RawMessageListener {
453 using Callback = std::function<DBusHandlerResult(DBusMessage* message)>;
456 std::list<RawMessageListener> mListeners;
457 aui::fast_pimpl<DBusError,
sizeof(
void*) * 3 + 20,
alignof(
void*)> mError;
458 DBusConnection* mConnection =
nullptr;
459 std::atomic_bool mProcessingScheduled =
false;
464 template <aui::invocable Callback>
465 void throwExceptionOnError(Callback&& callback);
466 std::function<void()> addListener(RawMessageListener::Callback listener);
467 static dbus_bool_t addWatch(DBusWatch* watch,
void* data);
469 static DBusHandlerResult listener(DBusConnection *connection,
470 DBusMessage *message,
471 void *user_data)
noexcept;
472 static void deleter(
void* userData)
noexcept;
Exception thrown on dbus errors.
Definition: ADBus.h:341
IPC on freedesktop linux.
Definition: ADBus.h:335
Abstract AUI exception.
Definition: AException.h:29
A std::map with AUI extensions.
Definition: AMap.h:218
Definition: ARaiiHelper.h:17
Represents a Unicode character string.
Definition: AString.h:37
std::string toStdString() const noexcept
Definition: AString.cpp:338
A std::vector with AUI extensions.
Definition: AVector.h:38
API_AUI_CORE const ACommandLineArgs & args() noexcept
Definition: OSAndroid.cpp:29
#define AUI_ASSERT(condition)
Asserts that the passed condition evaluates to true.
Definition: Assert.h:55
Utility wrapper implementing the stack-allocated (fast) pimpl idiom.
Definition: APimpl.h:31
Forbids copy of your class.
Definition: values.h:40
static _unique< T, Deleter > make_unique_with_deleter(T *ptr, Deleter deleter=Deleter{})
Creates unique_ptr from raw pointer and a deleter.
Definition: SharedPtrTypes.h:125
Definition: parameter_pack.h:76