diff --git a/config/config.json b/config/config.json index 3478a56..e4d2626 100644 --- a/config/config.json +++ b/config/config.json @@ -38,25 +38,25 @@ "function_name": "adsb_read" }, "web_server": { - "webapp": "D:/ae/proj/projects/ECAP_Server/ver/v1.0.4/wwwroot", + "webapp": "@/../third_party/eacp_webapp/wwwroot", "tiles": "D:/tiles" }, "device": { "net": [ - { - "key": "device", - "ip": "192.168.1.75", - "port": 80, - "netmask": "255.255.255.0", - "gateway": "192.168.1.1" - }, - { - "key": "wifi", - "ip": "192.168.10.193", - "port": 80, - "netmask": "255.255.255.0", - "gateway": "192.168.10.1" - } + { + "key": "device", + "ip": "192.168.1.75", + "port": 80, + "netmask": "255.255.255.0", + "gateway": "192.168.1.1" + }, + { + "key": "wifi", + "ip": "192.168.10.193", + "port": 80, + "netmask": "255.255.255.0", + "gateway": "192.168.10.1" + } ] }, "mode_acs": { @@ -78,131 +78,131 @@ "tcp_server_default_connect_user_buffer_size": 409600, "tcp_server_default_connect_system_buffer_size": 409600, "list": [ - { - "type": "Data_Feed_TCP_Server", - "key": "Port_10003", - "enable": true, - "output_format": { - "type": "BIN", - "use_status": true, - "mode_s_output_type": "ALL_Mode_S", - "use_mode_ac": true, - "sbs_only_pos": true - }, - "port": 10003, - "connect_user_buffer_size": 409600, - "connect_system_buffer_size": 409600 - }, - { - "type": "Data_Feed_UDP_Server", - "key": "22333", - "enable": false, - "output_format": { - "type": "BIN", - "use_status": false, - "mode_s_output_type": "ALL_Mode_S", - "use_mode_ac": false, - "sbs_only_pos": false - }, - "port": 50001 - }, - { - "type": "Data_Feed_UDP_Client", - "key": "Port_10004", - "enable": false, - "output_format": { - "type": "AVR", - "use_status": false, - "mode_s_output_type": "DF_11_17_18", - "use_mode_ac": false, - "sbs_only_pos": true - }, - "port": 30004, - "url": "192.168.1.75" - }, - { - "type": "Data_Feed_TCP_Client", - "key": "Port_10005", - "enable": false, - "output_format": { - "type": "BIN", - "use_status": true, - "mode_s_output_type": "NO_POS_Mode_S", - "use_mode_ac": true, - "sbs_only_pos": true - }, - "url": "192.168.1.167", - "port": 10005 - }, - { - "type": "Data_Feed_TCP_Server", - "key": "Port_30003", - "enable": false, - "output_format": { - "type": "SBS", - "use_status": false, - "mode_s_output_type": "ALL_Mode_S", - "use_mode_ac": true, - "sbs_only_pos": true - }, - "port": 30003, - "connect_user_buffer_size": 0, - "connect_system_buffer_size": 0 - } + { + "type": "Data_Feed_TCP_Server", + "key": "Port_10003", + "enable": true, + "output_format": { + "type": "BIN", + "use_status": true, + "mode_s_output_type": "ALL_Mode_S", + "use_mode_ac": true, + "sbs_only_pos": true + }, + "port": 10003, + "connect_user_buffer_size": 409600, + "connect_system_buffer_size": 409600 + }, + { + "type": "Data_Feed_UDP_Server", + "key": "22333", + "enable": false, + "output_format": { + "type": "BIN", + "use_status": false, + "mode_s_output_type": "ALL_Mode_S", + "use_mode_ac": false, + "sbs_only_pos": false + }, + "port": 50001 + }, + { + "type": "Data_Feed_UDP_Client", + "key": "Port_10004", + "enable": false, + "output_format": { + "type": "AVR", + "use_status": false, + "mode_s_output_type": "DF_11_17_18", + "use_mode_ac": false, + "sbs_only_pos": true + }, + "port": 30004, + "url": "192.168.1.75" + }, + { + "type": "Data_Feed_TCP_Client", + "key": "Port_10005", + "enable": false, + "output_format": { + "type": "BIN", + "use_status": true, + "mode_s_output_type": "NO_POS_Mode_S", + "use_mode_ac": true, + "sbs_only_pos": true + }, + "url": "192.168.1.167", + "port": 10005 + }, + { + "type": "Data_Feed_TCP_Server", + "key": "Port_30003", + "enable": false, + "output_format": { + "type": "SBS", + "use_status": false, + "mode_s_output_type": "ALL_Mode_S", + "use_mode_ac": true, + "sbs_only_pos": true + }, + "port": 30003, + "connect_user_buffer_size": 0, + "connect_system_buffer_size": 0 + } ] }, "data_source": { "list": [ - { - "type": "Dll_Data_Source", - "key": "lzy_dll", - "enable": true, - "base_station_show": true, - "aircraft_show": true, - "color": "#454641", - "aircraft_pixel_size": 28, - "lat": 37.433547, - "lon": 121.408730, - "alt": 23.000000, - "update_form_gps": true, - "show_icao": true, - "show_call_sign": false, - "show_fly_status": false, - "keep_mode": true, - "library_path": "@/dll_source.dll", - "function_name": "adsb_read", - "data_type": "BIN_Blank_Text", - "buffer_size": 200000 - }, - { - "type": "File_Data_Source", - "key": "aaaa", - "enable": false, - "base_station_show": true, - "aircraft_show": true, - "color": "#d1a54c", - "aircraft_pixel_size": 20, - "lat": 37.000000, - "lon": 121.000000, - "alt": 0.000000, - "update_form_gps": false, - "show_icao": true, - "show_call_sign": true, - "show_fly_status": true, - "keep_mode": true, - "file_path": "D:\\ae\\proj\\projects\\ECAP_Server\\data\\BIN_Blank_Text\\ADS-B_195_0205.txt", - "data_type": "BIN_Blank_Text", - "play_mode": "loop" - } + { + "type": "Dll_Data_Source", + "key": "lzy_dll", + "enable": true, + "base_station_show": true, + "aircraft_show": true, + "color": "#454641", + "aircraft_pixel_size": 28, + "lat": 37.433547, + "lon": 121.408730, + "alt": 23.000000, + "update_form_gps": true, + "show_icao": true, + "show_call_sign": false, + "show_fly_status": false, + "keep_mode": true, + "library_path": "@/dll_source.dll", + "function_name": "adsb_read", + "data_type": "BIN_Blank_Text", + "buffer_size": 200000 + }, + { + "type": "File_Data_Source", + "key": "aaaa", + "enable": false, + "base_station_show": true, + "aircraft_show": true, + "color": "#d1a54c", + "aircraft_pixel_size": 20, + "lat": 37.000000, + "lon": 121.000000, + "alt": 0.000000, + "update_form_gps": false, + "show_icao": true, + "show_call_sign": true, + "show_fly_status": true, + "keep_mode": true, + "file_path": "D:\\ae\\proj\\projects\\ECAP_Server\\data\\BIN_Blank_Text\\ADS-B_195_0205.txt", + "data_type": "BIN_Blank_Text", + "play_mode": "loop" + } ] }, "source_feed_relation": { "list": [ - { - "key": "key_10003", - "enable": true, - "type": "First_Source_To_All_Feed_Relation" - } + { + "key": "key_10003", + "enable": true, + "type": "First_Source_To_All_Feed_Relation" + } ] } }, @@ -218,85 +218,85 @@ "mlat_server": true }, "external_database": { - "ecap_sqlite_path": "D:/ae/proj/projects/ECAP_Server/sqlite/ecap.sqlite", + "ecap_sqlite_path": "@/../data/sqlite/ecap.sqlite", "list": [ - { - "name": "tar1090_db_aircraft", - "download_url": "https://raw.githubusercontent.com/wiedehopf/tar1090-db/refs/heads/csv/aircraft.csv.gz", - "description": "wiedehopf/tar1090-db 发布的轻量 ICAO24 飞机静态库,提供注册号、机型、年份和运营方备注。", - "update_interval_seconds": 604800, - "last_updated_at": 1780388281 - }, - { - "name": "wiedehopf_tar1090_db_aircraft", - "download_url": "https://raw.githubusercontent.com/wiedehopf/tar1090-db/refs/heads/csv/aircraft.csv.gz", - "description": "wiedehopf/tar1090-db 项目发布的飞机静态数据库镜像,供 tar1090 本地识别飞机。", - "update_interval_seconds": 604800, - "last_updated_at": 1780381804 - }, - { - "name": "mictronics_aircraft_database", - "download_url": "https://raw.githubusercontent.com/wiedehopf/tar1090-db/refs/heads/csv/aircraft.csv.gz", - "description": "Mictronics 社区飞机数据库的 tar1090 汇总镜像,可按 ICAO24 查询注册号、机型和运营方。", - "update_interval_seconds": 604800, - "last_updated_at": 1780381804 - }, - { - "name": "opensky_aircraft_database", - "download_url": "https://opensky-network.org/datasets/metadata/aircraftDatabase.csv", - "description": "OpenSky Network 飞机元数据 CSV,包含制造商、型号、注册号和运营方等字段。", - "update_interval_seconds": 604800, - "last_updated_at": 1780381804 - }, - { - "name": "faa_aircraft_registry", - "download_url": "https://registry.faa.gov/database/ReleasableAircraft.zip", - "description": "FAA 官方可公开下载的美国飞机注册库,MASTER.txt 包含 Mode-S Hex 注册信息。", - "update_interval_seconds": 86400, - "last_updated_at": 1780381804 - }, - { - "name": "icao_doc_8643_aircraft_type_designators", - "download_url": "", - "description": "ICAO Doc 8643 机型代码表,用于将 A320、B738 等 designator 映射为制造商、型号和类别。", - "update_interval_seconds": 2419200, - "last_updated_at": 1780381804 - }, - { - "name": "vrs_routes", - "download_url": "https://vrs-standing-data.adsb.lol/routes.csv", - "description": "VRS 航线表,以 callsign 查询机场代码序列,用于推断起飞机场、经停机场和目的机场。", - "update_interval_seconds": 3600, - "last_updated_at": 1780381804 - }, - { - "name": "vrs_airports", - "download_url": "https://vrs-standing-data.adsb.lol/airports.csv", - "description": "VRS 机场字典,提供机场代码、名称、国家、经纬度和高度。", - "update_interval_seconds": 3600, - "last_updated_at": 1780381804 - }, - { - "name": "adsblol_vrs_standing_data_routes", - "download_url": "https://vrs-standing-data.adsb.lol/routes.csv", - "description": "ADSB.lol 发布的 VRS standing-data 航线镜像,以 callsign 查询机场代码序列。", - "update_interval_seconds": 3600, - "last_updated_at": 1780381804 - }, - { - "name": "vradarserver_standing_data_routes", - "download_url": "https://vrs-standing-data.adsb.lol/routes.csv", - "description": "Virtual Radar Server standing-data 的航线适配表;当前在线更新使用 ADSB.lol 公共镜像。", - "update_interval_seconds": 3600, - "last_updated_at": 1780381804 - }, - { - "name": "opensky_flightdata_api_cache", - "download_url": "", - "description": "OpenSky FlightData API 查询缓存,按 ICAO24 和时间范围保存历史航班起降机场结果。", - "update_interval_seconds": 0, - "last_updated_at": 1780381804 - } + { + "name": "tar1090_db_aircraft", + "download_url": "https://raw.githubusercontent.com/wiedehopf/tar1090-db/refs/heads/csv/aircraft.csv.gz", + "description": "wiedehopf/tar1090-db 发布的轻量 ICAO24 飞机静态库,提供注册号、机型、年份和运营方备注。", + "update_interval_seconds": 604800, + "last_updated_at": 1780388281 + }, + { + "name": "wiedehopf_tar1090_db_aircraft", + "download_url": "https://raw.githubusercontent.com/wiedehopf/tar1090-db/refs/heads/csv/aircraft.csv.gz", + "description": "wiedehopf/tar1090-db 项目发布的飞机静态数据库镜像,供 tar1090 本地识别飞机。", + "update_interval_seconds": 604800, + "last_updated_at": 1780381804 + }, + { + "name": "mictronics_aircraft_database", + "download_url": "https://raw.githubusercontent.com/wiedehopf/tar1090-db/refs/heads/csv/aircraft.csv.gz", + "description": "Mictronics 社区飞机数据库的 tar1090 汇总镜像,可按 ICAO24 查询注册号、机型和运营方。", + "update_interval_seconds": 604800, + "last_updated_at": 1780381804 + }, + { + "name": "opensky_aircraft_database", + "download_url": "https://opensky-network.org/datasets/metadata/aircraftDatabase.csv", + "description": "OpenSky Network 飞机元数据 CSV,包含制造商、型号、注册号和运营方等字段。", + "update_interval_seconds": 604800, + "last_updated_at": 1780381804 + }, + { + "name": "faa_aircraft_registry", + "download_url": "https://registry.faa.gov/database/ReleasableAircraft.zip", + "description": "FAA 官方可公开下载的美国飞机注册库,MASTER.txt 包含 Mode-S Hex 注册信息。", + "update_interval_seconds": 86400, + "last_updated_at": 1780381804 + }, + { + "name": "icao_doc_8643_aircraft_type_designators", + "download_url": "", + "description": "ICAO Doc 8643 机型代码表,用于将 A320、B738 等 designator 映射为制造商、型号和类别。", + "update_interval_seconds": 2419200, + "last_updated_at": 1780381804 + }, + { + "name": "vrs_routes", + "download_url": "https://vrs-standing-data.adsb.lol/routes.csv", + "description": "VRS 航线表,以 callsign 查询机场代码序列,用于推断起飞机场、经停机场和目的机场。", + "update_interval_seconds": 3600, + "last_updated_at": 1780381804 + }, + { + "name": "vrs_airports", + "download_url": "https://vrs-standing-data.adsb.lol/airports.csv", + "description": "VRS 机场字典,提供机场代码、名称、国家、经纬度和高度。", + "update_interval_seconds": 3600, + "last_updated_at": 1780381804 + }, + { + "name": "adsblol_vrs_standing_data_routes", + "download_url": "https://vrs-standing-data.adsb.lol/routes.csv", + "description": "ADSB.lol 发布的 VRS standing-data 航线镜像,以 callsign 查询机场代码序列。", + "update_interval_seconds": 3600, + "last_updated_at": 1780381804 + }, + { + "name": "vradarserver_standing_data_routes", + "download_url": "https://vrs-standing-data.adsb.lol/routes.csv", + "description": "Virtual Radar Server standing-data 的航线适配表;当前在线更新使用 ADSB.lol 公共镜像。", + "update_interval_seconds": 3600, + "last_updated_at": 1780381804 + }, + { + "name": "opensky_flightdata_api_cache", + "download_url": "", + "description": "OpenSky FlightData API 查询缓存,按 ICAO24 和时间范围保存历史航班起降机场结果。", + "update_interval_seconds": 0, + "last_updated_at": 1780381804 + } ] } } diff --git a/module/Local_Server/External_Database/External_Database.cpp b/module/Local_Server/External_Database/External_Database.cpp index f0633ef..772f5c8 100644 --- a/module/Local_Server/External_Database/External_Database.cpp +++ b/module/Local_Server/External_Database/External_Database.cpp @@ -1,16 +1,13 @@ #include "global.h" - #include "../server/Global.h" #include "../server/Performance_Monitor.h" #include "Core/Base/Coro_Result.h" #include "Resource_Utils.h" #include "Resources.h" - #include #include #include #include - #include #include #include @@ -18,845 +15,774 @@ #include #include #include - namespace { - Psc::JSON - external_resource_status_to_json(const External_Resource_Status &status) { +Psc::JSON +external_resource_status_to_json(const External_Resource_Status& status) { return Psc::JSON::object({ - {"name", status.name}, - {"row_count", status.row_count}, - {"downloaded", status.downloaded}, - {"imported", status.imported}, - {"message", status.message}, + {"name", status.name}, + {"row_count", status.row_count}, + {"downloaded", status.downloaded}, + {"imported", status.imported}, + {"message", status.message}, }); - } - - Psc::JSON external_resource_status_list_to_json( - const std::vector &status_list) { +} +Psc::JSON external_resource_status_list_to_json( + const std::vector& status_list) { auto result = Psc::JSON::array(); - for (const auto &status: status_list) { - result.append(external_resource_status_to_json(status)); + for (const auto& status : status_list) { + result.append(external_resource_status_to_json(status)); } return result; - } - - trantor::ConcurrentTaskQueue &external_database_task_queue() { +} +trantor::ConcurrentTaskQueue& external_database_task_queue() { static trantor::ConcurrentTaskQueue queue(2, "external_database"); return queue; - } - - template - void run_external_database_async(Work &&work, Callback &&callback) { - auto callback_holder = std::make_shared >( - std::forward(callback)); - +} +template +void run_external_database_async(Work&& work, Callback&& callback) { + auto callback_holder = std::make_shared>( + std::forward(callback)); external_database_task_queue().runTaskInQueue( - [work = std::forward(work), callback_holder]() mutable { - try { - (*callback_holder)(nullptr, work()); - } catch (...) { - (*callback_holder)(std::current_exception(), T{}); - } - }); - } - - template - asio::awaitable await_external_database_callback(Starter starter) { - auto result = co_await Psc::coro::callback_result( - [starter = std::move(starter)](auto done) mutable { - starter([done = std::move(done)](std::exception_ptr exception, - T value) mutable { - if (exception) { - done.set_exception(exception); - return; - } - done(std::move(value)); + [work = std::forward(work), callback_holder]() mutable { + try { + (*callback_holder)(nullptr, work()); + } + catch (...) { + (*callback_holder)(std::current_exception(), T{}); + } + }); +} +template +asio::awaitable await_external_database_callback(Starter starter) { + auto result = co_await Psc::coro::callback_result( + [starter = std::move(starter)](auto done) mutable { + starter([done = std::move(done)](std::exception_ptr exception, + T value) mutable { + if (exception) { + done.set_exception(exception); + return; + } + done(std::move(value)); + }); }); - }); co_return std::move(result); - } +} } // namespace - std::optional External_Database_Row::get(std::string_view column) const { - const auto iter = columns.find(std::string(column)); - return iter == columns.end() ? std::nullopt : iter->second; + const auto iter = columns.find(std::string(column)); + return iter == columns.end() ? std::nullopt : iter->second; } - Psc::JSON External_Database_Row::to_json() const { - auto result = Psc::JSON::object(); - for (const auto &[column, value]: columns) { - result.append({column, value ? Psc::JSON(*value) : Psc::JSON(nullptr)}); - } - return result; + auto result = Psc::JSON::object(); + for (const auto& [column, value] : columns) { + result.append({column, value ? Psc::JSON(*value) : Psc::JSON(nullptr)}); + } + return result; } - External_Resources::External_Resources( - std::string_view name, std::string_view cache_file_name, std::string_view download_url, - std::string_view description, const std::uint64_t update_interval_seconds) { - this->name = std::string(name); - this->cache_file_name = std::string(cache_file_name); - this->download_url = std::string(download_url); - this->description = std::string(description); - this->update_interval_seconds = update_interval_seconds; + std::string_view name, std::string_view cache_file_name, std::string_view download_url, + std::string_view description, const std::uint64_t update_interval_seconds) { + this->name = std::string(name); + this->cache_file_name = std::string(cache_file_name); + this->download_url = std::string(download_url); + this->description = std::string(description); + this->update_interval_seconds = update_interval_seconds; } - void External_Resources::mark_updated() { - last_updated_at = std::time(nullptr); + last_updated_at = std::time(nullptr); } - -void External_Resources::clear_last_updated_at() { last_updated_at = 0; } - -std::size_t External_Resources::row_count(SQLite::Database &db) const { - return static_cast( - db.execAndGet("SELECT COUNT(*) FROM " + - External_Database_Utils::quote_identifier(name)) - .getInt64()); +void External_Resources::clear_last_updated_at() { + last_updated_at = 0; +} +std::size_t External_Resources::row_count(SQLite::Database& db) const { + return static_cast( + db.execAndGet("SELECT COUNT(*) FROM " + + External_Database_Utils::quote_identifier(name)) + .getInt64()); } - std::filesystem::path -External_Resources::source_file(const std::filesystem::path &cache_pos) const { - return cache_pos / cache_file_name; +External_Resources::source_file(const std::filesystem::path& cache_pos) const { + return cache_pos / cache_file_name; } - -bool External_Resources::fetch(const std::filesystem::path &cache_pos, +bool External_Resources::fetch(const std::filesystem::path& cache_pos, const bool force_download) const { - const auto target_file = source_file(cache_pos); - if (!force_download) - return false; - if (download_url.empty()) - return false; - External_Database_Utils::download_to_file(download_url, target_file); - return true; + const auto target_file = source_file(cache_pos); + if (!force_download) + return false; + if (download_url.empty()) + return false; + External_Database_Utils::download_to_file(download_url, target_file); + return true; } - -External_Resource_Status External_Resources::update(SQLite::Database &db, const std::filesystem::path &cache_pos, +External_Resource_Status External_Resources::update(SQLite::Database& db, const std::filesystem::path& cache_pos, const bool force_download, const bool only_when_empty) { - create_table(db); - External_Resource_Status result{name, row_count(db), false, false, ""}; - if (only_when_empty && result.row_count != 0) { - result.message = "table already populated"; - return result; - } - if (cache_pos.empty()) { - throw std::invalid_argument("cache_pos is empty"); - } - std::filesystem::create_directories(cache_pos); - result.downloaded = fetch(cache_pos, force_download); - if (cache_file_name.empty()) { - result.message = "dynamic query required"; - return result; - } - const auto local_file = source_file(cache_pos); - if (!std::filesystem::exists(local_file)) { - result.message = download_url.empty() - ? "offline import or dynamic query required" - : "cache file unavailable"; - return result; - } - - result.row_count = import_file(db, local_file); - result.imported = true; - result.message = "ok"; - mark_updated(); - return result; -} - -External_Resource_Status -External_Resources::import_offline(SQLite::Database &db, - const std::filesystem::path &source_file) { - create_table(db); - External_Resource_Status result{name, 0, false, false, ""}; - result.row_count = import_file(db, source_file); - result.imported = true; - result.message = "ok"; - mark_updated(); - return result; -} - -External_Resource_Status -External_Resources::clear_table(SQLite::Database &db, - const std::filesystem::path &cache_pos) { - SQLite::Transaction transaction(db); - db.exec("DROP TABLE IF EXISTS " + - External_Database_Utils::quote_identifier(name)); - create_table(db); - transaction.commit(); - - if (!cache_file_name.empty()) { - std::error_code error; - std::filesystem::remove(source_file(cache_pos), error); - if (error) { - throw std::runtime_error("Cannot remove cache file for resource " + name + - ": " + error.message()); + create_table(db); + External_Resource_Status result{name, row_count(db), false, false, ""}; + if (only_when_empty && result.row_count != 0) { + result.message = "table already populated"; + return result; } - } - - clear_last_updated_at(); - return {name, 0, false, false, "table cleared"}; + if (cache_pos.empty()) { + throw std::invalid_argument("cache_pos is empty"); + } + std::filesystem::create_directories(cache_pos); + result.downloaded = fetch(cache_pos, force_download); + if (cache_file_name.empty()) { + result.message = "dynamic query required"; + return result; + } + const auto local_file = source_file(cache_pos); + if (!std::filesystem::exists(local_file)) { + result.message = download_url.empty() + ? "offline import or dynamic query required" + : "cache file unavailable"; + return result; + } + result.row_count = import_file(db, local_file); + result.imported = true; + result.message = "ok"; + mark_updated(); + return result; +} +External_Resource_Status +External_Resources::import_offline(SQLite::Database& db, + const std::filesystem::path& source_file) { + create_table(db); + External_Resource_Status result{name, 0, false, false, ""}; + result.row_count = import_file(db, source_file); + result.imported = true; + result.message = "ok"; + mark_updated(); + return result; +} +External_Resource_Status +External_Resources::clear_table(SQLite::Database& db, + const std::filesystem::path& cache_pos) { + SQLite::Transaction transaction(db); + db.exec("DROP TABLE IF EXISTS " + + External_Database_Utils::quote_identifier(name)); + create_table(db); + transaction.commit(); + if (!cache_file_name.empty()) { + std::error_code error; + std::filesystem::remove(source_file(cache_pos), error); + if (error) { + throw std::runtime_error("Cannot remove cache file for resource " + name + + ": " + error.message()); + } + } + clear_last_updated_at(); + return {name, 0, false, false, "table cleared"}; } - std::optional External_Resources::query_one( - SQLite::Database &db, - const std::vector &primary_key_values) const { - const auto &columns = primary_key_columns(); - if (columns.size() != primary_key_values.size()) { - throw std::invalid_argument( - "primary key value count mismatch for resource: " + name); - } - - std::string sql = "SELECT * FROM " + - External_Database_Utils::quote_identifier(name) + " WHERE "; - for (std::size_t index = 0; index < columns.size(); ++index) { - if (index != 0) - sql += " AND "; - sql += External_Database_Utils::quote_identifier(columns[index]) + + SQLite::Database& db, + const std::vector& primary_key_values) const { + const auto& columns = primary_key_columns(); + if (columns.size() != primary_key_values.size()) { + throw std::invalid_argument( + "primary key value count mismatch for resource: " + name); + } + std::string sql = "SELECT * FROM " + + External_Database_Utils::quote_identifier(name) + " WHERE "; + for (std::size_t index = 0; index < columns.size(); ++index) { + if (index != 0) + sql += " AND "; + sql += External_Database_Utils::quote_identifier(columns[index]) + " = ? COLLATE NOCASE"; - } - sql += " LIMIT 1"; - - SQLite::Statement statement(db, sql); - for (std::size_t index = 0; index < primary_key_values.size(); ++index) { - statement.bind( - static_cast(index + 1), - External_Database_Utils::normalize_key(primary_key_values[index])); - } - if (!statement.executeStep()) - return std::nullopt; - - External_Database_Row row; - for (int index = 0; index < statement.getColumnCount(); ++index) { - const auto name = statement.getColumnName(index); - if (statement.isColumnNull(index)) { - row.columns.emplace(name, std::nullopt); - } else { - row.columns.emplace(name, statement.getColumn(index).getString()); } - } - return row; + sql += " LIMIT 1"; + SQLite::Statement statement(db, sql); + for (std::size_t index = 0; index < primary_key_values.size(); ++index) { + statement.bind( + static_cast(index + 1), + External_Database_Utils::normalize_key(primary_key_values[index])); + } + if (!statement.executeStep()) + return std::nullopt; + External_Database_Row row; + for (int index = 0; index < statement.getColumnCount(); ++index) { + const auto name = statement.getColumnName(index); + if (statement.isColumnNull(index)) { + row.columns.emplace(name, std::nullopt); + } + else { + row.columns.emplace(name, statement.getColumn(index).getString()); + } + } + return row; } - External_Resources_Manager::External_Resources_Manager() { - register_external_resource(make_tar1090_db_aircraft_csv_gz_resource()); - register_external_resource(make_wiedehopf_tar1090_db_resource()); - register_external_resource(make_mictronics_aircraft_database_resource()); - register_external_resource(make_opensky_aircraft_database_resource()); - register_external_resource(make_faa_aircraft_registry_resource()); - register_external_resource(make_icao_doc_8643_resource()); - register_external_resource(make_vrs_routes_resource()); - register_external_resource(make_vrs_airports_resource()); - register_external_resource(make_adsblol_vrs_standing_data_resource()); - register_external_resource(make_vradarserver_standing_data_resource()); - register_external_resource(make_opensky_flightdata_api_resource()); + register_external_resource(make_tar1090_db_aircraft_csv_gz_resource()); + register_external_resource(make_wiedehopf_tar1090_db_resource()); + register_external_resource(make_mictronics_aircraft_database_resource()); + register_external_resource(make_opensky_aircraft_database_resource()); + register_external_resource(make_faa_aircraft_registry_resource()); + register_external_resource(make_icao_doc_8643_resource()); + register_external_resource(make_vrs_routes_resource()); + register_external_resource(make_vrs_airports_resource()); + register_external_resource(make_adsblol_vrs_standing_data_resource()); + register_external_resource(make_vradarserver_standing_data_resource()); + register_external_resource(make_opensky_flightdata_api_resource()); } - -void External_Resources_Manager::init(const Psc::JSON *that_json) { - if (!that_json) - return; - const auto list = that_json->get("list"); - if (!list) - return; - std::lock_guard lock(mtx_); - for (const auto &config: list->children) { - const auto name = config.try_get_string("name"); - if (!name) - continue; - for (const auto &resource: resources_) { - if (resource->name != *name) - continue; - resource->init(&config); - break; +void External_Resources_Manager::init(const Psc::JSON* that_json) { + if (!that_json) + return; + const auto list = that_json->get("list"); + if (!list) + return; + std::lock_guard lock(mtx_); + for (const auto& config : list->children) { + const auto name = config.try_get_string("name"); + if (!name) + continue; + for (const auto& resource : resources_) { + if (resource->name != *name) + continue; + resource->init(&config); + break; + } } - } - Get_J(ecap_sqlite_path) + Get_J(ecap_sqlite_path) } - Psc::JSON External_Resources_Manager::to_base_json() const { - std::lock_guard lock(mtx_); - auto ret = Psc::JSON::object(); - Ret_J(ecap_sqlite_path) - auto list = Psc::JSON::array(); - for (const std::unique_ptr &resource: resources_) { - list.children.emplace_back(resource->to_json()); - } - ret.children.emplace_back(Psc::JSON{"list", list}); - return ret; + std::lock_guard lock(mtx_); + auto ret = Psc::JSON::object(); + Ret_J(ecap_sqlite_path) + auto list = Psc::JSON::array(); + for (const std::unique_ptr& resource : resources_) { + list.children.emplace_back(resource->to_json()); + } + ret.children.emplace_back(Psc::JSON{"list", list}); + return ret; } - void External_Resources_Manager::load_sqlite_db(std::string_view path) { - try { - db_ = std::make_unique(path, SQLite::OPEN_READWRITE | - SQLite::OPEN_CREATE); - } catch (SQLite::Exception &error) { - Psc::fail_fast(std::string("load_sqlite_db error: ") + error.what()); - } - - db_->exec("PRAGMA journal_mode=WAL;"); - db_->exec("PRAGMA synchronous=NORMAL;"); - auto pos = std::filesystem::path(path).parent_path(); - // std::cout << "path" << path << " " << pos; - initialize(*db_, pos); - sync_missing(*db_); + try { + db_ = std::make_unique(path, SQLite::OPEN_READWRITE | + SQLite::OPEN_CREATE); + } + catch (SQLite::Exception& error) { + Psc::fail_fast(std::string("load_sqlite_db error: ") + error.what()); + } + db_->exec("PRAGMA journal_mode=WAL;"); + db_->exec("PRAGMA synchronous=NORMAL;"); + auto pos = std::filesystem::path(path).parent_path(); + // std::cout << "path" << path << " " << pos; + initialize(*db_, pos); + sync_missing(*db_); } - std::vector External_Resources_Manager::refresh_external_databases( - const bool force_download) { - return refresh_all(require_db(), force_download); + const bool force_download) { + return refresh_all(require_db(), force_download); } - External_Resource_Status External_Resources_Manager::refresh_external_database( - std::string_view resource_name, const bool force_download) { - return refresh_one(require_db(), resource_name, force_download); + std::string_view resource_name, const bool force_download) { + return refresh_one(require_db(), resource_name, force_download); } - External_Resource_Status External_Resources_Manager::import_external_database( - std::string_view resource_name, - const std::filesystem::path &source_file) { - return import_offline(require_db(), resource_name, source_file); + std::string_view resource_name, + const std::filesystem::path& source_file) { + return import_offline(require_db(), resource_name, source_file); } - External_Resource_Status External_Resources_Manager::clear_external_database_table( - std::string_view resource_name) { - return clear_table(require_db(), resource_name); + std::string_view resource_name) { + return clear_table(require_db(), resource_name); } - std::optional External_Resources_Manager::query_external_database( - std::string_view resource_name, - const std::vector &primary_key_values) const { - return query_one(require_db(), resource_name, primary_key_values); + std::string_view resource_name, + const std::vector& primary_key_values) const { + return query_one(require_db(), resource_name, primary_key_values); } - -std::map > +std::map> External_Resources_Manager::query_aircraft_external_databases( - std::string_view icao24) const { - return query_aircraft(require_db(), icao24); + std::string_view icao24) const { + return query_aircraft(require_db(), icao24); } - -std::map > +std::map> External_Resources_Manager::query_callsign_external_databases( - const std::optional &callsign) const { - return query_callsign(require_db(), callsign); + const std::optional& callsign) const { + return query_callsign(require_db(), callsign); } - std::vector External_Resources_Manager::external_database_status() const { - return status(require_db()); + return status(require_db()); } - void External_Resources_Manager::async_refresh_external_databases( - const bool force_download, Status_List_Callback callback) { - run_external_database_async >( - [this, force_download]() { - return refresh_external_databases(force_download); - }, - std::move(callback)); + const bool force_download, Status_List_Callback callback) { + run_external_database_async>( + [this, force_download]() { + return refresh_external_databases(force_download); + }, + std::move(callback)); } - void External_Resources_Manager::async_refresh_external_database( - std::string_view resource_name, const bool force_download, - Status_Callback callback) { - run_external_database_async( - [this, resource_name = std::move(resource_name), force_download]() { - return refresh_external_database(resource_name, force_download); - }, - std::move(callback)); + std::string_view resource_name, const bool force_download, + Status_Callback callback) { + run_external_database_async( + [this, resource_name = std::move(resource_name), force_download]() { + return refresh_external_database(resource_name, force_download); + }, + std::move(callback)); } - void External_Resources_Manager::async_import_external_database( - std::string_view resource_name, std::filesystem::path source_file, - Status_Callback callback) { - run_external_database_async( - [this, resource_name = std::move(resource_name), - source_file = std::move(source_file)]() { - return import_external_database(resource_name, source_file); - }, - std::move(callback)); + std::string_view resource_name, std::filesystem::path source_file, + Status_Callback callback) { + run_external_database_async( + [this, resource_name = std::move(resource_name), + source_file = std::move(source_file)]() { + return import_external_database(resource_name, source_file); + }, + std::move(callback)); } - void External_Resources_Manager::async_clear_external_database_table( - std::string_view resource_name, Status_Callback callback) { - run_external_database_async( - [this, resource_name = std::move(resource_name)]() { - return clear_external_database_table(resource_name); - }, - std::move(callback)); + std::string_view resource_name, Status_Callback callback) { + run_external_database_async( + [this, resource_name = std::move(resource_name)]() { + return clear_external_database_table(resource_name); + }, + std::move(callback)); } - void External_Resources_Manager::async_query_external_database( - std::string_view resource_name, std::vector primary_key_values, - Row_Callback callback) const { - run_external_database_async >( - [this, resource_name = std::move(resource_name), - primary_key_values = std::move(primary_key_values)]() { - return query_external_database(resource_name, primary_key_values); - }, - std::move(callback)); + std::string_view resource_name, std::vector primary_key_values, + Row_Callback callback) const { + run_external_database_async>( + [this, resource_name = std::move(resource_name), + primary_key_values = std::move(primary_key_values)]() { + return query_external_database(resource_name, primary_key_values); + }, + std::move(callback)); } - void External_Resources_Manager::async_query_aircraft_external_databases( - std::string_view icao24, Row_Map_Callback callback) const { - run_external_database_async< - std::map > >( - [this, icao24 = std::move(icao24)]() { - return query_aircraft_external_databases(icao24); - }, - std::move(callback)); + std::string_view icao24, Row_Map_Callback callback) const { + run_external_database_async< + std::map>>( + [this, icao24 = std::move(icao24)]() { + return query_aircraft_external_databases(icao24); + }, + std::move(callback)); } - void External_Resources_Manager::async_query_callsign_external_databases( - std::optional callsign, Row_Map_Callback callback) const { - run_external_database_async< - std::map > >( - [this, callsign = std::move(callsign)]() { - return query_callsign_external_databases(callsign); - }, - std::move(callback)); + std::optional callsign, Row_Map_Callback callback) const { + run_external_database_async< + std::map>>( + [this, callsign = std::move(callsign)]() { + return query_callsign_external_databases(callsign); + }, + std::move(callback)); } - void External_Resources_Manager::async_external_database_status( - Status_List_Callback callback) const { - run_external_database_async >( - [this]() { return external_database_status(); }, std::move(callback)); + Status_List_Callback callback) const { + run_external_database_async>( + [this]() { + return external_database_status(); + }, std::move(callback)); } - -asio::awaitable > +asio::awaitable> External_Resources_Manager::refresh_external_databases_coro( - const bool force_download) { - co_return co_await await_external_database_callback< - std::vector >( - [this, force_download](Status_List_Callback callback) { - async_refresh_external_databases(force_download, std::move(callback)); - }); + const bool force_download) { + co_return co_await await_external_database_callback< + std::vector>( + [this, force_download](Status_List_Callback callback) { + async_refresh_external_databases(force_download, std::move(callback)); + }); } - asio::awaitable External_Resources_Manager::refresh_external_database_coro( - std::string_view resource_name, const bool force_download) { - co_return co_await await_external_database_callback( - [this, resource_name = std::move(resource_name), - force_download](Status_Callback callback) mutable { - async_refresh_external_database(std::move(resource_name), - force_download, std::move(callback)); - }); + std::string_view resource_name, const bool force_download) { + co_return co_await await_external_database_callback( + [this, resource_name = std::move(resource_name), + force_download](Status_Callback callback) mutable { + async_refresh_external_database(std::move(resource_name), + force_download, std::move(callback)); + }); } - asio::awaitable External_Resources_Manager::import_external_database_coro( - std::string_view resource_name, std::filesystem::path source_file) { - co_return co_await await_external_database_callback( - [this, resource_name = std::move(resource_name), - source_file = std::move(source_file)](Status_Callback callback) mutable { - async_import_external_database(std::move(resource_name), - std::move(source_file), - std::move(callback)); - }); + std::string_view resource_name, std::filesystem::path source_file) { + co_return co_await await_external_database_callback( + [this, resource_name = std::move(resource_name), + source_file = std::move(source_file)](Status_Callback callback) mutable { + async_import_external_database(std::move(resource_name), + std::move(source_file), + std::move(callback)); + }); } - asio::awaitable External_Resources_Manager::clear_external_database_table_coro( - std::string_view resource_name) { - co_return co_await await_external_database_callback( - [this, resource_name = - std::move(resource_name)](Status_Callback callback) mutable { - async_clear_external_database_table(std::move(resource_name), - std::move(callback)); - }); + std::string_view resource_name) { + co_return co_await await_external_database_callback( + [this, resource_name = + std::move(resource_name)](Status_Callback callback) mutable { + async_clear_external_database_table(std::move(resource_name), + std::move(callback)); + }); } - -asio::awaitable > +asio::awaitable> External_Resources_Manager::query_external_database_coro( - std::string_view resource_name, - std::vector primary_key_values) const { - co_return co_await await_external_database_callback< - std::optional >( - [this, resource_name = std::move(resource_name), - primary_key_values = - std::move(primary_key_values)](Row_Callback callback) mutable { - async_query_external_database(std::move(resource_name), - std::move(primary_key_values), - std::move(callback)); - }); + std::string_view resource_name, + std::vector primary_key_values) const { + co_return co_await await_external_database_callback< + std::optional>( + [this, resource_name = std::move(resource_name), + primary_key_values = + std::move(primary_key_values)](Row_Callback callback) mutable { + async_query_external_database(std::move(resource_name), + std::move(primary_key_values), + std::move(callback)); + }); } - -asio::awaitable > +asio::awaitable> External_Resources_Manager::query_aircraft_external_databases_coro( - std::string_view icao24) const { - auto result = co_await Psc::coro::callback_result< - std::shared_ptr >( - [this, icao24 = std::move(icao24)](auto done) mutable { - async_query_aircraft_external_databases( - std::move(icao24), - [done = std::move(done)](std::exception_ptr exception, - External_Database_Row_Map value) mutable { - if (exception) { - done.set_exception(exception); - return; - } - done(std::make_shared( - std::move(value))); + std::string_view icao24) const { + auto result = co_await Psc::coro::callback_result< + std::shared_ptr>( + [this, icao24 = std::move(icao24)](auto done) mutable { + async_query_aircraft_external_databases( + std::move(icao24), + [done = std::move(done)](std::exception_ptr exception, + External_Database_Row_Map value) mutable { + if (exception) { + done.set_exception(exception); + return; + } + done(std::make_shared( + std::move(value))); + }); }); - }); - co_return result; + co_return result; } - -asio::awaitable > +asio::awaitable> External_Resources_Manager::query_callsign_external_databases_coro( - std::optional callsign) const { - auto result = co_await Psc::coro::callback_result< - std::shared_ptr >( - [this, callsign = std::move(callsign)](auto done) mutable { - async_query_callsign_external_databases( - std::move(callsign), - [done = std::move(done)](std::exception_ptr exception, - External_Database_Row_Map value) mutable { - if (exception) { - done.set_exception(exception); - return; - } - done(std::make_shared( - std::move(value))); + std::optional callsign) const { + auto result = co_await Psc::coro::callback_result< + std::shared_ptr>( + [this, callsign = std::move(callsign)](auto done) mutable { + async_query_callsign_external_databases( + std::move(callsign), + [done = std::move(done)](std::exception_ptr exception, + External_Database_Row_Map value) mutable { + if (exception) { + done.set_exception(exception); + return; + } + done(std::make_shared( + std::move(value))); + }); }); - }); - co_return result; + co_return result; } - -asio::awaitable > +asio::awaitable> External_Resources_Manager::external_database_status_coro() const { - co_return co_await await_external_database_callback< - std::vector >( - [this](Status_List_Callback callback) { - async_external_database_status(std::move(callback)); - }); + co_return co_await await_external_database_callback< + std::vector>( + [this](Status_List_Callback callback) { + async_external_database_status(std::move(callback)); + }); } - -void External_Resources_Manager::server(Global *g) { - auto &svr = g->svr; - const auto &api = g->api; - - svr.Post(api + "get_external_database_config", [this](HTTP_Param) { - auto t = warp(to_base_json()).to_json_string(); - - res->setBody(t); - }); - svr.PostCoro( - api + "get_external_database_status", - [this](HTTP_Param) -> drogon::Task<> { - auto status_list = - co_await Ecap_Coro::to_drogon(external_database_status_coro()); - - res->setBody(warp(external_resource_status_list_to_json(status_list)) - .to_json_string()); - co_return; - }); - svr.PostCoro( - api + "refresh_external_database", - [this, g](HTTP_Param) -> drogon::Task<> { - CHECK_JSON_PARAM - HTTP_REQUIRE_VALUE(name, params.try_get_string("name")) - const auto result = co_await Ecap_Coro::to_drogon( - refresh_external_database_coro(name, true)); - g->save(); - res->setBody( - warp(external_resource_status_to_json(result)).to_json_string()); - co_return; - }); - svr.PostCoro(api + "refresh_external_databases", - [this, g](HTTP_Param) -> drogon::Task<> { - const auto result = co_await Ecap_Coro::to_drogon( - refresh_external_databases_coro(true)); - g->save(); - res->setBody( - warp(external_resource_status_list_to_json(result)) - .to_json_string()); - co_return; - }); - svr.PostCoro( - api + "import_external_database", - [this, g](HTTP_Param) -> drogon::Task<> { - CHECK_JSON_PARAM - HTTP_REQUIRE_VALUE(name, params.try_get_string("name")) - HTTP_REQUIRE_VALUE(source_file, params.try_get_string("source_file")) - const auto result = co_await Ecap_Coro::to_drogon( - import_external_database_coro(name, source_file)); - g->save(); - res->setBody( - warp(external_resource_status_to_json(result)).to_json_string()); - co_return; - }); - svr.PostCoro( - api + "upload_external_database", - [this, g](HTTP_Param) -> drogon::Task<> { - drogon::MultiPartParser parser; - if (parser.parse(req) != 0) { - throw_invalid_http_param("multipart"); - } - const auto name = parser.getOptionalParameter("name"); - if (!name || parser.getFiles().size() != 1) { - throw_invalid_http_param("name or file"); - } - - const auto &upload = parser.getFiles().front(); - const auto serial = - std::chrono::steady_clock::now().time_since_epoch().count(); - auto extension = std::string(upload.getFileExtension()); - if (!extension.empty() && extension.front() != '.') { - extension.insert(extension.begin(), '.'); - } - const auto saved_name = - "external_database_" + std::to_string(serial) + extension; - if (upload.saveAs(saved_name) != 0) { - throw std::runtime_error( - "Cannot save uploaded external database file"); - } - - const auto source_file = - std::filesystem::path(drogon::app().getUploadPath()) / saved_name; - const auto result = co_await Ecap_Coro::to_drogon( - import_external_database_coro(*name, source_file)); - g->save(); - res->setBody( - warp(external_resource_status_to_json(result)).to_json_string()); - co_return; - }); - svr.PostCoro( - api + "clear_external_database_table", - [this, g](HTTP_Param) -> drogon::Task<> { - CHECK_JSON_PARAM - HTTP_REQUIRE_VALUE(name, params.try_get_string("name")) - const auto result = co_await Ecap_Coro::to_drogon( - clear_external_database_table_coro(name)); - g->save(); - res->setBody( - warp(external_resource_status_to_json(result)).to_json_string()); - co_return; - }); - svr.PostCoro( - api + "query_external_database", [this](HTTP_Param) -> drogon::Task<> { - CHECK_JSON_PARAM - HTTP_REQUIRE_VALUE(name, params.try_get_string("name")) - HTTP_REQUIRE_PTR(primary_key_values_json, - params.get("primary_key_values")) - std::vector primary_key_values; - for (const auto &value: primary_key_values_json->children) { - if (value.valueType != Psc::JsonType::String) { - throw_invalid_http_param("primary_key_values"); - } - primary_key_values.push_back(value.val); - } - const auto row = co_await Ecap_Coro::to_drogon( - query_external_database_coro(name, std::move(primary_key_values))); - res->setBody(row - ? warp(row->to_json()).to_json_string() - : Psc::JSON(nullptr).to_json_string()); - co_return; +void External_Resources_Manager::server(Global* g) { + auto& svr = g->svr; + const auto& api = g->api; + svr.Post(api + "get_external_database_config", [this](HTTP_Param) { + auto t = warp(to_base_json()).to_json_string(); + res->setBody(t); }); + svr.Post_Coro( + api + "get_external_database_status", + [this](HTTP_Param) -> drogon::Task<> { + auto status_list = + co_await Ecap_Coro::to_drogon(external_database_status_coro()); + res->setBody(warp(external_resource_status_list_to_json(status_list)) + .to_json_string()); + co_return; + }); + svr.Post_Coro( + api + "refresh_external_database", + [this, g](HTTP_Param) -> drogon::Task<> { + CHECK_JSON_PARAM + HTTP_REQUIRE_VALUE(name, params.try_get_string("name")) + const auto result = co_await Ecap_Coro::to_drogon( + refresh_external_database_coro(name, true)); + g->save(); + res->setBody( + warp(external_resource_status_to_json(result)).to_json_string()); + co_return; + }); + svr.Post_Coro(api + "refresh_external_databases", + [this, g](HTTP_Param) -> drogon::Task<> { + const auto result = co_await Ecap_Coro::to_drogon( + refresh_external_databases_coro(true)); + g->save(); + res->setBody( + warp(external_resource_status_list_to_json(result)) + .to_json_string()); + co_return; + }); + svr.Post_Coro( + api + "import_external_database", + [this, g](HTTP_Param) -> drogon::Task<> { + CHECK_JSON_PARAM + HTTP_REQUIRE_VALUE(name, params.try_get_string("name")) + HTTP_REQUIRE_VALUE(source_file, params.try_get_string("source_file")) + const auto result = co_await Ecap_Coro::to_drogon( + import_external_database_coro(name, source_file)); + g->save(); + res->setBody( + warp(external_resource_status_to_json(result)).to_json_string()); + co_return; + }); + svr.Post_Coro( + api + "upload_external_database", + [this, g](HTTP_Param) -> drogon::Task<> { + drogon::MultiPartParser parser; + if (parser.parse(req) != 0) { + throw_invalid_http_param("multipart"); + } + const auto name = parser.getOptionalParameter("name"); + if (!name || parser.getFiles().size() != 1) { + throw_invalid_http_param("name or file"); + } + const auto& upload = parser.getFiles().front(); + const auto serial = + std::chrono::steady_clock::now().time_since_epoch().count(); + auto extension = std::string(upload.getFileExtension()); + if (!extension.empty() && extension.front() != '.') { + extension.insert(extension.begin(), '.'); + } + const auto saved_name = + "external_database_" + std::to_string(serial) + extension; + if (upload.saveAs(saved_name) != 0) { + throw std::runtime_error( + "Cannot save uploaded external database file"); + } + const auto source_file = + std::filesystem::path(drogon::app().getUploadPath()) / saved_name; + const auto result = co_await Ecap_Coro::to_drogon( + import_external_database_coro(*name, source_file)); + g->save(); + res->setBody( + warp(external_resource_status_to_json(result)).to_json_string()); + co_return; + }); + svr.Post_Coro( + api + "clear_external_database_table", + [this, g](HTTP_Param) -> drogon::Task<> { + CHECK_JSON_PARAM + HTTP_REQUIRE_VALUE(name, params.try_get_string("name")) + const auto result = co_await Ecap_Coro::to_drogon( + clear_external_database_table_coro(name)); + g->save(); + res->setBody( + warp(external_resource_status_to_json(result)).to_json_string()); + co_return; + }); + svr.Post_Coro( + api + "query_external_database", [this](HTTP_Param) -> drogon::Task<> { + CHECK_JSON_PARAM + HTTP_REQUIRE_VALUE(name, params.try_get_string("name")) + HTTP_REQUIRE_PTR(primary_key_values_json, + params.get("primary_key_values")) + std::vector primary_key_values; + for (const auto& value : primary_key_values_json->children) { + if (value.valueType != Psc::JsonType::String) { + throw_invalid_http_param("primary_key_values"); + } + primary_key_values.push_back(value.val); + } + const auto row = co_await Ecap_Coro::to_drogon( + query_external_database_coro(name, std::move(primary_key_values))); + res->setBody(row + ? warp(row->to_json()).to_json_string() + : Psc::JSON(nullptr).to_json_string()); + co_return; + }); } - void External_Resources_Manager::register_external_resource( - std::unique_ptr external_res) { - if (!external_res) - throw std::invalid_argument("external resource is null"); - resources_.push_back(std::move(external_res)); + std::unique_ptr external_res) { + if (!external_res) + throw std::invalid_argument("external resource is null"); + resources_.push_back(std::move(external_res)); } - -void External_Resources_Manager::initialize(SQLite::Database &db, +void External_Resources_Manager::initialize(SQLite::Database& db, std::filesystem::path cache_pos) { - std::lock_guard lock(mtx_); - cache_pos_ = std::move(cache_pos); - for (const auto &resource: resources_) - resource->create_table(db); + std::lock_guard lock(mtx_); + cache_pos_ = std::move(cache_pos); + for (const auto& resource : resources_) + resource->create_table(db); } - std::vector -External_Resources_Manager::sync_missing(SQLite::Database &db) { - return update_all(db, false, true); +External_Resources_Manager::sync_missing(SQLite::Database& db) { + return update_all(db, false, true); } - std::vector -External_Resources_Manager::refresh_all(SQLite::Database &db, +External_Resources_Manager::refresh_all(SQLite::Database& db, const bool force_download) { - return update_all(db, force_download, false); + return update_all(db, force_download, false); } - External_Resource_Status -External_Resources_Manager::refresh_one(SQLite::Database &db, +External_Resources_Manager::refresh_one(SQLite::Database& db, std::string_view resource_name, const bool force_download) { - std::lock_guard lock(mtx_); - return get_resource(resource_name) - .update(db, cache_pos_, force_download, false); + std::lock_guard lock(mtx_); + return get_resource(resource_name) + .update(db, cache_pos_, force_download, false); } - External_Resource_Status External_Resources_Manager::import_offline( - SQLite::Database &db, std::string_view resource_name, - const std::filesystem::path &source_file) { - std::lock_guard lock(mtx_); - return get_resource(resource_name).import_offline(db, source_file); + SQLite::Database& db, std::string_view resource_name, + const std::filesystem::path& source_file) { + std::lock_guard lock(mtx_); + return get_resource(resource_name).import_offline(db, source_file); } - External_Resource_Status -External_Resources_Manager::clear_table(SQLite::Database &db, +External_Resources_Manager::clear_table(SQLite::Database& db, std::string_view resource_name) { - std::lock_guard lock(mtx_); - return get_resource(resource_name).clear_table(db, cache_pos_); + std::lock_guard lock(mtx_); + return get_resource(resource_name).clear_table(db, cache_pos_); } - std::optional External_Resources_Manager::query_one( - SQLite::Database &db, std::string_view resource_name, - const std::vector &primary_key_values) const { - std::lock_guard lock(mtx_); - return get_resource(resource_name).query_one(db, primary_key_values); + SQLite::Database& db, std::string_view resource_name, + const std::vector& primary_key_values) const { + std::lock_guard lock(mtx_); + return get_resource(resource_name).query_one(db, primary_key_values); } - -std::map > -External_Resources_Manager::query_aircraft(SQLite::Database &db, +std::map> +External_Resources_Manager::query_aircraft(SQLite::Database& db, std::string_view icao24) const { - Scope_Timer timer( - "external_database.query_aircraft", - Global::instance()->http_monitor_config.slow_scope_threshold_ms); - static const std::vector kAircraftResourceKeys = { - "tar1090_db_aircraft", "wiedehopf_tar1090_db_aircraft", - "mictronics_aircraft_database", "opensky_aircraft_database", - "faa_aircraft_registry", - }; - std::lock_guard lock(mtx_); - std::map > result; - const auto add_row = [&](std::string_view resource_name, - const std::vector &primary_key_values, - std::string_view result_name = std::string{}) { - auto &resource = get_resource(resource_name); - auto row = resource.query_one(db, primary_key_values); - if (!row) - return std::shared_ptr{}; - auto shared_row = std::make_shared(std::move(*row)); - result.emplace(std::string(result_name.empty() ? resource_name : result_name), - shared_row); - return shared_row; - }; - - std::optional type_code; - for (const auto &resource_name: kAircraftResourceKeys) { - const auto row = add_row(resource_name, std::vector{std::string(icao24)}); - if (row && !type_code) { - type_code = row->get("type_code"); - if (!type_code) - type_code = row->get("typecode"); + Scope_Timer timer( + "external_database.query_aircraft", + Global::instance()->http_monitor_config.slow_scope_threshold_ms); + static const std::vector kAircraftResourceKeys = { + "tar1090_db_aircraft", "wiedehopf_tar1090_db_aircraft", + "mictronics_aircraft_database", "opensky_aircraft_database", + "faa_aircraft_registry", + }; + std::lock_guard lock(mtx_); + std::map> result; + const auto add_row = [&](std::string_view resource_name, + const std::vector& primary_key_values, + std::string_view result_name = std::string{}) { + auto& resource = get_resource(resource_name); + auto row = resource.query_one(db, primary_key_values); + if (!row) + return std::shared_ptr{}; + auto shared_row = std::make_shared(std::move(*row)); + result.emplace(std::string(result_name.empty() ? resource_name : result_name), + shared_row); + return shared_row; + }; + std::optional type_code; + for (const auto& resource_name : kAircraftResourceKeys) { + const auto row = add_row(resource_name, std::vector{std::string(icao24)}); + if (row && !type_code) { + type_code = row->get("type_code"); + if (!type_code) + type_code = row->get("typecode"); + } } - } - - if (type_code) - add_row("icao_doc_8643_aircraft_type_designators", {*type_code}); - return result; + if (type_code) + add_row("icao_doc_8643_aircraft_type_designators", {*type_code}); + return result; } - -std::map > +std::map> External_Resources_Manager::query_callsign( - SQLite::Database &db, const std::optional &callsign) const { - Scope_Timer timer( - "external_database.query_callsign", - Global::instance()->http_monitor_config.slow_scope_threshold_ms); - static const std::vector kRouteResourceKeys = { - "vrs_routes", - "adsblol_vrs_standing_data_routes", - "vradarserver_standing_data_routes", - }; - - std::lock_guard lock(mtx_); - std::map > result; - const auto add_row = [&](std::string_view resource_name, - const std::vector &primary_key_values, - std::string_view result_name = std::string{}) { - auto &resource = get_resource(resource_name); - auto row = resource.query_one(db, primary_key_values); - if (!row) - return std::shared_ptr{}; - auto shared_row = std::make_shared(std::move(*row)); - result.emplace(result_name.empty() ? resource_name : result_name, - shared_row); - return shared_row; - }; - - std::set airport_codes; - if (callsign && !callsign->empty()) { - for (const auto &resource_name: kRouteResourceKeys) { - const auto row = add_row(resource_name, {*callsign}); - if (!row) - continue; - const auto airports = row->get("AirportCodes"); - if (!airports) - continue; - - std::size_t start = 0; - while (start < airports->size()) { - const auto end = airports->find('-', start); - airport_codes.emplace(airports->substr(start, end - start)); - if (end == std::string::npos) - break; - start = end + 1; - } + SQLite::Database& db, const std::optional& callsign) const { + Scope_Timer timer( + "external_database.query_callsign", + Global::instance()->http_monitor_config.slow_scope_threshold_ms); + static const std::vector kRouteResourceKeys = { + "vrs_routes", + "adsblol_vrs_standing_data_routes", + "vradarserver_standing_data_routes", + }; + std::lock_guard lock(mtx_); + std::map> result; + const auto add_row = [&](std::string_view resource_name, + const std::vector& primary_key_values, + std::string_view result_name = std::string{}) { + auto& resource = get_resource(resource_name); + auto row = resource.query_one(db, primary_key_values); + if (!row) + return std::shared_ptr{}; + auto shared_row = std::make_shared(std::move(*row)); + result.emplace(result_name.empty() ? resource_name : result_name, + shared_row); + return shared_row; + }; + std::set airport_codes; + if (callsign && !callsign->empty()) { + for (const auto& resource_name : kRouteResourceKeys) { + const auto row = add_row(resource_name, {*callsign}); + if (!row) + continue; + const auto airports = row->get("AirportCodes"); + if (!airports) + continue; + std::size_t start = 0; + while (start < airports->size()) { + const auto end = airports->find('-', start); + airport_codes.emplace(airports->substr(start, end - start)); + if (end == std::string::npos) + break; + start = end + 1; + } + } } - } - - for (const auto &airport_code: airport_codes) { - if (airport_code.empty()) - continue; - add_row("vrs_airports", {airport_code}, "vrs_airports:" + airport_code); - } - return result; + for (const auto& airport_code : airport_codes) { + if (airport_code.empty()) + continue; + add_row("vrs_airports", {airport_code}, "vrs_airports:" + airport_code); + } + return result; } - std::vector -External_Resources_Manager::status(SQLite::Database &db) const { - std::lock_guard lock(mtx_); - std::vector result; - for (const auto &resource: resources_) { - result.push_back( - {resource->name, resource->row_count(db), false, false, ""}); - } - return result; +External_Resources_Manager::status(SQLite::Database& db) const { + std::lock_guard lock(mtx_); + std::vector result; + for (const auto& resource : resources_) { + result.push_back( + {resource->name, resource->row_count(db), false, false, ""}); + } + return result; } - -SQLite::Database &External_Resources_Manager::require_db() const { - if (!db_) { - throw std::runtime_error("DB not loaded. Call load_sqlite_db() first."); - } - return *db_; +SQLite::Database& External_Resources_Manager::require_db() const { + if (!db_) { + throw std::runtime_error("DB not loaded. Call load_sqlite_db() first."); + } + return *db_; } - -External_Resources &External_Resources_Manager::get_resource( - std::string_view resource_name) const { - for (const auto &resource: resources_) { - if (resource->name == resource_name) - return *resource; - } - throw std::invalid_argument("unknown external resource: " + std::string(resource_name)); +External_Resources& External_Resources_Manager::get_resource( + std::string_view resource_name) const { + for (const auto& resource : resources_) { + if (resource->name == resource_name) + return *resource; + } + throw std::invalid_argument("unknown external resource: " + std::string(resource_name)); } - std::vector -External_Resources_Manager::update_all(SQLite::Database &db, +External_Resources_Manager::update_all(SQLite::Database& db, const bool force_download, const bool only_when_empty) { - std::lock_guard lock(mtx_); - std::vector result; - for (const auto &resource: resources_) { - External_Resource_Status status; - try { - status = - resource->update(db, cache_pos_, force_download, only_when_empty); - std::cout << "External database [" << status.name << "] " - << status.message << ", rows=" << status.row_count << std::endl; - result.push_back(std::move(status)); - } catch (const std::exception &error) { - std::cerr << "External database [" << resource->name - << "] update failed: [" << error.what() << "]" << " status.message:" << status.message << std::endl; - result.push_back({ - resource->name, resource->row_count(db), false, false, - error.what() - }); + std::lock_guard lock(mtx_); + std::vector result; + for (const auto& resource : resources_) { + External_Resource_Status status; + try { + status = + resource->update(db, cache_pos_, force_download, only_when_empty); + std::cout << "External database [" << status.name << "] " + << status.message << ", rows=" << status.row_count << std::endl; + result.push_back(std::move(status)); + } + catch (const std::exception& error) { + std::cerr << "External database [" << resource->name + << "] update failed: [" << error.what() << "]" << " status.message:" << status.message << std::endl; + result.push_back({ + resource->name, resource->row_count(db), false, false, + error.what() + }); + } } - } - return result; + return result; } diff --git a/module/Local_Server/server/Global.cpp b/module/Local_Server/server/Global.cpp index b1857c2..4c7d839 100644 --- a/module/Local_Server/server/Global.cpp +++ b/module/Local_Server/server/Global.cpp @@ -5,377 +5,462 @@ #include #include #include - -BaseLogger *server_logger = nullptr; +BaseLogger* server_logger = nullptr; Debug_Logger_Info_Manager debug_logger_info_manager; - void Global::handle_old_logs() { - auto mode = log_config.open_mode; - std::string dirPath = get_exe_dir() + "/" + "logs"; - namespace fs = std::filesystem; - try { - switch (mode) { - case Log_Config::Open_Mode::Rename: { - auto now = std::chrono::system_clock::now(); - auto in_time_t = std::chrono::system_clock::to_time_t(now); - std::ostringstream oss; - oss << std::put_time(std::localtime(&in_time_t), "%Y-%m-%d_%H-%M-%S"); - fs::path newDirPath = dirPath + "_" + oss.str(); - if (fs::exists(newDirPath)) { - std::cout << "New directory name already exists!" << std::endl; - return; - } - fs::rename(dirPath, newDirPath); - std::cout << "Directory renamed to: " << newDirPath << std::endl; - break; - } - case Log_Config::Open_Mode::Delete: { - if (fs::exists(dirPath)) { - fs::remove_all(dirPath); // 删除目录及其所有内容 - std::cout << "Directory and its contents deleted: " << dirPath - << std::endl; - } - if (fs::create_directories(dirPath)) { - std::cout << "Directory created: " << dirPath << std::endl; - } else { - std::cout << "创建目录失败: " << dirPath << std::endl; - Psc::fail_fast(); - } - fs::permissions(dirPath, fs::perms::owner_all | fs::perms::group_all | - fs::perms::others_all); - break; - } - case Log_Config::Open_Mode::Append: - break; - default: - std::cerr << "未知的打开模式!" << std::endl; - break; - } - } catch (const std::exception &ex) { - std::cerr << "Error: " + Psc::platform_2_utf8(ex.what()) + "\n"; - } -} - -Global::Global() { - - auto j = load(); - log_config.from_base_json(j.get("log")); - handle_old_logs(); - Base_Logger_Manager::instance() - ->set_thread_num(1) - .set_flush_seconds(3) - .init(); - int piece_num = log_config.piece_num; - int size_MB = log_config.size_MB; - int MB = 1024 * 1024; - asio_socket::socket_logger = - new BaseLogger("@/logs/socket", MB * size_MB, piece_num); - serial::serial_logger = - new BaseLogger("@/logs/serial", MB * size_MB, piece_num); - SSR::mode_s_logger = - new BaseLogger("@/logs/mode_s", MB * size_MB * 10, piece_num); - dsp_logger = new BaseLogger("@/logs/dsp", MB * size_MB, piece_num); - // libais::libais_logger = new BaseLogger("@/logs/libais", MB * size_MB, - // piece_num); - server_logger = new BaseLogger("@/logs/server", MB * size_MB, piece_num); - asio_socket::socket_logger->set_redirect( - [](const BaseLogger::Log_Info &log_info) { - auto msg = "[" + std::string("func") + "~" + log_info.func_pattern + - "] " + log_info.log_type.to_string() + log_info.content; - debug_logger_info_manager.push_info(msg); - }); - serial::serial_logger->set_redirect([](const BaseLogger::Log_Info &log_info) { - auto msg = "[" + std::string("func") + "~" + log_info.func_pattern + "] " + - log_info.log_type.to_string() + log_info.content; - debug_logger_info_manager.push_info(msg); - }); - fromJson(&j); - -#ifdef Cache_Some_Mode_S - auto old_parse_ok_json = SSR::parse_ok_json; - SSR::parse_ok_json = [old_parse_ok_json](Aircraft_Info *aircraft_info, - SSR::P_S mode_s_msg, - Psc::JSON json) { - old_parse_ok_json(aircraft_info, mode_s_msg, json); - auto f = static_cast(aircraft_info); - f->add_msg_limit(mode_s_msg); - }; -#endif - - SSR::cpr_cb = [](SSR::CPR_Error_Type t, std::string_view log, - SSR::P_S msg) { - auto src = std::dynamic_pointer_cast(msg->source); - Mode_S_Statistic_Data *ss = &src->mode_s_statistic; - if (t != SSR::CPR_Error_Type::Normal) { - ss->add_cpr_error(t); - } - SSR::mode_s_logger->debug("CPR/" + to_string(t), {}, log); - }; - // 处理错误 - SSR::parse_call_back = - [this](SSR::Parse_Call_Back_Type type, SSR::Aircraft_Info *info, - std::string_view field_name, std::vector bds_list, - void *, SSR::P_S msg) { - auto src = std::dynamic_pointer_cast(msg->source); - Mode_S_Statistic_Data *ss = &src->mode_s_statistic; - if (type == SSR::Parse_Call_Back_Type::Unknown_DF) { - // std::cout << "Unknown DF type!" << (int)(msg->df) << std::endl; - return; + auto mode = log_config.open_mode; + std::string dirPath = get_exe_dir() + "/" + "logs"; + namespace fs = std::filesystem; + try { + switch (mode) { + case Log_Config::Open_Mode::Rename: { + auto now = std::chrono::system_clock::now(); + auto in_time_t = std::chrono::system_clock::to_time_t(now); + std::ostringstream oss; + oss << std::put_time(std::localtime(&in_time_t), "%Y-%m-%d_%H-%M-%S"); + fs::path newDirPath = dirPath + "_" + oss.str(); + if (fs::exists(newDirPath)) { + std::cout << "New directory name already exists!" << std::endl; + return; + } + fs::rename(dirPath, newDirPath); + std::cout << "Directory renamed to: " << newDirPath << std::endl; + break; } - DF_Statistic_Data *dfs = ss->get_create_df_statistic_data(msg->df); + case Log_Config::Open_Mode::Delete: { + if (fs::exists(dirPath)) { + fs::remove_all(dirPath); // 删除目录及其所有内容 + std::cout << "Directory and its contents deleted: " << dirPath + << std::endl; + } + if (fs::create_directories(dirPath)) { + std::cout << "Directory created: " << dirPath << std::endl; + } + else { + std::cout << "创建目录失败: " << dirPath << std::endl; + Psc::fail_fast(); + } + fs::permissions(dirPath, fs::perms::owner_all | fs::perms::group_all | + fs::perms::others_all); + break; + } + case Log_Config::Open_Mode::Append: + break; + default: + std::cerr << "未知的打开模式!" << std::endl; + break; + } + } + catch (const std::exception& ex) { + std::cerr << "Error: " + Psc::platform_2_utf8(ex.what()) + "\n"; + } +} +Global::Global() { + auto j = load(); + log_config.from_base_json(j.get("log")); + handle_old_logs(); + Base_Logger_Manager::instance() + ->set_thread_num(1) + .set_flush_seconds(3) + .init(); + int piece_num = log_config.piece_num; + int size_MB = log_config.size_MB; + int MB = 1024 * 1024; + asio_socket::socket_logger = + new BaseLogger("@/logs/socket", MB * size_MB, piece_num); + serial::serial_logger = + new BaseLogger("@/logs/serial", MB * size_MB, piece_num); + SSR::mode_s_logger = + new BaseLogger("@/logs/mode_s", MB * size_MB * 10, piece_num); + dsp_logger = new BaseLogger("@/logs/dsp", MB * size_MB, piece_num); + // libais::libais_logger = new BaseLogger("@/logs/libais", MB * size_MB, + // piece_num); + server_logger = new BaseLogger("@/logs/server", MB * size_MB, piece_num); + asio_socket::socket_logger->set_redirect( + [](const BaseLogger::Log_Info& log_info) { + auto msg = "[" + std::string("func") + "~" + log_info.func_pattern + + "] " + log_info.log_type.to_string() + log_info.content; + debug_logger_info_manager.push_info(msg); + }); + serial::serial_logger->set_redirect([](const BaseLogger::Log_Info& log_info) { + auto msg = "[" + std::string("func") + "~" + log_info.func_pattern + "] " + + log_info.log_type.to_string() + log_info.content; + debug_logger_info_manager.push_info(msg); + }); + fromJson(&j); +#ifdef Cache_Some_Mode_S + auto old_parse_ok_json = SSR::parse_ok_json; + SSR::parse_ok_json = [old_parse_ok_json](Aircraft_Info* aircraft_info, + SSR::P_S mode_s_msg, + Psc::JSON json) { + old_parse_ok_json(aircraft_info, mode_s_msg, json); + auto f = static_cast(aircraft_info); + f->add_msg_limit(mode_s_msg); + }; +#endif + SSR::cpr_cb = [](SSR::CPR_Error_Type t, std::string_view log, + SSR::P_S msg) { + auto src = std::dynamic_pointer_cast(msg->source); + Mode_S_Statistic_Data* ss = &src->mode_s_statistic; + if (t != SSR::CPR_Error_Type::Normal) { + ss->add_cpr_error(t); + } + SSR::mode_s_logger->debug("CPR/" + to_string(t), {}, log); + }; + // 处理错误 + SSR::parse_call_back = + [this](SSR::Parse_Call_Back_Type type, SSR::Aircraft_Info* info, + std::string_view field_name, std::vector bds_list, + void*, SSR::P_S msg) { + auto src = std::dynamic_pointer_cast(msg->source); + Mode_S_Statistic_Data* ss = &src->mode_s_statistic; + if (type == SSR::Parse_Call_Back_Type::Unknown_DF) { + // std::cout << "Unknown DF type!" << (int)(msg->df) << std::endl; + return; + } + DF_Statistic_Data* dfs = ss->get_create_df_statistic_data(msg->df); dfs->add(); if (type == SSR::Parse_Call_Back_Type::Normal_Block) { - dfs->add_sub_part(field_name); - info->update(msg); - } else if (type == SSR::Parse_Call_Back_Type::CRC_Error) { - dfs->add_crc_error(); - // std::cout << field_name << " :crc_error msg:" << msg->msg_hex << - // " df:" << (int)msg->df << std::endl; - } else if (type == SSR::Parse_Call_Back_Type::Length_Error) { - ss->add_length_error(field_name); - // std::cout << field_name << " :length_error msg:" << msg->msg_hex - // << " df:" << (int)msg->df << std::endl; + dfs->add_sub_part(field_name); + info->update(msg); + } + else if (type == SSR::Parse_Call_Back_Type::CRC_Error) { + dfs->add_crc_error(); + // std::cout << field_name << " :crc_error msg:" << msg->msg_hex << + // " df:" << (int)msg->df << std::endl; + } + else if (type == SSR::Parse_Call_Back_Type::Length_Error) { + ss->add_length_error(field_name); + // std::cout << field_name << " :length_error msg:" << msg->msg_hex + // << " df:" << (int)msg->df << std::endl; } - // else if (type == Mode_S::Parse_Call_Back_Type::UNKNOWN_ERROR) {} else // {} - }; - auto str = toJson().to_json_string(); - server_logger->debug("启动", {}, str); - SSR::mode_s_logger->debug("启动", {}, str); - // libais::libais_logger->debug("启动", {}, str); - std::cout << str << std::endl; - // libais::log = normal_log; - // libais::log = ais_log; - // mode_s_log_info = mode_s_log; - init_web_server(); + }; + auto str = toJson().to_json_string(); + server_logger->debug("启动", {}, str); + SSR::mode_s_logger->debug("启动", {}, str); + // libais::libais_logger->debug("启动", {}, str); + std::cout << str << std::endl; + // libais::log = normal_log; + // libais::log = ais_log; + // mode_s_log_info = mode_s_log; + init_web_server(); } -Global::~Global() { std::cout << "Global::~Global()" << std::endl; } - -void replace(std::string &originalStr, std::string_view findStr, +Global::~Global() { + std::cout << "Global::~Global()" << std::endl; +} +void replace(std::string& originalStr, std::string_view findStr, std::string_view replaceStr) { - size_t pos = originalStr.find(findStr); - while (pos != std::string::npos) { - originalStr.replace(pos, findStr.length(), replaceStr); - pos = originalStr.find(findStr, pos + replaceStr.length()); - } + size_t pos = originalStr.find(findStr); + while (pos != std::string::npos) { + originalStr.replace(pos, findStr.length(), replaceStr); + pos = originalStr.find(findStr, pos + replaceStr.length()); + } } std::string oneLine(std::string_view str) { - auto ret = std::string(str); - replace(ret, "\n", "[n]"); - return ret; + auto ret = std::string(str); + replace(ret, "\n", "[n]"); + return ret; } bool isHexadecimal(std::string_view str) { - return std::all_of(str.begin(), str.end(), [](unsigned char c) { - return std::isdigit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'); - }); + return std::all_of(str.begin(), str.end(), [](unsigned char c) { + return std::isdigit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'); + }); } void handle_buffer_muti_start( - std::string &buffer, std::string_view data, - const std::set &prefix_list, - const std::function &callback) { - if (!data.empty()) { - buffer += data; - // std::cout << "[data]:" + data + "\n"; - // std::cout << "[buffer]:" + buffer + "\n"; - while (!buffer.empty() && buffer.back() == '\n') { - buffer.pop_back(); - } - while (true) { - std::string c; - size_t pos = 0, n = buffer.size(); - for (; pos < n; pos++) { - bool find = false; - for (std::string_view prefix : prefix_list) { - if (pos + prefix.size() <= n) { - if (buffer.substr(pos, prefix.size()) == prefix) { - c = prefix; - find = true; - break; - } - } + std::string& buffer, std::string_view data, + const std::set& prefix_list, + const std::function& callback) { + if (!data.empty()) { + buffer += data; + // std::cout << "[data]:" + data + "\n"; + // std::cout << "[buffer]:" + buffer + "\n"; + while (!buffer.empty() && buffer.back() == '\n') { + buffer.pop_back(); + } + while (true) { + std::string c; + size_t pos = 0, n = buffer.size(); + for (; pos < n; pos++) { + bool find = false; + for (std::string_view prefix : prefix_list) { + if (pos + prefix.size() <= n) { + if (buffer.substr(pos, prefix.size()) == prefix) { + c = prefix; + find = true; + break; + } + } + } + if (find) + break; + } + if (pos == n) + break; + std::string line = c + buffer.substr(0, pos); // 截取从开头到!之前的数据 + buffer = buffer.substr(pos + 1); // 更新buffer为剩余数据 + // std::cout << "[line]:" + line + "\n"; + if (pos != 0) + callback(line); } - if (find) - break; - } - if (pos == n) - break; - std::string line = c + buffer.substr(0, pos); // 截取从开头到!之前的数据 - buffer = buffer.substr(pos + 1); // 更新buffer为剩余数据 - // std::cout << "[line]:" + line + "\n"; - if (pos != 0) - callback(line); } - } } void handle_buffer_head_tail( - std::string &buffer, std::string_view data, std::string_view prefix, + std::string& buffer, std::string_view data, std::string_view prefix, std::string_view suffix, - const std::function &callback) { - // 只在数据可用时进行读取 - if (!data.empty()) { - buffer += data; - size_t pos; - while ((pos = buffer.find_first_of(suffix)) != std::string::npos) { - size_t start = buffer.find_first_of(prefix); - if (start == std::string::npos) - break; - std::string packet = buffer.substr(start + 1, pos - start - 1); - buffer.erase(0, pos + 1); - // 处理尾部空格 - while (!buffer.empty() && buffer.back() == '\n') { - buffer.pop_back(); - } - if (!packet.empty()) { - callback(packet); - } + const std::function& callback) { + // 只在数据可用时进行读取 + if (!data.empty()) { + buffer += data; + size_t pos; + while ((pos = buffer.find_first_of(suffix)) != std::string::npos) { + size_t start = buffer.find_first_of(prefix); + if (start == std::string::npos) + break; + std::string packet = buffer.substr(start + 1, pos - start - 1); + buffer.erase(0, pos + 1); + // 处理尾部空格 + while (!buffer.empty() && buffer.back() == '\n') { + buffer.pop_back(); + } + if (!packet.empty()) { + callback(packet); + } + } } - } } - -void read_ais_serial_data(std::atomic &running) { - // static int t = config.ais.read_serial_milliseconds; - // static bool ais_log = config.console_config.ais_serial; - // static bool use_ais_serial = !config.ais_mock.enable || - // config.ais_mock.use_real_serial; static auto lm = - // Light_Manager::instance(); serial::Serial* ais_serial{}; if - // (use_ais_serial) ais_serial = create_serial(config.ais.port_name, - // config.ais.baud_rate); libais::VdmStream stream; std::string ais_buffer; - // while (running.load(std::memory_order_acquire) == true) - // { - // std::string ais_data = use_ais_serial ? ais_serial->read() : - // mock_ais_serial.read(); if (!ais_data.empty()) - // { - // if (ais_log && !ais_data.empty()) - // { - // std::cout << "read:[ais_serial]:" << ais_data << std::endl; - // } - // libais::libais_logger->debug("ais_serial_read/ais_serial_read", {}, - // ais_data + "\n"); handle_buffer_muti_start(ais_buffer, ais_data, - // {"!", "$"}, [&](std::string& line) { - // lm->light_control(Light_Type::AIS, true); - // stream.AddLine(line); - // while (auto msg = stream.PopOldestMessage()) - // { - // parse_ais(msg.get()); - // } - // lm->light_control(Light_Type::AIS, false); - // }); - // } - // std::this_thread::sleep_for(std::chrono::milliseconds(t)); - // } - // delete ais_serial; +void read_ais_serial_data(std::atomic& running) { + // static int t = config.ais.read_serial_milliseconds; + // static bool ais_log = config.console_config.ais_serial; + // static bool use_ais_serial = !config.ais_mock.enable || + // config.ais_mock.use_real_serial; static auto lm = + // Light_Manager::instance(); serial::Serial* ais_serial{}; if + // (use_ais_serial) ais_serial = create_serial(config.ais.port_name, + // config.ais.baud_rate); libais::VdmStream stream; std::string ais_buffer; + // while (running.load(std::memory_order_acquire) == true) + // { + // std::string ais_data = use_ais_serial ? ais_serial->read() : + // mock_ais_serial.read(); if (!ais_data.empty()) + // { + // if (ais_log && !ais_data.empty()) + // { + // std::cout << "read:[ais_serial]:" << ais_data << std::endl; + // } + // libais::libais_logger->debug("ais_serial_read/ais_serial_read", {}, + // ais_data + "\n"); handle_buffer_muti_start(ais_buffer, ais_data, + // {"!", "$"}, [&](std::string& line) { + // lm->light_control(Light_Type::AIS, true); + // stream.AddLine(line); + // while (auto msg = stream.PopOldestMessage()) + // { + // parse_ais(msg.get()); + // } + // lm->light_control(Light_Type::AIS, false); + // }); + // } + // std::this_thread::sleep_for(std::chrono::milliseconds(t)); + // } + // delete ais_serial; } -bool is_10004(SSR::Mode_S_Msg &msg) { - bool DF_11_17_18 = - msg.df == SSR::Downlink_Format::All_Call_Reply_11 || - msg.df == SSR::Downlink_Format::Extended_Squitter_17 || - msg.df == SSR::Downlink_Format::Extended_Squitter_Non_Transponder_18; - return DF_11_17_18; +bool is_10004(SSR::Mode_S_Msg& msg) { + bool DF_11_17_18 = + msg.df == SSR::Downlink_Format::All_Call_Reply_11 || + msg.df == SSR::Downlink_Format::Extended_Squitter_17 || + msg.df == SSR::Downlink_Format::Extended_Squitter_Non_Transponder_18; + return DF_11_17_18; } - std::string to_file_name(std::string_view str) { - auto ret = std::string(str); - // 定义允许的合法字符 - auto is_valid_char = [](char c) { - return std::isalnum(c) || c == '_' || c == '-' || - c == '.'; // 允许字母、数字、下划线、连字符、点 - }; - // 替换非法字符为下划线 '_' - std::transform(ret.begin(), ret.end(), ret.begin(), - [&](char c) { return is_valid_char(c) ? c : '_'; }); - // 检查结果字符串是否全是替换字符,防止生成全是下划线的文件名 - if (ret.find_first_not_of('_') == std::string::npos) { - return "default_file_name"; // 返回一个默认文件名 - } - return ret; + auto ret = std::string(str); + // 定义允许的合法字符 + auto is_valid_char = [](char c) { + return std::isalnum(c) || c == '_' || c == '-' || + c == '.'; // 允许字母、数字、下划线、连字符、点 + }; + // 替换非法字符为下划线 '_' + std::transform(ret.begin(), ret.end(), ret.begin(), + [&](char c) { + return is_valid_char(c) ? c : '_'; + }); + // 检查结果字符串是否全是替换字符,防止生成全是下划线的文件名 + if (ret.find_first_not_of('_') == std::string::npos) { + return "default_file_name"; // 返回一个默认文件名 + } + return ret; } void Debug_Logger_Info_Manager::push_info(std::string_view c) { - std::lock_guard g(mtx); - std::string content = std::to_string(cur_serial_number) + ": " + std::string(c); - size_t content_length = content.size(); - info_list.push_back({cur_serial_number, content}); - current_total_length += content_length; - while (current_total_length > max_length && !info_list.empty()) { - current_total_length -= info_list.front().content.size(); - info_list.pop_front(); // 删除最早的记录 - } - cur_serial_number++; + std::lock_guard g(mtx); + std::string content = std::to_string(cur_serial_number) + ": " + std::string(c); + size_t content_length = content.size(); + info_list.push_back({cur_serial_number, content}); + current_total_length += content_length; + while (current_total_length > max_length && !info_list.empty()) { + current_total_length -= info_list.front().content.size(); + info_list.pop_front(); // 删除最早的记录 + } + cur_serial_number++; } Serial_Number_Type Debug_Logger_Info_Manager::get_cur_serial_number() { - std::lock_guard g(mtx); - return cur_serial_number; + std::lock_guard g(mtx); + return cur_serial_number; } JSON Debug_Logger_Info_Manager::to_json() { - JSON ret = JSON::object(); - ret.append({"cur_serial_number", cur_serial_number}); - return ret; + JSON ret = JSON::object(); + ret.append({"cur_serial_number", cur_serial_number}); + return ret; } bool Web_Server::listen(std::string_view host, int port) { - drogon::HttpAppFramework *app = &drogon::app(); - auto g = Global::instance(); - Json::Value drogon_config; - { - auto jsonStr = g->drogon_config.to_json_string(); - std::cout << "drogon::app().run(); " << jsonStr << std::endl; - Json::CharReaderBuilder builder; - std::string errs; - auto reader = builder.newCharReader(); - if (!reader->parse(jsonStr.c_str(), jsonStr.c_str() + jsonStr.size(), - &drogon_config, &errs)) { - // 解析失败 - std::cout << "drogon 配置文件加载失败!json格式解析失败!" << jsonStr - << std::endl; - Psc::fail_fast(); + drogon::HttpAppFramework* app = &drogon::app(); + auto g = Global::instance(); + Json::Value drogon_config; + { + auto jsonStr = g->drogon_config.to_json_string(); + std::cout << "drogon::app().run(); " << jsonStr << std::endl; + Json::CharReaderBuilder builder; + std::string errs; + auto reader = builder.newCharReader(); + if (!reader->parse(jsonStr.c_str(), jsonStr.c_str() + jsonStr.size(), + &drogon_config, &errs)) { + // 解析失败 + std::cout << "drogon 配置文件加载失败!json格式解析失败!" << jsonStr + << std::endl; + Psc::fail_fast(); + } + delete reader; } - delete reader; - } - app->loadConfigJson(drogon_config); - app->disableSigtermHandling(); // 关闭服务器信号处理 - app->addListener(std::string(host), port); - auto base_dir = get_exe_dir(); - // app->setLogPath(base_dir + "/logs/drogon.log"); - app->setUploadPath(base_dir + "/../drogon_uploads"); - app->run(); - return true; + app->loadConfigJson(drogon_config); + app->disableSigtermHandling(); // 关闭服务器信号处理 + app->addListener(std::string(host), port); + auto base_dir = get_exe_dir(); + // app->setLogPath(base_dir + "/logs/drogon.log"); + app->setUploadPath(base_dir + "/../drogon_uploads"); + app->run(); + return true; +} +Web_Server& Web_Server::Post(std::string_view pattern, Handler handler) { + drogon::app().registerHandler( + std::string(pattern), + [handler](const drogon::HttpRequestPtr& request, + std::function&& callback) { + auto resp = drogon::HttpResponse::newHttpResponse(); + resp->setContentTypeCode(drogon::CT_APPLICATION_JSON); + handler(request, resp); + callback(resp); + }, + {drogon::Post} + ); + return *this; +} +Web_Server& Web_Server::Post_Coro(std::string_view pattern, CoroHandler handler) { + drogon::app().registerHandler(std::string(pattern), [handler = std::move(handler)]( + const drogon::HttpRequestPtr& request, + std::function&& callback) { + auto resp = drogon::HttpResponse::newHttpResponse(); + resp->setContentTypeCode(drogon::CT_APPLICATION_JSON); + drogon::async_run( + [handler, request, resp, callback = std::move(callback)]() mutable -> drogon::Task<> { + try { + co_await handler(request, resp); + } + catch (const std::exception& error) { + resp->setStatusCode(drogon::k500InternalServerError); + resp->setBody(Psc::JSON::object({{"error", std::string(error.what())}}).to_json_string()); + std::terminate(); + } + catch (...) { + resp->setStatusCode(drogon::k500InternalServerError); + resp->setBody(Psc::JSON::object({{"error", "unknown error"}}).to_json_string()); + std::terminate(); + } + callback(resp); + co_return; + }); + }, + {drogon::Post} + ); + return *this; +} +Web_Server& Web_Server::Get(std::string_view pattern, Handler handler) { + drogon::app().registerHandlerViaRegex( + std::string(pattern), + [handler](const drogon::HttpRequestPtr& request, + std::function&& callback) { + auto resp = drogon::HttpResponse::newHttpResponse(); + resp->setContentTypeCode(drogon::CT_APPLICATION_JSON); + handler(request, resp); + callback(resp); + }, + {drogon::Get} + ); + return *this; +} +Web_Server& Web_Server::Get_Coro(std::string_view pattern, CoroHandler handler) { + drogon::app().registerHandlerViaRegex( + std::string(pattern), + [handler = std::move(handler)]( + const drogon::HttpRequestPtr& request, + std::function&& callback) { + auto resp = drogon::HttpResponse::newHttpResponse(); + resp->setContentTypeCode(drogon::CT_APPLICATION_JSON); + drogon::async_run( + [handler, request, resp, callback = std::move(callback)]() mutable -> drogon::Task<> { + try { + co_await handler(request, resp); + } + catch (const std::exception& error) { + resp->setStatusCode(drogon::k500InternalServerError); + resp->setBody(Psc::JSON::object({{"error", std::string(error.what())}}).to_json_string()); + std::terminate(); + } + catch (...) { + resp->setStatusCode(drogon::k500InternalServerError); + resp->setBody(Psc::JSON::object({{"error", "unknown error"}}).to_json_string()); + std::terminate(); + } + callback(resp); + co_return; + }); + }, + {drogon::Get} + ); + return *this; } - std::string Debug_Logger_Info_Manager::get_info(Serial_Number_Type serial_number) { - std::lock_guard g(mtx); - std::string result; - if (serial_number == cur_serial_number) { - return ""; - } - // 从后向前遍历 data 列表 - for (auto it = info_list.rbegin(); it != info_list.rend(); ++it) { - // std::cout << "max_length: " << max_length << " size: " << - // info_list.size() << " serial_number " << serial_number << "cur_sequence" - // << it->sequence << " content.size" << it->content.size() << std::endl; - if (it->sequence >= serial_number) { - result = it->content + result; // 叠加 content - } else { - break; + std::lock_guard g(mtx); + std::string result; + if (serial_number == cur_serial_number) { + return ""; } - } - return result; + // 从后向前遍历 data 列表 + for (auto it = info_list.rbegin(); it != info_list.rend(); ++it) { + // std::cout << "max_length: " << max_length << " size: " << + // info_list.size() << " serial_number " << serial_number << "cur_sequence" + // << it->sequence << " content.size" << it->content.size() << std::endl; + if (it->sequence >= serial_number) { + result = it->content + result; // 叠加 content + } + else { + break; + } + } + return result; } - -std::string inet_address_to_string(const trantor::InetAddress &addr) { - char buf[INET6_ADDRSTRLEN] = {0}; - - if (!addr.isIpV6()) { - // IPv4 - auto sa = reinterpret_cast(addr.getSockAddr()); - inet_ntop(AF_INET, &(sa->sin_addr), buf, sizeof(buf)); - uint16_t port = ntohs(sa->sin_port); - return std::string(buf) + ":" + std::to_string(port); - } else { - // IPv6 - auto sa6 = - reinterpret_cast(addr.getSockAddr()); - inet_ntop(AF_INET6, &(sa6->sin6_addr), buf, sizeof(buf)); - uint16_t port = ntohs(sa6->sin6_port); - return "[" + std::string(buf) + "]:" + std::to_string(port); - } +std::string inet_address_to_string(const trantor::InetAddress& addr) { + char buf[INET6_ADDRSTRLEN] = {0}; + if (!addr.isIpV6()) { + // IPv4 + auto sa = reinterpret_cast(addr.getSockAddr()); + inet_ntop(AF_INET, &(sa->sin_addr), buf, sizeof(buf)); + uint16_t port = ntohs(sa->sin_port); + return std::string(buf) + ":" + std::to_string(port); + } + else { + // IPv6 + auto sa6 = + reinterpret_cast(addr.getSockAddr()); + inet_ntop(AF_INET6, &(sa6->sin6_addr), buf, sizeof(buf)); + uint16_t port = ntohs(sa6->sin6_port); + return "[" + std::string(buf) + "]:" + std::to_string(port); + } } diff --git a/module/Local_Server/server/Global.h b/module/Local_Server/server/Global.h index 36db7fa..efd1e9d 100644 --- a/module/Local_Server/server/Global.h +++ b/module/Local_Server/server/Global.h @@ -1,8 +1,5 @@ #pragma once #include - - - #include "Core/Base/ThreadManager.h" #include "../Data_Source/export.h" #include "../State_Report/State_Report.h" @@ -10,9 +7,7 @@ #include "Ucoro_Drogon_Glue.h" #include "Config.h" #include - #include "Config.h" - #include "../../Radarcape_Core/cpp-httplib/httplib.h" #include "../Data_Source/export.h" #include "Core/Net_Adapter/Net_Adapter.h" @@ -20,13 +15,11 @@ #include #include #include - // 集中 管理日志 using namespace Psc; extern BaseLogger* server_logger; std::string to_file_name(std::string_view str); -std::string inet_address_to_string(const trantor::InetAddress &addr); - +std::string inet_address_to_string(const trantor::InetAddress& addr); using Serial_Number_Type = unsigned int; struct Debug_Logger_Info_Manager { void push_info(std::string_view content); @@ -47,24 +40,17 @@ private: std::mutex mtx; }; extern Debug_Logger_Info_Manager debug_logger_info_manager; - - - #define RET_OK \ res.status = StatusCode::OK_200; \ res.set_content("{\"status\": 200}", "application/json"); - inline JSON warp(const JSON& data) { +inline JSON warp(const JSON& data) { // Json ret = Json::object(); // ret.append({"status", 200}); // ret.append({"data", data}); // return ret; return data; } - - - #define HTTP_Param const drogon::HttpRequestPtr& req, const drogon::HttpResponsePtr& res - class Web_Server { public: std::string update = "update_"; @@ -76,125 +62,22 @@ public: using Handler = std::function; using CoroHandler = std::function(const drogon::HttpRequestPtr&, const drogon::HttpResponsePtr&)>; bool listen(std::string_view host, int port); - ~Web_Server() = default; - - - - - static void stop() { std::cout << "开始停止web服务" << std::endl; drogon::app().quit(); } - - Web_Server& Post(std::string_view pattern, Handler handler) { - drogon::app().registerHandler( - std::string(pattern), - [handler](const drogon::HttpRequestPtr& request, - std::function&& callback) { - auto resp = drogon::HttpResponse::newHttpResponse(); - resp->setContentTypeCode(drogon::CT_APPLICATION_JSON); - - handler(request, resp); - - callback(resp); - }, - {drogon::Post} - ); - - return *this; - } - - Web_Server& PostCoro(std::string_view pattern, CoroHandler handler) { - drogon::app().registerHandler( - std::string(pattern), - [handler = std::move(handler)]( - const drogon::HttpRequestPtr& request, - std::function&& callback) { - auto resp = drogon::HttpResponse::newHttpResponse(); - resp->setContentTypeCode(drogon::CT_APPLICATION_JSON); - - drogon::async_run( - [handler, request, resp, callback = std::move(callback)]() mutable -> drogon::Task<> { - try { - co_await handler(request, resp); - } catch (const std::exception& error) { - resp->setStatusCode(drogon::k500InternalServerError); - resp->setBody(Psc::JSON::object({{"error", std::string(error.what())}}).to_json_string()); - } catch (...) { - resp->setStatusCode(drogon::k500InternalServerError); - resp->setBody(Psc::JSON::object({{"error", "unknown error"}}).to_json_string()); - } - callback(resp); - co_return; - }); - }, - {drogon::Post} - ); - - return *this; - } - - Web_Server& Get(std::string_view pattern, Handler handler) { - drogon::app().registerHandlerViaRegex( - std::string(pattern), - [handler](const drogon::HttpRequestPtr& request, - std::function&& callback) { - auto resp = drogon::HttpResponse::newHttpResponse(); - resp->setContentTypeCode(drogon::CT_APPLICATION_JSON); - - handler(request, resp); - - callback(resp); - }, - {drogon::Get} - ); - - return *this; - } - - Web_Server& GetCoro(std::string_view pattern, CoroHandler handler) { - drogon::app().registerHandlerViaRegex( - std::string(pattern), - [handler = std::move(handler)]( - const drogon::HttpRequestPtr& request, - std::function&& callback) { - auto resp = drogon::HttpResponse::newHttpResponse(); - resp->setContentTypeCode(drogon::CT_APPLICATION_JSON); - - drogon::async_run( - [handler, request, resp, callback = std::move(callback)]() mutable -> drogon::Task<> { - try { - co_await handler(request, resp); - } catch (const std::exception& error) { - resp->setStatusCode(drogon::k500InternalServerError); - resp->setBody(Psc::JSON::object({{"error", std::string(error.what())}}).to_json_string()); - } catch (...) { - resp->setStatusCode(drogon::k500InternalServerError); - resp->setBody(Psc::JSON::object({{"error", "unknown error"}}).to_json_string()); - } - callback(resp); - co_return; - }); - }, - {drogon::Get} - ); - - return *this; - } + Web_Server& Post(std::string_view pattern, Handler handler); + Web_Server& Post_Coro(std::string_view pattern, CoroHandler handler); + Web_Server& Get(std::string_view pattern, Handler handler); + Web_Server& Get_Coro(std::string_view pattern, CoroHandler handler); }; - - // 这个对象不释放 - - - - - class Mlat_MSG { public: - explicit Mlat_MSG(const std::shared_ptr& first) { list.push_back(first);} + explicit Mlat_MSG(const std::shared_ptr& first) { + list.push_back(first); + } [[nodiscard]] std::optional icao() const { auto a = list[0]; auto t = a->type; @@ -203,21 +86,26 @@ public: } return std::nullopt; } - [[nodiscard]] std::string msg_hex() const { return list[0]->msg_hex;} - [[nodiscard]] SSR::Mode_Msg::T type() const { return static_cast(list[0]->type);} - [[nodiscard]] SSR::MLAT_timestamp& timestamp() const { return list[0]->mlat_timestamp;} - [[nodiscard]] std::shared_ptr data_source() const { return list[0]->source;} + [[nodiscard]] std::string msg_hex() const { + return list[0]->msg_hex; + } + [[nodiscard]] SSR::Mode_Msg::T type() const { + return static_cast(list[0]->type); + } + [[nodiscard]] SSR::MLAT_timestamp& timestamp() const { + return list[0]->mlat_timestamp; + } + [[nodiscard]] std::shared_ptr data_source() const { + return list[0]->source; + } void add(const std::shared_ptr& t) { list.push_back(t); } - [[nodiscard]] size_t size() const { return list.size(); } + [[nodiscard]] size_t size() const { + return list.size(); + } std::vector> list; }; - - - - - class Mlat_Handler { public: std::list get_all() { @@ -227,18 +115,14 @@ public: std::swap(ok_list, ret); return ret; } - void push(const std::shared_ptr& msg) { std::lock_guard g(mtx); - if (list.empty()) { list.emplace_back(msg); return; } - auto time = msg->mlat_timestamp; auto p = list.rbegin(); - while (p != list.rend()) { auto cur_time = p->timestamp(); // 往前最多找3秒 @@ -261,12 +145,7 @@ protected: std::mutex ok_mtx; std::mutex mtx; }; - - - - - -class Global : public Config, public Singleton{ +class Global : public Config, public Singleton { public: // asio::io_context ctx; std::atomic init_ok{false}; @@ -277,8 +156,7 @@ public: return mode_acs.data_source_config.map.get(std::string(data_source_key)).value_or(nullptr); } std::shared_ptr total_source() { - for (auto i : mode_acs.data_source_config.map.list()) - { + for (auto i : mode_acs.data_source_config.map.list()) { if (i->enable) return i; } return mode_acs.data_source_config.map.list().at(0); @@ -291,9 +169,6 @@ public: std::time_t start_server_time; DELETE_COPY(Global) }; - - - void handle_buffer_muti_start(std::string& buffer, std::string_view data, const std::set& prefix_list, const std::function& callback); void handle_buffer_head_tail(std::string& buffer, std::string_view data, std::string_view prefix, diff --git a/third_party/init.bash b/third_party/init.bash index 6570b42..89b3577 100644 --- a/third_party/init.bash +++ b/third_party/init.bash @@ -10,11 +10,7 @@ fetch_repo() { local branch="$2" local dir="$3" if [ -d "$dir" ]; then - git -C "$dir" rev-parse --is-inside-work-tree >/dev/null - git -C "$dir" remote set-url origin "$repo" - git -C "$dir" fetch origin "$branch" - git -C "$dir" checkout "$branch" - git -C "$dir" pull --ff-only origin "$branch" + echo "文件夹【$dir】已存在 跳过初始化 " else git clone --branch "$branch" --single-branch "$repo" "$dir" fi diff --git a/third_party/init.ps1 b/third_party/init.ps1 deleted file mode 100644 index 4798460..0000000 --- a/third_party/init.ps1 +++ /dev/null @@ -1,44 +0,0 @@ -$ErrorActionPreference = "Stop" -$scriptDir = $PSScriptRoot -if ( [string]::IsNullOrWhiteSpace($scriptDir)) -{ - $scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path -} -$root = (Resolve-Path -LiteralPath (Join-Path $scriptDir "..")).Path -Set-Location -LiteralPath $root -$origin = git remote get-url origin -$origin = $origin.TrimEnd("/") -$remoteRoot = $origin -replace "/[^/]+(\.git)?$", "" -function Fetch-Repo -{ - param( - [string]$Repo, - [string]$Branch, - [string]$Dir - ) - if (Test-Path -LiteralPath $Dir -PathType Container) - { - git -C $Dir rev-parse --is-inside-work-tree *> $null - git -C $Dir remote set-url origin $Repo - git -C $Dir fetch origin $Branch - git -C $Dir checkout $Branch - git -C $Dir pull --ff-only origin $Branch - } - else - { - git clone --branch $Branch --single-branch $Repo $Dir - } -} -function Fetch-RepoEx -{ - param( - [string]$Name - ) - $repo = "$remoteRoot/$Name" - $branch = "master" - Fetch-Repo -Repo $repo -Branch $branch -Dir "third_party/$Name" -} -Fetch-RepoEx "build_infra" -Fetch-RepoEx "CPP_Core" -Fetch-RepoEx "SSR" -Fetch-RepoEx "eacp_webapp" \ No newline at end of file diff --git a/third_party/start_web_app.bash b/third_party/start_web_app.bash new file mode 100644 index 0000000..296fe18 --- /dev/null +++ b/third_party/start_web_app.bash @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +set -euo pipefail +root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +node_dir="/c/Users/wyc/AppData/Roaming/JetBrains/WebStorm2026.1/node/versions/24.18.0" +export PATH="$node_dir:$PATH" +cd "$root/third_party/eacp_webapp" +node --version +npm --version +npm run dev -- --host 0.0.0.0