polyphony 0.78 → 0.81
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/CHANGELOG.md +19 -0
- data/Gemfile.lock +2 -1
- data/examples/core/pingpong.rb +7 -4
- data/examples/core/zlib_stream.rb +15 -0
- data/ext/polyphony/backend_common.c +16 -8
- data/ext/polyphony/backend_common.h +9 -3
- data/ext/polyphony/backend_io_uring.c +85 -31
- data/ext/polyphony/backend_libev.c +33 -17
- data/ext/polyphony/fiber.c +27 -27
- data/ext/polyphony/polyphony.c +9 -8
- data/ext/polyphony/polyphony.h +21 -7
- data/ext/polyphony/thread.c +6 -2
- data/lib/polyphony/adapters/fs.rb +4 -0
- data/lib/polyphony/adapters/process.rb +14 -1
- data/lib/polyphony/adapters/redis.rb +28 -0
- data/lib/polyphony/adapters/sequel.rb +19 -1
- data/lib/polyphony/core/debug.rb +201 -0
- data/lib/polyphony/core/exceptions.rb +21 -6
- data/lib/polyphony/core/global_api.rb +228 -73
- data/lib/polyphony/core/resource_pool.rb +65 -20
- data/lib/polyphony/core/sync.rb +57 -12
- data/lib/polyphony/core/thread_pool.rb +42 -5
- data/lib/polyphony/core/throttler.rb +21 -5
- data/lib/polyphony/core/timer.rb +125 -1
- data/lib/polyphony/extensions/exception.rb +36 -6
- data/lib/polyphony/extensions/fiber.rb +244 -61
- data/lib/polyphony/extensions/io.rb +4 -2
- data/lib/polyphony/extensions/kernel.rb +9 -4
- data/lib/polyphony/extensions/object.rb +8 -0
- data/lib/polyphony/extensions/openssl.rb +3 -1
- data/lib/polyphony/extensions/socket.rb +458 -39
- data/lib/polyphony/extensions/thread.rb +108 -43
- data/lib/polyphony/extensions/timeout.rb +12 -1
- data/lib/polyphony/extensions.rb +1 -0
- data/lib/polyphony/net.rb +66 -7
- data/lib/polyphony/version.rb +1 -1
- data/lib/polyphony.rb +0 -2
- data/test/test_backend.rb +6 -2
- data/test/test_global_api.rb +0 -23
- data/test/test_io.rb +7 -7
- data/test/test_resource_pool.rb +1 -1
- data/test/test_signal.rb +15 -15
- data/test/test_thread.rb +1 -1
- data/test/test_throttler.rb +0 -6
- data/test/test_trace.rb +189 -24
- metadata +9 -8
- data/lib/polyphony/core/channel.rb +0 -15
@@ -5,30 +5,73 @@ require 'socket'
|
|
5
5
|
require_relative './io'
|
6
6
|
require_relative '../core/thread_pool'
|
7
7
|
|
8
|
+
# BasicSocket extensions
|
8
9
|
class BasicSocket
|
9
|
-
|
10
|
+
# Returns `:backend_recv`. This method is used to tell parsers which read
|
11
|
+
# method to use for this object.
|
12
|
+
#
|
13
|
+
# @return [:backend_recv] use Polyphony.backend_recv to parse from socket
|
14
|
+
def __read_method__
|
10
15
|
:backend_recv
|
11
16
|
end
|
12
17
|
end
|
13
18
|
|
14
|
-
# Socket
|
19
|
+
# Socket extensions # TODO: rewrite in C
|
15
20
|
class ::Socket
|
21
|
+
|
22
|
+
# Accepts an incoming connection.
|
23
|
+
|
24
|
+
# @return [TCPSocket] new connection
|
16
25
|
def accept
|
17
26
|
Polyphony.backend_accept(self, TCPSocket)
|
18
27
|
end
|
19
28
|
|
29
|
+
# call-seq:
|
30
|
+
# socket.accept_loop { |conn| ... }
|
31
|
+
#
|
32
|
+
# Accepts incoming connections in an infinite loop.
|
33
|
+
#
|
34
|
+
# @param &block [Proc] handler block
|
35
|
+
# @return [void]
|
20
36
|
def accept_loop(&block)
|
21
37
|
Polyphony.backend_accept_loop(self, TCPSocket, &block)
|
22
38
|
end
|
23
39
|
|
24
40
|
NO_EXCEPTION = { exception: false }.freeze
|
25
41
|
|
42
|
+
# Connects to the given address
|
43
|
+
#
|
44
|
+
# @param addr [AddrInfo, String] address to connect to
|
45
|
+
# @return [::Socket] self
|
26
46
|
def connect(addr)
|
27
47
|
addr = Addrinfo.new(addr) if addr.is_a?(String)
|
28
48
|
Polyphony.backend_connect(self, addr.ip_address, addr.ip_port)
|
49
|
+
self
|
29
50
|
end
|
30
51
|
|
31
52
|
alias_method :orig_read, :read
|
53
|
+
|
54
|
+
# call-seq:
|
55
|
+
# socket.read -> string
|
56
|
+
# socket.read(maxlen) -> string
|
57
|
+
# socket.read(maxlen, buf) -> buf
|
58
|
+
# socket.read(maxlen, buf, buf_pos) -> buf
|
59
|
+
#
|
60
|
+
# Reads from the socket. If `maxlen` is given, reads up to `maxlen` bytes from
|
61
|
+
# the socket, otherwise reads to `EOF`. If `buf` is given, it is used as the
|
62
|
+
# buffer to read into, otherwise a new string is allocated. If `buf_pos` is
|
63
|
+
# given, reads into the given offset (in bytes) in the given buffer. If the
|
64
|
+
# given buffer offset is negative, it is calculated from the current end of
|
65
|
+
# the buffer (`-1` means the read data will be appended to the end of the
|
66
|
+
# buffer).
|
67
|
+
#
|
68
|
+
# If no bytes are available and `EOF` is not hit, this method will block until
|
69
|
+
# the socket is ready to read from.
|
70
|
+
#
|
71
|
+
# @param maxlen [Integer, nil] maximum bytes to read from socket
|
72
|
+
# @param buf [String, nil] buffer to read into
|
73
|
+
# @param buf_pos [Number] buffer position to read into
|
74
|
+
# @return [String] buffer used for reading
|
32
75
|
def read(maxlen = nil, buf = nil, buf_pos = 0)
|
33
76
|
return Polyphony.backend_recv(self, buf, maxlen, buf_pos) if buf
|
34
77
|
return Polyphony.backend_recv(self, +'', maxlen, 0) if maxlen
|
@@ -45,19 +88,70 @@ class ::Socket
|
|
45
88
|
buf
|
46
89
|
end
|
47
90
|
|
91
|
+
# call-seq:
|
92
|
+
# socket.recv(maxlen) -> string
|
93
|
+
# socket.recv(maxlen, flags) -> string
|
94
|
+
# socket.recv(maxlen, flags, buf) -> buf
|
95
|
+
#
|
96
|
+
# Receives up to `maxlen` bytes from the socket. If `outbuf` is given, it is
|
97
|
+
# used as the buffer to receive into, otherwise a new string is allocated and
|
98
|
+
# used as buffer.
|
99
|
+
#
|
100
|
+
# If no bytes are available, this method will block until the socket is ready
|
101
|
+
# to receive from.
|
102
|
+
#
|
103
|
+
# @param maxlen [Integer] maximum bytes to receive
|
104
|
+
# @param flags [Integer] receive flags
|
105
|
+
# @param outbuf [String, nil] buffer for reading or nil to allocate new string
|
106
|
+
# @return [String] receive buffer
|
48
107
|
def recv(maxlen, flags = 0, outbuf = nil)
|
49
108
|
Polyphony.backend_recv(self, outbuf || +'', maxlen, 0)
|
50
109
|
end
|
51
110
|
|
111
|
+
# call-seq:
|
112
|
+
# socket.recv_loop { |data| ... }
|
113
|
+
# socket.recv_loop(maxlen) { |data| ... }
|
114
|
+
# socket.read_loop { |data| ... }
|
115
|
+
# socket.read_loop(maxlen) { |data| ... }
|
116
|
+
#
|
117
|
+
# Receives up to `maxlen` bytes at a time in an infinite loop. Read buffers
|
118
|
+
# will be passed to the given block.
|
119
|
+
#
|
120
|
+
# @param maxlen [Integer] maximum bytes to receive
|
121
|
+
# @param &block [Proc] handler block
|
122
|
+
# @return [void]
|
52
123
|
def recv_loop(maxlen = 8192, &block)
|
53
124
|
Polyphony.backend_recv_loop(self, maxlen, &block)
|
54
125
|
end
|
55
126
|
alias_method :read_loop, :recv_loop
|
56
127
|
|
128
|
+
# call-seq:
|
129
|
+
# socket.feed_loop(receiver, method)
|
130
|
+
# socket.feed_loop(receiver, method) { |result| ... }
|
131
|
+
#
|
132
|
+
# Receives data from the socket in an infinite loop, passing the data to the
|
133
|
+
# given receiver using the given method. If a block is given, the result of
|
134
|
+
# the method call to the receiver is passed to the block.
|
135
|
+
#
|
136
|
+
# This method can be used to feed data into parser objects. The following
|
137
|
+
# example shows how to feed data from a socket directly into a MessagePack
|
138
|
+
# unpacker:
|
139
|
+
#
|
140
|
+
# unpacker = MessagePack::Unpacker.new
|
141
|
+
# buffer = []
|
142
|
+
# reader = spin do
|
143
|
+
# i.feed_loop(unpacker, :feed_each) { |msg| handle_msg(msg) }
|
144
|
+
# end
|
145
|
+
#
|
146
|
+
# @param receiver [any] receiver object
|
147
|
+
# @param method [Symbol] method to call
|
148
|
+
# @param &block [Proc] block to handle result of method call to receiver
|
149
|
+
# @return [void]
|
57
150
|
def feed_loop(receiver, method = :call, &block)
|
58
151
|
Polyphony.backend_recv_feed_loop(self, receiver, method, &block)
|
59
152
|
end
|
60
153
|
|
154
|
+
# :no-doc:
|
61
155
|
def recvfrom(maxlen, flags = 0)
|
62
156
|
buf = +''
|
63
157
|
while true
|
@@ -71,43 +165,74 @@ class ::Socket
|
|
71
165
|
end
|
72
166
|
end
|
73
167
|
|
74
|
-
#
|
75
|
-
#
|
76
|
-
#
|
77
|
-
|
78
|
-
#
|
79
|
-
#
|
80
|
-
#
|
81
|
-
|
82
|
-
#
|
83
|
-
#
|
84
|
-
# end
|
85
|
-
|
86
|
-
|
87
|
-
|
168
|
+
# call-seq:
|
169
|
+
# socket.readpartial(maxlen) -> string
|
170
|
+
# socket.readpartial(maxlen, buf) -> buf
|
171
|
+
# socket.readpartial(maxlen, buf, buf_pos) -> buf
|
172
|
+
# socket.readpartial(maxlen, buf, buf_pos, raise_on_eof) -> buf
|
173
|
+
#
|
174
|
+
# Reads up to `maxlen` from the socket. If `buf` is given, it is used as the
|
175
|
+
# buffer to read into, otherwise a new string is allocated. If `buf_pos` is
|
176
|
+
# given, reads into the given offset (in bytes) in the given buffer. If the
|
177
|
+
# given buffer offset is negative, it is calculated from the current end of
|
178
|
+
# the buffer (`-1` means the read data will be appended to the end of the
|
179
|
+
# buffer). If `raise_on_eof` is `true` (the default,) an `EOFError` will be
|
180
|
+
# raised on `EOF`, otherwise `nil` will be returned.
|
181
|
+
#
|
182
|
+
# If no bytes are available and `EOF` is not hit, this method will block until
|
183
|
+
# the socket is ready to read from.
|
184
|
+
#
|
185
|
+
# @param maxlen [Integer, nil] maximum bytes to read from socket
|
186
|
+
# @param buf [String, nil] buffer to read into
|
187
|
+
# @param buf_pos [Number] buffer position to read into
|
188
|
+
# @param raise_on_eof [bool] whether to raise an exception on `EOF`
|
189
|
+
# @return [String, nil] buffer used for reading or nil on `EOF`
|
190
|
+
def readpartial(maxlen, buf = +'', buf_pos = 0, raise_on_eof = true)
|
191
|
+
result = Polyphony.backend_recv(self, buf, maxlen, buf_pos)
|
88
192
|
raise EOFError if !result && raise_on_eof
|
89
193
|
end
|
90
194
|
|
91
195
|
ZERO_LINGER = [0, 0].pack('ii').freeze
|
92
196
|
|
197
|
+
# Sets the linger option to 0.
|
198
|
+
#
|
199
|
+
# @return [::Socket] self
|
93
200
|
def dont_linger
|
94
201
|
setsockopt(Socket::SOL_SOCKET, Socket::SO_LINGER, ZERO_LINGER)
|
202
|
+
self
|
95
203
|
end
|
96
204
|
|
205
|
+
# Sets the `NODELAY` option.
|
206
|
+
#
|
207
|
+
# @return [::Socket] self
|
97
208
|
def no_delay
|
98
209
|
setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
|
210
|
+
self
|
99
211
|
end
|
100
212
|
|
213
|
+
# Sets the `REUSEADDR` option.
|
214
|
+
#
|
215
|
+
# @return [::Socket] self
|
101
216
|
def reuse_addr
|
102
217
|
setsockopt(Socket::SOL_SOCKET, Socket::SO_REUSEADDR, 1)
|
218
|
+
self
|
103
219
|
end
|
104
220
|
|
221
|
+
# Sets the `REUSEPORT` option.
|
222
|
+
#
|
223
|
+
# @return [::Socket] self
|
105
224
|
def reuse_port
|
106
225
|
setsockopt(::Socket::SOL_SOCKET, ::Socket::SO_REUSEPORT, 1)
|
226
|
+
self
|
107
227
|
end
|
108
228
|
|
109
229
|
class << self
|
110
230
|
alias_method :orig_getaddrinfo, :getaddrinfo
|
231
|
+
|
232
|
+
# Resolves the given addr using a worker thread from the default thread
|
233
|
+
# pool.
|
234
|
+
#
|
235
|
+
# @return [AddrInfo]
|
111
236
|
def getaddrinfo(*args)
|
112
237
|
Polyphony::ThreadPool.process { orig_getaddrinfo(*args) }
|
113
238
|
end
|
@@ -120,10 +245,16 @@ class ::TCPSocket
|
|
120
245
|
|
121
246
|
attr_reader :io
|
122
247
|
|
123
|
-
|
124
|
-
new
|
248
|
+
class << self
|
249
|
+
alias_method :open, :new
|
125
250
|
end
|
126
251
|
|
252
|
+
# Initializes the socket.
|
253
|
+
#
|
254
|
+
# @param remote_host [String] remote host
|
255
|
+
# @param remote_port [Integer] remote port
|
256
|
+
# @param local_host [String] local host
|
257
|
+
# @param local_port [Integer] local port
|
127
258
|
def initialize(remote_host, remote_port, local_host = nil, local_port = nil)
|
128
259
|
remote_addr = Addrinfo.tcp(remote_host, remote_port)
|
129
260
|
@io = Socket.new remote_addr.afamily, Socket::SOCK_STREAM
|
@@ -139,37 +270,89 @@ class ::TCPSocket
|
|
139
270
|
end
|
140
271
|
|
141
272
|
alias_method :orig_close, :close
|
273
|
+
|
274
|
+
# Closes the socket.
|
275
|
+
#
|
276
|
+
# @return [TCPSocket] self
|
142
277
|
def close
|
143
278
|
@io ? @io.close : orig_close
|
279
|
+
self
|
144
280
|
end
|
145
281
|
|
146
282
|
alias_method :orig_setsockopt, :setsockopt
|
283
|
+
|
284
|
+
# Calls `setsockopt` with the given arguments.
|
285
|
+
#
|
286
|
+
# @return [TCPSocket] self
|
147
287
|
def setsockopt(*args)
|
148
288
|
@io ? @io.setsockopt(*args) : orig_setsockopt(*args)
|
289
|
+
self
|
149
290
|
end
|
150
291
|
|
151
292
|
alias_method :orig_closed?, :closed?
|
293
|
+
|
294
|
+
# Returns true if the socket is closed.
|
295
|
+
#
|
296
|
+
# @return [bool] is socket closed
|
152
297
|
def closed?
|
153
298
|
@io ? @io.closed? : orig_closed?
|
154
299
|
end
|
155
300
|
|
301
|
+
# Sets the linger option to 0.
|
302
|
+
#
|
303
|
+
# @return [::Socket] self
|
156
304
|
def dont_linger
|
157
|
-
setsockopt(
|
305
|
+
setsockopt(Socket::SOL_SOCKET, Socket::SO_LINGER, ZERO_LINGER)
|
306
|
+
self
|
158
307
|
end
|
159
308
|
|
309
|
+
# Sets the `NODELAY` option.
|
310
|
+
#
|
311
|
+
# @return [::Socket] self
|
160
312
|
def no_delay
|
161
|
-
setsockopt(
|
313
|
+
setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
|
314
|
+
self
|
162
315
|
end
|
163
316
|
|
317
|
+
# Sets the `REUSEADDR` option.
|
318
|
+
#
|
319
|
+
# @return [::Socket] self
|
164
320
|
def reuse_addr
|
165
|
-
setsockopt(
|
321
|
+
setsockopt(Socket::SOL_SOCKET, Socket::SO_REUSEADDR, 1)
|
322
|
+
self
|
166
323
|
end
|
167
324
|
|
325
|
+
# Sets the `REUSEPORT` option.
|
326
|
+
#
|
327
|
+
# @return [::Socket] self
|
168
328
|
def reuse_port
|
169
329
|
setsockopt(::Socket::SOL_SOCKET, ::Socket::SO_REUSEPORT, 1)
|
330
|
+
self
|
170
331
|
end
|
171
332
|
|
172
333
|
alias_method :orig_read, :read
|
334
|
+
|
335
|
+
# call-seq:
|
336
|
+
# socket.read -> string
|
337
|
+
# socket.read(maxlen) -> string
|
338
|
+
# socket.read(maxlen, buf) -> buf
|
339
|
+
# socket.read(maxlen, buf, buf_pos) -> buf
|
340
|
+
#
|
341
|
+
# Reads from the socket. If `maxlen` is given, reads up to `maxlen` bytes from
|
342
|
+
# the socket, otherwise reads to `EOF`. If `buf` is given, it is used as the
|
343
|
+
# buffer to read into, otherwise a new string is allocated. If `buf_pos` is
|
344
|
+
# given, reads into the given offset (in bytes) in the given buffer. If the
|
345
|
+
# given buffer offset is negative, it is calculated from the current end of
|
346
|
+
# the buffer (`-1` means the read data will be appended to the end of the
|
347
|
+
# buffer).
|
348
|
+
#
|
349
|
+
# If no bytes are available and `EOF` is not hit, this method will block until
|
350
|
+
# the socket is ready to read from.
|
351
|
+
#
|
352
|
+
# @param maxlen [Integer, nil] maximum bytes to read from socket
|
353
|
+
# @param buf [String, nil] buffer to read into
|
354
|
+
# @param buf_pos [Number] buffer position to read into
|
355
|
+
# @return [String] buffer used for reading
|
173
356
|
def read(maxlen = nil, buf = nil, buf_pos = 0)
|
174
357
|
return Polyphony.backend_recv(self, buf, maxlen, buf_pos) if buf
|
175
358
|
return Polyphony.backend_recv(self, +'', maxlen, 0) if maxlen
|
@@ -186,48 +369,131 @@ class ::TCPSocket
|
|
186
369
|
buf
|
187
370
|
end
|
188
371
|
|
372
|
+
# call-seq:
|
373
|
+
# socket.recv(maxlen) -> string
|
374
|
+
# socket.recv(maxlen, flags) -> string
|
375
|
+
# socket.recv(maxlen, flags, buf) -> buf
|
376
|
+
#
|
377
|
+
# Receives up to `maxlen` bytes from the socket. If `outbuf` is given, it is
|
378
|
+
# used as the buffer to receive into, otherwise a new string is allocated and
|
379
|
+
# used as buffer.
|
380
|
+
#
|
381
|
+
# If no bytes are available, this method will block until the socket is ready
|
382
|
+
# to receive from.
|
383
|
+
#
|
384
|
+
# @param maxlen [Integer] maximum bytes to receive
|
385
|
+
# @param flags [Integer] receive flags
|
386
|
+
# @param outbuf [String, nil] buffer for reading or nil to allocate new string
|
387
|
+
# @return [String] receive buffer
|
189
388
|
def recv(maxlen, flags = 0, outbuf = nil)
|
190
389
|
Polyphony.backend_recv(self, outbuf || +'', maxlen, 0)
|
191
390
|
end
|
192
391
|
|
392
|
+
# call-seq:
|
393
|
+
# socket.recv_loop { |data| ... }
|
394
|
+
# socket.recv_loop(maxlen) { |data| ... }
|
395
|
+
# socket.read_loop { |data| ... }
|
396
|
+
# socket.read_loop(maxlen) { |data| ... }
|
397
|
+
#
|
398
|
+
# Receives up to `maxlen` bytes at a time in an infinite loop. Read buffers
|
399
|
+
# will be passed to the given block.
|
400
|
+
#
|
401
|
+
# @param maxlen [Integer] maximum bytes to receive
|
402
|
+
# @param &block [Proc] handler block
|
403
|
+
# @return [void]
|
193
404
|
def recv_loop(maxlen = 8192, &block)
|
194
405
|
Polyphony.backend_recv_loop(self, maxlen, &block)
|
195
406
|
end
|
196
407
|
alias_method :read_loop, :recv_loop
|
197
408
|
|
409
|
+
# call-seq:
|
410
|
+
# socket.feed_loop(receiver, method)
|
411
|
+
# socket.feed_loop(receiver, method) { |result| ... }
|
412
|
+
#
|
413
|
+
# Receives data from the socket in an infinite loop, passing the data to the
|
414
|
+
# given receiver using the given method. If a block is given, the result of
|
415
|
+
# the method call to the receiver is passed to the block.
|
416
|
+
#
|
417
|
+
# This method can be used to feed data into parser objects. The following
|
418
|
+
# example shows how to feed data from a socket directly into a MessagePack
|
419
|
+
# unpacker:
|
420
|
+
#
|
421
|
+
# unpacker = MessagePack::Unpacker.new
|
422
|
+
# buffer = []
|
423
|
+
# reader = spin do
|
424
|
+
# i.feed_loop(unpacker, :feed_each) { |msg| handle_msg(msg) }
|
425
|
+
# end
|
426
|
+
#
|
427
|
+
# @param receiver [any] receiver object
|
428
|
+
# @param method [Symbol] method to call
|
429
|
+
# @param &block [Proc] block to handle result of method call to receiver
|
430
|
+
# @return [void]
|
198
431
|
def feed_loop(receiver, method = :call, &block)
|
199
432
|
Polyphony.backend_recv_feed_loop(self, receiver, method, &block)
|
200
433
|
end
|
201
434
|
|
202
|
-
#
|
203
|
-
#
|
204
|
-
#
|
205
|
-
|
206
|
-
#
|
207
|
-
#
|
208
|
-
#
|
209
|
-
|
210
|
-
#
|
211
|
-
#
|
212
|
-
# end
|
213
|
-
|
435
|
+
# call-seq:
|
436
|
+
# socket.readpartial(maxlen) -> string
|
437
|
+
# socket.readpartial(maxlen, buf) -> buf
|
438
|
+
# socket.readpartial(maxlen, buf, buf_pos) -> buf
|
439
|
+
# socket.readpartial(maxlen, buf, buf_pos, raise_on_eof) -> buf
|
440
|
+
#
|
441
|
+
# Reads up to `maxlen` from the socket. If `buf` is given, it is used as the
|
442
|
+
# buffer to read into, otherwise a new string is allocated. If `buf_pos` is
|
443
|
+
# given, reads into the given offset (in bytes) in the given buffer. If the
|
444
|
+
# given buffer offset is negative, it is calculated from the current end of
|
445
|
+
# the buffer (`-1` means the read data will be appended to the end of the
|
446
|
+
# buffer). If `raise_on_eof` is `true` (the default,) an `EOFError` will be
|
447
|
+
# raised on `EOF`, otherwise `nil` will be returned.
|
448
|
+
#
|
449
|
+
# If no bytes are available and `EOF` is not hit, this method will block until
|
450
|
+
# the socket is ready to read from.
|
451
|
+
#
|
452
|
+
# @param maxlen [Integer, nil] maximum bytes to read from socket
|
453
|
+
# @param buf [String, nil] buffer to read into
|
454
|
+
# @param buf_pos [Number] buffer position to read into
|
455
|
+
# @param raise_on_eof [bool] whether to raise an exception on `EOF`
|
456
|
+
# @return [String, nil] buffer used for reading or nil on `EOF`
|
214
457
|
def readpartial(maxlen, str = +'', buffer_pos = 0, raise_on_eof = true)
|
215
458
|
result = Polyphony.backend_recv(self, str, maxlen, buffer_pos)
|
216
459
|
raise EOFError if !result && raise_on_eof
|
217
460
|
result
|
218
461
|
end
|
219
462
|
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
463
|
+
# Performs a non-blocking read from the socket of up to `maxlen` bytes. If
|
464
|
+
# `buf` is given, it is used as the read buffer, otherwise a new string will
|
465
|
+
# be allocated. If the socket is not ready for reading and `exception` is
|
466
|
+
# true, an `IO::WaitReadable` will be raised. If the socket is not ready for
|
467
|
+
# reading and `exception` is false, `:wait_readable` is returned.
|
468
|
+
#
|
469
|
+
# @param maxlen [Integer] maximum bytes to read
|
470
|
+
# @param buf [String, nil] read buffer
|
471
|
+
# @param exception [bool] whether to raise an exception if not ready for reading
|
472
|
+
# @return [String, :wait_readable] read buffer
|
473
|
+
def read_nonblock(len, buf = nil, exception: true)
|
474
|
+
@io.read_nonblock(len, buf, exception: exception)
|
475
|
+
end
|
476
|
+
|
477
|
+
# Performs a non-blocking to the socket. If the socket is not ready for
|
478
|
+
# writing and `exception` is true, an `IO::WaitWritable` will be raised. If
|
479
|
+
# the socket is not ready for writing and `exception` is false,
|
480
|
+
# `:wait_writable` is returned.
|
481
|
+
#
|
482
|
+
# @param buf [String, nil] write buffer
|
483
|
+
# @param exception [bool] whether to raise an exception if not ready for reading
|
484
|
+
# @return [Integer, :wait_readable] number of bytes written
|
224
485
|
def write_nonblock(buf, exception: true)
|
225
486
|
@io.write_nonblock(buf, exception: exception)
|
226
487
|
end
|
227
488
|
end
|
228
489
|
|
229
|
-
#
|
490
|
+
# TCPServer extensions
|
230
491
|
class ::TCPServer
|
492
|
+
|
493
|
+
# Initializes the TCP server socket.
|
494
|
+
#
|
495
|
+
# @param hostname [String, nil] hostname to connect to
|
496
|
+
# @param port [Integer] port to connect to
|
231
497
|
def initialize(hostname = nil, port = 0)
|
232
498
|
addr = Addrinfo.tcp(hostname, port)
|
233
499
|
@io = Socket.new addr.afamily, Socket::SOCK_STREAM
|
@@ -236,26 +502,53 @@ class ::TCPServer
|
|
236
502
|
end
|
237
503
|
|
238
504
|
alias_method :orig_accept, :accept
|
505
|
+
|
506
|
+
# Accepts an incoming connection.
|
507
|
+
|
508
|
+
# @return [TCPSocket] new connection
|
239
509
|
def accept
|
240
510
|
Polyphony.backend_accept(@io, TCPSocket)
|
241
511
|
end
|
242
512
|
|
513
|
+
# call-seq:
|
514
|
+
# socket.accept_loop { |conn| ... }
|
515
|
+
#
|
516
|
+
# Accepts incoming connections in an infinite loop.
|
517
|
+
#
|
518
|
+
# @param &block [Proc] handler block
|
519
|
+
# @return [void]
|
243
520
|
def accept_loop(&block)
|
244
521
|
Polyphony.backend_accept_loop(@io, TCPSocket, &block)
|
245
522
|
end
|
246
523
|
|
247
524
|
alias_method :orig_close, :close
|
525
|
+
|
526
|
+
# Closes the server socket.
|
527
|
+
#
|
528
|
+
# @return [TCPServer] self
|
248
529
|
def close
|
249
530
|
@io.close
|
531
|
+
self
|
250
532
|
end
|
251
533
|
end
|
252
534
|
|
253
535
|
class ::UNIXServer
|
254
536
|
alias_method :orig_accept, :accept
|
255
|
-
|
537
|
+
|
538
|
+
# Accepts an incoming connection.
|
539
|
+
|
540
|
+
# @return [UNIXSocket] new connection
|
541
|
+
def accept
|
256
542
|
Polyphony.backend_accept(self, UNIXSocket)
|
257
543
|
end
|
258
544
|
|
545
|
+
# call-seq:
|
546
|
+
# socket.accept_loop { |conn| ... }
|
547
|
+
#
|
548
|
+
# Accepts incoming connections in an infinite loop.
|
549
|
+
#
|
550
|
+
# @param &block [Proc] handler block
|
551
|
+
# @return [void]
|
259
552
|
def accept_loop(&block)
|
260
553
|
Polyphony.backend_accept_loop(self, UNIXSocket, &block)
|
261
554
|
end
|
@@ -263,6 +556,28 @@ end
|
|
263
556
|
|
264
557
|
class ::UNIXSocket
|
265
558
|
alias_method :orig_read, :read
|
559
|
+
|
560
|
+
# call-seq:
|
561
|
+
# socket.read -> string
|
562
|
+
# socket.read(maxlen) -> string
|
563
|
+
# socket.read(maxlen, buf) -> buf
|
564
|
+
# socket.read(maxlen, buf, buf_pos) -> buf
|
565
|
+
#
|
566
|
+
# Reads from the socket. If `maxlen` is given, reads up to `maxlen` bytes from
|
567
|
+
# the socket, otherwise reads to `EOF`. If `buf` is given, it is used as the
|
568
|
+
# buffer to read into, otherwise a new string is allocated. If `buf_pos` is
|
569
|
+
# given, reads into the given offset (in bytes) in the given buffer. If the
|
570
|
+
# given buffer offset is negative, it is calculated from the current end of
|
571
|
+
# the buffer (`-1` means the read data will be appended to the end of the
|
572
|
+
# buffer).
|
573
|
+
#
|
574
|
+
# If no bytes are available and `EOF` is not hit, this method will block until
|
575
|
+
# the socket is ready to read from.
|
576
|
+
#
|
577
|
+
# @param maxlen [Integer, nil] maximum bytes to read from socket
|
578
|
+
# @param buf [String, nil] buffer to read into
|
579
|
+
# @param buf_pos [Number] buffer position to read into
|
580
|
+
# @return [String] buffer used for reading
|
266
581
|
def read(maxlen = nil, buf = nil, buf_pos = 0)
|
267
582
|
return Polyphony.backend_recv(self, buf, maxlen, buf_pos) if buf
|
268
583
|
return Polyphony.backend_recv(self, +'', maxlen, 0) if maxlen
|
@@ -279,41 +594,145 @@ class ::UNIXSocket
|
|
279
594
|
buf
|
280
595
|
end
|
281
596
|
|
597
|
+
# call-seq:
|
598
|
+
# socket.recv(maxlen) -> string
|
599
|
+
# socket.recv(maxlen, flags) -> string
|
600
|
+
# socket.recv(maxlen, flags, buf) -> buf
|
601
|
+
#
|
602
|
+
# Receives up to `maxlen` bytes from the socket. If `outbuf` is given, it is
|
603
|
+
# used as the buffer to receive into, otherwise a new string is allocated and
|
604
|
+
# used as buffer.
|
605
|
+
#
|
606
|
+
# If no bytes are available, this method will block until the socket is ready
|
607
|
+
# to receive from.
|
608
|
+
#
|
609
|
+
# @param maxlen [Integer] maximum bytes to receive
|
610
|
+
# @param flags [Integer] receive flags
|
611
|
+
# @param outbuf [String, nil] buffer for reading or nil to allocate new string
|
612
|
+
# @return [String] receive buffer
|
282
613
|
def recv(maxlen, flags = 0, outbuf = nil)
|
283
614
|
Polyphony.backend_recv(self, outbuf || +'', maxlen, 0)
|
284
615
|
end
|
285
616
|
|
617
|
+
# call-seq:
|
618
|
+
# socket.recv_loop { |data| ... }
|
619
|
+
# socket.recv_loop(maxlen) { |data| ... }
|
620
|
+
# socket.read_loop { |data| ... }
|
621
|
+
# socket.read_loop(maxlen) { |data| ... }
|
622
|
+
#
|
623
|
+
# Receives up to `maxlen` bytes at a time in an infinite loop. Read buffers
|
624
|
+
# will be passed to the given block.
|
625
|
+
#
|
626
|
+
# @param maxlen [Integer] maximum bytes to receive
|
627
|
+
# @param &block [Proc] handler block
|
628
|
+
# @return [void]
|
286
629
|
def recv_loop(maxlen = 8192, &block)
|
287
630
|
Polyphony.backend_recv_loop(self, maxlen, &block)
|
288
631
|
end
|
289
632
|
alias_method :read_loop, :recv_loop
|
290
633
|
|
634
|
+
# call-seq:
|
635
|
+
# socket.feed_loop(receiver, method)
|
636
|
+
# socket.feed_loop(receiver, method) { |result| ... }
|
637
|
+
#
|
638
|
+
# Receives data from the socket in an infinite loop, passing the data to the
|
639
|
+
# given receiver using the given method. If a block is given, the result of
|
640
|
+
# the method call to the receiver is passed to the block.
|
641
|
+
#
|
642
|
+
# This method can be used to feed data into parser objects. The following
|
643
|
+
# example shows how to feed data from a socket directly into a MessagePack
|
644
|
+
# unpacker:
|
645
|
+
#
|
646
|
+
# unpacker = MessagePack::Unpacker.new
|
647
|
+
# buffer = []
|
648
|
+
# reader = spin do
|
649
|
+
# i.feed_loop(unpacker, :feed_each) { |msg| handle_msg(msg) }
|
650
|
+
# end
|
651
|
+
#
|
652
|
+
# @param receiver [any] receiver object
|
653
|
+
# @param method [Symbol] method to call
|
654
|
+
# @param &block [Proc] block to handle result of method call to receiver
|
655
|
+
# @return [void]
|
291
656
|
def feed_loop(receiver, method = :call, &block)
|
292
657
|
Polyphony.backend_recv_feed_loop(self, receiver, method, &block)
|
293
658
|
end
|
294
659
|
|
660
|
+
# Sends the given message on the socket.
|
661
|
+
#
|
662
|
+
# @param mesg [String] data to send
|
663
|
+
# @param flags [Integer] send flags
|
664
|
+
# @return [Integer] number of bytes sent
|
295
665
|
def send(mesg, flags)
|
296
666
|
Polyphony.backend_send(self, mesg, flags)
|
297
667
|
end
|
298
668
|
|
669
|
+
# Sends one or more strings on the socket. The strings are guaranteed to be
|
670
|
+
# written as a single blocking operation.
|
671
|
+
#
|
672
|
+
# @param *args [Array<String>] string buffers to write
|
673
|
+
# @return [Integer] number of bytes written
|
299
674
|
def write(*args)
|
300
675
|
Polyphony.backend_sendv(self, args, 0)
|
301
676
|
end
|
302
677
|
|
678
|
+
# Sends the given message on the socket.
|
679
|
+
#
|
680
|
+
# @param mesg [String] data to send
|
681
|
+
# @return [Integer] number of bytes sent
|
303
682
|
def <<(mesg)
|
304
683
|
Polyphony.backend_send(self, mesg, 0)
|
305
684
|
end
|
306
685
|
|
686
|
+
# call-seq:
|
687
|
+
# socket.readpartial(maxlen) -> string
|
688
|
+
# socket.readpartial(maxlen, buf) -> buf
|
689
|
+
# socket.readpartial(maxlen, buf, buf_pos) -> buf
|
690
|
+
# socket.readpartial(maxlen, buf, buf_pos, raise_on_eof) -> buf
|
691
|
+
#
|
692
|
+
# Reads up to `maxlen` from the socket. If `buf` is given, it is used as the
|
693
|
+
# buffer to read into, otherwise a new string is allocated. If `buf_pos` is
|
694
|
+
# given, reads into the given offset (in bytes) in the given buffer. If the
|
695
|
+
# given buffer offset is negative, it is calculated from the current end of
|
696
|
+
# the buffer (`-1` means the read data will be appended to the end of the
|
697
|
+
# buffer). If `raise_on_eof` is `true` (the default,) an `EOFError` will be
|
698
|
+
# raised on `EOF`, otherwise `nil` will be returned.
|
699
|
+
#
|
700
|
+
# If no bytes are available and `EOF` is not hit, this method will block until
|
701
|
+
# the socket is ready to read from.
|
702
|
+
#
|
703
|
+
# @param maxlen [Integer, nil] maximum bytes to read from socket
|
704
|
+
# @param buf [String, nil] buffer to read into
|
705
|
+
# @param buf_pos [Number] buffer position to read into
|
706
|
+
# @param raise_on_eof [bool] whether to raise an exception on `EOF`
|
707
|
+
# @return [String, nil] buffer used for reading or nil on `EOF`
|
307
708
|
def readpartial(maxlen, str = +'', buffer_pos = 0, raise_on_eof = true)
|
308
709
|
result = Polyphony.backend_recv(self, str, maxlen, buffer_pos)
|
309
710
|
raise EOFError if !result && raise_on_eof
|
310
711
|
result
|
311
712
|
end
|
312
713
|
|
714
|
+
# Performs a non-blocking read from the socket of up to `maxlen` bytes. If
|
715
|
+
# `buf` is given, it is used as the read buffer, otherwise a new string will
|
716
|
+
# be allocated. If the socket is not ready for reading and `exception` is
|
717
|
+
# true, an `IO::WaitReadable` will be raised. If the socket is not ready for
|
718
|
+
# reading and `exception` is false, `:wait_readable` is returned.
|
719
|
+
#
|
720
|
+
# @param maxlen [Integer] maximum bytes to read
|
721
|
+
# @param buf [String, nil] read buffer
|
722
|
+
# @param exception [bool] whether to raise an exception if not ready for reading
|
723
|
+
# @return [String, :wait_readable] read buffer
|
313
724
|
def read_nonblock(len, str = nil, exception: true)
|
314
725
|
@io.read_nonblock(len, str, exception: exception)
|
315
726
|
end
|
316
727
|
|
728
|
+
# Performs a non-blocking to the socket. If the socket is not ready for
|
729
|
+
# writing and `exception` is true, an `IO::WaitWritable` will be raised. If
|
730
|
+
# the socket is not ready for writing and `exception` is false,
|
731
|
+
# `:wait_writable` is returned.
|
732
|
+
#
|
733
|
+
# @param buf [String, nil] write buffer
|
734
|
+
# @param exception [bool] whether to raise an exception if not ready for reading
|
735
|
+
# @return [Integer, :wait_readable] number of bytes written
|
317
736
|
def write_nonblock(buf, exception: true)
|
318
737
|
@io.write_nonblock(buf, exception: exception)
|
319
738
|
end
|