mqtt 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,15 +1,7 @@
1
1
  ---
2
- !binary "U0hBMQ==":
3
- metadata.gz: !binary |-
4
- Y2MwODVmNmViNWEyM2ViM2NkMDk1ODIzNzg3ZGJiM2EyYTdlZTJlMw==
5
- data.tar.gz: !binary |-
6
- OWI1ZGM5Yzk4OWZiZDBkMDY5ZDM5NTllMWQ3YzRhYTk3NThmNDY3Ng==
2
+ SHA1:
3
+ metadata.gz: b740779b0a3780a38d3c673f47e512201329ccf7
4
+ data.tar.gz: 514676334d05c2affb8371b24d25c635efd829fb
7
5
  SHA512:
8
- metadata.gz: !binary |-
9
- NDg1ZTMxZTdkNjM2ZDk2ZmU0ZGRiYzcyNWI0ZDk1MWI1MGU3OTRmMmI3Yzkx
10
- NmRiYzQ0NmE3NDlhNDQ1MDExNmY2OGM2NzNjYWNlMTAwODc0NDRiNzM3MDU1
11
- YWYxYTYyNDdmZTUxNjI2YjM2ODU2ZTgxMGVhNjM1NjAwOWViY2I=
12
- data.tar.gz: !binary |-
13
- YzkwNjYyYzYxODgyYzZjZWU2MGZhMzQ0YWZhNWM3MTVhNzdjNTFjMjEzYWFj
14
- OGMzN2NlYjNmYTdjYzVmODNhZDZmZGIzMDg4ZjBjYmY5MzljNzRlODljMjI0
15
- NTI3OGRmZDhhODA0NDA2NDI5ZTBlYzhjZWE3MWJhNGQwYzE4OWQ=
6
+ metadata.gz: 162771d3087a48968de71863b569ed455bbc6a7f92a1370175db4237bec9b5625ce6b3b7d0997e98eb625bdd900e14cf564152bf35f48f04ea76f857dd3066e3
7
+ data.tar.gz: 2fa7f6b485082a7f830a063e5a829147ad419566b3ffe0d90a82e8024906b9d37861e97fe779f59fb3230d8309312f0fd17a4e3dd817dd4593dfdab697c03a67
data/NEWS.md CHANGED
@@ -1,6 +1,21 @@
1
1
  Ruby MQTT NEWS
2
2
  ==============
3
3
 
4
+ Ruby MQTT Version 0.5.0 (2016-04-16)
5
+ ------------------------------------
6
+
7
+ * Switched default protocol version to 3.1.1
8
+ * Added support for Server Name Identification (SNI)
9
+ * Fix for unescaping user/password in URI
10
+ * Fix for bug in MQTT::Proxy class
11
+ * Add the ability to ignore retained packets when subscribed.
12
+ * Fix problem of wrong Puback packet ID
13
+ * Don't keepalive ping if disconnected
14
+ * Immediately close socket after failed Connack
15
+ * FakeServer improvements
16
+ * Fix for working with mathn library.
17
+
18
+
4
19
  Ruby MQTT Version 0.4.0 (2016-06-27)
5
20
  ------------------------------------
6
21
 
@@ -10,7 +10,7 @@ class MQTT::Client
10
10
  # Port number of the remote server
11
11
  attr_accessor :port
12
12
 
13
- # The version number of the MQTT protocol to use (default 3.1.0)
13
+ # The version number of the MQTT protocol to use (default 3.1.1)
14
14
  attr_accessor :version
15
15
 
16
16
  # Set to true to enable SSL/TLS encrypted communication
