kunlang_video/src/mqtt_client.cpp

173 lines
4.7 KiB
C++
Raw Normal View History

2025-09-08 10:59:08 +08:00
#include "mqtt_client.hpp"
2025-11-14 14:56:02 +08:00
2025-09-08 10:59:08 +08:00
#include <chrono>
2025-09-10 11:19:40 +08:00
#include <future>
2025-11-14 14:56:02 +08:00
#include <iostream>
#include <thread>
2025-09-08 10:59:08 +08:00
2025-09-10 11:18:29 +08:00
extern std::atomic<bool> g_running;
2025-11-14 14:56:02 +08:00
MQTTClient::MQTTClient(const MQTTConfig& config) : config_(config), connected_(false) { initializeClient(); }
2025-09-08 10:59:08 +08:00
MQTTClient::~MQTTClient()
{
2025-11-14 14:56:02 +08:00
force_disconnect(); // 析构时直接释放资源,不阻塞
2025-09-08 10:59:08 +08:00
}
void MQTTClient::initializeClient()
{
std::string address = "tcp://" + config_.server_ip + ":" + std::to_string(config_.server_port);
client_ = std::make_shared<mqtt::async_client>(address, config_.client_id);
client_->set_callback(*this);
}
void MQTTClient::connect()
{
std::lock_guard<std::mutex> lock(mutex_);
2025-11-14 14:56:02 +08:00
if (connected_ || !g_running) // 添加g_running检查
2025-09-08 10:59:08 +08:00
return;
try
{
auto connOpts = mqtt::connect_options_builder()
.clean_session(config_.clean_session)
.automatic_reconnect(true)
.keep_alive_interval(std::chrono::seconds(config_.keep_alive))
.user_name(config_.username)
.password(config_.password)
.finalize();
2025-09-10 13:33:29 +08:00
// 异步连接,不阻塞
2025-11-14 14:56:02 +08:00
auto tok = client_->connect(connOpts); // 返回 token
2025-09-08 10:59:08 +08:00
}
2025-11-14 14:56:02 +08:00
catch (const mqtt::exception& e)
2025-09-08 10:59:08 +08:00
{
2025-09-10 10:34:36 +08:00
connected_ = false;
2025-09-08 16:40:04 +08:00
LOG_ERROR("[MQTT] Connect failed: " + std::string(e.what()));
2025-09-08 10:59:08 +08:00
}
}
void MQTTClient::disconnect()
{
std::lock_guard<std::mutex> lock(mutex_);
2025-11-14 14:56:02 +08:00
if (!connected_) return;
2025-09-08 10:59:08 +08:00
try
{
2025-11-14 14:56:02 +08:00
auto disc_tok = client_->disconnect(); // 异步返回 token
2025-09-10 11:24:52 +08:00
2025-09-10 13:33:29 +08:00
// 等待短时间,检查 g_running
for (int i = 0; i < 10 && g_running; ++i)
2025-09-10 11:24:52 +08:00
{
2025-11-14 14:56:02 +08:00
if (disc_tok->is_complete()) break;
2025-09-10 11:24:52 +08:00
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
2025-09-10 11:18:29 +08:00
2025-09-10 13:33:29 +08:00
if (!disc_tok->is_complete())
2025-09-10 11:18:29 +08:00
{
LOG_WARN("[MQTT] Disconnect timed out, forcing disconnection");
2025-09-10 13:33:29 +08:00
client_->stop_consuming();
client_.reset();
2025-09-10 11:18:29 +08:00
}
2025-09-08 10:59:08 +08:00
}
2025-11-14 14:56:02 +08:00
catch (const mqtt::exception& e)
2025-09-08 10:59:08 +08:00
{
2025-09-08 16:40:04 +08:00
LOG_ERROR("[MQTT] Disconnect failed: " + std::string(e.what()));
2025-09-08 10:59:08 +08:00
}
2025-09-10 10:34:36 +08:00
connected_ = false;
2025-11-14 14:56:02 +08:00
if (on_disconnect_) on_disconnect_();
2025-09-08 10:59:08 +08:00
}
2025-09-10 11:18:29 +08:00
void MQTTClient::force_disconnect()
{
std::lock_guard<std::mutex> lock(mutex_);
2025-11-14 14:56:02 +08:00
if (!connected_) return;
2025-09-10 11:18:29 +08:00
try
{
// 直接停止客户端,不等待正常断开
client_->stop_consuming();
client_.reset();
}
2025-11-14 14:56:02 +08:00
catch (const mqtt::exception& e)
2025-09-10 11:18:29 +08:00
{
LOG_ERROR("[MQTT] Force disconnect failed: " + std::string(e.what()));
}
connected_ = false;
2025-11-14 14:56:02 +08:00
if (on_disconnect_) on_disconnect_();
2025-09-10 11:18:29 +08:00
}
2025-11-14 14:56:02 +08:00
void MQTTClient::publish(const std::string& topic, const std::string& payload, int qos)
2025-09-08 10:59:08 +08:00
{
2025-11-14 14:56:02 +08:00
if (qos == -1) qos = config_.qos;
2025-09-08 10:59:08 +08:00
try
{
2025-11-14 14:56:02 +08:00
client_->publish(topic, payload.data(), payload.size(), qos, false); // 异步,不阻塞
2025-09-09 17:19:59 +08:00
// 如果 topic 不包含 "heartbeat",才打印日志
2025-11-14 14:56:02 +08:00
if (topic.find("status") == std::string::npos)
2025-09-09 17:19:59 +08:00
{
LOG_INFO("[MQTT] Published message to topic: " + topic);
}
2025-09-08 10:59:08 +08:00
}
2025-11-14 14:56:02 +08:00
catch (const mqtt::exception& e)
2025-09-08 10:59:08 +08:00
{
2025-09-08 16:40:04 +08:00
LOG_ERROR("[MQTT] Publish failed: " + std::string(e.what()));
2025-09-10 10:34:36 +08:00
connected_ = false;
2025-11-14 14:56:02 +08:00
if (on_disconnect_) on_disconnect_();
2025-09-08 10:59:08 +08:00
}
}
2025-11-14 14:56:02 +08:00
void MQTTClient::subscribe(const std::string& topic, int qos)
2025-09-08 10:59:08 +08:00
{
2025-11-14 14:56:02 +08:00
if (qos == -1) qos = config_.qos;
2025-09-08 10:59:08 +08:00
try
{
2025-11-14 14:56:02 +08:00
client_->subscribe(topic, qos); // 异步,不阻塞
2025-09-09 10:25:16 +08:00
LOG_INFO("[MQTT] Subscribed to topic: " + topic);
2025-09-08 10:59:08 +08:00
}
2025-11-14 14:56:02 +08:00
catch (const mqtt::exception& e)
2025-09-08 10:59:08 +08:00
{
2025-09-09 10:25:16 +08:00
LOG_ERROR("[MQTT] Subscribe failed: " + std::string(e.what()));
2025-09-10 10:34:36 +08:00
connected_ = false;
2025-11-14 14:56:02 +08:00
if (on_disconnect_) on_disconnect_();
2025-09-08 10:59:08 +08:00
}
}
2025-11-14 14:56:02 +08:00
void MQTTClient::switchServer(const MQTTConfig& newConfig)
2025-09-08 10:59:08 +08:00
{
std::lock_guard<std::mutex> lock(mutex_);
2025-09-10 10:34:36 +08:00
disconnect();
2025-09-08 10:59:08 +08:00
config_ = newConfig;
initializeClient();
connect();
}
2025-11-14 14:56:02 +08:00
bool MQTTClient::isConnected() const { return connected_; }
2025-09-08 10:59:08 +08:00
2025-09-10 10:34:36 +08:00
void MQTTClient::setConnectCallback(ConnectCallback cb) { on_connect_ = cb; }
void MQTTClient::setDisconnectCallback(DisconnectCallback cb) { on_disconnect_ = cb; }
void MQTTClient::setMessageCallback(MessageCallback cb) { on_message_ = cb; }
2025-11-14 14:56:02 +08:00
void MQTTClient::connection_lost(const std::string& cause)
2025-09-08 10:59:08 +08:00
{
connected_ = false;
2025-09-10 10:11:18 +08:00
LOG_WARN("[MQTT] Connection lost: " + cause);
2025-11-14 14:56:02 +08:00
if (on_disconnect_) on_disconnect_();
2025-09-10 10:11:18 +08:00
}
2025-11-14 14:56:02 +08:00
void MQTTClient::connected(const std::string& cause)
2025-09-10 10:11:18 +08:00
{
connected_ = true;
LOG_INFO("[MQTT] Reconnected: " + cause);
2025-11-14 14:56:02 +08:00
if (on_connect_) on_connect_();
2025-09-08 10:59:08 +08:00
}
void MQTTClient::message_arrived(mqtt::const_message_ptr msg)
{
2025-11-14 14:56:02 +08:00
if (on_message_) on_message_(msg->get_topic(), msg->get_payload_str());
2025-09-08 10:59:08 +08:00
}