* @brief Applies endpoint + credential fields to the publisher; returns error on failure. */
| 261 | * @brief Applies endpoint + credential fields to the publisher; returns error on failure. |
| 262 | */ |
| 263 | [[nodiscard]] static std::optional<QString> applyPublisherEndpoint(MQTT::Publisher& p, |
| 264 | const QJsonObject& params) |
| 265 | { |
| 266 | if (params.contains(QStringLiteral("hostname"))) { |
| 267 | const auto host = params.value(QStringLiteral("hostname")).toString(); |
| 268 | if (host.trimmed().isEmpty()) |
| 269 | return QStringLiteral("hostname must not be empty"); |
| 270 | |
| 271 | p.setHostname(host); |
| 272 | } |
| 273 | |
| 274 | if (params.contains(QStringLiteral("port"))) { |
| 275 | const int port = params.value(QStringLiteral("port")).toInt(-1); |
| 276 | if (!portIsValid(port)) |
| 277 | return QStringLiteral("port must be in [1, 65535] (got %1)").arg(port); |
| 278 | |
| 279 | p.setPort(static_cast<quint16>(port)); |
| 280 | } |
| 281 | |
| 282 | if (params.contains(QStringLiteral("clientId"))) |
| 283 | p.setClientId(params.value(QStringLiteral("clientId")).toString()); |
| 284 | |
| 285 | if (params.contains(QStringLiteral("customClientId"))) |
| 286 | p.setCustomClientId(params.value(QStringLiteral("customClientId")).toBool()); |
| 287 | |
| 288 | const bool hasUser = params.contains(QStringLiteral("username")); |
| 289 | const bool hasPass = params.contains(QStringLiteral("password")); |
| 290 | if (hasPass && !hasUser) |
| 291 | return QStringLiteral("Setting 'password' requires 'username' in the same call"); |
| 292 | |
| 293 | if (hasUser) |
| 294 | p.setUsername(params.value(QStringLiteral("username")).toString()); |
| 295 | |
| 296 | if (hasPass) |
| 297 | p.setPassword(params.value(QStringLiteral("password")).toString()); |
| 298 | |
| 299 | return std::nullopt; |
| 300 | } |
| 301 | |
| 302 | /** |
| 303 | * @brief Applies topic + mode + frequency fields to the publisher; returns error on failure. |
no test coverage detected