[Telepathy-commits] [telepathy-qt4/master] PendingHandles: Do not fail if one of the requested identifiers is valid.

Andre Moreira Magalhaes (andrunko) andre.magalhaes at collabora.co.uk
Tue Mar 24 09:36:28 PDT 2009


Added validIds, invalidIds methods.
---
 TelepathyQt4/Client/connection.cpp      |   29 +------
 TelepathyQt4/Client/pending-handles.cpp |  155 +++++++++++++++++++++++++++++--
 TelepathyQt4/Client/pending-handles.h   |    8 ++-
 tests/dbus/contacts.cpp                 |    4 +-
 4 files changed, 156 insertions(+), 40 deletions(-)

diff --git a/TelepathyQt4/Client/connection.cpp b/TelepathyQt4/Client/connection.cpp
index b25d89f..93ce159 100644
--- a/TelepathyQt4/Client/connection.cpp
+++ b/TelepathyQt4/Client/connection.cpp
@@ -1161,15 +1161,6 @@ PendingHandles *Connection::requestHandles(uint handleType, const QStringList &n
 
     PendingHandles *pending =
         new PendingHandles(this, handleType, names);
-    QDBusPendingCallWatcher *watcher =
-        new QDBusPendingCallWatcher(
-                mPriv->baseInterface->RequestHandles(handleType, names),
-                pending);
-
-    pending->connect(watcher,
-                     SIGNAL(finished(QDBusPendingCallWatcher *)),
-                     SLOT(onCallFinished(QDBusPendingCallWatcher *)));
-
     return pending;
 }
 
@@ -1223,24 +1214,8 @@ PendingHandles *Connection::referenceHandles(uint handleType, const UIntList &ha
         "of the handles -" << notYetHeld.size() << "to go";
 
     PendingHandles *pending =
-        new PendingHandles(this, handleType, handles, alreadyHeld);
-
-    if (!notYetHeld.isEmpty()) {
-        debug() << " Calling HoldHandles";
-
-        QDBusPendingCallWatcher *watcher =
-            new QDBusPendingCallWatcher(
-                    mPriv->baseInterface->HoldHandles(handleType, notYetHeld),
-                    pending);
-
-        pending->connect(watcher,
-                         SIGNAL(finished(QDBusPendingCallWatcher *)),
-                         SLOT(onCallFinished(QDBusPendingCallWatcher *)));
-    }
-    else {
-        debug() << " All handles already held, not calling HoldHandles";
-    }
-
+        new PendingHandles(this, handleType, handles,
+                alreadyHeld, notYetHeld);
     return pending;
 }
 
diff --git a/TelepathyQt4/Client/pending-handles.cpp b/TelepathyQt4/Client/pending-handles.cpp
index 7100736..af4b9ab 100644
--- a/TelepathyQt4/Client/pending-handles.cpp
+++ b/TelepathyQt4/Client/pending-handles.cpp
@@ -42,6 +42,14 @@ struct PendingHandles::Private
     UIntList handlesToReference;
     ReferencedHandles handles;
     ReferencedHandles alreadyHeld;
+
+    QStringList validNames;
+    QHash<QString, QPair<QString, QString> > invalidNames;
+
+    // one to one requests (ids)
+    QHash<QDBusPendingCallWatcher *, QString> idsForWatchers;
+    QHash<QString, uint> handlesForIds;
+    int requests;
 };
 
 PendingHandles::PendingHandles(Connection* connection, uint handleType, const QStringList& names)
@@ -53,9 +61,21 @@ PendingHandles::PendingHandles(Connection* connection, uint handleType, const QS
     mPriv->handleType = handleType;
     mPriv->isRequest = true;
     mPriv->namesRequested = names;
+    mPriv->requests = 0;
+
+    // try to request all handles at once
+    QDBusPendingCallWatcher *watcher =
+        new QDBusPendingCallWatcher(
+                connection->baseInterface()->RequestHandles(handleType, names),
+                this);
+    connect(watcher,
+            SIGNAL(finished(QDBusPendingCallWatcher *)),
+            SLOT(onCallFinished(QDBusPendingCallWatcher *)));
 }
 
