куча изменений, но зато теперь сохраняются настройки QoS и есть алгоритм сохранения параметров в API

This commit is contained in:
2024-11-11 17:35:25 +03:00
parent 435f215118
commit cb9d412c8e
10 changed files with 398 additions and 77 deletions

View File

@@ -11,7 +11,6 @@
#include <boost/log/utility/setup/formatter_parser.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/asio/ssl/context.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <cstddef>
#include <memory>
@@ -101,9 +100,6 @@ public:
api->startDaemon();
auth.users.emplace_back(std::make_shared<http::auth::User>("admin"));
sf->registerFile(INDEX_HTML, mime_types::text_html, false);
sf->registerFile(LOGIN_HTML, mime_types::text_html, false);
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);
@@ -115,6 +111,9 @@ public:
constexpr bool allowCacheCss = true;
#endif
sf->registerFile(INDEX_HTML, mime_types::text_html, allowCacheCss);
sf->registerFile(LOGIN_HTML, mime_types::text_html, allowCacheCss);
sf->registerFile(STYLE_CSS, mime_types::text_css, allowCacheCss);
sf->registerFile(FIELDS_CSS, mime_types::text_css, allowCacheCss);
}
@@ -177,18 +176,6 @@ public:
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>("/vid/video_2024-11-06_15-49-35.mp4", [this](const auto& req, auto& rep) { boost::ignore_unused(req); sf->serve(KB_MP4, rep); }));
s.resources.emplace_back(std::make_unique<http::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) {
if (req.method != "GET") {
http::server::stockReply(http::server::bad_request, rep);
@@ -203,6 +190,20 @@ 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") {
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::resource::GenericResource>("/api/resetPacketStatistics", [this](const auto& req, auto& rep) {
if (req.method != "POST") {
http::server::stockReply(http::server::bad_request, rep);
@@ -216,19 +217,36 @@ 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::resource::GenericResource>("/api/set/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 += "}";
rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size());
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"({"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());
}
}));
}
~ServerResources() = default;

View File

