/*
 * @Author: your name
 * @Date: 2023-07-20 17:15:33
 * @LastEditors: your name
 * @LastEditTime: 2023-07-23 20:09:39
 * @Description: file content
 * @FilePath: /shigetai_lirs/nvidia_ascend_engine/common_engine/DataUploadEngine/DeviceStatusUpSerEngine.cpp
 * 
 * Copyright © 2022 <Shandong Matrix Software Engineering Co., Ltd>
 */
#include "DeviceStatusUpSerEngine.h"
#include "myutils.h"


DeviceStatusUpSerEngine::DeviceStatusUpSerEngine() {}
DeviceStatusUpSerEngine::~DeviceStatusUpSerEngine() {}

APP_ERROR DeviceStatusUpSerEngine::Init()
{
    strPort0_ = engineName_ + "_" + std::to_string(engineId_) + "_0";
    strGetTokenURL_ = MyYaml::GetIns()->GetStringValue("gc_gettoken_url");
    strURL_ = MyYaml::GetIns()->GetStringValue("gc_device_status_url");
    strPoundNo_ = MyYaml::GetIns()->GetStringValue("atlas_poundno");
    LogInfo << "DeviceStatusUpSerEngine Init ok";
    return APP_ERR_OK;
}

APP_ERROR DeviceStatusUpSerEngine::DeInit()
{
    LogDebug << "curl_easy_cleanup";
    curl_easy_cleanup(pCurl_);

    /*  这个处理移动到main中， 防止多线程调用
    LogDebug << "内存清理";
    curl_global_cleanup();
    */
    LogInfo << "DeviceStatusUpSerEngine DeInit ok";
    return APP_ERR_OK;
}

/**
* libcurl回调函数
* inParam : void *pBuffer   回调内容地址
          : size_t size     回调单个数据大小
          : size_t nmemb    回调数据个数               
* outParam: std::string &strResp    返回内容
* return  : 回调数据大小
*/
size_t DeviceStatusUpSerEngine::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 DeviceStatusUpSerEngine::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, "guest_01", CURL_ZERO_TERMINATED);
    pPart = curl_mime_addpart(pMultipart);
    curl_mime_name(pPart, "password");
    curl_mime_data(pPart, "d55b0f642e817eea24725d2f2a31dd08", 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 DeviceStatusUpSerEngine::ResultToHttpSrv(Json::Value &jvRequest)
{
    //获取token
    std::string strBladeAuth("blade-auth:");
    if (!GetToken(strBladeAuth))
    {
        LogError << " 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 << jvRequest.toStyledString()
                 << " curl_easy_perform fail:" << curl_easy_strerror(res);
        return false;
    }

    //4. 执行成功解析响应内容
    LogDebug << "设备异常上传结果:" << 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 << jvRequest.toStyledString()
                 << " response content fail " << strResponse;
        return false;
    }

    if (!jvResponse["success"].asBool())
    {
        LogError << jvRequest.toStyledString()
                 << " response fail:" << strResponse;
        return false;
    }

    LogInfo << jvRequest.toStyledString()
            << " post success";
    return true;
}


APP_ERROR DeviceStatusUpSerEngine::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))
            {
                iNoDataCnt_ = 0;
            }
            continue;
        }
        iNoDataCnt_ = 0;

        std::shared_ptr<std::string> pWarn = std::static_pointer_cast<std::string>(pVoidData0);

        ai_matrix::DataSourceConfig dataSourceConfig = MyYaml::GetIns()->GetDataSourceConfigById(0); //获取摄像机参数

        //组装post信息
        Json::Value jvRequest;
        jvRequest["tainsModule"] = "2"; // 传输模块:0=装车模块,1=超偏载模块,2=车号识别模块,3=web 模块
        jvRequest["networkStatus"] = "异常"; //网络状态: 正常/异常
        jvRequest["devName"] = "摄像头";// 设备名称
        jvRequest["devSn"] = strPoundNo_+"股道";// 设备编码
        jvRequest["cpuData"] = "";// CPU 情况
        jvRequest["memoryUsage"] = "";// 内存使用情况
        jvRequest["devRunningStatus"] = "异常";// 设备运行状态：正常/异常
        jvRequest["devCheckResult"] = *pWarn;// 检测结果
        jvRequest["devIp"] = dataSourceConfig.strUrl;// 设备 IP
        jvRequest["devAccount"] = "";// 设备账号
        if (!ResultToHttpSrv(jvRequest))
        {
            LogError << "摄像头异常状态上传服务器失败！";
        }
    }
    return APP_ERR_OK;
}
