diff --git a/devtool.py b/devtool.py index 3cf2418..d2e2777 100755 --- a/devtool.py +++ b/devtool.py @@ -44,6 +44,25 @@ def cp_get_dma_debug(base_url, param_name): return res.content.decode('utf-8') +def cp_set_network(base_url, param_name, value): + session = do_login(base_url) + res = session.post(f"{base_url}/dev/cpapicall", params={ + "f": "SetDmaDebug", + "param": param_name, + "value": value + }) + return res.content.decode('utf-8') + + +def cp_get_network(base_url, param_name): + session = do_login(base_url) + res = session.post(f"{base_url}/dev/cpapicall", params={ + "f": "GetDmaDebug", + "param": param_name + }) + return res.content.decode('utf-8') + + def set_logging(base_url, value): print(cp_set_dma_debug(base_url, "log_bool", value)) @@ -53,6 +72,8 @@ if __name__ == '__main__': print(f"Usage: {sys.argv[0]} http(s)://terminal-url logging on|off") print(f" set_dma_debug ") print(f" get_dma_debug ") + print(f" set_network ") + print(f" get_network ") exit(1) if sys.argv[2] == "logging": @@ -67,7 +88,17 @@ if __name__ == '__main__': print(cp_set_dma_debug(sys.argv[1], sys.argv[3], sys.argv[4])) elif sys.argv[2] == "get_dma_debug": if len(sys.argv) != 4: - print("Wrong set dma debug usage!") + print("Wrong get dma debug usage!") + else: + print(cp_get_dma_debug(sys.argv[1], sys.argv[3])) + elif sys.argv[2] == "set_network": + if len(sys.argv) != 5: + print("Wrong set network usage!") + else: + print(cp_set_dma_debug(sys.argv[1], sys.argv[3], sys.argv[4])) + elif sys.argv[2] == "get_network": + if len(sys.argv) != 4: + print("Wrong get dma debug usage!") else: print(cp_get_dma_debug(sys.argv[1], sys.argv[3])) else: diff --git a/front-generator/render-params.json b/front-generator/render-params.json index bb62170..ac1f769 100644 --- a/front-generator/render-params.json +++ b/front-generator/render-params.json @@ -120,10 +120,10 @@ { "widget": "settings-container", "childs": [ - {"widget": "text", "label": "Пароль для входа в сеть ЦЗС", "name": "netCesPassword"}, + {"widget": "text", "label": "Пароль для входа в сеть ЦЗС", "name": "cesPassword"}, {"widget": "h3", "label": "Настройки интерфейса управления"}, - {"widget": "ip-address", "label": "IP Интерфейса управления (/24)", "name": "netManagementIp"}, - {"widget": "text", "label": "Имя веб-сервера", "name": "netServerName"} + {"widget": "ip-address-mask", "label": "Интерфейс управления (a.d.d.r/mask)", "name": "managementIp"}, + {"widget": "text", "label": "Имя веб-сервера", "name": "serverName"} ] } ] @@ -322,7 +322,7 @@ "widget": "settings-container", "childs": [ {"widget": "h3", "label": "Настройки интерфейса управления"}, - {"widget": "ip-address", "label": "Интерфейс управления (/24)", "name": "managementIp"}, + {"widget": "ip-address-mask", "label": "Интерфейс управления (a.d.d.r/mask)", "name": "managementIp"}, { "widget": "select", "label": "Режим сети", "name": "isL2", "values": [{"label": "Маршрутизатор", "value": "false"}, {"label": "Коммутатор", "value": "true"}] @@ -464,7 +464,7 @@ "widget": "settings-container", "childs": [ {"widget": "h3", "label": "Настройки интерфейса управления"}, - {"widget": "ip-address", "label": "Интерфейс управления (/24)", "name": "managementIp"}, + {"widget": "ip-address-mask", "label": "Интерфейс управления (a.d.d.r/mask)", "name": "managementIp"}, { "widget": "select", "label": "Режим сети", "name": "isL2", "values": [{"label": "Маршрутизатор", "value": "false"}, {"label": "Коммутатор", "value": "true"}] diff --git a/front-generator/template/common/admin-methods.js.j2 b/front-generator/template/common/admin-methods.js.j2 index edc863c..3769cc1 100644 --- a/front-generator/template/common/admin-methods.js.j2 +++ b/front-generator/template/common/admin-methods.js.j2 @@ -74,7 +74,7 @@ }, async restoreAllSettings() { // Порядок применения настроек - const settingsApplyOrder = ['qos', 'tcpaccel', 'rxtx', 'buclnb', 'network']; + const settingsApplyOrder = ['qos', 'tcpaccel', 'dpdi', 'rxtx', 'buclnb', 'network']; // 1. Чтение JSON-файла, выбранного пользователем const fileInput = document.createElement('input'); diff --git a/front-generator/template/common/widgets.j2 b/front-generator/template/common/widgets.j2 index e4441da..d09f275 100644 --- a/front-generator/template/common/widgets.j2 +++ b/front-generator/template/common/widgets.j2 @@ -58,6 +58,10 @@ {{ widget.label }} {% endmacro %} +{% macro build_widget_ip_address_mask(param_group, widget) %} + {{ widget.label }} + +{% endmacro %} {% macro build_widget_text(param_group, widget) %} {{ widget.label }} @@ -78,22 +82,23 @@ {% elif widget.widget == 'modulation-modcod' %}{{ build_widget_modulation_modcod(param_group, widget) }} {% elif widget.widget == 'modulation-speed' %}{{ build_widget_modulation_speed(param_group, widget) }} {% elif widget.widget == 'ip-address' %}{{ build_widget_ip_address(param_group, widget) }} +{% elif widget.widget == 'ip-address-mask' %}{{ build_widget_ip_address_mask(param_group, widget) }} {% elif widget.widget == 'text' %}{{ build_widget_text(param_group, widget) }} {% else %}

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

{{ widget }}

{% endif %} {% endmacro %} {% macro build_getter_js(param_group, widget) %}{% if widget.widget in ['flex-container', 'settings-container', 'h2', 'h3', 'submit', 'watch', 'watch-expr'] %}null{% -elif widget.widget in ['checkbox', 'number', 'select', 'ip-address', 'modulation-modcod', 'modulation-speed', 'text'] %}this.param{{ param_group | title }}.{{ widget.name }}{% +elif widget.widget in ['checkbox', 'number', 'select', 'ip-address', 'ip-address-mask', 'modulation-modcod', 'modulation-speed', 'text'] %}this.param{{ param_group | title }}.{{ widget.name }}{% elif widget.widget == 'number-int' %}parseFloat(this.param{{ param_group | title }}.{{ widget.name }}.replace(/[^0-9,.]/g, '').replace(',', '.')){% else %}

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

{{ widget }}

{% endif %}{% endmacro %} {% macro build_setter_js(param_group, widget, expr) %}{% if widget.widget in ['flex-container', 'settings-container', 'h2', 'h3', 'submit', 'watch', 'watch-expr'] %}null{% -elif widget.widget in ['checkbox', 'number', 'select', 'ip-address', 'modulation-modcod', 'modulation-speed', 'text'] %}this.param{{ param_group | title }}.{{ widget.name }} = {{ expr }}{% +elif widget.widget in ['checkbox', 'number', 'select', 'ip-address', 'ip-address-mask', 'modulation-modcod', 'modulation-speed', 'text'] %}this.param{{ param_group | title }}.{{ widget.name }} = {{ expr }}{% elif widget.widget == 'number-int' %}this.param{{ param_group | title }}.{{ widget.name }} = this.inputFormatNumber({{ expr }}, {{ js_build_number_number_validator(widget) }}){% else %}

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

{{ widget }}

{% endif %}{% endmacro %} {% macro build_setter(param_group, widget, expr) %}{% if widget.widget in ['flex-container', 'settings-container', 'h2', 'h3', 'submit', 'watch', 'watch-expr'] %}null{% -elif widget.widget in ['checkbox', 'number', 'select', 'ip-address', 'modulation-modcod', 'modulation-speed', 'text'] %}param{{ param_group | title }}.{{ widget.name }} = {{ expr }}{% +elif widget.widget in ['checkbox', 'number', 'select', 'ip-address', 'ip-address-mask', 'modulation-modcod', 'modulation-speed', 'text'] %}param{{ param_group | title }}.{{ widget.name }} = {{ expr }}{% elif widget.widget == 'number-int' %}param{{ param_group | title }}.{{ widget.name }} = inputFormatNumber({{ expr }}, {{ js_build_number_number_validator(widget) }}){% else %}

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

{{ widget }}

{% endif %}{% endmacro %} diff --git a/src/api-driver/structs.cpp b/src/api-driver/structs.cpp index 8c02f79..5accb97 100644 --- a/src/api-driver/structs.cpp +++ b/src/api-driver/structs.cpp @@ -9,50 +9,6 @@ #define TIME_NOW() std::chrono::time_point_cast(std::chrono::system_clock::now()).time_since_epoch().count() -typedef boost::property_tree::ptree::path_type json_path; - -// static int calculateSubnetMask(const std::string& subnet_mask) { -// int mask = 0; -// std::istringstream iss(subnet_mask); -// std::string octet; -// while (std::getline(iss, octet, '.')) { -// int octet_value = std::stoi(octet); -// for (int i = 7; i >= 0; i--) { -// if (octet_value & (1 << i)) { -// mask++; -// } -// } -// } -// return mask; -// } - -/** - * Преобразует строку вида `1.2.3.4/24` в пару строк вида `1.2.3.4` `255.255.255.0` - */ -// std::pair splitIpAndMask(const std::string& input) { -// auto pos = input.find('/'); -// if (pos == std::string::npos) { -// // Обработка ошибки: нет символа '/' -// throw std::runtime_error("address not contains mask"); -// } -// std::string ip = input.substr(0, pos); -// const unsigned int mask_int = std::stoul(input.substr(pos + 1)); -// -// if (mask_int > 32) { -// throw std::runtime_error("invalid mask"); -// } -// -// std::string mask_binary = std::string(mask_int, '1') + std::string(32 - mask_int, '0'); -// std::string mask_str; -// -// for (unsigned int i = 0; i < 4; ++i) { -// std::string octet = mask_binary.substr(i * 8u, 8); -// int octet_value = std::stoi(octet, nullptr, 2); -// mask_str += std::to_string(octet_value) + (i < 3 ? "." : ""); -// } -// -// return std::make_pair(ip, mask_str); -// } static inline void rtrim(std::string &s) { s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) { return !std::isspace(ch); @@ -94,14 +50,13 @@ std::string makeTimepointFromMillis(int64_t unix_time_ms) { #ifdef API_OBJECT_DEBUG_METRICS_ENABLE api_driver::obj::StatisticsLogger::StatisticsLogger(): timeStart(TIME_NOW()) {} -std::string api_driver::obj::StatisticsLogger::getSettings() { +nlohmann::json api_driver::obj::StatisticsLogger::getSettings() { std::lock_guard _lock(mutex); - std::stringstream res; - res << "{\"en\":" << boolAsStr(this->logEn); - res << ",\"logPeriodMs\":" << logPeriodMs; - res << ",\"maxAgeMs\":" << maxAgeMs; - res << '}'; - return res.str(); + nlohmann::json res; + res["en"] = this->logEn; + res["logPeriodMs"] = logPeriodMs.load(); + res["maxAgeMs"] = maxAgeMs.load(); + return res; } void api_driver::obj::StatisticsLogger::setSettings(const nlohmann::json& data) { @@ -178,6 +133,49 @@ api_driver::obj::StatisticsLogger::~StatisticsLogger() = default; #endif #ifdef API_OBJECT_NETWORK_SETTINGS_ENABLE +static int calculateSubnetMask(const std::string& subnet_mask) { + int mask = 0; + std::istringstream iss(subnet_mask); + std::string octet; + while (std::getline(iss, octet, '.')) { + int octet_value = std::stoi(octet); + for (int i = 7; i >= 0; i--) { + if (octet_value & (1 << i)) { + mask++; + } + } + } + return mask; +} + +/** + * Преобразует строку вида `1.2.3.4/24` в пару строк вида `1.2.3.4` `255.255.255.0` + */ +std::pair splitIpAndMask(const std::string& input) { + auto pos = input.find('/'); + if (pos == std::string::npos) { + // Обработка ошибки: нет символа '/' + throw std::runtime_error("address not contains mask"); + } + std::string ip = input.substr(0, pos); + const unsigned int mask_int = std::stoul(input.substr(pos + 1)); + + if (mask_int > 32) { + throw std::runtime_error("invalid mask"); + } + + std::string mask_binary = std::string(mask_int, '1') + std::string(32 - mask_int, '0'); + std::string mask_str; + + for (unsigned int i = 0; i < 4; ++i) { + std::string octet = mask_binary.substr(i * 8u, 8); + int octet_value = std::stoi(octet, nullptr, 2); + mask_str += std::to_string(octet_value) + (i < 3 ? "." : ""); + } + + return std::make_pair(ip, mask_str); +} + api_driver::obj::TerminalNetworkSettings::TerminalNetworkSettings() { loadDefaults(); } api_driver::obj::TerminalNetworkSettings::TerminalNetworkSettings(const TerminalNetworkSettings &src) = default; @@ -185,7 +183,7 @@ api_driver::obj::TerminalNetworkSettings::TerminalNetworkSettings(const Terminal api_driver::obj::TerminalNetworkSettings & api_driver::obj::TerminalNetworkSettings::operator=(const TerminalNetworkSettings &src) = default; void api_driver::obj::TerminalNetworkSettings::loadDefaults() { - managementIp = "0.0.0.0"; + managementIp = "0.0.0.0/24"; managementGateway = ""; isL2 = true; dataIp = "0.0.0.0"; @@ -197,8 +195,8 @@ void api_driver::obj::TerminalNetworkSettings::updateCallback(proxy::CpProxy &cp loadDefaults(); try { managementIp = cp.getNetwork("addr"); - // s.managementIp += "/"; - // s.managementIp += std::to_string(calculateSubnetMask(cp.getNetwork("mask"))); + managementIp += "/"; + managementIp += std::to_string(calculateSubnetMask(cp.getNetwork("mask"))); managementGateway = cp.getNetwork("gateway"); if (cp.getNetwork("mode") == "tun") { @@ -228,12 +226,13 @@ void api_driver::obj::TerminalNetworkSettings::updateFromJson(const nlohmann::js void api_driver::obj::TerminalNetworkSettings::store(proxy::CpProxy& cp) { try { cp.setNetwork("mode", isL2 ? "tap" : "tun"); - cp.setNetwork("addr", managementIp); + auto [mAddr, mMask] = splitIpAndMask(managementIp); + cp.setNetwork("addr", mAddr); + cp.setNetwork("mask", mMask); if (!isL2) { cp.setNetwork("addr_data", dataIp); } - cp.setNetwork("mask", "255.255.255.0"); cp.setNetwork("gateway", managementGateway); // cp.setNetwork("data_mtu", std::to_string(dataMtu)); diff --git a/src/api-driver/structs.h b/src/api-driver/structs.h index 6b7f0b0..e162d62 100644 --- a/src/api-driver/structs.h +++ b/src/api-driver/structs.h @@ -7,8 +7,6 @@ #include #include #include -//#include - #include "common/nlohmann/json.hpp" @@ -30,7 +28,7 @@ namespace api_driver::obj { * * @return {"en": bool, "logPeriodMs": int, "maxAgeMs": int} */ - std::string getSettings(); + nlohmann::json getSettings(); void setSettings(const nlohmann::json& data); void updateCallback(proxy::CpProxy& cp); diff --git a/src/main.cpp b/src/main.cpp index a39e87f..b2965de 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -595,6 +595,8 @@ public: })); #ifdef API_OBJECT_DEBUG_METRICS_ENABLE s.resources.emplace_back(std::make_unique("/dev/settings", this->auth, http::auth::User::DEVELOPER, [this](const auto& req, auto& rep) { + rep.status = http::server::ok; + rep.headers.push_back({.name = "Content-Type", .value = toString(mime_types::text_plain)}); nlohmann::json resultJson; try { @@ -603,7 +605,7 @@ public: resultJson["logstat"] = api->getLoggingStatisticsSettings(); } else if (req.method == "POST") { auto reqJson = nlohmann::json::parse(std::string(req.payload.begin(), req.payload.end())); - api->setQosSettings(reqJson); + api->setLoggingStatisticsSettings(reqJson); resultJson["status"] = "ok"; resultJson["logstat"] = api->getLoggingStatisticsSettings(); diff --git a/src/terminal_api_driver.cpp b/src/terminal_api_driver.cpp index 8bf9a3c..42e803d 100644 --- a/src/terminal_api_driver.cpp +++ b/src/terminal_api_driver.cpp @@ -186,7 +186,7 @@ std::string api_driver::ApiDriver::getOtaFileLocation() const { #endif #ifdef MODEM_IS_SCPC -std::string api_driver::ApiDriver::getLoggingStatisticsSettings() { +nlohmann::json api_driver::ApiDriver::getLoggingStatisticsSettings() { return this->daemon->statsLogs.getSettings(); } diff --git a/src/terminal_api_driver.h b/src/terminal_api_driver.h index 7f42ffe..23fbaf5 100644 --- a/src/terminal_api_driver.h +++ b/src/terminal_api_driver.h @@ -78,7 +78,7 @@ namespace api_driver { void executeInApi(const std::function &callback); #ifdef API_OBJECT_DEBUG_METRICS_ENABLE - std::string getLoggingStatisticsSettings(); + nlohmann::json getLoggingStatisticsSettings(); void setLoggingStatisticsSettings(const nlohmann::json& data); /** diff --git a/static/main-scpc.html b/static/main-scpc.html index c6c3389..356a5ff 100644 --- a/static/main-scpc.html +++ b/static/main-scpc.html @@ -494,8 +494,8 @@

Настройки интерфейса управления