boss-protocol 0.1.3 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.ruby-version +1 -0
- data/README.md +12 -4
- data/lib/boss-protocol/version.rb +1 -1
- data/lib/boss-protocol.rb +68 -11
- data/samples/testp.rb +6 -2
- data/spec/boss_spec.rb +22 -0
- metadata +10 -13
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 48d7d49095b00c5a6c7c1fc9c349e623cb52bc62
|
4
|
+
data.tar.gz: e15a3c17f710e7e07af4922ab85a70a01990e6a9
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5d8586643c80b3bf34e73e624ca496733ad7e3c5e659f8021d59a42f4c4cb936f4e5385aaaeb0a874197febd98c31a0d56a13b1f7fce1624eb5eecc017de812b
|
7
|
+
data.tar.gz: d4835694296bd13626adaaeb10bc5cc1d950e53f1a1c71d9a5d868f38028f7bdc4f1baf8a8e97c1df511767c6dae49f7afbbdad9259329f332f3e2656e178248
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
ruby-2.0
|
data/README.md
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
# Boss Protocol
|
2
2
|
|
3
|
-
BOSS is acronym for Binary Object
|
3
|
+
BOSS is an acronym for Binary Object Streaming Specification.
|
4
4
|
|
5
|
-
The
|
5
|
+
The bit-effective, platform-independent streamable and traversable
|
6
6
|
typed binary protocol. Allow to effectively store small or any sized integers,
|
7
7
|
strings or binary data of any size, floats and doubles, arrays and hashes in a
|
8
8
|
very effective way. It caches repeating objects and stores/restores links to
|
@@ -13,7 +13,7 @@ size, signed integers of absolutely any size, arrays and hashes with no limit
|
|
13
13
|
on items and overall gross size. It is desirable to use build-in compression when
|
14
14
|
appropriate.
|
15
15
|
|
16
|
-
Streamable means that you can use a pipe (tcp/ip
|
16
|
+
Streamable means that you can use a pipe (for example tcp/ip), put the object at
|
17
17
|
one side and load it on other, one-by-one, and caching and links will be
|
18
18
|
restored properly.
|
19
19
|
|
@@ -23,6 +23,14 @@ json/boss/whatever. For example, typical JSON reduces in size twice with Boss.
|
|
23
23
|
|
24
24
|
Boss protocol also allow to transparently compress its representations.
|
25
25
|
|
26
|
+
Boss also supports "stream mode" that lacks tree reconstruction but could be
|
27
|
+
effectively use when implementing long-living streams (e.g. stream protocols).
|
28
|
+
In regular mode it causes unlimited cache grows as Boss would try to reconstruct
|
29
|
+
all possible references to already serialized objects. In the stream mode only
|
30
|
+
strings are cached, and cache size and capacity are dynamically limited.
|
31
|
+
Boss writes stream mode marker and handles stream mode on receiving end
|
32
|
+
automatically.
|
33
|
+
|
26
34
|
Supported types:
|
27
35
|
|
28
36
|
* Signed integers of any length
|
@@ -86,7 +94,7 @@ To use the transparent compression:
|
|
86
94
|
## Streaming sample
|
87
95
|
|
88
96
|
This sample shows boss object hierarchies passing between 2 forked processes
|
89
|
-
using a pipe:
|
97
|
+
using a pipe (see samples/):
|
90
98
|
|
91
99
|
if fork
|
92
100
|
wr.close
|
data/lib/boss-protocol.rb
CHANGED
@@ -36,6 +36,8 @@ require 'zlib'
|
|
36
36
|
# Attn! We removed Bzip2 compression for the sake of compatibility. We may add it back when situation
|
37
37
|
# with bz2 implementations on various platforms will be eased
|
38
38
|
#
|
39
|
+
# 1.3 Stream mode added
|
40
|
+
#
|
39
41
|
# 1.2 version adds support for booelans and removes support for python __reduce__ - based objects
|
40
42
|
# as absolutely non portable. It also introduces
|
41
43
|
#
|
@@ -51,8 +53,9 @@ require 'zlib'
|
|
51
53
|
|
52
54
|
module Boss
|
53
55
|
|
54
|
-
class NotSupportedException < StandardError;
|
55
|
-
|
56
|
+
class NotSupportedException < StandardError;
|
57
|
+
end
|
58
|
+
# Basic types
|
56
59
|
TYPE_INT = 0
|
57
60
|
TYPE_EXTRA = 1
|
58
61
|
TYPE_NINT = 2
|
@@ -85,7 +88,9 @@ module Boss
|
|
85
88
|
TFALSE = 13
|
86
89
|
|
87
90
|
TCOMPRESSED = 14
|
88
|
-
TTIME
|
91
|
+
TTIME = 15
|
92
|
+
|
93
|
+
XT_STREAM_MODE = 16
|
89
94
|
|
90
95
|
def checkArg(cond, msg=nil)
|
91
96
|
raise ArgumentError unless cond
|
@@ -94,7 +99,6 @@ module Boss
|
|
94
99
|
class UnknownTypeException < Exception;
|
95
100
|
end
|
96
101
|
|
97
|
-
##
|
98
102
|
# Formats ruby object hierarchies with BOSS
|
99
103
|
# notation
|
100
104
|
#
|
@@ -112,6 +116,20 @@ module Boss
|
|
112
116
|
@cache = { nil => 0 }
|
113
117
|
end
|
114
118
|
|
119
|
+
|
120
|
+
# Switch to stream mode. Stream mode limits cache using to strings only in LRU
|
121
|
+
# mode using specified parameters. Stream mode writes a marker into output so
|
122
|
+
# decoder knows it.
|
123
|
+
# @param max_string_size maximum allowed size of the string to be cached.
|
124
|
+
# longer strings will not be cached
|
125
|
+
# @param max_cache_entries
|
126
|
+
def stream_mode max_cache_entries, max_string_size
|
127
|
+
@max_cache_entries, @max_string_size = max_cache_entries, max_string_size
|
128
|
+
whdr TYPE_EXTRA, XT_STREAM_MODE
|
129
|
+
self << max_cache_entries.to_i << max_string_size.to_i
|
130
|
+
@cache = { nil => 0 }
|
131
|
+
end
|
132
|
+
|
115
133
|
##
|
116
134
|
# same as put but automatically select and use proper compression. Parser.get
|
117
135
|
# will automatically decompress.
|
@@ -128,8 +146,8 @@ module Boss
|
|
128
146
|
else
|
129
147
|
data = Zlib::Deflate.new.deflate(data, Zlib::FINISH)
|
130
148
|
1
|
131
|
-
|
132
|
-
|
149
|
+
#data = Bzip2.compress data
|
150
|
+
#2
|
133
151
|
end
|
134
152
|
whdr type, data.length
|
135
153
|
wbin data
|
@@ -211,18 +229,39 @@ module Boss
|
|
211
229
|
|
212
230
|
private
|
213
231
|
|
214
|
-
##
|
215
232
|
# Write cache ref if the object is cached, and return true
|
216
233
|
# otherwise store object in the cache. Caller should
|
217
234
|
# write object to @io if notCached return true, and skip
|
218
235
|
# writing otherwise
|
236
|
+
|
219
237
|
def notCached(obj)
|
220
238
|
n = @cache[obj]
|
221
239
|
if n
|
222
240
|
whdr TYPE_CREF, n
|
223
241
|
false
|
224
242
|
else
|
225
|
-
|
243
|
+
# Check stream mode
|
244
|
+
if @max_string_size
|
245
|
+
if obj.is_a?(String) && obj.length <= @max_string_size
|
246
|
+
if @cache.length > @max_cache_entries
|
247
|
+
minIndex = @cache.length - @max_cache_entries
|
248
|
+
key = nil
|
249
|
+
@cache.each { |k, v|
|
250
|
+
next if k == nil
|
251
|
+
if v == minIndex
|
252
|
+
key = k
|
253
|
+
else
|
254
|
+
@cache[k] = v - 1
|
255
|
+
end
|
256
|
+
}
|
257
|
+
key == nil and raise "Cache implementation failed"
|
258
|
+
@cache.delete key
|
259
|
+
end
|
260
|
+
@cache[obj] = @cache.length
|
261
|
+
end
|
262
|
+
else
|
263
|
+
@cache[obj] = @cache.length
|
264
|
+
end
|
226
265
|
true
|
227
266
|
end
|
228
267
|
end
|
@@ -351,21 +390,26 @@ module Boss
|
|
351
390
|
end
|
352
391
|
when TTIME
|
353
392
|
Time.at renc
|
393
|
+
when XT_STREAM_MODE
|
394
|
+
@cache = [nil]
|
395
|
+
@max_cache_entries = get + 1 # Count 0th element (always 0)
|
396
|
+
@max_string_size = get
|
397
|
+
get
|
354
398
|
else
|
355
399
|
raise UnknownTypeException
|
356
400
|
end
|
357
401
|
when TYPE_TEXT, TYPE_BIN
|
358
402
|
s = rbin value
|
359
403
|
s.force_encoding code == TYPE_BIN ? Encoding::BINARY : Encoding::UTF_8
|
360
|
-
|
404
|
+
cache_object s
|
361
405
|
s
|
362
406
|
when TYPE_LIST
|
363
407
|
# p "items", value
|
364
|
-
|
408
|
+
cache_object (list = [])
|
365
409
|
value.times { list << get }
|
366
410
|
list
|
367
411
|
when TYPE_DICT
|
368
|
-
|
412
|
+
cache_object (dict = {})
|
369
413
|
value.times { dict[get] = get }
|
370
414
|
dict
|
371
415
|
when TYPE_CREF
|
@@ -391,6 +435,19 @@ module Boss
|
|
391
435
|
|
392
436
|
private
|
393
437
|
|
438
|
+
def cache_object object
|
439
|
+
# Stream mode?
|
440
|
+
if @max_cache_entries
|
441
|
+
if object.is_a?(String) && object.length <= @max_string_size
|
442
|
+
# Should cache
|
443
|
+
@cache << object
|
444
|
+
@cache.delete_at(1) if @cache.length > @max_cache_entries
|
445
|
+
end
|
446
|
+
else
|
447
|
+
@cache << object
|
448
|
+
end
|
449
|
+
end
|
450
|
+
|
394
451
|
##
|
395
452
|
# Read header and return code,value
|
396
453
|
def rhdr
|
data/samples/testp.rb
CHANGED
@@ -1,14 +1,18 @@
|
|
1
|
+
# The interprocess communication using BOSS through
|
2
|
+
# pipes
|
3
|
+
|
1
4
|
require '../lib/boss-protocol'
|
2
5
|
|
3
6
|
rd, wr = IO.pipe
|
4
7
|
|
5
8
|
if fork
|
6
9
|
wr.close
|
7
|
-
|
10
|
+
# There is more than one way:
|
11
|
+
if true
|
8
12
|
# You can do it with block:
|
9
13
|
Boss::Parser.new(rd).each { |obj| puts "Got an object: #{obj}" }
|
10
14
|
else
|
11
|
-
# You can do it without block
|
15
|
+
# You can do it without block:
|
12
16
|
input = Boss::Parser.new rd
|
13
17
|
puts "Got an object: #{input.get}" while !input.eof?
|
14
18
|
end
|
data/spec/boss_spec.rb
CHANGED
@@ -152,6 +152,28 @@ describe 'Boss' do
|
|
152
152
|
-> { Boss.dump MyObject.new }.should raise_error(Boss::NotSupportedException)
|
153
153
|
end
|
154
154
|
|
155
|
+
it 'should implement stream mode' do
|
156
|
+
out = Boss::Formatter.new
|
157
|
+
out.stream_mode 3, 10
|
158
|
+
3.times { out << "String too long" }
|
159
|
+
(1..6).each { |n| out << "test#{n}" }
|
160
|
+
(4..6).each { |n| out << "test#{n}" }
|
161
|
+
(4..6).each { |n| out << "test#{n}" }
|
162
|
+
out << "test7"
|
163
|
+
|
164
|
+
res = "\x81\x18P{String too long{String too long{String too long+test1+test2+test3+test4+test5+test6\r\x15\x1D\r\x15\x1D+test7"
|
165
|
+
res.force_encoding 'binary'
|
166
|
+
out.string.should == res
|
167
|
+
|
168
|
+
inp = Boss::Parser.new out.string
|
169
|
+
|
170
|
+
3.times { inp.get.should == "String too long" }
|
171
|
+
(1..6).each { |n| inp.get.should == "test#{n}" }
|
172
|
+
(4..6).each { |n| inp.get.should == "test#{n}" }
|
173
|
+
(4..6).each { |n| inp.get.should == "test#{n}" }
|
174
|
+
inp.get.should == "test7"
|
175
|
+
end
|
176
|
+
|
155
177
|
def round_check(ob)
|
156
178
|
ob.should == Boss.load(Boss.dump(ob))
|
157
179
|
end
|
metadata
CHANGED
@@ -1,30 +1,27 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: boss-protocol
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
5
|
-
prerelease:
|
4
|
+
version: 1.3.0
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- sergeych
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date: 2013-
|
11
|
+
date: 2013-08-21 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: rspec
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
|
-
- -
|
17
|
+
- - '>='
|
20
18
|
- !ruby/object:Gem::Version
|
21
19
|
version: '0'
|
22
20
|
type: :development
|
23
21
|
prerelease: false
|
24
22
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
23
|
requirements:
|
27
|
-
- -
|
24
|
+
- - '>='
|
28
25
|
- !ruby/object:Gem::Version
|
29
26
|
version: '0'
|
30
27
|
description: Binary streamable bit-effective protocol to effectively store object
|
@@ -37,6 +34,7 @@ extra_rdoc_files: []
|
|
37
34
|
files:
|
38
35
|
- .gitignore
|
39
36
|
- .rspec
|
37
|
+
- .ruby-version
|
40
38
|
- Gemfile
|
41
39
|
- LICENSE.txt
|
42
40
|
- README.md
|
@@ -49,27 +47,26 @@ files:
|
|
49
47
|
- spec/spec_helper.rb
|
50
48
|
homepage: ''
|
51
49
|
licenses: []
|
50
|
+
metadata: {}
|
52
51
|
post_install_message:
|
53
52
|
rdoc_options: []
|
54
53
|
require_paths:
|
55
54
|
- lib
|
56
55
|
required_ruby_version: !ruby/object:Gem::Requirement
|
57
|
-
none: false
|
58
56
|
requirements:
|
59
|
-
- -
|
57
|
+
- - '>='
|
60
58
|
- !ruby/object:Gem::Version
|
61
59
|
version: '0'
|
62
60
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
63
|
-
none: false
|
64
61
|
requirements:
|
65
|
-
- -
|
62
|
+
- - '>='
|
66
63
|
- !ruby/object:Gem::Version
|
67
64
|
version: '0'
|
68
65
|
requirements: []
|
69
66
|
rubyforge_project:
|
70
|
-
rubygems_version:
|
67
|
+
rubygems_version: 2.0.6
|
71
68
|
signing_key:
|
72
|
-
specification_version:
|
69
|
+
specification_version: 4
|
73
70
|
summary: Traversable and streamable to protocol supports lists, hashes, caching, compression
|
74
71
|
and more
|
75
72
|
test_files:
|