-PendingHandles::PendingHandles(Connection* connection, uint handleType, const UIntList& handles, const UIntList& alreadyHeld)
+PendingHandles::PendingHandles(Connection *connection, uint handleType,
+        const UIntList &handles, const UIntList &alreadyHeld,
+        const UIntList &notYetHeld)
     : PendingOperation(connection), mPriv(new Private)
 {
     debug() << "PendingHandles(reference)";
@@ -65,11 +85,22 @@ PendingHandles::PendingHandles(Connection* connection, uint handleType, const UI
     mPriv->isRequest = false;
     mPriv->handlesToReference = handles;
     mPriv->alreadyHeld = ReferencedHandles(connection, handleType, alreadyHeld);
+    mPriv->requests = 0;
 
-    if (alreadyHeld == handles) {
+    if (notYetHeld.isEmpty()) {
         debug() << " All handles already held, finishing up instantly";
         mPriv->handles = mPriv->alreadyHeld;
         setFinished();
+    } else {
+        debug() << " Calling HoldHandles";
+
+        QDBusPendingCallWatcher *watcher =
+            new QDBusPendingCallWatcher(
+                    connection->baseInterface()->HoldHandles(handleType, notYetHeld),
+                    this);
+        connect(watcher,
+                SIGNAL(finished(QDBusPendingCallWatcher *)),
+                SLOT(onCallFinished(QDBusPendingCallWatcher *)));
     }
 }
 
@@ -103,6 +134,32 @@ const QStringList& PendingHandles::namesRequested() const
     return mPriv->namesRequested;
 }
 
+QStringList PendingHandles::validNames() const
+{
+    if (!isFinished()) {
+        warning() << "PendingHandles::validNames called before finished";
+        return QStringList();
+    } else if (!isValid()) {
+        warning() << "PendingHandles::validNames called when not valid";
+        return QStringList();
+    }
+
+    return mPriv->validNames;
+}
+
+QHash<QString, QPair<QString, QString> > PendingHandles::invalidNames() const
+{
+    if (!isFinished()) {
+        warning() << "PendingHandles::invalidNames called before finished";
+        return QHash<QString, QPair<QString, QString> >();
+    } else if (!isValid()) {
+        warning() << "PendingHandles::invalidNames called when not valid";
+        return QHash<QString, QPair<QString, QString> >();
+    }
+
+    return mPriv->invalidNames;
+}
+
 const UIntList& PendingHandles::handlesToReference() const
 {
     return mPriv->handlesToReference;
@@ -119,17 +176,41 @@ void PendingHandles::onCallFinished(QDBusPendingCallWatcher* watcher)
     if (mPriv->isRequest) {
         QDBusPendingReply<UIntList> reply = *watcher;
 
-        debug() << "Received reply to RequestHandles";
-
         if (reply.isError()) {
-            debug().nospace() << " Failure: error " << reply.error().name() << ": " << reply.error().message();
-            setFinishedWithError(reply.error());
+            if (mPriv->namesRequested.size() == 1) {
+                debug().nospace() << " Failure: error " <<
+                    reply.error().name() << ": " <<
+                    reply.error().message();
+
+                mPriv->invalidNames.insert(mPriv->namesRequested.first(),
+                        QPair<QString, QString>(reply.error().name(),
+                            reply.error().message()));
+                setFinishedWithError(reply.error());
+                connection()->handleRequestLanded(mPriv->handleType);
+                return;
+            }
+
+            // try to request one handles at a time
+            foreach (const QString &name, mPriv->namesRequested) {
+                QDBusPendingCallWatcher *watcher =
+                    new QDBusPendingCallWatcher(
+                            mPriv->connection->baseInterface()->RequestHandles(
+                                mPriv->handleType,
+                                QStringList() << name),
+                            this);
+                connect(watcher,
+                        SIGNAL(finished(QDBusPendingCallWatcher *)),
+                        SLOT(onRequestHandlesFinished(QDBusPendingCallWatcher *)));
+                mPriv->idsForWatchers.insert(watcher, name);
+            }
         } else {
-            mPriv->handles = ReferencedHandles(connection(), handleType(), reply.value());
+            debug() << "Received reply to RequestHandles";
+            mPriv->handles = ReferencedHandles(connection(),
+                    mPriv->handleType, reply.value());
+            mPriv->validNames.append(mPriv->namesRequested);
             setFinished();
+            connection()->handleRequestLanded(mPriv->handleType);
         }
-
-        connection()->handleRequestLanded(handleType());
     } else {
         QDBusPendingReply<void> reply = *watcher;
 
@@ -139,7 +220,8 @@ void PendingHandles::onCallFinished(QDBusPendingCallWatcher* watcher)
             debug().nospace() << " Failure: error " << reply.error().name() << ": " << reply.error().message();
             setFinishedWithError(reply.error());
         } else {
-            mPriv->handles = ReferencedHandles(connection(), handleType(), handlesToReference());
+            mPriv->handles = ReferencedHandles(connection(),
+                    mPriv->handleType, handlesToReference());
             setFinished();
         }
     }
@@ -147,5 +229,58 @@ void PendingHandles::onCallFinished(QDBusPendingCallWatcher* watcher)
     watcher->deleteLater();
 }
 
