/**
* @file:    $RCSfile: save2json.cpp,v $
* @brief:   $IEC 61850 Protocol
*
* @version: $Revision: 1.21 $
* @date:    $Date: 2020/10/27 08:51:07 $
* @author:  $Author: lizhongming $
* @state:   $State: Exp $
*
* @latest:  $Id: save2json.cpp,v 1.21 2020/10/27 08:51:07 lizhongming Exp $
*
*/

using namespace std;
#include <iostream>
#include <stdio.h>
#include <assert.h>
#include <fstream>      // std::filebuf
#include <string.h>

#include <sstream>

#include "qdebug.h"
#include <QSettings>
#include <QDateTime>
#include <QDir>
#include <QMap>//CZY 2023-08-17 WW 2023年3月13日17:21:02 增加多ICD支持
#include <apr_uuid.h>  
#include <apr_strings.h>

#include "../log4cplus/log4.h"//lnk添加log4

#include "../mms/db_interface.h"
#include "../json/save2json.h" 
#include "../json/mms_json_inter.h"
#include "kafka_producer.h" 
//#include "../rocketmq/CPushConsumer.h"
#include "../rocketmq/DefaultMQPushConsumer.h"
#include <vector>
#include "../json/cjson.h" //解json
#include <sstream>	//创建xml
#include <fstream>  //创建xml
bool createXmlFile(int devindex, int mpindex, bool realData, bool soeData, int limit,std::string type);
extern int recall_json_handle(const char* jstr);
extern std::string intToString(int number);
int StringToInt(const std::string& str);
extern pthread_mutex_t mtx;//lnk20250115

extern bool should_process_after_start(const rocketmq::MQMessageExt& msg);
extern int64_t G_APP_START_MS;

extern int RECALL_ONLY_FLAG; //lnk20260309添加一个全局变量，标志是否只运行补招程序



extern void SendFileWeb(const std::string& strUrl,
                        const char* localpath,
                        const char* cloudpath,
                        char* wavepath,
						int type);

extern int DownloadFileWeb(const std::string& strUrl,
                           const char* remotePath,
                           const char* localpath);



#ifdef __cplusplus
extern "C" {

//解决编译lnk20250509
#define thisFileName __FILE__

#include "../mms/rdb_client.h"
#include "node.h"//lnk20241223
#include "mvl_defs.h"
#include "mms_vvar.h"
#endif /* __cplusplus */
	extern unsigned int	g_node_id;
	extern int          g_front_seg_index;
	extern char			subdir[128];
	extern int			comtrade_remain_file_num;
	extern node_t* g_node; //lnk20241223
	extern LD_info_t* find_LD_info_only_from_mp_id(char* mp_id);//lnk20241223
	extern void print_terminal(const terminal* tmnl);

	extern ST_RET mms_mvla_obtfile(MVL_NET_INFO  *net_info,
                               ST_CHAR *srcfilename,
                               ST_CHAR *destfilename,
                               int iTimeout);

	extern ST_RET mms_mvla_fdelete (MVL_NET_INFO  *net_info,ST_CHAR *file_to_delete,int iTimeout);

	extern ST_RET write_common_oper(chnl_usr_t *chnl_usr,
                         ST_CHAR *domName,
                         const char *ctlName,
                         ST_INT oper_type_id,
                         ST_INT timeOut);
	extern ST_RET write_mod_stval(chnl_usr_t *chnl_usr,
                       ST_CHAR *domName,
                       ST_INT timeOut);

	extern ST_RET mms_conclude_disconnect(MVL_NET_INFO *net_info, ST_INT timeOut);

	extern int BuildResetDomName(ied_usr_t *ied_usr, char *domName, size_t domNameSize);

	extern pt61850app_t *g_pt61850app;

	extern RPT_TYPEIDS g_rpt_typeids;
#ifdef __cplusplus
}
#endif
#ifndef nullptr
#define nullptr NULL
#endif

extern uint32_t	g_mqproducer_blocked_times;

extern int INITFLAG;

extern std::string FRONT_INST;

extern QMutex kafka_data_list_mutex;
extern QList<Ckafka_data_t> kafka_data_list;

extern QMutex oss_data_list_mutex;
extern QList<oss_data_t> oss_data_list;
extern int FILE_FLAG;
KafkaSendThread myThrd;
//WW 2023-08-22 增加数据库线程和WebSokcet线程
WebSocketThread socketThrd; //Web Socket线程类对象

WebhttpThread webhttpThrd; //Web http线程类对象 lnk202411
httpThread httpThrd; //Web http线程类对象  lnk202411
mqconsumerThread mqconsumerThrd;//mq消费者线程lnk20241213

OnTimerThread onTimerThrd;//定时线程

extern int FILE_FLAG;
extern int SEND_FLAG;
extern char* BROKER_LIST;
extern char* TOPIC_STAT;
extern char* TOPIC_PST;
extern char* TOPIC_PLT;
extern char* TOPIC_EVENT;
extern char* TOPIC_ALARM;
extern char* TOPIC_SNG;
extern char* TOPIC_RTDATA;//lnk20241220
extern char* UDS_UPLOAD_URL;
extern char				g_onlyIP[255];			//直连某个IP，仅仅为方便测试
//WW 2023-08-22 end

//lnk20241216添加mq消费者
extern std::string G_MQCONSUMER_IPPORT;//rocketmq ip+port
extern std::string G_MQCONSUMER_TOPIC_RT;//topie_realtimedata
extern std::string G_MQCONSUMER_TAG_RT;//tag
extern std::string G_MQCONSUMER_KEY_RT;//key
extern std::string G_MQCONSUMER_TOPIC_UD;//topie_update
extern std::string G_MQCONSUMER_TAG_UD;//tag
extern std::string G_MQCONSUMER_KEY_UD;//key
extern std::string G_MQCONSUMER_TOPIC_RC;//topie_recall
extern std::string G_MQCONSUMER_TAG_RC;//tag
extern std::string G_MQCONSUMER_KEY_RC;//key
extern std::string G_MQCONSUMER_TOPIC_SET;//topie_recall
extern std::string G_MQCONSUMER_TAG_SET;//tag
extern std::string G_MQCONSUMER_KEY_SET;//key
extern std::string G_MQCONSUMER_TOPIC_LOG;//topie_log
extern std::string G_MQCONSUMER_TAG_LOG;//tag
extern std::string G_MQCONSUMER_KEY_LOG;//key
extern std::string G_LOG_TOPIC;//topie
extern std::string G_LOG_TAG;//tag
extern std::string G_LOG_KEY;//key
extern std::string G_MQCONSUMER_TOPIC_FILE;//topie_file
extern std::string G_MQCONSUMER_TAG_FILE;//tag
extern std::string G_MQCONSUMER_KEY_FILE;//key
extern std::string G_REPLY_TOPIC_FILE;//topie_file
extern std::string G_REPLY_TAG_FILE;//tag
extern std::string G_REPLY_KEY_FILE;//key
extern std::string Topic_Reply_Topic;
extern std::string Topic_Reply_Tag;
extern std::string Topic_Reply_Key;

extern std::string WEB_FILEUPLOAD;
extern std::string WEB_FILEDOWNLOAD;

extern std::string G_ROCKETMQ_CONSUMER;

bool showinshellflag =false;


#define APRTIME_8H  (28800000000ULL)
#define APRTIME_1H  (3600000000ULL)
///////////////////////////////////////////////////////////////////////////////

const int MAX_LIST_SIZE = 16;
//static QMap<int, QList<long long> > real_data_report_map;
static QMap<int, QMap<int, QList<long long>>> real_data_report_map;	//多个监测点的多个实时报告的时间列表lnk20250624
static QMap<QString, json_block_data*> json_data_map;//CZY 2023-08-17 ww 2023年3月13日17:23:17扩展Map，用于保存各条线路的数据
static QMap<QString, json_block_data*> json_flicker_data_map;//CZY 2023-09-11 展Map，用于保存各条线路的闪变数据
static QMap<QString, json_block_data*> json_pst_data_map;//CZY 2023-09-11 展Map，用于保存各条线路的闪变数据
static QMap<QString, json_block_data*> json_trace_data_map;

//////////////////////////////////////////////////////////////////////////////lnk20260310文件控制
pthread_mutex_t g_file_req_mutex = PTHREAD_MUTEX_INITIALIZER;
std::list<file_dir_req_t*> g_file_dir_req_list;

bool is_blank(const std::string& str)
{
    for (std::string::const_iterator it = str.begin(); it != str.end(); ++it)
    {
        if (!std::isspace(*it)) {
            return false;
        }
    }
    return true;
}

///////////////////////////////////////////////////////////////////////////////////

int	urcbRealDataHasReceived(int dev_index, int rptNo, LD_info_t* LD_info, long long Time)	//增加报告入参lnk20250624
{
	QList<long long>& ts_list = real_data_report_map[LD_info->line_id][rptNo];
	bool bFind = ts_list.contains(Time); //实时数据时间链表
	if (bFind == false) {
		ts_list.append(Time);
		if (ts_list.size() > MAX_LIST_SIZE)
			ts_list.removeFirst();

		//lnk20241223每收到一次实时数据就检查一下数量
		int real_report_count = 0;
		//real_report_count = get_real_report_count(LD_info);
		real_report_count = LD_info->rptinfo[rptNo]->count;//lnk20250624

		//调试
		std::cout << "real_report_count is" << real_report_count << std::endl;
		std::cout << "mp limit is" << LD_info->limit << std::endl;

		if(real_report_count >= LD_info->limit){
			std::cout << "real_report_count reach limit!!!"<< std::endl;
			//生成delete.xml
			if (!createXmlFile(dev_index, LD_info->line_id, 0, 0, 0,"delete")) {
    	    	std::cerr << "Failed to create delete XML file!!!." << std::endl;
    		}
		}

		return 0; //没有重复数据
	}
	else
		return 1; //有重复数据
}

//////////////////////////////////////////////////////////////////////////

void add_comm_log(char* log_str)
{
	QDateTime now = QDateTime::currentDateTime();
	QString level_str = QString("[info]");
	QString head_str = QString("");
	QString tail_str = QString("");
#ifdef  __GNUC__
	QString com_log_fn("/usr/local/saslog/");
#else
	QString com_log_fn("../etc/log/");
#endif	

	if (g_node_id == STAT_DATA_BASE_NODE_ID)
		com_log_fn += "comm_100_stat.txt";
	else if (g_node_id == THREE_SECS_DATA_BASE_NODE_ID)
		com_log_fn += "comm_200_3s.txt";
	else if (g_node_id == SOE_COMTRADE_BASE_NODE_ID)
		com_log_fn += "comm_300_comtrade.txt";
	else if (g_node_id == HIS_DATA_BASE_NODE_ID)
		com_log_fn += "comm_400_his.txt";
	else if (g_node_id == PQDIF_DATA_BASE_NODE_ID)
		com_log_fn += "comm_800_pqdif.txt";
	else if (g_node_id == NEW_HIS_DATA_BASE_NODE_ID) {
		com_log_fn.append(QString("comm_400_his_%1.txt").arg(g_front_seg_index));
	}
	else if(g_node_id == RECALL_HIS_DATA_BASE_NODE_ID)
		com_log_fn += "comm_600_recall.txt";
	else if (g_node_id == RECALL_ALL_DATA_BASE_NODE_ID) {
		com_log_fn.append(QString("comm_700_allrecall_%1.txt").arg(g_front_seg_index));
	}
	else
		com_log_fn += "comm_x00_unknown.txt";

	QFile file(com_log_fn);
	if (!file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Append))
		return;
	QTextStream out(&file);
	out << (now.toString("yyyy-MM-dd hh:mm:ss") + " " + level_str + " " + QString::fromAscii(log_str)) << endl;
}

void add_sng_log(char* log_str)
{
	QDateTime now = QDateTime::currentDateTime();
	QString level_str = QString("[info]");
	QString head_str = QString("");
	QString tail_str = QString("");
#ifdef  __GNUC__
	QString com_log_fn("/usr/local/saslog/");
#else
	QString com_log_fn("../etc/log/");
#endif	

	com_log_fn += "sng_kafka_json.txt";

	QFile file(com_log_fn);
	if (!file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Append))
		return;
	QTextStream out(&file);
	out << (now.toString("yyyy-MM-dd hh:mm:ss") + " " + level_str + " " + QString::fromAscii(log_str)) << endl;
}

void add_stat_kafka_json_log(char* log_str)
{
	QDateTime now = QDateTime::currentDateTime();
	QString level_str = QString("[info]");
	QString head_str = QString("");
	QString tail_str = QString("");
#ifdef  __GNUC__
	QString com_log_fn("/usr/local/saslog/");
#else
	QString com_log_fn("../etc/log/");
#endif	

	com_log_fn += "stat_kafka_json.txt";

	QFile file(com_log_fn);
	if (!file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Append))
		return;
	QTextStream out(&file);
	out << (now.toString("yyyy-MM-dd hh:mm:ss") + " " + level_str + " " + QString::fromAscii(log_str)) << endl;
}

//////////////////////////////////////////////////////////////////////////
/*新增rocketmq发送数据lnk10-10*/
void my_rocketmq_send(Ckafka_data_t& data)
{
	try{
		static std::string topic;
		static std::string cfg_His_tp;
		static std::string cfg_PLT_tp;
		static std::string cfg_PST_tp;
		static std::string cfg_Evt_tp;
		static std::string cfg_Alm_tp;
		static std::string cfg_Rt_tp;
		static bool init = false;
		if (!init) {

			cfg_His_tp = TOPIC_STAT;
			cfg_PLT_tp = TOPIC_PLT;
			cfg_PST_tp = TOPIC_PST;
			cfg_Evt_tp = TOPIC_EVENT;
			cfg_Alm_tp = TOPIC_ALARM;
			cfg_Rt_tp  = TOPIC_RTDATA;

			init = true;
		}

		std::string key = data.mp_id.toStdString();
		std::string senddata = data.strText.toStdString();
		if (data.strTopic == "HISDATA")
		{
			topic = cfg_His_tp;
		}
		else if (data.strTopic == "PLT")
	{
		topic = cfg_PLT_tp;
	}
		else if (data.strTopic == "PST")
	{
		topic = cfg_PST_tp;
	}
		else if (data.strTopic == "Event")
	{
		topic = cfg_Evt_tp;
	}
		else if (data.strTopic == "Alm")
	{
		topic = cfg_Alm_tp;
	}
		else if (data.strTopic == "RTDATA")//lnk20241220
	{
		topic = cfg_Rt_tp;
	}
		else
	{
		topic = data.strTopic.toStdString();
		
	}
		if (g_onlyIP[0] != 0)
		{
			//单例模式
			add_sng_log(data.strText.toAscii().data());

		}
		//rocketmq_producer_send(const_cast<char*>(senddata.c_str()),const_cast<char*>(topic.c_str()));
		rocketmq_producer_send(senddata, topic,FRONT_INST,key);//lnk20250623修复偶发性doublefree
	}
	catch (const std::exception& e)
    {
        std::cout << "[MQ][EXCEPTION] "
                  << e.what()
                  << std::endl;

        DIY_ERRORLOG_CODE("process",0,LOG_CODE_MQ,
            "mq发送异常:%s", e.what());
    }
    catch (...)
    {
        std::cout << "[MQ][UNKNOWN_EXCEPTION]" << std::endl;

        DIY_ERRORLOG_CODE("process",0,LOG_CODE_MQ,
            "mq发送未知异常");
    }
}

#if 0
void my_kafka_send(Ckafka_data_t& data)
{
#ifdef  __GNUC__
	static FeKafkaProducer kafkaProducer;
#endif

	int retsize = -1;
	static std::string topic;
	static std::string cfg_His_tp;
	static std::string cfg_PLT_tp;
	static std::string cfg_PST_tp;
	static std::string cfg_Evt_tp;
	static std::string cfg_Alm_tp;
	static std::string cfg_Sng_tp;
	static bool init = false;
	if (!init) {

		cfg_His_tp = TOPIC_STAT;
		cfg_PLT_tp = TOPIC_PLT;
		cfg_PST_tp = TOPIC_PST;
		cfg_Evt_tp = TOPIC_EVENT;
		cfg_Alm_tp = TOPIC_ALARM;
		cfg_Sng_tp = TOPIC_SNG;

		cout << cfg_His_tp << endl;

		std::string brokerlist = BROKER_LIST;
	

#ifdef  __GNUC__
		if (kafkaProducer.init(brokerlist)) {
			printf("kafka producer init success(%s)\n", brokerlist.c_str());
			/*bool ret  = kafkaProducer.create_topic(topic);
			if(ret)
				printf("create topic OK \n");
			else
				printf("create topic Failed \n");*/
		}
		else
			printf("kafka producer init Failed(%s)\n", brokerlist.c_str());
#endif 
		init = true;
	}

	char tmp_str[256];
	apr_snprintf(tmp_str, sizeof(tmp_str), "%d", data.monitor_id);
	std::string key = std::string(tmp_str);

	std::string senddata = data.strText.toStdString();
	if (data.strTopic == "HISDATA")
	{
		topic = cfg_His_tp;
	}
	else if (data.strTopic == "PLT")
	{
		topic = cfg_PLT_tp;
	}
	else if (data.strTopic == "PST")
	{
		topic = cfg_PST_tp;
	}
	else if (data.strTopic == "Event")
	{
		topic = cfg_Evt_tp;
		add_stat_kafka_json_log(data.strText.toAscii().data());
	}
	else if (data.strTopic == "Alm")
	{
		topic = cfg_Alm_tp;
	}
	else
	{
		topic = data.strTopic.toStdString();
	}

	if (g_onlyIP[0] != 0)
	{
		add_sng_log(data.strText.toAscii().data());
	}
#ifdef  __GNUC__
	retsize = kafkaProducer.send(senddata.c_str(), senddata.length(), topic, RdKafka::Topic::PARTITION_UA, &key);
#endif

	if (retsize > 0) {
		printf("\nkafka send, monitor_id:[%s] topic:[%s] Success,return length %d\n", key.c_str(), topic.c_str(), retsize);
	}
	else
		printf("\nFailed kafka send, monitor_id:[%s] topic:[%s]\n", key.c_str(), topic.c_str());

}
#endif

