сделал кеширование статистики и настроек терминала

This commit is contained in:
Vladislav Ostapov 2024-11-08 12:14:09 +03:00
parent fae7a2ffc8
commit a833c0f68a
4 changed files with 214 additions and 27 deletions

View File

@ -98,6 +98,7 @@ public:
ServerResources(const ServerResources&) = delete; ServerResources(const ServerResources&) = delete;
ServerResources(): sf(std::make_unique<http::resource::StaticFileFactory>()), api(std::make_unique<api_driver::ApiDriver>()) { ServerResources(): 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")); auth.users.emplace_back(std::make_shared<http::auth::User>("admin"));
sf->registerFile(INDEX_HTML, mime_types::text_html, false); sf->registerFile(INDEX_HTML, mime_types::text_html, false);

View File

@ -1,19 +1,187 @@
#include "terminal_api_driver.h" #include "terminal_api_driver.h"
#include <cmath> #include <cmath>
#include "terminal_api/ControlProtoCInterface.h" #include "terminal_api/ControlProtoCInterface.h"
#include <sstream> #include <sstream>
#include <iomanip> #include <iomanip>
#include <shared_mutex>
#include <boost/thread.hpp>
#include <boost/log/trivial.hpp>
#include "../dependencies/control_system/common/protocol_commands.h" #include "../dependencies/control_system/common/protocol_commands.h"
/**
* Этот демон нужен для того, чтобы получать статистику из API, а так же корректно сохранять настройки
*/
class api_driver::TerminalApiDaemon {
private:
TSID sid;
boost::thread daemon;
void updateStatistics() {
modulator_state modulator{};
CP_GetModulatorState(sid, modulator);
demodulator_state demodulator{};
CP_GetDemodulatorState(sid, demodulator);
device_state device{};
CP_GetDeviceState(sid, device);
{
std::lock_guard lock(this->stateMutex);
this->modState = modulator;
this->demodState = demodulator;
this->devState = device;
}
}
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{};
CP_GetBUC_LNB_settings(sid, bucLnb);
{
std::lock_guard lock(this->settingsMutex);
this->modSettings = mod;
this->demodSettings = demod;
this->acmSettings = acm;
this->dpdiSettings = dpdi;
this->bucLnbSettings = bucLnb;
}
}
void run() {
// это демон, который в бесконечном цикле опрашивает API
struct IntervalUpdate_t {
int64_t lastUpdate;
int64_t periodMs;
bool checkNeedUpdate(int64_t now) {
// тут нет смысла спать меньше чем на 20мс, поэтому можно разрешить чтение на некоторое время раньше
return now - lastUpdate >= (periodMs - 20);
}
int64_t getNextUpdate(int64_t now) {
if (checkNeedUpdate(now)) {
return 0;
}
auto next = now - lastUpdate;
return next < 0 ? 0 : next;
}
};
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;
try {
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;
try {
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();
}
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::shared_mutex stateMutex;
modulator_state modState{};
demodulator_state demodState{};
device_state devState{};
std::shared_mutex settingsMutex;
modulator_settings modSettings{};
demodulator_settings demodSettings{};
ACM_parameters_serv_ acmSettings{};
DPDI_parmeters dpdiSettings{};
buc_lnb_settings bucLnbSettings{};
public:
explicit TerminalApiDaemon(TSID sid): sid(sid), daemon([this]() { this->run(); }) {}
/**
* Получение статистики, копирует текущие значения в структуры, переданные по указателю. Если передан пустой указатель, копирования не произойдет.
* @param mod статистика модулятра
* @param demod статистика демодулятора
* @param dev статистика устройства (температуры)
*/
void getStatistics(modulator_state* mod, demodulator_state* demod, device_state* dev) {
if (mod != nullptr || demod != nullptr || dev != nullptr) {
std::shared_lock lock(this->stateMutex);
if (mod) { *mod = this->modState; }
if (demod) { *demod = this->demodState; }
if (dev) { *dev = this->devState; }
}
}
/**
* Получение настроек, копирует текущие значения в структуры, переданные по указателю. Если передан пустой указатель, копирования не произойдет.
*/
void getSettings(modulator_settings* mod, demodulator_settings* demod, ACM_parameters_serv_* acm, DPDI_parmeters* dpdi, buc_lnb_settings* bucLnb) {
if (mod || demod || acm || dpdi || bucLnb) {
std::shared_lock lock(this->settingsMutex);
if (mod) { *mod = this->modSettings; }
if (demod) { *demod = this->demodSettings; }
if (acm) { *acm = this->acmSettings; }
if (dpdi) { *dpdi = this->dpdiSettings; }
if (bucLnb) { *bucLnb = this->bucLnbSettings; }
}
}
~TerminalApiDaemon() {
try {
daemon.interrupt();
daemon.try_join_for(boost::chrono::seconds(2));
} catch (std::exception& e) {
BOOST_LOG_TRIVIAL(error) << "api_driver::~TerminalApiDaemon(): " << e.what();
}
}
};
api_driver::ApiDriver::ApiDriver() { api_driver::ApiDriver::ApiDriver() {
CP_Login("admin", "pass", &sid, &access); CP_Login("admin", "pass", &sid, &access);
CP_GetDmaDebug(sid, "status_init", &deviceInitState); CP_GetDmaDebug(sid, "status_init", &deviceInitState);
} }
void api_driver::ApiDriver::startDaemon() {
if (daemon == nullptr) {
daemon = std::make_unique<TerminalApiDaemon>(this->sid);
BOOST_LOG_TRIVIAL(info) << "api_driver::ApiDriver::startDaemon(): API daemon succes started!";
}
}
static const char* boolAsStr(bool value) { static const char* boolAsStr(bool value) {
return value ? "true" : "false"; return value ? "true" : "false";
} }
@ -28,12 +196,6 @@ static std::string buildEscapedString(const std::string& source) {
return "\"" + str + "\""; return "\"" + str + "\"";
} }
static bool DriverCP_GetCinC(TSID sid) {
modulator_settings s{};
CP_GetModulatorSettings(sid, s);
return s.is_cinc;
}
void writeDouble(std::ostream& out, double value, int prec = 2) { void writeDouble(std::ostream& out, double value, int prec = 2) {
if (std::isnan(value) || std::isinf(value)) { if (std::isnan(value) || std::isinf(value)) {
out << "\"nan\""; out << "\"nan\"";
@ -55,19 +217,18 @@ std::tuple<uint8_t, uint8_t> translateCoordinates(double abs) {
std::string api_driver::ApiDriver::loadTerminalState() const { std::string api_driver::ApiDriver::loadTerminalState() const {
if (daemon == nullptr) {
return R"({"error": "api daemon not started!"})";
}
std::stringstream result; std::stringstream result;
result << "{\n\"initState\":" << buildEscapedString(this->deviceInitState); result << "{\n\"initState\":" << buildEscapedString(this->deviceInitState);
modulator_state modulator{}; modulator_state modulator{};
CP_GetModulatorState(sid, modulator);
demodulator_state demodulator{}; demodulator_state demodulator{};
CP_GetDemodulatorState(sid, demodulator);
device_state device{}; device_state device{};
CP_GetDeviceState(sid, device); daemon->getStatistics(&modulator, &demodulator, &device);
const bool isCinC = this->getIsCinC();
const bool isCinC = DriverCP_GetCinC(sid);
result << ",\"isCinC\":" << boolAsStr(isCinC); result << ",\"isCinC\":" << boolAsStr(isCinC);
@ -166,19 +327,23 @@ void api_driver::ApiDriver::resetPacketStatistics() const {
} }
std::string api_driver::ApiDriver::loadSettings() const { std::string api_driver::ApiDriver::loadSettings() const {
modulator_settings modSettings{}; if (daemon == nullptr) {
CP_GetModulatorSettings(sid, modSettings); return R"({"error": "api daemon not started!"})";
uint32_t modulatorModcod; }
CP_GetModulatorParams(sid, "modcod", &modulatorModcod);
modulator_settings modSettings{};
demodulator_settings demodSettings{}; demodulator_settings demodSettings{};
CP_GetDemodulatorSettings(sid, demodSettings);
ACM_parameters_serv_ acmSettings{}; ACM_parameters_serv_ acmSettings{};
CP_GetAcmParams(sid, &acmSettings);
DPDI_parmeters dpdiSettings{}; DPDI_parmeters dpdiSettings{};
CP_GetDpdiParams(sid, &dpdiSettings);
buc_lnb_settings bucLnb{}; buc_lnb_settings bucLnb{};
CP_GetBUC_LNB_settings(sid, bucLnb); daemon->getSettings(&modSettings, &demodSettings, &acmSettings, &dpdiSettings, &bucLnb);
uint32_t modulatorModcod;
{
modulator_state ms{};
daemon->getStatistics(&ms, nullptr, nullptr);
modulatorModcod = ms.modcod;
}
std::stringstream result; std::stringstream result;
result << "{\n\"general.isCinC\":" << boolAsStr(modSettings.is_cinc); result << "{\n\"general.isCinC\":" << boolAsStr(modSettings.is_cinc);
@ -244,3 +409,9 @@ std::string api_driver::ApiDriver::loadSettings() const {
} }
api_driver::ApiDriver::~ApiDriver() = default; api_driver::ApiDriver::~ApiDriver() = default;
bool api_driver::ApiDriver::getIsCinC() const {
modulator_settings s{};
daemon->getSettings(&s, nullptr, nullptr, nullptr, nullptr);
return s.is_cinc;
}

View File

@ -1,11 +1,18 @@
#ifndef TERMINAL_API_DRIVER_H #ifndef TERMINAL_API_DRIVER_H
#define TERMINAL_API_DRIVER_H #define TERMINAL_API_DRIVER_H
#include <memory>
#include <string> #include <string>
#include <terminal_api/ControlProtoCInterface.h> #include <terminal_api/ControlProtoCInterface.h>
namespace api_driver { namespace api_driver {
constexpr int CACHE_STATISTICS_UPDATE_MS = 500;
constexpr int CACHE_SETTINGS_UPDATE_MS = 5000;
class TerminalApiDaemon;
/** /**
* Это ApiDriver. Все ответы он будет возвращать в виде json. * Это ApiDriver. Все ответы он будет возвращать в виде json.
*/ */
@ -13,6 +20,11 @@ namespace api_driver {
public: public:
explicit ApiDriver(); explicit ApiDriver();
/**
* Запуск демона
*/
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} * @return {"txState":false,"rxState":false,"rx.sym_sync_lock":false,"rx.freq_search_lock":false,"rx.afc_lock":false,"rx.pkt_sync":false}
@ -33,6 +45,9 @@ namespace api_driver {
unsigned int access{0}; unsigned int access{0};
std::string deviceInitState; std::string deviceInitState;
std::unique_ptr<TerminalApiDaemon> daemon;
bool getIsCinC() const;
}; };
} }

View File

@ -28,7 +28,7 @@
<div :class="{ value_bad: initState !== 'Успешная инициализация системы' }">{{ initState }}</div> <div :class="{ value_bad: initState !== 'Успешная инициализация системы' }">{{ initState }}</div>
<div id="content"> <div id="content">
<div class="tabs-body-item tabs-item-flex-container" v-show="activeTab === 'monitoring'"> <div class="tabs-body-item tabs-item-flex-container" v-show="activeTab === 'monitoring'">
<div> <div class="settings-set-container">
<h2>Статистика приема</h2> <h2>Статистика приема</h2>
<table> <table>
<tbody> <tbody>
@ -59,7 +59,7 @@
</table> </table>
<button @click="resetPacketsStatistics()"> Сброс статистики </button> <button @click="resetPacketsStatistics()"> Сброс статистики </button>
</div> </div>
<div> <div class="settings-set-container">
<h2>Статистика передачи</h2> <h2>Статистика передачи</h2>
<table> <table>
<tbody> <tbody>
@ -73,7 +73,7 @@
</tbody> </tbody>
</table> </table>
</div> </div>
<div v-if="isCinC === true"> <div class="settings-set-container" v-if="isCinC === true">
<h2>Статистика режима CinC</h2> <h2>Статистика режима CinC</h2>
<table> <table>
<tbody> <tbody>
@ -85,7 +85,7 @@
</tbody> </tbody>
</table> </table>
</div> </div>
<div> <div class="settings-set-container">
<h2>Состояние устройства</h2> <h2>Состояние устройства</h2>
<table> <table>
<tbody> <tbody>