urlResponse listener gets called multiple times if failed requesting

Hi, I implemented a threaded file downloader and it works well in general. but when it fails to download a file, the urlResponse listener gets called multiple times even after calling ofRemoveURLRequest(id);

Here’s my example code

URLSaver::URLSaver()
{
    ofAddListener(ofURLResponseEvent(), this, &URLSaver::urlResponse);
    startThread();
}

URLSaver::~URLSaver()
{
    commands.close();
    waitForThread(true);
    ofRemoveListener(ofURLResponseEvent(), this, &URLSaver::urlResponse);
}

void URLSaver::saveURL(const string &url, const string &path)
{
    ofURLSaverEntry entry;
    entry.url = url;
    entry.path = path;
    entry.shouldStop = false;
    commands.send(entry);
}

void URLSaver::clear()
{
    ofURLSaverEntry entry;
    entry.shouldStop = true;
    commands.send(entry);
}

void URLSaver::threadedFunction(){
    
    ofURLSaverEntry entry;
    
    while (commands.receive(entry)) {
        
        if (!entry.shouldStop)
            ofSaveURLAsync(entry.url, entry.path);
        else
            ofRemoveAllURLRequests();
    }
}

void URLSaver::urlResponse(ofHttpResponse &response)
{
    if (response.status == 200) {
        
        cout << "FILE DOWNLOAD SUCCESS" << endl;
    }
    else {

        cout << "FILE DOWNLOAD FAILED" << endl;
        ofRemoveURLRequest(response.request.getId());
    }
}

If the file is successfully downloaded, it prints “FILE DOWNLOAD SUCCESS” once as it should be.

But if it fails to download a file, it prints “FILE DOWNLOAD FAILED” multiple times (like 4~10 times). But I don’t understand why.

Is this normal? Any idea how to fix this? Thanks!

One thing, ofSaveURLAsync already runs in it’s own thread so there’s no need to use your own, if you want to use your own thread to have more control over invalidation or similar then use ofSaveURL instead otherwise just using ofSaveURLAsync from the main thread will do the same you are doing now,

When an URL fails, it’s re-added to the queue immediately but the notification happens in the main thread so you don’t have to deal with locking… which means that the url can get re-added a couple of times before you invalidate it

1 Like

Thank you so much @arturo.
I switched to using ofSaveURLTo() and now it seems to work well without the problem I had.

Here’s my new code.

URLSaver::URLSaver()
{
    startThread();
}

URLSaver::~URLSaver()
{
    commands.close();
    waitForThread(true);
}

void URLSaver::saveURL(const string &url, const string &path)
{
    ofURLSaverEntry entry;
    entry.url = url;
    entry.path = path;
    shouldClear = false;
    commands.send(entry);
}

void URLSaver::clear()
{
    ofURLSaverEntry entry;
    shouldClear = true;
    commands.send(entry);
}

void URLSaver::threadedFunction(){
    
    ofURLSaverEntry entry;
    
    while (commands.receive(entry)) {
        
        if (!shouldClear) {
            
            const ofHttpResponse &response = ofSaveURLTo(entry.url, entry.path);
            
            if (response.error == "OK") {
                
                cout << "FILE DOWNLOAD SUCCESS" << endl;
            }
            else {
                
                cout << "FILE DOWNLOAD FAILED" << endl;
            }
        }
        else {
            
            cout << "FILE DOWNLOAD CANCELED!!" << endl;
        }
        
    }
    
}