StompMq 0.1

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/README ADDED
File without changes
data/lib/stompmq.rb ADDED
@@ -0,0 +1,2 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
2
+ require 'stompmq/connection'
@@ -0,0 +1,131 @@
1
+ require 'socket'
2
+ require 'stompmq/frame'
3
+ require 'stompmq/message'
4
+
5
+ module StompMq
6
+ class InvalidFrameType < StandardError; end
7
+ class CorruptFrame < StandardError; end
8
+ class CorruptHeader < StandardError; end
9
+ class ProtocolSequenceViolation < StandardError; end
10
+ class StompErrorReceived < StandardError; end
11
+
12
+ # Represents a connection to a STOMP message broker.
13
+ class Connection
14
+ # Connect to a STOMP broker and log in.
15
+ def initialize(opts = { :broker => 'localhost', :port => 61613, :username => nil, :passcode => nil })
16
+ @buffer = ""
17
+ @broker = opts[:broker]
18
+ @port = opts[:port]
19
+ @username = opts[:username]
20
+ @passcode = opts[:passcode]
21
+ @sock = TCPSocket.new @broker, @port
22
+ send_frame :connect, {:login => @username, :passcode => @passcode}
23
+ frame = receive_frame(15)
24
+ raise ProtocolSequenceViolation unless frame.cmd == 'CONNECTED'
25
+ self
26
+ end
27
+
28
+ # Subscribe to a STOMP queue.
29
+ def subscribe(opts = { :queue => nil })
30
+ queue = opts[:queue]
31
+ send_frame :subscribe, {:destination => queue}
32
+ end
33
+
34
+ # Send a STOMP message to a queue.
35
+ def send_message(opts = { :queue => nil, :header => {}, :content => {} })
36
+ queue = args[:queue]
37
+ content = args[:content]
38
+ header = args[:header]
39
+
40
+ header = {:destination => queue}.merge(header)
41
+ send_frame :send, header, content
42
+ end
43
+
44
+ # Receive a STOMP message.
45
+ def receive_message(timeout = 0)
46
+ frame = receive_frame(timeout)
47
+ return nil if !frame
48
+ raise StompErrorReceived.new(frame.content) if frame.cmd == 'ERROR'
49
+ raise ProtocolSequenceViolation unless frame.cmd == 'MESSAGE'
50
+ StompMq::Message.new(frame.header, frame.content)
51
+ end
52
+
53
+ private
54
+
55
+ # Transmit a standard STOMP frame.
56
+ def send_frame(function, header = {}, content = {})
57
+ frame = "#{function.to_s.upcase}\n"
58
+ header['content-length'] = content.to_s.length
59
+ header.each do |key, val|
60
+ frame += "#{key.to_s}:#{val.to_s}\n"
61
+ end
62
+ frame += "\n"
63
+ frame += "#{content.to_s}\000"
64
+ @sock.puts(frame)
65
+ end
66
+
67
+ # Receive a standard STOMP frame.
68
+ def receive_frame(timeout = 0)
69
+ receive_data(timeout)
70
+ parse_frame
71
+ end
72
+
73
+ # Receive data waiting on a socket. If timeout is passed, block for this many seconds,
74
+ # otherwise don't block, return nil if no frame is waiting.
75
+ def receive_data(timeout = 0)
76
+ sock_ready = select([@sock], nil, nil, timeout)
77
+ return nil if !sock_ready
78
+ @buffer += @sock.recv(1024)
79
+ end
80
+
81
+ # Parse the instance buffer and pick out one frame. If one entire frame is not available
82
+ # in the buffer, returns nil.
83
+ def parse_frame
84
+ return nil if !@buffer["\000"]
85
+
86
+ cmd = header_text = nil
87
+ @buffer.lstrip!
88
+ raise CorruptFrame.new("No end to header found.") unless @buffer.include?("\n\n")
89
+ begin
90
+ cmd = @buffer.slice!(0..@buffer.index("\n")).chomp
91
+ header_text = @buffer.slice!(0..@buffer.index("\n\n")+1).chomp
92
+ rescue ArgumentError
93
+ raise CorruptFrame.new
94
+ end
95
+ raise CorruptHeader.new("Found null in header.") if header_text.include?("\000")
96
+
97
+ # split the header text up into a proper hash
98
+ header = {}
99
+ header_text.split("\n").each do |keyval|
100
+ key,val = keyval.split(':')
101
+ header[key] = val
102
+ end
103
+
104
+ # content runs until the first null, or per the content-length header if present.
105
+ content_length = @buffer.index("\000")
106
+ content_length = header['content-length'].to_i if header['content-length']
107
+ content = ''
108
+ if(@buffer.length) < content_length then
109
+ # turns out we don't have a full frame after all! push the cmd/header back in.
110
+ @buffer = "#{cmd}\n#{header_text}\n\n#{buffer}"
111
+ return nil
112
+ puts "NIL!"
113
+ end
114
+ if(content_length > 0) then
115
+ content = @buffer[0..content_length-1]
116
+ @buffer[0..content_length] = ''
117
+ else
118
+ content = nil
119
+ @buffer[0] = ''
120
+ end
121
+
122
+ raise InvalidFrameType.new unless ['CONNECTED', 'RECEIPT', 'MESSAGE', 'ERROR'].include?(cmd)
123
+
124
+ return StompMq::Frame.new(cmd, header, content)
125
+ end
126
+
127
+ def buffer=(buffer)
128
+ @buffer = buffer
129
+ end
130
+ end
131
+ end
@@ -0,0 +1,12 @@
1
+ module StompMq
2
+ # Holds a STOMP frame of any type.
3
+ class Frame
4
+ attr_reader :cmd, :header, :content
5
+
6
+ def initialize(cmd, header, content)
7
+ @cmd = cmd
8
+ @header = header
9
+ @content = content
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,11 @@
1
+ module StompMq
2
+ # Holds a STOMP message.
3
+ class Message
4
+ attr_reader :header, :content
5
+
6
+ def initialize(header, content)
7
+ @header = header
8
+ @content = content
9
+ end
10
+ end
11
+ end
metadata ADDED
@@ -0,0 +1,58 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: StompMq
3
+ version: !ruby/object:Gem::Version
4
+ version: "0.1"
5
+ platform: ruby
6
+ authors:
7
+ - Sarah Nordstrom
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2008-09-01 00:00:00 -04:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description:
17
+ email: sarahemm@sarahemm.net
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - README
24
+ files:
25
+ - lib/stompmq
26
+ - lib/stompmq/connection.rb
27
+ - lib/stompmq/frame.rb
28
+ - lib/stompmq/message.rb
29
+ - lib/stompmq.rb
30
+ - README
31
+ has_rdoc: true
32
+ homepage: http://www.rubyforge.org/stompmq/
33
+ post_install_message:
34
+ rdoc_options: []
35
+
36
+ require_paths:
37
+ - lib
38
+ required_ruby_version: !ruby/object:Gem::Requirement
39
+ requirements:
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ version: "0"
43
+ version:
44
+ required_rubygems_version: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: "0"
49
+ version:
50
+ requirements: []
51
+
52
+ rubyforge_project: stompmq
53
+ rubygems_version: 1.0.1
54
+ signing_key:
55
+ specification_version: 2
56
+ summary: Support for the STOMP messaging protocol in Ruby.
57
+ test_files: []
58
+