221 const std::string& instanceName,
222 const std::function<
void(
typename HttpClient::Config*)>& configurator) {
223 using SocketAddress =
typename HttpClient::SocketAddress;
225 HttpClient httpClient(
227 [](
const std::shared_ptr<web::http::client::MasterRequest>& req) {
228 const std::string connectionName = req->getSocketContext()->getSocketConnection()->getConnectionName();
230 req->set(
"Sec-WebSocket-Protocol",
"mqtt");
235 [connectionName](
bool success) {
236 VLOG(1) << connectionName <<
": HTTP Upgrade (http -> websocket||"
237 <<
"mqtt" <<
") start " << (success ?
"success" :
"failed");
239 []([[maybe_unused]]
const std::shared_ptr<web::http::client::Request>& req,
240 [[maybe_unused]]
const std::shared_ptr<web::http::client::Response>& res,
241 [[maybe_unused]]
bool success) {
243 [connectionName]([[maybe_unused]]
const std::shared_ptr<web::http::client::Request>& req,
const std::string& message) {
244 VLOG(1) << connectionName <<
": Request parse error: " << message;
247 []([[maybe_unused]]
const std::shared_ptr<web::http::client::Request>& req) {
248 VLOG(1) <<
"Session ended";
251 configurator(httpClient.getConfig());
253 httpClient.getConfig()->Instance::configurable(
false);
254 httpClient.getConfig()->Remote::configurable(
false);
255 httpClient.getConfig()->setRetry()->setRetryBase(1);
256 httpClient.getConfig()->setReconnect();
258 handleFlowControllers(httpClient.getFlowController());
260 httpClient.connect([instanceName](
const SocketAddress& socketAddress,
const core::socket::State& state) {
261 reportState(instanceName, socketAddress, state);
270 for (
const auto& [bridgeName, bridge] : mqtt::bridge::lib::BridgeStore::instance().getBridgeMap()) {
271 VLOG(0) <<
"Starting bridge: " << bridgeName;
273 if (!bridge.getDisabled()) {
274 mqtt::bridge::lib::SSEDistributor::instance().bridgeStarting(bridgeName);
276 for (
const auto& [fullInstanceName, broker] : bridge.getBrokerMap()) {
277 if (!broker.getDisabled()) {
278 mqtt::bridge::lib::SSEDistributor::instance().brokerConnecting(bridgeName, fullInstanceName);
280 VLOG(1) <<
" Creating broker instance: " << fullInstanceName;
281 VLOG(1) <<
" Broker prefix: " << broker.getPrefix();
282 VLOG(1) <<
" Broker client id: " << broker.getClientId();
283 VLOG(1) <<
" Broker disabled: " << broker.getDisabled();
284 VLOG(1) <<
" Broker address: " << broker.getAddress();
285 VLOG(1) <<
" Broker prefix: " << broker.getPrefix();
286 VLOG(1) <<
" Broker username: " << broker.getUsername();
287 VLOG(1) <<
" Broker password: " << broker.getPassword();
288 VLOG(1) <<
" Broker client-id: " << broker.getClientId();
289 VLOG(1) <<
" Broker clean session: " << broker.getCleanSession();
290 VLOG(1) <<
" Broker will-topic: " << broker.getWillTopic();
291 VLOG(1) <<
" Broker will-message: " << broker.getWillMessage();
292 VLOG(1) <<
" Broker will-qos: " <<
static_cast<
int>(broker.getWillQoS());
293 VLOG(1) <<
" Broker will-retain: " << broker.getWillRetain();
294 VLOG(1) <<
" Broker loop prevention: " << broker.getLoopPrevention();
295 VLOG(1) <<
" Bridge disabled: " << bridge.getDisabled();
296 VLOG(1) <<
" Bridge prefix: " << bridge.getPrefix();
297 VLOG(1) <<
" Bridge Transport: " << broker.getTransport();
298 VLOG(1) <<
" Bridge Protocol: " << broker.getProtocol();
299 VLOG(1) <<
" Bridge Encryption: " << broker.getEncryption();
301 VLOG(1) <<
" Topics:";
302 const std::list<iot::mqtt::Topic>& topics = broker.getTopics();
303 for (
const iot::mqtt::Topic& topic : topics) {
304 VLOG(1) <<
" " << topic.getName() <<
":" <<
static_cast<uint16_t>(topic.getQoS());
307 const std::string& transport = broker.getTransport();
308 const std::string& protocol = broker.getProtocol();
309 const std::string& encryption = broker.getEncryption();
311 if (transport ==
"stream") {
312 if (protocol ==
"in") {
313 if (encryption ==
"legacy") {
314#if defined(CONFIG_MQTTSUITE_BRIDGE_TCP_IPV4)
315 startClient<net::in::stream::legacy::SocketClient>(
317 [&broker](net::in::stream::legacy::config::ConfigSocketClient* config) {
318 config->setDisableNagleAlgorithm();
320 config->Remote::setHost(broker.getAddress()[
"host"]);
321 config->Remote::setPort(broker.getAddress()[
"port"]);
323 config->setDisabled(broker.getDisabled() || broker.getBridge().getDisabled());
326 VLOG(1) <<
" Transport '" << transport <<
"', protocol '" << protocol <<
"', encryption '" << encryption
327 <<
"' not supported.";
329 }
else if (encryption ==
"tls") {
330#if defined(CONFIG_MQTTSUITE_BRIDGE_TLS_IPV4)
331 startClient<net::in::stream::tls::SocketClient>(
333 [&broker](net::in::stream::tls::config::ConfigSocketClient* config) {
334 config->setDisableNagleAlgorithm();
336 config->Remote::setHost(broker.getAddress()[
"host"]);
337 config->Remote::setPort(broker.getAddress()[
"port"]);
339 config->setDisabled(broker.getDisabled() || broker.getBridge().getDisabled());
342 VLOG(1) <<
" Transport '" << transport <<
"', protocol '" << protocol <<
"', encryption '" << encryption
343 <<
"' not supported.";
346 }
else if (protocol ==
"in6") {
347 if (encryption ==
"legacy") {
348#if defined(CONFIG_MQTTSUITE_BRIDGE_TCP_IPV6)
349 startClient<net::in6::stream::legacy::SocketClient>(
351 [&broker](net::in6::stream::legacy::config::ConfigSocketClient* config) {
352 config->setDisableNagleAlgorithm();
354 config->Remote::setHost(broker.getAddress()[
"host"]);
355 config->Remote::setPort(broker.getAddress()[
"port"]);
357 config->setDisabled(broker.getDisabled() || broker.getBridge().getDisabled());
360 VLOG(1) <<
" Transport '" << transport <<
"', protocol '" << protocol <<
"', encryption '" << encryption
361 <<
"' not supported.";
363 }
else if (encryption ==
"tls") {
364#if defined(CONFIG_MQTTSUITE_BRIDGE_TLS_IPV6)
365 startClient<net::in6::stream::tls::SocketClient>(
367 [&broker](net::in6::stream::tls::config::ConfigSocketClient* config) {
368 config->setDisableNagleAlgorithm();
370 config->Remote::setHost(broker.getAddress()[
"host"]);
371 config->Remote::setPort(broker.getAddress()[
"port"]);
373 config->setDisabled(broker.getDisabled() || broker.getBridge().getDisabled());
376 VLOG(1) <<
" Transport '" << transport <<
"', protocol '" << protocol <<
"', encryption '" << encryption
377 <<
"' not supported.";
380 }
else if (protocol ==
"un") {
381 if (encryption ==
"legacy") {
382#if defined(CONFIG_MQTTSUITE_BRIDGE_UNIX)
383 startClient<net::un::stream::legacy::SocketClient>(
385 [&broker](net::un::stream::legacy::config::ConfigSocketClient* config) {
386 config->Remote::setSunPath(broker.getAddress()[
"host"]);
388 config->setDisabled(broker.getDisabled() || broker.getBridge().getDisabled());
391 VLOG(1) <<
" Transport '" << transport <<
"', protocol '" << protocol <<
"', encryption '" << encryption
392 <<
"' not supported.";
394 }
else if (encryption ==
"tls") {
395#if defined(CONFIG_MQTTSUITE_BRIDGE_UNIX_TLS)
396 startClient<net::un::stream::tls::SocketClient>(
398 [&broker](net::un::stream::tls::config::ConfigSocketClient* config) {
399 config->Remote::setSunPath(broker.getAddress()[
"host"]);
401 config->setDisabled(broker.getDisabled() || broker.getBridge().getDisabled());
404 VLOG(1) <<
" Transport '" << transport <<
"', protocol '" << protocol <<
"', encryption '" << encryption
405 <<
"' not supported.";
409 }
else if (transport ==
"websocket") {
410 if (protocol ==
"in") {
411 if (encryption ==
"legacy") {
412#if defined(CONFIG_MQTTSUITE_BRIDGE_TCP_IPV4) && defined(CONFIG_MQTTSUITE_BRIDGE_WS)
413 startClient<web::http::legacy::in::Client>(
415 [&broker](net::in::stream::legacy::config::ConfigSocketClient* config) {
416 config->setDisableNagleAlgorithm();
418 config->Remote::setHost(broker.getAddress()[
"host"]);
419 config->Remote::setPort(broker.getAddress()[
"port"]);
421 config->setDisabled(broker.getDisabled() || broker.getBridge().getDisabled());
424 VLOG(1) <<
" Transport '" << transport <<
"', protocol '" << protocol <<
"', encryption '" << encryption
425 <<
"' not supported.";
427 }
else if (encryption ==
"tls") {
428#if defined(CONFIG_MQTTSUITE_BRIDGE_TLS_IPV4) && defined(CONFIG_MQTTSUITE_BRIDGE_WSS)
429 startClient<web::http::tls::in::Client>(
431 [&broker](net::in::stream::tls::config::ConfigSocketClient* config) {
432 config->setDisableNagleAlgorithm();
434 config->Remote::setHost(broker.getAddress()[
"host"]);
435 config->Remote::setPort(broker.getAddress()[
"port"]);
437 config->setDisabled(broker.getDisabled() || broker.getBridge().getDisabled());
440 VLOG(1) <<
" Transport '" << transport <<
"', protocol '" << protocol <<
"', encryption '" << encryption
441 <<
"' not supported.";
444 }
else if (protocol ==
"in6") {
445 if (encryption ==
"legacy") {
446#if defined(CONFIG_MQTTSUITE_BRIDGE_TCP_IPV6) && defined(CONFIG_MQTTSUITE_BRIDGE_WS)
447 startClient<web::http::legacy::in6::Client>(
449 [&broker](net::in6::stream::legacy::config::ConfigSocketClient* config) {
450 config->setDisableNagleAlgorithm();
452 config->Remote::setHost(broker.getAddress()[
"host"]);
453 config->Remote::setPort(broker.getAddress()[
"port"]);
455 config->setDisabled(broker.getDisabled() || broker.getBridge().getDisabled());
458 VLOG(1) <<
" Transport '" << transport <<
"', protocol '" << protocol <<
"', encryption '" << encryption
459 <<
"' not supported.";
461 }
else if (encryption ==
"tls") {
462#if defined(CONFIG_MQTTSUITE_BRIDGE_TLS_IPV6) && defined(CONFIG_MQTTSUITE_BRIDGE_WSS)
463 startClient<web::http::tls::in6::Client>(
465 [&broker](net::in6::stream::tls::config::ConfigSocketClient* config) {
466 config->setDisableNagleAlgorithm();
468 config->Remote::setHost(broker.getAddress()[
"host"]);
469 config->Remote::setPort(broker.getAddress()[
"port"]);
471 config->setDisabled(broker.getDisabled() || broker.getBridge().getDisabled());
474 VLOG(1) <<
" Transport '" << transport <<
"', protocol '" << protocol <<
"', encryption '" << encryption
475 <<
"' not supported.";
478 }
else if (protocol ==
"un") {
479 if (encryption ==
"legacy") {
480#if defined(CONFIG_MQTTSUITE_BRIDGE_UNIX) && defined(CONFIG_MQTTSUITE_BRIDGE_WS)
481 startClient<web::http::legacy::un::Client>(
483 [&broker](net::un::stream::legacy::config::ConfigSocketClient* config) {
484 config->Remote::setSunPath(broker.getAddress()[
"path"]);
486 config->setDisabled(broker.getDisabled() || broker.getBridge().getDisabled());
489 VLOG(1) <<
" Transport '" << transport <<
"', protocol '" << protocol <<
"', encryption '" << encryption
490 <<
"' not supported.";
492 }
else if (encryption ==
"tls") {
493#if defined(CONFIG_MQTTSUITE_BRIDGE_UNIX_TLS) && defined(CONFIG_MQTTSUITE_BRIDGE_WSS)
494 startClient<web::http::tls::un::Client>(
496 [&broker](net::un::stream::tls::config::ConfigSocketClient* config) {
497 config->Remote::setSunPath(broker.getAddress()[
"path"]);
499 config->setDisabled(broker.getDisabled() || broker.getBridge().getDisabled());
502 VLOG(1) <<
" Transport '" << transport <<
"', protocol '" << protocol <<
"', encryption '" << encryption
503 <<
"' not supported.";
508 VLOG(1) <<
" Transport '" << transport <<
"' not supported.";
511 mqtt::bridge::lib::SSEDistributor::instance().brokerDisabled(bridgeName, fullInstanceName);
515 mqtt::bridge::lib::SSEDistributor::instance().bridgeDisabled(bridgeName);
520int main(
int argc,
char* argv[]) {
523 core::SNodeC::init(argc, argv);
525 const express::Router router(
express::middleware::JsonMiddleware());
527 router.get(
"/api/bridge/config", [] APPLICATION(req, res) {
528 res->send(mqtt::bridge::lib::BridgeStore::instance().getBridgesConfigJson().dump(4));
531 router.patch(
"/api/bridge/config", [] APPLICATION(req, res) {
532 req->getAttribute<nlohmann::json>(
533 [&res](nlohmann::json& jsonPatch) {
535 if (mqtt::bridge::lib::BridgeStore::instance().patch(jsonPatch)) {
536 res->send(R"({"success": true, "message": "Bridge config patch applied"})"_json.dump());
538 if (closeBridges()) {
542 res->status(404).send(R"({"success": false, "message": "Bridge config patch failed to applie"})"_json.dump());
545 res->status(409).send(
546 R"({"success": false, "message": "Bridge is in restarting state. Patch not applied"})"_json.dump());
549 [&res](
const std::string& key) {
550 VLOG(1) <<
"Attribute type not found: " << key;
552 res->status(400).send(
"Attribute type not found: " + key);
556 router.get(
"/api/bridge/sse", [] APPLICATION(req, res) {
557 if (web::http::ciContains(req->get(
"Accept"),
"text/event-stream")) {
558 res->set(
"Content-Type",
"text/event-stream")
559 .set(
"Cache-Control",
"no-cache")
560 .set(
"Connection",
"keep-alive");
563 std::string data{
"data"};
566 res->redirect(
"/clients");
570 router.get(
"/", [] APPLICATION(req, res) {
571 res->redirect(
"/config");
574 router.get(
"/config", [] APPLICATION(req, res) {
575 res->redirect(
"/config/index.html");
578 router.use(
"/config",
579 express::middleware::StaticMiddleware(utils::Config::configRoot.getSubCommand<mqtt::
bridge::
ConfigBridge>()->getHtmlDir()));
581 router.get(
"*", [] APPLICATION(req, res) {
582 res->redirect(
"/config/index.html");
589 [](net::in::stream::legacy::config::ConfigSocketServer* config) {
590 config->setPort(8081);
592 config->setReuseAddress();
599 [](net::in::stream::tls::config::ConfigSocketServer* config) {
600 config->setPort(8082);
602 config->setReuseAddress();
606 utils::Config::configRoot.getSubCommand<mqtt::
bridge::
ConfigBridge>()->getDefinitionFile()
)) {
609 VLOG(1) <<
"Loading bridge definition file failed";
612 return core::SNodeC::start();