Removes PsychicHttp dependency

This commit is contained in:
Rune Harlyk
2026-01-22 22:20:13 +01:00
committed by Rune Harlyk
parent 0b8e060063
commit 64199ac1a3
22 changed files with 256 additions and 413 deletions
+4 -3
View File
@@ -1,3 +1,5 @@
#pragma once
#include <template/stateful_service.h>
#include <template/stateful_endpoint.h>
#include <template/stateful_persistence.h>
@@ -16,14 +18,13 @@ class APService : public StatefulService<APSettings> {
void loop();
void recoveryMode();
esp_err_t getStatus(PsychicRequest *request);
esp_err_t getStatus(httpd_req_t *request);
void status(JsonObject &root);
APNetworkStatus getAPNetworkStatus();
StatefulHttpEndpoint<APSettings> endpoint;
private:
PsychicHttpServer *_server;
FSPersistence<APSettings> _persistence;
DNSServer *_dnsServer;
@@ -37,4 +38,4 @@ class APService : public StatefulService<APSettings> {
void startAP();
void stopAP();
void handleDNS();
};
};
@@ -1,28 +0,0 @@
#pragma once
#include <PsychicHttp.h>
#include <template/stateful_service.h>
#include <list>
#include <map>
#include <vector>
#include <string>
#include <communication/comm_base.hpp>
class Websocket : public CommAdapterBase {
public:
Websocket(PsychicHttpServer &server, const char *route = "/api/ws");
void begin() override;
private:
PsychicWebSocketHandler socket_;
PsychicHttpServer &server_;
const char *route_;
void onWSOpen(PsychicWebSocketClient *client);
void onWSClose(PsychicWebSocketClient *client);
esp_err_t onFrame(PsychicWebSocketRequest *request, httpd_ws_frame *frame);
void send(const uint8_t *data, size_t len, int cid = -1) override;
};
+2 -11
View File
@@ -2,52 +2,43 @@
#include <WiFi.h>
#include <ArduinoJson.h>
#include <PsychicHttp.h>
#include <esp_http_server.h>
#include "platform_shared/message.pb.h"
#define FT_ENABLED(feature) feature
// ESP32 camera off by default
#ifndef USE_CAMERA
#define USE_CAMERA 0
#endif
// ESP32 IMU on by default
#ifndef USE_MPU6050
#define USE_MPU6050 0
#endif
// ESP32 IMU on by default
#ifndef USE_BNO055
#define USE_BNO055 1
#endif
// ESP32 magnetometer on by default
#ifndef USE_HMC5883
#define USE_HMC5883 0
#endif
// ESP32 barometer off by default
#ifndef USE_BMP180
#define USE_BMP180 0
#endif
// ESP32 SONAR off by default
#ifndef USE_USS
#define USE_USS 0
#endif
// PCA9685 Servo controller on by default
#ifndef USE_PCA9685
#define USE_PCA9685 1
#endif
// WS2812 LED strip off by default
#ifndef USE_WS2812
#define USE_WS2812 0
#endif
// ESP32 MDNS on by default
#ifndef USE_MDNS
#define USE_MDNS 1
#endif
@@ -78,6 +69,6 @@ void features(JsonObject& root);
void features_request(const socket_message_FeaturesDataRequest& fd_req, socket_message_FeaturesDataResponse& fd_res);
esp_err_t getFeatures(PsychicRequest* request);
esp_err_t getFeatures(httpd_req_t* request);
} // namespace feature_service
+8 -11
View File
@@ -1,7 +1,7 @@
#pragma once
#include <PsychicHttp.h>
#include <esp_http_server.h>
#include <ArduinoJson.h>
#include <LittleFS.h>
#include <string>
@@ -16,18 +16,15 @@
#define MDNS_SETTINGS_FILE "/config/mdnsSettings.json"
namespace FileSystem {
extern PsychicUploadHandler *uploadHandler;
std::string listFiles(const std::string &directory, bool isRoot = true);
bool deleteFile(const char *filename);
bool editFile(const char *filename, const char *content);
esp_err_t uploadFile(PsychicRequest *request, const std::string &filename, uint64_t index, uint8_t *data, size_t len,
bool last);
esp_err_t getFiles(PsychicRequest *request);
esp_err_t getConfigFile(PsychicRequest *request);
esp_err_t handleDelete(PsychicRequest *request, JsonVariant &json);
esp_err_t handleEdit(PsychicRequest *request, JsonVariant &json);
esp_err_t getFiles(httpd_req_t *request);
esp_err_t getConfigFile(httpd_req_t *request);
esp_err_t handleDelete(httpd_req_t *request, JsonVariant &json);
esp_err_t handleEdit(httpd_req_t *request, JsonVariant &json);
esp_err_t mkdir(httpd_req_t *request, JsonVariant &json);
esp_err_t mkdir(PsychicRequest *request, JsonVariant &json);
} // namespace FileSystem
} // namespace FileSystem
+5 -4
View File
@@ -1,6 +1,7 @@
#pragma once
#include <PsychicHttp.h>
#include <esp_http_server.h>
#include <ArduinoJson.h>
#include <ESPmDNS.h>
#include <template/stateful_service.h>
#include <template/stateful_endpoint.h>
@@ -25,10 +26,10 @@ class MDNSService : public StatefulService<MDNSSettings> {
void begin();
esp_err_t getStatus(PsychicRequest *request);
esp_err_t getStatus(httpd_req_t *request);
void getStatus(JsonVariant &root);
static esp_err_t queryServices(PsychicRequest *request, JsonVariant &json);
static esp_err_t queryServices(httpd_req_t *request, JsonVariant &json);
StatefulHttpEndpoint<MDNSSettings> endpoint;
};
};
+3 -4
View File
@@ -1,9 +1,8 @@
#pragma once
#include <ArduinoJson.h>
#include <PsychicHttp.h>
#include <esp_http_server.h>
#include <WiFi.h>
#include <async_worker.h>
#include <features.h>
#include <template/stateful_persistence.h>
@@ -31,8 +30,8 @@ class CameraService : public StatefulService<CameraSettings> {
esp_err_t begin();
esp_err_t cameraStill(PsychicRequest *request);
esp_err_t cameraStream(PsychicRequest *request);
esp_err_t cameraStill(httpd_req_t *request);
esp_err_t cameraStream(httpd_req_t *request);
StatefulHttpEndpoint<CameraSettings> endpoint;
@@ -2,7 +2,6 @@
#define ServoController_h
#include <Adafruit_PWMServoDriver.h>
#include <communication/websocket_adapter.h>
#include <template/stateful_persistence.h>
#include <template/stateful_service.h>
#include <template/stateful_endpoint.h>
+5 -5
View File
@@ -1,7 +1,7 @@
#pragma once
#include <ESPmDNS.h>
#include <PsychicHttp.h>
#include <esp_http_server.h>
#include <WiFi.h>
#include <filesystem.h>
#include <global.h>
@@ -13,9 +13,9 @@
#include "platform_shared/message.pb.h"
namespace system_service {
esp_err_t handleReset(PsychicRequest *request);
esp_err_t handleRestart(PsychicRequest *request);
esp_err_t handleSleep(PsychicRequest *request);
esp_err_t handleReset(httpd_req_t *request);
esp_err_t handleRestart(httpd_req_t *request);
esp_err_t handleSleep(httpd_req_t *request);
void reset();
void restart();
@@ -25,4 +25,4 @@ void getAnalytics(socket_message_AnalyticsData &analytics);
void getStaticSystemInformation(socket_message_StaticSystemInformation &info);
const char *resetReason(esp_reset_reason_t reason);
} // namespace system_service
} // namespace system_service
+16 -17
View File
@@ -1,7 +1,9 @@
#pragma once
#include <PsychicHttp.h>
#include <esp_http_server.h>
#include <ArduinoJson.h>
#include <template/stateful_service.h>
#include <communication/native_server.h>
#include <functional>
@@ -20,29 +22,26 @@ class StatefulHttpEndpoint {
StatefulService<T> *statefulService)
: _stateReader(stateReader), _stateUpdater(stateUpdater), _statefulService(statefulService) {}
esp_err_t handleStateUpdate(PsychicRequest *request, JsonVariant &json) {
esp_err_t handleStateUpdate(httpd_req_t *request, JsonVariant &json) {
JsonVariant jsonObject = json.as<JsonVariant>();
StateUpdateResult outcome = _statefulService->updateWithoutPropagation(jsonObject, _stateUpdater);
if (outcome == StateUpdateResult::ERROR)
return request->reply(400);
else if ((outcome == StateUpdateResult::CHANGED)) {
// persist the changes to the FS
if (outcome == StateUpdateResult::ERROR) {
return NativeServer::sendError(request, 400, "Invalid state");
} else if ((outcome == StateUpdateResult::CHANGED)) {
_statefulService->callUpdateHandlers(HTTP_ENDPOINT_ORIGIN_ID);
}
PsychicJsonResponse response = PsychicJsonResponse(request, false);
jsonObject = response.getRoot();
_statefulService->read(jsonObject, _stateReader);
return response.send();
JsonDocument doc;
JsonVariant root = doc.to<JsonVariant>();
_statefulService->read(root, _stateReader);
return NativeServer::sendJson(request, 200, doc);
}
esp_err_t getState(PsychicRequest *request) {
PsychicJsonResponse response = PsychicJsonResponse(request, false);
JsonVariant jsonObject = response.getRoot();
_statefulService->read(jsonObject, _stateReader);
return response.send();
esp_err_t getState(httpd_req_t *request) {
JsonDocument doc;
JsonVariant root = doc.to<JsonVariant>();
_statefulService->read(root, _stateReader);
return NativeServer::sendJson(request, 200, doc);
}
};
+5 -5
View File
@@ -1,6 +1,6 @@
#pragma once
#include <PsychicHttp.h>
#include <esp_http_server.h>
#include <WiFi.h>
#include <ESPmDNS.h>
#include <string>
@@ -43,9 +43,9 @@ class WiFiService : public StatefulService<WiFiSettings> {
const char *getHostname() { return state().hostname.c_str(); }
static esp_err_t handleScan(PsychicRequest *request);
static esp_err_t getNetworks(PsychicRequest *request);
static esp_err_t getNetworkStatus(PsychicRequest *request);
static esp_err_t handleScan(httpd_req_t *request);
static esp_err_t getNetworks(httpd_req_t *request);
static esp_err_t getNetworkStatus(httpd_req_t *request);
StatefulHttpEndpoint<WiFiSettings> endpoint;
};
};
+2 -2
View File
@@ -1,5 +1,5 @@
#pragma once
#include <PsychicHttp.h>
#include <communication/native_server.h>
#include "WWWData.h"
void mountStaticAssets(PsychicHttpServer& s);
void mountStaticAssets(NativeServer& s);
+7 -6
View File
@@ -1,4 +1,5 @@
#include <ap_service.h>
#include <communication/native_server.h>
static const char *TAG = "APService";
@@ -12,11 +13,11 @@ APService::~APService() {}
void APService::begin() { _persistence.readFromFS(); }
esp_err_t APService::getStatus(PsychicRequest *request) {
PsychicJsonResponse response = PsychicJsonResponse(request, false);
JsonObject root = response.getRoot();
esp_err_t APService::getStatus(httpd_req_t *request) {
JsonDocument doc;
JsonObject root = doc.to<JsonObject>();
status(root);
return response.send();
return NativeServer::sendJson(request, 200, doc);
}
void APService::status(JsonObject &root) {
@@ -73,7 +74,7 @@ void APService::startAP() {
WiFi.softAP(state().ssid.c_str(), state().password.c_str(), state().channel, state().ssidHidden,
state().maxClients);
#if CONFIG_IDF_TARGET_ESP32C3
WiFi.setTxPower(WIFI_POWER_8_5dBm); // https://www.wemos.cc/en/latest/c3/c3_mini_1_0_0.html#about-wifi
WiFi.setTxPower(WIFI_POWER_8_5dBm);
#endif
if (!_dnsServer) {
IPAddress apIp = WiFi.softAPIP();
@@ -98,4 +99,4 @@ void APService::handleDNS() {
if (_dnsServer) {
_dnsServer->processNextRequest();
}
}
}
@@ -1,47 +0,0 @@
#include <communication/websocket_adapter.h>
static const char* TAG = "Websocket";
Websocket::Websocket(PsychicHttpServer& server, const char* route) : server_(server), route_(route) {
socket_.onOpen(std::bind(&Websocket::onWSOpen, this, std::placeholders::_1));
socket_.onClose(std::bind(&Websocket::onWSClose, this, std::placeholders::_1));
socket_.onFrame(std::bind(&Websocket::onFrame, this, std::placeholders::_1, std::placeholders::_2));
}
void Websocket::begin() { server_.on(route_, &socket_); }
void Websocket::onWSOpen(PsychicWebSocketClient* client) {
ESP_LOGI(TAG, "Client connected: %s [%u]", client->remoteIP().toString().c_str(), client->socket());
sendPong(client->socket());
}
void Websocket::onWSClose(PsychicWebSocketClient* client) {
ESP_LOGI(TAG, "Client disconnected: %s [%u]", client->remoteIP().toString().c_str(), client->socket());
removeClient(client->socket());
}
esp_err_t Websocket::onFrame(PsychicWebSocketRequest* request, httpd_ws_frame* frame) {
if (frame->type != HTTPD_WS_TYPE_BINARY) {
ESP_LOGW(TAG, "Expected binary frame, got type %d", frame->type);
return ESP_OK;
}
handleIncoming(frame->payload, frame->len, request->client()->socket());
return ESP_OK;
}
void Websocket::send(const uint8_t* data, size_t len, int cid) {
if (cid >= 0) {
auto* client = socket_.getClient(cid);
if (client) {
esp_err_t err = client->sendMessage(HTTPD_WS_TYPE_BINARY, data, len);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to send message to client %d: %s (len=%u)", cid, esp_err_to_name(err), len);
}
} else {
ESP_LOGW(TAG, "Client %d not found for send", cid);
}
} else {
socket_.sendAll(HTTPD_WS_TYPE_BINARY, data, len);
}
}
+7 -13
View File
@@ -1,28 +1,24 @@
#include <features.h>
#include <communication/native_server.h>
namespace feature_service {
// New function to print all feature flags to log
void printFeatureConfiguration() {
ESP_LOGI("Features", "====================== FEATURE FLAGS ======================");
ESP_LOGI("Features", "Firmware version: %s, name: %s, target: %s", APP_VERSION, APP_NAME, BUILD_TARGET);
// Core features
ESP_LOGI("Features", "USE_CAMERA: %s", USE_CAMERA ? "enabled" : "disabled");
ESP_LOGI("Features", "USE_MOTION: %s", USE_MOTION ? "enabled" : "disabled");
// Sensors
ESP_LOGI("Features", "USE_BNO055: %s", USE_BNO055 ? "enabled" : "disabled");
ESP_LOGI("Features", "USE_MPU6050: %s", USE_MPU6050 ? "enabled" : "disabled");
ESP_LOGI("Features", "USE_HMC5883: %s", USE_HMC5883 ? "enabled" : "disabled");
ESP_LOGI("Features", "USE_BMP180: %s", USE_BMP180 ? "enabled" : "disabled");
ESP_LOGI("Features", "USE_USS: %s", USE_USS ? "enabled" : "disabled");
// Peripherals
ESP_LOGI("Features", "USE_PCA9685: %s", USE_PCA9685 ? "enabled" : "disabled");
ESP_LOGI("Features", "USE_WS2812: %s", USE_WS2812 ? "enabled" : "disabled");
// Web services
ESP_LOGI("Features", "USE_MDNS: %s", USE_MDNS ? "enabled" : "disabled");
ESP_LOGI("Features", "EMBED_WEBAPP: %s", EMBED_WEBAPP ? "enabled" : "disabled");
ESP_LOGI("Features", "KINEMATICS_VARIANT: %s", KINEMATICS_VARIANT_STR);
@@ -45,9 +41,7 @@ void features_request(const socket_message_FeaturesDataRequest& fd_req, socket_m
fd_res.variant = const_cast<char*>(KINEMATICS_VARIANT_STR);
}
void features(JsonObject &root) {
void features(JsonObject& root) {
root["camera"] = USE_CAMERA ? true : false;
root["imu"] = (USE_MPU6050 || USE_BNO055) ? true : false;
root["mag"] = (USE_HMC5883 || USE_BNO055) ? true : false;
@@ -63,11 +57,11 @@ void features(JsonObject &root) {
root["variant"] = KINEMATICS_VARIANT_STR;
}
esp_err_t getFeatures(PsychicRequest *request) {
PsychicJsonResponse response = PsychicJsonResponse(request, false);
JsonObject root = response.getRoot();
esp_err_t getFeatures(httpd_req_t* request) {
JsonDocument doc;
JsonObject root = doc.to<JsonObject>();
features(root);
return response.send();
return NativeServer::sendJson(request, 200, doc);
}
} // namespace feature_service
} // namespace feature_service
+26 -57
View File
@@ -1,62 +1,53 @@
#include <filesystem.h>
#include <communication/native_server.h>
static const char *TAG = "FileService";
namespace FileSystem {
PsychicUploadHandler *uploadHandler;
esp_err_t getFiles(httpd_req_t *request) {
std::string files = listFiles("/");
httpd_resp_set_type(request, "application/json");
return httpd_resp_send(request, files.c_str(), files.length());
}
class Initializer {
public:
Initializer() {
uploadHandler = new PsychicUploadHandler();
uploadHandler->onUpload([](PsychicRequest *request, const String &filename, uint64_t index, uint8_t *data,
size_t len, bool last) -> esp_err_t {
return uploadFile(request, std::string(filename.c_str()), index, data, len, last);
});
uploadHandler->onRequest([](PsychicRequest *request) { return request->reply(200); });
esp_err_t getConfigFile(httpd_req_t *request) {
const char *uri = request->uri;
std::string path = "/config" + std::string(uri).substr(11);
if (!ESP_FS.exists(path.c_str())) {
return NativeServer::sendError(request, 404, "File not found");
}
};
static Initializer initializer;
esp_err_t getFiles(PsychicRequest *request) { return request->reply(200, "application/json", listFiles("/").c_str()); }
esp_err_t getConfigFile(PsychicRequest *request) {
String path = "/config" + request->uri().substring(11);
if (!ESP_FS.exists(path)) {
return request->reply(404, "text/plain", "File not found");
}
File file = ESP_FS.open(path, "r");
File file = ESP_FS.open(path.c_str(), "r");
if (!file) {
return request->reply(500, "text/plain", "Failed to open file");
return NativeServer::sendError(request, 500, "Failed to open file");
}
String content = file.readString();
file.close();
return request->reply(200, "application/json", content.c_str());
httpd_resp_set_type(request, "application/json");
return httpd_resp_send(request, content.c_str(), content.length());
}
esp_err_t handleDelete(PsychicRequest *request, JsonVariant &json) {
esp_err_t handleDelete(httpd_req_t *request, JsonVariant &json) {
if (json.is<JsonObject>()) {
const char *filename = json["file"].as<const char *>();
ESP_LOGI(TAG, "Deleting file: %s", filename);
return deleteFile(filename) ? request->reply(200) : request->reply(500);
return deleteFile(filename) ? NativeServer::sendOk(request)
: NativeServer::sendError(request, 500, "Delete failed");
}
return request->reply(400);
return NativeServer::sendError(request, 400, "Invalid request");
}
esp_err_t handleEdit(PsychicRequest *request, JsonVariant &json) {
esp_err_t handleEdit(httpd_req_t *request, JsonVariant &json) {
if (json.is<JsonObject>()) {
const char *filename = json["file"].as<const char *>();
const char *content = json["content"].as<const char *>();
ESP_LOGI(TAG, "Editing file: %s", filename);
return editFile(filename, content) ? request->reply(200) : request->reply(500);
return editFile(filename, content) ? NativeServer::sendOk(request)
: NativeServer::sendError(request, 500, "Edit failed");
}
return request->reply(400);
return NativeServer::sendError(request, 400, "Invalid request");
}
/* Helpers */
bool deleteFile(const char *filename) { return ESP_FS.remove(filename); }
std::string listFiles(const std::string &directory, bool isRoot) {
@@ -89,28 +80,6 @@ std::string listFiles(const std::string &directory, bool isRoot) {
return output;
}
esp_err_t uploadFile(PsychicRequest *request, const std::string &filename, uint64_t index, uint8_t *data, size_t len,
bool last) {
File file;
std::string path = "/www/" + filename;
ESP_LOGI(TAG, "Writing %d/%d bytes to: %s\n", (int)index + (int)len, request->contentLength(), path.c_str());
if (last) ESP_LOGI(TAG, "%s is finished. Total bytes: %d\n", path.c_str(), (int)index + (int)len);
file = ESP_FS.open(path.c_str(), !index ? FILE_WRITE : FILE_APPEND);
if (!file) {
ESP_LOGE(TAG, "Failed to open file");
return ESP_FAIL;
}
if (!file.write(data, len)) {
ESP_LOGE(TAG, "Write failed");
return ESP_FAIL;
}
return ESP_OK;
}
bool editFile(const char *filename, const char *content) {
File file = ESP_FS.open(filename, FILE_WRITE);
if (!file) return false;
@@ -120,10 +89,10 @@ bool editFile(const char *filename, const char *content) {
return true;
}
esp_err_t mkdir(PsychicRequest *request, JsonVariant &json) {
esp_err_t mkdir(httpd_req_t *request, JsonVariant &json) {
const char *path = json["path"].as<const char *>();
ESP_LOGI(TAG, "Creating directory: %s", path);
return ESP_FS.mkdir(path) ? request->reply(200) : request->reply(500);
return ESP_FS.mkdir(path) ? NativeServer::sendOk(request) : NativeServer::sendError(request, 500, "mkdir failed");
}
} // namespace FileSystem
} // namespace FileSystem
+83 -93
View File
@@ -1,5 +1,4 @@
#include <Arduino.h>
#include <PsychicHttp.h>
#include <ESPmDNS.h>
#include <WiFi.h>
#include <Wire.h>
@@ -11,7 +10,8 @@
#include <peripherals/servo_controller.h>
#include <peripherals/led_service.h>
#include <peripherals/camera_service.h>
#include <communication/websocket_adapter.h>
#include <communication/native_server.h>
#include <communication/native_websocket.h>
#include <features.h>
#include <motion.h>
#include <wifi_service.h>
@@ -21,11 +21,8 @@
#include <www_mount.hpp>
// Communication
PsychicHttpServer server;
Websocket socket {server, "/api/ws"};
NativeWebsocket socket {nativeServer, "/api/ws"};
// Core
Peripherals peripherals;
ServoController servoController;
MotionService motionService;
@@ -39,99 +36,91 @@ Camera::CameraService cameraService;
MDNSService mdnsService;
#endif
// Service
WiFiService wifiService;
APService apService;
void setupServer() {
server.config.max_uri_handlers = 50 + WWW_ASSETS_COUNT;
server.config.stack_size = 32768; // 32KB
server.maxUploadSize = 1000000; // 1 MB;
server.listen(80);
server.on("/api/system/reset", HTTP_POST,
[&](PsychicRequest *request, JsonVariant &json) { return system_service::handleReset(request); });
server.on("/api/system/restart", HTTP_POST,
[&](PsychicRequest *request, JsonVariant &json) { return system_service::handleRestart(request); });
server.on("/api/system/sleep", HTTP_POST,
[&](PsychicRequest *request, JsonVariant &json) { return system_service::handleSleep(request); });
nativeServer.config(50 + WWW_ASSETS_COUNT, 32768, 1000000);
nativeServer.listen(80);
nativeServer.on("/api/system/reset", HTTP_POST,
[&](httpd_req_t *request, JsonVariant &json) { return system_service::handleReset(request); });
nativeServer.on("/api/system/restart", HTTP_POST,
[&](httpd_req_t *request, JsonVariant &json) { return system_service::handleRestart(request); });
nativeServer.on("/api/system/sleep", HTTP_POST,
[&](httpd_req_t *request, JsonVariant &json) { return system_service::handleSleep(request); });
#if USE_CAMERA
server.on("/api/camera/still", HTTP_GET,
[&](PsychicRequest *request) { return cameraService.cameraStill(request); });
server.on("/api/camera/stream", HTTP_GET,
[&](PsychicRequest *request) { return cameraService.cameraStream(request); });
server.on("/api/camera/settings", HTTP_GET,
[&](PsychicRequest *request) { return cameraService.endpoint.getState(request); });
server.on("/api/camera/settings", HTTP_POST, [&](PsychicRequest *request, JsonVariant &json) {
nativeServer.on("/api/camera/still", HTTP_GET,
[&](httpd_req_t *request) { return cameraService.cameraStill(request); });
nativeServer.on("/api/camera/stream", HTTP_GET,
[&](httpd_req_t *request) { return cameraService.cameraStream(request); });
nativeServer.on("/api/camera/settings", HTTP_GET,
[&](httpd_req_t *request) { return cameraService.endpoint.getState(request); });
nativeServer.on("/api/camera/settings", HTTP_POST, [&](httpd_req_t *request, JsonVariant &json) {
return cameraService.endpoint.handleStateUpdate(request, json);
});
#endif
server.on("/api/servo/config", HTTP_GET,
[&](PsychicRequest *request) { return servoController.endpoint.getState(request); });
server.on("/api/servo/config", HTTP_POST, [&](PsychicRequest *request, JsonVariant &json) {
nativeServer.on("/api/servo/config", HTTP_GET,
[&](httpd_req_t *request) { return servoController.endpoint.getState(request); });
nativeServer.on("/api/servo/config", HTTP_POST, [&](httpd_req_t *request, JsonVariant &json) {
return servoController.endpoint.handleStateUpdate(request, json);
});
// WiFi
server.on("/api/wifi/sta/settings", HTTP_GET,
[&](PsychicRequest *request) { return wifiService.endpoint.getState(request); });
server.on("/api/wifi/sta/settings", HTTP_POST, [&](PsychicRequest *request, JsonVariant &json) {
nativeServer.on("/api/wifi/sta/settings", HTTP_GET,
[&](httpd_req_t *request) { return wifiService.endpoint.getState(request); });
nativeServer.on("/api/wifi/sta/settings", HTTP_POST, [&](httpd_req_t *request, JsonVariant &json) {
return wifiService.endpoint.handleStateUpdate(request, json);
});
server.on("/api/wifi/scan", HTTP_GET, [&](PsychicRequest *request) { return wifiService.handleScan(request); });
server.on("/api/wifi/networks", HTTP_GET,
[&](PsychicRequest *request) { return wifiService.getNetworks(request); });
server.on("/api/wifi/sta/status", HTTP_GET,
[&](PsychicRequest *request) { return wifiService.getNetworkStatus(request); });
nativeServer.on("/api/wifi/scan", HTTP_GET, [&](httpd_req_t *request) { return wifiService.handleScan(request); });
nativeServer.on("/api/wifi/networks", HTTP_GET,
[&](httpd_req_t *request) { return wifiService.getNetworks(request); });
nativeServer.on("/api/wifi/sta/status", HTTP_GET,
[&](httpd_req_t *request) { return wifiService.getNetworkStatus(request); });
// AP
server.on("/api/ap/status", HTTP_GET, [&](PsychicRequest *request) { return apService.getStatus(request); });
server.on("/api/ap/settings", HTTP_GET,
[&](PsychicRequest *request) { return apService.endpoint.getState(request); });
server.on("/api/ap/settings", HTTP_POST, [&](PsychicRequest *request, JsonVariant &json) {
nativeServer.on("/api/ap/status", HTTP_GET, [&](httpd_req_t *request) { return apService.getStatus(request); });
nativeServer.on("/api/ap/settings", HTTP_GET,
[&](httpd_req_t *request) { return apService.endpoint.getState(request); });
nativeServer.on("/api/ap/settings", HTTP_POST, [&](httpd_req_t *request, JsonVariant &json) {
return apService.endpoint.handleStateUpdate(request, json);
});
// Peripherals
server.on("/api/peripherals", HTTP_GET,
[&](PsychicRequest *request) { return peripherals.endpoint.getState(request); });
server.on("/api/peripherals", HTTP_POST, [&](PsychicRequest *request, JsonVariant &json) {
nativeServer.on("/api/peripherals", HTTP_GET,
[&](httpd_req_t *request) { return peripherals.endpoint.getState(request); });
nativeServer.on("/api/peripherals", HTTP_POST, [&](httpd_req_t *request, JsonVariant &json) {
return peripherals.endpoint.handleStateUpdate(request, json);
});
// MDNS
#if FT_ENABLED(USE_MDNS)
server.on("/api/mdns", HTTP_GET, [&](PsychicRequest *request) { return mdnsService.endpoint.getState(request); });
server.on("/api/mdns", HTTP_POST, [&](PsychicRequest *request, JsonVariant &json) {
nativeServer.on("/api/mdns", HTTP_GET,
[&](httpd_req_t *request) { return mdnsService.endpoint.getState(request); });
nativeServer.on("/api/mdns", HTTP_POST, [&](httpd_req_t *request, JsonVariant &json) {
return mdnsService.endpoint.handleStateUpdate(request, json);
});
server.on("/api/mdns/status", HTTP_GET, [&](PsychicRequest *request) { return mdnsService.getStatus(request); });
server.on("/api/mdns/query", HTTP_POST,
[&](PsychicRequest *request, JsonVariant &json) { return mdnsService.queryServices(request, json); });
nativeServer.on("/api/mdns/status", HTTP_GET, [&](httpd_req_t *request) { return mdnsService.getStatus(request); });
nativeServer.on("/api/mdns/query", HTTP_POST,
[&](httpd_req_t *request, JsonVariant &json) { return mdnsService.queryServices(request, json); });
#endif
// Filesystem
server.on("/api/config/*", HTTP_GET, [](PsychicRequest *request) { return FileSystem::getConfigFile(request); });
server.on("/api/files", HTTP_GET, [&](PsychicRequest *request) { return FileSystem::getFiles(request); });
server.on("/api/files", HTTP_POST, FileSystem::uploadHandler);
server.on("/api/files/delete", HTTP_POST,
[&](PsychicRequest *request, JsonVariant &json) { return FileSystem::handleDelete(request, json); });
server.on("/api/files/edit", HTTP_POST,
[&](PsychicRequest *request, JsonVariant &json) { return FileSystem::handleEdit(request, json); });
server.on("/api/files/mkdir", HTTP_POST,
[&](PsychicRequest *request, JsonVariant &json) { return FileSystem::mkdir(request, json); });
nativeServer.on("/api/config/*", HTTP_GET, [](httpd_req_t *request) { return FileSystem::getConfigFile(request); });
nativeServer.on("/api/files", HTTP_GET, [&](httpd_req_t *request) { return FileSystem::getFiles(request); });
nativeServer.on("/api/files/delete", HTTP_POST,
[&](httpd_req_t *request, JsonVariant &json) { return FileSystem::handleDelete(request, json); });
nativeServer.on("/api/files/edit", HTTP_POST,
[&](httpd_req_t *request, JsonVariant &json) { return FileSystem::handleEdit(request, json); });
nativeServer.on("/api/files/mkdir", HTTP_POST,
[&](httpd_req_t *request, JsonVariant &json) { return FileSystem::mkdir(request, json); });
#if EMBED_WEBAPP
mountStaticAssets(server);
mountStaticAssets(nativeServer);
#endif
server.on("/*", HTTP_OPTIONS, [](PsychicRequest *request) { // CORS handling
PsychicResponse response(request);
response.setCode(200);
return response.send();
nativeServer.on("/*", HTTP_OPTIONS, [](httpd_req_t *request) {
httpd_resp_set_status(request, "200 OK");
return httpd_resp_send(request, nullptr, 0);
});
DefaultHeaders::Instance().addHeader("Server", APP_NAME);
DefaultHeaders::Instance().addHeader("Access-Control-Allow-Origin", "*");
DefaultHeaders::Instance().addHeader("Access-Control-Allow-Headers", "Accept, Content-Type, Authorization");
DefaultHeaders::Instance().addHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
DefaultHeaders::Instance().addHeader("Access-Control-Max-Age", "86400");
nativeServer.addDefaultHeader("Server", APP_NAME);
nativeServer.addDefaultHeader("Access-Control-Allow-Origin", "*");
nativeServer.addDefaultHeader("Access-Control-Allow-Headers", "Accept, Content-Type, Authorization");
nativeServer.addDefaultHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
nativeServer.addDefaultHeader("Access-Control-Max-Age", "86400");
}
void setupEventSocket() {
@@ -164,76 +153,77 @@ void setupEventSocket() {
data.active ? servoController.activate() : servoController.deactivate();
});
socket.on<socket_message_FSUploadData>([&](const socket_message_FSUploadData &data, int clientId) {
FileSystemWS::fsHandler.handleUploadData(data);
});
socket.on<socket_message_FSUploadData>(
[&](const socket_message_FSUploadData &data, int clientId) { FileSystemWS::fsHandler.handleUploadData(data); });
using CorrelationHandler =
std::function<void(const socket_message_CorrelationRequest &, socket_message_CorrelationResponse &, int)>;
static std::map<pb_size_t, CorrelationHandler> correlationHandlers = {
{socket_message_CorrelationRequest_features_data_request_tag, // Features data
{socket_message_CorrelationRequest_features_data_request_tag,
[](const auto &req, auto &res, int clientId) {
res.which_response = socket_message_CorrelationResponse_features_data_response_tag;
feature_service::features_request(req.request.features_data_request, res.response.features_data_response);
}},
{socket_message_CorrelationRequest_i2c_scan_data_request_tag, // i2c data
{socket_message_CorrelationRequest_i2c_scan_data_request_tag,
[](const auto &req, auto &res, int clientId) {
res.which_response = socket_message_CorrelationResponse_i2c_scan_data_tag;
peripherals.scanI2C();
peripherals.getI2CScanProto(res.response.i2c_scan_data);
}},
{socket_message_CorrelationRequest_imu_calibrate_execute_tag, // Calibration request
{socket_message_CorrelationRequest_imu_calibrate_execute_tag,
[](const auto &req, auto &res, int clientId) {
res.which_response = socket_message_CorrelationResponse_imu_calibrate_data_tag;
res.response.imu_calibrate_data.success = peripherals.calibrateIMU();
}},
{socket_message_CorrelationRequest_system_information_request_tag, // All system information data
{socket_message_CorrelationRequest_system_information_request_tag,
[](const auto &req, auto &res, int clientId) {
res.which_response = socket_message_CorrelationResponse_system_information_response_tag;
res.response.system_information_response.has_analytics_data = true;
res.response.system_information_response.has_static_system_information = true;
system_service::getAnalytics(res.response.system_information_response.analytics_data);
system_service::getStaticSystemInformation(res.response.system_information_response.static_system_information);
res.which_response = socket_message_CorrelationResponse_system_information_response_tag;
res.response.system_information_response.has_analytics_data = true;
res.response.system_information_response.has_static_system_information = true;
system_service::getAnalytics(res.response.system_information_response.analytics_data);
system_service::getStaticSystemInformation(
res.response.system_information_response.static_system_information);
}},
// Filesystem operations
{socket_message_CorrelationRequest_fs_delete_request_tag, // Delete file/directory
{socket_message_CorrelationRequest_fs_delete_request_tag,
[](const auto &req, auto &res, int clientId) {
res.which_response = socket_message_CorrelationResponse_fs_delete_response_tag;
res.response.fs_delete_response = FileSystemWS::fsHandler.handleDelete(req.request.fs_delete_request);
}},
{socket_message_CorrelationRequest_fs_mkdir_request_tag, // Create directory
{socket_message_CorrelationRequest_fs_mkdir_request_tag,
[](const auto &req, auto &res, int clientId) {
res.which_response = socket_message_CorrelationResponse_fs_mkdir_response_tag;
res.response.fs_mkdir_response = FileSystemWS::fsHandler.handleMkdir(req.request.fs_mkdir_request);
}},
{socket_message_CorrelationRequest_fs_list_request_tag, // List directory
{socket_message_CorrelationRequest_fs_list_request_tag,
[](const auto &req, auto &res, int clientId) {
res.which_response = socket_message_CorrelationResponse_fs_list_response_tag;
res.response.fs_list_response = FileSystemWS::fsHandler.handleList(req.request.fs_list_request);
}},
{socket_message_CorrelationRequest_fs_download_request_tag, // Streaming download (no response, streams data)
{socket_message_CorrelationRequest_fs_download_request_tag,
[](const auto &req, auto &res, int clientId) {
FileSystemWS::fsHandler.handleDownloadRequest(req.request.fs_download_request, clientId);
res.status_code = 0;
}},
{socket_message_CorrelationRequest_fs_upload_start_tag, // Upload start
{socket_message_CorrelationRequest_fs_upload_start_tag,
[](const auto &req, auto &res, int clientId) {
res.which_response = socket_message_CorrelationResponse_fs_upload_start_response_tag;
res.response.fs_upload_start_response = FileSystemWS::fsHandler.handleUploadStart(req.request.fs_upload_start, clientId);
res.response.fs_upload_start_response =
FileSystemWS::fsHandler.handleUploadStart(req.request.fs_upload_start, clientId);
}},
{socket_message_CorrelationRequest_fs_cancel_transfer_tag, // Cancel transfer
{socket_message_CorrelationRequest_fs_cancel_transfer_tag,
[](const auto &req, auto &res, int clientId) {
res.which_response = socket_message_CorrelationResponse_fs_cancel_transfer_response_tag;
res.response.fs_cancel_transfer_response = FileSystemWS::fsHandler.handleCancelTransfer(req.request.fs_cancel_transfer);
res.response.fs_cancel_transfer_response =
FileSystemWS::fsHandler.handleCancelTransfer(req.request.fs_cancel_transfer);
}},
};
@@ -339,4 +329,4 @@ void setup() {
ESP_LOGI("main", "Finished booting");
}
void loop() { vTaskDelete(nullptr); }
void loop() { vTaskDelete(nullptr); }
+9 -8
View File
@@ -1,4 +1,5 @@
#include <mdns_service.h>
#include <communication/native_server.h>
static const char *TAG = "MDNSService";
@@ -64,11 +65,11 @@ void MDNSService::addServices() {
}
}
esp_err_t MDNSService::getStatus(PsychicRequest *request) {
PsychicJsonResponse response = PsychicJsonResponse(request, false);
JsonVariant root = response.getRoot();
esp_err_t MDNSService::getStatus(httpd_req_t *request) {
JsonDocument doc;
JsonVariant root = doc.to<JsonVariant>();
getStatus(root);
return response.send();
return NativeServer::sendJson(request, 200, doc);
}
void MDNSService::getStatus(JsonVariant &root) {
@@ -76,12 +77,12 @@ void MDNSService::getStatus(JsonVariant &root) {
root["started"] = _started;
}
esp_err_t MDNSService::queryServices(PsychicRequest *request, JsonVariant &json) {
esp_err_t MDNSService::queryServices(httpd_req_t *request, JsonVariant &json) {
std::string service = json["service"].as<std::string>();
std::string proto = json["protocol"].as<std::string>();
PsychicJsonResponse response = PsychicJsonResponse(request, false);
JsonVariant root = response.getRoot();
JsonDocument doc;
JsonVariant root = doc.to<JsonVariant>();
ESP_LOGI(TAG, "Querying for service: %s, protocol: %s", service.c_str(), proto.c_str());
@@ -96,5 +97,5 @@ esp_err_t MDNSService::queryServices(PsychicRequest *request, JsonVariant &json)
serviceObj["port"] = MDNS.port(i);
}
return response.send();
return NativeServer::sendJson(request, 200, doc);
}
+33 -50
View File
@@ -1,4 +1,5 @@
#include <peripherals/camera_service.h>
#include <communication/native_server.h>
namespace Camera {
@@ -83,78 +84,60 @@ esp_err_t CameraService::begin() {
return err;
}
esp_err_t CameraService::cameraStill(PsychicRequest *request) {
esp_err_t CameraService::cameraStill(httpd_req_t *request) {
camera_fb_t *fb = safe_camera_fb_get();
if (!fb) {
ESP_LOGE(TAG, "Camera capture failed");
request->reply(500, "text/plain", "Camera capture failed");
return ESP_FAIL;
return NativeServer::sendError(request, 500, "Camera capture failed");
}
PsychicStreamResponse response = PsychicStreamResponse(request, "image/jpeg", "capture.jpg");
response.beginSend();
response.write(fb->buf, fb->len);
httpd_resp_set_type(request, "image/jpeg");
httpd_resp_set_hdr(request, "Content-Disposition", "inline; filename=capture.jpg");
esp_err_t res = httpd_resp_send(request, (const char *)fb->buf, fb->len);
esp_camera_fb_return(fb);
return response.endSend();
return res;
}
void streamTask(void *pv) {
esp_err_t CameraService::cameraStream(httpd_req_t *request) {
httpd_resp_set_type(request, _STREAM_CONTENT_TYPE);
camera_fb_t *fb = NULL;
char part_buf[64];
uint8_t *buf = NULL;
size_t buf_len = 0;
esp_err_t res = ESP_OK;
PsychicRequest *request = static_cast<PsychicRequest *>(pv);
httpd_req_t *copy = nullptr;
res = httpd_req_async_handler_begin(request->request(), &copy);
if (res != ESP_OK) {
return;
}
PsychicHttpServer *server = request->server();
PsychicRequest new_request = PsychicRequest(server, copy);
request = &new_request;
PsychicStreamResponse response = PsychicStreamResponse(request, _STREAM_CONTENT_TYPE);
camera_fb_t *fb = NULL;
char *part_buf[64];
size_t buf_len = 0;
uint8_t *buf = NULL;
int64_t fr_start = esp_timer_get_time();
response.beginSend();
for (;;) {
while (res == ESP_OK) {
fb = safe_camera_fb_get();
if (!fb) {
ESP_LOGE("Stream", "Camera capture failed");
ESP_LOGE(TAG, "Camera capture failed");
break;
}
if (fb->format != PIXFORMAT_JPEG) {
if (!frame2jpg(fb, 80, &buf, &buf_len)) break;
if (!frame2jpg(fb, 80, &buf, &buf_len)) {
esp_camera_fb_return(fb);
break;
}
} else {
buf_len = fb->len;
buf = fb->buf;
}
size_t hlen = snprintf((char *)part_buf, 64, _STREAM_PART, buf_len);
size_t w = response.write((const char *)part_buf, hlen);
w += response.write((const char *)buf, buf_len);
w += response.write((char *)_STREAM_BOUNDARY, strlen(_STREAM_BOUNDARY));
if (w == 62) break;
size_t hlen = snprintf(part_buf, 64, _STREAM_PART, buf_len);
res = httpd_resp_send_chunk(request, part_buf, hlen);
if (res == ESP_OK) res = httpd_resp_send_chunk(request, (const char *)buf, buf_len);
if (res == ESP_OK) res = httpd_resp_send_chunk(request, _STREAM_BOUNDARY, strlen(_STREAM_BOUNDARY));
esp_camera_fb_return(fb);
safe_sensor_return();
buf = NULL;
taskYIELD();
int64_t delay = 30000ll - esp_timer_get_time() - fr_start;
if (delay > 0) vTaskDelay(pdMS_TO_TICKS(delay));
}
ESP_LOGI("Stream", "Stream ended");
response.endSend();
httpd_req_async_handler_complete(copy);
vTaskDelete(NULL);
}
esp_err_t CameraService::cameraStream(PsychicRequest *request) {
xTaskCreate(streamTask, "Stream client task", 4096, request, 4, nullptr);
vTaskDelay(pdMS_TO_TICKS(100));
vTaskDelay(pdMS_TO_TICKS(30));
}
ESP_LOGI(TAG, "Stream ended");
httpd_resp_send_chunk(request, NULL, 0);
return ESP_OK;
}
@@ -193,4 +176,4 @@ void CameraService::updateCamera() {
safe_sensor_return();
}
} // namespace Camera
} // namespace Camera
+8 -7
View File
@@ -1,22 +1,23 @@
#include "system_service.h"
#include <communication/native_server.h>
namespace system_service {
static const char *TAG = "SystemService";
esp_err_t handleReset(PsychicRequest *request) {
esp_err_t handleReset(httpd_req_t *request) {
reset();
return request->reply(200);
return NativeServer::sendOk(request);
}
esp_err_t handleRestart(PsychicRequest *request) {
esp_err_t handleRestart(httpd_req_t *request) {
restart();
return request->reply(200);
return NativeServer::sendOk(request);
}
esp_err_t handleSleep(PsychicRequest *request) {
esp_err_t handleSleep(httpd_req_t *request) {
sleep();
return request->reply(200);
return NativeServer::sendOk(request);
}
void reset() {
@@ -141,4 +142,4 @@ const char *resetReason(esp_reset_reason_t reason) {
}
}
} // namespace system_service
} // namespace system_service
+19 -21
View File
@@ -1,4 +1,5 @@
#include <wifi_service.h>
#include <communication/native_server.h>
WiFiService::WiFiService()
: _persistence(WiFiSettings::read, WiFiSettings::update, this, WIFI_SETTINGS_FILE),
@@ -38,25 +39,28 @@ void WiFiService::reconfigureWiFiConnection() {
void WiFiService::loop() { EXECUTE_EVERY_N_MS(reconnectDelay, manageSTA()); }
esp_err_t WiFiService::handleScan(PsychicRequest *request) {
esp_err_t WiFiService::handleScan(httpd_req_t *request) {
if (WiFi.scanComplete() != -1) {
WiFi.scanDelete();
WiFi.scanNetworks(true);
}
return request->reply(202);
httpd_resp_set_status(request, "202 Accepted");
return httpd_resp_send(request, nullptr, 0);
}
esp_err_t WiFiService::getNetworks(PsychicRequest *request) {
esp_err_t WiFiService::getNetworks(httpd_req_t *request) {
int numNetworks = WiFi.scanComplete();
if (numNetworks == -1)
return request->reply(202);
else if (numNetworks < -1)
if (numNetworks == -1) {
httpd_resp_set_status(request, "202 Accepted");
return httpd_resp_send(request, nullptr, 0);
} else if (numNetworks < -1) {
return handleScan(request);
}
PsychicJsonResponse response = PsychicJsonResponse(request, false);
JsonObject root = response.getRoot();
JsonDocument doc;
JsonObject root = doc.to<JsonObject>();
getNetworks(root);
return response.send();
return NativeServer::sendJson(request, 200, doc);
}
void WiFiService::setupMDNS(const char *hostname) {
@@ -80,11 +84,11 @@ void WiFiService::getNetworks(JsonObject &root) {
}
}
esp_err_t WiFiService::getNetworkStatus(PsychicRequest *request) {
PsychicJsonResponse response = PsychicJsonResponse(request, false);
JsonObject root = response.getRoot();
esp_err_t WiFiService::getNetworkStatus(httpd_req_t *request) {
JsonDocument doc;
JsonObject root = doc.to<JsonObject>();
getNetworkStatus(root);
return response.send();
return NativeServer::sendJson(request, 200, doc);
}
void WiFiService::getNetworkStatus(JsonObject &root) {
@@ -116,12 +120,10 @@ void WiFiService::manageSTA() {
}
void WiFiService::connectToWiFi() {
// reset availability flag for all stored networks
for (auto &network : state().wifiSettings) {
network.available = false;
}
// scanning for available networks
int scanResult = WiFi.scanNetworks();
if (scanResult == WIFI_SCAN_FAILED) {
ESP_LOGE("WiFiSettingsService", "WiFi scan failed.");
@@ -130,7 +132,6 @@ void WiFiService::connectToWiFi() {
} else {
ESP_LOGI("WiFiSettingsService", "%d networks found.", scanResult);
// find the best network to connect
wifi_settings_t *bestNetwork = nullptr;
int32_t bestNetworkDb = FACTORY_WIFI_RSSI_THRESHOLD;
@@ -178,19 +179,16 @@ void WiFiService::connectToWiFi() {
void WiFiService::configureNetwork(wifi_settings_t &network) {
if (network.staticIPConfig) {
// configure for static IP
WiFi.config(network.localIP, network.gatewayIP, network.subnetMask, network.dnsIP1, network.dnsIP2);
} else {
// configure for DHCP
WiFi.config(IPAddress(0, 0, 0, 0), IPAddress(0, 0, 0, 0), IPAddress(0, 0, 0, 0));
}
WiFi.setHostname(state().hostname.c_str());
// attempt to connect to the network
WiFi.begin(network.ssid.c_str(), network.password.c_str());
#if CONFIG_IDF_TARGET_ESP32C3
WiFi.setTxPower(WIFI_POWER_8_5dBm); // https://www.wemos.cc/en/latest/c3/c3_mini_1_0_0.html#about-wifi
WiFi.setTxPower(WIFI_POWER_8_5dBm);
#endif
}
@@ -210,4 +208,4 @@ void WiFiService::onStationModeStop(WiFiEvent_t event, WiFiEventInfo_t info) {
void WiFiService::onStationModeGotIP(WiFiEvent_t event, WiFiEventInfo_t info) {
ESP_LOGI("WiFiStatus", "WiFi Got IP. localIP=%s, hostName=%s", WiFi.localIP().toString().c_str(),
WiFi.getHostname());
}
}
+14 -19
View File
@@ -1,30 +1,25 @@
#include "www_mount.hpp"
static esp_err_t web_send(PsychicRequest* req, const WebAsset& asset) {
PsychicResponse resp(req);
resp.setCode(200);
resp.setContentType(asset.mime);
if (asset.gz) resp.addHeader("Content-Encoding", "gzip");
if (WWW_OPT.add_vary) resp.addHeader("Vary", "Accept-Encoding");
static esp_err_t web_send(httpd_req_t* req, const WebAsset& asset) {
httpd_resp_set_status(req, "200 OK");
httpd_resp_set_type(req, asset.mime);
if (asset.gz) httpd_resp_set_hdr(req, "Content-Encoding", "gzip");
if (WWW_OPT.add_vary) httpd_resp_set_hdr(req, "Vary", "Accept-Encoding");
char cc[64];
snprintf(cc, sizeof(cc), "public, immutable, max-age=%u", WWW_OPT.max_age);
resp.addHeader("Cache-Control", cc);
httpd_resp_set_hdr(req, "Cache-Control", cc);
char et[34];
snprintf(et, sizeof(et), "\"%08x\"", asset.etag);
resp.addHeader("ETag", et);
resp.setContent(asset.data, asset.len);
return resp.send();
httpd_resp_set_hdr(req, "ETag", et);
return httpd_resp_send(req, (const char*)asset.data, asset.len);
}
void mountStaticAssets(PsychicHttpServer& server) {
static uint8_t buf[sizeof(PsychicWebHandler) * WWW_ASSETS_COUNT];
void mountStaticAssets(NativeServer& server) {
for (size_t i = 0; i < WWW_ASSETS_COUNT; i++) {
const WebAsset* a = &WWW_ASSETS[i];
auto* handle = new (&buf[i * sizeof(PsychicWebHandler)]) PsychicWebHandler();
handle->onRequest([a](PsychicRequest* req) { return web_send(req, *a); });
server.on(a->uri, HTTP_GET, handle);
if (strcmp(a->uri, WWW_OPT.default_uri) == 0) {
server.defaultEndpoint->setHandler(handle);
}
server.on(a->uri, HTTP_GET, [a](httpd_req_t* req) { return web_send(req, *a); });
}
}
}
-1
View File
@@ -110,7 +110,6 @@ build_src_flags =
test_ignore = test_embedded
board_build.filesystem = littlefs
lib_deps =
hoeken/PsychicHttp@^1.2.1
ArduinoJson@>=7.0.0
teckel12/NewPing@^1.9.7
jrowberg/I2Cdevlib-MPU6050@^1.0.0