Files
RCiRoot e3f7733316 V20260829-2.6.1
完成框架目录和模块重构;新增核心、单例、工具、加密及框架 SDK;统一任务、相机和 RPC 接口,并增加离线检测、相机标定、备份恢复、版本管理、崩溃守护和心跳监控功能。
2026-09-20 16:01:09 +08:00

460 lines
13 KiB
C++

#include "rpc_finsTcp.h"
#include "../RpcExeProcessThread.h"
#include <QDebug>
#include <QElapsedTimer>
#include <QMutexLocker>
rpcModuleBase* create()
{
qDebug() << "rpc_finsTcp create success!";
return new rpc_finsTcp;
}
void destory(rpcModuleBase* ptr)
{
delete ptr;
qDebug() << "rpc_finsTcp destory success!";
}
rpc_finsTcp::rpc_finsTcp() = default;
QByteArray rpc_finsTcp::makeExecuteRequest(const QByteArray& command, quint32& id)
{
id = idCounter.fetch_add(1);
return RpcFrameCodec::build(
id,
RpcFrameCodec::CmdExecute,
RpcFrameCodec::requestPayload("finstcp_instance_0", QString::fromUtf8(command)));
}
QByteArray rpc_finsTcp::executeReadCommand(QByteArray& input)
{
RpcClient* client = nullptr;
{
QMutexLocker locker(&mutex);
client = readClients.value(input);
if (!client) {
client = new RpcClient("127.0.0.1", 9000);
if (client->_connectionStatus != Connected) {
delete client;
return QByteArray();
}
if (!client->initialize("finstcp_instance_0", m_IP, m_port)) {
qWarning() << "[rpc_finsTcp] read client initialization failed"
<< m_IP << m_port;
delete client;
return QByteArray();
}
readClients.insert(input, client);
}
}
return client->execute("finstcp_instance_0", input);
}
bool rpc_finsTcp::executeWriteCommand(QByteArray& input)
{
if (input == "null") {
return true;
}
if (input.startsWith("init_")) {
return parseInitCommand(input);
}
const QList<QByteArray> parts = input.split('_');
if (parts.size() < 4 || parts.at(0) == "read") {
qWarning() << "[rpc_finsTcp] asynchronous write rejected: invalid command" << input;
return false;
}
quint32 id = 0;
const QByteArray request = makeExecuteRequest(input, id);
return enqueueWrite(request, id, input);
}
rpc_finsTcp::~rpc_finsTcp()
{
if (writeClient) {
writeClient->stopWorker();
delete writeClient;
writeClient = nullptr;
}
qDeleteAll(readClients);
readClients.clear();
stopRpcServer();
qDebug() << "~rpc_finsTcp success!";
}
bool rpc_finsTcp::readData(std::vector<cv::Mat>& vec_mat, QByteArray& data)
{
Q_UNUSED(vec_mat);
RpcClient* client = nullptr;
{
QMutexLocker locker(&mutex);
client = readClients.value(data);
if (!client) {
client = new RpcClient("127.0.0.1", 9000);
if (client->_connectionStatus != Connected) {
delete client;
return false;
}
client->initialize("finstcp_instance_0", m_IP, m_port);
readClients.insert(data, client);
}
}
const QByteArray response = client->execute("finstcp_instance_0", data);
if (response.isEmpty()) {
return false;
}
data = response;
return true;
}
bool rpc_finsTcp::writeData(std::vector<cv::Mat>& vec_mat, QByteArray& data)
{
Q_UNUSED(vec_mat);
const QList<QByteArray> parts = data.split('_');
if (parts.size() < 3) {
qWarning() << "[rpc_finsTcp] asynchronous write rejected: invalid command" << data;
return false;
}
if (parts.at(0) == "init") {
m_IP = parts.at(1);
m_port = parts.at(2).toInt();
} else if (data.contains("read")) {
return true;
} else {
if (data.contains("null")) {
return true;
}
if (!data.contains("Heart")) {
qDebug() << data;
}
quint32 id = 0;
const QByteArray request = makeExecuteRequest(data, id);
if (!enqueueWrite(request, id, data)) {
return false;
}
}
return true;
}
bool rpc_finsTcp::initParas(QByteArray& data)
{
if (!parseInitCommand(data)) {
return false;
}
if (!startRpcServer()) {
return false;
}
writeClient = new RpcClientWorker();
if (!writeClient->startAndWait()) {
qWarning() << "[rpc_finsTcp] asynchronous writer thread failed to connect";
delete writeClient;
writeClient = nullptr;
stopRpcServer();
return false;
}
if (!sendInitCommand()) {
writeClient->stopWorker();
delete writeClient;
writeClient = nullptr;
stopRpcServer();
return false;
}
return true;
}
bool rpc_finsTcp::startRpcServer()
{
if (!processThread) {
processThread = new RpcExeProcessThread();
}
if (processThread->startExe("post_rpc_server_1_2_0.exe")) {
return true;
}
delete processThread;
processThread = nullptr;
return false;
}
void rpc_finsTcp::stopRpcServer()
{
if (!processThread) {
return;
}
processThread->stopExe();
delete processThread;
processThread = nullptr;
}
bool rpc_finsTcp::parseInitCommand(const QByteArray& input)
{
const QList<QByteArray> parts = input.split('_');
if (parts.size() < 3 || parts.at(0) != "init") {
qCritical() << input << "expected init_ip_port";
return false;
}
bool portOk = false;
const int port = parts.at(2).toInt(&portOk);
if (parts.at(1).isEmpty() || !portOk || port <= 0 || port > 65535) {
qCritical() << input << "invalid init parameters";
return false;
}
m_IP = QString::fromUtf8(parts.at(1));
m_port = port;
return true;
}
bool rpc_finsTcp::sendInitCommand()
{
const quint32 id = idCounter.fetch_add(1);
const QByteArray request = RpcFrameCodec::build(
id,
RpcFrameCodec::CmdInit,
RpcFrameCodec::requestPayload(
"finstcp_instance_0", m_IP + "\n" + QString::number(m_port)));
return enqueueWrite(request, id,
("init_" + m_IP + "_" + QString::number(m_port)).toUtf8());
}
bool rpc_finsTcp::run()
{
return true;
}
RpcClient::RpcClient(const QString& host, quint16 port)
: host_(host), port_(port)
{
socket_.connectToHost(host_, port_);
if (!socket_.waitForConnected(3000)) {
qWarning() << "[RpcClient] Initial connection failed:" << socket_.errorString();
_connectionStatus = Disconnected;
} else {
qDebug() << "[RpcClient] Connected to" << host_ << ":" << port_;
_connectionStatus = Connected;
}
}
bool RpcClient::reconnect()
{
if (socket_.state() == QAbstractSocket::ConnectedState) {
return true;
}
socket_.abort();
codec_.clear();
socket_.connectToHost(host_, port_);
return socket_.waitForConnected(3000);
}
bool RpcClient::initialize(const QString& module, const QString& ip, int port)
{
QMutexLocker locker(&mutex_);
if (!reconnect()) {
return false;
}
const quint32 id = idCounter_++;
const QByteArray payload = RpcFrameCodec::requestPayload(
module, ip + "\n" + QString::number(port));
const QByteArray frame = RpcFrameCodec::build(id, RpcFrameCodec::CmdInit, payload);
RpcFrameCodec::Frame response;
return sendFrameAndAwait(frame, id, response) &&
response.cmd == RpcFrameCodec::RespOk;
}
bool RpcClient::isConnected(const QString& module)
{
QMutexLocker locker(&mutex_);
if (!reconnect()) {
return false;
}
const quint32 id = idCounter_++;
const QByteArray frame = RpcFrameCodec::build(
id, RpcFrameCodec::CmdIsConnected,
RpcFrameCodec::requestPayload(module));
RpcFrameCodec::Frame response;
if (!sendFrameAndAwait(frame, id, response) || response.cmd != RpcFrameCodec::RespOk) {
return false;
}
return !response.payload.isEmpty() && response.payload.at(0) != '\0';
}
QByteArray RpcClient::execute(const QString& module, const QByteArray& command)
{
QMutexLocker locker(&mutex_);
if (!reconnect()) {
return QByteArray();
}
const quint32 id = idCounter_++;
const QByteArray frame = RpcFrameCodec::build(
id, RpcFrameCodec::CmdExecute,
RpcFrameCodec::requestPayload(module, QString::fromUtf8(command)));
RpcFrameCodec::Frame response;
if (!sendFrameAndAwait(frame, id, response) || response.cmd != RpcFrameCodec::RespOk) {
qWarning() << "[RpcClient] execute request failed";
return QByteArray();
}
return response.payload;
}
bool RpcClient::sendFrame(const QByteArray& request, quint32 id)
{
QMutexLocker locker(&mutex_);
if (!reconnect()) {
qWarning() << "[RpcClient] asynchronous write failed: RPC server is not connected";
return false;
}
RpcFrameCodec::Frame response;
if (!sendFrameAndAwait(request, id, response)) {
qWarning() << "[RpcClient] asynchronous write failed: response timeout or socket error"
<< "requestId=" << id;
return false;
}
if (response.cmd != RpcFrameCodec::RespOk) {
qWarning() << "[RpcClient] asynchronous write rejected by server"
<< "requestId=" << id
<< "response=" << response.payload;
return false;
}
return true;
}
bool RpcClient::waitAndReadResponse(quint32 expectId,
RpcFrameCodec::Frame& response,
int timeoutMs)
{
QElapsedTimer timer;
timer.start();
while (timer.elapsed() < timeoutMs) {
if (socket_.bytesAvailable() == 0) {
const int remain = timeoutMs - static_cast<int>(timer.elapsed());
if (!socket_.waitForReadyRead(qMin(remain, 1000))) {
continue;
}
}
const QByteArray chunk = socket_.readAll();
if (!chunk.isEmpty()) {
codec_.append(chunk);
}
const QList<RpcFrameCodec::Frame> frames = codec_.takeFrames();
for (const RpcFrameCodec::Frame& frame : frames) {
if (frame.id == expectId) {
response = frame;
return true;
}
}
}
return false;
}
bool RpcClient::sendFrameAndAwait(const QByteArray& frame, quint32 id,
RpcFrameCodec::Frame& response, int timeoutMs)
{
if (socket_.write(frame) == -1 || !socket_.waitForBytesWritten(1000)) {
qWarning() << "[RpcClient] frame write failed";
return false;
}
return waitAndReadResponse(id, response, timeoutMs);
}
RpcClientWorker::~RpcClientWorker()
{
stopWorker();
}
bool RpcClientWorker::startAndWait(int timeoutMs)
{
if (!isRunning()) {
start();
}
QMutexLocker locker(&stateMutex_);
while (!initialized_) {
if (!initializedCondition_.wait(&stateMutex_, timeoutMs)) {
qWarning() << "writer init timeout";
return false;
}
}
return connection_ == Connected;
}
bool RpcClientWorker::enqueue(const QByteArray& request, quint32 id,
const QByteArray& command)
{
QMutexLocker locker(&queueMutex_);
if (stopping_ || !isReady()) {
qWarning() << "write rejected: writer not ready"
<< "requestId=" << id;
return false;
}
queue_.enqueue({request, command, id});
queueCondition_.wakeOne();
return true;
}
bool RpcClientWorker::isReady() const
{
QMutexLocker locker(&stateMutex_);
return initialized_ && connection_ == Connected;
}
void RpcClientWorker::stopWorker()
{
{
QMutexLocker locker(&queueMutex_);
stopping_ = true;
queue_.clear();
queueCondition_.wakeAll();
}
if (isRunning() && QThread::currentThread() != this) {
if (!wait(10000)) {
qWarning() << "writer stop timeout";
}
}
}
void RpcClientWorker::run()
{
RpcClient client;
{
QMutexLocker locker(&stateMutex_);
connection_ = client._connectionStatus;
initialized_ = true;
initializedCondition_.wakeAll();
}
for (;;) {
PendingWrite pending;
{
QMutexLocker locker(&queueMutex_);
while (queue_.isEmpty() && !stopping_) {
queueCondition_.wait(&queueMutex_);
}
if (stopping_) {
break;
}
pending = queue_.dequeue();
}
if (!client.sendFrame(pending.request, pending.id)) {
qWarning() << "write failed" << pending.command;
}
else if (!pending.command.contains("Heart")) {
qDebug() << pending.command;
}
}
}
bool rpc_finsTcp::enqueueWrite(const QByteArray& request, quint32 id,
const QByteArray& command)
{
if (!writeClient) {
qWarning() << "[rpc_finsTcp] asynchronous write rejected: writer thread is not initialized"
<< "requestId=" << id;
return false;
}
return writeClient->enqueue(request, id, command);
}