添加Openssl,Gmssl加密库

This commit is contained in:
lixiaoyuan
2025-09-22 20:01:41 +08:00
parent ee98556eec
commit 6878952da8
240 changed files with 48082 additions and 2724 deletions

View File

@@ -71,6 +71,7 @@ include_directories(
${THIRDPARTY_PATH}/spdlog-1.13.0/include
${THIRDPARTY_PATH}/OpenXLSX/include
${THIRDPARTY_PATH}/GmSSL-3.1.1/include
${THIRDPARTY_PATH}/OpenSSL-3.5.3/include
#${PVLIBS_PATH}/include/pvserver
#${PVLIBS_PATH}/include/rllib
)
@@ -108,7 +109,7 @@ target_link_libraries(${PROJECT_NAME}
${THIRDPARTY_PATH}/paho_mqtt/lib/paho-mqtt3c.lib
${THIRDPARTY_PATH}/OpenXLSX/lib/OpenXLSX.lib
${THIRDPARTY_PATH}/GmSSL-3.1.1/lib/gmssl.lib
${THIRDPARTY_PATH}/OpenSSL-3.5.3/lib/VC/x64/MD/libcrypto.lib
#${PVLIBS_PATH}/x64/serverlib.lib
#${PVLIBS_PATH}/x64/rllib.lib
)

View File

@@ -115,7 +115,7 @@ void Application::runThreadStat()
while (!isQuit)
{
static TimeTick ttStat(1);
if(ttStat.elapse(10))
if(Config::option.stat.enabled && ttStat.elapse(Config::option.stat.interval))
{
// 设备历史数据(电压、电流、功率),存储到 history_day
// 统计数据,存储到 stat_day

View File

@@ -24,6 +24,7 @@ bool Config::init(std::string filename)
JSON::read(jsonroot, "weburl", option.webSrvUrl);
JSON::read(jsonroot, "launchdate", option.lunchDate);
JSON::read(jsonroot, "exportpath", option.exportpath);
JSON::read(jsonroot, "windowEnabled", option.windowEnabled);
if (jsonroot.contains("database"))
{
@@ -110,6 +111,14 @@ bool Config::init(std::string filename)
JSON::read(jsonItem, "enabled", info.enabled);
}
}
if (jsonroot.contains("statistics"))
{
njson& json = jsonroot["statistics"];
JSON::read(json, "enabled", option.stat.enabled);
JSON::read(json, "interval", option.stat.interval);
if (option.stat.interval <= 0) { option.stat.interval = 60; }
}
return true;
}

View File

@@ -46,6 +46,12 @@ struct AppOption
std::map<std::string, VideoInfo> mapVideo;
int windowEnabled {0};
struct {
int enabled {0};
int interval {60};
} stat;
};
class Config

View File

