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 this.uploadFw.progress = 0 const blob = await readFileAsArrayBuffer(this.uploadFw.filename) const xhr = new XMLHttpRequest(); await new Promise((resolve) => { xhr.upload.addEventListener("progress", (event) => { if (event.lengthComputable) { this.uploadFw.progress = Math.round((event.loaded / event.total) * 1000) / 10; } }); xhr.addEventListener("loadend", () => { this.uploadFw.progress = 100 const rep = JSON.parse(xhr.responseText); this.uploadFw.sha256 = rep['sha256'] resolve(xhr.readyState === 4 && xhr.status === 200); }); xhr.open("PUT", "/api/firmwareUpdate", true); xhr.setRequestHeader("Content-Type", "application/octet-stream"); xhr.send(blob); }); } catch (e) { alert(`Ошибка загрузки файла: ${e}`); } this.submitStatus.firmwareUpload = false }, async settingsPerformFirmwareUpgrade() { if (this.submitStatus.firmwareUpgrade) { return } this.submitStatus.firmwareUpgrade = true try { await fetch('/api/doFirmwareUpgrade', { method: 'POST' }) } catch (e) { console.log("failed to perform upgrade firmware: ", e) } this.submitStatus.firmwareUpgrade = false }, {% if modem == 'tdma' %} async settingsPerformFirmwareUpgradeOta() { if (this.submitStatus.firmwareUpgradeOta) { return } this.submitStatus.firmwareUpgradeOta = true try { await fetch('/api/doFirmwareUpgrade?ota=1', { method: 'POST' }) } catch (e) { console.log("failed to perform upgrade firmware: ", e) } this.submitStatus.firmwareUpgradeOta = false }, {% endif %} doModemReboot() { if (this.submitStatus.modemReboot !== null) { return } this.submitStatus.modemReboot = 30 fetch('/api/reboot', { method: 'POST' }).then((r) => {}) }, async restoreAllSettings() { // Порядок применения настроек const settingsApplyOrder = ['qos', 'tcpaccel', 'rxtx', 'buclnb', 'network']; // 1. Чтение JSON-файла, выбранного пользователем const fileInput = document.createElement('input'); fileInput.type = 'file'; fileInput.accept = '.json'; const filePromise = new Promise((resolve, reject) => { fileInput.onchange = e => { const file = e.target.files[0]; if (!file) { reject(new Error('Файл не выбран')); return; } const reader = new FileReader(); reader.onload = event => { try { const jsonData = JSON.parse(event.target.result); resolve(jsonData); } catch (error) { reject(new Error('Ошибка парсинга JSON')); } }; reader.onerror = () => reject(new Error('Ошибка чтения файла')); reader.readAsText(file); }; fileInput.click(); }); try { const settingsToApply = await filePromise; const errors = []; // 2. Перебор групп параметров в заданном порядке for (const groupName of settingsApplyOrder) { if (!settingsToApply.hasOwnProperty(groupName)) { continue; // Пропускаем группы, которых нет в файле } const groupSettings = settingsToApply[groupName]; if (typeof groupSettings !== 'object' || groupSettings === null) { continue; } try { // 2.1. POST-запрос для применения группы параметров const postResponse = await fetch(`/api/set/${groupName}`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(groupSettings) }); if (!postResponse.ok) { throw new Error(`HTTP error ${postResponse.status}`); } const postResult = await postResponse.json(); if (postResult.status !== 'ok') { throw new Error(`API error: ${postResult.message || 'unknown error'}`); } // 2.2. Проверка примененных параметров const getResponse = await fetch('/api/get/settings', { method: 'GET' }); if (!getResponse.ok) { throw new Error(`HTTP error ${getResponse.status}`); } const fetchSettingsResult = await getResponse.json(); if (fetchSettingsResult.status !== 'ok') { throw new Error('Не удалось получить текущие настройки'); } // Проверка соответствия параметров const appliedGroup = fetchSettingsResult.settings[groupName] || {}; const failedSettings = []; for (const [key, value] of Object.entries(groupSettings)) { if (appliedGroup[key] !== value) { failedSettings.push(`${key} (ожидалось: ${value}, получено: ${appliedGroup[key]})`); } } if (failedSettings.length > 0) { throw new Error(`Не совпадают параметры: ${failedSettings.join(', ')}`); } } catch (groupError) { errors.push(`Группа ${groupName}: ${groupError.message}`); } } // 3. Показ ошибок, если они есть if (errors.length > 0) { const errorMessage = errors.join('\n\n') + '\n\nНекоторые настройки могли примениться некорректно.\nСтраница будет перезагружена.'; alert(errorMessage); } } catch (error) { alert(`Ошибка при восстановлении настроек: ${error.message}`); return; } // 4. Перезагрузка страницы location.reload(); }, async dumpAllSettings() { function downloadAsFile(data, filename) { let a = document.createElement("a"); let file = new Blob([data], {type: 'application/json'}); a.href = URL.createObjectURL(file); a.download = filename; a.click(); } const response = await fetch('/api/get/settings', { method: 'GET' }) if (response.ok) { const jres = await response.json() if (jres["status"] === "ok") { downloadAsFile(JSON.stringify(jres["settings"], null, 4), "backup-" + this.about.firmwareVersion + "-" + this.about.modemSn + ".json") } } },