arpie 0.0.4 → 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- data/BINARY_SPEC +218 -0
- data/README +46 -0
- data/Rakefile +2 -2
- data/lib/arpie/binary.rb +754 -0
- data/lib/arpie/error.rb +39 -0
- data/lib/arpie/protocol.rb +103 -106
- data/lib/arpie/xmlrpc.rb +4 -4
- data/lib/arpie.rb +2 -0
- data/spec/protocol_merge_and_split_spec.rb +28 -8
- data/spec/protocol_spec.rb +4 -0
- metadata +12 -8
data/lib/arpie/error.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
module Arpie
|
2
|
+
|
3
|
+
# Raised by arpie when a Protocol thinks the stream got corrupted
|
4
|
+
# (by calling bogon!).
|
5
|
+
# This usually results in a dropped connection.
|
6
|
+
class StreamError < IOError ; end
|
7
|
+
# Raised by arpie when a Protocol needs more data to parse a packet.
|
8
|
+
# Usually only of relevance to the programmer when using Protocol#from directly.
|
9
|
+
class EIncomplete < RuntimeError ; end
|
10
|
+
|
11
|
+
# :stopdoc:
|
12
|
+
# Used internally by arpie.
|
13
|
+
class ETryAgain < RuntimeError ; end
|
14
|
+
class YieldResult < RuntimeError
|
15
|
+
attr_reader :result
|
16
|
+
def initialize result
|
17
|
+
@result = result
|
18
|
+
end
|
19
|
+
end
|
20
|
+
# :startdoc:
|
21
|
+
|
22
|
+
# Call this if you think the stream has been corrupted, or
|
23
|
+
# non-protocol data arrived.
|
24
|
+
# +message+ is the text to display.
|
25
|
+
# +data+ is the optional misbehaving data for printing.
|
26
|
+
# This breaks out of the caller.
|
27
|
+
def bogon! data = nil, message = nil
|
28
|
+
raise StreamError, "#{self.is_a?(Class) ? self.to_s : self.class.to_s}:" +
|
29
|
+
" BOGON#{data.nil? ? "" : " " + data.inspect}" +
|
30
|
+
"#{message.nil? ? "" : " -- #{message}" }"
|
31
|
+
end
|
32
|
+
|
33
|
+
# Tell the caller that the given chunk of data
|
34
|
+
# is not enough to construct a whole message.
|
35
|
+
# This breaks out of the caller.
|
36
|
+
def incomplete!
|
37
|
+
raise EIncomplete, "#{self.is_a?(Class) ? self : self.class} needs more data"
|
38
|
+
end
|
39
|
+
end
|
data/lib/arpie/protocol.rb
CHANGED
@@ -1,28 +1,9 @@
|
|
1
1
|
require 'shellwords'
|
2
2
|
require 'yaml'
|
3
|
+
require 'zlib'
|
3
4
|
|
4
5
|
module Arpie
|
5
6
|
MTU = 1024
|
6
|
-
# Raised by arpie when a Protocol thinks the stream got corrupted
|
7
|
-
# (by calling stream_error!).
|
8
|
-
# This usually results in a dropped connection.
|
9
|
-
class StreamError < IOError ; end
|
10
|
-
# Raised by arpie when a Protocol needs more data to parse a packet.
|
11
|
-
# Usually only of relevance to the programmer when using Protocol#from directly.
|
12
|
-
class EIncomplete < RuntimeError ; end
|
13
|
-
|
14
|
-
# :stopdoc:
|
15
|
-
# Used internally by arpie.
|
16
|
-
class ESwallow < RuntimeError ; end
|
17
|
-
class ETryAgain < RuntimeError ; end
|
18
|
-
class YieldResult < RuntimeError
|
19
|
-
attr_reader :result
|
20
|
-
def initialize result
|
21
|
-
@result = result
|
22
|
-
end
|
23
|
-
end
|
24
|
-
# :startdoc:
|
25
|
-
|
26
7
|
# A RPC call. You need to wrap all calls sent over RPC protocols in this.
|
27
8
|
class RPCall < Struct.new(:ns, :meth, :argv, :uuid); end
|
28
9
|
|
@@ -30,6 +11,7 @@ module Arpie
|
|
30
11
|
# list, into which io data can be fed and parsed packets received; and
|
31
12
|
# vice versa.
|
32
13
|
class ProtocolChain
|
14
|
+
include Arpie
|
33
15
|
|
34
16
|
# Array of Protocols.
|
35
17
|
attr_reader :chain
|
@@ -67,9 +49,18 @@ module Arpie
|
|
67
49
|
# Convert the given +message+ to wire format by
|
68
50
|
# passing it through all protocols in the chain.
|
69
51
|
def to message
|
70
|
-
|
71
|
-
|
52
|
+
messages = [message]
|
53
|
+
@chain.each {|p|
|
54
|
+
for_next = []
|
55
|
+
messages.each {|msg|
|
56
|
+
p.to(msg) do |a|
|
57
|
+
for_next << a
|
58
|
+
end
|
59
|
+
}
|
60
|
+
|
61
|
+
messages = for_next
|
72
62
|
}
|
63
|
+
messages
|
73
64
|
end
|
74
65
|
|
75
66
|
# Convert the given +binary+ to message format
|
@@ -106,56 +97,54 @@ module Arpie
|
|
106
97
|
cut_to_index = nil
|
107
98
|
messages_for_next = []
|
108
99
|
|
109
|
-
messages.
|
100
|
+
messages.each_with_index do |message, m_index|
|
110
101
|
cut_to_index = p.from(message) do |object|
|
111
102
|
messages_for_next << object
|
112
103
|
end rescue case $!
|
113
|
-
|
114
104
|
when YieldResult
|
115
105
|
messages_for_next.concat($!.result)
|
116
106
|
next
|
117
107
|
|
118
|
-
when ESwallow
|
119
|
-
messages.delete(message)
|
120
|
-
messages_for_next = messages
|
121
|
-
p_index -= 1
|
122
|
-
break
|
123
|
-
|
124
108
|
when EIncomplete
|
125
|
-
|
126
|
-
|
127
|
-
if p_index > 0
|
128
|
-
# Unwind to the parent protocol and let it read in some
|
129
|
-
# more messages ..
|
130
|
-
messages_for_next = messages
|
131
|
-
messages_for_next.shift
|
132
|
-
p_index -= 1
|
133
|
-
break
|
134
|
-
|
135
|
-
# The first protocol manages +io+.
|
109
|
+
if messages.size - 1 - m_index > 0
|
110
|
+
next
|
136
111
|
else
|
137
|
-
|
138
|
-
@buffer << io.readpartial(MTU) rescue raise $!.class,
|
139
|
-
"#{$!.to_s}; unparseable bytes remaining in buffer: #{@buffer.size}"
|
140
|
-
retry
|
112
|
+
raise
|
141
113
|
end
|
142
114
|
|
143
|
-
|
115
|
+
else
|
116
|
+
raise
|
117
|
+
end
|
118
|
+
end rescue case $!
|
119
|
+
when EIncomplete
|
120
|
+
if p_index == 0
|
121
|
+
select([io])
|
122
|
+
@buffer << io.readpartial(MTU) rescue raise $!.class,
|
123
|
+
"#{$!.to_s}; unparseable bytes remaining in buffer: #{@buffer.size}"
|
144
124
|
retry
|
145
125
|
|
146
126
|
else
|
147
|
-
|
148
|
-
|
149
|
-
|
127
|
+
p_index = 0
|
128
|
+
messages_for_next = []
|
129
|
+
messages = [@buffer]
|
130
|
+
next # of loop protocol chain
|
131
|
+
end
|
150
132
|
|
151
|
-
|
152
|
-
|
133
|
+
else
|
134
|
+
raise
|
135
|
+
end
|
136
|
+
|
137
|
+
if messages_for_next.size == 0
|
138
|
+
# Get back to IO level and retry reading more crud
|
139
|
+
messages_for_next = [@buffer]
|
140
|
+
p_index = -1
|
141
|
+
end
|
153
142
|
|
154
143
|
messages = messages_for_next
|
155
144
|
|
156
145
|
if p_index == 0
|
157
146
|
if cut_to_index.nil? || cut_to_index < 0
|
158
|
-
raise "Protocol '#{p.class.to_s}'implementation faulty: " +
|
147
|
+
raise "Protocol '#{p.class.to_s}' implementation faulty: " +
|
159
148
|
"from did return an invalid cut index: #{cut_to_index.inspect}."
|
160
149
|
else
|
161
150
|
@buffer[0, cut_to_index] = ""
|
@@ -163,16 +152,18 @@ module Arpie
|
|
163
152
|
end
|
164
153
|
|
165
154
|
p_index += 1
|
166
|
-
end # chain
|
155
|
+
end # loop chain
|
167
156
|
|
168
157
|
message = messages.shift
|
169
158
|
@messages = messages
|
170
159
|
message
|
171
160
|
end
|
172
161
|
|
162
|
+
|
173
163
|
# Write +message+ to +io+.
|
174
|
-
def write_message io,
|
175
|
-
|
164
|
+
def write_message io, *messages
|
165
|
+
binary = messages.map {|m| to(m)}
|
166
|
+
io.write(binary)
|
176
167
|
end
|
177
168
|
|
178
169
|
def reset
|
@@ -183,17 +174,25 @@ module Arpie
|
|
183
174
|
# A Protocol converts messages (which are arbitary objects)
|
184
175
|
# to a suitable on-the-wire format, and back.
|
185
176
|
class Protocol
|
177
|
+
include Arpie
|
186
178
|
|
187
179
|
# Set this to true in child classes which implement
|
188
180
|
# message separation within a stream.
|
189
181
|
CAN_SEPARATE_MESSAGES = false
|
190
182
|
|
183
|
+
# :stopdoc:
|
184
|
+
# The stowbuffer hash used by assemble! No need to touch this, usually.
|
185
|
+
attr_reader :stowbuffer
|
186
|
+
# The meta-information hash used by assemble! No need to touch this, usually.
|
187
|
+
attr_reader :metabuffer
|
188
|
+
# :startdoc:
|
189
|
+
|
191
190
|
# Convert obj to on-the-wire format.
|
192
191
|
def to obj
|
193
|
-
obj
|
192
|
+
yield obj
|
194
193
|
end
|
195
194
|
|
196
|
-
# Extract message(s) from +binary+.
|
195
|
+
# Extract message(s) from +binary+.
|
197
196
|
#
|
198
197
|
# Yields each message found, with all protocol-specifics stripped.
|
199
198
|
#
|
@@ -219,74 +218,55 @@ module Arpie
|
|
219
218
|
raise ETryAgain
|
220
219
|
end
|
221
220
|
|
222
|
-
# Tell the protocol chain that the given chunk of data
|
223
|
-
# is not enough to construct a whole message.
|
224
|
-
# This breaks out of Protocol#from.
|
225
|
-
def incomplete!
|
226
|
-
raise EIncomplete
|
227
|
-
end
|
228
|
-
|
229
|
-
# Swallow the complete message currently passed to Protocol#from.
|
230
|
-
# Not advised for the outermost protocol, which works on io buffer streams
|
231
|
-
# and may swallow more than intended.
|
232
|
-
def gulp!
|
233
|
-
raise ESwallow
|
234
|
-
end
|
235
|
-
alias_method :swallow!, :gulp!
|
236
|
-
|
237
221
|
# Stow away a message in this protocols buffer for later reassembly.
|
238
222
|
# Optional argument: a token if you are planning to reassemble multiple
|
239
223
|
# interleaved/fragmented message streams.
|
240
224
|
#
|
225
|
+
# If you pass a block, that block will be called; if no block is given,
|
226
|
+
# Protocol#assemble will be invoked.
|
227
|
+
#
|
228
|
+
# Any leftover binaries passed into assemble! that get not returned in
|
229
|
+
# the assembler will be discarded; they are assumed to be syntax or framework.
|
230
|
+
#
|
241
231
|
# +binary+ is the binary packet you want to add to the assembly
|
242
|
-
# +token+ is a object which can be used to
|
232
|
+
# +token+ is a object which can be used to identify multiple concurrent assemblies (think Hash.keys)
|
243
233
|
# +meta+ is a hash containing meta-information for this assembly
|
244
234
|
# each call to assemble! will merge these hashes, and pass them
|
245
235
|
# on to Protocol#assemble
|
246
|
-
def assemble! binary, token = :default, meta = {}
|
236
|
+
def assemble! binary, token = :default, meta = {} # :yields: binaries, metadata
|
247
237
|
@stowbuffer ||= {}
|
248
238
|
@stowbuffer[token] ||= []
|
249
239
|
@stowbuffer[token] << binary
|
250
240
|
|
251
241
|
@metabuffer ||= {}
|
252
242
|
@metabuffer[token] ||= {}
|
253
|
-
@metabuffer[token].merge(meta)
|
254
|
-
|
255
|
-
assembled =
|
256
|
-
|
257
|
-
|
258
|
-
assembled
|
259
|
-
|
260
|
-
|
261
|
-
#
|
262
|
-
#
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
raise YieldResult, assembled
|
243
|
+
@metabuffer[token].merge!(meta)
|
244
|
+
|
245
|
+
assembled = nil
|
246
|
+
|
247
|
+
if block_given?
|
248
|
+
assembled = yield(@stowbuffer[token], @metabuffer[token])
|
249
|
+
|
250
|
+
else
|
251
|
+
# This raises EIncomplete when not enough messages are there,
|
252
|
+
# and passes it straight on to #read_message
|
253
|
+
assembled = assemble(@stowbuffer[token], @metabuffer[token])
|
254
|
+
end
|
255
|
+
|
256
|
+
@stowbuffer.delete(token)
|
257
|
+
@metabuffer.delete(token)
|
258
|
+
raise YieldResult, [assembled]
|
269
259
|
end
|
270
260
|
|
271
261
|
# Called when we're trying to reassemble a stream of packets.
|
272
262
|
#
|
273
263
|
# Call incomplete! when not enough data is here to reassemble this stream,
|
274
264
|
# and yield all results of the reassembled stream.
|
275
|
-
def assemble binaries,
|
265
|
+
def assemble binaries, meta
|
276
266
|
raise NotImplementedError, "Tried to assemble! something, but no assembler defined."
|
277
267
|
end
|
278
|
-
|
279
|
-
# Call this if you think the stream has been corrupted, or
|
280
|
-
# non-protocol data arrived.
|
281
|
-
# +message+ is the text to display.
|
282
|
-
# +data+ is the optional misbehaving data for printing.
|
283
|
-
# This breaks out of Protocol#from.
|
284
|
-
def bogon! data = nil, message = nil
|
285
|
-
raise StreamError, "#{self.class.to_s}#{message.nil? ? " thinks the data is bogus" : ": " + message }#{data.nil? ? "" : ": " + data.inspect}."
|
286
|
-
end
|
287
268
|
end
|
288
269
|
|
289
|
-
|
290
270
|
# A sample binary protocol, which simply prefixes each message with the
|
291
271
|
# size of the data to be expected.
|
292
272
|
class SizedProtocol < Protocol
|
@@ -300,7 +280,7 @@ module Arpie
|
|
300
280
|
end
|
301
281
|
|
302
282
|
def to object
|
303
|
-
[object.size, object].pack('Qa*')
|
283
|
+
yield [object.size, object].pack('Qa*')
|
304
284
|
end
|
305
285
|
end
|
306
286
|
|
@@ -310,7 +290,7 @@ module Arpie
|
|
310
290
|
# Messages are arbitary objects.
|
311
291
|
class MarshalProtocol < Protocol
|
312
292
|
def to object
|
313
|
-
Marshal.dump(object)
|
293
|
+
yield Marshal.dump(object)
|
314
294
|
end
|
315
295
|
|
316
296
|
def from binary
|
@@ -336,7 +316,7 @@ module Arpie
|
|
336
316
|
end
|
337
317
|
|
338
318
|
def to object
|
339
|
-
object.to_s + @separator
|
319
|
+
yield object.to_s + @separator
|
340
320
|
end
|
341
321
|
end
|
342
322
|
|
@@ -347,7 +327,7 @@ module Arpie
|
|
347
327
|
def to object
|
348
328
|
raise ArgumentError, "#{self.class.to_s} can only encode arrays." unless
|
349
329
|
object.is_a?(Array)
|
350
|
-
Shellwords.join(object.map {|x| x.to_s })
|
330
|
+
yield Shellwords.join(object.map {|x| x.to_s })
|
351
331
|
end
|
352
332
|
|
353
333
|
def from binary
|
@@ -361,7 +341,7 @@ module Arpie
|
|
361
341
|
CAN_SEPARATE_MESSAGES = true
|
362
342
|
|
363
343
|
def to object
|
364
|
-
YAML.dump(object) + "...\n"
|
344
|
+
yield YAML.dump(object) + "...\n"
|
365
345
|
end
|
366
346
|
|
367
347
|
def from binary
|
@@ -370,4 +350,21 @@ module Arpie
|
|
370
350
|
4 + index
|
371
351
|
end
|
372
352
|
end
|
353
|
+
|
354
|
+
# A transparent zlib stream de/compression protocol.
|
355
|
+
class ZlibProtocol < Protocol
|
356
|
+
def initialize
|
357
|
+
@inflater = Zlib::Inflate.new
|
358
|
+
@deflater = Zlib::Deflate.new
|
359
|
+
end
|
360
|
+
|
361
|
+
def to object
|
362
|
+
yield @deflater.deflate(object) + @deflater.flush
|
363
|
+
end
|
364
|
+
|
365
|
+
def from binary
|
366
|
+
yield @inflater.inflate(binary)
|
367
|
+
binary.size
|
368
|
+
end
|
369
|
+
end
|
373
370
|
end
|
data/lib/arpie/xmlrpc.rb
CHANGED
@@ -29,7 +29,7 @@ module Arpie
|
|
29
29
|
raise ArgumentError, "Can only encode Arpie::RPCall" unless
|
30
30
|
object.is_a?(Arpie::RPCall)
|
31
31
|
|
32
|
-
@writer.methodCall((object.ns.nil? ? '' : object.ns + '.') + object.meth, *object.argv)
|
32
|
+
yield @writer.methodCall((object.ns.nil? ? '' : object.ns + '.') + object.meth, *object.argv)
|
33
33
|
end
|
34
34
|
|
35
35
|
def from binary
|
@@ -43,7 +43,7 @@ module Arpie
|
|
43
43
|
|
44
44
|
def to object
|
45
45
|
setup
|
46
|
-
case object
|
46
|
+
yield case object
|
47
47
|
when Exception
|
48
48
|
# TODO: wrap XMLFault
|
49
49
|
raise NotImplementedError, "Cannot encode exceptions"
|
@@ -93,7 +93,7 @@ module Arpie
|
|
93
93
|
public_class_method :new
|
94
94
|
|
95
95
|
def to object
|
96
|
-
"GET / HTTP/1.[01]\r\nContent-Length: #{object.size}\r\n\r\n" + object
|
96
|
+
yield "GET / HTTP/1.[01]\r\nContent-Length: #{object.size}\r\n\r\n" + object
|
97
97
|
end
|
98
98
|
|
99
99
|
end
|
@@ -102,7 +102,7 @@ module Arpie
|
|
102
102
|
public_class_method :new
|
103
103
|
|
104
104
|
def to object
|
105
|
-
"HTTP/1.0 200 OK\r\nContent-Length: #{object.size}\r\n\r\n" + object
|
105
|
+
yield "HTTP/1.0 200 OK\r\nContent-Length: #{object.size}\r\n\r\n" + object
|
106
106
|
end
|
107
107
|
end
|
108
108
|
end
|
data/lib/arpie.rb
CHANGED
@@ -3,25 +3,35 @@ require File.join(File.dirname(__FILE__), 'spec_helper')
|
|
3
3
|
class Splitter < Arpie::Protocol
|
4
4
|
def from binary
|
5
5
|
yield binary.size
|
6
|
+
|
6
7
|
binary.each_char do |c|
|
7
8
|
yield c
|
8
9
|
end
|
9
10
|
end
|
10
11
|
end
|
11
12
|
|
12
|
-
class
|
13
|
+
class BufferedSplitter < Arpie::Protocol
|
13
14
|
def from binary
|
14
|
-
unless @
|
15
|
-
|
16
|
-
|
15
|
+
unless defined? @buf
|
16
|
+
yield binary.size * 2
|
17
|
+
@buf = true
|
17
18
|
end
|
18
19
|
|
19
|
-
|
20
|
+
binary.each_char do |c|
|
21
|
+
yield c
|
22
|
+
end
|
20
23
|
end
|
24
|
+
end
|
21
25
|
|
22
|
-
|
23
|
-
|
24
|
-
|
26
|
+
|
27
|
+
class Merger < Arpie::Protocol
|
28
|
+
def from binary
|
29
|
+
assemble! binary do |binaries, meta|
|
30
|
+
binaries.size >= 1 or incomplete!
|
31
|
+
binaries.size - 1 >= binaries[0].to_i or incomplete!
|
32
|
+
binaries.shift
|
33
|
+
binaries.join('')
|
34
|
+
end
|
25
35
|
end
|
26
36
|
end
|
27
37
|
|
@@ -45,3 +55,13 @@ describe "Merger::Splitter::Sized" do subject { [Merger, Splitter, Arpie::SizedP
|
|
45
55
|
chain_read.should == t
|
46
56
|
end
|
47
57
|
end
|
58
|
+
|
59
|
+
describe "Merger::BufferedSplitter::Sized" do subject { [Merger, BufferedSplitter, Arpie::SizedProtocol] }
|
60
|
+
it_should_behave_like "ProtocolChainSetup"
|
61
|
+
|
62
|
+
it "should re-read io for more data if assembly fails" do
|
63
|
+
@chain.write_message(@w, "split")
|
64
|
+
Thread.new { sleep 0.1; @chain.write_message(@w, "split") }
|
65
|
+
chain_read.should == "splitsplit"
|
66
|
+
end
|
67
|
+
end
|
data/spec/protocol_spec.rb
CHANGED
@@ -112,6 +112,10 @@ describe "Sized::Marshal::Sized" do subject { [Arpie::SizedProtocol, Arpie::Mars
|
|
112
112
|
it_should_behave_like "ProtocolChain"
|
113
113
|
end
|
114
114
|
|
115
|
+
describe "Zlib::Marshal::Sized" do subject { [Arpie::ZlibProtocol, Arpie::MarshalProtocol, Arpie::SizedProtocol] }
|
116
|
+
it_should_behave_like "ProtocolChain"
|
117
|
+
end
|
118
|
+
|
115
119
|
# Shellwords is a bit of a special case, because it only encodes arrays.
|
116
120
|
describe "Shellwords::Separator" do subject { [Arpie::ShellwordsProtocol, Arpie::SeparatorProtocol] }
|
117
121
|
it_should_behave_like "ProtocolChain"
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: arpie
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bernhard Stoeckner
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-02-
|
12
|
+
date: 2009-02-24 00:00:00 +01:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -31,25 +31,29 @@ extensions: []
|
|
31
31
|
extra_rdoc_files:
|
32
32
|
- README
|
33
33
|
- COPYING
|
34
|
+
- BINARY_SPEC
|
34
35
|
files:
|
35
36
|
- COPYING
|
36
37
|
- README
|
37
38
|
- Rakefile
|
38
|
-
- spec/rcov.opts
|
39
|
-
- spec/protocol_merge_and_split_spec.rb
|
40
|
-
- spec/spec_helper.rb
|
41
39
|
- spec/protocol_spec.rb
|
42
40
|
- spec/spec.opts
|
41
|
+
- spec/spec_helper.rb
|
42
|
+
- spec/protocol_merge_and_split_spec.rb
|
43
|
+
- spec/rcov.opts
|
43
44
|
- spec/client_server_spec.rb
|
45
|
+
- lib/arpie.rb
|
44
46
|
- lib/arpie
|
45
|
-
- lib/arpie/proxy.rb
|
46
|
-
- lib/arpie/xmlrpc.rb
|
47
47
|
- lib/arpie/client.rb
|
48
|
+
- lib/arpie/error.rb
|
48
49
|
- lib/arpie/protocol.rb
|
50
|
+
- lib/arpie/binary.rb
|
51
|
+
- lib/arpie/proxy.rb
|
52
|
+
- lib/arpie/xmlrpc.rb
|
49
53
|
- lib/arpie/server.rb
|
50
|
-
- lib/arpie.rb
|
51
54
|
- tools/benchmark.rb
|
52
55
|
- tools/protocol_benchmark.rb
|
56
|
+
- BINARY_SPEC
|
53
57
|
has_rdoc: true
|
54
58
|
homepage: http://arpie.elv.es
|
55
59
|
post_install_message:
|