Compare commits
84 Commits
0b794fac40
...
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 | |||
df4b990316 | |||
dc2d464f41 | |||
087da149f1 | |||
c0e7e1e300 | |||
800473b4e3 | |||
dd0a6813a8 | |||
e2c9877017 | |||
b51e303006 | |||
00aa17bb37 | |||
5175362d1b | |||
857a01528b | |||
cb9d412c8e | |||
435f215118 | |||
4c1ce6031b | |||
1f5eb54225 | |||
d1ad7baad1 | |||
16b9776bfd | |||
a833c0f68a | |||
fae7a2ffc8 | |||
4a293e10f6 | |||
eaee827261 | |||
6f62c3e1fa | |||
40e12f1c67 | |||
541b08a40e | |||
5bfc5cebaf | |||
b2ed7ab015 | |||
3714207983 | |||
0eacd76810 | |||
b561dedb2b |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -4,3 +4,4 @@ cmake-build-*
|
||||
cert.pem
|
||||
key.pem
|
||||
dh.pem
|
||||
/web-action
|
||||
|
@@ -15,8 +15,21 @@ else()
|
||||
message(FATAL_ERROR "You must set build type \"Debug\" or \"Release\". Another build types not supported!")
|
||||
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)
|
||||
|
||||
# максимальный размер тела запроса 200mb
|
||||
add_definitions(-DHTTP_MAX_PAYLOAD=200000000)
|
||||
|
||||
add_subdirectory(dependencies/control_system)
|
||||
|
||||
add_executable(terminal-web-server
|
||||
@@ -40,8 +53,12 @@ add_executable(terminal-web-server
|
||||
src/auth/resources.h
|
||||
src/auth/jwt.cpp
|
||||
src/auth/jwt.h
|
||||
src/auth/utils.cpp
|
||||
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(OpenSSL REQUIRED)
|
||||
target_link_libraries(terminal-web-server ${Boost_LIBRARIES} ${OPENSSL_LIBRARIES} terminal-client-api)
|
||||
|
8
dependencies/control_system/CMakeLists.txt
vendored
Normal file → Executable file
8
dependencies/control_system/CMakeLists.txt
vendored
Normal file → Executable file
@@ -1,6 +1,6 @@
|
||||
cmake_minimum_required(VERSION 3.20)
|
||||
|
||||
project(terminal-client-api)
|
||||
project(terminal)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
|
||||
@@ -14,15 +14,15 @@ include(CheckCXXCompilerFlag)
|
||||
set(CMAKE_CXX_FLAGS -fPIC)
|
||||
|
||||
set(default_build_type "Release")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Werror")
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "-ggdb -O0 -fprofile-arcs -ftest-coverage")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "-ggdb -O0")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "-O2 -s -DNDEBUG ")
|
||||
message(${CMAKE_CXX_FLAGS})
|
||||
message("CMAKE_BUILD_TYPE: " ${CMAKE_BUILD_TYPE})
|
||||
|
||||
message(${CMAKE_CXX_FLAGS})
|
||||
|
||||
add_library(terminal-client-api SHARED
|
||||
add_library(terminal-client-api STATIC
|
||||
client/main.cpp
|
||||
client/sock_client.cpp
|
||||
client/system_client.cpp
|
||||
|
253
dependencies/control_system/client/main.cpp
vendored
253
dependencies/control_system/client/main.cpp
vendored
@@ -1,11 +1,252 @@
|
||||
#include <shared_mutex>
|
||||
#include "terminal_api/ControlProtoCInterface.h"
|
||||
#include <terminal_api/ControlProtoCInterface.h>
|
||||
#include "system_client.h"
|
||||
|
||||
std::shared_mutex mtx;
|
||||
TSID sid_counter { 0 };
|
||||
std::map<TSID, std::unique_ptr<system_client>> clients;
|
||||
|
||||
EXTERNC CP_Result CP_SetQoSSettings(TSID sid, const std::string &qos_settings_json, bool is_enable){
|
||||
std::shared_lock lock(mtx);
|
||||
try
|
||||
{
|
||||
if (clients.find(sid) == clients.end())
|
||||
return ERROR;
|
||||
auto resp = clients[sid]->send_set_qos_settings_json(qos_settings_json, is_enable);
|
||||
if (resp == response_type::error)
|
||||
return ERROR;
|
||||
return OK;
|
||||
}
|
||||
|
||||
catch(const std::exception& e)
|
||||
{
|
||||
return ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
EXTERNC CP_Result CP_GetQoSSettings(TSID sid, std::string &qos_settings_json, bool &is_enable){
|
||||
std::shared_lock lock(mtx);
|
||||
try
|
||||
{
|
||||
if (clients.find(sid) == clients.end())
|
||||
return ERROR;
|
||||
|
||||
auto resp = clients[sid]->send_get_qos_settings_json(qos_settings_json, is_enable);
|
||||
if (resp == response_type::error)
|
||||
return ERROR;
|
||||
return OK;
|
||||
}
|
||||
|
||||
catch(const std::exception& e)
|
||||
{
|
||||
return ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
EXTERNC CP_Result CP_SetBUC_LNB_settings(TSID sid, buc_lnb_settings &settings){
|
||||
std::shared_lock lock(mtx);
|
||||
try
|
||||
{
|
||||
if (clients.find(sid) == clients.end())
|
||||
return ERROR;
|
||||
auto settings_ = reinterpret_cast<buc_lnb_settings_com&>(settings);
|
||||
auto resp = clients[sid]->send_set_buc_lnb_settings(settings_);
|
||||
if (resp == response_type::error)
|
||||
return ERROR;
|
||||
return OK;
|
||||
}
|
||||
|
||||
catch(const std::exception& e)
|
||||
{
|
||||
return ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
EXTERNC CP_Result CP_GetBUC_LNB_settings(TSID sid, buc_lnb_settings &settings){
|
||||
std::shared_lock lock(mtx);
|
||||
try
|
||||
{
|
||||
if (clients.find(sid) == clients.end())
|
||||
return ERROR;
|
||||
|
||||
buc_lnb_settings_com settings_com;
|
||||
auto resp = clients[sid]->send_get_buc_lnb_settings(settings_com);
|
||||
|
||||
if (resp == response_type::error)
|
||||
return ERROR;
|
||||
settings = reinterpret_cast<buc_lnb_settings&>(settings_com);
|
||||
return OK;
|
||||
}
|
||||
|
||||
catch(const std::exception& e)
|
||||
{
|
||||
return ERROR;
|
||||
}
|
||||
}
|
||||
EXTERNC CP_Result CP_SetModulatorSettings(TSID sid, modulator_settings& settings){
|
||||
std::shared_lock lock(mtx);
|
||||
try
|
||||
{
|
||||
if (clients.find(sid) == clients.end())
|
||||
return ERROR;
|
||||
auto settings_ = reinterpret_cast<modulator_settings_com&>(settings);
|
||||
auto resp = clients[sid]->send_set_modulator_settings(settings_);
|
||||
if (resp == response_type::error)
|
||||
return ERROR;
|
||||
return OK;
|
||||
}
|
||||
|
||||
catch(const std::exception& e)
|
||||
{
|
||||
return ERROR;
|
||||
}
|
||||
}
|
||||
EXTERNC CP_Result CP_SetDemodulatorSettings(TSID sid, demodulator_settings& settings){
|
||||
std::shared_lock lock(mtx);
|
||||
try
|
||||
{
|
||||
if (clients.find(sid) == clients.end())
|
||||
return ERROR;
|
||||
auto settings_ = reinterpret_cast<demodulator_settings_com&>(settings);
|
||||
auto resp = clients[sid]->send_set_demodulator_settings(settings_);
|
||||
if (resp == response_type::error)
|
||||
return ERROR;
|
||||
return OK;
|
||||
}
|
||||
|
||||
catch(const std::exception& e)
|
||||
{
|
||||
return ERROR;
|
||||
}
|
||||
}
|
||||
EXTERNC CP_Result CP_GetModulatorSettings(TSID sid, modulator_settings& settings){
|
||||
std::shared_lock lock(mtx);
|
||||
try
|
||||
{
|
||||
if (clients.find(sid) == clients.end())
|
||||
return ERROR;
|
||||
|
||||
modulator_settings_com settings_com;
|
||||
auto resp = clients[sid]->send_get_modulator_settings(settings_com);
|
||||
if (resp == response_type::error)
|
||||
return ERROR;
|
||||
settings = reinterpret_cast<modulator_settings&>(settings_com);
|
||||
return OK;
|
||||
}
|
||||
|
||||
catch(const std::exception& e)
|
||||
{
|
||||
return ERROR;
|
||||
}
|
||||
}
|
||||
EXTERNC CP_Result CP_GetDemodulatorSettings(TSID sid, demodulator_settings& settings){
|
||||
std::shared_lock lock(mtx);
|
||||
try
|
||||
{
|
||||
if (clients.find(sid) == clients.end())
|
||||
return ERROR;
|
||||
demodulator_settings_com settings_com;
|
||||
auto resp = clients[sid]->send_get_demodulator_settings(settings_com);
|
||||
if (resp == response_type::error)
|
||||
return ERROR;
|
||||
std::cout << "settings_com.rollof: " << settings_com.rollof << std::endl;
|
||||
std::cout << "settings_com.gain: " << settings_com.gain << std::endl;
|
||||
settings = reinterpret_cast<demodulator_settings&>(settings_com);
|
||||
return OK;
|
||||
}
|
||||
|
||||
catch(const std::exception& e)
|
||||
{
|
||||
return ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
EXTERNC CP_Result CP_GetDemodulatorState(TSID sid, demodulator_state &state){
|
||||
std::shared_lock lock(mtx);
|
||||
try
|
||||
{
|
||||
if (clients.find(sid) == clients.end())
|
||||
return ERROR;
|
||||
demodulator_state_com state_com;
|
||||
auto resp = clients[sid]->send_get_demodulator_state(state_com);
|
||||
|
||||
if (resp == response_type::error)
|
||||
{
|
||||
std::cout << "error" << std::endl;
|
||||
return ERROR;
|
||||
}
|
||||
state = reinterpret_cast<demodulator_state&>(state_com);
|
||||
state.locks = reinterpret_cast<demodulator_locks&>(state_com.locks);
|
||||
return OK;
|
||||
}
|
||||
|
||||
catch(const std::exception& e)
|
||||
{
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
}
|
||||
EXTERNC CP_Result CP_GetModulatorState(TSID sid, modulator_state &state){
|
||||
std::shared_lock lock(mtx);
|
||||
try
|
||||
{
|
||||
if (clients.find(sid) == clients.end())
|
||||
return ERROR;
|
||||
modulator_state_com state_com;
|
||||
auto resp = clients[sid]->send_get_modulator_state(state_com);
|
||||
if (resp == response_type::error)
|
||||
return ERROR;
|
||||
state = reinterpret_cast<modulator_state&>(state_com);
|
||||
return OK;
|
||||
}
|
||||
|
||||
catch(const std::exception& e)
|
||||
{
|
||||
return ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
EXTERNC CP_Result CP_GetCinCState(TSID sid, CinC_state &state){
|
||||
std::shared_lock lock(mtx);
|
||||
try
|
||||
{
|
||||
if (clients.find(sid) == clients.end())
|
||||
return ERROR;
|
||||
CinC_state_com state_com;
|
||||
auto resp = clients[sid]->send_get_cinc_state(state_com);
|
||||
if (resp == response_type::error)
|
||||
return ERROR;
|
||||
state = reinterpret_cast<CinC_state&>(state_com);
|
||||
return OK;
|
||||
}
|
||||
|
||||
catch(const std::exception& e)
|
||||
{
|
||||
return ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
EXTERNC CP_Result CP_GetDeviceState(TSID sid, device_state &state){
|
||||
|
||||
std::shared_lock lock(mtx);
|
||||
try
|
||||
{
|
||||
if (clients.find(sid) == clients.end())
|
||||
return ERROR;
|
||||
device_state_com state_com;
|
||||
auto resp = clients[sid]->send_get_device_state(state_com);
|
||||
if (resp == response_type::error)
|
||||
return ERROR;
|
||||
state = reinterpret_cast<device_state&>(state_com);
|
||||
return OK;
|
||||
}
|
||||
|
||||
catch(const std::exception& e)
|
||||
{
|
||||
return ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
EXTERNC CP_Result CP_SetRollofBaudrate(TSID sid, double rollof, double baudrate)
|
||||
{
|
||||
std::shared_lock lock(mtx);
|
||||
@@ -285,6 +526,16 @@ EXTERNC CP_Result CP_GetNetwork(TSID sid, const char *param_name, std::string *v
|
||||
net_val = network_value::mac_eth1;
|
||||
else if(cmd == "name_serv")
|
||||
net_val = network_value::name_serv;
|
||||
else if(cmd == "network_debug_send")
|
||||
net_val = network_value::network_debug_send;
|
||||
else if(cmd == "network_port_metric")
|
||||
net_val = network_value::network_port_metric;
|
||||
else if(cmd == "network_port_data")
|
||||
net_val = network_value::network_port_data;
|
||||
else if(cmd == "if_debug_mode")
|
||||
net_val = network_value::if_debug_mode;
|
||||
else if(cmd == "periodic_send_metrics")
|
||||
net_val = network_value::periodic_send_metrics;
|
||||
|
||||
auto resp = clients[sid]->send_get_network_settings(net_val, val_from_server);
|
||||
if (resp == response_type::error)
|
||||
|
@@ -29,8 +29,8 @@ void client::start()
|
||||
seq_packet::seqpacket_protocol::socket::message_flags in_flags { MSG_WAITALL };
|
||||
socket_.async_receive(boost::asio::buffer(data_), in_flags,
|
||||
std::bind(&client::handle_read, this,
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2));
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2));
|
||||
}
|
||||
|
||||
void client::handle_connect(const boost::system::error_code & error)
|
||||
|
285
dependencies/control_system/client/system_client.cpp
vendored
285
dependencies/control_system/client/system_client.cpp
vendored
@@ -315,6 +315,83 @@ void system_client::data_received(const std::vector<uint8_t> & data)
|
||||
break;
|
||||
}
|
||||
|
||||
case cmd_type::get_demodulator_state:
|
||||
{
|
||||
if(cmd.rsp == response_type::ok)
|
||||
{
|
||||
cmd_get_demodulator_state value;
|
||||
iarchive(value);
|
||||
data_from_serv = value;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case cmd_type::get_modulator_state:
|
||||
{
|
||||
if(cmd.rsp == response_type::ok)
|
||||
{
|
||||
cmd_get_modulator_state value;
|
||||
iarchive(value);
|
||||
data_from_serv = value;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case cmd_type::get_lnb_buc_settings:
|
||||
{
|
||||
if(cmd.rsp == response_type::ok)
|
||||
{
|
||||
cmd_lnb_buc_settings value;
|
||||
iarchive(value);
|
||||
data_from_serv = value;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case cmd_type::get_demodulator_settings:
|
||||
{
|
||||
if(cmd.rsp == response_type::ok)
|
||||
{
|
||||
cmd_demodulator_settings value;
|
||||
iarchive(value);
|
||||
data_from_serv = value;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case cmd_type::get_modulator_settings:
|
||||
{
|
||||
if(cmd.rsp == response_type::ok)
|
||||
{
|
||||
cmd_modulator_settings value;
|
||||
iarchive(value);
|
||||
data_from_serv = value;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case cmd_type::get_device_state:
|
||||
{
|
||||
if(cmd.rsp == response_type::ok)
|
||||
{
|
||||
cmd_get_device_state value;
|
||||
iarchive(value);
|
||||
data_from_serv = value;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case cmd_type::get_cinc_state:
|
||||
{
|
||||
if(cmd.rsp == response_type::ok)
|
||||
{
|
||||
cmd_get_cinc_state value;
|
||||
iarchive(value);
|
||||
data_from_serv = value;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case cmd_type::get_dma_debugg:
|
||||
{
|
||||
if (cmd.rsp == response_type::ok)
|
||||
@@ -356,6 +433,16 @@ void system_client::data_received(const std::vector<uint8_t> & data)
|
||||
}
|
||||
break;
|
||||
}
|
||||
case cmd_type::get_qos_settings_json:
|
||||
{
|
||||
if (cmd.rsp == response_type::ok)
|
||||
{
|
||||
cmd_qos_settings value;
|
||||
iarchive(value);
|
||||
data_from_serv = value;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
|
||||
@@ -628,6 +715,40 @@ response_type system_client::send_get_qos_params(std::string &node, const name_c
|
||||
return result;
|
||||
}
|
||||
|
||||
response_type system_client::send_set_qos_settings_json(const std::string &json_string, bool is_enable){
|
||||
std::scoped_lock lock(cmd_in_progress_mtx);
|
||||
uint32_t curr_id { ++cmd_id };
|
||||
cmd_header cmd_qos_header{curr_id, cmd_type::set_qos_settings_json};
|
||||
cmd_qos_settings qos_settings{json_string, is_enable};
|
||||
|
||||
send_to_socket(cmd_qos_header, qos_settings);
|
||||
|
||||
std::any data_to_serv;
|
||||
|
||||
auto result = wait_for_response(curr_id, cmd_type::set_qos_settings, data_to_serv);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
response_type system_client::send_get_qos_settings_json(std::string &json_string, bool &is_enable){
|
||||
std::scoped_lock lock(cmd_in_progress_mtx);
|
||||
uint32_t curr_id { ++cmd_id };
|
||||
cmd_header cmd_qos_header{curr_id, cmd_type::get_qos_settings_json};
|
||||
cmd_qos_settings qos_settings{json_string, is_enable};
|
||||
|
||||
send_to_socket(cmd_qos_header, qos_settings);
|
||||
|
||||
std::any data_from_serv;
|
||||
|
||||
auto result = wait_for_response(curr_id, cmd_type::get_qos_settings_json, data_from_serv);
|
||||
if (data_from_serv.has_value())
|
||||
{
|
||||
json_string = std::any_cast<cmd_qos_settings>(data_from_serv).json_string;
|
||||
is_enable = std::any_cast<cmd_qos_settings>(data_from_serv).is_enable;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
response_type system_client::send_set_10g_config(const cmd_10g_config & _10g_config, std::string &value)
|
||||
{
|
||||
std::scoped_lock lock(cmd_in_progress_mtx);
|
||||
@@ -677,6 +798,168 @@ response_type system_client::send_set_lbq_params(const uint32_t & tick_ms, const
|
||||
return result;
|
||||
}
|
||||
|
||||
response_type system_client::send_set_modulator_settings(modulator_settings_com &settings)
|
||||
{
|
||||
std::scoped_lock lock(cmd_in_progress_mtx);
|
||||
uint32_t curr_id { ++cmd_id };
|
||||
cmd_header cmd_acm_header{curr_id, cmd_type::set_modulator_settings};
|
||||
|
||||
cmd_modulator_settings settings_;
|
||||
settings_.modulator_settings = settings;
|
||||
send_to_socket(cmd_acm_header, settings_);
|
||||
|
||||
std::any data_to_serv;
|
||||
|
||||
auto result = wait_for_response(curr_id, cmd_type::set_modulator_settings, data_to_serv);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
response_type system_client::send_set_demodulator_settings(demodulator_settings_com &settings)
|
||||
{
|
||||
std::scoped_lock lock(cmd_in_progress_mtx);
|
||||
uint32_t curr_id { ++cmd_id };
|
||||
cmd_header cmd_acm_header{curr_id, cmd_type::set_demodulator_settings};
|
||||
|
||||
cmd_demodulator_settings settings_;
|
||||
settings_.demodulator_settings = settings;
|
||||
send_to_socket(cmd_acm_header, settings_);
|
||||
|
||||
std::any data_to_serv;
|
||||
|
||||
auto result = wait_for_response(curr_id, cmd_type::set_demodulator_settings, data_to_serv);
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
response_type system_client::send_get_modulator_settings(modulator_settings_com &settings)
|
||||
{
|
||||
std::scoped_lock lock(cmd_in_progress_mtx);
|
||||
uint32_t curr_id { ++cmd_id };
|
||||
cmd_header cmd_dpdi_header{curr_id, cmd_type::get_modulator_settings};
|
||||
cmd_modulator_settings modulator;
|
||||
send_to_socket(cmd_dpdi_header, modulator);
|
||||
|
||||
std::any data_from_serv;
|
||||
|
||||
auto result = wait_for_response(curr_id, cmd_type::get_modulator_settings, data_from_serv);
|
||||
if (data_from_serv.has_value())
|
||||
settings = std::any_cast<cmd_modulator_settings>(data_from_serv).modulator_settings;
|
||||
return result;
|
||||
}
|
||||
|
||||
response_type system_client::send_get_demodulator_settings(demodulator_settings_com &settings)
|
||||
{
|
||||
std::scoped_lock lock(cmd_in_progress_mtx);
|
||||
uint32_t curr_id { ++cmd_id };
|
||||
cmd_header cmd_dpdi_header{curr_id, cmd_type::get_demodulator_settings};
|
||||
cmd_demodulator_settings demodulator;
|
||||
send_to_socket(cmd_dpdi_header, demodulator);
|
||||
std::any data_from_serv;
|
||||
|
||||
auto result = wait_for_response(curr_id, cmd_type::get_demodulator_settings, data_from_serv);
|
||||
if (data_from_serv.has_value())
|
||||
settings = std::any_cast<cmd_demodulator_settings>(data_from_serv).demodulator_settings;
|
||||
return result;
|
||||
}
|
||||
|
||||
response_type system_client::send_get_demodulator_state(demodulator_state_com &demodulator_state){
|
||||
std::scoped_lock lock(cmd_in_progress_mtx);
|
||||
uint32_t curr_id { ++cmd_id };
|
||||
cmd_header cmd_dpdi_header{curr_id, cmd_type::get_demodulator_state};
|
||||
cmd_get_demodulator_state demodulator;
|
||||
send_to_socket(cmd_dpdi_header, demodulator);
|
||||
|
||||
std::any data_from_serv;
|
||||
|
||||
auto result = wait_for_response(curr_id, cmd_type::get_demodulator_state, data_from_serv);
|
||||
if (data_from_serv.has_value())
|
||||
demodulator_state = std::any_cast<cmd_get_demodulator_state>(data_from_serv).demodulator_state;
|
||||
return result;
|
||||
}
|
||||
|
||||
response_type system_client::send_get_modulator_state(modulator_state_com &modulator_state){
|
||||
std::scoped_lock lock(cmd_in_progress_mtx);
|
||||
uint32_t curr_id { ++cmd_id };
|
||||
cmd_header cmd_dpdi_header{curr_id, cmd_type::get_modulator_state};
|
||||
cmd_get_modulator_state modulator;
|
||||
send_to_socket(cmd_dpdi_header, modulator);
|
||||
|
||||
std::any data_from_serv;
|
||||
|
||||
auto result = wait_for_response(curr_id, cmd_type::get_modulator_state, data_from_serv);
|
||||
if (data_from_serv.has_value())
|
||||
modulator_state = std::any_cast<cmd_get_modulator_state>(data_from_serv).modulator_state;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
response_type system_client::send_set_buc_lnb_settings(buc_lnb_settings_com &settings){
|
||||
std::scoped_lock lock(cmd_in_progress_mtx);
|
||||
uint32_t curr_id { ++cmd_id };
|
||||
cmd_header cmd_acm_header{curr_id, cmd_type::set_lnb_buc_settings};
|
||||
|
||||
cmd_lnb_buc_settings settings_;
|
||||
settings_.buc_lnb = settings;
|
||||
send_to_socket(cmd_acm_header, settings_);
|
||||
|
||||
std::any data_to_serv;
|
||||
|
||||
auto result = wait_for_response(curr_id, cmd_type::set_lnb_buc_settings, data_to_serv);
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
response_type system_client::send_get_buc_lnb_settings(buc_lnb_settings_com &settings){
|
||||
std::scoped_lock lock(cmd_in_progress_mtx);
|
||||
uint32_t curr_id { ++cmd_id };
|
||||
cmd_header cmd_buc_lnb_header{curr_id, cmd_type::get_lnb_buc_settings};
|
||||
cmd_lnb_buc_settings lnb_buc;
|
||||
send_to_socket(cmd_buc_lnb_header, lnb_buc);
|
||||
|
||||
std::any data_from_serv;
|
||||
|
||||
auto result = wait_for_response(curr_id, cmd_type::get_lnb_buc_settings, data_from_serv);
|
||||
if (data_from_serv.has_value())
|
||||
settings = std::any_cast<cmd_lnb_buc_settings>(data_from_serv).buc_lnb;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
response_type system_client::send_get_device_state(device_state_com &device_state ){
|
||||
std::scoped_lock lock(cmd_in_progress_mtx);
|
||||
uint32_t curr_id { ++cmd_id };
|
||||
cmd_header cmd_dpdi_header{curr_id, cmd_type::get_device_state};
|
||||
cmd_get_device_state device;
|
||||
send_to_socket(cmd_dpdi_header, device);
|
||||
|
||||
std::any data_from_serv;
|
||||
|
||||
auto result = wait_for_response(curr_id, cmd_type::get_device_state, data_from_serv);
|
||||
if (data_from_serv.has_value())
|
||||
device_state = std::any_cast<cmd_get_device_state>(data_from_serv).device_state;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
response_type system_client::send_get_cinc_state(CinC_state_com &cinc_state){
|
||||
std::scoped_lock lock(cmd_in_progress_mtx);
|
||||
uint32_t curr_id { ++cmd_id };
|
||||
cmd_header cmd_dpdi_header{curr_id, cmd_type::get_cinc_state};
|
||||
|
||||
cmd_get_cinc_state cinc;
|
||||
send_to_socket(cmd_dpdi_header, cinc);
|
||||
std::any data_from_serv;
|
||||
|
||||
auto result = wait_for_response(curr_id, cmd_type::get_cinc_state, data_from_serv);
|
||||
if (data_from_serv.has_value())
|
||||
cinc_state = std::any_cast<cmd_get_cinc_state>(data_from_serv).cinc_state;
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
response_type system_client::send_set_acm_params(const ACM_parameters_serv &acm_params)
|
||||
{
|
||||
std::scoped_lock lock(cmd_in_progress_mtx);
|
||||
@@ -752,4 +1035,4 @@ response_type system_client::send_get_network_settings(const network_value & cmd
|
||||
if (data_from_serv.has_value())
|
||||
value = std::any_cast<std::string>(data_from_serv);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
@@ -48,6 +48,20 @@ public:
|
||||
response_type send_set_acm_params(const ACM_parameters_serv &acm_params);
|
||||
response_type send_get_acm_params(cmd_get_acm_param &acm_params);
|
||||
|
||||
response_type send_get_demodulator_state(demodulator_state_com &demodulator_state);
|
||||
response_type send_get_modulator_state(modulator_state_com &modulator_state);
|
||||
|
||||
response_type send_get_device_state(device_state_com &device_state);
|
||||
response_type send_get_cinc_state(CinC_state_com &cinc_state);
|
||||
|
||||
response_type send_set_modulator_settings(modulator_settings_com &settings);
|
||||
response_type send_set_demodulator_settings(demodulator_settings_com &settings);
|
||||
response_type send_get_modulator_settings(modulator_settings_com &settings);
|
||||
response_type send_get_demodulator_settings(demodulator_settings_com &settings);
|
||||
|
||||
response_type send_set_buc_lnb_settings(buc_lnb_settings_com &settings);
|
||||
response_type send_get_buc_lnb_settings(buc_lnb_settings_com &settings);
|
||||
|
||||
response_type send_set_dpdi_params(dpdi_parameters &dpdi_params);
|
||||
response_type send_get_dpdi_params(dpdi_parameters &dpdi_params);
|
||||
|
||||
@@ -56,6 +70,8 @@ public:
|
||||
response_type send_set_qos_params(const std::string &node, const name_classes_qos & class_qos);
|
||||
response_type send_get_qos_params(std::string &node, const name_classes_qos & class_qos);
|
||||
|
||||
response_type send_set_qos_settings_json(const std::string &json_string, bool is_enable);
|
||||
response_type send_get_qos_settings_json(std::string &json_string, bool &is_enable);
|
||||
|
||||
void set_stdout_callback(std::function<void(const char *, uint32_t)> cb);
|
||||
void abort();
|
||||
|
@@ -47,6 +47,95 @@ enum class cmd_dma_debugg
|
||||
begin_save_config = 17
|
||||
};
|
||||
|
||||
struct modulator_settings_com{
|
||||
uint32_t baudrate;
|
||||
double central_freq_in_kGz;
|
||||
double rollof;
|
||||
double attenuation;
|
||||
bool is_test_data;
|
||||
bool is_save_current_state;
|
||||
bool is_carrier;
|
||||
bool tx_is_on;
|
||||
bool is_cinc;
|
||||
uint32_t modcod_tx;
|
||||
};
|
||||
|
||||
struct modulator_state_com{
|
||||
bool is_tx_on;
|
||||
float snr_remote;
|
||||
uint16_t modcod;
|
||||
bool is_short;
|
||||
bool is_pilots;
|
||||
uint32_t speed_in_bytes_tx;
|
||||
uint32_t speed_in_bytes_tx_iface;
|
||||
};
|
||||
|
||||
struct demodulator_locks_com{
|
||||
bool pkt_sync;
|
||||
bool afc_lock;
|
||||
bool freq_lock;
|
||||
bool sym_sync_lock;
|
||||
};
|
||||
|
||||
struct demodulator_settings_com
|
||||
{
|
||||
uint32_t baudrate;
|
||||
double central_freq_in_kGz;
|
||||
double rollof;
|
||||
bool is_aru_on;
|
||||
bool is_rvt_iq;
|
||||
double gain;
|
||||
};
|
||||
|
||||
struct demodulator_state_com{
|
||||
float snr;
|
||||
uint16_t modcod;
|
||||
bool is_short;
|
||||
bool is_pilots;
|
||||
float rssi;
|
||||
double afc_err;
|
||||
double crs_freq_err;
|
||||
double sym_err;
|
||||
double fine_freq_err;
|
||||
double if_overload;
|
||||
uint32_t packet_ok_cnt;
|
||||
uint32_t packet_bad_cnt;;
|
||||
uint32_t dummy_cnt;
|
||||
uint32_t speed_in_bytes_rx;
|
||||
uint32_t speed_in_bytes_rx_iface;
|
||||
demodulator_locks_com locks;
|
||||
};
|
||||
|
||||
struct CinC_state_com{
|
||||
float ratio_signal_signal;
|
||||
bool carrier_lock;
|
||||
int32_t freq_error_offset;
|
||||
uint32_t delay_dpdi;
|
||||
int32_t freq_fine_estimate;
|
||||
uint32_t cnt_bad_lock;
|
||||
};
|
||||
|
||||
struct device_state_com{
|
||||
double adrv_temp;
|
||||
double zynq_temp;
|
||||
double pl_temp;
|
||||
};
|
||||
|
||||
enum class voltage_lnb_com{
|
||||
DISABLE = 0, _13V, _18V, _24V
|
||||
};
|
||||
enum class voltage_buc_com{
|
||||
DISABLE = 0, _24V, _48V
|
||||
};
|
||||
struct buc_lnb_settings_com
|
||||
{
|
||||
voltage_lnb_com lnb;
|
||||
bool is_ref_10MHz_lnb = false;
|
||||
voltage_buc_com buc;
|
||||
bool is_ref_10MHz_buc = false;
|
||||
bool is_ref_10MHz_output = false;
|
||||
bool is_save_current_state = false;
|
||||
};
|
||||
enum class name_classes_qos
|
||||
{
|
||||
realtime1 = 0,
|
||||
@@ -292,7 +381,19 @@ enum class cmd_type
|
||||
get_network = 27,
|
||||
set_qos_settings = 28,
|
||||
get_qos_settings = 29,
|
||||
set_lbq_params = 30
|
||||
set_lbq_params = 30,
|
||||
get_demodulator_state = 31,
|
||||
get_modulator_state = 32,
|
||||
get_cinc_state = 33,
|
||||
get_device_state = 34,
|
||||
set_modulator_settings = 35,
|
||||
set_demodulator_settings = 36,
|
||||
get_modulator_settings = 37,
|
||||
get_demodulator_settings = 38,
|
||||
set_lnb_buc_settings = 39,
|
||||
get_lnb_buc_settings = 40,
|
||||
set_qos_settings_json = 41,
|
||||
get_qos_settings_json = 42
|
||||
};
|
||||
|
||||
struct cmd_lbq_params
|
||||
@@ -306,6 +407,91 @@ struct cmd_lbq_params
|
||||
}
|
||||
};
|
||||
|
||||
struct cmd_lnb_buc_settings{
|
||||
buc_lnb_settings_com buc_lnb;
|
||||
template<class Archive>
|
||||
void serialize(Archive & archive)
|
||||
{
|
||||
archive(buc_lnb.buc, buc_lnb.is_ref_10MHz_buc, buc_lnb.lnb,buc_lnb.is_ref_10MHz_lnb, buc_lnb.is_ref_10MHz_output, buc_lnb.is_save_current_state);
|
||||
}
|
||||
};
|
||||
|
||||
struct cmd_get_cinc_state
|
||||
{
|
||||
CinC_state_com cinc_state;
|
||||
template<class Archive>
|
||||
void serialize(Archive & archive)
|
||||
{
|
||||
archive(cinc_state.carrier_lock, cinc_state.cnt_bad_lock,
|
||||
cinc_state.delay_dpdi, cinc_state.freq_error_offset,
|
||||
cinc_state.freq_fine_estimate,
|
||||
cinc_state.ratio_signal_signal);
|
||||
}
|
||||
};
|
||||
|
||||
struct cmd_get_device_state
|
||||
{
|
||||
device_state_com device_state;
|
||||
template<class Archive>
|
||||
void serialize(Archive & archive)
|
||||
{
|
||||
archive(device_state.adrv_temp, device_state.pl_temp, device_state.zynq_temp);
|
||||
}
|
||||
};
|
||||
|
||||
struct cmd_demodulator_settings
|
||||
{
|
||||
demodulator_settings_com demodulator_settings;
|
||||
|
||||
template<class Archive>
|
||||
void serialize(Archive & archive)
|
||||
{
|
||||
archive(demodulator_settings.baudrate,demodulator_settings.central_freq_in_kGz,
|
||||
demodulator_settings.gain, demodulator_settings.is_aru_on,
|
||||
demodulator_settings.is_rvt_iq, demodulator_settings.rollof);
|
||||
}
|
||||
};
|
||||
|
||||
struct cmd_get_demodulator_state
|
||||
{
|
||||
demodulator_state_com demodulator_state;
|
||||
template<class Archive>
|
||||
void serialize(Archive & archive)
|
||||
{
|
||||
archive(demodulator_state.snr, demodulator_state.modcod, demodulator_state.is_short, demodulator_state.is_pilots,
|
||||
demodulator_state.rssi, demodulator_state.afc_err, demodulator_state.crs_freq_err,
|
||||
demodulator_state.sym_err, demodulator_state.fine_freq_err, demodulator_state.if_overload,
|
||||
demodulator_state.packet_ok_cnt, demodulator_state.packet_bad_cnt, demodulator_state.dummy_cnt,
|
||||
demodulator_state.speed_in_bytes_rx, demodulator_state.speed_in_bytes_rx_iface,
|
||||
demodulator_state.locks.afc_lock, demodulator_state.locks.freq_lock, demodulator_state.locks.pkt_sync, demodulator_state.locks.sym_sync_lock );
|
||||
}
|
||||
};
|
||||
|
||||
struct cmd_modulator_settings
|
||||
{
|
||||
modulator_settings_com modulator_settings;
|
||||
|
||||
template<class Archive>
|
||||
void serialize(Archive & archive)
|
||||
{
|
||||
archive(modulator_settings.attenuation,modulator_settings.baudrate, modulator_settings.central_freq_in_kGz,
|
||||
modulator_settings.is_carrier, modulator_settings.is_cinc,
|
||||
modulator_settings.is_save_current_state, modulator_settings.is_test_data,
|
||||
modulator_settings.rollof, modulator_settings.tx_is_on, modulator_settings.modcod_tx);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
struct cmd_get_modulator_state{
|
||||
modulator_state_com modulator_state;
|
||||
template<class Archive>
|
||||
void serialize(Archive & archive)
|
||||
{
|
||||
archive(modulator_state.snr_remote, modulator_state.modcod, modulator_state.is_short, modulator_state.is_pilots,
|
||||
modulator_state.is_tx_on, modulator_state.speed_in_bytes_tx, modulator_state.speed_in_bytes_tx_iface);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct cmd_get_network
|
||||
{
|
||||
@@ -382,7 +568,15 @@ struct cmd_get_acm_param
|
||||
archive(enable, max_attenuation, max_modcod, min_attenuation, min_modcod, snr_treashold, enable_auto_atten, snr_treashold_acm, period_pack);
|
||||
}
|
||||
};
|
||||
|
||||
struct cmd_qos_settings{
|
||||
std::string json_string;
|
||||
bool is_enable;
|
||||
template<class Archive>
|
||||
void serialize(Archive & archive)
|
||||
{
|
||||
archive(json_string, is_enable);
|
||||
}
|
||||
};
|
||||
struct cmd_set_qos_settings
|
||||
{
|
||||
std::string node;
|
||||
|
76
dependencies/control_system/example-get-statistics.cpp
vendored
Normal file
76
dependencies/control_system/example-get-statistics.cpp
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
#include "include/terminal_api/ControlProtoCInterface.h"
|
||||
#include <iostream>
|
||||
int main()
|
||||
{
|
||||
TSID sid{0};
|
||||
unsigned int access{0};
|
||||
if(CP_Login("admin","pass",&sid,&access) == OK)
|
||||
{
|
||||
std::cout << "Succsec" << std::endl;
|
||||
}
|
||||
CinC_state state_cinc;
|
||||
state_cinc.carrier_lock = false;
|
||||
CP_GetCinCState(sid,state_cinc);
|
||||
std::cout << state_cinc.carrier_lock << std::endl;
|
||||
std::cout << state_cinc.freq_error_offset << std::endl;
|
||||
std::cout << state_cinc.delay_dpdi << std::endl;
|
||||
std::cout << state_cinc.cnt_bad_lock << std::endl;
|
||||
modulator_state modulator;
|
||||
CP_GetModulatorState(sid, modulator);
|
||||
std::cout << modulator.is_pilots << "\n"
|
||||
<< modulator.modcod << "\n"
|
||||
<< modulator.snr_remote << "\n";
|
||||
demodulator_state demodulator;
|
||||
demodulator.dummy_cnt = 11111;
|
||||
CP_GetDemodulatorState(sid, demodulator);
|
||||
std::cout << "end CP_GetDemodulatorState" << std::endl;
|
||||
std::cout << demodulator.is_short << std::endl;
|
||||
std::cout << demodulator.modcod << std::endl;
|
||||
std::cout << "afc_lock: " <<demodulator.locks.afc_lock << std::endl;
|
||||
std::cout << "sym_sync_lock: " <<demodulator.locks.sym_sync_lock << std::endl;
|
||||
std::cout << "freq_lock: " <<demodulator.locks.freq_lock << std::endl;
|
||||
std::cout << "pkt_sync: " << demodulator.locks.pkt_sync << std::endl;
|
||||
modulator_settings setting_modulator;
|
||||
setting_modulator.baudrate = 2000000;
|
||||
setting_modulator.central_freq_in_kGz = 1340000.24;
|
||||
setting_modulator.rollof = 0.25;
|
||||
setting_modulator.tx_is_on = true;
|
||||
setting_modulator.is_test_data = false;
|
||||
setting_modulator.is_save_current_state = true;
|
||||
setting_modulator.is_cinc = false;
|
||||
setting_modulator.is_carrier = true;
|
||||
CP_SetModulatorSettings(sid, setting_modulator);
|
||||
demodulator_settings demodulator_sett;
|
||||
demodulator_sett.baudrate = 1340000;
|
||||
demodulator_sett.central_freq_in_kGz = 2400000.34;
|
||||
demodulator_sett.is_rvt_iq = true;
|
||||
demodulator_sett.is_aru_on = true;
|
||||
demodulator_sett.gain = 13;
|
||||
demodulator_sett.rollof = 0.15;
|
||||
if(CP_SetDemodulatorSettings(sid, demodulator_sett)== OK)
|
||||
{
|
||||
std::cout << "OK SET DEMODULATOR SETTINGS" << std::endl;
|
||||
}
|
||||
demodulator_settings demodulator_settings_;
|
||||
if(CP_GetDemodulatorSettings(sid,demodulator_settings_) == OK)
|
||||
{
|
||||
std::cout << "OK GET DEMODULATOR SETTINGS" << std::endl;
|
||||
std::cout << demodulator_settings_.baudrate << std::endl;
|
||||
std::cout << demodulator_settings_.gain<< std::endl;
|
||||
std::cout << demodulator_settings_.rollof << std::endl;
|
||||
std::cout << demodulator_settings_.is_aru_on << std::endl;
|
||||
std::cout << demodulator_settings_.is_rvt_iq << std::endl;
|
||||
std::cout << demodulator_settings_.central_freq_in_kGz << std::endl;
|
||||
}
|
||||
modulator_settings modulator_settings_;
|
||||
if(CP_GetModulatorSettings(sid,modulator_settings_)== OK)
|
||||
{
|
||||
std::cout << "OK GET MODULATOR SETTINGS" << std::endl;
|
||||
std::cout << modulator_settings_.baudrate << std::endl;
|
||||
std::cout << modulator_settings_.attenuation << std::endl;
|
||||
std::cout << modulator_settings_.central_freq_in_kGz << std::endl;
|
||||
std::cout << modulator_settings_.is_carrier << std::endl;
|
||||
std::cout << modulator_settings_.is_cinc << std::endl;
|
||||
std::cout << modulator_settings_.rollof << std::endl;
|
||||
}
|
||||
}
|
@@ -1,14 +1,14 @@
|
||||
#ifndef __CONTROL_PROTO_COMMANDS__
|
||||
#define __CONTROL_PROTO_COMMANDS__
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#ifdef __cplusplus
|
||||
#include <cstdint>
|
||||
#define EXTERNC extern "C"
|
||||
#else
|
||||
#include <stdint.h>
|
||||
#define EXTERNC extern
|
||||
#endif
|
||||
|
||||
@@ -75,6 +75,111 @@ LO -- lo frequency
|
||||
*/
|
||||
EXTERNC CP_Result CP_ModulatorParams(TSID sid, const char *modulator_param, uint32_t value);
|
||||
|
||||
struct modulator_state{
|
||||
bool is_tx_on;
|
||||
float snr_remote;
|
||||
uint16_t modcod;
|
||||
bool is_short;
|
||||
bool is_pilots;
|
||||
uint32_t speed_in_bytes_tx;
|
||||
uint32_t speed_in_bytes_tx_iface;
|
||||
};
|
||||
EXTERNC CP_Result CP_GetModulatorState(TSID sid, modulator_state &state);
|
||||
|
||||
struct demodulator_locks{
|
||||
bool pkt_sync;
|
||||
bool afc_lock;
|
||||
bool freq_lock;
|
||||
bool sym_sync_lock;
|
||||
};
|
||||
struct demodulator_state{
|
||||
float snr;
|
||||
uint16_t modcod;
|
||||
bool is_short;
|
||||
bool is_pilots;
|
||||
float rssi;
|
||||
double afc_err;
|
||||
double crs_freq_err;
|
||||
double sym_err;
|
||||
double fine_freq_err;
|
||||
double if_overload;
|
||||
uint32_t packet_ok_cnt;
|
||||
uint32_t packet_bad_cnt;
|
||||
uint32_t dummy_cnt;
|
||||
uint32_t speed_in_bytes_rx;
|
||||
uint32_t speed_in_bytes_rx_iface;
|
||||
demodulator_locks locks;
|
||||
};
|
||||
EXTERNC CP_Result CP_GetDemodulatorState(TSID sid, demodulator_state &state);
|
||||
|
||||
struct CinC_state{
|
||||
float ratio_signal_signal;
|
||||
bool carrier_lock;
|
||||
int32_t freq_error_offset;
|
||||
uint32_t delay_dpdi;
|
||||
int32_t freq_fine_estimate;
|
||||
uint32_t cnt_bad_lock;
|
||||
};
|
||||
EXTERNC CP_Result CP_GetCinCState(TSID sid, CinC_state &state);
|
||||
|
||||
struct device_state{
|
||||
double adrv_temp;
|
||||
double zynq_temp;
|
||||
double pl_temp;
|
||||
};
|
||||
EXTERNC CP_Result CP_GetDeviceState(TSID sid, device_state &state);
|
||||
|
||||
struct modulator_settings{
|
||||
uint32_t baudrate;
|
||||
double central_freq_in_kGz;
|
||||
double rollof;
|
||||
double attenuation;
|
||||
bool is_test_data;
|
||||
bool is_save_current_state;
|
||||
bool is_carrier;
|
||||
bool tx_is_on;
|
||||
bool is_cinc;
|
||||
uint32_t modcod_tx;
|
||||
};
|
||||
|
||||
EXTERNC CP_Result CP_SetModulatorSettings(TSID sid, modulator_settings& settings);
|
||||
EXTERNC CP_Result CP_GetModulatorSettings(TSID sid, modulator_settings& settings);
|
||||
|
||||
struct demodulator_settings
|
||||
{
|
||||
uint32_t baudrate;
|
||||
double central_freq_in_kGz;
|
||||
double rollof;
|
||||
bool is_aru_on;
|
||||
bool is_rvt_iq;
|
||||
double gain;
|
||||
};
|
||||
|
||||
EXTERNC CP_Result CP_SetDemodulatorSettings(TSID sid, demodulator_settings& settings);
|
||||
EXTERNC CP_Result CP_GetDemodulatorSettings(TSID sid, demodulator_settings& settings);
|
||||
|
||||
enum class voltage_lnb{
|
||||
DISABLE = 0, _13V, _18V, _24V
|
||||
};
|
||||
enum class voltage_buc{
|
||||
DISABLE = 0, _24V, _48V
|
||||
};
|
||||
struct buc_lnb_settings
|
||||
{
|
||||
voltage_lnb lnb;
|
||||
bool is_ref_10MHz_lnb = false;
|
||||
voltage_buc buc;
|
||||
bool is_ref_10MHz_buc = false;
|
||||
bool is_ref_10MHz_output = false;
|
||||
bool is_save_current_state = false;
|
||||
};
|
||||
|
||||
EXTERNC CP_Result CP_SetBUC_LNB_settings(TSID sid, buc_lnb_settings &settings);
|
||||
EXTERNC CP_Result CP_GetBUC_LNB_settings(TSID sid, buc_lnb_settings &settings);
|
||||
|
||||
EXTERNC CP_Result CP_SetQoSSettings(TSID sid, const std::string &qos_settings_json, bool is_enable);
|
||||
EXTERNC CP_Result CP_GetQoSSettings(TSID sid, std::string &qos_settings_json, bool &is_enable);
|
||||
|
||||
EXTERNC CP_Result CP_GetModulatorParams(TSID sid, const char *modulator_param, uint32_t *value);
|
||||
|
||||
EXTERNC CP_Result CP_GetDemodulatorParams(TSID sid, const char *demodulator_param, uint32_t *value);
|
||||
|
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,
|
@@ -1,5 +1,80 @@
|
||||
//
|
||||
// Created by vlad on 04.11.2024.
|
||||
//
|
||||
|
||||
#include "jwt.h"
|
||||
#include <random>
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
std::string http::auth::jwt::secretKey;
|
||||
|
||||
void http::auth::jwt::generateSecretKey() {
|
||||
secretKey.clear();
|
||||
|
||||
std::random_device rd;
|
||||
std::mt19937 generator(rd());
|
||||
std::uniform_int_distribution<> distribution('!', '~');
|
||||
for (size_t i = 0; i < 32; ++i) {
|
||||
secretKey += static_cast<char>(distribution(generator));
|
||||
}
|
||||
}
|
||||
|
||||
// payload, signature
|
||||
static std::pair<std::string, std::string> parseJwtFromCookie(const std::string& input) {
|
||||
std::string val1, val2;
|
||||
size_t dotPos = input.find('.');
|
||||
|
||||
// Если точка найдена
|
||||
if (dotPos != std::string::npos) {
|
||||
val1 = input.substr(0, dotPos);
|
||||
|
||||
// Если в val1 есть еще точки, нужно найти последнюю точку
|
||||
size_t lastDotPos = val1.find_last_of('.');
|
||||
if (lastDotPos != std::string::npos) {
|
||||
val1 = val1.substr(0, lastDotPos + 1);
|
||||
}
|
||||
|
||||
val2 = input.substr(dotPos + 1);
|
||||
} else {
|
||||
// Точка не найдена, val1 - вся строка
|
||||
val1 = input;
|
||||
}
|
||||
|
||||
return std::make_pair(http::utils::b64Decode(val1), val2);
|
||||
}
|
||||
|
||||
http::auth::jwt::Jwt http::auth::jwt::Jwt::fromCookies(const std::string &cookie) {
|
||||
auto pc = utils::parseCookies(cookie);
|
||||
Jwt t;
|
||||
if (pc.find("auth") != pc.end()) {
|
||||
auto tmp = parseJwtFromCookie(pc.at("auth"));
|
||||
t.payload = tmp.first;
|
||||
t.signature = tmp.second;
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
http::auth::jwt::Jwt http::auth::jwt::Jwt::fromUser(const std::string &user) {
|
||||
Jwt t;
|
||||
t.payload = user;
|
||||
return t;
|
||||
}
|
||||
|
||||
bool http::auth::jwt::Jwt::isValid() {
|
||||
if (payload.empty() || signature.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto realSignature = utils::sha256(this->payload + secretKey);
|
||||
return signature == realSignature;
|
||||
}
|
||||
|
||||
std::string http::auth::jwt::Jwt::getUsername() {
|
||||
return payload;
|
||||
}
|
||||
|
||||
std::string http::auth::jwt::Jwt::asCookie() {
|
||||
signature = utils::sha256(this->payload + secretKey);
|
||||
auto val = utils::b64Encode(payload) + "." + signature;
|
||||
return "auth=" + val + ";Path=/; Max-Age=86400; HttpOnly; SameSite=Lax";
|
||||
}
|
||||
|
||||
http::auth::jwt::Jwt::~Jwt() = default;
|
||||
|
@@ -4,10 +4,22 @@
|
||||
#include "resources.h"
|
||||
|
||||
namespace http::auth::jwt {
|
||||
extern std::string secretKey;
|
||||
|
||||
constexpr const char* EMPTY_AUTH_COOKIE = "auth=;Path=/; Max-Age=86400; HttpOnly; SameSite=Lax";;
|
||||
|
||||
void generateSecretKey();
|
||||
|
||||
/**
|
||||
* Упрощенная реализация JWT (Json Web Token). Токен имеет вид: `{ username | base64 }.{ signature | base64 }`.
|
||||
* Сигнатура вычисляется следующим образом: `SHA256(username + secret)`.
|
||||
* Имя cookie: `auth`.
|
||||
*/
|
||||
class Jwt {
|
||||
std::string payload;
|
||||
std::string signature;
|
||||
public:
|
||||
static Jwt fromCookies(const std::string& cookie);
|
||||
static Jwt fromString(const std::string& cookie);
|
||||
static Jwt fromUser(const std::string& User);
|
||||
|
||||
bool isValid();
|
||||
|
@@ -1,15 +1,98 @@
|
||||
//
|
||||
// Created by vlad on 31.10.2024.
|
||||
//
|
||||
|
||||
#include "resources.h"
|
||||
|
||||
#include <boost/log/trivial.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <utility>
|
||||
#include "jwt.h"
|
||||
#include "utils.h"
|
||||
|
||||
// http::auth::AuentificationRequiredResource::AuentificationRequiredResource(const std::string &path, AuthProvider& provider, resource::respGenerator generator): BasicResource(path), generator_(std::move(generator)) {
|
||||
// }
|
||||
//
|
||||
// void http::auth::AuentificationRequiredResource::handle(const server::Request &req, server::Reply &rep) {
|
||||
// }
|
||||
//
|
||||
// http::auth::AuentificationRequiredResource::~AuentificationRequiredResource() = default;
|
||||
|
||||
http::auth::User::User(const std::string &username, const std::string &passwordHash): username(username),
|
||||
passwordHash(passwordHash.empty() ? utils::sha256(username) : passwordHash) {}
|
||||
|
||||
http::auth::User::User(const std::string &username, const std::string &passwordHash, uint32_t perms): perms(perms),
|
||||
username(username), passwordHash(passwordHash.empty() ? utils::sha256(username) : passwordHash) {}
|
||||
|
||||
bool http::auth::User::checkPassword(const std::string &pass) const {
|
||||
return utils::sha256(pass) == passwordHash;
|
||||
}
|
||||
|
||||
void http::auth::User::setPassword(const std::string &pass) {
|
||||
this->passwordHash = utils::sha256(pass);
|
||||
}
|
||||
|
||||
bool http::auth::User::checkPremisions(uint32_t p) const {
|
||||
if (this->perms & SUPERUSER) {
|
||||
return true;
|
||||
}
|
||||
return (this->perms & p) == p;
|
||||
}
|
||||
|
||||
void http::auth::User::setPremisions(uint32_t p) {
|
||||
if (p & SUPERUSER) {
|
||||
this->perms = SUPERUSER;
|
||||
} else {
|
||||
this->perms |= p;
|
||||
}
|
||||
}
|
||||
|
||||
void http::auth::User::resetPremisions(uint32_t p) {
|
||||
this->perms &= p;
|
||||
}
|
||||
|
||||
http::auth::User::~User() = default;
|
||||
|
||||
|
||||
http::auth::AuthProvider::AuthProvider() = default;
|
||||
|
||||
std::shared_ptr<http::auth::User> http::auth::AuthProvider::doAuth(const std::string &username, const std::string &password, server::Reply &rep) {
|
||||
for (const auto& u: users) {
|
||||
if (u->username == username) {
|
||||
if (u->checkPassword(password)) {
|
||||
auto t = jwt::Jwt::fromUser(u->username);
|
||||
rep.headers.push_back({.name = "Set-Cookie", .value = t.asCookie()});
|
||||
return u;
|
||||
}
|
||||
BOOST_LOG_TRIVIAL(warning) << "http::auth::AuthProvider::doAuth(): Failed to login " << username << ", password: " << password << " (incorrect password)";
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
BOOST_LOG_TRIVIAL(warning) << "http::auth::AuthProvider::doAuth(): Failed to login " << username << ", password: " << password << " (user not found)";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<http::auth::User> http::auth::AuthProvider::getSession(const server::Request &req) {
|
||||
auto t = jwt::Jwt::fromCookies(req.getHeaderValue("cookie"));
|
||||
if (t.isValid()) {
|
||||
const auto name = t.getUsername();
|
||||
// токен валидный, ищем юзера
|
||||
for (auto& u: users) {
|
||||
if (u->username == name) {
|
||||
return u;
|
||||
}
|
||||
}
|
||||
BOOST_LOG_TRIVIAL(warning) << "http::auth::AuthProvider::getSession(): Found valid session for a non-existent user " << name;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
http::auth::AuthProvider::~AuthProvider() = default;
|
||||
|
||||
http::auth::AuthRequiredResource::AuthRequiredResource(const std::string &path, AuthProvider& provider, resource::respGenerator generator):
|
||||
BasicResource(path), provider_(provider), generator_(std::move(generator)), perms(User::SUPERUSER) {}
|
||||
|
||||
http::auth::AuthRequiredResource::AuthRequiredResource(const std::string &path, AuthProvider& provider, uint32_t perms, resource::respGenerator generator):
|
||||
BasicResource(path), provider_(provider), generator_(std::move(generator)), perms(perms) {}
|
||||
|
||||
void http::auth::AuthRequiredResource::handle(const server::Request &req, server::Reply &rep) {
|
||||
if (auto user = this->provider_.getSession(req)) {
|
||||
if (user->checkPremisions(this->perms)) {
|
||||
this->generator_(req, rep);
|
||||
return;
|
||||
}
|
||||
stockReply(server::forbidden, rep);
|
||||
} else {
|
||||
stockReply(server::unauthorized, rep);
|
||||
}
|
||||
}
|
||||
|
||||
http::auth::AuthRequiredResource::~AuthRequiredResource() = default;
|
||||
|
@@ -9,20 +9,33 @@ namespace http::auth {
|
||||
*/
|
||||
class User {
|
||||
private:
|
||||
uint32_t perms;
|
||||
uint32_t perms{};
|
||||
|
||||
public:
|
||||
const std::string username;
|
||||
std::string passwordHash;
|
||||
|
||||
User(const std::string& username, const std::string& passwordHash);
|
||||
/**
|
||||
* Конструктор пользователя. По-умолчанию пользователь создается без прав, их нужно задать отдельной функцией.
|
||||
* @param username Имя пользователя, он же - логин.
|
||||
* @param passwordHash Хеш sha256 пароля пользователя. Если передать пустой, то пароль будет сгенерирован такой же, как и имя пользователя.
|
||||
*/
|
||||
explicit User(const std::string& username, const std::string& passwordHash = "");
|
||||
|
||||
/**
|
||||
* Конструктор пользователя с указанными правами. Аналогично первому конструктору.
|
||||
* @param username Имя пользователя, он же - логин.
|
||||
* @param passwordHash Хеш sha256 пароля пользователя. Если передать пустой, то пароль будет сгенерирован такой же, как и имя пользователя.
|
||||
* @param perms Права пользователя
|
||||
*/
|
||||
explicit User(const std::string& username, const std::string& passwordHash, uint32_t perms);
|
||||
|
||||
/**
|
||||
* Проверить пароль на соответствие хешу
|
||||
* @param pass
|
||||
* @return
|
||||
*/
|
||||
bool checkPassword(const std::string& pass);
|
||||
bool checkPassword(const std::string& pass) const;
|
||||
|
||||
/**
|
||||
* Установка пароля
|
||||
@@ -37,13 +50,14 @@ namespace http::auth {
|
||||
static constexpr uint32_t WATCH_SETTINGS = 0x0008; // просмотр настроек , если недоступно, то вкладки с настройками не будет
|
||||
static constexpr uint32_t EDIT_SETTINGS = 0x0010; // редактирование настроек, установка параметров модулятора/демодулятора/dma/cinc
|
||||
static constexpr uint32_t UPDATE_FIRMWARE = 0x0020; // обновление прошивки
|
||||
static constexpr uint32_t SETUP_QOS = 0x0040; // управление профилем QoS
|
||||
|
||||
/**
|
||||
* Проверить, что у пользователя есть нужное право. Если это суперпользователь, то у него по умолчанию все права есть.
|
||||
* @param p набор прав, из констант данного класса.
|
||||
* @return
|
||||
*/
|
||||
bool checkPremisions(uint32_t p);
|
||||
bool checkPremisions(uint32_t p) const;
|
||||
|
||||
void setPremisions(uint32_t p);
|
||||
void resetPremisions(uint32_t p);
|
||||
@@ -65,24 +79,28 @@ namespace http::auth {
|
||||
* @param rep
|
||||
* @return true, в случае успешной авторизации
|
||||
*/
|
||||
bool doAuth(const std::string& username, const std::string& password, server::Reply& rep);
|
||||
std::shared_ptr<http::auth::User> doAuth(const std::string &username, const std::string &password, server::Reply &rep);
|
||||
|
||||
std::shared_ptr<User> getSession(server::Request& req);
|
||||
std::vector<std::shared_ptr<User>> users;
|
||||
|
||||
std::shared_ptr<User> getSession(const server::Request &req);
|
||||
|
||||
~AuthProvider();
|
||||
};
|
||||
|
||||
class AuentificationRequiredResource final: public resource::BasicResource {
|
||||
class AuthRequiredResource final: public resource::BasicResource {
|
||||
public:
|
||||
explicit AuentificationRequiredResource(const std::string& path, std::shared_ptr<AuthProvider> provider, resource::respGenerator generator);
|
||||
explicit AuthRequiredResource(const std::string& path, AuthProvider& provider, resource::respGenerator generator);
|
||||
explicit AuthRequiredResource(const std::string& path, AuthProvider& provider, uint32_t perms, resource::respGenerator generator);
|
||||
|
||||
void handle(const server::Request &req, server::Reply &rep) override;
|
||||
|
||||
~AuentificationRequiredResource() override;
|
||||
~AuthRequiredResource() override;
|
||||
|
||||
private:
|
||||
AuthProvider& provider_;
|
||||
resource::respGenerator generator_;
|
||||
std::shared_ptr<AuthProvider> provider_;
|
||||
uint32_t perms;
|
||||
};
|
||||
}
|
||||
|
||||
|
128
src/auth/utils.cpp
Normal file
128
src/auth/utils.cpp
Normal file
@@ -0,0 +1,128 @@
|
||||
#include "utils.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <openssl/sha.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/buffer.h>
|
||||
#include <string>
|
||||
#include <iomanip>
|
||||
|
||||
|
||||
std::string http::utils::sha256(const std::string &payload) {
|
||||
return sha256(payload.c_str(), payload.size());
|
||||
}
|
||||
|
||||
std::string http::utils::sha256(const char* data, size_t size) {
|
||||
unsigned char hash[SHA256_DIGEST_LENGTH];
|
||||
SHA256(reinterpret_cast<const unsigned char *>(data), size, hash);
|
||||
|
||||
// Преобразуем хеш в шестнадцатеричную строку
|
||||
std::stringstream ss;
|
||||
for (unsigned char i : hash) {
|
||||
ss << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(i);
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
inline std::string sha256AsB64(const std::string &payload) {
|
||||
// Вычисляем SHA256 хеш
|
||||
unsigned char hash[SHA256_DIGEST_LENGTH];
|
||||
SHA256(reinterpret_cast<const unsigned char *>(payload.c_str()), payload.length(), hash);
|
||||
return http::utils::b64Encode(reinterpret_cast<const char *>(hash), SHA256_DIGEST_LENGTH);
|
||||
}
|
||||
|
||||
static const char b64_table[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
|
||||
std::string http::utils::b64Encode(const char* data, size_t size) {
|
||||
using ::std::string;
|
||||
|
||||
// Use = signs so the end is properly padded.
|
||||
string retval((((size + 2) / 3) * 4), '=');
|
||||
::std::size_t outpos = 0;
|
||||
int bits_collected = 0;
|
||||
unsigned int accumulator = 0;
|
||||
|
||||
for (size_t index = 0; index < size; index++) {
|
||||
const char i = *(data + index);
|
||||
accumulator = (accumulator << 8) | (i & 0xff);
|
||||
bits_collected += 8;
|
||||
while (bits_collected >= 6) {
|
||||
bits_collected -= 6;
|
||||
retval[outpos++] = b64_table[(accumulator >> bits_collected) & 0x3fu];
|
||||
}
|
||||
}
|
||||
if (bits_collected > 0) {
|
||||
// Any trailing bits that are missing.
|
||||
assert(bits_collected < 6);
|
||||
accumulator <<= 6 - bits_collected;
|
||||
retval[outpos++] = b64_table[accumulator & 0x3fu];
|
||||
}
|
||||
assert(outpos >= (retval.size() - 2));
|
||||
assert(outpos <= retval.size());
|
||||
return retval;
|
||||
}
|
||||
|
||||
std::string http::utils::b64Encode(const std::string &payload) {
|
||||
return b64Encode(payload.c_str(), payload.size());
|
||||
}
|
||||
|
||||
std::string http::utils::b64Decode(const std::string &ascdata) {
|
||||
static const unsigned char reverse_table[128] = {
|
||||
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
|
||||
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
|
||||
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63,
|
||||
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64,
|
||||
64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
|
||||
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64,
|
||||
64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
|
||||
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64
|
||||
};
|
||||
|
||||
using ::std::string;
|
||||
string retval;
|
||||
int bits_collected = 0;
|
||||
unsigned int accumulator = 0;
|
||||
|
||||
for (const auto cd: ascdata) {
|
||||
const auto c = static_cast<int>(cd);
|
||||
if (::std::isspace(c) || c == '=') {
|
||||
// Skip whitespace and padding. Be liberal in what you accept.
|
||||
continue;
|
||||
}
|
||||
if ((c > 127) || (c < 0) || (reverse_table[c] > 63)) {
|
||||
throw ::std::invalid_argument("This contains characters not legal in a base64 encoded string.");
|
||||
}
|
||||
accumulator = (accumulator << 6) | reverse_table[c];
|
||||
bits_collected += 6;
|
||||
if (bits_collected >= 8) {
|
||||
bits_collected -= 8;
|
||||
retval += static_cast<char>((accumulator >> bits_collected) & 0xffu);
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
std::map<std::string, std::string> http::utils::parseCookies(const std::string& cookieString) {
|
||||
std::map<std::string, std::string> cookies;
|
||||
std::istringstream cookieStream(cookieString);
|
||||
|
||||
std::string cookie;
|
||||
while (std::getline(cookieStream, cookie, ';')) {
|
||||
// Разделяем имя и значение Cookie
|
||||
size_t equalPos = cookie.find('=');
|
||||
if (equalPos == std::string::npos) {
|
||||
continue; // Неверный формат Cookie
|
||||
}
|
||||
std::string name = cookie.substr(0, equalPos);
|
||||
std::string value = cookie.substr(equalPos + 1);
|
||||
|
||||
// Удаляем пробелы с начала и конца значения Cookie
|
||||
value.erase(0, value.find_first_not_of(' '));
|
||||
value.erase(value.find_last_not_of(' ') + 1);
|
||||
|
||||
// Добавляем Cookie в map
|
||||
cookies[name] = value;
|
||||
}
|
||||
|
||||
return cookies;
|
||||
}
|
19
src/auth/utils.h
Normal file
19
src/auth/utils.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#ifndef UTILS_H
|
||||
#define UTILS_H
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
namespace http::utils {
|
||||
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 b64Encode(const char* data, size_t size);
|
||||
std::string b64Encode(const std::string& payload);
|
||||
std::string b64Decode(const std::string& payload);
|
||||
|
||||
std::map<std::string, std::string> parseCookies(const std::string& cookieStrin);
|
||||
}
|
||||
|
||||
#endif //UTILS_H
|
422
src/main.cpp
422
src/main.cpp
@@ -11,16 +11,22 @@
|
||||
#include <boost/log/utility/setup/formatter_parser.hpp>
|
||||
#include <boost/asio/buffer.hpp>
|
||||
#include <boost/asio/ssl/context.hpp>
|
||||
#include <boost/property_tree/json_parser.hpp>
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <fstream>
|
||||
|
||||
#include "terminal_api_driver.h"
|
||||
#include "auth/resources.h"
|
||||
#include "auth/jwt.h"
|
||||
#include "auth/utils.h"
|
||||
|
||||
|
||||
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) {
|
||||
std::ifstream is(path, std::ios::in | std::ios::binary);
|
||||
@@ -76,77 +82,121 @@ void init_logging() {
|
||||
class ServerResources {
|
||||
std::unique_ptr<http::resource::StaticFileFactory> sf;
|
||||
std::unique_ptr<api_driver::ApiDriver> api;
|
||||
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:
|
||||
static constexpr const char* INDEX_HTML = "static/main.html";
|
||||
static constexpr const char* LOGIN_HTML = "static/login.html";
|
||||
static constexpr const char* LOGIN_FAILED_HTML = "static/login-failed.html";
|
||||
#if defined(MODEM_IS_TDMA)
|
||||
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* KROKODIL_GIF = "static/krokodil.gif";
|
||||
static constexpr const char* VUE_JS = "static/js/vue.js"; // это тоже можно кешировать
|
||||
static constexpr const char* FAVICON_ICO = "/favicon.ico";
|
||||
static constexpr const char* VUE_JS = "/js/vue.js"; // это тоже можно кешировать
|
||||
|
||||
// а эти стили нельзя кешировать в отладочной версии
|
||||
static constexpr const char* STYLE_CSS = "static/style.css";
|
||||
static constexpr const char* FIELDS_CSS = "static/fields.css";
|
||||
static constexpr const char* STYLE_CSS = "/style.css";
|
||||
static constexpr const char* FIELDS_CSS = "/fields.css";
|
||||
static constexpr const char* INTERNET_JPG = "/internet.jpg";
|
||||
|
||||
ServerResources(const ServerResources&) = delete;
|
||||
|
||||
ServerResources(): sf(std::make_unique<http::resource::StaticFileFactory>()), api(std::make_unique<api_driver::ApiDriver>()) {
|
||||
sf->registerFile(INDEX_HTML, mime_types::text_html, false);
|
||||
sf->registerFile(LOGIN_HTML, mime_types::text_html, false);
|
||||
sf->registerFile(LOGIN_FAILED_HTML, mime_types::text_html, false);
|
||||
explicit ServerResources(const std::string& staticFilesPath): sf(std::make_unique<http::resource::StaticFileFactory>()), api(std::make_unique<api_driver::ApiDriver>()) {
|
||||
api->startDaemon();
|
||||
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(KROKODIL_GIF, mime_types::image_gif, true);
|
||||
sf->registerFile(VUE_JS, mime_types::javascript, true);
|
||||
|
||||
#if USE_DEBUG
|
||||
constexpr bool allowCacheCss = false;
|
||||
#else
|
||||
constexpr bool allowCacheCss = true;
|
||||
#endif
|
||||
|
||||
sf->registerFile(STYLE_CSS, mime_types::text_css, allowCacheCss);
|
||||
sf->registerFile(FIELDS_CSS, mime_types::text_css, allowCacheCss);
|
||||
sf->registerFile(staticFilesPath + "/favicon.png", FAVICON_ICO, mime_types::image_png, true);
|
||||
sf->registerFile(staticFilesPath + VUE_JS, VUE_JS, mime_types::javascript, true);
|
||||
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);
|
||||
sf->registerFile(staticFilesPath + LOGIN_HTML, LOGIN_HTML, mime_types::text_html, true);
|
||||
sf->registerFile(staticFilesPath + INTERNET_JPG, INTERNET_JPG, mime_types::image_jpeg, true);
|
||||
}
|
||||
|
||||
void registerResources(http::server::Server& s) {
|
||||
s.resources.emplace_back(std::make_unique<http::resource::GenericResource>("/", [this](const auto& req, auto& rep) {
|
||||
boost::ignore_unused(req);
|
||||
sf->serve(INDEX_HTML, rep);
|
||||
auto user = auth.getSession(req);
|
||||
if (user == nullptr) {
|
||||
http::server::httpRedirect(rep, "/login");
|
||||
} else {
|
||||
sf->serve(INDEX_HTML, rep);
|
||||
}
|
||||
}));
|
||||
|
||||
s.resources.emplace_back(std::make_unique<http::resource::GenericResource>("/login", [this](const auto& req, auto& rep) {
|
||||
if (req.method == "GET") {
|
||||
sf->serve(LOGIN_HTML, rep);
|
||||
auto user = auth.getSession(req);
|
||||
if (user == nullptr) {
|
||||
sf->serve(LOGIN_HTML, rep);
|
||||
} else {
|
||||
http::server::httpRedirect(rep, "/");
|
||||
}
|
||||
} else if (req.method == "POST") {
|
||||
sf->serve(LOGIN_FAILED_HTML, rep);
|
||||
rep.status = http::server::ok;
|
||||
rep.headers.clear();
|
||||
rep.headers.push_back({.name = "Content-Type", .value = toString(mime_types::json)});
|
||||
try {
|
||||
std::istringstream is(std::string(req.payload.data(), req.payload.size()));
|
||||
boost::property_tree::ptree pt;
|
||||
read_json(is, pt);
|
||||
|
||||
auto u = auth.doAuth(pt.get<std::string>("username"), pt.get<std::string>("password"), rep);
|
||||
if (u == nullptr) {
|
||||
throw std::runtime_error("invalid session");
|
||||
}
|
||||
std::string result = R"({"redirect":"/"})";
|
||||
rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size());
|
||||
} catch (std::exception &e) {
|
||||
BOOST_LOG_TRIVIAL(error) << e.what() << std::endl;
|
||||
std::string result = R"({"error":"Неверный логин или пароль"})";
|
||||
rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size());
|
||||
}
|
||||
} else {
|
||||
http::server::stockReply(http::server::bad_request, rep);
|
||||
}
|
||||
}));
|
||||
s.resources.emplace_back(std::make_unique<http::resource::GenericResource>("/logout", [](const auto& req, auto& rep) {
|
||||
if (req.method == "GET") {
|
||||
http::server::httpRedirect(rep, "/login");
|
||||
rep.headers.push_back({.name = "Set-Cookie", .value = http::auth::jwt::EMPTY_AUTH_COOKIE});
|
||||
} else {
|
||||
http::server::stockReply(http::server::bad_request, 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>("/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>("/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>(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>(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>(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>("/api/statistics", [](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 char* json = R"({"key":"value"})";
|
||||
rep.content.insert(rep.content.end(), json, json + strlen(json));
|
||||
}));
|
||||
|
||||
s.resources.emplace_back(std::make_unique<http::resource::GenericResource>("/api/get/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") {
|
||||
http::server::stockReply(http::server::bad_request, rep);
|
||||
}
|
||||
@@ -156,11 +206,39 @@ public:
|
||||
rep.headers.push_back({.name = "Content-Type", .value = toString(mime_types::json)});
|
||||
std::string result = R"({"mainState":)";
|
||||
result += api->loadTerminalState();
|
||||
result += R"(,"sysinfo":)";
|
||||
result += api->loadSysInfo();
|
||||
result += "}";
|
||||
rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size());
|
||||
}));
|
||||
|
||||
s.resources.emplace_back(std::make_unique<http::resource::GenericResource>("/api/resetPacketStatistics", [this](const auto& req, auto& rep) {
|
||||
s.resources.emplace_back(std::make_unique<http::auth::AuthRequiredResource>("/api/get/settings", this->auth, http::auth::User::WATCH_SETTINGS, [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)});
|
||||
std::string result = R"({"settings":)";
|
||||
result += api->loadSettings();
|
||||
result += "}";
|
||||
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) {
|
||||
if (req.method != "POST") {
|
||||
http::server::stockReply(http::server::bad_request, rep);
|
||||
}
|
||||
@@ -173,18 +251,242 @@ public:
|
||||
rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size());
|
||||
}));
|
||||
|
||||
s.resources.emplace_back(std::make_unique<http::resource::GenericResource>("/api/get/settings", [this](const auto& req, auto& rep) {
|
||||
if (req.method != "GET") {
|
||||
s.resources.emplace_back(std::make_unique<http::auth::AuthRequiredResource>("/api/set/qos", this->auth, http::auth::User::SETUP_QOS, [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)});
|
||||
std::string result = R"({"settings":)";
|
||||
result += api->loadSettings();
|
||||
result += "}";
|
||||
|
||||
try {
|
||||
std::stringstream ss;
|
||||
ss.str(std::string(req.payload.begin(), req.payload.end()));
|
||||
boost::property_tree::ptree pt;
|
||||
read_json(ss, pt);
|
||||
|
||||
api->setQosSettings(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/qos): Can't set QoS 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/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);
|
||||
}
|
||||
|
||||
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->setBucLnbSettings(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/bucLnb): Can't set settings: " << e.what();
|
||||
const std::string result = R"({"status":"error"})";
|
||||
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) {
|
||||
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->setCincSettings(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/cinc): Can't set CinC settings: " << e.what();
|
||||
const std::string result = R"({"status":"error"})";
|
||||
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) {
|
||||
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->setRxTxSettings(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/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 += "\"}";
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -199,9 +501,9 @@ int main(int argc, char *argv[]) {
|
||||
if (argc != 4 && argc != 5) {
|
||||
std::cerr << "Usage: http_server <ssl|nossl> <address> <port> [static files directory]\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 << " receiver nossl 0::0 80\n";
|
||||
std::cerr << " receiver nossl 0::0 80 .\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -214,7 +516,17 @@ int main(int argc, char *argv[]) {
|
||||
BOOST_LOG_TRIVIAL(info) << "Starting RELEASE build" << argv[0];
|
||||
#endif
|
||||
|
||||
ServerResources resources;
|
||||
#ifdef USE_DEBUG
|
||||
http::auth::jwt::secretKey = "^}u'ZKyQ%;+:lnh^GS7!=G~nRK?7[{``";
|
||||
BOOST_LOG_TRIVIAL(info) << "DEBUG build use pre-created key " << http::auth::jwt::secretKey;
|
||||
#else
|
||||
http::auth::jwt::generateSecretKey();
|
||||
BOOST_LOG_TRIVIAL(info) << "Generated new secret key " << http::auth::jwt::secretKey;
|
||||
#endif
|
||||
|
||||
const std::string staticFilesPath = (argc == 5 ? argv[4]: ".");
|
||||
BOOST_LOG_TRIVIAL(info) << "Use static files path: " << staticFilesPath << "/";
|
||||
ServerResources resources(staticFilesPath);
|
||||
|
||||
// Initialise the server.
|
||||
std::unique_ptr<http::server::Server> s;
|
||||
|
@@ -13,6 +13,8 @@ namespace http::server {
|
||||
}
|
||||
|
||||
void Connection::start() {
|
||||
request_parser_.reset();
|
||||
request_.reset();
|
||||
doRead();
|
||||
}
|
||||
|
||||
@@ -23,14 +25,6 @@ namespace http::server {
|
||||
Connection::~Connection() = default;
|
||||
|
||||
void Connection::doRead() {
|
||||
request_parser_.reset();
|
||||
request_.headers.clear();
|
||||
request_.method.clear();
|
||||
request_.queryUri.clear();
|
||||
if (request_.url != nullptr) {
|
||||
request_.url.reset(nullptr);
|
||||
}
|
||||
|
||||
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) {
|
||||
if (!ec) {
|
||||
@@ -43,6 +37,7 @@ namespace http::server {
|
||||
doWrite();
|
||||
} else if (result == RequestParser::bad) {
|
||||
stockReply(bad_request, reply_);
|
||||
needClose = true;
|
||||
doWrite();
|
||||
} else {
|
||||
doRead();
|
||||
@@ -55,9 +50,7 @@ namespace http::server {
|
||||
|
||||
void Connection::doWrite() {
|
||||
reply_.headers.push_back({.name = "Server", .value = SERVER_HEADER_VALUE});
|
||||
if (!reply_.content.empty()) {
|
||||
reply_.headers.push_back({.name = "Content-Length", .value = std::to_string(reply_.content.size())});
|
||||
}
|
||||
reply_.headers.push_back({.name = "Content-Length", .value = std::to_string(reply_.content.size())});
|
||||
if (request_.http_version_major == 1) {
|
||||
reply_.headers.push_back({.name = "Connection", .value = "keep-alive"});
|
||||
}
|
||||
@@ -66,8 +59,10 @@ namespace http::server {
|
||||
|
||||
auto self(shared_from_this());
|
||||
async_write(socket_, reply_.to_buffers(), [this, self](boost::system::error_code ec, std::size_t) {
|
||||
if (!ec) {
|
||||
if (!ec && !needClose) {
|
||||
// keep alive Connection
|
||||
request_parser_.reset();
|
||||
request_.reset();
|
||||
doRead();
|
||||
} else {
|
||||
connection_manager_.stop(shared_from_this());
|
||||
@@ -81,6 +76,8 @@ namespace http::server {
|
||||
|
||||
void SslConnection::start() {
|
||||
get_lowest_layer(stream_).expires_after(std::chrono::seconds(30));
|
||||
request_parser_.reset();
|
||||
request_.reset();
|
||||
|
||||
// Perform the SSL handshake
|
||||
stream_.async_handshake(boost::asio::ssl::stream_base::server, boost::beast::bind_front_handler([this](auto ec) {
|
||||
@@ -90,6 +87,11 @@ namespace http::server {
|
||||
}
|
||||
|
||||
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;
|
||||
@@ -97,11 +99,6 @@ namespace http::server {
|
||||
void SslConnection::doRead() {
|
||||
get_lowest_layer(stream_).expires_after(std::chrono::seconds(30));
|
||||
|
||||
request_parser_.reset();
|
||||
request_.headers.clear();
|
||||
request_.method.clear();
|
||||
request_.queryUri.clear();
|
||||
|
||||
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) {
|
||||
if (!ec) {
|
||||
@@ -114,6 +111,7 @@ namespace http::server {
|
||||
doWrite();
|
||||
} else if (result == RequestParser::bad) {
|
||||
stockReply(bad_request, reply_);
|
||||
needClose = true;
|
||||
doWrite();
|
||||
} else {
|
||||
doRead();
|
||||
@@ -126,9 +124,7 @@ namespace http::server {
|
||||
|
||||
void SslConnection::doWrite() {
|
||||
reply_.headers.push_back({.name = "Server", .value = SERVER_HEADER_VALUE});
|
||||
if (!reply_.content.empty()) {
|
||||
reply_.headers.push_back({.name = "Content-Length", .value = std::to_string(reply_.content.size())});
|
||||
}
|
||||
reply_.headers.push_back({.name = "Content-Length", .value = std::to_string(reply_.content.size())});
|
||||
if (request_.http_version_major == 1) {
|
||||
reply_.headers.push_back({.name = "Connection", .value = "keep-alive"});
|
||||
}
|
||||
@@ -137,8 +133,10 @@ namespace http::server {
|
||||
|
||||
auto self(shared_from_this());
|
||||
async_write(stream_, reply_.to_buffers(), [this, self](boost::system::error_code ec, std::size_t) {
|
||||
if (!ec) {
|
||||
if (!ec && !needClose) {
|
||||
// keep alive Connection
|
||||
request_parser_.reset();
|
||||
request_.reset();
|
||||
doRead();
|
||||
} else {
|
||||
connection_manager_.stop(shared_from_this());
|
||||
|
@@ -72,6 +72,8 @@ namespace http::server {
|
||||
|
||||
/// The reply to be sent back to the client.
|
||||
Reply reply_;
|
||||
|
||||
bool needClose = false;
|
||||
};
|
||||
|
||||
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.
|
||||
Reply reply_;
|
||||
|
||||
bool needClose = false;
|
||||
};
|
||||
|
||||
typedef std::shared_ptr<ConnectionBase> connection_ptr;
|
||||
|
@@ -36,6 +36,7 @@ std::string http::server::mime_types::toString(Mime m) {
|
||||
case text_plain: return "text/plain";
|
||||
case text_html: return "text/html";
|
||||
case text_css: return "text/css";
|
||||
case video_mp4: return "video/mp4";
|
||||
case json: return "application/json";
|
||||
case javascript: return "application/javascript";
|
||||
case blob:
|
||||
|
@@ -15,6 +15,7 @@ namespace http::server::mime_types {
|
||||
text_plain, // text/plain
|
||||
text_html, // text/html
|
||||
text_css, // text/css
|
||||
video_mp4, // video/mp4
|
||||
json, // application/json
|
||||
javascript, // application/javascript
|
||||
blob // application/octet-stream
|
||||
|
@@ -13,6 +13,7 @@ namespace http::server {
|
||||
const std::string multiple_choices = "HTTP/1.1 300 Multiple Choices\r\n";
|
||||
const std::string moved_permanently = "HTTP/1.1 301 Moved Permanently\r\n";
|
||||
const std::string moved_temporarily = "HTTP/1.1 302 Moved Temporarily\r\n";
|
||||
const std::string see_other_redirect = "HTTP/1.1 303 See Other\r\n";
|
||||
const std::string not_modified = "HTTP/1.1 304 Not Modified\r\n";
|
||||
const std::string bad_request = "HTTP/1.1 400 Bad Request\r\n";
|
||||
const std::string unauthorized = "HTTP/1.1 401 Unauthorized\r\n";
|
||||
@@ -39,6 +40,8 @@ namespace http::server {
|
||||
return boost::asio::buffer(moved_permanently);
|
||||
case status_type::moved_temporarily:
|
||||
return boost::asio::buffer(moved_temporarily);
|
||||
case status_type::see_other_redirect:
|
||||
return boost::asio::buffer(see_other_redirect);
|
||||
case status_type::not_modified:
|
||||
return boost::asio::buffer(not_modified);
|
||||
case status_type::bad_request:
|
||||
@@ -78,7 +81,9 @@ namespace http::server {
|
||||
buffers.push_back(boost::asio::buffer(misc_strings::crlf));
|
||||
}
|
||||
buffers.emplace_back(boost::asio::buffer(misc_strings::crlf));
|
||||
buffers.emplace_back(boost::asio::buffer(content));
|
||||
if (!content.empty()) {
|
||||
buffers.emplace_back(boost::asio::buffer(content));
|
||||
}
|
||||
return buffers;
|
||||
}
|
||||
|
||||
@@ -212,4 +217,10 @@ namespace http::server {
|
||||
rep.headers.push_back({.name = "Content-Type", .value = toString(mime_types::text_html)});
|
||||
stock_replies::as_content(status, rep.content);
|
||||
}
|
||||
|
||||
void httpRedirect(Reply &rep, const std::string &location) {
|
||||
rep.status = see_other_redirect;
|
||||
rep.content.clear();
|
||||
rep.headers.push_back({.name = "Location", .value = location});
|
||||
}
|
||||
} // namespace http::server
|
||||
|
@@ -16,6 +16,7 @@ namespace http::server {
|
||||
multiple_choices = 300,
|
||||
moved_permanently = 301,
|
||||
moved_temporarily = 302,
|
||||
see_other_redirect = 303,
|
||||
not_modified = 304,
|
||||
bad_request = 400,
|
||||
unauthorized = 401,
|
||||
@@ -46,6 +47,7 @@ namespace http::server {
|
||||
/// Get a stock reply.
|
||||
void stockReply(status_type status, Reply& rep);
|
||||
|
||||
void httpRedirect(Reply& rep, const std::string& location);
|
||||
} // namespace http::Server
|
||||
|
||||
|
||||
|
@@ -19,14 +19,23 @@ namespace http::server {
|
||||
};
|
||||
|
||||
/// A request received from a client.
|
||||
struct Request {
|
||||
class Request {
|
||||
public:
|
||||
Request();
|
||||
|
||||
void reset();
|
||||
std::string getHeaderValue(const std::string& headerName) const;
|
||||
|
||||
std::string method;
|
||||
std::string queryUri;
|
||||
std::unique_ptr<Url> url;
|
||||
bool is_keep_alive;
|
||||
int http_version_major;
|
||||
int http_version_minor;
|
||||
bool is_keep_alive{};
|
||||
int http_version_major{};
|
||||
int http_version_minor{};
|
||||
std::vector<header> headers;
|
||||
std::vector<char> payload;
|
||||
|
||||
~Request();
|
||||
};
|
||||
} // namespace http::Server
|
||||
|
||||
|
@@ -1,11 +1,30 @@
|
||||
#include "request_parser.hpp"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include "request.hpp"
|
||||
|
||||
|
||||
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) {
|
||||
std::istringstream iss(query);
|
||||
std::string param;
|
||||
@@ -32,6 +51,32 @@ namespace http::server {
|
||||
|
||||
Url::~Url() = default;
|
||||
|
||||
Request::Request() = default;
|
||||
|
||||
void Request::reset() {
|
||||
method = "";
|
||||
queryUri = "";
|
||||
if (url != nullptr) {
|
||||
url.reset(nullptr);
|
||||
}
|
||||
is_keep_alive = false;
|
||||
http_version_major = 0;
|
||||
http_version_minor = 0;
|
||||
headers.clear();
|
||||
payload.clear();
|
||||
}
|
||||
|
||||
std::string Request::getHeaderValue(const std::string &headerName) const {
|
||||
for (const auto& header: headers) {
|
||||
if (boost::iequals(header.name, headerName)) {
|
||||
return header.value;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
Request::~Request() = default;
|
||||
|
||||
|
||||
RequestParser::RequestParser()
|
||||
: state_(method_start) {
|
||||
@@ -39,10 +84,17 @@ namespace http::server {
|
||||
|
||||
void RequestParser::reset() {
|
||||
state_ = method_start;
|
||||
contentLenghtHeader = 0;
|
||||
}
|
||||
|
||||
RequestParser::result_type RequestParser::consume(Request &req, char input) {
|
||||
switch (state_) {
|
||||
case expecting_payload:
|
||||
req.payload.push_back(input);
|
||||
if (req.payload.size() < contentLenghtHeader) {
|
||||
return indeterminate;
|
||||
}
|
||||
return good;
|
||||
case method_start:
|
||||
if (!is_char(input) || is_ctl(input) || is_tspecial(input)) {
|
||||
return bad;
|
||||
@@ -55,36 +107,34 @@ namespace http::server {
|
||||
if (input == ' ') {
|
||||
state_ = uri;
|
||||
return indeterminate;
|
||||
} else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) {
|
||||
return bad;
|
||||
} else {
|
||||
req.method.push_back(input);
|
||||
return indeterminate;
|
||||
}
|
||||
if (!is_char(input) || is_ctl(input) || is_tspecial(input)) {
|
||||
return bad;
|
||||
}
|
||||
req.method.push_back(input);
|
||||
return indeterminate;
|
||||
case uri:
|
||||
if (input == ' ') {
|
||||
state_ = http_version_h;
|
||||
return indeterminate;
|
||||
} else if (is_ctl(input)) {
|
||||
return bad;
|
||||
} else {
|
||||
req.queryUri.push_back(input);
|
||||
return indeterminate;
|
||||
}
|
||||
if (is_ctl(input)) {
|
||||
return bad;
|
||||
}
|
||||
req.queryUri.push_back(input);
|
||||
return indeterminate;
|
||||
case http_version_h:
|
||||
if (input == 'H') {
|
||||
state_ = http_version_t_1;
|
||||
return indeterminate;
|
||||
} else {
|
||||
return bad;
|
||||
}
|
||||
return bad;
|
||||
case http_version_t_1:
|
||||
if (input == 'T') {
|
||||
state_ = http_version_t_2;
|
||||
return indeterminate;
|
||||
} else {
|
||||
return bad;
|
||||
}
|
||||
return bad;
|
||||
case http_version_t_2:
|
||||
if (input == 'T') {
|
||||
state_ = http_version_p;
|
||||
@@ -155,17 +205,23 @@ namespace http::server {
|
||||
if (input == '\r') {
|
||||
state_ = expecting_newline_3;
|
||||
return indeterminate;
|
||||
} else if (!req.headers.empty() && (input == ' ' || input == '\t')) {
|
||||
}
|
||||
if (!req.headers.empty() && (input == ' ' || input == '\t')) {
|
||||
state_ = header_lws;
|
||||
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:
|
||||
if (input == '\r') {
|
||||
state_ = expecting_newline_2;
|
||||
@@ -183,12 +239,12 @@ namespace http::server {
|
||||
if (input == ':') {
|
||||
state_ = space_before_header_value;
|
||||
return indeterminate;
|
||||
} else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) {
|
||||
return bad;
|
||||
} else {
|
||||
req.headers.back().name.push_back(input);
|
||||
return indeterminate;
|
||||
}
|
||||
if (!is_char(input) || is_ctl(input) || is_tspecial(input)) {
|
||||
return bad;
|
||||
}
|
||||
req.headers.back().name.push_back(input);
|
||||
return indeterminate;
|
||||
case space_before_header_value:
|
||||
if (input == ' ') {
|
||||
state_ = header_value;
|
||||
@@ -216,9 +272,21 @@ namespace http::server {
|
||||
case expecting_newline_3:
|
||||
if (input == '\n') {
|
||||
req.url = std::make_unique<Url>(req.queryUri);
|
||||
return good;
|
||||
auto content_len = req.getHeaderValue("content-length");
|
||||
if (content_len.empty()) {
|
||||
return good;
|
||||
}
|
||||
contentLenghtHeader = std::stoul(content_len);
|
||||
if (contentLenghtHeader == 0) {
|
||||
return good;
|
||||
}
|
||||
if (requestBodySizeResolver(req, contentLenghtHeader)) {
|
||||
state_ = expecting_payload;
|
||||
return indeterminate;
|
||||
}
|
||||
}
|
||||
return bad;
|
||||
|
||||
default:
|
||||
return bad;
|
||||
}
|
||||
|
@@ -8,7 +8,7 @@
|
||||
|
||||
|
||||
namespace http::server {
|
||||
struct Request;
|
||||
class Request;
|
||||
|
||||
/// Parser for incoming requests.
|
||||
class RequestParser {
|
||||
@@ -73,8 +73,11 @@ namespace http::server {
|
||||
space_before_header_value,
|
||||
header_value,
|
||||
expecting_newline_2,
|
||||
expecting_newline_3
|
||||
expecting_newline_3,
|
||||
expecting_payload
|
||||
} state_;
|
||||
|
||||
size_t contentLenghtHeader = 0;
|
||||
};
|
||||
} // namespace http::Server
|
||||
|
||||
|
@@ -3,8 +3,6 @@
|
||||
#include <fstream>
|
||||
#include <utility>
|
||||
|
||||
#include "../../dependencies/control_system/common/protocol_commands.h"
|
||||
|
||||
static void loadFile(const std::string& path, std::vector<char>& content) {
|
||||
std::ifstream is(path, std::ios::in | std::ios::binary);
|
||||
if (!is) {
|
||||
@@ -24,37 +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::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) {
|
||||
BOOST_LOG_TRIVIAL(info) << "Load static file " << this->path;
|
||||
loadFile(this->path, this->content);
|
||||
BOOST_LOG_TRIVIAL(info) << "Load static file " << this->webPath;
|
||||
loadFile(path, this->content);
|
||||
} 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 " << this->path;
|
||||
loadFile(this->path, this->content);
|
||||
BOOST_LOG_TRIVIAL(info) << "Load static file " << path;
|
||||
loadFile(path, this->content);
|
||||
#endif
|
||||
}
|
||||
http::resource::StaticFileFactory::StaticFileDef::~StaticFileDef() = default;
|
||||
|
||||
http::resource::StaticFileFactory::StaticFileFactory() = default;
|
||||
|
||||
void http::resource::StaticFileFactory::registerFile(const std::string &path, server::mime_types::Mime type, bool allowCache) {
|
||||
this->files.emplace_back(path, type, 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, webPath, type, allowCache);
|
||||
}
|
||||
|
||||
void http::resource::StaticFileFactory::serve(const std::string &path, server::Reply &rep) {
|
||||
for (auto& f: this->files) {
|
||||
if (f.path == path) {
|
||||
if (f.webPath == path) {
|
||||
#ifdef USE_DEBUG
|
||||
if (f.allowCache) {
|
||||
rep.content.clear();
|
||||
rep.content.insert(rep.content.end(), f.content.begin(), f.content.end());
|
||||
} else {
|
||||
BOOST_LOG_TRIVIAL(debug) << "Reload file " << path << " (http path: " << path << ")";
|
||||
loadFile(f.path, rep.content);
|
||||
loadFile(f.fsPath, rep.content);
|
||||
}
|
||||
#else
|
||||
rep.content.clear();
|
||||
|
@@ -23,9 +23,12 @@ namespace http::resource {
|
||||
class StaticFileFactory {
|
||||
class StaticFileDef {
|
||||
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;
|
||||
bool allowCache;
|
||||
std::vector<char> content;
|
||||
@@ -36,7 +39,7 @@ namespace http::resource {
|
||||
public:
|
||||
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);
|
||||
|
||||
|
@@ -1,6 +1,7 @@
|
||||
#include "server.hpp"
|
||||
#include <utility>
|
||||
#include <boost/beast/core/basic_stream.hpp>
|
||||
#include <boost/log/trivial.hpp>
|
||||
|
||||
|
||||
namespace http::server {
|
||||
@@ -126,7 +127,12 @@ namespace http::server {
|
||||
if (res->path != req.url->path) {
|
||||
continue;
|
||||
}
|
||||
res->handle(req, rep);
|
||||
try {
|
||||
res->handle(req, rep);
|
||||
} catch (std::exception& e) {
|
||||
BOOST_LOG_TRIVIAL(error) << "Server::requestHandler(): what = " << e.what();
|
||||
stockReply(internal_server_error, rep);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -1,37 +1,81 @@
|
||||
#ifndef TERMINAL_API_DRIVER_H
|
||||
#define TERMINAL_API_DRIVER_H
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
#include <terminal_api/ControlProtoCInterface.h>
|
||||
|
||||
|
||||
namespace api_driver {
|
||||
constexpr int CACHE_STATISTICS_UPDATE_MS = 500;
|
||||
constexpr int CACHE_SETTINGS_UPDATE_MS = 5000;
|
||||
constexpr int CACHE_QOS_UPDATE_MS = 5000;
|
||||
|
||||
class TerminalApiDaemon;
|
||||
|
||||
/**
|
||||
* Это ApiDriver. Все ответы он будет возвращать в виде json.
|
||||
*/
|
||||
* Это ApiDriver. Все ответы он будет возвращать в виде json.
|
||||
*/
|
||||
class ApiDriver {
|
||||
public:
|
||||
explicit ApiDriver();
|
||||
|
||||
/**
|
||||
* Запросить общее состояние терминала
|
||||
* @return {"txState":false,"rxState":false,"rx.sym_sync_lock":false,"rx.freq_search_lock":false,"rx.afc_lock":false,"rx.pkt_sync":false}
|
||||
*/
|
||||
std::string loadTerminalState();
|
||||
* Запуск демона
|
||||
*/
|
||||
void startDaemon();
|
||||
|
||||
/**
|
||||
* Сбросить статистику пакетов
|
||||
*/
|
||||
* Запросить общее состояние терминала
|
||||
* @return {"txState":false,"rxState":false,"rx.sym_sync_lock":false,"rx.freq_search_lock":false,"rx.afc_lock":false,"rx.pkt_sync":false}
|
||||
*/
|
||||
std::string loadTerminalState() const;
|
||||
|
||||
/**
|
||||
* Сбросить статистику пакетов
|
||||
*/
|
||||
void resetPacketStatistics() const;
|
||||
|
||||
std::string loadSettings();
|
||||
std::string loadSettings() const;
|
||||
|
||||
std::string loadFirmwareVersion() const;
|
||||
|
||||
/**
|
||||
* Установить настройки RX/TX, readback можно получить используя loadTerminalState
|
||||
*/
|
||||
void setRxTxSettings(boost::property_tree::ptree &pt);
|
||||
|
||||
#ifdef MODEM_IS_SCPC
|
||||
/**
|
||||
* Установить настройки CinC, readback можно получить используя loadTerminalState.
|
||||
*/
|
||||
void setCincSettings(boost::property_tree::ptree &pt);
|
||||
#endif
|
||||
/**
|
||||
* Установить настройки BUC и LNB, readback можно получить используя loadTerminalState.
|
||||
*/
|
||||
void setBucLnbSettings(boost::property_tree::ptree &pt);
|
||||
|
||||
/**
|
||||
* Установить настройки QoS, readback можно получить используя loadTerminalState.
|
||||
*/
|
||||
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();
|
||||
|
||||
private:
|
||||
TSID sid{0};
|
||||
unsigned int access{0};
|
||||
|
||||
std::unique_ptr<TerminalApiDaemon> daemon;
|
||||
};
|
||||
}
|
||||
|
||||
|
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 {
|
||||
margin: 0.5em 0;
|
||||
margin: 0.5em 0 3px;
|
||||
background: var(--brand-bg);
|
||||
}
|
||||
.tabs-header > * {
|
||||
@@ -7,7 +7,6 @@
|
||||
}
|
||||
.tabs-btn {
|
||||
text-decoration: none;
|
||||
font-size: 18px;
|
||||
border: none;
|
||||
padding: 10px 25px;
|
||||
text-align: center;
|
||||
@@ -17,7 +16,7 @@
|
||||
}
|
||||
.tabs-btn.active {
|
||||
color: var(--brand-text);
|
||||
border-bottom: 3px solid var(--brand-text);
|
||||
border-bottom: 3px solid var(--bg-action);
|
||||
}
|
||||
.tabs-body-item {
|
||||
padding: 20px 0;
|
||||
@@ -37,6 +36,30 @@
|
||||
border-radius: 0.5em;
|
||||
}
|
||||
|
||||
.dangerous-button, .action-button {
|
||||
border: solid 1px var(--text-color2);
|
||||
border-radius: 0.5em;
|
||||
padding: 0.3em;
|
||||
margin: 0.2em;
|
||||
}
|
||||
|
||||
.summary-actions {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: stretch;
|
||||
}
|
||||
.summary-actions * {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.dangerous-button {
|
||||
background: var(--bg-danger);
|
||||
}
|
||||
|
||||
.action-button {
|
||||
background: var(--bg-action);
|
||||
}
|
||||
|
||||
.nav-bar-element {
|
||||
margin: 0.5em;
|
||||
border-bottom: 2px solid var(--text-color2);
|
||||
@@ -47,48 +70,102 @@
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.tabs-item-flex-container > * {
|
||||
flex: 1 1 auto
|
||||
}
|
||||
|
||||
.tabs-item-flex-container > *, .settings-set-container {
|
||||
padding: 1em;
|
||||
margin: 1em;
|
||||
border: 1px solid var(--text-color2);
|
||||
border-radius: 0.2em;
|
||||
}
|
||||
|
||||
.tabs-item-flex-container th {
|
||||
.settings-set-container {
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
.settings-set-container th {
|
||||
text-align: left;
|
||||
font-weight: normal;
|
||||
padding-right: 1em;
|
||||
}
|
||||
.settings-set-container td {
|
||||
min-width: 10em;
|
||||
}
|
||||
.tabs-item-flex-container h2 {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
form label * {
|
||||
.settings-set-container > h3 {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
label * {
|
||||
display: block;
|
||||
}
|
||||
form label {
|
||||
margin: 1em 0;
|
||||
|
||||
label {
|
||||
margin: 1em 0.5em;
|
||||
display: block;
|
||||
background: var(--bg-selected);
|
||||
/*background: var(--bg-selected);*/
|
||||
color: var(--text-color2);
|
||||
}
|
||||
form input {
|
||||
.settings-set-container input, .settings-set-container select {
|
||||
margin-top: 0.5em;
|
||||
border: none;
|
||||
border-bottom: solid 2px var(--text-color);
|
||||
width: 100%;
|
||||
border-bottom: solid 2px var(--text-color2);
|
||||
width: 20em;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
form input:focus {
|
||||
.settings-set-container input:focus {
|
||||
outline: 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 */
|
||||
select * {
|
||||
background: var(--bg-selected);
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
.settings-set-container tr > * {
|
||||
border-bottom: solid 1px var(--text-color2);
|
||||
}
|
||||
|
||||
.settings-set-container tr:hover {
|
||||
background: var(--bg-selected);
|
||||
}
|
||||
|
||||
details > summary {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
.submit-spinner {
|
||||
display: inline-block;
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
border: 3px solid #f3f3f3; /* Цвет границы */
|
||||
border-radius: 50%; /* Делаем круг */
|
||||
border-top-color: #3498db; /* Цвет верхней границы */
|
||||
animation: spin 0.8s linear infinite; /* Анимация вращения */
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
/*********************** Стили для красивых 'switch' ***********************/
|
||||
|
||||
.toggle-input {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
margin: 5px 10px;
|
||||
width: 50px;
|
||||
@@ -116,7 +193,7 @@ form input:focus {
|
||||
|
||||
.toggle-input input[type="checkbox"]:checked + .slider {
|
||||
left: 25px;
|
||||
background-color: var(--brand-text);
|
||||
background-color: var(--bg-action);
|
||||
}
|
||||
|
||||
.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 |
347
static/js/vue.js
347
static/js/vue.js
@@ -1,6 +1,6 @@
|
||||
/*!
|
||||
* Vue.js v2.7.16
|
||||
* (c) 2014-2023 Evan You
|
||||
* Vue.js v2.7.14
|
||||
* (c) 2014-2022 Evan You
|
||||
* Released under the MIT License.
|
||||
*/
|
||||
(function (global, factory) {
|
||||
@@ -82,16 +82,9 @@
|
||||
return val == null
|
||||
? ''
|
||||
: Array.isArray(val) || (isPlainObject(val) && val.toString === _toString)
|
||||
? JSON.stringify(val, replacer, 2)
|
||||
? JSON.stringify(val, null, 2)
|
||||
: 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.
|
||||
* If the conversion fails, return original string.
|
||||
@@ -253,7 +246,9 @@
|
||||
*/
|
||||
function genStaticKeys$1(modules) {
|
||||
return modules
|
||||
.reduce(function (keys, m) { return keys.concat(m.staticKeys || []); }, [])
|
||||
.reduce(function (keys, m) {
|
||||
return keys.concat(m.staticKeys || []);
|
||||
}, [])
|
||||
.join(',');
|
||||
}
|
||||
/**
|
||||
@@ -730,35 +725,30 @@
|
||||
};
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
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);
|
||||
};
|
||||
|
||||
typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
||||
var e = new Error(message);
|
||||
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
||||
/******************************************************************************
|
||||
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;
|
||||
@@ -892,7 +882,7 @@
|
||||
});
|
||||
|
||||
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
|
||||
* update computation.
|
||||
@@ -951,7 +941,7 @@
|
||||
var keys = Object.keys(value);
|
||||
for (var i = 0; i < keys.length; 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.
|
||||
*/
|
||||
function defineReactive(obj, key, val, customSetter, shallow, mock, observeEvenIfShallow) {
|
||||
if (observeEvenIfShallow === void 0) { observeEvenIfShallow = false; }
|
||||
function defineReactive(obj, key, val, customSetter, shallow, mock) {
|
||||
var dep = new Dep();
|
||||
var property = Object.getOwnPropertyDescriptor(obj, key);
|
||||
if (property && property.configurable === false) {
|
||||
@@ -999,10 +988,10 @@
|
||||
var getter = property && property.get;
|
||||
var setter = property && property.set;
|
||||
if ((!getter || setter) &&
|
||||
(val === NO_INITIAL_VALUE || arguments.length === 2)) {
|
||||
(val === NO_INIITIAL_VALUE || arguments.length === 2)) {
|
||||
val = obj[key];
|
||||
}
|
||||
var childOb = shallow ? val && val.__ob__ : observe(val, false, mock);
|
||||
var childOb = !shallow && observe(val, false, mock);
|
||||
Object.defineProperty(obj, key, {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
@@ -1047,7 +1036,7 @@
|
||||
else {
|
||||
val = newVal;
|
||||
}
|
||||
childOb = shallow ? newVal && newVal.__ob__ : observe(newVal, false, mock);
|
||||
childOb = !shallow && observe(newVal, false, mock);
|
||||
{
|
||||
dep.notify({
|
||||
type: "set" /* TriggerOpTypes.SET */,
|
||||
@@ -2510,10 +2499,11 @@
|
||||
// to the data on the placeholder node.
|
||||
vm.$vnode = _parentVnode;
|
||||
// render self
|
||||
var prevInst = currentInstance;
|
||||
var prevRenderInst = currentRenderingInstance;
|
||||
var vnode;
|
||||
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);
|
||||
currentRenderingInstance = vm;
|
||||
vnode = render.call(vm._renderProxy, vm.$createElement);
|
||||
@@ -2537,8 +2527,8 @@
|
||||
}
|
||||
}
|
||||
finally {
|
||||
currentRenderingInstance = prevRenderInst;
|
||||
setCurrentInstance(prevInst);
|
||||
currentRenderingInstance = null;
|
||||
setCurrentInstance();
|
||||
}
|
||||
// if the returned array contains only a single node, allow it
|
||||
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 isUpdatingChildComponent = false;
|
||||
function setActiveInstance(vm) {
|
||||
@@ -3211,8 +3095,7 @@
|
||||
if (setContext === void 0) { setContext = true; }
|
||||
// #7573 disable dep collection when invoking lifecycle hooks
|
||||
pushTarget();
|
||||
var prevInst = currentInstance;
|
||||
var prevScope = getCurrentScope();
|
||||
var prev = currentInstance;
|
||||
setContext && setCurrentInstance(vm);
|
||||
var handlers = vm.$options[hook];
|
||||
var info = "".concat(hook, " hook");
|
||||
@@ -3224,10 +3107,7 @@
|
||||
if (vm._hasHookEvent) {
|
||||
vm.$emit('hook:' + hook);
|
||||
}
|
||||
if (setContext) {
|
||||
setCurrentInstance(prevInst);
|
||||
prevScope && prevScope.on();
|
||||
}
|
||||
setContext && setCurrentInstance(prev);
|
||||
popTarget();
|
||||
}
|
||||
|
||||
@@ -3445,10 +3325,7 @@
|
||||
var instance = currentInstance;
|
||||
var call = function (fn, type, args) {
|
||||
if (args === void 0) { args = null; }
|
||||
var res = invokeWithErrorHandling(fn, null, args, instance, type);
|
||||
if (deep && res && res.__ob__)
|
||||
res.__ob__.dep.depend();
|
||||
return res;
|
||||
return invokeWithErrorHandling(fn, null, args, instance, type);
|
||||
};
|
||||
var getter;
|
||||
var forceTrigger = false;
|
||||
@@ -3473,7 +3350,6 @@
|
||||
return s.value;
|
||||
}
|
||||
else if (isReactive(s)) {
|
||||
s.__ob__.dep.depend();
|
||||
return traverse(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) {
|
||||
if (!currentInstance) {
|
||||
{
|
||||
@@ -3911,7 +3893,7 @@
|
||||
suspensible = _b === void 0 ? false : _b, // in Vue 3 default is true
|
||||
userOnError = source.onError;
|
||||
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 retries = 0;
|
||||
@@ -4014,7 +3996,7 @@
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
@@ -4391,7 +4373,7 @@
|
||||
"Instead, use a data or computed property based on the prop's " +
|
||||
"value. Prop being mutated: \"".concat(key, "\""), vm);
|
||||
}
|
||||
}, true /* shallow */);
|
||||
});
|
||||
}
|
||||
// static props are already proxied on the component's prototype
|
||||
// during Vue.extend(). We only need to proxy props defined at
|
||||
@@ -4707,9 +4689,6 @@
|
||||
vm.__v_skip = true;
|
||||
// effect scope
|
||||
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;
|
||||
// merge options
|
||||
if (options && options._isComponent) {
|
||||
@@ -5956,7 +5935,7 @@
|
||||
return false;
|
||||
}
|
||||
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) {
|
||||
var entry = cache[key];
|
||||
if (entry) {
|
||||
@@ -5966,7 +5945,6 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
$vnode.componentOptions.children = undefined;
|
||||
}
|
||||
function pruneCacheEntry(cache, key, keys, current) {
|
||||
var entry = cache[key];
|
||||
@@ -6288,7 +6266,7 @@
|
||||
}
|
||||
var el = document.createElement(tag);
|
||||
if (tag.indexOf('-') > -1) {
|
||||
// https://stackoverflow.com/a/28210364/1070244
|
||||
// http://stackoverflow.com/a/28210364/1070244
|
||||
return (unknownElementCache[tag] =
|
||||
el.constructor === window.HTMLUnknownElement ||
|
||||
el.constructor === window.HTMLElement);
|
||||
@@ -7163,11 +7141,8 @@
|
||||
var insert_1 = ancestor.data.hook.insert;
|
||||
if (insert_1.merged) {
|
||||
// start at index 1 to avoid re-invoking component mounted hook
|
||||
// clone insert hooks to avoid being mutated during iteration.
|
||||
// e.g. for customed directives under transition group.
|
||||
var cloned = insert_1.fns.slice(1);
|
||||
for (var i_10 = 0; i_10 < cloned.length; i_10++) {
|
||||
cloned[i_10]();
|
||||
for (var i_10 = 1; i_10 < insert_1.fns.length; i_10++) {
|
||||
insert_1.fns[i_10]();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8306,8 +8281,10 @@
|
||||
}
|
||||
for (name in newStyle) {
|
||||
cur = newStyle[name];
|
||||
// ie9 setting to null has no effect, must use empty string
|
||||
setProp(el, name, cur == null ? '' : cur);
|
||||
if (cur !== oldStyle[name]) {
|
||||
// ie9 setting to null has no effect, must use empty string
|
||||
setProp(el, name, cur == null ? '' : cur);
|
||||
}
|
||||
}
|
||||
}
|
||||
var style$1 = {
|
||||
@@ -9554,7 +9531,7 @@
|
||||
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)) {
|
||||
var conditionalEnd = html.indexOf(']>');
|
||||
if (conditionalEnd >= 0) {
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 1.4 MiB |
@@ -1,99 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>RSCM-101 | Вход</title>
|
||||
<link rel="stylesheet" type="text/css" href="/style.css">
|
||||
<style>
|
||||
#form-wrapper {
|
||||
overflow: hidden;
|
||||
max-width: 27em;
|
||||
margin: 5em auto;
|
||||
height: auto;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.form-row {
|
||||
padding: 4px 0;
|
||||
margin: 1.5em;
|
||||
}
|
||||
|
||||
.form-row * {
|
||||
font-size: 1em;
|
||||
text-align: left;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.form-row label {
|
||||
line-height: 2em;
|
||||
font-weight: bolder;
|
||||
}
|
||||
|
||||
.form-row input {
|
||||
padding: 8px;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
border: none;
|
||||
border-bottom: var(--brand-bg) 2px solid;
|
||||
background-color: var(--bg-color);
|
||||
text-overflow: ellipsis;
|
||||
min-height: 2em;
|
||||
}
|
||||
|
||||
.form-row input:focus {
|
||||
outline: none;
|
||||
border: none;
|
||||
border-bottom: var(--brand-text) 2px solid;
|
||||
background-color: var(--bg-selected);
|
||||
}
|
||||
|
||||
#submit {
|
||||
border: none;
|
||||
font-weight: bolder;
|
||||
background: var(--bg-action);
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="form-wrapper">
|
||||
<h1> Вход </h1>
|
||||
<form method="POST" id="login-form">
|
||||
{% csrf_token %}
|
||||
<div class="form-row value-bad">
|
||||
Неверный логин или пароль
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<label for="username">Имя пользователя</label>
|
||||
<input type="text" name="username" id="username" required/>
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<label for="password">Пароль</label>
|
||||
<input type="password" name="password" id="password" required/>
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<input id="submit" type="submit" value="Войти">
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.getElementById("username").onkeydown = (e) => {
|
||||
if (e.key === 'Enter') {
|
||||
document.getElementById("password").focus()
|
||||
}
|
||||
}
|
||||
|
||||
document.getElementById("password").onkeydown = (e) => {
|
||||
if (e.key === 'Enter') {
|
||||
document.getElementById("login-form").submit()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@@ -35,7 +35,7 @@
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
border: none;
|
||||
border-bottom: var(--brand-bg) 2px solid;
|
||||
border-bottom: var(--text-color2) 2px solid;
|
||||
background-color: var(--bg-color);
|
||||
text-overflow: ellipsis;
|
||||
min-height: 2em;
|
||||
@@ -44,7 +44,7 @@
|
||||
.form-row input:focus {
|
||||
outline: none;
|
||||
border: none;
|
||||
border-bottom: var(--brand-text) 2px solid;
|
||||
border-bottom: var(--bg-action) 2px solid;
|
||||
background-color: var(--bg-selected);
|
||||
}
|
||||
|
||||
@@ -52,6 +52,7 @@
|
||||
border: none;
|
||||
font-weight: bolder;
|
||||
background: var(--bg-action);
|
||||
color: var(--text-color);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@@ -61,13 +62,8 @@
|
||||
|
||||
<div id="form-wrapper">
|
||||
<h1> Вход </h1>
|
||||
<form method="POST" id="login-form">
|
||||
<!-- {% csrf_token %}-->
|
||||
<!-- {% if message %}-->
|
||||
<!-- <div class="form-row value-bad">-->
|
||||
<!-- {{ message }}-->
|
||||
<!-- </div>-->
|
||||
<!-- {% endif %}-->
|
||||
<form id="login-form" onsubmit="submitLoginForm(); return false">
|
||||
<div class="form-row value-bad" hidden id="form-error-message"></div>
|
||||
|
||||
<div class="form-row">
|
||||
<label for="username">Имя пользователя</label>
|
||||
@@ -97,6 +93,41 @@
|
||||
document.getElementById("login-form").submit()
|
||||
}
|
||||
}
|
||||
|
||||
const loginForm = document.getElementById('login-form');
|
||||
const formErrorMessage = document.getElementById('form-error-message')
|
||||
|
||||
function submitLoginForm() {
|
||||
const username = document.getElementById('username').value
|
||||
const password = document.getElementById('password').value
|
||||
|
||||
const requestData = {
|
||||
"username": username,
|
||||
"password": password
|
||||
};
|
||||
|
||||
fetch('/login', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(requestData)
|
||||
}).then(response => {
|
||||
// Обработка ответа сервера
|
||||
response.json().then((value) => {
|
||||
if (value["error"]) {
|
||||
formErrorMessage.innerText = value["error"]
|
||||
formErrorMessage.removeAttribute("hidden")
|
||||
} else {
|
||||
window.location = "/"
|
||||
}
|
||||
})
|
||||
}).catch(error => {
|
||||
formErrorMessage.innerText = error
|
||||
formErrorMessage.removeAttribute("hidden")
|
||||
console.error('Ошибка отправки запроса:', error) // Обработка ошибки отправки запроса
|
||||
})
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
1700
static/main-scpc.html
Normal file
1700
static/main-scpc.html
Normal file
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
585
static/main.html
585
static/main.html
@@ -1,585 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>RSCM-101</title>
|
||||
<link rel="stylesheet" type="text/css" href="/style.css">
|
||||
<link rel="stylesheet" type="text/css" href="/fields.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="app" hidden>
|
||||
<div>
|
||||
<span class="nav-bar-element">Прием: <span :class="{ indicator_bad: stat_rx.state === true, indicator_good: stat_rx.state === false, indicator: true }"></span></span>
|
||||
<span class="nav-bar-element">Передача: <span :class="{ indicator_bad: stat_tx.state === true, indicator_good: stat_tx.state === false, indicator: true }"></span></span>
|
||||
<span class="nav-bar-element">Тест: <span :class="{ indicator_bad: testState === true, indicator_good: testState === false, indicator: true }"></span></span>
|
||||
<!-- Последнее обновление: {{ lastUpdateTime }}-->
|
||||
</div>
|
||||
<div class="tabs">
|
||||
<div class="tabs-header">
|
||||
<span style="font-weight:bold">RSCM-101</span>
|
||||
<a href="#monitoring" class="tabs-btn" @click="activeTab = 'monitoring'" :class="{ active: activeTab === 'monitoring' }">Мониторинг</a>
|
||||
<a href="#setup" class="tabs-btn" @click="activeTab = 'setup'" :class="{ active: activeTab === 'setup' }">Настройки</a>
|
||||
<a href="#admin" class="tabs-btn" @click="activeTab = 'admin'" :class="{ active: activeTab === 'admin' }">Администрирование</a>
|
||||
</div>
|
||||
<div class="tabs-body">
|
||||
<div class="tabs-body-item tabs-item-flex-container" v-show="activeTab === 'monitoring'">
|
||||
<div>
|
||||
<h2>Статистика приема</h2>
|
||||
<table>
|
||||
<tbody>
|
||||
<tr><th>Прием</th><td><span :class="{ indicator_bad: stat_rx.state === true, indicator_good: stat_rx.state === false, indicator: true }"></span></td></tr>
|
||||
<tr><th>Захват символьной</th><td><span :class="{ indicator_bad: stat_rx.sym_sync_lock === true, indicator_good: stat_rx.sym_sync_lock === false, indicator: true }"></span></td></tr>
|
||||
<tr><th>Захват ФАПЧ</th><td><span :class="{ indicator_bad: stat_rx.afc_lock === true, indicator_good: stat_rx.afc_lock === false, indicator: true }"></span></td></tr>
|
||||
<tr><th>Захват поиска по частоте</th><td><span :class="{ indicator_bad: stat_rx.freq_search_lock === true, indicator_good: stat_rx.freq_search_lock === false, indicator: true }"></span></td></tr>
|
||||
<tr><th>Захват пакетной синхр.</th><td><span :class="{ indicator_bad: stat_rx.pkt_sync === true, indicator_good: stat_rx.pkt_sync === false, indicator: true }"></span></td></tr>
|
||||
<tr><th>ОСШ/RSSI</th><td>{{ stat_rx.snr }} / {{ stat_rx.rssi }}</td></tr>
|
||||
<tr><th>Modcod/размер кадра</th><td>{{ stat_rx.modcod }} / {{ stat_rx.frameSize }}</td></tr>
|
||||
<tr><th>Пилот-символы</th><td>{{ stat_rx.pilots }}</td></tr>
|
||||
<tr><th>Символьная ошибка</th><td>{{ stat_rx.symError }}</td></tr>
|
||||
<tr><th>Грубая/точная част. ошибка, Гц</th><td>{{ stat_rx.freqErr }} / {{ stat_rx.freqErrAcc }}</td></tr>
|
||||
<tr><th>Ур. входного сигнала</th><td>{{ stat_rx.inputSignalLevel }}</td></tr>
|
||||
<tr><th>Ошибка ФАПЧ</th><td>{{ stat_rx.pllError }}</td></tr>
|
||||
<tr><th>Инф. скорость на приеме</th><td>{{ stat_rx.speedOnRxKbit }} kbit/s</td></tr>
|
||||
<tr><th>Инф. скорость на интерфейсе</th><td>{{ stat_rx.speedOnIifKbit }} kbit/s</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p> Статистика пакетов </p>
|
||||
<table>
|
||||
<tbody>
|
||||
<tr><th>Качественных пакетов</th><td>{{ stat_rx.packetsOk }}</td></tr>
|
||||
<tr><th>Поврежденных пакетов</th><td>{{ stat_rx.packetsBad }}</td></tr>
|
||||
<tr><th>DUMMY</th><td>{{ stat_rx.packetsDummy }}</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<button @click="resetPacketsStatistics()"> Сброс статистики </button>
|
||||
</div>
|
||||
<div>
|
||||
<h2>Статистика передачи</h2>
|
||||
<table>
|
||||
<tbody>
|
||||
<tr><th>Передача</th><td><span :class="{ indicator_bad: stat_tx.state === true, indicator_good: stat_tx.state === false, indicator: true }"></span></td></tr>
|
||||
<tr><th>ОСШ дальнего приема</th><td>{{ stat_tx.snr }}</td></tr>
|
||||
<tr><th>Modcod</th><td>{{ stat_tx.modcod }}</td></tr>
|
||||
<tr><th>Размер кадра</th><td>{{ stat_tx.frameSize }}</td></tr>
|
||||
<tr><th>Пилот-символы</th><td>{{ stat_tx.pilots }}</td></tr>
|
||||
<tr><th>Инф. скорость на передаче</th><td>{{ stat_tx.speedOnTxKbit }} kbit/s</td></tr>
|
||||
<tr><th>Инф. скорость на интерфейсе</th><td>{{ stat_tx.speedOnIifKbit }} kbit/s</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div v-if="isCinC === true">
|
||||
<h2>Статистика режима CinC</h2>
|
||||
<table>
|
||||
<tbody>
|
||||
<tr><th>ОСС</th><td>{{ stat_cinc.occ }}</td></tr>
|
||||
<tr><th>Захват коррелятора</th><td><span :class="{ indicator_bad: stat_cinc.correlator === true, indicator_good: stat_cinc.correlator === false, indicator: true }"></span></td></tr>
|
||||
<tr><th>Кол-во срывов коррелятора</th><td>{{ stat_cinc.correlatorFails }}</td></tr>
|
||||
<tr><th>Грубая/точная част. ошибка, Гц</th><td>{{ stat_cinc.freqErr }} / {{ stat_cinc.freqErrAcc }}</td></tr>
|
||||
<tr><th>Задержка в канале, мс</th><td>{{ stat_cinc.channelDelay }}</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div>
|
||||
<h2>Состояние устройства</h2>
|
||||
<table>
|
||||
<tbody>
|
||||
<tr><th>Температура ADRV</th><td>{{ stat_device.adrv }} °C</td></tr>
|
||||
<tr><th>Температура ZYNC</th><td>{{ stat_device.zync }} °C</td></tr>
|
||||
<tr><th>Температура FPGA</th><td>{{ stat_device.fpga }} °C</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tabs-body-item" v-show="activeTab === 'setup' && settingFetchComplete">
|
||||
<h2>Настройки приема/передачи</h2>
|
||||
<form method="POST" onsubmit="" class="settings-set-container">
|
||||
<label>
|
||||
<span>Режим работы</span>
|
||||
<select v-model="param.general.mode">
|
||||
<option value="scpc">SCPC</option>
|
||||
<option value="cinc">CinC</option>
|
||||
</select>
|
||||
</label>
|
||||
<button type="submit">Сохранить</button>
|
||||
</form>
|
||||
<div class="tabs-item-flex-container">
|
||||
<form>
|
||||
<h2>Настройки передатчика</h2>
|
||||
<label>
|
||||
<span>Включить передатчик</span>
|
||||
<span class="toggle-input">
|
||||
<input type="checkbox" v-model="param.general.txEn" />
|
||||
<span class="slider"></span>
|
||||
</span>
|
||||
</label>
|
||||
<label>
|
||||
<span>Автоматический запуск передатчика</span>
|
||||
<span class="toggle-input">
|
||||
<input type="checkbox" v-model="param.general.autoStartTx" />
|
||||
<span class="slider"></span>
|
||||
</span>
|
||||
</label>
|
||||
<label>
|
||||
<span>Режим работы модулятора</span>
|
||||
<select v-model="param.general.modulatorMode">
|
||||
<option value="normal">Нормальный</option>
|
||||
<option value="test">Тест (CW)</option>
|
||||
</select>
|
||||
</label>
|
||||
<label>
|
||||
<span>Входные данные</span>
|
||||
<select v-model="param.general.inputData">
|
||||
<option value="eth">Ethernet</option>
|
||||
<option value="test">Тест (CW)</option>
|
||||
</select>
|
||||
</label>
|
||||
<button type="submit">Сохранить</button>
|
||||
</form>
|
||||
<form>
|
||||
<h2>Параметры передачи</h2>
|
||||
<label>
|
||||
<span>Центральная частота, кГц</span>
|
||||
<input v-model="param.tx.centerFreq"/>
|
||||
</label>
|
||||
<label>
|
||||
<span>Символьная скорость, Бод</span>
|
||||
<input v-model="param.tx.cymRate"/>
|
||||
</label>
|
||||
<label>
|
||||
<span>Roll-off</span>
|
||||
<select v-model="param.tx.rolloff">
|
||||
<option value="5">0.05</option>
|
||||
<option value="10">0.10</option>
|
||||
<option value="15">0.15</option>
|
||||
<option value="20">0.20</option>
|
||||
<option value="25">0.25</option>
|
||||
</select>
|
||||
</label>
|
||||
<label>
|
||||
<span>Номер послед-ти Голда</span>
|
||||
<select v-model="param.tx.goldan">
|
||||
<option value="0">0</option>
|
||||
<option value="1">1</option>
|
||||
</select>
|
||||
</label>
|
||||
<label>
|
||||
<span>Ослабление, dB</span>
|
||||
<input v-model="param.tx.attenuation"/>
|
||||
</label>
|
||||
<button type="submit">Сохранить</button>
|
||||
</form>
|
||||
<form>
|
||||
<h2>Режим работы DVB-S2</h2>
|
||||
<label>
|
||||
<span>Режим</span>
|
||||
<select v-model="param.dvbs2.mode">
|
||||
<option value="ccm">CCM</option>
|
||||
<option value="acm">ACM</option>
|
||||
</select>
|
||||
</label>
|
||||
<label>
|
||||
<span>Размер кадра</span>
|
||||
<select v-model="param.dvbs2.frameSize">
|
||||
<option value="normal">normal</option>
|
||||
<option value="short">short</option>
|
||||
</select>
|
||||
</label>
|
||||
<label>
|
||||
<span>Пилот-символы</span>
|
||||
<select v-model="param.dvbs2.pilots">
|
||||
<option value="true">pilots</option>
|
||||
<option value="false">no pilots</option>
|
||||
</select>
|
||||
</label>
|
||||
|
||||
<label v-show="param.dvbs2.mode === 'ccm'">
|
||||
<span>Модуляция</span>
|
||||
<select v-model="param.dvbs2.ccm_modulation">
|
||||
<option value="qpsk">QPSK</option>
|
||||
<option value="8psk">8PSK</option>
|
||||
<option value="16apsk">16APSK</option>
|
||||
<option value="32apsk">32APSK</option>
|
||||
</select>
|
||||
</label>
|
||||
<label v-show="param.dvbs2.mode === 'ccm'">
|
||||
<span>Скорость кода</span>
|
||||
<select v-model="param.dvbs2.ccm_speed">
|
||||
<option value="1/4">1/4</option>
|
||||
<option value="1/3">1/3</option>
|
||||
<option value="2/5">2/5</option>
|
||||
<option value="1/2">1/2</option>
|
||||
<option value="2/3">2/3</option>
|
||||
<option value="3/4">3/4</option>
|
||||
<option value="4/5">4/5</option>
|
||||
<option value="5/6">5/6</option>
|
||||
<option value="8/9">8/9</option>
|
||||
<option value="9/10">9/10</option>
|
||||
</select>
|
||||
</label>
|
||||
|
||||
<label v-show="param.dvbs2.mode === 'acm'">
|
||||
<span>Модуляция (макс. режим)</span>
|
||||
<select v-model="param.dvbs2.acm_maxModulation">
|
||||
<option value="qpsk">QPSK</option>
|
||||
<option value="8psk">8PSK</option>
|
||||
<option value="16apsk">16APSK</option>
|
||||
<option value="32apsk">32APSK</option>
|
||||
</select>
|
||||
</label>
|
||||
<label v-show="param.dvbs2.mode === 'acm'">
|
||||
<span>Скорость кода (макс. режим)</span>
|
||||
<select v-model="param.dvbs2.acm_maxSpeed">
|
||||
<option value="1/4">1/4</option>
|
||||
<option value="1/3">1/3</option>
|
||||
<option value="2/5">2/5</option>
|
||||
<option value="1/2">1/2</option>
|
||||
<option value="2/3">2/3</option>
|
||||
<option value="3/4">3/4</option>
|
||||
<option value="4/5">4/5</option>
|
||||
<option value="5/6">5/6</option>
|
||||
<option value="8/9">8/9</option>
|
||||
<option value="9/10">9/10</option>
|
||||
</select>
|
||||
</label>
|
||||
<label v-show="param.dvbs2.mode === 'acm'">
|
||||
<span>Модуляция (мин. режим)</span>
|
||||
<select v-model="param.dvbs2.acm_minModulation">
|
||||
<option value="qpsk">QPSK</option>
|
||||
<option value="8psk">8PSK</option>
|
||||
<option value="16apsk">16APSK</option>
|
||||
<option value="32apsk">32APSK</option>
|
||||
</select>
|
||||
</label>
|
||||
<label v-show="param.dvbs2.mode === 'acm'">
|
||||
<span>Скорость кода (мин. режим)</span>
|
||||
<select v-model="param.dvbs2.acm_minSpeed">
|
||||
<option value="'1/4'">1/4</option>
|
||||
<option value="'1/3'">1/3</option>
|
||||
<option value="'2/5'">2/5</option>
|
||||
<option value="'1/2'">1/2</option>
|
||||
<option value="'2/3'">2/3</option>
|
||||
<option value="'3/4'">3/4</option>
|
||||
<option value="'4/5'">4/5</option>
|
||||
<option value="'5/6'">5/6</option>
|
||||
<option value="'8/9'">8/9</option>
|
||||
<option value="'9/10'">9/10</option>
|
||||
</select>
|
||||
</label>
|
||||
|
||||
<button type="submit">Сохранить</button>
|
||||
</form>
|
||||
<form>
|
||||
<h2>Настройки авто-регулировки мощности</h2>
|
||||
<label>
|
||||
<span>Авто-регулировка мощности</span>
|
||||
<span class="toggle-input">
|
||||
<input type="checkbox" v-model="param.acp.en" />
|
||||
<span class="slider"></span>
|
||||
</span>
|
||||
</label>
|
||||
<label>
|
||||
<span>Максимальное ослабление</span>
|
||||
<input v-model="param.acp.maxAttenuation"/>
|
||||
</label>
|
||||
<label>
|
||||
<span>Минимальное ослабление</span>
|
||||
<input v-model="param.acp.minAttenuation"/>
|
||||
</label>
|
||||
<label>
|
||||
<span>Требуемое ОСШ</span>
|
||||
<input v-model="param.acp.requiredSnr"/>
|
||||
</label>
|
||||
<button type="submit">Сохранить</button>
|
||||
</form>
|
||||
<form>
|
||||
<h2>Настройка приемника</h2>
|
||||
<label>
|
||||
<span>Режим управления усилением</span>
|
||||
<select v-model="param.rx.gainMode">
|
||||
<option value="auto">АРУ</option>
|
||||
<option value="manual">РРУ</option>
|
||||
</select>
|
||||
</label>
|
||||
<label v-show="param.rx.gainMode === 'manual'">
|
||||
<span>Усиление, dB</span>
|
||||
<input v-model="param.rx.manualGain"/>
|
||||
</label>
|
||||
<label>
|
||||
<span>Инверсия спектра</span>
|
||||
<span class="toggle-input">
|
||||
<input type="checkbox" v-model="param.rx.spectrumInversion" />
|
||||
<span class="slider"></span>
|
||||
</span>
|
||||
</label>
|
||||
<label>
|
||||
<span>Центральная частота, кГц</span>
|
||||
<input v-model="param.rx.centerFreq"/>
|
||||
</label>
|
||||
<label>
|
||||
<span>Символьная скорость, Бод</span>
|
||||
<input v-model="param.rx.cymRate"/>
|
||||
</label>
|
||||
<label>
|
||||
<span>Roll-off</span>
|
||||
<select v-model="param.rx.rolloff">
|
||||
<option value="5">0.05</option>
|
||||
<option value="10">0.10</option>
|
||||
<option value="15">0.15</option>
|
||||
<option value="20">0.20</option>
|
||||
<option value="25">0.25</option>
|
||||
</select>
|
||||
</label>
|
||||
<label>
|
||||
<span>Номер послед-ти Голда</span>
|
||||
<select v-model="param.rx.goldan">
|
||||
<option value="0">0</option>
|
||||
<option value="1">1</option>
|
||||
</select>
|
||||
</label>
|
||||
<label>
|
||||
<span>Ослабление, dB</span>
|
||||
<input v-model="param.rx.attenuation"/>
|
||||
</label>
|
||||
<button type="submit">Сохранить</button>
|
||||
</form>
|
||||
</div>
|
||||
<div v-show="param.general.mode === 'cinc'">
|
||||
<h2>Настройки режима CinC</h2>
|
||||
<p>CinC пока нельзя настроить, но скоро разработчик это поправит)</p>
|
||||
</div>
|
||||
<div>
|
||||
<h2>Настройки питания и опорного генератора</h2>
|
||||
<p>Эти настройки пока недоступны, но скоро разработчик это поправит)</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tabs-body-item" v-show="activeTab === 'admin'">
|
||||
<p>
|
||||
Эти настройки пока недоступны, но скоро разработчик это поправит. А пока смотри на крокодила
|
||||
</p>
|
||||
<img loading="lazy" src="/images/krokodil_vzryvaetsya_hd.gif" alt="krokodil">
|
||||
</div>
|
||||
</div>
|
||||
<p>Последнее обновление статистики: {{ lastUpdateTime }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Версия для разработки включает в себя возможность вывода в консоль полезных уведомлений -->
|
||||
<script src="/js/vue.js"></script>
|
||||
<script>
|
||||
// const router = useRouter();
|
||||
const availableTabs = ['monitoring', 'setup', 'admin']
|
||||
const defaultTab = availableTabs[0]
|
||||
|
||||
function getCurrentTab() {
|
||||
const sl = window.location.hash.slice(1)
|
||||
if (availableTabs.indexOf(sl) >= 0) {
|
||||
return sl
|
||||
}
|
||||
return defaultTab
|
||||
}
|
||||
|
||||
// TODO: взять модкоды из раздела 5.5.2.2 https://www.etsi.org/deliver/etsi_en/302300_302399/302307/01.01.02_60/en_302307v010102p.pdf
|
||||
// и прикрутить декодинг модкода
|
||||
|
||||
const app = new Vue({
|
||||
el: '#app',
|
||||
data: {
|
||||
isCinC: null,
|
||||
|
||||
stat_rx: {
|
||||
// индикаторы
|
||||
state: '?', // общее состояние
|
||||
sym_sync_lock: '?', // захват символьной
|
||||
freq_search_lock: '?', // Захват поиска по частоте
|
||||
afc_lock: '?', // захват ФАПЧ
|
||||
pkt_sync: '?', // захват пакетной синхронизации
|
||||
|
||||
// куча других параметров, идет в том же порядке, что и в таблице
|
||||
snr: '?', rssi: '?',
|
||||
modcod: '?', frameSize: '?',
|
||||
pilots: '?',
|
||||
symError: '?',
|
||||
freqErr: '?', freqErrAcc: '?',
|
||||
inputSignalLevel: '?',
|
||||
pllError: '?',
|
||||
speedOnRxKbit: '?',
|
||||
speedOnIifKbit: '?',
|
||||
|
||||
// статистика пакетов
|
||||
packetsOk: '?', packetsBad: '?', packetsDummy: '?',
|
||||
},
|
||||
stat_tx: {
|
||||
// состояние
|
||||
state: '?',
|
||||
|
||||
// прочие поля
|
||||
snr: '?', modcod: '?', frameSize: '?', pilots: '?', speedOnTxKbit: '?', speedOnIifKbit: '?',
|
||||
},
|
||||
stat_cinc: {
|
||||
occ: '?',
|
||||
correlator: null,
|
||||
correlatorFails: '?',
|
||||
freqErr: '?', freqErrAcc: '?',
|
||||
channelDelay: '?'
|
||||
},
|
||||
stat_device: { // температурные датчики
|
||||
adrv: 0, zync: 0, fpga: 0
|
||||
},
|
||||
|
||||
param: {
|
||||
general: {
|
||||
mode: 'scpc',
|
||||
txEn: false, // включен/выключен
|
||||
modulatorMode: 'normal', // режим работы модулятора
|
||||
autoStartTx: false, // было "режим работы передатчика"
|
||||
inputData: 'eth', // входные данные: eth или test
|
||||
},
|
||||
tx: {
|
||||
attenuation: -3.0, // ослабление
|
||||
goldan: '0',
|
||||
rolloff: 20,
|
||||
cymRate: 100000,
|
||||
centerFreq: 1200000.0,
|
||||
},
|
||||
dvbs2: {
|
||||
mode: 'ccm',
|
||||
frameSize: 'normal',
|
||||
pilots: false,
|
||||
|
||||
// CCM
|
||||
ccm_modulation: 'qpsk',
|
||||
ccm_speed: '1/2',
|
||||
|
||||
// ACM
|
||||
acm_maxModulation: 'qpsk',
|
||||
acm_maxSpeed: '1/2',
|
||||
acm_minModulation: 'qpsk',
|
||||
acm_minSpeed: '1/2',
|
||||
|
||||
snrReserve: 0.5,
|
||||
servicePacketPeriod: 15,
|
||||
},
|
||||
// авто-регулировка мощности
|
||||
acp: {
|
||||
en: false,
|
||||
maxAttenuation: -2.0,
|
||||
minAttenuation: -3.0,
|
||||
requiredSnr: -10,
|
||||
},
|
||||
rx: {
|
||||
gainMode: 'auto', // режим управления усилением
|
||||
manualGain: 70, // усиление, только для ручного режима
|
||||
spectrumInversion: false,
|
||||
|
||||
goldan: '0',
|
||||
rolloff: 20,
|
||||
cymRate: 100000,
|
||||
centerFreq: 1200000.0,
|
||||
},
|
||||
|
||||
buc: {
|
||||
|
||||
},
|
||||
lnb: {},
|
||||
serviceSettings: {},
|
||||
},
|
||||
|
||||
message: "<err>",
|
||||
|
||||
testState: '?',
|
||||
lastUpdateTime: new Date(),
|
||||
activeTab: getCurrentTab(),
|
||||
settingFetchComplete: false
|
||||
},
|
||||
methods: {
|
||||
updateStatistics(vals) {
|
||||
this.lastUpdateTime = new Date();
|
||||
this.isCinC = vals["mainState"]["isCinC"]
|
||||
|
||||
this.stat_rx.state = vals["mainState"]["rx.state"]
|
||||
this.stat_rx.sym_sync_lock = vals["mainState"]["rx.sym_sync_lock"]
|
||||
this.stat_rx.freq_search_lock = vals["mainState"]["rx.freq_search_lock"]
|
||||
this.stat_rx.afc_lock = vals["mainState"]["rx.afc_lock"]
|
||||
this.stat_rx.pkt_sync = vals["mainState"]["rx.pkt_sync"]
|
||||
this.stat_rx.snr = vals["mainState"]["rx.snr"]
|
||||
this.stat_rx.rssi = vals["mainState"]["rx.rssi"]
|
||||
this.stat_rx.modcod = vals["mainState"]["rx.modcod"]
|
||||
this.stat_rx.frameSize = vals["mainState"]["rx.frameSize"]
|
||||
this.stat_rx.pilots = vals["mainState"]["rx.pilots"]
|
||||
this.stat_rx.symError = vals["mainState"]["rx.symError"]
|
||||
this.stat_rx.freqErr = vals["mainState"]["rx.freqErr"]
|
||||
this.stat_rx.freqErrAcc = vals["mainState"]["rx.freqErrAcc"]
|
||||
this.stat_rx.inputSignalLevel = vals["mainState"]["rx.inputSignalLevel"]
|
||||
this.stat_rx.pllError = vals["mainState"]["rx.pllError"]
|
||||
this.stat_rx.speedOnRxKbit = vals["mainState"]["rx.speedOnRxKbit"]
|
||||
this.stat_rx.speedOnIifKbit = vals["mainState"]["rx.speedOnIifKbit"]
|
||||
this.stat_rx.packetsOk = vals["mainState"]["rx.packetsOk"]
|
||||
this.stat_rx.packetsBad = vals["mainState"]["rx.packetsBad"]
|
||||
this.stat_rx.packetsDummy = vals["mainState"]["rx.packetsDummy"]
|
||||
|
||||
this.stat_tx.state = vals["mainState"]["tx.state"]
|
||||
this.stat_tx.snr = vals["mainState"]["rx.snr"]
|
||||
this.stat_tx.modcod = vals["mainState"]["rx.modcod"]
|
||||
this.stat_tx.frameSize = vals["mainState"]["rx.frameSize"]
|
||||
this.stat_tx.pilots = vals["mainState"]["rx.pilots"]
|
||||
this.stat_tx.speedOnTxKbit = vals["mainState"]["tx.speedOnTxKbit"]
|
||||
this.stat_tx.speedOnIifKbit = vals["mainState"]["rx.speedOnIifKbit"]
|
||||
|
||||
this.stat_cinc.occ = vals["mainState"]["cinc.occ"]
|
||||
this.stat_cinc.correlator = vals["mainState"]["cinc.correlator"]
|
||||
this.stat_cinc.correlatorFails = vals["mainState"]["cinc.correlatorFails"]
|
||||
this.stat_cinc.freqErr = vals["mainState"]["cinc.freqErr"]
|
||||
this.stat_cinc.freqErrAcc = vals["mainState"]["cinc.freqErrAcc"]
|
||||
this.stat_cinc.channelDelay = vals["mainState"]["cinc.channelDelay"]
|
||||
|
||||
this.stat_device.adrv = vals["mainState"]["device.adrv"]
|
||||
this.stat_device.zync = vals["mainState"]["device.zync"]
|
||||
this.stat_device.fpga = vals["mainState"]["device.fpga"]
|
||||
|
||||
this.testState = vals["mainState"]["testState"]
|
||||
},
|
||||
|
||||
resetPacketsStatistics() {
|
||||
fetch('/api/resetPacketStatistics', {
|
||||
method: 'POST'
|
||||
}).then(() => {
|
||||
this.stat_rx.packetsOk = 0
|
||||
this.stat_rx.packetsBad = 0
|
||||
this.stat_rx.packetsDummy = 0
|
||||
})
|
||||
},
|
||||
|
||||
updateSettings(vals) {
|
||||
this.settingFetchComplete = true
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
const doFetchStatistics = async () => {
|
||||
let d = await fetch("/api/get/statistics")
|
||||
this.updateStatistics(await d.json())
|
||||
|
||||
setTimeout(() => {
|
||||
doFetchStatistics()
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
doFetchStatistics().then(() => {})
|
||||
|
||||
const doFetchSettings = async () => {
|
||||
let d = await fetch("/api/get/settings")
|
||||
this.updateSettings(await d.json())
|
||||
}
|
||||
|
||||
doFetchSettings().then(() => {})
|
||||
|
||||
document.getElementById("app").removeAttribute("hidden")
|
||||
}
|
||||
})
|
||||
|
||||
// import MyComponent from './modules/header'
|
||||
// const sh = new Vue(MyComponent)
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@@ -2,16 +2,17 @@
|
||||
body {
|
||||
--text-color: #262626;
|
||||
--text-color2: #3d3d3d;
|
||||
--text-good: green;
|
||||
--text-bad: red;
|
||||
--text-good: #0CF500;
|
||||
--text-bad: #F5000C;
|
||||
|
||||
--brand-bg: #EDF3FE;
|
||||
--brand-text: #5488F7;
|
||||
--brand-bg: #B3C0D1;
|
||||
--brand-text: #0146f4;
|
||||
|
||||
--bg-color: #FEFEFE;
|
||||
--bg-selected: #F1F1F1;
|
||||
--bg-element: #a7a7a7;
|
||||
--bg-action: #5181fe;
|
||||
--bg-action: #81a7ff;
|
||||
--bg-danger: #ff6464;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
@@ -19,8 +20,8 @@ body {
|
||||
body {
|
||||
--text-color: #eee;
|
||||
--text-color2: #bbb;
|
||||
--text-good: greenyellow;
|
||||
--text-bad: orangered;
|
||||
--text-good: #91FF00;
|
||||
--text-bad: #FF1F2A;
|
||||
|
||||
--brand-bg: #393E50;
|
||||
--brand-text: #5F93F3;
|
||||
@@ -28,7 +29,8 @@ body {
|
||||
--bg-color: #2d2c33;
|
||||
--bg-selected: #424248;
|
||||
--bg-element: #626268;
|
||||
--bg-action: #4a70d5;
|
||||
--bg-action: #3a58af;
|
||||
--bg-danger: #ac1e1e;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,6 +44,7 @@ body {
|
||||
}
|
||||
|
||||
body {
|
||||
overflow-y: visible;
|
||||
background: var(--bg-color);
|
||||
margin: 0; /* браузеры зачем-то ставят свое значение */
|
||||
}
|
||||
@@ -50,31 +53,15 @@ body {
|
||||
margin: 0.5em;
|
||||
}
|
||||
|
||||
/* увеличение размера шрифтов */
|
||||
|
||||
* { font-size: large; }
|
||||
h1 { font-size: xxx-large; }
|
||||
h2 { font-size: xx-large; }
|
||||
h3 { font-size: larger; }
|
||||
|
||||
/* ========== MAIN STYLES ========== */
|
||||
|
||||
header > h1 {
|
||||
text-align: center;
|
||||
background-color: var(--brand-bg);
|
||||
padding: 0.5em;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
header * {
|
||||
color: var(--brand-text);
|
||||
}
|
||||
|
||||
header > nav {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
header > nav > a {
|
||||
margin: 0.5em;
|
||||
}
|
||||
|
||||
.value-good {
|
||||
color: var(--text-good);
|
||||
}
|
||||
|
Reference in New Issue
Block a user