初步修改
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user