初步修改

This commit is contained in:
2026-08-09 14:13:35 +08:00
parent 1e1e77e41a
commit 6fe0bed78e
26 changed files with 2007 additions and 681 deletions
+163 -66
View File
@@ -1,30 +1,136 @@
#include "Config.h"
#include "Config_Default.h"
#include <algorithm>
#include <array>
#include <exception>
#include <filesystem>
#include <mutex>
#include <stdexcept>
#include <string_view>
#include <utility>
#include "Global.h"
#include "Psc_Cpp_Core/Base/Check.h"
#include "Psc_Cpp_Core/Net_Adapter/Net_Adapter.h"
#undef interface
std::string default_config_path;
std::string get_config_path() {
// #ifdef WIN32
// get_exe_dir()
// return "D:/ae/proj/projects/ECAP_Server/config/config.json";
// #endif
static bool first = true;
if (!default_config_path.empty())
return default_config_path;
std::string ret;
std::ostringstream oss;
std::string file_name = "config.json";
ret = get_exe_dir() + "/" + file_name;
if (first) {
std::cout << oss.str() << std::endl;
first = false;
std::string default_config_directory;
namespace {
constexpr std::string_view config_section_names[] = {"version", "dsp", "drogon", "http_monitor", "mlat", "web_server", "map_resources", "map_view", "map_models", "device", "mode_acs", "log", "console", "external_database", "cesium_graphics"};
constexpr std::string_view config_section_name(Config_Section section) {
return config_section_names[static_cast<std::size_t>(section)];
}
std::filesystem::path config_directory() {
if (!default_config_directory.empty()) {
return default_config_directory;
}
return ret;
return std::filesystem::path(get_exe_dir()) / "config";
}
std::filesystem::path config_section_path(Config_Section section) {
return config_directory() / (std::string(config_section_name(section)) + ".json");
}
std::array<std::mutex, static_cast<std::size_t>(Config_Section::count)> config_section_mutexes;
void write_config_section_unlocked(Config_Section section, const Psc::JSON& value) {
const auto directory = config_directory();
std::filesystem::create_directories(directory);
const auto path = config_section_path(section);
auto temporary = path;
temporary += ".tmp";
std::ofstream output(temporary, std::ios::binary | std::ios::trunc);
if (!output) {
throw std::runtime_error("cannot open config section: " + temporary.string());
}
const auto json = value.to_json_string();
output.write(json.data(), static_cast<std::streamsize>(json.size()));
output.close();
if (output.fail()) {
throw std::runtime_error("cannot write config section: " + temporary.string());
}
std::error_code error;
std::filesystem::remove(path, error);
std::filesystem::rename(temporary, path);
}
void write_config_section(Config_Section section, const Psc::JSON& value) {
std::lock_guard lock(config_section_mutexes[static_cast<std::size_t>(section)]);
write_config_section_unlocked(section, value);
}
Psc::JSON read_existing_config_section_unlocked(Config_Section section) {
const auto path = config_section_path(section);
std::ifstream input(path, std::ios::binary);
if (!input) {
throw std::runtime_error("cannot open config section: " + path.string());
}
std::ostringstream buffer;
buffer << input.rdbuf();
return Psc::parse_json(buffer.str());
}
void merge_json_object(Psc::JSON& target, const Psc::JSON& value) {
for (const auto& child : value.children) {
auto iterator = std::find_if(target.children.begin(), target.children.end(), [&](const Psc::JSON& current) {
return current.key == child.key;
});
if (iterator == target.children.end()) {
target.append(child);
continue;
}
if (iterator->valueType == Psc::Object && child.valueType == Psc::Object)
merge_json_object(*iterator, child);
else
*iterator = child;
}
}
Psc::JSON read_config_section(Config_Section section, const Psc::JSON& defaults) {
const auto path = config_section_path(section);
if (!std::filesystem::exists(path)) {
const auto name = config_section_name(section);
const auto value = defaults.get(name);
if (value == nullptr) {
throw std::runtime_error("default config section does not exist: " + std::string(name));
}
write_config_section(section, *value);
return *value;
}
std::ifstream input(path, std::ios::binary);
if (!input) {
throw std::runtime_error("cannot open config section: " + path.string());
}
std::ostringstream buffer;
buffer << input.rdbuf();
return Psc::parse_json(buffer.str());
}
Psc::JSON config_section_value(Global& global, Config_Section section) {
switch (section) {
case Config_Section::version: return Psc::JSON(global.version);
case Config_Section::dsp: return global.dsp_config.to_base_json();
case Config_Section::drogon: return global.drogon_config;
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::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();
case Config_Section::console: return global.console_config.to_base_json();
case Config_Section::external_database: return global.external_resources_manager.to_base_json();
case Config_Section::cesium_graphics: return global.cesium_graphics_config.to_base_json();
case Config_Section::count: break;
}
std::terminate();
}
}
std::string get_config_directory() {
return config_directory().string();
}
Psc::JSON Config::load() {
std::filesystem::create_directories(config_directory());
const auto defaults = Psc::parse_json(std::string_view(reinterpret_cast<const char*>(ecap_default_config_json), sizeof(ecap_default_config_json)));
auto result = Psc::JSON::object();
for (std::size_t index = 0; index < static_cast<std::size_t>(Config_Section::count); ++index) {
const auto section = static_cast<Config_Section>(index);
result.append({std::string(config_section_name(section)), read_config_section(section, defaults)});
}
std::cout << get_current_date_string() << " 启动加载配置目录: 【" << config_directory().string() << "" << std::endl;
return result;
}
static std::vector<std::string> read_string_array(const Psc::JSON* json, std::string_view key) {
auto field = json->get(key);
@@ -359,27 +465,29 @@ Psc::JSON Map_View_Config::to_base_json() const {
return ret;
}
void Cesium_Graphics_Config::from_base_json(const Psc::JSON* that_json, bool not_exist_use_default_value) {
if (that_json == nullptr) {
if (that_json == nullptr)
return;
}
if (that_json->valueType != Psc::Object) {
if (that_json->valueType != Psc::Object)
throw Psc::json_assign_error(std::make_error_code(std::errc::invalid_argument), "cesium_graphics");
}
Cesium_Graphics_Config_Data::from_base_json(that_json, not_exist_use_default_value);
target_frame_rate = std::clamp(target_frame_rate, 1u, 120u);
resolution_scale = std::clamp(resolution_scale, 0.2, 1.5);
msaa_samples = std::clamp(msaa_samples, 1u, 8u);
maximum_screen_space_error = std::clamp(maximum_screen_space_error, 1u, 16u);
terrain_maximum_level = std::clamp(terrain_maximum_level, 0u, 24u);
terrain_cache_tiles = std::clamp(terrain_cache_tiles, 16u, 2048u);
performance_panel_x = std::max(0.0, performance_panel_x);
performance_panel_y = std::max(0.0, performance_panel_y);
view_axes_panel_y = std::max(0.0, view_axes_panel_y);
view_axes_panel_size = std::clamp(view_axes_panel_size, 48.0, 240.0);
occlusion_sample_spacing_meters = std::clamp(occlusion_sample_spacing_meters, 10.0, 5000.0);
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;
});
}
Psc::JSON Cesium_Graphics_Config::to_base_json() const {
return Cesium_Graphics_Config_Data::to_base_json();
return settings.snapshot().to_base_json();
}
Map_Model_Item_Config::Map_Model_Item_Config(std::string url) : url(std::move(url)) {
}
@@ -431,34 +539,8 @@ Psc::JSON Map_Model_Config::to_base_json() const {
return ret;
}
void Mode_ACS_Config::server(Global* g) {
auto& svr = g->svr;
auto& api = g->api;
data_source_config.server(g);
data_feed_config.server(g);
source_feed_relation_config.server(g);
svr.Post(api + "get_mode_s_basic_config", [this](HTTP_Param) {
CHECK_JSON_PARAM
res->setBody(warp(to_base_json()).to_json_string());
});
svr.Post(api + "set_mode_s_basic_config", [this](HTTP_Param) {
CHECK_JSON_PARAM
auto& j = o_params.value();
init_base_json(&j, false);
if (auto min_points = j.try_get_number<std::size_t>("aircraft_change_list_min_position_points")) {
aircraft_change_list_min_position_points = min_points.value();
}
if (auto range_filter = j.try_get_bool("aircraft_change_list_adsb_range_filter")) {
aircraft_change_list_adsb_range_filter = range_filter.value();
}
if (auto range_factor = j.try_get_number<double>("aircraft_change_list_adsb_range_factor")) {
aircraft_change_list_adsb_range_factor = range_factor.value();
}
if (auto target_altitude = j.try_get_number<double>("adsb_theoretical_target_altitude_meters")) {
adsb_theoretical_target_altitude_meters = target_altitude.value();
}
Global::save();
res->setBody(warp(to_base_json()).to_json_string());
});
}
void Device_Config::server(Global* g) {
auto& svr = g->svr;
@@ -514,7 +596,7 @@ void Device_Config::server(Global* g) {
*w.list.get("device").value() = device;
*w.list.get("wifi").value() = wifi;
}
Global::save();
Global::save(Config_Section::device);
if (use) {
std::string interface;
{
@@ -571,9 +653,24 @@ void Device_Config::server(Global* g) {
});
}
void Config::save() {
std::ofstream config_file;
config_file.open(get_config_path());
std::string json = Global::instance()->toJson().to_json_string();
config_file.write(json.c_str(), static_cast<long long>(json.size()));
config_file.close();
auto& global = *Global::instance();
for (std::size_t index = 0; index < static_cast<std::size_t>(Config_Section::count); ++index) {
const auto section = static_cast<Config_Section>(index);
write_config_section(section, config_section_value(global, section));
}
}
void Config::save(Config_Section section) {
auto& global = *Global::instance();
write_config_section(section, config_section_value(global, section));
}
void Config::save(Config_Section section, const Psc::JSON& value) {
write_config_section(section, value);
}
void Config::merge(Config_Section section, const Psc::JSON& value) {
std::lock_guard lock(config_section_mutexes[static_cast<std::size_t>(section)]);
auto current = read_existing_config_section_unlocked(section);
if (current.valueType != Psc::Object || value.valueType != Psc::Object)
throw std::invalid_argument("config merge requires object");
merge_json_object(current, value);
write_config_section_unlocked(section, current);
}