3

So I'm trying to enlist the use of ESPAsyncWebServer for a project, and due to the size of said project I'm refactoring my code into a bunch of different libraries. This is to be part of the Client Server handling section.

I've determined how to effectively pass the *request to separate functions for the purpose of cleaning my code up. I.E. Within my Libraries .cpp file

server->on("/heap", HTTP_GET, [this](AsyncWebServerRequest *request) { handleHeap(request); });

which fires:

void CServer::handleHeap(AsyncWebServerRequest *request) { request->send(200, "text/plain", String(ESP.getFreeHeap())); }

Where I'm running into an issue is trying to pass in my "Processor" function to the response for templating.

String CServer::processor(const String &var)
{
if (var == "locationLat")
return String(gps.location.lat());
return String();
}

void CServer::handleGPS(AsyncWebServerRequest *request)
{
request->send(SPIFFS, "/gps.htm", String(), processor);
}

error: no matching function for call to 'AsyncWebServerRequest::send(fs::FS&, const char [9], String, )

Trying to pass processor() in a Lambda also doesn't compile, because there isn't a parameter going in.

error: no matching function for call to 'CServer::processor()' request->send(SPIFFS, "/gps.htm", String(), [this] { processor(); });
^ lib\CServer\CServer.cpp:128:66: note:
candidate is: lib\CServer\CServer.cpp:108:8: note: String
CServer::processor(const String&)

sooo, how do I handle passing the required processor function, into my response parameters as instructed in the guide here?

For reference:

String processor(const String& var)
{
if(var == "HELLO_FROM_TEMPLATE")
return F("Hello world!");
return String();
}

// ...

//Send index.htm with template processor function
request->send(SPIFFS, "/index.htm", String(), false, processor);

Fine if its all in main.cpp, but that is not what I want to do!

Jarod42
  • 203,559
  • 14
  • 181
  • 302
  • I assume it works fine in `main` because it's a local function, whereas your `processor` function is a member function. I don't know for certain, but could you just wrap the parameter in a lambda? – Tas Jan 03 '20 at 08:38
  • Presumably you could add a string argument to your lambda and pass that to process? – Alan Birtles Jan 03 '20 at 08:41

2 Answers2

8

Since your processor function is a class method, you'll need to bind it with the implicit this argument.

We can find the callback typedef : typedef std::function<String(const String&)> AwsTemplateProcessor;

request->send(SPIFFS, "/index.htm", String(), false, [this](const String &var) -> String { return this->processor(var); });

The lambda here is taking a const String &var as parameter such as the AwsTemplateProcessor, and we precise the return type of the AwsTemplateProcessor function by writing -> String after the lambda prototype. By precising the parameters and the return type correctly the send method can relate the lambda to the std::function (AwsTemplateProcessor).

Lucas Gras
  • 961
  • 1
  • 7
  • 22
  • 1
    With the first method I'm getting the compilation error: 'placeholders' is not a namespace-name. The lambda works! It looks like the "-> String" portion made all the difference. Could you shed some light on what this portion of the lambda is doing? If you compare it to what @Jarod42 posted below (which the AWS function doesn't match)that appears to be the only difference. – Rockclimber399 Jan 03 '20 at 16:21
  • While it is compiling, I'm getting the following warning: lib\CServer\CServer.cpp:128:108: warning: no return statement in function returning non-void [-Wreturn-type] request->send(SPIFFS, "/gps.htm", String(), false, [this](const String &var) -> String { processor(var); }); and the template processor is not functioning, so I'm wondering if the return is getting lost somewhere? – Rockclimber399 Jan 03 '20 at 17:08
  • You need to return the processor in order to return the `String` in the lambda. `[this](const String &var) -> String { return processor(var); }` – Lucas Gras Jan 03 '20 at 17:12
  • 1
    This was the issue and makes sense. Functioning as expected now. Thank you! – Rockclimber399 Jan 03 '20 at 17:26
1

Make your method static, or call should be:

void CServer::handleGPS(AsyncWebServerRequest *request)
{
    request->send(SPIFFS, "/gps.htm", String(), [this](const String& var) { return processor(var); });
}
Jarod42
  • 203,559
  • 14
  • 181
  • 302