更新
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
|
||||
#include "Global.h"
|
||||
#include "Performance_Monitor.h"
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <string_view>
|
||||
#include "Global.h"
|
||||
#include "Performance_Monitor.h"
|
||||
namespace {
|
||||
constexpr std::size_t kMaxLogRequestBodySize = 8 * 1024;
|
||||
void Log_Request_Body_If_Small(const drogon::HttpRequestPtr& request) {
|
||||
@@ -13,13 +13,12 @@ void Log_Request_Body_If_Small(const drogon::HttpRequestPtr& request) {
|
||||
}
|
||||
if (body.size() <= kMaxLogRequestBodySize) {
|
||||
LOG_INFO << "[request body] "
|
||||
<< "path=" << request->path() << ", size=" << body.size()
|
||||
<< ", body=" << std::string(body.data(), body.size());
|
||||
<< "path=" << request->path() << ", size=" << body.size()
|
||||
<< ", body=" << std::string(body.data(), body.size());
|
||||
}
|
||||
else {
|
||||
LOG_INFO << "[request body skipped] "
|
||||
<< "path=" << request->path() << ", size=" << body.size()
|
||||
<< ", max=" << kMaxLogRequestBodySize;
|
||||
<< "path=" << request->path() << ", size=" << body.size() << ", max=" << kMaxLogRequestBodySize;
|
||||
}
|
||||
}
|
||||
bool Is_Invalid_Http_Param(const std::exception& e) {
|
||||
@@ -31,21 +30,17 @@ bool Is_Safe_Version_Directory_Name(std::string_view name) {
|
||||
if (name.empty() || name == "." || name == "..") {
|
||||
return false;
|
||||
}
|
||||
return std::ranges::all_of(name, [](unsigned char ch) {
|
||||
return std::isalnum(ch) != 0 || ch == '.' || ch == '_' || ch == '-';
|
||||
});
|
||||
return std::ranges::all_of(
|
||||
name, [](unsigned char ch) { return std::isalnum(ch) != 0 || ch == '.' || ch == '_' || ch == '-'; });
|
||||
}
|
||||
bool Is_Safe_Archive_Extension(std::string_view extension) {
|
||||
if (extension.empty() || extension.front() == '.' ||
|
||||
extension.back() == '.') {
|
||||
if (extension.empty() || extension.front() == '.' || extension.back() == '.') {
|
||||
return false;
|
||||
}
|
||||
return std::ranges::all_of(extension, [](unsigned char ch) {
|
||||
return std::isalnum(ch) != 0 || ch == '.' || ch == '_' || ch == '-';
|
||||
});
|
||||
return std::ranges::all_of(
|
||||
extension, [](unsigned char ch) { return std::isalnum(ch) != 0 || ch == '.' || ch == '_' || ch == '-'; });
|
||||
}
|
||||
std::string Normalize_Archive_Extension(std::string_view extension,
|
||||
std::string_view fallback = "zip") {
|
||||
std::string Normalize_Archive_Extension(std::string_view extension, std::string_view fallback = "zip") {
|
||||
auto normalized = std::string(extension);
|
||||
while (!normalized.empty() && normalized.front() == '.') {
|
||||
normalized.erase(normalized.begin());
|
||||
@@ -58,8 +53,7 @@ std::string Normalize_Archive_Extension(std::string_view extension,
|
||||
}
|
||||
return normalized;
|
||||
}
|
||||
std::optional<std::string> Try_Get_String_Field(const JSON& object,
|
||||
std::string_view key) {
|
||||
std::optional<std::string> Try_Get_String_Field(const JSON& object, std::string_view key) {
|
||||
const JSON* value = object.get(key);
|
||||
if (value == nullptr) {
|
||||
return std::nullopt;
|
||||
@@ -73,9 +67,8 @@ struct Archive_Export_Request {
|
||||
std::string version;
|
||||
Archive_Write_Options archive;
|
||||
};
|
||||
Archive_Export_Request
|
||||
Parse_Archive_Export_Request(const drogon::HttpRequestPtr& req,
|
||||
std::string_view default_version) {
|
||||
Archive_Export_Request Parse_Archive_Export_Request(const drogon::HttpRequestPtr& req,
|
||||
std::string_view default_version) {
|
||||
Archive_Export_Request result;
|
||||
result.version = std::move(default_version);
|
||||
const auto& body = req->getBody();
|
||||
@@ -109,8 +102,7 @@ Parse_Archive_Export_Request(const drogon::HttpRequestPtr& req,
|
||||
}
|
||||
}
|
||||
else {
|
||||
result.archive.extension =
|
||||
Normalize_Archive_Extension(result.archive.extension);
|
||||
result.archive.extension = Normalize_Archive_Extension(result.archive.extension);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -118,15 +110,8 @@ const Archive_Layout_Rules& Upgrade_Zip_Layout_Rules() {
|
||||
static const Archive_Layout_Rules rules = [] {
|
||||
Archive_Layout_Rules value;
|
||||
value.directories = {
|
||||
{
|
||||
"",
|
||||
{"adsb_cfg.ini", "config.json", "ecap_server", "lib9002config.json"},
|
||||
{"lib9002", "wwwroot"},
|
||||
{},
|
||||
{}
|
||||
},
|
||||
{"lib9002", {"lib9002.so", "testserver"}, {"env"}, {}, {}}
|
||||
};
|
||||
{"", {"adsb_cfg.ini", "config.json", "ecap_server", "lib9002config.json"}, {"lib9002", "wwwroot"}, {}, {}},
|
||||
{"lib9002", {"lib9002.so", "testserver"}, {"env"}, {}, {}}};
|
||||
return value;
|
||||
}();
|
||||
return rules;
|
||||
@@ -134,9 +119,7 @@ const Archive_Layout_Rules& Upgrade_Zip_Layout_Rules() {
|
||||
} // namespace
|
||||
void setupCors();
|
||||
void Global::init_web_server() {
|
||||
register_http_performance_monitor(
|
||||
http_monitor_config.access_log,
|
||||
http_monitor_config.slow_request_threshold_ms);
|
||||
register_http_performance_monitor(http_monitor_config.access_log, http_monitor_config.slow_request_threshold_ms);
|
||||
setupCors();
|
||||
static auto& web_server = web_server_config;
|
||||
Web_Server& svr = this->svr;
|
||||
@@ -146,8 +129,7 @@ void Global::init_web_server() {
|
||||
if (std::filesystem::exists(path)) {
|
||||
std::string content;
|
||||
httplib::detail::read_file(path, content);
|
||||
auto content_type = httplib::detail::find_content_type(
|
||||
path, {}, "application/octet-stream");
|
||||
auto content_type = httplib::detail::find_content_type(path, {}, "application/octet-stream");
|
||||
if (path.ends_with(".glb")) {
|
||||
content_type = "model/gltf-binary";
|
||||
}
|
||||
@@ -170,58 +152,51 @@ void Global::init_web_server() {
|
||||
};
|
||||
auto add_path = [return_file](std::string_view path) {
|
||||
drogon::app().registerHandlerViaRegex(
|
||||
std::string(path),
|
||||
[return_file](
|
||||
const drogon::HttpRequestPtr& req,
|
||||
std::function<void(const drogon::HttpResponsePtr&)>&& callback) {
|
||||
callback(return_file(web_server.get_true_webapp() + "/index.html"));
|
||||
},
|
||||
{drogon::Get});
|
||||
};
|
||||
init_tiles();
|
||||
drogon::app().registerHandlerViaRegex(
|
||||
"/",
|
||||
[return_file](
|
||||
const drogon::HttpRequestPtr& req,
|
||||
std::function<void(const drogon::HttpResponsePtr&)>&& callback) {
|
||||
std::string(path),
|
||||
[return_file](const drogon::HttpRequestPtr& req,
|
||||
std::function<void(const drogon::HttpResponsePtr&)>&& callback) {
|
||||
callback(return_file(web_server.get_true_webapp() + "/index.html"));
|
||||
},
|
||||
{drogon::Get});
|
||||
};
|
||||
init_tiles();
|
||||
drogon::app().registerHandlerViaRegex(
|
||||
"/",
|
||||
[return_file](const drogon::HttpRequestPtr& req, std::function<void(const drogon::HttpResponsePtr&)>&& callback) {
|
||||
callback(return_file(web_server.get_true_webapp() + "/index.html"));
|
||||
},
|
||||
{drogon::Get});
|
||||
add_path(R"(^/settings)");
|
||||
add_path(R"(^/map)");
|
||||
add_path(R"(^/map3d)");
|
||||
add_path(R"(^/dsp)");
|
||||
add_path(R"(^/aircraftlist)");
|
||||
drogon::app().registerHandlerViaRegex(
|
||||
R"(^/ui(/.*)?$)",
|
||||
[return_file](
|
||||
const drogon::HttpRequestPtr& req,
|
||||
std::function<void(const drogon::HttpResponsePtr&)>&& callback) {
|
||||
std::cout << req->path() << std::endl;
|
||||
auto res = drogon::HttpResponse::newHttpResponse();
|
||||
auto path = web_server.get_true_webapp();
|
||||
auto rp = req->path().substr(3);
|
||||
if (rp.empty()) {
|
||||
rp = "/";
|
||||
}
|
||||
auto is_spa_path = [](std::string_view value) {
|
||||
return value == "/" || value == "/map" || value == "/map3d" ||
|
||||
value == "/settings" || value == "/dsp" || value == "/aircraftlist";
|
||||
};
|
||||
if (is_spa_path(rp)) {
|
||||
path += "/index.html";
|
||||
}
|
||||
else {
|
||||
path += rp;
|
||||
}
|
||||
callback(return_file(path));
|
||||
});
|
||||
R"(^/ui(/.*)?$)",
|
||||
[return_file](const drogon::HttpRequestPtr& req, std::function<void(const drogon::HttpResponsePtr&)>&& callback) {
|
||||
auto res = drogon::HttpResponse::newHttpResponse();
|
||||
auto path = web_server.get_true_webapp();
|
||||
auto rp = req->path().substr(3);
|
||||
if (rp.empty()) {
|
||||
rp = "/";
|
||||
}
|
||||
auto is_spa_path = [](std::string_view value) {
|
||||
return value == "/" || value == "/map" || value == "/map3d" || value == "/settings" || value == "/dsp" ||
|
||||
value == "/aircraftlist";
|
||||
};
|
||||
if (is_spa_path(rp)) {
|
||||
path += "/index.html";
|
||||
}
|
||||
else {
|
||||
path += rp;
|
||||
}
|
||||
callback(return_file(path));
|
||||
});
|
||||
State_Report::instance();
|
||||
svr.Get(R"(/get_debug_info)", [](HTTP_Param) {
|
||||
JSON arr = JSON::array();
|
||||
auto& sp = Global::instance()->mode_acs.data_feed_config.pool_;
|
||||
arr.append(JSON::object(
|
||||
{{"remain_size", sp.remain_size()}, {"free_size", sp.free_size()}}));
|
||||
arr.append(JSON::object({{"remain_size", sp.remain_size()}, {"free_size", sp.free_size()}}));
|
||||
res->setBody(arr.to_json_string("", "\n", ""));
|
||||
});
|
||||
mlat.server(this);
|
||||
@@ -232,90 +207,76 @@ void Global::init_web_server() {
|
||||
dsp_config.server(this);
|
||||
// s.w.init();
|
||||
drogon::app().registerHandler(
|
||||
api + "export_logs",
|
||||
[](const drogon::HttpRequestPtr& req,
|
||||
std::function<void(const drogon::HttpResponsePtr&)>&& cb) {
|
||||
try {
|
||||
auto export_request =
|
||||
Parse_Archive_Export_Request(req, Global::instance()->version);
|
||||
std::string name = export_request.version;
|
||||
auto version_dir = std::filesystem::path(get_exe_dir() + "/..");
|
||||
std::string data = archive_directory_to_memory(
|
||||
version_dir / name / "logs", {}, export_request.archive);
|
||||
auto resp = drogon::HttpResponse::newHttpResponse();
|
||||
resp->setBody(data);
|
||||
resp->setContentTypeString("application/octet-stream");
|
||||
resp->addHeader("Content-Disposition",
|
||||
"attachment; filename*=UTF-8''" + name + "_logs." +
|
||||
std::string(export_request.archive.extension));
|
||||
resp->addHeader("ok", "true");
|
||||
cb(resp);
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
auto resp = drogon::HttpResponse::newHttpResponse();
|
||||
resp->addHeader("ok", "false");
|
||||
Psc::JSON json =
|
||||
JSON::object({{"message", Psc::platform_2_utf8(e.what())}});
|
||||
resp->setContentTypeCode(drogon::CT_APPLICATION_JSON);
|
||||
resp->setBody(json.to_json_string());
|
||||
cb(resp);
|
||||
}
|
||||
});
|
||||
api + "export_logs",
|
||||
[](const drogon::HttpRequestPtr& req, std::function<void(const drogon::HttpResponsePtr&)>&& cb) {
|
||||
try {
|
||||
auto export_request = Parse_Archive_Export_Request(req, Global::instance()->version);
|
||||
std::string name = export_request.version;
|
||||
auto version_dir = std::filesystem::path(get_exe_dir() + "/..");
|
||||
std::string data = archive_directory_to_memory(version_dir / name / "logs", {}, export_request.archive);
|
||||
auto resp = drogon::HttpResponse::newHttpResponse();
|
||||
resp->setBody(data);
|
||||
resp->setContentTypeString("application/octet-stream");
|
||||
resp->addHeader("Content-Disposition",
|
||||
"attachment; filename*=UTF-8''" + name + "_logs." +
|
||||
std::string(export_request.archive.extension));
|
||||
resp->addHeader("ok", "true");
|
||||
cb(resp);
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
auto resp = drogon::HttpResponse::newHttpResponse();
|
||||
resp->addHeader("ok", "false");
|
||||
Psc::JSON json = JSON::object({{"message", Psc::platform_2_utf8(e.what())}});
|
||||
resp->setContentTypeCode(drogon::CT_APPLICATION_JSON);
|
||||
resp->setBody(json.to_json_string());
|
||||
cb(resp);
|
||||
}
|
||||
});
|
||||
drogon::app().registerHandler(
|
||||
api + "export_version",
|
||||
[](const drogon::HttpRequestPtr& req,
|
||||
std::function<void(const drogon::HttpResponsePtr&)>&& cb) {
|
||||
try {
|
||||
auto export_request =
|
||||
Parse_Archive_Export_Request(req, Global::instance()->version);
|
||||
std::string name = export_request.version;
|
||||
auto version_dir = std::filesystem::path(get_exe_dir() + "/..");
|
||||
std::cout << "准备压缩:" << std::endl;
|
||||
std::string data = archive_directory_to_memory(
|
||||
version_dir / name,
|
||||
{
|
||||
"logs/", "uploads/", "drogon_uploads/",
|
||||
"backups/", // ghw的什么文件路径
|
||||
"stack_trace.txt", "pt.log", "ecap_server.log", "Core", "core",
|
||||
name + ".zip", name + "." + std::string(export_request.archive.extension)
|
||||
},
|
||||
export_request.archive);
|
||||
std::cout << "压缩成功:" << data.size() << std::endl;
|
||||
auto resp = drogon::HttpResponse::newHttpResponse();
|
||||
resp->setBody(data);
|
||||
resp->setContentTypeString("application/octet-stream");
|
||||
resp->addHeader("Content-Disposition",
|
||||
"attachment; filename*=UTF-8''" + name + "." +
|
||||
std::string(export_request.archive.extension));
|
||||
resp->addHeader("ok", "true");
|
||||
cb(resp);
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
auto message = Psc::platform_2_utf8(e.what());
|
||||
std::cout << "导出异常触发:" << message << " " << LOG_POS
|
||||
<< std::endl;
|
||||
auto resp = drogon::HttpResponse::newHttpResponse();
|
||||
Psc::JSON json = JSON::object({{"message", message}});
|
||||
resp->setContentTypeCode(drogon::CT_APPLICATION_JSON);
|
||||
resp->setBody(json.to_json_string());
|
||||
resp->addHeader("ok", "false");
|
||||
cb(resp);
|
||||
}
|
||||
});
|
||||
drogon::app().registerHandler(api + "restart_device", [](const drogon::
|
||||
HttpRequestPtr
|
||||
& req,
|
||||
std::function<void(
|
||||
const drogon::
|
||||
HttpResponsePtr
|
||||
&)>
|
||||
&& cb) {
|
||||
api + "export_version",
|
||||
[](const drogon::HttpRequestPtr& req, std::function<void(const drogon::HttpResponsePtr&)>&& cb) {
|
||||
try {
|
||||
auto export_request = Parse_Archive_Export_Request(req, Global::instance()->version);
|
||||
std::string name = export_request.version;
|
||||
auto version_dir = std::filesystem::path(get_exe_dir() + "/..");
|
||||
std::cout << "准备压缩:" << std::endl;
|
||||
std::string data =
|
||||
archive_directory_to_memory(version_dir / name,
|
||||
{"logs/", "uploads/", "drogon_uploads/",
|
||||
"backups/", // ghw的什么文件路径
|
||||
"stack_trace.txt", "pt.log", "ecap_server.log", "Core", "core", name + ".zip",
|
||||
name + "." + std::string(export_request.archive.extension)},
|
||||
export_request.archive);
|
||||
std::cout << "压缩成功:" << data.size() << std::endl;
|
||||
auto resp = drogon::HttpResponse::newHttpResponse();
|
||||
resp->setBody(data);
|
||||
resp->setContentTypeString("application/octet-stream");
|
||||
resp->addHeader("Content-Disposition",
|
||||
"attachment; filename*=UTF-8''" + name + "." +
|
||||
std::string(export_request.archive.extension));
|
||||
resp->addHeader("ok", "true");
|
||||
cb(resp);
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
auto message = Psc::platform_2_utf8(e.what());
|
||||
std::cout << "导出异常触发:" << message << " " << LOG_POS << std::endl;
|
||||
auto resp = drogon::HttpResponse::newHttpResponse();
|
||||
Psc::JSON json = JSON::object({{"message", message}});
|
||||
resp->setContentTypeCode(drogon::CT_APPLICATION_JSON);
|
||||
resp->setBody(json.to_json_string());
|
||||
resp->addHeader("ok", "false");
|
||||
cb(resp);
|
||||
}
|
||||
});
|
||||
drogon::app().registerHandler(
|
||||
api + "restart_device",
|
||||
[](const drogon::HttpRequestPtr& req, std::function<void(const drogon::HttpResponsePtr&)>&& cb) {
|
||||
#ifdef __linux__
|
||||
std::string root_dir = Psc::get_exe_dir() + "/..";
|
||||
std::string log_file = fmt::format("{}/restart_device.log", root_dir);
|
||||
std::string cmd = fmt::format(
|
||||
R"(systemd-run --scope --slice=system.slice sudo bash "{}/restart_device.bash" > {} 2>&1 &)",
|
||||
root_dir, log_file);
|
||||
std::string cmd =
|
||||
fmt::format(R"(systemd-run --scope --slice=system.slice sudo bash "{}/restart_device.bash" > {} 2>&1 &)",
|
||||
root_dir, log_file);
|
||||
std::cout << "Generated Command: " << cmd << std::endl;
|
||||
std::system(cmd.c_str());
|
||||
#endif
|
||||
@@ -325,104 +286,88 @@ void Global::init_web_server() {
|
||||
cb(resp);
|
||||
});
|
||||
drogon::app().registerHandler(
|
||||
api + "import_version",
|
||||
[](const drogon::HttpRequestPtr& req,
|
||||
std::function<void(const drogon::HttpResponsePtr&)>&& cb) {
|
||||
try {
|
||||
// ---------- 参数校验 ----------
|
||||
auto dir = req->getHeader("dir");
|
||||
if (!Is_Safe_Version_Directory_Name(dir)) {
|
||||
throw std::invalid_argument("invalid or missing header: dir");
|
||||
}
|
||||
const auto& body = req->getBody();
|
||||
auto archive_layout_result = validate_archive_layout_from_memory(
|
||||
body.data(), body.size(), Upgrade_Zip_Layout_Rules());
|
||||
if (!archive_layout_result) {
|
||||
throw Invalid_Archive_Error(archive_layout_result.error());
|
||||
}
|
||||
auto version_dir = std::filesystem::path(get_exe_dir() + "/..");
|
||||
// ---------- 路径准备 ----------
|
||||
auto targetDir = version_dir / dir;
|
||||
std::cout << "========dir====" << dir << std::endl;
|
||||
std::cout << "========version_dir====" << version_dir << std::endl;
|
||||
std::cout << "========targetDir====" << targetDir << std::endl;
|
||||
std::filesystem::create_directories(targetDir);
|
||||
const auto archive_extension =
|
||||
Normalize_Archive_Extension(req->getHeader("archive-extension"));
|
||||
auto archivePath = targetDir / (dir + "." + archive_extension);
|
||||
// ---------- 写 zip ----------
|
||||
std::ofstream ofs(archivePath, std::ios::binary);
|
||||
if (!ofs) {
|
||||
throw std::runtime_error("open archive failed: " +
|
||||
archivePath.string());
|
||||
}
|
||||
ofs.write(body.data(), body.size());
|
||||
if (!ofs) {
|
||||
throw std::runtime_error("write archive failed: " +
|
||||
archivePath.string());
|
||||
}
|
||||
ofs.close();
|
||||
if (!ofs) {
|
||||
throw std::runtime_error("close archive failed: " +
|
||||
archivePath.string());
|
||||
}
|
||||
api + "import_version",
|
||||
[](const drogon::HttpRequestPtr& req, std::function<void(const drogon::HttpResponsePtr&)>&& cb) {
|
||||
try {
|
||||
// ---------- 参数校验 ----------
|
||||
auto dir = req->getHeader("dir");
|
||||
if (!Is_Safe_Version_Directory_Name(dir)) {
|
||||
throw std::invalid_argument("invalid or missing header: dir");
|
||||
}
|
||||
const auto& body = req->getBody();
|
||||
auto archive_layout_result =
|
||||
validate_archive_layout_from_memory(body.data(), body.size(), Upgrade_Zip_Layout_Rules());
|
||||
if (!archive_layout_result) {
|
||||
throw Invalid_Archive_Error(archive_layout_result.error());
|
||||
}
|
||||
auto version_dir = std::filesystem::path(get_exe_dir() + "/..");
|
||||
// ---------- 路径准备 ----------
|
||||
auto targetDir = version_dir / dir;
|
||||
std::cout << "========dir====" << dir << std::endl;
|
||||
std::cout << "========version_dir====" << version_dir << std::endl;
|
||||
std::cout << "========targetDir====" << targetDir << std::endl;
|
||||
std::filesystem::create_directories(targetDir);
|
||||
const auto archive_extension = Normalize_Archive_Extension(req->getHeader("archive-extension"));
|
||||
auto archivePath = targetDir / (dir + "." + archive_extension);
|
||||
// ---------- 写 zip ----------
|
||||
std::ofstream ofs(archivePath, std::ios::binary);
|
||||
if (!ofs) {
|
||||
throw std::runtime_error("open archive failed: " + archivePath.string());
|
||||
}
|
||||
ofs.write(body.data(), body.size());
|
||||
if (!ofs) {
|
||||
throw std::runtime_error("write archive failed: " + archivePath.string());
|
||||
}
|
||||
ofs.close();
|
||||
if (!ofs) {
|
||||
throw std::runtime_error("close archive failed: " + archivePath.string());
|
||||
}
|
||||
#ifdef _WIN32
|
||||
std::string root_dir = version_dir.string();
|
||||
std::string old_version =
|
||||
Global::instance()->version; // Global version info
|
||||
std::string new_version = dir;
|
||||
std::string log_file = fmt::format(
|
||||
"{}/upgrade_{}_to_{}.log", root_dir, old_version, new_version);
|
||||
std::string cmd = fmt::format(
|
||||
R"(powershell -NoProfile -ExecutionPolicy Bypass -Command "& {{ . '{}/upgrade.legacy' '{}' '{}' > '{}' 2>&1 }}" )",
|
||||
root_dir, old_version, new_version, log_file);
|
||||
std::string root_dir = version_dir.string();
|
||||
std::string old_version = Global::instance()->version; // Global version info
|
||||
std::string new_version = dir;
|
||||
std::string log_file = fmt::format("{}/upgrade_{}_to_{}.log", root_dir, old_version, new_version);
|
||||
std::string cmd = fmt::format(
|
||||
R"(powershell -NoProfile -ExecutionPolicy Bypass -Command "& {{ . '{}/upgrade.legacy' '{}' '{}' > '{}' 2>&1 }}" )",
|
||||
root_dir, old_version, new_version, log_file);
|
||||
#else
|
||||
std::string root_dir = version_dir.string();
|
||||
std::string old_version =
|
||||
Global::instance()->version; // Global version info
|
||||
std::string new_version = dir;
|
||||
std::string log_file = fmt::format(
|
||||
"{}/upgrade_{}_to_{}.log", root_dir, old_version, new_version);
|
||||
std::string cmd = fmt::format(
|
||||
R"(systemd-run --scope --slice=system.slice sudo bash "{}/upgrade.bash" "{}" "{}" > {} 2>&1 &)",
|
||||
root_dir, old_version, new_version, log_file);
|
||||
std::string root_dir = version_dir.string();
|
||||
std::string old_version = Global::instance()->version; // Global version info
|
||||
std::string new_version = dir;
|
||||
std::string log_file = fmt::format("{}/upgrade_{}_to_{}.log", root_dir, old_version, new_version);
|
||||
std::string cmd =
|
||||
fmt::format(R"(systemd-run --scope --slice=system.slice sudo bash "{}/upgrade.bash" "{}" "{}" > {} 2>&1 &)",
|
||||
root_dir, old_version, new_version, log_file);
|
||||
#endif
|
||||
std::cout << "Generated Command: " << cmd << std::endl;
|
||||
std::system(cmd.c_str());
|
||||
// ---------- 成功响应 ----------
|
||||
auto resp = drogon::HttpResponse::newHttpResponse();
|
||||
resp->setContentTypeCode(drogon::CT_APPLICATION_JSON);
|
||||
resp->setBody(R"({"ok":true})");
|
||||
cb(resp);
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
auto resp = drogon::HttpResponse::newHttpResponse();
|
||||
const bool invalid_input =
|
||||
dynamic_cast<const Invalid_Archive_Error*>(&e) != nullptr ||
|
||||
dynamic_cast<const std::invalid_argument*>(&e) != nullptr;
|
||||
resp->setStatusCode(invalid_input
|
||||
? drogon::k400BadRequest
|
||||
: drogon::k500InternalServerError);
|
||||
resp->setContentTypeCode(drogon::CT_APPLICATION_JSON);
|
||||
auto reason = Psc::platform_2_utf8(e.what());
|
||||
std::cout << "异常" << reason << std::endl;
|
||||
Psc::JSON json = JSON::object({{"ok", false}, {"error", reason}});
|
||||
resp->setBody(json.to_json_string());
|
||||
cb(resp);
|
||||
}
|
||||
},
|
||||
{drogon::Post});
|
||||
std::cout << "Generated Command: " << cmd << std::endl;
|
||||
std::system(cmd.c_str());
|
||||
// ---------- 成功响应 ----------
|
||||
auto resp = drogon::HttpResponse::newHttpResponse();
|
||||
resp->setContentTypeCode(drogon::CT_APPLICATION_JSON);
|
||||
resp->setBody(R"({"ok":true})");
|
||||
cb(resp);
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
auto resp = drogon::HttpResponse::newHttpResponse();
|
||||
const bool invalid_input = dynamic_cast<const Invalid_Archive_Error*>(&e) != nullptr ||
|
||||
dynamic_cast<const std::invalid_argument*>(&e) != nullptr;
|
||||
resp->setStatusCode(invalid_input ? drogon::k400BadRequest : drogon::k500InternalServerError);
|
||||
resp->setContentTypeCode(drogon::CT_APPLICATION_JSON);
|
||||
auto reason = Psc::platform_2_utf8(e.what());
|
||||
std::cout << "异常" << reason << std::endl;
|
||||
Psc::JSON json = JSON::object({{"ok", false}, {"error", reason}});
|
||||
resp->setBody(json.to_json_string());
|
||||
cb(resp);
|
||||
}
|
||||
},
|
||||
{drogon::Post});
|
||||
svr.Post(api + "get_debug_log", [](HTTP_Param) {
|
||||
CHECK_JSON_PARAM
|
||||
HTTP_REQUIRE_VALUE(
|
||||
start_serial_number,
|
||||
params.try_get_number<Serial_Number_Type>("serial_number"))
|
||||
auto log =
|
||||
base64_encode(debug_logger_info_manager.get_info(start_serial_number));
|
||||
HTTP_REQUIRE_VALUE(start_serial_number, params.try_get_number<Serial_Number_Type>("serial_number"))
|
||||
auto log = base64_encode(debug_logger_info_manager.get_info(start_serial_number));
|
||||
JSON ret = JSON::object();
|
||||
ret.append({"log", log});
|
||||
ret.append(
|
||||
{"serial_number", debug_logger_info_manager.get_cur_serial_number()});
|
||||
ret.append({"serial_number", debug_logger_info_manager.get_cur_serial_number()});
|
||||
ret.append({"start_serial_number", start_serial_number});
|
||||
res->setBody(warp(ret).to_json_string());
|
||||
});
|
||||
@@ -456,108 +401,98 @@ void Global::init_web_server() {
|
||||
res->setBody(warp(ret).to_json_string());
|
||||
});
|
||||
da.setDefaultHandler(
|
||||
[](const drogon::HttpRequestPtr& req,
|
||||
std::function<void(const drogon::HttpResponsePtr&)>&& callback) {
|
||||
LOG_WARN << "[http route not found] "
|
||||
<< "path=" << req->path();
|
||||
auto res = drogon::HttpResponse::newHttpResponse();
|
||||
res->setStatusCode(drogon::k404NotFound);
|
||||
res->setBody("not found");
|
||||
res->addHeader("Content-Type", "text/plain; charset=utf-8");
|
||||
callback(res);
|
||||
});
|
||||
[](const drogon::HttpRequestPtr& req, std::function<void(const drogon::HttpResponsePtr&)>&& callback) {
|
||||
LOG_WARN << "[http route not found] "
|
||||
<< "path=" << req->path();
|
||||
auto res = drogon::HttpResponse::newHttpResponse();
|
||||
res->setStatusCode(drogon::k404NotFound);
|
||||
res->setBody("not found");
|
||||
res->addHeader("Content-Type", "text/plain; charset=utf-8");
|
||||
callback(res);
|
||||
});
|
||||
da.setCustomErrorHandler(
|
||||
[](drogon::HttpStatusCode status,
|
||||
const drogon::HttpRequestPtr& req) -> drogon::HttpResponsePtr {
|
||||
LOG_WARN << "[http error] "
|
||||
<< "path=" << req->path()
|
||||
<< ", status=" << static_cast<int>(status);
|
||||
auto res = drogon::HttpResponse::newHttpResponse();
|
||||
res->setStatusCode(status);
|
||||
res->setBody("http error");
|
||||
res->addHeader("Content-Type", "text/plain; charset=utf-8");
|
||||
return res;
|
||||
});
|
||||
da.setExceptionHandler(
|
||||
[](const std::exception& e, const drogon::HttpRequestPtr& req,
|
||||
std::function<void(const drogon::HttpResponsePtr&)>&& callback) {
|
||||
auto res = drogon::HttpResponse::newHttpResponse();
|
||||
if (Is_Invalid_Http_Param(e)) {
|
||||
LOG_WARN << "[invalid http parameters] "
|
||||
<< "path=" << req->path() << ", detail=" << e.what();
|
||||
Log_Request_Body_If_Small(req);
|
||||
res->setStatusCode(drogon::k400BadRequest);
|
||||
res->setContentTypeCode(drogon::CT_APPLICATION_JSON);
|
||||
res->setBody(R"({"code":400,"message":"invalid http parameters"})");
|
||||
}
|
||||
else {
|
||||
LOG_ERROR << "[handler exception] "
|
||||
<< "path=" << req->path() << ", what=" << e.what();
|
||||
res->setStatusCode(drogon::k500InternalServerError);
|
||||
res->setContentTypeCode(drogon::CT_APPLICATION_JSON);
|
||||
res->setBody(R"({"code":500,"message":"internal server error"})");
|
||||
}
|
||||
callback(res);
|
||||
});
|
||||
[](drogon::HttpStatusCode status, const drogon::HttpRequestPtr& req) -> drogon::HttpResponsePtr {
|
||||
LOG_WARN << "[http error] "
|
||||
<< "path=" << req->path() << ", status=" << static_cast<int>(status);
|
||||
auto res = drogon::HttpResponse::newHttpResponse();
|
||||
res->setStatusCode(status);
|
||||
res->setBody("http error");
|
||||
res->addHeader("Content-Type", "text/plain; charset=utf-8");
|
||||
return res;
|
||||
});
|
||||
da.setExceptionHandler([](const std::exception& e, const drogon::HttpRequestPtr& req,
|
||||
std::function<void(const drogon::HttpResponsePtr&)>&& callback) {
|
||||
auto res = drogon::HttpResponse::newHttpResponse();
|
||||
if (Is_Invalid_Http_Param(e)) {
|
||||
LOG_WARN << "[invalid http parameters] "
|
||||
<< "path=" << req->path() << ", detail=" << e.what();
|
||||
Log_Request_Body_If_Small(req);
|
||||
res->setStatusCode(drogon::k400BadRequest);
|
||||
res->setContentTypeCode(drogon::CT_APPLICATION_JSON);
|
||||
res->setBody(R"({"code":400,"message":"invalid http parameters"})");
|
||||
}
|
||||
else {
|
||||
LOG_ERROR << "[handler exception] "
|
||||
<< "path=" << req->path() << ", what=" << e.what();
|
||||
res->setStatusCode(drogon::k500InternalServerError);
|
||||
res->setContentTypeCode(drogon::CT_APPLICATION_JSON);
|
||||
res->setBody(R"({"code":500,"message":"internal server error"})");
|
||||
}
|
||||
callback(res);
|
||||
});
|
||||
da.setUploadPath(get_exe_dir() + "/drogon_uploads");
|
||||
std::cout << "上传路径: " << da.getUploadPath() << std::endl;
|
||||
init_ok = true;
|
||||
}
|
||||
void setupCors() {
|
||||
// Register sync advice to handle CORS preflight (OPTIONS) requests
|
||||
drogon::app().registerSyncAdvice(
|
||||
[](const drogon::HttpRequestPtr& req) -> drogon::HttpResponsePtr {
|
||||
if (req->method() == drogon::HttpMethod::Options) {
|
||||
auto resp = drogon::HttpResponse::newHttpResponse();
|
||||
// Set Access-Control-Allow-Origin header based on the Origin
|
||||
// request header
|
||||
const auto& origin = req->getHeader("Origin");
|
||||
if (!origin.empty()) {
|
||||
resp->addHeader("Access-Control-Allow-Origin", origin);
|
||||
}
|
||||
// Set Access-Control-Allow-Methods based on the requested method
|
||||
const auto& requestMethod =
|
||||
req->getHeader("Access-Control-Request-Method");
|
||||
if (!requestMethod.empty()) {
|
||||
resp->addHeader("Access-Control-Allow-Methods", requestMethod);
|
||||
}
|
||||
// Allow credentials to be included in cross-origin requests
|
||||
resp->addHeader("Access-Control-Allow-Credentials", "true");
|
||||
// Set allowed headers from the Access-Control-Request-Headers
|
||||
// header
|
||||
const auto& requestHeaders =
|
||||
req->getHeader("Access-Control-Request-Headers");
|
||||
if (!requestHeaders.empty()) {
|
||||
resp->addHeader("Access-Control-Allow-Headers", requestHeaders);
|
||||
}
|
||||
return std::move(resp);
|
||||
}
|
||||
return {};
|
||||
});
|
||||
// Register post-handling advice to add CORS headers to all responses
|
||||
drogon::app().registerPostHandlingAdvice(
|
||||
[](const drogon::HttpRequestPtr& req,
|
||||
const drogon::HttpResponsePtr& resp) -> void {
|
||||
// Set Access-Control-Allow-Origin based on the Origin request
|
||||
// header
|
||||
drogon::app().registerSyncAdvice([](const drogon::HttpRequestPtr& req) -> drogon::HttpResponsePtr {
|
||||
if (req->method() == drogon::HttpMethod::Options) {
|
||||
auto resp = drogon::HttpResponse::newHttpResponse();
|
||||
// Set Access-Control-Allow-Origin header based on the Origin
|
||||
// request header
|
||||
const auto& origin = req->getHeader("Origin");
|
||||
if (!origin.empty()) {
|
||||
resp->addHeader("Access-Control-Allow-Origin", origin);
|
||||
}
|
||||
// Reflect the requested Access-Control-Request-Method back in the
|
||||
// response
|
||||
const auto& requestMethod =
|
||||
req->getHeader("Access-Control-Request-Method");
|
||||
// Set Access-Control-Allow-Methods based on the requested method
|
||||
const auto& requestMethod = req->getHeader("Access-Control-Request-Method");
|
||||
if (!requestMethod.empty()) {
|
||||
resp->addHeader("Access-Control-Allow-Methods", requestMethod);
|
||||
}
|
||||
// Allow credentials to be included in cross-origin requests
|
||||
resp->addHeader("Access-Control-Allow-Credentials", "true");
|
||||
// Reflect the requested Access-Control-Request-Headers back
|
||||
const auto& requestHeaders =
|
||||
req->getHeader("Access-Control-Request-Headers");
|
||||
// Set allowed headers from the Access-Control-Request-Headers
|
||||
// header
|
||||
const auto& requestHeaders = req->getHeader("Access-Control-Request-Headers");
|
||||
if (!requestHeaders.empty()) {
|
||||
resp->addHeader("Access-Control-Allow-Headers", requestHeaders);
|
||||
}
|
||||
});
|
||||
return std::move(resp);
|
||||
}
|
||||
return {};
|
||||
});
|
||||
// Register post-handling advice to add CORS headers to all responses
|
||||
drogon::app().registerPostHandlingAdvice(
|
||||
[](const drogon::HttpRequestPtr& req, const drogon::HttpResponsePtr& resp) -> void {
|
||||
// Set Access-Control-Allow-Origin based on the Origin request
|
||||
// header
|
||||
const auto& origin = req->getHeader("Origin");
|
||||
if (!origin.empty()) {
|
||||
resp->addHeader("Access-Control-Allow-Origin", origin);
|
||||
}
|
||||
// Reflect the requested Access-Control-Request-Method back in the
|
||||
// response
|
||||
const auto& requestMethod = req->getHeader("Access-Control-Request-Method");
|
||||
if (!requestMethod.empty()) {
|
||||
resp->addHeader("Access-Control-Allow-Methods", requestMethod);
|
||||
}
|
||||
// Allow credentials to be included in cross-origin requests
|
||||
resp->addHeader("Access-Control-Allow-Credentials", "true");
|
||||
// Reflect the requested Access-Control-Request-Headers back
|
||||
const auto& requestHeaders = req->getHeader("Access-Control-Request-Headers");
|
||||
if (!requestHeaders.empty()) {
|
||||
resp->addHeader("Access-Control-Allow-Headers", requestHeaders);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user