{"id":18720476,"url":"https://github.com/stiffstream/mosquitto_transport","last_synced_at":"2025-11-10T21:30:15.726Z","repository":{"id":92244857,"uuid":"206790270","full_name":"Stiffstream/mosquitto_transport","owner":"Stiffstream","description":"mosquitto_transport is an experiment of writing SObjectizer-based wrapper around mosquitto library.","archived":false,"fork":false,"pushed_at":"2019-09-06T13:01:22.000Z","size":48,"stargazers_count":4,"open_issues_count":0,"forks_count":0,"subscribers_count":4,"default_branch":"master","last_synced_at":"2024-12-28T11:28:18.887Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Stiffstream.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-09-06T12:35:32.000Z","updated_at":"2023-09-16T09:18:41.000Z","dependencies_parsed_at":"2023-06-08T03:15:15.689Z","dependency_job_id":null,"html_url":"https://github.com/Stiffstream/mosquitto_transport","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Stiffstream%2Fmosquitto_transport","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Stiffstream%2Fmosquitto_transport/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Stiffstream%2Fmosquitto_transport/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Stiffstream%2Fmosquitto_transport/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Stiffstream","download_url":"https://codeload.github.com/Stiffstream/mosquitto_transport/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":239583650,"owners_count":19663238,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-07T13:31:15.554Z","updated_at":"2025-11-10T21:30:15.675Z","avatar_url":"https://github.com/Stiffstream.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# What Is It?\n\n_mosquitto_transport_ is an experiment of writing [SObjectizer](https://stiffstream.com/en/products/sobjectizer.html)-based wrapper around [mosquitto](https://mosquitto.org/) library. It IS developed and maintained by [StiffStream](https://stiffstream.com).\n\n# Obtaining And Building\n\nTo use _mosquitto_transport_ it is necessary to have:\n\n* C++14 compiler (gcc 5.4 or above, clang 3.8 or above);\n* [Mxx_ru](https://sourceforge.net/projects/mxxru/) 1.6.13 or above;\n* Boost-1.58 or above.\n\n## MxxRu::externals Recipes\n\nThere is an example of recipes for MxxRu::externals:\n\n```rb\nMxxRu::arch_externals :mosquitto_transport do |e|\n  e.url 'https://github.com/Stiffstream/mosquitto_transport/archive/v.0.6.2.tar.gz'\n\n  e.map_dir 'dev/mosquitto_transport' =\u003e 'dev'\nend\n\nMxxRu::arch_externals :libmosquitto do |e|\n  e.url 'https://github.com/eao197/mosquitto/archive/v1.4.8-p1.tar.gz'\n\n  e.map_dir 'lib' =\u003e 'dev/libmosquitto'\n  e.map_file 'config.h' =\u003e 'dev/libmosquitto/*'\nend\n\nMxxRu::arch_externals :libmosquitto_mxxru do |e|\n  e.url 'https://github.com/Stiffstream/libmosquitto_mxxru/archive/v.1.1.0.tar.gz'\n\n  e.map_file 'dev/libmosquitto/prj.rb' =\u003e 'dev/libmosquitto/*'\nend\n\nMxxRu::arch_externals :fmt do |e|\n  e.url 'https://github.com/fmtlib/fmt/archive/4.1.0.zip'\n\n  e.map_dir 'fmt' =\u003e 'dev/fmt'\nend\n\nMxxRu::arch_externals :fmtlib_mxxru do |e|\n  e.url 'https://github.com/Stiffstream/fmtlib_mxxru/archive/fmt-4.1.0.tar.gz'\n\n  e.map_dir 'dev/fmt_mxxru' =\u003e 'dev'\nend\n\nMxxRu::arch_externals :spdlog do |e|\n  e.url 'https://github.com/gabime/spdlog/archive/v0.16.3.zip'\n\n  e.map_dir 'include' =\u003e 'dev/spdlog'\nend\n\nMxxRu::arch_externals :spdlog_mxxru do |e|\n  e.url 'https://github.com/Stiffstream/spdlog_mxxru/archive/v.1.2.1.tar.gz'\n\n  e.map_dir 'dev/spdlog_mxxru' =\u003e 'dev'\nend\n\nMxxRu::arch_externals :so5 do |e|\n  e.url 'https://sourceforge.net/projects/sobjectizer/files/sobjectizer/SObjectizer%20Core%20v.5.5/so-5.5.24.4.tar.xz'\n\n  e.map_dir 'dev/so_5' =\u003e 'dev'\n  e.map_dir 'dev/timertt' =\u003e 'dev'\nend\n\nMxxRu::arch_externals :catch do |e|\n  e.url 'https://github.com/catchorg/Catch2/archive/v2.2.2.tar.gz'\n\n  e.map_file 'single_include/catch.hpp' =\u003e 'dev/catch/*'\nend\n```\n\n# License\n\n_mosquitto_transport_ is distributed under [BSD-3-Clause](http://spdx.org/licenses/BSD-3-Clause.html) license.  See LICENSE file for more information.\n\n# How To Use\n\n## mosquitto Library Initialization And Deinitialization\n\nTo initialize and deinitialize mosquitto library correctly an instance of `lib_initializer_t` must be created. This instance must live for all time while mosquitto-transport is used in application. A reference to that instance must be passed to the constructor of every `a_transport_manager_t` agent.\n\nFor example:\n\n```cpp\nnamespace mosqt = mosquitto_transport;\nint main()\n{\n  mosqt::lib_initializer mosq_init;\n  so_5::launch( [\u0026]( so_5::environment_t \u0026 env ) {\n    ...\n  } );\n}\n```\n\n## Creation Of Transport Manager\n\nEvery client connection to MQTT broker is under control of `a_transport_manager_t` agent. Because of that an agent of this type must be created.\n\n**Note.** Agent `a_transport_manager_t` uses thread-safe event handler so the `adv_thread_pool` dispatcher can be used for that agent.\n\n**Note.** It is better to place `a_transport_manager_t` instance to separate cooperation.\n\nAfter creation of `a_transport_manager_t` a value of `instance_t` must be obtained from it. This value will be used for message publishing and retrieving.\n\nA very simple example:\n\n```cpp\nnamespace mosqt = mosquitto_transport;\nmosqt::instance_t make_transport(so_5::environment_t \u0026 env, mosqt::lib_initializer_t \u0026 mosq_init)\n{\n  mosqt::instance_t instance;\n  env.introduce_coop( [\u0026](so_5::coop_t \u0026 coop) {\n    auto tm = coop.make_agent\u003c mosqt::a_transport_manager_t \u003e(\n      // A reference to mosquitto library initializer.\n      std::ref{mosq_init},\n      // Broker connection params.\n      mosqt::connection_params_t{\n        // ID for client on broker.\n        \"my-clien-name\",\n        // Broker host.\n        \"localhost\",\n        // Broker port.\n        1883,\n        // Keepalive timer in seconds.\n        30 },\n      // Logger instance to be used.\n      spdlog::stdout_logger_mt(\"mosqt\") );\n    instance = tm-\u003einstance();\n  } );\n  return instance;\n}\n```\n\n## Message Encoding and Decoding Principles\n\nmosquitto_transport library supports automatic message encoding and decoding.\nBut it requires some help from application code.\n\nTo encode message into some format (binary, JSON, XML and so on) there should\nbe a partial or full specialization of\n`mosquitto_transport::encoder_t\u003cENCODER_TAG,MSG\u003e` template. For example it\ncould looks like:\n\n```cpp\nstruct json_encoding {}; // Will be used as tag type.\n\nnamespace mosquitto_transport {\n\n// Partial specialization for all message types.\ntemplate\u003c typename MSG \u003e\nstruct encoder_t\u003c json_encoding, MSG \u003e\n{\n  // Actual encoding method.\n  static std::string encode( const MSG \u0026 what )\n  {\n    // Assume every MSG has `to_json` method.\n    return what.to_json();\n  }\n};\n\n}\n```\n\nSimilary for decoding a message from some format there should be a partial of\nfull specialization of `mosquitto_transport::decoder_t\u003cDECODER_TAG,MSG\u003e`\ntemplate. Something like that:\n\n```cpp\nstruct json_encoding {}; // Will be used as tag type.\n\nnamespace mosquitto_transport {\n\n// Partial specialization for all message types.\ntemplate\u003c typename MSG \u003e\nstruct decoder_t\u003c json_encoding, MSG \u003e\n{\n  // Actual decoding method.\n  static MSG decode( const std::string \u0026 payload )\n  {\n    // Assume every MSG has `from_json` method.\n    MSG m;\n    m.from_json(payload);\n    return m;\n  }\n};\n\n}\n```\n\nAfter that some useful typedefs could be defined:\n\n```cpp\nusing topic_subscriber = mosquitto_transport::topic_subscriber_t\u003c json_encoding \u003e;\nusing topic_publisher = mosquitto_transport::topic_publisher_t\u003c json_encoding \u003e;\n```\n\n## Message Publishing \n\nThere is just one way for publishing messages in v.0.3.\n\nIt requires usage of `mosquitto_transport::publisher_t` template class and its\nmethod `publish`:\n\n```cpp\nnamespace mosqt = mosquitto_transport;\n\nmosqt::instance_t instance = ...; // Value returned by a_transport_manager_t agent.\n\n// Publish instance of status_update_t message into \"clients/statuses/updates\" topic.\n// Type json_encoding means that there is an appropriate specialization\n// for mosquitto_transport::encoder_t template.\nmosqt::topic_publisher_t\u003c json_encoding \u003e::publish(\n  instance, // Transport manager to be used.\n  \"clients/statuses/updates\", // Topic for message.\n  status_update_t{...} ); // Message to be published.\n```cpp\n\nA call to `topic_publisher_t\u003cTAG\u003e::publish` can be shortened if there is an\nalias like that:\n\n```cpp\nnamespace mosqt = mosquitto_transport;\n...\nusing topic_publisher = mosqt::topic_publisher_t\u003c json_encoding \u003e;\n...\ntopic_publisher::publish(\n  instance, // Transport manager to be used.\n  \"clients/statuses/updates\", // Topic for message.\n  status_update_t{...} ); // Message to be published.\n```\n\n**Attention.** *All messages are published with QoS=0.*\n\n## Message Subscription\n\nTo receive messages for a topic it is necessary to create a subscription from\nsome special mbox. This mbox is created automatically and managed to\nmosquitto\\_transport.\n\nTo create subscription it is necessary to use template class\n`mosquitto_transport::topic_subscriber_t\u003cDECODER_TAG\u003e` and its template method\nsubscribe:\n\n```cpp\nnamespace mosqt = mosquitto_transport;\n...\nclass status_receiver_t : public so_5::agent_t\n{\n  mosqt::instance_t m_transport;\n  ...\npublic :\n  status_receiver_t(context_t ctx, mosqt::instance_t transport)\n    : so_5::agent_t{ctx}\n    , m_transport{std::move(transport)}\n  {}\n  virtual void so_define_agent() override\n  {\n    mosqt::topic_subscriber_t\u003c json_encoding \u003e::subscribe(\n      m_transpor, // Transport manager to be used for subscription.\n      \"clients/statuses/updates\", // Topic to be subscribed.\n      // Lambda to do agent subscription actions.\n      [this]( so_5::mbox_t mbox ) {\n        so_default_state().event( mbox, \u0026status_receiver_t::on_status_update );\n        st_finishing.event( mbox, \u0026status_receiver_t::on_status_update );\n        ...\n      } );\n    ...\n  }\n  ...\nprivate :\n  // Message will be delivered as mosquitto_transport::incoming_message_t.\n  void on_status_update(const mosqt::incoming_message_t\u003c json_encoding \u003e \u0026 cmd)\n  {\n    // cmd contains topic name and payload.\n    // Actual message object should be extracted manually.\n    const status_update_t upd = cmd.decode\u003c status_update_t \u003e();\n  }\n};\n```cpp\n\nA call to `topic_subscriber_t\u003cTAG\u003e::subscribe` can be shortened if there is an\nalias like that:\n\n```cpp\nnamespace mosqt = mosquitto_transport;\n...\nusing topic_subscriber = mosqt::topic_subscriber_t\u003c json_encoding \u003e;\n...\ntopic_subscriber::subscribe(\n  m_transpor, // Transport manager to be used for subscription.\n  \"clients/statuses/updates\", // Topic to be subscribed.\n  // Lambda to do agent subscription actions.\n  [this]( so_5::mbox_t mbox ) {\n    so_default_state().event( mbox, \u0026status_receiver_t::on_status_update );\n    st_finishing.event( mbox, \u0026status_receiver_t::on_status_update );\n    ...\n  } );\n```\n\n**Note.** There is also short name `msg_type` which can be used for\nsimplification of incoming messages handling:\n\n```cpp\nnamespace mosqt = mosquitto_transport;\n...\nusing topic_subscriber = mosqt::topic_subscriber_t\u003c json_encoding \u003e;\n...\nvoid status_receiver_t::on_status_update(const topic_subscriber::msg_type \u0026 cmd)\n{\n  const auto \u0026 upd = cmd.decode\u003c status_update_t \u003e();\n}\n```\n\n### Supscriptions With Wildcards In Topic Filters\n\nSince v.0.3 there is a possibility to subscribe to several topics by using\nwildcards `+` and `#` in topic filters. It could be done usual way:\n\n```cpp\nnamespace mosqt = mosquitto_transport;\n...\nusing topic_subscriber = mosqt::topic_subscriber_t\u003c json_encoding \u003e;\n...\nvoid status_listener_t::so_define_agent() override\n{\n\ttopic_subscriber::subscribe(\n\t\tm_transpor, // Transport manager to be used for subscription.\n\t\t\"client/+/status/updates\", // Topic filter to be subscribed.\n\t\t// Lambda to do agent subscription actions.\n\t\t[this]( const so_5::mbox_t \u0026 mbox ) {\n\t\t\tso_subscribe( mbox ).event( \u0026status_listener_t::on_status_update );\n\t\t\t...\n\t\t} );\n}\n```\n\n*Note.* When agent is subscribed to topic filter with wildcards it will\nreceive actual topic name in `incoming_message_t`. For example if agent is\nsubscribed to `client/+/status/updates` and there is a message from\ntopic `client/1/status/updates` then name `client/1/status/updates` will\nbe in `incoming_message_t::topic_name`.\n\n### Subscription Availability And Unavailability Notifications\n\nSince v.0.3 there are notifications about subscriptions availability and\nunavailability.\n\nMessage `mosquitto_transport::subscription_available_t` is sent when\nsubscription to topic is completed successfully.\n\nMessage `mosquitto_transport::subscription_unavailable_t` is send when\nconnection to MQTT broker is lost.\n\nMethod `topic_name()` of these messages will return the original topic\nfilter which was passed to `subscribe` method. For example, if topic filter\n`/sport/results/#` was used then this value will be returned by\n`topic_name()` methods.\n\n```cpp\nnamespace mosqt = mosquitto_transport;\n...\nusing topic_subscriber = mosqt::topic_subscriber_t\u003c json_encoding \u003e;\n...\nvoid status_listener_t::so_define_agent() override\n{\n\ttopic_subscriber::subscribe(\n\t\tm_transpor, // Transport manager to be used for subscription.\n\t\t\"client/+/status/updates\", // Topic filter to be subscribed.\n\t\t// Lambda to do agent subscription actions.\n\t\t[this]( const so_5::mbox_t \u0026 mbox ) {\n\t\t\tso_subscribe( mbox )\n\t\t\t\t.event( \u0026status_listener_t::on_topic_subscribed )\n\t\t\t\t.event( \u0026status_listener_t::on_topic_lost );\n\n\t\t\tso_subscribe( mbox ).event( \u0026status_listener_t::on_status_update );\n\t\t\t...\n\t\t} );\n}\n\nvoid status_listener_t::on_topic_subscribed(\n\tconst mosqt::subscription_available_t \u0026 cmd )\n{\n\t// cmd.topic_name() will contain \"client/+/status/updates\" name.\n\t...\n}\n\nvoid status_listener_t::on_topic_lost(\n\tconst mosqt::subscription_unavailable_t \u0026 cmd )\n{\n\t// cmd.topic_name() will contain \"client/+/status/updates\" name.\n\t...\n}\n```\n\n**Note.** Because MQTT allows delivery of messages from subscribed topics\nbefore completion of subscription operation it is possible to receve some\nmessages from subscribed topics before arival of `subscription_available_t`\nmessage.\n\n*Note.* Message `subscription_unavailable_t` can be sent before\n`subscription_available_t`. It is possible in situation when new subscription\nis not finished but a connection to broker is lost.\n\n### Subscription Failure\n\nSubscription is an asynchronous process. The subscription result could be\nreceived after some time. And this result could be negative.\n\nIf the case of subscription failure an exception is thrown on the context\nof `transport_manager` agent. This exeption usually leads to abortion\nof the whole application.\n\nThere is a way to specify another reaction for subscription failure.\nMethod `topic_subscriber_t::subscriber` can receive yet another parameter.\nIf this parameter has value `mosquitto_transport::notify_on_failure` then\na special message will be sent instead on throwing an exception:\n\n```cpp\nnamespace mosqt = mosquitto_transport;\n...\nusing topic_subscriber = mosqt::topic_subscriber_t\u003c json_encoding \u003e;\n...\nvoid status_listener_t::so_define_agent() override\n{\n\ttopic_subscriber::subscribe(\n\t\tm_transpor, // Transport manager to be used for subscription.\n\t\t\"client/+/status/updates\", // Topic filter to be subscribed.\n\t\t// Lambda to do agent subscription actions.\n\t\t[this]( const so_5::mbox_t \u0026 mbox ) {\n\t\t\tso_subscribe( mbox )\n\t\t\t\t.event( \u0026status_listener_t::on_topic_subscribed )\n\t\t\t\t.event( \u0026status_listener_t::on_topic_lost )\n\t\t\t\t.event( \u0026status_listener_t::on_topic_failed );\n\n\t\t\tso_subscribe( mbox ).event( \u0026status_listener_t::on_status_update );\n\t\t\t...\n\t\t},\n\t\t// Send subscription_failed_t message instead on throwing an exception.\n\t\tmosqt::notify_on_failure );\n}\n\nvoid status_listener_t::on_topic_failed(\n\tconst mosqt::subscription_failed_t \u0026 cmd )\n{\n\t// cmd.topic_name() will contain \"client/+/status/updates\" name.\n\t// cmd.description() will contain description of the failure.\n\t...\n}\n```\n\n### Subscription Timeout\n\nThere is a time limit for subscription operation. If `SUBACK` response is not received during specified\ntimeout then the whole subscription operation will be considered as failed. And appropriate reaction will\nbe performed (see above).\n\nSubscription timeout is 60 seconds by default. It can be changed by `set_subscription_timeout` method\nof `transport_manager`. This method must be called before registration of `transport_manager` registration:\n\n```cpp\nusing namespace std::chrono_literals;\n\nnamespace mosqt = mosquitto_transport;\nmosqt::instance_t make_transport(so_5::environment_t \u0026 env, mosqt::lib_initializer_t \u0026 mosq_init)\n{\n  mosqt::instance_t instance;\n  env.introduce_coop( [\u0026](so_5::coop_t \u0026 coop) {\n    auto tm = coop.make_agent\u003c mosqt::a_transport_manager_t \u003e(\n      std::ref{mosq_init},\n      mosqt::connection_params_t{\"my-clien-id\", \"localhost\", 1883, 30 },\n      spdlog::stdout_logger_mt(\"mosqt\") );\n    // Setting the timeout for subscription operation.\n    tm-\u003eset_subscription_timeout( 15s ); // Wait no more than 15 seconds.\n    instance = tm-\u003einstance();\n  } );\n  return instance;\n}\n```\n\n## Broker Connection And Disconnection Notifications\n\nThere are `mosquitto_transport::broker_connected_t` and\n`mosquitto_transport::broker_disconnected_t` signals. They can be used to\ndetection of connection status. Something like:\n\n```cpp\nnamespace mosqt = mosquitto_transport;\n...\nclass client_t : public so_5::agent_t\n{\n  mosqt::instance_t m_transport;\n  ...\npublic :\n  client_t(context_t ctx, mosqt::instance_t transport)\n    : so_5::agent_t{ctx}\n    , m_transport{std::move(transport)}\n  {}\n  virtual void so_define_agent() override\n  {\n    so_subscribe( m_transport.mbox() )\n      .event\u003c mosqt::broker_connected_t \u003e( \u0026client_t::on_connected )\n      .event\u003c mosqt::broker_disconnected_t \u003e( \u0026client_t::on_disconnected );\n    ...\n  }\n...\n};\n```\n\n## Setting The Will\n\nMQTT will can be set by `a_transport_manager_t::mqtt_will_set()` method. Please note that this method must be called before the registration of transport manager agent!\n\n```cpp\nnamespace mosqt = mosquitto_transport;\nmosqt::instance_t make_transport(so_5::environment_t \u0026 env, mosqt::lib_initializer_t \u0026 mosq_init)\n{\n  mosqt::instance_t instance;\n  env.introduce_coop( [\u0026](so_5::coop_t \u0026 coop) {\n    auto tm = coop.make_agent\u003c mosqt::a_transport_manager_t \u003e(\n      std::ref{mosq_init},\n      mosqt::connection_params_t{\"my-clien-id\", \"localhost\", 1883, 30 },\n      spdlog::stdout_logger_mt(\"mosqt\") );\n    // Setting the will for the client.\n    tm-\u003emqtt_will_set(\n      \"clients/statuses/offline\", // Topic for the will.\n      \"my-client-id\" ); // Payload of the will message.\n    instance = tm-\u003einstance();\n  } );\n  return instance;\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstiffstream%2Fmosquitto_transport","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstiffstream%2Fmosquitto_transport","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstiffstream%2Fmosquitto_transport/lists"}