mqtt 0.0.2 → 0.0.3

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