169 lines
6.4 KiB
C++
169 lines
6.4 KiB
C++
#include "RestApiServer.h"
|
|
|
|
RestApiServer::RestApiServer(ClusterContext& ctx, uint16_t port) : server(port), ctx(ctx) {}
|
|
|
|
void RestApiServer::addEndpoint(const String& uri, int method, std::function<void(AsyncWebServerRequest*)> requestHandler) {
|
|
serviceRegistry.push_back(std::make_tuple(uri, method));
|
|
// Store in NodeInfo for local node
|
|
if (ctx.memberList && !ctx.memberList->empty()) {
|
|
(*ctx.memberList)[0].apiEndpoints.push_back(std::make_tuple(uri, method));
|
|
}
|
|
server.on(uri.c_str(), method, requestHandler);
|
|
}
|
|
|
|
void RestApiServer::addEndpoint(const String& uri, int method, std::function<void(AsyncWebServerRequest*)> requestHandler,
|
|
std::function<void(AsyncWebServerRequest*, const String&, size_t, uint8_t*, size_t, bool)> uploadHandler) {
|
|
serviceRegistry.push_back(std::make_tuple(uri, method));
|
|
if (ctx.memberList && !ctx.memberList->empty()) {
|
|
(*ctx.memberList)[0].apiEndpoints.push_back(std::make_tuple(uri, method));
|
|
}
|
|
server.on(uri.c_str(), method, requestHandler, uploadHandler);
|
|
}
|
|
|
|
void RestApiServer::begin() {
|
|
addEndpoint("/api/node/status", HTTP_GET,
|
|
std::bind(&RestApiServer::getSystemStatusJson, this, std::placeholders::_1));
|
|
addEndpoint("/api/cluster/members", HTTP_GET,
|
|
std::bind(&RestApiServer::getClusterMembersJson, this, std::placeholders::_1));
|
|
addEndpoint("/api/node/update", HTTP_POST,
|
|
std::bind(&RestApiServer::onFirmwareUpdateRequest, this, std::placeholders::_1),
|
|
std::bind(&RestApiServer::onFirmwareUpload, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5, std::placeholders::_6)
|
|
);
|
|
addEndpoint("/api/node/restart", HTTP_POST,
|
|
std::bind(&RestApiServer::onRestartRequest, this, std::placeholders::_1));
|
|
server.begin();
|
|
}
|
|
|
|
void RestApiServer::getSystemStatusJson(AsyncWebServerRequest *request) {
|
|
JsonDocument doc;
|
|
doc["freeHeap"] = ESP.getFreeHeap();
|
|
doc["chipId"] = ESP.getChipId();
|
|
doc["sdkVersion"] = ESP.getSdkVersion();
|
|
doc["cpuFreqMHz"] = ESP.getCpuFreqMHz();
|
|
doc["flashChipSize"] = ESP.getFlashChipSize();
|
|
JsonArray apiArr = doc["api"].to<JsonArray>();
|
|
for (const auto& entry : serviceRegistry) {
|
|
JsonObject apiObj = apiArr.add<JsonObject>();
|
|
apiObj["uri"] = std::get<0>(entry);
|
|
apiObj["method"] = std::get<1>(entry);
|
|
}
|
|
String json;
|
|
serializeJson(doc, json);
|
|
request->send(200, "application/json", json);
|
|
}
|
|
|
|
void RestApiServer::getClusterMembersJson(AsyncWebServerRequest *request) {
|
|
JsonDocument doc;
|
|
JsonArray arr = doc["members"].to<JsonArray>();
|
|
for (const auto& node : *ctx.memberList) {
|
|
JsonObject obj = arr.add<JsonObject>();
|
|
obj["hostname"] = node.hostname;
|
|
obj["ip"] = node.ip.toString();
|
|
obj["lastSeen"] = node.lastSeen;
|
|
obj["latency"] = node.latency;
|
|
obj["status"] = statusToStr(node.status);
|
|
obj["resources"]["freeHeap"] = node.resources.freeHeap;
|
|
obj["resources"]["chipId"] = node.resources.chipId;
|
|
obj["resources"]["sdkVersion"] = node.resources.sdkVersion;
|
|
obj["resources"]["cpuFreqMHz"] = node.resources.cpuFreqMHz;
|
|
obj["resources"]["flashChipSize"] = node.resources.flashChipSize;
|
|
JsonArray apiArr = obj["api"].to<JsonArray>();
|
|
for (const auto& endpoint : node.apiEndpoints) {
|
|
JsonObject apiObj = apiArr.add<JsonObject>();
|
|
apiObj["uri"] = std::get<0>(endpoint);
|
|
methodToStr(endpoint, apiObj);
|
|
}
|
|
}
|
|
String json;
|
|
serializeJson(doc, json);
|
|
request->send(200, "application/json", json);
|
|
}
|
|
|
|
void RestApiServer::methodToStr(const std::tuple<String, int> &endpoint, ArduinoJson::V742PB22::JsonObject &apiObj)
|
|
{
|
|
int method = std::get<1>(endpoint);
|
|
const char *methodStr = nullptr;
|
|
switch (method)
|
|
{
|
|
case HTTP_GET:
|
|
methodStr = "GET";
|
|
break;
|
|
case HTTP_POST:
|
|
methodStr = "POST";
|
|
break;
|
|
case HTTP_PUT:
|
|
methodStr = "PUT";
|
|
break;
|
|
case HTTP_DELETE:
|
|
methodStr = "DELETE";
|
|
break;
|
|
case HTTP_PATCH:
|
|
methodStr = "PATCH";
|
|
break;
|
|
default:
|
|
methodStr = "UNKNOWN";
|
|
break;
|
|
}
|
|
apiObj["method"] = methodStr;
|
|
}
|
|
|
|
void RestApiServer::onFirmwareUpdateRequest(AsyncWebServerRequest *request) {
|
|
bool hasError = !Update.hasError();
|
|
AsyncWebServerResponse *response = request->beginResponse(200, "application/json", hasError ? "{\"status\": \"OK\"}" : "{\"status\": \"FAIL\"}");
|
|
response->addHeader("Connection", "close");
|
|
request->send(response);
|
|
request->onDisconnect([]() {
|
|
Serial.println("[API] Restart device");
|
|
delay(10);
|
|
ESP.restart();
|
|
});
|
|
}
|
|
|
|
void RestApiServer::onFirmwareUpload(AsyncWebServerRequest *request, const String &filename, size_t index, uint8_t *data, size_t len, bool final) {
|
|
if (!index) {
|
|
Serial.print("[OTA] Update Start ");
|
|
Serial.println(filename);
|
|
Update.runAsync(true);
|
|
if(!Update.begin(request->contentLength(), U_FLASH)) {
|
|
Serial.println("[OTA] Update failed: not enough space");
|
|
Update.printError(Serial);
|
|
AsyncWebServerResponse *response = request->beginResponse(500, "application/json", "{\"status\": \"FAIL\"}");
|
|
response->addHeader("Connection", "close");
|
|
request->send(response);
|
|
return;
|
|
} else {
|
|
Update.printError(Serial);
|
|
}
|
|
}
|
|
if (!Update.hasError()){
|
|
if (Update.write(data, len) != len) {
|
|
Update.printError(Serial);
|
|
}
|
|
}
|
|
if (final) {
|
|
if (Update.end(true)) {
|
|
if(Update.isFinished()) {
|
|
Serial.print("[OTA] Update Success with ");
|
|
Serial.print(index + len);
|
|
Serial.println("B");
|
|
} else {
|
|
Serial.println("[OTA] Update not finished");
|
|
}
|
|
} else {
|
|
Serial.print("[OTA] Update failed: ");
|
|
Update.printError(Serial);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
void RestApiServer::onRestartRequest(AsyncWebServerRequest *request) {
|
|
AsyncWebServerResponse *response = request->beginResponse(200, "application/json", "{\"status\": \"restarting\"}");
|
|
response->addHeader("Connection", "close");
|
|
request->send(response);
|
|
request->onDisconnect([]() {
|
|
Serial.println("[API] Restart device");
|
|
delay(10);
|
|
ESP.restart();
|
|
});
|
|
} |