修复问题
This commit is contained in:
@@ -19,7 +19,7 @@ asio::awaitable<void> Data_Feed_UDP_Server::send_coro(std::string_view data) {
|
||||
co_return;
|
||||
}
|
||||
asio::awaitable<void> Data_Feed_UDP_Server::_open() {
|
||||
const auto value = specific.snapshot();
|
||||
const auto value = specific.read([](const auto& value) { return value; });
|
||||
svr.set_bind_address("0.0.0.0", value.port);
|
||||
svr.create();
|
||||
server_logger->c_debug({}, {}, to_string() + "开启!");
|
||||
@@ -60,7 +60,7 @@ void Data_feed_Config::server(Global* g) {
|
||||
});
|
||||
}
|
||||
void BIN_Msg_Buffer::push(std::string_view msg) {
|
||||
auto output_packet_size = Global::instance()->mode_acs.data_feed_config.settings.member<&Data_feed_Config_Data::packet_byte_size>().snapshot();
|
||||
auto output_packet_size = Global::instance()->mode_acs.data_feed_config.settings.member<&Data_feed_Config_Data::packet_byte_size>().read([](const auto& value) { return value; });
|
||||
std::lock_guard<std::mutex> g(mtx);
|
||||
auto& pool = Global::instance()->mode_acs.data_feed_config.pool_;
|
||||
if (msg_list_cache.empty() || msg_list_cache.back()->size() > output_packet_size) {
|
||||
@@ -85,7 +85,7 @@ BIN_Msg_Buffer::BIN_Msg_Buffer() {
|
||||
msg_list.reserve(8 * 1024);
|
||||
}
|
||||
Psc::JSON BIN_Msg_Buffer::state_json() {
|
||||
auto output_packet_size = Global::instance()->mode_acs.data_feed_config.settings.member<&Data_feed_Config_Data::packet_byte_size>().snapshot();
|
||||
auto output_packet_size = Global::instance()->mode_acs.data_feed_config.settings.member<&Data_feed_Config_Data::packet_byte_size>().read([](const auto& value) { return value; });
|
||||
size_t size, cache_size, pool_capacity, pool_free_count;
|
||||
{
|
||||
std::lock_guard<std::mutex> g(mtx);
|
||||
|
||||
@@ -44,15 +44,13 @@ public:
|
||||
}
|
||||
virtual Psc::JSON to_json() {
|
||||
Psc::JSON ret = With_Loop_Coro::to_base_json();
|
||||
ret.append(Psc::JSON("output_format", output_format.snapshot().to_base_json()));
|
||||
ret.append(Psc::JSON("output_format", output_format.read([](const auto& value) { return value.to_base_json(); })));
|
||||
return ret;
|
||||
}
|
||||
virtual void from_json(const Psc::JSON* that_json, bool not_exist_use_default_value) {
|
||||
With_Loop_Coro::from_base_json(that_json, not_exist_use_default_value);
|
||||
auto value = output_format.snapshot();
|
||||
value.from_base_json(that_json->get("output_format"), not_exist_use_default_value);
|
||||
output_format.write([&](auto& target) {
|
||||
target = value;
|
||||
output_format.write([&](auto& value) {
|
||||
value.from_base_json(that_json->get("output_format"), not_exist_use_default_value);
|
||||
});
|
||||
}
|
||||
virtual Psc::JSON get_custom_state_json() {
|
||||
@@ -96,7 +94,7 @@ public:
|
||||
Psc::asio_socket::TCP_Server_Coro svr;
|
||||
Psc::JSON get_custom_state_json() override {
|
||||
auto& state = svr.state;
|
||||
auto value = specific.snapshot();
|
||||
auto value = specific.read([](const auto& value) { return value; });
|
||||
auto ret = value.to_base_json();
|
||||
ret.key = "fixed";
|
||||
auto result = VAR_JSON_1(state);
|
||||
@@ -115,21 +113,19 @@ public:
|
||||
}
|
||||
void from_json(const Psc::JSON* that_json, bool not_exist_use_default_value) override {
|
||||
Data_Feed::from_json(that_json, not_exist_use_default_value);
|
||||
auto value = specific.snapshot();
|
||||
value.from_base_json(that_json, not_exist_use_default_value);
|
||||
specific.write([&](auto& target) {
|
||||
target = value;
|
||||
specific.write([&](auto& value) {
|
||||
value.from_base_json(that_json, not_exist_use_default_value);
|
||||
});
|
||||
}
|
||||
Psc::JSON to_json() override {
|
||||
return Data_Feed::to_json() += specific.snapshot().to_base_json();
|
||||
return Data_Feed::to_json() += specific.read([](const auto& value) { return value.to_base_json(); });
|
||||
}
|
||||
asio::awaitable<void> _close() override {
|
||||
co_await svr.close_coro();
|
||||
co_return;
|
||||
}
|
||||
asio::awaitable<void> _open() override {
|
||||
const auto value = specific.snapshot();
|
||||
const auto value = specific.read([](const auto& value) { return value; });
|
||||
svr.set_connect_user_buffer_size(value.connect_user_buffer_size);
|
||||
svr.set_connect_system_buffer_size(value.connect_system_buffer_size);
|
||||
svr.set_tcp_no_delay(false);
|
||||
@@ -206,7 +202,7 @@ public:
|
||||
co_return;
|
||||
}
|
||||
asio::awaitable<void> _open() override {
|
||||
const auto value = specific.snapshot();
|
||||
const auto value = specific.read([](const auto& value) { return value; });
|
||||
Psc::asio_socket::Sockaddr_In sockaddr_in;
|
||||
sockaddr_in.ip = value.url;
|
||||
sockaddr_in.port = value.port;
|
||||
@@ -217,14 +213,12 @@ public:
|
||||
}
|
||||
void from_json(const Psc::JSON* that_json, bool not_exist_use_default_value) override {
|
||||
Data_Feed::from_json(that_json, not_exist_use_default_value);
|
||||
auto value = specific.snapshot();
|
||||
value.from_base_json(that_json, not_exist_use_default_value);
|
||||
specific.write([&](auto& target) {
|
||||
target = value;
|
||||
specific.write([&](auto& value) {
|
||||
value.from_base_json(that_json, not_exist_use_default_value);
|
||||
});
|
||||
}
|
||||
Psc::JSON to_json() override {
|
||||
return Data_Feed::to_json() += specific.snapshot().to_base_json();
|
||||
return Data_Feed::to_json() += specific.read([](const auto& value) { return value.to_base_json(); });
|
||||
}
|
||||
};
|
||||
class Data_Feed_UDP_Server_Data {
|
||||
@@ -265,14 +259,12 @@ public:
|
||||
}
|
||||
void from_json(const Psc::JSON* that_json, bool not_exist_use_default_value) override {
|
||||
Data_Feed::from_json(that_json, not_exist_use_default_value);
|
||||
auto value = specific.snapshot();
|
||||
value.from_base_json(that_json, not_exist_use_default_value);
|
||||
specific.write([&](auto& target) {
|
||||
target = value;
|
||||
specific.write([&](auto& value) {
|
||||
value.from_base_json(that_json, not_exist_use_default_value);
|
||||
});
|
||||
}
|
||||
Psc::JSON to_json() override {
|
||||
return Data_Feed::to_json() += specific.snapshot().to_base_json();
|
||||
return Data_Feed::to_json() += specific.read([](const auto& value) { return value.to_base_json(); });
|
||||
}
|
||||
asio::awaitable<void> _close() override {
|
||||
co_await svr.close_coro();
|
||||
@@ -316,14 +308,12 @@ public:
|
||||
Psc::asio_socket::UDP_Client_Coro cli;
|
||||
void from_json(const Psc::JSON* that_json, bool not_exist_use_default_value) override {
|
||||
Data_Feed::from_json(that_json, not_exist_use_default_value);
|
||||
auto value = specific.snapshot();
|
||||
value.from_base_json(that_json, not_exist_use_default_value);
|
||||
specific.write([&](auto& target) {
|
||||
target = value;
|
||||
specific.write([&](auto& value) {
|
||||
value.from_base_json(that_json, not_exist_use_default_value);
|
||||
});
|
||||
}
|
||||
Psc::JSON to_json() override {
|
||||
return Data_Feed::to_json() += specific.snapshot().to_base_json();
|
||||
return Data_Feed::to_json() += specific.read([](const auto& value) { return value.to_base_json(); });
|
||||
}
|
||||
asio::awaitable<void> _close() override {
|
||||
std::cout << "udp client target address:" << cli.dest_address.to_string() << " closed" << std::endl;
|
||||
@@ -331,7 +321,7 @@ public:
|
||||
co_return;
|
||||
}
|
||||
asio::awaitable<void> _open() override {
|
||||
const auto value = specific.snapshot();
|
||||
const auto value = specific.read([](const auto& value) { return value; });
|
||||
cli.create();
|
||||
cli.set_dest_address(value.url, value.port);
|
||||
co_await cli.connect_coro();
|
||||
@@ -392,10 +382,8 @@ public:
|
||||
t->from_json(&it, not_exist_use_default_value);
|
||||
map.push_back(t);
|
||||
}
|
||||
auto value = settings.snapshot();
|
||||
value.from_base_json(that_json, not_exist_use_default_value);
|
||||
settings.write([&](auto& target) {
|
||||
target = value;
|
||||
settings.write([&](auto& value) {
|
||||
value.from_base_json(that_json, not_exist_use_default_value);
|
||||
});
|
||||
}
|
||||
Psc::JSON list() const {
|
||||
@@ -406,7 +394,7 @@ public:
|
||||
return connect_json;
|
||||
}
|
||||
Psc::JSON to_json() const {
|
||||
Psc::JSON ret = settings.snapshot().to_base_json();
|
||||
Psc::JSON ret = settings.read([](const auto& value) { return value.to_base_json(); });
|
||||
ret.append({"list", list()});
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ Data_Source::Data_Source() {
|
||||
// parse_format = std::make_shared<Input_Format>();
|
||||
// 写入到配置文件是懒加载 其他保存时他跟着保存
|
||||
base_station.handle_when_updated = [this](SSR::HULC_Status_Message msg) {
|
||||
if (!settings.member<&Data_Source_Data::update_form_gps>().snapshot())
|
||||
if (!settings.member<&Data_Source_Data::update_form_gps>().read([](const auto& value) { return value; }))
|
||||
return;
|
||||
settings.write([&](auto& value) {
|
||||
value.lat = msg.get_latitude();
|
||||
@@ -179,7 +179,7 @@ std::optional<std::string> File_Data_Source::get_raw_line(int& ret_index) {
|
||||
}
|
||||
std::optional<std::string> log_info = std::nullopt;
|
||||
if (index == part_infos.size()) {
|
||||
const auto config = specific.snapshot();
|
||||
const auto config = specific.read([](const auto& value) { return value; });
|
||||
if (config.play_mode == Play_Mode::loop) {
|
||||
index = 0;
|
||||
}
|
||||
@@ -308,7 +308,7 @@ asio::awaitable<void> File_Data_Source::_close() {
|
||||
}
|
||||
asio::awaitable<void> File_Data_Source::_open() {
|
||||
std::lock_guard g(mtx);
|
||||
const auto config = specific.snapshot();
|
||||
const auto config = specific.read([](const auto& value) { return value; });
|
||||
auto path = Psc::get_abs_path(config.file_path);
|
||||
namespace fs = std::filesystem;
|
||||
if (!fs::exists(path)) {
|
||||
@@ -360,7 +360,7 @@ void File_Data_Source::origin_data_transform_mode_data(std::string& mode_data) {
|
||||
std::lock_guard g(mtx);
|
||||
assert(mode_data.size() == 0);
|
||||
int ret_index = 0;
|
||||
const auto config = specific.snapshot();
|
||||
const auto config = specific.read([](const auto& value) { return value; });
|
||||
if (config.play_mode != Play_Mode::analysis) {
|
||||
std::optional<std::string> log_info = get_raw_line(ret_index);
|
||||
mode_data = log_info.has_value() ? get_true_from_raw_line(this, config.data_type, ret_index, log_info.value()) : "";
|
||||
@@ -419,7 +419,7 @@ void Dll_Data_Source::origin_data_transform_mode_data(std::string& mode_data) {
|
||||
auto start = std::chrono::steady_clock::now();
|
||||
if (read_func_ptr == nullptr)
|
||||
return;
|
||||
const auto config = specific.snapshot();
|
||||
const auto config = specific.read([](const auto& value) { return value; });
|
||||
auto buf = reinterpret_cast<char*>(buffer.data());
|
||||
auto len = read_func_ptr(buf, config.buffer_size);
|
||||
vs.update(len);
|
||||
@@ -437,7 +437,7 @@ void Dll_Data_Source::origin_data_transform_mode_data(std::string& mode_data) {
|
||||
mode_data = ret;
|
||||
}
|
||||
asio::awaitable<void> Shared_Memory_Data_Source::_open() {
|
||||
const auto config = specific.snapshot();
|
||||
const auto config = specific.read([](const auto& value) { return value; });
|
||||
sm = std::make_unique<Psc::SM_RingBuffer>();
|
||||
sm->init(config.shared_memory_name, config.shared_memory_size);
|
||||
co_return;
|
||||
@@ -461,7 +461,7 @@ void Shared_Memory_Data_Source::origin_data_transform_mode_data(std::string& mod
|
||||
if (Global::instance()->console_config.mode_s_console) {
|
||||
std::cout << "read:" << data << std::endl;
|
||||
}
|
||||
const auto config = specific.snapshot();
|
||||
const auto config = specific.read([](const auto& value) { return value; });
|
||||
auto ret = get_true_from_raw_line(this, config.data_type, -1, data);
|
||||
mode_data = ret;
|
||||
}
|
||||
|
||||
@@ -186,14 +186,12 @@ public:
|
||||
return ret;
|
||||
}
|
||||
virtual Psc::JSON to_json() {
|
||||
return With_Loop_Coro::to_base_json() += settings.snapshot().to_base_json();
|
||||
return With_Loop_Coro::to_base_json() += settings.read([](const auto& value) { return value.to_base_json(); });
|
||||
}
|
||||
virtual void from_json(const Psc::JSON* that_json, bool not_exist_use_default_value) {
|
||||
With_Loop_Coro::from_base_json(that_json, not_exist_use_default_value);
|
||||
auto value = settings.snapshot();
|
||||
value.from_base_json(that_json, not_exist_use_default_value);
|
||||
settings.write([&](auto& target) {
|
||||
target = value;
|
||||
settings.write([&](auto& value) {
|
||||
value.from_base_json(that_json, not_exist_use_default_value);
|
||||
});
|
||||
}
|
||||
std::string buffer;
|
||||
@@ -233,7 +231,7 @@ public:
|
||||
type = "TCP_Client_Data_Source";
|
||||
}
|
||||
asio::awaitable<void> _open() override {
|
||||
const auto value = specific.snapshot();
|
||||
const auto value = specific.read([](const auto& value) { return value; });
|
||||
Psc::asio_socket::Sockaddr_In addr;
|
||||
addr.ip = value.ip;
|
||||
addr.port = value.port;
|
||||
@@ -247,14 +245,12 @@ public:
|
||||
co_return;
|
||||
}
|
||||
Psc::JSON to_json() override {
|
||||
return Data_Source::to_json() += specific.snapshot().to_base_json();
|
||||
return Data_Source::to_json() += specific.read([](const auto& value) { return value.to_base_json(); });
|
||||
}
|
||||
void from_json(const Psc::JSON* that_json, bool not_exist_use_default_value) override {
|
||||
Data_Source::from_json(that_json, not_exist_use_default_value);
|
||||
auto value = specific.snapshot();
|
||||
value.from_base_json(that_json, not_exist_use_default_value);
|
||||
specific.write([&](auto& target) {
|
||||
target = value;
|
||||
specific.write([&](auto& value) {
|
||||
value.from_base_json(that_json, not_exist_use_default_value);
|
||||
});
|
||||
}
|
||||
asio::awaitable<std::string> read_coro() override {
|
||||
@@ -288,7 +284,7 @@ public:
|
||||
type = "Serial_Data_Source";
|
||||
}
|
||||
asio::awaitable<void> _open() override {
|
||||
const auto value = specific.snapshot();
|
||||
const auto value = specific.read([](const auto& value) { return value; });
|
||||
serial = std::make_unique<Psc::serial::Serial_Coro>();
|
||||
serial->set_serial_name(value.port_name);
|
||||
serial->set_baud_rate(value.baud_rate);
|
||||
@@ -317,14 +313,12 @@ public:
|
||||
co_return co_await serial->read_coro();
|
||||
}
|
||||
Psc::JSON to_json() override {
|
||||
return Data_Source::to_json() += specific.snapshot().to_base_json();
|
||||
return Data_Source::to_json() += specific.read([](const auto& value) { return value.to_base_json(); });
|
||||
}
|
||||
void from_json(const Psc::JSON* that_json, bool not_exist_use_default_value) override {
|
||||
Data_Source::from_json(that_json, not_exist_use_default_value);
|
||||
auto value = specific.snapshot();
|
||||
value.from_base_json(that_json, not_exist_use_default_value);
|
||||
specific.write([&](auto& target) {
|
||||
target = value;
|
||||
specific.write([&](auto& value) {
|
||||
value.from_base_json(that_json, not_exist_use_default_value);
|
||||
});
|
||||
}
|
||||
std::unique_ptr<Psc::serial::Serial_Coro> serial{};
|
||||
@@ -392,21 +386,19 @@ public:
|
||||
std::shared_ptr<Cache_Msg> pre_cache = nullptr;
|
||||
std::deque<std::shared_ptr<Cache_Msg>> cache_list;
|
||||
std::string get_true_file_path() const {
|
||||
return Psc::get_abs_path(specific.member<&File_Data_Source_Data::file_path>().snapshot());
|
||||
return Psc::get_abs_path(specific.member<&File_Data_Source_Data::file_path>().read([](const auto& value) { return value; }));
|
||||
}
|
||||
asio::awaitable<void> _close() override;
|
||||
asio::awaitable<void> _open() override;
|
||||
std::vector<std::string> readBinaryFileAsString(std::string_view filepath, size_t part_size);
|
||||
void from_json(const Psc::JSON* that_json, bool not_exist_use_default_value) override {
|
||||
Data_Source::from_json(that_json, not_exist_use_default_value);
|
||||
auto value = specific.snapshot();
|
||||
value.from_base_json(that_json, not_exist_use_default_value);
|
||||
specific.write([&](auto& target) {
|
||||
target = value;
|
||||
specific.write([&](auto& value) {
|
||||
value.from_base_json(that_json, not_exist_use_default_value);
|
||||
});
|
||||
}
|
||||
Psc::JSON to_json() override {
|
||||
return Data_Source::to_json() += specific.snapshot().to_base_json();
|
||||
return Data_Source::to_json() += specific.read([](const auto& value) { return value.to_base_json(); });
|
||||
}
|
||||
void origin_data_transform_mode_data(std::string& data) override;
|
||||
void handle_mode_s(std::shared_ptr<SSR::Mode_S_Msg>& msg) override;
|
||||
@@ -453,15 +445,14 @@ public:
|
||||
std::vector<std::uint8_t> buffer;
|
||||
void from_json(const Psc::JSON* that_json, bool not_exist_use_default_value) override {
|
||||
Data_Source::from_json(that_json, not_exist_use_default_value);
|
||||
auto value = specific.snapshot();
|
||||
value.from_base_json(that_json, not_exist_use_default_value);
|
||||
specific.write([&](auto& target) {
|
||||
target = value;
|
||||
const auto buffer_size = specific.write([&](auto& value) {
|
||||
value.from_base_json(that_json, not_exist_use_default_value);
|
||||
return value.buffer_size;
|
||||
});
|
||||
buffer.resize(value.buffer_size);
|
||||
buffer.resize(buffer_size);
|
||||
}
|
||||
Psc::JSON to_json() override {
|
||||
return Data_Source::to_json() += specific.snapshot().to_base_json();
|
||||
return Data_Source::to_json() += specific.read([](const auto& value) { return value.to_base_json(); });
|
||||
}
|
||||
void* lib{};
|
||||
using Func_Type = size_t (*)(char* buf, std::size_t max_len);
|
||||
@@ -474,7 +465,7 @@ public:
|
||||
co_return;
|
||||
}
|
||||
asio::awaitable<void> _open() override {
|
||||
const auto value = specific.snapshot();
|
||||
const auto value = specific.read([](const auto& value) { return value; });
|
||||
{
|
||||
auto r = Psc::try_load_library(Psc::get_abs_path(value.library_path));
|
||||
if (!r) {
|
||||
@@ -524,14 +515,12 @@ public:
|
||||
}
|
||||
void from_json(const Psc::JSON* that_json, bool not_exist_use_default_value) override {
|
||||
Data_Source::from_json(that_json, not_exist_use_default_value);
|
||||
auto value = specific.snapshot();
|
||||
value.from_base_json(that_json, not_exist_use_default_value);
|
||||
specific.write([&](auto& target) {
|
||||
target = value;
|
||||
specific.write([&](auto& value) {
|
||||
value.from_base_json(that_json, not_exist_use_default_value);
|
||||
});
|
||||
}
|
||||
Psc::JSON to_json() override {
|
||||
return Data_Source::to_json() += specific.snapshot().to_base_json();
|
||||
return Data_Source::to_json() += specific.read([](const auto& value) { return value.to_base_json(); });
|
||||
}
|
||||
asio::awaitable<void> _open() override;
|
||||
asio::awaitable<void> _close() override;
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#include "Data_Source_Handler.h"
|
||||
#include <string_view>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
#include "Data_Source.h"
|
||||
#include "Local_Server/server/Global.h"
|
||||
#include "Local_Server/server/io_coro.h"
|
||||
@@ -145,7 +147,7 @@ size_t Data_Source_Handler::process_mode_acs_data(std::string_view origin_data)
|
||||
}
|
||||
};
|
||||
auto f = [this, source, handle_packet](std::string& packet) {
|
||||
const auto wait = Global::instance()->mode_acs.settings.member<&Mode_ACS_Config_Data::wait_process_msg>().snapshot();
|
||||
const auto wait = Global::instance()->mode_acs.settings.member<&Mode_ACS_Config_Data::wait_process_msg>().read([](const auto& value) { return value; });
|
||||
if (wait) {
|
||||
handle_packet(packet);
|
||||
}
|
||||
@@ -168,29 +170,28 @@ void Data_Source_Handler::handle_mode_s(std::shared_ptr<SSR::Mode_S_Msg>& mode_s
|
||||
mem2hex(t, true, " "), mem2hex(mode_s_msg->packet, true, " "), t, mode_s_msg->packet);
|
||||
Psc::fail_fast(data);
|
||||
}
|
||||
const auto cfg = Global::instance()->mode_acs.settings.snapshot();
|
||||
const auto source_cfg = source->settings.snapshot();
|
||||
bool time_space_filter = cfg.time_space_filter;
|
||||
bool speed_filter = cfg.speed_filter;
|
||||
bool use_system_time = source_cfg.ignore_msg_time;
|
||||
const auto mode_config = Global::instance()->mode_acs.settings.read([](const auto& value) {
|
||||
return std::tuple{value.time_space_filter, value.speed_filter, value.aircraft_change_list_adsb_range_filter, value.aircraft_change_list_adsb_range_factor, value.max_speed_m_s, value.air_pos_timeout, value.surface_pos_timeout};
|
||||
});
|
||||
const auto source_config = source->settings.read([](const auto& value) {
|
||||
return std::tuple{value.ignore_msg_time, value.base_station_has_valid_position, value.lat, value.lon, value.alt};
|
||||
});
|
||||
const auto [time_space_filter, speed_filter, range_filter, range_factor, max_speed_m_s, air_pos_timeout, surface_pos_timeout] = mode_config;
|
||||
const auto [use_system_time, base_station_has_valid_position, lat, lon, alt] = source_config;
|
||||
auto base_station_pos = source->base_station.get_pos();
|
||||
if (!base_station_pos && source_cfg.base_station_has_valid_position)
|
||||
base_station_pos = SSR::Position_3D{source_cfg.lat, source_cfg.lon, source_cfg.alt};
|
||||
auto range_filter = cfg.aircraft_change_list_adsb_range_filter;
|
||||
auto range_factor = cfg.aircraft_change_list_adsb_range_factor;
|
||||
SSR::ADS_B_T::Constraint air_constraint{cfg.max_speed_m_s, cfg.air_pos_timeout, SSR::cpr_cb, time_space_filter,
|
||||
speed_filter, use_system_time, base_station_pos, source_cfg.alt,
|
||||
range_filter, range_factor};
|
||||
SSR::ADS_B_T::Constraint surface_constraint{cfg.max_speed_m_s, cfg.surface_pos_timeout, SSR::cpr_cb, time_space_filter,
|
||||
speed_filter, use_system_time, base_station_pos, source_cfg.alt,
|
||||
range_filter, range_factor};
|
||||
if (!base_station_pos && base_station_has_valid_position)
|
||||
base_station_pos = SSR::Position_3D{lat, lon, alt};
|
||||
SSR::ADS_B_T::Constraint air_constraint{max_speed_m_s, air_pos_timeout, SSR::cpr_cb, time_space_filter,
|
||||
speed_filter, use_system_time, base_station_pos, alt, range_filter, range_factor};
|
||||
SSR::ADS_B_T::Constraint surface_constraint{max_speed_m_s, surface_pos_timeout, SSR::cpr_cb, time_space_filter,
|
||||
speed_filter, use_system_time, base_station_pos, alt, range_filter, range_factor};
|
||||
SSR::parse_mode_s_bin(source.get(), mode_s_msg, base_station_pos, air_constraint, surface_constraint);
|
||||
auto base = source->get_aircraft(mode_s_msg->icao);
|
||||
if (base) {
|
||||
auto derived = std::dynamic_pointer_cast<Aircraft>(base);
|
||||
derived->refresh_external_database_info();
|
||||
}
|
||||
if (Global::instance()->mlat.settings.member<&MLAT_Config_Data::merge>().snapshot()) {
|
||||
if (Global::instance()->mlat.settings.member<&MLAT_Config_Data::merge>().read([](const auto& value) { return value; })) {
|
||||
auto& mh = Global::instance()->mlat_handler;
|
||||
mh.push(mode_s_msg);
|
||||
auto tt = mh.get_all();
|
||||
@@ -288,31 +289,33 @@ void Data_Source_Handler::refresh_data_feed_key_list() {
|
||||
const auto feeds = global->mode_acs.data_feed_config.map.list();
|
||||
const auto relations = global->mode_acs.source_feed_relation_config.map.list();
|
||||
for (const auto& relation : relations) {
|
||||
const auto config = relation->settings.snapshot();
|
||||
if (!config.enable || relation->type != "One_to_One_Relation")
|
||||
continue;
|
||||
const auto source = global->mode_acs.data_source_config.map.get(config.source_key);
|
||||
const auto feed = global->mode_acs.data_feed_config.map.get(config.feed_key);
|
||||
if (source.has_value() && feed.has_value() && source.value()->enabled() && feed.value()->enabled() && !assignment.contains(config.feed_key))
|
||||
assignment.emplace(config.feed_key, config.source_key);
|
||||
relation->settings.read([&](const auto& config) {
|
||||
if (!config.enable || relation->type != "One_to_One_Relation")
|
||||
return;
|
||||
const auto source = global->mode_acs.data_source_config.map.get(config.source_key);
|
||||
const auto feed = global->mode_acs.data_feed_config.map.get(config.feed_key);
|
||||
if (source.has_value() && feed.has_value() && source.value()->enabled() && feed.value()->enabled() && !assignment.contains(config.feed_key))
|
||||
assignment.emplace(config.feed_key, config.source_key);
|
||||
});
|
||||
}
|
||||
for (const auto& relation : relations) {
|
||||
const auto config = relation->settings.snapshot();
|
||||
if (!config.enable || relation->type != "Name_One_To_Many_Relation")
|
||||
continue;
|
||||
const auto source = global->mode_acs.data_source_config.map.get(config.source_key);
|
||||
if (!source.has_value() || !source.value()->enabled())
|
||||
continue;
|
||||
const std::string& prefix = config.feed_name.empty() ? config.source_key : config.feed_name;
|
||||
for (const auto& feed : feeds) {
|
||||
if (!feed->enabled() || assignment.contains(feed->key) || !feed->key.starts_with(prefix))
|
||||
continue;
|
||||
assignment.emplace(feed->key, config.source_key);
|
||||
}
|
||||
relation->settings.read([&](const auto& config) {
|
||||
if (!config.enable || relation->type != "Name_One_To_Many_Relation")
|
||||
return;
|
||||
const auto source = global->mode_acs.data_source_config.map.get(config.source_key);
|
||||
if (!source.has_value() || !source.value()->enabled())
|
||||
return;
|
||||
const std::string& prefix = config.feed_name.empty() ? config.source_key : config.feed_name;
|
||||
for (const auto& feed : feeds) {
|
||||
if (!feed->enabled() || assignment.contains(feed->key) || !feed->key.starts_with(prefix))
|
||||
continue;
|
||||
assignment.emplace(feed->key, config.source_key);
|
||||
}
|
||||
});
|
||||
}
|
||||
bool use_default = false;
|
||||
for (const auto& relation : relations) {
|
||||
if (relation->type == "First_Source_To_All_Feed_Relation" && relation->settings.member<&Source_Feed_Relation_Data::enable>().snapshot()) {
|
||||
if (relation->type == "First_Source_To_All_Feed_Relation" && relation->settings.member<&Source_Feed_Relation_Data::enable>().read([](const auto& value) { return value; })) {
|
||||
use_default = true;
|
||||
break;
|
||||
}
|
||||
@@ -351,12 +354,12 @@ std::optional<std::string> convert_to_send_format(Data_Source_Handler* ds, const
|
||||
auto& type = msg->type;
|
||||
auto fs = dynamic_cast<File_Data_Source*>(msg->source.get());
|
||||
if (fs) {
|
||||
if (fs->specific.member<&File_Data_Source_Data::play_mode>().snapshot() == Play_Mode::analysis) {
|
||||
if (fs->specific.member<&File_Data_Source_Data::play_mode>().read([](const auto& value) { return value; }) == Play_Mode::analysis) {
|
||||
// std::cout << fs->key << " analysis i ==" << i << std::endl;
|
||||
}
|
||||
}
|
||||
// 出口输出的条件
|
||||
const auto feed_format = feed->output_format.snapshot();
|
||||
const auto feed_format = feed->output_format.read([](const auto& value) { return value; });
|
||||
const auto output_format = feed_format.type;
|
||||
const auto use_mode_ac = feed_format.use_mode_ac;
|
||||
const auto use_status = feed_format.use_status;
|
||||
@@ -488,9 +491,9 @@ void Data_Source_Handler::push_to_feed(const std::shared_ptr<SSR::Msg>& msg) {
|
||||
refresh_data_feed_key_list();
|
||||
need_refresh_data_feed_key_list = false;
|
||||
}
|
||||
const auto mode_config = Global::instance()->mode_acs.settings.snapshot();
|
||||
const auto other_size = mode_config.mode_other_max_num;
|
||||
const auto s_size = mode_config.mode_s_max_num;
|
||||
const auto [other_size, s_size] = Global::instance()->mode_acs.settings.read([](const auto& value) {
|
||||
return std::pair{value.mode_other_max_num, value.mode_s_max_num};
|
||||
});
|
||||
std::vector<std::string> list;
|
||||
for (const auto& item : cached_data_feed_key_list) {
|
||||
auto& key = item.key;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#include "../server/Global.h"
|
||||
#include "../server/Performance_Monitor.h"
|
||||
#include "../server/WebSocket_Manager.h"
|
||||
|
||||
#include <tuple>
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <cmath>
|
||||
@@ -290,7 +290,7 @@ void register_aircraft_stream_ws() {
|
||||
}
|
||||
}
|
||||
Aircraft::Aircraft(std::string_view icao) : Aircraft_Info(icao) {
|
||||
auto size = Global::instance()->mode_acs.settings.member<&Mode_ACS_Config_Data::max_track_point_size>().snapshot();
|
||||
auto size = Global::instance()->mode_acs.settings.member<&Mode_ACS_Config_Data::max_track_point_size>().read([](const auto& value) { return value; });
|
||||
air_pos_track_list.init(size);
|
||||
surface_pos_track_list.init(size);
|
||||
}
|
||||
@@ -332,7 +332,7 @@ void DataBase::delete_timeout_aircraft() {
|
||||
std::cout << "未初始化的 timestamp " << LOG_POS << std::endl;
|
||||
}
|
||||
long long time = std::time(nullptr) - item->timestamp;
|
||||
return time > Global::instance()->mode_acs.settings.member<&Mode_ACS_Config_Data::timeout_seconds>().snapshot();
|
||||
return time > Global::instance()->mode_acs.settings.member<&Mode_ACS_Config_Data::timeout_seconds>().read([](const auto& value) { return value; });
|
||||
});
|
||||
}
|
||||
|
||||
@@ -360,16 +360,17 @@ std::vector<std::shared_ptr<SSR::Aircraft_Info>>
|
||||
DataBase::get_visible_aircraft_snapshot() {
|
||||
std::vector<std::shared_ptr<SSR::Aircraft_Info>> ret;
|
||||
auto g = Global::instance();
|
||||
auto min_position_points =
|
||||
g->mode_acs.settings.member<&Mode_ACS_Config_Data::aircraft_change_list_min_position_points>().snapshot();
|
||||
auto range_filter = g->mode_acs.settings.member<&Mode_ACS_Config_Data::aircraft_change_list_adsb_range_filter>().snapshot();
|
||||
auto range_factor = g->mode_acs.settings.member<&Mode_ACS_Config_Data::aircraft_change_list_adsb_range_factor>().snapshot();
|
||||
const auto [min_position_points, range_filter, range_factor] = g->mode_acs.settings.read([](const auto& value) {
|
||||
return std::tuple{value.aircraft_change_list_min_position_points, value.aircraft_change_list_adsb_range_filter, value.aircraft_change_list_adsb_range_factor};
|
||||
});
|
||||
auto source = g->source(get_key());
|
||||
auto base_position = base_station.get_pos();
|
||||
if (source) {
|
||||
const auto source_config = source->settings.snapshot();
|
||||
if (!base_position && source_config.base_station_has_valid_position) {
|
||||
base_position = SSR::Position_3D{source_config.lat, source_config.lon, source_config.alt};
|
||||
const auto [valid_position, lat, lon, alt] = source->settings.read([](const auto& value) {
|
||||
return std::tuple{value.base_station_has_valid_position, value.lat, value.lon, value.alt};
|
||||
});
|
||||
if (!base_position && valid_position) {
|
||||
base_position = SSR::Position_3D{lat, lon, alt};
|
||||
}
|
||||
}
|
||||
for (auto &it : aircraft_map.values()) {
|
||||
@@ -541,13 +542,14 @@ void database_server(Global *g) {
|
||||
if (db) {
|
||||
ret = db->base_station.to_Json();
|
||||
auto target_height =
|
||||
g->mode_acs.settings.member<&Mode_ACS_Config_Data::adsb_theoretical_target_altitude_meters>().snapshot();
|
||||
const auto source_config = db->settings.snapshot();
|
||||
auto range = Base_Station::theoretical_detection_range_meters(source_config.alt,
|
||||
target_height);
|
||||
ret.append({"latitude", source_config.lat});
|
||||
ret.append({"longitude", source_config.lon});
|
||||
ret.append({"height", source_config.alt});
|
||||
g->mode_acs.settings.member<&Mode_ACS_Config_Data::adsb_theoretical_target_altitude_meters>().read([](const auto& value) { return value; });
|
||||
const auto [lat, lon, alt] = db->settings.read([](const auto& value) {
|
||||
return std::tuple{value.lat, value.lon, value.alt};
|
||||
});
|
||||
auto range = Base_Station::theoretical_detection_range_meters(alt, target_height);
|
||||
ret.append({"latitude", lat});
|
||||
ret.append({"longitude", lon});
|
||||
ret.append({"height", alt});
|
||||
ret.append({"adsb_theoretical_target_altitude_meters", target_height});
|
||||
ret.append({"adsb_theoretical_detection_range_meters", range});
|
||||
ret.append({"理论探测范围", range});
|
||||
@@ -615,7 +617,7 @@ void database_server(Global *g) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto limit_msg_num = g->mode_acs.settings.member<&Mode_ACS_Config_Data::default_min_aircraft_list_num>().snapshot();
|
||||
auto limit_msg_num = g->mode_acs.settings.member<&Mode_ACS_Config_Data::default_min_aircraft_list_num>().read([](const auto& value) { return value; });
|
||||
auto t = params.get("limit_msg_num");
|
||||
if (t) {
|
||||
HTTP_REQUIRE_VALUE(requested_limit_msg_num, t->try_number_val<int>())
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "adminive/adapters/nlohmann_json.hpp"
|
||||
#include <algorithm>
|
||||
#include <charconv>
|
||||
#include <cstdint>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
@@ -71,9 +72,61 @@ struct Source_Feed_Relation_Row {
|
||||
std::string feed_key;
|
||||
std::string feed_name;
|
||||
};
|
||||
struct External_Resource_Row {
|
||||
std::string name;
|
||||
std::string description;
|
||||
std::string download_url;
|
||||
std::uint64_t update_interval_seconds{};
|
||||
std::int64_t last_updated_at{};
|
||||
std::size_t row_count{};
|
||||
std::string state;
|
||||
};
|
||||
struct Backend_Config_Row {
|
||||
std::string section;
|
||||
std::string path;
|
||||
std::string value;
|
||||
};
|
||||
}
|
||||
namespace adminive {
|
||||
template <>
|
||||
struct Type_Descriptor<ecap::adminive_config::External_Resource_Row> {
|
||||
static auto get() {
|
||||
using T = ecap::adminive_config::External_Resource_Row;
|
||||
return object<T>("external_resource", "外部数据源管理",
|
||||
ADMINIVE_FIELD_LABEL(T, name, "数据表"),
|
||||
ADMINIVE_FIELD_LABEL(T, description, "说明"),
|
||||
ADMINIVE_FIELD_LABEL(T, download_url, "在线来源"),
|
||||
ADMINIVE_FIELD_LABEL(T, update_interval_seconds, "建议更新周期(秒)"),
|
||||
ADMINIVE_FIELD_LABEL(T, last_updated_at, "上次更新时间"),
|
||||
ADMINIVE_FIELD_LABEL(T, row_count, "行数"),
|
||||
ADMINIVE_FIELD_LABEL(T, state, "状态"));
|
||||
}
|
||||
};
|
||||
template <>
|
||||
struct Type_View_Descriptor<ecap::adminive_config::External_Resource_Row> {
|
||||
static Table_View table() {
|
||||
using T = ecap::adminive_config::External_Resource_Row;
|
||||
return table_view<T>(column<&T::name>("数据表").search(), column<&T::description>("说明"), column<&T::download_url>("在线来源"), column<&T::row_count>("行数").sort(), column<&T::last_updated_at>("上次更新时间").sort(), column<&T::update_interval_seconds>("建议更新周期(秒)"), column<&T::state>("状态")).titled("外部数据源管理");
|
||||
}
|
||||
};
|
||||
template <>
|
||||
struct Type_Descriptor<ecap::adminive_config::Backend_Config_Row> {
|
||||
static auto get() {
|
||||
using T = ecap::adminive_config::Backend_Config_Row;
|
||||
return object<T>("backend_config", "后端完整配置",
|
||||
ADMINIVE_FIELD_LABEL(T, section, "配置分区"),
|
||||
ADMINIVE_FIELD_LABEL(T, path, "配置项"),
|
||||
ADMINIVE_FIELD_LABEL(T, value, "当前值"));
|
||||
}
|
||||
};
|
||||
template <>
|
||||
struct Type_View_Descriptor<ecap::adminive_config::Backend_Config_Row> {
|
||||
static Table_View table() {
|
||||
using T = ecap::adminive_config::Backend_Config_Row;
|
||||
return table_view<T>(column<&T::section>("配置分区").filter(), column<&T::path>("配置项").search(), column<&T::value>("当前值")).titled("后端完整配置(只读)");
|
||||
}
|
||||
};
|
||||
template <>
|
||||
struct Type_Descriptor<ecap::adminive_config::Data_Source_Row> {
|
||||
static auto get() {
|
||||
using T = ecap::adminive_config::Data_Source_Row;
|
||||
@@ -274,6 +327,38 @@ adminive::Resource_Transaction<Data_feed_Config_Data> data_feed_settings_transac
|
||||
};
|
||||
return transaction;
|
||||
}
|
||||
adminive::Resource_Transaction<Map_View_Config> map_view_transaction(Global* global) {
|
||||
adminive::Resource_Transaction<Map_View_Config> transaction;
|
||||
transaction.prepare = [global](const Map_View_Config& value, const adminive::Request_Context&) {
|
||||
if(!Map_View_Config::is_scene_mode(value.scene_mode))
|
||||
throw adminive::Field_Validation_Error("scene_mode", "场景模式必须为 2d 或 3d");
|
||||
global->map_resources_config.read([&](const auto& resources) {
|
||||
if(!resources.is_imagery_key(value.map2d.current_imagery_key))
|
||||
throw adminive::Field_Validation_Error("map2d.current_imagery_key", "影像源不存在");
|
||||
if(!resources.is_terrain_key(value.map2d.current_terrain_key))
|
||||
throw adminive::Field_Validation_Error("map2d.current_terrain_key", "地形源不存在");
|
||||
if(!resources.is_imagery_key(value.map3d.current_imagery_key))
|
||||
throw adminive::Field_Validation_Error("map3d.current_imagery_key", "影像源不存在");
|
||||
if(!resources.is_terrain_key(value.map3d.current_terrain_key))
|
||||
throw adminive::Field_Validation_Error("map3d.current_terrain_key", "地形源不存在");
|
||||
});
|
||||
};
|
||||
transaction.commit = [global](const Map_View_Config& value, const adminive::Request_Context&) {
|
||||
global->map_resources_config.write([&](auto& resources) {
|
||||
resources.current_imagery_key = value.scene_mode == "2d" ? value.map2d.current_imagery_key : value.map3d.current_imagery_key;
|
||||
});
|
||||
Config::save(Config_Section::map_view, value.to_base_json());
|
||||
Config::save(Config_Section::map_resources);
|
||||
};
|
||||
transaction.rollback = [global](const Map_View_Config& value, const adminive::Request_Context&) {
|
||||
global->map_resources_config.write([&](auto& resources) {
|
||||
resources.current_imagery_key = value.scene_mode == "2d" ? value.map2d.current_imagery_key : value.map3d.current_imagery_key;
|
||||
});
|
||||
Config::save(Config_Section::map_view, value.to_base_json());
|
||||
Config::save(Config_Section::map_resources);
|
||||
};
|
||||
return transaction;
|
||||
}
|
||||
void save_data_sources(Global* global) {
|
||||
auto patch = Psc::JSON::object();
|
||||
patch.append({"data_source", global->mode_acs.data_source_config.to_json()});
|
||||
@@ -404,32 +489,39 @@ Data_Source_Row source_row(const std::shared_ptr<Data_Source>& source) {
|
||||
row.key = source->key;
|
||||
row.type = source_type(source->type);
|
||||
row.enable = source->enabled();
|
||||
row.config = source->settings.snapshot();
|
||||
source->settings.read([&](const auto& value) {
|
||||
row.config = value;
|
||||
});
|
||||
row.state = Psc::to_string(source->state);
|
||||
if(const auto source_value = dynamic_cast<TCP_Client_Data_Source*>(source.get())) {
|
||||
const auto value = source_value->specific.snapshot();
|
||||
row.ip = value.ip;
|
||||
row.port = value.port;
|
||||
source_value->specific.read([&](const auto& value) {
|
||||
row.ip = value.ip;
|
||||
row.port = value.port;
|
||||
});
|
||||
} else if(const auto source_value = dynamic_cast<Serial_Data_Source*>(source.get())) {
|
||||
const auto value = source_value->specific.snapshot();
|
||||
row.port_name = value.port_name;
|
||||
row.baud_rate = value.baud_rate;
|
||||
source_value->specific.read([&](const auto& value) {
|
||||
row.port_name = value.port_name;
|
||||
row.baud_rate = value.baud_rate;
|
||||
});
|
||||
} else if(const auto source_value = dynamic_cast<File_Data_Source*>(source.get())) {
|
||||
const auto value = source_value->specific.snapshot();
|
||||
row.file_path = value.file_path;
|
||||
row.data_type = value.data_type;
|
||||
row.play_mode = value.play_mode;
|
||||
source_value->specific.read([&](const auto& value) {
|
||||
row.file_path = value.file_path;
|
||||
row.data_type = value.data_type;
|
||||
row.play_mode = value.play_mode;
|
||||
});
|
||||
} else if(const auto source_value = dynamic_cast<Dll_Data_Source*>(source.get())) {
|
||||
const auto value = source_value->specific.snapshot();
|
||||
row.library_path = value.library_path;
|
||||
row.function_name = value.function_name;
|
||||
row.data_type = value.data_type;
|
||||
row.buffer_size = value.buffer_size;
|
||||
source_value->specific.read([&](const auto& value) {
|
||||
row.library_path = value.library_path;
|
||||
row.function_name = value.function_name;
|
||||
row.data_type = value.data_type;
|
||||
row.buffer_size = value.buffer_size;
|
||||
});
|
||||
} else if(const auto source_value = dynamic_cast<Shared_Memory_Data_Source*>(source.get())) {
|
||||
const auto value = source_value->specific.snapshot();
|
||||
row.shared_memory_name = value.shared_memory_name;
|
||||
row.shared_memory_size = value.shared_memory_size;
|
||||
row.data_type = value.data_type;
|
||||
source_value->specific.read([&](const auto& value) {
|
||||
row.shared_memory_name = value.shared_memory_name;
|
||||
row.shared_memory_size = value.shared_memory_size;
|
||||
row.data_type = value.data_type;
|
||||
});
|
||||
}
|
||||
return row;
|
||||
}
|
||||
@@ -475,24 +567,31 @@ Data_Feed_Row feed_row(const std::shared_ptr<Data_Feed>& feed) {
|
||||
row.key = feed->key;
|
||||
row.type = feed_type(feed->type);
|
||||
row.enable = feed->enabled();
|
||||
row.output_format = feed->output_format.snapshot();
|
||||
row.format = row.output_format.type;
|
||||
feed->output_format.read([&](const auto& value) {
|
||||
row.output_format = value;
|
||||
row.format = value.type;
|
||||
});
|
||||
row.state = Psc::to_string(feed->state);
|
||||
if(const auto feed_value = dynamic_cast<Data_Feed_TCP_Server*>(feed.get())) {
|
||||
const auto value = feed_value->specific.snapshot();
|
||||
row.port = value.port;
|
||||
row.connect_user_buffer_size = value.connect_user_buffer_size;
|
||||
row.connect_system_buffer_size = value.connect_system_buffer_size;
|
||||
feed_value->specific.read([&](const auto& value) {
|
||||
row.port = value.port;
|
||||
row.connect_user_buffer_size = value.connect_user_buffer_size;
|
||||
row.connect_system_buffer_size = value.connect_system_buffer_size;
|
||||
});
|
||||
} else if(const auto feed_value = dynamic_cast<Data_Feed_UDP_Server*>(feed.get())) {
|
||||
row.port = feed_value->specific.member<&Data_Feed_UDP_Server_Data::port>().snapshot();
|
||||
feed_value->specific.read([&](const auto& value) {
|
||||
row.port = value.port;
|
||||
});
|
||||
} else if(const auto feed_value = dynamic_cast<Data_Feed_TCP_Client*>(feed.get())) {
|
||||
const auto value = feed_value->specific.snapshot();
|
||||
row.url = value.url;
|
||||
row.port = value.port;
|
||||
feed_value->specific.read([&](const auto& value) {
|
||||
row.url = value.url;
|
||||
row.port = value.port;
|
||||
});
|
||||
} else if(const auto feed_value = dynamic_cast<Data_Feed_UDP_Client*>(feed.get())) {
|
||||
const auto value = feed_value->specific.snapshot();
|
||||
row.url = value.url;
|
||||
row.port = value.port;
|
||||
feed_value->specific.read([&](const auto& value) {
|
||||
row.url = value.url;
|
||||
row.port = value.port;
|
||||
});
|
||||
}
|
||||
return row;
|
||||
}
|
||||
@@ -525,13 +624,14 @@ void apply_feed_row(const std::shared_ptr<Data_Feed>& feed, const Data_Feed_Row&
|
||||
}
|
||||
Source_Feed_Relation_Row relation_row(const std::shared_ptr<Source_Feed_Relation>& relation) {
|
||||
Source_Feed_Relation_Row row;
|
||||
const auto value = relation->settings.snapshot();
|
||||
row.key = relation->key;
|
||||
row.type = relation_type(relation->type);
|
||||
row.enable = value.enable;
|
||||
row.source_key = value.source_key;
|
||||
row.feed_key = value.feed_key;
|
||||
row.feed_name = value.feed_name;
|
||||
relation->settings.read([&](const auto& value) {
|
||||
row.enable = value.enable;
|
||||
row.source_key = value.source_key;
|
||||
row.feed_key = value.feed_key;
|
||||
row.feed_name = value.feed_name;
|
||||
});
|
||||
return row;
|
||||
}
|
||||
void apply_relation_row(const std::shared_ptr<Source_Feed_Relation>& relation, const Source_Feed_Relation_Row& row) {
|
||||
@@ -570,6 +670,34 @@ std::vector<Source_Feed_Relation_Row> relation_rows(Global* global) {
|
||||
rows.push_back(relation_row(relation));
|
||||
return rows;
|
||||
}
|
||||
std::vector<External_Resource_Row> external_resource_rows(Global* global) {
|
||||
std::map<std::string, External_Resource_Status> status_by_name;
|
||||
for(auto status : global->external_resources_manager.external_database_status())
|
||||
status_by_name.emplace(status.name, std::move(status));
|
||||
const auto config = global->external_resources_manager.to_base_json();
|
||||
const auto* list = config.get("list");
|
||||
std::vector<External_Resource_Row> rows;
|
||||
if(!list)
|
||||
return rows;
|
||||
rows.reserve(list->children.size());
|
||||
for(const auto& item : list->children) {
|
||||
External_Resources_Data value;
|
||||
value.from_base_json(&item, false);
|
||||
External_Resource_Row row;
|
||||
row.name = value.name;
|
||||
row.description = value.description;
|
||||
row.download_url = value.download_url;
|
||||
row.update_interval_seconds = value.update_interval_seconds;
|
||||
row.last_updated_at = static_cast<std::int64_t>(value.last_updated_at);
|
||||
const auto status = status_by_name.find(value.name);
|
||||
if(status != status_by_name.end()) {
|
||||
row.row_count = status->second.row_count;
|
||||
row.state = status->second.message;
|
||||
}
|
||||
rows.push_back(std::move(row));
|
||||
}
|
||||
return rows;
|
||||
}
|
||||
Json source_amis_schema() {
|
||||
return adminive::to_amis_table_schema<Json, Data_Source_Row>("/api/adminive/config/data_sources", adminive::describe_table_view<Data_Source_Row>());
|
||||
}
|
||||
@@ -579,11 +707,72 @@ Json feed_amis_schema() {
|
||||
Json relation_amis_schema() {
|
||||
return adminive::to_amis_table_schema<Json, Source_Feed_Relation_Row>("/api/adminive/config/source_feed_relations", adminive::describe_table_view<Source_Feed_Relation_Row>());
|
||||
}
|
||||
Json external_resource_amis_schema() {
|
||||
auto schema = adminive::to_amis_table_schema<Json, External_Resource_Row>("/api/adminive/config/external_resources", adminive::describe_table_view<External_Resource_Row>());
|
||||
auto& crud = schema["body"][0];
|
||||
const std::string crud_id = "external_resource_table_crud";
|
||||
crud["headerToolbar"] = Json::array({Json{{"type", "columns-toggler"}, {"draggable", true}}, "reload", Json{{"type", "button"}, {"label", "全部后端下载并导入"}, {"level", "primary"}, {"actionType", "ajax"}, {"api", Json{{"method", "post"}, {"url", "/api/refresh_external_databases"}}}, {"reload", crud_id}}});
|
||||
auto& columns = crud["columns"];
|
||||
if(!columns.empty())
|
||||
columns.erase(columns.end() - 1);
|
||||
const auto refresh_button = Json{{"type", "button"}, {"label", "后端下载并导入"}, {"level", "link"}, {"actionType", "ajax"}, {"api", Json{{"method", "post"}, {"url", "/api/refresh_external_database"}, {"data", Json{{"name", "${name}"}}}}}, {"reload", crud_id}};
|
||||
const auto download_button = Json{{"type", "button"}, {"label", "前端下载"}, {"level", "link"}, {"actionType", "url"}, {"url", "${download_url}"}, {"blank", true}, {"disabledOn", "!this.download_url"}};
|
||||
const auto upload_button = Json{{"type", "button"}, {"label", "离线导入"}, {"level", "link"}, {"actionType", "dialog"}, {"dialog", Json{{"title", "离线导入 ${name}"}, {"body", Json{{"type", "input-file"}, {"name", "file"}, {"label", "数据文件"}, {"accept", ".csv,.gz,.zip,.txt"}, {"receiver", Json{{"method", "post"}, {"url", "/api/upload_external_database"}, {"data", Json{{"name", "${name}"}}}}}}}}}};
|
||||
const auto clear_button = Json{{"type", "button"}, {"label", "清空数据表"}, {"level", "link"}, {"className", "text-danger"}, {"actionType", "ajax"}, {"confirmText", "确定清空 ${name}?"}, {"api", Json{{"method", "post"}, {"url", "/api/clear_external_database_table"}, {"data", Json{{"name", "${name}"}}}}}, {"reload", crud_id}};
|
||||
columns.push_back(Json{{"type", "operation"}, {"label", "操作"}, {"buttons", Json::array({refresh_button, download_button, upload_button, clear_button})}});
|
||||
return schema;
|
||||
}
|
||||
void append_backend_config_rows(const Json& value, const std::string& section, const std::string& path, std::vector<Backend_Config_Row>& rows) {
|
||||
if(value.is_object() && !value.empty()) {
|
||||
for(auto it = value.begin(); it != value.end(); ++it)
|
||||
append_backend_config_rows(it.value(), section.empty() ? it.key() : section, path.empty() ? it.key() : path + "." + it.key(), rows);
|
||||
return;
|
||||
}
|
||||
if(value.is_array() && !value.empty()) {
|
||||
for(std::size_t i = 0; i < value.size(); ++i)
|
||||
append_backend_config_rows(value[i], section, path + "[" + std::to_string(i) + "]", rows);
|
||||
return;
|
||||
}
|
||||
rows.push_back({section, path, value.is_string() ? value.get<std::string>() : value.dump()});
|
||||
}
|
||||
std::vector<Backend_Config_Row> backend_config_rows(Global* global) {
|
||||
const auto config = Json::parse(global->toJson().to_json_string());
|
||||
std::vector<Backend_Config_Row> rows;
|
||||
append_backend_config_rows(config, {}, {}, rows);
|
||||
return rows;
|
||||
}
|
||||
Json backend_config_amis_schema() {
|
||||
auto schema = adminive::to_amis_table_schema<Json, Backend_Config_Row>("/api/adminive/config/backend_config", adminive::describe_table_view<Backend_Config_Row>());
|
||||
auto& crud = schema["body"][0];
|
||||
crud["headerToolbar"] = Json::array({Json{{"type", "columns-toggler"}, {"draggable", true}}, "reload"});
|
||||
auto& columns = crud["columns"];
|
||||
if(!columns.empty())
|
||||
columns.erase(columns.end() - 1);
|
||||
return schema;
|
||||
}
|
||||
Json archive_operations_schema() {
|
||||
const auto formats = Json::array({Json{{"label", "ZIP (.zip)"}, {"value", "zip"}, {"format", "zip"}, {"filter", ""}, {"extension", "zip"}}, Json{{"label", "TAR (.tar)"}, {"value", "tar"}, {"format", "pax"}, {"filter", ""}, {"extension", "tar"}}, Json{{"label", "TAR.GZ (.tar.gz)"}, {"value", "tar.gz"}, {"format", "pax"}, {"filter", "gzip"}, {"extension", "tar.gz"}}, Json{{"label", "TAR.XZ (.tar.xz)"}, {"value", "tar.xz"}, {"format", "pax"}, {"filter", "xz"}, {"extension", "tar.xz"}}, Json{{"label", "TAR.ZST (.tar.zst)"}, {"value", "tar.zst"}, {"format", "pax"}, {"filter", "zstd"}, {"extension", "tar.zst"}}, Json{{"label", "TAR.BZ2 (.tar.bz2)"}, {"value", "tar.bz2"}, {"format", "pax"}, {"filter", "bzip2"}, {"extension", "tar.bz2"}}, Json{{"label", "TAR.LZ4 (.tar.lz4)"}, {"value", "tar.lz4"}, {"format", "pax"}, {"filter", "lz4"}, {"extension", "tar.lz4"}}, Json{{"label", "7Z (.7z)"}, {"value", "7z"}, {"format", "7zip"}, {"filter", ""}, {"extension", "7z"}}});
|
||||
return Json{{"title", "导入导出"}, {"formats", std::move(formats)}, {"exports", Json::array({Json{{"name", "版本"}, {"api", "/api/export_version"}, {"allow_version_selection", true}}, Json{{"name", "日志"}, {"api", "/api/export_logs"}, {"allow_version_selection", false}}})}, {"import_api", "/api/import_version"}, {"import_accept", ".tar.zstd,.tar.zst,.tar.gz,.tgz,.tar.xz,.txz,.tar.bz2,.tbz2,.tar.lz4,.zip,.7z,.rar,.tar,.cpio,.iso,.xar"}};
|
||||
}
|
||||
Json cesium_models_schema(Global* global) {
|
||||
Json aircraft_types = Json::array();
|
||||
global->map_model_config.read([&](const auto& config) {
|
||||
for(const auto& [key, value] : config.aircraft_models) {
|
||||
static_cast<void>(value);
|
||||
aircraft_types.push_back(key);
|
||||
}
|
||||
});
|
||||
return Json{{"title", "Cesium 模型设置"}, {"data_api", "/map/models"}, {"upload_accept", ".glb"}, {"aircraft_types", std::move(aircraft_types)}};
|
||||
}
|
||||
Json system_actions_schema() {
|
||||
return Json{{"type", "panel"}, {"title", "设备操作"}, {"body", Json::array({Json{{"type", "button"}, {"label", "重启 FPGA 设备"}, {"level", "primary"}, {"actionType", "ajax"}, {"confirmText", "确定重启 FPGA 设备?"}, {"api", Json{{"method", "post"}, {"url", "/api/restart_device"}}}}})}};
|
||||
}
|
||||
class Adminive_Config_Resources {
|
||||
public:
|
||||
explicit Adminive_Config_Resources(Global* global) : global_(global),
|
||||
mode_acs_resource_(global->mode_acs.settings, mode_acs_path, mode_acs_transaction()),
|
||||
data_feed_settings_resource_(global->mode_acs.data_feed_config.settings, data_feed_settings_path, data_feed_settings_transaction()),
|
||||
map_view_resource_(global->map_view_config, map_view_path, map_view_transaction(global)),
|
||||
mlat_resource_(global->mlat.settings, mlat_path, value_section_transaction<MLAT_Config_Data>(Config_Section::mlat)),
|
||||
cesium_graphics_resource_(global->cesium_graphics_config.settings, cesium_graphics_path, value_section_transaction<Cesium_Graphics_Config_Data>(Config_Section::cesium_graphics)) {
|
||||
}
|
||||
@@ -591,16 +780,49 @@ public:
|
||||
auto& app = drogon::app();
|
||||
mode_acs_resource_.bind(app);
|
||||
data_feed_settings_resource_.bind(app);
|
||||
map_view_resource_.bind(app);
|
||||
mlat_resource_.bind(app);
|
||||
cesium_graphics_resource_.bind(app);
|
||||
bind_data_sources(app);
|
||||
bind_data_feeds(app);
|
||||
bind_relations(app);
|
||||
bind_external_resources(app);
|
||||
bind_backend_config(app);
|
||||
app.registerHandler(manifest_path, [this](const drogon::HttpRequestPtr&, std::function<void(const drogon::HttpResponsePtr&)>&& callback) {
|
||||
callback(adminive::make_drogon_response(adminive::make_http_success<Json>(manifest())));
|
||||
}, {drogon::Get});
|
||||
}
|
||||
private:
|
||||
void bind_backend_config(drogon::HttpAppFramework& app) {
|
||||
const auto get = adminive::make_drogon_constraints(drogon::Get, {});
|
||||
app.registerHandler(backend_config_path + "/descriptor", [](const drogon::HttpRequestPtr&, std::function<void(const drogon::HttpResponsePtr&)>&& callback) {
|
||||
callback(adminive::make_drogon_response(adminive::make_http_success<Json>(adminive::to_descriptor_json<Json, Backend_Config_Row>())));
|
||||
}, get);
|
||||
app.registerHandler(backend_config_path + "/view", [](const drogon::HttpRequestPtr&, std::function<void(const drogon::HttpResponsePtr&)>&& callback) {
|
||||
callback(adminive::make_drogon_response(adminive::make_http_success<Json>(adminive::to_view_json<Json, Backend_Config_Row>(adminive::describe_table_view<Backend_Config_Row>()))));
|
||||
}, get);
|
||||
app.registerHandler(backend_config_path + "/amis", [](const drogon::HttpRequestPtr&, std::function<void(const drogon::HttpResponsePtr&)>&& callback) {
|
||||
callback(adminive::make_drogon_response(adminive::make_http_success<Json>(backend_config_amis_schema())));
|
||||
}, get);
|
||||
app.registerHandler(backend_config_path, [this](const drogon::HttpRequestPtr& request, std::function<void(const drogon::HttpResponsePtr&)>&& callback) {
|
||||
callback(adminive::make_drogon_response(list_response<Backend_Config_Row>(backend_config_path, backend_config_rows(global_), read_collection_query(request))));
|
||||
}, get);
|
||||
}
|
||||
void bind_external_resources(drogon::HttpAppFramework& app) {
|
||||
const auto get = adminive::make_drogon_constraints(drogon::Get, {});
|
||||
app.registerHandler(external_resources_path + "/descriptor", [](const drogon::HttpRequestPtr&, std::function<void(const drogon::HttpResponsePtr&)>&& callback) {
|
||||
callback(adminive::make_drogon_response(adminive::make_http_success<Json>(adminive::to_descriptor_json<Json, External_Resource_Row>())));
|
||||
}, get);
|
||||
app.registerHandler(external_resources_path + "/view", [](const drogon::HttpRequestPtr&, std::function<void(const drogon::HttpResponsePtr&)>&& callback) {
|
||||
callback(adminive::make_drogon_response(adminive::make_http_success<Json>(adminive::to_view_json<Json, External_Resource_Row>(adminive::describe_table_view<External_Resource_Row>()))));
|
||||
}, get);
|
||||
app.registerHandler(external_resources_path + "/amis", [](const drogon::HttpRequestPtr&, std::function<void(const drogon::HttpResponsePtr&)>&& callback) {
|
||||
callback(adminive::make_drogon_response(adminive::make_http_success<Json>(external_resource_amis_schema())));
|
||||
}, get);
|
||||
app.registerHandler(external_resources_path, [this](const drogon::HttpRequestPtr& request, std::function<void(const drogon::HttpResponsePtr&)>&& callback) {
|
||||
callback(adminive::make_drogon_response(list_response<External_Resource_Row>(external_resources_path, external_resource_rows(global_), read_collection_query(request))));
|
||||
}, get);
|
||||
}
|
||||
void bind_data_sources(drogon::HttpAppFramework& app) {
|
||||
const auto get = adminive::make_drogon_constraints(drogon::Get, {});
|
||||
const auto post = adminive::make_drogon_constraints(drogon::Post, {});
|
||||
@@ -896,7 +1118,7 @@ private:
|
||||
}, post);
|
||||
}
|
||||
Json manifest() const {
|
||||
const auto view = adminive::composition_view("ecap_config", adminive::compose::frontend(adminive::compose::slot("mode_acs"), adminive::compose::slot("data_feed_settings"), adminive::compose::slot("data_sources"), adminive::compose::slot("data_feeds"), adminive::compose::slot("source_feed_relations"), adminive::compose::slot("mlat"), adminive::compose::slot("cesium_graphics"))).titled("ECAP 配置");
|
||||
const auto view = adminive::composition_view("ecap_config", adminive::compose::frontend(adminive::compose::slot("mode_acs"), adminive::compose::slot("data_feed_settings"), adminive::compose::slot("data_sources"), adminive::compose::slot("data_feeds"), adminive::compose::slot("source_feed_relations"), adminive::compose::slot("mlat"), adminive::compose::slot("map_view"), adminive::compose::slot("cesium_graphics"), adminive::compose::slot("external_resources"), adminive::compose::slot("archive_operations"), adminive::compose::slot("cesium_models"), adminive::compose::slot("backend_config"), adminive::compose::slot("system_actions"))).titled("ECAP 配置");
|
||||
const std::vector<adminive::Composition_Slot_Contract> contracts = {
|
||||
{"mode_acs", "amis_schema", mode_acs_path + "/descriptor", mode_acs_path + "/view", mode_acs_path + "/data", mode_acs_path + "/amis"},
|
||||
{"data_feed_settings", "amis_schema", data_feed_settings_path + "/descriptor", data_feed_settings_path + "/view", data_feed_settings_path + "/data", data_feed_settings_path + "/amis"},
|
||||
@@ -904,7 +1126,13 @@ private:
|
||||
{"data_feeds", "amis_schema", data_feeds_path + "/descriptor", data_feeds_path + "/view", data_feeds_path, data_feeds_path + "/amis"},
|
||||
{"source_feed_relations", "amis_schema", relations_path + "/descriptor", relations_path + "/view", relations_path, relations_path + "/amis"},
|
||||
{"mlat", "amis_schema", mlat_path + "/descriptor", mlat_path + "/view", mlat_path + "/data", mlat_path + "/amis"},
|
||||
{"cesium_graphics", "amis_schema", cesium_graphics_path + "/descriptor", cesium_graphics_path + "/view", cesium_graphics_path + "/data", cesium_graphics_path + "/amis"}
|
||||
{"map_view", "amis_schema", map_view_path + "/descriptor", map_view_path + "/view", map_view_path + "/data", map_view_path + "/amis"},
|
||||
{"cesium_graphics", "amis_schema", cesium_graphics_path + "/descriptor", cesium_graphics_path + "/view", cesium_graphics_path + "/data", cesium_graphics_path + "/amis"},
|
||||
{"external_resources", "amis_schema", external_resources_path + "/descriptor", external_resources_path + "/view", external_resources_path, external_resources_path + "/amis"},
|
||||
{"archive_operations", "ecap_archive_operations", {}, {}, {}, {}},
|
||||
{"cesium_models", "ecap_cesium_models", {}, {}, "/map/models", {}},
|
||||
{"backend_config", "amis_schema", backend_config_path + "/descriptor", backend_config_path + "/view", backend_config_path, backend_config_path + "/amis"},
|
||||
{"system_actions", "amis_schema", {}, {}, {}, {}}
|
||||
};
|
||||
const std::map<std::string, Json> schemas = {
|
||||
{"mode_acs", mode_acs_resource_.amis_schema()},
|
||||
@@ -913,15 +1141,24 @@ private:
|
||||
{"data_feeds", feed_amis_schema()},
|
||||
{"source_feed_relations", relation_amis_schema()},
|
||||
{"mlat", mlat_resource_.amis_schema()},
|
||||
{"cesium_graphics", cesium_graphics_resource_.amis_schema()}
|
||||
{"map_view", map_view_resource_.amis_schema()},
|
||||
{"cesium_graphics", cesium_graphics_resource_.amis_schema()},
|
||||
{"external_resources", external_resource_amis_schema()},
|
||||
{"archive_operations", archive_operations_schema()},
|
||||
{"cesium_models", cesium_models_schema(global_)},
|
||||
{"backend_config", backend_config_amis_schema()},
|
||||
{"system_actions", system_actions_schema()}
|
||||
};
|
||||
return adminive::to_composition_manifest_json<Json>(view, contracts, schemas);
|
||||
}
|
||||
static inline const std::string mode_acs_path = "/api/adminive/config/mode_acs";
|
||||
static inline const std::string data_feed_settings_path = "/api/adminive/config/data_feed_settings";
|
||||
static inline const std::string map_view_path = "/api/adminive/config/map_view";
|
||||
static inline const std::string data_sources_path = "/api/adminive/config/data_sources";
|
||||
static inline const std::string data_feeds_path = "/api/adminive/config/data_feeds";
|
||||
static inline const std::string relations_path = "/api/adminive/config/source_feed_relations";
|
||||
static inline const std::string external_resources_path = "/api/adminive/config/external_resources";
|
||||
static inline const std::string backend_config_path = "/api/adminive/config/backend_config";
|
||||
static inline const std::string mlat_path = "/api/adminive/config/mlat";
|
||||
static inline const std::string cesium_graphics_path = "/api/adminive/config/cesium_graphics";
|
||||
static inline const std::string manifest_path = "/api/adminive/config/manifest";
|
||||
@@ -929,6 +1166,7 @@ private:
|
||||
std::mutex topology_mutex_;
|
||||
adminive::Drogon_Resource<Mode_ACS_Config_Data, Json> mode_acs_resource_;
|
||||
adminive::Drogon_Resource<Data_feed_Config_Data, Json> data_feed_settings_resource_;
|
||||
adminive::Drogon_Resource<Map_View_Config, Json> map_view_resource_;
|
||||
adminive::Drogon_Resource<MLAT_Config_Data, Json> mlat_resource_;
|
||||
adminive::Drogon_Resource<Cesium_Graphics_Config_Data, Json> cesium_graphics_resource_;
|
||||
};
|
||||
|
||||
@@ -104,9 +104,18 @@ Psc::JSON config_section_value(Global& global, Config_Section section) {
|
||||
case Config_Section::http_monitor: return global.http_monitor_config.to_base_json();
|
||||
case Config_Section::mlat: return global.mlat.to_base_json();
|
||||
case Config_Section::web_server: return global.web_server_config.to_base_json();
|
||||
case Config_Section::map_resources: return global.map_resources_config.to_base_json();
|
||||
case Config_Section::map_view: return global.map_view_config.to_base_json();
|
||||
case Config_Section::map_models: return global.map_model_config.to_base_json();
|
||||
case Config_Section::map_resources:
|
||||
return global.map_resources_config.read([](const auto& value) {
|
||||
return value.to_base_json();
|
||||
});
|
||||
case Config_Section::map_view:
|
||||
return global.map_view_config.read([](const auto& value) {
|
||||
return value.to_base_json();
|
||||
});
|
||||
case Config_Section::map_models:
|
||||
return global.map_model_config.read([](const auto& value) {
|
||||
return value.to_base_json();
|
||||
});
|
||||
case Config_Section::device: return global.device_config.to_base_json();
|
||||
case Config_Section::mode_acs: return global.mode_acs.to_base_json();
|
||||
case Config_Section::log: return global.log_config.to_base_json();
|
||||
@@ -469,25 +478,25 @@ void Cesium_Graphics_Config::from_base_json(const Psc::JSON* that_json, bool not
|
||||
return;
|
||||
if (that_json->valueType != Psc::Object)
|
||||
throw Psc::json_assign_error(std::make_error_code(std::errc::invalid_argument), "cesium_graphics");
|
||||
auto value = settings.snapshot();
|
||||
value.from_base_json(that_json, not_exist_use_default_value);
|
||||
value.target_frame_rate = std::clamp(value.target_frame_rate, 1u, 120u);
|
||||
value.resolution_scale = std::clamp(value.resolution_scale, 0.2, 1.5);
|
||||
value.msaa_samples = std::clamp(value.msaa_samples, 1u, 8u);
|
||||
value.maximum_screen_space_error = std::clamp(value.maximum_screen_space_error, 1u, 16u);
|
||||
value.terrain_maximum_level = std::clamp(value.terrain_maximum_level, 0u, 24u);
|
||||
value.terrain_cache_tiles = std::clamp(value.terrain_cache_tiles, 16u, 2048u);
|
||||
value.performance_panel_x = std::max(0.0, value.performance_panel_x);
|
||||
value.performance_panel_y = std::max(0.0, value.performance_panel_y);
|
||||
value.view_axes_panel_y = std::max(0.0, value.view_axes_panel_y);
|
||||
value.view_axes_panel_size = std::clamp(value.view_axes_panel_size, 48.0, 240.0);
|
||||
value.occlusion_sample_spacing_meters = std::clamp(value.occlusion_sample_spacing_meters, 10.0, 5000.0);
|
||||
settings.write([&](auto& target) {
|
||||
target = value;
|
||||
settings.write([&](auto& value) {
|
||||
value.from_base_json(that_json, not_exist_use_default_value);
|
||||
value.target_frame_rate = std::clamp(value.target_frame_rate, 1u, 120u);
|
||||
value.resolution_scale = std::clamp(value.resolution_scale, 0.2, 1.5);
|
||||
value.msaa_samples = std::clamp(value.msaa_samples, 1u, 8u);
|
||||
value.maximum_screen_space_error = std::clamp(value.maximum_screen_space_error, 1u, 16u);
|
||||
value.terrain_maximum_level = std::clamp(value.terrain_maximum_level, 0u, 24u);
|
||||
value.terrain_cache_tiles = std::clamp(value.terrain_cache_tiles, 16u, 2048u);
|
||||
value.performance_panel_x = std::max(0.0, value.performance_panel_x);
|
||||
value.performance_panel_y = std::max(0.0, value.performance_panel_y);
|
||||
value.view_axes_panel_y = std::max(0.0, value.view_axes_panel_y);
|
||||
value.view_axes_panel_size = std::clamp(value.view_axes_panel_size, 48.0, 240.0);
|
||||
value.occlusion_sample_spacing_meters = std::clamp(value.occlusion_sample_spacing_meters, 10.0, 5000.0);
|
||||
});
|
||||
}
|
||||
Psc::JSON Cesium_Graphics_Config::to_base_json() const {
|
||||
return settings.snapshot().to_base_json();
|
||||
return settings.read([](const auto& value) {
|
||||
return value.to_base_json();
|
||||
});
|
||||
}
|
||||
Map_Model_Item_Config::Map_Model_Item_Config(std::string url) : url(std::move(url)) {
|
||||
}
|
||||
|
||||
@@ -122,22 +122,22 @@ struct Mode_ACS_Config {
|
||||
std::cout << " ~Mode_S_Config()" << std::endl;
|
||||
}
|
||||
Psc::JSON to_base_json() const {
|
||||
auto ret = settings.snapshot().to_base_json();
|
||||
auto ret = settings.read([](const auto& value) {
|
||||
return value.to_base_json();
|
||||
});
|
||||
ret.append(Psc::JSON("data_feed", data_feed_config.to_json()));
|
||||
ret.append(Psc::JSON("data_source", data_source_config.to_json()));
|
||||
ret.append(Psc::JSON("source_feed_relation", source_feed_relation_config.to_json()));
|
||||
return ret;
|
||||
}
|
||||
void from_json(const Psc::JSON* that_json, bool not_exist_use_default_value) {
|
||||
auto value = settings.snapshot();
|
||||
value.from_base_json(that_json, not_exist_use_default_value);
|
||||
settings.write([&](auto& target) {
|
||||
target = value;
|
||||
settings.write([&](auto& value) {
|
||||
value.from_base_json(that_json, not_exist_use_default_value);
|
||||
SSR::Monitor_Mode_ACS_Message_Num = value.monitor_msg_live;
|
||||
});
|
||||
data_feed_config.init(that_json->get("data_feed"), not_exist_use_default_value);
|
||||
data_source_config.init(that_json->get("data_source"), not_exist_use_default_value);
|
||||
source_feed_relation_config.from_json(that_json->get("source_feed_relation"), not_exist_use_default_value);
|
||||
SSR::Monitor_Mode_ACS_Message_Num = value.monitor_msg_live;
|
||||
}
|
||||
void server(Global* g);
|
||||
};
|
||||
@@ -215,6 +215,17 @@ struct Map_Resources_Config {
|
||||
[[nodiscard]] bool is_imagery_key(std::string_view key) const;
|
||||
[[nodiscard]] bool is_terrain_key(std::string_view key) const;
|
||||
};
|
||||
namespace adminive {
|
||||
template <>
|
||||
struct Type_Descriptor<Map_Resources_Config> {
|
||||
static auto get() {
|
||||
using T = Map_Resources_Config;
|
||||
return object<T>("map_resources_config", "地图资源配置",
|
||||
ADMINIVE_FIELD_LABEL(T, current_imagery_key, "当前影像源").read_write(),
|
||||
ADMINIVE_FIELD_LABEL(T, tile_sources, "地图瓦片源").read_write());
|
||||
}
|
||||
};
|
||||
}
|
||||
struct Map_Camera_Config {
|
||||
double longitude = 121.27;
|
||||
double latitude = 37.41;
|
||||
@@ -224,6 +235,21 @@ struct Map_Camera_Config {
|
||||
double roll = 0.0;
|
||||
PSC_USE_JSON
|
||||
};
|
||||
namespace adminive {
|
||||
template <>
|
||||
struct Type_Descriptor<Map_Camera_Config> {
|
||||
static auto get() {
|
||||
using T = Map_Camera_Config;
|
||||
return object<T>("map_camera_config", "地图相机",
|
||||
ADMINIVE_FIELD_LABEL(T, longitude, "经度").editable().number_input(),
|
||||
ADMINIVE_FIELD_LABEL(T, latitude, "纬度").editable().number_input(),
|
||||
ADMINIVE_FIELD_LABEL(T, height, "高度").editable().number_input(),
|
||||
ADMINIVE_FIELD_LABEL(T, heading, "航向角").editable().number_input(),
|
||||
ADMINIVE_FIELD_LABEL(T, pitch, "俯仰角").editable().number_input(),
|
||||
ADMINIVE_FIELD_LABEL(T, roll, "横滚角").editable().number_input());
|
||||
}
|
||||
};
|
||||
}
|
||||
struct Map_Tile_View_Config {
|
||||
std::string current_imagery_key = "imagery";
|
||||
std::string current_terrain_key = "terrain";
|
||||
@@ -232,6 +258,19 @@ struct Map_Tile_View_Config {
|
||||
void from_base_json(const Psc::JSON* that_json, bool not_exist_use_default_value);
|
||||
[[nodiscard]] Psc::JSON to_base_json() const;
|
||||
};
|
||||
namespace adminive {
|
||||
template <>
|
||||
struct Type_Descriptor<Map_Tile_View_Config> {
|
||||
static auto get() {
|
||||
using T = Map_Tile_View_Config;
|
||||
return object<T>("map_tile_view_config", "地图瓦片视图",
|
||||
ADMINIVE_FIELD_LABEL(T, current_imagery_key, "影像源").editable().text_input(),
|
||||
ADMINIVE_FIELD_LABEL(T, current_terrain_key, "地形源").editable().text_input(),
|
||||
ADMINIVE_FIELD_LABEL(T, tile_zoom_mode, "缩放模式").editable().select_input(),
|
||||
ADMINIVE_FIELD_LABEL(T, tile_display_maximum_level, "显示最大层级").editable().number_input());
|
||||
}
|
||||
};
|
||||
}
|
||||
struct Map_View_Config {
|
||||
std::string scene_mode = "3d";
|
||||
Map_Tile_View_Config map2d;
|
||||
@@ -242,6 +281,20 @@ struct Map_View_Config {
|
||||
[[nodiscard]] Psc::JSON to_base_json() const;
|
||||
[[nodiscard]] static bool is_scene_mode(std::string_view mode);
|
||||
};
|
||||
namespace adminive {
|
||||
template <>
|
||||
struct Type_Descriptor<Map_View_Config> {
|
||||
static auto get() {
|
||||
using T = Map_View_Config;
|
||||
return object<T>("map_view_config", "地图视图配置",
|
||||
ADMINIVE_FIELD_LABEL(T, scene_mode, "场景模式").editable().required().text_input(),
|
||||
ADMINIVE_FIELD_LABEL(T, map2d, "2D 地图").editable(),
|
||||
ADMINIVE_FIELD_LABEL(T, map3d, "3D 地图").editable(),
|
||||
ADMINIVE_FIELD_LABEL(T, camera, "相机").editable(),
|
||||
ADMINIVE_FIELD_LABEL(T, base_station_fly_to_height_offset_meters, "基站飞行高度偏移(米)").editable().number_input());
|
||||
}
|
||||
};
|
||||
}
|
||||
struct Cesium_Graphics_Config_Data {
|
||||
bool debug_show_frames_per_second = true;
|
||||
std::uint32_t target_frame_rate = 30;
|
||||
@@ -356,6 +409,19 @@ struct Map_Model_Config {
|
||||
void from_base_json(const Psc::JSON* that_json, bool not_exist_use_default_value);
|
||||
[[nodiscard]] Psc::JSON to_base_json() const;
|
||||
};
|
||||
namespace adminive {
|
||||
template <>
|
||||
struct Type_Descriptor<Map_Model_Config> {
|
||||
static auto get() {
|
||||
using T = Map_Model_Config;
|
||||
return object<T>("map_model_config", "Cesium 模型配置",
|
||||
ADMINIVE_FIELD_LABEL(T, aircraft_model, "默认飞机模型").read_write(),
|
||||
ADMINIVE_FIELD_LABEL(T, aircraft_models, "机型模型").read_write(),
|
||||
ADMINIVE_FIELD_LABEL(T, base_station_model, "基站模型").read_write(),
|
||||
ADMINIVE_FIELD_LABEL(T, device_model, "设备模型").read_write());
|
||||
}
|
||||
};
|
||||
}
|
||||
struct Net_Config {
|
||||
std::string key{};
|
||||
std::string ip{};
|
||||
@@ -409,10 +475,10 @@ public:
|
||||
MLAT_Config mlat;
|
||||
Device_Config device_config;
|
||||
Web_Server_Config web_server_config;
|
||||
Map_Resources_Config map_resources_config;
|
||||
Map_View_Config map_view_config;
|
||||
adminive::Managed_Value<Map_Resources_Config> map_resources_config;
|
||||
adminive::Managed_Value<Map_View_Config> map_view_config;
|
||||
Cesium_Graphics_Config cesium_graphics_config;
|
||||
Map_Model_Config map_model_config;
|
||||
adminive::Managed_Value<Map_Model_Config> map_model_config;
|
||||
Mode_ACS_Config mode_acs;
|
||||
Log_Config log_config;
|
||||
Console_Config console_config{};
|
||||
@@ -425,10 +491,16 @@ public:
|
||||
void from_base_json(Psc::JSON* that_json, bool not_exist_use_default_value) {
|
||||
Get_J(version) mlat.from_json(that_json->get("mlat"), not_exist_use_default_value);
|
||||
web_server_config.from_base_json(that_json->get("web_server"), not_exist_use_default_value);
|
||||
map_resources_config.from_base_json(that_json->get("map_resources"), not_exist_use_default_value);
|
||||
map_view_config.from_base_json(that_json->get("map_view"), not_exist_use_default_value);
|
||||
map_resources_config.write([&](auto& value) {
|
||||
value.from_base_json(that_json->get("map_resources"), not_exist_use_default_value);
|
||||
});
|
||||
map_view_config.write([&](auto& value) {
|
||||
value.from_base_json(that_json->get("map_view"), not_exist_use_default_value);
|
||||
});
|
||||
cesium_graphics_config.from_base_json(that_json->get("cesium_graphics"), not_exist_use_default_value);
|
||||
map_model_config.from_base_json(that_json->get("map_models"), not_exist_use_default_value);
|
||||
map_model_config.write([&](auto& value) {
|
||||
value.from_base_json(that_json->get("map_models"), not_exist_use_default_value);
|
||||
});
|
||||
device_config.from_json(that_json->get("device"), not_exist_use_default_value);
|
||||
mode_acs.from_json(that_json->get("mode_acs"), not_exist_use_default_value);
|
||||
console_config.from_base_json(that_json->get("console"), not_exist_use_default_value);
|
||||
@@ -445,9 +517,9 @@ public:
|
||||
{"http_monitor", http_monitor_config.to_base_json()},
|
||||
{"mlat", mlat.to_base_json()},
|
||||
{"web_server", web_server_config.to_base_json()},
|
||||
{"map_resources", map_resources_config.to_base_json()},
|
||||
{"map_view", map_view_config.to_base_json()},
|
||||
{"map_models", map_model_config.to_base_json()},
|
||||
{"map_resources", map_resources_config.read([](const auto& value) { return value.to_base_json(); })},
|
||||
{"map_view", map_view_config.read([](const auto& value) { return value.to_base_json(); })},
|
||||
{"map_models", map_model_config.read([](const auto& value) { return value.to_base_json(); })},
|
||||
{"device", device_config.to_base_json()},
|
||||
{"mode_acs", mode_acs.to_base_json()},
|
||||
//{"ais", ais.to_json()},
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "MLAT.h"
|
||||
#include <fstream>
|
||||
#include <string_view>
|
||||
#include <tuple>
|
||||
#include "Global.h"
|
||||
time_t datetime_to_timestamp(std::string_view datetime) {
|
||||
std::tm tm = {};
|
||||
@@ -98,21 +99,20 @@ void read(MLAT_Data* buf, std::uint16_t* len) {
|
||||
MLAT_Config::MLAT_Config() {
|
||||
}
|
||||
void MLAT_Config::from_json(const Psc::JSON* that_json, bool not_exist_use_default_value) {
|
||||
auto value = settings.snapshot();
|
||||
value.from_base_json(that_json, not_exist_use_default_value);
|
||||
settings.write([&](auto& target) {
|
||||
target = value;
|
||||
const auto [enable, library_path, function_name] = settings.write([&](auto& value) {
|
||||
value.from_base_json(that_json, not_exist_use_default_value);
|
||||
return std::tuple{value.enable, value.library_path, value.function_name};
|
||||
});
|
||||
if (value.enable) {
|
||||
if (enable) {
|
||||
{
|
||||
auto r = Psc::try_load_library(Psc::get_abs_path(value.library_path));
|
||||
auto r = Psc::try_load_library(Psc::get_abs_path(library_path));
|
||||
if (!r) {
|
||||
Psc::fail_fast();
|
||||
}
|
||||
lib = r.value();
|
||||
}
|
||||
{
|
||||
auto r = Psc::try_load_function(lib, value.function_name);
|
||||
auto r = Psc::try_load_function(lib, function_name);
|
||||
if (!r) {
|
||||
Psc::fail_fast();
|
||||
}
|
||||
|
||||
@@ -62,7 +62,9 @@ public:
|
||||
~MLAT_Config() = default;
|
||||
MLAT_Config();
|
||||
[[nodiscard]] Psc::JSON to_base_json() const {
|
||||
return settings.snapshot().to_base_json();
|
||||
return settings.read([](const auto& value) {
|
||||
return value.to_base_json();
|
||||
});
|
||||
}
|
||||
void* lib{};
|
||||
using Func_Type = void (*)(MLAT_Data* buf, std::uint16_t* len);
|
||||
|
||||
@@ -3,14 +3,12 @@
|
||||
#include "Global.h"
|
||||
void Source_Feed_Relation::from_json(const Psc::JSON* that_json) {
|
||||
Get_J(key) Get_J(type)
|
||||
auto value = settings.snapshot();
|
||||
value.from_base_json(that_json, true);
|
||||
settings.write([&](auto& target) {
|
||||
target = value;
|
||||
settings.write([&](auto& value) {
|
||||
value.from_base_json(that_json, true);
|
||||
});
|
||||
}
|
||||
Psc::JSON Source_Feed_Relation::to_json() const {
|
||||
auto ret = settings.snapshot().to_base_json();
|
||||
auto ret = settings.read([](const auto& value) { return value.to_base_json(); });
|
||||
ret.append({"key", key});
|
||||
ret.append({"type", type});
|
||||
return ret;
|
||||
@@ -47,14 +45,14 @@ bool Source_Feed_Relation_Config::source_has_dependency(std::string_view key) co
|
||||
for (const auto& relation : map.list()) {
|
||||
if (relation->type == "First_Source_To_All_Feed_Relation")
|
||||
continue;
|
||||
if (relation->settings.member<&Source_Feed_Relation_Data::source_key>().snapshot() == key)
|
||||
if (relation->settings.member<&Source_Feed_Relation_Data::source_key>().read([](const auto& value) { return value; }) == key)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool Source_Feed_Relation_Config::feed_has_dependency(std::string_view key) const {
|
||||
for (const auto& relation : map.list()) {
|
||||
const auto value = relation->settings.snapshot();
|
||||
const auto value = relation->settings.read([](const auto& value) { return value; });
|
||||
if (relation->type == "One_to_One_Relation" && value.feed_key == key)
|
||||
return true;
|
||||
if (relation->type == "Name_One_To_Many_Relation") {
|
||||
@@ -71,7 +69,7 @@ void Source_Feed_Relation_Config::validate(const Source_Feed_Relation& relation,
|
||||
auto existing = map.get(relation.key);
|
||||
if (existing.has_value() && relation.key != current_key)
|
||||
throw std::invalid_argument("关系名称已存在: " + relation.key);
|
||||
const auto value = relation.settings.snapshot();
|
||||
const auto value = relation.settings.read([](const auto& value) { return value; });
|
||||
if (relation.type == "One_to_One_Relation") {
|
||||
if (!source_exists(value.source_key))
|
||||
throw std::invalid_argument("数据源不存在: " + value.source_key);
|
||||
@@ -80,7 +78,7 @@ void Source_Feed_Relation_Config::validate(const Source_Feed_Relation& relation,
|
||||
for (const auto& item : map.list()) {
|
||||
if (item->key == current_key || item->type != "One_to_One_Relation")
|
||||
continue;
|
||||
if (item->settings.member<&Source_Feed_Relation_Data::feed_key>().snapshot() == value.feed_key)
|
||||
if (item->settings.member<&Source_Feed_Relation_Data::feed_key>().read([](const auto& value) { return value; }) == value.feed_key)
|
||||
throw std::invalid_argument("数据馈送已存在一对一关系: " + value.feed_key);
|
||||
}
|
||||
return;
|
||||
|
||||
@@ -40,7 +40,9 @@ public:
|
||||
void sync_wait();
|
||||
[[nodiscard]] bool running() const;
|
||||
[[nodiscard]] bool enabled() const {
|
||||
return config.member<&With_Loop_Coro_Config::enable>().snapshot();
|
||||
return config.member<&With_Loop_Coro_Config::enable>().read([](bool value) {
|
||||
return value;
|
||||
});
|
||||
}
|
||||
void set_enabled(bool value) {
|
||||
config.member<&With_Loop_Coro_Config::enable>().write([value](bool& target) {
|
||||
@@ -48,17 +50,17 @@ public:
|
||||
});
|
||||
}
|
||||
[[nodiscard]] Psc::JSON to_base_json() const {
|
||||
auto ret = config.snapshot().to_base_json();
|
||||
auto ret = config.read([](const auto& value) {
|
||||
return value.to_base_json();
|
||||
});
|
||||
ret.append({"type", type});
|
||||
ret.append({"key", key});
|
||||
return ret;
|
||||
}
|
||||
void from_base_json(const Psc::JSON* that_json, bool not_exist_use_default_value) {
|
||||
Get_J(type) Get_J(key)
|
||||
auto value = config.snapshot();
|
||||
value.from_base_json(that_json, not_exist_use_default_value);
|
||||
config.write([&](auto& target) {
|
||||
target = value;
|
||||
config.write([&](auto& value) {
|
||||
value.from_base_json(that_json, not_exist_use_default_value);
|
||||
});
|
||||
}
|
||||
asio::awaitable<void> tick();
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <format>
|
||||
#include <sstream>
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
static std::string thread_id_str() {
|
||||
std::ostringstream oss;
|
||||
oss << std::this_thread::get_id();
|
||||
@@ -160,9 +161,9 @@ asio::awaitable<void> Data_Feed::loop_coro() {
|
||||
auto other_num = feed->msg_buffer.mode_other_msg_num.load();
|
||||
const std::vector<std::string*>& all = feed->msg_buffer.get_all();
|
||||
Pool_Guard pg(&pool, all);
|
||||
const auto mode_config = mode_acs.settings.snapshot();
|
||||
auto num = mode_config.report_data_feed_msg_mum;
|
||||
auto monitor_msg_live = mode_config.monitor_msg_live;
|
||||
const auto [num, monitor_msg_live] = mode_acs.settings.read([](const auto& value) {
|
||||
return std::pair{value.report_data_feed_msg_mum, value.monitor_msg_live};
|
||||
});
|
||||
if (monitor_msg_live && num != 0 && all.size() > num && too_many_msg_limit.test()) {
|
||||
std::ostringstream oss;
|
||||
oss << "feed_key:" << feed->key << " ";
|
||||
@@ -227,7 +228,7 @@ asio::awaitable<void> Data_Source::loop_coro() {
|
||||
if (data_source_debug) {
|
||||
std::cout << std::format("[4] ds:{} after read thread:{}\n", key, thread_id_str()) << std::flush;;
|
||||
}
|
||||
const auto wait = Global::instance()->mode_acs.settings.member<&Mode_ACS_Config_Data::wait_process_msg>().snapshot();
|
||||
const auto wait = Global::instance()->mode_acs.settings.member<&Mode_ACS_Config_Data::wait_process_msg>().read([](const auto& value) { return value; });
|
||||
if (wait) {
|
||||
// 调度到别的线程
|
||||
co_await resume_on(co->process_data->get_executor());
|
||||
|
||||
@@ -484,19 +484,26 @@ void register_map_resources_handler() {
|
||||
return;
|
||||
}
|
||||
auto key = parsed.value().try_get_string("current_imagery_key");
|
||||
if (!key.has_value() || !global->map_resources_config.is_imagery_key(key.value())) {
|
||||
const bool valid_key = key.has_value() && global->map_resources_config.read([&](const auto& config) {
|
||||
return config.is_imagery_key(key.value());
|
||||
});
|
||||
if (!valid_key) {
|
||||
response->setStatusCode(drogon::k400BadRequest);
|
||||
response->setContentTypeCode(drogon::CT_TEXT_PLAIN);
|
||||
response->setBody("invalid current_imagery_key");
|
||||
callback(response);
|
||||
return;
|
||||
}
|
||||
global->map_resources_config.current_imagery_key = key.value();
|
||||
global->map_resources_config.write([&](auto& config) {
|
||||
config.current_imagery_key = key.value();
|
||||
});
|
||||
Global::save(Config_Section::map_resources);
|
||||
}
|
||||
response->setStatusCode(drogon::k200OK);
|
||||
response->setContentTypeCode(drogon::CT_APPLICATION_JSON);
|
||||
response->setBody(global->map_resources_config.to_public_json().to_json_string());
|
||||
response->setBody(global->map_resources_config.read([](const auto& config) {
|
||||
return config.to_public_json().to_json_string();
|
||||
}));
|
||||
response->addHeader("Cache-Control", "no-store");
|
||||
callback(response);
|
||||
},
|
||||
@@ -538,8 +545,12 @@ void register_map_graphics_handler() {
|
||||
{drogon::Get, drogon::Post});
|
||||
}
|
||||
Psc::JSON make_map_view_response(Global* global) {
|
||||
auto ret = global->map_view_config.to_base_json();
|
||||
ret.append({"current_imagery_key", global->map_resources_config.current_imagery_key});
|
||||
auto ret = global->map_view_config.read([](const auto& config) {
|
||||
return config.to_base_json();
|
||||
});
|
||||
global->map_resources_config.read([&](const auto& config) {
|
||||
ret.append({"current_imagery_key", config.current_imagery_key});
|
||||
});
|
||||
return ret;
|
||||
}
|
||||
bool is_multipart_request(const drogon::HttpRequestPtr& req) {
|
||||
@@ -590,9 +601,13 @@ void save_uploaded_model_file(const drogon::HttpFile& upload, std::string_view m
|
||||
if (extension != ".glb") {
|
||||
throw std::invalid_argument("model file must be .glb");
|
||||
}
|
||||
if (model_type == "aircraft_type" &&
|
||||
!global->map_model_config.aircraft_models.contains(std::string(aircraft_model_key))) {
|
||||
throw std::invalid_argument("unknown aircraft_model_key");
|
||||
if (model_type == "aircraft_type") {
|
||||
const bool exists = global->map_model_config.read([&](const auto& config) {
|
||||
return config.aircraft_models.contains(std::string(aircraft_model_key));
|
||||
});
|
||||
if (!exists) {
|
||||
throw std::invalid_argument("unknown aircraft_model_key");
|
||||
}
|
||||
}
|
||||
auto upload_dir = std::filesystem::path(drogon::app().getUploadPath());
|
||||
std::filesystem::create_directories(upload_dir);
|
||||
@@ -610,18 +625,20 @@ void save_uploaded_model_file(const drogon::HttpFile& upload, std::string_view m
|
||||
std::filesystem::copy_file(temp_path, source_dir / file_name, std::filesystem::copy_options::overwrite_existing);
|
||||
std::filesystem::remove(temp_path);
|
||||
auto url = "/ui/model/" + file_name;
|
||||
if (model_type == "aircraft") {
|
||||
global->map_model_config.aircraft_model.url = url;
|
||||
}
|
||||
else if (model_type == "aircraft_type") {
|
||||
global->map_model_config.aircraft_models[std::string(aircraft_model_key)].url = url;
|
||||
}
|
||||
else if (model_type == "base_station") {
|
||||
global->map_model_config.base_station_model.url = url;
|
||||
}
|
||||
else {
|
||||
global->map_model_config.device_model.url = url;
|
||||
}
|
||||
global->map_model_config.write([&](auto& config) {
|
||||
if (model_type == "aircraft") {
|
||||
config.aircraft_model.url = url;
|
||||
}
|
||||
else if (model_type == "aircraft_type") {
|
||||
config.aircraft_models[std::string(aircraft_model_key)].url = url;
|
||||
}
|
||||
else if (model_type == "base_station") {
|
||||
config.base_station_model.url = url;
|
||||
}
|
||||
else {
|
||||
config.device_model.url = url;
|
||||
}
|
||||
});
|
||||
}
|
||||
void handle_map_model_upload(const drogon::HttpRequestPtr& req, Global* global) {
|
||||
drogon::MultiPartParser parser;
|
||||
@@ -641,7 +658,9 @@ void handle_map_model_config_update(const drogon::HttpRequestPtr& req, Global* g
|
||||
if (!parsed.has_value()) {
|
||||
throw std::invalid_argument("invalid map_models");
|
||||
}
|
||||
global->map_model_config.from_base_json(&parsed.value(), false);
|
||||
global->map_model_config.write([&](auto& config) {
|
||||
config.from_base_json(&parsed.value(), false);
|
||||
});
|
||||
Global::save(Config_Section::map_models);
|
||||
}
|
||||
void register_map_models_handler() {
|
||||
@@ -661,7 +680,9 @@ void register_map_models_handler() {
|
||||
}
|
||||
response->setStatusCode(drogon::k200OK);
|
||||
response->setContentTypeCode(drogon::CT_APPLICATION_JSON);
|
||||
response->setBody(global->map_model_config.to_base_json().to_json_string());
|
||||
response->setBody(global->map_model_config.read([](const auto& config) {
|
||||
return config.to_base_json().to_json_string();
|
||||
}));
|
||||
}
|
||||
catch (const std::exception& error) {
|
||||
response->setStatusCode(drogon::k400BadRequest);
|
||||
@@ -689,7 +710,10 @@ void register_map_view_handler() {
|
||||
return;
|
||||
}
|
||||
auto key = parsed.value().try_get_string("current_imagery_key");
|
||||
if (!key.has_value() || !global->map_resources_config.is_imagery_key(key.value())) {
|
||||
const bool valid_key = key.has_value() && global->map_resources_config.read([&](const auto& config) {
|
||||
return config.is_imagery_key(key.value());
|
||||
});
|
||||
if (!valid_key) {
|
||||
response->setStatusCode(drogon::k400BadRequest);
|
||||
response->setContentTypeCode(drogon::CT_TEXT_PLAIN);
|
||||
response->setBody("invalid current_imagery_key");
|
||||
@@ -697,18 +721,26 @@ void register_map_view_handler() {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
auto next_view = global->map_view_config;
|
||||
auto next_view = global->map_view_config.read([](const auto& config) {
|
||||
return config;
|
||||
});
|
||||
next_view.from_base_json(&parsed.value(), false);
|
||||
if (!global->map_resources_config.is_imagery_key(next_view.map2d.current_imagery_key) ||
|
||||
!global->map_resources_config.is_imagery_key(next_view.map3d.current_imagery_key)) {
|
||||
throw std::invalid_argument("invalid current_imagery_key");
|
||||
}
|
||||
if (!next_view.map3d.current_terrain_key.empty() &&
|
||||
!global->map_resources_config.is_terrain_key(next_view.map3d.current_terrain_key)) {
|
||||
throw std::invalid_argument("invalid current_terrain_key");
|
||||
}
|
||||
global->map_resources_config.current_imagery_key = key.value();
|
||||
global->map_view_config = next_view;
|
||||
global->map_resources_config.read([&](const auto& config) {
|
||||
if (!config.is_imagery_key(next_view.map2d.current_imagery_key) ||
|
||||
!config.is_imagery_key(next_view.map3d.current_imagery_key)) {
|
||||
throw std::invalid_argument("invalid current_imagery_key");
|
||||
}
|
||||
if (!next_view.map3d.current_terrain_key.empty() &&
|
||||
!config.is_terrain_key(next_view.map3d.current_terrain_key)) {
|
||||
throw std::invalid_argument("invalid current_terrain_key");
|
||||
}
|
||||
});
|
||||
global->map_resources_config.write([&](auto& config) {
|
||||
config.current_imagery_key = key.value();
|
||||
});
|
||||
global->map_view_config.write([&](auto& config) {
|
||||
config = std::move(next_view);
|
||||
});
|
||||
Global::save(Config_Section::map_resources);
|
||||
Global::save(Config_Section::map_view);
|
||||
}
|
||||
@@ -734,7 +766,9 @@ void Global::init_tiles() {
|
||||
register_map_graphics_handler();
|
||||
register_map_models_handler();
|
||||
register_map_view_handler();
|
||||
for (const auto& source : map_resources_config.tile_sources) {
|
||||
register_tile_source_handler(source);
|
||||
}
|
||||
map_resources_config.read([](const auto& config) {
|
||||
for (const auto& source : config.tile_sources) {
|
||||
register_tile_source_handler(source);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user