Compare commits
2 Commits
484a6abe08
...
0dcc562b7d
Author | SHA1 | Date | |
---|---|---|---|
0dcc562b7d | |||
6467333846 |
1
.gitignore
vendored
1
.gitignore
vendored
@ -4,3 +4,4 @@ cmake-build-*
|
||||
cert.pem
|
||||
key.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;
|
||||
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:
|
||||
static constexpr const char* INDEX_HTML = "static/main.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());
|
||||
}
|
||||
}));
|
||||
|
||||
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;
|
||||
|
@ -1,6 +1,5 @@
|
||||
#include "request_parser.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include "request.hpp"
|
||||
|
||||
@ -14,16 +13,16 @@ namespace http::server {
|
||||
*/
|
||||
static bool requestBodySizeResolver(Request& req, size_t reqSize) {
|
||||
// разрешаем тело только для POST запросов
|
||||
if (req.method != "POST") {
|
||||
return false;
|
||||
if (req.method == "POST") {
|
||||
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 < 0x4000; // 16кб на все POST-запросы к API будет более чем достаточно
|
||||
return false;
|
||||
}
|
||||
|
||||
static void parseParams(Url& u, const std::string& query) {
|
||||
@ -277,7 +276,7 @@ namespace http::server {
|
||||
if (content_len.empty()) {
|
||||
return good;
|
||||
}
|
||||
contentLenghtHeader = std::stol(content_len);
|
||||
contentLenghtHeader = std::stoul(content_len);
|
||||
if (contentLenghtHeader == 0) {
|
||||
return good;
|
||||
}
|
||||
|
161
static/main.html
161
static/main.html
@ -426,14 +426,14 @@
|
||||
<div class="settings-set-container">
|
||||
<label>
|
||||
<span>Активировать QoS</span>
|
||||
<span class="toggle-input"><input type="checkbox" v-model="qos.en" /><span class="slider"></span></span>
|
||||
<span class="toggle-input"><input type="checkbox" v-model="param.qos.en" /><span class="slider"></span></span>
|
||||
</label>
|
||||
</div>
|
||||
<template>
|
||||
<div v-for="classesGroup in ['rt1', 'rt2', 'rt3', 'cd']">
|
||||
<h3>Классы {{ classesGroup.toUpperCase() }}</h3>
|
||||
<button class="action-button" @click="qosAddClass(classesGroup)">Добавить класс {{ classesGroup.toUpperCase() }}</button>
|
||||
<details v-for="(qosClass, index) in qos[classesGroup]" :key="index" class="settings-set-container">
|
||||
<details v-for="(qosClass, index) in param.qos[classesGroup]" :key="index" class="settings-set-container">
|
||||
<summary>
|
||||
<span v-if="classesGroup === 'cd'">#{{ index }} CIR={{ qosClass.cir }}кбит, PIR={{ qosClass.pir }}кбит {{ qosClass.description }}</span>
|
||||
<span v-if="classesGroup !== 'cd'">#{{ index }} CBR={{ qosClass.cir }}кбит {{ qosClass.description }}</span>
|
||||
@ -531,11 +531,11 @@
|
||||
<div class="settings-set-container">
|
||||
<label>
|
||||
<span>Активировать акселерацию</span>
|
||||
<span class="toggle-input"><input type="checkbox" v-model="tcpAccel.en" /><span class="slider"></span></span>
|
||||
<span class="toggle-input"><input type="checkbox" v-model="param.tcpAccel.en" /><span class="slider"></span></span>
|
||||
</label>
|
||||
<label>
|
||||
<span>Максимальное количество соединений</span>
|
||||
<input type="number" v-model="tcpAccel.maxConnections" min="1" max="10000" />
|
||||
<input type="number" v-model="param.tcpAccel.maxConnections" min="1" max="10000" />
|
||||
</label>
|
||||
</div>
|
||||
<button class="action-button" @click="settingsSubmitTcpAccel()">Применить <span class="submit-spinner" v-show="submitStatus.tcpAccel"></span></button>
|
||||
@ -617,10 +617,10 @@
|
||||
|
||||
<h3>Обновление ПО</h3>
|
||||
<label>
|
||||
<span>Порт для CinC</span>
|
||||
<input type="file" accept="application/zip">
|
||||
<span>Файл {{ this.uploadFw.progress !== null ? `(${this.uploadFw.progress}%)` : '' }}</span>
|
||||
<input type="file" accept="application/zip" @change="(e) => { this.uploadFw.filename = e.target.files[0] }">
|
||||
</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 hidden>
|
||||
@ -798,6 +798,7 @@
|
||||
network: false,
|
||||
debugSend: false,
|
||||
tcpAccel: false,
|
||||
firmwareUpload: false,
|
||||
},
|
||||
|
||||
stat_rx: {
|
||||
@ -935,20 +936,25 @@
|
||||
modemSn: '?',
|
||||
macManagement: '?',
|
||||
macData: '?',
|
||||
}
|
||||
},
|
||||
|
||||
qos: {
|
||||
en: false,
|
||||
rt1: [],
|
||||
rt2: [],
|
||||
rt3: [],
|
||||
cd: [],
|
||||
},
|
||||
|
||||
tcpAccel: {
|
||||
en: false,
|
||||
maxConnections: 128
|
||||
},
|
||||
},
|
||||
|
||||
qos: {
|
||||
en: false,
|
||||
rt1: [],
|
||||
rt2: [],
|
||||
rt3: [],
|
||||
cd: [],
|
||||
},
|
||||
|
||||
tcpAccel: {
|
||||
en: false,
|
||||
maxConnections: 128
|
||||
uploadFw: {
|
||||
progress: null,
|
||||
filename: null
|
||||
},
|
||||
|
||||
testState: false,
|
||||
@ -1177,16 +1183,16 @@
|
||||
return res
|
||||
}
|
||||
let query = {
|
||||
"en": this.qos.en,
|
||||
"en": this.param.qos.en,
|
||||
"rt1": [],
|
||||
"rt2": [],
|
||||
"rt3": [],
|
||||
"cd": []
|
||||
}
|
||||
for (let i = 0; i < this.qos.rt1.length; i++) { query.rt1.push(_translateQosClass('rt', this.qos.rt1[i])) }
|
||||
for (let i = 0; i < this.qos.rt2.length; i++) { query.rt2.push(_translateQosClass('rt', this.qos.rt2[i])) }
|
||||
for (let i = 0; i < this.qos.rt3.length; i++) { query.rt3.push(_translateQosClass('rt', this.qos.rt3[i])) }
|
||||
for (let i = 0; i < this.qos.cd.length; i++) { query.cd.push(_translateQosClass('rt', this.qos.cd[i])) }
|
||||
for (let i = 0; i < this.param.qos.rt1.length; i++) { query.rt1.push(_translateQosClass('rt', this.param.qos.rt1[i])) }
|
||||
for (let i = 0; i < this.param.qos.rt2.length; i++) { query.rt2.push(_translateQosClass('rt', this.param.qos.rt2[i])) }
|
||||
for (let i = 0; i < this.param.qos.rt3.length; i++) { query.rt3.push(_translateQosClass('rt', this.param.qos.rt3[i])) }
|
||||
for (let i = 0; i < this.param.qos.cd.length; i++) { query.cd.push(_translateQosClass('rt', this.param.qos.cd[i])) }
|
||||
|
||||
console.log(query)
|
||||
fetch('/api/set/qos', {
|
||||
@ -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) {
|
||||
const doFetchSettings = async () => {
|
||||
let d = await fetch("/api/get/settings")
|
||||
@ -1360,14 +1419,14 @@
|
||||
|
||||
updateQosSettings(vals) {
|
||||
this.submitStatus.qos = false
|
||||
this.qos.en = vals["settings"]["qos.enabled"]
|
||||
this.param.qos.en = vals["settings"]["qos.enabled"]
|
||||
|
||||
const qosProfile = vals["settings"]["qos.profile"]
|
||||
if (qosProfile !== null && qosProfile !== undefined) {
|
||||
this.qos.rt1 = [] // .splice(0, this.qos.rt1.length)
|
||||
this.qos.rt2 = [] // .splice(0, this.qos.rt2.length)
|
||||
this.qos.rt3 = [] // .splice(0, this.qos.rt3.length)
|
||||
this.qos.cd = [] // .splice(0, this.qos.cd.length)
|
||||
this.param.qos.rt1 = [] // .splice(0, this.param.qos.rt1.length)
|
||||
this.param.qos.rt2 = [] // .splice(0, this.param.qos.rt2.length)
|
||||
this.param.qos.rt3 = [] // .splice(0, this.param.qos.rt3.length)
|
||||
this.param.qos.cd = [] // .splice(0, this.param.qos.cd.length)
|
||||
|
||||
for (let trafficClass in qosProfile) {
|
||||
if (['rt1', 'rt2', 'rt3', 'cd'].indexOf(trafficClass) < 0) {
|
||||
@ -1402,10 +1461,10 @@
|
||||
})
|
||||
}
|
||||
switch (trafficClass) {
|
||||
case 'rt1': this.qos.rt1.push(result); break
|
||||
case 'rt2': this.qos.rt2.push(result); break
|
||||
case 'rt3': this.qos.rt3.push(result); break
|
||||
case 'cd': this.qos.cd.push(result); break
|
||||
case 'rt1': this.param.qos.rt1.push(result); break
|
||||
case 'rt2': this.param.qos.rt2.push(result); break
|
||||
case 'rt3': this.param.qos.rt3.push(result); break
|
||||
case 'cd': this.param.qos.cd.push(result); break
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1448,7 +1507,6 @@
|
||||
this.param.firmware.macData = vals["settings"]["firmware.macData"]
|
||||
},
|
||||
|
||||
// addQosClass()
|
||||
qosAddClass(name) {
|
||||
let res = {
|
||||
isEnabled: true,
|
||||
@ -1458,10 +1516,10 @@
|
||||
filters: []
|
||||
}
|
||||
switch (name) {
|
||||
case 'rt1': this.qos.rt1.push(res); break
|
||||
case 'rt2': this.qos.rt2.push(res); break
|
||||
case 'rt3': this.qos.rt3.push(res); break
|
||||
case 'cd': this.qos.cd.push(res); break
|
||||
case 'rt1': this.param.qos.rt1.push(res); break
|
||||
case 'rt2': this.param.qos.rt2.push(res); break
|
||||
case 'rt3': this.param.qos.rt3.push(res); break
|
||||
case 'cd': this.param.qos.cd.push(res); break
|
||||
}
|
||||
},
|
||||
|
||||
@ -1477,28 +1535,28 @@
|
||||
dscp: ""
|
||||
}
|
||||
switch (name) {
|
||||
case 'rt1': this.qos.rt1[index].filters.push(rule); break
|
||||
case 'rt2': this.qos.rt2[index].filters.push(rule); break
|
||||
case 'rt3': this.qos.rt3[index].filters.push(rule); break
|
||||
case 'cd': this.qos.cd[index].filters.push(rule); break
|
||||
case 'rt1': this.param.qos.rt1[index].filters.push(rule); break
|
||||
case 'rt2': this.param.qos.rt2[index].filters.push(rule); break
|
||||
case 'rt3': this.param.qos.rt3[index].filters.push(rule); break
|
||||
case 'cd': this.param.qos.cd[index].filters.push(rule); break
|
||||
}
|
||||
},
|
||||
|
||||
qosDelClass(name, index) {
|
||||
switch (name) {
|
||||
case 'rt1': this.qos.rt1.splice(index, 1); break
|
||||
case 'rt2': this.qos.rt2.splice(index, 1); break
|
||||
case 'rt3': this.qos.rt3.splice(index, 1); break
|
||||
case 'cd': this.qos.cd.splice(index, 1); break
|
||||
case 'rt1': this.param.qos.rt1.splice(index, 1); break
|
||||
case 'rt2': this.param.qos.rt2.splice(index, 1); break
|
||||
case 'rt3': this.param.qos.rt3.splice(index, 1); break
|
||||
case 'cd': this.param.qos.cd.splice(index, 1); break
|
||||
}
|
||||
},
|
||||
|
||||
qosDelFilter(name, index, filterIndex) {
|
||||
switch (name) {
|
||||
case 'rt1': this.qos.rt1[index].filters.splice(filterIndex, 1); break
|
||||
case 'rt2': this.qos.rt2[index].filters.splice(filterIndex, 1); break
|
||||
case 'rt3': this.qos.rt3[index].filters.splice(filterIndex, 1); break
|
||||
case 'cd': this.qos.cd[index].filters.splice(filterIndex, 1); break
|
||||
case 'rt1': this.param.qos.rt1[index].filters.splice(filterIndex, 1); break
|
||||
case 'rt2': this.param.qos.rt2[index].filters.splice(filterIndex, 1); break
|
||||
case 'rt3': this.param.qos.rt3[index].filters.splice(filterIndex, 1); break
|
||||
case 'cd': this.param.qos.cd[index].filters.splice(filterIndex, 1); break
|
||||
}
|
||||
},
|
||||
|
||||
@ -1564,9 +1622,6 @@
|
||||
document.getElementById("app").removeAttribute("hidden")
|
||||
}
|
||||
})
|
||||
|
||||
// import MyComponent from './modules/header'
|
||||
// const sh = new Vue(MyComponent)
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
Loading…
x
Reference in New Issue
Block a user