void my_datahub_send(Ckafka_data_t& data)
{
	static std::string topic;
	static std::string cfg_His_tp;
	static std::string cfg_PLT_tp;
	static std::string cfg_PST_tp;
	static std::string cfg_Evt_tp;
	static std::string cfg_Alm_tp;
	static bool init = false;
	if (!init) {

		cfg_His_tp = TOPIC_STAT;
		cfg_PLT_tp = TOPIC_PLT;
		cfg_PST_tp = TOPIC_PST;
		cfg_Evt_tp = TOPIC_EVENT;
		cfg_Alm_tp = TOPIC_ALARM;

		init = true;
	}

	std::string key = data.mp_id.toStdString();
	std::string senddata = data.strText.toStdString();
	if (data.strTopic == "HISDATA")
	{
		topic = cfg_His_tp;
	}
	else if (data.strTopic == "PLT")
	{
		topic = cfg_PLT_tp;
	}
	else if (data.strTopic == "PST")
	{
		topic = cfg_PST_tp;
	}
	else if (data.strTopic == "Event")
	{
		topic = cfg_Evt_tp;
	}
	else if (data.strTopic == "Alm")
	{
		topic = cfg_Alm_tp;
	}
	else
	{
		topic = data.strTopic.toStdString();
	}
	if (g_onlyIP[0] != 0)
	{
		//单例模式
		add_sng_log(data.strText.toAscii().data());

	}
	//DataHub_Send_Datahub(const_cast<char*>(topic.c_str()), const_cast<char*>(senddata.c_str()));
	printf("\ndatahub send, monitor_id:[%s] topic:[%s] Success\n", key.c_str(), topic.c_str());
}

void concatenate_and_separate(char str1[], char str2[], QString* result) {
	QString qstr1 = QString(str1);
	QString qstr2 = QString(str2);
	*result = qstr1 + "-" + qstr2;
}

