Browse Source

Reduce memory footprint of API calls (#1133)

pull/1135/head
Xose Pérez 5 years ago
parent
commit
373fc53545
4 changed files with 86 additions and 63 deletions
  1. +59
    -53
      code/espurna/api.ino
  2. +2
    -0
      code/espurna/config/prototypes.h
  3. +4
    -6
      code/espurna/relay.ino
  4. +21
    -4
      code/espurna/web.ino

+ 59
- 53
code/espurna/api.ino View File

@ -70,52 +70,6 @@ bool _asJson(AsyncWebServerRequest *request) {
return asJson;
}
ArRequestHandlerFunction _bindAPI(unsigned int apiID) {
return [apiID](AsyncWebServerRequest *request) {
webLog(request);
if (!_authAPI(request)) return;
web_api_t api = _apis[apiID];
// Check if its a PUT
if (api.putFn != NULL) {
if (request->hasParam("value", request->method() == HTTP_PUT)) {
AsyncWebParameter* p = request->getParam("value", request->method() == HTTP_PUT);
(api.putFn)((p->value()).c_str());
}
}
// Get response from callback
char value[API_BUFFER_SIZE] = {0};
(api.getFn)(value, API_BUFFER_SIZE);
// The response will be a 404 NOT FOUND if the resource is not available
if (0 == value[0]) {
DEBUG_MSG_P(PSTR("[API] Sending 404 response\n"));
request->send(404);
return;
}
DEBUG_MSG_P(PSTR("[API] Sending response '%s'\n"), value);
// Format response according to the Accept header
if (_asJson(request)) {
char buffer[64];
if (isNumber(value)) {
snprintf_P(buffer, sizeof(buffer), PSTR("{ \"%s\": %s }"), api.key, value);
} else {
snprintf_P(buffer, sizeof(buffer), PSTR("{ \"%s\": \"%s\" }"), api.key, value);
}
request->send(200, "application/json", buffer);
} else {
request->send(200, "text/plain", value);
}
};
}
void _onAPIs(AsyncWebServerRequest *request) {
webLog(request);
@ -172,24 +126,75 @@ void _onRPC(AsyncWebServerRequest *request) {
}
bool _apiRequestCallback(AsyncWebServerRequest *request) {
// Not API request
String url = request->url();
if (!url.startsWith("/api/")) return false;
for (unsigned char i=0; i < _apis.size(); i++) {
// Search API url
web_api_t api = _apis[i];
if (!url.endsWith(api.key)) continue;
// Log and check credentials
webLog(request);
if (!_authAPI(request)) return false;
// Check if its a PUT
if (api.putFn != NULL) {
if (request->hasParam("value", request->method() == HTTP_PUT)) {
AsyncWebParameter* p = request->getParam("value", request->method() == HTTP_PUT);
(api.putFn)((p->value()).c_str());
}
}
// Get response from callback
char value[API_BUFFER_SIZE] = {0};
(api.getFn)(value, API_BUFFER_SIZE);
// The response will be a 404 NOT FOUND if the resource is not available
if (0 == value[0]) {
DEBUG_MSG_P(PSTR("[API] Sending 404 response\n"));
request->send(404);
return false;
}
DEBUG_MSG_P(PSTR("[API] Sending response '%s'\n"), value);
// Format response according to the Accept header
if (_asJson(request)) {
char buffer[64];
if (isNumber(value)) {
snprintf_P(buffer, sizeof(buffer), PSTR("{ \"%s\": %s }"), api.key, value);
} else {
snprintf_P(buffer, sizeof(buffer), PSTR("{ \"%s\": \"%s\" }"), api.key, value);
}
request->send(200, "application/json", buffer);
} else {
request->send(200, "text/plain", value);
}
return true;
}
return false;
}
// -----------------------------------------------------------------------------
void apiRegister(const char * key, api_get_callback_f getFn, api_put_callback_f putFn) {
// Store it
web_api_t api;
char buffer[40];
snprintf_P(buffer, sizeof(buffer), PSTR("/api/%s"), key);
api.key = strdup(key);
api.getFn = getFn;
api.putFn = putFn;
_apis.push_back(api);
// Bind call
unsigned int methods = HTTP_GET;
if (putFn != NULL) methods += HTTP_PUT;
webServer()->on(buffer, methods, _bindAPI(_apis.size() - 1));
}
void apiSetup() {
@ -197,6 +202,7 @@ void apiSetup() {
webServer()->on("/rpc", HTTP_GET, _onRPC);
wsOnSendRegister(_apiWebSocketOnSend);
wsOnReceiveRegister(_apiWebSocketOnReceive);
webRequestRegister(_apiRequestCallback);
}
#endif // WEB_SUPPORT

+ 2
- 0
code/espurna/config/prototypes.h View File

@ -142,6 +142,8 @@ void nice_delay(unsigned long ms);
#define AsyncWebSocket void
#define AwsEventType void *
#endif
typedef std::function<bool(AsyncWebServerRequest *request)> web_request_callback_f;
void webRequestRegister(web_request_callback_f callback);
// -----------------------------------------------------------------------------
// WebSockets


+ 4
- 6
code/espurna/relay.ino View File

@ -632,11 +632,11 @@ void relaySetupWS() {
void relaySetupAPI() {
char key[20];
// API entry points (protected with apikey)
for (unsigned int relayID=0; relayID<relayCount(); relayID++) {
char key[20];
snprintf_P(key, sizeof(key), PSTR("%s/%d"), MQTT_TOPIC_RELAY, relayID);
apiRegister(key,
[relayID](char * buffer, size_t len) {
@ -680,9 +680,6 @@ void relaySetupAPI() {
_relays[relayID].pulse = relayStatus(relayID) ? RELAY_PULSE_ON : RELAY_PULSE_OFF;
relayToggle(relayID, true, false);
return;
}
);
@ -966,10 +963,11 @@ void relaySetup() {
// Dummy relays for AI Light, Magic Home LED Controller, H801,
// Sonoff Dual and Sonoff RF Bridge
#if DUMMY_RELAY_COUNT > 0
unsigned int _delay_on[8] = {RELAY1_DELAY_ON, RELAY2_DELAY_ON, RELAY3_DELAY_ON, RELAY4_DELAY_ON, RELAY5_DELAY_ON, RELAY6_DELAY_ON, RELAY7_DELAY_ON, RELAY8_DELAY_ON};
unsigned int _delay_off[8] = {RELAY1_DELAY_OFF, RELAY2_DELAY_OFF, RELAY3_DELAY_OFF, RELAY4_DELAY_OFF, RELAY5_DELAY_OFF, RELAY6_DELAY_OFF, RELAY7_DELAY_OFF, RELAY8_DELAY_OFF};
for (unsigned char i=0; i < DUMMY_RELAY_COUNT; i++) {
_relays.push_back((relay_t) {0, RELAY_TYPE_NORMAL,0,_delay_on[i], _delay_off[i]});
_relays.push_back((relay_t) {0, RELAY_TYPE_NORMAL,0,_delay_on[i], _delay_off[i]});
}
#else


+ 21
- 4
code/espurna/web.ino View File

@ -45,6 +45,8 @@ char _last_modified[50];
std::vector<uint8_t> * _webConfigBuffer;
bool _webConfigSuccess = false;
std::vector<web_request_callback_f> _web_request_callbacks;
// -----------------------------------------------------------------------------
// HOOKS
// -----------------------------------------------------------------------------
@ -326,6 +328,19 @@ void _onUpgradeData(AsyncWebServerRequest *request, String filename, size_t inde
}
}
void _onRequest(AsyncWebServerRequest *request){
// Send request to subscribers
for (unsigned char i = 0; i < _web_request_callbacks.size(); i++) {
bool response = (_web_request_callbacks[i])(request);
if (response) return;
}
// No subscriber handled the request, return a 404
request->send(404);
}
// -----------------------------------------------------------------------------
bool webAuthenticate(AsyncWebServerRequest *request) {
@ -345,6 +360,10 @@ AsyncWebServer * webServer() {
return _server;
}
void webRequestRegister(web_request_callback_f callback) {
_web_request_callbacks.push_back(callback);
}
unsigned int webPort() {
#if ASYNC_TCP_SSL_ENABLED & WEB_SSL_ENABLED
return 443;
@ -389,10 +408,8 @@ void webSetup() {
});
#endif
// 404
_server->onNotFound([](AsyncWebServerRequest *request){
request->send(404);
});
// Handle other requests, including 404
_server->onNotFound(_onRequest);
// Run server
#if ASYNC_TCP_SSL_ENABLED & WEB_SSL_ENABLED


Loading…
Cancel
Save