diff --git a/.gitignore b/.gitignore index cd6780b..323f570 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,7 @@ cert.pem key.pem dh.pem /web-action + +# эти файлы после генерации должны быть перемещены в `/static` +front-generator/main-scpc.html +front-generator/main-tdma.html diff --git a/front-generator/render-params.json b/front-generator/render-params.json index 84c3c95..4e0e623 100644 --- a/front-generator/render-params.json +++ b/front-generator/render-params.json @@ -1,74 +1,336 @@ { - "monitoring-params": {}, - "params": { - "rxtx": { - "rx.en": { - "model": "w:switch", - "label": "Включить передатчик" - }, - "rx.isTestInputData": { - "model": "w:select", - "label": "Включить передатчик", - "items": [ - {"value": "false", "label": "Ethernet"}, - {"value": "true", "label": "Тест (CW)"} - ] - }, - "rx.freqKhz": { - "model": "w:number", - "number.type": "int", - "number.step": 1, - "number.min": 500000, - "number.max": 15000000 - } - } - }, "modem_types": { "tdma": { "modem_name": "RCSM-101 TDMA", - "groupsList": ["rxtx"], + "dangerousParamGroups": { + "buclnb": "Применение неправильных настроек может вывести из строя оборудование! Продолжить?", + "network": "Применение этих настроек может сделать модем недоступным! Продолжить?" + }, + "params": { + "rxtx": [ + {"widget": "h2", "label": "Настройки приема/передачи"}, + { + "widget": "flex-container", + "childs": [ + { + "widget": "settings-container", + "childs": [ + {"widget": "h3", "label": "Настройки передатчика"}, + {"widget": "checkbox", "label": "Включить передатчик", "name": "txEn"}, + { + "widget": "select", "label": "Входные данные", "name": "txIsTestInput", + "values": [ + {"label": "SCPC", "value": "false"}, + {"label": "Тест", "value": "true"} + ] + }, + {"widget": "number", "label": "Центральная частота, КГц", "name": "txCentralFreq", "min": 900000, "step": 0.01, "v_show": "paramRxrx.txIsTestInput"}, + {"widget": "number", "label": "Символьная скорость, Бод", "name": "txBaudrate", "min": 0, "step": 1, "v_show": "paramRxrx.txIsTestInput"}, + {"widget": "number", "label": "Ослабление, дБ", "name": "txAttenuation", "min": 0, "step": 1} + ] + }, + { + "widget": "settings-container", + "childs": [ + { "widget": "h3", "label": "Настройки приемника" }, + { + "widget": "select", "label": "Режим управления усилением", "name": "rxAgcEn", + "values": [ + {"label": "АРУ", "value": "true"}, + {"label": "РРУ", "value": "false"} + ] + }, + {"widget": "number", "label": "Ручное усиление, дБ", "name": "rxManualGain", "v_show": "!paramRxtx.rxAgcEn", "min": -40}, + {"widget": "checkbox", "label": "Инверсия спектра", "name": "rxSpectrumInversion"}, + {"widget": "number", "label": "Центральная частота, КГц", "name": "rxCentralFreq", "min": 900000, "step": 0.01}, + {"widget": "number", "label": "Символьная скорость, Бод", "name": "rxBaudrate", "min": 0, "step": 1}, + { + "widget": "select", "label": "Roll-off", "name": "rxRolloff", + "values": [{"label": "0.02", "value": "2"}, {"label": "0.05", "value": "5"}, {"label": "0.10", "value": "10"}, {"label": "0.15", "value": "15"}, {"label": "0.20", "value": "20"}, {"label": "0.25", "value": "25"}] + } + ] + } + ] + } + ], + "buclnb": [ + {"widget": "h2", "label": "Настройки питания и опорного генератора"}, + { + "widget": "flex-container", + "childs": [ + { + "widget": "settings-container", + "childs": [ + {"widget": "h3", "label": "Настройки BUC"}, + {"widget": "checkbox", "label": "Подача опоры 10МГц", "name": "bucRefClk10M"}, + { + "widget": "select", "label": "Питание BUC", "name": "bucPowering", + "values": [ + {"label": "Выкл", "value": "0"}, + {"label": "24В", "value": "24"} + ] + } + ] + }, + { + "widget": "settings-container", + "childs": [ + {"widget": "h3", "label": "Настройки LNB"}, + {"widget": "checkbox", "label": "Подача опоры 10МГц", "name": "lnbRefClk10M"}, + { + "widget": "select", "label": "Питание LNB", "name": "lnbPowering", + "values": [ + {"label": "Выкл", "value": "0"}, + {"label": "13В", "value": "13"}, + {"label": "18В", "value": "18"}, + {"label": "24В", "value": "24"} + ] + } + ] + }, + { + "widget": "settings-container", + "childs": [ + {"widget": "h3", "label": "Сервисные настройки"}, + {"widget": "checkbox", "label": "Подача опоры 10МГц на 'Выход 10МГц'", "name": "srvRefClk10M"}, + {"widget": "checkbox", "label": "Автозапуск BUC и LNB при включении", "name": "bucLnbAutoStart"} + ] + } + ] + } + ], + "network": [ + {"widget": "h2", "label": "Настройки сети"}, + { + "widget": "settings-container", + "childs": [ + {"widget": "h3", "label": "Настройки интерфейса управления"}, + {"widget": "ip-address", "label": "Интерфейс управления (/24)", "name": "netManagementIp"}, + { + "widget": "select", "label": "Режим сети", "name": "netIsL2", + "values": [{"label": "Маршрутизатор", "value": "false"}, {"label": "Коммутатор", "value": "true"}] + }, + {"widget": "ip-address", "label": "Интерфейс данных (/24)", "name": "netDataIp", "v_show": "paramNetwork.netIsL2 === false"}, + {"widget": "number", "label": "MTU интерфейса данных", "name": "netDataMtu", "min": 1500, "step": 1, "max": 2000} + ] + } + ] + }, "tabs": [ - { - "name": "monitoring", - "desc": "Мониторинг" - }, - { - "name": "setup", - "desc": "Настройки", - "widgets": [ - {"group": "html", "name": "h3", "payload": "Настройки передатчика"}, - {"group": "rxtx", "name": "rx.en"}, - {"group": "rxtx", "name": "rx.isTestInputData"}, - {"group": "html", "name": "h3", "payload": "Параметры передачи"}, - {"group": "rxtx", "name": "rx.freqKhz"} - ] - }, - { - "name": "admin", - "desc": "Администрирование" - } + {"name": "monitoring", "desc": "Мониторинг"}, + {"name": "setup", "desc": "Настройки"}, + {"name": "admin", "desc": "Администрирование"} ] }, "scpc": { "modem_name": "RCSM-101", - "groupsList": ["rxtx"], + "dangerousParamGroups": { + "buclnb": "Применение неправильных настроек может вывести из строя оборудование! Продолжить?", + "network": "Применение этих настроек может сделать модем недоступным! Продолжить?" + }, + "params": { + "rxtx": [ + {"widget": "h2", "label": "Настройки приема/передачи"}, + { + "widget": "settings-container", + "childs": [ + { + "widget": "select", "label": "Режим работы", "name": "isCinC", + "values": [{"label": "SCPC", "value": "false"}, {"label": "CinC", "value": "true"}] + } + ] + }, + { + "widget": "flex-container", + "childs": [ + { + "widget": "settings-container", + "childs": [ + {"widget": "h3", "label": "Настройки передатчика"}, + {"widget": "checkbox", "label": "Включить передатчик", "name": "txEn"}, + {"widget": "checkbox", "label": "Автоматический запуск передатчика", "name": "txAutoStart"}, + { + "widget": "select", "label": "Режим работы модулятора", "name": "txModulatorIsTest", + "values": [{"label": "Нормальный", "value": "false"}, {"label": "Тест (CW)", "value": "true"}] + }, + { + "widget": "select", "label": "Входные данные", "name": "txIsTestInput", + "values": [{"label": "SCPC", "value": "false"}, {"label": "Тест", "value": "true"}] + }, + {"widget": "h3", "label": "Параметры передачи"}, + {"widget": "number", "label": "Центральная частота, КГц", "name": "txCentralFreq", "min": 900000, "step": 0.01}, + {"widget": "number", "label": "Символьная скорость, Бод", "name": "txBaudrate", "min": 0, "step": 1}, + { + "widget": "select", "label": "Roll-off", "name": "txRolloff", + "values": [{"label": "0.02", "value": "2"}, {"label": "0.05", "value": "5"}, {"label": "0.10", "value": "10"}, {"label": "0.15", "value": "15"}, {"label": "0.20", "value": "20"}, {"label": "0.25", "value": "25"}] + }, + { + "widget": "select", "label": "Номер последовательности Голда", "name": "txGoldan", + "values": [{"label": "0", "value": "0"}, {"label": "1", "value": "1"}] + }, + {"widget": "number", "label": "Ослабление, дБ", "name": "txAttenuation", "min": 0, "step": 1} + ] + }, + { + "widget": "settings-container", + "childs": [ + {"widget": "h3", "label": "Режим работы DVB-S2"}, + {"widget": "number", "label": "Период служебных пакетов, сек", "name": "dvbServicePacketPeriod", "min": 0, "step": 1, "max": 60}, + { + "widget": "select", "label": "Режим модуляции", "name": "dvbIsAcm", + "values": [{"label": "CCM", "value": "false"}, {"label": "ACM", "value": "true"}] + }, + { + "widget": "select", "label": "Размер кадра", "name": "txFrameSizeNormal", + "values": [{"label": "normal", "value": "true"}, {"label": "short", "value": "false"}] + }, + {"widget": "modulation-modcod", "label": "Модуляция", "name": "dvbCcm", "v_show": "paramRxtx.dvbIsAcm === false"}, + {"widget": "modulation-speed", "label": "Скорость кода", "name": "dvbCcm", "v_show": "paramRxtx.dvbIsAcm === false"}, + {"widget": "watch", "label": "Текущий модкод", "model": "statRx.modcod", "v_show": "paramRxtx.dvbIsAcm === true"}, + {"widget": "modulation-modcod", "label": "Модуляция (мин. режим)", "name": "dvbAcmMin", "v_show": "paramRxtx.dvbIsAcm === true"}, + {"widget": "modulation-speed", "label": "Скорость кода (мин. режим)", "name": "dvbAcmMin", "v_show": "paramRxtx.dvbIsAcm === true"}, + {"widget": "modulation-modcod", "label": "Модуляция (макс. режим)", "name": "dvbAcmMax", "v_show": "paramRxtx.dvbIsAcm === true"}, + {"widget": "modulation-speed", "label": "Скорость кода (макс. режим)", "name": "dvbAcmMax", "v_show": "paramRxtx.dvbIsAcm === true"}, + {"widget": "number", "label": "Запас ОСШ, дБ", "name": "dvbSnrReserve", "min": 0, "step": 0.01, "max": 10} + ] + }, + { + "widget": "settings-container", + "childs": [ + {"widget": "h3", "label": "Авто-регулировка мощности"}, + {"widget": "checkbox", "label": "Авто-регулировка мощности", "name": "aupcEn"}, + {"widget": "number", "label": "Минимальное ослабление, дБ", "name": "aupcMinAttenuation", "min": 0, "step": 0.01, "max": 10}, + {"widget": "number", "label": "Максимальное ослабление, дБ", "name": "aupcMaxAttenuation", "min": 0, "step": 0.01, "max": 10}, + {"widget": "number", "label": "Требуемое ОСШ", "name": "aupcRequiredSnr", "min": 0, "step": 0.01, "max": 10} + ] + }, + { + "widget": "settings-container", + "childs": [ + {"widget": "h3", "label": "Настройки приемника"}, + { + "widget": "select", "label": "Режим управления усилением", "name": "rxAgcEn", + "values": [{"label": "РРУ", "value": "false"}, {"label": "АРУ", "value": "true"}] + }, + {"widget": "number", "label": "Усиление, дБ", "name": "rxManualGain", "min": -40, "step": 0.01, "max": 40, "v_show": "paramRxtx.rxAgcEn === false"}, + {"widget": "checkbox", "label": "Инверсия спектра", "name": "rxSpectrumInversion"}, + {"widget": "number", "label": "Центральная частота, КГц", "name": "rxCentralFreq", "min": 900000, "step": 0.01}, + {"widget": "number", "label": "Символьная скорость, Бод", "name": "rxBaudrate", "min": 0, "step": 1}, + { + "widget": "select", "label": "Roll-off", "name": "rxRolloff", + "values": [{"label": "0.02", "value": "2"}, {"label": "0.05", "value": "5"}, {"label": "0.10", "value": "10"}, {"label": "0.15", "value": "15"}, {"label": "0.20", "value": "20"}, {"label": "0.25", "value": "25"}] + }, + { + "widget": "select", "label": "Номер последовательности Голда", "name": "rxGoldan", + "values": [{"label": "0", "value": "0"}, {"label": "1", "value": "1"}] + } + ] + } + ] + } + ], + "cinc": [ + {"widget": "h2", "label": "Настройки режима CinC", "v_show": "paramRxtx.isCinC"}, + { + "widget": "settings-container", "v_show": "paramRxtx.isCinC", + "childs": [ + { + "widget": "select", "label": "Метод расчета задержки", "name": "cincIsPositional", + "values": [ + {"label": "Позиционированием", "value": "true"}, + {"label": "Окном задержки", "value": "false"} + ] + }, + {"widget": "number", "label": "Полоса поиска, КГц ±", "name": "cincSearchBandwidth", "min": 0, "step": 1, "max": 100}, + {"widget": "h2", "label": "Настройки позиционирования", "v_show": "paramCinc.cincIsPositional === true"}, + {"widget": "number", "label": "Широта станции", "name": "cincPositionStationLatitude", "v_show": "paramCinc.cincIsPositional === true", "min": -180, "step": 0.000001, "max": 180}, + {"widget": "number", "label": "Долгота станции", "name": "cincPositionStationLongitude", "v_show": "paramCinc.cincIsPositional === true", "min": -180, "step": 0.000001, "max": 180}, + {"widget": "number", "label": "Подспутниковая точка", "name": "cincPositionSatelliteLongitude", "v_show": "paramCinc.cincIsPositional === true", "min": -180, "step": 0.000001, "max": 180}, + {"widget": "h2", "label": "Задержка до спутника", "v_show": "paramCinc.cincIsPositional === false"}, + {"widget": "number", "label": "от, мс", "name": "cincDelayMin", "v_show": "paramCinc.cincIsPositional === false", "min": 0, "step": 0.1, "max": 400}, + {"widget": "number", "label": "до, мс", "name": "cincDelayMax", "v_show": "paramCinc.cincIsPositional === false", "min": 0, "step": 0.1, "max": 400}] + }, + {"widget": "submit", "v_show": "paramRxtx.isCinC"} + ], + "buclnb": [ + {"widget": "h2", "label": "Настройки питания и опорного генератора"}, + { + "widget": "flex-container", + "childs": [ + { + "widget": "settings-container", + "childs": [ + {"widget": "h3", "label": "Настройки BUC"}, + {"widget": "checkbox", "label": "Подача опоры 10МГц", "name": "bucRefClk10M"}, + { + "widget": "select", "label": "Питание BUC", "name": "bucPowering", + "values": [ + {"label": "Выкл", "value": "0"}, + {"label": "24В", "value": "24"}, + {"label": "48В", "value": "48"} + ] + } + ] + }, + { + "widget": "settings-container", + "childs": [ + {"widget": "h3", "label": "Настройки LNB"}, + {"widget": "checkbox", "label": "Подача опоры 10МГц", "name": "lnbRefClk10M"}, + { + "widget": "select", "label": "Питание LNB", "name": "lnbPowering", + "values": [ + {"label": "Выкл", "value": "0"}, + {"label": "13В", "value": "13"}, + {"label": "18В", "value": "18"}, + {"label": "24В", "value": "24"} + ] + } + ] + }, + { + "widget": "settings-container", + "childs": [ + {"widget": "h3", "label": "Сервисные настройки"}, + {"widget": "checkbox", "label": "Подача опоры 10МГц на 'Выход 10МГц'", "name": "srvRefClk10M"}, + {"widget": "checkbox", "label": "Автозапуск BUC и LNB при включении", "name": "bucLnbAutoStart"} + ] + } + ] + } + ], + "tcpaccel": [ + {"widget": "h2", "label": "Настройки TCP-акселерации"}, + { + "widget": "settings-container", + "childs": [ + {"widget": "checkbox", "label": "Активировать акселерацию", "name": "accelEn"}, + {"widget": "number", "label": "Максимальное количество соединений", "name": "accelMaxConnections", "min": 0, "step": 1, "max": 4000} + ] + } + ], + "network": [ + {"widget": "h2", "label": "Настройки сети"}, + { + "widget": "settings-container", + "childs": [ + {"widget": "h3", "label": "Настройки интерфейса управления"}, + {"widget": "ip-address", "label": "Интерфейс управления (/24)", "name": "netManagementIp"}, + { + "widget": "select", "label": "Режим сети", "name": "netIsL2", + "values": [{"label": "Маршрутизатор", "value": "false"}, {"label": "Коммутатор", "value": "true"}] + }, + {"widget": "ip-address", "label": "Интерфейс данных (/24)", "name": "netDataIp", "v_show": "paramNetwork.netIsL2 === false"}, + {"widget": "number", "label": "MTU интерфейса данных", "name": "netDataMtu", "min": 1500, "step": 1, "max": 2000} + ] + } + ] + }, "tabs": [ - { - "name": "monitoring", - "desc": "Мониторинг" - }, - { - "name": "setup", - "desc": "Настройки" - }, - { - "name": "qos", - "desc": "QoS" - }, - { - "name": "admin", - "desc": "Администрирование" - } + {"name": "monitoring", "desc": "Мониторинг"}, + {"name": "setup", "desc": "Настройки"}, + {"name": "qos", "desc": "QoS"}, + {"name": "admin", "desc": "Администрирование"} ] } } diff --git a/front-generator/render.py b/front-generator/render.py index 5dbef8f..14704a5 100644 --- a/front-generator/render.py +++ b/front-generator/render.py @@ -1,22 +1,90 @@ import json - from jinja2 import Environment, FileSystemLoader import sys +import os + +with open('render-params.json') as f: + GLOBAL_CONFIG = json.load(f) + + +def extract_param_names(mc): + result = [] + + def helper_extract(widget): + if 'childs' in widget: + r = [] + for child in widget['childs']: + r += helper_extract(child) + return r + elif 'name' in widget: + match widget['widget']: + case 'select': return [{"name": widget['name'], "initValue": widget['values'][0]['value']}] + case 'checkbox': return [{"name": widget['name'], "initValue": 'false'}] + case 'number': return [{"name": widget['name'], "initValue": widget['min'] if widget['min'] else '0'}] + case 'modulation-modcod': return [{"name": widget['name'] + "Modulation", "initValue": '"QPSK"'}] + case 'modulation-speed': return [{"name": widget['name'] + "Speed", "initValue": '"1/4"'}] + case 'watch': return [] + + return [{"name": widget['name'], "initValue": 'null'}] + return [] + + for cat in mc['params']: + ws = [] + for w in mc['params'][cat]: + ws += helper_extract(w) + # ws.sort(key=lambda k: k['name']) + result.append({ + "group": cat, + "params": ws + }) + + return result + + +def add_submit_widgets(params): + def find_submit(w): + if w['widget'] == 'submit': + return True + if 'childs' in w: + for c in w['childs']: + if find_submit(c): + return True + return False + + for group in params: + wid_found = False + for wid in params[group]: + if find_submit(wid): + wid_found = True + break + if wid_found: + continue + + params[group].append({"widget": "submit"}) + + + +def extract_param_groups(mc): + return [k for k in mc['params']] def build_modem_env(modem): - with open('render-params.json') as f: - config = json.load(f) - if modem not in config['modem_types']: + if modem not in GLOBAL_CONFIG['modem_types']: raise RuntimeError(f"Modem '{modem}' is not exist in config!") - mc = config['modem_types'][modem] + mc = GLOBAL_CONFIG['modem_types'][modem] + + add_submit_widgets(mc['params']) return { + "modem": modem, "modem_name": mc['modem_name'], "header_tabs": mc['tabs'], - "js_tabs_array": str([t['name'] for t in mc['tabs']]), - "params": {"groupsList": mc["groupsList"]} | config["params"] + "tab_names_array": [t['name'] for t in mc['tabs']], + "params": mc["params"], + "dangerousParamGroups": mc["dangerousParamGroups"] if 'dangerousParamGroups' in mc else {}, + "paramGroups": extract_param_names(mc), + "paramGroupsList": extract_param_groups(mc), } @@ -32,8 +100,8 @@ def render_modem(modem): if __name__ == '__main__': - if len(sys.argv) != 2: - print(f"Usage: {sys.argv[0]} ") - - render_modem(sys.argv[1]) + for mt in GLOBAL_CONFIG['modem_types']: + print(f'Generating {mt} modem...') + render_modem(mt) + os.system(f'cp -u main-{mt}.html ../static') diff --git a/front-generator/template/common/admin-methods.js.j2 b/front-generator/template/common/admin-methods.js.j2 new file mode 100644 index 0000000..407738b --- /dev/null +++ b/front-generator/template/common/admin-methods.js.j2 @@ -0,0 +1,62 @@ + 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 + }, + + doModemReboot() { + if (this.submitStatus.modemReboot !== null) { + return + } + this.submitStatus.modemReboot = 30 + fetch('/api/reboot', { method: 'POST' }).then((r) => {}) + }, diff --git a/front-generator/template/common/admin.html.j2 b/front-generator/template/common/admin.html.j2 new file mode 100644 index 0000000..ee8fbfc --- /dev/null +++ b/front-generator/template/common/admin.html.j2 @@ -0,0 +1,34 @@ +{% from 'common/widgets.j2' import build_widget %} +
+ {% if 'network' in params %} + {% for w in params['network'] %}{{ build_widget('network', w) | indent(12, true) }}{% endfor %} + {% endif %} + {% raw %} +

