#include "Database.h" #include "Data_Source.h" #include "../server/Global.h" #include "../server/Performance_Monitor.h" #include #include #include #include #include #include namespace { double to_radians(double degrees) { return degrees * 3.14159265358979323846 / 180.0; } double to_degrees(double radians) { return radians * 180.0 / 3.14159265358979323846; } bool aircraft_in_base_station_radio_range(const std::optional &base_position, const SSR::Position_Info &position, double factor) { if (!base_position) { return true; } return SSR::CPR::in_radio_line_of_sight_range(*base_position, base_position->alt, position, position.alt, factor); } double track_heading_from_points(const SSR::Position_Info &first, const SSR::Position_Info &second) { auto lat1 = to_radians(first.lat); auto lat2 = to_radians(second.lat); auto dlon = to_radians(second.lon - first.lon); auto y = std::sin(dlon) * std::cos(lat2); auto x = std::cos(lat1) * std::sin(lat2) - std::sin(lat1) * std::cos(lat2) * std::cos(dlon); auto angle = to_degrees(std::atan2(y, x)); return angle < 0 ? angle + 360.0 : angle; } double track_pitch_from_points(const SSR::Position_Info &first, const SSR::Position_Info &second) { auto distance = SSR::CPR::haversine(first, second); return std::atan2(second.alt - first.alt, distance) * 180.0 / 3.14159265358979323846; } Psc::JSON track_orientation_json_from_points(const SSR::Position_Info &first, const SSR::Position_Info &second) { auto ret = Psc::JSON::object(); ret.append({"heading", track_heading_from_points(first, second)}); ret.append({"pitch", track_pitch_from_points(first, second)}); ret.append({"roll", 0.0}); return ret; } } Aircraft::Aircraft(std::string_view icao) : Aircraft_Info(icao) { auto size = Global::instance()->mode_acs.max_track_point_size.load(); air_pos_track_list.init(size); surface_pos_track_list.init(size); } void Aircraft::refresh_external_database_info() { auto &manager = Global::instance()->external_resources_manager; if (!external_database_info_loaded) { external_database_info = manager.query_aircraft_external_databases(icao); external_database_info_loaded = true; } auto callsign = flight(); if (!callsign) callsign = bds20_call_sign(); if (last_external_database_callsign == callsign) { return; } callsign_external_database_info = manager.query_callsign_external_databases(callsign); last_external_database_callsign = std::move(callsign); } std::shared_ptr DataBase::get_aircraft(std::string_view icao) { return aircraft_map.get(std::string(icao)); } std::shared_ptr DataBase::create_aircraft(std::string_view icao) { auto ret = aircraft_map.create(std::string(icao)); ret->refresh_external_database_info(); return ret; } void DataBase::delete_timeout_aircraft() { aircraft_map.remove_cond([](const std::shared_ptr &item) { if (item->timestamp == 0) { std::cout << "未初始化的 timestamp " << LOG_POS << std::endl; } long long time = std::time(nullptr) - item->timestamp; return time > Global::instance()->mode_acs.timeout_seconds; }); } JSON DataBase::get_aircraftlist() { JSON json = JSON::array(); for (auto &it : aircraft_map.values()) { auto o = Aircraft_List_JSON_Service_O::to_That(this, it.get()); json.children.push_back(o.toJson()); } return json; } Psc::JSON DataBase::get_aircraftlist(int limit_msg_num) { JSON json = JSON::array(); for (auto &it : aircraft_map.values()) { if (it->times < limit_msg_num) continue; auto o = Aircraft_List_JSON_Service_O::to_That(this, it.get()); json.children.push_back(o.toJson()); } return json; } JSON DataBase::get_all_aircraft_json() { JSON json = JSON::array(); auto g = Global::instance(); auto min_position_points = g->mode_acs.aircraft_change_list_min_position_points.load(); auto range_filter = g->mode_acs.aircraft_change_list_adsb_range_filter.load(); auto range_factor = g->mode_acs.aircraft_change_list_adsb_range_factor.load(); auto source = g->source(get_key()); auto base_position = base_station.get_pos(); if (source) { if (!base_position && source->base_station_has_valid_position.load()) { base_position = SSR::Position_3D{source->lat, source->lon, source->alt}; } } size_t num = 0; for (auto &it : aircraft_map.values()) { if (it->air_pos_track_list.size() < min_position_points) { continue; } auto last_position = it->air_pos_track_list.last(); if (!last_position) { continue; } if (range_filter && !aircraft_in_base_station_radio_range(base_position, *last_position, range_factor)) { continue; } auto vto = Flight_VTO::to_VTO(it.get()); json.children.push_back(vto.to_json()); num++; } have_pos_aircraft_num = num; return json; } JSON DataBase::get_aircraft_list_after(time_t timestamp) { JSON json = JSON::array(); auto g = Global::instance(); for (auto &it : aircraft_map.values()) { auto vto = Flight_VTO::to_VTO(it.get()); bool have_pos = !it.get()->air_pos_track_list.empty(); if (have_pos && vto.time_stamp > timestamp) { json.children.push_back(vto.to_json()); } } return json; } #ifdef Cache_Some_Mode_S Psc::JSON DataBase::get_limit_mode_s_msg_info() { JSON ret = JSON::object(); JSON list = JSON::array(); std::map map; std::map num_test; for (auto &air : aircraft_map.values()) { if (air->total_num > Cache_Some_Mode_S_Num) continue; Psc::JSON air_json = Psc::JSON::object(); { Psc::JSON ms = Psc::JSON::array(); int n = air->cache.size(); for (auto msg : air->cache) { Psc::JSON cur = Psc::JSON::object( {{"hex", msg->msg_hex}, {"df", to_string(msg->df)}}); if (msg->df == Downlink_Format::Extended_Squitter_17) { auto tc = type_code(msg->msg_bin); cur.children.push_back({"tc", tc}); map[tc]++; num_test[air->total_num] = n; } ms.append(cur); } air_json.children.push_back({"icao", air->icao}); air_json.children.push_back({"total_num", air->total_num}); air_json.children.push_back({"ms", ms}); } list.children.push_back(air_json); } ret.children.push_back({"key", key}); for (auto pair : map) { ret.children.push_back({std::to_string(pair.first), pair.second}); } Psc::JSON t = Psc::JSON::object(); for (auto pair : num_test) { t.children.push_back({std::to_string(pair.first), pair.second}); } ret.children.push_back({"数量统计", t}); ret.children.push_back({"list", list}); return ret; } #endif size_t DataBase::get_aircraft_num() { return aircraft_map.size(); } #define _init_db \ HTTP_REQUIRE_VALUE(data_source_key, \ params.try_get_string("data_source_key")) \ auto db = Global::instance()->source(data_source_key); \ if (db == nullptr) { \ res->setStatusCode(drogon::k503ServiceUnavailable); \ JSON ret; \ res->setBody(ret.to_json_string()); \ return; \ } void database_server(Global *g) { auto &svr = g->svr; auto &api = g->api; // g->load_aircraft_csv(g->mode_acs.aircraft_csv_path); g->external_resources_manager.load_sqlite_db( Psc::get_abs_path(g->external_resources_manager.ecap_sqlite_path)); #ifdef Cache_Some_Mode_S svr.Post(api + "get_cache_some_mode_s_info", [](HTTP_Param) { CHECK_JSON_PARAM _init_db auto g = Global::instance(); auto ret = JSON::object(); if (db) { ret = db->get_limit_mode_s_msg_info(); } res->setBody(warp(ret).to_json_string()); }); #endif svr.Post(api + "get_base_station_location", [](HTTP_Param) { CHECK_JSON_PARAM _init_db auto g = Global::instance(); auto ret = JSON::object(); if (db) { ret = db->base_station.to_Json(); auto target_height = g->mode_acs.adsb_theoretical_target_altitude_meters.load(); auto range = BaseStation::theoretical_detection_range_meters(db->alt, target_height); ret.append({"latitude", db->lat}); ret.append({"longitude", db->lon}); ret.append({"height", db->alt}); ret.append({"adsb_theoretical_target_altitude_meters", target_height}); ret.append({"adsb_theoretical_detection_range_meters", range}); ret.append({"理论探测范围", range}); } res->setBody(warp(ret).to_json_string()); }); svr.Post(api + "get_aircraft_base_info", [](HTTP_Param) { CHECK_JSON_PARAM _init_db HTTP_REQUIRE_VALUE(icao, params.try_get_string("icao")) auto aircraft = db->get_aircraft(icao); JSON ret; if (aircraft != nullptr) { auto vto = Flight_VTO::to_VTO(aircraft.get()); ret = vto.to_base_info_json(); } res->setBody(ret.to_json_string()); }); svr.Post(api + "get_aircraft_detail_info", [](HTTP_Param) { CHECK_JSON_PARAM _init_db HTTP_REQUIRE_VALUE(icao, params.try_get_string("icao")) auto aircraft = db->get_aircraft(icao); JSON ret; if (aircraft != nullptr) { ret = aircraft->toJson(); } res->setBody(ret.to_json_string()); }); svr.Post(api + "get_aircraft_track_list", [](HTTP_Param) { CHECK_JSON_PARAM _init_db HTTP_REQUIRE_VALUE(icao, params.try_get_string("icao")) HTTP_REQUIRE_VALUE(last_size, params.try_get_number( "last_size")) auto aircraft = db->get_aircraft(icao); JSON ret; if (aircraft != nullptr) { ret = aircraft->air_pos_track_list.get_last_array_json(last_size); auto last_two = aircraft->air_pos_track_list.last_two(); if (last_two.has_value()) { ret.children.insert( ret.children.begin(), JSON("track_orientation", track_orientation_json_from_points(last_two->first, last_two->second))); } ret.children.insert(ret.children.begin(), JSON("ds", data_source_key)); ret.children.insert(ret.children.begin(), JSON("icao", icao)); } res->setBody(ret.to_json_string()); }); svr.Post(api + "get_aircraft_list_after", [](HTTP_Param) { CHECK_JSON_PARAM _init_db HTTP_REQUIRE_VALUE( timestamp, params.try_get_number("timestamp")) auto ret = db->get_aircraft_list_after(timestamp); res->setBody(ret.to_json_string()); }); svr.Post(api + "aircraft_change_list", [](HTTP_Param) { CHECK_JSON_PARAM _init_db JSON ret = JSON::array(); if (db) { ret = db->get_all_aircraft_json(); } else { } res->setBody(warp(ret).to_json_string()); }); svr.Get(R"(/aircraftlist.json)", [](HTTP_Param) { auto list = Global::instance()->mode_acs.data_source_config.map.list(); std::shared_ptr ts = nullptr; auto ret = JSON::array(); for (const auto &li : list) { if (li->enable) { ret = li->get_aircraftlist(); break; } } res->setBody(ret.to_json_string("", "\n", "")); }); // aircraftlist.json 的带数据源版本 svr.Post(api + "aircraft_list", [](HTTP_Param) { CHECK_JSON_PARAM auto g = Global::instance(); HTTP_REQUIRE_VALUE(data_source_key, params.try_get_string("data_source_key")) std::shared_ptr db; { db = g->source(data_source_key); } if (db == nullptr) { res->setStatusCode(drogon::k503ServiceUnavailable); JSON ret; res->setBody(ret.to_json_string()); return; } auto limit_msg_num = g->mode_acs.default_min_aircraft_list_num.load(); auto t = params.get("limit_msg_num"); if (t) { HTTP_REQUIRE_VALUE(requested_limit_msg_num, t->try_number_val()) limit_msg_num = requested_limit_msg_num; } JSON ret = JSON::array(); { Scope_Timer timer("aircraft_list.db_query", g->http_monitor_config.slow_scope_threshold_ms); ret = db->get_aircraftlist(limit_msg_num); } std::string body; { Scope_Timer timer("aircraft_list.json_serialization", g->http_monitor_config.slow_scope_threshold_ms); body = warp(ret).to_json_string(); } res->setBody(body); }); } static std::string output; static void log_i(std::string_view label, std::string_view value, std::string_view unit = "") { std::ostringstream oss; // Format the label and value oss << std::left << std::setw(30) << label << ": " << value; // Add unit if not empty if (!unit.empty()) { oss << " " << unit << "\n"; } else { oss << "\n"; } // Append formatted string to output output += oss.str(); } static void log_i(std::string_view label, double value, std::string_view unit = "") { log_i(label, std::to_string(value), unit); }