| 166 | } |
| 167 | |
| 168 | void MqttClient::setSubscriptions(const QStringList& topics) |
| 169 | { |
| 170 | #ifdef HAVE_MQTT |
| 171 | QStringList desired; |
| 172 | for (const QString& raw : topics) { |
| 173 | const QString topic = raw.trimmed(); |
| 174 | if (!topic.isEmpty() && !desired.contains(topic)) { |
| 175 | desired.append(topic); |
| 176 | } |
| 177 | } |
| 178 | |
| 179 | const QStringList previous = m_pendingTopics; |
| 180 | m_pendingTopics = desired; |
| 181 | |
| 182 | if (!m_connected || !m_mosq) { |
| 183 | return; |
| 184 | } |
| 185 | |
| 186 | for (const QString& topic : previous) { |
| 187 | if (!desired.contains(topic)) { |
| 188 | mosquitto_unsubscribe(m_mosq, nullptr, topic.toUtf8().constData()); |
| 189 | qCDebug(lcMqtt) << "MqttClient: unsubscribed from" << topic; |
| 190 | } |
| 191 | } |
| 192 | |
| 193 | // Subscribe only to topics in `desired` that weren't already in |
| 194 | // `previous`. Mosquitto's subscribe is idempotent broker-side, so |
| 195 | // re-subscribing to a stable topic is correct-but-wasteful — costs |
| 196 | // a small CONNECT packet and a SUBACK round-trip for every retained |
| 197 | // topic on every settings change. Pin the diff here so a 20-topic |
| 198 | // user-list with one added topic emits one SUBSCRIBE instead of 20. |
| 199 | for (const QString& topic : desired) { |
| 200 | if (previous.contains(topic)) |
| 201 | continue; |
| 202 | int rc = mosquitto_subscribe(m_mosq, nullptr, topic.toUtf8().constData(), 0); |
| 203 | if (rc != MOSQ_ERR_SUCCESS) { |
| 204 | qCWarning(lcMqtt) << "MqttClient: subscribe failed for" << topic |
| 205 | << mosquitto_strerror(rc); |
| 206 | } else { |
| 207 | qCDebug(lcMqtt) << "MqttClient: subscribed to" << topic; |
| 208 | } |
| 209 | } |
| 210 | #else |
| 211 | Q_UNUSED(topics); |
| 212 | #endif |
| 213 | } |
| 214 | |
| 215 | void MqttClient::subscribe(const QString& topic) |
| 216 | { |
no test coverage detected