2009-09-14 6 views
11

Con un proxy Qt DBus basato su QDbusAbstractInterface (tramite qdbusxml2cpp), qual è il modo migliore di gestire il servizio/oggetto che si desidera interfacciare per non essere disponibile quando si avvia? Nota: non mi interessa semplicemente conoscerlo (puoi usare BlahService.isValid() per scoprirlo); Voglio essere in grado di sapere se è valido, e sapere quando diventa valido, così posso cambiare stato (e trasmettere quel cambiamento di stato con un segnale), e su quel cambiamento di stato fare altre cose. Al contrario, voglio sapere quando non è più valido per ragioni simili.In attesa che un servizio DBus sia disponibile in Qt

Senza il monitoraggio dello stato del servizio:

#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? 
} 

Probabilmente abbiamo bisogno di guardare per NameOwnerChanged sull'oggetto di connessione DBus - a meno che il codice dbus del QT fa questo per noi - e poi quando otteniamo quello stato cambio di segnale e, se necessario, collegare o disconnettere i segnali dall'oggetto.

Tutti gli esempi che trovo o ignorano il problema o semplicemente escono se l'oggetto server non esiste e non si occupano di andare via. L'esempio Qt Car/Controller rileva almeno se il server si spegne e stampa "Disconnected" se isValid() diventa falso durante l'uso, ma è polling isValid().

Aggiunto:

noti che QtDbusAbtractInterface registra per passaggi di proprietà del server (NameOwnerChanged), e aggiornamenti IsValid() in caso di cambiamenti. Quindi sospetto che tu possa connettersi direttamente al segnale serverOwnerChanged per scoprire le modifiche alla proprietà e usarlo come indicatore per riprovare, anche se non sarai in grado di fidarti diValido perché potrebbe essere aggiornato prima o dopo aver ricevuto il segnale.

In alternativa (brutto) è possibile impostare un timer e il polling per isValid().

risposta

9

Ok, dal momento che nessuno rispondeva, ho trovato la risposta nel frattempo:

che si desidera guardare NameOwnerChanged:

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

e

void 
VcsApplicationController::serviceOwnerChanged(const QString &name, 
               const QString &oldOwner, 
               const QString &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(); 
     } 
    } 
} 

noti che ci può essere condizioni di gara con metodi su FooService all'interno di serviceOwnerChanged - Non sono ancora sicuro se sono un effetto collaterale del binding (dbus-C++ nel mio caso di test), o inerente alla progettazione di dbus (possibile - no on sulla mailing list dbus risponderà alla domanda). Se è una vera condizione di gara, puoi attendere su un segnale Ready()/qualunque, se controlli l'API DBus. Se non controlli l'altra estremità, puoi aggiungere un ritardo molto breve oppure puoi anche guardare AddMatch() per assicurarti che il nuovo proprietario abbia aggiunto una corrispondenza al nome.

+0

Io uso questa linea per ottenere solo il segnale per il servizio che desidero: 'QDBusConnection :: systemBus(). Connect (" org.freedesktop.DBus ","/org/freedesktop/DBus "," org.freedesktop. DBus ", " NameOwnerChanged ", QStringList() <<" org.freedesktop.Avahi "," sss ", this, SLOT (AvahiNameOwnerChanged (QString, QString, QString)))' Per quanto riguarda le condizioni di gara, I cancella la mia vecchia interfaccia e ne ottieni una nuova quando ottengo questo segnale. – Harvey

3

Con Qt 5.3, serviceOwnerChanged obsoleto. Utilizzare QDBusServiceWatcher che consente di guardare per un servizio specifico anziché tutti.