добавил обновление прошивки из веб морды
This commit is contained in:
parent
6467333846
commit
0dcc562b7d
1
.gitignore
vendored
1
.gitignore
vendored
@ -4,3 +4,4 @@ cmake-build-*
|
|||||||
cert.pem
|
cert.pem
|
||||||
key.pem
|
key.pem
|
||||||
dh.pem
|
dh.pem
|
||||||
|
/do-terminal-update.sh
|
||||||
|
28
src/main.cpp
28
src/main.cpp
@ -80,6 +80,19 @@ class ServerResources {
|
|||||||
std::unique_ptr<api_driver::ApiDriver> api;
|
std::unique_ptr<api_driver::ApiDriver> api;
|
||||||
http::auth::AuthProvider auth{};
|
http::auth::AuthProvider auth{};
|
||||||
|
|
||||||
|
void doTerminaFwUpdate(const http::server::Request& req) {
|
||||||
|
std::ofstream f("/tmp/firmware.zip", std::ios::binary);
|
||||||
|
|
||||||
|
if (f.is_open()) {
|
||||||
|
f.write(req.payload.data(), static_cast<long>(req.payload.size()));
|
||||||
|
f.close();
|
||||||
|
|
||||||
|
system("do-terminal-update.sh");
|
||||||
|
} else {
|
||||||
|
throw std::runtime_error("File is not open");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static constexpr const char* INDEX_HTML = "static/main.html";
|
static constexpr const char* INDEX_HTML = "static/main.html";
|
||||||
static constexpr const char* LOGIN_HTML = "static/login.html";
|
static constexpr const char* LOGIN_HTML = "static/login.html";
|
||||||
@ -322,6 +335,21 @@ public:
|
|||||||
rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size());
|
rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size());
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
s.resources.emplace_back(std::make_unique<http::auth::AuthRequiredResource>("/api/firmwareUpdate", this->auth, http::auth::User::UPDATE_FIRMWARE, [this](const auto& req, auto& rep) {
|
||||||
|
if (req.method != "PUT") {
|
||||||
|
http::server::stockReply(http::server::bad_request, rep);
|
||||||
|
}
|
||||||
|
this->doTerminaFwUpdate(req);
|
||||||
|
|
||||||
|
rep.status = http::server::ok;
|
||||||
|
rep.headers.clear();
|
||||||
|
rep.headers.push_back({.name = "Content-Type", .value = toString(mime_types::json)});
|
||||||
|
std::string result = R"({"status":"ok","fwsize":)";
|
||||||
|
result += std::to_string(req.payload.size());
|
||||||
|
result += "}";
|
||||||
|
rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size());
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
~ServerResources() = default;
|
~ServerResources() = default;
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
#include "request_parser.hpp"
|
#include "request_parser.hpp"
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include "request.hpp"
|
#include "request.hpp"
|
||||||
|
|
||||||
@ -14,16 +13,16 @@ namespace http::server {
|
|||||||
*/
|
*/
|
||||||
static bool requestBodySizeResolver(Request& req, size_t reqSize) {
|
static bool requestBodySizeResolver(Request& req, size_t reqSize) {
|
||||||
// разрешаем тело только для POST запросов
|
// разрешаем тело только для POST запросов
|
||||||
if (req.method != "POST") {
|
if (req.method == "POST") {
|
||||||
return false;
|
return reqSize < 0x4000; // 16кб на все POST-запросы к API будет более чем достаточно
|
||||||
}
|
}
|
||||||
|
|
||||||
// для обновления прошивки разрешаем большое тело
|
// это для обновления прошивки
|
||||||
if (req.url->path == "/api/firmwareUpdate") {
|
if (req.method == "PUT" && req.url->path == "/api/firmwareUpdate") {
|
||||||
return reqSize <= HTTP_MAX_PAYLOAD;
|
return reqSize <= HTTP_MAX_PAYLOAD;
|
||||||
}
|
}
|
||||||
|
|
||||||
return reqSize < 0x4000; // 16кб на все POST-запросы к API будет более чем достаточно
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void parseParams(Url& u, const std::string& query) {
|
static void parseParams(Url& u, const std::string& query) {
|
||||||
@ -277,7 +276,7 @@ namespace http::server {
|
|||||||
if (content_len.empty()) {
|
if (content_len.empty()) {
|
||||||
return good;
|
return good;
|
||||||
}
|
}
|
||||||
contentLenghtHeader = std::stol(content_len);
|
contentLenghtHeader = std::stoul(content_len);
|
||||||
if (contentLenghtHeader == 0) {
|
if (contentLenghtHeader == 0) {
|
||||||
return good;
|
return good;
|
||||||
}
|
}
|
||||||
|
@ -617,10 +617,10 @@
|
|||||||
|
|
||||||
<h3>Обновление ПО</h3>
|
<h3>Обновление ПО</h3>
|
||||||
<label>
|
<label>
|
||||||
<span>Порт для CinC</span>
|
<span>Файл {{ this.uploadFw.progress !== null ? `(${this.uploadFw.progress}%)` : '' }}</span>
|
||||||
<input type="file" accept="application/zip">
|
<input type="file" accept="application/zip" @change="(e) => { this.uploadFw.filename = e.target.files[0] }">
|
||||||
</label>
|
</label>
|
||||||
<button class="dangerous-button" @click="settingsUploadUpdate()">Обновить встроенное ПО</button>
|
<button class="dangerous-button" @click="settingsUploadUpdate()">Обновить встроенное ПО <span class="submit-spinner" v-show="submitStatus.firmwareUpload"></span></button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div hidden>
|
<div hidden>
|
||||||
@ -798,6 +798,7 @@
|
|||||||
network: false,
|
network: false,
|
||||||
debugSend: false,
|
debugSend: false,
|
||||||
tcpAccel: false,
|
tcpAccel: false,
|
||||||
|
firmwareUpload: false,
|
||||||
},
|
},
|
||||||
|
|
||||||
stat_rx: {
|
stat_rx: {
|
||||||
@ -951,6 +952,11 @@
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
uploadFw: {
|
||||||
|
progress: null,
|
||||||
|
filename: null
|
||||||
|
},
|
||||||
|
|
||||||
testState: false,
|
testState: false,
|
||||||
initState: '',
|
initState: '',
|
||||||
lastUpdateTime: new Date(),
|
lastUpdateTime: new Date(),
|
||||||
@ -1277,6 +1283,59 @@
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
|
async settingsUploadUpdate() {
|
||||||
|
if (!this.uploadFw.filename) {
|
||||||
|
alert('Выберите файл для загрузки');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function readFileAsArrayBuffer(fileName) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
if (!fileName) { reject(`Файл не выбран`); return }
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onload = (e) => { resolve(reader.result) }
|
||||||
|
reader.onerror = (e) => { reject(e) }
|
||||||
|
reader.readAsArrayBuffer(fileName)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.submitStatus.firmwareUpload = true
|
||||||
|
const blob = await readFileAsArrayBuffer(this.uploadFw.filename)
|
||||||
|
|
||||||
|
const xhr = new XMLHttpRequest();
|
||||||
|
const success = await new Promise((resolve) => {
|
||||||
|
xhr.upload.addEventListener("progress", (event) => {
|
||||||
|
if (event.lengthComputable) {
|
||||||
|
this.uploadFw.progress = Math.round((event.loaded / event.total) * 1000) / 10;
|
||||||
|
console.log("upload progress:", this.uploadFw.progress);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
xhr.addEventListener("loadend", () => {
|
||||||
|
this.uploadFw.progress = 100
|
||||||
|
resolve(xhr.readyState === 4 && xhr.status === 200);
|
||||||
|
});
|
||||||
|
xhr.open("PUT", "/api/firmwareUpdate", true);
|
||||||
|
xhr.setRequestHeader("Content-Type", "application/octet-stream");
|
||||||
|
xhr.send(blob);
|
||||||
|
});
|
||||||
|
console.log("success:", success);
|
||||||
|
// const result = await fetch('', {
|
||||||
|
// method: 'POST',
|
||||||
|
// body: await readFileAsArrayBuffer(this.uploadFw.filename),
|
||||||
|
// headers: {
|
||||||
|
// 'Content-Type': 'application/zip',
|
||||||
|
// },
|
||||||
|
// onuploadprogress: (progressEvent) => {
|
||||||
|
// this.uploadFw.progress = Math.round((progressEvent.loaded / progressEvent.total) * 100);
|
||||||
|
// },
|
||||||
|
// })
|
||||||
|
} catch (e) {
|
||||||
|
alert(`Ошибка загрузки файла: ${e}`);
|
||||||
|
}
|
||||||
|
this.submitStatus.firmwareUpload = false
|
||||||
|
},
|
||||||
|
|
||||||
performUpdateSettings(reloadParts) {
|
performUpdateSettings(reloadParts) {
|
||||||
const doFetchSettings = async () => {
|
const doFetchSettings = async () => {
|
||||||
let d = await fetch("/api/get/settings")
|
let d = await fetch("/api/get/settings")
|
||||||
|
Loading…
x
Reference in New Issue
Block a user