shadyabhi
shadyabhi

Reputation: 17234

Wait for a SLOT to finish

I use QNetworkAccessManager to do form POST.

I have connected signals and slots as:

connect(manager,SIGNAL(finished(QNetworkReply*)),this,SLOT(readCookies(QNetworkReply*)));

Now, I make a request by doing:

manager->post(request,postData);

Now readCookies(QNetworkReply *) will be run as soon as SIGNAL is emitted. Now, using the Cookies which I get in this slot, I have to make one more POST..

As signals & slots are asynchronous, I want to wait till I get the cookies from my first POST and then I again want to do another post using the cookies I got in first POST like

//Setting new request, headers etc...
manager->post(request2,postData2);

I want the later to always be executed after first one has executed (so that I get proper cookies value).

What is the way to go? I am new to all these SIGNALS & SLOTS so please bear with me.

Upvotes: 4

Views: 2950

Answers (3)

Frank Osterfeld
Frank Osterfeld

Reputation: 25165

You can do the post in your readCookies() slot:

void readCookies( QNetworkReply* reply ) {
    if ( ...error? ) {
        report error...
        return;
    }

    ...
    manager->post(request2,postData2);
}

I will be called when the cookies is read, and you can then continue with your post. Connect that to a second slot, and so on. Managing multiple, possibly parallely running asynchronous operations like this can become errorprone though, if you manage many of them in a single object. I would suggest to use the Command Pattern - here I described why I find it extremely useful in exactly this context. The sequence of request and asnychronous operations is encapsulated in a single object (abbreviated, with some pseudo-code):

class PostStuffOperation : public QObject {
    Q_OBJECT
public:
    enum Error {
       NoError=0,
       Error=1,
       ...
    };

    Error error() const; //operation successful or not?
    QString errorString() const; //human-readable error description

    ... setters for all the information the operation needs
    ...
    void start() {
       ...start your first request and connect it to cookiesRead 
    }

public Q_SLOTS:
    void cookiesRead( QNetworkReply * ) {
    if ( error ) {
       // set error and errorString...
       emit finished( this ); //couldn't read cookies, so the operation fails
       return;
    }
    ... do post
 }

 void postFinished( QNetworkReply* ) {
     if ( error ) {
         // set error and errorString...
     }

    emit finished( this ); //post finished - that means the whole operation finished
 }
Q_SIGNALS:
    void finished( PostStuffOperation* );
};

To start the operation, you do

PostStuffOperation op* = new PostStuffOperation( this );
... pass data like server, port etc. to the operation
connect( op, SIGNAL(finished()), this, SLOT(postOperationFinished()) );
op->start();

void postOperationFinished( PostStuffOperation* op ) {
    if ( op->error != PostStuffOperation::NoError ) {
        //handle error, e.g. show message box
    }
}

It makes sense to have a common baseclass for such operations, see e.g. KDE's KJob.

Upvotes: 4

Gunther Piez
Gunther Piez

Reputation: 30449

You can send a second signal connected to another slot (the resend slot), if you have finished the evaluation of your first cookie. You can do that directly in the slot. You can also call slots like a normal member function.

Upvotes: 0

Patrice Bernassola
Patrice Bernassola

Reputation: 14446

You can connect a signal from this to a slot from your manager and emit the signal after reading the cookies. By example:

connect(this, SIGNAL(cookiesRead()), manager, SLOT(PostAgain());

So your readCookies function will be:

{
   // Read cookies
   emit cookiesRead();
}

Of course you can send all data you want form signal to slot.

Hope that helps

Upvotes: 4

Related Questions