xchan.rb 0.17.0 → 0.17.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.
- checksums.yaml +4 -4
- data/.github/workflows/tests.yml +2 -2
- data/.gitlab-ci.yml +1 -1
- data/lib/xchan/bytes.rb +17 -26
- data/lib/xchan/{stat.rb → counter.rb} +12 -13
- data/lib/xchan/unix_socket.rb +26 -23
- data/lib/xchan/version.rb +1 -1
- data/test/xchan_test.rb +7 -3
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5509107cf1cda5e847f3c15e19c81ba9323c2dbb524a7ef808eeb820d5bcdeb9
|
4
|
+
data.tar.gz: 43deff543ee38ace3ca8a083a043eb1c6bbedec9143bd2c8e17de50f13127031
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d5455dd6c714bc4060ec1f563b46d8a9eaee32e5aa58c2a2508de99f53fc29e346d07ac04e719822bc394b66ac6ba6ddf5585bf7958c606a0f1f375c113b4310
|
7
|
+
data.tar.gz: '09bd28506d18a63e8e917ad1189c708cc6643b852707508ee0edf563064bd3618d3ae251d85e06f618672c414537b4da3db0538b61e4c11c2a6c64fff3394f38'
|
data/.github/workflows/tests.yml
CHANGED
@@ -12,7 +12,7 @@ jobs:
|
|
12
12
|
fail-fast: false
|
13
13
|
matrix:
|
14
14
|
os: [ubuntu-latest, macos-latest]
|
15
|
-
ruby: [3.1, 3.2]
|
15
|
+
ruby: [3.1, 3.2, 3.3]
|
16
16
|
runs-on: ${{ matrix.os }}
|
17
17
|
steps:
|
18
18
|
- uses: actions/checkout@v2
|
@@ -23,4 +23,4 @@ jobs:
|
|
23
23
|
- run: SERIALIZER=marshal bundle exec rake
|
24
24
|
- run: SERIALIZER=json bundle exec rake
|
25
25
|
- run: SERIALIZER=yaml bundle exec rake
|
26
|
-
- run: SERIALIZER=
|
26
|
+
- run: SERIALIZER=pure bundle exec rake
|
data/.gitlab-ci.yml
CHANGED
data/lib/xchan/bytes.rb
CHANGED
@@ -1,39 +1,31 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
##
|
4
|
-
#
|
5
|
-
#
|
6
|
-
#
|
7
|
-
#
|
8
|
-
# the
|
9
|
-
# is read from a channel, the array decreases in
|
10
|
-
# size.
|
4
|
+
# {Chan::Bytes Chan::Bytes} represents a collection
|
5
|
+
# of byte counts for each object stored on a channel.
|
6
|
+
# When an object is written to a channel, the collection
|
7
|
+
# increases in size, and when an object is read from
|
8
|
+
# a channel, the collection decreases in size.
|
11
9
|
class Chan::Bytes
|
12
10
|
require "json"
|
13
|
-
require_relative "
|
14
|
-
|
15
|
-
##
|
16
|
-
# @return [Chan::Stat]
|
17
|
-
attr_reader :stat
|
11
|
+
require_relative "counter"
|
18
12
|
|
19
13
|
##
|
20
14
|
# @param [String] tmpdir
|
21
|
-
#
|
15
|
+
# Directory where temporary files are stored
|
22
16
|
#
|
23
17
|
# @return [Chan::Bytes]
|
24
18
|
def initialize(tmpdir)
|
25
|
-
@serializer = JSON
|
26
19
|
@io = Chan.temporary_file("xchan.bytes", tmpdir:)
|
27
20
|
@io.sync = true
|
28
|
-
@stat = Chan::Stat.new(tmpdir)
|
29
21
|
write(@io, [])
|
30
22
|
end
|
31
23
|
|
32
24
|
##
|
33
|
-
#
|
25
|
+
# Adds a count to the start of the collection
|
34
26
|
#
|
35
27
|
# @param [Integer] len
|
36
|
-
#
|
28
|
+
# The bytesize of an object
|
37
29
|
#
|
38
30
|
# @return [void]
|
39
31
|
def unshift(len)
|
@@ -41,15 +33,14 @@ class Chan::Bytes
|
|
41
33
|
bytes = read(@io)
|
42
34
|
bytes.unshift(len)
|
43
35
|
write(@io, bytes)
|
44
|
-
@stat.store(bytes_written: len)
|
45
36
|
len
|
46
37
|
end
|
47
38
|
|
48
39
|
##
|
49
|
-
#
|
40
|
+
# Adds a count to the end of the collection
|
50
41
|
#
|
51
42
|
# @param [Integer] len
|
52
|
-
#
|
43
|
+
# The bytesize of an object
|
53
44
|
#
|
54
45
|
# @return [void]
|
55
46
|
def push(len)
|
@@ -57,25 +48,25 @@ class Chan::Bytes
|
|
57
48
|
bytes = read(@io)
|
58
49
|
bytes.push(len)
|
59
50
|
write(@io, bytes)
|
60
|
-
@stat.store(bytes_written: len)
|
61
51
|
len
|
62
52
|
end
|
63
53
|
|
64
54
|
##
|
55
|
+
# Removes a count from the start of the collection
|
56
|
+
#
|
65
57
|
# @return [Integer]
|
66
|
-
# Returns
|
58
|
+
# Returns the removed byte count
|
67
59
|
def shift
|
68
60
|
bytes = read(@io)
|
69
61
|
return 0 if bytes.size.zero?
|
70
62
|
len = bytes.shift
|
71
63
|
write(@io, bytes)
|
72
|
-
@stat.store(bytes_read: len)
|
73
64
|
len
|
74
65
|
end
|
75
66
|
|
76
67
|
##
|
77
68
|
# @return [Integer]
|
78
|
-
# Returns the
|
69
|
+
# Returns the number of objects in the collection
|
79
70
|
def size
|
80
71
|
read(@io).size
|
81
72
|
end
|
@@ -100,10 +91,10 @@ class Chan::Bytes
|
|
100
91
|
end
|
101
92
|
|
102
93
|
def serialize(bytes)
|
103
|
-
|
94
|
+
JSON.dump(bytes)
|
104
95
|
end
|
105
96
|
|
106
97
|
def deserialize(bytes)
|
107
|
-
|
98
|
+
JSON.load(bytes)
|
108
99
|
end
|
109
100
|
end
|
@@ -1,33 +1,32 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
##
|
4
|
-
#
|
5
|
-
#
|
6
|
-
#
|
7
|
-
class Chan::
|
4
|
+
# {Chan::Counter Chan::Counter} provides a counter
|
5
|
+
# for the number of written and received bytes on a
|
6
|
+
# given channel.
|
7
|
+
class Chan::Counter
|
8
8
|
require "json"
|
9
9
|
|
10
10
|
##
|
11
11
|
# @param [String] tmpdir
|
12
|
-
#
|
12
|
+
# Directory where temporary files are stored
|
13
13
|
#
|
14
|
-
# @return [Chan::
|
14
|
+
# @return [Chan::Counter]
|
15
15
|
def initialize(tmpdir)
|
16
|
-
@
|
17
|
-
@io = Chan.temporary_file("xchan.stat", tmpdir:)
|
16
|
+
@io = Chan.temporary_file("xchan.counter", tmpdir:)
|
18
17
|
write(@io, {"bytes_read" => 0, "bytes_written" => 0})
|
19
18
|
end
|
20
19
|
|
21
20
|
##
|
22
21
|
# @return [Integer]
|
23
|
-
# Returns the number of bytes written to a channel
|
22
|
+
# Returns the number of bytes written to a channel
|
24
23
|
def bytes_written
|
25
24
|
read(@io).fetch("bytes_written")
|
26
25
|
end
|
27
26
|
|
28
27
|
##
|
29
28
|
# @return [Integer]
|
30
|
-
# Returns the number of bytes read from a channel
|
29
|
+
# Returns the number of bytes read from a channel
|
31
30
|
def bytes_read
|
32
31
|
read(@io).fetch("bytes_read")
|
33
32
|
end
|
@@ -36,7 +35,7 @@ class Chan::Stat
|
|
36
35
|
# @param [Hash] new_stat
|
37
36
|
# @return [void]
|
38
37
|
# @private
|
39
|
-
def
|
38
|
+
def increment!(new_stat)
|
40
39
|
stat = read(@io)
|
41
40
|
new_stat.each { stat[_1.to_s] += _2 }
|
42
41
|
write(@io, stat)
|
@@ -54,10 +53,10 @@ class Chan::Stat
|
|
54
53
|
end
|
55
54
|
|
56
55
|
def serialize(bytes)
|
57
|
-
|
56
|
+
JSON.dump(bytes)
|
58
57
|
end
|
59
58
|
|
60
59
|
def deserialize(bytes)
|
61
|
-
|
60
|
+
JSON.load(bytes)
|
62
61
|
end
|
63
62
|
end
|
data/lib/xchan/unix_socket.rb
CHANGED
@@ -39,25 +39,26 @@ class Chan::UNIXSocket
|
|
39
39
|
@serializer = Chan.serializers[serializer]&.call || serializer
|
40
40
|
@r, @w = ::UNIXSocket.pair(sock_type)
|
41
41
|
@bytes = Chan::Bytes.new(tmpdir)
|
42
|
+
@counter = Chan::Counter.new(tmpdir)
|
42
43
|
@lock = LockFile.new Chan.temporary_file("xchan.lock", tmpdir:)
|
43
44
|
end
|
44
45
|
|
45
46
|
##
|
46
47
|
# @return [<#dump, #load>]
|
47
|
-
# Returns the serializer used by the channel
|
48
|
+
# Returns the serializer used by the channel
|
48
49
|
def serializer
|
49
50
|
@serializer
|
50
51
|
end
|
51
52
|
|
52
53
|
##
|
53
54
|
# @return [Boolean]
|
54
|
-
# Returns true when the channel is closed
|
55
|
+
# Returns true when the channel is closed
|
55
56
|
def closed?
|
56
57
|
@r.closed? and @w.closed?
|
57
58
|
end
|
58
59
|
|
59
60
|
##
|
60
|
-
# Closes the channel
|
61
|
+
# Closes the channel
|
61
62
|
#
|
62
63
|
# @raise [IOError]
|
63
64
|
# When the channel is closed.
|
@@ -79,13 +80,13 @@ class Chan::UNIXSocket
|
|
79
80
|
# Performs a blocking write
|
80
81
|
#
|
81
82
|
# @param [Object] object
|
82
|
-
# An object
|
83
|
+
# An object
|
83
84
|
#
|
84
85
|
# @raise [IOError]
|
85
|
-
# When the channel is closed
|
86
|
+
# When the channel is closed
|
86
87
|
#
|
87
88
|
# @return [Object]
|
88
|
-
# Returns the number of bytes written to the channel
|
89
|
+
# Returns the number of bytes written to the channel
|
89
90
|
def send(object)
|
90
91
|
send_nonblock(object)
|
91
92
|
rescue Chan::WaitWritable, Chan::WaitLockable
|
@@ -97,24 +98,25 @@ class Chan::UNIXSocket
|
|
97
98
|
# Performs a non-blocking write
|
98
99
|
#
|
99
100
|
# @param [Object] object
|
100
|
-
# An object
|
101
|
+
# An object
|
101
102
|
#
|
102
103
|
# @raise [IOError]
|
103
|
-
# When the channel is closed
|
104
|
+
# When the channel is closed
|
104
105
|
#
|
105
106
|
# @raise [Chan::WaitWritable]
|
106
|
-
# When a write to
|
107
|
+
# When a write to {#w} blocks
|
107
108
|
#
|
108
109
|
# @raise [Chan::WaitLockable]
|
109
|
-
# When a write blocks because of a lock held by another process
|
110
|
+
# When a write blocks because of a lock held by another process
|
110
111
|
#
|
111
112
|
# @return [Integer, nil]
|
112
|
-
# Returns the number of bytes written to the channel
|
113
|
+
# Returns the number of bytes written to the channel
|
113
114
|
def send_nonblock(object)
|
114
115
|
@lock.lock_nonblock
|
115
116
|
raise IOError, "channel closed" if closed?
|
116
117
|
len = @w.write_nonblock(serialize(object))
|
117
118
|
@bytes.push(len)
|
119
|
+
@counter.increment!(bytes_written: len)
|
118
120
|
len.tap { @lock.release }
|
119
121
|
rescue IOError, IO::WaitWritable, Errno::ENOBUFS => ex
|
120
122
|
@lock.release
|
@@ -134,10 +136,10 @@ class Chan::UNIXSocket
|
|
134
136
|
# Performs a blocking read
|
135
137
|
#
|
136
138
|
# @raise [IOError]
|
137
|
-
# When the channel is closed
|
139
|
+
# When the channel is closed
|
138
140
|
#
|
139
141
|
# @return [Object]
|
140
|
-
# Returns an object from the channel
|
142
|
+
# Returns an object from the channel
|
141
143
|
def recv
|
142
144
|
recv_nonblock
|
143
145
|
rescue Chan::WaitReadable
|
@@ -152,21 +154,22 @@ class Chan::UNIXSocket
|
|
152
154
|
# Performs a non-blocking read
|
153
155
|
#
|
154
156
|
# @raise [IOError]
|
155
|
-
# When the channel is closed
|
157
|
+
# When the channel is closed
|
156
158
|
#
|
157
159
|
# @raise [Chan::WaitReadable]
|
158
|
-
# When a read from
|
160
|
+
# When a read from {#r} blocks
|
159
161
|
#
|
160
162
|
# @raise [Chan::WaitLockable]
|
161
|
-
# When a read blocks because of a lock held by another process
|
163
|
+
# When a read blocks because of a lock held by another process
|
162
164
|
#
|
163
165
|
# @return [Object]
|
164
|
-
# Returns an object from the channel
|
166
|
+
# Returns an object from the channel
|
165
167
|
def recv_nonblock
|
166
168
|
@lock.lock_nonblock
|
167
169
|
raise IOError, "closed channel" if closed?
|
168
170
|
len = @bytes.shift
|
169
171
|
obj = deserialize(@r.read_nonblock(len.zero? ? 1 : len))
|
172
|
+
@counter.increment!(bytes_read: len)
|
170
173
|
obj.tap { @lock.release }
|
171
174
|
rescue IOError => ex
|
172
175
|
@lock.release
|
@@ -190,7 +193,7 @@ class Chan::UNIXSocket
|
|
190
193
|
# ch.to_a.last # => 4
|
191
194
|
#
|
192
195
|
# @return [Array<Object>]
|
193
|
-
# Returns the
|
196
|
+
# Returns the contents of the channel
|
194
197
|
def to_a
|
195
198
|
lock do
|
196
199
|
[].tap { _1.push(recv) until empty? }
|
@@ -199,7 +202,7 @@ class Chan::UNIXSocket
|
|
199
202
|
|
200
203
|
##
|
201
204
|
# @return [Boolean]
|
202
|
-
# Returns true when the channel is empty
|
205
|
+
# Returns true when the channel is empty
|
203
206
|
def empty?
|
204
207
|
return true if closed?
|
205
208
|
lock { size.zero? }
|
@@ -210,17 +213,17 @@ class Chan::UNIXSocket
|
|
210
213
|
|
211
214
|
##
|
212
215
|
# @return [Integer]
|
213
|
-
# Returns the total number of bytes written to the channel
|
216
|
+
# Returns the total number of bytes written to the channel
|
214
217
|
def bytes_sent
|
215
|
-
lock { @
|
218
|
+
lock { @counter.bytes_written }
|
216
219
|
end
|
217
220
|
alias_method :bytes_written, :bytes_sent
|
218
221
|
|
219
222
|
##
|
220
223
|
# @return [Integer]
|
221
|
-
# Returns the total number of bytes read from the channel
|
224
|
+
# Returns the total number of bytes read from the channel
|
222
225
|
def bytes_received
|
223
|
-
lock { @
|
226
|
+
lock { @counter.bytes_read }
|
224
227
|
end
|
225
228
|
alias_method :bytes_read, :bytes_received
|
226
229
|
|
data/lib/xchan/version.rb
CHANGED
data/test/xchan_test.rb
CHANGED
@@ -4,7 +4,7 @@ require_relative "setup"
|
|
4
4
|
|
5
5
|
class Chan::Test < Test::Unit::TestCase
|
6
6
|
def setup
|
7
|
-
@ch = xchan
|
7
|
+
@ch = xchan(serializer)
|
8
8
|
end
|
9
9
|
|
10
10
|
def teardown
|
@@ -17,9 +17,13 @@ class Chan::Test < Test::Unit::TestCase
|
|
17
17
|
@ch
|
18
18
|
end
|
19
19
|
|
20
|
+
def serializer
|
21
|
+
ENV.fetch("SERIALIZER", "pure").to_sym
|
22
|
+
end
|
23
|
+
|
20
24
|
def object
|
21
|
-
case
|
22
|
-
when
|
25
|
+
case serializer
|
26
|
+
when :pure then "xchan"
|
23
27
|
else %w[xchan]
|
24
28
|
end
|
25
29
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: xchan.rb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.17.
|
4
|
+
version: 0.17.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- '0x1eef'
|
@@ -127,7 +127,7 @@ files:
|
|
127
127
|
- Rakefile.rb
|
128
128
|
- lib/xchan.rb
|
129
129
|
- lib/xchan/bytes.rb
|
130
|
-
- lib/xchan/
|
130
|
+
- lib/xchan/counter.rb
|
131
131
|
- lib/xchan/tempfile.rb
|
132
132
|
- lib/xchan/unix_socket.rb
|
133
133
|
- lib/xchan/version.rb
|