#ifndef PSC_GLOBAL_INCLUDE_H #define PSC_GLOBAL_INCLUDE_H #include #include #include #include #include #include #include #include #include #include #include #include #include "Psc_Cpp_Core/Statistics/Statistics.h" #include "Psc_Cpp_Core/socket/ByteOrder.h" #include "SSR/export.h" class Global; class Invalid_Http_Param final : public std::runtime_error { public: using std::runtime_error::runtime_error; }; [[noreturn]] inline void throw_invalid_http_param(const char* detail) { throw Invalid_Http_Param(detail); } #define CHECK_JSON_PARAM \ auto o_params = Psc::try_parse_json(req->body().data()); \ if (!o_params.has_value()) { \ throw_invalid_http_param("request body is not valid JSON"); \ } \ auto& params = o_params.value(); \ auto that_json = ¶ms; #define HTTP_REQUIRE_VALUE(NAME, EXPRESSION) \ auto o_http_##NAME = (EXPRESSION); \ if (!o_http_##NAME.has_value()) { \ throw_invalid_http_param(#NAME); \ } \ auto NAME = std::move(o_http_##NAME).value(); #define HTTP_REQUIRE_PTR(NAME, EXPRESSION) \ auto NAME = (EXPRESSION); \ if ((NAME) == nullptr) { \ throw_invalid_http_param(#NAME); \ } #define HTTP_REQUIRE_TRUE(EXPRESSION, DETAIL) \ if (!(EXPRESSION)) { \ throw_invalid_http_param(DETAIL); \ } template class Ordered_List { public: void swap(size_t i, size_t j) { std::lock_guard g(mtx); if (i >= _list.size() || j >= _list.size()) return; std::swap(_list[i], _list[j]); } void push_back(Value_Type value) { std::lock_guard g(mtx); _list.push_back(value); // 添加默认值 } void insert(int i, Value_Type value) { std::lock_guard g(mtx); _list.insert(_list.begin() + i, value); } Value_Type get(size_t i) { return _list[i]; } void remove(size_t i) { std::lock_guard g(mtx); if (i >= _list.size()) return; _list.erase(_list.begin() + i); } std::vector list() { std::lock_guard g(mtx); return this->_list; } void clear() { list().clear(); } protected: std::mutex mtx; std::vector _list; }; template class Ordered_Map { public: std::optional get(Key_Type key) const { std::lock_guard g(mtx); auto it = _map.find(key); if (it != _map.end()) { return it->second; } return std::nullopt; } bool swap(size_t i, size_t j) { std::lock_guard g(mtx); if (i >= _list.size() || j >= _list.size()) return false; std::swap(_list[i], _list[j]); // 更新 map 中的 value,假设你可以从 Value 中获取 key Key_Type key_i = _list[i]->key; Key_Type key_j = _list[j]->key; _map[key_i] = _list[i]; _map[key_j] = _list[j]; return true; } void push_back(Value_Type value) { std::lock_guard g(mtx); _list.push_back(value); // 添加默认值 _map[value->key] = value; // 插入到 map } bool insert(int i, Value_Type value) { std::lock_guard g(mtx); if (i < 0 || static_cast(i) > _list.size()) return false; _list.insert(_list.begin() + i, value); _map[value->key] = value; return true; } Value_Type get(size_t i) { return _list[i]; } std::optional try_get(size_t i) { std::lock_guard g(mtx); if (i >= _list.size()) return std::nullopt; return _list[i]; } bool remove(size_t i) { std::lock_guard g(mtx); if (i >= _list.size()) return false; Key_Type& key = _list[i]->key; _map.erase(key); _list.erase(_list.begin() + i); return true; } std::vector list() const { std::lock_guard g(mtx); return this->_list; } // std::map map(){ // std::lock_guard g(mtx); // return this->_map; // } bool set_order(const std::vector& keys) { std::lock_guard g(mtx); if (keys.size() != _list.size()) return false; std::vector reordered; reordered.reserve(_list.size()); for (const auto& key : keys) { auto iterator = _map.find(key); if (iterator == _map.end()) return false; reordered.push_back(iterator->second); } _list = std::move(reordered); return true; } void clear() { std::lock_guard g(mtx); _list.clear(); _map.clear(); } protected: mutable std::mutex mtx; std::vector _list; std::map _map; }; class Mode_AC_Statistic_Data { public: Psc::JSON to_json() { std::lock_guard g(mtx); Psc::JSON ret = Psc::JSON::object(); const auto messages_per_second = utc == std::time(nullptr) ? pre_second_num : 0; ret.append({"messages_per_second", messages_per_second}); ret.append({"messages_total", total_num}); ret.append({"length_errors_total", length_error_num.load()}); return ret; } void add() { std::lock_guard g(mtx); add_inter(); } void add_length_error() { std::lock_guard g(mtx); add_inter(); length_error_num++; } protected: std::atomic length_error_num{}; void add_inter() { total_num++; auto cur_time = std::time(nullptr); if (cur_time != utc) { utc = cur_time; pre_second_num = 0; } pre_second_num++; } std::mutex mtx; size_t pre_second_num{}; size_t total_num{}; time_t utc{}; }; class Statistic_Data { public: time_t utc{}; size_t pre_second_num{}; size_t total_num{}; [[nodiscard]] Psc::JSON to_json() const { Psc::JSON ret = Psc::JSON::object(); const auto messages_per_second = utc == std::time(nullptr) ? pre_second_num : 0; ret.append({"messages_per_second", messages_per_second}); ret.append({"messages_total", total_num}); return ret; } Statistic_Data() = default; }; class DF_Statistic_Data { public: time_t utc{}; size_t pre_second_num{}; size_t total_num{}; size_t crc_error_num{}; Psc::JSON to_json() { std::lock_guard lock(mtx); return to_json_locked(); } [[nodiscard]] std::tuple counters() const { std::lock_guard lock(mtx); return {utc == std::time(nullptr) ? pre_second_num : 0, total_num, crc_error_num}; } void add() { std::lock_guard lock(mtx); add_inter(); } void add_crc_error() { std::lock_guard lock(mtx); crc_error_num++; } void add_sub_part(std::string_view key) { std::lock_guard lock(mtx); add_sub_part_inter(key); } protected: Psc::JSON to_json_locked() const { Psc::JSON ret = Psc::JSON::object(); const auto messages_per_second = utc == std::time(nullptr) ? pre_second_num : 0; const auto crc_error_percent = total_num == 0 ? 0.0 : static_cast(crc_error_num) * 100.0 / static_cast(total_num); ret.append({"messages_per_second", messages_per_second}); ret.append({"messages_total", total_num}); ret.append({"crc_errors_total", crc_error_num}); ret.append({"crc_error_percent", crc_error_percent}); Psc::JSON subtypes = Psc::JSON::object(); for (const auto& cur : statistic_map) { subtypes.append({cur.first, cur.second.to_json()}); } ret.append({"subtypes", subtypes}); return ret; } void add_inter() { total_num++; auto cur_time = std::time(nullptr); if (cur_time != utc) { utc = cur_time; pre_second_num = 0; } pre_second_num++; } void add_sub_part_inter(std::string_view key) { auto t = get_create_statistic_data(key); t->total_num++; auto cur_time = std::time(nullptr); if (cur_time != t->utc) { t->utc = cur_time; t->pre_second_num = 0; } t->pre_second_num++; } Statistic_Data* get_create_statistic_data(std::string_view key) { Statistic_Data* t; auto key_string = std::string(key); auto iter = statistic_map.find(key_string); if (iter == statistic_map.end()) { Statistic_Data cur{}; statistic_map.insert(std::make_pair(key_string, cur)); } t = &statistic_map[key_string]; return t; } std::map statistic_map; mutable std::mutex mtx; }; class CPR_Percentage_Statistic_Data { public: void add(SSR::CPR_Type cpr_type, SSR::CPR_Ret_Type result_type) { std::lock_guard lock(mtx); switch (result_type) { case SSR::CPR_Ret_Type::Speed_Error: case SSR::CPR_Ret_Type::Parse_OK: case SSR::CPR_Ret_Type::Inter_Error: case SSR::CPR_Ret_Type::Time_Space_Too_Long: break; case SSR::CPR_Ret_Type::Lack_Other_Msg: case SSR::CPR_Ret_Type::Lack_Old_Pos: case SSR::CPR_Ret_Type::Base: return; } auto& statistic = statistic_map[cpr_type]; ++statistic.total_num; ++statistic.result_num[result_type]; } Psc::JSON to_json() const { std::lock_guard lock(mtx); Psc::JSON result = Psc::JSON::object(); for (const auto& [cpr_type, statistic] : statistic_map) { Psc::JSON type_result = Psc::JSON::object(); type_result.append({"total", statistic.total_num}); for (auto result_type : statistic_types) { size_t num = 0; auto iter = statistic.result_num.find(result_type); if (iter != statistic.result_num.end()) { num = iter->second; } double rate = statistic.total_num == 0 ? 0.0 : static_cast(num) / static_cast(statistic.total_num) * 100.0; Psc::JSON value = Psc::JSON::object(); value.append({"count", num}); value.append({"percent", rate}); type_result.append({Psc::to_string(result_type), value}); } result.append({Psc::to_string(cpr_type), type_result}); } return result; } protected: struct Statistic_Data { size_t total_num{}; std::map result_num; }; inline static constexpr std::array statistic_types{ SSR::CPR_Ret_Type::Speed_Error, SSR::CPR_Ret_Type::Parse_OK, SSR::CPR_Ret_Type::Inter_Error, SSR::CPR_Ret_Type::Time_Space_Too_Long, SSR::CPR_Ret_Type::Out_of_Maximum_Detection_Range}; std::map statistic_map; mutable std::mutex mtx; }; class Mode_S_Statistic_Data { public: Psc::JSON to_json() { std::lock_guard lock(mtx); size_t total_pre_second_num = 0; size_t total_num = 0; size_t crc_error_num = 0; for (auto& [_, statistic] : DF_Statistic_Data_map) { const auto [pre_second, total, crc_error] = statistic.counters(); total_pre_second_num += pre_second; total_num += total; crc_error_num += crc_error; } Psc::JSON ret = Psc::JSON::object(); const auto crc_error_percent = total_num == 0 ? 0.0 : static_cast(crc_error_num) * 100.0 / static_cast(total_num); ret.append({"messages_per_second", total_pre_second_num}); ret.append({"messages_total", total_num}); ret.append({"length_errors_total", length_error_num.load()}); ret.append({"crc_errors_total", crc_error_num}); ret.append({"crc_error_percent", crc_error_percent}); Psc::JSON df_sub_type = Psc::JSON::object(); for (auto& cur : DF_Statistic_Data_map) { df_sub_type.append({Psc::to_string(cur.first) + " [" + std::to_string(static_cast(cur.first)) + "]", cur.second.to_json()}); } ret.append({"downlink_formats", df_sub_type}); ret.append({"cpr", cpr_statistic_data.to_json()}); return ret; } void add_length_error(std::string_view key) { ++length_error_num; } void add_cpr_error(SSR::CPR_Type cpr_type, SSR::CPR_Ret_Type result_type) { cpr_statistic_data.add(cpr_type, result_type); } DF_Statistic_Data* get_create_df_statistic_data(const SSR::Downlink_Format& key) { std::lock_guard lock(mtx); return &DF_Statistic_Data_map.try_emplace(key).first->second; } size_t get_total_pre_second_num() { std::lock_guard lock(mtx); size_t ret = 0; for (auto& cur : DF_Statistic_Data_map) ret += std::get<0>(cur.second.counters()); return ret; } size_t get_total_num() { std::lock_guard lock(mtx); size_t ret = 0; for (auto& cur : DF_Statistic_Data_map) ret += std::get<1>(cur.second.counters()); return ret; } size_t get_crc_error_num() { std::lock_guard lock(mtx); size_t ret = 0; for (auto& cur : DF_Statistic_Data_map) ret += std::get<2>(cur.second.counters()); return ret; } protected: std::atomic length_error_num{}; std::map DF_Statistic_Data_map; CPR_Percentage_Statistic_Data cpr_statistic_data; std::mutex mtx; }; template class Immutable : public T {}; #endif