From 4b9dd5c1997dc0dcc02433afe04148409c0262ee Mon Sep 17 00:00:00 2001 From: wyc <1104749580@qq.com> Date: Sun, 9 Aug 2026 15:30:12 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- module/Local_Server/Data_Feed/Data_Feed.cpp | 6 +- module/Local_Server/Data_Feed/Data_Feed.h | 56 ++- .../Local_Server/Data_Source/Data_Source.cpp | 14 +- module/Local_Server/Data_Source/Data_Source.h | 59 ++-- .../Data_Source/Data_Source_Handler.cpp | 87 ++--- module/Local_Server/Data_Source/Database.cpp | 38 ++- .../Local_Server/server/Adminive_Config.cpp | 320 +++++++++++++++--- module/Local_Server/server/Config.cpp | 47 +-- module/Local_Server/server/Config.h | 102 +++++- module/Local_Server/server/MLAT.cpp | 14 +- module/Local_Server/server/MLAT.h | 4 +- .../server/Source_Feed_Relation.cpp | 16 +- module/Local_Server/server/With_Loop_Coro.h | 14 +- module/Local_Server/server/io_coro.cpp | 9 +- module/Local_Server/server/tiles.cpp | 108 ++++-- 15 files changed, 616 insertions(+), 278 deletions(-) diff --git a/module/Local_Server/Data_Feed/Data_Feed.cpp b/module/Local_Server/Data_Feed/Data_Feed.cpp index 219bb6b..d415b31 100644 --- a/module/Local_Server/Data_Feed/Data_Feed.cpp +++ b/module/Local_Server/Data_Feed/Data_Feed.cpp @@ -19,7 +19,7 @@ asio::awaitable Data_Feed_UDP_Server::send_coro(std::string_view data) { co_return; } asio::awaitable 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 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 g(mtx); diff --git a/module/Local_Server/Data_Feed/Data_Feed.h b/module/Local_Server/Data_Feed/Data_Feed.h index f5dd10c..564fbb4 100644 --- a/module/Local_Server/Data_Feed/Data_Feed.h +++ b/module/Local_Server/Data_Feed/Data_Feed.h @@ -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 _close() override { co_await svr.close_coro(); co_return; } asio::awaitable _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 _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 _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 _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 _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; } diff --git a/module/Local_Server/Data_Source/Data_Source.cpp b/module/Local_Server/Data_Source/Data_Source.cpp index 385c5cd..05e4657 100644 --- a/module/Local_Server/Data_Source/Data_Source.cpp +++ b/module/Local_Server/Data_Source/Data_Source.cpp @@ -53,7 +53,7 @@ Data_Source::Data_Source() { // parse_format = std::make_shared(); // 写入到配置文件是懒加载 其他保存时他跟着保存 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 File_Data_Source::get_raw_line(int& ret_index) { } std::optional 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 File_Data_Source::_close() { } asio::awaitable 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 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(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 Shared_Memory_Data_Source::_open() { - const auto config = specific.snapshot(); + const auto config = specific.read([](const auto& value) { return value; }); sm = std::make_unique(); 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; } diff --git a/module/Local_Server/Data_Source/Data_Source.h b/module/Local_Server/Data_Source/Data_Source.h index f6d7a55..f0768e2 100644 --- a/module/Local_Server/Data_Source/Data_Source.h +++ b/module/Local_Server/Data_Source/Data_Source.h @@ -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 _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 read_coro() override { @@ -288,7 +284,7 @@ public: type = "Serial_Data_Source"; } asio::awaitable _open() override { - const auto value = specific.snapshot(); + const auto value = specific.read([](const auto& value) { return value; }); serial = std::make_unique(); 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 serial{}; @@ -392,21 +386,19 @@ public: std::shared_ptr pre_cache = nullptr; std::deque> 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 _close() override; asio::awaitable _open() override; std::vector 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& msg) override; @@ -453,15 +445,14 @@ public: std::vector 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 _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 _open() override; asio::awaitable _close() override; diff --git a/module/Local_Server/Data_Source/Data_Source_Handler.cpp b/module/Local_Server/Data_Source/Data_Source_Handler.cpp index 8a977af..7a85153 100644 --- a/module/Local_Server/Data_Source/Data_Source_Handler.cpp +++ b/module/Local_Server/Data_Source/Data_Source_Handler.cpp @@ -1,5 +1,7 @@ #include "Data_Source_Handler.h" #include +#include +#include #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& 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(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 convert_to_send_format(Data_Source_Handler* ds, const auto& type = msg->type; auto fs = dynamic_cast(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& 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 list; for (const auto& item : cached_data_feed_key_list) { auto& key = item.key; diff --git a/module/Local_Server/Data_Source/Database.cpp b/module/Local_Server/Data_Source/Database.cpp index ec8cd01..fefdaed 100644 --- a/module/Local_Server/Data_Source/Database.cpp +++ b/module/Local_Server/Data_Source/Database.cpp @@ -3,7 +3,7 @@ #include "../server/Global.h" #include "../server/Performance_Monitor.h" #include "../server/WebSocket_Manager.h" - +#include #include #include #include @@ -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> DataBase::get_visible_aircraft_snapshot() { std::vector> 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()) diff --git a/module/Local_Server/server/Adminive_Config.cpp b/module/Local_Server/server/Adminive_Config.cpp index 397faf1..769ce6f 100644 --- a/module/Local_Server/server/Adminive_Config.cpp +++ b/module/Local_Server/server/Adminive_Config.cpp @@ -6,6 +6,7 @@ #include "adminive/adapters/nlohmann_json.hpp" #include #include +#include #include #include #include @@ -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 { + static auto get() { + using T = ecap::adminive_config::External_Resource_Row; + return object("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 { + static Table_View table() { + using T = ecap::adminive_config::External_Resource_Row; + return table_view(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 { + static auto get() { + using T = ecap::adminive_config::Backend_Config_Row; + return object("backend_config", "后端完整配置", + ADMINIVE_FIELD_LABEL(T, section, "配置分区"), + ADMINIVE_FIELD_LABEL(T, path, "配置项"), + ADMINIVE_FIELD_LABEL(T, value, "当前值")); + } +}; +template <> +struct Type_View_Descriptor { + static Table_View table() { + using T = ecap::adminive_config::Backend_Config_Row; + return table_view(column<&T::section>("配置分区").filter(), column<&T::path>("配置项").search(), column<&T::value>("当前值")).titled("后端完整配置(只读)"); + } +}; +template <> struct Type_Descriptor { static auto get() { using T = ecap::adminive_config::Data_Source_Row; @@ -274,6 +327,38 @@ adminive::Resource_Transaction data_feed_settings_transac }; return transaction; } +adminive::Resource_Transaction map_view_transaction(Global* global) { + adminive::Resource_Transaction 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& 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(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(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(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(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(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& 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(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(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(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(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& feed, const Data_Feed_Row& } Source_Feed_Relation_Row relation_row(const std::shared_ptr& 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& relation, const Source_Feed_Relation_Row& row) { @@ -570,6 +670,34 @@ std::vector relation_rows(Global* global) { rows.push_back(relation_row(relation)); return rows; } +std::vector external_resource_rows(Global* global) { + std::map 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 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(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("/api/adminive/config/data_sources", adminive::describe_table_view()); } @@ -579,11 +707,72 @@ Json feed_amis_schema() { Json relation_amis_schema() { return adminive::to_amis_table_schema("/api/adminive/config/source_feed_relations", adminive::describe_table_view()); } +Json external_resource_amis_schema() { + auto schema = adminive::to_amis_table_schema("/api/adminive/config/external_resources", adminive::describe_table_view()); + 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& 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() : value.dump()}); +} +std::vector backend_config_rows(Global* global) { + const auto config = Json::parse(global->toJson().to_json_string()); + std::vector rows; + append_backend_config_rows(config, {}, {}, rows); + return rows; +} +Json backend_config_amis_schema() { + auto schema = adminive::to_amis_table_schema("/api/adminive/config/backend_config", adminive::describe_table_view()); + 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(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(Config_Section::mlat)), cesium_graphics_resource_(global->cesium_graphics_config.settings, cesium_graphics_path, value_section_transaction(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&& callback) { callback(adminive::make_drogon_response(adminive::make_http_success(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&& callback) { + callback(adminive::make_drogon_response(adminive::make_http_success(adminive::to_descriptor_json()))); + }, get); + app.registerHandler(backend_config_path + "/view", [](const drogon::HttpRequestPtr&, std::function&& callback) { + callback(adminive::make_drogon_response(adminive::make_http_success(adminive::to_view_json(adminive::describe_table_view())))); + }, get); + app.registerHandler(backend_config_path + "/amis", [](const drogon::HttpRequestPtr&, std::function&& callback) { + callback(adminive::make_drogon_response(adminive::make_http_success(backend_config_amis_schema()))); + }, get); + app.registerHandler(backend_config_path, [this](const drogon::HttpRequestPtr& request, std::function&& callback) { + callback(adminive::make_drogon_response(list_response(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&& callback) { + callback(adminive::make_drogon_response(adminive::make_http_success(adminive::to_descriptor_json()))); + }, get); + app.registerHandler(external_resources_path + "/view", [](const drogon::HttpRequestPtr&, std::function&& callback) { + callback(adminive::make_drogon_response(adminive::make_http_success(adminive::to_view_json(adminive::describe_table_view())))); + }, get); + app.registerHandler(external_resources_path + "/amis", [](const drogon::HttpRequestPtr&, std::function&& callback) { + callback(adminive::make_drogon_response(adminive::make_http_success(external_resource_amis_schema()))); + }, get); + app.registerHandler(external_resources_path, [this](const drogon::HttpRequestPtr& request, std::function&& callback) { + callback(adminive::make_drogon_response(list_response(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 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 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(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_resource_; adminive::Drogon_Resource data_feed_settings_resource_; + adminive::Drogon_Resource map_view_resource_; adminive::Drogon_Resource mlat_resource_; adminive::Drogon_Resource cesium_graphics_resource_; }; diff --git a/module/Local_Server/server/Config.cpp b/module/Local_Server/server/Config.cpp index 1b17010..acd1a4e 100644 --- a/module/Local_Server/server/Config.cpp +++ b/module/Local_Server/server/Config.cpp @@ -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)) { } diff --git a/module/Local_Server/server/Config.h b/module/Local_Server/server/Config.h index 1c134f7..846041c 100644 --- a/module/Local_Server/server/Config.h +++ b/module/Local_Server/server/Config.h @@ -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 { + static auto get() { + using T = Map_Resources_Config; + return object("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 { + static auto get() { + using T = Map_Camera_Config; + return object("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 { + static auto get() { + using T = Map_Tile_View_Config; + return object("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 { + static auto get() { + using T = Map_View_Config; + return object("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 { + static auto get() { + using T = Map_Model_Config; + return object("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; + adminive::Managed_Value map_view_config; Cesium_Graphics_Config cesium_graphics_config; - Map_Model_Config map_model_config; + adminive::Managed_Value 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()}, diff --git a/module/Local_Server/server/MLAT.cpp b/module/Local_Server/server/MLAT.cpp index 4c5ee5a..bd3cec2 100644 --- a/module/Local_Server/server/MLAT.cpp +++ b/module/Local_Server/server/MLAT.cpp @@ -1,6 +1,7 @@ #include "MLAT.h" #include #include +#include #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(); } diff --git a/module/Local_Server/server/MLAT.h b/module/Local_Server/server/MLAT.h index 7ced769..306741a 100644 --- a/module/Local_Server/server/MLAT.h +++ b/module/Local_Server/server/MLAT.h @@ -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); diff --git a/module/Local_Server/server/Source_Feed_Relation.cpp b/module/Local_Server/server/Source_Feed_Relation.cpp index 758994c..9baa2dd 100644 --- a/module/Local_Server/server/Source_Feed_Relation.cpp +++ b/module/Local_Server/server/Source_Feed_Relation.cpp @@ -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; diff --git a/module/Local_Server/server/With_Loop_Coro.h b/module/Local_Server/server/With_Loop_Coro.h index e042868..3948922 100644 --- a/module/Local_Server/server/With_Loop_Coro.h +++ b/module/Local_Server/server/With_Loop_Coro.h @@ -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 tick(); diff --git a/module/Local_Server/server/io_coro.cpp b/module/Local_Server/server/io_coro.cpp index 0cbb969..ff85e32 100644 --- a/module/Local_Server/server/io_coro.cpp +++ b/module/Local_Server/server/io_coro.cpp @@ -14,6 +14,7 @@ #include #include #include +#include static std::string thread_id_str() { std::ostringstream oss; oss << std::this_thread::get_id(); @@ -160,9 +161,9 @@ asio::awaitable Data_Feed::loop_coro() { auto other_num = feed->msg_buffer.mode_other_msg_num.load(); const std::vector& 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 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()); diff --git a/module/Local_Server/server/tiles.cpp b/module/Local_Server/server/tiles.cpp index 29ee3ef..9169a9f 100644 --- a/module/Local_Server/server/tiles.cpp +++ b/module/Local_Server/server/tiles.cpp @@ -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); + } + }); }