0

I am working on a wasm project where I need to define a empscripten fetch callback in a C++ header file, because I need to update a member variable. Can someone help me with how I define a callback function i C++, where I am able to update a local member variable?

In MyClass.CPP do I have the following method

void MyClass::Register()
{
    emscripten_fetch_attr_t attr;
    emscripten_fetch_attr_init(&attr);
    attr.onsuccess = DownloadSucceeded;
    attr.onerror = DownloadFailed;
}

I have defined DownloadSucceeded and DownloadFailed in my header file.

void DownloadSucceeded(emscripten_fetch_t* fetch)
{
    printf("Finished downloading %llu bytes from URL %s.\n", fetch->numBytes, fetch->url);
    emscripten_fetch_close(fetch); // Free data associated with the fetch.
    m_unlocked = true;
}

void DownloadFailed(emscripten_fetch_t* fetch)
{
    printf("Downloading %s failed, HTTP failure status code: %d.\n", fetch->url, fetch->status);
    emscripten_fetch_close(fetch); // Also free data on failure.
    m_unlocked = false;
}

I get the following exception:

reference to non-static member function must be called

From the above exception I tried to send a reference instead, but that didn't seem to work either. If some clever guy can explain why and how to solve this I would be grateful!

My naive reference example which does not work either:

attr.onsuccess = &DetectorBridge::DownloadSucceeded;

Gives:

assigning to 'void (*)(struct emscripten_fetch_t *)' from incompatible type 'void (mynamespace::MyClass::*)(emscripten_fetch_t *)'
DNRN
  • 2,397
  • 4
  • 30
  • 48
  • @john huh? It has `void *userData` member. – 273K Jul 06 '23 at 07:49
  • @273K Yes, I realise that now. It fooled me because the usual practise would be to put the user data pointer directly in the callback signature. I checked the emscriptem source and realised my mistake. – john Jul 06 '23 at 07:52
  • No. I'm simply just trying to update `m_locked` from the callback. Not sure where you get the `*void userData` from my question? – DNRN Jul 06 '23 at 07:53
  • @DNRN `userData` is the solution to your problem. – john Jul 06 '23 at 07:54
  • `emscripten` requires C-style callbacks. You cannot pass a non-static member function as a C-style callback. – n. m. could be an AI Jul 06 '23 at 07:59
  • Side note - don't define functions in header files unless they are `inline`. – john Jul 06 '23 at 07:59
  • Thanks. I normally implement them in the cpp file, but somehow these two flowed to the header.. – DNRN Jul 06 '23 at 08:04

1 Answers1

1

Looking at the emscriptem source it seems you need to do something like this, where you save your MyClass pointer to a field that emscriptem has designed for this purpose.

void MyClass::Register()
{
    emscripten_fetch_attr_t attr;
    emscripten_fetch_attr_init(&attr);
    attr.onsuccess = DownloadSucceeded;
    attr.onerror = DownloadFailed;
    attr.userData = this; // save this object
}

Then when you get the callback use that saved pointer to modify your variables

void DownloadSucceeded(emscripten_fetch_t* fetch)
{
    printf("Finished downloading %llu bytes from URL %s.\n", 
        fetch->numBytes, fetch->url);
    static_cast<MyClass*>(fetch->userData)->m_unlocked = true; // get saved object
    emscripten_fetch_close(fetch); // Free data associated with the fetch.
}

I'm ignoring the issue of access to the m_unlocked member variable, but if that is an issue there are the usual solutions.

john
  • 85,011
  • 4
  • 57
  • 81