boblemaire / asyncHTTPrequest

asynchronous HTTP for ESP using ESPasyncTCP. Works like XMLHTTPrequest in JS.
GNU General Public License v3.0
64 stars 31 forks source link

Question: Use of Optional Argument in asyncHTTPRequest::onReadyStateChange() #26

Closed lbussy closed 4 years ago

lbussy commented 4 years ago

Bob,

I need to say I understand that this is my problem, not yours - I'm just hoping you have time to give me a pointer. This is sort of a follow-up to Question: Identifying Caller in Callback #25. Basically, I have 1-N request types which I might be using and hope to re-use a function that actually sends the data. The callback needs to know the calling function's context in order to meet my needs.

The plan was to pass a variable to the callback, and thereby identify which report it is that's being handled. The only way I am able to do this is by &reference. When I do that, the original variable goes out of scope from the caller. I can prove that by adding a delay() in my calling function so that it's still "alive" when the callback fires.

Here's my header:

#ifndef _MYASYNC_H
#define _MYASYNC_H

#include <asyncHTTPrequest.h>
#include <AsyncTCP.h>
#include <ArduinoLog.h>
#include <Arduino.h>

enum ReportKey
{
    MY_REPORT0,
    MY_REPORT1,
    MY_REPORT2,
    MY_REPORT3,
    MY_REPORT4
};

void sendRequest();
void requestCB(void *, asyncHTTPrequest *, int);

#endif // _MYASYNC_H

And the code:

#include "myAsync.h"

asyncHTTPrequest
    request0,
    request1,
    request2,
    request3,
    request4;

asyncHTTPrequest reports[5] = {
    request0,
    request1,
    request2,
    request3,
    request4
};

const char *reporttype[5] = {
    "request0",
    "request1",
    "request2",
    "request3",
    "request4"
};

const char *reportname[5] = {
    "Request 0",
    "Request 1",
    "Request 2",
    "Request 3",
    "Request 4"
};

void sendRequest()
{
    ReportKey reportkey = MY_REPORT0;
    //reports[reportkey].setDebug(true);
    Log.verbose(F("DEBUG: Sending: '%s' report (%d)." CR), reportname[reportkey], reportkey);
    reports[reportkey].onReadyStateChange(requestCB, &reportkey);
    if (reports[reportkey].readyState() == 0 || reports[reportkey].readyState() == 4)
    {
        reports[reportkey].open("GET", "http://1.1.1.1/");
        reports[reportkey].send();
    }
}

void requestCB(void *optParm, asyncHTTPrequest *request, int readyState)
{
    if (readyState == 4)
    {
        ReportKey reportkey = *(ReportKey*)optParm;
        // const int *__attribute__((unused)) reportkey = static_cast<const int *>(optParm);
        //const char *__attribute__((unused)) thisReport = (reportkey >= 0 && reportkey <= 4) ? reportname[reportkey] : "";
        const int __attribute__((unused)) code = (request->responseHTTPcode() >= 0 && request->responseHTTPcode() <= 599) ? request->responseHTTPcode() : 0;
        const int __attribute__((unused)) elapsed = (request->elapsedTime() >= 0) ? request->elapsedTime() : 0;
        const char *__attribute__((unused)) response = (request->responseText()) ? request->responseText().c_str(): "";

        Log.verbose(F("DEBUG: Return Code: %d, Elapsed: %d, reportkey: '%d'." CR), code, elapsed, reportkey);
    }
}

The results are (predictably) inconsistent:

    428858 V: DEBUG: Return Code: 301, Elapsed: 26, reportkey: '0'.
    433831 V: DEBUG: Sending: 'Request 0' report (0).
    433860 V: DEBUG: Return Code: 301, Elapsed: 27, reportkey: '397088'.
    438831 V: DEBUG: Sending: 'Request 0' report (0).
    438854 V: DEBUG: Return Code: 301, Elapsed: 22, reportkey: '1073431156'.
    443831 V: DEBUG: Sending: 'Request 0' report (0).
    443851 V: DEBUG: Return Code: 301, Elapsed: 19, reportkey: '0'.

I understand why, but since you have this functionality there I'm relatively certain what I need is possible and I'm just too dense to get it. Any assistance would be appreciated.

- Lee

lbussy commented 4 years ago

Well, I got around this by using a pointer function to the callbacks and then having the callbacks in turn call the handler. Seems inelegant but it is working.