Created
March 12, 2017 11:28
-
-
Save me-no-dev/01d309cd3760737238cec3468b96f117 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <ESPAsyncWebServer.h> | |
#include "SPI.h" | |
#include "SD.h" | |
bool SD_exists(String path){ | |
bool exists = false; | |
sd::File test = SD.open(path); | |
if(test){ | |
test.close(); | |
exists = true; | |
} | |
return exists; | |
} | |
class AsyncSDFileResponse: public AsyncAbstractResponse { | |
private: | |
sd::File _content; | |
String _path; | |
void _setContentType(String path){ | |
if (path.endsWith(".html")) _contentType = "text/html"; | |
else if (path.endsWith(".htm")) _contentType = "text/html"; | |
else if (path.endsWith(".css")) _contentType = "text/css"; | |
else if (path.endsWith(".txt")) _contentType = "text/plain"; | |
else if (path.endsWith(".js")) _contentType = "application/javascript"; | |
else if (path.endsWith(".png")) _contentType = "image/png"; | |
else if (path.endsWith(".gif")) _contentType = "image/gif"; | |
else if (path.endsWith(".jpg")) _contentType = "image/jpeg"; | |
else if (path.endsWith(".ico")) _contentType = "image/x-icon"; | |
else if (path.endsWith(".svg")) _contentType = "image/svg+xml"; | |
else if (path.endsWith(".xml")) _contentType = "text/xml"; | |
else if (path.endsWith(".pdf")) _contentType = "application/pdf"; | |
else if (path.endsWith(".zip")) _contentType = "application/zip"; | |
else if(path.endsWith(".gz")) _contentType = "application/x-gzip"; | |
else _contentType = "application/octet-stream"; | |
} | |
public: | |
AsyncSDFileResponse(String path, String contentType=String(), bool download=false){ | |
_code = 200; | |
_path = path; | |
if(!download && !SD_exists(_path) && SD_exists(_path+".gz")){ | |
_path = _path+".gz"; | |
addHeader("Content-Encoding", "gzip"); | |
} | |
if(download) | |
_contentType = "application/octet-stream"; | |
else | |
_setContentType(path); | |
_content = SD.open(_path); | |
_contentLength = _content.size(); | |
} | |
~AsyncSDFileResponse(){ | |
if(_content) | |
_content.close(); | |
} | |
bool _sourceValid(){ return !!(_content); } | |
size_t _fillBuffer(uint8_t *buf, size_t maxLen){ | |
int r = _content.read(buf, maxLen); | |
if(r < 0){ | |
os_printf("Error\n"); | |
_content.close(); | |
return 0; | |
} | |
return r; | |
} | |
}; | |
class SDEditor: public AsyncWebHandler { | |
private: | |
String _username; | |
String _password; | |
bool _uploadAuthenticated; | |
uint32_t _startTime; | |
sd::File uploadFile; | |
void _delete(String path){ | |
sd::File file = SD.open((char *)path.c_str()); | |
if(!file.isDirectory()){ | |
file.close(); | |
SD.remove((char *)path.c_str()); | |
return; | |
} | |
file.rewindDirectory(); | |
sd::File entry; | |
String entryPath; | |
while(true) { | |
entry = file.openNextFile(); | |
if (!entry) break; | |
entryPath = path + "/" +entry.name(); | |
if(entry.isDirectory()){ | |
entry.close(); | |
_delete(entryPath); | |
} else { | |
entry.close(); | |
SD.remove((char *)entryPath.c_str()); | |
} | |
entryPath = String(); | |
} | |
SD.rmdir((char *)path.c_str()); | |
path = String(); | |
file.close(); | |
} | |
public: | |
SDEditor(String username=String(), String password=String()):_username(username),_password(password),_uploadAuthenticated(false),_startTime(0){} | |
bool canHandle(AsyncWebServerRequest *request){ | |
if(request->method() == HTTP_GET && request->url() == "/edit" && (SD_exists((char*)"/edit.htm") || SD_exists((char*)"/edit.htm.gz"))) | |
return true; | |
else if(request->method() == HTTP_GET && request->url() == "/list") | |
return true; | |
else if(request->method() == HTTP_GET && (request->url().endsWith("/") || SD_exists(request->url()) || (!request->hasParam("download") && SD_exists(request->url()+".gz")))) | |
return true; | |
else if(request->method() == HTTP_POST && request->url() == "/edit") | |
return true; | |
else if(request->method() == HTTP_DELETE && request->url() == "/edit") | |
return true; | |
else if(request->method() == HTTP_PUT && request->url() == "/edit") | |
return true; | |
return false; | |
} | |
void handleRequest(AsyncWebServerRequest *request){ | |
if(_username.length() && (request->method() != HTTP_GET || request->url() == "/edit" || request->url() == "/list") && !request->authenticate(_username.c_str(),_password.c_str())) | |
return request->requestAuthentication(); | |
if(request->method() == HTTP_GET && request->url() == "/edit"){ | |
request->send(new AsyncSDFileResponse("/edit.htm")); | |
} else if(request->method() == HTTP_GET && request->url() == "/list"){ | |
if(request->hasParam("dir")){ | |
String path = request->getParam("dir")->value(); | |
sd::File entry; | |
sd::File dir = SD.open((char *)path.c_str()); | |
if(!dir.isDirectory()){ | |
dir.close(); | |
request->send(400); | |
} else { | |
dir.rewindDirectory(); | |
String output = "["; | |
while(true) { | |
entry = dir.openNextFile(); | |
if (!entry) break; | |
if (output != "[") output += ','; | |
output += "{\"type\":\""; | |
output += (entry.isDirectory())?"dir":"file"; | |
output += "\",\"name\":\""; | |
String name = String(entry.name()); | |
name.toLowerCase(); | |
output += name; | |
output += "\"}"; | |
entry.close(); | |
} | |
output += "]"; | |
dir.close(); | |
request->send(200, "text/json", output); | |
output = String(); | |
} | |
} | |
else | |
request->send(400); | |
} else if(request->method() == HTTP_GET){ | |
String path = request->url(); | |
if(path.endsWith("/")) | |
path += "index.htm"; | |
request->send(new AsyncSDFileResponse(path, String(), request->hasParam("download"))); | |
} else if(request->method() == HTTP_DELETE){ | |
if(request->hasParam("path", true) && SD_exists(request->getParam("path", true)->value())){ | |
_delete(request->getParam("path", true)->value()); | |
request->send(200, "", "DELETE: "+request->getParam("path", true)->value()); | |
} else | |
request->send(404); | |
} else if(request->method() == HTTP_POST){ | |
if(request->hasParam("data", true, true) && SD_exists(request->getParam("data", true, true)->value())) | |
request->send(200, "", "UPLOADED: "+request->getParam("data", true, true)->value()); | |
else | |
request->send(500); | |
} else if(request->method() == HTTP_PUT){ | |
if(request->hasParam("path", true)){ | |
String filename = request->getParam("path", true)->value(); | |
if(SD_exists(filename)){ | |
request->send(200); | |
} else { | |
sd::File f = SD.open(filename, FILE_WRITE | O_TRUNC); | |
if(f){ | |
f.write((uint8_t)0x00); | |
f.close(); | |
request->send(200, "", "CREATE: "+filename); | |
} else { | |
request->send(500); | |
} | |
} | |
} else | |
request->send(400); | |
} | |
} | |
void handleUpload(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final){ | |
if(!index){ | |
uploadFile = SD.open(filename, FILE_WRITE | O_TRUNC); | |
_startTime = millis(); | |
} | |
if(len && uploadFile) | |
uploadFile.write(data, len); | |
if(final){ | |
if(uploadFile) uploadFile.close(); | |
uint32_t uploadTime = millis() - _startTime; | |
os_printf("upload: %s, %u B, %u ms\n", filename.c_str(), index+len, uploadTime); | |
} | |
} | |
}; | |
const char *getSdTypeString(){ | |
if (SD.type() == SD_CARD_TYPE_SD1){ | |
return "SD1"; | |
} else if(SD.type() == SD_CARD_TYPE_SD2){ | |
return "SD2"; | |
} else if(SD.type() == SD_CARD_TYPE_SDHC){ | |
return "SDHC"; | |
} else { | |
return "UNKNOWN"; | |
} | |
} | |
String getSizeString(size_t bytes){ | |
if (bytes < 1024){ | |
return String(String(bytes)+"B"); | |
} else if(bytes < (1024 * 1024)){ | |
return String(String(bytes/1024.0)+"KB"); | |
} else if(bytes < (1024 * 1024 * 1024)){ | |
return String(String(bytes/1024.0/1024.0)+"MB"); | |
} else { | |
return String(String(bytes/1024.0/1024.0/1024.0)+"GB"); | |
} | |
} | |
bool initSD(){ | |
if (SD.begin(SS, 32000000)){ | |
Serial.print("\n==== SD Card Info ====\n"); | |
Serial.printf("SD Type: %s FAT%d, Size: %s\n", getSdTypeString(), SD.fatType(), getSizeString(SD.size()).c_str()); | |
Serial.printf("SD Blocks: total: %d, size: %s\n", SD.totalBlocks(), getSizeString(SD.blockSize()).c_str()); | |
Serial.printf("SD Clusters: total: %d, blocks: %d, size: %s\n", SD.totalClusters(), SD.blocksPerCluster(), getSizeString(SD.clusterSize()).c_str()); | |
sd::File entry; | |
sd::File dir = SD.open("/"); | |
dir.rewindDirectory(); | |
while(true){ | |
entry = dir.openNextFile(); | |
if (!entry) break; | |
Serial.printf("SD File: %s, type: %s, size: %s\n", entry.name(), (entry.isDirectory())?"dir":"file", getSizeString(entry.size()).c_str()); | |
entry.close(); | |
} | |
dir.close(); | |
Serial.println(); | |
return true; | |
} else | |
Serial.println("SD Card Not Found!"); | |
return false; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi, Im trying to compile it, but getting errors:
'sd' has not been declared
When remove 'sd::', I get:
'class fs::File' has no member named 'isDirectory'