mirror of
https://gitee.com/js-yhsec/energy_storage.git
synced 2026-05-28 03:09:24 +08:00
完成系统管理web端功能,实现系统管理服务端接口,实现登录功能
This commit is contained in:
@@ -8,16 +8,30 @@ set(CMAKE_CXX_STANDARD 17)
|
|||||||
# 【注意】visual studio编译时的字符编码问题,配置属性 --> C/C++ --> 命令行 --> 其它选项: /utf-8 或添加如下指令
|
# 【注意】visual studio编译时的字符编码问题,配置属性 --> C/C++ --> 命令行 --> 其它选项: /utf-8 或添加如下指令
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /utf-8")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /utf-8")
|
||||||
|
|
||||||
# Qt_PATH 为 Qt 的安装地址
|
# 设置 Release 模式启用调试信息
|
||||||
set(QT_PATH "D:/Programs/Qt5/5.15.2/msvc2019_64")
|
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Zi")
|
||||||
set(CMAKE_PREFIX_PATH ${QT_PATH}/lib/cmake)
|
# 设置 Release 模式的优化级别和其他选项
|
||||||
|
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Od /Ob2")
|
||||||
|
# 设置 Release 模式下链接器的调试信息
|
||||||
|
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /DEBUG")
|
||||||
|
|
||||||
|
# Qt_PATH 为 Qt 的安装地址
|
||||||
|
set(QT_PATH "D:/Programs/Qt5/5.15.2/msvc2019")
|
||||||
|
set(CMAKE_PREFIX_PATH ${QT_PATH}/lib/cmake)
|
||||||
|
|
||||||
# 开启自动编译
|
# 开启自动编译
|
||||||
set(CMAKE_AUTOMOC ON)
|
set(CMAKE_AUTOMOC ON)
|
||||||
set(CMAKE_AUTOUIC ON)
|
set(CMAKE_AUTOUIC ON)
|
||||||
set(CMAKE_AUTORCC ON)
|
set(CMAKE_AUTORCC ON)
|
||||||
find_package(Qt5 COMPONENTS Widgets AxContainer Network SerialBus SerialPort Charts WebEngineWidgets REQUIRED)
|
find_package(Qt5 COMPONENTS
|
||||||
|
Widgets
|
||||||
|
AxContainer
|
||||||
|
Network
|
||||||
|
SerialBus
|
||||||
|
SerialPort
|
||||||
|
Charts
|
||||||
|
WebEngineWidgets
|
||||||
|
REQUIRED)
|
||||||
|
|
||||||
add_definitions(-DWIN32_LEAN_AND_MEAN)
|
add_definitions(-DWIN32_LEAN_AND_MEAN)
|
||||||
|
|
||||||
@@ -31,6 +45,7 @@ include_directories(
|
|||||||
${ROOT_PATH}/widgets
|
${ROOT_PATH}/widgets
|
||||||
${THIRDPARTY_PATH}
|
${THIRDPARTY_PATH}
|
||||||
${THIRDPARTY_PATH}/mysql/include
|
${THIRDPARTY_PATH}/mysql/include
|
||||||
|
${THIRDPARTY_PATH}/nlohmann_json-3.11.2
|
||||||
)
|
)
|
||||||
|
|
||||||
macro(ADD_SOURCE_GROUP srcpath)
|
macro(ADD_SOURCE_GROUP srcpath)
|
||||||
@@ -53,8 +68,16 @@ ADD_SOURCE_GROUP(widgets/pages)
|
|||||||
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/../bin)
|
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/../bin)
|
||||||
add_executable(${PROJECT_NAME} ${SOURCE_FILE})
|
add_executable(${PROJECT_NAME} ${SOURCE_FILE})
|
||||||
|
|
||||||
target_link_libraries(${PROJECT_NAME} Qt5::Widgets Qt5::AxContainer Qt5::Network Qt5::SerialBus Qt5::SerialPort Qt5::Charts Qt5::WebEngineWidgets)
|
target_link_libraries(${PROJECT_NAME}
|
||||||
|
Qt5::Widgets
|
||||||
|
Qt5::AxContainer
|
||||||
|
Qt5::Network
|
||||||
|
Qt5::SerialBus
|
||||||
|
Qt5::SerialPort
|
||||||
|
Qt5::Charts
|
||||||
|
Qt5::WebEngineWidgets
|
||||||
|
)
|
||||||
target_link_libraries(${PROJECT_NAME}
|
target_link_libraries(${PROJECT_NAME}
|
||||||
ws2_32 iphlpapi
|
ws2_32 iphlpapi
|
||||||
${THIRDPARTY_PATH}/mysql/lib/x64/libmysql.lib
|
${THIRDPARTY_PATH}/mysql/lib/Win32/libmysql.lib
|
||||||
)
|
)
|
||||||
18
src/app/Admin.cpp
Normal file
18
src/app/Admin.cpp
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
#include "Admin.h"
|
||||||
|
#include "app/Dao.h"
|
||||||
|
#include "common/Logger.h"
|
||||||
|
|
||||||
|
Errcode Admin::longin(std::string username, std::string passwd)
|
||||||
|
{
|
||||||
|
std::string err;
|
||||||
|
Errcode ecode = DAO::login(nullptr, username, passwd, err);
|
||||||
|
if (ecode != Errcode::OK)
|
||||||
|
{
|
||||||
|
XLOGE() << "login error, username=" << username << ", err=" << err;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
XLOGE() << "login success, username=" << username;
|
||||||
|
}
|
||||||
|
return ecode;
|
||||||
|
}
|
||||||
16
src/app/Admin.h
Normal file
16
src/app/Admin.h
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include "app/errcode.h"
|
||||||
|
|
||||||
|
class Admin
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static Admin& instance()
|
||||||
|
{
|
||||||
|
static Admin admin;
|
||||||
|
return admin;
|
||||||
|
}
|
||||||
|
|
||||||
|
Errcode longin(std::string username, std::string pwd);
|
||||||
|
};
|
||||||
@@ -2,20 +2,68 @@
|
|||||||
|
|
||||||
#include "common/Utils.h"
|
#include "common/Utils.h"
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
#include "app/Dao.h"
|
||||||
|
#include "app/Device.h"
|
||||||
|
|
||||||
void Application::init()
|
void Application::init()
|
||||||
{
|
{
|
||||||
std::thread([=]()
|
Config::init("assets/config/app.json");
|
||||||
|
|
||||||
|
// 设置数据库配置
|
||||||
|
DaoEntity::setOption(Config::option.database.host,
|
||||||
|
Config::option.database.port,
|
||||||
|
Config::option.database.user,
|
||||||
|
Config::option.database.passwd,
|
||||||
|
Config::option.database.dbname);
|
||||||
|
XLOGI() << "[APP] set database option: host=" << Config::option.database.host
|
||||||
|
<< ", port=" << Config::option.database.port
|
||||||
|
<< ", user=" << Config::option.database.user
|
||||||
|
<< ", dbname=" << Config::option.database.dbname;
|
||||||
|
|
||||||
|
// 连接数据库,读取基础信息
|
||||||
|
|
||||||
|
|
||||||
|
// 读取设备信息,连接设备
|
||||||
|
this->initDevice();
|
||||||
|
std::thread([=]() { runThreadDevice(); }).detach();
|
||||||
|
|
||||||
|
// 创建主业务循环线程
|
||||||
|
std::thread([=]() { runThreadMain(); }).detach();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::initDevice()
|
||||||
{
|
{
|
||||||
while (!isQuit()) { runThreadMain(); }
|
DaoEntity dao("");
|
||||||
}).detach();
|
std::string sql = "select * from device;";
|
||||||
|
vector<DataFields> result;
|
||||||
|
dao.exec(sql, result);
|
||||||
|
for (auto& fields: result)
|
||||||
|
{
|
||||||
|
Device::add(fields);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::runThreadMain()
|
void Application::runThreadMain()
|
||||||
{
|
{
|
||||||
static TimeTick tt;
|
while (!isQuit())
|
||||||
tt.elapse(1000);
|
{
|
||||||
|
|
||||||
//XLOGD() << "HelloWorld";
|
|
||||||
|
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void Application::runThreadDevice()
|
||||||
|
{
|
||||||
|
while (!isQuit())
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -15,11 +15,16 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void init();
|
void init();
|
||||||
|
void initDevice();
|
||||||
|
|
||||||
bool isQuit() { return isQuit_; }
|
bool isQuit() { return isQuit_; }
|
||||||
Operator& getOperator() { return op_; }
|
Operator& getOperator() { return op_; }
|
||||||
|
|
||||||
void runThreadMain();
|
void runThreadMain();
|
||||||
|
|
||||||
|
|
||||||
|
void runThreadDevice();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool isQuit_ = false;
|
bool isQuit_ = false;
|
||||||
|
|
||||||
|
|||||||
38
src/app/Config.cpp
Normal file
38
src/app/Config.cpp
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
#include "Config.h"
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
#include "common/JsonN.h"
|
||||||
|
#include "Logger.h"
|
||||||
|
|
||||||
|
AppOption Config::option;
|
||||||
|
|
||||||
|
bool Config::init(std::string filename)
|
||||||
|
{
|
||||||
|
NJson jsonroot;
|
||||||
|
bool ret = NJsonLoad(filename, jsonroot);
|
||||||
|
if (!ret)
|
||||||
|
{
|
||||||
|
XLOGE() << "[APP] load config failed, filename=" << filename;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
XLOGI() << "[APP] load config success, filename=" << filename;
|
||||||
|
|
||||||
|
if (jsonroot.contains("database"))
|
||||||
|
{
|
||||||
|
NJson json = jsonroot.at("database");
|
||||||
|
option.database.host = json.contains("host") ? json.at("host") : "";
|
||||||
|
option.database.port = json.contains("port") ? json.at("port") : 0;
|
||||||
|
option.database.user = json.contains("user") ? json.at("user") : "";
|
||||||
|
option.database.passwd = json.contains("passwd") ? json.at("passwd") : "";
|
||||||
|
option.database.dbname = json.contains("dbname") ? json.at("dbname") : "";
|
||||||
|
|
||||||
|
XLOGI() << "[APP] load database config end. host=" << option.database.host;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
XLOGI() << "[APP] load database config error: not found. host=" << option.database.host;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
26
src/app/Config.h
Normal file
26
src/app/Config.h
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
struct DatabaseOption
|
||||||
|
{
|
||||||
|
std::string host;
|
||||||
|
int port;
|
||||||
|
std::string user;
|
||||||
|
std::string passwd;
|
||||||
|
std::string dbname;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AppOption
|
||||||
|
{
|
||||||
|
DatabaseOption database;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Config
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static bool init(std::string filename);
|
||||||
|
|
||||||
|
|
||||||
|
static AppOption option;
|
||||||
|
};
|
||||||
@@ -3,6 +3,8 @@
|
|||||||
#include "common/Utils.h"
|
#include "common/Utils.h"
|
||||||
#include "common/Snowflake.h"
|
#include "common/Snowflake.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
enum class EnDatabaseErr
|
enum class EnDatabaseErr
|
||||||
{
|
{
|
||||||
SUCCESS = 0,
|
SUCCESS = 0,
|
||||||
@@ -13,7 +15,7 @@ std::shared_ptr<DaoEntity> DAO::get(std::string tableName)
|
|||||||
return std::make_shared<DaoEntity>(tableName);
|
return std::make_shared<DaoEntity>(tableName);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DAO::login(std::shared_ptr<DaoEntity> dao, std::string account, std::string passwd, std::string& err)
|
Errcode DAO::login(std::shared_ptr<DaoEntity> dao, std::string account, std::string passwd, std::string& err)
|
||||||
{
|
{
|
||||||
std::string t = Utils::timeNowStr();
|
std::string t = Utils::timeNowStr();
|
||||||
if (!dao)
|
if (!dao)
|
||||||
@@ -24,7 +26,7 @@ bool DAO::login(std::shared_ptr<DaoEntity> dao, std::string account, std::string
|
|||||||
{
|
{
|
||||||
err = "数据库连接错误";
|
err = "数据库连接错误";
|
||||||
DAO::writeSystemLog(dao, 2, "", account, "用户登录失败:" + err);
|
DAO::writeSystemLog(dao, 2, "", account, "用户登录失败:" + err);
|
||||||
return false;
|
return Errcode::ERR_DB_CONN;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string sql = "SELECT * FROM user WHERE account='" + account + "';";
|
std::string sql = "SELECT * FROM user WHERE account='" + account + "';";
|
||||||
@@ -35,24 +37,24 @@ bool DAO::login(std::shared_ptr<DaoEntity> dao, std::string account, std::string
|
|||||||
{
|
{
|
||||||
err = "数据库操作错误";
|
err = "数据库操作错误";
|
||||||
DAO::writeSystemLog(dao, 2, "", account, "用户登录失败:" + err);
|
DAO::writeSystemLog(dao, 2, "", account, "用户登录失败:" + err);
|
||||||
return false;
|
return Errcode::ERR_DB_CONN;
|
||||||
}
|
}
|
||||||
if (res.size() <=0)
|
if (res.size() <=0)
|
||||||
{
|
{
|
||||||
err = "用户不存在";
|
err = "用户不存在";
|
||||||
DAO::writeSystemLog(dao, 2, "", account, "用户登录失败:" + err);
|
DAO::writeSystemLog(dao, 2, "", account, "用户登录失败:" + err);
|
||||||
return false;
|
return Errcode::ERR_LOGIN_USER_NOTEXIST;
|
||||||
}
|
}
|
||||||
DataFields& fields = res[0];
|
DataFields& fields = res[0];
|
||||||
std::string userId = fields.get_str("user_id");
|
std::string userId = fields.getStr("user_id");
|
||||||
int loginCount = fields.get_int("login_count");
|
int loginCount = fields.getInt("login_count");
|
||||||
|
|
||||||
// 判断密码
|
// 判断密码
|
||||||
if (passwd != fields.get_str("passwd"))
|
if (passwd != fields.getStr("passwd"))
|
||||||
{
|
{
|
||||||
err = "密码错误";
|
err = "密码错误";
|
||||||
DAO::writeSystemLog(dao, 2, userId, account, "用户登录失败:" + err);
|
DAO::writeSystemLog(dao, 2, userId, account, "用户登录失败:" + err);
|
||||||
return false;
|
return Errcode::ERR_LOGIN_PASSWD;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = "登录成功";
|
err = "登录成功";
|
||||||
@@ -66,7 +68,7 @@ bool DAO::login(std::shared_ptr<DaoEntity> dao, std::string account, std::string
|
|||||||
}
|
}
|
||||||
|
|
||||||
DAO::writeSystemLog(dao, 2, userId, account, "用户登录成功");
|
DAO::writeSystemLog(dao, 2, userId, account, "用户登录成功");
|
||||||
return true;
|
return Errcode::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DAO::writeSystemLog(std::shared_ptr<DaoEntity> dao, int type, std::string userId, std::string account, std::string text)
|
bool DAO::writeSystemLog(std::shared_ptr<DaoEntity> dao, int type, std::string userId, std::string account, std::string text)
|
||||||
@@ -83,12 +85,12 @@ bool DAO::writeSystemLog(std::shared_ptr<DaoEntity> dao, int type, std::string u
|
|||||||
// 数据库写入登录日志
|
// 数据库写入登录日志
|
||||||
dao->setTableName("system_log");
|
dao->setTableName("system_log");
|
||||||
DataFields fieldsLog;
|
DataFields fieldsLog;
|
||||||
fieldsLog.set("id", Snowflake::instance().nextIdStr());
|
fieldsLog.set("log_id", Snowflake::instance().getIdStr());
|
||||||
fieldsLog.set("type", 2);
|
fieldsLog.set("type", 2);
|
||||||
fieldsLog.set("user_id", userId);
|
fieldsLog.set("user_id", userId);
|
||||||
fieldsLog.set("user_account", account);
|
fieldsLog.set("user_account", account);
|
||||||
fieldsLog.set("content", text);
|
fieldsLog.set("content", text);
|
||||||
fieldsLog.set("log_time", Utils::timeNowStr());
|
fieldsLog.set("create_time", Utils::timeNowStr());
|
||||||
bool ret = dao->insertFields({fieldsLog});
|
bool ret = dao->insertFields({fieldsLog});
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -114,7 +116,7 @@ int DAO::insertUser(DataFields& fields)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string account = fields.get_str("account");
|
std::string account = fields.getStr("account");
|
||||||
|
|
||||||
// step1: 查询
|
// step1: 查询
|
||||||
std::vector<DataFields> res;
|
std::vector<DataFields> res;
|
||||||
@@ -128,7 +130,7 @@ int DAO::insertUser(DataFields& fields)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
fields.set("user_id", Snowflake::instance().nextIdStr());
|
fields.set("user_id", Snowflake::instance().getIdStr());
|
||||||
fields.set("create_time", Utils::timeNowStr());
|
fields.set("create_time", Utils::timeNowStr());
|
||||||
ret = dao->insertFields(fields);
|
ret = dao->insertFields(fields);
|
||||||
return (ret) ? 0 : 1;
|
return (ret) ? 0 : 1;
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
#include "database/DaoEntity.h"
|
#include "database/DaoEntity.h"
|
||||||
|
|
||||||
|
#include "app/errcode.h"
|
||||||
|
|
||||||
class DAO
|
class DAO
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static std::shared_ptr<DaoEntity> get(std::string tableName="");
|
static std::shared_ptr<DaoEntity> get(std::string tableName="");
|
||||||
|
|
||||||
static bool login(std::shared_ptr<DaoEntity> dao, std::string account, std::string passwd, std::string& err);
|
static Errcode login(std::shared_ptr<DaoEntity> dao, std::string account, std::string passwd, std::string& err);
|
||||||
|
|
||||||
static bool writeSystemLog(std::shared_ptr<DaoEntity> dao, int type, std::string userId, std::string account, std::string text);
|
static bool writeSystemLog(std::shared_ptr<DaoEntity> dao, int type, std::string userId, std::string account, std::string text);
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,126 @@
|
|||||||
|
#include "Device.h"
|
||||||
|
|
||||||
|
#include "common/Logger.h"
|
||||||
|
#include "common/Utils.h"
|
||||||
|
#include "protocol/Communicator.h"
|
||||||
|
#include "common/JsonN.h"
|
||||||
|
|
||||||
|
//int DeviceEntity::getAttrInt(std::string key)
|
||||||
|
//{
|
||||||
|
// auto iter = mapAttrs.find(key);
|
||||||
|
// if (iter == mapAttrs.end()) { return 0; }
|
||||||
|
// return Utils::toInt(iter->second);
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//float DeviceEntity::getAttrFloat(std::string key)
|
||||||
|
//{
|
||||||
|
// auto iter = mapAttrs.find(key);
|
||||||
|
// if (iter == mapAttrs.end()) { return 0.0f; }
|
||||||
|
// return Utils::toFloat(iter->second);
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//double DeviceEntity::getAttrDouble(std::string key)
|
||||||
|
//{
|
||||||
|
// auto iter = mapAttrs.find(key);
|
||||||
|
// if (iter == mapAttrs.end()) { return 0.0; }
|
||||||
|
// return Utils::toDouble(iter->second);
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//std::string DeviceEntity::getAttrStr(std::string key)
|
||||||
|
//{
|
||||||
|
// auto iter = mapAttrs.find(key);
|
||||||
|
// if (iter == mapAttrs.end()) { return ""; }
|
||||||
|
// return iter->second;
|
||||||
|
//}
|
||||||
|
|
||||||
|
int DeviceEntity::startComm()
|
||||||
|
{
|
||||||
|
if (!isOpen)
|
||||||
|
{
|
||||||
|
if (commEntity && commEntity->isAlive())
|
||||||
|
{
|
||||||
|
commEntity->close();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从属性列表中获取通讯方式和通讯地址、端口
|
||||||
|
std::string commType = attrs.getStr("commType");
|
||||||
|
|
||||||
|
// 如果entity的通讯协议类型当前配置不一致,需要关闭连接删除通讯后创建新的通讯
|
||||||
|
if (commEntity && commEntity->type != commType)
|
||||||
|
{
|
||||||
|
commEntity->close();
|
||||||
|
commEntity = nullptr;
|
||||||
|
}
|
||||||
|
// 创建新的通讯
|
||||||
|
if (!commEntity)
|
||||||
|
{
|
||||||
|
commEntity = Communicator::createEntity(attrs);
|
||||||
|
if (!commEntity) { return -1; }
|
||||||
|
}
|
||||||
|
|
||||||
|
commEntity->start();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ================================================================================================
|
||||||
|
// $$Device
|
||||||
|
std::map<int, std::shared_ptr<DeviceEntity>> Device::mapDevices;
|
||||||
|
|
||||||
|
void Device::add(DataFields& fields)
|
||||||
|
{
|
||||||
|
auto entity = std::make_shared<DeviceEntity>();
|
||||||
|
entity->deviceId = fields.getInt("device_id");
|
||||||
|
entity->type = fields.getInt("type");
|
||||||
|
entity->name = fields.getStr("name");
|
||||||
|
entity->code = fields.getStr("code");
|
||||||
|
entity->isOpen = fields.getInt("is_open");
|
||||||
|
entity->attrsJson = fields.getStr("attrs");
|
||||||
|
|
||||||
|
// 解析属性的JSON字符串,转换成键值对
|
||||||
|
NJson jsonroot;
|
||||||
|
bool ret = NJsonParse(entity->attrsJson, jsonroot);
|
||||||
|
if (!ret) // 解析错误
|
||||||
|
{
|
||||||
|
XLOGE() << "device attr json parse error, device_id=" << entity->deviceId;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (auto& [key, val] : jsonroot.items()) {
|
||||||
|
std::string valType = val.type_name();
|
||||||
|
if (valType == "string") {
|
||||||
|
entity->attrs.set(key, val.get<std::string>());
|
||||||
|
}
|
||||||
|
else if (valType == "number") {
|
||||||
|
entity->attrs.set(key, val.get<int>());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
XLOGE() << key << ": [" << valType << "]";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存设备 entity 到 map
|
||||||
|
if (entity->deviceId != -1)
|
||||||
|
{
|
||||||
|
mapDevices[entity->deviceId] = entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 启动通讯,该函数中会自动判断isOpen状态,选择是否进行通讯连接
|
||||||
|
entity->startComm();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::shared_ptr<DeviceEntity>> Device::getDeviceByType(int type)
|
||||||
|
{
|
||||||
|
std::vector<std::shared_ptr<DeviceEntity>> vecDevice;
|
||||||
|
for (auto iter = mapDevices.begin(); iter!=mapDevices.end(); ++iter)
|
||||||
|
{
|
||||||
|
auto device = iter->second;
|
||||||
|
if (device && (type<=0 || device->type == type))
|
||||||
|
{
|
||||||
|
vecDevice.push_back(device);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return vecDevice;
|
||||||
|
}
|
||||||
@@ -1,7 +1,54 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <map>
|
||||||
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include <common/DataFields.h>
|
||||||
|
|
||||||
|
class CommEntity;
|
||||||
|
|
||||||
|
class DeviceEntity
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
int deviceId = -1;
|
||||||
|
int type = -1;
|
||||||
|
std::string name;
|
||||||
|
std::string code;
|
||||||
|
bool isOpen = false;
|
||||||
|
std::string attrsJson = "";
|
||||||
|
|
||||||
|
|
||||||
|
int err = 0;
|
||||||
|
int online = 0;
|
||||||
|
int status = 0;
|
||||||
|
|
||||||
|
|
||||||
|
//std::map<std::string, std::string> mapAttrs;
|
||||||
|
DataFields attrs;
|
||||||
|
|
||||||
|
// 通讯entity
|
||||||
|
std::shared_ptr<CommEntity> commEntity;
|
||||||
|
|
||||||
|
//int getAttrInt(std::string key);
|
||||||
|
//float getAttrFloat(std::string key);
|
||||||
|
//double getAttrDouble(std::string key);
|
||||||
|
//std::string getAttrStr(std::string key);
|
||||||
|
|
||||||
|
// 启动通讯
|
||||||
|
int startComm();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
class Device
|
class Device
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static bool init();
|
static void add(DataFields& fields);
|
||||||
|
|
||||||
|
static std::vector<std::shared_ptr<DeviceEntity>> getDeviceByType(int type);
|
||||||
|
|
||||||
|
public:
|
||||||
|
static std::map<int, std::shared_ptr<DeviceEntity>> mapDevices;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -4,9 +4,8 @@
|
|||||||
|
|
||||||
bool Operator::login(std::string account, std::string passwd, std::string& err)
|
bool Operator::login(std::string account, std::string passwd, std::string& err)
|
||||||
{
|
{
|
||||||
bool ret = DAO::login(nullptr, account, passwd, err);
|
auto ecode = DAO::login(nullptr, account, passwd, err);
|
||||||
|
if (ecode == Errcode::OK)
|
||||||
if (ret)
|
|
||||||
{
|
{
|
||||||
XLOGD() << "用户[" + account + "]登录成功";
|
XLOGD() << "用户[" + account + "]登录成功";
|
||||||
}
|
}
|
||||||
@@ -14,5 +13,5 @@ bool Operator::login(std::string account, std::string passwd, std::string& err)
|
|||||||
{
|
{
|
||||||
XLOGD() << "用户[" + account + "]登录失败: " << err;
|
XLOGD() << "用户[" + account + "]登录失败: " << err;
|
||||||
}
|
}
|
||||||
return ret;
|
return (ecode == Errcode::OK);
|
||||||
}
|
}
|
||||||
15
src/app/errcode.h
Normal file
15
src/app/errcode.h
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
enum class Errcode
|
||||||
|
{
|
||||||
|
OK = 0,
|
||||||
|
|
||||||
|
ERR = 100,
|
||||||
|
|
||||||
|
ERR_DB_CONN = 101, // 数据库连接错误
|
||||||
|
ERR_DB_SQL = 102, // 数据库查询SQL错误
|
||||||
|
|
||||||
|
ERR_LOGIN_USER_NOTEXIST = 103, // 登入错误,用户不存在
|
||||||
|
ERR_LOGIN_PASSWD = 104, // 登入错误,密码不正确
|
||||||
|
|
||||||
|
};
|
||||||
@@ -7,4 +7,4 @@ cd #buildmsvc2019
|
|||||||
|
|
||||||
@REM Visual Studio 16 2019/Visual Studio 17 2022
|
@REM Visual Studio 16 2019/Visual Studio 17 2022
|
||||||
@REM Win32/x64
|
@REM Win32/x64
|
||||||
cmake ../src -G "Visual Studio 16 2019" -A x64
|
cmake ../src -G "Visual Studio 16 2019" -A Win32
|
||||||
@@ -3,45 +3,45 @@
|
|||||||
|
|
||||||
void DataFields::set(string key, string val)
|
void DataFields::set(string key, string val)
|
||||||
{
|
{
|
||||||
map_fields_[key] = val;
|
mapFields_[key] = val;
|
||||||
}
|
}
|
||||||
void DataFields::set(string key, float val)
|
void DataFields::set(string key, float val)
|
||||||
{
|
{
|
||||||
map_fields_[key] = std::to_string(val);
|
mapFields_[key] = std::to_string(val);
|
||||||
}
|
}
|
||||||
void DataFields::set(string key, int val)
|
void DataFields::set(string key, int val)
|
||||||
{
|
{
|
||||||
map_fields_[key] = std::to_string(val);
|
mapFields_[key] = std::to_string(val);
|
||||||
}
|
}
|
||||||
void DataFields::set(string key, int64_t val)
|
void DataFields::set(string key, int64_t val)
|
||||||
{
|
{
|
||||||
map_fields_[key] = std::to_string(val);
|
mapFields_[key] = std::to_string(val);
|
||||||
}
|
}
|
||||||
string DataFields::get_str(string key)
|
string DataFields::getStr(string key)
|
||||||
{
|
{
|
||||||
if (map_fields_.count(key) > 0)
|
if (mapFields_.count(key) > 0)
|
||||||
{
|
{
|
||||||
return map_fields_[key];
|
return mapFields_[key];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
int DataFields::get_int(string key)
|
int DataFields::getInt(string key)
|
||||||
{
|
{
|
||||||
return map_fields_.count(key) > 0 ? Utils::toInt(map_fields_[key]) : 0;
|
return mapFields_.count(key) > 0 ? Utils::toInt(mapFields_[key]) : 0;
|
||||||
}
|
}
|
||||||
float DataFields::get_float(string key)
|
float DataFields::getFloat(string key)
|
||||||
{
|
{
|
||||||
return map_fields_.count(key) > 0 ? Utils::toFloat(map_fields_[key]) : 0.0f;
|
return mapFields_.count(key) > 0 ? Utils::toFloat(mapFields_[key]) : 0.0f;
|
||||||
}
|
}
|
||||||
void DataFields::remove(string key)
|
void DataFields::remove(string key)
|
||||||
{
|
{
|
||||||
auto it = map_fields_.find(key);
|
auto it = mapFields_.find(key);
|
||||||
if (it != map_fields_.end())
|
if (it != mapFields_.end())
|
||||||
{
|
{
|
||||||
map_fields_.erase(it);
|
mapFields_.erase(it);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void DataFields::append(DataFields& datafield)
|
void DataFields::append(DataFields& datafield)
|
||||||
@@ -49,19 +49,19 @@ void DataFields::append(DataFields& datafield)
|
|||||||
auto& map_f = datafield.fields();
|
auto& map_f = datafield.fields();
|
||||||
for (auto it = map_f.begin(); it != map_f.end(); it++)
|
for (auto it = map_f.begin(); it != map_f.end(); it++)
|
||||||
{
|
{
|
||||||
map_fields_[it->first] = it->second;
|
mapFields_[it->first] = it->second;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
map<string, string>& DataFields::fields()
|
map<string, string>& DataFields::fields()
|
||||||
{
|
{
|
||||||
return map_fields_;
|
return mapFields_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DataFields::check(string key, string val, string d)
|
void DataFields::check(string key, string val, string d)
|
||||||
{
|
{
|
||||||
if (map_fields_.count(key) > 0 && map_fields_[key] == val)
|
if (mapFields_.count(key) > 0 && mapFields_[key] == val)
|
||||||
{
|
{
|
||||||
map_fields_[key] = d;
|
mapFields_[key] = d;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,7 +69,7 @@ string DataFields::get_insert_sql(string tbname)
|
|||||||
{
|
{
|
||||||
string key;
|
string key;
|
||||||
string val;
|
string val;
|
||||||
for (auto it = map_fields_.begin(); it != map_fields_.end(); it++)
|
for (auto it = mapFields_.begin(); it != mapFields_.end(); it++)
|
||||||
{
|
{
|
||||||
if (!key.empty())
|
if (!key.empty())
|
||||||
{
|
{
|
||||||
@@ -93,9 +93,9 @@ string DataFields::get_update_sql(string tbname, string sql_c)
|
|||||||
{
|
{
|
||||||
ostringstream oss;
|
ostringstream oss;
|
||||||
oss << "update " << tbname << " set ";
|
oss << "update " << tbname << " set ";
|
||||||
for (auto iter = map_fields_.begin(); iter != map_fields_.end(); iter++)
|
for (auto iter = mapFields_.begin(); iter != mapFields_.end(); iter++)
|
||||||
{
|
{
|
||||||
if (iter != map_fields_.begin())
|
if (iter != mapFields_.begin())
|
||||||
{
|
{
|
||||||
oss << ",";
|
oss << ",";
|
||||||
};
|
};
|
||||||
@@ -120,12 +120,12 @@ string DataFields::get_update_sql(string tbname, std::vector<std::string> vec_ke
|
|||||||
|
|
||||||
ostringstream oss;
|
ostringstream oss;
|
||||||
oss << "update " << tbname << " set ";
|
oss << "update " << tbname << " set ";
|
||||||
for (auto iter = map_fields_.begin(); iter != map_fields_.end(); iter++)
|
for (auto iter = mapFields_.begin(); iter != mapFields_.end(); iter++)
|
||||||
{
|
{
|
||||||
auto& k = iter->first;
|
auto& k = iter->first;
|
||||||
auto& v = iter->second;
|
auto& v = iter->second;
|
||||||
if (!map_keys[k]) { continue; }
|
if (!map_keys[k]) { continue; }
|
||||||
if (iter != map_fields_.begin())
|
if (iter != mapFields_.begin())
|
||||||
{
|
{
|
||||||
oss << ",";
|
oss << ",";
|
||||||
};
|
};
|
||||||
@@ -145,7 +145,7 @@ string DataFields::get_update_sql(string tbname, std::vector<std::string> vec_ke
|
|||||||
|
|
||||||
void DataFields::foreach_item(function<void(string key, string val)> on_foraach)
|
void DataFields::foreach_item(function<void(string key, string val)> on_foraach)
|
||||||
{
|
{
|
||||||
for (auto it = map_fields_.begin(); it != map_fields_.end(); it++)
|
for (auto it = mapFields_.begin(); it != mapFields_.end(); it++)
|
||||||
{
|
{
|
||||||
if (on_foraach)
|
if (on_foraach)
|
||||||
{
|
{
|
||||||
@@ -153,15 +153,15 @@ void DataFields::foreach_item(function<void(string key, string val)> on_foraach)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bool DataFields::is_empty(string key)
|
bool DataFields::isEmpty(string key)
|
||||||
{
|
{
|
||||||
auto& s = map_fields_[key];
|
auto& s = mapFields_[key];
|
||||||
return s.empty();
|
return s.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DataFields::is_float_number(string key)
|
bool DataFields::is_float_number(string key)
|
||||||
{
|
{
|
||||||
auto& s = map_fields_[key];
|
auto& s = mapFields_[key];
|
||||||
if (s.empty())
|
if (s.empty())
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@@ -179,7 +179,7 @@ bool DataFields::is_float_number(string key)
|
|||||||
string DataFields::to_str()
|
string DataFields::to_str()
|
||||||
{
|
{
|
||||||
string s;
|
string s;
|
||||||
for (auto it = map_fields_.begin(); it != map_fields_.end(); it++)
|
for (auto it = mapFields_.begin(); it != mapFields_.end(); it++)
|
||||||
{
|
{
|
||||||
s += ("[" + it->first + ":" + it->second + "] ");
|
s += ("[" + it->first + ":" + it->second + "] ");
|
||||||
}
|
}
|
||||||
@@ -188,10 +188,10 @@ string DataFields::to_str()
|
|||||||
|
|
||||||
int DataFields::size()
|
int DataFields::size()
|
||||||
{
|
{
|
||||||
return map_fields_.size();
|
return mapFields_.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DataFields::clear()
|
void DataFields::clear()
|
||||||
{
|
{
|
||||||
map_fields_.clear();
|
mapFields_.clear();
|
||||||
}
|
}
|
||||||
@@ -51,19 +51,19 @@ public:
|
|||||||
* 获取 string 值
|
* 获取 string 值
|
||||||
* @param: [string key] 索引名称
|
* @param: [string key] 索引名称
|
||||||
*/
|
*/
|
||||||
string get_str(string key);
|
string getStr(string key);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取 int 值
|
* 获取 int 值
|
||||||
* @param: [string key] 索引名称
|
* @param: [string key] 索引名称
|
||||||
*/
|
*/
|
||||||
int get_int(string key);
|
int getInt(string key);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取 float 值
|
* 获取 float 值
|
||||||
* @param: [string key] 索引名称
|
* @param: [string key] 索引名称
|
||||||
*/
|
*/
|
||||||
float get_float(string key);
|
float getFloat(string key);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除指定索引的值
|
* 删除指定索引的值
|
||||||
@@ -122,7 +122,7 @@ public:
|
|||||||
* 判断是否含有数据项
|
* 判断是否含有数据项
|
||||||
* @param: [string key] 索引名称
|
* @param: [string key] 索引名称
|
||||||
*/
|
*/
|
||||||
bool is_empty(string key);
|
bool isEmpty(string key);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 判断数据项是否是float数值类型
|
* 判断数据项是否是float数值类型
|
||||||
@@ -143,7 +143,7 @@ public:
|
|||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
map<string, string> map_fields_;
|
map<string, string> mapFields_;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
67
src/common/JsonN.h
Normal file
67
src/common/JsonN.h
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
#include <fstream>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
using NJson = nlohmann::json;
|
||||||
|
|
||||||
|
/// =============================================================================================
|
||||||
|
/// 使用说明:
|
||||||
|
|
||||||
|
/// 创建 -------------
|
||||||
|
// json j;
|
||||||
|
// j["name"] = "Alice";
|
||||||
|
// j["age"] = 25;
|
||||||
|
// j["address"] = {{"city", "Beijing"}, {"country", "China"}};
|
||||||
|
|
||||||
|
/// 字符串解析 -------------
|
||||||
|
// json::parse(R"({"name": "Alice", "age": 25})");
|
||||||
|
// 说明:解析失败会抛出异常
|
||||||
|
// try {
|
||||||
|
// auto j = json::parse("invalid json");
|
||||||
|
// }
|
||||||
|
// catch (json::parse_error& e) {
|
||||||
|
// std::cerr << "JSON 解析错误: " << e.what() << std::endl;
|
||||||
|
// }
|
||||||
|
|
||||||
|
/// 文件解析 -------------
|
||||||
|
// std::ifstream file("data.json");
|
||||||
|
// json j;
|
||||||
|
// file >> j;
|
||||||
|
|
||||||
|
/// 访问 JSON 数据 -------------
|
||||||
|
// std::string name = j["name"]; // 直接访问
|
||||||
|
// int age = j.at("age"); // 使用 at() 检查 key 是否存在
|
||||||
|
// auto address = j["address"]; // 获取数组
|
||||||
|
|
||||||
|
/// 序列化为字符串 -------------
|
||||||
|
// std::string json_str = j.dump(4); // 4 表示缩进,美化输出
|
||||||
|
|
||||||
|
static bool NJsonLoad(std::string jsonfile, NJson& json)
|
||||||
|
{
|
||||||
|
std::ifstream ifs(jsonfile);
|
||||||
|
if (ifs.is_open())
|
||||||
|
{
|
||||||
|
ifs >> json;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool NJsonParse(std::string jsonstr, NJson& json)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
json = NJson::parse(jsonstr);
|
||||||
|
}
|
||||||
|
catch (nlohmann::json::parse_error& e)
|
||||||
|
{
|
||||||
|
//std::cerr << "JSON 解析错误: " << e.what() << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool NJsonLHas(NJson& json, std::string key)
|
||||||
|
{
|
||||||
|
return json.contains("database");
|
||||||
|
}
|
||||||
@@ -6,12 +6,10 @@
|
|||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <exception>
|
#include <exception>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <string>
|
|
||||||
|
|
||||||
// 如果不使用 mutex, 则开启下面这个定义, 但是我发现, 还是开启 mutex 功能, 速度比较快
|
// 如果不使用 mutex, 则开启下面这个定义, 但是我发现, 还是开启 mutex 功能, 速度比较快
|
||||||
// #define SNOWFLAKE_ID_WORKER_NO_LOCK
|
// #define SNOWFLAKE_ID_WORKER_NO_LOCK
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 分布式id生成类
|
* @brief 分布式id生成类
|
||||||
* https://segmentfault.com/a/1190000011282426
|
* https://segmentfault.com/a/1190000011282426
|
||||||
@@ -19,44 +17,44 @@
|
|||||||
*
|
*
|
||||||
* 64bit id: 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
|
* 64bit id: 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
|
||||||
* || || || | | |
|
* || || || | | |
|
||||||
* |└---------------------------时间戳--------------------------┘└中心-┘└机器-┘ └----序列号----┘
|
* |└---------------------------时间戳---------------------------┘└-中心-┘└机器-┘ └----序列号----┘
|
||||||
* |
|
|
||||||
* 不用
|
* 不用
|
||||||
* SnowFlake的优点: 整体上按照时间自增排序, 并且整个分布式系统内不会产生ID碰撞(由数据中心ID和机器ID作区分), 并且效率较高, 经测试, SnowFlake每秒能够产生26万ID左右.
|
* SnowFlake的优点: 整体上按照时间自增排序, 并且整个分布式系统内不会产生ID碰撞(由数据中心ID和机器ID作区分), 并且效率较高, 经测试, SnowFlake每秒能够产生26万ID左右.
|
||||||
*/
|
*/
|
||||||
class Snowflake
|
class Snowflake
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static Snowflake& instance()
|
//typedef unsigned int UInt;
|
||||||
{
|
//typedef unsigned long long int UInt64;
|
||||||
static Snowflake sf;
|
|
||||||
return sf;
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef unsigned int UInt;
|
|
||||||
typedef unsigned long long int UInt64;
|
|
||||||
|
|
||||||
#ifdef SNOWFLAKE_ID_WORKER_NO_LOCK
|
#ifdef SNOWFLAKE_ID_WORKER_NO_LOCK
|
||||||
typedef std::atomic<UInt> AtomicUInt;
|
typedef std::atomic<UInt> AtomicUInt;
|
||||||
typedef std::atomic<UInt64> AtomicUInt64;
|
typedef std::atomic<uint64_t> AtomicUInt64;
|
||||||
#else
|
#else
|
||||||
typedef UInt AtomicUInt;
|
typedef unsigned int AtomicUInt;
|
||||||
typedef UInt64 AtomicUInt64;
|
typedef uint64_t AtomicUInt64;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void set_worker_id(UInt workerId)
|
static Snowflake& instance()
|
||||||
{
|
{
|
||||||
this->workerId = workerId;
|
static Snowflake inst;
|
||||||
|
return inst;
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_datacenter_id(UInt datacenterId)
|
void setWorkerId(unsigned int workerId) {
|
||||||
{
|
this->workerId_ = workerId;
|
||||||
this->datacenterId = datacenterId;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
string nextIdStr()
|
void setDatacenterId(unsigned int datacenterId) {
|
||||||
{
|
this->datacenterId_ = datacenterId;
|
||||||
return std::to_string(next_id());
|
}
|
||||||
|
|
||||||
|
uint64_t getId() {
|
||||||
|
return nextId();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string getIdStr() {
|
||||||
|
return std::to_string(nextId());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -64,68 +62,55 @@ public:
|
|||||||
*
|
*
|
||||||
* @return SnowflakeId
|
* @return SnowflakeId
|
||||||
*/
|
*/
|
||||||
UInt64 next_id()
|
uint64_t nextId() {
|
||||||
{
|
|
||||||
#ifndef SNOWFLAKE_ID_WORKER_NO_LOCK
|
#ifndef SNOWFLAKE_ID_WORKER_NO_LOCK
|
||||||
std::unique_lock<std::mutex> lock {mutex};
|
std::unique_lock<std::mutex> lock {mutex};
|
||||||
AtomicUInt64 timestamp {0};
|
AtomicUInt64 timestamp {0};
|
||||||
#else
|
#else
|
||||||
static AtomicUInt64 timestamp {0};
|
static AtomicUInt64 timestamp {0};
|
||||||
#endif
|
#endif
|
||||||
timestamp = time_now_ms();
|
timestamp = timetick();
|
||||||
|
|
||||||
// 如果当前时间小于上一次ID生成的时间戳,说明系统时钟回退过这个时候应当抛出异常
|
// 如果当前时间小于上一次ID生成的时间戳,说明系统时钟回退过这个时候应当抛出异常
|
||||||
if (timestamp < lastTimestamp)
|
if (timestamp < lastTimestamp_) {
|
||||||
{
|
|
||||||
std::ostringstream s;
|
std::ostringstream s;
|
||||||
s << "clock moved backwards. Refusing to generate id for " << lastTimestamp - timestamp << " milliseconds";
|
s << "clock moved backwards. Refusing to generate id for " << lastTimestamp_ - timestamp << " milliseconds";
|
||||||
throw std::exception(std::runtime_error(s.str()));
|
throw std::exception(std::runtime_error(s.str()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lastTimestamp == timestamp)
|
if (lastTimestamp_ == timestamp) {
|
||||||
{
|
|
||||||
// 如果是同一时间生成的,则进行毫秒内序列
|
// 如果是同一时间生成的,则进行毫秒内序列
|
||||||
sequence = (sequence + 1) & sequenceMask;
|
sequence_ = (sequence_ + 1) & sequenceMask;
|
||||||
if (0 == sequence)
|
if (0 == sequence_) {
|
||||||
{
|
|
||||||
// 毫秒内序列溢出, 阻塞到下一个毫秒,获得新的时间戳
|
// 毫秒内序列溢出, 阻塞到下一个毫秒,获得新的时间戳
|
||||||
timestamp = next_millis(lastTimestamp);
|
timestamp = tilNextMillis(lastTimestamp_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
sequence_ = 0;
|
||||||
sequence = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef SNOWFLAKE_ID_WORKER_NO_LOCK
|
#ifndef SNOWFLAKE_ID_WORKER_NO_LOCK
|
||||||
lastTimestamp = timestamp;
|
lastTimestamp_ = timestamp;
|
||||||
#else
|
#else
|
||||||
lastTimestamp = timestamp.load();
|
lastTimestamp_ = timestamp.load();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// 移位并通过或运算拼到一起组成64位的ID
|
// 移位并通过或运算拼到一起组成64位的ID
|
||||||
//return ((timestamp - twepoch) << timestampLeftShift)
|
return ((timestamp - twepoch_) << timestampLeftShift)
|
||||||
// | (datacenterId << datacenterIdShift)
|
| (datacenterId_ << datacenterIdShift)
|
||||||
// | (workerId << workerIdShift)
|
| (workerId_ << workerIdShift)
|
||||||
// | sequence;
|
| sequence_;
|
||||||
return ((timestamp - twepoch) << sequenceBits)
|
|
||||||
//| (datacenterId << datacenterIdShift)
|
|
||||||
//| (workerId << workerIdShift)
|
|
||||||
| sequence;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Snowflake() : workerId(0), datacenterId(0), sequence(0), lastTimestamp(0)
|
Snowflake() : workerId_(0), datacenterId_(0), sequence_(0), lastTimestamp_(0) {}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 返回以毫秒为单位的当前时间
|
* 返回以毫秒为单位的当前时间
|
||||||
*
|
*
|
||||||
* @return 当前时间(毫秒)
|
* @return 当前时间(毫秒)
|
||||||
*/
|
*/
|
||||||
UInt64 time_now_ms() const
|
uint64_t timetick() const {
|
||||||
{
|
|
||||||
//auto t = std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now());
|
//auto t = std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now());
|
||||||
auto t = std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::system_clock::now());
|
auto t = std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::system_clock::now());
|
||||||
return t.time_since_epoch().count();
|
return t.time_since_epoch().count();
|
||||||
@@ -137,12 +122,10 @@ protected:
|
|||||||
* @param lastTimestamp 上次生成ID的时间截
|
* @param lastTimestamp 上次生成ID的时间截
|
||||||
* @return 当前时间戳
|
* @return 当前时间戳
|
||||||
*/
|
*/
|
||||||
UInt64 next_millis(UInt64 lastTimestamp) const
|
uint64_t tilNextMillis(uint64_t lastTimestamp) const {
|
||||||
{
|
uint64_t timestamp = timetick();
|
||||||
UInt64 timestamp = time_now_ms();
|
while (timestamp <= lastTimestamp) {
|
||||||
while (timestamp <= lastTimestamp)
|
timestamp = timetick();
|
||||||
{
|
|
||||||
timestamp = time_now_ms();
|
|
||||||
}
|
}
|
||||||
return timestamp;
|
return timestamp;
|
||||||
}
|
}
|
||||||
@@ -154,74 +137,74 @@ private:
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 开始时间截 (2010-01-01 00:00:00.000) 1262275200000
|
* 开始时间截 2025-01-01 00:00:00.000
|
||||||
*/
|
*/
|
||||||
const UInt64 twepoch = 1262275200000;
|
const uint64_t twepoch_ = 1735660800000;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 机器id所占的位数
|
* 机器id所占的位数
|
||||||
*/
|
*/
|
||||||
const UInt workerIdBits = 5;
|
const unsigned int workerIdBits = 4;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 数据中心id所占的位数
|
* 数据中心id所占的位数
|
||||||
*/
|
*/
|
||||||
const UInt datacenterIdBits = 5;
|
const unsigned int datacenterIdBits = 1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 序列所占的位数
|
* 序列所占的位数
|
||||||
*/
|
*/
|
||||||
const UInt sequenceBits = 12;
|
const unsigned int sequenceBits = 12;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 机器ID向左移12位
|
* 机器ID向左移12位
|
||||||
*/
|
*/
|
||||||
const UInt workerIdShift = sequenceBits;
|
const unsigned int workerIdShift = sequenceBits;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 数据标识id向左移17位
|
* 数据标识id向左移16位
|
||||||
*/
|
*/
|
||||||
const UInt datacenterIdShift = workerIdShift + workerIdBits;
|
const unsigned int datacenterIdShift = workerIdShift + workerIdBits;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 时间截向左移22位
|
* 时间截向左移17位
|
||||||
*/
|
*/
|
||||||
const UInt timestampLeftShift = datacenterIdShift + datacenterIdBits;
|
const unsigned int timestampLeftShift = datacenterIdShift + datacenterIdBits;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 支持的最大机器id,结果是31
|
* 支持的最大机器id,
|
||||||
*/
|
*/
|
||||||
const UInt maxWorkerId = -1 ^ (-1 << workerIdBits);
|
const unsigned int maxWorkerId = -1 ^ (-1 << workerIdBits);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 支持的最大数据中心id,结果是31
|
* 支持的最大数据中心id,
|
||||||
*/
|
*/
|
||||||
const UInt maxDatacenterId = -1 ^ (-1 << datacenterIdBits);
|
const unsigned int maxDatacenterId = -1 ^ (-1 << datacenterIdBits);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 生成序列的掩码,这里为4095
|
* 生成序列的掩码,这里为4095
|
||||||
*/
|
*/
|
||||||
const UInt sequenceMask = -1 ^ (-1 << sequenceBits);
|
const unsigned int sequenceMask = -1 ^ (-1 << sequenceBits);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 工作机器id(0~31)
|
* 工作机器id(0~31)
|
||||||
*/
|
*/
|
||||||
UInt workerId;
|
unsigned int workerId_;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 数据中心id(0~31)
|
* 数据中心id(0~31)
|
||||||
*/
|
*/
|
||||||
UInt datacenterId;
|
unsigned int datacenterId_;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 毫秒内序列(0~4095)
|
* 毫秒内序列(0~4095)
|
||||||
*/
|
*/
|
||||||
AtomicUInt sequence {0};
|
AtomicUInt sequence_ {0};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 上次生成ID的时间截
|
* 上次生成ID的时间截
|
||||||
*/
|
*/
|
||||||
AtomicUInt64 lastTimestamp {0};
|
AtomicUInt64 lastTimestamp_ {0};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // _JW_CORE_ID_WORKER_H_
|
#endif // _JW_CORE_ID_WORKER_H_
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
//#include "PvInstance.h"
|
//#include "PvInstance.h"
|
||||||
//#include "spdlogger.h"
|
//#include "spdlogger.h"
|
||||||
|
|
||||||
MysqlOptions DaoEntity::options_;
|
MysqlOption DaoEntity::option_;
|
||||||
|
|
||||||
DaoEntity::DaoEntity(string tb_name)
|
DaoEntity::DaoEntity(string tb_name)
|
||||||
{
|
{
|
||||||
@@ -12,7 +12,7 @@ DaoEntity::DaoEntity(string tb_name)
|
|||||||
//opts.password = "123456";
|
//opts.password = "123456";
|
||||||
//opts.port = 3306;
|
//opts.port = 3306;
|
||||||
//opts.dbname = "pvb";
|
//opts.dbname = "pvb";
|
||||||
db_ = make_shared<MysqlClient>(DaoEntity::options_);
|
db_ = make_shared<MysqlClient>(DaoEntity::option_);
|
||||||
if (!db_->isConnected())
|
if (!db_->isConnected())
|
||||||
{
|
{
|
||||||
//Global::data().status_msg = "数据库连接异常!";
|
//Global::data().status_msg = "数据库连接异常!";
|
||||||
@@ -26,9 +26,17 @@ DaoEntity::~DaoEntity()
|
|||||||
db_ = nullptr;
|
db_ = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
MysqlOptions& DaoEntity::mysqlOptions()
|
MysqlOption& DaoEntity::mysqlOption()
|
||||||
{
|
{
|
||||||
return DaoEntity::options_;
|
return DaoEntity::option_;
|
||||||
|
}
|
||||||
|
void DaoEntity::setOption(std::string host, int port, std::string user, std::string pwd, std::string dbname)
|
||||||
|
{
|
||||||
|
option_.host = host;
|
||||||
|
option_.port = port;
|
||||||
|
option_.user = user;
|
||||||
|
option_.password = pwd;
|
||||||
|
option_.dbname = dbname;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<DaoEntity> DaoEntity::create(string tb_name)
|
std::shared_ptr<DaoEntity> DaoEntity::create(string tb_name)
|
||||||
@@ -39,13 +47,13 @@ std::shared_ptr<DaoEntity> DaoEntity::create(string tb_name)
|
|||||||
|
|
||||||
bool DaoEntity::execOnce(string sql)
|
bool DaoEntity::execOnce(string sql)
|
||||||
{
|
{
|
||||||
auto db = make_shared<MysqlClient>(DaoEntity::options_);
|
auto db = make_shared<MysqlClient>(DaoEntity::option_);
|
||||||
return db->exec(sql);
|
return db->exec(sql);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DaoEntity::execOnce(string sql, vector<DataFields>& result)
|
bool DaoEntity::execOnce(string sql, vector<DataFields>& result)
|
||||||
{
|
{
|
||||||
auto db = make_shared<MysqlClient>(DaoEntity::options_);
|
auto db = make_shared<MysqlClient>(DaoEntity::option_);
|
||||||
return db->exec(sql, result);
|
return db->exec(sql, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,7 +149,7 @@ bool DaoEntity::duplicateUpdate(DataFields& fields, vector<string>& keys)
|
|||||||
{
|
{
|
||||||
s_data += ",";
|
s_data += ",";
|
||||||
}
|
}
|
||||||
s_data += (k + "='" + fields.get_str(k) + "'");
|
s_data += (k + "='" + fields.getStr(k) + "'");
|
||||||
}
|
}
|
||||||
string sql = "INSERT INTO " + tableName_ + "(" + s_key + ") VALUES (" + s_val + ") ON duplicate KEY UPDATE " + s_data;
|
string sql = "INSERT INTO " + tableName_ + "(" + s_key + ") VALUES (" + s_val + ") ON duplicate KEY UPDATE " + s_data;
|
||||||
return this->db_->exec(sql);
|
return this->db_->exec(sql);
|
||||||
@@ -178,7 +186,7 @@ bool DaoEntity::queryFields(string keys, const string& sql_c, PageInfo& pageinfo
|
|||||||
pageinfo.total = 0;
|
pageinfo.total = 0;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
pageinfo.total = res_total[0].get_int("total");
|
pageinfo.total = res_total[0].getInt("total");
|
||||||
if (pageinfo.total <= 0)
|
if (pageinfo.total <= 0)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -9,7 +9,8 @@ public:
|
|||||||
DaoEntity(string tableName);
|
DaoEntity(string tableName);
|
||||||
~DaoEntity();
|
~DaoEntity();
|
||||||
|
|
||||||
static MysqlOptions& mysqlOptions();
|
static MysqlOption& mysqlOption();
|
||||||
|
static void setOption(std::string host, int port, std::string user, std::string pwd, std::string dbname);
|
||||||
|
|
||||||
static std::shared_ptr<DaoEntity> create(string tableName);
|
static std::shared_ptr<DaoEntity> create(string tableName);
|
||||||
|
|
||||||
@@ -99,7 +100,7 @@ public:
|
|||||||
bool updateFields(DataFields& fields, vector<string> vecKeys, const string& cond);
|
bool updateFields(DataFields& fields, vector<string> vecKeys, const string& cond);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static MysqlOptions options_;
|
static MysqlOption option_;
|
||||||
|
|
||||||
// mysql 数据库操作对象
|
// mysql 数据库操作对象
|
||||||
std::shared_ptr<MysqlClient> db_ = nullptr;
|
std::shared_ptr<MysqlClient> db_ = nullptr;
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
//#include "Spdlogger.h"
|
//#include "Spdlogger.h"
|
||||||
#include "Logger.h"
|
#include "Logger.h"
|
||||||
|
|
||||||
MysqlClient::MysqlClient(MysqlOptions opts) : options_(opts)
|
MysqlClient::MysqlClient(MysqlOption option) : option_(option)
|
||||||
{
|
{
|
||||||
conn();
|
conn();
|
||||||
}
|
}
|
||||||
@@ -20,9 +20,10 @@ int MysqlClient::conn()
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
mysql_ = mysql_init(nullptr);
|
mysql_ = mysql_init(nullptr);
|
||||||
MYSQL* ret = mysql_real_connect(mysql_, options_.host.c_str(), options_.user.c_str(), options_.password.c_str(), options_.dbname.c_str(), options_.port, NULL, 0);
|
MYSQL* ret = mysql_real_connect(mysql_, option_.host.c_str(), option_.user.c_str(), option_.password.c_str(), option_.dbname.c_str(), option_.port, NULL, 0);
|
||||||
if (ret == NULL)
|
if (ret == NULL)
|
||||||
{
|
{
|
||||||
|
std::string err = mysql_error(mysql_);
|
||||||
//Spdlogger::info("[mysql] connect failed: {}", mysql_error(mysql_));
|
//Spdlogger::info("[mysql] connect failed: {}", mysql_error(mysql_));
|
||||||
mysql_ = nullptr;
|
mysql_ = nullptr;
|
||||||
}
|
}
|
||||||
@@ -49,7 +50,7 @@ void MysqlClient::close()
|
|||||||
|
|
||||||
bool MysqlClient::exec(std::string sql)
|
bool MysqlClient::exec(std::string sql)
|
||||||
{
|
{
|
||||||
XLOGD() << "Mysql exec sql=" << sql;
|
//XLOGD() << "Mysql exec sql=" << sql;
|
||||||
if (!mysql_)
|
if (!mysql_)
|
||||||
{
|
{
|
||||||
XLOGE() << "Mysql exec error, database is not connected.";
|
XLOGE() << "Mysql exec error, database is not connected.";
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
struct MysqlOptions
|
struct MysqlOption
|
||||||
{
|
{
|
||||||
std::string host;
|
std::string host;
|
||||||
std::string user;
|
std::string user;
|
||||||
@@ -27,7 +27,7 @@ struct MysqlOptions
|
|||||||
class MysqlClient
|
class MysqlClient
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MysqlClient(MysqlOptions options);
|
MysqlClient(MysqlOption option);
|
||||||
~MysqlClient();
|
~MysqlClient();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -62,7 +62,7 @@ private:
|
|||||||
MYSQL* mysql_ = nullptr;
|
MYSQL* mysql_ = nullptr;
|
||||||
|
|
||||||
// 数据库连接信息
|
// 数据库连接信息
|
||||||
MysqlOptions options_;
|
MysqlOption option_;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // !!! _DbMysql_H_
|
#endif // !!! _DbMysql_H_
|
||||||
|
|||||||
81
src/main.cpp
81
src/main.cpp
@@ -1,4 +1,5 @@
|
|||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QtWebEngineWidgets/QtWebEngineWidgets>
|
#include <QtWebEngineWidgets/QtWebEngineWidgets>
|
||||||
@@ -9,44 +10,60 @@
|
|||||||
#include "app/Application.h"
|
#include "app/Application.h"
|
||||||
#include "app/Dao.h"
|
#include "app/Dao.h"
|
||||||
|
|
||||||
|
#include "common/Snowflake.h"
|
||||||
|
#include "protocol/TcpEntity.h"
|
||||||
|
|
||||||
|
#include "common/JsonN.h"
|
||||||
|
|
||||||
|
#include "app/Config.h"
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
SetConsoleOutputCP(CP_UTF8); // 设置控制台输出为UTF-8
|
// 设置控制台输出为 UTF-8 编码
|
||||||
|
SetConsoleOutputCP(CP_UTF8);
|
||||||
|
// 设置控制台输入为 UTF-8 编码(如果需要输入中文)
|
||||||
|
SetConsoleCP(CP_UTF8);
|
||||||
|
|
||||||
auto& mysqlOptions = DaoEntity::mysqlOptions();
|
NJson jsonroot;
|
||||||
mysqlOptions.host = "localhost";
|
NJsonParse(R"({"name": "Alice", "age": 25, 111,})", jsonroot);
|
||||||
mysqlOptions.port = 3306;
|
|
||||||
mysqlOptions.user = "root";
|
std::cout << (jsonroot.is_null() ? "ERROR" : "OK") << std::endl;
|
||||||
mysqlOptions.password = "123456";
|
|
||||||
mysqlOptions.dbname = "ees";
|
////std::cout << Snowflake::instance().getId() << std::endl;
|
||||||
|
//for (int i = 0; i<=10; ++i) {
|
||||||
|
// //std::cout << Snowflake::instance().getId() << std::endl;
|
||||||
|
//}
|
||||||
|
|
||||||
|
|
||||||
std::string filename = "assets/html/data中文.txt";
|
//DaoEntity dao("");
|
||||||
|
//
|
||||||
std::filesystem::path filePath = std::filesystem::u8path("assets/html/data中文.txt");
|
//std::string filename = "assets/html/data中文.txt";
|
||||||
//std::locale::global(locale(""));//将全局区域设为操作系统默认区域
|
//
|
||||||
std::ifstream ifs(filePath, std::ios::binary);
|
//std::filesystem::path filePath = std::filesystem::u8path("assets/html/data中文.txt");
|
||||||
//std::locale::global(locale("C"));//还原全局区域设定
|
////std::locale::global(locale(""));//将全局区域设为操作系统默认区域
|
||||||
|
//std::ifstream ifs(filePath, std::ios::binary);
|
||||||
if (ifs.is_open())
|
////std::locale::global(locale("C"));//还原全局区域设定
|
||||||
{
|
|
||||||
// 将文件指针移动到末尾获取文件大小
|
|
||||||
ifs.seekg(0, std::ios::end);
|
|
||||||
std::streamsize size = ifs.tellg();
|
|
||||||
ifs.seekg(0, std::ios::beg);
|
|
||||||
|
|
||||||
std::string buf(size, '\0');
|
|
||||||
ifs.read(&buf[0], size);
|
|
||||||
std::cout << "文件内容: " << buf << std::endl;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
std::cout << "error" << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
//if (ifs.is_open())
|
||||||
|
//{
|
||||||
|
// // 将文件指针移动到末尾获取文件大小
|
||||||
|
// ifs.seekg(0, std::ios::end);
|
||||||
|
// std::streamsize size = ifs.tellg();
|
||||||
|
// ifs.seekg(0, std::ios::beg);
|
||||||
|
|
||||||
|
// std::string buf(size, '\0');
|
||||||
|
// ifs.read(&buf[0], size);
|
||||||
|
// std::cout << "文件内容: " << buf << std::endl;
|
||||||
|
//}
|
||||||
|
//else
|
||||||
|
//{
|
||||||
|
// std::cout << "error" << std::endl;
|
||||||
|
//}
|
||||||
|
|
||||||
|
//TcpEntity tcpEntity;
|
||||||
|
//tcpEntity.setHost("127.0.0.1", 9901, true);
|
||||||
|
//tcpEntity.setReconnect(5000);
|
||||||
|
//tcpEntity.start();
|
||||||
|
|
||||||
// 运行后台服务
|
// 运行后台服务
|
||||||
Application::instance().init();
|
Application::instance().init();
|
||||||
@@ -58,5 +75,9 @@ int main(int argc, char** argv)
|
|||||||
mainWin.resize(1920, 1080);
|
mainWin.resize(1920, 1080);
|
||||||
mainWin.show();
|
mainWin.show();
|
||||||
qapp.exec();
|
qapp.exec();
|
||||||
|
|
||||||
|
//while (1) {
|
||||||
|
// std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||||
|
//}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
28
src/protocol/Communicator.cpp
Normal file
28
src/protocol/Communicator.cpp
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
#include "Communicator.h"
|
||||||
|
#include "TcpEntity.h"
|
||||||
|
|
||||||
|
std::shared_ptr<CommEntity> Communicator::createEntity(DataFields& data)
|
||||||
|
{
|
||||||
|
std::string commType = data.getStr("commType");
|
||||||
|
std::string ip = data.getStr("ip");
|
||||||
|
int port = data.getInt("port");
|
||||||
|
int isclient = data.getInt("isclient");
|
||||||
|
|
||||||
|
if (commType == "TCP")
|
||||||
|
{
|
||||||
|
auto entity = std::make_shared<TcpEntity>();
|
||||||
|
entity->setHost(ip, port, isclient);
|
||||||
|
return entity;
|
||||||
|
}
|
||||||
|
else if (commType == "MODBUS")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
else if (commType == "ACTIVEX")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
else if (commType == "SDK")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
39
src/protocol/Communicator.h
Normal file
39
src/protocol/Communicator.h
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "common/DataFields.h"
|
||||||
|
|
||||||
|
class CommEntity
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CommEntity() {}
|
||||||
|
CommEntity(std::string type) : type(type) {}
|
||||||
|
|
||||||
|
void setType(std::string type) { this->type = type; }
|
||||||
|
|
||||||
|
// 启动通讯连接
|
||||||
|
virtual int start() { return 0; };
|
||||||
|
// 关闭通讯连接
|
||||||
|
virtual void close() { isCloseRequest_ = true; };
|
||||||
|
|
||||||
|
std::string id() { return id_; }
|
||||||
|
|
||||||
|
bool isAlive() { return isAlive_; }
|
||||||
|
bool isConnected() { return isConnected_; }
|
||||||
|
|
||||||
|
public:
|
||||||
|
std::string id_;
|
||||||
|
bool isAlive_ = false;
|
||||||
|
bool isConnected_ = false;
|
||||||
|
bool isCloseRequest_ = false;
|
||||||
|
std::string type;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class Communicator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static std::shared_ptr<CommEntity> createEntity(DataFields& data);
|
||||||
|
};
|
||||||
281
src/protocol/TcpEntity.cpp
Normal file
281
src/protocol/TcpEntity.cpp
Normal file
@@ -0,0 +1,281 @@
|
|||||||
|
#include "TcpEntity.h"
|
||||||
|
#include "common/Utils.h"
|
||||||
|
#include <sstream>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
static std::string ToHexText(std::string s)
|
||||||
|
{
|
||||||
|
std::stringstream ss;
|
||||||
|
for (unsigned int i = 0; i < s.size(); ++i)
|
||||||
|
{
|
||||||
|
unsigned char ch = s[i];
|
||||||
|
ss << std::setw(2) << std::setfill('0') << std::hex << std::uppercase << (int)ch << ((i < s.size() - 1) ? " " : "");
|
||||||
|
}
|
||||||
|
return ss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
TcpEntity::TcpEntity(TcpHandler* handler)
|
||||||
|
: handler_(handler), isClient_(true)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
TcpEntity::~TcpEntity()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void TcpEntity::setHandler(TcpHandler* handler)
|
||||||
|
{
|
||||||
|
handler_ = handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TcpEntity::setHost(string host, int port, bool isClient)
|
||||||
|
{
|
||||||
|
host_ = host;
|
||||||
|
port_ = port;
|
||||||
|
isClient_ = isClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void TcpEntity::setReconnect(int ms)
|
||||||
|
{
|
||||||
|
tReconnect_ = ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
int TcpEntity::start()
|
||||||
|
{
|
||||||
|
if (isAlive_)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
isAlive_ = true;
|
||||||
|
|
||||||
|
WSADATA wsaData;
|
||||||
|
if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
sockaddr_.sin_family = AF_INET;
|
||||||
|
sockaddr_.sin_port = htons(port_);
|
||||||
|
sockaddr_.sin_addr.S_un.S_addr = (isClient_ ? inet_addr(host_.c_str()) : htonl(INADDR_ANY));
|
||||||
|
|
||||||
|
std::thread([=]() { this->runThreadTcp(); }).detach();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TcpEntity::runThreadTcp()
|
||||||
|
{
|
||||||
|
//if (isRequestClose_) { break; }
|
||||||
|
//std::this_thread::sleep_for(std::chrono::milliseconds(1000));
|
||||||
|
|
||||||
|
std::cout << "TCP thread start ..." << std::endl;
|
||||||
|
if (isClient_)
|
||||||
|
{
|
||||||
|
this->runClientLoop();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this->runServerLoop();
|
||||||
|
}
|
||||||
|
isAlive_ = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TcpEntity::close()
|
||||||
|
{
|
||||||
|
isCloseRequest_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TcpEntity::runServerLoop()
|
||||||
|
{
|
||||||
|
sock_ = ::socket(AF_INET, SOCK_STREAM, 0);
|
||||||
|
// 绑定套接字 【注意】functional中定义了bind与winsock2的定义发生重载导致异常,这里需要使用::bind(加::)
|
||||||
|
if (::bind(sock_, (SOCKADDR*)&sockaddr_, sizeof(SOCKADDR)) == SOCKET_ERROR)
|
||||||
|
{
|
||||||
|
std::cout << "TCP server bind [" << hostport() << "] failed." << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 启动监听,准备接收客户请求
|
||||||
|
if (::listen(sock_, 5) == SOCKET_ERROR)
|
||||||
|
{
|
||||||
|
std::cout << "TCP server listen [" << hostport() << "] failed." << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int addrlen = sizeof(SOCKADDR);
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
if (isCloseRequest_) { break; }
|
||||||
|
|
||||||
|
Client client;
|
||||||
|
|
||||||
|
// 等待客户请求到来
|
||||||
|
client.sock = ::accept(sock_, (SOCKADDR*)&client.sock_addr, &addrlen);
|
||||||
|
if (client.sock == INVALID_SOCKET)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
client.host = inet_ntoa(client.sock_addr.sin_addr);
|
||||||
|
|
||||||
|
// 存储客户端的连接信息
|
||||||
|
vecClient_.push_back(client);
|
||||||
|
|
||||||
|
// 创建线程处理
|
||||||
|
std::thread th([=]() { this->runServerRecvLoop(client, client.host); });
|
||||||
|
th.detach();
|
||||||
|
}
|
||||||
|
::closesocket(sock_);
|
||||||
|
|
||||||
|
// 连接关闭
|
||||||
|
for (auto iter = vecClient_.begin(); iter != vecClient_.end(); ++iter)
|
||||||
|
{
|
||||||
|
::closesocket(iter->sock);
|
||||||
|
vecClient_.erase(iter);
|
||||||
|
}
|
||||||
|
isCloseRequest_ = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TcpEntity::runServerRecvLoop(Client client, std::string client_name)
|
||||||
|
{
|
||||||
|
std::vector<char> buf(1024000, 0);
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
if (isCloseRequest_ || !isAlive_)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
memset(buf.data(), 0, buf.size());
|
||||||
|
// 接收数据
|
||||||
|
int n = ::recv(client.sock, &buf[0], buf.size(), 0);
|
||||||
|
// 需要判断 errno是否等于 EINTR 。如果errno == EINTR 则说明recv函数是由于程序接收到信号后返回的,socket连接还是正常的
|
||||||
|
if (n <= 0 && GetLastError() != EINTR)
|
||||||
|
{
|
||||||
|
// 客户端连接异常(关闭)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 连接关闭
|
||||||
|
for (auto iter = vecClient_.begin(); iter != vecClient_.end(); ++iter)
|
||||||
|
{
|
||||||
|
if (iter->sock == client.sock)
|
||||||
|
{
|
||||||
|
vecClient_.erase(iter);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TcpEntity::runClientLoop()
|
||||||
|
{
|
||||||
|
// 数据缓存
|
||||||
|
std::vector<char> buf(1024000, 0);
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
if (isCloseRequest_) { break; }
|
||||||
|
|
||||||
|
//创建套接字,向服务器发出连接请求
|
||||||
|
sock_ = ::socket(AF_INET, SOCK_STREAM, 0);
|
||||||
|
if (::connect(sock_, (SOCKADDR*)&sockaddr_, sizeof(SOCKADDR)) != SOCKET_ERROR)
|
||||||
|
{
|
||||||
|
isConnected_ = true;
|
||||||
|
std::cout << "TCP client connect to [" << hostport() << "] success." << std::endl;
|
||||||
|
|
||||||
|
// 连接服务器成功,循环等待接受消息
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
if (isCloseRequest_) { break; }
|
||||||
|
|
||||||
|
memset(buf.data(), 0, buf.size());
|
||||||
|
int n = ::recv(sock_, buf.data(), buf.size(), 0);
|
||||||
|
if (n <= 0 && GetLastError() != EINTR)
|
||||||
|
{
|
||||||
|
// TCP通讯异常, 关闭连接
|
||||||
|
::closesocket(sock_);
|
||||||
|
isConnected_ = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 处理消息
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
isConnected_ = false;
|
||||||
|
std::cout << "TCP client connect to [" << hostport() << "] failed." << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 连接异常
|
||||||
|
if (tReconnect_ > 0)
|
||||||
|
{
|
||||||
|
// 重新连接
|
||||||
|
std::cout << "TCP client [" << hostport() << "] reconnect (" << tReconnect_ << ")." << std::endl;
|
||||||
|
//std::this_thread::sleep_for(std::chrono::microseconds(tReconnect_));
|
||||||
|
Sleep(tReconnect_);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 关闭线程
|
||||||
|
std::cout << "TCP client [" << hostport() << "] close." << std::endl;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (sock_ != INVALID_SOCKET)
|
||||||
|
{
|
||||||
|
::closesocket(sock_);
|
||||||
|
sock_ = INVALID_SOCKET;
|
||||||
|
isConnected_ = false;
|
||||||
|
}
|
||||||
|
if (isCloseRequest_)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
isCloseRequest_ = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TcpEntity::sendData(std::string data, std::string clientId)
|
||||||
|
{
|
||||||
|
if (isClient_)
|
||||||
|
{
|
||||||
|
// #客户端
|
||||||
|
if (sock_ == INVALID_SOCKET)
|
||||||
|
{
|
||||||
|
//Spdlogger::error("TCP client send data failed, connect error, invalid socket, device: {}:{}.", this->type_, client_code);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
int len = ::send(sock_, data.c_str(), data.size(), 0);
|
||||||
|
//Spdlogger::info("TCP client send data success, data length={}, device: {}:{}.", len, this->type_, client_code);
|
||||||
|
return (len > 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (vecClient_.size() <= 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (auto& client : vecClient_)
|
||||||
|
{
|
||||||
|
std::string client_addr = inet_ntoa(client.sock_addr.sin_addr);
|
||||||
|
::send(client.sock, data.c_str(), data.size(), 0);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool TcpEntity::isAlive()
|
||||||
|
{
|
||||||
|
return isAlive_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TcpEntity::isConnected()
|
||||||
|
{
|
||||||
|
return isConnected_;
|
||||||
|
}
|
||||||
117
src/protocol/TcpEntity.h
Normal file
117
src/protocol/TcpEntity.h
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
#ifndef _TcpEntity_H_
|
||||||
|
#define _TcpEntity_H_
|
||||||
|
|
||||||
|
#include <Winsock2.h>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <thread>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
#include "Communicator.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
enum class ETcpEvent
|
||||||
|
{
|
||||||
|
NUL = 0, //
|
||||||
|
SRV_SUCCESS, // 服务端启动成功(listen成功)
|
||||||
|
ACCEPT, // 服务端接收到客户端的连接
|
||||||
|
CONN_OK, // 作为客户端时,连接成功
|
||||||
|
CONN_ERR, // 作为客户端时,连接失败
|
||||||
|
MSG_RECV, // 接收消息
|
||||||
|
MSG_SEND, // 发送消息
|
||||||
|
CLOSE, // 断开连接
|
||||||
|
ERR // 异常错误
|
||||||
|
};
|
||||||
|
|
||||||
|
class TcpHandler;
|
||||||
|
class TcpParser;
|
||||||
|
|
||||||
|
class TcpEntity : public CommEntity, public std::enable_shared_from_this<TcpEntity>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
struct Client
|
||||||
|
{
|
||||||
|
SOCKET sock;
|
||||||
|
SOCKADDR_IN sock_addr;
|
||||||
|
std::string host;
|
||||||
|
std::shared_ptr<TcpParser> parser = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
// 初始化服务端
|
||||||
|
TcpEntity(TcpHandler* handler = nullptr);
|
||||||
|
~TcpEntity();
|
||||||
|
|
||||||
|
int start() override;
|
||||||
|
void close() override;
|
||||||
|
|
||||||
|
void runThreadTcp();
|
||||||
|
|
||||||
|
void setHost(string host, int port, bool is_client);
|
||||||
|
std::string host() { return host_; }
|
||||||
|
int port() { return port_; }
|
||||||
|
std::string hostport() { return host_ + ":" + std::to_string(port_); }
|
||||||
|
|
||||||
|
void setReconnect(int ms);
|
||||||
|
|
||||||
|
bool isClient() { return isClient_; }
|
||||||
|
|
||||||
|
void setHandler(TcpHandler* handler);
|
||||||
|
|
||||||
|
bool sendData(std::string data, std::string clientId="");
|
||||||
|
|
||||||
|
bool isAlive();
|
||||||
|
bool isConnected();
|
||||||
|
|
||||||
|
|
||||||
|
std::shared_ptr<TcpParser> parser = nullptr;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void runServerLoop();
|
||||||
|
void runServerRecvLoop(Client client, std::string client_name);
|
||||||
|
|
||||||
|
void runClientLoop();
|
||||||
|
|
||||||
|
private:
|
||||||
|
// 本机的SOCKET对象
|
||||||
|
SOCKET sock_ = INVALID_SOCKET;
|
||||||
|
|
||||||
|
// socket addr信息
|
||||||
|
SOCKADDR_IN sockaddr_;
|
||||||
|
|
||||||
|
// TCP类型是否是客户端: true: 客户端, false: 服务端
|
||||||
|
bool isClient_ = true;
|
||||||
|
|
||||||
|
// 通讯地址,作为客户端时有效
|
||||||
|
std::string host_;
|
||||||
|
|
||||||
|
// 通讯端口
|
||||||
|
int port_ = 0;
|
||||||
|
|
||||||
|
// 重连间隔时间,单位秒
|
||||||
|
int tReconnect_ = 0;
|
||||||
|
|
||||||
|
// 作为服务端时连接的客户端SOCKET
|
||||||
|
std::vector<Client> vecClient_;
|
||||||
|
|
||||||
|
// 回调处理对象
|
||||||
|
TcpHandler* handler_ = nullptr;
|
||||||
|
|
||||||
|
bool isAlive_ = false;
|
||||||
|
bool isCloseRequest_ = false;
|
||||||
|
bool isConnected_ = false;
|
||||||
|
|
||||||
|
// 状态更新时间戳
|
||||||
|
int64_t ts_;
|
||||||
|
|
||||||
|
int64_t tsHeartbeat_=0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class TcpHandler
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual void onEvent(TcpEntity* entity, TcpEntity::Client* client, ETcpEvent evt, std::string msg) {};
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // !_TcpEntity_H_
|
||||||
@@ -80,26 +80,11 @@ void Menu::onMenuBtnClicked()
|
|||||||
|
|
||||||
MainWindow::MainWindow()
|
MainWindow::MainWindow()
|
||||||
{
|
{
|
||||||
webView = std::make_shared<QWebEngineView>(this);
|
if (1)
|
||||||
|
{
|
||||||
MyWebHandler* myWebHandler = new MyWebHandler();
|
this->initWebView();
|
||||||
QWebChannel* webChannel = new QWebChannel();
|
|
||||||
webChannel->registerObject("cppNative", myWebHandler);
|
|
||||||
webView->page()->setWebChannel(webChannel);
|
|
||||||
|
|
||||||
webView->setGeometry(0, 0, 1920, 1080);
|
|
||||||
// 默认设置透明, 解决加载时的白屏闪烁
|
|
||||||
webView->page()->setBackgroundColor(Qt::transparent);
|
|
||||||
|
|
||||||
webView->setContextMenuPolicy(Qt::NoContextMenu);
|
|
||||||
//webView.load(QUrl("https://www.baidu.com"));
|
|
||||||
webView->load(QUrl("file:///assets/html/main.html"));
|
|
||||||
//connect(wWebView.get(), &QWebEngineView::loadFinished, this, &MyWidget::slotLoadFinished);
|
|
||||||
|
|
||||||
//std::string htmlContent = "HelloWorld";
|
|
||||||
//webView->setHtml(htmlContent.c_str(), QUrl("file:///assets/html/"));
|
|
||||||
webView->show();
|
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
QUI::label(labBkg_, this, 0, 0, 1920, 1080, "");
|
QUI::label(labBkg_, this, 0, 0, 1920, 1080, "");
|
||||||
labBkg_.setPixmap(QPixmap("assets/ui/bkg01.png"));
|
labBkg_.setPixmap(QPixmap("assets/ui/bkg01.png"));
|
||||||
@@ -130,6 +115,29 @@ MainWindow::MainWindow()
|
|||||||
timer_.start(1000);
|
timer_.start(1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::initWebView()
|
||||||
|
{
|
||||||
|
webView_ = std::make_shared<QWebEngineView>(this);
|
||||||
|
|
||||||
|
MyWebHandler* myWebHandler = new MyWebHandler();
|
||||||
|
QWebChannel* webChannel = new QWebChannel();
|
||||||
|
webChannel->registerObject("cppNative", myWebHandler);
|
||||||
|
webView_->page()->setWebChannel(webChannel);
|
||||||
|
|
||||||
|
webView_->setGeometry(0, 0, 1920, 1080);
|
||||||
|
// 默认设置透明, 解决加载时的白屏闪烁
|
||||||
|
webView_->page()->setBackgroundColor(Qt::transparent);
|
||||||
|
|
||||||
|
webView_->setContextMenuPolicy(Qt::NoContextMenu);
|
||||||
|
//webView.load(QUrl("https://www.baidu.com"));
|
||||||
|
webView_->load(QUrl("file:///assets/html/main.html"));
|
||||||
|
//connect(wWebView.get(), &QWebEngineView::loadFinished, this, &MyWidget::slotLoadFinished);
|
||||||
|
|
||||||
|
//std::string htmlContent = "HelloWorld";
|
||||||
|
//webView->setHtml(htmlContent.c_str(), QUrl("file:///assets/html/"));
|
||||||
|
webView_->show();
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindow::initMenu()
|
void MainWindow::initMenu()
|
||||||
{
|
{
|
||||||
std::vector<std::string> vecMenuId =
|
std::vector<std::string> vecMenuId =
|
||||||
@@ -146,9 +154,9 @@ void MainWindow::initMenu()
|
|||||||
void MainWindow::resizeEvent(QResizeEvent* event)
|
void MainWindow::resizeEvent(QResizeEvent* event)
|
||||||
{
|
{
|
||||||
auto& size = event->size();
|
auto& size = event->size();
|
||||||
if (webView)
|
if (webView_)
|
||||||
{
|
{
|
||||||
webView->resize(size);
|
webView_->resize(size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,6 +30,8 @@ public:
|
|||||||
MainWindow();
|
MainWindow();
|
||||||
void initMenu();
|
void initMenu();
|
||||||
|
|
||||||
|
void initWebView();
|
||||||
|
|
||||||
void resizeEvent(QResizeEvent* event);
|
void resizeEvent(QResizeEvent* event);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
@@ -51,5 +53,5 @@ public:
|
|||||||
|
|
||||||
std::shared_ptr<Menu> menu_ = nullptr;
|
std::shared_ptr<Menu> menu_ = nullptr;
|
||||||
|
|
||||||
std::shared_ptr<QWebEngineView> webView;
|
std::shared_ptr<QWebEngineView> webView_;
|
||||||
};
|
};
|
||||||
@@ -7,6 +7,21 @@
|
|||||||
#include "common/Logger.h"
|
#include "common/Logger.h"
|
||||||
#include "Snowflake.h"
|
#include "Snowflake.h"
|
||||||
#include "app/Dao.h"
|
#include "app/Dao.h"
|
||||||
|
#include "app/Admin.h"
|
||||||
|
#include "app/Device.h"
|
||||||
|
|
||||||
|
static void VariantListRes(std::vector<DataFields>& data, QVariantList& listRes)
|
||||||
|
{
|
||||||
|
for (auto& fields: data)
|
||||||
|
{
|
||||||
|
QVariantMap row;
|
||||||
|
for (auto& field: fields.fields())
|
||||||
|
{
|
||||||
|
row[field.first.c_str()] = field.second.c_str();
|
||||||
|
}
|
||||||
|
listRes << row;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void JSsetResPaginaion(QVariantMap& result, std::vector<DataFields>& data, int page, int pageSize, int count, int code, string err)
|
static void JSsetResPaginaion(QVariantMap& result, std::vector<DataFields>& data, int page, int pageSize, int count, int code, string err)
|
||||||
{
|
{
|
||||||
@@ -47,16 +62,16 @@ void MyWebHandler::log(const QString& text)
|
|||||||
|
|
||||||
QString MyWebHandler::readFile(const QString& filename)
|
QString MyWebHandler::readFile(const QString& filename)
|
||||||
{
|
{
|
||||||
//std::string filePath = "assets/html/系统管理/index.html"; //filename.toStdString();
|
std::string fileName = filename.toStdString();
|
||||||
std::filesystem::path filePath = std::filesystem::u8path(filename.toStdString());
|
XLOGD() << "[cppNative] readFile: " << fileName;
|
||||||
XLOGD() << "[cppNative] readFile: " << filePath;
|
std::filesystem::path filePath = std::filesystem::u8path(fileName);
|
||||||
std::ifstream ifs(filePath);
|
std::ifstream ifs(filePath);
|
||||||
if (ifs.is_open())
|
if (ifs.is_open())
|
||||||
{
|
{
|
||||||
// 获取文件大小
|
// 获取文件大小
|
||||||
ifs.seekg(0, std::ios::end);
|
ifs.seekg(0, std::ios::end);
|
||||||
std::streamsize size = ifs.tellg();
|
std::streamsize size = ifs.tellg();
|
||||||
XLOGD() << "[cppNative] readFile [" << filePath << "] success, data size=" << size;
|
XLOGD() << "[cppNative] readFile [" << fileName << "] success, data size=" << size;
|
||||||
|
|
||||||
// 定位回文件开始,读取文件内容到缓冲区
|
// 定位回文件开始,读取文件内容到缓冲区
|
||||||
ifs.seekg(0, std::ios::beg);
|
ifs.seekg(0, std::ios::beg);
|
||||||
@@ -67,11 +82,23 @@ QString MyWebHandler::readFile(const QString& filename)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
XLOGD() << "[cppNative] readFile [" << filePath << "] failed.";
|
XLOGD() << "[cppNative] readFile [" << fileName << "] failed.";
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MyWebHandler::login(const QString& username, const QString& passwd)
|
||||||
|
{
|
||||||
|
XLOGI() << "login request: " << username.toStdString();
|
||||||
|
Errcode ecode = Admin::instance().longin(username.toStdString(), passwd.toStdString());
|
||||||
|
|
||||||
|
//std::this_thread::sleep_for(std::chrono::milliseconds(10000));
|
||||||
|
emit signalLongin(username, int(ecode));
|
||||||
|
}
|
||||||
|
|
||||||
|
void MyWebHandler::loginOut(const QString& username)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
QVariantMap MyWebHandler::queryUserList(int page, int pageSize)
|
QVariantMap MyWebHandler::queryUserList(int page, int pageSize)
|
||||||
{
|
{
|
||||||
@@ -102,7 +129,7 @@ int MyWebHandler::insertUser(QVariantMap params)
|
|||||||
|
|
||||||
|
|
||||||
// 设置用户角色
|
// 设置用户角色
|
||||||
std::string user_id = fields.get_str("user_id");
|
std::string user_id = fields.getStr("user_id");
|
||||||
if (params.contains("role_id")) {
|
if (params.contains("role_id")) {
|
||||||
|
|
||||||
int role_id = params["role_id"].toInt();
|
int role_id = params["role_id"].toInt();
|
||||||
@@ -161,16 +188,24 @@ int MyWebHandler::updateUser(const QString& userId, QVariantMap params)
|
|||||||
// 角色管理接口
|
// 角色管理接口
|
||||||
QVariantMap MyWebHandler::queryRoleList(int page, int pageSize)
|
QVariantMap MyWebHandler::queryRoleList(int page, int pageSize)
|
||||||
{
|
{
|
||||||
|
QVariantMap result;
|
||||||
|
|
||||||
std::vector<DataFields> res;
|
std::vector<DataFields> res;
|
||||||
auto dao = DAO::get("role");
|
auto dao = DAO::get("role");
|
||||||
bool ret = dao->exec("SELECT * FROM role;", res);
|
bool ret = dao->exec("SELECT * FROM role;", res);
|
||||||
|
|
||||||
QVariantMap result;
|
|
||||||
JSsetResPaginaion(result, res, page, pageSize, res.size(), 0, "操作成功");
|
JSsetResPaginaion(result, res, page, pageSize, res.size(), 0, "操作成功");
|
||||||
|
|
||||||
XLOGD() << "[cppNative] queryRoleList " << (ret ? "success." : "failed.");
|
XLOGD() << "[cppNative] queryRoleList " << (ret ? "success." : "failed.");
|
||||||
|
|
||||||
|
//QtConcurrent::run([this]()
|
||||||
|
// {
|
||||||
|
// XLOGD() << "[cppNative] lxy ========== queryRoleList 1111111111111111111111 ";
|
||||||
|
// QThread::msleep(2000);
|
||||||
|
// XLOGD() << "[cppNative] lxy ========== queryRoleList 2222222222222222222222 ";
|
||||||
|
// });
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
int MyWebHandler::insertRole(QVariantMap params)
|
int MyWebHandler::insertRole(QVariantMap params)
|
||||||
{
|
{
|
||||||
DataFields fields;
|
DataFields fields;
|
||||||
@@ -313,6 +348,66 @@ QVariantMap MyWebHandler::queryDeviceList(int page, int pageSize)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void JSgetReqParamSql(QString key, QVariantMap& params, std::string& sql)
|
||||||
|
{
|
||||||
|
if (params.contains(key))
|
||||||
|
{
|
||||||
|
auto& v = params[key];
|
||||||
|
std::string typeName = v.typeName();
|
||||||
|
|
||||||
|
|
||||||
|
XLOGD() << key.toStdString() << " : " << typeName;
|
||||||
|
if (!sql.empty()) sql += ",";
|
||||||
|
|
||||||
|
if ("QVariantList" == typeName)
|
||||||
|
{
|
||||||
|
std::string str = "";
|
||||||
|
for (auto& item : v.toList())
|
||||||
|
{
|
||||||
|
if (!str.empty()) str += ",";
|
||||||
|
str += ("'" + item.toString().toStdString() + "'");
|
||||||
|
}
|
||||||
|
sql += ("`" + key.toStdString() + "` IN (" + str + ")");
|
||||||
|
XLOGD() << "QVariantList";
|
||||||
|
}
|
||||||
|
else if ("QString" == typeName)
|
||||||
|
{
|
||||||
|
// 如果是数组, 需要处理数组格式: ["","",""]
|
||||||
|
sql += ("`" + key.toStdString() + "`='" + v.toString().toStdString() + "'");
|
||||||
|
XLOGD() << "QString";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
XLOGD() << "???";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariantList MyWebHandler::queryDevice(QVariantMap params)
|
||||||
|
{
|
||||||
|
XLOGD() << "MyWebHandler::queryDevice -- params.size=" << params.size();
|
||||||
|
|
||||||
|
QVariantList result;
|
||||||
|
|
||||||
|
std::string sqlc = "";
|
||||||
|
JSgetReqParamSql("type", params, sqlc);
|
||||||
|
|
||||||
|
if (sqlc.empty()) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string sql = "SELECT * FROM device WHERE " + sqlc + ";";
|
||||||
|
auto dao = DAO::get("device");
|
||||||
|
std::vector<DataFields> res;
|
||||||
|
bool ret = dao->exec(sql, res);
|
||||||
|
XLOGD() << "sql=" << sql;
|
||||||
|
XLOGD() << "queryDevice: size=" << res.size();
|
||||||
|
|
||||||
|
VariantListRes(res, result);
|
||||||
|
|
||||||
|
XLOGD() << "queryDevice: result size=" << result.size();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
int MyWebHandler::insertDevice(QVariantMap params)
|
int MyWebHandler::insertDevice(QVariantMap params)
|
||||||
{
|
{
|
||||||
DataFields fields;
|
DataFields fields;
|
||||||
@@ -600,5 +695,31 @@ QVariantMap MyWebHandler::querySecRecordList(int page, int pageSize)
|
|||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
int MyWebHandler::insertSecRecord(QVariantMap params) {};
|
int MyWebHandler::insertSecRecord(QVariantMap params) { return 0; };
|
||||||
int MyWebHandler::updateSecRecord(const QString& policyId, QVariantMap params) {};
|
int MyWebHandler::updateSecRecord(const QString& policyId, QVariantMap params) { return 0; };
|
||||||
|
|
||||||
|
|
||||||
|
QVariantList MyWebHandler::getDeviceInfo(const QVariantList& types)
|
||||||
|
{
|
||||||
|
std::vector<std::shared_ptr<DeviceEntity>> vecDevice;
|
||||||
|
for (auto item: types)
|
||||||
|
{
|
||||||
|
int deviceType = item.toInt();
|
||||||
|
auto vecRes = Device::getDeviceByType(deviceType);
|
||||||
|
vecDevice.insert(vecDevice.end(), vecRes.begin(), vecRes.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariantList result;
|
||||||
|
for (auto& device: vecDevice)
|
||||||
|
{
|
||||||
|
QVariantMap row;
|
||||||
|
row["device_id"] = device->deviceId;
|
||||||
|
row["name"] = device->name.c_str();
|
||||||
|
row["type"] = device->type;
|
||||||
|
row["status"] = device->status;
|
||||||
|
row["online"] = device->online;
|
||||||
|
row["err"] = device->err;
|
||||||
|
result << row;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@
|
|||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
#include <QVariantMap>
|
#include <QVariantMap>
|
||||||
#include <QVariantList>
|
#include <QVariantList>
|
||||||
|
#include <QtConcurrent/QtConcurrent>
|
||||||
|
|
||||||
class MyWebHandler : public QObject
|
class MyWebHandler : public QObject
|
||||||
{
|
{
|
||||||
@@ -22,7 +23,11 @@ signals:
|
|||||||
//在C++中定义的信号,可以在JS端监听此信号接收消息
|
//在C++中定义的信号,可以在JS端监听此信号接收消息
|
||||||
void signalNativeTextChanged(const QString& text);
|
void signalNativeTextChanged(const QString& text);
|
||||||
|
|
||||||
void singalReadFileFinished(const QString& text);
|
void signalReadFileFinished(const QString& text);
|
||||||
|
|
||||||
|
void signalLongin(const QString& username, const int& ecode);
|
||||||
|
|
||||||
|
void signalLonout();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
//C++ 端的公共槽函数,可以在JS端调用。
|
//C++ 端的公共槽函数,可以在JS端调用。
|
||||||
@@ -32,6 +37,13 @@ public slots:
|
|||||||
|
|
||||||
QString readFile(const QString& filename);
|
QString readFile(const QString& filename);
|
||||||
|
|
||||||
|
|
||||||
|
// ================================================================================================================
|
||||||
|
// 登录,返回用户信息
|
||||||
|
void login(const QString& username, const QString& password);
|
||||||
|
// 登出
|
||||||
|
void loginOut(const QString& username);
|
||||||
|
|
||||||
// ================================================================================================================
|
// ================================================================================================================
|
||||||
// 用户管理接口
|
// 用户管理接口
|
||||||
QVariantMap queryUserList(int page, int pageSize);
|
QVariantMap queryUserList(int page, int pageSize);
|
||||||
@@ -64,6 +76,8 @@ public slots:
|
|||||||
// ================================================================================================================
|
// ================================================================================================================
|
||||||
// 设备管理接口
|
// 设备管理接口
|
||||||
QVariantMap queryDeviceList(int page, int pageSize);
|
QVariantMap queryDeviceList(int page, int pageSize);
|
||||||
|
|
||||||
|
QVariantList queryDevice(QVariantMap params);
|
||||||
int insertDevice(QVariantMap params);
|
int insertDevice(QVariantMap params);
|
||||||
int deleteDevice(const QString& deviceId);
|
int deleteDevice(const QString& deviceId);
|
||||||
int updateDevice(const QString& deviceId, QVariantMap params);
|
int updateDevice(const QString& deviceId, QVariantMap params);
|
||||||
@@ -101,6 +115,9 @@ public slots:
|
|||||||
int insertSecRecord(QVariantMap params);
|
int insertSecRecord(QVariantMap params);
|
||||||
int updateSecRecord(const QString& policyId, QVariantMap params);
|
int updateSecRecord(const QString& policyId, QVariantMap params);
|
||||||
|
|
||||||
|
// ================================================================================================================
|
||||||
|
QVariantList getDeviceInfo(const QVariantList& types);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
QString nativeText_;
|
QString nativeText_;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user