446 lines
17 KiB
C++
446 lines
17 KiB
C++
#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<Json::CharReader> 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_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() << " carriageOrder:" << jvRequest["carriageOrder"].asInt()
|
||
<< " curl_easy_perform fail:" << curl_easy_strerror(res);
|
||
return false;
|
||
}
|
||
|
||
//4. 执行成功解析响应内容
|
||
LogInfo << "http resp:" << strResponse;
|
||
Json::CharReaderBuilder readerBuilder;
|
||
std::shared_ptr<Json::CharReader> 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<Json::CharReader> 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<void> 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<Train> pTrain = std::static_pointer_cast<Train>(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;
|
||
}
|