mqtt 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
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: