Compare commits
55 Commits
df4b990316
...
v1.1-stabl
Author | SHA1 | Date | |
---|---|---|---|
479200df9e | |||
20cf08e2a1 | |||
ab654a754c | |||
8990fed8f0 | |||
be6c8023c5 | |||
24cb1061a7 | |||
77ba05e407 | |||
f3454897d8 | |||
dc4e37eb8a | |||
522abee794 | |||
8278e4119f | |||
0a3a282d0f | |||
3d97824ee7 | |||
55fa498dc1 | |||
f5c5caa31c | |||
833374a80e | |||
b67011b9a3 | |||
91e9c0301e | |||
98dcc06a6a | |||
e0aacfe8aa | |||
3e4ffc8281 | |||
1f8ea04f43 | |||
ad6d734f4a | |||
6d79d60eb1 | |||
572a2583f0 | |||
925fec6dda | |||
5f3d5791da | |||
c05a9cff7a | |||
dff0ba1cd3 | |||
43f35da9a2 | |||
ac04c0545b | |||
3e46f82c0e | |||
1536914888 | |||
1a80e9d455 | |||
e2618e0300 | |||
1d73547eae | |||
4a27a46c27 | |||
55448c2bfe | |||
87725ad20a | |||
cc354b73e3 | |||
200dfef698 | |||
5ab16a89db | |||
e27164a8b3 | |||
ccc7766e88 | |||
6d076f03cd | |||
ed1bd12c95 | |||
515a05ec9b | |||
eda26319c4 | |||
0dcc562b7d | |||
6467333846 | |||
484a6abe08 | |||
9577ac844d | |||
ed0bfce64d | |||
8da8c054bf | |||
90b1f221ea |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -4,3 +4,4 @@ cmake-build-*
|
|||||||
cert.pem
|
cert.pem
|
||||||
key.pem
|
key.pem
|
||||||
dh.pem
|
dh.pem
|
||||||
|
/web-action
|
||||||
|
@@ -15,6 +15,16 @@ else()
|
|||||||
message(FATAL_ERROR "You must set build type \"Debug\" or \"Release\". Another build types not supported!")
|
message(FATAL_ERROR "You must set build type \"Debug\" or \"Release\". Another build types not supported!")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if("${MODEM_TYPE}" STREQUAL "SCPC")
|
||||||
|
add_definitions(-DMODEM_IS_SCPC)
|
||||||
|
message(STATUS "Selected SCPC modem")
|
||||||
|
elseif ("${MODEM_TYPE}" STREQUAL "TDMA")
|
||||||
|
add_definitions(-DMODEM_IS_TDMA)
|
||||||
|
message(STATUS "Selected TDMA modem")
|
||||||
|
else()
|
||||||
|
message(FATAL_ERROR "You must set `MODEM_TYPE` \"SCPC\" or \"TDMA\"!")
|
||||||
|
endif()
|
||||||
|
|
||||||
add_compile_options(-Wall -Wextra -Wsign-conversion)
|
add_compile_options(-Wall -Wextra -Wsign-conversion)
|
||||||
|
|
||||||
# максимальный размер тела запроса 200mb
|
# максимальный размер тела запроса 200mb
|
||||||
@@ -47,6 +57,8 @@ add_executable(terminal-web-server
|
|||||||
src/auth/utils.h
|
src/auth/utils.h
|
||||||
)
|
)
|
||||||
|
|
||||||
|
add_definitions(-DBOOST_LOG_DYN_LINK)
|
||||||
|
|
||||||
find_package(Boost 1.53.0 COMPONENTS system thread filesystem log log_setup REQUIRED)
|
find_package(Boost 1.53.0 COMPONENTS system thread filesystem log log_setup REQUIRED)
|
||||||
find_package(OpenSSL REQUIRED)
|
find_package(OpenSSL REQUIRED)
|
||||||
target_link_libraries(terminal-web-server ${Boost_LIBRARIES} ${OPENSSL_LIBRARIES} terminal-client-api)
|
target_link_libraries(terminal-web-server ${Boost_LIBRARIES} ${OPENSSL_LIBRARIES} terminal-client-api)
|
||||||
|
6
dependencies/control_system/CMakeLists.txt
vendored
6
dependencies/control_system/CMakeLists.txt
vendored
@@ -14,15 +14,15 @@ include(CheckCXXCompilerFlag)
|
|||||||
set(CMAKE_CXX_FLAGS -fPIC)
|
set(CMAKE_CXX_FLAGS -fPIC)
|
||||||
|
|
||||||
set(default_build_type "Release")
|
set(default_build_type "Release")
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Werror")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
|
||||||
set(CMAKE_CXX_FLAGS_DEBUG "-ggdb -O0 -fprofile-arcs -ftest-coverage")
|
set(CMAKE_CXX_FLAGS_DEBUG "-ggdb -O0")
|
||||||
set(CMAKE_CXX_FLAGS_RELEASE "-O2 -s -DNDEBUG ")
|
set(CMAKE_CXX_FLAGS_RELEASE "-O2 -s -DNDEBUG ")
|
||||||
message(${CMAKE_CXX_FLAGS})
|
message(${CMAKE_CXX_FLAGS})
|
||||||
message("CMAKE_BUILD_TYPE: " ${CMAKE_BUILD_TYPE})
|
message("CMAKE_BUILD_TYPE: " ${CMAKE_BUILD_TYPE})
|
||||||
|
|
||||||
message(${CMAKE_CXX_FLAGS})
|
message(${CMAKE_CXX_FLAGS})
|
||||||
|
|
||||||
add_library(terminal-client-api SHARED
|
add_library(terminal-client-api STATIC
|
||||||
client/main.cpp
|
client/main.cpp
|
||||||
client/sock_client.cpp
|
client/sock_client.cpp
|
||||||
client/system_client.cpp
|
client/system_client.cpp
|
||||||
|
75
front-generator/render-params.json
Normal file
75
front-generator/render-params.json
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
{
|
||||||
|
"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"],
|
||||||
|
"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": "Администрирование"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"scpc": {
|
||||||
|
"modem_name": "RCSM-101",
|
||||||
|
"groupsList": ["rxtx"],
|
||||||
|
"tabs": [
|
||||||
|
{
|
||||||
|
"name": "monitoring",
|
||||||
|
"desc": "Мониторинг"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "setup",
|
||||||
|
"desc": "Настройки"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "qos",
|
||||||
|
"desc": "QoS"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "admin",
|
||||||
|
"desc": "Администрирование"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
39
front-generator/render.py
Normal file
39
front-generator/render.py
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
import json
|
||||||
|
|
||||||
|
from jinja2 import Environment, FileSystemLoader
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
def build_modem_env(modem):
|
||||||
|
with open('render-params.json') as f:
|
||||||
|
config = json.load(f)
|
||||||
|
if modem not in config['modem_types']:
|
||||||
|
raise RuntimeError(f"Modem '{modem}' is not exist in config!")
|
||||||
|
|
||||||
|
mc = config['modem_types'][modem]
|
||||||
|
|
||||||
|
return {
|
||||||
|
"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"]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def render_modem(modem):
|
||||||
|
loader = FileSystemLoader('template')
|
||||||
|
env = Environment(loader=loader, trim_blocks=True, lstrip_blocks=True)
|
||||||
|
template = env.get_template('main.html')
|
||||||
|
|
||||||
|
context = build_modem_env(modem)
|
||||||
|
|
||||||
|
with open(f"main-{modem}.html", "w") as f:
|
||||||
|
f.write(template.render(context))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
if len(sys.argv) != 2:
|
||||||
|
print(f"Usage: {sys.argv[0]} <scpc|tdma>")
|
||||||
|
|
||||||
|
render_modem(sys.argv[1])
|
||||||
|
|
139
front-generator/template/default-js.js
Normal file
139
front-generator/template/default-js.js
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
{% 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 %}
|
1361
front-generator/template/main.html
Normal file
1361
front-generator/template/main.html
Normal file
File diff suppressed because it is too large
Load Diff
181
front-generator/template/vue-data.js
Normal file
181
front-generator/template/vue-data.js
Normal file
@@ -0,0 +1,181 @@
|
|||||||
|
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,
|
@@ -98,9 +98,9 @@ namespace http::auth {
|
|||||||
~AuthRequiredResource() override;
|
~AuthRequiredResource() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint32_t perms;
|
|
||||||
resource::respGenerator generator_;
|
|
||||||
AuthProvider& provider_;
|
AuthProvider& provider_;
|
||||||
|
resource::respGenerator generator_;
|
||||||
|
uint32_t perms;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -9,9 +9,12 @@
|
|||||||
|
|
||||||
|
|
||||||
std::string http::utils::sha256(const std::string &payload) {
|
std::string http::utils::sha256(const std::string &payload) {
|
||||||
// Вычисляем SHA256 хеш
|
return sha256(payload.c_str(), payload.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string http::utils::sha256(const char* data, size_t size) {
|
||||||
unsigned char hash[SHA256_DIGEST_LENGTH];
|
unsigned char hash[SHA256_DIGEST_LENGTH];
|
||||||
SHA256(reinterpret_cast<const unsigned char *>(payload.c_str()), payload.length(), hash);
|
SHA256(reinterpret_cast<const unsigned char *>(data), size, hash);
|
||||||
|
|
||||||
// Преобразуем хеш в шестнадцатеричную строку
|
// Преобразуем хеш в шестнадцатеричную строку
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
|
@@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
namespace http::utils {
|
namespace http::utils {
|
||||||
std::string sha256(const std::string& payload);
|
std::string sha256(const std::string& payload);
|
||||||
|
std::string sha256(const char* data, size_t size);
|
||||||
std::string sha256AsB64(const std::string& payload);
|
std::string sha256AsB64(const std::string& payload);
|
||||||
|
|
||||||
std::string b64Encode(const char* data, size_t size);
|
std::string b64Encode(const char* data, size_t size);
|
||||||
|
230
src/main.cpp
230
src/main.cpp
@@ -19,10 +19,14 @@
|
|||||||
#include "terminal_api_driver.h"
|
#include "terminal_api_driver.h"
|
||||||
#include "auth/resources.h"
|
#include "auth/resources.h"
|
||||||
#include "auth/jwt.h"
|
#include "auth/jwt.h"
|
||||||
|
#include "auth/utils.h"
|
||||||
|
|
||||||
|
|
||||||
namespace ssl = boost::asio::ssl; // from <boost/asio/ssl.hpp>
|
namespace ssl = boost::asio::ssl; // from <boost/asio/ssl.hpp>
|
||||||
|
|
||||||
|
constexpr const char* REBOOT_COMMAND = "web-action reboot";
|
||||||
|
constexpr const char* UPGRADE_COMMAND = "web-action upgrade";
|
||||||
|
|
||||||
|
|
||||||
static std::vector<char> loadFile(const std::string& path) {
|
static std::vector<char> loadFile(const std::string& path) {
|
||||||
std::ifstream is(path, std::ios::in | std::ios::binary);
|
std::ifstream is(path, std::ios::in | std::ios::binary);
|
||||||
@@ -80,36 +84,59 @@ class ServerResources {
|
|||||||
std::unique_ptr<api_driver::ApiDriver> api;
|
std::unique_ptr<api_driver::ApiDriver> api;
|
||||||
http::auth::AuthProvider auth{};
|
http::auth::AuthProvider auth{};
|
||||||
|
|
||||||
|
bool upgradeOrRebootRunning = false;
|
||||||
|
|
||||||
|
static void onUploadFirmware(const http::server::Request& req) {
|
||||||
|
std::ofstream f("/tmp/firmware.zip", std::ios::binary);
|
||||||
|
|
||||||
|
if (f.is_open()) {
|
||||||
|
f.write(req.payload.data(), static_cast<long>(req.payload.size()));
|
||||||
|
f.close();
|
||||||
|
} else {
|
||||||
|
throw std::runtime_error("File is not open");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void doTerminalUpgrade() const {
|
||||||
|
api->executeInApi([](TSID sid) {
|
||||||
|
CP_SetDmaDebug(sid, "begin_save_config", "");
|
||||||
|
system(UPGRADE_COMMAND);
|
||||||
|
CP_SetDmaDebug(sid, "save_config", "");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static constexpr const char* INDEX_HTML = "static/main.html";
|
#if defined(MODEM_IS_TDMA)
|
||||||
static constexpr const char* LOGIN_HTML = "static/login.html";
|
static constexpr const char* INDEX_HTML = "/main-tdma.html";
|
||||||
|
#elif defined(MODEM_IS_SCPC)
|
||||||
|
static constexpr const char* INDEX_HTML = "/main-scpc.html";
|
||||||
|
#else
|
||||||
|
#error "Modem type not defined!"
|
||||||
|
#endif
|
||||||
|
static constexpr const char* LOGIN_HTML = "/login.html";
|
||||||
|
|
||||||
// картинки, их даже можно кешировать
|
// картинки, их даже можно кешировать
|
||||||
static constexpr const char* FAVICON_ICO = "static/favicon.png";
|
static constexpr const char* FAVICON_ICO = "/favicon.ico";
|
||||||
static constexpr const char* KROKODIL_GIF = "static/krokodil.gif";
|
static constexpr const char* VUE_JS = "/js/vue.js"; // это тоже можно кешировать
|
||||||
static constexpr const char* VUE_JS = "static/js/vue.js"; // это тоже можно кешировать
|
|
||||||
|
|
||||||
// а эти стили нельзя кешировать в отладочной версии
|
// а эти стили нельзя кешировать в отладочной версии
|
||||||
static constexpr const char* STYLE_CSS = "static/style.css";
|
static constexpr const char* STYLE_CSS = "/style.css";
|
||||||
static constexpr const char* FIELDS_CSS = "static/fields.css";
|
static constexpr const char* FIELDS_CSS = "/fields.css";
|
||||||
static constexpr const char* KB_MP4 = "static/video_2024-11-06_15-49-35.mp4";
|
static constexpr const char* INTERNET_JPG = "/internet.jpg";
|
||||||
|
|
||||||
ServerResources(const ServerResources&) = delete;
|
ServerResources(const ServerResources&) = delete;
|
||||||
|
|
||||||
ServerResources(): sf(std::make_unique<http::resource::StaticFileFactory>()), api(std::make_unique<api_driver::ApiDriver>()) {
|
explicit ServerResources(const std::string& staticFilesPath): sf(std::make_unique<http::resource::StaticFileFactory>()), api(std::make_unique<api_driver::ApiDriver>()) {
|
||||||
api->startDaemon();
|
api->startDaemon();
|
||||||
auth.users.emplace_back(std::make_shared<http::auth::User>("admin", "", http::auth::User::SUPERUSER));
|
auth.users.emplace_back(std::make_shared<http::auth::User>("admin", "", http::auth::User::SUPERUSER));
|
||||||
|
|
||||||
sf->registerFile(FAVICON_ICO, mime_types::image_png, true);
|
sf->registerFile(staticFilesPath + "/favicon.png", FAVICON_ICO, mime_types::image_png, true);
|
||||||
sf->registerFile(KROKODIL_GIF, mime_types::image_gif, true);
|
sf->registerFile(staticFilesPath + VUE_JS, VUE_JS, mime_types::javascript, true);
|
||||||
sf->registerFile(VUE_JS, mime_types::javascript, true);
|
sf->registerFile(staticFilesPath + STYLE_CSS, STYLE_CSS, mime_types::text_css, true);
|
||||||
sf->registerFile(KB_MP4, mime_types::video_mp4, 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);
|
||||||
sf->registerFile(STYLE_CSS, mime_types::text_css, true);
|
sf->registerFile(staticFilesPath + LOGIN_HTML, LOGIN_HTML, mime_types::text_html, true);
|
||||||
sf->registerFile(FIELDS_CSS, mime_types::text_css, true);
|
sf->registerFile(staticFilesPath + INTERNET_JPG, INTERNET_JPG, mime_types::image_jpeg, true);
|
||||||
|
|
||||||
sf->registerFile(INDEX_HTML, mime_types::text_html, false);
|
|
||||||
sf->registerFile(LOGIN_HTML, mime_types::text_html, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void registerResources(http::server::Server& s) {
|
void registerResources(http::server::Server& s) {
|
||||||
@@ -154,7 +181,7 @@ public:
|
|||||||
http::server::stockReply(http::server::bad_request, rep);
|
http::server::stockReply(http::server::bad_request, rep);
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
s.resources.emplace_back(std::make_unique<http::resource::GenericResource>("/logout", [this](const auto& req, auto& rep) {
|
s.resources.emplace_back(std::make_unique<http::resource::GenericResource>("/logout", [](const auto& req, auto& rep) {
|
||||||
if (req.method == "GET") {
|
if (req.method == "GET") {
|
||||||
http::server::httpRedirect(rep, "/login");
|
http::server::httpRedirect(rep, "/login");
|
||||||
rep.headers.push_back({.name = "Set-Cookie", .value = http::auth::jwt::EMPTY_AUTH_COOKIE});
|
rep.headers.push_back({.name = "Set-Cookie", .value = http::auth::jwt::EMPTY_AUTH_COOKIE});
|
||||||
@@ -163,12 +190,11 @@ public:
|
|||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
s.resources.emplace_back(std::make_unique<http::resource::GenericResource>("/favicon.ico", [this](const auto& req, auto& rep) { boost::ignore_unused(req); sf->serve(FAVICON_ICO, rep); }));
|
s.resources.emplace_back(std::make_unique<http::resource::GenericResource>(FAVICON_ICO, [this](const auto& req, auto& rep) { boost::ignore_unused(req); sf->serve(FAVICON_ICO, rep); }));
|
||||||
s.resources.emplace_back(std::make_unique<http::resource::GenericResource>("/images/krokodil_vzryvaetsya_hd.gif", [this](const auto& req, auto& rep) { boost::ignore_unused(req); sf->serve(KROKODIL_GIF, rep); }));
|
s.resources.emplace_back(std::make_unique<http::resource::GenericResource>(STYLE_CSS, [this](const auto& req, auto& rep) { boost::ignore_unused(req); sf->serve(STYLE_CSS, rep); }));
|
||||||
s.resources.emplace_back(std::make_unique<http::resource::GenericResource>("/style.css", [this](const auto& req, auto& rep) { boost::ignore_unused(req); sf->serve(STYLE_CSS, rep); }));
|
s.resources.emplace_back(std::make_unique<http::resource::GenericResource>(FIELDS_CSS, [this](const auto& req, auto& rep) { boost::ignore_unused(req); sf->serve(FIELDS_CSS, rep); }));
|
||||||
s.resources.emplace_back(std::make_unique<http::resource::GenericResource>("/fields.css", [this](const auto& req, auto& rep) { boost::ignore_unused(req); sf->serve(FIELDS_CSS, rep); }));
|
s.resources.emplace_back(std::make_unique<http::resource::GenericResource>(VUE_JS, [this](const auto& req, auto& rep) { boost::ignore_unused(req); sf->serve(VUE_JS, rep); }));
|
||||||
s.resources.emplace_back(std::make_unique<http::resource::GenericResource>("/js/vue.js", [this](const auto& req, auto& rep) { boost::ignore_unused(req); sf->serve(VUE_JS, rep); }));
|
s.resources.emplace_back(std::make_unique<http::resource::GenericResource>(INTERNET_JPG, [this](const auto& req, auto& rep) { boost::ignore_unused(req); sf->serve(INTERNET_JPG, rep); }));
|
||||||
s.resources.emplace_back(std::make_unique<http::resource::GenericResource>("/vid/video_2024-11-06_15-49-35.mp4", [this](const auto& req, auto& rep) { boost::ignore_unused(req); sf->serve(KB_MP4, rep); }));
|
|
||||||
|
|
||||||
s.resources.emplace_back(std::make_unique<http::auth::AuthRequiredResource>("/api/get/statistics", this->auth, http::auth::User::WATCH_STATISTICS, [this](const auto& req, auto& rep) {
|
s.resources.emplace_back(std::make_unique<http::auth::AuthRequiredResource>("/api/get/statistics", this->auth, http::auth::User::WATCH_STATISTICS, [this](const auto& req, auto& rep) {
|
||||||
if (req.method != "GET") {
|
if (req.method != "GET") {
|
||||||
@@ -180,6 +206,8 @@ public:
|
|||||||
rep.headers.push_back({.name = "Content-Type", .value = toString(mime_types::json)});
|
rep.headers.push_back({.name = "Content-Type", .value = toString(mime_types::json)});
|
||||||
std::string result = R"({"mainState":)";
|
std::string result = R"({"mainState":)";
|
||||||
result += api->loadTerminalState();
|
result += api->loadTerminalState();
|
||||||
|
result += R"(,"sysinfo":)";
|
||||||
|
result += api->loadSysInfo();
|
||||||
result += "}";
|
result += "}";
|
||||||
rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size());
|
rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size());
|
||||||
}));
|
}));
|
||||||
@@ -198,6 +226,18 @@ public:
|
|||||||
rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size());
|
rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size());
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
s.resources.emplace_back(std::make_unique<http::auth::AuthRequiredResource>("/api/get/aboutFirmware", this->auth, 0, [this](const auto& req, auto& rep) {
|
||||||
|
if (req.method != "GET") {
|
||||||
|
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)});
|
||||||
|
const auto result = api->loadFirmwareVersion();
|
||||||
|
rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size());
|
||||||
|
}));
|
||||||
|
|
||||||
s.resources.emplace_back(std::make_unique<http::auth::AuthRequiredResource>("/api/resetPacketStatistics", this->auth, http::auth::User::RESET_PACKET_STATISTICS, [this](const auto& req, auto& rep) {
|
s.resources.emplace_back(std::make_unique<http::auth::AuthRequiredResource>("/api/resetPacketStatistics", this->auth, http::auth::User::RESET_PACKET_STATISTICS, [this](const auto& req, auto& rep) {
|
||||||
if (req.method != "POST") {
|
if (req.method != "POST") {
|
||||||
http::server::stockReply(http::server::bad_request, rep);
|
http::server::stockReply(http::server::bad_request, rep);
|
||||||
@@ -266,7 +306,7 @@ public:
|
|||||||
rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size());
|
rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size());
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
#ifdef MODEM_IS_SCPC
|
||||||
s.resources.emplace_back(std::make_unique<http::auth::AuthRequiredResource>("/api/set/cinc", this->auth, http::auth::User::EDIT_SETTINGS, [this](const auto& req, auto& rep) {
|
s.resources.emplace_back(std::make_unique<http::auth::AuthRequiredResource>("/api/set/cinc", this->auth, http::auth::User::EDIT_SETTINGS, [this](const auto& req, auto& rep) {
|
||||||
if (req.method != "POST") {
|
if (req.method != "POST") {
|
||||||
http::server::stockReply(http::server::bad_request, rep);
|
http::server::stockReply(http::server::bad_request, rep);
|
||||||
@@ -294,7 +334,7 @@ public:
|
|||||||
rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size());
|
rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size());
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
#endif
|
||||||
s.resources.emplace_back(std::make_unique<http::auth::AuthRequiredResource>("/api/set/rxtx", this->auth, http::auth::User::EDIT_SETTINGS, [this](const auto& req, auto& rep) {
|
s.resources.emplace_back(std::make_unique<http::auth::AuthRequiredResource>("/api/set/rxtx", this->auth, http::auth::User::EDIT_SETTINGS, [this](const auto& req, auto& rep) {
|
||||||
if (req.method != "POST") {
|
if (req.method != "POST") {
|
||||||
http::server::stockReply(http::server::bad_request, rep);
|
http::server::stockReply(http::server::bad_request, rep);
|
||||||
@@ -322,6 +362,132 @@ public:
|
|||||||
rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size());
|
rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size());
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
s.resources.emplace_back(std::make_unique<http::auth::AuthRequiredResource>("/api/set/network", 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->setNetworkSettings(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();
|
||||||
|
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<http::auth::AuthRequiredResource>("/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();
|
||||||
|
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<http::auth::AuthRequiredResource>("/api/reboot", this->auth, 0, [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)});
|
||||||
|
const std::string result = R"({"status":"ok"})";
|
||||||
|
rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size());
|
||||||
|
this->upgradeOrRebootRunning = true;
|
||||||
|
system(REBOOT_COMMAND);
|
||||||
|
}));
|
||||||
|
s.resources.emplace_back(std::make_unique<http::auth::AuthRequiredResource>("/api/resetSettings", this->auth, http::auth::User::SUPERUSER, [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)});
|
||||||
|
const std::string result = R"({"status":"ok"})";
|
||||||
|
rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size());
|
||||||
|
api->resetDefaultSettings();
|
||||||
|
system(REBOOT_COMMAND);
|
||||||
|
}));
|
||||||
|
|
||||||
|
s.resources.emplace_back(std::make_unique<http::auth::AuthRequiredResource>("/api/firmwareUpdate", this->auth, http::auth::User::UPDATE_FIRMWARE, [this](const auto& req, auto& rep) {
|
||||||
|
if (req.method != "PUT") {
|
||||||
|
http::server::stockReply(http::server::bad_request, rep);
|
||||||
|
}
|
||||||
|
this->upgradeOrRebootRunning = true;
|
||||||
|
onUploadFirmware(req);
|
||||||
|
|
||||||
|
rep.status = http::server::ok;
|
||||||
|
rep.headers.clear();
|
||||||
|
rep.headers.push_back({.name = "Content-Type", .value = toString(mime_types::json)});
|
||||||
|
std::string result = R"({"status":"ok","fwsize":)";
|
||||||
|
result += std::to_string(req.payload.size());
|
||||||
|
result += R"(,"sha256":")";
|
||||||
|
result += http::utils::sha256(req.payload.data(), req.payload.size());
|
||||||
|
result += "\"}";
|
||||||
|
rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size());
|
||||||
|
this->upgradeOrRebootRunning = false;
|
||||||
|
}));
|
||||||
|
|
||||||
|
s.resources.emplace_back(std::make_unique<http::auth::AuthRequiredResource>("/api/doFirmwareUpgrade", this->auth, http::auth::User::UPDATE_FIRMWARE, [this](const auto& req, auto& rep) {
|
||||||
|
if (req.method != "POST") {
|
||||||
|
http::server::stockReply(http::server::bad_request, rep);
|
||||||
|
}
|
||||||
|
this->upgradeOrRebootRunning = true;
|
||||||
|
doTerminalUpgrade();
|
||||||
|
rep.status = http::server::ok;
|
||||||
|
rep.headers.clear();
|
||||||
|
rep.headers.push_back({.name = "Content-Type", .value = toString(mime_types::json)});
|
||||||
|
const auto result = api->loadFirmwareVersion();
|
||||||
|
rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size());
|
||||||
|
}));
|
||||||
|
|
||||||
|
s.resources.emplace_back(std::make_unique<http::auth::AuthRequiredResource>("/dev", this->auth, http::auth::User::SUPERUSER, [this](const auto& req, auto& rep) {
|
||||||
|
boost::ignore_unused(req);
|
||||||
|
sf->serve(INTERNET_JPG, rep);
|
||||||
|
}));
|
||||||
|
|
||||||
|
s.resources.emplace_back(std::make_unique<http::auth::AuthRequiredResource>("/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;
|
~ServerResources() = default;
|
||||||
@@ -335,9 +501,9 @@ int main(int argc, char *argv[]) {
|
|||||||
if (argc != 4 && argc != 5) {
|
if (argc != 4 && argc != 5) {
|
||||||
std::cerr << "Usage: http_server <ssl|nossl> <address> <port> [static files directory]\n";
|
std::cerr << "Usage: http_server <ssl|nossl> <address> <port> [static files directory]\n";
|
||||||
std::cerr << " For IPv4, try:\n";
|
std::cerr << " For IPv4, try:\n";
|
||||||
std::cerr << " receiver nossl 0.0.0.0 80\n";
|
std::cerr << " receiver nossl 0.0.0.0 80 .\n";
|
||||||
std::cerr << " For IPv6, try:\n";
|
std::cerr << " For IPv6, try:\n";
|
||||||
std::cerr << " receiver nossl 0::0 80\n";
|
std::cerr << " receiver nossl 0::0 80 .\n";
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -358,7 +524,9 @@ int main(int argc, char *argv[]) {
|
|||||||
BOOST_LOG_TRIVIAL(info) << "Generated new secret key " << http::auth::jwt::secretKey;
|
BOOST_LOG_TRIVIAL(info) << "Generated new secret key " << http::auth::jwt::secretKey;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ServerResources resources;
|
const std::string staticFilesPath = (argc == 5 ? argv[4]: ".");
|
||||||
|
BOOST_LOG_TRIVIAL(info) << "Use static files path: " << staticFilesPath << "/";
|
||||||
|
ServerResources resources(staticFilesPath);
|
||||||
|
|
||||||
// Initialise the server.
|
// Initialise the server.
|
||||||
std::unique_ptr<http::server::Server> s;
|
std::unique_ptr<http::server::Server> s;
|
||||||
|
@@ -13,6 +13,8 @@ namespace http::server {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Connection::start() {
|
void Connection::start() {
|
||||||
|
request_parser_.reset();
|
||||||
|
request_.reset();
|
||||||
doRead();
|
doRead();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -23,9 +25,6 @@ namespace http::server {
|
|||||||
Connection::~Connection() = default;
|
Connection::~Connection() = default;
|
||||||
|
|
||||||
void Connection::doRead() {
|
void Connection::doRead() {
|
||||||
request_parser_.reset();
|
|
||||||
request_.reset();
|
|
||||||
|
|
||||||
auto self(shared_from_this());
|
auto self(shared_from_this());
|
||||||
socket_.async_read_some(boost::asio::buffer(buffer_), [this, self](boost::system::error_code ec, std::size_t bytes_transferred) {
|
socket_.async_read_some(boost::asio::buffer(buffer_), [this, self](boost::system::error_code ec, std::size_t bytes_transferred) {
|
||||||
if (!ec) {
|
if (!ec) {
|
||||||
@@ -38,6 +37,7 @@ namespace http::server {
|
|||||||
doWrite();
|
doWrite();
|
||||||
} else if (result == RequestParser::bad) {
|
} else if (result == RequestParser::bad) {
|
||||||
stockReply(bad_request, reply_);
|
stockReply(bad_request, reply_);
|
||||||
|
needClose = true;
|
||||||
doWrite();
|
doWrite();
|
||||||
} else {
|
} else {
|
||||||
doRead();
|
doRead();
|
||||||
@@ -59,8 +59,10 @@ namespace http::server {
|
|||||||
|
|
||||||
auto self(shared_from_this());
|
auto self(shared_from_this());
|
||||||
async_write(socket_, reply_.to_buffers(), [this, self](boost::system::error_code ec, std::size_t) {
|
async_write(socket_, reply_.to_buffers(), [this, self](boost::system::error_code ec, std::size_t) {
|
||||||
if (!ec) {
|
if (!ec && !needClose) {
|
||||||
// keep alive Connection
|
// keep alive Connection
|
||||||
|
request_parser_.reset();
|
||||||
|
request_.reset();
|
||||||
doRead();
|
doRead();
|
||||||
} else {
|
} else {
|
||||||
connection_manager_.stop(shared_from_this());
|
connection_manager_.stop(shared_from_this());
|
||||||
@@ -74,6 +76,8 @@ namespace http::server {
|
|||||||
|
|
||||||
void SslConnection::start() {
|
void SslConnection::start() {
|
||||||
get_lowest_layer(stream_).expires_after(std::chrono::seconds(30));
|
get_lowest_layer(stream_).expires_after(std::chrono::seconds(30));
|
||||||
|
request_parser_.reset();
|
||||||
|
request_.reset();
|
||||||
|
|
||||||
// Perform the SSL handshake
|
// Perform the SSL handshake
|
||||||
stream_.async_handshake(boost::asio::ssl::stream_base::server, boost::beast::bind_front_handler([this](auto ec) {
|
stream_.async_handshake(boost::asio::ssl::stream_base::server, boost::beast::bind_front_handler([this](auto ec) {
|
||||||
@@ -83,6 +87,11 @@ namespace http::server {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void SslConnection::stop() {
|
void SslConnection::stop() {
|
||||||
|
try {
|
||||||
|
stream_.shutdown();
|
||||||
|
} catch (std::exception& e) {
|
||||||
|
BOOST_LOG_TRIVIAL(warning) << "SslConnection::stop(): Can't shutdown ssl socket: " << e.what();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SslConnection::~SslConnection() = default;
|
SslConnection::~SslConnection() = default;
|
||||||
@@ -90,9 +99,6 @@ namespace http::server {
|
|||||||
void SslConnection::doRead() {
|
void SslConnection::doRead() {
|
||||||
get_lowest_layer(stream_).expires_after(std::chrono::seconds(30));
|
get_lowest_layer(stream_).expires_after(std::chrono::seconds(30));
|
||||||
|
|
||||||
request_parser_.reset();
|
|
||||||
request_.reset();
|
|
||||||
|
|
||||||
auto self(shared_from_this());
|
auto self(shared_from_this());
|
||||||
stream_.async_read_some(boost::asio::buffer(buffer_), [this, self](boost::system::error_code ec, std::size_t bytes_transferred) {
|
stream_.async_read_some(boost::asio::buffer(buffer_), [this, self](boost::system::error_code ec, std::size_t bytes_transferred) {
|
||||||
if (!ec) {
|
if (!ec) {
|
||||||
@@ -105,6 +111,7 @@ namespace http::server {
|
|||||||
doWrite();
|
doWrite();
|
||||||
} else if (result == RequestParser::bad) {
|
} else if (result == RequestParser::bad) {
|
||||||
stockReply(bad_request, reply_);
|
stockReply(bad_request, reply_);
|
||||||
|
needClose = true;
|
||||||
doWrite();
|
doWrite();
|
||||||
} else {
|
} else {
|
||||||
doRead();
|
doRead();
|
||||||
@@ -126,8 +133,10 @@ namespace http::server {
|
|||||||
|
|
||||||
auto self(shared_from_this());
|
auto self(shared_from_this());
|
||||||
async_write(stream_, reply_.to_buffers(), [this, self](boost::system::error_code ec, std::size_t) {
|
async_write(stream_, reply_.to_buffers(), [this, self](boost::system::error_code ec, std::size_t) {
|
||||||
if (!ec) {
|
if (!ec && !needClose) {
|
||||||
// keep alive Connection
|
// keep alive Connection
|
||||||
|
request_parser_.reset();
|
||||||
|
request_.reset();
|
||||||
doRead();
|
doRead();
|
||||||
} else {
|
} else {
|
||||||
connection_manager_.stop(shared_from_this());
|
connection_manager_.stop(shared_from_this());
|
||||||
|
@@ -72,6 +72,8 @@ namespace http::server {
|
|||||||
|
|
||||||
/// The reply to be sent back to the client.
|
/// The reply to be sent back to the client.
|
||||||
Reply reply_;
|
Reply reply_;
|
||||||
|
|
||||||
|
bool needClose = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
class SslConnection final : public ConnectionBase, public std::enable_shared_from_this<SslConnection> {
|
class SslConnection final : public ConnectionBase, public std::enable_shared_from_this<SslConnection> {
|
||||||
@@ -114,6 +116,8 @@ namespace http::server {
|
|||||||
|
|
||||||
/// The reply to be sent back to the client.
|
/// The reply to be sent back to the client.
|
||||||
Reply reply_;
|
Reply reply_;
|
||||||
|
|
||||||
|
bool needClose = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::shared_ptr<ConnectionBase> connection_ptr;
|
typedef std::shared_ptr<ConnectionBase> connection_ptr;
|
||||||
|
@@ -1,11 +1,30 @@
|
|||||||
#include "request_parser.hpp"
|
#include "request_parser.hpp"
|
||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
#include "request.hpp"
|
#include "request.hpp"
|
||||||
|
|
||||||
|
|
||||||
namespace http::server {
|
namespace http::server {
|
||||||
|
constexpr int HTTP_MAX_HEADERS = 64;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Функция, позволяющая или запрещающая выделение размера тела для запросов.
|
||||||
|
* @return true, если тело удовлетворяет размерам
|
||||||
|
*/
|
||||||
|
static bool requestBodySizeResolver(Request& req, size_t reqSize) {
|
||||||
|
// разрешаем тело только для POST запросов
|
||||||
|
if (req.method == "POST") {
|
||||||
|
return reqSize < 0x4000; // 16кб на все POST-запросы к API будет более чем достаточно
|
||||||
|
}
|
||||||
|
|
||||||
|
// это для обновления прошивки
|
||||||
|
if (req.method == "PUT" && req.url->path == "/api/firmwareUpdate") {
|
||||||
|
return reqSize <= HTTP_MAX_PAYLOAD;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
static void parseParams(Url& u, const std::string& query) {
|
static void parseParams(Url& u, const std::string& query) {
|
||||||
std::istringstream iss(query);
|
std::istringstream iss(query);
|
||||||
std::string param;
|
std::string param;
|
||||||
@@ -72,7 +91,7 @@ namespace http::server {
|
|||||||
switch (state_) {
|
switch (state_) {
|
||||||
case expecting_payload:
|
case expecting_payload:
|
||||||
req.payload.push_back(input);
|
req.payload.push_back(input);
|
||||||
if (req.payload.size() <= contentLenghtHeader - 1) {
|
if (req.payload.size() < contentLenghtHeader) {
|
||||||
return indeterminate;
|
return indeterminate;
|
||||||
}
|
}
|
||||||
return good;
|
return good;
|
||||||
@@ -186,17 +205,23 @@ namespace http::server {
|
|||||||
if (input == '\r') {
|
if (input == '\r') {
|
||||||
state_ = expecting_newline_3;
|
state_ = expecting_newline_3;
|
||||||
return indeterminate;
|
return indeterminate;
|
||||||
} else if (!req.headers.empty() && (input == ' ' || input == '\t')) {
|
}
|
||||||
|
if (!req.headers.empty() && (input == ' ' || input == '\t')) {
|
||||||
state_ = header_lws;
|
state_ = header_lws;
|
||||||
return indeterminate;
|
return indeterminate;
|
||||||
} else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) {
|
|
||||||
return bad;
|
|
||||||
} else {
|
|
||||||
req.headers.emplace_back();
|
|
||||||
req.headers.back().name.push_back(input);
|
|
||||||
state_ = header_name;
|
|
||||||
return indeterminate;
|
|
||||||
}
|
}
|
||||||
|
if (!is_char(input) || is_ctl(input) || is_tspecial(input)) {
|
||||||
|
return bad;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (req.headers.size() > HTTP_MAX_HEADERS) {
|
||||||
|
return bad;
|
||||||
|
}
|
||||||
|
req.headers.emplace_back();
|
||||||
|
req.headers.back().name.push_back(input);
|
||||||
|
state_ = header_name;
|
||||||
|
return indeterminate;
|
||||||
|
|
||||||
case header_lws:
|
case header_lws:
|
||||||
if (input == '\r') {
|
if (input == '\r') {
|
||||||
state_ = expecting_newline_2;
|
state_ = expecting_newline_2;
|
||||||
@@ -251,15 +276,14 @@ namespace http::server {
|
|||||||
if (content_len.empty()) {
|
if (content_len.empty()) {
|
||||||
return good;
|
return good;
|
||||||
}
|
}
|
||||||
contentLenghtHeader = std::stol(content_len);
|
contentLenghtHeader = std::stoul(content_len);
|
||||||
if (contentLenghtHeader == 0) {
|
if (contentLenghtHeader == 0) {
|
||||||
return good;
|
return good;
|
||||||
}
|
}
|
||||||
state_ = expecting_payload;
|
if (requestBodySizeResolver(req, contentLenghtHeader)) {
|
||||||
if (contentLenghtHeader > HTTP_MAX_PAYLOAD) {
|
state_ = expecting_payload;
|
||||||
return bad;
|
return indeterminate;
|
||||||
}
|
}
|
||||||
return indeterminate;
|
|
||||||
}
|
}
|
||||||
return bad;
|
return bad;
|
||||||
|
|
||||||
|
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
|
|
||||||
namespace http::server {
|
namespace http::server {
|
||||||
struct Request;
|
class Request;
|
||||||
|
|
||||||
/// Parser for incoming requests.
|
/// Parser for incoming requests.
|
||||||
class RequestParser {
|
class RequestParser {
|
||||||
|
@@ -3,8 +3,6 @@
|
|||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#include "../../dependencies/control_system/common/protocol_commands.h"
|
|
||||||
|
|
||||||
static void loadFile(const std::string& path, std::vector<char>& content) {
|
static void loadFile(const std::string& path, std::vector<char>& content) {
|
||||||
std::ifstream is(path, std::ios::in | std::ios::binary);
|
std::ifstream is(path, std::ios::in | std::ios::binary);
|
||||||
if (!is) {
|
if (!is) {
|
||||||
@@ -24,32 +22,42 @@ static void loadFile(const std::string& path, std::vector<char>& content) {
|
|||||||
|
|
||||||
http::resource::BasicResource::BasicResource(std::string path): path(std::move(path)) {}
|
http::resource::BasicResource::BasicResource(std::string path): path(std::move(path)) {}
|
||||||
|
|
||||||
http::resource::StaticFileFactory::StaticFileDef::StaticFileDef(std::string path, server::mime_types::Mime type, bool allowCache): path(std::move(path)), type(type), allowCache(allowCache) {
|
http::resource::StaticFileFactory::StaticFileDef::StaticFileDef(const std::string& path, std::string webPath, server::mime_types::Mime type, bool allowCache):
|
||||||
|
webPath(std::move(webPath)),
|
||||||
|
#ifdef USE_DEBUG
|
||||||
|
fsPath(path),
|
||||||
|
#endif
|
||||||
|
type(type), allowCache(allowCache) {
|
||||||
|
#ifdef USE_DEBUG
|
||||||
if (allowCache) {
|
if (allowCache) {
|
||||||
BOOST_LOG_TRIVIAL(info) << "Load static file " << this->path;
|
BOOST_LOG_TRIVIAL(info) << "Load static file " << this->webPath;
|
||||||
loadFile(this->path, this->content);
|
loadFile(path, this->content);
|
||||||
} else {
|
} else {
|
||||||
BOOST_LOG_TRIVIAL(info) << "Skip loading static file " << this->path;
|
BOOST_LOG_TRIVIAL(info) << "Skip loading static file " << this->webPath;
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
BOOST_LOG_TRIVIAL(info) << "Load static file " << path;
|
||||||
|
loadFile(path, this->content);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
http::resource::StaticFileFactory::StaticFileDef::~StaticFileDef() = default;
|
http::resource::StaticFileFactory::StaticFileDef::~StaticFileDef() = default;
|
||||||
|
|
||||||
http::resource::StaticFileFactory::StaticFileFactory() = default;
|
http::resource::StaticFileFactory::StaticFileFactory() = default;
|
||||||
|
|
||||||
void http::resource::StaticFileFactory::registerFile(const std::string &path, server::mime_types::Mime type, bool allowCache) {
|
void http::resource::StaticFileFactory::registerFile(const std::string &path, const std::string &webPath, server::mime_types::Mime type, bool allowCache) {
|
||||||
this->files.emplace_back(path, type, allowCache);
|
this->files.emplace_back(path, webPath, type, allowCache);
|
||||||
}
|
}
|
||||||
|
|
||||||
void http::resource::StaticFileFactory::serve(const std::string &path, server::Reply &rep) {
|
void http::resource::StaticFileFactory::serve(const std::string &path, server::Reply &rep) {
|
||||||
for (auto& f: this->files) {
|
for (auto& f: this->files) {
|
||||||
if (f.path == path) {
|
if (f.webPath == path) {
|
||||||
#ifdef USE_DEBUG
|
#ifdef USE_DEBUG
|
||||||
if (f.allowCache) {
|
if (f.allowCache) {
|
||||||
rep.content.clear();
|
rep.content.clear();
|
||||||
rep.content.insert(rep.content.end(), f.content.begin(), f.content.end());
|
rep.content.insert(rep.content.end(), f.content.begin(), f.content.end());
|
||||||
} else {
|
} else {
|
||||||
BOOST_LOG_TRIVIAL(debug) << "Reload file " << path << " (http path: " << path << ")";
|
BOOST_LOG_TRIVIAL(debug) << "Reload file " << path << " (http path: " << path << ")";
|
||||||
loadFile(f.path, rep.content);
|
loadFile(f.fsPath, rep.content);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
rep.content.clear();
|
rep.content.clear();
|
||||||
|
@@ -23,9 +23,12 @@ namespace http::resource {
|
|||||||
class StaticFileFactory {
|
class StaticFileFactory {
|
||||||
class StaticFileDef {
|
class StaticFileDef {
|
||||||
public:
|
public:
|
||||||
StaticFileDef(std::string path, server::mime_types::Mime type, bool allowCache = true);
|
StaticFileDef(const std::string& path, std::string webPath, server::mime_types::Mime type, bool allowCache = true);
|
||||||
|
|
||||||
std::string path;
|
std::string webPath;
|
||||||
|
#ifdef USE_DEBUG
|
||||||
|
std::string fsPath;
|
||||||
|
#endif
|
||||||
server::mime_types::Mime type;
|
server::mime_types::Mime type;
|
||||||
bool allowCache;
|
bool allowCache;
|
||||||
std::vector<char> content;
|
std::vector<char> content;
|
||||||
@@ -36,7 +39,7 @@ namespace http::resource {
|
|||||||
public:
|
public:
|
||||||
StaticFileFactory();
|
StaticFileFactory();
|
||||||
|
|
||||||
void registerFile(const std::string& path, server::mime_types::Mime type, bool allowCache = true);
|
void registerFile(const std::string& path, const std::string &webPath, server::mime_types::Mime type, bool allowCache = true);
|
||||||
|
|
||||||
void serve(const std::string& path, server::Reply& rep);
|
void serve(const std::string& path, server::Reply& rep);
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -39,16 +39,19 @@ namespace api_driver {
|
|||||||
|
|
||||||
std::string loadSettings() const;
|
std::string loadSettings() const;
|
||||||
|
|
||||||
|
std::string loadFirmwareVersion() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Установить настройки RX/TX, readback можно получить используя loadTerminalState
|
* Установить настройки RX/TX, readback можно получить используя loadTerminalState
|
||||||
*/
|
*/
|
||||||
void setRxTxSettings(boost::property_tree::ptree &pt);
|
void setRxTxSettings(boost::property_tree::ptree &pt);
|
||||||
|
|
||||||
|
#ifdef MODEM_IS_SCPC
|
||||||
/**
|
/**
|
||||||
* Установить настройки CinC, readback можно получить используя loadTerminalState.
|
* Установить настройки CinC, readback можно получить используя loadTerminalState.
|
||||||
*/
|
*/
|
||||||
void setCincSettings(boost::property_tree::ptree &pt);
|
void setCincSettings(boost::property_tree::ptree &pt);
|
||||||
|
#endif
|
||||||
/**
|
/**
|
||||||
* Установить настройки BUC и LNB, readback можно получить используя loadTerminalState.
|
* Установить настройки BUC и LNB, readback можно получить используя loadTerminalState.
|
||||||
*/
|
*/
|
||||||
@@ -59,16 +62,20 @@ namespace api_driver {
|
|||||||
*/
|
*/
|
||||||
void setQosSettings(boost::property_tree::ptree &pt);
|
void setQosSettings(boost::property_tree::ptree &pt);
|
||||||
|
|
||||||
|
void setNetworkSettings(boost::property_tree::ptree & pt);
|
||||||
|
|
||||||
|
void setDebugSendSettings(boost::property_tree::ptree & pt);
|
||||||
|
|
||||||
|
void resetDefaultSettings();
|
||||||
|
|
||||||
|
void executeInApi(const std::function<void(TSID sid)>& callback);
|
||||||
|
|
||||||
|
static std::string loadSysInfo();
|
||||||
|
|
||||||
~ApiDriver();
|
~ApiDriver();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TSID sid{0};
|
|
||||||
unsigned int access{0};
|
|
||||||
|
|
||||||
std::string deviceInitState;
|
|
||||||
std::unique_ptr<TerminalApiDaemon> daemon;
|
std::unique_ptr<TerminalApiDaemon> daemon;
|
||||||
|
|
||||||
bool getIsCinC() const;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
16
static/dev-params.json
Normal file
16
static/dev-params.json
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"params": [
|
||||||
|
{
|
||||||
|
"label": "Запись пакетов",
|
||||||
|
"name": "log_bool",
|
||||||
|
"widget": "checkbox",
|
||||||
|
"function": "DmaDebug"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Unused test",
|
||||||
|
"name": "log_bool",
|
||||||
|
"widget": "checkbox",
|
||||||
|
"function": "DmaDebug"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
10
static/dev.html
Normal file
10
static/dev.html
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Title</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
@@ -1,5 +1,5 @@
|
|||||||
.tabs-header {
|
.tabs-header {
|
||||||
margin: 0.5em 0;
|
margin: 0.5em 0 3px;
|
||||||
background: var(--brand-bg);
|
background: var(--brand-bg);
|
||||||
}
|
}
|
||||||
.tabs-header > * {
|
.tabs-header > * {
|
||||||
@@ -7,7 +7,6 @@
|
|||||||
}
|
}
|
||||||
.tabs-btn {
|
.tabs-btn {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
font-size: 18px;
|
|
||||||
border: none;
|
border: none;
|
||||||
padding: 10px 25px;
|
padding: 10px 25px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
@@ -17,7 +16,7 @@
|
|||||||
}
|
}
|
||||||
.tabs-btn.active {
|
.tabs-btn.active {
|
||||||
color: var(--brand-text);
|
color: var(--brand-text);
|
||||||
border-bottom: 3px solid var(--brand-text);
|
border-bottom: 3px solid var(--bg-action);
|
||||||
}
|
}
|
||||||
.tabs-body-item {
|
.tabs-body-item {
|
||||||
padding: 20px 0;
|
padding: 20px 0;
|
||||||
@@ -58,7 +57,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.action-button {
|
.action-button {
|
||||||
background: var(--brand-bg);
|
background: var(--bg-action);
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-bar-element {
|
.nav-bar-element {
|
||||||
@@ -85,11 +84,12 @@
|
|||||||
padding: 1em;
|
padding: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tabs-item-flex-container th {
|
.settings-set-container th {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
|
font-weight: normal;
|
||||||
padding-right: 1em;
|
padding-right: 1em;
|
||||||
}
|
}
|
||||||
.tabs-item-flex-container td {
|
.settings-set-container td {
|
||||||
min-width: 10em;
|
min-width: 10em;
|
||||||
}
|
}
|
||||||
.tabs-item-flex-container h2 {
|
.tabs-item-flex-container h2 {
|
||||||
@@ -113,7 +113,7 @@ label {
|
|||||||
.settings-set-container input, .settings-set-container select {
|
.settings-set-container input, .settings-set-container select {
|
||||||
margin-top: 0.5em;
|
margin-top: 0.5em;
|
||||||
border: none;
|
border: none;
|
||||||
border-bottom: solid 2px var(--text-color);
|
border-bottom: solid 2px var(--text-color2);
|
||||||
width: 20em;
|
width: 20em;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
@@ -121,7 +121,11 @@ label {
|
|||||||
.settings-set-container input:focus {
|
.settings-set-container input:focus {
|
||||||
outline: none;
|
outline: none;
|
||||||
border: none;
|
border: none;
|
||||||
border-bottom: solid 2px var(--brand-text);
|
border-bottom: solid 2px var(--bg-action);
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-set-container input:invalid {
|
||||||
|
border: solid 1px var(--text-bad);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* костыль для браузеров, которые некорректно стилизуют элементы option */
|
/* костыль для браузеров, которые некорректно стилизуют элементы option */
|
||||||
@@ -189,7 +193,7 @@ details > summary {
|
|||||||
|
|
||||||
.toggle-input input[type="checkbox"]:checked + .slider {
|
.toggle-input input[type="checkbox"]:checked + .slider {
|
||||||
left: 25px;
|
left: 25px;
|
||||||
background-color: var(--brand-text);
|
background-color: var(--bg-action);
|
||||||
}
|
}
|
||||||
|
|
||||||
.toggle-input input[type="checkbox"]:checked + .slider:before {
|
.toggle-input input[type="checkbox"]:checked + .slider:before {
|
||||||
|
BIN
static/internet.jpg
Normal file
BIN
static/internet.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 72 KiB |
299
static/js/vue.js
299
static/js/vue.js
@@ -1,6 +1,6 @@
|
|||||||
/*!
|
/*!
|
||||||
* Vue.js v2.7.16
|
* Vue.js v2.7.14
|
||||||
* (c) 2014-2023 Evan You
|
* (c) 2014-2022 Evan You
|
||||||
* Released under the MIT License.
|
* Released under the MIT License.
|
||||||
*/
|
*/
|
||||||
(function (global, factory) {
|
(function (global, factory) {
|
||||||
@@ -82,16 +82,9 @@
|
|||||||
return val == null
|
return val == null
|
||||||
? ''
|
? ''
|
||||||
: Array.isArray(val) || (isPlainObject(val) && val.toString === _toString)
|
: Array.isArray(val) || (isPlainObject(val) && val.toString === _toString)
|
||||||
? JSON.stringify(val, replacer, 2)
|
? JSON.stringify(val, null, 2)
|
||||||
: String(val);
|
: String(val);
|
||||||
}
|
}
|
||||||
function replacer(_key, val) {
|
|
||||||
// avoid circular deps from v3
|
|
||||||
if (val && val.__v_isRef) {
|
|
||||||
return val.value;
|
|
||||||
}
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
/**
|
/**
|
||||||
* Convert an input value to a number for persistence.
|
* Convert an input value to a number for persistence.
|
||||||
* If the conversion fails, return original string.
|
* If the conversion fails, return original string.
|
||||||
@@ -253,7 +246,9 @@
|
|||||||
*/
|
*/
|
||||||
function genStaticKeys$1(modules) {
|
function genStaticKeys$1(modules) {
|
||||||
return modules
|
return modules
|
||||||
.reduce(function (keys, m) { return keys.concat(m.staticKeys || []); }, [])
|
.reduce(function (keys, m) {
|
||||||
|
return keys.concat(m.staticKeys || []);
|
||||||
|
}, [])
|
||||||
.join(',');
|
.join(',');
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
@@ -756,11 +751,6 @@
|
|||||||
return __assign.apply(this, arguments);
|
return __assign.apply(this, arguments);
|
||||||
};
|
};
|
||||||
|
|
||||||
typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
|
||||||
var e = new Error(message);
|
|
||||||
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
||||||
};
|
|
||||||
|
|
||||||
var uid$2 = 0;
|
var uid$2 = 0;
|
||||||
var pendingCleanupDeps = [];
|
var pendingCleanupDeps = [];
|
||||||
var cleanupDeps = function () {
|
var cleanupDeps = function () {
|
||||||
@@ -892,7 +882,7 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
var arrayKeys = Object.getOwnPropertyNames(arrayMethods);
|
var arrayKeys = Object.getOwnPropertyNames(arrayMethods);
|
||||||
var NO_INITIAL_VALUE = {};
|
var NO_INIITIAL_VALUE = {};
|
||||||
/**
|
/**
|
||||||
* In some cases we may want to disable observation inside a component's
|
* In some cases we may want to disable observation inside a component's
|
||||||
* update computation.
|
* update computation.
|
||||||
@@ -951,7 +941,7 @@
|
|||||||
var keys = Object.keys(value);
|
var keys = Object.keys(value);
|
||||||
for (var i = 0; i < keys.length; i++) {
|
for (var i = 0; i < keys.length; i++) {
|
||||||
var key = keys[i];
|
var key = keys[i];
|
||||||
defineReactive(value, key, NO_INITIAL_VALUE, undefined, shallow, mock);
|
defineReactive(value, key, NO_INIITIAL_VALUE, undefined, shallow, mock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -988,8 +978,7 @@
|
|||||||
/**
|
/**
|
||||||
* Define a reactive property on an Object.
|
* Define a reactive property on an Object.
|
||||||
*/
|
*/
|
||||||
function defineReactive(obj, key, val, customSetter, shallow, mock, observeEvenIfShallow) {
|
function defineReactive(obj, key, val, customSetter, shallow, mock) {
|
||||||
if (observeEvenIfShallow === void 0) { observeEvenIfShallow = false; }
|
|
||||||
var dep = new Dep();
|
var dep = new Dep();
|
||||||
var property = Object.getOwnPropertyDescriptor(obj, key);
|
var property = Object.getOwnPropertyDescriptor(obj, key);
|
||||||
if (property && property.configurable === false) {
|
if (property && property.configurable === false) {
|
||||||
@@ -999,10 +988,10 @@
|
|||||||
var getter = property && property.get;
|
var getter = property && property.get;
|
||||||
var setter = property && property.set;
|
var setter = property && property.set;
|
||||||
if ((!getter || setter) &&
|
if ((!getter || setter) &&
|
||||||
(val === NO_INITIAL_VALUE || arguments.length === 2)) {
|
(val === NO_INIITIAL_VALUE || arguments.length === 2)) {
|
||||||
val = obj[key];
|
val = obj[key];
|
||||||
}
|
}
|
||||||
var childOb = shallow ? val && val.__ob__ : observe(val, false, mock);
|
var childOb = !shallow && observe(val, false, mock);
|
||||||
Object.defineProperty(obj, key, {
|
Object.defineProperty(obj, key, {
|
||||||
enumerable: true,
|
enumerable: true,
|
||||||
configurable: true,
|
configurable: true,
|
||||||
@@ -1047,7 +1036,7 @@
|
|||||||
else {
|
else {
|
||||||
val = newVal;
|
val = newVal;
|
||||||
}
|
}
|
||||||
childOb = shallow ? newVal && newVal.__ob__ : observe(newVal, false, mock);
|
childOb = !shallow && observe(newVal, false, mock);
|
||||||
{
|
{
|
||||||
dep.notify({
|
dep.notify({
|
||||||
type: "set" /* TriggerOpTypes.SET */,
|
type: "set" /* TriggerOpTypes.SET */,
|
||||||
@@ -2510,10 +2499,11 @@
|
|||||||
// to the data on the placeholder node.
|
// to the data on the placeholder node.
|
||||||
vm.$vnode = _parentVnode;
|
vm.$vnode = _parentVnode;
|
||||||
// render self
|
// render self
|
||||||
var prevInst = currentInstance;
|
|
||||||
var prevRenderInst = currentRenderingInstance;
|
|
||||||
var vnode;
|
var vnode;
|
||||||
try {
|
try {
|
||||||
|
// There's no need to maintain a stack because all render fns are called
|
||||||
|
// separately from one another. Nested component's render fns are called
|
||||||
|
// when parent component is patched.
|
||||||
setCurrentInstance(vm);
|
setCurrentInstance(vm);
|
||||||
currentRenderingInstance = vm;
|
currentRenderingInstance = vm;
|
||||||
vnode = render.call(vm._renderProxy, vm.$createElement);
|
vnode = render.call(vm._renderProxy, vm.$createElement);
|
||||||
@@ -2537,8 +2527,8 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
currentRenderingInstance = prevRenderInst;
|
currentRenderingInstance = null;
|
||||||
setCurrentInstance(prevInst);
|
setCurrentInstance();
|
||||||
}
|
}
|
||||||
// if the returned array contains only a single node, allow it
|
// if the returned array contains only a single node, allow it
|
||||||
if (isArray(vnode) && vnode.length === 1) {
|
if (isArray(vnode) && vnode.length === 1) {
|
||||||
@@ -2803,112 +2793,6 @@
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
var activeEffectScope;
|
|
||||||
var EffectScope = /** @class */ (function () {
|
|
||||||
function EffectScope(detached) {
|
|
||||||
if (detached === void 0) { detached = false; }
|
|
||||||
this.detached = detached;
|
|
||||||
/**
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
this.active = true;
|
|
||||||
/**
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
this.effects = [];
|
|
||||||
/**
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
this.cleanups = [];
|
|
||||||
this.parent = activeEffectScope;
|
|
||||||
if (!detached && activeEffectScope) {
|
|
||||||
this.index =
|
|
||||||
(activeEffectScope.scopes || (activeEffectScope.scopes = [])).push(this) - 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
EffectScope.prototype.run = function (fn) {
|
|
||||||
if (this.active) {
|
|
||||||
var currentEffectScope = activeEffectScope;
|
|
||||||
try {
|
|
||||||
activeEffectScope = this;
|
|
||||||
return fn();
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
activeEffectScope = currentEffectScope;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
warn$2("cannot run an inactive effect scope.");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
/**
|
|
||||||
* This should only be called on non-detached scopes
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
EffectScope.prototype.on = function () {
|
|
||||||
activeEffectScope = this;
|
|
||||||
};
|
|
||||||
/**
|
|
||||||
* This should only be called on non-detached scopes
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
EffectScope.prototype.off = function () {
|
|
||||||
activeEffectScope = this.parent;
|
|
||||||
};
|
|
||||||
EffectScope.prototype.stop = function (fromParent) {
|
|
||||||
if (this.active) {
|
|
||||||
var i = void 0, l = void 0;
|
|
||||||
for (i = 0, l = this.effects.length; i < l; i++) {
|
|
||||||
this.effects[i].teardown();
|
|
||||||
}
|
|
||||||
for (i = 0, l = this.cleanups.length; i < l; i++) {
|
|
||||||
this.cleanups[i]();
|
|
||||||
}
|
|
||||||
if (this.scopes) {
|
|
||||||
for (i = 0, l = this.scopes.length; i < l; i++) {
|
|
||||||
this.scopes[i].stop(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// nested scope, dereference from parent to avoid memory leaks
|
|
||||||
if (!this.detached && this.parent && !fromParent) {
|
|
||||||
// optimized O(1) removal
|
|
||||||
var last = this.parent.scopes.pop();
|
|
||||||
if (last && last !== this) {
|
|
||||||
this.parent.scopes[this.index] = last;
|
|
||||||
last.index = this.index;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.parent = undefined;
|
|
||||||
this.active = false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
return EffectScope;
|
|
||||||
}());
|
|
||||||
function effectScope(detached) {
|
|
||||||
return new EffectScope(detached);
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
function recordEffectScope(effect, scope) {
|
|
||||||
if (scope === void 0) { scope = activeEffectScope; }
|
|
||||||
if (scope && scope.active) {
|
|
||||||
scope.effects.push(effect);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function getCurrentScope() {
|
|
||||||
return activeEffectScope;
|
|
||||||
}
|
|
||||||
function onScopeDispose(fn) {
|
|
||||||
if (activeEffectScope) {
|
|
||||||
activeEffectScope.cleanups.push(fn);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
warn$2("onScopeDispose() is called when there is no active effect scope" +
|
|
||||||
" to be associated with.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var activeInstance = null;
|
var activeInstance = null;
|
||||||
var isUpdatingChildComponent = false;
|
var isUpdatingChildComponent = false;
|
||||||
function setActiveInstance(vm) {
|
function setActiveInstance(vm) {
|
||||||
@@ -3211,8 +3095,7 @@
|
|||||||
if (setContext === void 0) { setContext = true; }
|
if (setContext === void 0) { setContext = true; }
|
||||||
// #7573 disable dep collection when invoking lifecycle hooks
|
// #7573 disable dep collection when invoking lifecycle hooks
|
||||||
pushTarget();
|
pushTarget();
|
||||||
var prevInst = currentInstance;
|
var prev = currentInstance;
|
||||||
var prevScope = getCurrentScope();
|
|
||||||
setContext && setCurrentInstance(vm);
|
setContext && setCurrentInstance(vm);
|
||||||
var handlers = vm.$options[hook];
|
var handlers = vm.$options[hook];
|
||||||
var info = "".concat(hook, " hook");
|
var info = "".concat(hook, " hook");
|
||||||
@@ -3224,10 +3107,7 @@
|
|||||||
if (vm._hasHookEvent) {
|
if (vm._hasHookEvent) {
|
||||||
vm.$emit('hook:' + hook);
|
vm.$emit('hook:' + hook);
|
||||||
}
|
}
|
||||||
if (setContext) {
|
setContext && setCurrentInstance(prev);
|
||||||
setCurrentInstance(prevInst);
|
|
||||||
prevScope && prevScope.on();
|
|
||||||
}
|
|
||||||
popTarget();
|
popTarget();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3445,10 +3325,7 @@
|
|||||||
var instance = currentInstance;
|
var instance = currentInstance;
|
||||||
var call = function (fn, type, args) {
|
var call = function (fn, type, args) {
|
||||||
if (args === void 0) { args = null; }
|
if (args === void 0) { args = null; }
|
||||||
var res = invokeWithErrorHandling(fn, null, args, instance, type);
|
return invokeWithErrorHandling(fn, null, args, instance, type);
|
||||||
if (deep && res && res.__ob__)
|
|
||||||
res.__ob__.dep.depend();
|
|
||||||
return res;
|
|
||||||
};
|
};
|
||||||
var getter;
|
var getter;
|
||||||
var forceTrigger = false;
|
var forceTrigger = false;
|
||||||
@@ -3473,7 +3350,6 @@
|
|||||||
return s.value;
|
return s.value;
|
||||||
}
|
}
|
||||||
else if (isReactive(s)) {
|
else if (isReactive(s)) {
|
||||||
s.__ob__.dep.depend();
|
|
||||||
return traverse(s);
|
return traverse(s);
|
||||||
}
|
}
|
||||||
else if (isFunction(s)) {
|
else if (isFunction(s)) {
|
||||||
@@ -3617,6 +3493,112 @@
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var activeEffectScope;
|
||||||
|
var EffectScope = /** @class */ (function () {
|
||||||
|
function EffectScope(detached) {
|
||||||
|
if (detached === void 0) { detached = false; }
|
||||||
|
this.detached = detached;
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
this.active = true;
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
this.effects = [];
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
this.cleanups = [];
|
||||||
|
this.parent = activeEffectScope;
|
||||||
|
if (!detached && activeEffectScope) {
|
||||||
|
this.index =
|
||||||
|
(activeEffectScope.scopes || (activeEffectScope.scopes = [])).push(this) - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EffectScope.prototype.run = function (fn) {
|
||||||
|
if (this.active) {
|
||||||
|
var currentEffectScope = activeEffectScope;
|
||||||
|
try {
|
||||||
|
activeEffectScope = this;
|
||||||
|
return fn();
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
activeEffectScope = currentEffectScope;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
warn$2("cannot run an inactive effect scope.");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* This should only be called on non-detached scopes
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
EffectScope.prototype.on = function () {
|
||||||
|
activeEffectScope = this;
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* This should only be called on non-detached scopes
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
EffectScope.prototype.off = function () {
|
||||||
|
activeEffectScope = this.parent;
|
||||||
|
};
|
||||||
|
EffectScope.prototype.stop = function (fromParent) {
|
||||||
|
if (this.active) {
|
||||||
|
var i = void 0, l = void 0;
|
||||||
|
for (i = 0, l = this.effects.length; i < l; i++) {
|
||||||
|
this.effects[i].teardown();
|
||||||
|
}
|
||||||
|
for (i = 0, l = this.cleanups.length; i < l; i++) {
|
||||||
|
this.cleanups[i]();
|
||||||
|
}
|
||||||
|
if (this.scopes) {
|
||||||
|
for (i = 0, l = this.scopes.length; i < l; i++) {
|
||||||
|
this.scopes[i].stop(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// nested scope, dereference from parent to avoid memory leaks
|
||||||
|
if (!this.detached && this.parent && !fromParent) {
|
||||||
|
// optimized O(1) removal
|
||||||
|
var last = this.parent.scopes.pop();
|
||||||
|
if (last && last !== this) {
|
||||||
|
this.parent.scopes[this.index] = last;
|
||||||
|
last.index = this.index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.parent = undefined;
|
||||||
|
this.active = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return EffectScope;
|
||||||
|
}());
|
||||||
|
function effectScope(detached) {
|
||||||
|
return new EffectScope(detached);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
function recordEffectScope(effect, scope) {
|
||||||
|
if (scope === void 0) { scope = activeEffectScope; }
|
||||||
|
if (scope && scope.active) {
|
||||||
|
scope.effects.push(effect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function getCurrentScope() {
|
||||||
|
return activeEffectScope;
|
||||||
|
}
|
||||||
|
function onScopeDispose(fn) {
|
||||||
|
if (activeEffectScope) {
|
||||||
|
activeEffectScope.cleanups.push(fn);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
warn$2("onScopeDispose() is called when there is no active effect scope" +
|
||||||
|
" to be associated with.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function provide(key, value) {
|
function provide(key, value) {
|
||||||
if (!currentInstance) {
|
if (!currentInstance) {
|
||||||
{
|
{
|
||||||
@@ -3911,7 +3893,7 @@
|
|||||||
suspensible = _b === void 0 ? false : _b, // in Vue 3 default is true
|
suspensible = _b === void 0 ? false : _b, // in Vue 3 default is true
|
||||||
userOnError = source.onError;
|
userOnError = source.onError;
|
||||||
if (suspensible) {
|
if (suspensible) {
|
||||||
warn$2("The suspensible option for async components is not supported in Vue2. It is ignored.");
|
warn$2("The suspensiblbe option for async components is not supported in Vue2. It is ignored.");
|
||||||
}
|
}
|
||||||
var pendingRequest = null;
|
var pendingRequest = null;
|
||||||
var retries = 0;
|
var retries = 0;
|
||||||
@@ -4014,7 +3996,7 @@
|
|||||||
/**
|
/**
|
||||||
* Note: also update dist/vue.runtime.mjs when adding new exports to this file.
|
* Note: also update dist/vue.runtime.mjs when adding new exports to this file.
|
||||||
*/
|
*/
|
||||||
var version = '2.7.16';
|
var version = '2.7.14';
|
||||||
/**
|
/**
|
||||||
* @internal type is manually declared in <root>/types/v3-define-component.d.ts
|
* @internal type is manually declared in <root>/types/v3-define-component.d.ts
|
||||||
*/
|
*/
|
||||||
@@ -4391,7 +4373,7 @@
|
|||||||
"Instead, use a data or computed property based on the prop's " +
|
"Instead, use a data or computed property based on the prop's " +
|
||||||
"value. Prop being mutated: \"".concat(key, "\""), vm);
|
"value. Prop being mutated: \"".concat(key, "\""), vm);
|
||||||
}
|
}
|
||||||
}, true /* shallow */);
|
});
|
||||||
}
|
}
|
||||||
// static props are already proxied on the component's prototype
|
// static props are already proxied on the component's prototype
|
||||||
// during Vue.extend(). We only need to proxy props defined at
|
// during Vue.extend(). We only need to proxy props defined at
|
||||||
@@ -4707,9 +4689,6 @@
|
|||||||
vm.__v_skip = true;
|
vm.__v_skip = true;
|
||||||
// effect scope
|
// effect scope
|
||||||
vm._scope = new EffectScope(true /* detached */);
|
vm._scope = new EffectScope(true /* detached */);
|
||||||
// #13134 edge case where a child component is manually created during the
|
|
||||||
// render of a parent component
|
|
||||||
vm._scope.parent = undefined;
|
|
||||||
vm._scope._vm = true;
|
vm._scope._vm = true;
|
||||||
// merge options
|
// merge options
|
||||||
if (options && options._isComponent) {
|
if (options && options._isComponent) {
|
||||||
@@ -5956,7 +5935,7 @@
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
function pruneCache(keepAliveInstance, filter) {
|
function pruneCache(keepAliveInstance, filter) {
|
||||||
var cache = keepAliveInstance.cache, keys = keepAliveInstance.keys, _vnode = keepAliveInstance._vnode, $vnode = keepAliveInstance.$vnode;
|
var cache = keepAliveInstance.cache, keys = keepAliveInstance.keys, _vnode = keepAliveInstance._vnode;
|
||||||
for (var key in cache) {
|
for (var key in cache) {
|
||||||
var entry = cache[key];
|
var entry = cache[key];
|
||||||
if (entry) {
|
if (entry) {
|
||||||
@@ -5966,7 +5945,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$vnode.componentOptions.children = undefined;
|
|
||||||
}
|
}
|
||||||
function pruneCacheEntry(cache, key, keys, current) {
|
function pruneCacheEntry(cache, key, keys, current) {
|
||||||
var entry = cache[key];
|
var entry = cache[key];
|
||||||
@@ -6288,7 +6266,7 @@
|
|||||||
}
|
}
|
||||||
var el = document.createElement(tag);
|
var el = document.createElement(tag);
|
||||||
if (tag.indexOf('-') > -1) {
|
if (tag.indexOf('-') > -1) {
|
||||||
// https://stackoverflow.com/a/28210364/1070244
|
// http://stackoverflow.com/a/28210364/1070244
|
||||||
return (unknownElementCache[tag] =
|
return (unknownElementCache[tag] =
|
||||||
el.constructor === window.HTMLUnknownElement ||
|
el.constructor === window.HTMLUnknownElement ||
|
||||||
el.constructor === window.HTMLElement);
|
el.constructor === window.HTMLElement);
|
||||||
@@ -7163,11 +7141,8 @@
|
|||||||
var insert_1 = ancestor.data.hook.insert;
|
var insert_1 = ancestor.data.hook.insert;
|
||||||
if (insert_1.merged) {
|
if (insert_1.merged) {
|
||||||
// start at index 1 to avoid re-invoking component mounted hook
|
// start at index 1 to avoid re-invoking component mounted hook
|
||||||
// clone insert hooks to avoid being mutated during iteration.
|
for (var i_10 = 1; i_10 < insert_1.fns.length; i_10++) {
|
||||||
// e.g. for customed directives under transition group.
|
insert_1.fns[i_10]();
|
||||||
var cloned = insert_1.fns.slice(1);
|
|
||||||
for (var i_10 = 0; i_10 < cloned.length; i_10++) {
|
|
||||||
cloned[i_10]();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -8306,8 +8281,10 @@
|
|||||||
}
|
}
|
||||||
for (name in newStyle) {
|
for (name in newStyle) {
|
||||||
cur = newStyle[name];
|
cur = newStyle[name];
|
||||||
// ie9 setting to null has no effect, must use empty string
|
if (cur !== oldStyle[name]) {
|
||||||
setProp(el, name, cur == null ? '' : cur);
|
// ie9 setting to null has no effect, must use empty string
|
||||||
|
setProp(el, name, cur == null ? '' : cur);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var style$1 = {
|
var style$1 = {
|
||||||
@@ -9554,7 +9531,7 @@
|
|||||||
return "continue";
|
return "continue";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// https://en.wikipedia.org/wiki/Conditional_comment#Downlevel-revealed_conditional_comment
|
// http://en.wikipedia.org/wiki/Conditional_comment#Downlevel-revealed_conditional_comment
|
||||||
if (conditionalComment.test(html)) {
|
if (conditionalComment.test(html)) {
|
||||||
var conditionalEnd = html.indexOf(']>');
|
var conditionalEnd = html.indexOf(']>');
|
||||||
if (conditionalEnd >= 0) {
|
if (conditionalEnd >= 0) {
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 1.4 MiB |
@@ -35,7 +35,7 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
border: none;
|
border: none;
|
||||||
border-bottom: var(--brand-bg) 2px solid;
|
border-bottom: var(--text-color2) 2px solid;
|
||||||
background-color: var(--bg-color);
|
background-color: var(--bg-color);
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
min-height: 2em;
|
min-height: 2em;
|
||||||
@@ -44,7 +44,7 @@
|
|||||||
.form-row input:focus {
|
.form-row input:focus {
|
||||||
outline: none;
|
outline: none;
|
||||||
border: none;
|
border: none;
|
||||||
border-bottom: var(--brand-text) 2px solid;
|
border-bottom: var(--bg-action) 2px solid;
|
||||||
background-color: var(--bg-selected);
|
background-color: var(--bg-selected);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,6 +52,7 @@
|
|||||||
border: none;
|
border: none;
|
||||||
font-weight: bolder;
|
font-weight: bolder;
|
||||||
background: var(--bg-action);
|
background: var(--bg-action);
|
||||||
|
color: var(--text-color);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
1351
static/main-tdma.html
Normal file
1351
static/main-tdma.html
Normal file
File diff suppressed because it is too large
Load Diff
@@ -2,17 +2,17 @@
|
|||||||
body {
|
body {
|
||||||
--text-color: #262626;
|
--text-color: #262626;
|
||||||
--text-color2: #3d3d3d;
|
--text-color2: #3d3d3d;
|
||||||
--text-good: green;
|
--text-good: #0CF500;
|
||||||
--text-bad: red;
|
--text-bad: #F5000C;
|
||||||
|
|
||||||
--brand-bg: #EDF3FE;
|
--brand-bg: #B3C0D1;
|
||||||
--brand-text: #5488F7;
|
--brand-text: #0146f4;
|
||||||
|
|
||||||
--bg-color: #FEFEFE;
|
--bg-color: #FEFEFE;
|
||||||
--bg-selected: #F1F1F1;
|
--bg-selected: #F1F1F1;
|
||||||
--bg-element: #a7a7a7;
|
--bg-element: #a7a7a7;
|
||||||
--bg-action: #5181fe;
|
--bg-action: #81a7ff;
|
||||||
--bg-danger: #db2828;
|
--bg-danger: #ff6464;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (prefers-color-scheme: dark) {
|
@media (prefers-color-scheme: dark) {
|
||||||
@@ -20,8 +20,8 @@ body {
|
|||||||
body {
|
body {
|
||||||
--text-color: #eee;
|
--text-color: #eee;
|
||||||
--text-color2: #bbb;
|
--text-color2: #bbb;
|
||||||
--text-good: greenyellow;
|
--text-good: #91FF00;
|
||||||
--text-bad: orangered;
|
--text-bad: #FF1F2A;
|
||||||
|
|
||||||
--brand-bg: #393E50;
|
--brand-bg: #393E50;
|
||||||
--brand-text: #5F93F3;
|
--brand-text: #5F93F3;
|
||||||
@@ -29,7 +29,8 @@ body {
|
|||||||
--bg-color: #2d2c33;
|
--bg-color: #2d2c33;
|
||||||
--bg-selected: #424248;
|
--bg-selected: #424248;
|
||||||
--bg-element: #626268;
|
--bg-element: #626268;
|
||||||
--bg-action: #4a70d5;
|
--bg-action: #3a58af;
|
||||||
|
--bg-danger: #ac1e1e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,6 +53,13 @@ body {
|
|||||||
margin: 0.5em;
|
margin: 0.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* увеличение размера шрифтов */
|
||||||
|
|
||||||
|
* { font-size: large; }
|
||||||
|
h1 { font-size: xxx-large; }
|
||||||
|
h2 { font-size: xx-large; }
|
||||||
|
h3 { font-size: larger; }
|
||||||
|
|
||||||
/* ========== MAIN STYLES ========== */
|
/* ========== MAIN STYLES ========== */
|
||||||
|
|
||||||
.value-good {
|
.value-good {
|
||||||
|
Binary file not shown.
Reference in New Issue
Block a user