File indexing completed on 2024-12-01 04:33:00

0001 /**
0002  * SPDX-FileCopyrightText: 2013 Albert Vaca <albertvaka@gmail.com>
0003  *
0004  * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0005  */
0006 
0007 #include "responsewaiter.h"
0008 
0009 #include <QCoreApplication>
0010 #include <QDBusPendingCall>
0011 #include <QDBusPendingReply>
0012 #include <QDebug>
0013 
0014 Q_DECLARE_METATYPE(QDBusPendingReply<>)
0015 Q_DECLARE_METATYPE(QDBusPendingReply<QVariant>)
0016 Q_DECLARE_METATYPE(QDBusPendingReply<bool>)
0017 Q_DECLARE_METATYPE(QDBusPendingReply<int>)
0018 Q_DECLARE_METATYPE(QDBusPendingReply<QString>)
0019 
0020 DBusResponseWaiter *DBusResponseWaiter::m_instance = nullptr;
0021 
0022 DBusResponseWaiter *DBusResponseWaiter::instance()
0023 {
0024     if (!m_instance) {
0025         m_instance = new DBusResponseWaiter();
0026     }
0027     return m_instance;
0028 }
0029 
0030 DBusResponseWaiter::DBusResponseWaiter()
0031     : QObject()
0032 {
0033     m_registered << qRegisterMetaType<QDBusPendingReply<>>("QDBusPendingReply<>")
0034                  << qRegisterMetaType<QDBusPendingReply<QVariant>>("QDBusPendingReply<QVariant>")
0035                  << qRegisterMetaType<QDBusPendingReply<bool>>("QDBusPendingReply<bool>") << qRegisterMetaType<QDBusPendingReply<int>>("QDBusPendingReply<int>")
0036                  << qRegisterMetaType<QDBusPendingReply<QString>>("QDBusPendingReply<QString>");
0037 }
0038 
0039 QVariant DBusResponseWaiter::waitForReply(QVariant variant) const
0040 {
0041     if (QDBusPendingCall *call = const_cast<QDBusPendingCall *>(extractPendingCall(variant))) {
0042         call->waitForFinished();
0043 
0044         if (call->isError()) {
0045             qWarning() << "error:" << call->error();
0046             return QVariant(QStringLiteral("error"));
0047         }
0048 
0049         QDBusMessage reply = call->reply();
0050 
0051         if (reply.arguments().count() > 0) {
0052             return reply.arguments().at(0);
0053         }
0054     }
0055     return QVariant();
0056 }
0057 
0058 DBusAsyncResponse::DBusAsyncResponse(QObject *parent)
0059     : QObject(parent)
0060     , m_autodelete(false)
0061 {
0062     m_timeout.setSingleShot(true);
0063     m_timeout.setInterval(15000);
0064     connect(&m_timeout, &QTimer::timeout, this, &DBusAsyncResponse::onTimeout);
0065 }
0066 
0067 void DBusAsyncResponse::setPendingCall(QVariant variant)
0068 {
0069     if (QDBusPendingCall *call = const_cast<QDBusPendingCall *>(DBusResponseWaiter::instance()->extractPendingCall(variant))) {
0070         QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(*call);
0071         watcher->setProperty("pengingCallVariant", variant);
0072         connect(watcher, &QDBusPendingCallWatcher::finished, this, &DBusAsyncResponse::onCallFinished);
0073         connect(watcher, &QDBusPendingCallWatcher::finished, watcher, &QObject::deleteLater);
0074         connect(&m_timeout, &QTimer::timeout, watcher, &QObject::deleteLater);
0075         m_timeout.start();
0076     }
0077 }
0078 
0079 void DBusAsyncResponse::onCallFinished(QDBusPendingCallWatcher *watcher)
0080 {
0081     m_timeout.stop();
0082     QVariant variant = watcher->property("pengingCallVariant");
0083 
0084     if (QDBusPendingCall *call = const_cast<QDBusPendingCall *>(DBusResponseWaiter::instance()->extractPendingCall(variant))) {
0085         if (call->isError()) {
0086             Q_EMIT error(call->error().message());
0087         } else {
0088             QDBusMessage reply = call->reply();
0089 
0090             if (reply.arguments().count() > 0) {
0091                 Q_EMIT success(reply.arguments().at(0));
0092             } else {
0093                 Q_EMIT success(QVariant());
0094             }
0095         }
0096     }
0097     if (m_autodelete) {
0098         deleteLater();
0099     }
0100 }
0101 
0102 void DBusAsyncResponse::onTimeout()
0103 {
0104     Q_EMIT error(QStringLiteral("timeout when waiting dbus response!"));
0105 }
0106 
0107 const QDBusPendingCall *DBusResponseWaiter::extractPendingCall(QVariant &variant) const
0108 {
0109     for (int type : qAsConst(m_registered)) {
0110         if (variant.canConvert(QVariant::Type(type))) {
0111             return reinterpret_cast<const QDBusPendingCall *>(variant.constData());
0112         }
0113     }
0114 
0115     return nullptr;
0116 }
0117 
0118 #include "moc_responsewaiter.cpp"