@@ -64,7 +64,7 @@ class MQTT::Client
64
64
  ATTR_DEFAULTS = {
65
65
  :host => nil,
66
66
  :port => nil,
67
- :version => '3.1.0',
67
+ :version => '3.1.1',
68
68
  :keep_alive => 15,
69
69
  :clean_session => true,
70
70
  :client_id => nil,
@@ -264,6 +264,12 @@ class MQTT::Client
264
264
 
265
265
  @socket = OpenSSL::SSL::SSLSocket.new(tcp_socket, ssl_context)
266
266
  @socket.sync_close = true
267
+
268
+ # Set hostname on secure socket for Server Name Indication (SNI)
269
+ if @socket.respond_to?(:hostname=)
270
+ @socket.hostname = @host
271
+ end
272
+
267
273
  @socket.connect
268
274
  else
269
275
  @socket = tcp_socket
@@ -393,15 +399,17 @@ class MQTT::Client
393
399
  # # Do stuff here
394
400
  # end
395
401
  #
396
- def get(topic=nil)
402
+ def get(topic=nil, options={})
397
403
  if block_given?
398
404
  get_packet(topic) do |packet|
399
- yield(packet.topic, packet.payload)
405
+ yield(packet.topic, packet.payload) unless packet.retain && options[:omit_retained]
400
406
  end
401
407
  else
402
- # Wait for one packet to be available
403
- packet = get_packet(topic)
404
- return packet.topic, packet.payload
408
+ loop do
409
+ # Wait for one packet to be available
410
+ packet = get_packet(topic)
411
+ return packet.topic, packet.payload unless packet.retain && options[:omit_retained]
412
+ end
405
413
  end
406
414
  end
407
415
 
@@ -500,7 +508,7 @@ private
500
508
  end
501
509
 
502
510
  def keep_alive!
503
- if @keep_alive > 0
511
+ if @keep_alive > 0 && connected?
504
512
  response_timeout = (@keep_alive * 1.5).ceil
505
513
  if Time.now >= @last_ping_request + @keep_alive
506
514
  packet = MQTT::Packet::Pingreq.new
@@ -530,6 +538,9 @@ private
530
538
 
531
539
  # Check the return code
532
540
  if packet.return_code != 0x00
541
+ # 3.2.2.3 If a server sends a CONNACK packet containing a non-zero
542
+ # return code it MUST then close the Network Connection
543
+ @socket.close
533
544
  raise MQTT::ProtocolException.new(packet.return_msg)
534
545
  end
535
546
  end
@@ -560,8 +571,8 @@ private
560
571
  {
561
572
  :host => uri.host,
562
573
  :port => uri.port || nil,
563
- :username => uri.user,
564
- :password => uri.password,
574
+ :username => uri.user ? URI.unescape(uri.user) : nil,
575
+ :password => uri.password ? URI.unescape(uri.password) : nil,
565
576
  :ssl => ssl
566
577
  }
567
578
  end
@@ -194,7 +194,7 @@ module MQTT
194
194
  # Build up the body length field bytes
195
195
  begin
196
196
  digit = (body_length % 128)
197
- body_length = (body_length / 128)
197
+ body_length = body_length.div(128)
198
198
  # if there are more digits to encode, set the top bit of this digit
199
199
  digit |= 0x80 if (body_length > 0)
200
200
  header.push(digit)
@@ -95,19 +95,19 @@ class MQTT::Proxy
95
95
  # Iterate through each of the sockets with data to read
96
96
  if selected[0].include?(client_socket)
97
97
  packet = MQTT::Packet.read(client_socket)
98
- logger.debug "client -> <#{packet.type}>"
98
+ logger.debug "client -> <#{packet.type_name}>"
99
99
  packet = @client_filter.call(packet) unless @client_filter.nil?
100
100
  unless packet.nil?
101
101
  server_socket.write(packet)
102
- logger.debug "<#{packet.type}> -> server"
102
+ logger.debug "<#{packet.type_name}> -> server"
103
103
  end
104
104
  elsif selected[0].include?(server_socket)
105
105
  packet = MQTT::Packet.read(server_socket)
106
- logger.debug "server -> <#{packet.type}>"
106
+ logger.debug "server -> <#{packet.type_name}>"
107
107
  packet = @server_filter.call(packet) unless @server_filter.nil?
108
108
  unless packet.nil?
109
109
  client_socket.write(packet)
110
- logger.debug "<#{packet.type}> -> client"
110
+ logger.debug "<#{packet.type_name}> -> client"
111
111
  end
112
112
  else
113
113
  logger.error "Problem with select: socket is neither server or client"
@@ -1,4 +1,4 @@
1
1
  module MQTT
2
2
  # The version number of the MQTT gem
3
- VERSION = "0.4.0"
3
+ VERSION = "0.5.0"
4
4
  end
@@ -28,7 +28,7 @@ describe MQTT::Client do
28
28
  client = MQTT::Client.new
29
29
  expect(client.host).to eq(nil)
30
30
  expect(client.port).to eq(1883)
31
- expect(client.version).to eq('3.1.0')
31
+ expect(client.version).to eq('3.1.1')
32
32
  expect(client.keep_alive).to eq(15)
33
33
  end
34
34
 
@@ -117,6 +117,22 @@ describe MQTT::Client do
117
117
  expect(client.password).to eq('bpass')
118
118
  end
119
119
 
120
+ it "with a URI containing an escaped username and password" do
121
+ client = MQTT::Client.new(URI.parse('mqtt://foo%20bar:%40123%2B%25@mqtt.example.com'))
122
+ expect(client.host).to eq('mqtt.example.com')
123
+ expect(client.port).to eq(1883)
124
+ expect(client.username).to eq('foo bar')
125
+ expect(client.password).to eq('@123+%')
126
+ end
127
+
128
+ it "with a URI containing a double escaped username and password" do
129
+ client = MQTT::Client.new(URI.parse('mqtt://foo%2520bar:123%2525@mqtt.example.com'))
130
+ expect(client.host).to eq('mqtt.example.com')
131
+ expect(client.port).to eq(1883)
132
+ expect(client.username).to eq('foo%20bar')
133
+ expect(client.password).to eq('123%25')
134
+ end
135
+
120
136
  it "with a URI as a string" do
121
137
  client = MQTT::Client.new('mqtt://mqtt.example.com')
122
138
  expect(client.host).to eq('mqtt.example.com')
@@ -175,7 +191,7 @@ describe MQTT::Client do
175
191
  expect(client.ssl_context.cert).to be_a(OpenSSL::X509::Certificate)
176
192
  end
177
193
  end
178
-
194
+
179
195
  describe "setting a client private key file path" do
180
196
  it "should add a certificate to the SSL context" do
181
197
  expect(client.ssl_context.key).to be_nil
@@ -323,9 +339,9 @@ describe MQTT::Client do
323
339
  client.password = 'password'
324
340
  client.connect('myclient')
325
341
  expect(socket.string).to eq(
326
- "\x10\x2A"+
327
- "\x00\x06MQIsdp"+
328
- "\x03\xC2\x00\x0f"+
342
+ "\x10\x28"+
343
+ "\x00\x04MQTT"+
344
+ "\x04\xC2\x00\x0f"+
329
345
  "\x00\x08myclient"+
330
346
  "\x00\x08username"+
331
347
  "\x00\x08password"
@@ -403,6 +419,15 @@ describe MQTT::Client do
403
419
  allow(client).to receive(:receive_connack)
404
420
  client.connect
405
421
  end
422
+
423
+ it "should use set hostname on the SSL socket for SNI" do
424
+ expect(OpenSSL::SSL::SSLSocket).to receive(:new).and_return(ssl_socket)
425
+ expect(ssl_socket).to receive(:hostname=).with('mqtt.example.com')
426
+
427
+ client = MQTT::Client.new('mqtts://mqtt.example.com')
428
+ allow(client).to receive(:receive_connack)
429
+ client.connect
430
+ end
406
431
  end
407
432
 
408
433
  context "with a last will and testament set" do
@@ -429,9 +454,9 @@ describe MQTT::Client do
429
454
  it "should include the will in the CONNECT message" do
430
455
  client.connect('myclient')
431
456
  expect(socket.string).to eq(
432
- "\x10\x24"+
433
- "\x00\x06MQIsdp"+
434
- "\x03\x0e\x00\x0f"+
457
+ "\x10\x22"+
458
+ "\x00\x04MQTT"+
459
+ "\x04\x0e\x00\x0f"+
435
460
  "\x00\x08myclient"+
436
461
  "\x00\x05topic\x00\x05hello"
437
462
  )
@@ -473,6 +498,7 @@ describe MQTT::Client do
473
498
  socket.write("\x20\x02\x00\x00")
474
499
  socket.rewind
475
500
  expect { client.send(:receive_connack) }.not_to raise_error
501
+ expect(socket).not_to be_closed
476
502
  end
477
503
 
478
504
  it "should raise an exception if the packet type isn't CONNACK" do
@@ -504,6 +530,13 @@ describe MQTT::Client do
504
530
  socket.rewind
505
531
  expect { client.send(:receive_connack) }.to raise_error(MQTT::ProtocolException, /connection refused/i)
506
532
  end
533
+
534
+ it "should close the socket for an unsuccessful CONNACK packet" do
535
+ socket.write("\x20\x02\x00\x05")
536
+ socket.rewind
537
+ expect { client.send(:receive_connack) }.to raise_error(MQTT::ProtocolException, /not authorised/i)
538
+ expect(socket).to be_closed
539
+ end
507
540
  end
508
541
 
509
542
  describe "when calling the 'disconnect' method" do
@@ -595,7 +628,7 @@ describe MQTT::Client do
595
628
  it "correctly assigns consecutive ids to packets with QoS 1" do
596
629
  inject_puback(1)
597
630
  inject_puback(2)
598
-
631
+
599
632
  expect(client).to receive(:send_packet) { |packet| expect(packet.id).to eq(1) }
600
633
  client.publish "topic", "message", false, 1
601
634
  expect(client).to receive(:send_packet) { |packet| expect(packet.id).to eq(2) }
@@ -677,6 +710,15 @@ describe MQTT::Client do
677
710
  expect(client.queue_empty?).to be_truthy
678
711
  end
679
712
 
713
+ it "should successfully receive a valid PUBLISH packet, but not return it, if omit_retained is set" do
714
+ inject_packet(:topic => 'topic1', :payload => 'payload1', :qos => 1, :retain => 1)
715
+ inject_packet(:topic => 'topic1', :payload => 'payload2', :qos => 1)
716
+ topic,payload = client.get(nil, :omit_retained => true)
717
+ expect(topic).to eq('topic1')
718
+ expect(payload).to eq('payload2')
719
+ expect(client.queue_empty?).to be_truthy
720
+ end
721
+
680
722
  it "acks calling #get_packet and qos=1" do
681
723
  inject_packet(:topic => 'topic1', :payload => 'payload1', :qos => 1)
682
724
  expect(client).to receive(:send_packet).with(an_instance_of(MQTT::Packet::Puback))
@@ -712,6 +754,18 @@ describe MQTT::Client do
712
754
  break if payloads.size > 1
713
755
  end
714
756
  end
757
+
758
+ it "should ignore a PUBLISH message when it is marked as retained and omit_retained is set" do
759
+ inject_packet(:topic => 'topic0', :payload => 'payload0', :retain => 1)
760
+ inject_packet(:topic => 'topic1', :payload => 'payload1')
761
+ payloads = []
762
+ client.get(nil, :omit_retained => true) do |topic,payload|
763
+ payloads << payload
764
+ break if payloads.size > 0
765
+ end
766
+ expect(payloads.size).to eq(1)
767
+ expect(payloads).to eq(['payload1'])
768
+ end
715
769
  end
716
770
  end
717
771
 
@@ -845,6 +899,13 @@ describe MQTT::Client do
845
899
  /No Ping Response received for \d+ seconds/
846
900
  )
847
901
  end
902
+
903
+ it "should not raise an exception if no ping response received and client is disconnected" do
904
+ client.instance_variable_set('@last_ping_request', Time.now)
905
+ client.instance_variable_set('@last_ping_response', Time.at(0))
906
+ client.disconnect(false)
907
+ client.send('keep_alive!')
908
+ end
848
909
  end
849
910
 
850
911
  describe "generating a client identifier" do
@@ -24,9 +24,13 @@ describe "a client talking to a server" do
24
24
  end
25
25
 
26
26
  context "connecting and publishing a packet" do
27
- def connect_and_publish
27
+ def connect_and_publish(options = {})
28
28
  @client.connect
29
- @client.publish('test', 'foobar')
29
+
30
+ retain = options.fetch(:retain) { false }
31
+ qos = options.fetch(:qos) { 0 }
32
+
33
+ @client.publish('test', 'foobar', retain, qos)
30
34
  @client.disconnect
31
35
  @server.thread.join(1)
32
36
  end
@@ -50,6 +54,13 @@ describe "a client talking to a server" do
50
54
  connect_and_publish
51
55
  expect(@error_log.string).to be_empty
52
56
  end
57
+
58
+ context "with qos > 0" do
59
+ it "the server should have received a packet without timeout" do
60
+ connect_and_publish(:qos => 1)
61
+ expect(@server.last_publish).not_to be_nil
62
+ end
63
+ end
53
64
  end
54
65
 
55
66
  context "connecting, subscribing to a topic and getting a message" do
metadata CHANGED
@@ -1,83 +1,83 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mqtt
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nicholas J Humfrey
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-06-27 00:00:00.000000000 Z
11
+ date: 2017-04-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ! '>='
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
19
  version: 1.11.2
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ! '>='
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: 1.11.2
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ~>
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: 0.9.6
33
+ version: 10.2.2
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - ~>
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: 0.9.6
40
+ version: 10.2.2
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: yard
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - ~>
45
+ - - ">="
46
46
  - !ruby/object:Gem::Version
47
- version: 0.8.0
47
+ version: 0.8.7
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - ~>
52
+ - - ">="
53
53
  - !ruby/object:Gem::Version
54
- version: 0.8.0
54
+ version: 0.8.7
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: rspec
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - ~>
59
+ - - ">="
60
60
  - !ruby/object:Gem::Version
61
- version: 3.0.0
61
+ version: 3.5.0
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - ~>
66
+ - - ">="
67
67
  - !ruby/object:Gem::Version
68
- version: 3.0.0
68
+ version: 3.5.0
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: simplecov
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - ~>
73
+ - - ">="
74
74
  - !ruby/object:Gem::Version
75
75
  version: 0.9.2
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - ~>
80
+ - - ">="
81
81
  - !ruby/object:Gem::Version
82
82
  version: 0.9.2
83
83
  description: Pure Ruby gem that implements the MQTT protocol, a lightweight protocol
@@ -113,17 +113,17 @@ require_paths:
113
113
  - lib
114
114
  required_ruby_version: !ruby/object:Gem::Requirement
115
115
  requirements:
116
- - - ! '>='
116
+ - - ">="
117
117
  - !ruby/object:Gem::Version
118
118
  version: '0'
119
119
  required_rubygems_version: !ruby/object:Gem::Requirement
120
120
  requirements:
121
- - - ! '>='
121
+ - - ">="
122
122
  - !ruby/object:Gem::Version
123
123
  version: '0'
124
124
  requirements: []
125
125
  rubyforge_project: mqtt
126
- rubygems_version: 2.5.2
126
+ rubygems_version: 2.4.5
127
127
  signing_key:
128
128
  specification_version: 4
129
129
  summary: Implementation of the MQTT protocol
@@ -134,4 +134,3 @@ test_files:
134
134
  - spec/mqtt_sn_packet_spec.rb
135
135
  - spec/mqtt_version_spec.rb
136
136
  - spec/zz_client_integration_spec.rb
137
- has_rdoc: