refactor: improved OTA upgrade

This commit is contained in:
Yurii
2025-11-06 13:23:19 +03:00
parent f048d973d3
commit 192f4ee18b
2 changed files with 68 additions and 57 deletions

View File

@@ -22,7 +22,8 @@ public:
UpgradeType type;
UpgradeStatus status;
String error;
unsigned int written = 0;
size_t progress = 0;
size_t size = 0;
} UpgradeResult;
typedef std::function<bool(AsyncWebServerRequest *request, UpgradeType)> BeforeUpgradeCallback;
@@ -57,34 +58,47 @@ public:
this->firmwareResult.status = UpgradeStatus::NONE;
this->firmwareResult.error.clear();
this->firmwareResult.written = 0;
this->filesystemResult.status = UpgradeStatus::NONE;
this->filesystemResult.error.clear();
this->filesystemResult.written = 0;
}
void handleUpload(AsyncWebServerRequest *request, const String &fileName, size_t index, uint8_t *data, size_t dataLength, bool isFinal) override final {
UpgradeResult* result = nullptr;
unsigned int fileSize = 0;
const auto& fwName = request->hasParam("fw[name]", true) ? request->getParam("fw[name]", true)->value() : String();
const auto& fsName = request->hasParam("fs[name]", true) ? request->getParam("fs[name]", true)->value() : String();
if (fileName.equals(fwName)) {
result = &this->firmwareResult;
if (request->hasParam("fw[size]", true)) {
fileSize = request->getParam("fw[size]", true)->value().toInt();
}
} else if (fileName.equals(fsName)) {
result = &this->filesystemResult;
if (request->hasParam("fs[size]", true)) {
fileSize = request->getParam("fs[size]", true)->value().toInt();
}
if (!request->hasParam(asyncsrv::T_name, true, true)) {
// Missing content-disposition 'name' parameter
return;
}
if (result == nullptr || result->status != UpgradeStatus::NONE) {
const auto& pName = request->getParam(asyncsrv::T_name, true, true)->value();
if (pName.equals("fw")) {
result = &this->firmwareResult;
if (!index) {
result->progress = 0;
result->size = request->hasParam("fw_size", true)
? request->getParam("fw_size", true)->value().toInt()
: 0;
}
} else if (pName.equals("fs")) {
result = &this->filesystemResult;
if (!index) {
result->progress = 0;
result->size = request->hasParam("fs_size", true)
? request->getParam("fs_size", true)->value().toInt()
: 0;
}
} else {
// Unknown parameter name
return;
}
// check result status
if (result->status != UpgradeStatus::NONE) {
return;
}
@@ -93,18 +107,19 @@ public:
return;
}
if (!fileName.length() || !fileSize) {
if (!fileName.length()) {
result->status = UpgradeStatus::NO_FILE;
return;
}
if (index == 0) {
if (!index) {
// reset
if (Update.isRunning()) {
Update.end(false);
Update.clearError();
}
// try begin
bool begin = false;
if (result->type == UpgradeType::FIRMWARE) {
begin = Update.begin(UPDATE_SIZE_UNKNOWN, U_FLASH);
@@ -117,54 +132,52 @@ public:
result->status = UpgradeStatus::ERROR_ON_START;
result->error = Update.errorString();
Log.serrorln(FPSTR(L_PORTAL_OTA), F("File '%s', on start: %s"), fileName.c_str(), result->error.c_str());
Log.serrorln(FPSTR(L_PORTAL_OTA), "File '%s', on start: %s", fileName.c_str(), result->error.c_str());
return;
}
Log.sinfoln(FPSTR(L_PORTAL_OTA), F("File '%s', started"), fileName.c_str());
Log.sinfoln(FPSTR(L_PORTAL_OTA), "File '%s', started", fileName.c_str());
}
if (dataLength) {
result->written += dataLength;
if (Update.write(data, dataLength) != dataLength) {
Update.end(false);
result->status = UpgradeStatus::ERROR_ON_WRITE;
result->error = Update.errorString();
Log.serrorln(
FPSTR(L_PORTAL_OTA),
F("File '%s', on write %d bytes, %d of %d bytes"),
FPSTR(L_PORTAL_OTA), "File '%s', on write %d bytes, %d of %d bytes",
fileName.c_str(),
dataLength,
result->written,
fileSize
result->progress + dataLength,
result->size
);
return;
}
result->progress += dataLength;
Log.sinfoln(
FPSTR(L_PORTAL_OTA),
F("File '%s', write %d bytes, %d of %d bytes"),
FPSTR(L_PORTAL_OTA), "File '%s', write %d bytes, %d of %d bytes",
fileName.c_str(),
dataLength,
result->written,
fileSize
result->progress,
result->size
);
}
if (result->written > fileSize || (isFinal && result->written < fileSize)) {
Update.end(false);
result->status = UpgradeStatus::SIZE_MISMATCH;
if (result->size > 0) {
if (result->progress > result->size || (isFinal && result->progress < result->size)) {
Update.end(false);
result->status = UpgradeStatus::SIZE_MISMATCH;
Log.serrorln(
FPSTR(L_PORTAL_OTA),
F("File '%s', size mismatch: %d of %d bytes"),
fileName.c_str(),
result->written,
fileSize
);
return;
Log.serrorln(
FPSTR(L_PORTAL_OTA), "File '%s', size mismatch: %d of %d bytes",
fileName.c_str(),
result->progress,
result->size
);
return;
}
}
if (isFinal) {
@@ -172,12 +185,12 @@ public:
result->status = UpgradeStatus::ERROR_ON_FINISH;
result->error = Update.errorString();
Log.serrorln(FPSTR(L_PORTAL_OTA), F("File '%s', on finish: %s"), fileName.c_str(), result->error);
Log.serrorln(FPSTR(L_PORTAL_OTA), "File '%s', on finish: %s", fileName.c_str(), result->error);
return;
}
result->status = UpgradeStatus::SUCCESS;
Log.sinfoln(FPSTR(L_PORTAL_OTA), F("File '%s': finish"), fileName.c_str());
Log.sinfoln(FPSTR(L_PORTAL_OTA), "File '%s': finish", fileName.c_str());
}
}

View File

@@ -65,7 +65,7 @@
<label>
<span data-i18n>upgrade.fw</span>:
<div class="grid">
<input type="file" name="fw[file]" accept=".bin">
<input type="file" name="fw" accept=".bin">
<button type="button" class="fwResult hidden" disabled></button>
</div>
</label>
@@ -73,7 +73,7 @@
<label>
<span data-i18n>upgrade.fs</span>:
<div class="grid">
<input type="file" name="fs[file]" accept=".bin">
<input type="file" name="fs" accept=".bin">
<button type="button" class="fsResult hidden" disabled></button>
</div>
</label>
@@ -149,18 +149,16 @@
try {
let fd = new FormData();
const fw = upgradeForm.querySelector("[name='fw[file]']").files;
const fw = upgradeForm.querySelector("[name='fw']").files;
if (fw.length > 0) {
fd.append("fw[name]", fw[0].name);
fd.append("fw[size]", fw[0].size);
fd.append("fw[file]", fw[0]);
fd.append("fw_size", fw[0].size);
fd.append("fw", fw[0]);
}
const fs = upgradeForm.querySelector("[name='fs[file]']").files;
const fs = upgradeForm.querySelector("[name='fs']").files;
if (fs.length > 0) {
fd.append("fs[name]", fs[0].name);
fd.append("fs[size]", fs[0].size);
fd.append("fs[file]", fs[0]);
fd.append("fs_size", fs[0].size);
fd.append("fs", fs[0]);
}
let response = await fetch(upgradeForm.action, {