#include "ResultToHttpSrvEngine.h" #include "myutils.h" ResultToHttpSrvEngine::ResultToHttpSrvEngine() {} ResultToHttpSrvEngine::~ResultToHttpSrvEngine() {} APP_ERROR ResultToHttpSrvEngine::Init() { strPort0_ = engineName_ + "_" + std::to_string(engineId_) + "_0"; strUsername_ = MyYaml::GetIns()->GetStringValue("username"); strPassword_ = MyYaml::GetIns()->GetStringValue("password"); strURL_ = MyYaml::GetIns()->GetStringValue("gc_http_url"); strGetTokenURL_ = MyYaml::GetIns()->GetStringValue("gc_gettoken_url"); strImageSrv_ = MyYaml::GetIns()->GetPathValue("gc_image_srv"); strPoundNo_ = MyYaml::GetIns()->GetStringValue("atlas_poundno"); strFailSavePath_ = MyYaml::GetIns()->GetPathValue("gc_result_path") + "httpfailcontent.csv"; strFailSaveBakPath_ = MyYaml::GetIns()->GetPathValue("gc_result_path") + "httpfailcontent_bak.csv"; LogInfo << "ResultToHttpSrvEngine Init ok"; return APP_ERR_OK; } APP_ERROR ResultToHttpSrvEngine::DeInit() { LogDebug << "curl_easy_cleanup"; curl_easy_cleanup(pCurl_); /* 这个处理移动到main中, 防止多线程调用 LogDebug << "内存清理"; curl_global_cleanup(); */ LogInfo << "ResultToHttpSrvEngine DeInit ok"; return APP_ERR_OK; } /** * libcurl回调函数 * inParam : void *pBuffer 回调内容地址 : size_t size 回调单个数据大小 : size_t nmemb 回调数据个数 * outParam: std::string &strResp 返回内容 * return : 回调数据大小 */ size_t ResultToHttpSrvEngine::WriteCallBack(void *pBuffer, size_t size, size_t nmemb, std::string &strResp) { size_t sizes = size * nmemb; std::string strTemp((char*)pBuffer, sizes); strResp += strTemp; return sizes; } /** * 调用http接口获取token * inParam : * outParam: std::string &strBladeAuth 返回的token信息 * return : true:成功; false:失败 */ bool ResultToHttpSrvEngine::GetToken(std::string &strBladeAuth) { //1. 获得curl操作符 if (nullptr == pCurl_) { LogDebug<<"pCurl_ is null, invoke curl_easy_init"; pCurl_ = curl_easy_init(); if (nullptr == pCurl_) { LogError << "curl_easy_init failed !"; return false; } } //2. 设置head, 和表单 //设置head信息 struct curl_slist *pHeaderList = nullptr; pHeaderList = curl_slist_append(pHeaderList, "Authorization:Basic Y2xpZW50X2VudGVycHJpc2U6Y2xpZW50X2VudGVycHJpc2Vfc2VjcmV0"); //设置表单信息 curl_mime *pMultipart = curl_mime_init(pCurl_); curl_mimepart *pPart = curl_mime_addpart(pMultipart); curl_mime_name(pPart, "username"); curl_mime_data(pPart, strUsername_.c_str(), CURL_ZERO_TERMINATED); pPart = curl_mime_addpart(pMultipart); curl_mime_name(pPart, "password"); curl_mime_data(pPart, strPassword_.c_str(), CURL_ZERO_TERMINATED); pPart = curl_mime_addpart(pMultipart); curl_mime_name(pPart, "tenantId"); curl_mime_data(pPart, "000000", CURL_ZERO_TERMINATED); pPart = curl_mime_addpart(pMultipart); curl_mime_name(pPart, "grant_type"); curl_mime_data(pPart, "password", CURL_ZERO_TERMINATED); curl_easy_setopt(pCurl_, CURLOPT_CONNECTTIMEOUT, 1); //连接超时(1s连接不上服务器返回超时) curl_easy_setopt(pCurl_, CURLOPT_URL, strGetTokenURL_.c_str()); //设置url curl_easy_setopt(pCurl_, CURLOPT_HTTPHEADER, pHeaderList); //设置报文头 curl_easy_setopt(pCurl_, CURLOPT_MIMEPOST, pMultipart); //设置表单 //curl_easy_setopt(pCurl_, CURLOPT_POSTFIELDS, strBody.c_str()); //设置post内容 //curl_easy_setopt(pCurl_, CURLOPT_POST, 1); //设置操作为POST(为非0表示post) curl_easy_setopt(pCurl_, CURLOPT_WRITEFUNCTION, WriteCallBack); //设置回调函数 std::string strResponse; curl_easy_setopt(pCurl_, CURLOPT_WRITEDATA, &strResponse); //设置回调参数 //3. 执行http请求 CURLcode res = curl_easy_perform(pCurl_); curl_slist_free_all(pHeaderList); //清除headerlist curl_mime_free(pMultipart); //清除curl_mime curl_easy_reset(pCurl_); //重置curl if (res != CURLE_OK) { LogError << " curl_easy_perform fail:" << curl_easy_strerror(res); return false; } //4. 执行成功解析响应内容 Json::CharReaderBuilder readerBuilder; std::shared_ptr reader(readerBuilder.newCharReader()); Json::Value jvResponse; JSONCPP_STRING errs; if (!reader->parse(strResponse.data(), strResponse.data() + strResponse.size(), &jvResponse, &errs)) { LogError << " response content fail " << strResponse; return false; } LogDebug << "GetToken resp:" << strResponse; strBladeAuth += jvResponse["token_type"].asString(); strBladeAuth += " "; strBladeAuth += jvResponse["access_token"].asString(); return true; } /** * 列车信息提交http接口 * inParam : Json::Value &jvRequest 提交内容 * outParam: * return : true:提交成功; false:提交失败 */ bool ResultToHttpSrvEngine::ResultToHttpSrv(Json::Value &jvRequest) { //获取token std::string strBladeAuth("blade-auth:"); if (!GetToken(strBladeAuth)) { LogError << "comeTime:" << jvRequest["comeTime"].asString() << " carriageOrder:" << jvRequest["carriageOrder"].asInt() << " GetToken fail "; return false; } LogDebug << "strBladeAuth:" << strBladeAuth; //1. 获得curl操作符 if (nullptr == pCurl_) { LogDebug<<"pCurl_ is null, invoke curl_easy_init"; pCurl_ = curl_easy_init(); if (nullptr == pCurl_) { LogError << "curl_easy_init failed !"; return false; } } //2. 设置http请求信息 Json::StreamWriterBuilder jswBuilder; std::string strRequest = Json::writeString(jswBuilder, jvRequest); LogDebug << "to http:" << strRequest; std::string strResponse; struct curl_slist *pHeaderList = nullptr; pHeaderList = curl_slist_append(pHeaderList, "Accept:application/json"); pHeaderList = curl_slist_append(pHeaderList, "Content-Type:application/json"); pHeaderList = curl_slist_append(pHeaderList, "charset:utf-8"); pHeaderList = curl_slist_append(pHeaderList, strBladeAuth.c_str()); curl_easy_setopt(pCurl_, CURLOPT_CONNECTTIMEOUT, 1); //连接超时(1s连接不上服务器返回超时) curl_easy_setopt(pCurl_, CURLOPT_TIMEOUT, 1); // 设置超时时间为1秒 curl_easy_setopt(pCurl_, CURLOPT_URL, strURL_.c_str()); //设置url curl_easy_setopt(pCurl_, CURLOPT_HTTPHEADER, pHeaderList); //设置报文头 curl_easy_setopt(pCurl_, CURLOPT_POSTFIELDS, strRequest.c_str()); //设置post内容 curl_easy_setopt(pCurl_, CURLOPT_POST, 1); //设置操作为POST(为非0表示post) curl_easy_setopt(pCurl_, CURLOPT_WRITEFUNCTION, WriteCallBack); //设置回调函数 curl_easy_setopt(pCurl_, CURLOPT_WRITEDATA, &strResponse); //设置回调参数 //3. 执行http请求 CURLcode res = curl_easy_perform(pCurl_); curl_slist_free_all(pHeaderList); //清除headerlist curl_easy_reset(pCurl_); //重置curl if (res != CURLE_OK) { LogError << "comeTime:" << jvRequest["comeTime"].asString() << " 车节号:" << jvRequest["carriageOrder"].asInt() << " 识别结果上传失败:" << curl_easy_strerror(res); return false; } //4. 执行成功解析响应内容 LogInfo << "http resp:" << strResponse; Json::CharReaderBuilder readerBuilder; std::shared_ptr reader(readerBuilder.newCharReader()); Json::Value jvResponse; JSONCPP_STRING errs; if (!reader->parse(strResponse.data(), strResponse.data() + strResponse.size(), &jvResponse, &errs)) { LogError << "comeTime:" << jvRequest["comeTime"].asString() << " carriageOrder:" << jvRequest["carriageOrder"].asInt() << " response content fail " << strResponse; return false; } if (!jvResponse["success"].asBool()) { LogError << "comeTime:" << jvRequest["comeTime"].asString() << " carriageOrder:" << jvRequest["carriageOrder"].asInt() << " response fail"; return false; } LogInfo << "comeTime:" << jvRequest["comeTime"].asString() << " carriageOrder:" << jvRequest["carriageOrder"].asInt() << " post success"; return true; } /** * 处理上传失败的信息 * inParam : N/A * outParam: N/A * return : N/A */ void ResultToHttpSrvEngine::DealHttpFailInfo() { //队列有待处理数据,则先不处理异常数据。 if (inputQueMap_[strPort0_]->getSize() > 0) { LogDebug << "have new data to process"; return; } //文件不存在不处理 if (access(strFailSavePath_.c_str(), F_OK) == -1) { LogDebug << "no exit file:" << strFailSavePath_; return; } bool bAllSucc = true; std::ifstream inFile(strFailSavePath_.c_str(), std::ios::in); if (!inFile.is_open()) { LogError << strFailSavePath_ << " open fail"; return; } int iDealCnt = 0; std::string strLine; while (getline(inFile, strLine)) { Json::CharReaderBuilder jsrBuilder; std::shared_ptr reader(jsrBuilder.newCharReader()); Json::Value jvRequest; JSONCPP_STRING errs; if (!reader->parse(strLine.data(), strLine.data() + strLine.size(), &jvRequest, &errs)) { LogError << "json parse fail content:" << strLine; return; } /* 新数据到达后,异常数据还未开始处理,则直接关闭文件返回。先处理正常数据。 新数据到达后,异常数据处理中,则把异常未处理的数据全部当处理失败写入新文件中。先处理正常数据。 */ if (inputQueMap_[strPort0_]->getSize() > 0) { LogDebug << "Abnormal data processing, have new data to process"; if (0 == iDealCnt) { LogDebug << "Abnormal data processing not start"; inFile.close(); return; } SaveHttpFailInfo(jvRequest, strFailSaveBakPath_); bAllSucc = false; continue; } iDealCnt++; if (!ResultToHttpSrv(jvRequest)) { LogError << "re http post err:" << strLine; //SaveHttpFailInfo(jvRequest, strFailSaveBakPath_); // bAllSucc = false; continue; } } inFile.close(); if(bAllSucc) { //都处理成功,文件删除 remove(strFailSavePath_.c_str()); } else { //部分处理成功,重命名后再次被处理 rename(strFailSaveBakPath_.c_str(), strFailSavePath_.c_str()); } } /** * 保存http上传失败的信息 * inParam : Json::Value &jvRequest http失败信息 * : std::string &strFilePath 保存路径 * outParam: N/A * return : true(成功);false(失败) */ bool ResultToHttpSrvEngine::SaveHttpFailInfo(Json::Value &jvRequest, std::string &strFilePath) { std::ofstream outFile; outFile.open(strFilePath, std::ios::app); if (!outFile.is_open()) { LogError << strFilePath << " open fail"; return false; } Json::StreamWriterBuilder jswBuilder; jswBuilder["indentation"] = ""; std::string strRequest = Json::writeString(jswBuilder, jvRequest); outFile << strRequest << std::endl; outFile.close(); return true; } APP_ERROR ResultToHttpSrvEngine::Process() { int iRet = APP_ERR_OK; if (0 == MyYaml::GetIns()->GetIntValue("gc_http_open")) { LogDebug << " gc_http_open value is 0"; return APP_ERR_OK; } while (!isStop_) { std::shared_ptr pVoidData0 = nullptr; inputQueMap_[strPort0_]->pop(pVoidData0); if (nullptr == pVoidData0) { usleep(1000); //1ms //无数据大于1分钟 iNoDataCnt_++; if (iNoDataCnt_ > (60 * 1000)) { DealHttpFailInfo(); iNoDataCnt_ = 0; } continue; } iNoDataCnt_ = 0; std::shared_ptr pTrain = std::static_pointer_cast(pVoidData0); ai_matrix::DataSourceConfig dataSourceConfig = MyYaml::GetIns()->GetDataSourceConfigById(pTrain->trainNum.iDataSource); //获取摄像机参数 char szCameraNo[4] = {0}; sprintf(szCameraNo, "%03d", pTrain->trainNum.iDataSource + 1); char szNumImgPath[64] = {0}; //车号最优图片路径 if (!pTrain->trainNum.strBestImg.empty()) { sprintf(szNumImgPath, "/%03d/%s", pTrain->trainNum.iDataSource + 1, pTrain->trainNum.strBestImg.c_str()); } char szProImgPath[64] = {0}; //属性最优图片路径 if (!pTrain->trainPro.strBestImg.empty()) { sprintf(szProImgPath, "/%03d/%s", pTrain->trainPro.iDataSource + 1, pTrain->trainPro.strBestImg.c_str()); } // char szChkDateImgPath[64] = {0}; //定检期最优图片路径 // if (!pTrain->chkDate.strBestImg.empty()) // { // sprintf(szChkDateImgPath, "%03d/%s", pTrain->chkDate.iDataSource + 1, pTrain->chkDate.strBestImg.c_str()); // } // char szContainer1ImgPath[64] = {0}; //集装箱1最优图片路径 // if (!pTrain->container1.strBestImg.empty()) // { // sprintf(szContainer1ImgPath, "%03d/%s", pTrain->container1.iDataSource + 1, pTrain->container1.strBestImg.c_str()); // } // char szContainer2ImgPath[64] = {0}; //集装箱2最优图片路径 // if (!pTrain->container2.strBestImg.empty()) // { // sprintf(szContainer2ImgPath, "%03d/%s", pTrain->container2.iDataSource + 1, pTrain->container2.strBestImg.c_str()); // } std::string strTime = pTrain->strTrainName; strTime = MyUtils::getins()->replace_all_distinct(strTime, std::string("-"), std::string(":")); int iCategory = 0; if (pTrain->trainNum.iTrainTypeId == 3) { iCategory = 0; } else if(pTrain->trainNum.iTrainTypeId == 2) { iCategory = 1; } else if (pTrain->trainNum.iTrainTypeId == 6) { iCategory = 2; } else if (pTrain->trainNum.iTrainTypeId == 0) { iCategory = 3; } //组装post信息 Json::Value jvRequest; Json::Value jvSubObj; jvSubObj["poundNo"] = strPoundNo_; // 股道号 jvRequest["trainParams"] = jvSubObj; jvRequest["carriageType"] = pTrain->trainNum.strTrainType; // 车型 jvRequest["carriageNumber"] = pTrain->trainNum.strTrainNum; // 车厢号 jvRequest["carriageOrder"] = pTrain->iCarXH; // 车节号 jvRequest["cameraNumber"] = szCameraNo; // 摄像头编号 jvRequest["carriageTareweight"] = pTrain->trainPro.strSelf; // 皮重 jvRequest["carriageLoad"] = pTrain->trainPro.strLoad; // 载重 jvRequest["carriageVolume"] = pTrain->trainPro.strVolume; // 容积 jvRequest["carriageChangelength"] = pTrain->trainPro.strChange; // 换长 jvRequest["proImageName"] = strImageSrv_ + pTrain->strTrainDate + "/" + pTrain->strTrainName + szProImgPath; // 属性图片 jvRequest["numImageName"] = strImageSrv_ + pTrain->strTrainDate + "/" + pTrain->strTrainName + szNumImgPath; // 车号图片 jvRequest["comeTime"] = pTrain->strTrainDate + " " + strTime; // 来车时间 jvRequest["carriageCategory"] = iCategory; // 车厢类别:0敞车,1:漏洞矿车,2:平车,3:车头 jvRequest["isTheLast"] = pTrain->bIsEnd ? 1 : 0; // 是否最后一节: 0:否,1:是 jvRequest["startFrame"] = pTrain->iStartFrameId; //车厢开始帧 jvRequest["endFrame"] = pTrain->iEndFrameId; //车厢结束帧 jvRequest["skipFrame"] = dataSourceConfig.iSkipInterval; jvRequest["collectTime"] = MyUtils::getins()->Stamp2Time(pTrain->i64EndTimeStamp, true);//车厢切分的时间 //跳帧 if (!ResultToHttpSrv(jvRequest)) { // SaveHttpFailInfo(jvRequest, strFailSavePath_); } //列车结束后再次处理失败的信息 if (pTrain->bIsEnd) { DealHttpFailInfo(); } } return APP_ERR_OK; }