En attendant qu’un service DBus soit disponible dans Qt

Avec un proxy Qt DBus intégré à QDbusAbstractInterface (via qdbusxml2cpp), quel est le meilleur moyen de gérer le service / object que vous souhaitez interfacer pour ne pas être disponible au démarrage? Note: Je ne suis pas intéressé à le savoir simplement (vous pouvez utiliser BlahService.isValid () pour le découvrir); Je veux être en mesure de savoir si elle est valide et de savoir quand elle devient valide pour pouvoir changer d’état (et diffuser cet état avec un signal) et changer d’état sur d’autres choses. À l’inverse, je veux savoir quand ce n’est plus valable pour des raisons similaires.

Sans suivre l’état du service:

#define CONNECT_DBUS_SIG(x,y) connect(blah,SIGNAL(x),this,SLOT(y)) // FIX - should watch for service, and also handle it going away and // coming back blah = new BlahService("com.xyzzy.BlahService", "/com/xyzzy/BlahService", QDBusConnection::sessionBus(), this); if (!blah) return 0; if (blah.isValid()) { CONNECT_DBUS_SIG(foo(),Event_foo()); } else { // Since we aren't watching for registration, what can we do but exit? } 

Nous devons probablement surveiller NameOwnerChanged sur l’object de connexion DBus – à moins que le code dbus de QT ne le fasse pour nous – et ensuite, lorsque nous obtenons cet état, changez et si nécessaire connectez ou déconnectez les signaux de l’object.

Tous les exemples que je trouve ignorent le problème ou sortent simplement si l’object serveur n’existe pas et ne le traitent pas. L’exemple Car / Controller Qt remarque au moins si le serveur s’en va et imprime “Disconnected” si isValid () devient faux pendant l’utilisation, mais qu’il interroge isValid ().

Ajoutée:

Notez que QtDbusAbtractInterface enregistre les changements de propriété du serveur (NameOwnerChanged) et les mises à jour isValid () en cas de modification. Je pense donc que vous pouvez vous connecter directement à ce signal serverOwnerChanged pour connaître les modifications apscopes à la propriété et l’utiliser comme indicateur pour réessayer – même si vous ne pouvez pas faire confiance à isValid car il peut être mis à jour avant ou après votre signalement.

Alternativement (moche), vous pouvez configurer une timer et interroger isValid ().

Ok, puisque personne n’a répondu, j’ai trouvé la réponse entre-temps:

Vous voulez regarder NameOwnerChanged:

 // subscribe to notifications about when a service is registered/unregistered connect(QDBusConnection::sessionBus().interface(), SIGNAL(serviceOwnerChanged(QSsortingng,QSsortingng,QSsortingng)), this,SLOT(serviceOwnerChanged(QSsortingng,QSsortingng,QSsortingng))); 

et

 void VcsApplicationController::serviceOwnerChanged(const QSsortingng &name, const QSsortingng &oldOwner, const QSsortingng &newOwner) { Q_UNUSED(oldOwner); if (name == "com.foo.bar.FooService") { qLog(Whatever) << "serviceOwnerChanged" << name << oldOwner << newOwner; if (!newOwner.isEmpty()) { // New owner in town emit Initialized(); // or if you control the interface and both sides, you can wait for // a "Ready()" signal before declaring FooService ready for business. } else { // indicate we've lost connection, etc emit Uninitialized(); } } } 

Notez qu'il peut y avoir des conditions de concurrence avec les méthodes FooService dans serviceOwnerChanged - Je ne suis pas sûr si elles sont un effet secondaire de la liaison (dbus-c ++ dans mon scénario de test) ou inhérent à la conception de dbus (possible - non sur la liste de diffusion dbus répondra à la question). S'il existe une condition de concurrence réelle, vous pouvez attendre un signal Ready () / quel que soit le signal, si vous contrôlez l'API DBus. Si vous ne contrôlez pas l'autre extrémité, vous pouvez append un délai très court ou regarder AddMatch () pour vous assurer que le nouveau propriétaire a également ajouté une correspondance sur le nom.

Avec Qt 5.3, serviceOwnerChanged est obsolète. Utilisez QDBusServiceWatcher qui permet de surveiller un service spécifique au lieu de tous.