#include "generic_barrier.h" #include "application.h" #include "common/loging.h" #include "common/snowflake.h" #include "common/sys_util.h" namespace zsy { static long long getTime() { const auto now = std::chrono::system_clock::now(); const auto now_ms = std::chrono::time_point_cast(now); const auto epoch = now_ms.time_since_epoch(); return std::chrono::duration_cast(epoch).count(); } GenericBarrier::GenericBarrier(const BarrierProperties &config) : config(config) { Application::eventManager->subscribe(config.sn + "/open", [this](const EventManager::Event &) { this->open(); }); static auto subscribed = [] { auto cli = Application::mqttCliHolder->remoteCli(); if (cli) { auto clientId = cli->getClientId(); Application::eventManager->subscribe(clientId + "/yztq/1/barrier", [](const EventManager::Event &event) { if (!event.data.has_value()) { LOGGER_ERROR("开门请求参数错误"); return; } auto jsonData = event.data.value(); LOGGER_INFO("收到开门请求:{}", jsonData.dump()); const auto req = jsonData.get(); Application::eventManager->publish(req.deviceNo + "/open", jsonData.dump()); }); } else { LOGGER_ERROR("未找到 MQTT 远程客户端"); } Application::httpSvr->getEndpoint("/data", [](const httplib::Request &req, httplib::Response &res) { nlohmann::json j; try { // double weight = Application::deviceHolder->getPlatformScale("b11ceeb5-af42d80f")->reading(); // j["地磅读数"] = weight; // Application::deviceHolder->getSoundColumn( "b11ceeb5-af42d80f")->play("欢迎光临"); // auto reportPassResult = Application::reportSvr->reportPass("苏K85076", "b11ceeb5-af42d80f", ""); } catch (std::exception &e) { LOGGER_ERROR("错误", e.what()); j["错误"] = ""; } catch (...) { LOGGER_ERROR("错误"); j["错误"] = ""; } res.set_content(j.dump(), "application/json"); }); Application::httpSvr->postEndpoint("/plateRecognize", [](const httplib::Request &req, httplib::Response &res) { // static std::unordered_map cache; // static std::mutex cacheMutex; try { auto body = req.body; LOGGER_INFO("收到车牌识别结果:{}", body); auto [succ,recognizeResult] = GenericBarrier::parseRecognizeResult(body); if (!succ) { LOGGER_ERROR("车牌识别结果解析失败"); res.set_content(R"({})", "application/json"); return; } auto serialno = recognizeResult.alarmInfoPlate.serialno; auto imageFile = recognizeResult.alarmInfoPlate.result.plateResult.imageFile; auto license = recognizeResult.alarmInfoPlate.result.plateResult.license; if (serialno.empty() || imageFile.empty() || license.empty()) { LOGGER_ERROR("车牌识别结果解析失败"); res.set_content(R"({})", "application/json"); return; } if (license.find("无") != std::string::npos) { LOGGER_WARN("车牌识别失败"); res.set_content(R"({})", "application/json"); return; } /*auto ms = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); auto key = serialno + license; long long time = ms + 60000 * 5; { std::lock_guard lock(cacheMutex); std::erase_if(cache, [time](const auto &pair) { return pair.second >= time; }); if (cache.contains(key)) { if (cache[key] < time) { res.set_content(R"({})", "application/json"); LOGGER_INFO("重复的车牌识别结果:{} {}", serialno, license); return; } } cache[key] = ms; }*/ Application::threadPool->submit([imageFile,license, barrier = Application::deviceHolder->getBarrier(serialno)] { if (!barrier) { LOGGER_ERROR("未找到对应的道闸"); return; } barrier->resolveRecognizeResult(license, imageFile); }); } catch (std::exception &e) { LOGGER_ERROR("车牌识别结果处理失败: {}", e.what()); } catch (...) { LOGGER_ERROR("未知异常,车牌识别结果处理失败"); } res.set_content(R"({})", "application/json"); }); return true; }(); } void GenericBarrier::open() { LOGGER_INFO("收到开门请求:{} {}", config.name, config.sn); const long timestamp = static_cast(getTime()); BarrierBcd barrier; barrier.id = "open" + std::to_string(timestamp); barrier.sn = config.sn; barrier.timestamp = timestamp; barrier.payload.body.value = 2; barrier.payload.body.io = config.io; nlohmann::json j(barrier); auto topic = "device/" + config.sn + "/message/down/gpio_out"; auto data = j.dump(); LOGGER_INFO("打开道闸:{} {}", topic, data); try { auto cli = Application::mqttCliHolder->localCli(); if (cli) { cli->publish(topic, data, 0); } else { LOGGER_ERROR("未找到 MQTT 本地客户端"); } } catch (const std::exception &e) { LOGGER_INFO("开门失败:{}", e.what()); } catch (...) { LOGGER_ERROR("未知异常,开门失败"); } } std::tuple GenericBarrier::parseRecognizeResult(const std::string &jsonStr) { try { auto json = nlohmann::json::parse(jsonStr); RecognizeResult result = json.get(); return std::make_tuple(true, result); } catch (std::exception &e) { LOGGER_ERROR("未找到车牌识别结果:{}", e.what()); return std::make_tuple(false, RecognizeResult()); }catch (...) { LOGGER_ERROR("未知异常,未找到车牌识别结果"); return std::make_tuple(false, RecognizeResult()); } } void GenericBarrier::resolveRecognizeResult(const std::string &license, const std::string &imageFile) { try { LOGGER_INFO("车牌识别结果处理中,设备名称:{}", config.name); // 播放语音 1 /*Application::threadPool->submit([sn = config.sn] { Application::deviceHolder->getSoundColumn(sn)->play("欢迎光临"); });*/ std::thread t1([sn = config.sn] { Application::deviceHolder->getSoundColumn(sn)->play("欢迎光临"); }); // 上传车头照 auto imageFileDecode = SysUtil::base64_decode(imageFile); const std::shared_ptr imageFileStream = std::make_shared(imageFileDecode, std::ios_base::in | std::ios_base::binary); auto photoId = Snowflake::genIdStr(); auto now = std::chrono::system_clock::now(); std::time_t currentTime = std::chrono::system_clock::to_time_t(now); std::tm *localTime = std::localtime(¤tTime); std::stringstream ss; ss << std::put_time(localTime, "%Y%m%d"); std::string date = ss.str(); auto [carFrontUrlSucc,carFrontUrl] = Application::oss->upload(date + "/" + license + "_front_" + photoId + ".jpg", *imageFileStream); // 上报 1 auto reportPassResult = Application::reportSvr->reportPass(license, config.sn, carFrontUrl); if (!(reportPassResult.code == 0 && (reportPassResult.data.type == 1 || reportPassResult.data.type == 2))) { LOGGER_INFO("不处理:{}", config.name); t1.join(); return; } // 上报结果不为 0,播放语音 2 并读地磅,拍车斗并上传 /*Application::threadPool->submit([sn =config.sn] { Application::deviceHolder->getSoundColumn(sn)->play("正在称重,请稍后"); });*/ std::thread t2([sn = config.sn] { Application::deviceHolder->getSoundColumn(sn)->play("正在称重,请稍后"); }); double weight = Application::deviceHolder->getPlatformScale(config.sn)->reading(); auto photographPath = Application::deviceHolder->getVidicon(config.sn)->photograph(); auto [carBodyUrlSucc,carBodyUrl] = Application::oss->upload(date + "/" + license + "_body_" + photoId + ".jpg", photographPath); if (!photographPath.empty()) { auto pathPtr = SysUtil::ch_vlt(photographPath.c_str()); if (std::remove(pathPtr.get()) != 0) { auto [_,code,msg] = SysUtil::getError(); LOGGER_ERROR("临时照片删除失败:{},错误码:{},错误信息:{}", photographPath, code, msg); } else { LOGGER_ERROR("临时照片删除成功:{}", photographPath); } } // 上报 2 Application::reportSvr->report(license, config.sn, weight, carFrontUrl, carBodyUrl, reportPassResult.data.orderNo); t1.join(); t2.join(); } catch (std::exception &e) { LOGGER_ERROR("车牌识别结果处理失败: {}", e.what()); } catch (...) { LOGGER_ERROR("未知异常,车牌识别结果处理失败"); } } } // zsy