Система

+
+ + + + + + + + +
Версия ПО{{ about.firmwareVersion }}
ID модема{{ about.modemUid }}
Серийный номер{{ about.modemSn }}
MAC интерфейса управления{{ about.macManagement }}
MAC интерфейса управления{{ about.macData }}
+
+ +
+
+ +
+ +

Обновление ПО

+ + + +
{% endraw %} +
diff --git a/front-generator/template/common/all-params-data.js.j2 b/front-generator/template/common/all-params-data.js.j2 new file mode 100644 index 0000000..02445a9 --- /dev/null +++ b/front-generator/template/common/all-params-data.js.j2 @@ -0,0 +1,7 @@ +{% for g in paramGroups %} + param{{ g['group'] | title }}: { + {% for p in g['params'] %} + {{ p['name'] }}: {{ p['initValue'] }}, + {% endfor %} + }, +{% endfor %} \ No newline at end of file diff --git a/front-generator/template/common/all-params-methods.js.j2 b/front-generator/template/common/all-params-methods.js.j2 new file mode 100644 index 0000000..82d61cd --- /dev/null +++ b/front-generator/template/common/all-params-methods.js.j2 @@ -0,0 +1,29 @@ + {% for g in paramGroups %} + settingsSubmit{{ g['group'] | title }}() { + if (this.submitStatus.{{ g['group'] }}) { return } + {% if g['group'] in dangerousParamGroups %} + { if (!confirm("{{ dangerousParamGroups[g['group']] }}")) return } + {% endif %} + + let query = { + {% for p in g['params'] %} + "{{ p['name'] }}": this.param{{ g['group'] | title }}.{{ p['name'] }}, + {% endfor %} + } + + this.submitStatus.{{ g['group'] }} = true + fetch('/api/set/{{ g["group"] }}', {method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify(query) }) + .then(async (resp) => { this.update{{ g['group'] | title }}Settings(await resp.json()) }) + .catch((reason) => { alert(`Ошибка при применении настроек: ${reason}`) }) + .finally(() => { this.submitStatus.{{ g['group'] }} = false }) + }, + {% endfor %} + + {% for g in paramGroups %} + update{{ g['group'] | title }}Settings(vals) { + this.submitStatus.{{ g['group'] }} = false + {% for p in g['params'] %} + this.param{{ g['group'] | title }}.{{ p['name'] }} = vals["settings"]["{{ p['name'] }}"] + {% endfor %} + }, + {% endfor %} \ No newline at end of file diff --git a/front-generator/template/common/monitoring-data.js.j2 b/front-generator/template/common/monitoring-data.js.j2 new file mode 100644 index 0000000..87777fe --- /dev/null +++ b/front-generator/template/common/monitoring-data.js.j2 @@ -0,0 +1,47 @@ + statRx: { + // индикаторы + state: '?', // общее состояние + sym_sync_lock: '?', // захват символьной + freq_search_lock: '?', // Захват поиска по частоте + afc_lock: '?', // захват ФАПЧ + pkt_sync: '?', // захват пакетной синхронизации + + // куча других параметров, идет в том же порядке, что и в таблице + snr: '?', rssi: '?', + modcod: '?', frameSizeNormal: '?', + isPilots: '?', + symError: '?', + freqErr: '?', freqErrAcc: '?', + inputSignalLevel: '?', + pllError: '?', + speedOnRxKbit: '?', + speedOnIifKbit: '?', + + // статистика пакетов + packetsOk: '?', packetsBad: '?', packetsDummy: '?', + }, + statTx: { + // состояние + state: '?', + + // прочие поля + {% if modem == 'scpc' %} + snr: '?', modcod: '?', frameSizeNormal: '?', isPilots: '?', speedOnTxKbit: '?', speedOnIifKbit: '?', + {% else %} + modcod: '?', speedOnTxKbit: '?', speedOnIifKbit: '?', centerFreq: '?', symSpeed: '?', + {% endif %} + }, + {% if modem == 'scpc' %} + statCinc: { + occ: '?', + correlator: null, + correlatorFails: '?', + freqErr: '?', freqErrAcc: '?', + channelDelay: '?' + }, + {% endif %} + statDevice: { // температурные датчики + adrv: 0, zynq: 0, fpga: 0 + }, + statOs: {uptime: '?', load1: '?', load5: '?', load15: '?', totalram: '?', freeram: '?'}, + diff --git a/front-generator/template/common/monitoring-methods.js.j2 b/front-generator/template/common/monitoring-methods.js.j2 new file mode 100644 index 0000000..bc5d411 --- /dev/null +++ b/front-generator/template/common/monitoring-methods.js.j2 @@ -0,0 +1,102 @@ + updateStatistics(vals) { + function modcodToStr(modcod) { + // модкоды из раздела 5.5.2.2 https://www.etsi.org/deliver/etsi_en/302300_302399/302307/01.01.02_60/en_302307v010102p.pdf + const modcods = [ + "DUMMY", + "QPSK 1/4", "QPSK 1/3", "QPSK 2/5", "QPSK 1/2", "QPSK 3/5", "QPSK 2/3", "QPSK 3/4", "QPSK 4/5", "QPSK 5/6", "QPSK 8/9", "QPSK 9/10", + "8PSK 3/5", "8PSK 2/3", "8PSK 3/4", "8PSK 5/6", "8PSK 8/9", "8PSK 9/10", + "16APSK 2/3", "16APSK 3/4", "16APSK 4/5", "16APSK 5/6", "16APSK 8/9", "16APSK 9/10", + "32APSK 3/4", "32APSK 4/5", "32APSK 5/6", "32APSK 8/9", "32APSK 9/10", + ] + if (typeof modcod != "number" || modcod < 0 || modcod >= modcod.length) { + return "?"; + } + return modcods[modcod] + } + + this.lastUpdateTime = new Date(); + this.initState = vals["mainState"]["initState"] + {% if modem == 'scpc' %} + this.isCinC = vals["mainState"]["isCinC"] + {% endif %} + + this.statRx.state = vals["mainState"]["rx.state"] + this.statRx.sym_sync_lock = vals["mainState"]["rx.sym_sync_lock"] + this.statRx.freq_search_lock = vals["mainState"]["rx.freq_search_lock"] + this.statRx.afc_lock = vals["mainState"]["rx.afc_lock"] + this.statRx.pkt_sync = vals["mainState"]["rx.pkt_sync"] + this.statRx.snr = vals["mainState"]["rx.snr"] + this.statRx.rssi = vals["mainState"]["rx.rssi"] + this.statRx.modcod = modcodToStr(vals["mainState"]["rx.modcod"]) + this.statRx.frameSizeNormal = vals["mainState"]["rx.frameSizeNormal"] + this.statRx.isPilots = vals["mainState"]["rx.isPilots"] + this.statRx.symError = vals["mainState"]["rx.symError"] + this.statRx.freqErr = vals["mainState"]["rx.freqErr"] + this.statRx.freqErrAcc = vals["mainState"]["rx.freqErrAcc"] + this.statRx.inputSignalLevel = vals["mainState"]["rx.inputSignalLevel"] + this.statRx.pllError = vals["mainState"]["rx.pllError"] + this.statRx.speedOnRxKbit = vals["mainState"]["rx.speedOnRxKbit"] + this.statRx.speedOnIifKbit = vals["mainState"]["rx.speedOnIifKbit"] + this.statRx.packetsOk = vals["mainState"]["rx.packetsOk"] + this.statRx.packetsBad = vals["mainState"]["rx.packetsBad"] + this.statRx.packetsDummy = vals["mainState"]["rx.packetsDummy"] + + {% if modem == 'scpc' %} + this.statTx.state = vals["mainState"]["tx.state"] + this.statTx.snr = vals["mainState"]["tx.snr"] + this.statTx.modcod = modcodToStr(vals["mainState"]["tx.modcod"]) + this.statTx.frameSizeNormal = vals["mainState"]["tx.frameSizeNormal"] + this.statTx.isPilots = vals["mainState"]["tx.isPilots"] + this.statTx.speedOnTxKbit = vals["mainState"]["tx.speedOnTxKbit"] + this.statTx.speedOnIifKbit = vals["mainState"]["tx.speedOnIifKbit"] + + this.statCinc.occ = vals["mainState"]["cinc.occ"] + this.statCinc.correlator = vals["mainState"]["cinc.correlator"] + this.statCinc.correlatorFails = vals["mainState"]["cinc.correlatorFails"] + this.statCinc.freqErr = vals["mainState"]["cinc.freqErr"] + this.statCinc.freqErrAcc = vals["mainState"]["cinc.freqErrAcc"] + this.statCinc.channelDelay = vals["mainState"]["cinc.channelDelay"] + {% else %} + this.statTx.state = vals["mainState"]["tx.state"] + this.statTx.modcod = modcodToStr(vals["mainState"]["tx.modcod"]) + this.statTx.speedOnTxKbit = vals["mainState"]["tx.speedOnTxKbit"] + this.statTx.speedOnIifKbit = vals["mainState"]["tx.speedOnIifKbit"] + this.statTx.centerFreq = vals["mainState"]["tx.centerFreq"] + this.statTx.symSpeed = vals["mainState"]["tx.symSpeed"] + {% endif %} + + this.statDevice.adrv = vals["mainState"]["device.adrv"] + this.statDevice.zynq = vals["mainState"]["device.zynq"] + this.statDevice.fpga = vals["mainState"]["device.fpga"] + + this.testState = vals["mainState"]["testState"] + + // аптайм приходит в секундах, надо преобразовать его в человеко-читаемый вид + let uptime = vals["sysinfo"]["uptime"] + if (uptime) { + let secs = uptime % 60; uptime = Math.floor(uptime / 60) + let mins = uptime % 60; uptime = Math.floor(uptime / 60) + let hours = uptime % 24 + uptime = Math.floor( uptime / 24) + let res = `${hours}:${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}` + if (uptime > 0) { res = `${uptime} days, ` + res } + this.statOs.uptime = res + } else { + this.statOs.uptime = '?' + } + this.statOs.load1 = vals["sysinfo"]["load1min"] + this.statOs.load5 = vals["sysinfo"]["load5min"] + this.statOs.load15 = vals["sysinfo"]["load15min"] + this.statOs.totalram = vals["sysinfo"]["totalram"] + this.statOs.freeram = vals["sysinfo"]["freeram"] + }, + + resetPacketsStatistics() { + fetch('/api/resetPacketStatistics', { + method: 'POST' + }).then(() => { + this.statRx.packetsOk = 0 + this.statRx.packetsBad = 0 + this.statRx.packetsDummy = 0 + }) + }, \ No newline at end of file diff --git a/front-generator/template/common/monitoring.html.j2 b/front-generator/template/common/monitoring.html.j2 new file mode 100644 index 0000000..d1c1f82 --- /dev/null +++ b/front-generator/template/common/monitoring.html.j2 @@ -0,0 +1,84 @@ + {% raw %} +
+
+

Статистика приема

+ + + + + + + + + + + + + + + + + + +
Прием
Захват символьной
Захват ФАПЧ
Захват поиска по частоте
Захват пакетной синхр.
SNR/RSSI{{ statRx.snr }} / {{ statRx.rssi }}
Modcod{{ statRx.modcod }}
Размер кадра{{ statRx.frameSizeNormal ? 'normal' : 'short' }}
Пилот-символы{{ statRx.isPilots ? 'pilots' : 'no pilots' }}
Символьная ошибка{{ statRx.symError }}
Грубая/точная част. ошибка, Гц{{ statRx.freqErr }} / {{ statRx.freqErrAcc }}
Ур. входного сигнала{{ statRx.inputSignalLevel }}
Ошибка ФАПЧ{{ statRx.pllError }}
Инф. скорость на приеме{{ statRx.speedOnRxKbit }} kbit/s
Инф. скорость на интерфейсе{{ statRx.speedOnIifKbit }} kbit/s
+

Статистика пакетов

+ + + + + + +
Качественных пакетов{{ statRx.packetsOk }}
Поврежденных пакетов{{ statRx.packetsBad }}
DUMMY{{ statRx.packetsDummy }}
+ +
+
+

Статистика передачи

{% endraw %}{% if modem == 'scpc' %}{% raw %} + + + + + + + + + + +
Передача
ОСШ дальнего приема{{ statTx.snr }}
Modcod{{ statTx.modcod }}
Размер кадра{{ statTx.frameSizeNormal ? 'normal' : 'short' }}
Пилот-символы{{ statTx.isPilots ? 'pilots' : 'no pilots' }}
Инф. скорость на передаче{{ statTx.speedOnTxKbit }} kbit/s
Инф. скорость на интерфейсе{{ statTx.speedOnIifKbit }} kbit/s
{% endraw %}{% else %}{% raw %} + + + + + + + + + +
Передача
Modcod{{ statTx.modcod }}
Инф. скорость на передаче{{ statTx.speedOnTxKbit }} kbit/s
Инф. скорость на интерфейсе{{ statTx.speedOnIifKbit }} kbit/s
Центральная частота{{ statTx.centerFreq }} kHz
Символьная скорость{{ statTx.symSpeed }} ksymb
{% endraw %}{% endif %}{% raw %} +
{% endraw %}{% if modem == 'scpc' %}{% raw %} +
+

Статистика режима CinC

+ + + + + + + + +
ОСС{{ statCinc.occ }}
Захват коррелятора
Кол-во срывов коррелятора{{ statCinc.correlatorFails }}
Грубая/точная част. ошибка, Гц{{ statCinc.freqErr }} / {{ statCinc.freqErrAcc }}
Задержка в канале, мс{{ statCinc.channelDelay }}
+
{% endraw %}{% endif %}{% raw %} +
+

Состояние устройства

+ + + + + + + + + +
Температура ADRV{{ statDevice.adrv }} °C
Температура ZYNQ{{ statDevice.zynq }} °C
Температура FPGA{{ statDevice.fpga }} °C
Uptime{{ statOs.uptime }}
Load average{{ statOs.load1 }} {{ statOs.load5 }} {{ statOs.load15 }}
RAM total/free{{ statOs.totalram }}Mb/{{ statOs.freeram }}Mb
+
+
+ {% endraw %} \ No newline at end of file diff --git a/front-generator/template/common/qos-data.js.j2 b/front-generator/template/common/qos-data.js.j2 new file mode 100644 index 0000000..31da867 --- /dev/null +++ b/front-generator/template/common/qos-data.js.j2 @@ -0,0 +1,8 @@ + submitStatusQos: false, + paramQos: { + en: false, + rt1: [], + rt2: [], + rt3: [], + cd: [], + }, diff --git a/front-generator/template/common/qos-methods.js.j2 b/front-generator/template/common/qos-methods.js.j2 new file mode 100644 index 0000000..c234bf9 --- /dev/null +++ b/front-generator/template/common/qos-methods.js.j2 @@ -0,0 +1,221 @@ + settingsSubmitQoS() { + if (this.submitStatusQos) { return } + this.submitStatusQos = true + function _translateQosClass(trafficClass, qc) { + let res = { + cir: qc['cir'], + description: qc['description'], + filters: [] + } + if (trafficClass === 'cd') { + res.pir = qc.pir + } + if (!qc.isEnabled) { + res.disabled = true + } + for (const fi in qc.filters) { + let filter = {} + if (qc['filters'][fi].vlan !== "") { filter['vlan'] = qc['filters'][fi].vlan } + if (qc['filters'][fi].proto.length > 0) { + let tmp = ""; + for (let pid = 0; pid < qc['filters'][fi].proto.length; pid++) { + if (pid !== 0) { tmp += ',' } + tmp += qc['filters'][fi].proto[pid] + } + filter['proto'] = tmp + } + if (qc['filters'][fi].sport !== "") { filter['sport'] = qc['filters'][fi].sport } + if (qc['filters'][fi].dport !== "") { filter['dport'] = qc['filters'][fi].dport } + if (qc['filters'][fi].ip_src !== "") { filter['ip_src'] = qc['filters'][fi].ip_src } + if (qc['filters'][fi].ip_dest !== "") { filter['ip_dest'] = qc['filters'][fi].ip_dest } + if (qc['filters'][fi].dscp !== "") { filter['dscp'] = qc['filters'][fi].dscp } + + if (Object.keys(filter).length === 0) { continue } + if (!qc.filters[fi].isEnabled) { filter['disabled'] = true } + + res.filters.push(filter) + } + if (res.filters.length === 0) { + // автоматическое выключение класса, если правил нет + res.disabled = true + } + + return res + } + let query = { + "en": this.paramQos.en, + "rt1": [], + "rt2": [], + "rt3": [], + "cd": [] + } + for (let i = 0; i < this.paramQos.rt1.length; i++) { query.rt1.push(_translateQosClass('rt', this.paramQos.rt1[i])) } + for (let i = 0; i < this.paramQos.rt2.length; i++) { query.rt2.push(_translateQosClass('rt', this.paramQos.rt2[i])) } + for (let i = 0; i < this.paramQos.rt3.length; i++) { query.rt3.push(_translateQosClass('rt', this.paramQos.rt3[i])) } + for (let i = 0; i < this.paramQos.cd.length; i++) { query.cd.push(_translateQosClass('rt', this.paramQos.cd[i])) } + + //console.log(query) + fetch('/api/set/qos', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify(query) + }).then(async (resp) => { + this.submitStatusQos = false + this.updateQosSettings(await resp.json()) + }).catch((reason) => { + this.submitStatusQos = false + alert(`Ошибка при применении настроек: ${reason}`) + }) + }, + + updateQosSettings(vals) { + this.submitStatusQos = false + this.paramQos.en = vals["settings"]["qos.enabled"] + + const qosProfile = vals["settings"]["qos.profile"] + if (qosProfile !== null && qosProfile !== undefined) { + this.paramQos.rt1 = [] // .splice(0, this.paramQos.rt1.length) + this.paramQos.rt2 = [] // .splice(0, this.paramQos.rt2.length) + this.paramQos.rt3 = [] // .splice(0, this.paramQos.rt3.length) + this.paramQos.cd = [] // .splice(0, this.paramQos.cd.length) + + for (let trafficClass in qosProfile) { + if (['rt1', 'rt2', 'rt3', 'cd'].indexOf(trafficClass) < 0) { + continue + } + + if (Array.isArray(qosProfile[trafficClass])) { + for (let i = 0; i < qosProfile[trafficClass].length; i++) { + const qc = qosProfile[trafficClass][i] + let result = { + isEnabled: !qc.hasOwnProperty('disabled'), + cir: qc['cir'], + pir: 0, + description: qc['description'], + filters: [] + } + if (trafficClass === 'cd') { + if (qc['pir']) { + result.pir = qc['pir'] + } + } + for (let fi = 0; fi < qc['filters'].length; fi++) { + result.filters.push({ + isEnabled: !qc['filters'][fi].hasOwnProperty('disabled'), + vlan: qc['filters'][fi].hasOwnProperty('vlan') ? qc['filters'][fi]['vlan'] : '', + proto: qc['filters'][fi].hasOwnProperty('proto') ? qc['filters'][fi]['proto'].split(',') : [], + sport: qc['filters'][fi].hasOwnProperty('sport') ? qc['filters'][fi]['sport'] : '', + dport: qc['filters'][fi].hasOwnProperty('dport') ? qc['filters'][fi]['dport'] : '', + ip_src: qc['filters'][fi].hasOwnProperty('ip_src') ? qc['filters'][fi]['ip_src'] : '', + ip_dest: qc['filters'][fi].hasOwnProperty('ip_dest') ? qc['filters'][fi]['ip_dest'] : '', + dscp: qc['filters'][fi].hasOwnProperty('dscp') ? qc['filters'][fi]['dscp'] : '' + }) + } + switch (trafficClass) { + case 'rt1': this.paramQos.rt1.push(result); break + case 'rt2': this.paramQos.rt2.push(result); break + case 'rt3': this.paramQos.rt3.push(result); break + case 'cd': this.paramQos.cd.push(result); break + } + } + } + } + } + }, + + qosAddClass(name) { + let res = { + isEnabled: true, + cir: 0, + pir: 0, + description: "", + filters: [] + } + switch (name) { + case 'rt1': this.paramQos.rt1.push(res); break + case 'rt2': this.paramQos.rt2.push(res); break + case 'rt3': this.paramQos.rt3.push(res); break + case 'cd': this.paramQos.cd.push(res); break + } + }, + + qosClassAddRule(name, index) { + let rule = { + isEnabled: true, + vlan: "", + proto: [], + sport: "", + dport: "", + ip_src: "", + ip_dest: "", + dscp: "" + } + switch (name) { + case 'rt1': this.paramQos.rt1[index].filters.push(rule); break + case 'rt2': this.paramQos.rt2[index].filters.push(rule); break + case 'rt3': this.paramQos.rt3[index].filters.push(rule); break + case 'cd': this.paramQos.cd[index].filters.push(rule); break + } + }, + + qosDelClass(name, index) { + switch (name) { + case 'rt1': this.paramQos.rt1.splice(index, 1); break + case 'rt2': this.paramQos.rt2.splice(index, 1); break + case 'rt3': this.paramQos.rt3.splice(index, 1); break + case 'cd': this.paramQos.cd.splice(index, 1); break + } + }, + + qosDelFilter(name, index, filterIndex) { + switch (name) { + case 'rt1': this.paramQos.rt1[index].filters.splice(filterIndex, 1); break + case 'rt2': this.paramQos.rt2[index].filters.splice(filterIndex, 1); break + case 'rt3': this.paramQos.rt3[index].filters.splice(filterIndex, 1); break + case 'cd': this.paramQos.cd[index].filters.splice(filterIndex, 1); break + } + }, + + qosGenerateRuleDescription(filter) { + // попытка 1: просто отобразить все фильтры + let result = "" + let isFirst = true; + for (const key in filter) { + if (key === "isEnabled" || !filter[key] || (key === "proto" && filter['proto'].length === 0)) { + continue + } + if (isFirst) { + isFirst = false; + } else { + result += '; ' + } + result += `${key}: ${filter[key]}` + } + if (result === "") { + return "пустой" + } + + const maxResultLen = 60 + + if (result.length > maxResultLen) { + // попытка 2, отобразить что вообще в этом фильтре использовалось + result = "" + isFirst = true; + for (const key in filter) { + if (key === "isEnabled" || !filter[key] || (key === "proto" && filter['proto'].length === 0)) { + continue + } + if (isFirst) { + isFirst = false; + } else { + result += ', ' + } + result += `${key}` + } + } + + return result + }, + diff --git a/front-generator/template/common/qos.html.j2 b/front-generator/template/common/qos.html.j2 new file mode 100644 index 0000000..26ba039 --- /dev/null +++ b/front-generator/template/common/qos.html.j2 @@ -0,0 +1,107 @@ +{% from 'common/widgets.j2' import build_widget %} +{% raw %} +
+

Настройки QoS

+
+ +
+
+

Классы {{ classesGroup.toUpperCase() }}

+
+ + #{{ index }} CIR={{ qosClass.cir }}кбит, PIR={{ qosClass.pir }}кбит {{ qosClass.description }} + #{{ index }} CBR={{ qosClass.cir }}кбит {{ qosClass.description }} + + + + + + + + +

Фильтры ({{ qosClass.filters.length }})

+
+ +
+
+ + #{{ filterIndex }} {{ qosGenerateRuleDescription(filter) }} + + + + + + +
+ Протокол L3 + + + + + + + + + + +
+ + + + + +
+ +
+ +
+
+
+ + + {% endraw %}{% if 'tcpaccel' in params %} + {% for w in params['tcpaccel'] %}{{ build_widget('tcpaccel', w) | indent(12, true) }}{% endfor %} + {% endif %} +
\ No newline at end of file diff --git a/front-generator/template/common/setup.html.j2 b/front-generator/template/common/setup.html.j2 new file mode 100644 index 0000000..6587bc8 --- /dev/null +++ b/front-generator/template/common/setup.html.j2 @@ -0,0 +1,8 @@ +{% from 'common/widgets.j2' import build_widget %} +
+ {% for cat in ['rxtx', 'cinc', 'buclnb'] %} + {% if cat in params %} + {% for w in params[cat] %}{{ build_widget(cat, w) | indent(12, true) }}{% endfor %} + {% endif %} + {% endfor %} +
\ No newline at end of file diff --git a/front-generator/template/common/widgets.j2 b/front-generator/template/common/widgets.j2 new file mode 100644 index 0000000..c481d71 --- /dev/null +++ b/front-generator/template/common/widgets.j2 @@ -0,0 +1,63 @@ +{% macro build_widget_checkbox(param_group, widget) %} + {{ widget.label }} + +{% endmacro %} + +{# https://ru.stackoverflow.com/questions/1241064 #} +{% macro build_widget_number(param_group, widget) %}{{ widget.label }}{% endmacro %} + +{% macro build_widget_select(param_group, widget) %} + {{ widget.label }} + +{% endmacro %} + +{% macro build_widget_watch(param_group, widget) %}{{ widget.label }}{% endmacro %} + +{% macro build_widget_modulation_modcod(param_group, widget) %} + {{ widget.label }} + +{% endmacro %} + +{% macro build_widget_modulation_speed(param_group, widget) %} + {{ widget.label }} + +{% endmacro %} + +{% macro build_widget_flex_container(param_group, widget) %}
+{% for w in widget.childs %}{{ build_widget(param_group, w) | indent(4, true) }}{% endfor %} +
{% endmacro %} + +{% macro build_widget_settings_container(param_group, widget) %}
+{% for w in widget.childs %}{{ build_widget(param_group, w) | indent(4, true) }}{% endfor %} +
{% endmacro %} + +{% macro build_widget_ip_address(param_group, widget) %} + {{ widget.label }} + +{% endmacro %} + +{% macro build_widget(param_group, widget) %}{% if widget.widget == 'flex-container' %}{{ build_widget_flex_container(param_group, widget) }} +{% elif widget.widget == 'settings-container' %}{{ build_widget_settings_container(param_group, widget) }} +{% elif widget.widget == 'h2' %}{{ widget.label }} +{% elif widget.widget == 'h3' %}{{ widget.label }} +{% elif widget.widget == 'submit' %} +{% elif widget.widget == 'checkbox' %}{{ build_widget_checkbox(param_group, widget) }} +{% elif widget.widget == 'number' %}{{ build_widget_number(param_group, widget) }} +{% elif widget.widget == 'watch' %}{{ build_widget_watch(param_group, widget) }} +{% elif widget.widget == 'select' %}{{ build_widget_select(param_group, widget) }} +{% elif widget.widget == 'modulation-modcod' %}{{ build_widget_modulation_modcod(param_group, widget) }} +{% elif widget.widget == 'modulation-speed' %}{{ build_widget_modulation_speed(param_group, widget) }} +{% elif widget.widget == 'ip-address' %}{{ build_widget_ip_address(param_group, widget) }} +{% else %}

Widget '{{ widget.widget }}' not defined!

{{ widget }}

+{% endif %} +{% endmacro %} diff --git a/front-generator/template/default-js.js b/front-generator/template/default-js.js deleted file mode 100644 index 049de9c..0000000 --- a/front-generator/template/default-js.js +++ /dev/null @@ -1,139 +0,0 @@ -{% raw %}// для обновления высоты хидера -function updateHeaderHeight() { const header = document.querySelector('header'); document.body.style.setProperty('--header-height', `${header.offsetHeight}px`); } -window.addEventListener('load', updateHeaderHeight); window.addEventListener('resize', updateHeaderHeight); - -function getCurrentTab() { - const sl = window.location.hash.slice(1) - if (availableTabs.indexOf(sl) >= 0) { - return sl - } - return defaultTab -} - -function modcodToStr(modcod) { - // модкоды из раздела 5.5.2.2 https://www.etsi.org/deliver/etsi_en/302300_302399/302307/01.01.02_60/en_302307v010102p.pdf - - // NOTE модкоды со скоростью хода 3/5 не работают - const modcods = [ - "DUMMY", - "QPSK 1/4", - "QPSK 1/3", - "QPSK 2/5", - "QPSK 1/2", - "QPSK 3/5", // отключено - "QPSK 2/3", - "QPSK 3/4", - "QPSK 4/5", - "QPSK 5/6", - "QPSK 8/9", - "QPSK 9/10", - - "8PSK 3/5", // отключено - "8PSK 2/3", - "8PSK 3/4", - "8PSK 5/6", - "8PSK 8/9", - "8PSK 9/10", - - "16APSK 2/3", - "16APSK 3/4", - "16APSK 4/5", - "16APSK 5/6", - "16APSK 8/9", - "16APSK 9/10", - - "32APSK 3/4", - "32APSK 4/5", - "32APSK 5/6", - "32APSK 8/9", - "32APSK 9/10", - ] - if (typeof modcod != "number" || modcod < 0 || modcod >= modcod.length) { - return "?"; - } - return modcods[modcod] -} - -function toModcod(modulation, speed) { - switch (modulation.toLowerCase()) { - case 'qpsk': - switch (speed) { - case '1/4': return 1 - case '1/3': return 2 - case '2/5': return 3 - case '1/2': return 4 - case '3/5': return 5 // отключено - case '2/3': return 6 - case '3/4': return 7 - case '4/5': return 8 - case '5/6': return 9 - case '8/9': return 10 - case '9/10': return 11 - default: return 1 // минимальная скорость - } - case '8psk': - switch (speed) { - case '3/5': return 12 // отключено - case '2/3': return 13 - case '3/4': return 14 - case '5/6': return 15 - case '8/9': return 16 - case '9/10': return 17 - default: return 13 // минимальная скорость - } - case '16apsk': - switch (speed) { - case '2/3': return 18 - case '3/4': return 19 - case '4/5': return 20 - case '5/6': return 21 - case '8/9': return 22 - case '9/10': return 23 - default: return 18 // минимальная скорость - } - case '32apsk': - switch (speed) { - case '3/4': return 24 - case '4/5': return 25 - case '5/6': return 26 - case '8/9': return 27 - case '9/10': return 28 - default: return 24 - } - } -} - -function extractModulationAndSpeedFromModcod(modcod) { - switch (modcod) { - case 1: return { modulation: 'qpsk', speed: '1/4' } - case 2: return { modulation: 'qpsk', speed: '1/3' } - case 3: return { modulation: 'qpsk', speed: '2/5' } - case 4: return { modulation: 'qpsk', speed: '1/2' } - case 5: return { modulation: 'qpsk', speed: '3/5' } - case 6: return { modulation: 'qpsk', speed: '2/3' } - case 7: return { modulation: 'qpsk', speed: '3/4' } - case 8: return { modulation: 'qpsk', speed: '4/5' } - case 9: return { modulation: 'qpsk', speed: '5/6' } - case 10: return { modulation: 'qpsk', speed: '8/9' } - case 11: return { modulation: 'qpsk', speed: '9/10' } - case 12: return { modulation: '8psk', speed: '3/5' } - case 13: return { modulation: '8psk', speed: '2/3' } - case 14: return { modulation: '8psk', speed: '3/4' } - case 15: return { modulation: '8psk', speed: '5/6' } - case 16: return { modulation: '8psk', speed: '8/9' } - case 17: return { modulation: '8psk', speed: '9/10' } - case 18: return { modulation: '16apsk', speed: '2/3' } - case 19: return { modulation: '16apsk', speed: '3/4' } - case 20: return { modulation: '16apsk', speed: '4/5' } - case 21: return { modulation: '16apsk', speed: '5/6' } - case 22: return { modulation: '16apsk', speed: '8/9' } - case 23: return { modulation: '16apsk', speed: '9/10' } - case 24: return { modulation: '32apsk', speed: '3/4' } - case 25: return { modulation: '32apsk', speed: '4/5' } - case 26: return { modulation: '32apsk', speed: '5/6' } - case 27: return { modulation: '32apsk', speed: '8/9' } - case 28: return { modulation: '32apsk', speed: '9/10' } - } - return { modulation: 'qpsk', speed: '1/4' } -} -{% endraw %} \ No newline at end of file diff --git a/front-generator/template/main.html b/front-generator/template/main.html index d61f90f..fe4c60b 100644 --- a/front-generator/template/main.html +++ b/front-generator/template/main.html @@ -38,1255 +38,90 @@ \ No newline at end of file diff --git a/front-generator/template/vue-data.js b/front-generator/template/vue-data.js deleted file mode 100644 index 7eb163b..0000000 --- a/front-generator/template/vue-data.js +++ /dev/null @@ -1,181 +0,0 @@ - isCinC: false, - - // false - означает что статистика не отправляется, true - отправляется - submitStatus: { - {% for pg in params.groupsList %} - {{ pg }}: false, - {% endfor %} - firmwareUpload: false, - firmwareUpgrade: false, - // когда модем перезагружается, тут должен быть счетчик. Направление счета - к нулю - modemReboot: null - }, - - stat: { - - } - - stat_rx: { - // индикаторы - state: '?', // общее состояние - sym_sync_lock: '?', // захват символьной - freq_search_lock: '?', // Захват поиска по частоте - afc_lock: '?', // захват ФАПЧ - pkt_sync: '?', // захват пакетной синхронизации - - // куча других параметров, идет в том же порядке, что и в таблице - snr: '?', rssi: '?', - modcod: '?', frameSizeNormal: '?', - isPilots: '?', - symError: '?', - freqErr: '?', freqErrAcc: '?', - inputSignalLevel: '?', - pllError: '?', - speedOnRxKbit: '?', - speedOnIifKbit: '?', - - // статистика пакетов - packetsOk: '?', packetsBad: '?', packetsDummy: '?', - }, - stat_tx: { - // состояние - state: '?', - - // прочие поля - snr: '?', modcod: '?', frameSizeNormal: '?', isPilots: '?', speedOnTxKbit: '?', speedOnIifKbit: '?', - }, - stat_cinc: { - occ: '?', - correlator: null, - correlatorFails: '?', - freqErr: '?', freqErrAcc: '?', - channelDelay: '?' - }, - stat_device: { // температурные датчики - adrv: 0, zynq: 0, fpga: 0 - }, - - param: { - general: { - isCinC: Boolean, - txEn: Boolean, // включен/выключен - modulatorMode: 'normal', // режим работы модулятора - autoStartTx: Boolean, // было "режим работы передатчика" - isTestInputData: Boolean, // входные данные: eth или test - }, - tx: { - attenuation: Number, // ослабление - rolloff: Number, - cymRate: Number, - centerFreq: Number, - }, - dvbs2: { - mode: null, // ccm/acm - frameSizeNormal: null, // 'normal' / 'short' - // isPilots: false, - - // CCM - ccm_modulation: null, - ccm_speed: null, - - // ACM - acm_maxModulation: null, - acm_maxSpeed: null, - acm_minModulation: null, - acm_minSpeed: null, - - snrReserve: null, - servicePacketPeriod: null, - }, - // авто-регулировка мощности - acm: { - en: false, - maxAttenuation: null, - minAttenuation: null, - requiredSnr: null, - }, - rx: { - gainMode: null, // 'auto'/'manual' режим управления усилением - manualGain: 0, // усиление, только для ручного режима - spectrumInversion: false, - rolloff: 0, - cymRate: 100000, - centerFreq: 1200000.0, - }, - - cinc: { - mode: null, // 'positional' | 'delay' - searchBandwidth: 0, // полоса поиска в кГц - position: { - station: { - latitude: 0, - longitude: 0 - }, - satelliteLongitude: 0, - }, - delayMin: 0, - delayMax: 0 - }, - - buc: { - refClk10M: false, // подача опоры 10MHz - powering: 0 // 0, 24, 48 - }, - lnb: { - refClk10M: false, // подача опоры 10MHz - powering: 0 // 0, 13, 18, 24 - }, - serviceSettings: { - refClk10M: false, // подача опоры 10MHz - autoStart: false - }, - - network: { - managementIp: '', // 0.0.0.0/24 - managementGateway: '', - mode: String, // l2 | l3 - dataIp: '', // - dataMtu: 1500 - }, - debugSend: { - en: false, - receiverIp: '0.0.0.0', // 0.0.0.0 - portCinC: 0, - portData: 0, - timeout: 0 - }, - - qos: { - en: false, - rt1: [], - rt2: [], - rt3: [], - cd: [], - }, - - tcpAccel: { - en: false, - maxConnections: 128 - }, - }, - - uploadFw: { - progress: null, - filename: null, - sha256: null - }, - - // эти "настройки" - read only - about: { - firmwareVersion: '?', - modemUid: '?', - modemSn: '?', - macManagement: '?', - macData: '?', - }, - - testState: false, - initState: '', - lastUpdateTime: new Date(), - activeTab: getCurrentTab(), - settingFetchComplete: false, diff --git a/src/main.cpp b/src/main.cpp index f789d28..5cbd7f7 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -132,7 +132,11 @@ public: auth.users.emplace_back(std::make_shared("admin", "", http::auth::User::SUPERUSER)); sf->registerFile(staticFilesPath + "/favicon.png", FAVICON_ICO, mime_types::image_png, true); +#ifdef USE_DEBUG sf->registerFile(staticFilesPath + VUE_JS, VUE_JS, mime_types::javascript, true); +#else + sf->registerFile(staticFilesPath + "/js/vue.prod.js", VUE_JS, mime_types::javascript, true); +#endif sf->registerFile(staticFilesPath + STYLE_CSS, STYLE_CSS, mime_types::text_css, true); sf->registerFile(staticFilesPath + FIELDS_CSS, FIELDS_CSS, mime_types::text_css, true); sf->registerFile(staticFilesPath + INDEX_HTML, INDEX_HTML, mime_types::text_html, false); @@ -282,7 +286,7 @@ public: } })); - s.resources.emplace_back(std::make_unique("/api/set/bucLnb", this->auth, http::auth::User::SUPERUSER, [this](const auto& req, auto& rep) { + s.resources.emplace_back(std::make_unique("/api/set/buclnb", this->auth, http::auth::User::SUPERUSER, [this](const auto& req, auto& rep) { if (req.method != "POST") { http::server::stockReply(http::server::bad_request, rep); } @@ -304,7 +308,7 @@ public: result += "}"; rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size()); } catch (std::exception& e) { - BOOST_LOG_TRIVIAL(error) << "WebHandle(/api/set/bucLnb): Can't set settings: " << e.what(); + BOOST_LOG_TRIVIAL(error) << "WebHandle(/api/set/buclnb): Can't set BUC LNB settings: " << e.what(); const std::string result = R"({"status":"error"})"; rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size()); } @@ -388,35 +392,7 @@ public: result += "}"; rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size()); } catch (std::exception& e) { - BOOST_LOG_TRIVIAL(error) << "WebHandle(/api/set/rxtx): Can't set RX/TX settings: " << e.what(); - const std::string result = R"({"status":"error"})"; - rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size()); - } - })); - - s.resources.emplace_back(std::make_unique("/api/set/debugSend", this->auth, http::auth::User::EDIT_SETTINGS, [this](const auto& req, auto& rep) { - if (req.method != "POST") { - http::server::stockReply(http::server::bad_request, rep); - } - - rep.status = http::server::ok; - rep.headers.clear(); - rep.headers.push_back({.name = "Content-Type", .value = toString(mime_types::json)}); - - try { - std::stringstream ss; - ss.str(std::string(req.payload.begin(), req.payload.end())); - boost::property_tree::ptree pt; - read_json(ss, pt); - - api->setDebugSendSettings(pt); - - std::string result = R"({"status":"ok","settings":)"; - result += api->loadSettings(); - result += "}"; - rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size()); - } catch (std::exception& e) { - BOOST_LOG_TRIVIAL(error) << "WebHandle(/api/set/rxtx): Can't set RX/TX settings: " << e.what(); + BOOST_LOG_TRIVIAL(error) << "WebHandle(/api/set/network): Can't set network settings: " << e.what(); const std::string result = R"({"status":"error"})"; rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size()); } @@ -481,16 +457,16 @@ public: s.resources.emplace_back(std::make_unique("/dev", this->auth, http::auth::User::SUPERUSER, [this](const auto& req, auto& rep) { boost::ignore_unused(req); - sf->serve(INTERNET_JPG, rep); + sf->serve(DEV_HTML, rep); })); - s.resources.emplace_back(std::make_unique("/dev/fetchParams", this->auth, http::auth::User::SUPERUSER, [this](const auto& req, auto& rep) { - 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 += R"(,"sha256":")"; - result += "\"}"; - })); + // s.resources.emplace_back(std::make_unique("/dev/fetchParams", this->auth, http::auth::User::SUPERUSER, [this](const auto& req, auto& rep) { + // 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 += R"(,"sha256":")"; + // result += "\"}"; + // })); } ~ServerResources() = default; diff --git a/src/terminal_api_driver.cpp b/src/terminal_api_driver.cpp index eae5068..758a97b 100644 --- a/src/terminal_api_driver.cpp +++ b/src/terminal_api_driver.cpp @@ -16,48 +16,48 @@ typedef boost::property_tree::ptree::path_type json_path; static constexpr const char* DEFAULT_QOS_CLASSES = R"({"rt1":[],"rt2":[],"rt3":[],"cd":[]})"; -static int calculateSubnetMask(const std::string& subnet_mask) { - int mask = 0; - std::istringstream iss(subnet_mask); - std::string octet; - while (std::getline(iss, octet, '.')) { - int octet_value = std::stoi(octet); - for (int i = 7; i >= 0; i--) { - if (octet_value & (1 << i)) { - mask++; - } - } - } - return mask; -} +// static int calculateSubnetMask(const std::string& subnet_mask) { +// int mask = 0; +// std::istringstream iss(subnet_mask); +// std::string octet; +// while (std::getline(iss, octet, '.')) { +// int octet_value = std::stoi(octet); +// for (int i = 7; i >= 0; i--) { +// if (octet_value & (1 << i)) { +// mask++; +// } +// } +// } +// return mask; +// } /** * Преобразует строку вида `1.2.3.4/24` в пару строк вида `1.2.3.4` `255.255.255.0` */ -std::pair splitIpAndMask(const std::string& input) { - auto pos = input.find('/'); - if (pos == std::string::npos) { - // Обработка ошибки: нет символа '/' - throw std::runtime_error("address not contains mask"); - } - std::string ip = input.substr(0, pos); - const unsigned int mask_int = std::stoul(input.substr(pos + 1)); - - if (mask_int > 32) { - throw std::runtime_error("invalid mask"); - } - - std::string mask_binary = std::string(mask_int, '1') + std::string(32 - mask_int, '0'); - std::string mask_str; - - for (unsigned int i = 0; i < 4; ++i) { - std::string octet = mask_binary.substr(i * 8u, 8); - int octet_value = std::stoi(octet, nullptr, 2); - mask_str += std::to_string(octet_value) + (i < 3 ? "." : ""); - } - - return std::make_pair(ip, mask_str); -} +// std::pair splitIpAndMask(const std::string& input) { +// auto pos = input.find('/'); +// if (pos == std::string::npos) { +// // Обработка ошибки: нет символа '/' +// throw std::runtime_error("address not contains mask"); +// } +// std::string ip = input.substr(0, pos); +// const unsigned int mask_int = std::stoul(input.substr(pos + 1)); +// +// if (mask_int > 32) { +// throw std::runtime_error("invalid mask"); +// } +// +// std::string mask_binary = std::string(mask_int, '1') + std::string(32 - mask_int, '0'); +// std::string mask_str; +// +// for (unsigned int i = 0; i < 4; ++i) { +// std::string octet = mask_binary.substr(i * 8u, 8); +// int octet_value = std::stoi(octet, nullptr, 2); +// mask_str += std::to_string(octet_value) + (i < 3 ? "." : ""); +// } +// +// return std::make_pair(ip, mask_str); +// } static inline void rtrim(std::string &s) { s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) { @@ -67,7 +67,8 @@ static inline void rtrim(std::string &s) { class TerminalNetworkSettings { public: - std::string managementIp, managementGateway, mode, dataIp; + std::string managementIp, managementGateway, dataIp; + bool isL2 = true; unsigned int dataMtu = 1500; TerminalNetworkSettings() = default; @@ -77,10 +78,10 @@ public: TerminalNetworkSettings& operator= (const TerminalNetworkSettings& src) = default; void loadDefaults() { - managementIp = "0.0.0.0/0"; + managementIp = "0.0.0.0"; managementGateway = ""; - mode = "l2"; - dataIp = "0.0.0.0/0"; + isL2 = true; + dataIp = "0.0.0.0"; dataMtu = 1500; } }; @@ -193,21 +194,22 @@ private: void updateNetworkSettings() { TerminalNetworkSettings s; - std::string tmp; + std::lock_guard lock(this->cpApiMutex); - logCpApiError("api_driver::TerminalApiDaemon::updateNetworkSettings()->CP_GetNetwork(addr)", CP_GetNetwork(sid, "addr", &tmp)); - s.managementIp = tmp + "/"; - tmp.clear(); logCpApiError("api_driver::TerminalApiDaemon::updateNetworkSettings()->CP_GetNetwork(mask)", CP_GetNetwork(sid, "mask", &tmp)); - s.managementIp += std::to_string(calculateSubnetMask(tmp)); - tmp.clear(); logCpApiError("api_driver::TerminalApiDaemon::updateNetworkSettings()->CP_GetNetwork(gateway)", CP_GetNetwork(sid, "gateway", &s.managementGateway)); s.managementGateway = tmp; - tmp.clear(); logCpApiError("api_driver::TerminalApiDaemon::updateNetworkSettings()->CP_GetNetwork(mode)", CP_GetNetwork(sid, "mode", &tmp)); - if (tmp == "tun") { - s.mode = "l3"; + logCpApiError("api_driver::TerminalApiDaemon::updateNetworkSettings()->CP_GetNetwork(addr)", CP_GetNetwork(sid, "addr", &s.managementIp)); + // s.managementIp = tmp + "/"; + // tmp.clear(); logCpApiError("api_driver::TerminalApiDaemon::updateNetworkSettings()->CP_GetNetwork(mask)", CP_GetNetwork(sid, "mask", &tmp)); + // s.managementIp += std::to_string(calculateSubnetMask(tmp)); + logCpApiError("api_driver::TerminalApiDaemon::updateNetworkSettings()->CP_GetNetwork(gateway)", CP_GetNetwork(sid, "gateway", &s.managementGateway)); + std::string nm; logCpApiError("api_driver::TerminalApiDaemon::updateNetworkSettings()->CP_GetNetwork(mode)", CP_GetNetwork(sid, "mode", &nm)); + if (nm == "tun") { + s.isL2 = false; logCpApiError("api_driver::TerminalApiDaemon::updateNetworkSettings()->CP_GetNetwork(addr_data)", CP_GetNetwork(sid, "addr_data", &s.dataIp)); - s.dataIp += "/24"; + // s.dataIp += "/24"; } else { - s.mode = "l2"; - s.dataIp = "0.0.0.0/24"; + s.isL2 = true; + // s.dataIp = "0.0.0.0/24"; + s.dataIp = "0.0.0.0"; } s.dataMtu = 1500; @@ -564,41 +566,39 @@ public: } void setNetworkSettings(TerminalNetworkSettings& s, bool readback = true) { - const auto mang = splitIpAndMask(s.managementIp); - std::pair data; - bool isL2; - if (s.mode == "l2") { isL2 = true; } - else if (s.mode == "l3") { isL2 = false; data = splitIpAndMask(s.dataIp); } - else { throw std::runtime_error("invalid mode"); } + // const auto mang = splitIpAndMask(); + // std::pair data; + // if (!s.isL2) { + // data = splitIpAndMask(s.dataIp); + // } std::lock_guard lock(this->cpApiMutex); logCpApiError("api_driver::TerminalApiDaemon::setNetworkSettings()->CP_SetDmaDebug(begin_save_config)", CP_SetDmaDebug(sid, "begin_save_config", "")); - logCpApiError("api_driver::TerminalApiDaemon::setNetworkSettings()->CP_SetNetwork(mode)", CP_SetNetwork(sid, "mode", isL2 ? "tap" : "tun")); - logCpApiError("api_driver::TerminalApiDaemon::setNetworkSettings()->CP_SetNetwork(addr)", CP_SetNetwork(sid, "addr", mang.first.c_str())); - logCpApiError("api_driver::TerminalApiDaemon::setNetworkSettings()->CP_SetNetwork(mask)", CP_SetNetwork(sid, "mask", mang.second.c_str())); + logCpApiError("api_driver::TerminalApiDaemon::setNetworkSettings()->CP_SetNetwork(mode)", CP_SetNetwork(sid, "mode", s.isL2 ? "tap" : "tun")); + logCpApiError("api_driver::TerminalApiDaemon::setNetworkSettings()->CP_SetNetwork(addr)", CP_SetNetwork(sid, "addr", s.managementIp.c_str())); + logCpApiError("api_driver::TerminalApiDaemon::setNetworkSettings()->CP_SetNetwork(mask)", CP_SetNetwork(sid, "mask", "255.255.255.0")); logCpApiError("api_driver::TerminalApiDaemon::setNetworkSettings()->CP_SetNetwork(gateway)", CP_SetNetwork(sid, "gateway", s.managementGateway.c_str())); - if (!isL2) { - logCpApiError("api_driver::TerminalApiDaemon::setNetworkSettings()->CP_SetNetwork(data_addr)", CP_SetNetwork(sid, "data_addr", data.first.c_str())); + if (!s.isL2) { + logCpApiError("api_driver::TerminalApiDaemon::setNetworkSettings()->CP_SetNetwork(data_addr)", CP_SetNetwork(sid, "data_addr", s.dataIp.c_str())); // TODO маска не устанавливается, потому что в API этого нет } // TODO MTU не устанавливается, потому что в API этого нет if (readback) { - std::string tmp; s.loadDefaults(); s.managementIp.clear(); logCpApiError("api_driver::TerminalApiDaemon::setNetworkSettings()->CP_GetNetwork(addr)", CP_GetNetwork(sid, "addr", &s.managementIp)); - logCpApiError("api_driver::TerminalApiDaemon::setNetworkSettings()->CP_GetNetwork(mask)", CP_GetNetwork(sid, "mask", &tmp)); - s.managementIp += "/"; - s.managementIp += std::to_string(calculateSubnetMask(tmp)); + // logCpApiError("api_driver::TerminalApiDaemon::setNetworkSettings()->CP_GetNetwork(mask)", CP_GetNetwork(sid, "mask", &tmp)); + // s.managementIp += "/"; + // s.managementIp += std::to_string(calculateSubnetMask(tmp)); logCpApiError("api_driver::TerminalApiDaemon::setNetworkSettings()->CP_GetNetwork(gateway)", CP_GetNetwork(sid, "gateway", &s.managementGateway)); - tmp.clear(); logCpApiError("api_driver::TerminalApiDaemon::setNetworkSettings()->CP_GetNetwork(mode)", CP_GetNetwork(sid, "mode", &tmp)); - if (tmp == "tun") { - s.mode = "l3"; + std::string nm; logCpApiError("api_driver::TerminalApiDaemon::setNetworkSettings()->CP_GetNetwork(mode)", CP_GetNetwork(sid, "mode", &nm)); + if (nm == "tun") { + s.isL2 = false; logCpApiError("api_driver::TerminalApiDaemon::setNetworkSettings()->CP_GetNetwork(addr_data)", CP_GetNetwork(sid, "addr_data", &s.dataIp)); } else { - s.mode = "l2"; - s.dataIp = "0.0.0.0/24"; + s.isL2 = true; + s.dataIp = "0.0.0.0"; } s.dataMtu = 1500; { @@ -778,7 +778,7 @@ std::string api_driver::ApiDriver::loadTerminalState() const { result << ",\"cinc.correlatorFails\":" << cinc.cnt_bad_lock; result << ",\"cinc.freqErr\":" << cinc.freq_error_offset; result << ",\"cinc.freqErrAcc\":" << cinc.freq_fine_estimate; - result << ",\"cinc.channelDelay\":"; writeDouble(result, cinc.delay_dpdi, 1); + result << ",\"cinc.channelDelay\":" << cinc.delay_dpdi; } else { result << R"(,"cinc.correlator":null)"; } @@ -799,6 +799,59 @@ void api_driver::ApiDriver::resetPacketStatistics() const { this->daemon->resetPacketStatistics(); } +#ifdef MODEM_IS_SCPC +struct ModcodDef_t {const char* modulation; const char* speed;}; +const static ModcodDef_t ModcodDefs[] = { + {.modulation = "dummy", .speed = "0"}, + {.modulation = "qpsk", .speed = "1/4"}, + {.modulation = "qpsk", .speed = "1/3"}, + {.modulation = "qpsk", .speed = "2/5"}, + {.modulation = "qpsk", .speed = "1/2"}, + {.modulation = "qpsk", .speed = "3/5"}, + {.modulation = "qpsk", .speed = "2/3"}, + {.modulation = "qpsk", .speed = "3/4"}, + {.modulation = "qpsk", .speed = "4/5"}, + {.modulation = "qpsk", .speed = "5/6"}, + {.modulation = "qpsk", .speed = "8/9"}, + {.modulation = "qpsk", .speed = "9/10"}, + {.modulation = "8psk", .speed = "3/5"}, + {.modulation = "8psk", .speed = "2/3"}, + {.modulation = "8psk", .speed = "3/4"}, + {.modulation = "8psk", .speed = "5/6"}, + {.modulation = "8psk", .speed = "8/9"}, + {.modulation = "8psk", .speed = "9/10"}, + {.modulation = "16apsk", .speed = "2/3"}, + {.modulation = "16apsk", .speed = "3/4"}, + {.modulation = "16apsk", .speed = "4/5"}, + {.modulation = "16apsk", .speed = "5/6"}, + {.modulation = "16apsk", .speed = "8/9"}, + {.modulation = "16apsk", .speed = "9/10"}, + {.modulation = "32apsk", .speed = "3/4"}, + {.modulation = "32apsk", .speed = "4/5"}, + {.modulation = "32apsk", .speed = "5/6"}, + {.modulation = "32apsk", .speed = "8/9"}, + {.modulation = "32apsk", .speed = "9/10"}, +}; + +static const char* extractModcodModulation(uint32_t modcod, bool defaultQpsk1_4 = true) { + modcod >>= 2; + const auto* d = defaultQpsk1_4 ? ModcodDefs : ModcodDefs + 1; + if (modcod < 28) { + d = ModcodDefs + modcod; + } + return d->modulation; +} + +static const char* extractModcodSpeed(uint32_t modcod, bool defaultQpsk1_4 = true) { + modcod >>= 2; + const auto* d = defaultQpsk1_4 ? ModcodDefs : ModcodDefs + 1; + if (modcod < 28) { + d = ModcodDefs + modcod; + } + return d->speed; +} +#endif + std::string api_driver::ApiDriver::loadSettings() const { if (daemon == nullptr) { return R"({"error": "api daemon not started!"})"; @@ -818,93 +871,92 @@ std::string api_driver::ApiDriver::loadSettings() const { daemon->getNetworkSettings(network); std::stringstream result; + result << "{\n\"txAutoStart\":" << boolAsStr(modSettings.is_save_current_state); #ifdef MODEM_IS_SCPC - result << "{\n\"general.isCinC\":" << boolAsStr(modSettings.is_cinc); - result << ",\"general.txEn\":" << boolAsStr(modSettings.tx_is_on); - result << ",\"general.modulatorMode\":" << (modSettings.is_carrier ? "\"normal\"" : "\"test\""); - result << ",\"general.autoStartTx\":" << boolAsStr(modSettings.is_save_current_state); - result << ",\"general.isTestInputData\":" << boolAsStr(modSettings.is_test_data); - result << ",\n\"tx.attenuation\":"; writeDouble(result, modSettings.attenuation); - result << ",\"tx.rolloff\":" << static_cast(modSettings.rollof * 100); - result << ",\"tx.goldan\":" << static_cast(modSettings.qold_seq_is_active); - result << ",\"tx.cymRate\":" << modSettings.baudrate; - result << ",\"tx.centerFreq\":"; writeDouble(result, modSettings.central_freq_in_kGz, 3); - result << ",\"dvbs2.frameSizeNormal\":" << boolAsStr(!(modSettings.modcod_tx & 2)); - result << ",\"dvbs2.ccm_modcod\":" << (modSettings.modcod_tx >> 2); + result << ",\"txModulatorIsTest\":" << boolAsStr(!modSettings.is_carrier); +#endif + result << ",\"txIsTestInput\":" << boolAsStr(modSettings.is_test_data); + result << ",\"txCentralFreq\":"; writeDouble(result, modSettings.central_freq_in_kGz); + result << ",\"txBaudrate\":" << modSettings.baudrate; + result << ",\"txRolloff\":" << static_cast(modSettings.rollof * 100); +#ifdef MODEM_IS_SCPC + // result << ",\"txGoldan\":" << static_cast(modSettings.qold_seq_is_active); // TODO обновить библиотеку +#endif + result << ",\"txAttenuation\":"; writeDouble(result, modSettings.attenuation); - // result << ",\"dvbs2.isPilots\":" << "null"; - result << ",\n\"dvbs2.isAcm\":" << boolAsStr(acmSettings.enable); - result << ",\"dvbs2.acm_maxModcod\":" << (acmSettings.max_modcod >> 2); - result << ",\"dvbs2.acm_minModcod\":" << (acmSettings.min_modcod >> 2); - result << ",\"dvbs2.snrReserve\":"; writeDouble(result, acmSettings.snr_treashold_acm); - result << ",\"dvbs2.servicePacketPeriod\":" << acmSettings.period_pack; +#ifdef MODEM_IS_SCPC + result << ",\n\"isCinC\":" << boolAsStr(modSettings.is_cinc); + result << ",\n\"dvbServicePacketPeriod\":" << acmSettings.period_pack; + result << ",\"dvbIsAcm\":" << boolAsStr(acmSettings.enable); + result << ",\"txFrameSizeNormal\":" << boolAsStr((modSettings.modcod_tx & 2) == 0); - result << ",\n\"acm.en\":" << boolAsStr(acmSettings.enable_auto_atten); - result << ",\"acm.maxAttenuation\":"; writeDouble(result, acmSettings.max_attenuation); - result << ",\"acm.minAttenuation\":"; writeDouble(result, acmSettings.min_attenuation); - result << ",\"acm.requiredSnr\":"; writeDouble(result, acmSettings.snr_treashold); + result << R"(,"dvbCcmModulation":")" << extractModcodModulation(modSettings.modcod_tx) << "\""; + result << R"(,"dvbCcmSpeed":")" << extractModcodSpeed(modSettings.modcod_tx) << "\""; + result << R"(,"dvbAcmMinModulation":")" << extractModcodModulation(acmSettings.min_modcod) << "\""; + result << R"(,"dvbAcmMinSpeed":")" << extractModcodSpeed(acmSettings.min_modcod) << "\""; + result << R"(,"dvbAcmMaxModulation":")" << extractModcodModulation(acmSettings.max_modcod) << "\""; + result << R"(,"dvbAcmMaxSpeed":")" << extractModcodSpeed(acmSettings.max_modcod) << "\""; + result << ",\"dvbSnrReserve\":"; writeDouble(result, acmSettings.snr_treashold_acm); - result << ",\n\"rx.gainMode\":" << (demodSettings.is_aru_on ? "\"auto\"" : "\"manual\""); - result << ",\"rx.manualGain\":"; writeDouble(result, demodSettings.gain); - result << ",\"rx.spectrumInversion\":" << boolAsStr(demodSettings.is_rvt_iq); - result << ",\"rx.rolloff\":" << static_cast(demodSettings.rollof * 100); - result << ",\"rx.goldan\":" << static_cast(demodSettings.qold_seq_is_active); - result << ",\"rx.cymRate\":" << demodSettings.baudrate; - result << ",\"rx.centerFreq\":"; writeDouble(result, demodSettings.central_freq_in_kGz); + result << ",\n\"aupcEn\":" << boolAsStr(acmSettings.enable_auto_atten); + result << ",\"aupcMinAttenuation\":"; writeDouble(result, acmSettings.min_attenuation); + result << ",\"aupcMaxAttenuation\":"; writeDouble(result, acmSettings.max_attenuation); + result << ",\"aupcRequiredSnr\":"; writeDouble(result, acmSettings.snr_treashold); - result << ",\n\"cinc.mode\":" << (dpdiSettings.is_delay_window ? "\"delay\"" : "\"positional\""); - result << ",\"cinc.searchBandwidth\":" << dpdiSettings.freq_offset; // полоса поиска в кГц - result << ",\"cinc.position.station.latitude\":"; writeDouble(result, translateCoordinates(dpdiSettings.latitude_station_grad, dpdiSettings.latitude_station_minute), 6); - result << ",\"cinc.position.station.longitude\":"; writeDouble(result, translateCoordinates(dpdiSettings.longitude_station_grad, dpdiSettings.longitude_station_minute), 6); - result << ",\"cinc.position.satelliteLongitude\":"; writeDouble(result, translateCoordinates(dpdiSettings.longitude_sattelite_grad, dpdiSettings.longitude_sattelite_minute), 6); - result << ",\"cinc.delayMin\":" << dpdiSettings.min_delay; - result << ",\"cinc.delayMax\":" << dpdiSettings.max_delay; -#else - result << "{\n\"tx.txEn\":" << boolAsStr(modSettings.tx_is_on); - result << ",\"tx.isTestInputData\":" << boolAsStr(modSettings.is_test_data); - result << ",\"tx.cymRate\":" << modSettings.baudrate; - result << ",\"tx.centerFreq\":"; writeDouble(result, modSettings.central_freq_in_kGz, 3); - result << ",\"tx.attenuation\":"; writeDouble(result, modSettings.attenuation); - - result << ",\n\"rx.gainMode\":" << (demodSettings.is_aru_on ? "\"auto\"" : "\"manual\""); - result << ",\"rx.manualGain\":"; writeDouble(result, demodSettings.gain); - result << ",\"rx.spectrumInversion\":" << boolAsStr(demodSettings.is_rvt_iq); - result << ",\"rx.rolloff\":" << static_cast(demodSettings.rollof * 100); - result << ",\"rx.cymRate\":" << demodSettings.baudrate; - result << ",\"rx.centerFreq\":"; writeDouble(result, demodSettings.central_freq_in_kGz); + result << ",\n\"cincIsPositional\":" << boolAsStr(!dpdiSettings.is_delay_window); + result << ",\"cincSearchBandwidth\":" << dpdiSettings.freq_offset; // полоса поиска в кГц + result << ",\"cincPositionStationLatitude\":"; writeDouble(result, translateCoordinates(dpdiSettings.latitude_station_grad, dpdiSettings.latitude_station_minute), 6); + result << ",\"cincPositionStationLongitude\":"; writeDouble(result, translateCoordinates(dpdiSettings.longitude_station_grad, dpdiSettings.longitude_station_minute), 6); + result << ",\"cincPositionSatelliteLongitude\":"; writeDouble(result, translateCoordinates(dpdiSettings.longitude_sattelite_grad, dpdiSettings.longitude_sattelite_minute), 6); + result << ",\"cincDelayMin\":" << dpdiSettings.min_delay; + result << ",\"cincDelayMax\":" << dpdiSettings.max_delay; #endif - result << ",\n\"buc.refClk10M\":" << boolAsStr(bucLnb.is_ref_10MHz_buc); + result << ",\n\"rxAgcEn\":" << boolAsStr(demodSettings.is_aru_on); + result << ",\"rxSpectrumInversion\":" << boolAsStr(demodSettings.is_rvt_iq); + result << ",\"rxManualGain\":"; writeDouble(result, demodSettings.gain); + result << ",\"rxCentralFreq\":"; writeDouble(result, demodSettings.central_freq_in_kGz); + result << ",\"rxBaudrate\":" << demodSettings.baudrate; + result << ",\"rxRolloff\":" << static_cast(demodSettings.rollof * 100); +#ifdef MODEM_IS_SCPC + // result << ",\"txGoldan\":" << static_cast(demodSettings.qold_seq_is_active); // TODO обновить библиотеку +#endif + + // BUC LNB + result << ",\n\"bucRefClk10M\":" << boolAsStr(bucLnb.is_ref_10MHz_buc); switch (bucLnb.buc) { - case voltage_buc::_24V: result << ",\"buc.powering\":24"; break; - case voltage_buc::_48V: result << ",\"buc.powering\":48"; break; + case voltage_buc::_24V: result << ",\"bucPowering\":24"; break; +#ifdef MODEM_IS_SCPC + case voltage_buc::_48V: result << ",\"bucPowering\":48"; break; +#endif case voltage_buc::DISABLE: - default: result << ",\"buc.powering\":0"; + default: result << ",\"bucPowering\":0"; } - result << ",\n\"lnb.refClk10M\":" << boolAsStr(bucLnb.is_ref_10MHz_lnb); + result << ",\"lnbRefClk10M\":" << boolAsStr(bucLnb.is_ref_10MHz_lnb); switch (bucLnb.lnb) { - case voltage_lnb::_13V: result << ",\"lnb.powering\":13"; break; - case voltage_lnb::_18V: result << ",\"lnb.powering\":18"; break; - case voltage_lnb::_24V: result << ",\"lnb.powering\":24"; break; + case voltage_lnb::_13V: result << ",\"lnbPowering\":13"; break; + case voltage_lnb::_18V: result << ",\"lnbPowering\":18"; break; + case voltage_lnb::_24V: result << ",\"lnbPowering\":24"; break; case voltage_lnb::DISABLE: - default: result << ",\"lnb.powering\":0"; + default: result << ",\"lnbPowering\":0"; } - result << ",\n\"serviceSettings.refClk10M\":" << boolAsStr(bucLnb.is_ref_10MHz_output); - result << ",\"serviceSettings.autoStart\":" << boolAsStr(bucLnb.is_save_current_state); + result << ",\"srvRefClk10M\":" << boolAsStr(bucLnb.is_ref_10MHz_output); + result << ",\"bucLnbAutoStart\":" << boolAsStr(bucLnb.is_save_current_state); + // QoS bool qosEnabled = false; std::string qosClasses; daemon->getQosSettings(qosEnabled, qosClasses); - result << ",\n\"qos.enabled\":" << boolAsStr(qosEnabled); - result << ",\"qos.profile\":" << qosClasses; + result << ",\n\"qosEnabled\":" << boolAsStr(qosEnabled); + result << ",\"qosProfile\":" << qosClasses; // сеть - result << ",\"network.managementIp\":\n" << buildEscapedString(network.managementIp); - result << ",\"network.managementGateway\":\n" << buildEscapedString(network.managementGateway); - result << ",\"network.mode\":\n" << buildEscapedString(network.mode); - result << ",\"network.dataIp\":\n" << buildEscapedString(network.dataIp); - result << ",\"network.dataMtu\":\n" << network.dataMtu; + result << ",\"netManagementIp\":\n" << buildEscapedString(network.managementIp); + result << ",\"netIsL2\":\n" << boolAsStr(network.isL2); + result << ",\"netManagementGateway\":\n" << buildEscapedString(network.managementGateway); + result << ",\"netDataIp\":\n" << buildEscapedString(network.dataIp); + result << ",\"netDataMtu\":\n" << network.dataMtu; result << "}"; return result.str(); @@ -926,66 +978,78 @@ std::string api_driver::ApiDriver::loadFirmwareVersion() const { return result.str(); } +#ifdef MODEM_IS_SCPC +static uint32_t buildModcodFromPt(const boost::property_tree::ptree& pt, const std::string& name, bool isShortFrame) { + uint32_t modcod = 0; + const auto mod = pt.get(name + "Modulation"); + const auto speed = pt.get(name + "Speed"); + uint32_t _index = 0; + for (const auto& m: ModcodDefs) { + if (mod == m.modulation) { + if (modcod == 0) modcod = _index; + if (speed == m.speed) { + modcod = _index; + break; + } + } + _index++; + } + return (modcod << 2) | (isShortFrame ? 2 : 0); +} +#endif + void api_driver::ApiDriver::setRxTxSettings(boost::property_tree::ptree &pt) { modulator_settings mod{}; demodulator_settings demod{}; #ifdef MODEM_IS_SCPC ACM_parameters_serv_ acm{}; + daemon->getSettings(&mod, &demod, &acm, nullptr, nullptr); +#else + daemon->getSettings(&mod, &demod, nullptr); #endif // для модулятора #ifdef MODEM_IS_SCPC - mod.is_cinc = pt.get(json_path("general.isCinC", '/')); - mod.tx_is_on = pt.get(json_path("general.txEn", '/')); - auto tmp = pt.get(json_path("general.modulatorMode", '/')); - if (tmp == "normal") { mod.is_carrier = true; } - else if (tmp == "test") { mod.is_carrier = false; } - else { throw std::runtime_error("api_driver::ApiDriver::setRxTxSettings(): Wrong carrier mode: " + tmp); } - mod.is_save_current_state = pt.get(json_path("general.autoStartTx", '/')); - mod.is_test_data = pt.get(json_path("general.isTestInputData", '/')); - mod.attenuation = pt.get(json_path("tx.attenuation", '/')); - mod.rollof = pt.get(json_path("tx.rolloff", '/')) / 100.0; - mod.qold_seq_is_active = pt.get(json_path("tx.goldan", '/')); - mod.baudrate = pt.get(json_path("tx.cymRate", '/')); - mod.central_freq_in_kGz = pt.get(json_path("tx.centerFreq", '/')); + mod.is_cinc = pt.get("isCinC"); +#endif + mod.tx_is_on = pt.get("txEn"); +#ifdef MODEM_IS_SCPC + mod.is_save_current_state = pt.get("txAutoStart"); + mod.is_carrier = !pt.get("txModulatorIsTest"); +#endif + mod.is_test_data = pt.get("txIsTestInput"); + mod.central_freq_in_kGz = pt.get("txCentralFreq"); + mod.baudrate = pt.get("txBaudrate"); + mod.rollof = pt.get("txRolloff") / 100.0; +#ifdef MODEM_IS_SCPC + //mod.qold_seq_is_active = pt.get("isCinC"); +#endif + mod.attenuation = pt.get("txAttenuation"); - const bool acmIsShortFrame = !pt.get(json_path("dvbs2.frameSizeNormal", '/')); - mod.modcod_tx = (pt.get(json_path("dvbs2.ccm_modcod", '/')) << 2) | (acmIsShortFrame ? 2 : 0); -#else - mod.tx_is_on = pt.get(json_path("tx.txEn", '/')); - mod.is_test_data = pt.get(json_path("tx.isTestInputData", '/')); - mod.central_freq_in_kGz = pt.get(json_path("tx.centerFreq", '/')); - mod.baudrate = pt.get(json_path("tx.cymRate", '/')); - mod.attenuation = pt.get(json_path("tx.attenuation", '/')); +#ifdef MODEM_IS_SCPC + const bool acmIsShortFrame = !pt.get("txFrameSizeNormal"); + mod.modcod_tx = buildModcodFromPt(pt, "dvbCcm", acmIsShortFrame); #endif // демодулятор -#ifdef MODEM_IS_SCPC - tmp = pt.get(json_path("rx.gainMode", '/')); - demod.qold_seq_is_active = pt.get(json_path("rx.goldan", '/')); -#else - auto tmp = pt.get(json_path("rx.gainMode", '/')); -#endif - if (tmp == "auto") { demod.is_aru_on = true; } - else if (tmp == "manual") { demod.is_aru_on = false; } - else { throw std::runtime_error("api_driver::ApiDriver::setRxTxSettings(): Wrong gain mode: " + tmp); } - demod.gain = pt.get(json_path("rx.manualGain", '/')); - demod.baudrate = pt.get(json_path("rx.cymRate", '/')); - demod.is_rvt_iq = pt.get(json_path("rx.spectrumInversion", '/')); - demod.rollof = pt.get(json_path("rx.rolloff", '/')) / 100.0; - demod.central_freq_in_kGz = pt.get(json_path("rx.centerFreq", '/')); + demod.is_aru_on = pt.get("rxAgcEn"); + demod.gain = pt.get("rxManualGain"); + demod.is_rvt_iq = pt.get("aupcEn"); + demod.central_freq_in_kGz = pt.get("rxCentralFreq"); + demod.baudrate = pt.get("rxBaudrate"); + demod.rollof = pt.get("rxRolloff") / 100.0; #ifdef MODEM_IS_SCPC // ACM - acm.enable = pt.get(json_path("dvbs2.isAcm", '/')); - acm.max_modcod = (pt.get(json_path("dvbs2.acm_maxModcod", '/')) << 2) | (acmIsShortFrame ? 2 : 0); - acm.min_modcod = (pt.get(json_path("dvbs2.acm_minModcod", '/')) << 2) | (acmIsShortFrame ? 2 : 0); - acm.snr_treashold_acm = pt.get(json_path("dvbs2.snrReserve", '/')); // запас ОСШ - acm.period_pack = pt.get(json_path("dvbs2.servicePacketPeriod", '/')); - acm.enable_auto_atten = pt.get(json_path("acm.en", '/')); - acm.max_attenuation = pt.get(json_path("acm.maxAttenuation", '/')); - acm.min_attenuation = pt.get(json_path("acm.minAttenuation", '/')); - acm.snr_treashold = pt.get(json_path("acm.requiredSnr", '/')); // требуемый ОСШ + acm.period_pack = pt.get("dvbServicePacketPeriod"); + acm.enable = pt.get("rxAgcEn"); + acm.min_modcod = buildModcodFromPt(pt, "dvbAcmMin", acmIsShortFrame); + acm.max_modcod = buildModcodFromPt(pt, "dvbAcmMax", acmIsShortFrame); + acm.snr_treashold_acm = pt.get("dvbSnrReserve"); // запас ОСШ + acm.enable_auto_atten = pt.get(json_path("aupcEn", '/')); + acm.min_attenuation = pt.get("aupcMinAttenuation"); + acm.max_attenuation = pt.get("aupcMaxAttenuation"); + acm.snr_treashold = pt.get("aupcRequiredSnr"); daemon->setSettingsRxTx(mod, demod, acm); #else @@ -997,30 +1061,23 @@ void api_driver::ApiDriver::setRxTxSettings(boost::property_tree::ptree &pt) { void api_driver::ApiDriver::setCincSettings(boost::property_tree::ptree &pt) { DPDI_parmeters s{}; - //result << ",\n\"cinc.mode\":" << (dpdiSettings.is_delay_window ? "\"delay\"" : "\"positional\""); - auto tmp = pt.get(json_path("cinc.mode", '/')); - if (tmp == "delay") { s.is_delay_window = true; } - else if (tmp == "positional") { s.is_delay_window = false; } - else { - throw std::runtime_error("Wrong CinC mode: " + tmp); - } + s.is_delay_window = !pt.get("cincIsPositional"); + s.freq_offset = pt.get("cincSearchBandwidth"); - auto ctmp = translateCoordinates(pt.get(json_path("cinc.position.station.latitude", '/'))); + auto ctmp = translateCoordinates(pt.get("cincPositionStationLatitude")); s.latitude_station_grad = std::get<0>(ctmp); s.latitude_station_minute = std::get<1>(ctmp); - ctmp = translateCoordinates(pt.get(json_path("cinc.position.station.longitude", '/'))); + ctmp = translateCoordinates(pt.get("cincPositionStationLongitude")); s.longitude_station_grad = std::get<0>(ctmp); s.longitude_station_minute = std::get<1>(ctmp); - ctmp = translateCoordinates(pt.get(json_path("cinc.position.satelliteLongitude", '/'))); + ctmp = translateCoordinates(pt.get("cincPositionSatelliteLongitude")); s.longitude_sattelite_grad = std::get<0>(ctmp); s.longitude_sattelite_minute = std::get<1>(ctmp); - s.max_delay = pt.get(json_path("cinc.delayMax", '/')); - s.min_delay = pt.get(json_path("cinc.delayMin", '/')); - - s.freq_offset = pt.get(json_path("cinc.searchBandwidth", '/')); + s.min_delay = pt.get("cincDelayMin"); + s.max_delay = pt.get("cincDelayMax"); this->daemon->setSettingsCinc(s); } @@ -1028,19 +1085,13 @@ void api_driver::ApiDriver::setCincSettings(boost::property_tree::ptree &pt) { void api_driver::ApiDriver::setBucLnbSettings(boost::property_tree::ptree &pt) { buc_lnb_settings s{}; +#ifdef MODEM_IS_SCPC + daemon->getSettings(nullptr, nullptr, nullptr, nullptr, &s); +#else + daemon->getSettings(nullptr, nullptr, &s); +#endif - auto tmp = pt.get(json_path("lnb.powering", '/')); - switch (tmp) { - case 13: s.lnb = voltage_lnb::_13V; break; - case 18: s.lnb = voltage_lnb::_18V; break; - case 24: s.lnb = voltage_lnb::_24V; break; - case 0: - default: - s.lnb = voltage_lnb::DISABLE; - } - s.is_ref_10MHz_lnb = pt.get(json_path("lnb.refClk10M", '/')); - - tmp = pt.get(json_path("buc.powering", '/')); + auto tmp = pt.get("bucPowering"); switch (tmp) { case 24: s.buc = voltage_buc::_24V; break; #ifdef MODEM_IS_SCPC @@ -1050,11 +1101,21 @@ void api_driver::ApiDriver::setBucLnbSettings(boost::property_tree::ptree &pt) { default: s.lnb = voltage_lnb::DISABLE; } + s.is_ref_10MHz_buc = pt.get("bucRefClk10M"); - s.is_ref_10MHz_buc = pt.get(json_path("buc.refClk10M", '/')); + tmp = pt.get("lnbPowering"); + switch (tmp) { + case 13: s.lnb = voltage_lnb::_13V; break; + case 18: s.lnb = voltage_lnb::_18V; break; + case 24: s.lnb = voltage_lnb::_24V; break; + case 0: + default: + s.lnb = voltage_lnb::DISABLE; + } + s.is_ref_10MHz_lnb = pt.get("lnbRefClk10M"); - s.is_ref_10MHz_output = pt.get(json_path("serviceSettings.refClk10M", '/')); - s.is_save_current_state = pt.get(json_path("serviceSettings.autoStart", '/')); + s.is_ref_10MHz_output = pt.get("srvRefClk10M"); + s.is_save_current_state = pt.get("bucLnbAutoStart"); this->daemon->setSettingsBucLnb(s); } @@ -1071,19 +1132,17 @@ void api_driver::ApiDriver::setQosSettings(boost::property_tree::ptree &pt) { void api_driver::ApiDriver::setNetworkSettings(boost::property_tree::ptree &pt) { TerminalNetworkSettings s; - s.managementIp = pt.get(json_path("network.managementIp", '/')); - s.managementGateway = pt.get(json_path("network.managementGateway", '/')); - s.mode = pt.get(json_path("network.mode", '/')); - s.dataIp = pt.get(json_path("network.dataIp", '/')); - s.dataMtu = pt.get(json_path("network.dataMtu", '/')); + daemon->getNetworkSettings(s); + + s.managementIp = pt.get("netManagementIp"); + // s.managementGateway = pt.get(json_path("network.managementGateway", '/')); + s.isL2 = pt.get("netIsL2"); + s.dataIp = pt.get("netDataIp"); + s.dataMtu = pt.get("netDataMtu"); daemon->setNetworkSettings(s); } -void api_driver::ApiDriver::setDebugSendSettings(boost::property_tree::ptree &pt) { - boost::ignore_unused(pt); -} - void api_driver::ApiDriver::resetDefaultSettings() { daemon->resetDefaultSettings(); } @@ -1102,35 +1161,34 @@ std::string api_driver::ApiDriver::loadSysInfo() { struct sysinfo info{}; sysinfo(&info); - struct sysinfo { - long uptime; /* Seconds since boot */ - unsigned long loads[3]; /* 1, 5, and 15 minute load averages */ - unsigned long totalram; /* Total usable main memory size */ - unsigned long freeram; /* Available memory size */ - unsigned long sharedram; /* Amount of shared memory */ - unsigned long bufferram; /* Memory used by buffers */ - unsigned long totalswap; /* Total swap space size */ - unsigned long freeswap; /* Swap space still available */ - unsigned short procs; /* Number of current processes */ - unsigned long totalhigh; /* Total high memory size */ - unsigned long freehigh; /* Available high memory size */ - unsigned int mem_unit; /* Memory unit size in bytes */ - }; + // struct sysinfo { + // long uptime; /* Seconds since boot */ + // unsigned long loads[3]; /* 1, 5, and 15 minute load averages */ + // unsigned long totalram; /* Total usable main memory size */ + // unsigned long freeram; /* Available memory size */ + // unsigned long sharedram; /* Amount of shared memory */ + // unsigned long bufferram; /* Memory used by buffers */ + // unsigned long totalswap; /* Total swap space size */ + // unsigned long freeswap; /* Swap space still available */ + // unsigned short procs; /* Number of current processes */ + // unsigned long totalhigh; /* Total high memory size */ + // unsigned long freehigh; /* Available high memory size */ + // unsigned int mem_unit; /* Memory unit size in bytes */ + // }; + + double f_load = 1.0 / (1 << SI_LOAD_SHIFT); result << "{\n\"uptime\":" << info.uptime; - result << ",\"load1min\":" << info.loads[0]; - result << ",\"load5min\":" << info.loads[1]; - result << ",\"load15min\":" << info.loads[2]; - result << ",\"totalram\":" << info.totalram; - result << ",\"freeram\":" << info.freeram; - result << ",\"sharedram\":" << info.sharedram; - result << ",\"bufferram\":" << info.bufferram; - result << ",\"totalswap\":" << info.totalswap; - result << ",\"freeswap\":" << info.freeswap; + result << ",\"load1min\":"; writeDouble(result, f_load * static_cast(info.loads[0]), 2); + result << ",\"load5min\":"; writeDouble(result, f_load * static_cast(info.loads[1]), 2); + result << ",\"load15min\":"; writeDouble(result, f_load * static_cast(info.loads[2]), 2); + result << ",\"totalram\":" << ((info.totalram * info.mem_unit) >> 20); // Mb + result << ",\"freeram\":" << ((info.freeram * info.mem_unit) >> 20); // Mb + // result << ",\"sharedram\":" << ((info.sharedram * info.mem_unit) >> 20); // Mb + // result << ",\"bufferram\":" << ((info.bufferram * info.mem_unit) >> 20); // Mb + // result << ",\"totalswap\":" << info.totalswap * info.mem_unit; + // result << ",\"freeswap\":" << info.freeswap * info.mem_unit; result << ",\"procs\":" << static_cast(info.procs); - result << ",\"totalhigh\":" << info.totalhigh; - result << ",\"freehigh\":" << info.freehigh; - result << ",\"mem_unit\":" << info.mem_unit; result << "\n}"; return result.str(); } diff --git a/src/terminal_api_driver.h b/src/terminal_api_driver.h index c173070..4685532 100644 --- a/src/terminal_api_driver.h +++ b/src/terminal_api_driver.h @@ -64,8 +64,6 @@ namespace api_driver { void setNetworkSettings(boost::property_tree::ptree & pt); - void setDebugSendSettings(boost::property_tree::ptree & pt); - void resetDefaultSettings(); void executeInApi(const std::function& callback); diff --git a/static/dev.html b/static/dev.html index 566549b..7550adf 100644 --- a/static/dev.html +++ b/static/dev.html @@ -2,9 +2,103 @@ - Title + + RSCM-101 + + + + + + + \ No newline at end of file diff --git a/static/fields.css b/static/fields.css index 4a477b4..065faa9 100644 --- a/static/fields.css +++ b/static/fields.css @@ -135,7 +135,7 @@ select * { } .settings-set-container th, .settings-set-container td { - border-bottom: solid 1px var(--text-color2); + border-bottom: solid 1px var(--bg-element); } .settings-set-container table { border-collapse: collapse; } diff --git a/static/js/vue.js b/static/js/vue.js index 49ad25b..04dcc17 100644 --- a/static/js/vue.js +++ b/static/js/vue.js @@ -1,11909 +1,18096 @@ -/*! - * Vue.js v2.7.14 - * (c) 2014-2022 Evan You - * Released under the MIT License. - */ -(function (global, factory) { - typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : - typeof define === 'function' && define.amd ? define(factory) : - (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Vue = factory()); -})(this, (function () { 'use strict'; +/** +* vue v3.5.13 +* (c) 2018-present Yuxi (Evan) You and Vue contributors +* @license MIT +**/ +var Vue = (function (exports) { + 'use strict'; - var emptyObject = Object.freeze({}); - var isArray = Array.isArray; - // These helpers produce better VM code in JS engines due to their - // explicitness and function inlining. - function isUndef(v) { - return v === undefined || v === null; + /*! #__NO_SIDE_EFFECTS__ */ + // @__NO_SIDE_EFFECTS__ + function makeMap(str) { + const map = /* @__PURE__ */ Object.create(null); + for (const key of str.split(",")) map[key] = 1; + return (val) => val in map; } - function isDef(v) { - return v !== undefined && v !== null; - } - function isTrue(v) { - return v === true; - } - function isFalse(v) { - return v === false; - } - /** - * Check if value is primitive. - */ - function isPrimitive(value) { - return (typeof value === 'string' || - typeof value === 'number' || - // $flow-disable-line - typeof value === 'symbol' || - typeof value === 'boolean'); - } - function isFunction(value) { - return typeof value === 'function'; - } - /** - * Quick object check - this is primarily used to tell - * objects from primitive values when we know the value - * is a JSON-compliant type. - */ - function isObject(obj) { - return obj !== null && typeof obj === 'object'; - } - /** - * Get the raw type string of a value, e.g., [object Object]. - */ - var _toString = Object.prototype.toString; - function toRawType(value) { - return _toString.call(value).slice(8, -1); - } - /** - * Strict object type check. Only returns true - * for plain JavaScript objects. - */ - function isPlainObject(obj) { - return _toString.call(obj) === '[object Object]'; - } - function isRegExp(v) { - return _toString.call(v) === '[object RegExp]'; - } - /** - * Check if val is a valid array index. - */ - function isValidArrayIndex(val) { - var n = parseFloat(String(val)); - return n >= 0 && Math.floor(n) === n && isFinite(val); - } - function isPromise(val) { - return (isDef(val) && - typeof val.then === 'function' && - typeof val.catch === 'function'); - } - /** - * Convert a value to a string that is actually rendered. - */ - function toString(val) { - return val == null - ? '' - : Array.isArray(val) || (isPlainObject(val) && val.toString === _toString) - ? JSON.stringify(val, null, 2) - : String(val); - } - /** - * Convert an input value to a number for persistence. - * If the conversion fails, return original string. - */ - function toNumber(val) { - var n = parseFloat(val); - return isNaN(n) ? val : n; - } - /** - * Make a map and return a function for checking if a key - * is in that map. - */ - function makeMap(str, expectsLowerCase) { - var map = Object.create(null); - var list = str.split(','); - for (var i = 0; i < list.length; i++) { - map[list[i]] = true; - } - return expectsLowerCase ? function (val) { return map[val.toLowerCase()]; } : function (val) { return map[val]; }; - } - /** - * Check if a tag is a built-in tag. - */ - var isBuiltInTag = makeMap('slot,component', true); - /** - * Check if an attribute is a reserved attribute. - */ - var isReservedAttribute = makeMap('key,ref,slot,slot-scope,is'); - /** - * Remove an item from an array. - */ - function remove$2(arr, item) { - var len = arr.length; - if (len) { - // fast path for the only / last item - if (item === arr[len - 1]) { - arr.length = len - 1; - return; - } - var index = arr.indexOf(item); - if (index > -1) { - return arr.splice(index, 1); - } - } - } - /** - * Check whether an object has the property. - */ - var hasOwnProperty = Object.prototype.hasOwnProperty; - function hasOwn(obj, key) { - return hasOwnProperty.call(obj, key); - } - /** - * Create a cached version of a pure function. - */ - function cached(fn) { - var cache = Object.create(null); - return function cachedFn(str) { - var hit = cache[str]; - return hit || (cache[str] = fn(str)); - }; - } - /** - * Camelize a hyphen-delimited string. - */ - var camelizeRE = /-(\w)/g; - var camelize = cached(function (str) { - return str.replace(camelizeRE, function (_, c) { return (c ? c.toUpperCase() : ''); }); + + const EMPTY_OBJ = Object.freeze({}) ; + const EMPTY_ARR = Object.freeze([]) ; + const NOOP = () => { + }; + const NO = () => false; + const isOn = (key) => key.charCodeAt(0) === 111 && key.charCodeAt(1) === 110 && // uppercase letter + (key.charCodeAt(2) > 122 || key.charCodeAt(2) < 97); + const isModelListener = (key) => key.startsWith("onUpdate:"); + const extend = Object.assign; + const remove = (arr, el) => { + const i = arr.indexOf(el); + if (i > -1) { + arr.splice(i, 1); + } + }; + const hasOwnProperty$1 = Object.prototype.hasOwnProperty; + const hasOwn = (val, key) => hasOwnProperty$1.call(val, key); + const isArray = Array.isArray; + const isMap = (val) => toTypeString(val) === "[object Map]"; + const isSet = (val) => toTypeString(val) === "[object Set]"; + const isDate = (val) => toTypeString(val) === "[object Date]"; + const isRegExp = (val) => toTypeString(val) === "[object RegExp]"; + const isFunction = (val) => typeof val === "function"; + const isString = (val) => typeof val === "string"; + const isSymbol = (val) => typeof val === "symbol"; + const isObject = (val) => val !== null && typeof val === "object"; + const isPromise = (val) => { + return (isObject(val) || isFunction(val)) && isFunction(val.then) && isFunction(val.catch); + }; + const objectToString = Object.prototype.toString; + const toTypeString = (value) => objectToString.call(value); + const toRawType = (value) => { + return toTypeString(value).slice(8, -1); + }; + const isPlainObject = (val) => toTypeString(val) === "[object Object]"; + const isIntegerKey = (key) => isString(key) && key !== "NaN" && key[0] !== "-" && "" + parseInt(key, 10) === key; + const isReservedProp = /* @__PURE__ */ makeMap( + // the leading comma is intentional so empty string "" is also included + ",key,ref,ref_for,ref_key,onVnodeBeforeMount,onVnodeMounted,onVnodeBeforeUpdate,onVnodeUpdated,onVnodeBeforeUnmount,onVnodeUnmounted" + ); + const isBuiltInDirective = /* @__PURE__ */ makeMap( + "bind,cloak,else-if,else,for,html,if,model,on,once,pre,show,slot,text,memo" + ); + const cacheStringFunction = (fn) => { + const cache = /* @__PURE__ */ Object.create(null); + return (str) => { + const hit = cache[str]; + return hit || (cache[str] = fn(str)); + }; + }; + const camelizeRE = /-(\w)/g; + const camelize = cacheStringFunction( + (str) => { + return str.replace(camelizeRE, (_, c) => c ? c.toUpperCase() : ""); + } + ); + const hyphenateRE = /\B([A-Z])/g; + const hyphenate = cacheStringFunction( + (str) => str.replace(hyphenateRE, "-$1").toLowerCase() + ); + const capitalize = cacheStringFunction((str) => { + return str.charAt(0).toUpperCase() + str.slice(1); }); - /** - * Capitalize a string. - */ - var capitalize = cached(function (str) { - return str.charAt(0).toUpperCase() + str.slice(1); - }); - /** - * Hyphenate a camelCase string. - */ - var hyphenateRE = /\B([A-Z])/g; - var hyphenate = cached(function (str) { - return str.replace(hyphenateRE, '-$1').toLowerCase(); - }); - /** - * Simple bind polyfill for environments that do not support it, - * e.g., PhantomJS 1.x. Technically, we don't need this anymore - * since native bind is now performant enough in most browsers. - * But removing it would mean breaking code that was able to run in - * PhantomJS 1.x, so this must be kept for backward compatibility. - */ - /* istanbul ignore next */ - function polyfillBind(fn, ctx) { - function boundFn(a) { - var l = arguments.length; - return l - ? l > 1 - ? fn.apply(ctx, arguments) - : fn.call(ctx, a) - : fn.call(ctx); - } - boundFn._length = fn.length; - return boundFn; + const toHandlerKey = cacheStringFunction( + (str) => { + const s = str ? `on${capitalize(str)}` : ``; + return s; + } + ); + const hasChanged = (value, oldValue) => !Object.is(value, oldValue); + const invokeArrayFns = (fns, ...arg) => { + for (let i = 0; i < fns.length; i++) { + fns[i](...arg); + } + }; + const def = (obj, key, value, writable = false) => { + Object.defineProperty(obj, key, { + configurable: true, + enumerable: false, + writable, + value + }); + }; + const looseToNumber = (val) => { + const n = parseFloat(val); + return isNaN(n) ? val : n; + }; + const toNumber = (val) => { + const n = isString(val) ? Number(val) : NaN; + return isNaN(n) ? val : n; + }; + let _globalThis; + const getGlobalThis = () => { + return _globalThis || (_globalThis = typeof globalThis !== "undefined" ? globalThis : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : typeof global !== "undefined" ? global : {}); + }; + function genCacheKey(source, options) { + return source + JSON.stringify( + options, + (_, val) => typeof val === "function" ? val.toString() : val + ); } - function nativeBind(fn, ctx) { - return fn.bind(ctx); - } - // @ts-expect-error bind cannot be `undefined` - var bind$1 = Function.prototype.bind ? nativeBind : polyfillBind; - /** - * Convert an Array-like object to a real Array. - */ - function toArray(list, start) { - start = start || 0; - var i = list.length - start; - var ret = new Array(i); - while (i--) { - ret[i] = list[i + start]; - } - return ret; - } - /** - * Mix properties into target object. - */ - function extend(to, _from) { - for (var key in _from) { - to[key] = _from[key]; - } - return to; - } - /** - * Merge an Array of Objects into a single Object. - */ - function toObject(arr) { - var res = {}; - for (var i = 0; i < arr.length; i++) { - if (arr[i]) { - extend(res, arr[i]); + + const PatchFlagNames = { + [1]: `TEXT`, + [2]: `CLASS`, + [4]: `STYLE`, + [8]: `PROPS`, + [16]: `FULL_PROPS`, + [32]: `NEED_HYDRATION`, + [64]: `STABLE_FRAGMENT`, + [128]: `KEYED_FRAGMENT`, + [256]: `UNKEYED_FRAGMENT`, + [512]: `NEED_PATCH`, + [1024]: `DYNAMIC_SLOTS`, + [2048]: `DEV_ROOT_FRAGMENT`, + [-1]: `HOISTED`, + [-2]: `BAIL` + }; + + const slotFlagsText = { + [1]: "STABLE", + [2]: "DYNAMIC", + [3]: "FORWARDED" + }; + + const GLOBALS_ALLOWED = "Infinity,undefined,NaN,isFinite,isNaN,parseFloat,parseInt,decodeURI,decodeURIComponent,encodeURI,encodeURIComponent,Math,Number,Date,Array,Object,Boolean,String,RegExp,Map,Set,JSON,Intl,BigInt,console,Error,Symbol"; + const isGloballyAllowed = /* @__PURE__ */ makeMap(GLOBALS_ALLOWED); + + const range = 2; + function generateCodeFrame(source, start = 0, end = source.length) { + start = Math.max(0, Math.min(start, source.length)); + end = Math.max(0, Math.min(end, source.length)); + if (start > end) return ""; + let lines = source.split(/(\r?\n)/); + const newlineSequences = lines.filter((_, idx) => idx % 2 === 1); + lines = lines.filter((_, idx) => idx % 2 === 0); + let count = 0; + const res = []; + for (let i = 0; i < lines.length; i++) { + count += lines[i].length + (newlineSequences[i] && newlineSequences[i].length || 0); + if (count >= start) { + for (let j = i - range; j <= i + range || end > count; j++) { + if (j < 0 || j >= lines.length) continue; + const line = j + 1; + res.push( + `${line}${" ".repeat(Math.max(3 - String(line).length, 0))}| ${lines[j]}` + ); + const lineLength = lines[j].length; + const newLineSeqLength = newlineSequences[j] && newlineSequences[j].length || 0; + if (j === i) { + const pad = start - (count - (lineLength + newLineSeqLength)); + const length = Math.max( + 1, + end > count ? lineLength - pad : end - start + ); + res.push(` | ` + " ".repeat(pad) + "^".repeat(length)); + } else if (j > i) { + if (end > count) { + const length = Math.max(Math.min(end - count, lineLength), 1); + res.push(` | ` + "^".repeat(length)); + } + count += lineLength + newLineSeqLength; } + } + break; + } + } + return res.join("\n"); + } + + function normalizeStyle(value) { + if (isArray(value)) { + const res = {}; + for (let i = 0; i < value.length; i++) { + const item = value[i]; + const normalized = isString(item) ? parseStringStyle(item) : normalizeStyle(item); + if (normalized) { + for (const key in normalized) { + res[key] = normalized[key]; + } + } } return res; - } - /* eslint-disable no-unused-vars */ - /** - * Perform no operation. - * Stubbing args to make Flow happy without leaving useless transpiled code - * with ...rest (https://flow.org/blog/2017/05/07/Strict-Function-Call-Arity/). - */ - function noop(a, b, c) { } - /** - * Always return false. - */ - var no = function (a, b, c) { return false; }; - /* eslint-enable no-unused-vars */ - /** - * Return the same value. - */ - var identity = function (_) { return _; }; - /** - * Generate a string containing static keys from compiler modules. - */ - function genStaticKeys$1(modules) { - return modules - .reduce(function (keys, m) { - return keys.concat(m.staticKeys || []); - }, []) - .join(','); - } - /** - * Check if two values are loosely equal - that is, - * if they are plain objects, do they have the same shape? - */ - function looseEqual(a, b) { - if (a === b) - return true; - var isObjectA = isObject(a); - var isObjectB = isObject(b); - if (isObjectA && isObjectB) { - try { - var isArrayA = Array.isArray(a); - var isArrayB = Array.isArray(b); - if (isArrayA && isArrayB) { - return (a.length === b.length && - a.every(function (e, i) { - return looseEqual(e, b[i]); - })); - } - else if (a instanceof Date && b instanceof Date) { - return a.getTime() === b.getTime(); - } - else if (!isArrayA && !isArrayB) { - var keysA = Object.keys(a); - var keysB = Object.keys(b); - return (keysA.length === keysB.length && - keysA.every(function (key) { - return looseEqual(a[key], b[key]); - })); - } - else { - /* istanbul ignore next */ - return false; - } - } - catch (e) { - /* istanbul ignore next */ - return false; - } - } - else if (!isObjectA && !isObjectB) { - return String(a) === String(b); - } - else { - return false; - } - } - /** - * Return the first index at which a loosely equal value can be - * found in the array (if value is a plain object, the array must - * contain an object of the same shape), or -1 if it is not present. - */ - function looseIndexOf(arr, val) { - for (var i = 0; i < arr.length; i++) { - if (looseEqual(arr[i], val)) - return i; - } - return -1; - } - /** - * Ensure a function is called only once. - */ - function once(fn) { - var called = false; - return function () { - if (!called) { - called = true; - fn.apply(this, arguments); - } - }; - } - // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is#polyfill - function hasChanged(x, y) { - if (x === y) { - return x === 0 && 1 / x !== 1 / y; - } - else { - return x === x || y === y; - } - } - - var SSR_ATTR = 'data-server-rendered'; - var ASSET_TYPES = ['component', 'directive', 'filter']; - var LIFECYCLE_HOOKS = [ - 'beforeCreate', - 'created', - 'beforeMount', - 'mounted', - 'beforeUpdate', - 'updated', - 'beforeDestroy', - 'destroyed', - 'activated', - 'deactivated', - 'errorCaptured', - 'serverPrefetch', - 'renderTracked', - 'renderTriggered' - ]; - - var config = { - /** - * Option merge strategies (used in core/util/options) - */ - // $flow-disable-line - optionMergeStrategies: Object.create(null), - /** - * Whether to suppress warnings. - */ - silent: false, - /** - * Show production mode tip message on boot? - */ - productionTip: true, - /** - * Whether to enable devtools - */ - devtools: true, - /** - * Whether to record perf - */ - performance: false, - /** - * Error handler for watcher errors - */ - errorHandler: null, - /** - * Warn handler for watcher warns - */ - warnHandler: null, - /** - * Ignore certain custom elements - */ - ignoredElements: [], - /** - * Custom user key aliases for v-on - */ - // $flow-disable-line - keyCodes: Object.create(null), - /** - * Check if a tag is reserved so that it cannot be registered as a - * component. This is platform-dependent and may be overwritten. - */ - isReservedTag: no, - /** - * Check if an attribute is reserved so that it cannot be used as a component - * prop. This is platform-dependent and may be overwritten. - */ - isReservedAttr: no, - /** - * Check if a tag is an unknown element. - * Platform-dependent. - */ - isUnknownElement: no, - /** - * Get the namespace of an element - */ - getTagNamespace: noop, - /** - * Parse the real tag name for the specific platform. - */ - parsePlatformTagName: identity, - /** - * Check if an attribute must be bound using property, e.g. value - * Platform-dependent. - */ - mustUseProp: no, - /** - * Perform updates asynchronously. Intended to be used by Vue Test Utils - * This will significantly reduce performance if set to false. - */ - async: true, - /** - * Exposed for legacy reasons - */ - _lifecycleHooks: LIFECYCLE_HOOKS - }; - - /** - * unicode letters used for parsing html tags, component names and property paths. - * using https://www.w3.org/TR/html53/semantics-scripting.html#potentialcustomelementname - * skipping \u10000-\uEFFFF due to it freezing up PhantomJS - */ - var unicodeRegExp = /a-zA-Z\u00B7\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u037D\u037F-\u1FFF\u200C-\u200D\u203F-\u2040\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD/; - /** - * Check if a string starts with $ or _ - */ - function isReserved(str) { - var c = (str + '').charCodeAt(0); - return c === 0x24 || c === 0x5f; - } - /** - * Define a property. - */ - function def(obj, key, val, enumerable) { - Object.defineProperty(obj, key, { - value: val, - enumerable: !!enumerable, - writable: true, - configurable: true - }); - } - /** - * Parse simple path. - */ - var bailRE = new RegExp("[^".concat(unicodeRegExp.source, ".$_\\d]")); - function parsePath(path) { - if (bailRE.test(path)) { - return; - } - var segments = path.split('.'); - return function (obj) { - for (var i = 0; i < segments.length; i++) { - if (!obj) - return; - obj = obj[segments[i]]; - } - return obj; - }; - } - - // can we use __proto__? - var hasProto = '__proto__' in {}; - // Browser environment sniffing - var inBrowser = typeof window !== 'undefined'; - var UA = inBrowser && window.navigator.userAgent.toLowerCase(); - var isIE = UA && /msie|trident/.test(UA); - var isIE9 = UA && UA.indexOf('msie 9.0') > 0; - var isEdge = UA && UA.indexOf('edge/') > 0; - UA && UA.indexOf('android') > 0; - var isIOS = UA && /iphone|ipad|ipod|ios/.test(UA); - UA && /chrome\/\d+/.test(UA) && !isEdge; - UA && /phantomjs/.test(UA); - var isFF = UA && UA.match(/firefox\/(\d+)/); - // Firefox has a "watch" function on Object.prototype... - // @ts-expect-error firebox support - var nativeWatch = {}.watch; - var supportsPassive = false; - if (inBrowser) { - try { - var opts = {}; - Object.defineProperty(opts, 'passive', { - get: function () { - /* istanbul ignore next */ - supportsPassive = true; - } - }); // https://github.com/facebook/flow/issues/285 - window.addEventListener('test-passive', null, opts); - } - catch (e) { } - } - // this needs to be lazy-evaled because vue may be required before - // vue-server-renderer can set VUE_ENV - var _isServer; - var isServerRendering = function () { - if (_isServer === undefined) { - /* istanbul ignore if */ - if (!inBrowser && typeof global !== 'undefined') { - // detect presence of vue-server-renderer and avoid - // Webpack shimming the process - _isServer = - global['process'] && global['process'].env.VUE_ENV === 'server'; - } - else { - _isServer = false; - } - } - return _isServer; - }; - // detect devtools - var devtools = inBrowser && window.__VUE_DEVTOOLS_GLOBAL_HOOK__; - /* istanbul ignore next */ - function isNative(Ctor) { - return typeof Ctor === 'function' && /native code/.test(Ctor.toString()); - } - var hasSymbol = typeof Symbol !== 'undefined' && - isNative(Symbol) && - typeof Reflect !== 'undefined' && - isNative(Reflect.ownKeys); - var _Set; // $flow-disable-line - /* istanbul ignore if */ if (typeof Set !== 'undefined' && isNative(Set)) { - // use native Set when available. - _Set = Set; - } - else { - // a non-standard Set polyfill that only works with primitive keys. - _Set = /** @class */ (function () { - function Set() { - this.set = Object.create(null); - } - Set.prototype.has = function (key) { - return this.set[key] === true; - }; - Set.prototype.add = function (key) { - this.set[key] = true; - }; - Set.prototype.clear = function () { - this.set = Object.create(null); - }; - return Set; - }()); - } - - var currentInstance = null; - /** - * This is exposed for compatibility with v3 (e.g. some functions in VueUse - * relies on it). Do not use this internally, just use `currentInstance`. - * - * @internal this function needs manual type declaration because it relies - * on previously manually authored types from Vue 2 - */ - function getCurrentInstance() { - return currentInstance && { proxy: currentInstance }; - } - /** - * @internal - */ - function setCurrentInstance(vm) { - if (vm === void 0) { vm = null; } - if (!vm) - currentInstance && currentInstance._scope.off(); - currentInstance = vm; - vm && vm._scope.on(); - } - - /** - * @internal - */ - var VNode = /** @class */ (function () { - function VNode(tag, data, children, text, elm, context, componentOptions, asyncFactory) { - this.tag = tag; - this.data = data; - this.children = children; - this.text = text; - this.elm = elm; - this.ns = undefined; - this.context = context; - this.fnContext = undefined; - this.fnOptions = undefined; - this.fnScopeId = undefined; - this.key = data && data.key; - this.componentOptions = componentOptions; - this.componentInstance = undefined; - this.parent = undefined; - this.raw = false; - this.isStatic = false; - this.isRootInsert = true; - this.isComment = false; - this.isCloned = false; - this.isOnce = false; - this.asyncFactory = asyncFactory; - this.asyncMeta = undefined; - this.isAsyncPlaceholder = false; - } - Object.defineProperty(VNode.prototype, "child", { - // DEPRECATED: alias for componentInstance for backwards compat. - /* istanbul ignore next */ - get: function () { - return this.componentInstance; - }, - enumerable: false, - configurable: true - }); - return VNode; - }()); - var createEmptyVNode = function (text) { - if (text === void 0) { text = ''; } - var node = new VNode(); - node.text = text; - node.isComment = true; - return node; - }; - function createTextVNode(val) { - return new VNode(undefined, undefined, undefined, String(val)); - } - // optimized shallow clone - // used for static nodes and slot nodes because they may be reused across - // multiple renders, cloning them avoids errors when DOM manipulations rely - // on their elm reference. - function cloneVNode(vnode) { - var cloned = new VNode(vnode.tag, vnode.data, - // #7975 - // clone children array to avoid mutating original in case of cloning - // a child. - vnode.children && vnode.children.slice(), vnode.text, vnode.elm, vnode.context, vnode.componentOptions, vnode.asyncFactory); - cloned.ns = vnode.ns; - cloned.isStatic = vnode.isStatic; - cloned.key = vnode.key; - cloned.isComment = vnode.isComment; - cloned.fnContext = vnode.fnContext; - cloned.fnOptions = vnode.fnOptions; - cloned.fnScopeId = vnode.fnScopeId; - cloned.asyncMeta = vnode.asyncMeta; - cloned.isCloned = true; - return cloned; - } - - /* not type checking this file because flow doesn't play well with Proxy */ - var initProxy; - { - var allowedGlobals_1 = makeMap('Infinity,undefined,NaN,isFinite,isNaN,' + - 'parseFloat,parseInt,decodeURI,decodeURIComponent,encodeURI,encodeURIComponent,' + - 'Math,Number,Date,Array,Object,Boolean,String,RegExp,Map,Set,JSON,Intl,BigInt,' + - 'require' // for Webpack/Browserify - ); - var warnNonPresent_1 = function (target, key) { - warn$2("Property or method \"".concat(key, "\" is not defined on the instance but ") + - 'referenced during render. Make sure that this property is reactive, ' + - 'either in the data option, or for class-based components, by ' + - 'initializing the property. ' + - 'See: https://v2.vuejs.org/v2/guide/reactivity.html#Declaring-Reactive-Properties.', target); - }; - var warnReservedPrefix_1 = function (target, key) { - warn$2("Property \"".concat(key, "\" must be accessed with \"$data.").concat(key, "\" because ") + - 'properties starting with "$" or "_" are not proxied in the Vue instance to ' + - 'prevent conflicts with Vue internals. ' + - 'See: https://v2.vuejs.org/v2/api/#data', target); - }; - var hasProxy_1 = typeof Proxy !== 'undefined' && isNative(Proxy); - if (hasProxy_1) { - var isBuiltInModifier_1 = makeMap('stop,prevent,self,ctrl,shift,alt,meta,exact'); - config.keyCodes = new Proxy(config.keyCodes, { - set: function (target, key, value) { - if (isBuiltInModifier_1(key)) { - warn$2("Avoid overwriting built-in modifier in config.keyCodes: .".concat(key)); - return false; - } - else { - target[key] = value; - return true; - } - } - }); - } - var hasHandler_1 = { - has: function (target, key) { - var has = key in target; - var isAllowed = allowedGlobals_1(key) || - (typeof key === 'string' && - key.charAt(0) === '_' && - !(key in target.$data)); - if (!has && !isAllowed) { - if (key in target.$data) - warnReservedPrefix_1(target, key); - else - warnNonPresent_1(target, key); - } - return has || !isAllowed; - } - }; - var getHandler_1 = { - get: function (target, key) { - if (typeof key === 'string' && !(key in target)) { - if (key in target.$data) - warnReservedPrefix_1(target, key); - else - warnNonPresent_1(target, key); - } - return target[key]; - } - }; - initProxy = function initProxy(vm) { - if (hasProxy_1) { - // determine which proxy handler to use - var options = vm.$options; - var handlers = options.render && options.render._withStripped ? getHandler_1 : hasHandler_1; - vm._renderProxy = new Proxy(vm, handlers); - } - else { - vm._renderProxy = vm; - } - }; - } - - /****************************************************************************** - Copyright (c) Microsoft Corporation. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH - REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY - AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR - OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - PERFORMANCE OF THIS SOFTWARE. - ***************************************************************************** */ - - var __assign = function() { - __assign = Object.assign || function __assign(t) { - for (var s, i = 1, n = arguments.length; i < n; i++) { - s = arguments[i]; - for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; - } - return t; - }; - return __assign.apply(this, arguments); - }; - - var uid$2 = 0; - var pendingCleanupDeps = []; - var cleanupDeps = function () { - for (var i = 0; i < pendingCleanupDeps.length; i++) { - var dep = pendingCleanupDeps[i]; - dep.subs = dep.subs.filter(function (s) { return s; }); - dep._pending = false; - } - pendingCleanupDeps.length = 0; - }; - /** - * A dep is an observable that can have multiple - * directives subscribing to it. - * @internal - */ - var Dep = /** @class */ (function () { - function Dep() { - // pending subs cleanup - this._pending = false; - this.id = uid$2++; - this.subs = []; - } - Dep.prototype.addSub = function (sub) { - this.subs.push(sub); - }; - Dep.prototype.removeSub = function (sub) { - // #12696 deps with massive amount of subscribers are extremely slow to - // clean up in Chromium - // to workaround this, we unset the sub for now, and clear them on - // next scheduler flush. - this.subs[this.subs.indexOf(sub)] = null; - if (!this._pending) { - this._pending = true; - pendingCleanupDeps.push(this); - } - }; - Dep.prototype.depend = function (info) { - if (Dep.target) { - Dep.target.addDep(this); - if (info && Dep.target.onTrack) { - Dep.target.onTrack(__assign({ effect: Dep.target }, info)); - } - } - }; - Dep.prototype.notify = function (info) { - // stabilize the subscriber list first - var subs = this.subs.filter(function (s) { return s; }); - if (!config.async) { - // subs aren't sorted in scheduler if not running async - // we need to sort them now to make sure they fire in correct - // order - subs.sort(function (a, b) { return a.id - b.id; }); - } - for (var i = 0, l = subs.length; i < l; i++) { - var sub = subs[i]; - if (info) { - sub.onTrigger && - sub.onTrigger(__assign({ effect: subs[i] }, info)); - } - sub.update(); - } - }; - return Dep; - }()); - // The current target watcher being evaluated. - // This is globally unique because only one watcher - // can be evaluated at a time. - Dep.target = null; - var targetStack = []; - function pushTarget(target) { - targetStack.push(target); - Dep.target = target; - } - function popTarget() { - targetStack.pop(); - Dep.target = targetStack[targetStack.length - 1]; - } - - /* - * not type checking this file because flow doesn't play well with - * dynamically accessing methods on Array prototype - */ - var arrayProto = Array.prototype; - var arrayMethods = Object.create(arrayProto); - var methodsToPatch = [ - 'push', - 'pop', - 'shift', - 'unshift', - 'splice', - 'sort', - 'reverse' - ]; - /** - * Intercept mutating methods and emit events - */ - methodsToPatch.forEach(function (method) { - // cache original method - var original = arrayProto[method]; - def(arrayMethods, method, function mutator() { - var args = []; - for (var _i = 0; _i < arguments.length; _i++) { - args[_i] = arguments[_i]; - } - var result = original.apply(this, args); - var ob = this.__ob__; - var inserted; - switch (method) { - case 'push': - case 'unshift': - inserted = args; - break; - case 'splice': - inserted = args.slice(2); - break; - } - if (inserted) - ob.observeArray(inserted); - // notify change - { - ob.dep.notify({ - type: "array mutation" /* TriggerOpTypes.ARRAY_MUTATION */, - target: this, - key: method - }); - } - return result; - }); - }); - - var arrayKeys = Object.getOwnPropertyNames(arrayMethods); - var NO_INIITIAL_VALUE = {}; - /** - * In some cases we may want to disable observation inside a component's - * update computation. - */ - var shouldObserve = true; - function toggleObserving(value) { - shouldObserve = value; - } - // ssr mock dep - var mockDep = { - notify: noop, - depend: noop, - addSub: noop, - removeSub: noop - }; - /** - * Observer class that is attached to each observed - * object. Once attached, the observer converts the target - * object's property keys into getter/setters that - * collect dependencies and dispatch updates. - */ - var Observer = /** @class */ (function () { - function Observer(value, shallow, mock) { - if (shallow === void 0) { shallow = false; } - if (mock === void 0) { mock = false; } - this.value = value; - this.shallow = shallow; - this.mock = mock; - // this.value = value - this.dep = mock ? mockDep : new Dep(); - this.vmCount = 0; - def(value, '__ob__', this); - if (isArray(value)) { - if (!mock) { - if (hasProto) { - value.__proto__ = arrayMethods; - /* eslint-enable no-proto */ - } - else { - for (var i = 0, l = arrayKeys.length; i < l; i++) { - var key = arrayKeys[i]; - def(value, key, arrayMethods[key]); - } - } - } - if (!shallow) { - this.observeArray(value); - } - } - else { - /** - * Walk through all properties and convert them into - * getter/setters. This method should only be called when - * value type is Object. - */ - var keys = Object.keys(value); - for (var i = 0; i < keys.length; i++) { - var key = keys[i]; - defineReactive(value, key, NO_INIITIAL_VALUE, undefined, shallow, mock); - } - } - } - /** - * Observe a list of Array items. - */ - Observer.prototype.observeArray = function (value) { - for (var i = 0, l = value.length; i < l; i++) { - observe(value[i], false, this.mock); - } - }; - return Observer; - }()); - // helpers - /** - * Attempt to create an observer instance for a value, - * returns the new observer if successfully observed, - * or the existing observer if the value already has one. - */ - function observe(value, shallow, ssrMockReactivity) { - if (value && hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) { - return value.__ob__; - } - if (shouldObserve && - (ssrMockReactivity || !isServerRendering()) && - (isArray(value) || isPlainObject(value)) && - Object.isExtensible(value) && - !value.__v_skip /* ReactiveFlags.SKIP */ && - !isRef(value) && - !(value instanceof VNode)) { - return new Observer(value, shallow, ssrMockReactivity); - } - } - /** - * Define a reactive property on an Object. - */ - function defineReactive(obj, key, val, customSetter, shallow, mock) { - var dep = new Dep(); - var property = Object.getOwnPropertyDescriptor(obj, key); - if (property && property.configurable === false) { - return; - } - // cater for pre-defined getter/setters - var getter = property && property.get; - var setter = property && property.set; - if ((!getter || setter) && - (val === NO_INIITIAL_VALUE || arguments.length === 2)) { - val = obj[key]; - } - var childOb = !shallow && observe(val, false, mock); - Object.defineProperty(obj, key, { - enumerable: true, - configurable: true, - get: function reactiveGetter() { - var value = getter ? getter.call(obj) : val; - if (Dep.target) { - { - dep.depend({ - target: obj, - type: "get" /* TrackOpTypes.GET */, - key: key - }); - } - if (childOb) { - childOb.dep.depend(); - if (isArray(value)) { - dependArray(value); - } - } - } - return isRef(value) && !shallow ? value.value : value; - }, - set: function reactiveSetter(newVal) { - var value = getter ? getter.call(obj) : val; - if (!hasChanged(value, newVal)) { - return; - } - if (customSetter) { - customSetter(); - } - if (setter) { - setter.call(obj, newVal); - } - else if (getter) { - // #7981: for accessor properties without setter - return; - } - else if (!shallow && isRef(value) && !isRef(newVal)) { - value.value = newVal; - return; - } - else { - val = newVal; - } - childOb = !shallow && observe(newVal, false, mock); - { - dep.notify({ - type: "set" /* TriggerOpTypes.SET */, - target: obj, - key: key, - newValue: newVal, - oldValue: value - }); - } - } - }); - return dep; - } - function set(target, key, val) { - if ((isUndef(target) || isPrimitive(target))) { - warn$2("Cannot set reactive property on undefined, null, or primitive value: ".concat(target)); - } - if (isReadonly(target)) { - warn$2("Set operation on key \"".concat(key, "\" failed: target is readonly.")); - return; - } - var ob = target.__ob__; - if (isArray(target) && isValidArrayIndex(key)) { - target.length = Math.max(target.length, key); - target.splice(key, 1, val); - // when mocking for SSR, array methods are not hijacked - if (ob && !ob.shallow && ob.mock) { - observe(val, false, true); - } - return val; - } - if (key in target && !(key in Object.prototype)) { - target[key] = val; - return val; - } - if (target._isVue || (ob && ob.vmCount)) { - warn$2('Avoid adding reactive properties to a Vue instance or its root $data ' + - 'at runtime - declare it upfront in the data option.'); - return val; - } - if (!ob) { - target[key] = val; - return val; - } - defineReactive(ob.value, key, val, undefined, ob.shallow, ob.mock); - { - ob.dep.notify({ - type: "add" /* TriggerOpTypes.ADD */, - target: target, - key: key, - newValue: val, - oldValue: undefined - }); - } - return val; - } - function del(target, key) { - if ((isUndef(target) || isPrimitive(target))) { - warn$2("Cannot delete reactive property on undefined, null, or primitive value: ".concat(target)); - } - if (isArray(target) && isValidArrayIndex(key)) { - target.splice(key, 1); - return; - } - var ob = target.__ob__; - if (target._isVue || (ob && ob.vmCount)) { - warn$2('Avoid deleting properties on a Vue instance or its root $data ' + - '- just set it to null.'); - return; - } - if (isReadonly(target)) { - warn$2("Delete operation on key \"".concat(key, "\" failed: target is readonly.")); - return; - } - if (!hasOwn(target, key)) { - return; - } - delete target[key]; - if (!ob) { - return; - } - { - ob.dep.notify({ - type: "delete" /* TriggerOpTypes.DELETE */, - target: target, - key: key - }); - } - } - /** - * Collect dependencies on array elements when the array is touched, since - * we cannot intercept array element access like property getters. - */ - function dependArray(value) { - for (var e = void 0, i = 0, l = value.length; i < l; i++) { - e = value[i]; - if (e && e.__ob__) { - e.__ob__.dep.depend(); - } - if (isArray(e)) { - dependArray(e); - } - } - } - - function reactive(target) { - makeReactive(target, false); - return target; - } - /** - * Return a shallowly-reactive copy of the original object, where only the root - * level properties are reactive. It also does not auto-unwrap refs (even at the - * root level). - */ - function shallowReactive(target) { - makeReactive(target, true); - def(target, "__v_isShallow" /* ReactiveFlags.IS_SHALLOW */, true); - return target; - } - function makeReactive(target, shallow) { - // if trying to observe a readonly proxy, return the readonly version. - if (!isReadonly(target)) { - { - if (isArray(target)) { - warn$2("Avoid using Array as root value for ".concat(shallow ? "shallowReactive()" : "reactive()", " as it cannot be tracked in watch() or watchEffect(). Use ").concat(shallow ? "shallowRef()" : "ref()", " instead. This is a Vue-2-only limitation.")); - } - var existingOb = target && target.__ob__; - if (existingOb && existingOb.shallow !== shallow) { - warn$2("Target is already a ".concat(existingOb.shallow ? "" : "non-", "shallow reactive object, and cannot be converted to ").concat(shallow ? "" : "non-", "shallow.")); - } - } - var ob = observe(target, shallow, isServerRendering() /* ssr mock reactivity */); - if (!ob) { - if (target == null || isPrimitive(target)) { - warn$2("value cannot be made reactive: ".concat(String(target))); - } - if (isCollectionType(target)) { - warn$2("Vue 2 does not support reactive collection types such as Map or Set."); - } - } - } - } - function isReactive(value) { - if (isReadonly(value)) { - return isReactive(value["__v_raw" /* ReactiveFlags.RAW */]); - } - return !!(value && value.__ob__); - } - function isShallow(value) { - return !!(value && value.__v_isShallow); - } - function isReadonly(value) { - return !!(value && value.__v_isReadonly); - } - function isProxy(value) { - return isReactive(value) || isReadonly(value); - } - function toRaw(observed) { - var raw = observed && observed["__v_raw" /* ReactiveFlags.RAW */]; - return raw ? toRaw(raw) : observed; - } - function markRaw(value) { - // non-extensible objects won't be observed anyway - if (Object.isExtensible(value)) { - def(value, "__v_skip" /* ReactiveFlags.SKIP */, true); - } + } else if (isString(value) || isObject(value)) { return value; + } } - /** - * @internal - */ - function isCollectionType(value) { - var type = toRawType(value); - return (type === 'Map' || type === 'WeakMap' || type === 'Set' || type === 'WeakSet'); + const listDelimiterRE = /;(?![^(]*\))/g; + const propertyDelimiterRE = /:([^]+)/; + const styleCommentRE = /\/\*[^]*?\*\//g; + function parseStringStyle(cssText) { + const ret = {}; + cssText.replace(styleCommentRE, "").split(listDelimiterRE).forEach((item) => { + if (item) { + const tmp = item.split(propertyDelimiterRE); + tmp.length > 1 && (ret[tmp[0].trim()] = tmp[1].trim()); + } + }); + return ret; + } + function stringifyStyle(styles) { + if (!styles) return ""; + if (isString(styles)) return styles; + let ret = ""; + for (const key in styles) { + const value = styles[key]; + if (isString(value) || typeof value === "number") { + const normalizedKey = key.startsWith(`--`) ? key : hyphenate(key); + ret += `${normalizedKey}:${value};`; + } + } + return ret; + } + function normalizeClass(value) { + let res = ""; + if (isString(value)) { + res = value; + } else if (isArray(value)) { + for (let i = 0; i < value.length; i++) { + const normalized = normalizeClass(value[i]); + if (normalized) { + res += normalized + " "; + } + } + } else if (isObject(value)) { + for (const name in value) { + if (value[name]) { + res += name + " "; + } + } + } + return res.trim(); + } + function normalizeProps(props) { + if (!props) return null; + let { class: klass, style } = props; + if (klass && !isString(klass)) { + props.class = normalizeClass(klass); + } + if (style) { + props.style = normalizeStyle(style); + } + return props; } - /** - * @internal - */ - var RefFlag = "__v_isRef"; - function isRef(r) { - return !!(r && r.__v_isRef === true); - } - function ref$1(value) { - return createRef(value, false); - } - function shallowRef(value) { - return createRef(value, true); - } - function createRef(rawValue, shallow) { - if (isRef(rawValue)) { - return rawValue; - } - var ref = {}; - def(ref, RefFlag, true); - def(ref, "__v_isShallow" /* ReactiveFlags.IS_SHALLOW */, shallow); - def(ref, 'dep', defineReactive(ref, 'value', rawValue, null, shallow, isServerRendering())); - return ref; - } - function triggerRef(ref) { - if (!ref.dep) { - warn$2("received object is not a triggerable ref."); - } - { - ref.dep && - ref.dep.notify({ - type: "set" /* TriggerOpTypes.SET */, - target: ref, - key: 'value' - }); - } - } - function unref(ref) { - return isRef(ref) ? ref.value : ref; - } - function proxyRefs(objectWithRefs) { - if (isReactive(objectWithRefs)) { - return objectWithRefs; - } - var proxy = {}; - var keys = Object.keys(objectWithRefs); - for (var i = 0; i < keys.length; i++) { - proxyWithRefUnwrap(proxy, objectWithRefs, keys[i]); - } - return proxy; - } - function proxyWithRefUnwrap(target, source, key) { - Object.defineProperty(target, key, { - enumerable: true, - configurable: true, - get: function () { - var val = source[key]; - if (isRef(val)) { - return val.value; - } - else { - var ob = val && val.__ob__; - if (ob) - ob.dep.depend(); - return val; - } - }, - set: function (value) { - var oldValue = source[key]; - if (isRef(oldValue) && !isRef(value)) { - oldValue.value = value; - } - else { - source[key] = value; - } - } - }); - } - function customRef(factory) { - var dep = new Dep(); - var _a = factory(function () { - { - dep.depend({ - target: ref, - type: "get" /* TrackOpTypes.GET */, - key: 'value' - }); - } - }, function () { - { - dep.notify({ - target: ref, - type: "set" /* TriggerOpTypes.SET */, - key: 'value' - }); - } - }), get = _a.get, set = _a.set; - var ref = { - get value() { - return get(); - }, - set value(newVal) { - set(newVal); - } - }; - def(ref, RefFlag, true); - return ref; - } - function toRefs(object) { - if (!isReactive(object)) { - warn$2("toRefs() expects a reactive object but received a plain one."); - } - var ret = isArray(object) ? new Array(object.length) : {}; - for (var key in object) { - ret[key] = toRef(object, key); - } - return ret; - } - function toRef(object, key, defaultValue) { - var val = object[key]; - if (isRef(val)) { - return val; - } - var ref = { - get value() { - var val = object[key]; - return val === undefined ? defaultValue : val; - }, - set value(newVal) { - object[key] = newVal; - } - }; - def(ref, RefFlag, true); - return ref; - } + const HTML_TAGS = "html,body,base,head,link,meta,style,title,address,article,aside,footer,header,hgroup,h1,h2,h3,h4,h5,h6,nav,section,div,dd,dl,dt,figcaption,figure,picture,hr,img,li,main,ol,p,pre,ul,a,b,abbr,bdi,bdo,br,cite,code,data,dfn,em,i,kbd,mark,q,rp,rt,ruby,s,samp,small,span,strong,sub,sup,time,u,var,wbr,area,audio,map,track,video,embed,object,param,source,canvas,script,noscript,del,ins,caption,col,colgroup,table,thead,tbody,td,th,tr,button,datalist,fieldset,form,input,label,legend,meter,optgroup,option,output,progress,select,textarea,details,dialog,menu,summary,template,blockquote,iframe,tfoot"; + const SVG_TAGS = "svg,animate,animateMotion,animateTransform,circle,clipPath,color-profile,defs,desc,discard,ellipse,feBlend,feColorMatrix,feComponentTransfer,feComposite,feConvolveMatrix,feDiffuseLighting,feDisplacementMap,feDistantLight,feDropShadow,feFlood,feFuncA,feFuncB,feFuncG,feFuncR,feGaussianBlur,feImage,feMerge,feMergeNode,feMorphology,feOffset,fePointLight,feSpecularLighting,feSpotLight,feTile,feTurbulence,filter,foreignObject,g,hatch,hatchpath,image,line,linearGradient,marker,mask,mesh,meshgradient,meshpatch,meshrow,metadata,mpath,path,pattern,polygon,polyline,radialGradient,rect,set,solidcolor,stop,switch,symbol,text,textPath,title,tspan,unknown,use,view"; + const MATH_TAGS = "annotation,annotation-xml,maction,maligngroup,malignmark,math,menclose,merror,mfenced,mfrac,mfraction,mglyph,mi,mlabeledtr,mlongdiv,mmultiscripts,mn,mo,mover,mpadded,mphantom,mprescripts,mroot,mrow,ms,mscarries,mscarry,msgroup,msline,mspace,msqrt,msrow,mstack,mstyle,msub,msubsup,msup,mtable,mtd,mtext,mtr,munder,munderover,none,semantics"; + const VOID_TAGS = "area,base,br,col,embed,hr,img,input,link,meta,param,source,track,wbr"; + const isHTMLTag = /* @__PURE__ */ makeMap(HTML_TAGS); + const isSVGTag = /* @__PURE__ */ makeMap(SVG_TAGS); + const isMathMLTag = /* @__PURE__ */ makeMap(MATH_TAGS); + const isVoidTag = /* @__PURE__ */ makeMap(VOID_TAGS); - var rawToReadonlyFlag = "__v_rawToReadonly"; - var rawToShallowReadonlyFlag = "__v_rawToShallowReadonly"; - function readonly(target) { - return createReadonly(target, false); + const specialBooleanAttrs = `itemscope,allowfullscreen,formnovalidate,ismap,nomodule,novalidate,readonly`; + const isSpecialBooleanAttr = /* @__PURE__ */ makeMap(specialBooleanAttrs); + const isBooleanAttr = /* @__PURE__ */ makeMap( + specialBooleanAttrs + `,async,autofocus,autoplay,controls,default,defer,disabled,hidden,inert,loop,open,required,reversed,scoped,seamless,checked,muted,multiple,selected` + ); + function includeBooleanAttr(value) { + return !!value || value === ""; } - function createReadonly(target, shallow) { - if (!isPlainObject(target)) { - { - if (isArray(target)) { - warn$2("Vue 2 does not support readonly arrays."); - } - else if (isCollectionType(target)) { - warn$2("Vue 2 does not support readonly collection types such as Map or Set."); - } - else { - warn$2("value cannot be made readonly: ".concat(typeof target)); - } - } - return target; - } - if (!Object.isExtensible(target)) { - warn$2("Vue 2 does not support creating readonly proxy for non-extensible object."); - } - // already a readonly object - if (isReadonly(target)) { - return target; - } - // already has a readonly proxy - var existingFlag = shallow ? rawToShallowReadonlyFlag : rawToReadonlyFlag; - var existingProxy = target[existingFlag]; - if (existingProxy) { - return existingProxy; - } - var proxy = Object.create(Object.getPrototypeOf(target)); - def(target, existingFlag, proxy); - def(proxy, "__v_isReadonly" /* ReactiveFlags.IS_READONLY */, true); - def(proxy, "__v_raw" /* ReactiveFlags.RAW */, target); - if (isRef(target)) { - def(proxy, RefFlag, true); - } - if (shallow || isShallow(target)) { - def(proxy, "__v_isShallow" /* ReactiveFlags.IS_SHALLOW */, true); - } - var keys = Object.keys(target); - for (var i = 0; i < keys.length; i++) { - defineReadonlyProperty(proxy, target, keys[i], shallow); - } - return proxy; - } - function defineReadonlyProperty(proxy, target, key, shallow) { - Object.defineProperty(proxy, key, { - enumerable: true, - configurable: true, - get: function () { - var val = target[key]; - return shallow || !isPlainObject(val) ? val : readonly(val); - }, - set: function () { - warn$2("Set operation on key \"".concat(key, "\" failed: target is readonly.")); - } - }); - } - /** - * Returns a reactive-copy of the original object, where only the root level - * properties are readonly, and does NOT unwrap refs nor recursively convert - * returned properties. - * This is used for creating the props proxy object for stateful components. - */ - function shallowReadonly(target) { - return createReadonly(target, true); - } - - function computed(getterOrOptions, debugOptions) { - var getter; - var setter; - var onlyGetter = isFunction(getterOrOptions); - if (onlyGetter) { - getter = getterOrOptions; - setter = function () { - warn$2('Write operation failed: computed value is readonly'); - } - ; - } - else { - getter = getterOrOptions.get; - setter = getterOrOptions.set; - } - var watcher = isServerRendering() - ? null - : new Watcher(currentInstance, getter, noop, { lazy: true }); - if (watcher && debugOptions) { - watcher.onTrack = debugOptions.onTrack; - watcher.onTrigger = debugOptions.onTrigger; - } - var ref = { - // some libs rely on the presence effect for checking computed refs - // from normal refs, but the implementation doesn't matter - effect: watcher, - get value() { - if (watcher) { - if (watcher.dirty) { - watcher.evaluate(); - } - if (Dep.target) { - if (Dep.target.onTrack) { - Dep.target.onTrack({ - effect: Dep.target, - target: ref, - type: "get" /* TrackOpTypes.GET */, - key: 'value' - }); - } - watcher.depend(); - } - return watcher.value; - } - else { - return getter(); - } - }, - set value(newVal) { - setter(newVal); - } - }; - def(ref, RefFlag, true); - def(ref, "__v_isReadonly" /* ReactiveFlags.IS_READONLY */, onlyGetter); - return ref; - } - - var mark; - var measure; - { - var perf_1 = inBrowser && window.performance; - /* istanbul ignore if */ - if (perf_1 && - // @ts-ignore - perf_1.mark && - // @ts-ignore - perf_1.measure && - // @ts-ignore - perf_1.clearMarks && - // @ts-ignore - perf_1.clearMeasures) { - mark = function (tag) { return perf_1.mark(tag); }; - measure = function (name, startTag, endTag) { - perf_1.measure(name, startTag, endTag); - perf_1.clearMarks(startTag); - perf_1.clearMarks(endTag); - // perf.clearMeasures(name) - }; - } - } - - var normalizeEvent = cached(function (name) { - var passive = name.charAt(0) === '&'; - name = passive ? name.slice(1) : name; - var once = name.charAt(0) === '~'; // Prefixed last, checked first - name = once ? name.slice(1) : name; - var capture = name.charAt(0) === '!'; - name = capture ? name.slice(1) : name; - return { - name: name, - once: once, - capture: capture, - passive: passive - }; - }); - function createFnInvoker(fns, vm) { - function invoker() { - var fns = invoker.fns; - if (isArray(fns)) { - var cloned = fns.slice(); - for (var i = 0; i < cloned.length; i++) { - invokeWithErrorHandling(cloned[i], null, arguments, vm, "v-on handler"); - } - } - else { - // return handler return value for single handlers - return invokeWithErrorHandling(fns, null, arguments, vm, "v-on handler"); - } - } - invoker.fns = fns; - return invoker; - } - function updateListeners(on, oldOn, add, remove, createOnceHandler, vm) { - var name, cur, old, event; - for (name in on) { - cur = on[name]; - old = oldOn[name]; - event = normalizeEvent(name); - if (isUndef(cur)) { - warn$2("Invalid handler for event \"".concat(event.name, "\": got ") + String(cur), vm); - } - else if (isUndef(old)) { - if (isUndef(cur.fns)) { - cur = on[name] = createFnInvoker(cur, vm); - } - if (isTrue(event.once)) { - cur = on[name] = createOnceHandler(event.name, cur, event.capture); - } - add(event.name, cur, event.capture, event.passive, event.params); - } - else if (cur !== old) { - old.fns = cur; - on[name] = old; - } - } - for (name in oldOn) { - if (isUndef(on[name])) { - event = normalizeEvent(name); - remove(event.name, oldOn[name], event.capture); - } - } - } - - function mergeVNodeHook(def, hookKey, hook) { - if (def instanceof VNode) { - def = def.data.hook || (def.data.hook = {}); - } - var invoker; - var oldHook = def[hookKey]; - function wrappedHook() { - hook.apply(this, arguments); - // important: remove merged hook to ensure it's called only once - // and prevent memory leak - remove$2(invoker.fns, wrappedHook); - } - if (isUndef(oldHook)) { - // no existing hook - invoker = createFnInvoker([wrappedHook]); - } - else { - /* istanbul ignore if */ - if (isDef(oldHook.fns) && isTrue(oldHook.merged)) { - // already a merged invoker - invoker = oldHook; - invoker.fns.push(wrappedHook); - } - else { - // existing plain hook - invoker = createFnInvoker([oldHook, wrappedHook]); - } - } - invoker.merged = true; - def[hookKey] = invoker; - } - - function extractPropsFromVNodeData(data, Ctor, tag) { - // we are only extracting raw values here. - // validation and default values are handled in the child - // component itself. - var propOptions = Ctor.options.props; - if (isUndef(propOptions)) { - return; - } - var res = {}; - var attrs = data.attrs, props = data.props; - if (isDef(attrs) || isDef(props)) { - for (var key in propOptions) { - var altKey = hyphenate(key); - { - var keyInLowerCase = key.toLowerCase(); - if (key !== keyInLowerCase && attrs && hasOwn(attrs, keyInLowerCase)) { - tip("Prop \"".concat(keyInLowerCase, "\" is passed to component ") + - "".concat(formatComponentName( - // @ts-expect-error tag is string - tag || Ctor), ", but the declared prop name is") + - " \"".concat(key, "\". ") + - "Note that HTML attributes are case-insensitive and camelCased " + - "props need to use their kebab-case equivalents when using in-DOM " + - "templates. You should probably use \"".concat(altKey, "\" instead of \"").concat(key, "\".")); - } - } - checkProp(res, props, key, altKey, true) || - checkProp(res, attrs, key, altKey, false); - } - } - return res; - } - function checkProp(res, hash, key, altKey, preserve) { - if (isDef(hash)) { - if (hasOwn(hash, key)) { - res[key] = hash[key]; - if (!preserve) { - delete hash[key]; - } - return true; - } - else if (hasOwn(hash, altKey)) { - res[key] = hash[altKey]; - if (!preserve) { - delete hash[altKey]; - } - return true; - } - } + const isKnownHtmlAttr = /* @__PURE__ */ makeMap( + `accept,accept-charset,accesskey,action,align,allow,alt,async,autocapitalize,autocomplete,autofocus,autoplay,background,bgcolor,border,buffered,capture,challenge,charset,checked,cite,class,code,codebase,color,cols,colspan,content,contenteditable,contextmenu,controls,coords,crossorigin,csp,data,datetime,decoding,default,defer,dir,dirname,disabled,download,draggable,dropzone,enctype,enterkeyhint,for,form,formaction,formenctype,formmethod,formnovalidate,formtarget,headers,height,hidden,high,href,hreflang,http-equiv,icon,id,importance,inert,integrity,ismap,itemprop,keytype,kind,label,lang,language,loading,list,loop,low,manifest,max,maxlength,minlength,media,min,multiple,muted,name,novalidate,open,optimum,pattern,ping,placeholder,poster,preload,radiogroup,readonly,referrerpolicy,rel,required,reversed,rows,rowspan,sandbox,scope,scoped,selected,shape,size,sizes,slot,span,spellcheck,src,srcdoc,srclang,srcset,start,step,style,summary,tabindex,target,title,translate,type,usemap,value,width,wrap` + ); + const isKnownSvgAttr = /* @__PURE__ */ makeMap( + `xmlns,accent-height,accumulate,additive,alignment-baseline,alphabetic,amplitude,arabic-form,ascent,attributeName,attributeType,azimuth,baseFrequency,baseline-shift,baseProfile,bbox,begin,bias,by,calcMode,cap-height,class,clip,clipPathUnits,clip-path,clip-rule,color,color-interpolation,color-interpolation-filters,color-profile,color-rendering,contentScriptType,contentStyleType,crossorigin,cursor,cx,cy,d,decelerate,descent,diffuseConstant,direction,display,divisor,dominant-baseline,dur,dx,dy,edgeMode,elevation,enable-background,end,exponent,fill,fill-opacity,fill-rule,filter,filterRes,filterUnits,flood-color,flood-opacity,font-family,font-size,font-size-adjust,font-stretch,font-style,font-variant,font-weight,format,from,fr,fx,fy,g1,g2,glyph-name,glyph-orientation-horizontal,glyph-orientation-vertical,glyphRef,gradientTransform,gradientUnits,hanging,height,href,hreflang,horiz-adv-x,horiz-origin-x,id,ideographic,image-rendering,in,in2,intercept,k,k1,k2,k3,k4,kernelMatrix,kernelUnitLength,kerning,keyPoints,keySplines,keyTimes,lang,lengthAdjust,letter-spacing,lighting-color,limitingConeAngle,local,marker-end,marker-mid,marker-start,markerHeight,markerUnits,markerWidth,mask,maskContentUnits,maskUnits,mathematical,max,media,method,min,mode,name,numOctaves,offset,opacity,operator,order,orient,orientation,origin,overflow,overline-position,overline-thickness,panose-1,paint-order,path,pathLength,patternContentUnits,patternTransform,patternUnits,ping,pointer-events,points,pointsAtX,pointsAtY,pointsAtZ,preserveAlpha,preserveAspectRatio,primitiveUnits,r,radius,referrerPolicy,refX,refY,rel,rendering-intent,repeatCount,repeatDur,requiredExtensions,requiredFeatures,restart,result,rotate,rx,ry,scale,seed,shape-rendering,slope,spacing,specularConstant,specularExponent,speed,spreadMethod,startOffset,stdDeviation,stemh,stemv,stitchTiles,stop-color,stop-opacity,strikethrough-position,strikethrough-thickness,string,stroke,stroke-dasharray,stroke-dashoffset,stroke-linecap,stroke-linejoin,stroke-miterlimit,stroke-opacity,stroke-width,style,surfaceScale,systemLanguage,tabindex,tableValues,target,targetX,targetY,text-anchor,text-decoration,text-rendering,textLength,to,transform,transform-origin,type,u1,u2,underline-position,underline-thickness,unicode,unicode-bidi,unicode-range,units-per-em,v-alphabetic,v-hanging,v-ideographic,v-mathematical,values,vector-effect,version,vert-adv-y,vert-origin-x,vert-origin-y,viewBox,viewTarget,visibility,width,widths,word-spacing,writing-mode,x,x-height,x1,x2,xChannelSelector,xlink:actuate,xlink:arcrole,xlink:href,xlink:role,xlink:show,xlink:title,xlink:type,xmlns:xlink,xml:base,xml:lang,xml:space,y,y1,y2,yChannelSelector,z,zoomAndPan` + ); + function isRenderableAttrValue(value) { + if (value == null) { return false; + } + const type = typeof value; + return type === "string" || type === "number" || type === "boolean"; } - // The template compiler attempts to minimize the need for normalization by - // statically analyzing the template at compile time. - // - // For plain HTML markup, normalization can be completely skipped because the - // generated render function is guaranteed to return Array. There are - // two cases where extra normalization is needed: - // 1. When the children contains components - because a functional component - // may return an Array instead of a single root. In this case, just a simple - // normalization is needed - if any child is an Array, we flatten the whole - // thing with Array.prototype.concat. It is guaranteed to be only 1-level deep - // because functional components already normalize their own children. - function simpleNormalizeChildren(children) { - for (var i = 0; i < children.length; i++) { - if (isArray(children[i])) { - return Array.prototype.concat.apply([], children); - } - } - return children; - } - // 2. When the children contains constructs that always generated nested Arrays, - // e.g.