{"id":19509144,"url":"https://github.com/shellshoccar-jpn/mqttwrapper","last_synced_at":"2026-03-19T10:13:30.668Z","repository":{"id":166874374,"uuid":"626312272","full_name":"ShellShoccar-jpn/MQTTwrapper","owner":"ShellShoccar-jpn","description":"Two solutions to enable a web browser to act as both MQTT pub/sub","archived":false,"fork":false,"pushed_at":"2025-09-24T06:17:29.000Z","size":133,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-09-24T08:24:59.464Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"HTML","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"unlicense","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ShellShoccar-jpn.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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2023-04-11T08:06:12.000Z","updated_at":"2025-09-24T06:17:32.000Z","dependencies_parsed_at":"2024-11-07T15:21:07.186Z","dependency_job_id":"54267219-2f21-4374-8ffd-307bb1917c45","html_url":"https://github.com/ShellShoccar-jpn/MQTTwrapper","commit_stats":null,"previous_names":["shellshoccar-jpn/mqttwrapper"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/ShellShoccar-jpn/MQTTwrapper","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ShellShoccar-jpn%2FMQTTwrapper","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ShellShoccar-jpn%2FMQTTwrapper/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ShellShoccar-jpn%2FMQTTwrapper/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ShellShoccar-jpn%2FMQTTwrapper/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ShellShoccar-jpn","download_url":"https://codeload.github.com/ShellShoccar-jpn/MQTTwrapper/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ShellShoccar-jpn%2FMQTTwrapper/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29994618,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-02T01:47:34.672Z","status":"online","status_checked_at":"2026-03-02T02:00:07.342Z","response_time":60,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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-10T23:11:07.796Z","updated_at":"2026-03-02T07:01:11.225Z","avatar_url":"https://github.com/ShellShoccar-jpn.png","language":"HTML","funding_links":[],"categories":[],"sub_categories":[],"readme":"# MQTTwrapper and MQTT via HTTP/2\n\nThese are solutions and implementations that enable a web browser to act as both an MQTT publisher and subscriber. Initially, a web browser is a client-pull data receiving tool, which can only receive data when the browser requests it, so it cannot always get fresh data. On the other hand, the MQTT is based on the publish-subscribe pattern and its clients can receive fresh data that has just been generated.\n\nTo introduce the pub/sub transmission into web browsers, two protocols were invented. They are called \"WebSocket\" and \"Server-Sent Events.\" WebSocket is the smarter solution because both the web server and the client can send data spontaneously. However, it also has a weak point, which a few networks can overcome, as WebSocket does not have complete compatibility with HTTP. In comparison, Server-Sent Events is a type of HTTP function and can pass through HTTP networks without any problem. But it supports only server-to-client direction, and you have to use the classic HTTP POST method for upstream. To reduce such inefficiency, HTTP/2 is regularly used in that case.\n\nSo, I offer you two solutions and their implementations.\n\n* [\"MQTTwrapper\"](#a-mqttwrapper): A redundant MQTT JavaScript library wrapper with MQTT.js and Paho. These two libraries are implementations of the \"MQTT over WebSocket\"\n* [\"MQTT via HTTP/2\"](#b-mqtt-via-http2): A solution for web browsers to do MQTT bi-directional transmission by SSE and HTTP/2\n\n\n## CONTENTS OF THIS PACKAGE\n\nThis package contains the following files and directories.\n\n```\n./\n|-- README.md ........................ This file\n|-- LICENSE .......................... License information for this package\n|\n|-- public_html/ ..................... Directory for public web space\n|   |                                  - It contains Javascript library files,\n|   |                                    CGI scripts, and example HTML files.\n|   |                                  - If you want to put this package on a\n|   |                                    web server, we recommend you publish\n|   |                                    only the files in this directory.\n|   |                                  - Of course, unnecessary to care about it\n|   |                                    if you put this package within your\n|   |                                    local computer.\n|   |\n|   |-- sse/                           Demo files for \"MQTT via HTTP/2\"\n|   |   |\n|   |   |-- cgi/ ..................... CGI scripts written in shell script\n|   |   |   |\n|   |   |   |-- mqtt_via_http_down.cgi \"mosquitto_sub\" wrapper with SSE\n|   |   |   `-- mqtt_via_http_up.cgi . \"mosquitto_pub\" wrapper with HTTP POST\n|   |   |\n|   |   `-- examples/ ................ Directory for \"MQTT via HTTP/2\" examples\n|   |       |\n|   |       |-- index.html ........... Just a menu for the following examples\n|   |       |\n|   |       |-- helloworld.html ...... \"Hello, world!\" example (Try it first!)\n|   |       |-- messageboard.html .... \"Japanese Nostalgic Message Board\" example\n|   |       |                           (DOM operation)\n|   |       |-- realtimechart.html ... \"Realtime Chart\" example\n|   |       |                           (using the Chart.js library)\n|   |       |-- mapworm.html ......... \"Map Worm\" example \n|   |       |                           (using the Leaflet library)\n|   |       |-- whereareweat.html .... \"Where are we at?\" example\n|   |       |                           (using Geo API and the Leaflet library)\n|   |       |\n|   |       `-- mqttbrokers.js ....... Public MQTT broker list;\n|   |                                  It is loaded by the above examples.\n|   |\n|   `-- websocket/                     Demo files for \"MQTTwrapper\"\n|       |\n|       |-- lib.js/ .................. Directory for library files\n|       |   |\n|       |   `-- MQTTwrapper.js ....... The \"MQTTwrapper Class Library\" file\n|       |\n|       `-- examples/ ................ Directory for the \"MQTTwrapper\" class\n|           |                          examples\n|           |\n|           |-- index.html ........... Just a menu for the following examples\n|           |\n|           |-- helloworld.html ...... \"Hello, world!\" example (Try it first!)\n|           |-- messageboard.html .... \"Japanese Nostalgic Message Board\" example\n|           |                           (DOM operation)\n|           |-- realtimechart.html ... \"Realtime Chart\" example\n|           |                           (using the Chart.js library)\n|           |-- mapworm.html ......... \"Map Worm\" example \n|           |                           (using the Leaflet library)\n|           |-- whereareweat.html .... \"Where are we at?\" example\n|           |                           (using Geo API and the Leaflet library)\n|           |\n|           `-- mqttbrokers.js ....... Public MQTT broker list;\n|                                      It is loaded by the above examples.\n|\n`-- sh_for_examples/ ................. Directory for shell scripts to help the\n    |                                  above examples\n    |\n    |-- dummy_chart.sh ............... Dummy data generator for the\n    |                                  \"Realtime Chart\" examples\n    |\n    |-- mapworm.sh ................... Sample coordinates publisher for the\n    |                                  \"Map Worm\" examples\n    |\n    `-- mapworm.data/ ................ Directory for sample coordinates files\n```\n\n\n## A. MQTTwrapper\n\nThis library is to make the MQTT libraries [\"MQTT.js\"](https://github.com/mqttjs/MQTT.js) and [\"Paho\"](https://www.eclipse.org/paho/index.php?page=clients/js/index.php) more robust. If you use this library instead of them, your program can get longer life than the two libraries because this library works as a wrapper choosing available one of them. If one of them gets unavailable, this wrapper loads the other one.\n\nThe network configuration when you use the above libraries is as follows:\n\n```\n     +------------------------------------------------+        +---------------+\n     |                                                ---------\u003e Other MQTT    |\n     |     MQTT broker (with WebSocket support)       |        | Publishers    |\n     |                                                \u003c--------- / Subscribers |\n     +-------------!--------------------A-------------+        +---------------+\n         [.........!....................!.........]\n         [.........!MQTT................!MQTT.....] WebSocket\n         [.........!subscribe...........!publish..] tunnel\n         [.........!....................!.........](TCP #8083 etc.)\n         [.........!....................!.........]\n+------------------!--------------------!------------------+\n| Web Browser      !                    !                  |\n|                  !                    |                  |\n|                  !                    !                  |\n|                  !                    !                  |\n|                  V                    !                  |\n|   +---------------------+      +---------------------+   |\n|   | (MQTTwrapper class) |      | (MQTTwrapper class) |   |\n|   |setReceiverCallback()|      |      publish()      |   |\n|   +---------------------+      +---------------------+   |\n|                  :                    A                  |\n|                  V                    :                  |\n|     display the message             push a button        |\n|                                                          |\n+----------------------------------------------------------+\n```\n\nAn MQTT broker (that supports WebSocket) and one of the libraries make a single WebSocket connection directly, without any web servers. Both sides of the WebSocket nodes can send data spontaneously. Therefore, the WebSocket can function as a tunnel for MQTT packets. In other words, the native MQTT packets are encapsulated in the WebSocket payload. Then, every method on the broker and the browser encapsulates/decapsulates the MQTT packets and data.\n\n### First, try the \"Hello, world!\" example\n\nThe best way to understand what the library is and how easy to use is to try the \"Hello, world!\" example first! Just after you have done \"git clone\" me, open the \"./public_html/websocket/examples/helloworld.html\" with a web browser. Then try each step written in the \"How to Use Me\" section on the web page.\n\n### How to use the library\n\nNow that you know this library, we will tell you how to use this library in your web programs.\n\n1. Load the MQTT libraries you want to wrap and this file on your HTML file using the \u003cscript\u003e tags, like this:\n\n```HTML:example1\n\u003cscript src=\"https://unpkg.com/mqtt/dist/mqtt.min.js\"\u003e\u003c/script\u003e\n\u003cscript src=\"https://cdnjs.cloudflare.com/ajax/libs/paho-mqtt/1.0.1/mqttws31.min.js\"\u003e\u003c/script\u003e\n\u003cscript src=\"MQTTwrapper.js\"\u003e\u003c/script\u003e\n```\n\n(The place of the library file \"MQTTwrapper.js\" is written in the [\"CONTENTS OF THIS PACKAGE\"](#contents-of-this-package) section.)\n\n**THE \u003cscript\u003e TAG OF THIS FILE MUST BE LATER THAN THE MQTT LIBRARY TAGS!!!** Otherwise, this file will fail to wrap them.\n\nIf you want to specify the location URL of those libraries, specify the alternative URLs with the \u003cscript\u003e \"src\" properties.\n\n```HTML:example2\n\u003cscript src=\"./js/mqtt.min.js\"\u003e\u003c/script\u003e\n\u003cscript src=\"./js/mqttws31.min.js\"\u003e\u003c/script\u003e\n\u003cscript src=\"MQTTwrapper.js\"\u003e\u003c/script\u003e\n```\n\nIf you want to specify the order to try to wrap the MQTT libraries, you can write the order inside the script tag of the wrapper, like the following JSON:\n\n```HTML:example3\n\u003cscript src=\"./js/mqtt.min.js\"\u003e\u003c/script\u003e\n\u003cscript src=\"./js/mqttws31.min.js\"\u003e\u003c/script\u003e\n\u003cscript src=\"MQTTwrapper.js\"\u003e\n  { \"order\" : [ \"Paho\", \"MQTT.js\" ] }\n\u003c/script\u003e\n```\n\nThe current names you can specify are only \"MQTT.js\" and \"Paho.\" Be careful of typos in those spells. (Case sensitive) When not specified, the current default order is 1.\"MQTT.js\" 2.\"Paho.\"\n\n2. Use the \"MQTTwrapper\" class in your JavaScript. Here is an example.\n\n```Javascript:example1\nclient = new MQTTwrapper('ws://broker.mqttdashboard.com:8000/mqtt');\nif (client) {\n  client.connect({\n    \"cbConnected\"   :()=\u003e{console.log('Connected'                       );\n                          client.subscribe('testtopic/#'                );\n                          client.publish('test/channel1','Hello, world!');},\n    \"cbDisconnected\":()=\u003e{console.log('Discnnected normally'            );},\n    \"cbKilled\"      :()=\u003e{console.log('Discnnected suddenly'            );},\n    \"cbFailed\"      :()=\u003e{console.log('Failed to connect'               );}\n  });\n  client.setReceiverCallback(\n    function(message,topic){console.log(topic+':'+message);}\n  );\n} else {\n  console.error('Cannot create an instance');\n}\n```\n\nSee the reference section for detail.\n\n### REFERENCE (\"MQTTwrapper\" Class)\n\n```\n* \u003cProperty,static\u003e sLibname\n    Usage : str = MQTTerapper.sLibname;\n            - str ........ String variable to know which library\n                           is wrapped.\n    Return: At this version, this property returns one of the following\n            names.\n            - \"MQTT.js\" .. When this class wraps the MQTT.js.\n            - \"Paho\" ..... When this class wraps the Eclipse Paho.\n    Desc. : You can know which library is wrapped this time by\n            reading this property. But note that we may change the\n            word or spell of the name in the future. So the behavior\n            of your program should not strictly depend on the strict\n            spell.\n            This property is a readonly one.\n* \u003cFunction\u003e constructor()\n    Usage : obj = new MQTTwrapper(url, [id]);\n            - obj ... Variable to stock an object instance.\n            - url ... URL to connect the MQTT broker.\n                      (It must support \"MQTT over WebSocket\")\n            - id .... MQTT Client ID. You can omit this, and we\n                      recommend doing so. In that case, this wrapper\n                      generates an ID randomly. to do so. In that\n                      case, this wrapper generates the ID.\n    Desc. : You have to call this at first. However, the constructor\n            does not connect to the broker yet. The \"connect()\" method\n            is to connect to it.\n* \u003cFunction\u003e connect()\n    Usage : obj.connect([opt])\n            - opt .. Option parameter object. You can contain the\n                     following properties.\n                     (1) Callback functions\n                       [cbConnected]   : Callback function that is called\n                                         when connected successfully.\n                       [cbDisconnected]: Callback function that is called\n                                         when dicconnected normally. When\n                                         you do not omit the \"onKilled,\"\n                                         this value will be copied to it.\n                       [cbKilled]      : Callback function that is called\n                                         when dicconnected unintentionally.\n                                         In case you need to reconnect,\n                                         you can use this callback as a\n                                         trigger.\n                                         If you do not give me a valid\n                                         value, the value of the\n                                         \"onDisconnected\" will be copied.\n                       [cbFailed]      : Callback function that is called\n                                         when failed to connect to the\n                                         broker. This function accept one\n                                         argument.\n                                           1. (string type) To get the error\n                                              message\n                     (2) \"Will message\" parameters (optional)\n                       [will].topic    : Topic name (string type) for\n                                         the will message. (Mandatory when\n                                         you set the \"will\" property)\n                       [will].message  : Message body (string type)\n                                         for the will message. (Mandatory\n                                         when you set the \"will\" property)\n                       [will].[qos]    : MQTT QoS for the will message.\n                                         (You can omit this)\n                       [will].[retain] : MQTT Retain flag for the will\n                                         message. (You can omit this)\n    Return: Nothing.\n    Desc. : This method will try to establish the connection when you\n            call. And these callback functions will start being called\n            when the connection is established, closed, or failed.\n* \u003cFunction\u003e dicconnect()\n    Usage : obj.disconnect();\n            - obj ............. Variable stocking the object instance.\n    Return: Nothing.\n    Desc. : This method is to close the connection. And the\n            \"onDisconnected\" callback function you registered by the\n            \"connect()\" method may be called soon if the connection\n            is alive and it has been closed.\n            It is meaningless to call this method when you had not\n            called the \"connect()\" method, but also harmless.\n* \u003cFunction\u003e setReceiverCallback()\n    Usage : ret = obj.setReceiverCallback([cbReceived]);\n            - ret ......... Boolean variable to receive success or\n                            failure.\n            - obj ......... Variable stocking the object instance.\n            - cbReceived .. Callback function that is called when\n                            a message string has arrived.\n                            This function accepts three arguments.\n                              1. (string type) To get the message body.\n                              2. (string type) To get the topic name.\n                              3. (object type) To get other info.\n                                 This object has the following\n                                 properties.\n                                   qos    : (number type) MQTT QoS\n                                            parameter. (0,1,2)\n                                   retain : (boolean type) MQTT retain\n                                            flag. (true/false)\n                                   payloadBytes :\n                                            (Uint8Array type) The\n                                            message body. It means\n                                            the same data as the first\n                                            argument but with a\n                                            different data type.\n                                 Other properties are also visible,\n                                 but you must not depend on them.\n                                 They are only for debugging.\n    Return: Returns true when this method registers/unregisters the\n            callback function successfully. Or returns false when\n            something wrong happens.\n    Desc. : This method is to register the callback function that is\n            called when a subscribing message arrives. You can get both\n            the message body and the topic name with the function.\n            Therefore, you should call this method before calling the\n            \"subscribe()\" method.\n            If no function is registered, the arrived messages will\n            be purged.\n            The function will be unregistered when you call this method\n            with no argument or null value.\n* \u003cFunction\u003e subcscribe()\n    Usage : ret = obj.subcscribe(topic, [opt]);\n            - ret .... Boolean variable to receive whether success\n                       or failure.\n            - obj .... Variable stocking the object instance.\n            - topic .. Topic name (string type) to subscribe.\n            - opt ...... Option parameter object. You can contain the\n                         following properties.\n                           [qos]    : MQTT QoS. (Number type, 0, 1,\n                                      or 2. Default is 0)\n    Return: Returns true when this method can call the wrapping\n            \"subscribe()\" method. (However, it does not mean that\n            it succeeded in getting the acknowledgment for the request)\n            The cases in this method return false are:\n            - When the connection is not established.\n            - When the \"topic\" is omitted.\n            - When the \"topic\" is neither a string nor a number.\n            - When the \"topic\" is empty.\n    Desc. : Start subscribing to the MQTT topic. And the callback\n            function registerd by the \"setReceiverCallback()\" method\n            will start being called.\n            If no callback function is registered by the\n            \"setReceiverCallback()\" method, the arrived messages will\n            be purged.\n            Be careful that it will probably be failed to call this\n            method just after calling the \"connect()\" method because\n            the connection is not established yet.\n* \u003cFunction\u003e unsubcscribe()\n    Usage : ret = obj.subcscribe(topic);\n            - ret .... Boolean variable to receive whether success\n                       or failure.\n            - obj .... Variable stocking the object instance.\n            - topic .. Topic name (string type) to subscribe.\n    Return: Returns true when this method can call the wrapping\n            \"unsubscribe()\" method. (However, it does not mean that\n            it succeeded in getting the acknowledgment for the request)\n            The cases this method returns false are:\n            - When the connection is not established.\n            - When the \"topic\" is omitted.\n            - When the \"topic\" is neither a string nor a number.\n            - When the \"topic\" is empty.\n    Desc. : Finish subscribing to the MQTT topic. And the callback\n            function registerd by the \"setReceiverCallback()\" method\n            will finish being called.\n            You have to specify the same topic as when you set it\n            by calling the \"subscribe()\" method. Otherwise, maybe\n            you cannot stop the subscribing.\n* \u003cFunction\u003e publish()\n    Usage : ret = obj.publish(topic, message, opt);\n            - ret ...... Boolean variable to receive whether success\n                         or failure.\n            - obj ...... Variable stocking the object instance.\n            - topic .... (string type) Topic name to publish.\n            - message .. (number or string or Uint8Array type)\n                         Message body to publish.\n            - opt ...... Option parameter object. You can contain the\n                         following properties.\n                           [qos]    : (Number type) MQTT QoS. (0, 1,\n                                      or 2. Default is 0)\n                           [retain] : (Boolean type) MQTT Retain flag.\n                                      (true or false. Default is false)\n    Return: Returns true when this method can call the wrapping\n            \"publish()\" method. (However, it does not mean that it\n            succeeded in getting the acknowledgment for the request)\n            The cases this method returns false are:\n            - When the connection is not established.\n            - When the \"topic\" is omitted.\n            - When the \"topic\" is neither a string nor a number.\n            - When the \"topic\" is empty.\n            - When the \"message\" is omitted.\n            - When the \"message\" is neither a string nor a number.\n    Desc. : Publish a message to the topic channel specified the\n            \"topic\" argument.\n            Be careful that it will probably be failed to call this\n            method just after calling the \"connect()\" method because\n            the connection is not established yet.\n* \u003cProperty\u003e bConnected\n    Usage : status = obj.bConnected;\n            - status ..... Boolean variable to know now is connected\n                           or not.\n            - obj ........ Variable stocking the object instance\n    Return: True when the connection is established and alive.\n            False when not in the case.\n    Desc. : You can get the current status the connection to the\n            broker is alive or not by reading the property.\n            This property MUST BE a readonly one. So you MUST NOT\n            write the new status into it.\n```\n\n## B. MQTT via HTTP/2\n\nThis is our solution for bi-directional MQTT transmission in HTTP compliance. The basic idea is that.\n\n```\n     +------------------------------------------------+        +---------------+\n     |                                                ---------\u003e Other MQTT    |\n     |                   MQTT broker                  |        | Publishers    |\n     |                                                \u003c--------- / Subscribers |\n     +------|---------------------------A-------------+        +---------------+\n            |                           |\n            |subscribe                  |publish\n            |(MQTT #1883)               |(MQTT #1883)\n            |                           |\n+-----------|---------------------------|------------------+\n|           |            Web Server     |                  |\n|           V                           |                  |\n|  +------------------------+  +------------------------+  |\n|  |     mosquitto_sub      |  |     mosquitto_pub      |  |\n|  |      wrapper CGI       |  |      wrapper CGI       |  |\n|  |\"mqtt_via_http_down.cgi\"|  | \"mqtt_via_http_up.cgi\" |  |\n|  +------------------------+  +------------------------+  |\n|           !                           A                  |\n+-----------!---------------------------!------------------+\n      [.....!...........................!............]\n      [.....!.Server....................!............]  HTTP/2\n      [.....!..-Sent....................!.POST.......]  tunnel\n      [.....!.Events....................!.Method.....] (HTTPS #443)\n      [.....!(countinuous)..............!(one-shot)..]\n      [.....!...........................!............]\n+-----------!---------------------------!------------------+\n|           !            Web Browser    !                  |\n|           V                           !                  |\n|   +---------------------+      +---------------------+   |\n|   | (EventSource class) |      |  (fetch() method )  |   |\n|   +---------------------+      +---------------------+   |\n|           :                           A                  |\n|           V                           :                  |\n|     display the message          push a button           |\n|                                                          |\n+----------------------------------------------------------+\n```\n\n### Server-to-Browser Path (leftside in the figure)\n\nThere are two challenges for web browsers to become an MQTT subscriber. First, how to speak the MQTT protocol, and second, how to do server-push data receiving in HTTP compliance.\n To address the first challenge, the web browser uses a CGI mechanism to request the web server to execute the \"mosquitto_sub\" command. For the second challenge, the web browser uses the EventSource class to request the server to deliver data via Server-Sent Events.\n\n### Browser-to-Server Path (rightside in the figure)\n\nThere is a similar issue with the server-to-browser path as well. That is how to speak the MQTT protocol. Therefore, the web browser utilizes a CGI mechanism by calling the fetch() method to request that the web server execute the \"mosquitto_pub\" command.\n\n### To Reduce the HTTP Costs\n\nThe Server-Sent Events keep the HTTP connection during the MQTT subscription. On the other hand, the fetch() method requires a new HTTP connection for every new message it sends. Both ways require high costs. To make those data transmissions practical, HTTP/2 is necessary.\n\nHTTP/2 can work like a kind of tunnel for traditional HTTP connections. More precisely, a single TCP connection for HTTP/2 can multiplex multiple traditional HTTP connections, each represented as a separate stream. Therefore, HTTP/2 is practically required to make a web browser an MQTT client. And moreover, TLS is also practically required for HTTP/2 because most modern web browsers refuse to enable HTTP/2 over non-TLS connection by security reasons.\n\n### Try the \"Hello, world!\" example\n\nThe best way to understand the solution is and how easy to use is to try the \"Hello, world!\" example! Just after you have done \"git clone\" me, open the \"./public_html/sse/examples/helloworld.html\" with a web browser. Then try each step written in the \"How to Use Me\" section on the web page.\n\n\n## LICENSE\n\nThis is a public-domain software (CC0). It means that all of the people can use this for any purposes with no restrictions at all. By the way, We are fed up with the side effects which are brought about by the major licenses.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshellshoccar-jpn%2Fmqttwrapper","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fshellshoccar-jpn%2Fmqttwrapper","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshellshoccar-jpn%2Fmqttwrapper/lists"}