@@ -7,6 +7,8 @@
#include <shared_mutex>
#include <boost/thread.hpp>
#include <boost/log/trivial.hpp>
#include <boost/property_tree/json_parser.hpp>
#include "../dependencies/control_system/common/protocol_commands.h"
@@ -20,16 +22,16 @@ private:
void updateStatistics() {
modulator_state modulator{};
CP_GetModulatorState(sid, modulator);
demodulator_state demodulator{};
CP_GetDemodulatorState(sid, demodulator);
device_state device{};
std::lock_guard lock(this->cpApiMutex);
CP_GetModulatorState(sid, modulator);
CP_GetDemodulatorState(sid, demodulator);
CP_GetDeviceState(sid, device);
{
std::lock_guard lock(this->stateMutex);
std::lock_guard lock2(this->stateMutex);
this->modState = modulator;
this->demodState = demodulator;
this->devState = device;
@@ -38,20 +40,22 @@ private:
void updateSettings() {
modulator_settings mod{};
CP_GetModulatorSettings(sid, mod);
// uint32_t modulatorModcod;
// CP_GetModulatorParams(sid, "modcod", &modulatorModcod);
demodulator_settings demod{};
CP_GetDemodulatorSettings(sid, demod);
ACM_parameters_serv_ acm{};
CP_GetAcmParams(sid, &acm);
DPDI_parmeters dpdi{};
CP_GetDpdiParams(sid, &dpdi);
buc_lnb_settings bucLnb{};
std::lock_guard lock(this->cpApiMutex);
CP_GetModulatorSettings(sid, mod);
CP_GetDemodulatorSettings(sid, demod);
CP_GetAcmParams(sid, &acm);
CP_GetDpdiParams(sid, &dpdi);
CP_GetBUC_LNB_settings(sid, bucLnb);
{
std::lock_guard lock(this->settingsMutex);
std::lock_guard lock2(this->settingsMutex);
this->modSettings = mod;
this->demodSettings = demod;
this->acmSettings = acm;
@@ -60,6 +64,17 @@ private:
}
}
void updateQos() {
bool tmp1; std::string tmp2;
std::scoped_lock lock{this->cpApiMutex};
CP_GetQoSSettings(this->sid, tmp2, tmp1);
{
std::lock_guard lock2(this->qosSettingsMutex);
this->qosEnabled = tmp1;
this->qosClassesJson = tmp2;
}
}
void run() {
// это демон, который в бесконечном цикле опрашивает API
@@ -67,12 +82,14 @@ private:
int64_t lastUpdate;
int64_t periodMs;
bool checkNeedUpdate(int64_t now) {
std::function<void()> callback;
bool checkNeedUpdate(int64_t now) const {
// тут нет смысла спать меньше чем на 20мс, поэтому можно разрешить чтение на некоторое время раньше
return now - lastUpdate >= (periodMs - 20);
}
int64_t getNextUpdate(int64_t now) {
int64_t getNextUpdate(int64_t now) const {
if (checkNeedUpdate(now)) {
return 0;
}
@@ -81,40 +98,57 @@ private:
}
};
IntervalUpdate_t statUpdate{.lastUpdate = 0, .periodMs = CACHE_STATISTICS_UPDATE_MS};
IntervalUpdate_t settingsUpdate{.lastUpdate = 0, .periodMs = CACHE_SETTINGS_UPDATE_MS};
while (true) {
auto now = std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::system_clock::now()).time_since_epoch().count();
if (statUpdate.checkNeedUpdate(now)) {
statUpdate.lastUpdate = now;
IntervalUpdate_t updaters[] = {
// обновление статистики
{.lastUpdate = 0, .periodMs = CACHE_STATISTICS_UPDATE_MS, .callback = [this]() {
try {
updateStatistics();
this->updateStatistics();
BOOST_LOG_TRIVIAL(debug) << "api_driver::TerminalApiDaemon::updateStatistics(): success update!";
} catch (std::exception& e) {
BOOST_LOG_TRIVIAL(error) << "api_driver::TerminalApiDaemon::updateStatistics(): " << e.what();
}
now = std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::system_clock::now()).time_since_epoch().count();
}
if (settingsUpdate.checkNeedUpdate(now)) {
settingsUpdate.lastUpdate = now;
}},
// обновление кеша настроек
{.lastUpdate = 0, .periodMs = CACHE_SETTINGS_UPDATE_MS, .callback = [this]() {
try {
updateSettings();
this->updateSettings();
BOOST_LOG_TRIVIAL(debug) << "api_driver::TerminalApiDaemon::updateSettings(): success update!";
} catch (std::exception& e) {
BOOST_LOG_TRIVIAL(error) << "api_driver::TerminalApiDaemon::updateSettings(): " << e.what();
}
now = std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::system_clock::now()).time_since_epoch().count();
}},
// обновление кеша QoS
{.lastUpdate = 0, .periodMs = CACHE_QOS_UPDATE_MS, .callback = [this]() {
try {
this->updateQos();
BOOST_LOG_TRIVIAL(debug) << "api_driver::TerminalApiDaemon::updateQos(): success update!";
} catch (std::exception& e) {
BOOST_LOG_TRIVIAL(error) << "api_driver::TerminalApiDaemon::updateQos(): " << e.what();
}
}}
};
while (true) {
int64_t sleepTime = 60000; // минута по-умолчанию
auto now = std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::system_clock::now()).time_since_epoch().count();
for (auto& u: updaters) {
if (u.checkNeedUpdate(now)) {
u.lastUpdate = now;
u.callback();
now = std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::system_clock::now()).time_since_epoch().count();
}
sleepTime = std::min(sleepTime, u.getNextUpdate(now));
}
auto sleepTime = statUpdate.getNextUpdate(now);
sleepTime = std::min(sleepTime, settingsUpdate.getNextUpdate(now));
if (sleepTime > 0) {
boost::this_thread::sleep_for(boost::chrono::duration(boost::chrono::milliseconds(sleepTime)));
}
}
}
std::mutex cpApiMutex;
std::shared_mutex stateMutex;
modulator_state modState{};
demodulator_state demodState{};
@@ -127,8 +161,14 @@ private:
DPDI_parmeters dpdiSettings{};
buc_lnb_settings bucLnbSettings{};
std::shared_mutex qosSettingsMutex;
bool qosEnabled;
std::string qosClassesJson;
public:
explicit TerminalApiDaemon(TSID sid): sid(sid), daemon([this]() { this->run(); }) {}
explicit TerminalApiDaemon(TSID sid): sid(sid), daemon([this]() { this->run(); }), qosEnabled(false) {
this->qosClassesJson = "{}";
}
/**
* Получение статистики, копирует текущие значения в структуры, переданные по указателю. Если передан пустой указатель, копирования не произойдет.
@@ -159,6 +199,26 @@ public:
}
}
void getQosSettings(bool& isEnabled, std::string& json) {
std::shared_lock lock(this->settingsMutex);
isEnabled = this->qosEnabled;
json = this->qosClassesJson;
}
void setQosSettings(bool enabled, const std::string& str, bool readback = true) {
std::lock_guard lock(this->cpApiMutex);
CP_SetQoSSettings(this->sid, str, enabled);
if (readback) {
bool tmp1; std::string tmp2;
CP_GetQoSSettings(this->sid, tmp2, tmp1);
{
std::lock_guard lock2(this->qosSettingsMutex);
this->qosEnabled = tmp1;
this->qosClassesJson = tmp2;
}
}
}
~TerminalApiDaemon() {
try {
daemon.interrupt();
@@ -404,12 +464,27 @@ std::string api_driver::ApiDriver::loadSettings() const {
result << ",\n\"serviceSettings.refClk10M\":" << boolAsStr(bucLnb.is_ref_10MHz_output);
result << ",\"serviceSettings.autoStart\":" << boolAsStr(bucLnb.is_save_current_state);
bool qosEnabled = false; std::string qosClasses;
daemon->getQosSettings(qosEnabled, qosClasses);
result << ",\n\"qos.enabled\":" << boolAsStr(qosEnabled);
result << ",\"qos.profile\":" << qosClasses;
result << "}";
return result.str();
}
api_driver::ApiDriver::~ApiDriver() = default;
void api_driver::ApiDriver::setQosSettings(boost::property_tree::ptree &pt) {
bool enabled = pt.get<bool>("en");
pt.erase("en");
std::ostringstream oss;
write_json(oss, pt);
this->daemon->setQosSettings(enabled, oss.str());
}
bool api_driver::ApiDriver::getIsCinC() const {
modulator_settings s{};
daemon->getSettings(&s, nullptr, nullptr, nullptr, nullptr);

View File

@@ -3,6 +3,7 @@
#include <memory>
#include <string>
#include <boost/property_tree/ptree.hpp>
#include <terminal_api/ControlProtoCInterface.h>
@@ -10,6 +11,7 @@ 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;
@@ -40,6 +42,8 @@ namespace api_driver {
~ApiDriver();
void setQosSettings(boost::property_tree::ptree & pt);
private:
TSID sid{0};
unsigned int access{0};