celldee-bunny 0.2.0 → 0.3.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.
@@ -1,274 +0,0 @@
1
- if [].map.respond_to? :with_index
2
- class Array #:nodoc:
3
- def enum_with_index
4
- each.with_index
5
- end
6
- end
7
- else
8
- require 'enumerator'
9
- end
10
-
11
- module Transport
12
- class Buffer #:nodoc: all
13
-
14
- def initialize data = ''
15
- @data = data
16
- @pos = 0
17
- end
18
-
19
- attr_reader :pos
20
-
21
- def data
22
- @data.clone
23
- end
24
- alias :contents :data
25
- alias :to_s :data
26
-
27
- def << data
28
- @data << data.to_s
29
- self
30
- end
31
-
32
- def length
33
- @data.length
34
- end
35
-
36
- def empty?
37
- pos == length
38
- end
39
-
40
- def rewind
41
- @pos = 0
42
- end
43
-
44
- def read_properties *types
45
- types.shift if types.first == :properties
46
-
47
- i = 0
48
- values = []
49
-
50
- while props = read(:short)
51
- (0..14).each do |n|
52
- # no more property types
53
- break unless types[i]
54
-
55
- # if flag is set
56
- if props & (1<<(15-n)) != 0
57
- if types[i] == :bit
58
- # bit values exist in flags only
59
- values << true
60
- else
61
- # save type name for later reading
62
- values << types[i]
63
- end
64
- else
65
- # property not set or is false bit
66
- values << (types[i] == :bit ? false : nil)
67
- end
68
-
69
- i+=1
70
- end
71
-
72
- # bit(0) == 0 means no more property flags
73
- break unless props & 1 == 1
74
- end
75
-
76
- values.map do |value|
77
- value.is_a?(Symbol) ? read(value) : value
78
- end
79
- end
80
-
81
- def read *types
82
- if types.first == :properties
83
- return read_properties(*types)
84
- end
85
-
86
- values = types.map do |type|
87
- case type
88
- when :octet
89
- _read(1, 'C')
90
- when :short
91
- _read(2, 'n')
92
- when :long
93
- _read(4, 'N')
94
- when :longlong
95
- upper, lower = _read(8, 'NN')
96
- upper << 32 | lower
97
- when :shortstr
98
- _read read(:octet)
99
- when :longstr
100
- _read read(:long)
101
- when :timestamp
102
- Time.at read(:longlong)
103
- when :table
104
- t = Hash.new
105
-
106
- table = Buffer.new(read(:longstr))
107
- until table.empty?
108
- key, type = table.read(:shortstr, :octet)
109
- key = key.intern
110
- t[key] ||= case type
111
- when 83 # 'S'
112
- table.read(:longstr)
113
- when 73 # 'I'
114
- table.read(:long)
115
- when 68 # 'D'
116
- exp = table.read(:octet)
117
- num = table.read(:long)
118
- num / 10.0**exp
119
- when 84 # 'T'
120
- table.read(:timestamp)
121
- when 70 # 'F'
122
- table.read(:table)
123
- end
124
- end
125
-
126
- t
127
- when :bit
128
- if (@bits ||= []).empty?
129
- val = read(:octet)
130
- @bits = (0..7).map{|i| (val & 1<<i) != 0 }
131
- end
132
-
133
- @bits.shift
134
- else
135
- raise API::InvalidTypeError, "Cannot read data of type #{type}"
136
- end
137
- end
138
-
139
- types.size == 1 ? values.first : values
140
- end
141
-
142
- def write type, data
143
- case type
144
- when :octet
145
- _write(data, 'C')
146
- when :short
147
- _write(data, 'n')
148
- when :long
149
- _write(data, 'N')
150
- when :longlong
151
- lower = data & 0xffffffff
152
- upper = (data & ~0xffffffff) >> 32
153
- _write([upper, lower], 'NN')
154
- when :shortstr
155
- data = (data || '').to_s
156
- _write([data.length, data], 'Ca*')
157
- when :longstr
158
- if data.is_a? Hash
159
- write(:table, data)
160
- else
161
- data = (data || '').to_s
162
- _write([data.length, data], 'Na*')
163
- end
164
- when :timestamp
165
- write(:longlong, data.to_i)
166
- when :table
167
- data ||= {}
168
- write :longstr, (data.inject(Buffer.new) do |table, (key, value)|
169
- table.write(:shortstr, key.to_s)
170
-
171
- case value
172
- when String
173
- table.write(:octet, 83) # 'S'
174
- table.write(:longstr, value.to_s)
175
- when Fixnum
176
- table.write(:octet, 73) # 'I'
177
- table.write(:long, value)
178
- when Float
179
- table.write(:octet, 68) # 'D'
180
- # XXX there's gotta be a better way to do this..
181
- exp = value.to_s.split('.').last.length
182
- num = value * 10**exp
183
- table.write(:octet, exp)
184
- table.write(:long, num)
185
- when Time
186
- table.write(:octet, 84) # 'T'
187
- table.write(:timestamp, value)
188
- when Hash
189
- table.write(:octet, 70) # 'F'
190
- table.write(:table, value)
191
- end
192
-
193
- table
194
- end)
195
- when :bit
196
- [*data].to_enum(:each_slice, 8).each{|bits|
197
- write(:octet, bits.enum_with_index.inject(0){ |byte, (bit, i)|
198
- byte |= 1<<i if bit
199
- byte
200
- })
201
- }
202
- when :properties
203
- values = []
204
- data.enum_with_index.inject(0) do |short, ((type, value), i)|
205
- n = i % 15
206
- last = i+1 == data.size
207
-
208
- if (n == 0 and i != 0) or last
209
- if data.size > i+1
210
- short |= 1<<0
211
- elsif last and value
212
- values << [type,value]
213
- short |= 1<<(15-n)
214
- end
215
-
216
- write(:short, short)
217
- short = 0
218
- end
219
-
220
- if value and !last
221
- values << [type,value]
222
- short |= 1<<(15-n)
223
- end
224
-
225
- short
226
- end
227
-
228
- values.each do |type, value|
229
- write(type, value) unless type == :bit
230
- end
231
- else
232
- raise API::InvalidTypeError, "Cannot write data of type #{type}"
233
- end
234
-
235
- self
236
- end
237
-
238
- def extract
239
- begin
240
- cur_data, cur_pos = @data.clone, @pos
241
- yield self
242
- rescue API::BufferOverflowError
243
- @data, @pos = cur_data, cur_pos
244
- nil
245
- end
246
- end
247
-
248
- def _read(size, pack = nil)
249
- if @data.is_a?(API::Client)
250
- raw = @data.read(size)
251
- return raw if raw.nil? or pack.nil?
252
- return raw.unpack(pack).first
253
- end
254
-
255
- if @pos + size > length
256
- raise API::BufferOverflowError
257
- else
258
- data = @data[@pos,size]
259
- @data[@pos,size] = ''
260
- if pack
261
- data = data.unpack(pack)
262
- data = data.pop if data.size == 1
263
- end
264
- data
265
- end
266
- end
267
-
268
- def _write data, pack = nil
269
- data = [*data].pack(pack) if pack
270
- @data[@pos,0] = data
271
- @pos += data.length
272
- end
273
- end
274
- end
@@ -1,61 +0,0 @@
1
- module Transport
2
-
3
- class Frame #:nodoc: all
4
- def initialize payload = nil, channel = 0
5
- @channel, @payload = channel, payload
6
- end
7
- attr_accessor :channel, :payload
8
-
9
- def id
10
- self.class::ID
11
- end
12
-
13
- def to_binary
14
- buf = Buffer.new
15
- buf.write :octet, id
16
- buf.write :short, channel
17
- buf.write :longstr, payload
18
- buf.write :octet, FOOTER
19
- buf.rewind
20
- buf
21
- end
22
-
23
- def to_s
24
- to_binary.to_s
25
- end
26
-
27
- def == frame
28
- [ :id, :channel, :payload ].inject(true) do |eql, field|
29
- eql and __send__(field) == frame.__send__(field)
30
- end
31
- end
32
-
33
- class Method
34
- def initialize payload = nil, channel = 0
35
- super
36
- unless @payload.is_a? Protocol::Class::Method or @payload.nil?
37
- @payload = Protocol.parse(@payload)
38
- end
39
- end
40
- end
41
-
42
- class Header
43
- def initialize payload = nil, channel = 0
44
- super
45
- unless @payload.is_a? Protocol::Header or @payload.nil?
46
- @payload = Protocol::Header.new(@payload)
47
- end
48
- end
49
- end
50
-
51
- class Body; end
52
-
53
- def self.parse buf
54
- buf = Transport::Buffer.new(buf) unless buf.is_a? Transport::Buffer
55
- buf.extract do
56
- id, channel, payload, footer = buf.read(:octet, :short, :longstr, :octet)
57
- Transport::Frame.types[id].new(payload, channel) if footer == Transport::Frame::FOOTER
58
- end
59
- end
60
- end
61
- end
@@ -1,156 +0,0 @@
1
- module Protocol
2
- #:stopdoc:
3
- class Class::Method
4
- def initialize *args
5
- opts = args.pop if args.last.is_a? Hash
6
- opts ||= {}
7
-
8
- @debug = 1 # XXX hack, p(obj) == '' if no instance vars are set
9
-
10
- if args.size == 1 and args.first.is_a? Transport::Buffer
11
- buf = args.shift
12
- else
13
- buf = nil
14
- end
15
-
16
- self.class.arguments.each do |type, name|
17
- val = buf ? buf.read(type) :
18
- args.shift || opts[name] || opts[name.to_s]
19
- instance_variable_set("@#{name}", val)
20
- end
21
- end
22
-
23
- def arguments
24
- self.class.arguments.inject({}) do |hash, (type, name)|
25
- hash.update name => instance_variable_get("@#{name}")
26
- end
27
- end
28
-
29
- def to_binary
30
- buf = Transport::Buffer.new
31
- buf.write :short, self.class.parent.id
32
- buf.write :short, self.class.id
33
-
34
- bits = []
35
-
36
- self.class.arguments.each do |type, name|
37
- val = instance_variable_get("@#{name}")
38
- if type == :bit
39
- bits << (val || false)
40
- else
41
- unless bits.empty?
42
- buf.write :bit, bits
43
- bits = []
44
- end
45
- buf.write type, val
46
- end
47
- end
48
-
49
- buf.write :bit, bits unless bits.empty?
50
- buf.rewind
51
-
52
- buf
53
- end
54
-
55
- def to_s
56
- to_binary.to_s
57
- end
58
-
59
- def to_frame channel = 0
60
- Transport::Frame::Method.new(self, channel)
61
- end
62
- end
63
-
64
- #:startdoc:
65
- #
66
- # Contains a properties hash that holds some potentially interesting
67
- # information.
68
- # * :delivery_mode
69
- # 1 equals transient.
70
- # 2 equals persistent. Unconsumed persistent messages will survive
71
- # a server restart when they are stored in a durable queue.
72
- # * :redelivered
73
- # True or False
74
- # * :routing_key
75
- # The routing string used for matching this message to this queue.
76
- # * :priority
77
- # An integer in the range of 0 to 9 inclusive.
78
- # * :content_type
79
- # Always "application/octet-stream" (byte stream)
80
- # * :exchange
81
- # The source exchange which published this message.
82
- # * :message_count
83
- # The number of unconsumed messages contained in the queue.
84
- # * :delivery_tag
85
- # A monotonically increasing integer. This number should not be trusted
86
- # as a sequence number. There is no guarantee it won't get reset.
87
- class Header
88
- def initialize *args
89
- opts = args.pop if args.last.is_a? Hash
90
- opts ||= {}
91
-
92
- first = args.shift
93
-
94
- if first.is_a? ::Class and first.ancestors.include? Protocol::Class
95
- @klass = first
96
- @size = args.shift || 0
97
- @weight = args.shift || 0
98
- @properties = opts
99
-
100
- elsif first.is_a? Transport::Buffer or first.is_a? String
101
- buf = first
102
- buf = Transport::Buffer.new(buf) unless buf.is_a? Transport::Buffer
103
-
104
- @klass = Protocol.classes[buf.read(:short)]
105
- @weight = buf.read(:short)
106
- @size = buf.read(:longlong)
107
-
108
- props = buf.read(:properties, *klass.properties.map{|type,_| type })
109
- @properties = Hash[*klass.properties.map{|_,name| name }.zip(props).reject{|k,v| v.nil? }.flatten]
110
-
111
- else
112
- raise ArgumentError, 'Invalid argument'
113
- end
114
-
115
- end
116
- attr_accessor :klass, :size, :weight, :properties
117
-
118
- def to_binary
119
- buf = Transport::Buffer.new
120
- buf.write :short, klass.id
121
- buf.write :short, weight # XXX rabbitmq only supports weight == 0
122
- buf.write :longlong, size
123
- buf.write :properties, (klass.properties.map do |type, name|
124
- [ type, properties[name] || properties[name.to_s] ]
125
- end)
126
- buf.rewind
127
- buf
128
- end
129
-
130
- def to_s
131
- to_binary.to_s
132
- end
133
-
134
- def to_frame channel = 0
135
- Transport::Frame::Header.new(self, channel)
136
- end
137
-
138
- def == header
139
- [ :klass, :size, :weight, :properties ].inject(true) do |eql, field|
140
- eql and __send__(field) == header.__send__(field)
141
- end
142
- end
143
-
144
- def method_missing meth, *args, &blk
145
- @properties.has_key?(meth) || @klass.properties.find{|_,name| name == meth } ? @properties[meth] :
146
- super
147
- end
148
- end
149
-
150
- def self.parse buf
151
- buf = Transport::Buffer.new(buf) unless buf.is_a? Transport::Buffer
152
- class_id, method_id = buf.read(:short, :short)
153
- classes[class_id].methods[method_id].new(buf)
154
- end
155
- #:stopdoc:
156
- end