common.h 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801
  1. /**
  2. * common.h — 公共类型定义、枚举、结构体、全局变量声明
  3. * v43.2 模块化拆分 (编译修复版)
  4. */
  5. #ifndef COMMON_H
  6. #define COMMON_H
  7. #include <iostream>
  8. #include <iomanip>
  9. #include <sstream>
  10. #include <fstream>
  11. #include <thread>
  12. #include <mutex>
  13. #include <condition_variable>
  14. #include <deque>
  15. #include <list>
  16. #include <stdexcept>
  17. #include <unistd.h>
  18. #include <chrono>
  19. #include <time.h>
  20. #include <functional>
  21. #include <cmath>
  22. #include <climits>
  23. #include <sys/stat.h>
  24. #include <cstdlib>
  25. #include <cstring>
  26. #include <unordered_set>
  27. #include <unordered_map>
  28. #include <memory>
  29. #include <atomic>
  30. #include <csignal>
  31. #include <algorithm>
  32. #include <fcntl.h>
  33. #include <stdio.h>
  34. #include <stdlib.h>
  35. #include <string.h>
  36. #include <assert.h>
  37. #include <errno.h>
  38. #include <ctype.h>
  39. #include <vector>
  40. #include <string>
  41. #include <map>
  42. #include <utility>
  43. #include <ctime>
  44. #include <limits.h>
  45. #include <curl/curl.h>
  46. #include <cjson/cJSON.h>
  47. #include "opencv2/opencv.hpp"
  48. #include <sqlite3.h>
  49. #include <openssl/md5.h>
  50. extern "C" {
  51. #include <libavformat/avformat.h>
  52. #include <libavcodec/avcodec.h>
  53. #include <libavutil/avutil.h>
  54. #include <libavutil/hwcontext.h>
  55. #include <libavutil/hwcontext_drm.h>
  56. #include <libavutil/imgutils.h>
  57. #include <libswscale/swscale.h>
  58. }
  59. // HyperLPR3 SDK
  60. #include "hyper_lpr_sdk.h"
  61. // httplib 前向声明(避免在所有模块中包含大头文件)
  62. namespace httplib { class Server; }
  63. // ==================== 全局常量定义 ====================
  64. // ✅ fix24-v16: Web服务端口从config.ini [server] ip字段解析,不再硬编码
  65. #define WEB_SERVER_PORT_DEFAULT 8080
  66. #define MAX_DB_RECORDS 10000
  67. #define INTERVAL_SECONDS (5 * 60)
  68. #define KEYVALLEN 100
  69. extern int g_max_photo_groups;
  70. const int MAX_UPLOAD_FAIL = 5;
  71. const int BLOCK_TIMEOUT_SEC = 300;
  72. const int PLATE_DUPLICATE_INTERVAL_MS = 2000;
  73. const int REQUIRED_SUCCESS_GROUPS = 2;
  74. const int PHOTO_RETRY_COUNT = 2;
  75. const int HTTP_STATUS_OK = 200;
  76. const int BUSINESS_ERROR_CODE = 257;
  77. const int DB_CLEANUP_THRESHOLD_MB = 500;
  78. const long long DB_CLEANUP_THRESHOLD_BYTES = (long long)DB_CLEANUP_THRESHOLD_MB * 1024 * 1024;
  79. const int TOKEN_EXPIRE_SECONDS = 7200;
  80. const int TOKEN_REFRESH_BUFFER_SECONDS = 300;
  81. const int MAX_BILL_COUNT_PER_WINDOW = 1;
  82. const int MAX_RETRY_COUNT = 5;
  83. const int MAX_UPLOAD_PER_CYCLE = 2;
  84. const int PLATE_CLEANUP_TIMEOUT_SEC = 60;
  85. const int DAILY_CLEANUP_HOUR = 23;
  86. const int DAILY_CLEANUP_MINUTE = 10;
  87. const int STATUS_CLEANUP_INTERVAL_SEC = 600;
  88. const int MAIN_LOOP_BLOCK_THRESHOLD_MS = 500;
  89. const int DB_INSERT_RETRY_COUNT = 1;
  90. const int DB_BUSY_TIMEOUT_MS = 100;
  91. const int DB_HEALTH_CHECK_INTERVAL_SEC = 60;
  92. // ==================== 每日文件清理配置(fix19修改) ====================
  93. const int FILE_CLEANUP_HOUR = 2; // 凌晨2点执行文件清理
  94. const int FILE_CLEANUP_MINUTE = 0;
  95. // 照片清理:按容量阈值(MB),默认1GB,可通过config.ini配置
  96. extern long long g_photo_max_capacity_mb;
  97. // 日志清理:按天数,默认30天,可通过config.ini配置
  98. extern int g_log_retention_days;
  99. // ==================== 错误码定义 ====================
  100. enum class ErrorCode {
  101. SUCCESS = 0,
  102. NETWORK_ERROR = -1,
  103. BUSINESS_ERROR = -2,
  104. PARSE_ERROR = -3,
  105. INVALID_PARAM = -4,
  106. BLOCKED = -5,
  107. QUOTA_EXCEEDED = -6,
  108. DB_ERROR = -7,
  109. PERMANENT_FAILURE = -8
  110. };
  111. // ==================== 照片上传结果结构体 ====================
  112. struct PhotoUploadResult {
  113. bool lo_success;
  114. bool hi_success;
  115. int success_groups;
  116. PhotoUploadResult() : lo_success(false), hi_success(false), success_groups(0) {}
  117. };
  118. // ==================== 核心:进站/出站完全独立的状态管理 ====================
  119. struct ScenePlateStatus {
  120. private:
  121. std::unordered_set<std::string> blocked_plates;
  122. std::unordered_map<std::string, int> fail_count;
  123. std::unordered_map<std::string, time_t> block_time;
  124. mutable std::mutex mtx;
  125. public:
  126. bool is_blocked(const std::string& plate) {
  127. std::lock_guard<std::mutex> lock(mtx);
  128. auto it = blocked_plates.find(plate);
  129. if (it == blocked_plates.end()) return false;
  130. if (time(nullptr) >= block_time[plate]) {
  131. blocked_plates.erase(it);
  132. fail_count.erase(plate);
  133. block_time.erase(plate);
  134. return false;
  135. }
  136. return true;
  137. }
  138. void add_fail(const std::string& plate) {
  139. std::lock_guard<std::mutex> lock(mtx);
  140. fail_count[plate]++;
  141. if (fail_count[plate] >= MAX_UPLOAD_FAIL) {
  142. blocked_plates.insert(plate);
  143. block_time[plate] = time(nullptr) + BLOCK_TIMEOUT_SEC;
  144. }
  145. }
  146. void reset(const std::string& plate) {
  147. std::lock_guard<std::mutex> lock(mtx);
  148. blocked_plates.erase(plate);
  149. fail_count.erase(plate);
  150. block_time.erase(plate);
  151. }
  152. void cleanup_expired() {
  153. std::lock_guard<std::mutex> lock(mtx);
  154. time_t now = time(nullptr);
  155. for (auto it = block_time.begin(); it != block_time.end(); ) {
  156. if (now >= it->second) {
  157. blocked_plates.erase(it->first);
  158. fail_count.erase(it->first);
  159. it = block_time.erase(it);
  160. } else ++it;
  161. }
  162. }
  163. };
  164. extern ScenePlateStatus g_in_plate_status;
  165. extern ScenePlateStatus g_out_plate_status;
  166. // ==================== ROI配置结构体(v43新增) ====================
  167. struct ROIConfig {
  168. int x = 0;
  169. int y = 0;
  170. int width = 0;
  171. int height = 0;
  172. bool enabled = false;
  173. bool isFullFrame() const {
  174. return x == 0 && y == 0 && width == 0 && height == 0;
  175. }
  176. cv::Rect getRect(int img_w, int img_h) const {
  177. return cv::Rect(
  178. std::max(0, std::min(x, img_w - 1)),
  179. std::max(0, std::min(y, img_h - 1)),
  180. std::min(width > 0 ? width : img_w, img_w - std::max(0, std::min(x, img_w - 1))),
  181. std::min(height > 0 ? height : img_h, img_h - std::max(0, std::min(y, img_h - 1)))
  182. );
  183. }
  184. std::string toString() const {
  185. return "[" + std::to_string(x) + "," + std::to_string(y) + ","
  186. + std::to_string(width) + "," + std::to_string(height) + "]"
  187. + (enabled ? " ON" : " OFF");
  188. }
  189. };
  190. // ==================== 解码模式枚举(v43新增) ====================
  191. enum class DecodeMode {
  192. AUTO = 0,
  193. SOFT = 1,
  194. DRM = 2
  195. };
  196. // ==================== 进站/出站交替锁定机制 ====================
  197. enum class StationMode : int {
  198. INBOUND_ALLOWED = 0,
  199. OUTBOUND_ALLOWED = 1
  200. };
  201. struct PlateStationState {
  202. std::string plate;
  203. time_t last_in_time;
  204. time_t last_out_time;
  205. StationMode current_mode;
  206. PlateStationState() : last_in_time(0), last_out_time(0),
  207. current_mode(StationMode::INBOUND_ALLOWED) {}
  208. };
  209. // ==================== 联单缓存结构 ====================
  210. struct InBillCacheEntry {
  211. std::string tb_num;
  212. time_t create_time;
  213. int hit_count;
  214. int photo_count;
  215. bool bill_created;
  216. };
  217. struct OutBillCacheEntry {
  218. std::string tb_num;
  219. time_t create_time;
  220. int hit_count;
  221. int photo_count;
  222. bool bill_created;
  223. };
  224. // ==================== 错误恢复策略 ====================
  225. enum class UploadError {
  226. SUCCESS = 0,
  227. NETWORK_TIMEOUT,
  228. NETWORK_CONNECTION_FAILED,
  229. SERVER_ERROR_4XX,
  230. SERVER_ERROR_5XX,
  231. AUTH_FAILED,
  232. INVALID_RESPONSE,
  233. IMAGE_TOO_LARGE,
  234. UNKNOWN_ERROR
  235. };
  236. struct RecoveryStrategy {
  237. int max_retries;
  238. int retry_delay_ms;
  239. bool should_retry;
  240. };
  241. // ==================== 场景上传记录(TIME_WINDOW持久化) ====================
  242. struct SceneUploadRecord {
  243. int bill_count;
  244. time_t last_time;
  245. time_t trigger_time;
  246. bool bill_created;
  247. int photo_success_count;
  248. bool feishu_sent;
  249. int generation;
  250. time_t create_time;
  251. std::string tb_num;
  252. SceneUploadRecord() : bill_count(0), last_time(0), trigger_time(0),
  253. bill_created(false), photo_success_count(0), feishu_sent(false),
  254. generation(0), create_time(time(NULL)) {}
  255. };
  256. // ==================== 监控指标 ====================
  257. struct MonitorMetrics {
  258. std::atomic<int> createbill_total{ 0 };
  259. std::atomic<int> createbill_success{ 0 };
  260. std::atomic<int> createbill_business_error{ 0 };
  261. std::atomic<int> createbill_quota_exceeded{ 0 };
  262. std::deque<std::pair<time_t, int>> upload_time_records;
  263. std::mutex upload_time_mtx;
  264. std::atomic<int> time_window_hits{ 0 };
  265. std::atomic<int> in_cache_hits{ 0 };
  266. std::atomic<int> in_cache_misses{ 0 };
  267. std::atomic<int> out_cache_hits{ 0 };
  268. std::atomic<int> out_cache_misses{ 0 };
  269. std::atomic<int> upload_errors{ 0 };
  270. std::atomic<int> network_timeouts{ 0 };
  271. std::atomic<int> server_errors{ 0 };
  272. std::atomic<int> in_station_count{ 0 };
  273. std::atomic<int> out_station_count{ 0 };
  274. std::atomic<int> feishu_success_count{ 0 };
  275. std::deque<time_t> five_min_upload_times;
  276. std::mutex five_min_mtx;
  277. time_t start_time{ 0 };
  278. std::atomic<long long> main_loop_block_count{ 0 };
  279. std::atomic<long long> main_loop_max_block_ms{ 0 };
  280. std::atomic<int> photo_lo_success{ 0 };
  281. std::atomic<int> photo_hi_success{ 0 };
  282. std::atomic<int> photo_group_success{ 0 };
  283. std::atomic<int> db_duplicate_skip_count{ 0 };
  284. std::atomic<int> dir_create_error_count{ 0 };
  285. std::atomic<int> db_insert_error_count{ 0 };
  286. std::atomic<int> db_insert_retry_success{ 0 };
  287. std::atomic<int> permanent_failure_count{ 0 };
  288. std::atomic<int> alert_sent_count{ 0 };
  289. std::atomic<int> db_health_check_count{ 0 };
  290. // v42新增:交替锁定监控指标
  291. std::atomic<int> station_lock_in_count{ 0 };
  292. std::atomic<int> station_lock_out_count{ 0 };
  293. std::atomic<int> station_in_block_count{ 0 };
  294. std::atomic<int> station_out_block_count{ 0 };
  295. std::atomic<int> station_timeout_cleanup_count{ 0 };
  296. // v43新增:ROI监控指标
  297. std::atomic<int> roi_in_crop_count{ 0 };
  298. std::atomic<int> roi_out_crop_count{ 0 };
  299. std::atomic<int> roi_in_fullframe_count{ 0 };
  300. std::atomic<int> roi_out_fullframe_count{ 0 };
  301. // v43新增:飞书/解码/Web监控指标
  302. std::atomic<int> feishu_skip_count{ 0 };
  303. std::atomic<int> drm_decode_count{ 0 };
  304. std::atomic<int> soft_decode_count{ 0 };
  305. std::atomic<int> web_retry_count{ 0 };
  306. std::atomic<int> web_retry_success_count{ 0 };
  307. // fix20新增:推理耗时追踪
  308. std::deque<std::pair<time_t, int>> infer_time_records;
  309. std::mutex infer_time_mtx;
  310. void record_roi_crop(bool is_in) {
  311. is_in ? roi_in_crop_count++ : roi_out_crop_count++;
  312. }
  313. void record_roi_fullframe(bool is_in) {
  314. is_in ? roi_in_fullframe_count++ : roi_out_fullframe_count++;
  315. }
  316. void record_feishu_skip() { feishu_skip_count++; }
  317. void record_drm_decode() { drm_decode_count++; }
  318. void record_soft_decode() { soft_decode_count++; }
  319. void record_web_retry(bool success) {
  320. web_retry_count++;
  321. if (success) web_retry_success_count++;
  322. }
  323. void record_station_lock(bool is_in) {
  324. is_in ? station_lock_in_count++ : station_lock_out_count++;
  325. }
  326. void record_station_block(bool is_in) {
  327. is_in ? station_in_block_count++ : station_out_block_count++;
  328. }
  329. void record_station_timeout_cleanup() {
  330. station_timeout_cleanup_count++;
  331. }
  332. void record_upload_time(int duration_ms) {
  333. std::lock_guard<std::mutex> lock(upload_time_mtx);
  334. upload_time_records.push_back({ time(NULL), duration_ms });
  335. if (upload_time_records.size() > 10) {
  336. upload_time_records.pop_front();
  337. }
  338. }
  339. void record_createbill(bool success, bool is_business_error = false, bool is_quota_exceeded = false) {
  340. createbill_total++;
  341. if (success) createbill_success++;
  342. if (is_business_error) createbill_business_error++;
  343. if (is_quota_exceeded) createbill_quota_exceeded++;
  344. }
  345. void record_cache_hit(bool is_in, bool hit) {
  346. if (is_in) hit ? in_cache_hits++ : in_cache_misses++;
  347. else hit ? out_cache_hits++ : out_cache_misses++;
  348. }
  349. void record_error(UploadError error) {
  350. upload_errors++;
  351. switch (error) {
  352. case UploadError::NETWORK_TIMEOUT: network_timeouts++; break;
  353. case UploadError::SERVER_ERROR_5XX: server_errors++; break;
  354. default: break;
  355. }
  356. }
  357. void record_station(bool is_in) {
  358. is_in ? in_station_count++ : out_station_count++;
  359. }
  360. void record_feishu_success() { feishu_success_count++; }
  361. void record_photo_upload(bool lo_success, bool hi_success, bool group_success) {
  362. if (lo_success) photo_lo_success++;
  363. if (hi_success) photo_hi_success++;
  364. if (group_success) photo_group_success++;
  365. }
  366. void record_main_loop_block(long long duration_ms) {
  367. main_loop_block_count++;
  368. if (duration_ms > main_loop_max_block_ms.load()) {
  369. main_loop_max_block_ms.store(duration_ms);
  370. }
  371. if (duration_ms > MAIN_LOOP_BLOCK_THRESHOLD_MS) {
  372. std::cerr << "[告警] 主循环阻塞 " << duration_ms << "ms,超过阈值 "
  373. << MAIN_LOOP_BLOCK_THRESHOLD_MS << "ms" << std::endl;
  374. }
  375. }
  376. void record_db_duplicate_skip() { db_duplicate_skip_count++; }
  377. void record_dir_create_error() { dir_create_error_count++; }
  378. void record_db_insert_error() { db_insert_error_count++; }
  379. void record_db_insert_retry_success() { db_insert_retry_success++; }
  380. void record_permanent_failure() { permanent_failure_count++; }
  381. void record_alert_sent() { alert_sent_count++; }
  382. void record_db_health_check() { db_health_check_count++; }
  383. void record_inference_time(int duration_ms) {
  384. std::lock_guard<std::mutex> lock(infer_time_mtx);
  385. infer_time_records.push_back({ time(NULL), duration_ms });
  386. if (infer_time_records.size() > 20) {
  387. infer_time_records.pop_front();
  388. }
  389. }
  390. int get_avg_inference_time() {
  391. std::lock_guard<std::mutex> lock(infer_time_mtx);
  392. if (infer_time_records.empty()) return 0;
  393. int total = 0;
  394. for (auto& p : infer_time_records) total += p.second;
  395. return total / (int)infer_time_records.size();
  396. }
  397. int get_last_inference_time() {
  398. std::lock_guard<std::mutex> lock(infer_time_mtx);
  399. if (infer_time_records.empty()) return 0;
  400. return infer_time_records.back().second;
  401. }
  402. int get_avg_upload_time() {
  403. std::lock_guard<std::mutex> lock(upload_time_mtx);
  404. if (upload_time_records.empty()) return 0;
  405. int total = 0;
  406. for (auto& p : upload_time_records) total += p.second;
  407. return total / upload_time_records.size();
  408. }
  409. float get_createbill_success_rate() {
  410. int total = createbill_total.load();
  411. return total > 0 ? (float)createbill_success.load() / total : 0.0f;
  412. }
  413. float get_cache_hit_rate(bool is_in) {
  414. if (is_in) {
  415. int total = in_cache_hits.load() + in_cache_misses.load();
  416. return total > 0 ? (float)in_cache_hits.load() / total : 0.0f;
  417. } else {
  418. int total = out_cache_hits.load() + out_cache_misses.load();
  419. return total > 0 ? (float)out_cache_hits.load() / total : 0.0f;
  420. }
  421. }
  422. std::string get_uptime_string() {
  423. if (start_time == 0) return "0h00m00s";
  424. auto secs = time(NULL) - start_time;
  425. int h = secs / 3600; int m = (secs % 3600) / 60; int s = secs % 60;
  426. std::ostringstream oss;
  427. oss << h << "h" << std::setfill('0') << std::setw(2) << m << "m" << std::setw(2) << s << "s";
  428. return oss.str();
  429. }
  430. void print_report();
  431. };
  432. extern MonitorMetrics g_metrics;
  433. // ==================== C风格枚举和结构体 ====================
  434. typedef enum {
  435. BUILDING = 1,
  436. DOCK = 2,
  437. BACKFILL = 3
  438. } WTYPE;
  439. typedef enum {
  440. STATION_IN = 1,
  441. STATION_OUT = 2
  442. } DTYPE;
  443. typedef enum {
  444. POSITION_LO = 1,
  445. POSITION_HI = 2
  446. } GTYPE;
  447. typedef enum {
  448. CAPTURE_NORMAL = 1,
  449. CAPTURE_CAMERA_OFFLINE,
  450. CAPTURE_STORAGE_ERROR,
  451. CAPTURE_LENS_OBSTRUCTED,
  452. CAPTURE_ANGLE_ABNORMAL
  453. } CaptureStatus;
  454. typedef struct {
  455. WTYPE wtype;
  456. DTYPE dtype;
  457. GTYPE gtype;
  458. CaptureStatus status;
  459. time_t capture_time = 0; // ✅ fix23: 抓拍时间戳,保存帧被捕获时的时间
  460. } CaptureInfo;
  461. typedef struct {
  462. std::string tb_num;
  463. float confidence = 0.0f;
  464. std::string type;
  465. std::string code;
  466. cv::Mat image_front;
  467. cv::Mat image_side;
  468. int count = 0;
  469. bool is_report = false;
  470. std::string pic_path_front;
  471. std::string pic_path_side;
  472. int retry_count = 0;
  473. std::unique_ptr<CaptureInfo> cap_info_copy;
  474. time_t first_seen_time = 0;
  475. int db_id = 0;
  476. bool is_inbound = false;
  477. bool is_outbound = false;
  478. bool photo_saved = false;
  479. time_t last_station_blocked_time = 0; // ✅ fix11: 交替锁定拦截时间戳,防止被拦截后空转
  480. bool blocked_by_station_lock = false; // ✅ fix13: 区分BLOCKED来源(true=交替锁定, false=is_blocked)
  481. std::atomic<bool> upload_in_progress{false}; // ✅ fix18-P0: 上传进行中标志,防止peek与try_lock竞态
  482. time_t upload_complete_time = 0; // ✅ fix24-v6: 上传完成时间戳,防止刚上传完就被peek重置导致重复保存
  483. time_t db_capture_time = 0; // ✅ fix24-v18: 照片保存时固定的capture_time,防止识别线程竞态覆盖导致DB时间不一致
  484. } CarPlateInfo;
  485. // ==================== RTSPCapture 前向声明 ====================
  486. class RTSPCapture;
  487. // ==================== PlateRecApp 结构体 ====================
  488. typedef struct {
  489. P_HLPR_Context hlpr_ctx;
  490. RTSPCapture* capture_front_in = nullptr;
  491. RTSPCapture* capture_front_out = nullptr;
  492. RTSPCapture* capture_side_in = nullptr;
  493. RTSPCapture* capture_side_out = nullptr;
  494. CaptureInfo front_info_in;
  495. CaptureInfo front_info_out;
  496. CaptureInfo side_info_in;
  497. CaptureInfo side_info_out;
  498. time_t timer_front_in;
  499. time_t timer_front_out;
  500. std::mutex map_mtx;
  501. std::unordered_map<std::string, std::shared_ptr<CarPlateInfo>> map;
  502. } PlateRecApp;
  503. // ==================== 全局变量 extern 声明 ====================
  504. // 路径
  505. extern std::string pathComm;
  506. extern std::string model_path;
  507. // 配置变量
  508. extern std::string project_name;
  509. extern std::string point_number;
  510. extern std::string throughway;
  511. extern std::string rtsp_url_front_in;
  512. extern std::string rtsp_url_front_out;
  513. extern std::string rtsp_url_side_in;
  514. extern std::string rtsp_url_side_out;
  515. extern std::string app_api;
  516. extern std::string app_key;
  517. extern std::string app_secret;
  518. extern int DEBUG_LOG;
  519. extern std::atomic<int> TestFlag;
  520. extern int g_wType;
  521. extern int g_time_window_min;
  522. extern double g_PLATE_CONFIDENCE_THRESHOLD;
  523. extern double g_PLATE_LOG_THRESHOLD;
  524. // v43新增全局变量
  525. extern bool g_alternating_merge_enabled;
  526. extern ROIConfig g_roi_in;
  527. extern ROIConfig g_roi_out;
  528. extern bool g_roi_debug_enabled;
  529. extern DecodeMode g_hw_decode_mode;
  530. extern std::string g_hw_decode_device;
  531. extern std::string g_rtsp_transport;
  532. extern bool g_suppress_emergency_alert;
  533. extern int g_in_out_interval_sec;
  534. // fix24-v8: 共享摄像头模式(进站和出站共用同一个前向摄像头)
  535. // 启用后,根据交替锁定状态自动判断检测到的车牌是进站还是出站
  536. extern bool g_shared_capture_mode;
  537. // fix24-v14: 本地时区偏移(秒),用于SQLite中create_time字符串转Unix时间戳的校正
  538. extern int g_tz_offset_seconds;
  539. // fix18: config.ini路径(用于ROI写回)
  540. extern std::string g_config_ini_path;
  541. // fix18: 称重系统全局变量(config.ini key映射已在config.cpp中匹配)
  542. extern bool g_weight_enabled;
  543. extern bool g_flag_weight; // fix27: 飞书消息是否包含重量信息(config.ini: flagWeight=1)
  544. extern double g_weight_threshold_in;
  545. extern double g_weight_threshold_out;
  546. extern double g_weight_default_entry;
  547. extern double g_weight_default_exit;
  548. extern int g_weight_detection_time;
  549. extern int g_weight_tcp_connect_timeout;
  550. extern std::string g_weight_server_ip;
  551. extern int g_weight_server_port;
  552. extern double g_weight_max_kg;
  553. extern double g_weight_min_kg;
  554. extern int g_weight_stable_samples;
  555. extern double g_weight_stable_threshold;
  556. extern int g_weight_candidate_count;
  557. extern int g_weight_max_retries;
  558. extern int g_weight_retry_delay_ms;
  559. // fix18: MQTT全局变量
  560. extern bool g_mqtt_enabled;
  561. extern std::string g_mqtt_host;
  562. extern int g_mqtt_port;
  563. extern std::string g_mqtt_username;
  564. extern std::string g_mqtt_password;
  565. extern std::string g_mqtt_topic;
  566. extern std::string g_mqtt_client_id;
  567. // MQTT消息附加字段(从[MQTT]节点读取)
  568. extern std::string g_plate_color;
  569. extern std::string g_vehicle_type;
  570. // ==================== fix24 v43: [sync] 并行同步配置 ====================
  571. extern bool g_sync_parallel_enabled; // [sync] enabled (0=退回v41串行, 1=启用v43并行)
  572. extern int g_sync_reporter_timeout_sec; // Reporter 等待两路结果超时(秒)
  573. extern int g_sync_weight_retry_max; // 重量独立重试最大次数
  574. extern int g_sync_weight_retry_interval_sec; // 重量重试间隔(秒)
  575. extern int g_sync_tb_num_dedup_sec; // tb_num 去重窗口(秒)
  576. extern int g_sync_weight_snapshot_max_age_sec; // fix24 v43 Bug#18: 重量快照最大年龄(秒)
  577. // ==================== fix24 v44 P0: 预检测锁定配置 ====================
  578. // 地磅场景:车辆整体开上秤台,重量一次性加载,不存在半上秤误判
  579. // TCP线程每200ms采样,连续 prelock_stable_samples 个样本稳定且 > prelock_threshold_kg 即锁定
  580. // 车牌检测后优先消费预锁定值(0等待),未命中再走快照→阻塞等待
  581. extern double g_weight_prelock_threshold_kg; // 预检测触发阈值(kg),0=禁用
  582. extern int g_weight_prelock_stable_samples; // 预检测锁定时需要的连续稳定样本数
  583. // 交替锁定
  584. extern std::map<std::string, PlateStationState> g_plate_station_cache;
  585. extern std::mutex g_station_cache_mtx;
  586. extern const int STATION_CLEANUP_INTERVAL_SEC;
  587. const int STATION_LOCK_EXPIRE_SEC = 7200; // ✅ fix18: 交替锁定记录2小时过期,超时清零
  588. // ✅ fix16: 移除OUT_NO_RECORD_TIMEOUT_SEC和g_out_no_record_first_seen
  589. // 出站无进站记录永远拦截,不再需要超时放行机制
  590. // 帧级别去重
  591. extern std::unordered_map<std::string, time_t> g_in_plate_last_processed;
  592. extern std::unordered_map<std::string, time_t> g_out_plate_last_processed;
  593. extern std::mutex g_in_plate_last_processed_mtx;
  594. extern std::mutex g_out_plate_last_processed_mtx;
  595. // 飞书
  596. extern bool g_feishu_enabled; // fix27: 飞书消息独立开关(config.ini: [feishu] ENABLED=1)
  597. extern std::string g_feishu_app_id;
  598. extern std::string g_feishu_app_secret;
  599. extern std::string g_feishu_chat_id;
  600. extern long g_feishu_timeout_second;
  601. // 联单缓存
  602. extern std::unordered_map<std::string, InBillCacheEntry> g_in_bill_cache;
  603. extern std::mutex g_in_bill_cache_mtx;
  604. extern std::unordered_map<std::string, OutBillCacheEntry> g_out_bill_cache;
  605. extern std::mutex g_out_bill_cache_mtx;
  606. extern std::unordered_map<std::string, int> g_in_record;
  607. extern std::mutex g_in_record_mtx;
  608. extern std::unordered_map<std::string, int> g_out_record;
  609. extern std::mutex g_out_record_mtx;
  610. // 场景上传记录
  611. extern std::unordered_map<std::string, SceneUploadRecord> g_in_upload_records;
  612. extern std::unordered_map<std::string, SceneUploadRecord> g_out_upload_records;
  613. // 特殊车牌
  614. extern std::vector<std::string> g_special_plates;
  615. extern std::mutex g_special_plates_mtx;
  616. // 重试队列
  617. extern std::deque<std::shared_ptr<CarPlateInfo>> g_retry_queue;
  618. extern std::mutex g_retry_queue_mtx;
  619. // 数据库
  620. extern sqlite3* g_db;
  621. extern std::mutex g_db_mtx;
  622. extern std::string g_db_path;
  623. // Token
  624. extern std::string g_tenant_token;
  625. extern std::atomic<time_t> g_token_expire_time;
  626. extern std::mutex g_token_mtx;
  627. // 全局状态
  628. extern volatile std::sig_atomic_t g_running;
  629. extern std::atomic<time_t> g_last_data_activity_time;
  630. // PlateRecApp实例
  631. extern PlateRecApp plate_rec_app;
  632. extern uint32_t count;
  633. extern std::atomic<int> g_active_detach_threads;
  634. // Web服务器
  635. extern std::unique_ptr<std::thread> g_web_server_thread;
  636. extern std::unique_ptr<httplib::Server> g_web_server;
  637. extern std::atomic<bool> g_web_server_running;
  638. extern std::atomic<bool> g_web_server_initialized;
  639. // ✅ fix24-v19: HTTP重定向服务器(HTTP->HTTPS自动跳转)
  640. extern std::unique_ptr<std::thread> g_http_redirect_thread;
  641. extern std::unique_ptr<httplib::Server> g_http_redirect_server;
  642. // fix24-v12: HTTPS/SSL配置
  643. extern bool g_ssl_enabled;
  644. extern std::string g_ssl_cert_path;
  645. extern std::string g_ssl_key_path;
  646. // ✅ fix24-v16: Web服务端口(从config.ini [server] ip字段解析)
  647. extern int g_web_server_port;
  648. // ✅ fix24 功能一:登录认证系统全局对象
  649. // 必须在 httplib.h 被 include 之前定义 OpenSSL 宏(auth_middleware.h 会触发 httplib.h 包含)
  650. #ifndef CPPHTTPLIB_OPENSSL_SUPPORT
  651. #define CPPHTTPLIB_OPENSSL_SUPPORT
  652. #endif
  653. #include "auth_db.h"
  654. #include "auth_session.h"
  655. #include "auth_rate_limiter.h"
  656. #include "auth_middleware.h"
  657. extern auth::AuthDB *g_auth_db;
  658. extern auth::SessionManager *g_session_mgr;
  659. extern auth::RateLimiter *g_rate_limiter;
  660. extern auth::AuthMiddleware *g_auth_middleware;
  661. extern bool g_auth_enabled; // 是否启用认证(config.ini [auth] enabled)
  662. extern std::string g_auth_db_path; // 认证数据库路径(config.ini [auth] db_path)
  663. // ==================== 系统监控配置 (config.ini [system]) ====================
  664. extern int g_sys_monitor_interval; // 监控采样间隔(秒)
  665. extern int g_sys_temp_alert_threshold; // 温度告警阈值(°C)
  666. extern int g_sys_cpu_alert_threshold; // CPU告警阈值(%)
  667. extern std::string g_sys_db_path; // 系统监控数据库路径
  668. extern int g_sys_history_retention_days; // 全量数据保留天数
  669. extern int g_sys_aggregation_retention_days; // 聚合数据保留天数
  670. extern std::string g_sys_flush_time; // 每日刷盘时间(HH:MM,默认23:20)
  671. // ==================== frpc 管理配置 (config.ini [frpc]) ====================
  672. extern std::string g_frpc_config_path; // frpc.toml 路径
  673. extern std::string g_frpc_backup_path; // 备份路径
  674. extern std::string g_frpc_protected_tunnels; // 受保护隧道列表
  675. extern int g_frpc_restart_check_timeout; // 重启后等待检测时间(秒)
  676. extern bool g_frpc_auto_rollback; // 重启失败自动回滚
  677. extern bool g_frpc_web_enabled; // Web管理页面开关
  678. extern std::string g_frpc_admin_addr; // frpc admin API 地址
  679. extern int g_frpc_admin_port; // frpc admin API 端口
  680. extern std::string g_frpc_admin_user; // frpc admin 用户名
  681. extern std::string g_frpc_admin_password; // frpc admin 密码
  682. // ==================== 终端/SSH 配置 (config.ini [terminal]) ====================
  683. extern int g_ttyd_port; // ttyd 端口
  684. extern std::string g_ttyd_credential; // ttyd 凭证 (user:pass)
  685. extern int g_ttyd_max_clients; // ttyd 最大客户端数
  686. extern std::string g_ssh_keys_path; // authorized_keys 路径
  687. // ==================== 日志管理配置 (config.ini [log]) ====================
  688. extern int g_log_buffer_size_mb; // 日志缓冲区大小(MB)
  689. extern std::string g_log_flush_time; // 日志写回时间(HH:MM)
  690. extern std::string g_log_file; // 日志文件路径
  691. // g_log_retention_days 已在 fix19 中声明(第106行),此处不重复声明
  692. extern bool g_log_redirect_stdout; // 是否重定向 stdout/stderr
  693. // ✅ fix24-v36: 内存日志缓冲新增配置
  694. extern bool g_log_enabled; // 是否启用内存日志模式(1=内存, 0=直写文件)
  695. extern bool g_log_auto_flush_on_exit; // 程序退出时是否自动刷盘
  696. // 数据库记录结构
  697. struct DbRecord {
  698. int id;
  699. std::string create_time;
  700. time_t capture_time = 0; // ✅ fix24-v13: 抓拍时刻Unix时间戳
  701. std::string plate_number;
  702. std::string tb_num;
  703. int station_type;
  704. std::string lo_photo_path;
  705. std::string hi_photo_path;
  706. int lo_upload_status;
  707. int hi_upload_status;
  708. int feishu_status;
  709. int retry_count;
  710. };
  711. // 重试结果
  712. struct RetryResult {
  713. bool success = false;
  714. std::string message;
  715. std::string tb_num;
  716. int uploaded_photos = 0;
  717. };
  718. #endif // COMMON_H