Files
ECAP_Server/module/Local_Server/server/Config.cpp
T
2026-08-05 14:37:55 +08:00

580 lines
26 KiB
C++

#include "Config.h"
#include <algorithm>
#include <filesystem>
#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;
}
return ret;
}
static std::vector<std::string> read_string_array(const Psc::JSON* json, std::string_view key) {
auto field = json->get(key);
if (field == nullptr || field->valueType != Psc::Array) {
throw Psc::json_assign_error(std::make_error_code(std::errc::invalid_argument), std::string(key));
}
std::vector<std::string> ret;
ret.reserve(field->children.size());
for (const auto& child : field->children) {
if (child.valueType != Psc::String) {
throw Psc::json_assign_error(std::make_error_code(std::errc::invalid_argument), std::string(key));
}
ret.emplace_back(child.val);
}
return ret;
}
static std::vector<std::string> read_optional_string_array(const Psc::JSON* json, std::string_view key) {
auto field = json->get(key);
if (field == nullptr) {
return {};
}
if (field->valueType != Psc::Array) {
throw Psc::json_assign_error(std::make_error_code(std::errc::invalid_argument), std::string(key));
}
std::vector<std::string> ret;
ret.reserve(field->children.size());
for (const auto& child : field->children) {
if (child.valueType != Psc::String) {
throw Psc::json_assign_error(std::make_error_code(std::errc::invalid_argument), std::string(key));
}
ret.emplace_back(child.val);
}
return ret;
}
static Psc::JSON write_string_array(std::string_view key, const std::vector<std::string>& list) {
auto array = Psc::JSON::array();
for (const auto& path : list) {
array.append(Psc::JSON(path));
}
return Psc::JSON(key, array);
}
static const std::pair<std::string_view, std::string_view> kDefaultAircraftModelUrls[] = {
{"no_category_information", "/ui/model/aircraft-no-category-information.glb"},
{"surface_emergency_vehicle", "/ui/model/aircraft-surface-emergency-vehicle.glb"},
{"surface_service_vehicle", "/ui/model/aircraft-surface-service-vehicle.glb"},
{"ground_obstruction_4", "/ui/model/aircraft-ground-obstruction-4.glb"},
{"ground_obstruction_5", "/ui/model/aircraft-ground-obstruction-5.glb"},
{"ground_obstruction_6", "/ui/model/aircraft-ground-obstruction-6.glb"},
{"ground_obstruction_7", "/ui/model/aircraft-ground-obstruction-7.glb"},
{"glider", "/ui/model/aircraft-glider.glb"},
{"lighter_than_air", "/ui/model/aircraft-lighter-than-air.glb"},
{"parachutist", "/ui/model/aircraft-parachutist.glb"},
{"ultralight_hangglider_paraglider", "/ui/model/aircraft-ultralight-hangglider-paraglider.glb"},
{"reserved_3_5", "/ui/model/aircraft-reserved-3-5.glb"},
{"unmanned_aerial_vehicle", "/ui/model/aircraft-unmanned-aerial-vehicle.glb"},
{"space_transatmospheric_vehicle", "/ui/model/aircraft-space-transatmospheric-vehicle.glb"},
{"light_aircraft", "/ui/model/aircraft-light-aircraft.glb"},
{"medium_1_aircraft", "/ui/model/aircraft-medium-1-aircraft.glb"},
{"medium_2_aircraft", "/ui/model/aircraft-medium-2-aircraft.glb"},
{"high_vortex_aircraft", "/ui/model/aircraft-high-vortex-aircraft.glb"},
{"heavy_aircraft", "/ui/model/aircraft-heavy-aircraft.glb"},
{"high_performance_aircraft", "/ui/model/aircraft-high-performance-aircraft.glb"},
{"rotorcraft", "/ui/model/aircraft-rotorcraft.glb"}};
static std::map<std::string, Map_Model_Item_Config> make_default_aircraft_models() {
std::map<std::string, Map_Model_Item_Config> ret;
for (const auto& item : kDefaultAircraftModelUrls) {
ret.emplace(std::string(item.first), Map_Model_Item_Config{std::string(item.second), 50.0, -90.0, 0.0, 0.0});
}
return ret;
}
static std::map<std::string, Map_Model_Item_Config>
read_optional_model_object_field(const Psc::JSON* json, std::string_view key,
std::map<std::string, Map_Model_Item_Config> fallback,
bool not_exist_use_default_value) {
auto field = json->get(key);
if (field == nullptr) {
return fallback;
}
if (field->valueType != Psc::Object) {
throw Psc::json_assign_error(std::make_error_code(std::errc::invalid_argument), std::string(key));
}
for (const auto& child : field->children) {
if (child.valueType != Psc::Object) {
throw Psc::json_assign_error(std::make_error_code(std::errc::invalid_argument), std::string(key));
}
fallback[child.key].from_base_json(&child, not_exist_use_default_value);
}
return fallback;
}
static Psc::JSON write_model_object(std::string_view key, const std::map<std::string, Map_Model_Item_Config>& values) {
auto object = Psc::JSON::object();
for (const auto& item : values) {
object.append({item.first, item.second.to_base_json()});
}
return Psc::JSON(key, object);
}
static std::string read_optional_string_field(const Psc::JSON* json, std::string_view key) {
auto field = json->get(key);
if (field == nullptr) {
return {};
}
if (field->valueType != Psc::String) {
throw Psc::json_assign_error(std::make_error_code(std::errc::invalid_argument), std::string(key));
}
return field->val;
}
static std::string read_optional_string_field(const Psc::JSON* json, std::string_view key, std::string_view fallback) {
auto field = json->get(key);
if (field == nullptr) {
return std::string(fallback);
}
if (field->valueType != Psc::String) {
throw Psc::json_assign_error(std::make_error_code(std::errc::invalid_argument), std::string(key));
}
return field->val;
}
static std::uint32_t read_optional_uint32_field(const Psc::JSON* json, std::string_view key, std::uint32_t fallback) {
auto field = json->get(key);
if (field == nullptr) {
return fallback;
}
if (field->valueType != Psc::Number) {
throw Psc::json_assign_error(std::make_error_code(std::errc::invalid_argument), std::string(key));
}
return field->number_val<std::uint32_t>();
}
static double read_optional_double_field(const Psc::JSON* json, std::string_view key, double fallback) {
auto field = json->get(key);
if (field == nullptr) {
return fallback;
}
if (field->valueType != Psc::Number) {
throw Psc::json_assign_error(std::make_error_code(std::errc::invalid_argument), std::string(key));
}
return field->number_val<double>();
}
void Map_Tile_Config::from_base_json(const Psc::JSON* that_json, bool not_exist_use_default_value) {
if (that_json == nullptr || that_json->valueType != Psc::Object) {
throw Psc::json_assign_error(std::make_error_code(std::errc::invalid_argument), "map tile config");
}
Map_Tile_Config_Data::from_base_json(that_json, not_exist_use_default_value);
directories = read_optional_string_array(that_json, "directories");
files = read_optional_string_array(that_json, "files");
encoding = read_optional_string_field(that_json, "encoding");
}
Psc::JSON Map_Tile_Config::to_base_json() const {
auto ret = Map_Tile_Config_Data::to_base_json();
ret.append(write_string_array("directories", directories));
ret.append(write_string_array("files", files));
if (!encoding.empty()) {
ret.append({"encoding", encoding});
}
return ret;
}
Psc::JSON Map_Tile_Config::to_public_json(std::string_view url) const {
auto ret = Psc::JSON::object();
ret.append({"url", std::string(url)});
ret.append({"minimum_level", minimum_level});
ret.append({"maximum_level", maximum_level});
ret.append({"tile_size", tile_size});
ret.append({"projection", Psc::to_string(projection)});
ret.append({"y_axis", Psc::to_string(y_axis)});
if (!encoding.empty()) {
ret.append({"encoding", encoding});
}
return ret;
}
void Map_Tile_Source_Config::from_base_json(const Psc::JSON* that_json, bool not_exist_use_default_value) {
if (that_json == nullptr || that_json->valueType != Psc::Object) {
throw Psc::json_assign_error(std::make_error_code(std::errc::invalid_argument), "map tile source config");
}
Map_Tile_Source_Config_Data::from_base_json(that_json, not_exist_use_default_value);
url = read_optional_string_field(that_json, "url");
resource.from_base_json(that_json->get("resource"), not_exist_use_default_value);
}
Psc::JSON Map_Tile_Source_Config::to_base_json() const {
auto ret = Map_Tile_Source_Config_Data::to_base_json();
if (!url.empty()) {
ret.append({"url", url});
}
ret.append({"resource", resource.to_base_json()});
return ret;
}
Psc::JSON Map_Tile_Source_Config::to_public_json(std::string_view local_url) const {
auto ret = Psc::JSON::object();
ret.append({"key", key});
ret.append({"name", name});
ret.append({"tile_type", Psc::to_string(tile_type)});
ret.append({"request_method", Psc::to_string(request_method)});
ret.append({"resource", resource.to_public_json(local() ? local_url : url)});
return ret;
}
static std::vector<Map_Tile_Source_Config> read_optional_tile_source_array(const Psc::JSON* json, std::string_view key,
bool not_exist_use_default_value) {
auto field = json->get(key);
if (field == nullptr) {
return {};
}
if (field->valueType != Psc::Array) {
throw Psc::json_assign_error(std::make_error_code(std::errc::invalid_argument), std::string(key));
}
std::vector<Map_Tile_Source_Config> ret;
ret.reserve(field->children.size());
for (const auto& child : field->children) {
Map_Tile_Source_Config item;
item.from_base_json(&child, not_exist_use_default_value);
ret.push_back(std::move(item));
}
return ret;
}
static Psc::JSON write_tile_source_array(std::string_view key, const std::vector<Map_Tile_Source_Config>& list) {
auto array = Psc::JSON::array();
for (const auto& source : list) {
array.append(source.to_base_json());
}
return Psc::JSON(key, array);
}
void Map_Resources_Config::from_base_json(const Psc::JSON* that_json, bool not_exist_use_default_value) {
if (that_json == nullptr || that_json->valueType != Psc::Object) {
throw Psc::json_assign_error(std::make_error_code(std::errc::invalid_argument), "map_resources");
}
current_imagery_key = read_optional_string_field(that_json, "current_imagery_key");
if (current_imagery_key.empty()) {
current_imagery_key = "imagery";
}
tile_sources = read_optional_tile_source_array(that_json, "tile_sources", not_exist_use_default_value);
if (!is_imagery_key(current_imagery_key)) {
auto source = std::ranges::find_if(
tile_sources, [](const Map_Tile_Source_Config& item) { return item.tile_type == Map_Tile_Type::imagery; });
current_imagery_key = source == tile_sources.end() ? "" : source->key;
}
}
Psc::JSON Map_Resources_Config::to_base_json() const {
auto ret = Psc::JSON::object();
ret.append({"current_imagery_key", current_imagery_key});
ret.append(write_tile_source_array("tile_sources", tile_sources));
return ret;
}
Psc::JSON Map_Resources_Config::to_public_json() const {
auto ret = Psc::JSON::object();
auto sources = Psc::JSON::array();
auto imagery_sources = Psc::JSON::array();
auto terrain_sources = Psc::JSON::array();
auto terrain = Psc::JSON::object();
bool has_terrain = false;
for (const auto& source : tile_sources) {
auto url = "/map/tile_sources/" + source.key + "/{z}/{x}/{y}";
auto public_source = source.to_public_json(url);
sources.append(public_source);
if (source.tile_type == Map_Tile_Type::imagery) {
imagery_sources.append(public_source);
}
else if (source.tile_type == Map_Tile_Type::terrain) {
terrain_sources.append(public_source);
if (!has_terrain) {
terrain = *public_source.get("resource");
has_terrain = true;
}
}
}
ret.append({"current_imagery_key", current_imagery_key});
ret.append({"tile_sources", sources});
ret.append({"imagery_sources", imagery_sources});
ret.append({"terrain_sources", terrain_sources});
if (has_terrain) {
ret.append({"terrain", std::move(terrain)});
}
return ret;
}
bool Map_Resources_Config::is_imagery_key(std::string_view key) const {
return std::ranges::any_of(tile_sources, [key](const Map_Tile_Source_Config& source) {
return source.tile_type == Map_Tile_Type::imagery && source.key == key;
});
}
bool Map_Resources_Config::is_terrain_key(std::string_view key) const {
return std::ranges::any_of(tile_sources, [key](const Map_Tile_Source_Config& source) {
return source.tile_type == Map_Tile_Type::terrain && source.key == key;
});
}
bool Map_View_Config::is_scene_mode(std::string_view mode) {
return mode == "2d" || mode == "2.5d" || mode == "3d";
}
void Map_Tile_View_Config::from_base_json(const Psc::JSON* that_json, bool not_exist_use_default_value) {
if (that_json == nullptr) {
return;
}
if (that_json->valueType != Psc::Object) {
throw Psc::json_assign_error(std::make_error_code(std::errc::invalid_argument), "map_tile_view");
}
current_imagery_key = read_optional_string_field(that_json, "current_imagery_key", current_imagery_key);
current_terrain_key = read_optional_string_field(that_json, "current_terrain_key", current_terrain_key);
tile_zoom_mode = Psc::to_enum<Map_Tile_Zoom_Mode>(
read_optional_string_field(that_json, "tile_zoom_mode", Psc::to_string(tile_zoom_mode)));
tile_display_maximum_level = std::clamp(
read_optional_uint32_field(that_json, "tile_display_maximum_level", tile_display_maximum_level), 0u, 24u);
}
Psc::JSON Map_Tile_View_Config::to_base_json() const {
auto ret = Psc::JSON::object();
ret.append({"current_imagery_key", current_imagery_key});
ret.append({"current_terrain_key", current_terrain_key});
ret.append({"tile_zoom_mode", Psc::to_string(tile_zoom_mode)});
ret.append({"tile_display_maximum_level", tile_display_maximum_level});
return ret;
}
void Map_View_Config::from_base_json(const Psc::JSON* that_json, bool not_exist_use_default_value) {
if (that_json == nullptr) {
return;
}
if (that_json->valueType != Psc::Object) {
throw Psc::json_assign_error(std::make_error_code(std::errc::invalid_argument), "map_view");
}
auto next_scene_mode = read_optional_string_field(that_json, "scene_mode", scene_mode);
if (!is_scene_mode(next_scene_mode)) {
throw Psc::json_assign_error(std::make_error_code(std::errc::invalid_argument), "scene_mode");
}
scene_mode = next_scene_mode;
map2d.from_base_json(that_json->get("map2d"), not_exist_use_default_value);
map3d.from_base_json(that_json->get("map3d"), not_exist_use_default_value);
camera.from_base_json(that_json->get("camera"), not_exist_use_default_value);
base_station_fly_to_height_offset_meters =
std::max(100.0,
read_optional_double_field(that_json, "baseStationFlyToHeightOffsetMeters",
base_station_fly_to_height_offset_meters));
}
Psc::JSON Map_View_Config::to_base_json() const {
auto ret = Psc::JSON::object();
ret.append({"scene_mode", scene_mode});
ret.append({"map2d", map2d.to_base_json()});
ret.append({"map3d", map3d.to_base_json()});
ret.append({"camera", camera.to_base_json()});
ret.append({"baseStationFlyToHeightOffsetMeters", base_station_fly_to_height_offset_meters});
return ret;
}
void Cesium_Graphics_Config::from_base_json(const Psc::JSON* that_json, bool not_exist_use_default_value) {
if (that_json == nullptr) {
return;
}
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);
}
Psc::JSON Cesium_Graphics_Config::to_base_json() const {
return Cesium_Graphics_Config_Data::to_base_json();
}
Map_Model_Item_Config::Map_Model_Item_Config(std::string url) : url(std::move(url)) {
}
Map_Model_Item_Config::Map_Model_Item_Config(std::string url, double built_in_size, double heading, double pitch,
double roll) :
url(std::move(url)), built_in_size(built_in_size), heading_offset_degrees(heading), pitch_offset_degrees(pitch),
roll_offset_degrees(roll) {
}
void Map_Model_Item_Config::from_base_json(const Psc::JSON* that_json, bool not_exist_use_default_value) {
if (that_json == nullptr || that_json->valueType != Psc::Object) {
throw Psc::json_assign_error(std::make_error_code(std::errc::invalid_argument), "map_model_item");
}
url = read_optional_string_field(that_json, "url", url);
built_in_size = read_optional_double_field(that_json, "built_in_size", built_in_size);
heading_offset_degrees = read_optional_double_field(that_json, "heading_offset_degrees", heading_offset_degrees);
pitch_offset_degrees = read_optional_double_field(that_json, "pitch_offset_degrees", pitch_offset_degrees);
roll_offset_degrees = read_optional_double_field(that_json, "roll_offset_degrees", roll_offset_degrees);
}
Psc::JSON Map_Model_Item_Config::to_base_json() const {
auto ret = Psc::JSON::object();
ret.append({"url", url});
ret.append({"built_in_size", built_in_size});
ret.append({"heading_offset_degrees", heading_offset_degrees});
ret.append({"pitch_offset_degrees", pitch_offset_degrees});
ret.append({"roll_offset_degrees", roll_offset_degrees});
return ret;
}
Map_Model_Config::Map_Model_Config() : aircraft_models(make_default_aircraft_models()) {
}
void Map_Model_Config::from_base_json(const Psc::JSON* that_json, bool not_exist_use_default_value) {
if (that_json == nullptr) {
return;
}
if (that_json->valueType != Psc::Object) {
throw Psc::json_assign_error(std::make_error_code(std::errc::invalid_argument), "map_models");
}
aircraft_model.from_base_json(that_json->get("aircraft_model"), not_exist_use_default_value);
aircraft_models = read_optional_model_object_field(that_json, "aircraft_models", make_default_aircraft_models(),
not_exist_use_default_value);
base_station_model.from_base_json(that_json->get("base_station_model"), not_exist_use_default_value);
device_model.from_base_json(that_json->get("device_model"), not_exist_use_default_value);
}
Psc::JSON Map_Model_Config::to_base_json() const {
auto ret = Psc::JSON::object();
ret.append({"aircraft_model", aircraft_model.to_base_json()});
ret.append(write_model_object("aircraft_models", aircraft_models));
ret.append({"base_station_model", base_station_model.to_base_json()});
ret.append({"device_model", device_model.to_base_json()});
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;
auto& api = g->api;
svr.Post(api + "get_device_config", [this](HTTP_Param) { res->setBody(warp(to_base_json()).to_json_string()); });
svr.Post(api + "get_net_adapter_list", [this](HTTP_Param) {
JSON ret = JSON::object();
auto arr = JSON::array();
for (auto& it : Psc::get_net_adapter_info_map()) {
arr.append(it.second.to_Json());
}
ret.append({"list", arr});
res->setBody(warp(ret).to_json_string());
});
svr.Post(api + "set_device_config", [this](HTTP_Param) {
CHECK_JSON_PARAM
JSON old_device_config;
{
old_device_config = to_base_json();
}
HTTP_REQUIRE_PTR(net, params.get("net"))
Net_Config device, wifi;
bool has_device = false;
bool has_wifi = false;
for (const auto& it : net->children) {
HTTP_REQUIRE_VALUE(net_key, it.try_get_string("key"))
if (net_key == "device") {
device.from_base_json(&it, true);
has_device = true;
}
if (net_key == "wifi") {
wifi.from_base_json(&it, true);
has_wifi = true;
}
}
HTTP_REQUIRE_TRUE(has_device && has_wifi, "net")
bool it1 = check_ip_netmask_gateway(device.ip, device.netmask, device.gateway);
bool it2 = check_ip_netmask_gateway(wifi.ip, wifi.netmask, wifi.gateway);
bool p1 = check_port(device.port);
bool p2 = check_port(wifi.port);
if (!it1 || !it2 || !p1 || !p2) {
server_logger->error("", {}, LOG_POS + " ip port! " + device.ip + ":" + std::to_string(device.port));
res->setBody(warp(old_device_config).to_json_string());
return;
}
#if WIN32
bool use = false;
#else
bool use = true;
#endif
{
auto& w = *this;
*w.list.get("device").value() = device;
*w.list.get("wifi").value() = wifi;
}
Global::save();
if (use) {
std::string interface;
{
std::string path = get_exe_dir() + "/interface";
std::ifstream ifs(path);
if (!ifs.is_open()) {
server_logger->error("", {}, LOG_POS + " 无法打开文件! " + path);
res->setBody(warp(old_device_config).to_json_string());
return;
}
std::stringstream buffer;
buffer << ifs.rdbuf();
interface = buffer.str();
}
static auto set = [](std::string& interface, std::string_view token, std::string_view value) {
std::string var_name = "${" + std::string(token) + "}";
auto size = var_name.size();
size_t pos = interface.find(var_name);
while (pos != std::string::npos) {
interface.replace(pos, size, value);
pos = interface.find(var_name);
}
};
set(interface, "ip", device.ip);
set(interface, "gateway", device.gateway);
set(interface, "netmask", device.netmask);
set(interface, "wifi_ip", wifi.ip);
set(interface, "wifi_gateway", wifi.gateway);
set(interface, "wifi_netmask", wifi.netmask);
std::cout << interface << std::endl;
std::string path = "/etc/network/interfaces";
std::ofstream outfile(path);
if (!outfile.is_open()) {
server_logger->error("", {}, LOG_POS + " 无法打开文件!" + path);
res->setBody(warp(old_device_config).to_json_string());
return;
}
outfile << interface;
outfile.close();
std::string bash_path = get_exe_dir() + "/restart_net_service.sh";
if (!std::filesystem::exists(bash_path)) {
server_logger->error("", {}, LOG_POS + " !" + bash_path);
res->setBody(warp(old_device_config).to_json_string());
return;
}
int result = system(bash_path.c_str());
if (result != 0) {
server_logger->error("", {}, LOG_POS + " 脚本执行失败!" + bash_path);
res->setBody(warp(old_device_config).to_json_string());
return;
}
}
res->setBody(warp(params).to_json_string());
});
}
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();
}