LeechCraft 0.6.70-18808-g3467692359
Modular cross-platform feature rich live environment.
Loading...
Searching...
No Matches
async.h
Go to the documentation of this file.
1/**********************************************************************
2 * LeechCraft - modular cross-platform feature rich internet client.
3 * Copyright (C) 2006-2014 Georg Rudoy
4 *
5 * Distributed under the Boost Software License, Version 1.0.
6 * (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt)
7 **********************************************************************/
8
9#pragma once
10
11#include <QDBusConnection>
12#include <QDBusPendingReply>
13#include <util/sll/qtutil.h>
14#include <util/sll/typegetter.h>
18#include "dbusconfig.h"
19
20namespace LC::Util::DBus
21{
22 struct Endpoint
23 {
24 QString Service;
25 QString Path;
26 QString Interface;
27 QDBusConnection Conn = QDBusConnection::sessionBus ();
28
29 UTIL_DBUS_API AsyncReply<QVariant> GetRawProperty (const QString& property) const;
31
32 template<typename T>
33 Task<Either<QDBusError, T>> GetProperty (QString property) const
34 {
35 const auto eitherPropVar = co_await GetRawProperty (property);
36 const QVariant propVar = co_await eitherPropVar;
37 if (!propVar.canConvert<T> ())
38 {
39 const auto& errorMsg = "Property `%1` expected type %2 but has type %3."_qs
40 .arg (property, QMetaType::fromType<T> ().name (), propVar.typeName ());
41 co_return Left { QDBusError { QDBusError::InvalidSignature, errorMsg } };
42 }
43
44 co_return propVar.value<T> ();
45 }
46
47 template<typename... Rets, typename... Args>
48 AsyncReply<Rets...> Call (const QString& method, Args&&... args) const
49 {
50 auto msg = QDBusMessage::createMethodCall (Service, Path, Interface, method);
51 msg.setArguments ({ std::forward<Args> (args)... });
52 return { Conn.asyncCall (msg) };
53 }
54 };
55
56 UTIL_DBUS_API AsyncReply<> StartService (const QDBusConnection& conn, const QString& name);
57
58 class UTIL_DBUS_API TypedSignals : public QObject
59 {
60 Q_OBJECT
61
62 Endpoint Endpoint_;
63
64 QHash<QString, QList<std::function<void (const QDBusMessage&)>>> Handlers_;
65 public:
66 explicit TypedSignals (Endpoint endpoint, QObject *parent)
67 : QObject { parent }
68 , Endpoint_ { std::move (endpoint) }
69 {
70 }
71
72 template<typename F>
73 bool Connect (const QString& name, F&& handler)
74 {
75 auto& handlers = Handlers_ [name];
76 if (handlers.isEmpty ())
77 {
78 const auto connected = Endpoint_.Conn.connect (Endpoint_.Service,
79 Endpoint_.Path,
80 Endpoint_.Interface,
81 name,
82 this,
83 SLOT (invokeHandlers (QDBusMessage)));
84 if (!connected)
85 return false;
86 }
87
88 auto unwrapper = [this, name, handler = std::forward<F> (handler)] (const QDBusMessage& msg)
89 {
90 [&, this]<size_t... Ixs> (std::index_sequence<Ixs...>)
91 {
92 QDBusPendingReply<std::decay_t<ArgType_t<F, Ixs>>...> payload { msg };
93 if (payload.isError ())
94 {
95 qWarning () << Endpoint_.Service << Endpoint_.Path << Endpoint_.Interface << name
96 << "mismatching arguments:" << payload.error ();
97 return;
98 }
99 handler (payload.template argumentAt<Ixs> ()...);
100 } (std::make_index_sequence<ArgCount_v<F>> {});
101 };
102 handlers << std::move (unwrapper);
103
104 return true;
105 }
106 private slots:
107 void invokeHandlers (const QDBusMessage& msg) const
108 {
109 const auto& name = msg.member ();
110 const auto& handlers = Handlers_ [name];
111 if (handlers.isEmpty ())
112 qWarning () << "no handlers for" << name;
113 for (const auto& handler : handlers)
114 handler (msg);
115 }
116 };
117
119 {
120 std::unique_ptr<TypedSignals> TypedSignals_ {};
121
122 template<typename F>
123 bool Connect (const QString& name, F&& handler)
124 {
125 if (!TypedSignals_)
126 TypedSignals_ = std::make_unique<TypedSignals> (*this, nullptr);
127 return TypedSignals_->Connect (name, std::forward<F> (handler));
128 }
129
130 template<std::derived_from<QObject> Ctx, typename C, typename R, typename... Args>
131 requires std::derived_from<Ctx, C>
132 bool Connect (const QString& name, Ctx *ctx, R (C::*handler) (Args...))
133 {
134 return Connect (name, [ctx, handler] (Args... args) { std::invoke (handler, ctx, args...); });
135 }
136 };
137}
TypedSignals(Endpoint endpoint, QObject *parent)
Definition async.h:66
bool Connect(const QString &name, F &&handler)
Definition async.h:73
#define UTIL_DBUS_API
Definition dbusconfig.h:16
AsyncReply StartService(const QDBusConnection &conn, const QString &name)
Definition async.cpp:36
UTIL_DBUS_API AsyncReply< QVariantMap > GetAllProperties() const
Definition async.cpp:26
UTIL_DBUS_API AsyncReply< QVariant > GetRawProperty(const QString &property) const
Definition async.cpp:16
AsyncReply< Rets... > Call(const QString &method, Args &&... args) const
Definition async.h:48
Task< Either< QDBusError, T > > GetProperty(QString property) const
Definition async.h:33
QDBusConnection Conn
Definition async.h:27
std::unique_ptr< TypedSignals > TypedSignals_
Definition async.h:120
bool Connect(const QString &name, F &&handler)
Definition async.h:123
bool Connect(const QString &name, Ctx *ctx, R(C::*handler)(Args...))
Definition async.h:132