void KafkaSendThread::run()
{
	//线程开始创建生产者lnk20241211
	InitializeProducer();

	printf("\nKafkaSendThread::run() is called ...... \n\n");
	while (1) {
		Ckafka_data_t data;
		bool data_gotten;

		data_gotten = false;
		kafka_data_list_mutex.lock();
		if (!kafka_data_list.isEmpty()) {
			data_gotten = true;
			data = kafka_data_list.takeFirst();
		}
		kafka_data_list_mutex.unlock();

		if (data_gotten) {
			static uint32_t count = 0;
			printf("BEGIN my_kafka_send no.%i -------->>>>>>>>>>>> %s \n", count,
				QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz").toAscii().data());
			if (SEND_FLAG == 1) //kafka推送
			{
				//my_kafka_send(data);
			}
			else if (SEND_FLAG == 2)//datahub推送
			{
				//my_datahub_send(data);
			}
			else if (SEND_FLAG == 3)//rocketmq推送lnk10-11
			{
				my_rocketmq_send(data);
			}
			else //未配置 默认mq推送
			{
				my_rocketmq_send(data);
			}

			printf("END   my_kafka_send no.%i -------->>>>>>>>>>>> %s \n\n", count++,
				QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz").toAscii().data());
		}

		//清空计数器
		g_mqproducer_blocked_times =0;

		QThread::msleep(10);  // 避免 CPU 空转lnk20250326

	} 

	
	//线程结束摧毁生产者
	ShutdownAndDestroyProducer();//lnk20241211
}

//lnk20241213补招部分///////////////////////////////////////////////////////////////////////////////////////////////
// 提取 'data' 数组并返回为新的 JSON 字符串 (返回 std::string)
std::string extractDataJson(const char* inputJson) {
    // 解析输入 JSON 字符串
    cJSON* root = cJSON_Parse(inputJson);
    if (root == NULL) {
        std::cerr << "Error parsing JSON" << std::endl;
        return "";
    }

	// 提取 "messageBody" 部分
	cJSON* messageJson = cJSON_GetObjectItem(root, "messageBody");
	if (messageJson == NULL || messageJson->type != cJSON_String) {
	   std::cerr << "'messageJson' is missing or is not an cJSON_String" << std::endl;
	   cJSON_Delete(root);
	   return "";
	}

	// 解析 messageBody 中的 JSON 字符串
	const char* messageBodyStr = messageJson->valuestring;
	if (messageBodyStr == nullptr || strlen(messageBodyStr) == 0) {
		std::cerr << "Failed to parse 'messageBody' JSON or it's empty." << std::endl;
		cJSON_Delete(root);
		return "";
	}

	cJSON* messageBody = cJSON_Parse(messageBodyStr); // 解析 messageBody 字符串
	if (messageBody == NULL) {
	    std::cerr << "Failed to parse 'messageBody' JSON." << std::endl;
	    cJSON_Delete(root);
	    return "";
	}

	//添加guid
	// 提取 "guid" 部分
    cJSON* guidstr = cJSON_GetObjectItem(messageBody, "guid");
    if (guidstr == NULL || guidstr->type != cJSON_String) {
        std::cerr << "'guid' is missing or is not an string" << std::endl;
		cJSON_Delete(messageBody);
        cJSON_Delete(root);
        return "";
    }
	//guid回复
	std::string guid = guidstr->valuestring;
	send_reply_to_kafka(guid,"1","收到补招指令");

    // 提取 "data" 部分
    cJSON* data = cJSON_GetObjectItem(messageBody, "data");
    if (data == NULL || data->type != cJSON_Array) {
        std::cerr << "'data' is missing or is not an array" << std::endl;
		cJSON_Delete(messageBody);
        cJSON_Delete(root);
        return "";
    }

    // 创建新的 JSON 数组对象，只包含 "data" 部分
    cJSON* newJson = cJSON_CreateArray();  // 创建一个新的数组
	if (newJson == NULL) {
	    std::cerr << "Failed to create new JSON array" << std::endl;
	    cJSON_Delete(messageBody);
	    cJSON_Delete(root);
	    return "";
	}

    // 将 "data" 数组中的元素逐个添加到新数组中
    cJSON* dataItem = NULL;
    cJSON_ArrayForEach(dataItem, data) {
        cJSON_AddItemToArray(newJson, cJSON_Duplicate(dataItem, 1));
    }

    // 将新的 JSON 数组转换为字符串
    char* newJsonString = cJSON_Print(newJson);
    if (newJsonString == NULL) {
        std::cerr << "Error printing new JSON" << std::endl;
		cJSON_Delete(messageBody);
        cJSON_Delete(root);
        cJSON_Delete(newJson);
        return "";
    }

    // 转换为 std::string 类型
    std::string result(newJsonString);

    // 清理内存
    free(newJsonString);
	cJSON_Delete(messageBody);
    cJSON_Delete(root);
    cJSON_Delete(newJson);

    return result;  // 返回 std::string 类型的结果
}
//实时数据部分//////////////////////////////////////////////////////////////////////////////////////////////////////////
// 提取 JSON 消息中的相关字段
bool parseJsonMessageRT(const std::string& body, std::string& devSeries, std::string& line, bool& realData, bool& soeData, int& limit)
{
    // 解析 JSON 数据
    cJSON* root = cJSON_Parse(body.c_str());
    if (root == NULL) {
        std::cerr << "Failed to parse JSON message." << std::endl;
        return false;
    }

	// 提取 "messageBody" 部分
	cJSON* messageJson = cJSON_GetObjectItem(root, "messageBody");
	if (messageJson == NULL || messageJson->type != cJSON_String) {
	   std::cerr << "'messageJson' is missing or is not an cJSON_String" << std::endl;
	   cJSON_Delete(root);
	   return false;
	}

	// 解析 messageBody 中的 JSON 字符串
	const char* messageBodyStr = messageJson->valuestring;
	if (messageBodyStr == nullptr || strlen(messageBodyStr) == 0) {
		std::cerr << "Failed to parse 'messageBody' JSON or it's empty." << std::endl;
		cJSON_Delete(root);
		return false;
	}

	cJSON* messageBody = cJSON_Parse(messageBodyStr); // 解析 messageBody 字符串
	if (messageBody == NULL) {
	    std::cerr << "Failed to parse 'messageBody' JSON." << std::endl;
	    cJSON_Delete(root);
	    return false;
	}

    // 提取字段
    cJSON* devSeriesItem = cJSON_GetObjectItem(messageBody, "devSeries");
    cJSON* lineItem = cJSON_GetObjectItem(messageBody, "line");
    cJSON* realDataItem = cJSON_GetObjectItem(messageBody, "realData");
    cJSON* soeDataItem = cJSON_GetObjectItem(messageBody, "soeData");
    cJSON* limitItem = cJSON_GetObjectItem(messageBody, "limit");

	//添加guid
	std::string guid;
	cJSON* guidstr = cJSON_GetObjectItem(messageBody, "guid");
	if(guidstr)guid = guidstr->valuestring;

    if (devSeriesItem && lineItem && realDataItem && soeDataItem && limitItem) {
        devSeries = devSeriesItem->valuestring;
        line = lineItem->valuestring;
        realData = realDataItem->valueint;
        soeData = soeDataItem->valueint;
        limit = limitItem->valueint;

		//回复消息
		//执行结果直接看实时数据，不需要再回复，1是收到消息
		send_reply_to_kafka("11111","1","收到三秒数据指令");//实时数据没有下发guid

    } else {
        std::cerr << "Missing expected fields in JSON message." << std::endl;
		cJSON_Delete(messageBody);
        cJSON_Delete(root);
        return false;
    }

	cJSON_Delete(messageBody);
    cJSON_Delete(root);  // 清理 JSON 对象
    return true;
}

// 构造 XML 内容的函数新建和删除
std::string createnewXmlContent(int devindex, int mpindex, bool realData, bool soeData, int limit)
{
    std::ostringstream xmlContent;
    xmlContent << "<?xml version=\"1.0\" encoding=\"gb2312\"?>\n"
               << "<Trigger3S>\n"
               << "    <New>\n"
               << "        <Trigger Line=\"" << mpindex << "\" "
               << "RealData=\"" << (realData ? "true" : "false") << "\" "
               << "DevSeries=\"" << devindex << "\" "
               << "Limit=\"" << limit << "\" "
               << "Count=\"0\" "
               << "SOEData=\"" << (soeData ? "true" : "false") << "\"/>\n"
               << "    </New>\n"
               << "</Trigger3S>\n";
    return xmlContent.str();
}

std::string createdeleteXmlContent(int devindex, int mpindex)
{
    std::ostringstream xmlContent;
    xmlContent << "<?xml version=\"1.0\" encoding=\"gb2312\"?>\n"
               << "<Trigger3S>\n"
               << "    <Delete>\n"
               << "        <Trigger Line=\"" << mpindex << "\" "
               << "RealData=\"false\" "
               << "DevSeries=\"" << devindex << "\" "
               << "Limit=\"0\" "
               << "Count=\"0\" "
               << "SOEData=\"false\"/>\n"
               << "    </Delete>\n"
               << "</Trigger3S>\n";
    return xmlContent.str();
}

// 写入 XML 内容到文件的函数
bool writeToFile(const std::string& filePath, const std::string& xmlContent)
{
    // 打开文件流以写入 XML 内容
    std::ofstream outFile(filePath.c_str());  // 使用 c_str() 转换为 const char*
    if (outFile.is_open()) {
        outFile << xmlContent;  // 写入内容
        outFile.close();
        std::cout << "XML file created at: " << filePath << std::endl;
        return true;
    } else {
        std::cerr << "Failed to open file for writing: " << filePath << std::endl;
        return false;
    }
}

// 创建并写入新的 XML 文件的主函数
bool createXmlFile(int devindex, int mpindex, bool realData, bool soeData, int limit,std::string type)
{
	std::string xmlContent = "";
	std::string directory = "";
	std::string filePath = "";

	if(type == "new"){
		// 构造 XML 内容
    	xmlContent = createnewXmlContent(devindex, mpindex, realData, soeData, limit);

    	// 设置文件路径
    	directory = "../etc/trigger3s/";
    	filePath = directory + "newtrigger.xml";
	}
	else if(type == "delete"){
		// 构造 XML 内容
    	xmlContent = createdeleteXmlContent(devindex, mpindex);

    	// 设置文件路径
    	directory = "../etc/trigger3s/";
    	filePath = directory + "deletetrigger.xml";
	}
	else{
		std::cerr << "Failed to create xmlfile,type error: " << std::endl;
        return false;
	}
    

    // 创建目录（如果不存在）
    if (system(("mkdir -p " + directory).c_str()) != 0) {
        std::cerr << "Failed to create directory: " << directory << std::endl;
        return false;
    }

    // 将 XML 内容写入文件
    return writeToFile(filePath, xmlContent);
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////
//lnk20250108进程更新部分

// 用于关闭进程监听的端口
extern int server_socket; //Web Socket服务端实例
void close_listening_socket() {
    if (server_socket != -1) {
        // 关闭socket
        close(server_socket);
        std::cout << "Server socket closed successfully!" << std::endl;
        server_socket = -1;  // 重置 server_socket
    } else {
        std::cout << "No server socket to close!" << std::endl;
    }
}

//用于校验ip格式
bool isValidIP(const std::string &ip) {
    std::vector<std::string> parts;
    std::stringstream ss(ip);
    std::string part;
    
    // 使用 "." 作为分隔符将 IP 地址分割成各部分
    while (getline(ss, part, '.')) {
        parts.push_back(part);
    }

    // IP 地址必须有 4 部分
    if (parts.size() != 4) {
        return false;
    }

    // 校验每一部分是否为合法的数字且在 0 到 255 之间
    for (size_t i = 0; i < parts.size(); ++i) {
        // 校验每部分是否为数字
        for (size_t j = 0; j < parts[i].size(); ++j) {
            if (!isdigit(parts[i][j])) {
                return false;
            }
        }
        
        // 转换为整数并检查是否在有效范围内
        int num = atoi(parts[i].c_str());
        if (num < 0 || num > 255) {
            return false;
        }

        // 检查是否有前导零（如 01、001 等）
        if (parts[i].length() > 1 && parts[i][0] == '0') {
            return false;
        }
    }

    return true;
}

//执行脚本控制进程
void execute_bash(string fun,int process_num,string type)
{
	// 为 char 数组分配足够的空间
    char p_num_str[20];     
    // 使用 sprintf 转换
    std::sprintf(p_num_str, "%d", process_num);
	const char* script = "/FeProject/bin/set_process.sh";//使用setsid防止端口占用
    const char* param1 = fun.c_str();
    const char* param2 = p_num_str;
	const char* param3 = type.c_str();
    
    // 构造完整的命令
    char command[256];
    snprintf(command, sizeof(command), "%s %s %s %s &", script, param1, param2, param3);

	std::cout << "command:" << command <<std::endl;
    
    // 执行命令
    system(command);
}

//执行脚本控制进程
void execute_bash_debug(string fun,string ip,string type,int proindex)
{

	const char* script = "/FeProject/bin/set_debug.sh";//使用setsid防止端口占用
    const char* param1 = fun.c_str();
    const char* param2 = ip.c_str();
	const char* param3 = type.c_str();

	// 将 proindex 转换为字符串
    char param4[32];
    snprintf(param4, sizeof(param4), "%d", proindex);
    
    // 构造完整的命令
    char command[256];
    snprintf(command, sizeof(command), "%s %s %s %s %s &", script, param1, param2, param3,param4);

	std::cout << "command:" << command <<std::endl;
    
    // 执行命令
    system(command);
}

int parse_set(const std::string& json_str) {
    // 解析 JSON 字符串
    cJSON* root = cJSON_Parse(json_str.c_str());
    if (root == nullptr) {
        std::cout << "Error parsing JSON." << std::endl;
        return 1;
    }

	// 提取 "messageBody" 部分
	cJSON* messageJson = cJSON_GetObjectItem(root, "messageBody");
	if (messageJson == NULL || messageJson->type != cJSON_String) {
	   std::cerr << "'messageJson' is missing or is not an cJSON_String" << std::endl;
	   cJSON_Delete(root);
	   return 1;
	}

	// 解析 messageBody 中的 JSON 字符串
	const char* messageBodyStr = messageJson->valuestring;
	if (messageBodyStr == nullptr || strlen(messageBodyStr) == 0) {
		std::cerr << "Failed to parse 'messageBody' JSON or it's empty." << std::endl;
		cJSON_Delete(root);
		return 1;
	}

	cJSON* messageBody = cJSON_Parse(messageBodyStr); // 解析 messageBody 字符串
	if (messageBody == NULL) {
	    std::cerr << "Failed to parse 'messageBody' JSON." << std::endl;
	    cJSON_Delete(root);
	    return 1;
	}

	// 获取 guid 字段
	cJSON* guidstr = cJSON_GetObjectItem(messageBody, "guid");
	if (guidstr == nullptr) {
		std::cout << "Missing 'guid' in JSON." << std::endl;
		cJSON_Delete(messageBody);
		cJSON_Delete(root);
		return 1;
	}

	// 根据 guid 字段回复消息
	std::string guid = guidstr->valuestring;

    // 获取 code 字段
    cJSON* code = cJSON_GetObjectItem(messageBody, "code");
    if (code == nullptr) {
        std::cout << "Missing 'code' in JSON." << std::endl;
		cJSON_Delete(messageBody);
        cJSON_Delete(root);
        return 1;
    }

	// 根据 code 字段值执行不同的解析逻辑
    std::string code_str = code->valuestring;

	cJSON* processNo = cJSON_GetObjectItem(messageBody, "processNo");
	if (processNo == nullptr) {
        std::cout << "Missing 'processNo' in JSON." << std::endl;
		cJSON_Delete(messageBody);
        cJSON_Delete(root);
        return 1;
    }

	//判断是不是自己进程号：
	int index_value = processNo->valueint;	

	cJSON* funtion = cJSON_GetObjectItem(messageBody, "fun");
	if (funtion == nullptr) {
        std::cout << "Missing 'fun' in JSON." << std::endl;
		cJSON_Delete(messageBody);
        cJSON_Delete(root);
        return 1;
    }

	std::string fun = funtion->valuestring;

	cJSON* front = cJSON_GetObjectItem(messageBody, "frontType");
	if (front == nullptr) {
        std::cout << "Missing 'frontType' in JSON." << std::endl;
		cJSON_Delete(messageBody);
        cJSON_Delete(root);
        return 1;
    }

	std::string frontType = front->valuestring;

	if (index_value != g_front_seg_index && g_front_seg_index != 0) {
    	std::cout << "msg index:"<< index_value <<"doesnt match self index:" << g_front_seg_index << std::endl;
		cJSON_Delete(messageBody);
        cJSON_Delete(root);
        return 0;
	}

	//进程号为0或者进程号匹配上
	std::cout << "msg index:"<< index_value <<"  self index:" << g_front_seg_index << std::endl;

	DIY_INFOLOG_CODE("process",0,LOG_CODE_PROCESS_CONTROL,"【NORMAL】前置的%s%d号进程处理topic:%s_%s的进程控制消息",get_front_msg_from_subdir(), g_front_seg_index,FRONT_INST.c_str(),G_MQCONSUMER_TOPIC_SET.c_str());

    if (code_str == "set_process") {

		cJSON* num = cJSON_GetObjectItem(messageBody, "processNum");
		if (num == nullptr) {
			std::cout << "Missing 'processNum' in JSON." << std::endl;
			cJSON_Delete(messageBody);
			cJSON_Delete(root);
			return 1;
		}

		int processNum = num->valueint;
       	        
		//校验数据
		if((fun == "reset" || fun == "add") &&
			(processNum >=1 && processNum < 10) &&
			(frontType == "stat" || frontType == "recall" || frontType == "all")){

			if(g_node_id == STAT_DATA_BASE_NODE_ID && g_front_seg_index == 1){

				// 调用执行脚本函数
				if(fun == "reset"){
					close_listening_socket();
				}
        		execute_bash(fun, processNum, frontType);

				DIY_WARNLOG_CODE("process",0,LOG_CODE_PROCESS_CONTROL,"【WARN】前置的%s%d号进程执行指令:%s,reset表示重启所有进程,add表示添加进程",get_front_msg_from_subdir(), g_front_seg_index,fun.c_str());

				//脚本在3秒后执行
				//回复消息
				send_reply_to_kafka(guid,"1","收到重置进程指令,重启所有进程!");

				//上送日志

				std::cout << "this msg should only execute once" <<std::endl;
			}
			else{
				std::cout << "only cfg_stat_data index 1 can control process,this process not handle this msg" << std::endl;
			}
		}
		else if(fun == "delete"){
			//等待一会后退出进程
			MVL_LOG_ACSE0("MYLOG: recive delete msg, so exit to restart ");

			//回复消息
			send_reply_to_kafka(guid,"1","收到删除进程指令,这个进程将会重启 ");

			//上送日志
			DIY_WARNLOG_CODE("process",0,LOG_CODE_PROCESS_CONTROL,"【WARN】前置的%s%d号进程执行指令:%s,即将重启",get_front_msg_from_subdir(), g_front_seg_index,fun.c_str());

			apr_sleep(apr_time_from_sec(10));
			::_exit(-1039);	//进程退出
		}
		else{
			std::cout << "param is not executable" <<std::endl;
		}       	        
            				     
    }
	else if (code_str == "set_debug"){
		if(g_node_id == STAT_DATA_BASE_NODE_ID && g_front_seg_index == 1){
			std::cout << "cfg_stat_data process" << g_front_seg_index <<" handle this msg" << std::endl;

			cJSON* onlyip = cJSON_GetObjectItem(messageBody, "ip");
			if (onlyip == nullptr) {
				std::cout << "Missing 'ip' in JSON." << std::endl;
				cJSON_Delete(messageBody);
				cJSON_Delete(root);
				return 1;
			}
		
			std::string ip = onlyip->valuestring;

			cJSON* index_item = cJSON_GetObjectItem(messageBody, "proindex");
			if (index_item == nullptr) {
				std::cout << "Missing 'proindex' in JSON." << std::endl;
				cJSON_Delete(messageBody);
				cJSON_Delete(root);
				return 1;
			}
		
			int proindex = index_item->valueint;	

			std::cout << "proindex is :" << proindex <<std::endl;

			//校验数据
			if((fun == "start" || fun == "delete") &&
				isValidIP(ip) &&
				(frontType == "stat" || frontType == "recall" || frontType == "realTime" || frontType == "comtrade") &&
				(proindex >= 10 && proindex < 100)){	//单连测试用的进程号应该大于10小于100
        		execute_bash_debug(fun, ip, frontType,proindex);

				DIY_WARNLOG_CODE("process",0,LOG_CODE_PROCESS_CONTROL,"【WARN】前置的%s%d号进程执行指令:%s,start开启单连进程,delete杀死单连进程",get_front_msg_from_subdir(), g_front_seg_index,fun.c_str());
			}
			else{
				std::cout << "param is not executable" <<std::endl;
			}       	        

			std::cout << "this msg should only execute once" <<std::endl;
		}
		else{
			std::cout << "only cfg_stat_data index 1 can control process,this process not handle this msg" << std::endl;
		}
	}
	else{
		std::cout << "set process code str error" <<std::endl;
	}

    // 释放 JSON 对象
	cJSON_Delete(messageBody);
    cJSON_Delete(root);
	return 0;
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////
//lnk20250103台账更新部分
// 准备更新内容并生成 XML 字符串
// 添加缩进的函数
void add_indent(std::stringstream& stream, int level) {
    for (int i = 0; i < level; ++i) {
        stream << "  ";  // 每一级缩进 2 个空格
    }
}

static bool is_cfg_pqdif_process()
{
	return std::strstr(subdir, "cfg_pqdif_data") != NULL;
}

static bool is_pqdif_com_type(const char* com_type)
{
	QString type = com_type ? QString::fromLocal8Bit(com_type).trimmed() : QString();
	return type.compare("PQDIF", Qt::CaseInsensitive) == 0;
}

static void fill_terminal_com_type(terminal* tmnl, cJSON* item)
{
	if (tmnl == NULL)
		return;

	cJSON* comType = cJSON_GetObjectItem(item, "comType");
	if (comType == NULL)
		comType = cJSON_GetObjectItem(item, "com_type");

	if (comType && comType->type == cJSON_String)
		std::strncpy(tmnl->com_type, comType->valuestring, sizeof(tmnl->com_type) - 1);
	else
		std::strncpy(tmnl->com_type, "MMS", sizeof(tmnl->com_type) - 1);

	tmnl->com_type[sizeof(tmnl->com_type) - 1] = '\0';
}

static bool terminal_update_should_write_file(const terminal* tmnl)
{
	if (tmnl == NULL)
		return false;

	if (is_pqdif_com_type(tmnl->com_type))
		return is_cfg_pqdif_process();

	if (is_cfg_pqdif_process())
		return false;

	return true;
}

std::string prepare_update(const std::string& code_str, const terminal& json_data,const std::string& guid) //添加guid
{
    std::cout << "prepare update" << std::endl;

    std::stringstream xmlStream;
    int indentLevel = 0;  // 缩进级别

    // 根节点
    add_indent(xmlStream, indentLevel);
    xmlStream << "<ledger_update>" << std::endl;
    indentLevel++;

	// 添加 guid 节点
    add_indent(xmlStream, indentLevel);
    xmlStream << "<guid>" << guid << "</guid>" << std::endl;

    if (code_str == "ledger_modify" || code_str == "add_terminal") {

        // 如果是 modify 类型
        if (code_str == "ledger_modify") {
            add_indent(xmlStream, indentLevel);
            xmlStream << "<modify>" << std::endl;
			indentLevel++;
        }
        else {
            add_indent(xmlStream, indentLevel);
            xmlStream << "<add>" << std::endl;
			indentLevel++;
        }

        // 添加数据部分
        add_indent(xmlStream, indentLevel);
        xmlStream << "<terminalData>" << std::endl;
        indentLevel++;

        add_indent(xmlStream, indentLevel);
        xmlStream << "<id>" << json_data.terminal_id << "</id>" << std::endl;

        add_indent(xmlStream, indentLevel);
        xmlStream << "<ip>" << json_data.addr_str << "</ip>" << std::endl;  // Assuming `addr_str` for IP

        add_indent(xmlStream, indentLevel);
        xmlStream << "<devType>" << json_data.dev_type << "</devType>" << std::endl;

        add_indent(xmlStream, indentLevel);
        xmlStream << "<maintName>" << json_data.maint_name << "</maintName>" << std::endl;

        add_indent(xmlStream, indentLevel);
        xmlStream << "<orgName>" << json_data.org_name << "</orgName>" << std::endl;

        add_indent(xmlStream, indentLevel);
        xmlStream << "<port>" << json_data.port << "</port>" << std::endl;

        add_indent(xmlStream, indentLevel);
        xmlStream << "<stationName>" << json_data.station_name << "</stationName>" << std::endl;

        add_indent(xmlStream, indentLevel);
        xmlStream << "<terminalCode>" << json_data.terminal_code << "</terminalCode>" << std::endl;

        add_indent(xmlStream, indentLevel);
        xmlStream << "<updateTime>" << json_data.timestamp << "</updateTime>" << std::endl;  // Assuming `timestamp`

        add_indent(xmlStream, indentLevel);
        xmlStream << "<manufacturer>" << json_data.tmnl_factory << "</manufacturer>" << std::endl;

        add_indent(xmlStream, indentLevel);
        xmlStream << "<status>" << json_data.tmnl_status << "</status>" << std::endl;

        add_indent(xmlStream, indentLevel);
        xmlStream << "<series>" << json_data.dev_series << "</series>" << std::endl;

		add_indent(xmlStream, indentLevel);
        xmlStream << "<comType>" << (json_data.com_type[0] ? json_data.com_type : "MMS") << "</comType>" << std::endl;

		//lnk20250210
		add_indent(xmlStream, indentLevel);
        xmlStream << "<processNo>" << json_data.processNo << "</processNo>" << std::endl;

		//lnk20250305
        add_indent(xmlStream, indentLevel);
        xmlStream << "<devKey>" << json_data.dev_key << "</devKey>" << std::endl;

		add_indent(xmlStream, indentLevel);
        xmlStream << "<loglevel>" << json_data.log_level << "</loglevel>" << std::endl;

        // monitorData 部分
        for (int i = 0; json_data.line[i].monitor_id[0] != '\0'; i++) {
            const monitor& monitor = json_data.line[i];

            add_indent(xmlStream, indentLevel);
            xmlStream << "<monitorData" << (i + 1) << ">" << std::endl;
            indentLevel++;

            add_indent(xmlStream, indentLevel);
            xmlStream << "<id>" << monitor.monitor_id << "</id>" << std::endl;

            add_indent(xmlStream, indentLevel);
            xmlStream << "<name>" << monitor.monitor_name << "</name>" << std::endl;

            add_indent(xmlStream, indentLevel);
            xmlStream << "<lineNo>" << monitor.logical_device_seq << "</lineNo>" << std::endl;

            add_indent(xmlStream, indentLevel);
            xmlStream << "<voltageLevel>" << monitor.voltage_level << "</voltageLevel>" << std::endl;

            add_indent(xmlStream, indentLevel);
            xmlStream << "<ptType>" << monitor.terminal_connect << "</ptType>" << std::endl;

			add_indent(xmlStream, indentLevel);
            xmlStream << "<timestamp>" << monitor.timestamp << "</timestamp>" << std::endl;

			add_indent(xmlStream, indentLevel);
            xmlStream << "<terminal_code>" << monitor.terminal_code << "</terminal_code>" << std::endl;

			add_indent(xmlStream, indentLevel);
            xmlStream << "<status>" << monitor.status << "</status>" << std::endl;

			add_indent(xmlStream, indentLevel);
            xmlStream << "<loglevel>" << monitor.log_level << "</loglevel>" << std::endl;

            indentLevel--;
            add_indent(xmlStream, indentLevel);
            xmlStream << "</monitorData>" << std::endl;
        }

        indentLevel--;
        add_indent(xmlStream, indentLevel);
        xmlStream << "</terminalData>" << std::endl;

        // 结束 modify 或 add 标签
        if (code_str == "ledger_modify") {
			indentLevel--;
            add_indent(xmlStream, indentLevel);
            xmlStream << "</modify>" << std::endl;

        }
        else {
			indentLevel--;
            add_indent(xmlStream, indentLevel);
            xmlStream << "</add>" << std::endl;
			
        }

    } else if (code_str == "delete_terminal") {
        // 如果是 delete 类型
        add_indent(xmlStream, indentLevel);
        xmlStream << "<delete>" << std::endl;
        indentLevel++;

		add_indent(xmlStream, indentLevel);
        xmlStream << "<terminalData>" << std::endl;
        indentLevel++;

        add_indent(xmlStream, indentLevel);
        xmlStream << "<id>" << json_data.terminal_id << "</id>" << std::endl;

        add_indent(xmlStream, indentLevel);
        xmlStream << "<comType>" << (json_data.com_type[0] ? json_data.com_type : "MMS") << "</comType>" << std::endl;

		indentLevel--;
        add_indent(xmlStream, indentLevel);
        xmlStream << "</terminalData>" << std::endl;

        indentLevel--;
        add_indent(xmlStream, indentLevel);
        xmlStream << "</delete>" << std::endl;
    }
    else {
        std::cerr << "code_str error" << std::endl;
        return "";
    }

    // 结束根节点
    indentLevel--;
    add_indent(xmlStream, indentLevel);
    xmlStream << "</ledger_update>" << std::endl;

    return xmlStream.str();  // 返回构造的 XML 字符串
}

// 函数：将string字符串转换为整数
int StringToInt(const std::string& str) {
    std::stringstream ss(str);
    int number;
    ss >> number;  // 从字符串流中读取整数

    // 检查是否转换成功
    if (ss.fail()) {
        std::cerr << "Conversion failed!" << std::endl;
        return 0;  // 或者你可以选择返回一个标识失败的值，如-1
    }
    return number;
}

// 解析 JSON 字符串并执行相应操作
int parse_log(const std::string& json_str) {
    // 解析 JSON 字符串
    cJSON* root = cJSON_Parse(json_str.c_str());
    if (root == nullptr) {
        std::cout << "Error parsing JSON." << std::endl;
        return 1;
    }

	// 提取 "messageBody" 部分
	cJSON* messageJson = cJSON_GetObjectItem(root, "messageBody");
	if (messageJson == NULL || messageJson->type != cJSON_String) {
	   std::cerr << "'messageJson' is missing or is not an cJSON_String" << std::endl;
	   cJSON_Delete(root);
	   return 1;
	}

	// 解析 messageBody 中的 JSON 字符串
	const char* messageBodyStr = messageJson->valuestring;
	if (messageBodyStr == nullptr || strlen(messageBodyStr) == 0) {
		std::cerr << "Failed to parse 'messageBody' JSON or it's empty." << std::endl;
		cJSON_Delete(root);
		return 1;
	}

	cJSON* messageBody = cJSON_Parse(messageBodyStr); // 解析 messageBody 字符串
	if (messageBody == NULL) {
	    std::cerr << "Failed to parse 'messageBody' JSON." << std::endl;
	    cJSON_Delete(root);
	    return 1;
	}

	// 获取 guid 字段
	cJSON* guidstr = cJSON_GetObjectItem(messageBody, "guid");
	if (guidstr == nullptr) {
		std::cout << "Missing 'guid' in JSON." << std::endl;
		cJSON_Delete(messageBody);
		cJSON_Delete(root);
		return 1;
	}

	// 根据 guid 字段回复消息
	std::string guid = guidstr->valuestring;

    // 获取 code 字段
    cJSON* code = cJSON_GetObjectItem(messageBody, "code");
    if (code == nullptr) {
        std::cout << "Missing 'code' in JSON." << std::endl;
		cJSON_Delete(messageBody);
        cJSON_Delete(root);
        return 1;
    }

	// 根据 code 字段值执行不同的解析逻辑
	std::string code_str = code->valuestring;

	//获取进程号
	cJSON* process = cJSON_GetObjectItem(messageBody, "processNo");
	if (process == nullptr) {
        std::cout << "Missing 'processNo' in JSON." << std::endl;
		cJSON_Delete(messageBody);
        cJSON_Delete(root);
        return 1;
    }

	//判断是不是自己进程号：
	int processNo = process->valueint;

	// 获取 id 字段
	cJSON* idstr = cJSON_GetObjectItem(messageBody, "id");
	if (idstr == nullptr) {
		std::cout << "Missing 'id' in JSON." << std::endl;
		cJSON_Delete(messageBody);
		cJSON_Delete(root);
		return 1;
	}
	
	std::string id = idstr->valuestring;

	// 获取 level 字段
	cJSON* levelstr = cJSON_GetObjectItem(messageBody, "level");
	if (levelstr == nullptr) {
		std::cout << "Missing 'level' in JSON." << std::endl;
		cJSON_Delete(messageBody);
		cJSON_Delete(root);
		return 1;
	}
	
	std::string level = levelstr->valuestring;

	// 获取 grade 字段
	cJSON* gradestr = cJSON_GetObjectItem(messageBody, "grade");
	if (gradestr == nullptr) {
		std::cout << "Missing 'grade' in JSON." << std::endl;
		cJSON_Delete(messageBody);
		cJSON_Delete(root);
		return 1;
	}
	
	std::string grade = gradestr->valuestring;

	// 获取 logtype 字段
	cJSON* logtypestr = cJSON_GetObjectItem(messageBody, "logtype");
	if (logtypestr == nullptr) {
		std::cout << "Missing 'logtype' in JSON." << std::endl;
		cJSON_Delete(messageBody);
		cJSON_Delete(root);
		return 1;
	}
	
	int logtype = logtypestr->valueint;

	// 获取 frontType 字段
	cJSON* frontTypestr = cJSON_GetObjectItem(messageBody, "frontType");
	if (frontTypestr == nullptr) {
		std::cout << "Missing 'frontType' in JSON." << std::endl;
		cJSON_Delete(messageBody);
		cJSON_Delete(root);
		return 1;
	}
	
	std::string frontType = frontTypestr->valuestring;

	if (processNo != g_front_seg_index) {
    	std::cout << "msg index:"<< processNo <<"doesnt match self index:" << g_front_seg_index << std::endl;
		cJSON_Delete(messageBody);
        cJSON_Delete(root);
        return 0;
	}

	if (frontType != subdir) {
    	std::cout << "msg frontType:"<< frontType <<"doesnt match self frontType:" << subdir << std::endl;
		cJSON_Delete(messageBody);
        cJSON_Delete(root);
        return 0;
	}

	DIY_INFOLOG_CODE("process",0,LOG_CODE_LOG_REQUEST,"【NORMAL】前置的%s%d号进程处理日志控制消息",get_front_msg_from_subdir(), g_front_seg_index);

	//进程号和匹配上
	std::cout << "msg index:"<< processNo <<"  self index:" << g_front_seg_index << std::endl;
	std::cout << "msg frontType:"<< frontType <<"  self frontType:" << subdir << std::endl;

	//回复消息
	send_reply_to_kafka(guid,"1","收到日志控制指令");

	if (code_str == "set_log") {
		//校验数据
		if((level == "terminal" || level == "measurepoint") &&
			(grade == "NORMAL" || grade == "DEBUG") &&
			(!id.empty() && !is_blank(id))){

			//开启日志临时开关
			process_log_command(id, level, grade, logtype);	

		}
		else if((level == "measurepoint") && (grade == "TRACE") && (!id.empty() && !is_blank(id))){	//数据追踪
			//打开监测点数据追踪开关
			process_trace_command(id,1);	//每个报告各追踪1次
		}
		else{
			std::cout << "type doesnt match" <<std::endl;
			//记录warm

		}      
		std::cout << "this msg should only execute once" <<std::endl;
	}

    // 释放 JSON 对象
	cJSON_Delete(messageBody);
    cJSON_Delete(root);
	return 0;
}	

// 台账更新不区分功能
int parse_control(const std::string& json_str, const std::string& output_dir) {
    // 解析 JSON 字符串
    cJSON* root = cJSON_Parse(json_str.c_str());
    if (root == nullptr) {
        std::cout << "Error parsing JSON." << std::endl;
        return 1;
    }

	// 提取 "messageBody" 部分
	cJSON* messageJson = cJSON_GetObjectItem(root, "messageBody");
	if (messageJson == NULL || messageJson->type != cJSON_String) {
	   std::cerr << "'messageJson' is missing or is not an cJSON_String" << std::endl;
	   cJSON_Delete(root);
	   return 1;
	}

	// 解析 messageBody 中的 JSON 字符串
	const char* messageBodyStr = messageJson->valuestring;
	if (messageBodyStr == nullptr || strlen(messageBodyStr) == 0) {
		std::cerr << "Failed to parse 'messageBody' JSON or it's empty." << std::endl;
		cJSON_Delete(root);
		return 1;
	}

	cJSON* messageBody = cJSON_Parse(messageBodyStr); // 解析 messageBody 字符串
	if (messageBody == NULL) {
	    std::cerr << "Failed to parse 'messageBody' JSON." << std::endl;
	    cJSON_Delete(root);
	    return 1;
	}

    // 获取 code 字段
    cJSON* code = cJSON_GetObjectItem(messageBody, "code");
    if (code == nullptr) {
        std::cout << "Missing 'code' in JSON." << std::endl;
		cJSON_Delete(messageBody);
        cJSON_Delete(root);
        return 1;
    }

	// 根据 code 字段值执行不同的解析逻辑
	std::string code_str = code->valuestring;

	//获取进程号
	cJSON* process = cJSON_GetObjectItem(messageBody, "processNo");
	if (process == nullptr) {
		std::cout << "Missing 'processNo' in JSON." << std::endl;
		cJSON_Delete(messageBody);
		cJSON_Delete(root);
		return 1;
	}

	//判断是不是自己进程号：
	int process_No = process->valueint;

	// 获取 guid 字段
	cJSON* guidstr = cJSON_GetObjectItem(messageBody, "guid");
	if (guidstr == nullptr) {
		std::cout << "Missing 'guid' in JSON." << std::endl;
		cJSON_Delete(messageBody);
		cJSON_Delete(root);
		return 1;
	}

	// 根据 guid 字段回复消息
	std::string guid = guidstr->valuestring;

	//进程号为0的进程处理所有台账更新消息
	if (!is_cfg_pqdif_process() && process_No != g_front_seg_index && g_front_seg_index !=0) {
    	std::cout << "msg index:"<< process_No <<"doesnt match self index:" << g_front_seg_index << std::endl;
		cJSON_Delete(messageBody);
        cJSON_Delete(root);
        return 0;
	}

	//进程号为0或者进程号匹配上
	std::cout << "msg index:"<< process_No <<"  self index:" << g_front_seg_index << std::endl;

	//记录日志
	DIY_INFOLOG_CODE("process",0,LOG_CODE_LEDGER_UPDATE,"【NORMAL】前置的%s%d号进程处理topic:%s_%s的台账更新消息",get_front_msg_from_subdir(), g_front_seg_index,FRONT_INST.c_str(),G_MQCONSUMER_TOPIC_UD.c_str());

	//匹配后响应收到台账更新消息
	//除了回复收到消息，执行结束后还要回复结果
	send_reply_to_kafka(guid,"1","收到台账更新指令");

    if (code_str == "add_terminal" || code_str == "ledger_modify") {

		std::cout << "add or update ledger" << std::endl;

        // 解析 add_terminal 或 ledger_modify
        cJSON* data = cJSON_GetObjectItem(messageBody, "data");
        if (data != nullptr && data->type == cJSON_Array) {
            int data_size = cJSON_GetArraySize(data);
            for (int i = 0; i < data_size; i++) {
                cJSON* item = cJSON_GetArrayItem(data, i);

                terminal json_data;
				memset(&json_data, 0, sizeof(json_data));
                // 填充 terminal_dev 的数据
                cJSON* id = cJSON_GetObjectItem(item, "id"); // terminal_id
				if (id && id->type == cJSON_String) 
				    std::strncpy(json_data.terminal_id, id->valuestring, sizeof(json_data.terminal_id) - 1);
				else 
				    std::strncpy(json_data.terminal_id, "N/A", sizeof(json_data.terminal_id) - 1);

				cJSON* name = cJSON_GetObjectItem(item, "name"); // terminal_code
				if (name && name->type == cJSON_String) 
				    std::strncpy(json_data.terminal_code, name->valuestring, sizeof(json_data.terminal_code) - 1);
				else 
				    std::strncpy(json_data.terminal_code, "N/A", sizeof(json_data.terminal_code) - 1);

				cJSON* org_name = cJSON_GetObjectItem(item, "org_name"); // org_name
				if (org_name && org_name->type == cJSON_String) 
				    std::strncpy(json_data.org_name, org_name->valuestring, sizeof(json_data.org_name) - 1);
				else 
				    std::strncpy(json_data.org_name, "N/A", sizeof(json_data.org_name) - 1);

				cJSON* maint_name = cJSON_GetObjectItem(item, "maint_name"); // maint_name
				if (maint_name && maint_name->type == cJSON_String) 
				    std::strncpy(json_data.maint_name, maint_name->valuestring, sizeof(json_data.maint_name) - 1);
				else 
				    std::strncpy(json_data.maint_name, "N/A", sizeof(json_data.maint_name) - 1);

				cJSON* station_name = cJSON_GetObjectItem(item, "stationName"); // station_name
				if (station_name && station_name->type == cJSON_String) 
				    std::strncpy(json_data.station_name, station_name->valuestring, sizeof(json_data.station_name) - 1);
				else 
				    std::strncpy(json_data.station_name, "N/A", sizeof(json_data.station_name) - 1);

				cJSON* manufacturer = cJSON_GetObjectItem(item, "manufacturer"); // tmnl_factory
				if (manufacturer && manufacturer->type == cJSON_String) 
				    std::strncpy(json_data.tmnl_factory, manufacturer->valuestring, sizeof(json_data.tmnl_factory) - 1);
				else 
				    std::strncpy(json_data.tmnl_factory, "N/A", sizeof(json_data.tmnl_factory) - 1);

				cJSON* status = cJSON_GetObjectItem(item, "status"); // tmnl_status
				if (status && status->type == cJSON_String) 
				    std::strncpy(json_data.tmnl_status, status->valuestring, sizeof(json_data.tmnl_status) - 1);
				else 
				    std::strncpy(json_data.tmnl_status, "N/A", sizeof(json_data.tmnl_status) - 1);

				cJSON* dev_type = cJSON_GetObjectItem(item, "devType"); // dev_type
				if (dev_type && dev_type->type == cJSON_String) 
				    std::strncpy(json_data.dev_type, dev_type->valuestring, sizeof(json_data.dev_type) - 1);
				else 
				    std::strncpy(json_data.dev_type, "N/A", sizeof(json_data.dev_type) - 1);

				cJSON* dev_key = cJSON_GetObjectItem(item, "devKey"); // dev_key
				if (dev_key && dev_key->type == cJSON_String) 
				    std::strncpy(json_data.dev_key, dev_key->valuestring, sizeof(json_data.dev_key) - 1);
				else 
				    std::strncpy(json_data.dev_key, "N/A", sizeof(json_data.dev_key) - 1);

				cJSON* dev_series = cJSON_GetObjectItem(item, "series"); // dev_series
				if (dev_series && dev_series->type == cJSON_String) 
				    std::strncpy(json_data.dev_series, dev_series->valuestring, sizeof(json_data.dev_series) - 1);
				else 
				    std::strncpy(json_data.dev_series, "N/A", sizeof(json_data.dev_series) - 1);

				fill_terminal_com_type(&json_data, item);

				//lnk20250210台账进程号
				cJSON* processNo = cJSON_GetObjectItem(item, "processNo"); // processNo转为字符串
        		if (processNo && processNo->type == cJSON_Number) snprintf(json_data.processNo, sizeof(json_data.processNo), "%d", processNo->valueint);
        		else strncpy(json_data.processNo, "N/A", sizeof(json_data.processNo) - 1);

				cJSON* ip = cJSON_GetObjectItem(item, "ip"); // addr_str
				if (ip && ip->type == cJSON_String) 
				    std::strncpy(json_data.addr_str, ip->valuestring, sizeof(json_data.addr_str) - 1);
				else 
				    std::strncpy(json_data.addr_str, "N/A", sizeof(json_data.addr_str) - 1);

				cJSON* port = cJSON_GetObjectItem(item, "port"); // port
				if (port && port->type == cJSON_String) 
				    std::strncpy(json_data.port, port->valuestring, sizeof(json_data.port) - 1);
				else 
				    std::strncpy(json_data.port, "N/A", sizeof(json_data.port) - 1);

				cJSON* updateTime = cJSON_GetObjectItem(item, "updateTime"); // timestamp
				if (updateTime && updateTime->type == cJSON_String) 
				    std::strncpy(json_data.timestamp, updateTime->valuestring, sizeof(json_data.timestamp) - 1);
				else 
				    std::strncpy(json_data.timestamp, "N/A", sizeof(json_data.timestamp) - 1);


				//添加loglevel字段
				cJSON* loglevel = cJSON_GetObjectItem(item, "loglevel"); // log_level
				int tmp_level = -1;			
				// 先读取 loglevel
				if (loglevel && loglevel->type == cJSON_Number) {
				    tmp_level = loglevel->valueint;
				}
				else if (loglevel && loglevel->type == cJSON_String) {
				    tmp_level = atoi(loglevel->valuestring);
				}
				// 判断是否合法 (0~3)
				if (tmp_level >= 0 && tmp_level <= 3) {
				    json_data.log_level = tmp_level;
				} else {
				    json_data.log_level = 1; // 默认日志级别
				}
				printf("terminal log_level: %d\n", json_data.log_level);

                // monitorData 解析，填充到 line 数组中
                cJSON* monitorData = cJSON_GetObjectItem(item, "monitorData");
                if (monitorData != nullptr && monitorData->type == cJSON_Array) {
                    int monitorData_size = cJSON_GetArraySize(monitorData);

                    for (int j = 0; j < monitorData_size && j < 10; j++) {  // 最多 10 个监测点
                        cJSON* monitor_item = cJSON_GetArrayItem(monitorData, j);
                        monitor monitor_data;
						memset(&monitor_data, 0, sizeof(monitor_data));

                        cJSON* monitor_id = cJSON_GetObjectItem(monitor_item, "id"); // monitor_id
        				if (monitor_id && monitor_id->type == cJSON_String) 
        				    std::strncpy(monitor_data.monitor_id, monitor_id->valuestring, sizeof(monitor_data.monitor_id) - 1);
        				else 
        				    std::strncpy(monitor_data.monitor_id, "N/A", sizeof(monitor_data.monitor_id) - 1);

						//添加loglevel字段
						cJSON* loglevel = cJSON_GetObjectItem(monitor_item, "loglevel"); // log_level
						int tmp_level = -1;
						// 先尝试读取 loglevel
						if (loglevel && loglevel->type == cJSON_Number) {
						    tmp_level = loglevel->valueint;
						}
						else if (loglevel && loglevel->type == cJSON_String) {
						    tmp_level = atoi(loglevel->valuestring);
						}						
						// 判断是否合法 (0~3)
						if (tmp_level >= 0 && tmp_level <= 3) {
						    monitor_data.log_level = tmp_level;
						}
						else if (json_data.log_level >= 0 && json_data.log_level <= 3) { // 继承 terminal loglevel
						    monitor_data.log_level = json_data.log_level;
						}
						else {
						    monitor_data.log_level = 1; // 默认 warn
						}

        				cJSON* monitor_name = cJSON_GetObjectItem(monitor_item, "name"); // monitor_name
        				if (monitor_name && monitor_name->type == cJSON_String) 
        				    std::strncpy(monitor_data.monitor_name, monitor_name->valuestring, sizeof(monitor_data.monitor_name) - 1);
        				else 
        				    std::strncpy(monitor_data.monitor_name, "N/A", sizeof(monitor_data.monitor_name) - 1);

        				cJSON* voltage_level = cJSON_GetObjectItem(monitor_item, "voltageLevel"); // voltage_level
        				if (voltage_level && voltage_level->type == cJSON_String) 
        				    std::strncpy(monitor_data.voltage_level, voltage_level->valuestring, sizeof(monitor_data.voltage_level) - 1);
        				else 
        				    std::strncpy(monitor_data.voltage_level, "N/A", sizeof(monitor_data.voltage_level) - 1);

        				cJSON* monitor_status = cJSON_GetObjectItem(monitor_item, "status"); // status
        				if (monitor_status && monitor_status->type == cJSON_String) 
        				    std::strncpy(monitor_data.status, monitor_status->valuestring, sizeof(monitor_data.status) - 1);
        				else 
        				    std::strncpy(monitor_data.status, "N/A", sizeof(monitor_data.status) - 1);

        				cJSON* lineNo = cJSON_GetObjectItem(monitor_item, "lineNo"); // logical_device_seq
        				if (lineNo && lineNo->type == cJSON_String) 
						
        				    std::strncpy(monitor_data.logical_device_seq, lineNo->valuestring, sizeof(monitor_data.logical_device_seq) - 1);
						else 
        				    std::strncpy(monitor_data.logical_device_seq, "N/A", sizeof(monitor_data.logical_device_seq) - 1);

        				cJSON* ptType = cJSON_GetObjectItem(monitor_item, "ptType"); // terminal_connect
        				if (ptType && ptType->type == cJSON_String) 
						
        				    std::strncpy(monitor_data.terminal_connect, ptType->valuestring, sizeof(monitor_data.terminal_connect) - 1);
						else 
        				    std::strncpy(monitor_data.terminal_connect, "N/A", sizeof(monitor_data.terminal_connect) - 1);

        				std::strncpy(monitor_data.timestamp, json_data.timestamp, sizeof(monitor_data.timestamp) - 1);
        				std::strncpy(monitor_data.terminal_code, json_data.terminal_code, sizeof(monitor_data.terminal_code) - 1);
                        // 填充到 line 数组
                        json_data.line[j] = monitor_data;

                    }
                }

				print_terminal(&json_data);

				if (!terminal_update_should_write_file(&json_data)) {
					std::cout << "skip ledger update by comType:" << json_data.com_type
							  << " terminal:" << json_data.terminal_id
							  << " process:" << subdir << g_front_seg_index << std::endl;
					continue;
				}

                // 准备 XML 内容并写入文件
                std::string xmlContent = prepare_update(code_str, json_data,guid);//添加guid20250506
                if (xmlContent != "") {

					std::cout << "write to xml in /FeProject/etc/ledger_update" <<std::endl;

					char nodeid[20];
    				std::sprintf(nodeid, "%u", g_node_id);  // "%u" 用于 unsigned int
    				std::string nodeid_str(nodeid);

					std::string frontindex_str = intToString(g_front_seg_index);

					std::string file_name = output_dir + "/" + nodeid_str + "_" + frontindex_str + "_" + json_data.terminal_id + "_" + code_str + ".xml";
                    writeToFile(file_name, xmlContent);
                }
            }
        }
    }
    else if (code_str == "delete_terminal") {

		std::cout << "delete ledger" <<std::endl;

        // 解析 delete_terminal
        cJSON* data = cJSON_GetObjectItem(messageBody, "data");
        if (data != nullptr && data->type == cJSON_Array) {
            int data_size = cJSON_GetArraySize(data);
            for (int i = 0; i < data_size; i++) {
                cJSON* item = cJSON_GetArrayItem(data, i);

                // 只解析 id 字段
                cJSON* id = cJSON_GetObjectItem(item, "id");
                if (id != nullptr) {
                    terminal json_data;
					memset(&json_data, 0, sizeof(json_data));
                    std::strncpy(json_data.terminal_id, cJSON_GetObjectItem(item, "id")->valuestring, sizeof(json_data.terminal_id) - 1);
					fill_terminal_com_type(&json_data, item);

					if (!terminal_update_should_write_file(&json_data)) {
						std::cout << "skip delete ledger update by comType:" << json_data.com_type
								  << " terminal:" << json_data.terminal_id
								  << " process:" << subdir << g_front_seg_index << std::endl;
						continue;
					}

                    // 准备 XML 内容并写入文件
                    std::string xmlContent = prepare_update(code_str, json_data,guid);//添加guid20250506
					if(xmlContent != ""){
                    	char nodeid[20];
    					std::sprintf(nodeid, "%u", g_node_id);  // "%u" 用于 unsigned int
    					std::string nodeid_str(nodeid);

						std::string frontindex_str = intToString(g_front_seg_index);

						std::string file_name = output_dir + "/" + nodeid_str + "_" + frontindex_str + "_" +  json_data.terminal_id + "_delete_terminal.xml";
                    	writeToFile(file_name, xmlContent);		//写文件加上guid，读文件
					}
                }
            }
        }
    }
	else{
		std::cout << "code_str error" <<std::endl;
	}

    // 释放 JSON 对象
	cJSON_Delete(messageBody);
    cJSON_Delete(root);

	return 0;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////
//处理文件请求
static int ParseFileDirReq(const char *body, file_dir_req_t *req)
{
    if (body == NULL || req == NULL)
    {
        std::cout << "[ParseFileDirReq] body invalid" << std::endl;
        return -1;
    }

    cJSON *root = cJSON_Parse(body);
    if (root == NULL)
    {
        std::cout << "[ParseFileDirReq] parse json failed" << std::endl;
        return -1;
    }

    cJSON *guid      = cJSON_GetObjectItem(root, "guid");
    cJSON *frontid   = cJSON_GetObjectItem(root, "nodeId");
    cJSON *processNo = cJSON_GetObjectItem(root, "processNo");
    cJSON *devid     = cJSON_GetObjectItem(root, "devId");
    cJSON *type      = cJSON_GetObjectItem(root, "type");
    cJSON *path      = cJSON_GetObjectItem(root, "path");
    cJSON *remotepath = cJSON_GetObjectItem(root, "remotePath");

    if (!guid || guid->type != cJSON_String ||
        !frontid || frontid->type != cJSON_String ||
        !processNo || processNo->type != cJSON_Number ||
        !devid || devid->type != cJSON_String ||
        !type || type->type != cJSON_Number ||
        !path || path->type != cJSON_String)
    {
        std::cout << "[ParseFileDirReq] invalid"
                  << ", guid=" << (guid ? guid->type : -1)
                  << ", nodeId=" << (frontid ? frontid->type : -1)
                  << ", processNo=" << (processNo ? processNo->type : -1)
                  << ", devId=" << (devid ? devid->type : -1)
                  << ", type=" << (type ? type->type : -1)
                  << ", path=" << (path ? path->type : -1)
                  << std::endl;

        cJSON_Delete(root);
        return -1;
    }

    memset(req, 0, sizeof(file_dir_req_t));

    snprintf(req->guid, sizeof(req->guid), "%s", guid->valuestring);
    snprintf(req->frontid, sizeof(req->frontid), "%s", frontid->valuestring);
    req->processNo = processNo->valueint;
    snprintf(req->devid, sizeof(req->devid), "%s", devid->valuestring);
    req->type = type->valueint;
    snprintf(req->path, sizeof(req->path), "%s", path->valuestring);

    // remotePath 可选
    if (remotepath && remotepath->type == cJSON_String && remotepath->valuestring)
    {
        snprintf(req->remote_path,
                 sizeof(req->remote_path),
                 "%s",
                 remotepath->valuestring);
    }
    else
    {
        req->remote_path[0] = '\0';
    }

    req->create_time = time(NULL);

    cJSON_Delete(root);
    return 0;
}

static void PushFileDirReq(const file_dir_req_t *req)
{
    if (req == NULL)
        return;

    file_dir_req_t *node = new file_dir_req_t;
    *node = *req;

    pthread_mutex_lock(&g_file_req_mutex);

    g_file_dir_req_list.push_back(node);
    pthread_mutex_unlock(&g_file_req_mutex);
}

static file_dir_req_t* PopMatchedFileDirReq(const char *terminal_id)
{
    if (terminal_id == NULL || terminal_id[0] == 0)
        return NULL;

    file_dir_req_t *match = NULL;

    pthread_mutex_lock(&g_file_req_mutex);

    for (std::list<file_dir_req_t*>::iterator it = g_file_dir_req_list.begin();
         it != g_file_dir_req_list.end();
         ++it)
    {
        file_dir_req_t *node = *it;
        if (node != NULL && strcmp(node->devid, terminal_id) == 0)
        {
            match = node;
            g_file_dir_req_list.erase(it);
            break;
        }
    }

    pthread_mutex_unlock(&g_file_req_mutex);
    return match;
}

static std::string BuildFileDirRespJsonEx(const file_dir_req_t *req,	//文件请求的基本信息
                                          char **names,					//文件或目录的名称列表
                                          const char **itemTypes,		//文件或目录的类型列表（如 "file" 或 "dir"）
                                          int *itemSizes,				//文件的大小列表（如果是目录，可以设置为0或1）
                                          int itemNum,					//文件或目录的数量
                                          int result)					//操作结果，0表示成功，非0表示失败
{
    cJSON *root = cJSON_CreateObject();
    cJSON *detail = cJSON_CreateObject();
    cJSON *dirInfo = cJSON_CreateArray();

    cJSON_AddStringToObject(root, "guid", req ? req->guid : "");		//请求的唯一标识符
    cJSON_AddStringToObject(root, "nodeId", req ? req->frontid : "");	//请求发送方的前置机ID
    cJSON_AddNumberToObject(root, "processNo", req ? req->processNo : 0);//请求发送方的进程号
    cJSON_AddStringToObject(root, "devId", req ? req->devid : "");		//请求发送方的设备ID
    cJSON_AddNumberToObject(root, "type", req ? req->type : 0);			//请求类型，如0表示文件列表请求，1表示文件下载请求
    cJSON_AddNumberToObject(root, "result", result);					//操作结果

    for (int i = 0; i < itemNum; ++i)
    {
        cJSON *item = cJSON_CreateObject();
        cJSON_AddStringToObject(item, "name", (names && names[i]) ? names[i] : "");	//文件或目录的名称，下载文件这里响应远端文件路径，上传文件这里响应上传后的目录列表
        cJSON_AddStringToObject(item, "type", (itemTypes && itemTypes[i]) ? itemTypes[i] : "file");//文件或目录的类型，默认为 "file"
        cJSON_AddNumberToObject(item, "size", itemSizes ? itemSizes[i] : 1);//文件的大小，如果是目录，可以设置为0或1
        cJSON_AddItemToArray(dirInfo, item);
    }

    cJSON_AddItemToObject(detail, "dirInfo", dirInfo);

    cJSON_AddItemToObject(root, "detail", detail);

    char *json = cJSON_PrintUnformatted(root);
    std::string jsonStr = json ? json : "";

    if (json) free(json);
    cJSON_Delete(root);
    return jsonStr;
}

static std::string BuildFileDirRespJson(const file_dir_req_t *req,
                                        char **filenames,
                                        int filenum,
                                        int result)
{
    if (filenum <= 0)
        return BuildFileDirRespJsonEx(req, NULL, NULL, NULL, 0, result);

    const char **types = new const char*[filenum];
    int *sizes = new int[filenum];

    for (int i = 0; i < filenum; ++i)
    {
        sizes[i] = 1;

        if (filenames[i] != NULL)
        {
            int len = strlen(filenames[i]);

            // 以 / 结尾 -> dir
            if (len > 0 && filenames[i][len - 1] == '/')
            {
                types[i] = "dir";
            }
            else
            {
                types[i] = "file";
            }
        }
        else
        {
            types[i] = "file";
        }
    }

    std::string jsonStr =
        BuildFileDirRespJsonEx(req,
                               filenames,
                               types,
                               sizes,
                               filenum,
                               result);

    delete [] types;
    delete [] sizes;

    return jsonStr;
}

static std::string BuildSingleFileRespJson(const file_dir_req_t *req,
                                           const char *name,
                                           const char *itemType,
                                           int size,
                                           int result)
{
    char *names[1];
    const char *types[1];
    int sizes[1];

    if (name == NULL || result != 0)
    {
        return BuildFileDirRespJsonEx(req, NULL, NULL, NULL, 0, result);//异常响应-1
    }

    names[0] = (char *)name;
    types[0] = (itemType ? itemType : "file");
    sizes[0] = size;

    return BuildFileDirRespJsonEx(req, names, types, sizes, 1, result);
}

////////////////////////下载
static const char* GetFileNameOnly(const char* fullpath)
{
    if (fullpath == NULL)
        return "";

    const char* p1 = strrchr(fullpath, '/');
    const char* p2 = strrchr(fullpath, '\\');
    const char* p = p1 > p2 ? p1 : p2;

    return (p ? p + 1 : fullpath);
}

static int MakeDirRecursive(const char* dirPath)
{
    if (dirPath == NULL || dirPath[0] == '\0')
        return -1;

    char tmp[512] = {0};
    snprintf(tmp, sizeof(tmp), "%s", dirPath);

    int len = strlen(tmp);
    if (len <= 0)
        return -1;

    /* 去掉末尾 '/' */
    if (tmp[len - 1] == '/')
        tmp[len - 1] = '\0';

    for (char* p = tmp + 1; *p; ++p)
    {
        if (*p == '/')
        {
            *p = '\0';
            if (access(tmp, F_OK) != 0)
            {
                if (mkdir(tmp, 0777) != 0 && errno != EEXIST)
                {
                    printf("mkdir failed: %s, err=%s\n", tmp, strerror(errno));
                    return -1;
                }
            }
            *p = '/';
        }
    }

    if (access(tmp, F_OK) != 0)
    {
        if (mkdir(tmp, 0777) != 0 && errno != EEXIST)
        {
            printf("mkdir failed: %s, err=%s\n", tmp, strerror(errno));
            return -1;
        }
    }

    return 0;
}

static void SafePathName(const char* src, char* dst, size_t dstSize)
{
    if (dst == NULL || dstSize == 0)
        return;

    dst[0] = '\0';

    if (src == NULL)
        return;

    size_t j = 0;
    for (size_t i = 0; src[i] != '\0' && j + 1 < dstSize; ++i)
    {
        char c = src[i];
        if ((c >= '0' && c <= '9') ||
            (c >= 'a' && c <= 'z') ||
            (c >= 'A' && c <= 'Z') ||
            c == '.' || c == '_' || c == '-')
        {
            dst[j++] = c;
        }
        else
        {
            dst[j++] = '_';
        }
    }
    dst[j] = '\0';
}

static void trim_inplace(char *s)
{
    if (!s) return;

    char *p = s;
    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
        ++p;
    }

    if (p != s) {
        memmove(s, p, strlen(p) + 1);
    }

    int len = strlen(s);
    while (len > 0 &&
           (s[len - 1] == ' ' ||
            s[len - 1] == '\t' ||
            s[len - 1] == '\r' ||
            s[len - 1] == '\n')) {
        s[len - 1] = '\0';
        --len;
    }
}

static std::string get_parent_dir(const char* fullpath)
{
    if (fullpath == NULL) return "/";

    std::string s(fullpath);
    size_t pos = s.find_last_of('/');

    if (pos == std::string::npos) return "/";
    if (pos == 0) return "/";

    return s.substr(0, pos + 1);
}

static int BuildTempLocalPath(char* outPath,
                              size_t outSize,
                              chnl_usr_t* chnl_usr,
                              const char* remotePath)
{
    if (outPath == NULL || outSize == 0 || chnl_usr == NULL)
        return -1;

    const char* fileName = GetFileNameOnly(remotePath);
    if (fileName == NULL || fileName[0] == '\0')
        fileName = "tmp_file";

    const char* ipStr = chnl_usr->ip_str;
    if (ipStr == NULL || ipStr[0] == '\0')
        ipStr = "unknown_ip";

    char safeIp[128] = {0};
    SafePathName(ipStr, safeIp, sizeof(safeIp));

    char dirPath[512] = {0};
    snprintf(dirPath, sizeof(dirPath), "/FeProject/dat/filetodevice/%s", safeIp);

    /* 目录不存在则创建 */
    if (MakeDirRecursive(dirPath) != 0)
    {
        printf("BuildTempLocalPath mkdir failed: %s\n", dirPath);
        return -1;
    }

    int n = snprintf(outPath, outSize, "%s/%s", dirPath, fileName);
	if (n < 0 || (size_t)n >= outSize)
	{
	    printf("BuildTempLocalPath path too long, outSize=%zu, dir=%s, fileName=%s\n",
	           outSize, dirPath, fileName);
	    outPath[0] = '\0';
	    return -1;
	}

	return 0;
}

static int HandleTypeDownloadAndUpload(chnl_usr_t* chnl_usr,
                                       file_dir_req_t* req,
                                       std::string& jsonString)
{
    if (chnl_usr == NULL || req == NULL || chnl_usr->net_info == NULL)
        return -1;

    char localpath[512] = {0};
    if (BuildTempLocalPath(localpath, sizeof(localpath), chnl_usr, req->path) != 0)
    {
        DIY_ERRORLOG_CODE("process",0, LOG_CODE_FILE_CONTROL,
                          "【ERROR】构造本地临时路径失败 devid=%s path=%s",
                          req->devid, req->path);

        jsonString = BuildSingleFileRespJson(req, NULL, "file", 1, -1);
        return -1;
    }

	trim_inplace(req->path);
	trim_inplace(localpath);

	std::cout << "[FILE][GET] localpath=[" << localpath
	          << "], remote=[" << req->path << "]" << std::endl;

    ST_RET ret = mms_getFile(chnl_usr->net_info,
                             (ST_CHAR*)localpath,
                             (ST_CHAR*)req->path,
                             3 * g_pt61850app->mmsOpTimeout);

    if (ret != SD_SUCCESS)
    {
        DIY_ERRORLOG_CODE("process",0, LOG_CODE_FILE_CONTROL,
                          "【ERROR】装置文件下载失败 devid=%s, rem=%s, ret=0x%X",
                          req->devid, req->path, ret);

        jsonString = BuildSingleFileRespJson(req, NULL, "file", 1, -1);
        return -1;
    }

    DIY_INFOLOG_CODE(req->devid,1, LOG_CODE_FILE_CONTROL,
                "【NORMAL】装置文件下载成功 devid=%s, rem=%s, local=%s",
                req->devid, req->path, localpath);

    char wavepath[512] = {0};
	// 拼接上传路径
	char upload_path[1024] = {0};

	snprintf(upload_path,
	         sizeof(upload_path),
	         "/upload/%s%s",
	         req->devid,
	         req->path);
	
	std::string cloud_dir = get_parent_dir(upload_path);

	std::cout << "[FILE][UPLOAD]"
	          << " local=[" << localpath << "]"
	          << ", remoteFile=[" << upload_path << "]"
	          << ", cloudDir=[" << cloud_dir << "]"
	          << std::endl;

    SendFileWeb(WEB_FILEUPLOAD, localpath, cloud_dir.c_str(), wavepath,0);

    // 上传失败
	if (wavepath[0] == 0)
	{
	    std::cout << "[FILEUPLOAD] upload failed, wavepath empty" << std::endl;

	    jsonString = BuildSingleFileRespJson(req,
	                                         "",
	                                         "file",
	                                         1,
	                                         -1);   // 失败
	}
	else
	{
	    std::cout << "[FILEUPLOAD] upload success, wavepath="
	              << wavepath << std::endl;

	    jsonString = BuildSingleFileRespJson(req,
	                                         wavepath,
	                                         "file",
	                                         1,
	                                         0);    // 成功
	}

	remove(localpath);

    return 0;
}

///////////传输
static int HandleTypeTransferToDevice(chnl_usr_t* chnl_usr,
                                      file_dir_req_t* req,
                                      std::string& jsonString)
{
    if (chnl_usr == NULL || req == NULL || chnl_usr->net_info == NULL)
        return -1;

    char localpath[1024] = {0};
    if (BuildTempLocalPath(localpath, sizeof(localpath), chnl_usr, req->remote_path) != 0)
    {
        DIY_ERRORLOG_CODE(req->devid,1, LOG_CODE_FILE_CONTROL,
                          "【ERROR】构造本地临时路径失败 devid=%s path=%s",
                          req->devid, req->remote_path);

        jsonString = BuildSingleFileRespJson(req, NULL, "file", 1, -1);
        return -1;
    }

    int dlRet = DownloadFileWeb(WEB_FILEDOWNLOAD, req->remote_path, localpath);
    if (dlRet != 0)
    {
        DIY_ERRORLOG_CODE(req->devid,1, LOG_CODE_FILE_CONTROL,
                          "【ERROR】Web 文件下载失败 devid=%s, path=%s",
                          req->devid, req->remote_path);

        jsonString = BuildSingleFileRespJson(req, NULL, "file", 1, -1);
        return -1;
    }

    DIY_INFOLOG_CODE(req->devid,1, LOG_CODE_FILE_CONTROL,
                "【NORMAL】Web 文件下载成功 devid=%s, webpath=%s, local=%s",
                req->devid, req->remote_path, localpath);

    ST_RET ret = mms_mvla_obtfile(chnl_usr->net_info,
                                  (ST_CHAR*)localpath,		//本地路径
                                  (ST_CHAR*)req->path,		//装置路径
                                  3 * g_pt61850app->mmsOpTimeout);

    if (ret != SD_SUCCESS)
    {
        DIY_ERRORLOG_CODE(req->devid,1, LOG_CODE_FILE_CONTROL,
                          "【ERROR】文件传送到装置失败 devid=%s, src=%s, dest=%s, ret=0x%X",
                          req->devid, localpath, req->path, ret);

        jsonString = BuildSingleFileRespJson(req, NULL, "file", 1, -1);
        return -1;
    }

    DIY_INFOLOG_CODE(req->devid,1, LOG_CODE_FILE_CONTROL,
                "【NORMAL】文件传送到装置成功 devid=%s, src=%s, dest=%s",
                req->devid, localpath, req->path);

    jsonString = BuildSingleFileRespJson(req,
                                         req->path,
                                         "file",
                                         1,
                                         0);

	remove(localpath);
    return 0;
}

//////////删除
static int HandleDeleteFileInDevice(chnl_usr_t* chnl_usr,
                                    file_dir_req_t* req,
                                    std::string& jsonString)
{
    if (chnl_usr == NULL || req == NULL || chnl_usr->net_info == NULL)
    {
        if (req)
            jsonString = BuildSingleFileRespJson(req, NULL, "file", 1, -1);
        return -1;
    }

    if (req->path[0] == '\0')
    {
        DIY_ERRORLOG_CODE(req->devid, 1, LOG_CODE_FILE_CONTROL,
                          "【ERROR】删除装置文件失败，path为空 devid=%s",
                          req->devid);

        jsonString = BuildSingleFileRespJson(req, NULL, "file", 1, -1);
        return -1;
    }

    ST_RET ret = mms_mvla_fdelete(chnl_usr->net_info,
                                  (ST_CHAR*)req->path,
                                  3 * g_pt61850app->mmsOpTimeout);

    if (ret != SD_SUCCESS)
    {
        DIY_ERRORLOG_CODE(req->devid, 1, LOG_CODE_FILE_CONTROL,
                          "【ERROR】删除装置文件失败 devid=%s, path=%s, ret=0x%X",
                          req->devid, req->path, ret);

        jsonString = BuildSingleFileRespJson(req, req->path, "file", 1, -1);
        return -1;
    }

    DIY_INFOLOG_CODE(req->devid, 1, LOG_CODE_FILE_CONTROL,
                     "【NORMAL】删除装置文件成功 devid=%s, path=%s",
                     req->devid, req->path);

    jsonString = BuildSingleFileRespJson(req,
                                         req->path,
                                         "file",
                                         1,
                                         0);

    return 0;
}

/*
==============================================================================
TYPE ID DUMP
------------------------------------------------------------------------------

[TYPE] id=0  name=RTYP_BOOL         size=1   num_rt=1
[TYPE] id=1  name=RTYP_BTIME6       size=8   num_rt=1
[TYPE] id=2  name=RTYP_BSTR6        size=1   num_rt=1
[TYPE] id=3  name=RTYP_BSTR8        size=1   num_rt=1
[TYPE] id=4  name=RTYP_BSTR9        size=2   num_rt=1
[TYPE] id=5  name=RTYP_BVSTR6       size=3   num_rt=1
[TYPE] id=6  name=RTYP_BVSTR8       size=3   num_rt=1
[TYPE] id=7  name=RTYP_BVSTR10      size=4   num_rt=1
[TYPE] id=8  name=RTYP_INT8U        size=1   num_rt=1
[TYPE] id=9  name=RTYP_INT16U       size=2   num_rt=1
[TYPE] id=10 name=RTYP_OSTR8        size=8   num_rt=1
[TYPE] id=11 name=RTYP_VSTR32       size=33  num_rt=1
[TYPE] id=12 name=RTYP_VSTR65       size=66  num_rt=1
[TYPE] id=13 name=RTYP_INT32U       size=4   num_rt=1

------------------------------------------------------------------------------
自定义/业务类型
------------------------------------------------------------------------------

[TYPE] id=14 name=I16               size=2   num_rt=1
[TYPE] id=15 name=U32               size=4   num_rt=1
[TYPE] id=16 name=UTF8VSTRING13     size=28  num_rt=1

------------------------------------------------------------------------------
复杂结构体类型
------------------------------------------------------------------------------

[TYPE] id=17 name=phv_type          size=312 num_rt=152
[TYPE] id=18 name=phsx_type         size=52  num_rt=25

------------------------------------------------------------------------------
LEDRs Oper 动态创建结果
------------------------------------------------------------------------------
例如：
[CTRL_INIT] success dom=PQPQLD0 type_id=19*/
/////////////////////////////控制类消息处理


static int HandleTypeControlDevice(chnl_usr_t *chnl_usr,
                                   ied_usr_t *ied_usr,
                                   file_dir_req_t *req,
                                   std::string &jsonString)
{
    if (chnl_usr == NULL || chnl_usr->net_info == NULL ||
        ied_usr == NULL || req == NULL)
    {
        jsonString = BuildSingleFileRespJson(req, NULL, "control", 1, -1);
        return -1;
    }

    char domName[256] = {0};
    BuildResetDomName(ied_usr, domName, sizeof(domName));

    const char *controlName = NULL;
    ST_INT operTypeId = -1;
    ST_RET ret = SD_FAILURE;

    if (strcmp(req->path, "return") == 0)
    {
        controlName = "CO$LEDRs$Oper";
        operTypeId = ied_usr->oper_type_cache.ledrs_oper_type_id;

        if (ied_usr->oper_type_cache.inited != SD_TRUE || operTypeId < 0)
        {
            jsonString = BuildSingleFileRespJson(req, NULL, "control", 1, -1);
            DIY_ERRORLOG_CODE(req->devid, 1, LOG_CODE_FILE_CONTROL,
                "【ERROR】控制操作失败，LEDRs Oper type_id 未初始化 terminal_id=%s type_id=%d",
                req->devid, operTypeId);
            return -1;
        }

        printf("[CONTROL] before write_common_oper control=%s type_id=%d\n",
               controlName, operTypeId);

        ret = write_common_oper(chnl_usr,
                                 domName,
                                 controlName,
                                 operTypeId,
                                 g_pt61850app->mmsOpTimeout);

        printf("[CONTROL] after write_common_oper control=%s ret=0x%X\n",
               controlName, ret);
    }
    else if (strcmp(req->path, "reboot") == 0)
    {
        controlName = "CO$Reboot$Oper";
        operTypeId = ied_usr->oper_type_cache.reboot_oper_type_id;

        if (ied_usr->oper_type_cache.inited != SD_TRUE || operTypeId < 0)
        {
            jsonString = BuildSingleFileRespJson(req, NULL, "control", 1, -1);
            DIY_ERRORLOG_CODE(req->devid, 1, LOG_CODE_FILE_CONTROL,
                "【ERROR】控制操作失败，Reboot Oper type_id 未初始化 terminal_id=%s type_id=%d",
                req->devid, operTypeId);
            return -1;
        }

        printf("[CONTROL] before write_common_oper control=%s type_id=%d\n",
               controlName, operTypeId);

        ret = write_common_oper(chnl_usr,
                                 domName,
                                 controlName,
                                 operTypeId,
                                 g_pt61850app->mmsOpTimeout);

        printf("[CONTROL] after write_common_oper control=%s ret=0x%X\n",
               controlName, ret);
    }
    else if (strcmp(req->path, "reset") == 0)
    {
        controlName = "ST$Mod$stVal";

        printf("[CONTROL] before write_mod_stval control=%s\n", controlName);

        ret = write_mod_stval(chnl_usr,
                              domName,
                              g_pt61850app->mmsOpTimeout);

        printf("[CONTROL] after write_mod_stval ret=0x%X\n", ret);

        if (ret == SD_SUCCESS)
        {
            ST_RET discRet = mms_conclude_disconnect(chnl_usr->net_info,
                                                     g_pt61850app->mmsOpTimeout);

            printf("[CONTROL] disconnect after reset ret=0x%X\n", discRet);
        }
    }
    else
    {
        printf("[CONTROL] unknown path=%s\n", req->path);
        jsonString = BuildSingleFileRespJson(req, NULL, "control", 1, -1);
        return -1;
    }

    if (ret == SD_SUCCESS)
    {
        jsonString = BuildSingleFileRespJson(req, NULL, "control", 1, 0);
        DIY_WARNLOG_CODE(req->devid, 1, LOG_CODE_FILE_CONTROL,
            "【WARN】控制操作成功 terminal_id=%s path=%s", req->devid, req->path);
        return 0;
    }

    jsonString = BuildSingleFileRespJson(req, NULL, "control", 1, -1);
    DIY_ERRORLOG_CODE(req->devid, 1, LOG_CODE_FILE_CONTROL,
        "【ERROR】控制操作失败 terminal_id=%s path=%s ret=0x%X",
        req->devid, req->path, ret);

    return -1;
}

void HandleFileDirReqForChannel(chnl_usr_t *chnl_usr)
{
    if (chnl_usr == NULL) {
        std::cout << "[FILEDIR] chnl_usr is NULL" << std::endl;
        return;
    }

    if (chnl_usr->chnl == NULL) {
        std::cout << "[FILEDIR] chnl is NULL" << std::endl;
        return;
    }

    if (chnl_usr->chnl->ied == NULL) {
        std::cout << "[FILEDIR] ied is NULL" << std::endl;
        return;
    }

    ied_t *ied = chnl_usr->chnl->ied;
    ied_usr_t *ied_usr = GET_IEDEXT_ADDR(ied);
    if (ied_usr == NULL) {
        std::cout << "[FILEDIR] ied_usr is NULL" << std::endl;
        return;
    }

    if (ied_usr->terminal_id[0] == 0) {
        std::cout << "[FILEDIR] terminal_id empty" << std::endl;
        return;
    }

    if(DEBUGOPEN)std::cout << "[FILEDIR] checking req for terminal_id="
              << ied_usr->terminal_id << std::endl;

    file_dir_req_t *req = PopMatchedFileDirReq(ied_usr->terminal_id);
    if (req == NULL) {
        if(DEBUGOPEN)std::cout << "[FILEDIR] no matched request, terminal_id="
                  << ied_usr->terminal_id << std::endl;
        return;
    }

    std::cout << "[FILEDIR] matched request success, terminal_id="
              << ied_usr->terminal_id
              << ", guid=" << req->guid
              << std::endl;

    DIY_INFOLOG_CODE(req->devid,1, LOG_CODE_FILE_CONTROL,
                "【NORMAL】处理文件请求 terminal_id=%s type=%d path=%s",
                req->devid, req->type, req->path);

    std::string jsonString;
    int handleRet = -1;

    if (req->type == 0)
    {
        /* 目录查询 */
        char **filenames = NULL;
        int filenum = 0;

        ST_RET ret = mms_mvla_fdir(chnl_usr->net_info,
                                   (ST_CHAR*)req->path,
                                   3 * g_pt61850app->mmsOpTimeout,
                                   &filenames,
                                   &filenum,
                                   g_pt61850app->tmp_pool);

        jsonString = BuildFileDirRespJson(req,
                                          filenames,
                                          filenum,
                                          (ret == SD_SUCCESS) ? 0 : ret);

        DIY_INFOLOG_CODE(req->devid,1, LOG_CODE_FILE_CONTROL,
                    "【NORMAL】目录请求处理完成 terminal_id=%s ret=0x%X filenum=%d",
                    req->devid, ret, filenum);

        handleRet = (ret == SD_SUCCESS) ? 0 : -1;
    }
    else if (req->type == 1)
    {
        /* 装置下载到本地，再上传 Web */
        handleRet = HandleTypeDownloadAndUpload(chnl_usr, req, jsonString);
    }
    else if (req->type == 2)
    {
        /* Web 下载到本地，再传送到装置 /etc */
        handleRet = HandleTypeTransferToDevice(chnl_usr, req, jsonString);
    }
	else if (req->type == 3){
		/* 删除文件 */
		handleRet = HandleDeleteFileInDevice(chnl_usr, req, jsonString);
	}
	else if (req->type == 4){	//复位
		handleRet = HandleTypeControlDevice(chnl_usr,
                                      ied_usr,
                                      req,
                                      jsonString);
	}
    else
    {
        DIY_WARNLOG_CODE(req->devid,1, LOG_CODE_FILE_CONTROL,
                    "【WARN】未知文件请求类型 type=%d devid=%s path=%s",
                    req->type, req->devid, req->path);

        jsonString = BuildSingleFileRespJson(req, NULL, "file", 1, -1);//-1是失败
        handleRet = -1;
    }

    /* 统一回 Kafka */
    Ckafka_data_t dir_info;
    dir_info.strTopic = QString::fromStdString(G_REPLY_TOPIC_FILE);
	dir_info.mp_id = QString::fromLocal8Bit(req->devid);
    dir_info.strText  = QString::fromStdString(jsonString);

    kafka_data_list_mutex.lock();
    kafka_data_list.append(dir_info);
    kafka_data_list_mutex.unlock();

    delete req;
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////

int find_dev_index_from_dev_id(std::string dev_id)
{
	ied_t* ied = NULL;
	int			iedno;
	ied_usr_t* ied_usr = NULL;
	for (iedno = 0; iedno < g_node->n_clients; iedno++) {
		ied = g_node->clients[iedno];
		ied_usr = (ied_usr_t*)ied->usr_ext;
		if (ied_usr && strcmp(ied_usr->terminal_id, dev_id.c_str()) == 0) {
			return ied_usr->dev_idx;
		}

	}
	return 0;
}

int find_mp_index_from_mp_id(std::string line)
{
	LD_info_t* LD_info = NULL;
	LD_info = find_LD_info_only_from_mp_id((char*)line.c_str());
	if(LD_info == NULL){
		return 0;
	}
	else{
		return LD_info->line_id;
	}
	
}

char* find_mp_name_from_mp_id(const char* mp_id)
{
	LD_info_t* LD_info = NULL;
	LD_info = find_LD_info_only_from_mp_id((char*)mp_id);
	if(LD_info == NULL){
		return 0;
	}
	else{
		return LD_info->name;
	}
	
}

//int myMessageCallbackrtdata(CPushConsumer* consumer, CMessageExt* msg)
ConsumeStatus myMessageCallbackrtdata(
    const rocketmq::MQMessageExt& msg)
{
	if(INITFLAG != 1)return rocketmq::RECONSUME_LATER;//防止崩溃

	if (!should_process_after_start(msg)) {
	    std::cout << "[MQ] skip old message: "
	              << "topic=" << msg.getTopic()
	              << ", queueId=" << msg.getQueueId()
	              << ", offset=" << msg.getQueueOffset()
	              << ", bornTs=" << msg.getBornTimestamp()
	              << ", appStart=" << G_APP_START_MS
	              << std::endl;

	    return rocketmq::CONSUME_SUCCESS;
	}

    /*if (msg == NULL) {
        std::cerr << "Received null message." << std::endl;
        //return E_RECONSUME_LATER;
		return rocketmq::RECONSUME_LATER;
    }*/
	if (msg.getBody().empty()) {
	    std::cout << "empty msg body" << std::endl;
	}

    //const char* body = GetMessageBody(msg);
    //const char* key = GetMessageKeys(msg);
	std::string body = msg.getBody();
	std::string key  = msg.getKeys();
	std::string tag  = msg.getTags();
	std::string topic = msg.getTopic();

    //if (body == NULL) {
	if (body.empty()) {
        std::cerr << "Message body is NULL." << std::endl;
        //return E_RECONSUME_LATER;
		return rocketmq::RECONSUME_LATER;
    }
	else{
		//记录日志
		DIY_INFOLOG_CODE("process",0,LOG_CODE_RT_DATA,"【NORMAL】前置消费topic:%s_%s的实时触发消息",FRONT_INST.c_str(),G_MQCONSUMER_TOPIC_RT.c_str());

		// 处理消息（例如，打印消息内容）
    	std::cout << "rt data Callback received message: " << body << std::endl;
    	//if (key) {
		if (!key.empty()) {
    	    std::cout << "Message Key: " << key << std::endl;
    	}
    	else {
    	    std::cout << "Message Key: N/A" << std::endl;
    	}
		
		//处理消费数据
    	std::string devid, line;
    	bool realData, soeData;
    	int limit;
		// 解析 JSON 数据
    	if (!parseJsonMessageRT(body, devid, line, realData, soeData, limit)) {
    	    std::cerr << "Failed to parse the JSON message." << std::endl;
			//记录日志
			DIY_ERRORLOG_CODE("process",0,LOG_CODE_RT_DATA,"【ERROR】前置消费topic:%s_%s的实时触发消息失败,消息的json格式不正确",FRONT_INST.c_str(),G_MQCONSUMER_TOPIC_RT.c_str());
    	    //return E_RECONSUME_LATER;
			return rocketmq::RECONSUME_LATER;
    	}

		//mq处理实时数据指令查询台账时添加锁
		pthread_mutex_lock(&mtx);   std::cout << "rtdata hold lock !!!!!!!!!!!" << std::endl;

		int dev_index = find_dev_index_from_dev_id(devid);
		int mp_index = find_mp_index_from_mp_id(line);

		pthread_mutex_unlock(&mtx); std::cout << "rtdata free lock !!!!!!!!!!!" << std::endl;

		if(dev_index == 0 || mp_index == 0){
			std::cerr << "dev index or mp index is 0" << std::endl;
    	    //return E_RECONSUME_LATER;
			return rocketmq::RECONSUME_LATER;
		}
    	// 创建 XML 文件
    	if (!createXmlFile(dev_index, mp_index, realData, soeData, limit,"new")) {
			DIY_ERRORLOG_CODE("process",0,LOG_CODE_RT_DATA,"【ERROR】前置无法创建实时数据触发文件");
    	    std::cerr << "Failed to create the XML file." << std::endl;
    	    //return E_RECONSUME_LATER;
			return rocketmq::RECONSUME_LATER;
    	}
		
	}

    // 根据业务逻辑决定返回状态
    //return E_CONSUME_SUCCESS;
	return rocketmq::CONSUME_SUCCESS;
}

//int myMessageCallbackupdate(CPushConsumer* consumer, CMessageExt* msg)
ConsumeStatus myMessageCallbackupdate(
	const rocketmq::MQMessageExt& msg)
{
	if(INITFLAG != 1)return rocketmq::RECONSUME_LATER;//防止崩溃

	if (!should_process_after_start(msg)) {
	    std::cout << "[MQ] skip old message: "
	              << "topic=" << msg.getTopic()
	              << ", queueId=" << msg.getQueueId()
	              << ", offset=" << msg.getQueueOffset()
	              << ", bornTs=" << msg.getBornTimestamp()
	              << ", appStart=" << G_APP_START_MS
	              << std::endl;
		
	    return rocketmq::CONSUME_SUCCESS;
	}

    /*if (msg == NULL) {
        std::cerr << "Received null message." << std::endl;
        //return E_RECONSUME_LATER;
		return rocketmq::RECONSUME_LATER;
    }*/
	if (msg.getBody().empty()) {
	    std::cout << "empty msg body" << std::endl;
	}

    //const char* body = GetMessageBody(msg);
    //const char* key = GetMessageKeys(msg);
	std::string body = msg.getBody();
	std::string key  = msg.getKeys();
	std::string tag  = msg.getTags();
	std::string topic = msg.getTopic();

	//if (body == NULL) {
    if (body.empty()) {
        std::cerr << "Message body is empty." << std::endl;
        //return E_RECONSUME_LATER;
		return rocketmq::RECONSUME_LATER;
    }
	else{
		
		//处理消费数据
    	std::cout << "ledger update Callback received message: " << body << std::endl;
    	//if (key) {
		if (!key.empty()) {
    	    std::cout << "Message Key: " << key << std::endl;
    	}
    	else {
    	    std::cout << "Message Key: N/A" << std::endl;
    	}
		
		//处理台账更新消息
		if(RECALL_ONLY_FLAG != 1 || (g_node_id != STAT_DATA_BASE_NODE_ID)) {
			std::string updatefilepath = "/FeProject/etc/ledgerupdate";
			if(parse_control(body,updatefilepath)){
				DIY_ERRORLOG_CODE("process",0,LOG_CODE_LEDGER_UPDATE,"【ERROR】前置的%s%d号进程处理topic:%s_%s的台账更新消息失败,消息的json结构不正确",get_front_msg_from_subdir(), g_front_seg_index,FRONT_INST.c_str(),G_MQCONSUMER_TOPIC_UD.c_str());
			}
		}
		else{
			printf("only process recall config, skip ledger update\n");
			DIY_WARNLOG_CODE("process",0,LOG_CODE_SPACE_ALARM,"【WARN】当前配置为仅日志模式,统计数据进程跳过台账更新");
		}

	}

    // 根据业务逻辑决定返回状态
    //return E_CONSUME_SUCCESS;
	return rocketmq::CONSUME_SUCCESS;
}

//int myMessageCallbackset(CPushConsumer* consumer, CMessageExt* msg)
ConsumeStatus myMessageCallbackset(
	const rocketmq::MQMessageExt& msg)
{
	if(INITFLAG != 1)return rocketmq::RECONSUME_LATER;//防止崩溃

	if (!should_process_after_start(msg)) {
	    std::cout << "[MQ] skip old message: "
	              << "topic=" << msg.getTopic()
	              << ", queueId=" << msg.getQueueId()
	              << ", offset=" << msg.getQueueOffset()
	              << ", bornTs=" << msg.getBornTimestamp()
	              << ", appStart=" << G_APP_START_MS
	              << std::endl;
		
	    return rocketmq::CONSUME_SUCCESS;
	}

    /*if (msg == NULL) {
        std::cerr << "Received null message." << std::endl;
        //return E_RECONSUME_LATER;
		return rocketmq::RECONSUME_LATER;
    }*/
	if (msg.getBody().empty()) {
	    std::cout << "empty msg body" << std::endl;
	}

    //const char* body = GetMessageBody(msg);
    //const char* key = GetMessageKeys(msg);
	std::string body = msg.getBody();
	std::string key  = msg.getKeys();
	std::string tag  = msg.getTags();
	std::string topic = msg.getTopic();

    //if (body == NULL) {
	if (body.empty()) {
        std::cerr << "Message body is NULL." << std::endl;
        //return E_RECONSUME_LATER;
		return rocketmq::RECONSUME_LATER;
    }
	else{
		//处理消费数据
    	std::cout << "process Callback received message: " << body << std::endl;
    	//if (key) {
		if (!key.empty()) {
    	    std::cout << "Message Key: " << key << std::endl;
    	}
    	else {
    	    std::cout << "Message Key: N/A" << std::endl;
    	}
		
		//处理进程更新消息
		if(parse_set(body)){
			DIY_ERRORLOG_CODE("process",0,LOG_CODE_PROCESS_CONTROL,"【ERROR】前置的%s%d号进程处理topic:%s_%s的进程控制消息失败,消息的json结构不正确",get_front_msg_from_subdir(), g_front_seg_index,FRONT_INST.c_str(),G_MQCONSUMER_TOPIC_SET.c_str());
		}

	}

    // 根据业务逻辑决定返回状态
    //return E_CONSUME_SUCCESS;
	return rocketmq::CONSUME_SUCCESS;
}

//int myMessageCallbacklog(CPushConsumer* consumer, CMessageExt* msg)
ConsumeStatus myMessageCallbacklog(
	const rocketmq::MQMessageExt& msg)
{
	if(INITFLAG != 1)return rocketmq::RECONSUME_LATER;//防止崩溃

	if (!should_process_after_start(msg)) {
	    std::cout << "[MQ] skip old message: "
	              << "topic=" << msg.getTopic()
	              << ", queueId=" << msg.getQueueId()
	              << ", offset=" << msg.getQueueOffset()
	              << ", bornTs=" << msg.getBornTimestamp()
	              << ", appStart=" << G_APP_START_MS
	              << std::endl;
		
	    return rocketmq::CONSUME_SUCCESS;
	}

    /*if (msg == NULL) {
        std::cerr << "Received null message." << std::endl;
        //return E_RECONSUME_LATER;
		return rocketmq::RECONSUME_LATER;
    }*/
	if (msg.getBody().empty()) {
	    std::cout << "empty msg body" << std::endl;
	}

    //const char* body = GetMessageBody(msg);
    //const char* key = GetMessageKeys(msg);
	std::string body = msg.getBody();
	std::string key  = msg.getKeys();
	std::string tag  = msg.getTags();
	std::string topic = msg.getTopic();

    //if (body == NULL) {
	if (body.empty()) {
        std::cerr << "Message body is NULL." << std::endl;
        //return E_RECONSUME_LATER;
		return rocketmq::RECONSUME_LATER;
    }
	else{
		//处理消费数据
    	std::cout << "process Callback received message: " << body << std::endl;
    	//if (key) {
		if (!key.empty()) {
    	    std::cout << "Message Key: " << key << std::endl;
    	}
    	else {
    	    std::cout << "Message Key: N/A" << std::endl;
    	}
		
		//处理进程更新消息
		if(parse_log(body)){
			DIY_ERRORLOG_CODE("process",0,LOG_CODE_LOG_REQUEST,"【ERROR】前置的%s%d号进程处理topic:%s_%s的日志上送消息失败,消息的json结构不正确",get_front_msg_from_subdir(), g_front_seg_index,FRONT_INST.c_str(),G_MQCONSUMER_TOPIC_LOG.c_str());
		}

	}

    // 根据业务逻辑决定返回状态
    //return E_CONSUME_SUCCESS;
	return rocketmq::CONSUME_SUCCESS;
}

//int myMessageCallbackrecall(CPushConsumer* consumer, CMessageExt* msg)
ConsumeStatus myMessageCallbackrecall(
	const rocketmq::MQMessageExt& msg)
{
	if(INITFLAG != 1)return rocketmq::RECONSUME_LATER;//防止崩溃

	if (!should_process_after_start(msg)) {
	    std::cout << "[MQ] skip old message: "
	              << "topic=" << msg.getTopic()
	              << ", queueId=" << msg.getQueueId()
	              << ", offset=" << msg.getQueueOffset()
	              << ", bornTs=" << msg.getBornTimestamp()
	              << ", appStart=" << G_APP_START_MS
	              << std::endl;
		
	    return rocketmq::CONSUME_SUCCESS;
	}

	//调试
	std::cout << "myMessageCallbackrecall"<< std::endl;

    /*if (msg == NULL) {
        std::cerr << "Received null message." << std::endl;
        //return E_RECONSUME_LATER;
        return rocketmq::RECONSUME_LATER;
    }*/
	if (msg.getBody().empty()) {
	    std::cout << "empty msg body" << std::endl;
	}

    //const char* body = GetMessageBody(msg);
    //const char* key = GetMessageKeys(msg);
	std::string body = msg.getBody();
	std::string key  = msg.getKeys();
	std::string tag  = msg.getTags();
	std::string topic = msg.getTopic();

    //if (body == NULL) {
	if (body.empty()) {
        std::cerr << "Message body is NULL." << std::endl;
        //return E_RECONSUME_LATER;
        return rocketmq::RECONSUME_LATER;
    }
	else{
		// 处理消息（例如，打印消息内容）
    	std::cout << "recall Callback received message: " << body << std::endl;
    	//if (key) {
		if (!key.empty()) {
    	    std::cout << "Message Key: " << key << std::endl;
    	}
    	else {
    	    std::cout << "Message Key: N/A" << std::endl;
    	}
		//处理消费数据
		std::string result = extractDataJson(body.c_str());  // 使用 std::string 代替 malloc

		//调试
		std::cout << "extractDataJson:"<< result.c_str() <<std::endl;

    	if (!result.empty()) {
			pthread_mutex_lock(&mtx);	std::cout << "recall mq hold lock !!!!!!!!!!!" << std::endl;
        	recall_json_handle(result.c_str());  // 使用 c_str() 获取 const char* 类型
			pthread_mutex_unlock(&mtx); std::cout << "recall mq free lock !!!!!!!!!!!" << std::endl;
    	}
		else{
			std::cerr << "recall data is NULL." << std::endl;
			DIY_ERRORLOG_CODE("process",0,LOG_CODE_RECALL,"【ERROR】前置的%s%d号进程处理topic:%s_%s的补招触发消息失败,消息的json结构不正确",get_front_msg_from_subdir(), g_front_seg_index,FRONT_INST.c_str(),G_MQCONSUMER_TOPIC_RC.c_str());
		}
		
	}

    // 根据业务逻辑决定返回状态
    //return E_CONSUME_SUCCESS;
	return rocketmq::CONSUME_SUCCESS;
}

//int myMessageCallbackfile(CPushConsumer* consumer, CMessageExt* msg)
ConsumeStatus myMessageCallbackfile(
	const rocketmq::MQMessageExt& msg)
{
    if (INITFLAG != 1)return rocketmq::RECONSUME_LATER;

	if (!should_process_after_start(msg)) {
	    std::cout << "[MQ] skip old message: "
	              << "topic=" << msg.getTopic()
	              << ", queueId=" << msg.getQueueId()
	              << ", offset=" << msg.getQueueOffset()
	              << ", bornTs=" << msg.getBornTimestamp()
	              << ", appStart=" << G_APP_START_MS
	              << std::endl;
		
	    return rocketmq::CONSUME_SUCCESS;
	}

    /*if (msg == NULL) {
        std::cerr << "Received null message." << std::endl;
        //return E_RECONSUME_LATER;
        return rocketmq::RECONSUME_LATER;
    }*/
	if (msg.getBody().empty()) {
	    std::cout << "empty msg body" << std::endl;
	}

    //const char* body = GetMessageBody(msg);
    //const char* key = GetMessageKeys(msg);
	std::string body = msg.getBody();
	std::string key  = msg.getKeys();
	std::string tag  = msg.getTags();
	std::string topic = msg.getTopic();

    //if (body == NULL) {
	if (body.empty()) {
        std::cerr << "Message body is NULL." << std::endl;
        //return E_RECONSUME_LATER;
        return rocketmq::RECONSUME_LATER;
    }

	cJSON* outer = cJSON_Parse(body.c_str());
	if (!outer) {
	    std::cerr << "parse outer json failed" << std::endl;
	    return rocketmq::RECONSUME_LATER;
	}

	cJSON* messageBody = cJSON_GetObjectItem(outer, "messageBody");

	if (!messageBody ||
	    messageBody->type != cJSON_String ||
	    messageBody->valuestring == NULL)
	{
	    std::cerr << "messageBody invalid" << std::endl;
	    cJSON_Delete(outer);
	    return rocketmq::RECONSUME_LATER;
	}

	std::string realBody = messageBody->valuestring;

	cJSON_Delete(outer);

    DIY_INFOLOG_CODE("process",0,LOG_CODE_FILE_CONTROL,"【NORMAL】前置消费topic:%s_%s的文件控制消息",
                FRONT_INST.c_str(), G_MQCONSUMER_TOPIC_FILE.c_str());

    std::cout << "file Callback received message: " << realBody << std::endl;
    std::cout << "Message Key: " << (key.empty() ? "N/A" : key) << std::endl;

    file_dir_req_t req;
    if (ParseFileDirReq(realBody.c_str(), &req) != 0)
    {
        DIY_WARNLOG_CODE(req.devid,1,LOG_CODE_FILE_CONTROL,"【WARN】文件控制消息解析失败: %s", body);
        //return E_RECONSUME_LATER;
        return rocketmq::RECONSUME_LATER;
    }

    PushFileDirReq(&req);

    DIY_INFOLOG_CODE(req.devid,1, LOG_CODE_FILE_CONTROL,
                "【NORMAL】文件目录请求已入队 guid=%s devid=%s path=%s",
                req.guid, req.devid, req.path);

    //return E_CONSUME_SUCCESS;
	return rocketmq::CONSUME_SUCCESS;
}

//lnk20260424修改消费者topic去除id，id在配置文件中放入每个topic的tag
void mqconsumerThread::run()
{
	// 配置消费者参数
    std::string consumerName = G_ROCKETMQ_CONSUMER;//配置文件的消费者名称
    std::string nameServer = G_MQCONSUMER_IPPORT;            			// NameServer地址

	
	// 定义多个主题、标签及其对应的回调函数
    std::vector<Subscription> subscriptions;
	// 初始化消费者1 //lnk20241230只有实时进程会订阅实时topic，不订阅实时topic的进程无法触发实时数据
	if(g_node_id == THREE_SECS_DATA_BASE_NODE_ID){

		//lnk20260310添加文件管理
		subscriptions.push_back(Subscription(G_MQCONSUMER_TOPIC_FILE, G_MQCONSUMER_TAG_FILE, myMessageCallbackfile));
		subscriptions.push_back(Subscription(G_MQCONSUMER_TOPIC_RT, G_MQCONSUMER_TAG_RT, myMessageCallbackrtdata));
	}

	// 初始化消费者2 //所有进程都会订阅台账更新topic，不同功能进程的台账不能互相影响
	subscriptions.push_back(Subscription(G_MQCONSUMER_TOPIC_UD, G_MQCONSUMER_TAG_UD, myMessageCallbackupdate));

	// 初始化消费者3 //lnk20241230只有补招进程会订阅补招topic，不订阅补招topic的进程无法触发补招数据
	if(g_node_id == RECALL_HIS_DATA_BASE_NODE_ID){
		subscriptions.push_back(Subscription(G_MQCONSUMER_TOPIC_RC, G_MQCONSUMER_TAG_RC, myMessageCallbackrecall));
	}

	// 初始化消费者4 //lnk20250108只有稳态进程1会控制reset，
	subscriptions.push_back(Subscription(G_MQCONSUMER_TOPIC_SET, G_MQCONSUMER_TAG_SET, myMessageCallbackset));

	// 初始化消费者5 //所有进程都会订阅日志上送topic，不同功能进程的日志上送不能互相影响
	subscriptions.push_back(Subscription(G_MQCONSUMER_TOPIC_LOG, G_MQCONSUMER_TAG_LOG, myMessageCallbacklog));

    try {
        rocketmq_consumer_receive(consumerName, nameServer, subscriptions);
    }
    catch (const std::exception& e) {
        std::cerr << "Exception during consumerUD setup: " << e.what() << std::endl;
    }

    // 程序运行中，消费者会通过回调处理消息
    std::cout << "Consumer is running. " << std::endl;

}

//CZY 2023-08-23 get double class voltage level, if false will return 0;
double get_voltage_level(char voltage_level_char[]) {
	try
	{
		int n = atoi(voltage_level_char);

		switch (n)
		{
		case 1://交流6V
			return 0.006;
		case 2://交流12V
			return 0.012;
		case 3://交流24V
			return 0.024;
		case 4://交流36V
			return 0.036;
		case 5://交流48V
			return 0.048;
		case 6://交流110V
			return 0.11;
		case 7://交流220V
			return 0.22;
		case 8://交流380V（含400V）
			return 0.38;
		case 9://交流660V
			return 0.66;
		case 10://交流1000V（含1140V）
			return 1;
		case 11://交流600V
			return 0.6;
		case 12://交流750V
			return 0.75;
		case 13://交流1500V
			return 1.5;
		case 14://交流2000V
			return 2.0;
		case 15://交流2500V
			return 2.5;
		case 20://交流3kV
			return 3;
		case 21://交流6kV
			return 6;
		case 22://交流10kV
			return 10;
		case 23://交流15.75kV
			return 15.75;
		case 24://交流20kV
			return 20;
		case 25://交流35kV
			return 35;
		case 30://交流66kV
			return 66;
		case 31://交流72.5kV
			return 72.5;
		case 32://交流110kV
			return 110;
		case 33://交流220kV
			return 220;
		case 34://交流330kV
			return 330;
		case 35://交流500kV
			return 500;
		case 36://交流750kV
			return 750;
		case 37://交流1000kV
			return 1000;
		case 51://直流6V
			return 0.006;
		case 52://直流12V
			return 0.012;
		case 53://直流24V
			return 0.024;
		case 54://直流36V
			return 0.036;
		case 55://直流48V
			return 0.048;
		case 56://直流110V
			return 0.11;
		case 60://直流220V
			return 0.22;
		case 70://直流600V
			return 0.6;
		case 71://直流750V
			return 0.75;
		case 72://直流1500V
			return 1.5;
		case 73://直流3000V
			return 3.0;
		case 76://直流35kV
			return 35;
		case 77://直流30kV
			return 30;
		case 78://直流50kV
			return 50;
		case 80://直流120kV
			return 120;
		case 81://直流125kV
			return 125;
		case 82://直流400kV
			return 400;
		case 83://直流500kV
			return 500;
		case 84://直流660kV
			return 660;
		case 85://直流800kV
			return 800;
		case 86://直流1000kV
			return 1000;
		case 87://直流200kV
			return 200;
		case 88://直流320kV。
			return 320;
		default:
			return 0;
			break;
		}

	}
	catch (const std::exception&)
	{
		//error
		return 0;
	}
}

void try_start_kafka_thread()
{
	static int kafka_thread_created = 0;
	if (!kafka_thread_created) {
		myThrd.start();
		kafka_thread_created = 1;
	}
}

//lnk20241213
void try_start_mqconsumer_thread()
{
	static int mqconsumer_thread_created = 0;
	if (!mqconsumer_thread_created) {
		mqconsumerThrd.start();
		mqconsumer_thread_created = 1;
	}
}

/////////////////////////////////////////////////////////////////////////
json_block_data json_blkd;

//CZY 2023-08-17 WW 2022年12月6日14:09:08 增加多个ICD支持
//json_block_data json_blkd; //json拼接参数类对象,原有的一个数据对象，在多ICD下会出现数据错位问题
//解决方案是将此数据放入LDInfo结构中存储，保证一条线路一个json拼接参数类对象
void init_json_block_data(char mp_id[], char voltage_level[], int flicker_flag)//WW 2023年3月13日16:38:41 多ICD修改
{

	json_block_data* pdata;
	if (flicker_flag == 1) {
		if (!json_flicker_data_map.contains(mp_id))
		{
			pdata = new json_block_data();
			json_flicker_data_map.insert(mp_id, pdata);
		}
		pdata = json_flicker_data_map.value(mp_id);
	}
	else if (flicker_flag == 0) {
		if (!json_data_map.contains(mp_id))
		{
			pdata = new json_block_data();
			json_data_map.insert(mp_id, pdata);
		}
		pdata = json_data_map.value(mp_id);
	}
	else if (flicker_flag == 2) {
		if (!json_pst_data_map.contains(mp_id))
		{
			pdata = new json_block_data();
			json_pst_data_map.insert(mp_id, pdata);
		}
		pdata = json_pst_data_map.value(mp_id);
	}

	if (pdata == NULL)
		return;
	pdata->monitorId = -1;
	QString tmp;
	tmp.append(mp_id);
	pdata->mp_id = tmp;
	pdata->func_type = g_node_id;
	//flag 是品质， 异常送1， 正常送0
	pdata->flag = 0;   // //剔除标记，1不剔除，0剔除，默认剔除 
	pdata->mms_str_map.clear();
	pdata->voltage_level = get_voltage_level(voltage_level); //CZY 2023-08-23 add voltage_level
}



int json_block_create_start(char voltage_level[], char monid_char[], int flicker_flag, char temcode[], int line_id)//WW 2023年3月13日16:38 : 41 多ICD修改
{
	try_start_kafka_thread();

	init_json_block_data(monid_char, voltage_level, flicker_flag);
	json_block_data* pdata;
	if (flicker_flag == 1) {
		if (!json_flicker_data_map.contains(monid_char))//未查到数据
			return 0;
		pdata = json_flicker_data_map.value(monid_char);
	}
	else if (flicker_flag == 0)
	{
		if (!json_data_map.contains(monid_char))//未查到数据
			return 0;
		pdata = json_data_map.value(monid_char);
	}
	else if (flicker_flag == 2)
	{
		if (!json_pst_data_map.contains(monid_char))//未查到数据
			return 0;
		pdata = json_pst_data_map.value(monid_char);
	}

	if (pdata != NULL)
	{
		pdata->dev_type.append(temcode);
		pdata->monitorId = line_id;
		if (strlen(monid_char) != 0) {
			QString tmp;
			tmp.append(monid_char);
			pdata->mp_id = tmp;
		}
		else {
			monid_char = "not define";
			QString tmp;
			tmp.append(monid_char);
			pdata->mp_id = tmp;
		}
	}

	printf("\n\n---------- json_block_create_start: mp_id=%s,voltage_level=%s,line_id=%d \n", monid_char, voltage_level, line_id);
	return TRUE;
}


int json_block_create_time(char monid_char[], long long Time, int flicker_flag)//WW 2023年3月13日16:38:41 多ICD修改
{
	json_block_data* pdata;
	if (flicker_flag == 1) {
		if (!json_flicker_data_map.contains(monid_char))//未查到数据
			return 0;
		pdata = json_flicker_data_map.value(monid_char);
	}
	else if (flicker_flag == 0)
	{
		if (!json_data_map.contains(monid_char))//未查到数据
			return 0;
		pdata = json_data_map.value(monid_char);
	}
	else if (flicker_flag == 2)
	{
		if (!json_pst_data_map.contains(monid_char))//未查到数据
			return 0;
		pdata = json_pst_data_map.value(monid_char);
	}

	if (pdata != NULL)
		pdata->time = Time;
	printf("\njson_block_create_time: mp_id=%s,Time=%lld \n", monid_char, Time);
	return TRUE;
}


int json_block_create_flag(char monid_char[], int flag, int flicker_flag)//WW 2023年3月13日16:38:41 多ICD修改
{
	json_block_data* pdata;
	if (flicker_flag == 1) {
		if (!json_flicker_data_map.contains(monid_char))//未查到数据
			return 0;
		pdata = json_flicker_data_map.value(monid_char);
	}
	else if (flicker_flag == 0)
	{
		if (!json_data_map.contains(monid_char))//未查到数据
			return 0;
		pdata = json_data_map.value(monid_char);
	}
	else if (flicker_flag == 2)
	{
		if (!json_pst_data_map.contains(monid_char))//未查到数据
			return 0;
		pdata = json_pst_data_map.value(monid_char);
	}

	if (pdata != NULL)
		pdata->flag = flag;
	printf("\njson_block_create_flag: mp_id=%s,flag=%d \n", monid_char, flag);
	return TRUE;
}



int json_block_create_data(char monid_char[], char* mms_str, double v, int flicker_flag)//WW 2023年3月13日16:38:41 多ICD修改
{
	json_block_data* pdata;
	if (flicker_flag == 1) {
		if (!json_flicker_data_map.contains(monid_char))//未查到数据
			return 0;
		pdata = json_flicker_data_map.value(monid_char);
	}
	else if (flicker_flag == 0)
	{
		if (!json_data_map.contains(monid_char))//未查到数据
			return 0;
		pdata = json_data_map.value(monid_char);
	}
	else if (flicker_flag == 2)
	{
		if (!json_pst_data_map.contains(monid_char))//未查到数据
			return 0;
		pdata = json_pst_data_map.value(monid_char);
	}

	static int count = 0;
	if (pdata != NULL)
	{
		pdata->mms_str_map.insert(QString::fromAscii(mms_str), v);
		if (strstr(mms_str, "MMXU2$MX$PhV")){
			pdata->data_have_statistic = 1;
			printf("---------- json_block_create_data: mp_id= %s ,mms_str=%s value=%fkV----------\n", monid_char, mms_str, v);
		}
			
	}
	return TRUE;
}

static QString json_trace_block_key(char monid_char[], int flicker_flag, int rpt_no)
{
	QString key;
	key.append(monid_char ? monid_char : "");
	key.append("|");
	key.append(QString::number(flicker_flag));
	key.append("|");
	key.append(QString::number(rpt_no));
	return key;
}

static json_block_data* get_json_trace_block_data(char monid_char[], int flicker_flag, int rpt_no)
{
	QString key = json_trace_block_key(monid_char, flicker_flag, rpt_no);
	if (!json_trace_data_map.contains(key))
		return NULL;
	return json_trace_data_map.value(key);
}

static void init_json_trace_block_data(char monid_char[], char voltage_level[], int flicker_flag, int rpt_no)
{
	QString key = json_trace_block_key(monid_char, flicker_flag, rpt_no);
	json_block_data* pdata = NULL;
	if (!json_trace_data_map.contains(key)) {
		pdata = new json_block_data();
		json_trace_data_map.insert(key, pdata);
	}

	pdata = json_trace_data_map.value(key);
	pdata->monitorId = -1;
	pdata->func_type = g_node_id;
	pdata->flag = 0;
	pdata->time = 0;
	pdata->voltage_level = get_voltage_level(voltage_level);
	pdata->mp_id = monid_char ? QString::fromLocal8Bit(monid_char) : QString("not define");
	pdata->dev_type.clear();
	pdata->mms_str_map.clear();
	pdata->data_have_statistic = 0;
}

int json_trace_block_create_start(char voltage_level[], char monid_char[], int flicker_flag, char temcode[], int line_id, char v_wiring_type[], char rpt_id[], int rpt_no)
{
	(void)v_wiring_type;
	(void)rpt_id;
	if (!trace_json_is_enabled(monid_char, rpt_no))
		return 0;

	try_start_kafka_thread();
	init_json_trace_block_data(monid_char, voltage_level, flicker_flag, rpt_no);

	json_block_data* pdata = get_json_trace_block_data(monid_char, flicker_flag, rpt_no);
	if (pdata != NULL) {
		pdata->dev_type.append(temcode ? temcode : "");
		pdata->monitorId = line_id;
	}

	return TRUE;
}

int json_trace_block_create_time(char monid_char[], long long Time, int flicker_flag, char rpt_id[], int rpt_no)
{
	(void)rpt_id;
	json_block_data* pdata = get_json_trace_block_data(monid_char, flicker_flag, rpt_no);
	if (pdata == NULL)
		return 0;

	pdata->time = Time;
	return TRUE;
}

int json_trace_block_create_flag(char monid_char[], int flag, int flicker_flag, char rpt_id[], int rpt_no)
{
	(void)rpt_id;
	json_block_data* pdata = get_json_trace_block_data(monid_char, flicker_flag, rpt_no);
	if (pdata == NULL)
		return 0;

	pdata->flag = flag;
	return TRUE;
}

int json_trace_block_create_data(char monid_char[], char* mms_str, double v, int flicker_flag, char rpt_id[], int rpt_no)
{
	(void)rpt_id;
	json_block_data* pdata = get_json_trace_block_data(monid_char, flicker_flag, rpt_no);
	if (pdata == NULL)
		return 0;

	pdata->mms_str_map.insert(QString::fromAscii(mms_str), v);
	return TRUE;
}

int json_trace_block_create_end(char v_wiring_type[], char monid_char[], int flicker_flag, char rpt_id[], int rpt_no)
{
	QString key = json_trace_block_key(monid_char, flicker_flag, rpt_no);
	if (!json_trace_data_map.contains(key))
		return 1;

	json_block_data* pdata = json_trace_data_map.value(key);
	if (pdata == NULL) {
		json_trace_data_map.remove(key);
		return 1;
	}

	int ret = 1;
	if (pdata->mms_str_map.count() > 0)
		ret = trace_json_block_data(v_wiring_type, pdata, rpt_id, rpt_no);

	delete pdata;
	json_trace_data_map.remove(key);
	return ret;
}


//lnk2024-8-16添加接线参数
int json_block_create_end(char v_wiring_type[], char monid_char[], int flicker_flag)//WW 2023年3月13日16:38:41 多ICD修改
{
	json_block_data* pdata;
	if (flicker_flag == 1) {
		if (!json_flicker_data_map.contains(monid_char))//未查到数据
		{
			printf("---------- json_block_create_end: mp_id= %s json_flicker_data_map can't find MonitorId----------\n", monid_char);
			return 1;
		}
		pdata = json_flicker_data_map.value(monid_char);
	}
	else if (flicker_flag == 0)
	{
		if (!json_data_map.contains(monid_char))//未查到数据
		{
			printf("---------- json_block_create_end: mp_id= %s json_data_map can't find MonitorId----------\n", monid_char);
			return 1;
		}
		pdata = json_data_map.value(monid_char);
	}
	else if (flicker_flag == 2)
	{
		if (!json_pst_data_map.contains(monid_char))//未查到数据
		{
			printf("---------- json_block_create_end: mp_id= %s json_pst_data_map can't find MonitorId----------\n", monid_char);
			return 1;
		}
		pdata = json_pst_data_map.value(monid_char);
	}

	//调试用
	/*if (pdata != nullptr) {
	    printf("monitorId: %d\n", pdata->monitorId);
	    printf("func_type: %d\n", pdata->func_type);
	    printf("flag: %d\n", pdata->flag);
	    printf("time: %lld\n", pdata->time);
	    printf("voltage_level: %f\n", pdata->voltage_level);
	    printf("mp_id: %s\n", pdata->mp_id.toStdString().c_str());
	    printf("dev_type: %s\n", pdata->dev_type.toStdString().c_str());
	    printf("mms_str_map count: %d\n", pdata->mms_str_map.size());
	} else {
	    printf("pdata is NULL\n");
	}*/

	if (pdata->mms_str_map.count() == 0) {
		if (flicker_flag == 1) {
			json_flicker_data_map.remove(monid_char);
		}
		else if (flicker_flag == 0)
		{
			json_data_map.remove(monid_char);

		}
		else if (flicker_flag == 2)
		{
			json_pst_data_map.remove(monid_char);

		}
		printf("---------- json_block_create_end: mp_id= %s pdata->mms_str_map.count() == 0 ----------\n", monid_char);
		return 1;
	}
	//lnk2024-8-16添加接线参数
	int ret = transfer_json_block_data(v_wiring_type, pdata);

	if (pdata != NULL)
		delete pdata;
	if (flicker_flag == 1) {
		json_flicker_data_map.remove(monid_char);
	}
	else if (flicker_flag == 0)
	{
		json_data_map.remove(monid_char);

	}
	else if (flicker_flag == 2)
	{
		json_pst_data_map.remove(monid_char);

	}
	printf("---------- json_block_create_end: MonitorId= %s ----------\n", monid_char);
	return ret;
}

//////////////////////////////////////////////////////////////////////////////

void clear_old_comtrade_files()
{
	if (g_node_id != SOE_COMTRADE_BASE_NODE_ID)
		return;

	QString full_fn_str;
	QString dir_name("../comtrade/");
	QDir directory_comtrade(dir_name);
	QStringList fileNames = directory_comtrade.entryList(QDir::Files | QDir::NoDotAndDotDot, QDir::Time);

	if (fileNames.size() <= comtrade_remain_file_num)
		return;

	for (QStringList::size_type i = comtrade_remain_file_num; i != fileNames.size(); ++i) {
		full_fn_str = dir_name + fileNames.at(i);
		QFile::remove(full_fn_str);
	}
}

/////////////////////////////////////////////

int process_login_verify()
{
	int	 length = 64;
	char password[64 + 1];
	char* p = NULL;
	int count = 0;
	char encode_password[256];
	const char* passwordConfirm = "1c0e4e104de596846648ba495bd32601";

	memset(password, 0, sizeof(password));
	printf("Please input password : \n");
	p = password;
	count = 0;

	system("stty -echo");
	std::cin.getline(password, 64);
	system("stty echo");

	password[length] = '\0';

	MyGetSM4Code(password, (unsigned char*)"epri.sgcc.com.cn", encode_password);

	return (strcmp(encode_password, passwordConfirm));


}


///////////////////////////////////////////

void try_start_socket_thread()
{
	static int socket_thread_created = 0;
	if (!socket_thread_created) {
		socketThrd.start();
		socket_thread_created = 1;
	}
}

//lnk20241029
void try_start_web_http_thread()
{
	static int webhttp_thread_created = 0;
	if (!webhttp_thread_created) {
		webhttpThrd.start();
		webhttp_thread_created = 1;
	}
}
void try_start_http_thread()
{
	static int http_thread_created = 0;
	if (!http_thread_created) {
		httpThrd.start();
		http_thread_created = 1;
	}
}
//lnk20241202
int try_start_mqtest_thread(int argc, char *argv[])
{
	//不使用简单的循环线程，而是启动一个app，不仅执行循环线程，而且可以连接输入
	//安装qt打印
	qInstallMsgHandler(myQtMsgHandler);
	
	QCoreApplication a(argc, argv);

    // 创建 QThread 和 Worker 对象
    QThread *thread = new QThread();
    Worker *worker = new Worker();

    // 将 Worker 对象移动到 QThread 中
    worker->moveToThread(thread);

    // 连接信号和槽
    QObject::connect(thread, SIGNAL(started()), worker, SLOT(startServer()));
    QObject::connect(worker, SIGNAL(serverError()), thread, SLOT(quit()));
    QObject::connect(worker, SIGNAL(serverError()), worker, SLOT(deleteLater()));
    QObject::connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));

    // 启动线程
    thread->start();

    // 确保在应用退出时，线程也能正确退出
    QObject::connect(&a, SIGNAL(aboutToQuit()), thread, SLOT(quit()));

    return a.exec();
}

void try_start_ontimer_thread()
{
	static int ontimer_thread_created = 0;
	if (!ontimer_thread_created) {
		onTimerThrd.start();
		ontimer_thread_created = 1;
	}
}
//WW 2023-08-22 end

///////////////////////////////////////////
//ZW 2024-01-31 补招数据模式优化
static QMap<QString, int> mvl_type_ctrl_map;//ZW 2024-01-31 用于保存单次获取的模型
static int mvl_type_ctrl_map_size;//计数
//添加doname对应的数据模型
void add_mvl_type_ctrl(char doname[], int ctrl)
{
	if (!mvl_type_ctrl_map.contains(doname))
	{
		mvl_type_ctrl_map.insert(doname, ctrl);
	}
}

//删除map中所有数据模型
void del_mvl_type_ctrl()
{
	for (QMap<QString, int>::iterator it = mvl_type_ctrl_map.begin(); it != mvl_type_ctrl_map.end(); ++it) {
		QString key = it.key();
		int value = it.value();
		mvl_type_id_destroy(value);
	}
	mvl_type_ctrl_map.clear();
}

int get_mvl_type_ctrl_map_size() 
{
	return mvl_type_ctrl_map.count();
}
//查找对应doname的数据模型是否存在map中
int sel_mvl_type_ctrl_flag(char doname[])
{
	if (mvl_type_ctrl_map.contains(doname))
	{
		return mvl_type_ctrl_map.value(doname);
	}
	else
	{
		return -1;
	}
}
//ZW 2024-01-31 end
