Mathis
Mathis

Reputation: 53

Success callback Emscripten FETCH API in C++ class

I am working with WebAssembly and try to make an HTTPS request from C++. I have seen the solution of Emscripten FETCH API and tried to use it.

To test it, I created a Test class where I send the request like this :

void Test::sendRequest() {
    emscripten_fetch_attr_t attr;
    emscripten_fetch_attr_init(&attr);
    strcpy(attr.requestMethod, "GET");
    attr.attributes = EMSCRIPTEN_FETCH_LOAD_TO_MEMORY;
    attr.onsuccess = &Test::onSuccess;
    attr.onerror = &Test::onError;
    emscripten_fetch(&attr, "http://127.0.0.1:5000/");
}

And my onSuccess callback look like this :

void Test::onSuccess(struct emscripten_fetch_t *fetch) {
    printf("Finished downloading %llu bytes from URL %s.\n", fetch->numBytes, fetch->url);
    setText(QString::fromUtf8(fetch->data));
    emscripten_fetch_close(fetch); // Free data associated with the fetch.
}

But, when I try to compile I have an error saying :

error: assigning to 'void (*)(struct emscripten_fetch_t *)' from incompatible type 'void
  (Test::*)(struct emscripten_fetch_t *)'
attr.onsuccess = &Test::onSuccess;
                 ^~~~~~~~~~~~~~~~

It seems that I can't put the callback function in the class, but I need to access the class in order to modify the text attribute of the instance with the response.

I tried to define the Test class with the Singleton pattern and to remove the callback function from the class. With this method I can modify the text attribute getting the unique instance of the class but I would like to put callback function in the class directly if possible.

Upvotes: 2

Views: 1787

Answers (1)

molbdnilo
molbdnilo

Reputation: 66371

You can't use a non-static member function as a callback directly.

However, most callback interfaces have a "user data" field somewhere for communicating back to the originator.

emscripten_fetch_attr_t has a void* userData member where you can store any pointer you want.
This pointer is passed as userData in the argument to the callbacks, and you just need to cast it back to the correct type.

So you can use a free function as a wrapping callback, with the object as "user data":

void onSuccess(struct emscripten_fetch_t *fetch) {
    auto test = static_cast<Test*>(fetch->userData);
    test->onSuccess(fetch);
}

void Test::sendRequest() {
    emscripten_fetch_attr_t attr;
    emscripten_fetch_attr_init(&attr);
    strcpy(attr.requestMethod, "GET");
    attr.attributes = EMSCRIPTEN_FETCH_LOAD_TO_MEMORY;
    attr.userData = this;
    attr.onsuccess = onSuccess;
    // ...

And make sure that the object is alive when the callback fires.

Upvotes: 6

Related Questions