mqtt 0.0.2 → 0.0.3

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.
data/NEWS CHANGED
@@ -1,5 +1,10 @@
1
1
  = Ruby MQTT NEWS
2
2
 
3
+ == Ruby MQTT Version 0.0.3 (2009-02-08)
4
+
5
+ Added checking of Connection Acknowledgement.
6
+ Automatic client identifier generation.
7
+
3
8
  == Ruby MQTT Version 0.0.2 (2009-02-03)
4
9
 
5
10
  Added support for packets longer than 127 bytes.
data/README CHANGED
@@ -12,24 +12,35 @@ You may get the latest stable version from Rubyforge. Source gems are also avail
12
12
 
13
13
  == Synopsis
14
14
 
15
- require 'rubygems'
16
- require 'mqtt'
15
+ require 'rubygems'
16
+ require 'mqtt'
17
+
18
+ # Publish example
19
+ mqtt = MQTT::Client.new('mqtt.example.com')
20
+ mqtt.connect do |c|
21
+ c.publish('topic','message')
22
+ end
23
+
24
+ # Subscribe example
25
+ mqtt = MQTT::Client.new('mqtt.example.com')
26
+ client.connect do
27
+ client.subscribe('test')
28
+ loop do
29
+ topic,message = client.get
30
+ puts "#{topic}: #{message}"
31
+ end
32
+ end
17
33
 
18
- mqtt = MQTT::Client.new('mqtt.example.com')
19
- mqtt.connect('clientid') do |c|
20
- c.publish('topic','message')
21
- end
22
34
 
23
35
  == TODO
24
36
 
25
37
  * Process acknowledgement packets
26
- * Automatic uninque client identifier if none given
27
38
  * Create classes for each type of packet?
28
39
  * More validations of data/parameters
29
40
  * Implement exception throwing
30
41
  * Implement Will and Testament
31
- * Add unit tests
32
42
  * More examples
43
+ * Integration tests
33
44
  * Refactor to add callbacks that are called from seperate thread
34
45
  * Implement QOS Level 1
35
46
  * Implement QOS Level 2
@@ -37,7 +48,7 @@ You may get the latest stable version from Rubyforge. Source gems are also avail
37
48
 
38
49
  == Resources
39
50
 
40
- http://mqtt.org
51
+ http://www.mqtt.org
41
52
 
42
53
  == Contact
43
54
 
data/Rakefile CHANGED
@@ -8,7 +8,7 @@ require 'spec/rake/verify_rcov'
8
8
 
9
9
 
10
10
  NAME = "mqtt"
11
- VERS = "0.0.2"
11
+ VERS = "0.0.3"
12
12
  CLEAN.include ['pkg', 'rdoc']
13
13
 
14
14
  spec = Gem::Specification.new do |s|
data/examples/livetext.rb CHANGED
@@ -4,15 +4,11 @@ $:.unshift File.dirname(__FILE__)+'/../lib'
4
4
 
5
5
  require 'mqtt'
6
6
 
7
-
8
7
  client = MQTT::Client.new('hadrian.aelius.com')
9
- client.connect('livetextclient')
10
-
11
- client.subscribe('livetext/#')
12
-
13
- loop do
14
- topic,message = client.get
15
- puts "#{topic}: #{message}"
16
- end
17
-
18
- client.disconnect
8
+ client.connect do
9
+ client.subscribe('livetext/#')
10
+ loop do
11
+ topic,message = client.get
12
+ puts "#{topic}: #{message}"
13
+ end
14
+ end
@@ -4,15 +4,11 @@ $:.unshift File.dirname(__FILE__)+'/../lib'
4
4
 
5
5
  require 'mqtt'
6
6
 
7
-
8
7
  client = MQTT::Client.new('mqtt.example.com')
9
- client.connect('simple_get')
10
-
11
- client.subscribe('test')
12
-
13
- loop do
14
- topic,message = client.get
15
- puts "#{topic}: #{message}"
8
+ client.connect do
9
+ client.subscribe('#')
10
+ loop do
11
+ topic,message = client.get
12
+ puts "#{topic}: #{message}"
13
+ end
16
14
  end
17
-
18
- client.disconnect
@@ -5,8 +5,8 @@ $:.unshift File.dirname(__FILE__)+'/../lib'
5
5
  require 'mqtt'
6
6
 
7
7
  client = MQTT::Client.new('mqtt.example.com')
8
- client.connect('simple_publish_example') do |c|
8
+ client.connect do |c|
9
9
 
10
- c.publish('test', 'x' * 300)
10
+ c.publish('test', "The time is: #{Time.now}")
11
11
 
12
12
  end
data/lib/mqtt/client.rb CHANGED
@@ -4,6 +4,7 @@ require 'mqtt'
4
4
  require 'mqtt/packet'
5
5
  require 'thread'
6
6
  require 'socket'
7
+ require 'timeout'
7
8
 
8
9
 
9
10
  module MQTT
@@ -12,8 +13,10 @@ module MQTT
12
13
  class Client
13
14
  attr_reader :remote_host # Hostname of the remote broker