@@ -2,18 +2,8 @@
#include "common/JsonN.h"
#include "common/Utils.h"
std::string REGAddrOffset(std::string addr, int offset)
{
unsigned int val;
std::stringstream ss;
ss << std::hex << addr;
ss >> val;
return Utils::toHexStr(val + offset);
}
std::map<std::string, std::map<std::string, RegAddrUnit>> REGAddr::s_mapReg;
void REGAddr::load(std::string filename)
{
njson json;

View File

@@ -32,7 +32,7 @@ enum class EDeviceType
PCU = 103, //103 PCU 1
BMS = 104, //104 BMS 1
BCU = 105, //105 BCU 1
//106 充电桩 2
CHARGER = 106, //106 充电桩 2
//107 充电枪 2
//108 集中器 2
//109 光伏板 3

View File

@@ -241,16 +241,16 @@ bool Device::cache(int npos)
if (iter != s_mapDeviceAddrCurve.end())
{
auto& vecAddr = iter->second;
auto size = addrV.size();
auto size = vecAddr.size();
if (size >= 1) { addrV = vecAddr[0]; }
else if (size >= 2) { addrI = vecAddr[1]; }
else if (size >= 3) { addrP = vecAddr[2]; }
if (size >= 2) { addrI = vecAddr[1]; }
if (size >= 3) { addrP = vecAddr[2]; }
}
// 根据设备类型从参数(寄存器地址)中读取实时数据进行保存
int U = Utils::toInt(this->getParam(addrV, "0"));
int I = Utils::toInt(this->getParam(addrI, "0"));
int P = addrP.empty() ? U*I : Utils::toInt(this->getParam(addrP, "0"));
int P = addrP.empty() ? U*I*0.001 : Utils::toInt(this->getParam(addrP, "0"));
mapCacheVoltage[npos] = U;
mapCacheCurrent[npos] = I;
mapCachePower[npos] = P;
@@ -299,33 +299,33 @@ void Device::setParam(std::string k, int v)
{
running = 1;
}
else if (type == 101) // EMS
else if (type == int(EDeviceType::EMS)) // 101 EMS
{
running = 1;
}
else if (type == 102) // PCS
else if (type == int(EDeviceType::PCS)) // 102 PCS
{
if (k == "0x1003") err = v; // 故障状态 R uint16 1故障0正常 0 0x1003
else if (k == "0x1005") online = v; // 设备在线 R uint16 1在线0无效 1 0x1005
else if (k == "0x1009") running = (v==1 || v==2); //充放状态 R uint16 0待机, 1充电, 2放电, 3搁置 0 0x1009
}
else if (type == 103) // PCU
else if (type == int(EDeviceType::PCU)) // 103 PCU
{
if (k == "0x1002") err = v; //故障状态 R uint16 1故障0正常 0 0x1002
else if (k == "0x1004") online = v; //设备在线 R uint16 1在线0无效 1 0x1004
else if (k == "0x1006") running = v; //启停状态 R uint16 1开机0关机 1 0x1006
}
else if (type == 104) // BMS
else if (type == int(EDeviceType::BMS)) // 104 BMS
{
if (k == "0x004A") { err = (v==1); } //运行状态 R uint16 0 运行状态 0-正常 1-告警 2-保护 0x004A
else if (k == "0x004B") running = (v==1 || v==2); //充放电状态 R uint16 0 0-待机 1-充电 2-放电 0x004B
if (k == "0x0049") { err = (v==1); } //运行状态 R uint16 0 运行状态 0-正常 1-告警 2-保护 0x0049
else if (k == "0x004A") { running = (v==1 || v==2); } //充放电状态 R uint16 0 0-待机 1-充电 2-放电 0x004A
}
else if (type == int(EDeviceType::BCU)) // BCU
{
if (k == "0xA003") { running = (v==0x33 || v==0x44); } //蓄电池充放电状态 R uint16 "0x11开路,0x22待机,0x33充电,0x44放电" 34 0xA003
else if (k == "0xA004") { err = (v==0x55); } //电池组运行状态 R uint16 "0x11跳机,0x22待机,0x33放空,0x44充满,0x55预警,0x66正常" 102 0xA004
}
else if (type == 106) // 充电桩
else if (type == int(EDeviceType::CHARGER)) // 106 充电桩
{
if (k == "21") {
running = (mapParams["11"] == "充电" || mapParams["21"] == "充电"); // 充电状态: 0空闲1充电

View File

@@ -205,16 +205,23 @@ void Station::checkDevice()
}
}
void Station::readAlert(std::shared_ptr<Device> device, int v, std::string text)
void Station::readAlert(std::shared_ptr<Device> device, std::string addr, int v, std::string text)
{
Fields fields;
fields.set("log_id", Snowflake::instance().getIdStr());
if (device) { fields.set("device_id", device->deviceId); }
fields.set("type", int(EAlertType::DEVICE));
fields.set("context", text + ":故障(" + std::to_string(v) + ")");
fields.set("status", 1);
auto dao = DaoEntity::create("log_alert");
dao->insertFields(fields);
int64_t ts = Utils::time();
std::string alertId = std::to_string(device->deviceId) + "_" + addr;
int tsCache = mapAlertCache[alertId];
if (ts - tsCache > 60*5)
{
Fields fields;
fields.set("log_id", Snowflake::instance().getIdStr());
if (device) { fields.set("device_id", device->deviceId); }
fields.set("type", int(EAlertType::DEVICE));
fields.set("content", text + ":故障(" + std::to_string(v) + ")");
fields.set("status", 1);
auto dao = DaoEntity::create("log_alert");
dao->insertFields(fields);
mapAlertCache[alertId] = ts;
}
}
void Station::readRuntimeData(int deviceNo, string addr, int val)
@@ -360,12 +367,13 @@ void Station::writeStatistic()
std::string dt = Utils::dateStr();
int64_t tTime = Utils::time();
int64_t tDate = Utils::date();
int64_t tDelta = tTime - tDate;
int npos = (tTime-tDate) / 600;
for (auto iter = mapDevice.begin(); iter!=mapDevice.end(); ++iter)
{
auto device = iter->second;
if (device->cache(npos))
if (device->cache(npos) && device->type == int(EDeviceType::BMS))
{
Fields fields;
fields.set("dt", dt);
@@ -391,7 +399,6 @@ void Station::writeStatistic()
Fields fields;
fields.set("dt", Utils::dateStr(statData.ts));
fields.set("station_id", this->stationId);
fields.set("category", 1);
fields.set("device_id", 0);
fields.set("elect_in", statData.dayElectIn);
fields.set("elect_out", statData.dayElectOut);

View File

@@ -114,7 +114,7 @@ public:
void setGarewayWorkMode();
void checkDevice();
void readAlert(std::shared_ptr<Device> device, int v, std::string text);
void readAlert(std::shared_ptr<Device> device, std::string addr, int v, std::string text);
void readRuntimeData(int deviceNo, string addr, int val);
void readTHData(int deviceNo, string addr, int val);
void readFire40Data(int deviceNo, string addr, int val);
@@ -123,6 +123,7 @@ public:
void readGatewayStatus(int cdzStatus, int emuStatus);
void writeStatistic();
int posDayStat {0};
public:
int stationId {};
@@ -244,4 +245,6 @@ public:
int cdzStatus {-1};
int emuStatus {-1};
std::map<std::string, int64_t> mapAlertCache;
};

View File

@@ -150,6 +150,79 @@ string Crypto::md5(string src)
return md5_format(tempA) + md5_format(tempB) + md5_format(tempC) + md5_format(tempD);
}
#include "common/Utils.h"
static std::vector<uint8_t> hexToByte(const std::string& hexstr)
{
std::vector<uint8_t> v;
v.reserve(hexstr.size() / 2);
for (std::string::const_iterator it = hexstr.begin(); it != hexstr.end(); it += 2)
{
v.push_back(static_cast<char>(strtol(std::string(it, it + 2).c_str(), nullptr, 16)));
}
return v;
}
std::string Crypto::gmssl_sm2Encrypt(std::string pubKeyHex, std::string priKeyHex, std::string plainByte)
{
std::vector<uint8_t> pub_key = hexToByte(pubKeyHex);
std::vector<uint8_t> pri_keyBuf = hexToByte(priKeyHex);
sm2_z256_t pri_key {0};
sm2_z256_from_bytes(pri_key, pri_keyBuf.data());
SM2_KEY sm2k;
sm2_key_set_public_key(&sm2k, (SM2_Z256_POINT*)pub_key.data()); // +1 跳过 0x04 标记
sm2_key_set_private_key(&sm2k, pri_key);
sm2_key_print(stderr, 0, 4, "SM2_KEY", &sm2k);
//std::vector<uint8_t> plainText(plainByte.begin(), plainByte.end());
std::vector<uint8_t> ciphertext(SM2_MAX_CIPHERTEXT_SIZE);
size_t ciphertext_len = 0;
int ret = sm2_encrypt(&sm2k, (const uint8_t*)plainByte.data(), plainByte.size(), ciphertext.data(), &ciphertext_len);
return std::string(ciphertext.begin(), ciphertext.begin()+ciphertext_len);
}
std::string Crypto::gmssl_sm2Decrypt(std::string pubKeyHex, std::string priKeyHex, std::string cipherByte)
{
std::vector<uint8_t> pub_key = hexToByte(pubKeyHex);
std::vector<uint8_t> pri_keyBuf = hexToByte(priKeyHex);
sm2_z256_t pri_key {0};
sm2_z256_from_bytes(pri_key, pri_keyBuf.data());
SM2_KEY sm2k;
sm2_key_set_public_key(&sm2k, (SM2_Z256_POINT*)pub_key.data()); // +1 跳过 0x04 标记
sm2_key_set_private_key(&sm2k, pri_key);
sm2_key_print(stderr, 0, 4, "SM2_KEY", &sm2k);
//std::string ciphertHex = "44d37f6c644f22508b5387663e3a174384917eba7ce3b2a5bb9f79e191d40dfc6c0cfaf1819af562c1ee1bffcc55d2fb1da8114527e3a6993aaadda12a26b4b6f688ecd5d7700c8bd82a069ab4b30e0b499eef82d1dfeea261d2fd19d1f0ae95a4b3fd";
//Utils::toHex(ciphertext, ciphertext_len);
//std::vector<uint8_t> buf = hexToByte(ciphertHex);
std::vector<uint8_t> plainText(SM2_MAX_PLAINTEXT_SIZE);
size_t len = 0;
int ret = sm2_decrypt(&sm2k, (const uint8_t*)cipherByte.data(), cipherByte.size(), plainText.data(), &len);
return std::string(plainText.begin(), plainText.begin() + len);
}
string Crypto::sm3(std::string data)
{
SM3_CTX ctx;
sm3_init(&ctx);
sm3_update(&ctx, (const unsigned char*)data.data(), data.length());
std::vector<unsigned char> digest(SM3_DIGEST_SIZE);
sm3_finish(&ctx, digest.data());
std::stringstream ss;
for (int i = 0; i < digest.size(); ++i)
{
ss << std::hex << std::setw(2) << std::setfill('0') << (int)digest[i];
}
return ss.str();
}
std::vector<uint8_t> Crypto::sm4EcbEncrypt(const std::vector<uint8_t>& key, const std::vector<uint8_t>& plaintext)
{
SM4_KEY sm4_key;
@@ -172,4 +245,175 @@ std::vector<uint8_t> Crypto::sm4EcbDecrypt(const std::vector<uint8_t>& key, cons
sm4_encrypt(&sm4_key, &ciphertext[i], &plaintext[i]); // 注意解密时也是用sm4_encrypt函数但密钥是解密密钥
}
return plaintext;
}
// 错误处理函数
static void HandleOpensslError()
{
ERR_print_errors_fp(stderr);
unsigned long err = ERR_get_error();
}
// SM2 加密函数
std::string Crypto::ssl_sm2Encrypt(const std::string& public_key_hex, const std::string& plaintext)
{
EVP_PKEY* pubkey = Crypto::create_sm2_public_key_from_hex(public_key_hex);
EVP_PKEY_CTX* ctx = EVP_PKEY_CTX_new(pubkey, NULL);
if (!ctx) HandleOpensslError();
if (EVP_PKEY_encrypt_init(ctx) <= 0) HandleOpensslError();
// 获取加密后数据的长度
size_t ciphertext_len;
if (EVP_PKEY_encrypt(ctx, NULL, &ciphertext_len, (const uint8_t*)plaintext.data(), plaintext.size()) <= 0) {
HandleOpensslError();
}
// 执行加密
std::vector<unsigned char> ciphertext(ciphertext_len);
if (EVP_PKEY_encrypt(ctx, ciphertext.data(), &ciphertext_len, (const uint8_t*)plaintext.data(), plaintext.size()) <= 0) {
HandleOpensslError();
}
// 清理资源
EVP_PKEY_CTX_free(ctx);
EVP_PKEY_free(pubkey);
// 清理 OpenSSL
EVP_cleanup();
ERR_free_strings();
return std::string(ciphertext.begin(), ciphertext.begin() + ciphertext_len);
}
// SM2 解密函数
std::string Crypto::ssl_sm2Decrypt(const std::string& private_key_hex, const std::string& ciphertext)
{
EVP_PKEY* privkey = Crypto::create_sm2_private_key_from_hex(private_key_hex);
EVP_PKEY_CTX* ctx = EVP_PKEY_CTX_new(privkey, NULL);
if (!ctx) HandleOpensslError();
if (EVP_PKEY_decrypt_init(ctx) <= 0) HandleOpensslError();
// 获取解密后数据的长度
size_t plaintext_len;
if (EVP_PKEY_decrypt(ctx, NULL, &plaintext_len, (const uint8_t*)ciphertext.data(), ciphertext.size()) <= 0) {
HandleOpensslError();
}
// 执行解密
std::vector<unsigned char> plaintext(plaintext_len);
if (EVP_PKEY_decrypt(ctx, plaintext.data(), &plaintext_len, (const uint8_t*)ciphertext.data(), ciphertext.size()) <= 0) {
HandleOpensslError();
}
EVP_PKEY_CTX_free(ctx);
EVP_PKEY_free(privkey);
// 清理 OpenSSL
EVP_cleanup();
ERR_free_strings();
return std::string(plaintext.begin(), plaintext.begin() + plaintext_len);
}
// 将16进制字符串转换为字节数组
static std::vector<unsigned char> hexToBytes(const std::string& hex) {
std::vector<unsigned char> bytes;
for (size_t i = 0; i < hex.length(); i += 2)
{
std::string byteString = hex.substr(i, 2);
unsigned char byte = static_cast<unsigned char>(strtol(byteString.c_str(), NULL, 16));
bytes.push_back(byte);
}
return bytes;
}
// 从16进制字符串创建SM2私钥
EVP_PKEY* Crypto::create_sm2_private_key_from_hex(const std::string& private_key_hex)
{
// 将16进制私钥转换为字节
std::vector<unsigned char> private_key_bytes = hexToBytes(private_key_hex);
// 创建BIGNUM
BIGNUM* privBN = BN_bin2bn(private_key_bytes.data(), private_key_bytes.size(), NULL);
if (!privBN) HandleOpensslError();
// 创建EC_KEY并设置曲线和私钥
EC_KEY* ecKey = EC_KEY_new_by_curve_name(NID_sm2);
if (!ecKey) HandleOpensslError();
if (!EC_KEY_set_private_key(ecKey, privBN)) {
HandleOpensslError();
}
// 计算公钥
const EC_GROUP* group = EC_KEY_get0_group(ecKey);
EC_POINT* pub_point = EC_POINT_new(group);
if (!pub_point) HandleOpensslError();
if (!EC_POINT_mul(group, pub_point, privBN, NULL, NULL, NULL)) {
HandleOpensslError();
}
if (!EC_KEY_set_public_key(ecKey, pub_point)) {
HandleOpensslError();
}
// 创建EVP_PKEY
EVP_PKEY* pkey = EVP_PKEY_new();
if (!pkey) HandleOpensslError();
if (!EVP_PKEY_set1_EC_KEY(pkey, ecKey)) {
HandleOpensslError();
}
// 清理资源
BN_free(privBN);
EC_POINT_free(pub_point);
EC_KEY_free(ecKey);
return pkey;
}
// 从16进制字符串创建SM2公钥
EVP_PKEY* Crypto::create_sm2_public_key_from_hex(const std::string& public_key_hex)
{
// 将16进制公钥转换为字节
std::vector<unsigned char> public_key_bytes = hexToBytes(public_key_hex);
// 创建EC_KEY
EC_KEY* ec_key = EC_KEY_new_by_curve_name(NID_sm2);
if (!ec_key) HandleOpensslError();
// 从字节创建公钥点
const EC_GROUP* group = EC_KEY_get0_group(ec_key);
EC_POINT* pub_point = EC_POINT_new(group);
if (!pub_point) HandleOpensslError();
if (!EC_POINT_oct2point(group, pub_point, public_key_bytes.data(), public_key_bytes.size(), NULL)) {
HandleOpensslError();
}
if (!EC_KEY_set_public_key(ec_key, pub_point)) {
HandleOpensslError();
}
// 创建EVP_PKEY
EVP_PKEY* pkey = EVP_PKEY_new();
if (!pkey) HandleOpensslError();
if (!EVP_PKEY_set1_EC_KEY(pkey, ec_key)) {
HandleOpensslError();
}
// 清理资源
EC_POINT_free(pub_point);
EC_KEY_free(ec_key);
return pkey;
}

View File

@@ -1,14 +1,29 @@
#ifndef _Crypto_H_
#define _Crypto_H_
#include <iostream>
#include <vector>
#include <cstdlib>
#include <string>
#include <vector>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <gmssl/sm2.h>
#include <gmssl/sm3.h>
#include <gmssl/sm4.h>
#include <gmssl/hex.h>
#include <gmssl/sm2.h>
#include <gmssl/asn1.h>
#include <gmssl/rand.h>
#include <gmssl/error.h>
#include <gmssl/pkcs8.h>
#include <openssl/evp.h>
#include <openssl/ec.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include <openssl/bio.h>
#include <openssl/bn.h>
using namespace std;
@@ -16,7 +31,14 @@ using namespace std;
class Crypto
{
public:
static string md5(string src);
static string md5(string data);
static string sm3(std::string data);
static std::string gmssl_sm2Encrypt(std::string pubKeyHex, std::string priKeyHex, std::string plain);
static std::string gmssl_sm2Decrypt(std::string pubKeyHex, std::string priKeyHex, std::string cipher);
/**
* @brief SM4-ECB 加密示例
@@ -33,6 +55,13 @@ public:
* @return 明文字节向量
*/
static std::vector<uint8_t> sm4EcbDecrypt(const std::vector<uint8_t>& key, const std::vector<uint8_t>& ciphertext);
static std::string ssl_sm2Encrypt(const std::string& public_key_hex, const std::string& plaintext);
static std::string ssl_sm2Decrypt(const std::string& private_key_hex, const std::string& ciphertext);
static EVP_PKEY* create_sm2_private_key_from_hex(const std::string& private_key_hex);
static EVP_PKEY* create_sm2_public_key_from_hex(const std::string& public_key_hex);
};
#endif // ! _Crypto_H_

View File

@@ -6,6 +6,36 @@
#include <fstream>
using namespace std;
std::string Utils::toHex(std::vector<unsigned char>& s, int len/*=0*/)
{
if (len == 0) len = s.size();
std::stringstream ss;
for (int i = 0; i < len; ++i)
{
ss << std::hex << std::setw(2) << std::setfill('0') << (int)s[i];
}
return ss.str();
}
std::string Utils::toHex(const std::string& s)
{
std::stringstream ss;
for (int i = 0; i < s.size(); ++i)
{
ss << std::hex << std::setw(2) << std::setfill('0') << (int)static_cast<unsigned char>(s[i]);
}
return ss.str();
}
std::string Utils::fromHex(const std::string& hexstr)
{
std::vector<uint8_t> v;
v.reserve(hexstr.size() / 2);
for (std::string::const_iterator it = hexstr.begin(); it != hexstr.end(); it += 2)
{
v.push_back(static_cast<char>(strtol(std::string(it, it + 2).c_str(), nullptr, 16)));
}
return std::string(v.begin(), v.end());
}
string Utils::toStr(int v)
{
return std::to_string(v);
@@ -499,9 +529,3 @@ std::string Utils::readFile(std::string filename)
}
std::string Utils::toHexStr(int64_t val)
{
std::stringstream ss;
ss << "0x" << std::uppercase << setw(4) << setfill('0') << std::hex << val;
return ss.str();
}

View File

@@ -16,6 +16,10 @@ using namespace std;
class Utils
{
public:
static std::string toHex(std::vector<unsigned char>& s, int len = 0);
static std::string toHex(const std::string& s);
static std::string fromHex(const std::string& hexstr);
static string toStr(int v);
static string toStr(float v, int precision = 2);
static string toStr(double v, int precision = 2);
@@ -85,8 +89,6 @@ public:
static void split(string buf, string c, vector<string>& res);
static std::string readFile(std::string filename);
static std::string toHexStr(int64_t val);
};
class TimeTick

View File

@@ -1,130 +1,179 @@
#include <Windows.h>
#include <string>
#include <thread>
#include <QApplication>
#include <QtWebEngineWidgets/QtWebEngineWidgets>
#include <filesystem>
#include "common/Utils.h"
#include "common/Snowflake.h"
#include "common/JsonN.h"
#include "app/Application.h"
#include "app/Config.h"
#include "protocol/TcpEntity.h"
#include "widgets/MainWindow.h"
#include "common/Spdlogger.h"
#include "database/DaoEntity.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <fstream>
#include <string>
#include "DataStruct.h"
#include <filesystem>
#include <QApplication>
#include <QtWebEngineWidgets/QtWebEngineWidgets>
#include "qt/MainWeb.h"
#include "common/Utils.h"
#include "common/Snowflake.h"
#include "common/JsonN.h"
#include "common/Spdlogger.h"
#include "common/XlsxEntity.h"
#include "common/Crypto.h"
#include "app/Application.h"
#include "app/Config.h"
#include "app/DataStruct.h"
#include "database/Dao.h"
#include "common/XlsxEntity.h"
#include "protocol/TcpEntity.h"
#include "widgets/MainWindow.h"
#include "qt/MainWeb.h"
#include "qt/MainApp.h"
void memberJsonTest()
int SM2_test()
{
std::string fromJson = "fromJson(const std::string& str) {\nNJsonNode jsonroot;\nauto ret = NJson::parse(str, jsonroot);\nif (!ret) { return; }\n";
std::string toJson = "toJson() {\nNJsonNode jsonroot;";
// 未压缩格式(最常见)
// 前缀 : 04 (1字节) X坐标 : 32字节(64个十六进制字符) Y坐标 : 32字节(64个十六进制字符),总长度 : 1 + 32 + 32 = 65字节 = 130个十六进制字符
std::string hex_pub_key = "04661013d0b881d817085a251f0c0a7024e72c76e6eb0fd22c0170a508b123864ef7514df30cecb45deecf9b35810d0315b5164d63199c971ac3323c228ab48606";
std::string hex_pri_key = "b935087295c448b221abc571d88018ee9d037407c32aa4d7fbf627a143ad86a0";
std::ifstream ifs("", std::ios::in);
std::string line;
std::string cpp = "#include \"DataStruct.h\"\n\n";
if (ifs.is_open())
{
std::string s1;
std::string s2;
while (std::getline(ifs, line))
{
int pos = line.find("struct");
if (pos != std::string::npos)
{
std::string className = line.substr(pos+7);
s1 = "void " + className + "::" + fromJson;
s2 = "}\nstd::string " + className + "::" + toJson;
}
else
{
std::string key;
pos = line.find("uint");
if (pos != std::string::npos) { key = line.substr(pos+9); }
if (!key.empty())
{
pos = key.find(";");
if (pos != std::string::npos) { key = key.substr(0, pos); }
}
if (!key.empty())
{
s1 += ("NJson::read(jsonroot, \"" + key + "\", " + key + ");\n");
s2 += ("jsonroot[\"" + key + "\"] = " + key + ";\n");
}
}
}
ifs.close();
}
std::string cipherText = Crypto::gmssl_sm2Encrypt(hex_pub_key, hex_pri_key, "123456");
std::cout << "加密: " << Utils::toHex(cipherText) << std::endl;
//std::string strTmp = R"()";
//std::vector<std::string> vecTmp;
//Utils::split(strTmp, "\n", vecTmp);
std::string text = "306f022100f180bb383cddea024dfb6fea6c321f4b6901a468646df3da7d0040ebf107199f022009c363df8958c037f658da7060d429647802ac40560140e79685884a38f81cb10420783eb5b893994afdf7f68e2123e0c6e9469b3ea1f26297cb2b8e9cf6e27162a60406f99e4cbe6655";
std::string plainText = Crypto::gmssl_sm2Decrypt(hex_pub_key, hex_pri_key, Utils::fromHex(text));
std::cout << "解密: " << plainText << std::endl;
//std::string from = "void fromJson(const std::string& str) {\nNJsonNode jsonroot;\nauto ret = NJson::parse(str, jsonroot);\nif (!ret) { return; }\n";
//std::string to = "std::string toJson() {\nNJsonNode jsonroot;";
//for (auto& item: vecTmp)
//{
// std::string key;
// int pos = item.find_first_of("_");
// if (pos != std::string::npos) { key = item.substr(pos+3); }
// pos = key.find_first_of(";");
// if (pos != std::string::npos) { key = key.substr(0, pos); }
// SM2_KEY sm2k;
// if (!key.empty())
// FILE* f = fopen("D:/sm2pub.pem", "rb");
// if (f)
// {
// from += ("NJson::read(jsonroot, \"" + key + "\", " + key + ");\n");
// to += ("jsonroot[\"" + key + "\"] = " + key + ";\n");
// sm2_public_key_info_from_pem(&sm2k, f);
// std::vector<uint8_t> plainText(SM2_MAX_PLAINTEXT_SIZE);
// std::vector<uint8_t> ciphertext(SM2_MAX_CIPHERTEXT_SIZE);
// size_t ciphertext_len = -1;
// int ret = sm2_encrypt(&sm2k, plainText.data(), plainText.size(), ciphertext.data(), &ciphertext_len);
// std::cout << "加密: " << Utils::toHex(ciphertext, ciphertext_len) << std::endl;
// }
// FILE* f1 = fopen("D:/sm2.pem", "rb");
// if (f1)
// {
// sm2_private_key_info_from_pem(&sm2k, f1);
// }
// sm2_key_print(stderr, 0, 4, "SM2_KEY", &sm2k);
// std::cout << "";
//}
//from += "}";
//to += "return jsonroot.dump();\n}";
//std::cout << from << std::endl;
//std::cout << to << std::endl;
return 0;
}
#include "common/Crypto.h"
#include <openssl/evp.h>
#include <openssl/ec.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include <openssl/bio.h>
#include <openssl/bn.h>
#include <iostream>
#include <vector>
#include <string>
#include <iomanip>
#include <sstream>
// 错误处理函数
void HandleOpensslError() {
ERR_print_errors_fp(stderr);
exit(EXIT_FAILURE);
}
// 将16进制字符串转换为字节数组
std::vector<unsigned char> hexToBytes(const std::string& hex) {
std::vector<unsigned char> bytes;
for (size_t i = 0; i < hex.length(); i += 2) {
std::string byteString = hex.substr(i, 2);
unsigned char byte = static_cast<unsigned char>(strtol(byteString.c_str(), NULL, 16));
bytes.push_back(byte);
}
return bytes;
}
// 将字节数组转换为16进制字符串
std::string bytes_to_hex(const std::vector<unsigned char>& bytes) {
std::stringstream ss;
ss << std::hex << std::setfill('0');
for (unsigned char byte : bytes) {
ss << std::setw(2) << static_cast<unsigned int>(byte);
}
return ss.str();
}
void OpensslSM2_test()
{
// 初始化 OpenSSL
OpenSSL_add_all_algorithms();
ERR_load_crypto_strings();
// 示例16进制密钥
std::string private_key_hex = "b935087295c448b221abc571d88018ee9d037407c32aa4d7fbf627a143ad86a0";
std::string public_key_hex = "04661013d0b881d817085a251f0c0a7024e72c76e6eb0fd22c0170a508b123864ef7514df30cecb45deecf9b35810d0315b5164d63199c971ac3323c228ab48606";
// 要加密的明文
std::string plaintext = "123";
std::cout << "Original text: " << plaintext << std::endl;
std::cout << "Private key (hex): " << private_key_hex << std::endl;
std::cout << "Public key (hex): " << public_key_hex << std::endl;
// 加密
auto ciphertext = Crypto::ssl_sm2Encrypt(public_key_hex, plaintext);
std::cout << "Ciphertext (hex): " << Utils::toHex(ciphertext) << std::endl;
// 解密^
auto decryptedText = Crypto::ssl_sm2Decrypt(private_key_hex, ciphertext);
std::cout << "Decrypted text: " << decryptedText << std::endl;
// 验证加解密是否正确
if (plaintext == decryptedText) {
std::cout << "SM2 encryption and decryption successful!" << std::endl;
}
else {
std::cout << "SM2 encryption and decryption failed!" << std::endl;
}
{
// 未压缩格式(最常见)
// 前缀 : 04 (1字节) X坐标 : 32字节(64个十六进制字符) Y坐标 : 32字节(64个十六进制字符),总长度 : 1 + 32 + 32 = 65字节 = 130个十六进制字符
//std::string private_key_hex = "04661013d0b881d817085a251f0c0a7024e72c76e6eb0fd22c0170a508b123864ef7514df30cecb45deecf9b35810d0315b5164d63199c971ac3323c228ab48606";
//std::string public_key_hex = "b935087295c448b221abc571d88018ee9d037407c32aa4d7fbf627a143ad86a0";
//std::string cipherText = Crypto::sm2Encrypt(public_key_hex, private_key_hex, "123456");
//std::cout << "加密: " << Utils::toHex(cipherText) << std::endl;
std::string text(ciphertext.begin(), ciphertext.end());
//std::string textHex = "306f022100f180bb383cddea024dfb6fea6c321f4b6901a468646df3da7d0040ebf107199f022009c363df8958c037f658da7060d429647802ac40560140e79685884a38f81cb10420783eb5b893994afdf7f68e2123e0c6e9469b3ea1f26297cb2b8e9cf6e27162a60406f99e4cbe6655";
//std::string text = Utils::fromHex(text);
std::string plainText = Crypto::gmssl_sm2Decrypt(public_key_hex, private_key_hex, text);
std::cout << "解密: " << plainText << std::endl;
}
}
int main(int argc, char** argv)
{
// 示例密钥 (16字节)
std::string key = "1234567890123456";
// 示例明文 (必须是16字节的整数倍本例为16字节)
std::string plaintext = "HelloWorld";
// 加密
auto encryptText = Crypto::sm4EcbEncrypt(vector<uint8_t>(key.begin(), key.end()), vector<uint8_t>(plaintext.begin(), plaintext.end()));
// 解密
auto decryptText = Crypto::sm4EcbDecrypt(vector<uint8_t>(key.begin(), key.end()), encryptText);
// 输出十六进制结果
std::cout << "Original: " << plaintext << std::endl;
std::cout << "Encrypted: " << std::string(encryptText.begin(), encryptText.end()) << std::endl;
std::cout << "Decrypted: " << std::string(decryptText.begin(), decryptText.end()) << std::endl;
// 设置控制台输出为 UTF-8 编码
SetConsoleOutputCP(CP_UTF8);
// 设置控制台输入为 UTF-8 编码(如果需要输入中文)
SetConsoleCP(CP_UTF8);
//OpensslSM2_test();
//SM2_test();
// 初始化日志
Spdlogger::init(spdlog::level::info, "");
spdlog::info("[main] start ... ======================================================================");
@@ -133,7 +182,24 @@ int main(int argc, char** argv)
// 运行后台服务
Application::instance().init();
while (1) { std::this_thread::sleep_for(std::chrono::milliseconds(100)); };
if (Config::option.windowEnabled)
{
QApplication qapp(argc, argv);
QFont font("微软雅黑", 10, 600);
QApplication::setFont(font);
MainApp mainApp;
return qapp.exec();
}
else
{
while (1)
{
std::this_thread::sleep_for(std::chrono::milliseconds(100));
};
return 0;
}
// 启动 PV 服务主线程
//std::thread([=]()

View File

@@ -1042,19 +1042,16 @@ Errcode HttpEntity::updateAlertLog(const httplib::Request& req, njson& json, std
Errcode HttpEntity::queryPredictionDetail(const httplib::Request& req, njson& json, std::string& errmsg)
{
njson jsonData = njson::array();
std::vector<std::string> vecStoreIn(144), vecStoreOut(144), vecCharge(144), vecSolar(144), vecSolarP(144);
for (int i = 0; i<144; ++i)
const int num = 144;
std::vector<int> vecStoreIn(num, 0), vecStoreOut(num, 0), vecCharge(num, 0), vecSolar(num, 0), vecSolarP(num, 0);
for (int i = 0; i<num; ++i)
{
vecStoreIn[i] = Utils::toStr(float(Utils::random(50, 100)));
vecStoreOut[i] = Utils::toStr(float(Utils::random(50, 100)));
vecCharge[i] = Utils::toStr(float(Utils::random(50, 100)));
vecSolar[i] = Utils::toStr(float(Utils::random(50, 100)));
vecSolarP[i] = Utils::toStr(float(Utils::random(50, 100)));
vecStoreIn[i] = 0;
vecStoreOut[i] = 0;
vecCharge[i] = 0;
vecSolar[i] = 0;
vecSolarP[i] = 0;
}
json["data"] = jsonData;
json["data"] = {
{"W_store_in", vecStoreIn},
{"W_store_out", vecStoreOut},

View File

@@ -279,7 +279,7 @@ int MqttClient::onMessageArrived(char* topic, int topicLen, MQTTAsync_message* m
std::string command = GetSubStr("/", topicStr);
std::string deviceCode = GetSubStr("/", topicStr);
spdlog::info("[mqtt] <<<<<<<<<< message arrived: topic=[{},{}], len={}, payload={}", topic, msg->qos, len, payload);
spdlog::info("[mqtt] <<< message arrived: topic=[{},{}], len={}, payload={}", topic, msg->qos, len, payload);
njson json;
bool ret = JSON::parse(payload, json);
@@ -388,9 +388,9 @@ void MqttClient::ParseArrivedMessage(njson& json, string command, std::shared_pt
{
auto addr = iter->first;
auto& regUnit = iter->second;
if (regUnit.alert && val>=0)
if (regUnit.alert && val > 0)
{
station->readAlert(device, val, "[" + command + "]" + regUnit.name + "(" + addr + ")");
station->readAlert(device, addr, val, "[" + command + "]" + regUnit.name + "(" + addr + ")");
}
device->setParam(addr, val);

178
src/qt/MainApp.cpp Normal file
View File

@@ -0,0 +1,178 @@
#include "MainApp.h"
#include <QtCore/QVariant>
#include <QtWidgets/QApplication>
#include <QtWidgets/QComboBox>
#include <QtWidgets/QGridLayout>
#include <QtWidgets/QLabel>
#include <QtWidgets/QLineEdit>
#include <QtWidgets/QPushButton>
#include <QtWidgets/QWidget>
#include <QPalette>
#include <QGroupBox>
static const std::string QSS_BTN_MENU =
"QPushButton{background:rgba(50,128,218,200);color:white;border-radius:5px;border:2px solid rgb(10,120,215);font:bold 18px;}"
"QPushButton:hover{background-color:rgb(32,164,128);}"
"QPushButton:pressed{border-width:3px 0 0 3px;background-color:rgb(1,32,54);border-style:inset;}"
"QPushButton:disabled{color:rgb(150,150,150);}";
static const std::string QSS_LINE =
"QLineEdit { background-color: rgb(14, 49, 66); color: #ffffff; border: 1px solid rgb(18, 251, 255); border-radius: 5px; font: normal 13px; }";
static const std::string QSS_GROUP =
"QGroupBox { border: 1px solid gray; margin-top: 8px; border-radius: 5px;}"
"QGroupBox::title { subcontrol-origin: margin; subcontrol-position: top left; left:10px; margin-left: 0px; padding:0 1px; }";
MainApp::MainApp()
{
QPalette palette(this->palette());
// 设置背景为黑色
palette.setColor(QPalette::Window, QColor(1, 32, 54));
this->setAutoFillBackground(true);
this->setPalette(palette);
this->setStyleSheet("color: white;");
this->resize(1440, 900);
this->show();
//ui.bkg.setGeometry(0, 0, 1440, 900);
//ui.bkg.setStyleSheet("background-color: rgb(17, 36, 102);");
//ui.weburl = std::make_shared<LabelPair>(this, 10, 10, 240, 30);
//ui.weburl->setTitle("页面地址:");
//ui.weburl->setValue("http://www.baidu.com");
this->setMyLayout();
}
class MyMenu : public QWidget
{
public:
MyMenu(QWidget* parent) : QWidget(parent), layout(this)
{
this->setObjectName("menu");
this->setStyleSheet("#menu { background-color:rgba(120,120,120,80); }");
this->show();
vecMenuItems.reserve(20);
layout.setSpacing(2);
layout.setContentsMargins(2, 2, 2, 2);
this->addMenuItem("系统总览");
this->addMenuItem("运行监控");
}
void addMenuItem(std::string name)
{
int row = vecMenuItems.size();
auto item = std::make_shared<QPushButton>(this);
vecMenuItems.push_back(item);
item->setText(name.c_str());
item->setStyleSheet(QSS_BTN_MENU.c_str());
QSizePolicy sizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
item->setSizePolicy(sizePolicy);
layout.addWidget(item.get(), row, 0, 1, 1);
// 设置列宽和行高
layout.setRowMinimumHeight(row, 50); // 设置第0列的最小宽度为100像素
// 设置列和行的伸缩因子
layout.setRowStretch(row, 0); // 设置第0列的伸缩因子为0不伸缩
layout.setRowStretch(row+1, 2); // 设置第1列的伸缩因子为2使其更宽
}
std::vector<std::shared_ptr<QPushButton>> vecMenuItems;
QGridLayout layout;
};
void PairLine(QWidget* parent, int x, int y, string k, string v)
{
auto key = new QLabel(parent);
key->setText(k.c_str());
key->setGeometry(x, y, 80, 26);
auto value = new QLineEdit(parent);
value->setText(v.c_str());
value->setGeometry(x+80, y, 180, 26);
value->setStyleSheet(QSS_LINE.c_str());
}
class MyWorkspace : public QWidget
{
public:
MyWorkspace(QWidget* parent) : QWidget(parent)
{
this->setObjectName("workspace");
this->setStyleSheet("#workspace { background-color:rgba(100,100,100,50); }");
int x=10, y=10;
{
QGroupBox* groupBox = new QGroupBox("HTTP", this);
groupBox->setGeometry(x, y, 300, 120);
groupBox->setStyleSheet(QSS_GROUP.c_str());
PairLine(groupBox, 20, 20, "服务类型: ", "服务端");
PairLine(groupBox, 20, 50, "服务地址: ", "92.168.0.13:17900");
PairLine(groupBox, 20, 80, "服务状态: ", "---");
}
{
x += 320;
QGroupBox* groupBox = new QGroupBox("MQTT", this);
groupBox->setGeometry(x, y, 300, 120);
groupBox->setStyleSheet(QSS_GROUP.c_str());
PairLine(groupBox, 20, 20, "服务类型: ", "客户端");
PairLine(groupBox, 20, 50, "服务地址: ", "92.168.0.13:17800");
PairLine(groupBox, 20, 80, "服务状态: ", "---");
}
{
x += 320;
QGroupBox* groupBox = new QGroupBox("数据库", this);
groupBox->setGeometry(x, y, 300, 120);
groupBox->setStyleSheet(QSS_GROUP.c_str());
PairLine(groupBox, 20, 20, "数据库名: ", "ees");
PairLine(groupBox, 20, 50, "主机地址: ", "92.168.0.13:17800");
PairLine(groupBox, 20, 80, "用 户 名: ", "root");
}
}
};
void MainApp::setMyLayout()
{
layout.main = std::make_shared<QGridLayout>(this);
auto Widget = this;
layout.main->setObjectName(QString::fromUtf8("layout.main"));
layout.main->setSpacing(6);
layout.main->setContentsMargins(11, 11, 11, 11);
//// 设置间距和边距
//layout->setHorizontalSpacing(10); // 设置列间距为10像素
//layout->setVerticalSpacing(10); // 设置行间距为10像素
//layout->setContentsMargins(10, 10, 10, 10); // 设置内容边距为10像素
QSizePolicy sizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
MyMenu* menu = new MyMenu(this);
menu->setSizePolicy(sizePolicy);
layout.main->addWidget(menu, 0, 0, 1, 1);
MyWorkspace* workspace = new MyWorkspace(this);
workspace->setSizePolicy(sizePolicy);
layout.main->addWidget(workspace, 0, 1, 1, 1);
// 设置列宽和行高
layout.main->setColumnMinimumWidth(0, 200); // 设置第0列的最小宽度为100像素
//gridLayout->setRowMinimumHeight(0, 200); // 设置第0行的最小高度为50像素
// 设置列和行的伸缩因子
layout.main->setColumnStretch(0, 0); // 设置第0列的伸缩因子为0不伸缩
layout.main->setColumnStretch(1, 2); // 设置第1列的伸缩因子为2使其更宽
//gridLayout->setRowStretch(0, 1); // 设置第0行的伸缩因子为1
}

53
src/qt/MainApp.h Normal file
View File

@@ -0,0 +1,53 @@
#include <QMainWindow>
#include <QLabel>
#include <QPushButton>
#include <QHBoxLayout>
#include <string>
using namespace std;
class LabelPair
{
public:
LabelPair(QWidget* parent, int x, int y, int w, int h)
{
title.setParent(parent);
value.setParent(&title);
title.setGeometry(x, y, w, h);
value.setGeometry(80, 0, w-80, h);
title.show();
value.show();
}
void setTitle(std::string text)
{
title.setText(text.c_str());
}
void setValue(std::string text)
{
value.setText(text.c_str());
}
QLabel title;
QLabel value;
};
class MainApp : public QWidget
{
Q_OBJECT
public:
MainApp();
void setMyLayout();
struct {
std::shared_ptr<LabelPair> weburl {};
} ui;
struct {
std::shared_ptr<QGridLayout> main;
} layout;
};