2021-12-23 22:42:19 +01:00
|
|
|
|
#include "StandWebServer.h"
|
|
|
|
|
|
#ifdef STANDARD_WEB_SERVER
|
2021-12-24 22:49:06 +01:00
|
|
|
|
|
|
|
|
|
|
File fsUploadFile;
|
|
|
|
|
|
|
2021-12-23 22:42:19 +01:00
|
|
|
|
void standWebServerInit() {
|
|
|
|
|
|
// Кэшировать файлы для быстрой работы
|
|
|
|
|
|
HTTP.serveStatic("/css/", FileFS, "/css/", "max-age=31536000"); // кеширование на 1 год
|
|
|
|
|
|
HTTP.serveStatic("/js/", FileFS, "/js/", "max-age=31536000"); // кеширование на 1 год
|
|
|
|
|
|
HTTP.serveStatic("/png/", FileFS, "/png/", "max-age=31536000"); // кеширование на 1 год
|
|
|
|
|
|
|
|
|
|
|
|
HTTP.on("/settings.json", HTTP_GET, []() {
|
|
|
|
|
|
HTTP.send(200, "application/json", settingsFlashJson);
|
|
|
|
|
|
});
|
|
|
|
|
|
|
2022-01-22 00:15:49 +01:00
|
|
|
|
HTTP.on("/config.json", HTTP_GET, []() {
|
2022-01-24 00:57:22 +01:00
|
|
|
|
HTTP.send(200, "application/json", readFile(F("config.json"), 10000));
|
2022-01-22 00:15:49 +01:00
|
|
|
|
});
|
|
|
|
|
|
|
2021-12-23 22:42:19 +01:00
|
|
|
|
HTTP.on("/restart", HTTP_GET, []() {
|
|
|
|
|
|
// ESP.restart();
|
|
|
|
|
|
HTTP.send(200, "text/plain", "ok");
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// Добавляем функцию Update для перезаписи прошивки по WiFi при 1М(256K FileFS) и выше
|
|
|
|
|
|
// httpUpdater.setup(&HTTP);
|
|
|
|
|
|
// Запускаем HTTP сервер
|
|
|
|
|
|
HTTP.begin();
|
|
|
|
|
|
|
2021-12-23 22:56:45 +01:00
|
|
|
|
#ifdef REST_FILE_OPERATIONS
|
2021-12-23 22:42:19 +01:00
|
|
|
|
SPIFFS.begin();
|
|
|
|
|
|
{
|
|
|
|
|
|
Dir dir = SPIFFS.openDir("/");
|
|
|
|
|
|
while (dir.next()) {
|
|
|
|
|
|
String fileName = dir.fileName();
|
|
|
|
|
|
size_t fileSize = dir.fileSize();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
// HTTP страницы для работы с FFS
|
|
|
|
|
|
// list directory
|
|
|
|
|
|
HTTP.on("/list", HTTP_GET, handleFileList);
|
|
|
|
|
|
//загрузка редактора editor
|
|
|
|
|
|
HTTP.on("/edit", HTTP_GET, []() {
|
|
|
|
|
|
if (!handleFileRead("/edit.htm")) HTTP.send(404, "text/plain", "FileNotFound");
|
|
|
|
|
|
});
|
|
|
|
|
|
//Создание файла
|
|
|
|
|
|
HTTP.on("/edit", HTTP_PUT, handleFileCreate);
|
|
|
|
|
|
//Удаление файла
|
|
|
|
|
|
HTTP.on("/edit", HTTP_DELETE, handleFileDelete);
|
|
|
|
|
|
// first callback is called after the request has ended with all parsed arguments
|
|
|
|
|
|
// second callback handles file uploads at that location
|
|
|
|
|
|
HTTP.on(
|
|
|
|
|
|
"/edit", HTTP_POST, []() {
|
|
|
|
|
|
HTTP.send(200, "text/plain", "");
|
|
|
|
|
|
},
|
|
|
|
|
|
handleFileUpload);
|
|
|
|
|
|
#endif
|
|
|
|
|
|
// called when the url is not defined here
|
|
|
|
|
|
// use it to load content from SPIFFS
|
|
|
|
|
|
HTTP.onNotFound([]() {
|
|
|
|
|
|
if (!handleFileRead(HTTP.uri()))
|
|
|
|
|
|
HTTP.send(404, "text/plain", "FileNotFound");
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool handleFileRead(String path) {
|
|
|
|
|
|
if (path.endsWith("/")) path += "index.html";
|
|
|
|
|
|
String contentType = getContentType(path);
|
|
|
|
|
|
String pathWithGz = path + ".gz";
|
|
|
|
|
|
if (FileFS.exists(pathWithGz) || FileFS.exists(path)) {
|
|
|
|
|
|
if (FileFS.exists(pathWithGz))
|
|
|
|
|
|
path += ".gz";
|
|
|
|
|
|
File file = FileFS.open(path, "r");
|
2021-12-23 23:47:13 +01:00
|
|
|
|
HTTP.streamFile(file, contentType);
|
2021-12-23 22:42:19 +01:00
|
|
|
|
file.close();
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
String getContentType(String filename) {
|
|
|
|
|
|
if (HTTP.hasArg("download"))
|
|
|
|
|
|
return "application/octet-stream";
|
|
|
|
|
|
else if (filename.endsWith(".htm"))
|
|
|
|
|
|
return "text/html";
|
|
|
|
|
|
else if (filename.endsWith(".html"))
|
|
|
|
|
|
return "text/html";
|
|
|
|
|
|
else if (filename.endsWith(".json"))
|
|
|
|
|
|
return "application/json";
|
|
|
|
|
|
else if (filename.endsWith(".css"))
|
|
|
|
|
|
return "text/css";
|
|
|
|
|
|
else if (filename.endsWith(".js"))
|
|
|
|
|
|
return "application/javascript";
|
|
|
|
|
|
else if (filename.endsWith(".png"))
|
|
|
|
|
|
return "image/png";
|
|
|
|
|
|
else if (filename.endsWith(".gif"))
|
|
|
|
|
|
return "image/gif";
|
|
|
|
|
|
else if (filename.endsWith(".jpg"))
|
|
|
|
|
|
return "image/jpeg";
|
|
|
|
|
|
else if (filename.endsWith(".ico"))
|
|
|
|
|
|
return "image/x-icon";
|
|
|
|
|
|
else if (filename.endsWith(".xml"))
|
|
|
|
|
|
return "text/xml";
|
|
|
|
|
|
else if (filename.endsWith(".pdf"))
|
|
|
|
|
|
return "application/x-pdf";
|
|
|
|
|
|
else if (filename.endsWith(".zip"))
|
|
|
|
|
|
return "application/x-zip";
|
|
|
|
|
|
else if (filename.endsWith(".gz"))
|
|
|
|
|
|
return "application/x-gzip";
|
|
|
|
|
|
return "text/plain";
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2021-12-23 22:56:45 +01:00
|
|
|
|
#ifdef REST_FILE_OPERATIONS
|
2021-12-23 22:42:19 +01:00
|
|
|
|
// Здесь функции для работы с файловой системой
|
|
|
|
|
|
void handleFileUpload() {
|
|
|
|
|
|
if (HTTP.uri() != "/edit") return;
|
|
|
|
|
|
HTTPUpload& upload = HTTP.upload();
|
|
|
|
|
|
if (upload.status == UPLOAD_FILE_START) {
|
|
|
|
|
|
String filename = upload.filename;
|
|
|
|
|
|
if (!filename.startsWith("/")) filename = "/" + filename;
|
|
|
|
|
|
fsUploadFile = FileFS.open(filename, "w");
|
|
|
|
|
|
filename = String();
|
|
|
|
|
|
} else if (upload.status == UPLOAD_FILE_WRITE) {
|
|
|
|
|
|
// Serial.print("handleFileUpload Data: "); Serial.println(upload.currentSize);
|
|
|
|
|
|
if (fsUploadFile)
|
|
|
|
|
|
fsUploadFile.write(upload.buf, upload.currentSize);
|
|
|
|
|
|
} else if (upload.status == UPLOAD_FILE_END) {
|
|
|
|
|
|
if (fsUploadFile)
|
|
|
|
|
|
fsUploadFile.close();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void handleFileDelete() {
|
|
|
|
|
|
if (HTTP.args() == 0) return HTTP.send(500, "text/plain", "BAD ARGS");
|
|
|
|
|
|
String path = HTTP.arg(0);
|
|
|
|
|
|
if (path == "/")
|
|
|
|
|
|
return HTTP.send(500, "text/plain", "BAD PATH");
|
|
|
|
|
|
if (!FileFS.exists(path))
|
|
|
|
|
|
return HTTP.send(404, "text/plain", "FileNotFound");
|
|
|
|
|
|
FileFS.remove(path);
|
|
|
|
|
|
HTTP.send(200, "text/plain", "");
|
|
|
|
|
|
path = String();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void handleFileCreate() {
|
|
|
|
|
|
if (HTTP.args() == 0)
|
|
|
|
|
|
return HTTP.send(500, "text/plain", "BAD ARGS");
|
|
|
|
|
|
String path = HTTP.arg(0);
|
|
|
|
|
|
if (path == "/")
|
|
|
|
|
|
return HTTP.send(500, "text/plain", "BAD PATH");
|
|
|
|
|
|
if (FileFS.exists(path))
|
|
|
|
|
|
return HTTP.send(500, "text/plain", "FILE EXISTS");
|
|
|
|
|
|
File file = FileFS.open(path, "w");
|
|
|
|
|
|
if (file)
|
|
|
|
|
|
file.close();
|
|
|
|
|
|
else
|
|
|
|
|
|
return HTTP.send(500, "text/plain", "CREATE FAILED");
|
|
|
|
|
|
HTTP.send(200, "text/plain", "");
|
|
|
|
|
|
path = String();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void handleFileList() {
|
|
|
|
|
|
if (!HTTP.hasArg("dir")) {
|
|
|
|
|
|
HTTP.send(500, "text/plain", "BAD ARGS");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
String path = HTTP.arg("dir");
|
|
|
|
|
|
Dir dir = FileFS.openDir(path);
|
|
|
|
|
|
path = String();
|
|
|
|
|
|
String output = "[";
|
|
|
|
|
|
while (dir.next()) {
|
|
|
|
|
|
File entry = dir.openFile("r");
|
|
|
|
|
|
if (output != "[") output += ',';
|
|
|
|
|
|
bool isDir = false;
|
|
|
|
|
|
output += "{\"type\":\"";
|
|
|
|
|
|
output += (isDir) ? "dir" : "file";
|
|
|
|
|
|
output += "\",\"name\":\"";
|
|
|
|
|
|
output += String(entry.name()).substring(1);
|
|
|
|
|
|
output += "\"}";
|
|
|
|
|
|
entry.close();
|
|
|
|
|
|
}
|
|
|
|
|
|
output += "]";
|
|
|
|
|
|
HTTP.send(200, "text/json", output);
|
|
|
|
|
|
}
|
|
|
|
|
|
#endif
|
|
|
|
|
|
#endif
|
2021-12-23 23:47:13 +01:00
|
|
|
|
|
|
|
|
|
|
#ifdef STANDARD_WEB_SOCKETS
|
|
|
|
|
|
void standWebSocketsInit() {
|
|
|
|
|
|
standWebSocket.begin();
|
|
|
|
|
|
standWebSocket.onEvent(webSocketEvent);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void webSocketEvent(uint8_t num, WStype_t type, uint8_t* payload, size_t length) {
|
|
|
|
|
|
switch (type) {
|
2021-12-30 23:58:56 +01:00
|
|
|
|
case WStype_ERROR: {
|
|
|
|
|
|
Serial.printf("[%u] Error!\n", num);
|
|
|
|
|
|
} break;
|
|
|
|
|
|
|
2021-12-24 00:06:37 +01:00
|
|
|
|
case WStype_DISCONNECTED: {
|
2021-12-23 23:47:13 +01:00
|
|
|
|
Serial.printf("[%u] Disconnected!\n", num);
|
2021-12-24 00:06:37 +01:00
|
|
|
|
} break;
|
2021-12-23 23:47:13 +01:00
|
|
|
|
|
|
|
|
|
|
case WStype_CONNECTED: {
|
|
|
|
|
|
IPAddress ip = standWebSocket.remoteIP(num);
|
|
|
|
|
|
Serial.printf("[%u] Connected from %d.%d.%d.%d url: %s\n", num, ip[0], ip[1], ip[2], ip[3], payload);
|
|
|
|
|
|
standWebSocket.sendTXT(num, "Connected");
|
|
|
|
|
|
} break;
|
|
|
|
|
|
|
2021-12-24 00:06:37 +01:00
|
|
|
|
case WStype_TEXT: {
|
2022-01-25 22:17:55 +01:00
|
|
|
|
//максимальное количество символов заголовка
|
|
|
|
|
|
size_t headerLenth = 7;
|
|
|
|
|
|
String headerStr;
|
|
|
|
|
|
headerStr.reserve(headerLenth + 1);
|
|
|
|
|
|
for (size_t i = 0; i < headerLenth; i++) {
|
|
|
|
|
|
headerStr += (char)payload[i];
|
2021-12-24 00:44:11 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2022-01-25 22:17:55 +01:00
|
|
|
|
if (headerStr == "/config") {
|
2022-01-24 00:57:22 +01:00
|
|
|
|
sendFileToWs5("/widgets.json", num);
|
|
|
|
|
|
sendFileToWs5("/config.json", num);
|
2021-12-24 00:44:11 +01:00
|
|
|
|
}
|
2022-01-10 23:37:21 +01:00
|
|
|
|
|
2022-01-25 22:17:55 +01:00
|
|
|
|
if (headerStr == "/gifnoc") {
|
|
|
|
|
|
writeFileUint8("config.json", payload, length, headerLenth);
|
2021-12-25 01:52:25 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2021-12-24 00:06:37 +01:00
|
|
|
|
} break;
|
2021-12-23 23:47:13 +01:00
|
|
|
|
|
2021-12-24 00:06:37 +01:00
|
|
|
|
case WStype_BIN: {
|
2021-12-23 23:47:13 +01:00
|
|
|
|
Serial.printf("[%u] get binary length: %u\n", num, length);
|
2021-12-24 22:49:06 +01:00
|
|
|
|
// hexdump(payload, length);
|
2021-12-23 23:47:13 +01:00
|
|
|
|
// standWebSocket.sendBIN(num, payload, length);
|
2021-12-24 00:06:37 +01:00
|
|
|
|
} break;
|
2021-12-30 23:58:56 +01:00
|
|
|
|
|
|
|
|
|
|
case WStype_FRAGMENT_TEXT_START: {
|
|
|
|
|
|
Serial.printf("[%u] fragment test start: %u\n", num, length);
|
|
|
|
|
|
} break;
|
|
|
|
|
|
|
|
|
|
|
|
case WStype_FRAGMENT_BIN_START: {
|
|
|
|
|
|
Serial.printf("[%u] fragment bin start: %u\n", num, length);
|
|
|
|
|
|
} break;
|
|
|
|
|
|
|
|
|
|
|
|
case WStype_FRAGMENT: {
|
|
|
|
|
|
Serial.printf("[%u] fragment: %u\n", num, length);
|
|
|
|
|
|
} break;
|
|
|
|
|
|
|
|
|
|
|
|
case WStype_FRAGMENT_FIN: {
|
|
|
|
|
|
Serial.printf("[%u] fragment finish: %u\n", num, length);
|
|
|
|
|
|
} break;
|
|
|
|
|
|
|
|
|
|
|
|
case WStype_PING: {
|
|
|
|
|
|
Serial.printf("[%u] ping: %u\n", num, length);
|
|
|
|
|
|
} break;
|
|
|
|
|
|
|
|
|
|
|
|
case WStype_PONG: {
|
|
|
|
|
|
Serial.printf("[%u] pong: %u\n", num, length);
|
|
|
|
|
|
} break;
|
|
|
|
|
|
|
|
|
|
|
|
default: {
|
|
|
|
|
|
Serial.printf("[%u] not recognized: %u\n", num, length);
|
|
|
|
|
|
} break;
|
2021-12-23 23:47:13 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2021-12-24 01:26:50 +01:00
|
|
|
|
#ifdef ESP32
|
|
|
|
|
|
void hexdump(const void* mem, uint32_t len, uint8_t cols = 16) {
|
|
|
|
|
|
const uint8_t* src = (const uint8_t*)mem;
|
|
|
|
|
|
Serial.printf("\n[HEXDUMP] Address: 0x%08X len: 0x%X (%d)", (ptrdiff_t)src, len, len);
|
|
|
|
|
|
for (uint32_t i = 0; i < len; i++) {
|
|
|
|
|
|
if (i % cols == 0) {
|
|
|
|
|
|
Serial.printf("\n[0x%08X] 0x%08X: ", (ptrdiff_t)src, i);
|
|
|
|
|
|
}
|
|
|
|
|
|
Serial.printf("%02X ", *src);
|
|
|
|
|
|
src++;
|
|
|
|
|
|
}
|
|
|
|
|
|
Serial.printf("\n");
|
|
|
|
|
|
}
|
|
|
|
|
|
#endif
|
2021-12-23 23:47:13 +01:00
|
|
|
|
#endif
|
2022-01-21 17:34:11 +01:00
|
|
|
|
|
2022-01-24 22:28:33 +01:00
|
|
|
|
//посылка данных из файла в бинарном виде
|
2022-01-25 00:14:23 +01:00
|
|
|
|
void sendFileToWs5(const char* filename, uint8_t num) {
|
2022-01-25 01:41:14 +01:00
|
|
|
|
sendMark(filename, "/st", num);
|
|
|
|
|
|
size_t ws_buffer = 1024;
|
2022-01-24 00:57:22 +01:00
|
|
|
|
String path = filepath(filename);
|
|
|
|
|
|
auto file = FileFS.open(path, "r");
|
|
|
|
|
|
if (!file) {
|
|
|
|
|
|
SerialPrint(F("E"), F("FS"), F("reed file error"));
|
|
|
|
|
|
}
|
|
|
|
|
|
size_t fileSize = file.size();
|
2022-01-25 00:14:23 +01:00
|
|
|
|
SerialPrint(F("i"), F("WS"), "Send file '" + String(filename) + "', file size: " + String(fileSize));
|
2022-01-24 00:57:22 +01:00
|
|
|
|
uint8_t payload[ws_buffer + 1];
|
|
|
|
|
|
int countRead = file.read(payload, sizeof(payload) - 1);
|
|
|
|
|
|
while (countRead > 0) {
|
|
|
|
|
|
payload[countRead] = 0;
|
2022-01-25 00:14:23 +01:00
|
|
|
|
standWebSocket.sendBIN(num, payload, countRead);
|
2022-01-24 00:57:22 +01:00
|
|
|
|
countRead = file.read(payload, sizeof(payload) - 1);
|
|
|
|
|
|
}
|
2022-01-25 01:41:14 +01:00
|
|
|
|
sendMark(filename, "/end", num);
|
2022-01-24 00:57:22 +01:00
|
|
|
|
}
|
2022-01-25 00:14:23 +01:00
|
|
|
|
|
2022-01-25 01:41:14 +01:00
|
|
|
|
void sendMark(const char* filename, const char* mark, uint8_t num) {
|
|
|
|
|
|
char outChar[strlen(filename) + strlen(mark) + 1];
|
|
|
|
|
|
strcpy(outChar, mark);
|
|
|
|
|
|
strcat(outChar, filename);
|
|
|
|
|
|
size_t size = strlen(outChar);
|
|
|
|
|
|
uint8_t outUint[size];
|
|
|
|
|
|
for (size_t i = 0; i < size; i++) {
|
|
|
|
|
|
outUint[i] = uint8_t(outChar[i]);
|
|
|
|
|
|
}
|
|
|
|
|
|
standWebSocket.sendBIN(num, outUint, sizeof(outUint));
|
|
|
|
|
|
}
|
2022-01-25 22:17:55 +01:00
|
|
|
|
|
|
|
|
|
|
//посылка данных из файла в string
|
|
|
|
|
|
// void sendFileToWs3(const String& filename, uint8_t num) {
|
|
|
|
|
|
// standWebSocket.sendTXT(num, "/st" + filename);
|
|
|
|
|
|
// size_t ws_buffer = 512;
|
|
|
|
|
|
// String path = filepath(filename);
|
|
|
|
|
|
// auto file = FileFS.open(path, "r");
|
|
|
|
|
|
// if (!file) {
|
|
|
|
|
|
// SerialPrint(F("E"), F("FS"), F("reed file error"));
|
|
|
|
|
|
// }
|
|
|
|
|
|
// size_t fileSize = file.size();
|
|
|
|
|
|
// SerialPrint(F("i"), F("WS"), "Send file '" + filename + "', file size: " + String(fileSize));
|
|
|
|
|
|
// String ret;
|
|
|
|
|
|
// char temp[ws_buffer + 1];
|
|
|
|
|
|
// int countRead = file.readBytes(temp, sizeof(temp) - 1);
|
|
|
|
|
|
// while (countRead > 0) {
|
|
|
|
|
|
// temp[countRead] = 0;
|
|
|
|
|
|
// ret = temp;
|
|
|
|
|
|
// standWebSocket.sendTXT(num, ret);
|
|
|
|
|
|
// countRead = file.readBytes(temp, sizeof(temp) - 1);
|
|
|
|
|
|
// }
|
|
|
|
|
|
// standWebSocket.sendTXT(num, "/end" + filename);
|
|
|
|
|
|
//}
|
|
|
|
|
|
|
|
|
|
|
|
//посылка данных из файла в char
|
|
|
|
|
|
// void sendFileToWs4(const String& filename, uint8_t num) {
|
|
|
|
|
|
// standWebSocket.sendTXT(num, "/st" + filename);
|
|
|
|
|
|
// size_t ws_buffer = 512;
|
|
|
|
|
|
// String path = filepath(filename);
|
|
|
|
|
|
// auto file = FileFS.open(path, "r");
|
|
|
|
|
|
// if (!file) {
|
|
|
|
|
|
// SerialPrint(F("E"), F("FS"), F("reed file error"));
|
|
|
|
|
|
// }
|
|
|
|
|
|
// size_t fileSize = file.size();
|
|
|
|
|
|
// SerialPrint(F("i"), F("WS"), "Send file '" + filename + "', file size: " + String(fileSize));
|
|
|
|
|
|
// char temp[ws_buffer + 1];
|
|
|
|
|
|
// int countRead = file.readBytes(temp, sizeof(temp) - 1);
|
|
|
|
|
|
// while (countRead > 0) {
|
|
|
|
|
|
// temp[countRead] = 0;
|
|
|
|
|
|
// standWebSocket.sendTXT(num, temp, countRead);
|
|
|
|
|
|
// countRead = file.readBytes(temp, sizeof(temp) - 1);
|
|
|
|
|
|
// }
|
|
|
|
|
|
//}
|