14
15
  attr_reader :remote_port # Port number of the remote broker
15
- attr_accessor :keep_alive # Time between pings to remote broker
16
+ attr_accessor :keep_alive # Time (in seconds) between pings to remote broker
16
17
  attr_accessor :clean_start # Set the 'Clean Start' flag when connecting?
18
+ attr_accessor :client_id # Client Identifier
19
+ attr_accessor :ack_timeout # Number of seconds to wait for acknowledgement packets
17
20
 
18
21
  # Timeout between select polls (in seconds)
19
22
  SELECT_TIMEOUT = 0.5
@@ -22,9 +25,11 @@ module MQTT
22
25
  def initialize(remote_host='localhost', remote_port=1883)
23
26
  @remote_host = remote_host
24
27
  @remote_port = remote_port
25
- @message_id = 0
26
28
  @keep_alive = 10
27
29
  @clean_start = true
30
+ @client_id = random_letters(16)
31
+ @message_id = 0
32
+ @ack_timeout = 5
28
33
  @last_pingreq = Time.now
29
34
  @last_pingresp = Time.now
30
35
  @socket = nil
@@ -35,16 +40,12 @@ module MQTT
35
40
 
36
41
  # Connect to the MQTT broker
37
42
  # If a block is given, then yield to that block and then disconnect again.
38
- def connect(clientid)
43
+ def connect(clientid=nil)
44
+ @client_id = clientid unless clientid.nil?
45
+
39
46
  if not connected?
40
47
  # Create network socket
41
48
  @socket = TCPSocket.new(@remote_host,@remote_port)
42
-
43
- # Start packet reading thread
44
- @read_thread = Thread.new(Thread.current) do |parent|
45
- Thread.current[:parent] = parent
46
- loop { receive_packet }
47
- end
48
49
 
49
50
  # Protocol name and version
50
51
  packet = MQTT::Packet.new(:type => :connect)
@@ -61,10 +62,19 @@ module MQTT
61
62
  packet.add_short(@keep_alive)
62
63
 
63
64
  # Add the client identifier
64
- packet.add_string(clientid)
65
+ packet.add_string(@client_id)
65
66
 
66
67
  # Send packet
67
68
  send_packet(packet)
69
+
70
+ # Receive response
71
+ receive_connack
72
+
73
+ # Start packet reading thread
74
+ @read_thread = Thread.new(Thread.current) do |parent|
75
+ Thread.current[:parent] = parent
76
+ loop { receive_packet }
77
+ end
68
78
  end
69
79
 
70
80
  # If a block is given, then yield and disconnect
@@ -82,7 +92,7 @@ module MQTT
82
92
  packet = MQTT::Packet.new(:type => :disconnect)
83
93
  send_packet(packet)
84
94
  end
85
- @read_thread.kill unless @read_thread.nil?
95
+ @read_thread.kill if @read_thread and @read_thread.alive?
86
96
  @read_thread = nil
87
97
  @socket.close unless @socket.nil?
88
98
  @socket = nil
@@ -222,6 +232,31 @@ module MQTT
222
232
  end
223
233
  end
224
234
 
235
+ # Read and check a connection acknowledgement packet
236
+ def receive_connack
237
+ Timeout.timeout(@ack_timeout) do
238
+ packet = MQTT::Packet.read(@socket)
239
+ if packet.type != :connack
240
+ raise MQTT::ProtocolException.new("Response wan't a connection acknowledgement: #{packet.type}")
241
+ end
242
+
243
+ # Read in the return code
244
+ byte1, return_code = packet.shift_bytes(2)
245
+ if return_code == 0x00
246
+ # Success
247
+ nil
248
+ elsif return_code == 0x01
249
+ raise MQTT::ProtocolException.new("Connection refused: unacceptable protocol version")
250
+ elsif return_code == 0x02
251
+ raise MQTT::ProtocolException.new("Connection refused: client identifier rejected")
252
+ elsif return_code == 0x03
253
+ raise MQTT::ProtocolException.new("Connection refused: broker unavailable")
254
+ else
255
+ raise MQTT::ProtocolException.new("Connection refused: #{return_code}")
256
+ end
257
+ end
258
+ end
259
+
225
260
  # Send a packet to broker
226
261
  def send_packet(data)
227
262
  # Throw exception if we aren't connected
@@ -232,6 +267,24 @@ module MQTT
232
267
  @socket.write(data)
233
268
  end
234
269
  end
270
+
271
+ # Generate a string of random letters (0-9,a-z)
272
+ def random_letters(count)
273
+ str = ''
274
+ count.times do
275
+ num = rand(36)
276
+ if (num<10)
277
+ # Number
278
+ num += 48
279
+ else
280
+ # Letter
281
+ num += 87
282
+ end
283
+ str += num.chr
284
+ end
285
+ return str
286
+ end
287
+
235
288
 
236
289
  end
237
290
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mqtt
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nicholas J Humfrey
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-02-03 00:00:00 +00:00
12
+ date: 2009-02-08 00:00:00 +00:00
13
13
  default_executable:
14
14
  dependencies: []
15
15