mqtt-rails 1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +15 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +4 -0
  5. data/CODE_OF_CONDUCT.md +49 -0
  6. data/Gemfile +4 -0
  7. data/LICENSE +210 -0
  8. data/README.md +323 -0
  9. data/Rakefile +6 -0
  10. data/bin/console +14 -0
  11. data/bin/setup +8 -0
  12. data/lib/mqtt-rails.rb +144 -0
  13. data/lib/mqtt_rails/client.rb +414 -0
  14. data/lib/mqtt_rails/connection_helper.rb +172 -0
  15. data/lib/mqtt_rails/exception.rb +52 -0
  16. data/lib/mqtt_rails/handler.rb +274 -0
  17. data/lib/mqtt_rails/packet.rb +33 -0
  18. data/lib/mqtt_rails/packet/base.rb +315 -0
  19. data/lib/mqtt_rails/packet/connack.rb +102 -0
  20. data/lib/mqtt_rails/packet/connect.rb +183 -0
  21. data/lib/mqtt_rails/packet/disconnect.rb +38 -0
  22. data/lib/mqtt_rails/packet/pingreq.rb +29 -0
  23. data/lib/mqtt_rails/packet/pingresp.rb +38 -0
  24. data/lib/mqtt_rails/packet/puback.rb +44 -0
  25. data/lib/mqtt_rails/packet/pubcomp.rb +44 -0
  26. data/lib/mqtt_rails/packet/publish.rb +148 -0
  27. data/lib/mqtt_rails/packet/pubrec.rb +44 -0
  28. data/lib/mqtt_rails/packet/pubrel.rb +62 -0
  29. data/lib/mqtt_rails/packet/suback.rb +75 -0
  30. data/lib/mqtt_rails/packet/subscribe.rb +124 -0
  31. data/lib/mqtt_rails/packet/unsuback.rb +49 -0
  32. data/lib/mqtt_rails/packet/unsubscribe.rb +84 -0
  33. data/lib/mqtt_rails/publisher.rb +181 -0
  34. data/lib/mqtt_rails/sender.rb +129 -0
  35. data/lib/mqtt_rails/ssl_helper.rb +61 -0
  36. data/lib/mqtt_rails/subscriber.rb +166 -0
  37. data/lib/mqtt_rails/version.rb +3 -0
  38. data/mqtt-rails.gemspec +33 -0
  39. data/samples/client_blocking(reading).rb +29 -0
  40. data/samples/client_blocking(writing).rb +18 -0
  41. data/samples/getting_started.rb +49 -0
  42. data/samples/test_client.rb +69 -0
  43. metadata +126 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: '07387e175ea1e3133f15fb9bce534aab019799ebb6472bbe7d48479cb67b9405'
4
+ data.tar.gz: '0438ddc874e70a232032e23a461081e798d4528191fb821523abd8f5d9a586fb'
5
+ SHA512:
6
+ metadata.gz: d83640e2f6fff6190fe3ab6232d1ab2fc6a6401c4d05cadb17cc6ad9304ea40cf7d80911ae018ddc749cba5436d8566d4278fe755651bd6d239dba6b2eaf44e3
7
+ data.tar.gz: f70787d2ebfa9bb889c7ec8b50103cc0b429e6cf1b736c9aee3290e6d0b0786e96d448cf8fa59896466051915f4ae32f72ee69614d0118dca73c2e9f0a862fd9
data/.gitignore ADDED
@@ -0,0 +1,15 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+
11
+ .idea/
12
+ .rubocop.yml
13
+
14
+ *.gem
15
+ *.log
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2.3
4
+ before_install: gem install bundler -v 1.11.2
@@ -0,0 +1,49 @@
1
+ # Contributor Code of Conduct
2
+
3
+ As contributors and maintainers of this project, and in the interest of
4
+ fostering an open and welcoming community, we pledge to respect all people who
5
+ contribute through reporting issues, posting feature requests, updating
6
+ documentation, submitting pull requests or patches, and other activities.
7
+
8
+ We are committed to making participation in this project a harassment-free
9
+ experience for everyone, regardless of level of experience, gender, gender
10
+ identity and expression, sexual orientation, disability, personal appearance,
11
+ body size, race, ethnicity, age, religion, or nationality.
12
+
13
+ Examples of unacceptable behavior by participants include:
14
+
15
+ * The use of sexualized language or imagery
16
+ * Personal attacks
17
+ * Trolling or insulting/derogatory comments
18
+ * Public or private harassment
19
+ * Publishing other's private information, such as physical or electronic
20
+ addresses, without explicit permission
21
+ * Other unethical or unprofessional conduct
22
+
23
+ Project maintainers have the right and responsibility to remove, edit, or
24
+ reject comments, commits, code, wiki edits, issues, and other contributions
25
+ that are not aligned to this Code of Conduct, or to ban temporarily or
26
+ permanently any contributor for other behaviors that they deem inappropriate,
27
+ threatening, offensive, or harmful.
28
+
29
+ By adopting this Code of Conduct, project maintainers commit themselves to
30
+ fairly and consistently applying these principles to every aspect of managing
31
+ this project. Project maintainers who do not follow or enforce the Code of
32
+ Conduct may be permanently removed from the project team.
33
+
34
+ This code of conduct applies both within project spaces and in public spaces
35
+ when an individual is representing the project or its community.
36
+
37
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
38
+ reported by contacting a project maintainer at p-goudet@ruby-dev.jp. All
39
+ complaints will be reviewed and investigated and will result in a response that
40
+ is deemed necessary and appropriate to the circumstances. Maintainers are
41
+ obligated to maintain confidentiality with regard to the reporter of an
42
+ incident.
43
+
44
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage],
45
+ version 1.3.0, available at
46
+ [http://contributor-covenant.org/version/1/3/0/][version]
47
+
48
+ [homepage]: http://contributor-covenant.org
49
+ [version]: http://contributor-covenant.org/version/1/3/0/
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in MqttRailsRuby.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,210 @@
1
+ Eclipse Public License - v 1.0
2
+
3
+ THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC
4
+ LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM
5
+ CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.
6
+
7
+ 1. DEFINITIONS
8
+
9
+ "Contribution" means:
10
+
11
+ a) in the case of the initial Contributor, the initial code and documentation
12
+ distributed under this Agreement, and
13
+
14
+ b) in the case of each subsequent Contributor:
15
+
16
+ i) changes to the Program, and
17
+
18
+ ii) additions to the Program;
19
+
20
+ where such changes and/or additions to the Program originate from and are
21
+ distributed by that particular Contributor. A Contribution 'originates' from
22
+ a Contributor if it was added to the Program by such Contributor itself or
23
+ anyone acting on such Contributor's behalf. Contributions do not include additions
24
+ to the Program which: (i) are separate modules of software distributed in
25
+ conjunction with the Program under their own license agreement, and (ii) are
26
+ not derivative works of the Program.
27
+
28
+ "Contributor" means any person or entity that distributes the Program.
29
+
30
+ "Licensed Patents" mean patent claims licensable by a Contributor which are
31
+ necessarily infringed by the use or sale of its Contribution alone or when
32
+ combined with the Program.
33
+
34
+ "Program" means the Contributions distributed in accordance with this Agreement.
35
+
36
+ "Recipient" means anyone who receives the Program under this Agreement, including
37
+ all Contributors.
38
+
39
+ 2. GRANT OF RIGHTS
40
+
41
+ a) Subject to the terms of this Agreement, each Contributor hereby grants
42
+ Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce,
43
+ prepare derivative works of, publicly display, publicly perform, distribute
44
+ and sublicense the Contribution of such Contributor, if any, and such derivative
45
+ works, in source code and object code form.
46
+
47
+ b) Subject to the terms of this Agreement, each Contributor hereby grants
48
+ Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed
49
+ Patents to make, use, sell, offer to sell, import and otherwise transfer the
50
+ Contribution of such Contributor, if any, in source code and object code form.
51
+ This patent license shall apply to the combination of the Contribution and
52
+ the Program if, at the time the Contribution is added by the Contributor,
53
+ such addition of the Contribution causes such combination to be covered by
54
+ the Licensed Patents. The patent license shall not apply to any other combinations
55
+ which include the Contribution. No hardware per se is licensed hereunder.
56
+
57
+ c) Recipient understands that although each Contributor grants the licenses
58
+ to its Contributions set forth herein, no assurances are provided by any Contributor
59
+ that the Program does not infringe the patent or other intellectual property
60
+ rights of any other entity. Each Contributor disclaims any liability to Recipient
61
+ for claims brought by any other entity based on infringement of intellectual
62
+ property rights or otherwise. As a condition to exercising the rights and
63
+ licenses granted hereunder, each Recipient hereby assumes sole responsibility
64
+ to secure any other intellectual property rights needed, if any. For example,
65
+ if a third party patent license is required to allow Recipient to distribute
66
+ the Program, it is Recipient's responsibility to acquire that license before
67
+ distributing the Program.
68
+
69
+ d) Each Contributor represents that to its knowledge it has sufficient copyright
70
+ rights in its Contribution, if any, to grant the copyright license set forth
71
+ in this Agreement.
72
+
73
+ 3. REQUIREMENTS
74
+
75
+ A Contributor may choose to distribute the Program in object code form under
76
+ its own license agreement, provided that:
77
+
78
+ a) it complies with the terms and conditions of this Agreement; and
79
+
80
+ b) its license agreement:
81
+
82
+ i) effectively disclaims on behalf of all Contributors all warranties and
83
+ conditions, express and implied, including warranties or conditions of title
84
+ and non-infringement, and implied warranties or conditions of merchantability
85
+ and fitness for a particular purpose;
86
+
87
+ ii) effectively excludes on behalf of all Contributors all liability for damages,
88
+ including direct, indirect, special, incidental and consequential damages,
89
+ such as lost profits;
90
+
91
+ iii) states that any provisions which differ from this Agreement are offered
92
+ by that Contributor alone and not by any other party; and
93
+
94
+ iv) states that source code for the Program is available from such Contributor,
95
+ and informs licensees how to obtain it in a reasonable manner on or through
96
+ a medium customarily used for software exchange.
97
+
98
+ When the Program is made available in source code form:
99
+
100
+ a) it must be made available under this Agreement; and
101
+
102
+ b) a copy of this Agreement must be included with each copy of the Program.
103
+
104
+ Contributors may not remove or alter any copyright notices contained within
105
+ the Program.
106
+
107
+ Each Contributor must identify itself as the originator of its Contribution,
108
+ if any, in a manner that reasonably allows subsequent Recipients to identify
109
+ the originator of the Contribution.
110
+
111
+ 4. COMMERCIAL DISTRIBUTION
112
+
113
+ Commercial distributors of software may accept certain responsibilities with
114
+ respect to end users, business partners and the like. While this license is
115
+ intended to facilitate the commercial use of the Program, the Contributor
116
+ who includes the Program in a commercial product offering should do so in
117
+ a manner which does not create potential liability for other Contributors.
118
+ Therefore, if a Contributor includes the Program in a commercial product offering,
119
+ such Contributor ("Commercial Contributor") hereby agrees to defend and indemnify
120
+ every other Contributor ("Indemnified Contributor") against any losses, damages
121
+ and costs (collectively "Losses") arising from claims, lawsuits and other
122
+ legal actions brought by a third party against the Indemnified Contributor
123
+ to the extent caused by the acts or omissions of such Commercial Contributor
124
+ in connection with its distribution of the Program in a commercial product
125
+ offering. The obligations in this section do not apply to any claims or Losses
126
+ relating to any actual or alleged intellectual property infringement. In order
127
+ to qualify, an Indemnified Contributor must: a) promptly notify the Commercial
128
+ Contributor in writing of such claim, and b) allow the Commercial Contributor
129
+ to control, and cooperate with the Commercial Contributor in, the defense
130
+ and any related settlement negotiations. The Indemnified Contributor may participate
131
+ in any such claim at its own expense.
132
+
133
+ For example, a Contributor might include the Program in a commercial product
134
+ offering, Product X. That Contributor is then a Commercial Contributor. If
135
+ that Commercial Contributor then makes performance claims, or offers warranties
136
+ related to Product X, those performance claims and warranties are such Commercial
137
+ Contributor's responsibility alone. Under this section, the Commercial Contributor
138
+ would have to defend claims against the other Contributors related to those
139
+ performance claims and warranties, and if a court requires any other Contributor
140
+ to pay any damages as a result, the Commercial Contributor must pay those
141
+ damages.
142
+
143
+ 5. NO WARRANTY
144
+
145
+ EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON
146
+ AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS
147
+ OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF
148
+ TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
149
+ Each Recipient is solely responsible for determining the appropriateness of
150
+ using and distributing the Program and assumes all risks associated with its
151
+ exercise of rights under this Agreement, including but not limited to the
152
+ risks and costs of program errors, compliance with applicable laws, damage
153
+ to or loss of data, programs or equipment, and unavailability or interruption
154
+ of operations.
155
+
156
+ 6. DISCLAIMER OF LIABILITY
157
+
158
+ EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY
159
+ CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL,
160
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION
161
+ LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
162
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
163
+ WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS
164
+ GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
165
+
166
+ 7. GENERAL
167
+
168
+ If any provision of this Agreement is invalid or unenforceable under applicable
169
+ law, it shall not affect the validity or enforceability of the remainder of
170
+ the terms of this Agreement, and without further action by the parties hereto,
171
+ such provision shall be reformed to the minimum extent necessary to make such
172
+ provision valid and enforceable.
173
+
174
+ If Recipient institutes patent litigation against any entity (including a
175
+ cross-claim or counterclaim in a lawsuit) alleging that the Program itself
176
+ (excluding combinations of the Program with other software or hardware) infringes
177
+ such Recipient's patent(s), then such Recipient's rights granted under Section
178
+ 2(b) shall terminate as of the date such litigation is filed.
179
+
180
+ All Recipient's rights under this Agreement shall terminate if it fails to
181
+ comply with any of the material terms or conditions of this Agreement and
182
+ does not cure such failure in a reasonable period of time after becoming aware
183
+ of such noncompliance. If all Recipient's rights under this Agreement terminate,
184
+ Recipient agrees to cease use and distribution of the Program as soon as reasonably
185
+ practicable. However, Recipient's obligations under this Agreement and any
186
+ licenses granted by Recipient relating to the Program shall continue and survive.
187
+
188
+ Everyone is permitted to copy and distribute copies of this Agreement, but
189
+ in order to avoid inconsistency the Agreement is copyrighted and may only
190
+ be modified in the following manner. The Agreement Steward reserves the right
191
+ to publish new versions (including revisions) of this Agreement from time
192
+ to time. No one other than the Agreement Steward has the right to modify this
193
+ Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse
194
+ Foundation may assign the responsibility to serve as the Agreement Steward
195
+ to a suitable separate entity. Each new version of the Agreement will be given
196
+ a distinguishing version number. The Program (including Contributions) may
197
+ always be distributed subject to the version of the Agreement under which
198
+ it was received. In addition, after a new version of the Agreement is published,
199
+ Contributor may elect to distribute the Program (including its Contributions)
200
+ under the new version. Except as expressly stated in Sections 2(a) and 2(b)
201
+ above, Recipient receives no rights or licenses to the intellectual property
202
+ of any Contributor under this Agreement, whether expressly, by implication,
203
+ estoppel or otherwise. All rights in the Program not expressly granted under
204
+ this Agreement are reserved.
205
+
206
+ This Agreement is governed by the laws of the State of New York and the intellectual
207
+ property laws of the United States of America. No party to this Agreement
208
+ will bring a legal action under this Agreement more than one year after the
209
+ cause of action arose. Each party waives its rights to a jury trial in any
210
+ resulting litigation.
data/README.md ADDED
@@ -0,0 +1,323 @@
1
+ # MQTT RAILS
2
+
3
+ The following file describes the Paho Mqtt client API for the ruby programming language. It enables applications to connect to an MQTT message broker threw the [MQTT](http://mqtt.org/) protocol (versions 3.1.1). MQTT is a lightweight protocol designed for IoT/M2M. A Mqtt client can connect to a message broker in order to publish and received data contained in short messages. The messages are exchanged on topics where the client has to subscribe for receiving message.
4
+
5
+ Produced by Ruby development Inc.
6
+ ## Contents
7
+ * [Installation](#installation)
8
+ * [Usage](#usage)
9
+ * [Getting started](#getting-started)
10
+ * [Client](#client)
11
+ * [Initialization](#initialization)
12
+ * [Client's parameters](#clients-parameter)
13
+ * [Subscription](#subscription)
14
+ * [Publishing](#publishing)
15
+ * [Connection configuration](#connection-configuration)
16
+ * [Unencrypted mode](#unencrypted-mode)
17
+ * [Encrypted mode](#encrypted-mode)
18
+ * [Persistence](#persistence)
19
+ * [Foreground and Daemon](#foreground-and-daemon)
20
+ * [Control loops](#control-loops)
21
+ * [Reading loop](#reading-loop)
22
+ * [Writing loop](#writing-loop)
23
+ * [Miscellaneous loop](#miscellaneous-loop)
24
+ * [Handlers and Callbacks](#handlers-and-callbacks)
25
+ * [Handlers](#handlers)
26
+ * [Callbacks](#callbacks)
27
+ * [Mosquitto (message broker)](#mosquitto-message-broker)
28
+ * [Thanks](#thanks)
29
+
30
+ ## Installation
31
+
32
+ Add this line to your application's Gemfile:
33
+
34
+ ```ruby
35
+ gem 'mqtt-rails'
36
+ ```
37
+
38
+ And then execute:
39
+
40
+ $ bundle
41
+
42
+ Or install it yourself as:
43
+
44
+ $ gem install mqtt-rails
45
+
46
+ ## Usage
47
+
48
+ ### Getting started
49
+ The following samples files cover the main features of the client:
50
+ ```ruby
51
+ require 'mqtt-rails'
52
+
53
+ ### Create a simple client with default attributes
54
+ client = MqttRails::Client.new
55
+
56
+ ### Register a callback on message event to display messages
57
+ message_counter = 0
58
+ client.on_message do |message|
59
+ puts "Message recieved on topic: #{message.topic}\n>>> #{message.payload}"
60
+ message_counter += 1
61
+ end
62
+
63
+ ### Register a callback on suback to assert the subcription
64
+ waiting_suback = true
65
+ client.on_suback do
66
+ waiting_suback = false
67
+ puts "Subscribed"
68
+ end
69
+
70
+ ### Register a callback for puback event when receiving a puback
71
+ waiting_puback = true
72
+ client.on_puback do
73
+ waiting_puback = false
74
+ puts "Message Acknowledged"
75
+ end
76
+
77
+ ### Connect to the eclipse test server on port 1883 (Unencrypted mode)
78
+ client.connect('iot.eclipse.org', 1883)
79
+
80
+ ### Subscribe to a topic
81
+ client.subscribe(['/paho/ruby/test', 2])
82
+
83
+ ### Waiting for the suback answer and excute the previously set on_suback callback
84
+ while waiting_suback do
85
+ sleep 0.001
86
+ end
87
+
88
+ ### Publlish a message on the topic "/paho/ruby/test" with "retain == false" and "qos == 1"
89
+ client.publish("/paho/ruby/test", "Hello there!", false, 1)
90
+
91
+ while waiting_puback do
92
+ sleep 0.001
93
+ end
94
+
95
+ ### Waiting to assert that the message is displayed by on_message callback
96
+ sleep 1
97
+
98
+ ### Calling an explicit disconnect
99
+ client.disconnect
100
+ ```
101
+
102
+ ## Client
103
+ ### Initialization
104
+ The client may be initialized without paramaeters or with a hash of parameters. The list of client's accessor is details in the next parts. A client id would be generated if not provided, a default port would be also set (8883 if ssl set, else 1883).
105
+ ```ruby
106
+ client = MqttRails::Client.new
107
+ # Or
108
+ client = MqttRails::Client.new({host: "iot.eclispe.org", port: 1883, ssl: false})
109
+ ```
110
+
111
+ ### Client's parameters
112
+ The client has many accessors which help to configure the client depending on user's need. The different accessors could be splited in four roles, connection setup, last will setup, time-out setup and callback setup.
113
+ Connection setup:
114
+ ```
115
+ * host : The endpoint where the client would try to connect (defaut "")
116
+ * port : The port on the remote host where the socket would try to connect (default 1883)
117
+ * mqtt_version : The version of MQTT protocol used to communication (default 3.1.1)
118
+ * clean_session : If set to false, ask the message broker to try to restore the previous session (default true)
119
+ * persistent : Keep the client connected even after keep alive timer run out, automatically try to reconnect on failure (default false)
120
+ * reconnect_limit : If persistent mode is enabled, the maximum reconnect attempt (default 3)
121
+ * reconnect_delay : If persistent mode is enabled, the delay between to reconnection attempt in second (default 5)
122
+ * client_id : The identifier of the client (default nil)
123
+ * username : The username if the server require authentication (default nil)
124
+ * password : The password of the user if authentication required (default nil)
125
+ * ssl : Requiring the encryption for the communication (default false)
126
+ ```
127
+
128
+ Last Will:
129
+ ```
130
+ * will_topic : The topic where to publish the last will (default nil)
131
+ * will_payload : The message of the last will (default "")
132
+ * will_qos : The qos of the last will (default 0)
133
+ * will_retain : The retain status of the last will (default false)
134
+ ```
135
+
136
+ Timers:
137
+ ```
138
+ * keep_alive : The reference timer after which the client should decide to keep the connection alive or not
139
+ * ack_timeout : The timer after which a non-acknowledged packet is considered as a failure
140
+ ```
141
+
142
+ The description of the callback accessor is detailed in the section dedicated to the callbacks. The client also have three read only attributes which provide information on the client state.
143
+ ```
144
+ * registered_callback : The list of topics where callback have been registred which the associated callback
145
+ * subscribed_topics : The list of the topics where the client is currentely receiving publish.
146
+ * connection_state : The current state of the connection between the message broker and the client
147
+ ```
148
+
149
+ ### Subscription
150
+ In order to read a message sent on a topic, the client should subscribe to this topic. The client enables to subscribe to several topics in the same subscribe request. The subscription could also be done by using a wild-card, see more details on [MQTT protocol specifications](http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html). Each topic is subscribed with a maximum qos level, only message with a qos level lower or equal to this value would be forwarded to the client. The subscribe command accepts one or several pair, each pair is composed by the topic (or wild-card) and the maximum qos level.
151
+ ```ruby
152
+ ### Subscribe to two topics with maximum qos associated
153
+ client.subscribe(["/foo/bar", 1], ["/foo/foo/", 2])
154
+ ```
155
+
156
+ The subscription is persistent, in case of an unexpected disconnecting, the current subscription state is saved and a new subscribe request is sent to the message broker.
157
+
158
+ ### Publishing
159
+ User data could be sent to the message broker with the publish operation. A publish operation requires a topic, and payload (user data), two other parameters may be configured, retain and qos. The retain flag tell to the message broker to keep the current publish packet, see the [MQTT protocol specifications](http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html) for more details about retain. The qos enable different levels of control on the transmission of publish package. The MqttRails client supports the three levels of qos (0, 1 and 2), see the [MQTT protocol specifications](http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html) for qos level details. The default retain value is False and the qos level is 0.
160
+ ```ruby
161
+ ### Publish to the topics "/foo/bar", with qos = 1 and no retain
162
+ client.publish("/foo/bar", "Hello Wourld!", false, 1)
163
+ ```
164
+
165
+ ## Connection configuration
166
+ ### Unencrypted mode
167
+ The most simple connection way is the unencrypted mode. All data would be sent clearly to the message broker, also it might not be safe for sensitive data. The connect method may set up or override some parameters of the client, the host, the port, the keep_alive timer, the persistence mode and blocking mode.
168
+ ```ruby
169
+ ### Simply connect to the message broker with default value or pre-set value
170
+ client.connect
171
+ # Or
172
+ ### Connect to the message broker with all parameter
173
+ client.connect("iot.eclipse.org", 1883, client.keep_alive, client.persistent, client.blocking)
174
+ ```
175
+
176
+ ### Encrypted mode
177
+ The client supports the encrypted connection threw tls-ssl socket. In order to use encrypted mode, the ssl flag of the client should be set to True.
178
+ ``` ruby
179
+ ### Set the encryption mode to True
180
+ client.ssl = true
181
+ ### Configure the user SSL key and the certificate
182
+ client.config_ssl_context(certificate_path, key_path)
183
+ client.connect("test.mosquitto.org", 8883)
184
+ ### Or if rootCA is needed
185
+ client.config_ssl_context(certificate_path, key_path, rootCA_path)
186
+ client.connect("test.mosquitto.org", 8884)
187
+ ```
188
+
189
+ ### Persistence
190
+ The client holds a keep_alive timer is the reference time that the connection should be held. The timer is reset every time a new valid packet is received from the message broker. The persistence flag, when set to True, enables the client to be more independent from the keep_alive timer. Just before the keep_alive run out, the client sends a ping request to tell to the message broker that the connection should be kept. The persistent mode also enables the client to automatically reconnect to the message broker after an unexpected failure.
191
+ When the client's persistence flag is set to False, it just simply disconnects when the keep_alive timer runs out.
192
+ ```ruby
193
+ ### This will connect to the message broker, keep connected and automatically reconnect on failure
194
+ client.connect('iot.eclipse.org', 1883, client.keep_alive, true, client.blocking)
195
+ #Or
196
+ ### This only connect to the message broker, disconnect after keep_alive or on failure
197
+ client.connect('iot.eclipse.org', 1883, client.keep_alive, false, client.blocking)
198
+ ```
199
+ The client has two attributes `@reconnect_limit` and `@reconnect_delay` which configure the reconnection process. `@reconnection_limit` is the maximum reconnection attempt that a client could try and `@reconnection_delay` is the delay that the client waits between two reconnection attempt. Setting the `@reconnect_limit` to -1 would run the reconnection process forever.
200
+
201
+ ### Foreground and Daemon
202
+ The client could be connected to the message broker using the main thread in foreground or as a daemon in a separate thread. The default mode is daemon mode, the daemon would run in the background the read/write operation as well as the control of the timers. If the client is connected using the main thread, all control operations are left to the user, using the different control loops. There are four different loop roles is detailed in the next part.
203
+
204
+ ```ruby
205
+ ### Connect to the message broker executing the mqtt_loop (socket reading/writing) in the background
206
+ client.connect('iot.eclipse.org', 1883, client.keep_alive, client.persistence, true)
207
+ #Or
208
+ ### This only connect to the message broker, nothing more
209
+ client.connect('iot.eclipse.org', 1883, client.keep_alive, client.persistence, false)
210
+ ```
211
+
212
+ ## Control loops
213
+ /!\ The control loops should not be used in a daemon mode.
214
+ They are automatically run in separate thread and execute the necessary operations for reading, writing and checking the connection state.
215
+
216
+ ### Reading loop
217
+ The reading loop provides access to the socket in a reading mode. Periodically, the socket would be inspected to try to find a mqtt packet. The read loop accepts a parameter, which is the number of loop's turn. The default value is five turns.
218
+ The default value is defined in the MqttRails module as the constant MqttRails::MAX_READ, another module constant could be modified to control the socket inspection period. The referring constant is SELECT_TIMEOUT (MqttRails::SELECT_TIMEOUT) and its default value is 0.
219
+ ```ruby
220
+ ### Trying to read 'max_packet' packets from the client socket
221
+ client.loop_read(max_packet)
222
+ ```
223
+
224
+ ### Writing loop
225
+ The writing loop send the packets which have previously been stacked by MQTT operations. This loop also accepts a parameter, which is the maximum packets number that could be written as the MAX_WRITING constant (MqttRails::MAX_WRITING). The writing loop exit if the maximum number of packet have been sent or if the waiting packet queue is empty.
226
+ ```ruby
227
+ ### Writing 'max_packet' packets to the client socket
228
+ client.loop_write(max_packet)
229
+ ```
230
+
231
+ ### Miscellaneous loop
232
+ The misc loop performs different control operations, modifying the packets states and the connection state. The misc loop parses the different queue of packet that are waiting for an acknowledgement. If the ack_timeout of a packet had run out, the packet is re-sent. The size of the different waiting queues is defined as module constants. This loop also asserts that the connection is still available by checking the keep_alive timer.
233
+ ```ruby
234
+ ### Perfom control operations on packets queues and connection
235
+ client.loop_misc
236
+ ```
237
+
238
+ ## Handlers and Callbacks
239
+ ### Handlers
240
+ When a packet is received and inspected, an appropriate handler is called. The handler performs different control operation such as update the connection state, update the subscribed topics, and send publish control packets. Each packet has a specific handler, except the pingreq/pingresp packet. Before returning the handler executes a callback, if the user has configured one for this type of packet. The publish handler may execute sequentially two callbacks. One callback for the reception of a generic publish packet and another one, if the user has configured a callback for the topic where the publish packet has been received.
241
+
242
+ ### Callbacks
243
+ The callbacks could be defined in a three different ways, as block, as Proc or as Lambda. The callback has access to the packet which triggered it.
244
+ ```ruby
245
+ ### Register a callback trigger on the reception of a CONNACK packet with return code 0x00
246
+ client.on_connack = proc { puts "Successfully Connected" }
247
+
248
+ ### Register a callback trigger on the reception of PUBLISH packet
249
+ client.on_message do |packet|
250
+ puts "New message received on topic: #{packet.topic}\n>>>#{packet.payload}"
251
+ end
252
+ ```
253
+
254
+ A callback could be configured for every specific topics. The list of topics where a callbacks have been registered could be read at any time, threw the registered_callback variable. The following example details how to manage callbacks for specific topics.
255
+ ```ruby
256
+ ### Add a callback for every message received on /foo/bar
257
+ specific_callback = lambda { |packet| puts "Specific callback for #{packet.topic}" }
258
+ client.add_topic_callback("/foo/bar", specific_callback)
259
+ # Or
260
+ client.add_topic_callback("/foo/bar") do |packet|
261
+ puts "Specific callback for #{packet.topic}"
262
+ end
263
+
264
+ ### To remove a callback form a topic
265
+ client.remove_topic_callback("/foo/bar")
266
+ ```
267
+
268
+ ## Mosquitto (message broker)
269
+ Mosquitto is a message broker support by Eclipse, which is quite easy-going. In order to run spec or samples files, a message broker is needed. Mosquitto enable to run locally a message broker, it could be configured with the mosquitto.conf files.
270
+ ### Install mosquitto
271
+ #### OSX (homebrew)
272
+ ```
273
+ $ brew install mosquitto
274
+ ```
275
+ ### Run mosquitto
276
+ #### Default mode
277
+ The default mode of mosquitto is unencrypted, listening on the port 1883.
278
+ ```
279
+ $ mosquitto
280
+ ```
281
+
282
+ #### Encrypted mode
283
+ In order to successfully pass the spec, or for testing in encrypted mode, some configurations are needed on mosquitto. Private keys and certificates should be set on both client side and server side. The [mosquitto-tls](https://mosquitto.org/man/mosquitto-tls-7.html) page might help you create all the required credentials. Once the credentials are created, the mosquitto's config files should be updated as following.
284
+
285
+ ```
286
+ $ cp mosquitto.conf samples-mosquitto.conf
287
+ $ nano mosquitto.conf
288
+ ```
289
+
290
+ The following file enables the broker to support the unencrypted mode (default) on port 1883, and the encrypted mode on port 8883. Update the path variable with the file's location on your environment.
291
+ ```
292
+ ### mosquitto.conf
293
+ # =================================================================
294
+ # General configuration
295
+ # =================================================================
296
+ .
297
+ .
298
+ .
299
+ # =================================================================
300
+ # Extra listeners
301
+ # =================================================================
302
+ .
303
+ .
304
+ listener 8883
305
+ .
306
+ .
307
+ cafile "Path to the certificate authorithy certificate file"
308
+ certfile "Path to the server certificate file"
309
+ keyfile "Path to the server private keys file"
310
+ .
311
+ .
312
+ .
313
+ ```
314
+ Finally run the server with the updated configuration file.
315
+
316
+ ```
317
+ $ mosquitto -c mosquitto.conf
318
+ ```
319
+
320
+ See [Mosquitto message broker page](https://mosquitto.org/) for more details.
321
+
322
+ ## Thanks
323
+ Special thanks to [Nicholas Humfrey](https://github.com/njh) for providing a great help with the packet serializer/deserializer.