+void PendingHandles::onRequestHandlesFinished(QDBusPendingCallWatcher *watcher)
+{
+    QDBusPendingReply<UIntList> reply = *watcher;
+
+    Q_ASSERT(mPriv->idsForWatchers.contains(watcher));
+    QString id = mPriv->idsForWatchers.value(watcher);
+
+    debug() << "Received reply to RequestHandles(" << id << ")";
+
+    if (reply.isError()) {
+        debug().nospace() << " Failure: error " << reply.error().name() << ": "
+            << reply.error().message();
+        mPriv->invalidNames.insert(id,
+                QPair<QString, QString>(reply.error().name(),
+                    reply.error().message()));
+    } else {
+        Q_ASSERT(reply.value().size() == 1);
+        uint handle = reply.value().first();
+        mPriv->handlesForIds.insert(id, handle);
+    }
+
+    if (++mPriv->requests == mPriv->namesRequested.size()) {
+        if (mPriv->handlesForIds.size() == 0) {
+            // all requests failed
+            setFinishedWithError(reply.error());
+        } else {
+            // all requests either failed or finished successfully
+
+            // we need to return the handles in the same order as requested
+            UIntList handles;
+            foreach (const QString &name, mPriv->namesRequested) {
+                if (!mPriv->invalidNames.contains(name)) {
+                    Q_ASSERT(mPriv->handlesForIds.contains(name));
+                    handles.append(mPriv->handlesForIds.value(name));
+                    mPriv->validNames.append(name);
+                }
+            }
+            mPriv->handles = ReferencedHandles(connection(),
+                    mPriv->handleType, handles);
+
+            setFinished();
+        }
+
+        debug() << " namesRequested:" << mPriv->namesRequested;
+        debug() << " invalidNames  :" << mPriv->invalidNames;
+        debug() << " validNames    :" << mPriv->validNames;
+
+        connection()->handleRequestLanded(handleType());
+    }
+
+    watcher->deleteLater();
+}
+
 } // Telepathy::Client
 } // Telepathy
diff --git a/TelepathyQt4/Client/pending-handles.h b/TelepathyQt4/Client/pending-handles.h
index ec32955..f73e81e 100644
--- a/TelepathyQt4/Client/pending-handles.h
+++ b/TelepathyQt4/Client/pending-handles.h
@@ -131,6 +131,10 @@ public:
      */
     const QStringList& namesRequested() const;
 
+    QStringList validNames() const;
+
+    QHash<QString, QPair<QString, QString> > invalidNames() const;
+
     /**
      * If the operation was a reference (as returned by isReference()), returns
      * the handles which were to be referenced. Otherwise, returns an empty
@@ -156,12 +160,14 @@ public:
 
 private Q_SLOTS:
     void onCallFinished(QDBusPendingCallWatcher* watcher);
+    void onRequestHandlesFinished(QDBusPendingCallWatcher *watcher);
 
 private:
     friend class Connection;
 
     PendingHandles(Connection* connection, uint handleType, const QStringList& names);
-    PendingHandles(Connection* connection, uint handleType, const UIntList& handles, const UIntList& alreadyHeld);
+    PendingHandles(Connection *connection, uint handleType, const UIntList &handles,
+            const UIntList &alreadyHeld, const UIntList &notYetHeld);
 
     struct Private;
     friend struct Private;
diff --git a/tests/dbus/contacts.cpp b/tests/dbus/contacts.cpp
index aa1e57c..205989d 100644
--- a/tests/dbus/contacts.cpp
+++ b/tests/dbus/contacts.cpp
@@ -340,12 +340,12 @@ void TestContacts::testForIdentifiers()
                 SLOT(expectSuccessfulCall(Telepathy::Client::PendingOperation*))));
     QCOMPARE(mLoop->exec(), 1);
 
-    // A request with both valid and invalid IDs should also fail
+    // A request with both valid and invalid IDs should succeed
     fails = mConn->contactManager()->contactsForIdentifiers(invalidIDs + validIDs + invalidIDs);
     QVERIFY(connect(fails,
                 SIGNAL(finished(Telepathy::Client::PendingOperation*)),
                 SLOT(expectSuccessfulCall(Telepathy::Client::PendingOperation*))));
-    QCOMPARE(mLoop->exec(), 1);
+    QCOMPARE(mLoop->exec(), 0);
 
     // Go on to the meat: valid IDs
     PendingContacts *pending = mConn->contactManager()->contactsForIdentifiers(validIDs);
-- 
1.5.6.5




More information about the telepathy-commits mailing list