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.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +19 -0
  3. data/Gemfile.lock +2 -1
  4. data/examples/core/pingpong.rb +7 -4
  5. data/examples/core/zlib_stream.rb +15 -0
  6. data/ext/polyphony/backend_common.c +16 -8
  7. data/ext/polyphony/backend_common.h +9 -3
  8. data/ext/polyphony/backend_io_uring.c +85 -31
  9. data/ext/polyphony/backend_libev.c +33 -17
  10. data/ext/polyphony/fiber.c +27 -27
  11. data/ext/polyphony/polyphony.c +9 -8
  12. data/ext/polyphony/polyphony.h +21 -7
  13. data/ext/polyphony/thread.c +6 -2
  14. data/lib/polyphony/adapters/fs.rb +4 -0
  15. data/lib/polyphony/adapters/process.rb +14 -1
  16. data/lib/polyphony/adapters/redis.rb +28 -0
  17. data/lib/polyphony/adapters/sequel.rb +19 -1
  18. data/lib/polyphony/core/debug.rb +201 -0
  19. data/lib/polyphony/core/exceptions.rb +21 -6
  20. data/lib/polyphony/core/global_api.rb +228 -73
  21. data/lib/polyphony/core/resource_pool.rb +65 -20
  22. data/lib/polyphony/core/sync.rb +57 -12
  23. data/lib/polyphony/core/thread_pool.rb +42 -5
  24. data/lib/polyphony/core/throttler.rb +21 -5
  25. data/lib/polyphony/core/timer.rb +125 -1
  26. data/lib/polyphony/extensions/exception.rb +36 -6
  27. data/lib/polyphony/extensions/fiber.rb +244 -61
  28. data/lib/polyphony/extensions/io.rb +4 -2
  29. data/lib/polyphony/extensions/kernel.rb +9 -4
  30. data/lib/polyphony/extensions/object.rb +8 -0
  31. data/lib/polyphony/extensions/openssl.rb +3 -1
  32. data/lib/polyphony/extensions/socket.rb +458 -39
  33. data/lib/polyphony/extensions/thread.rb +108 -43
  34. data/lib/polyphony/extensions/timeout.rb +12 -1
  35. data/lib/polyphony/extensions.rb +1 -0
  36. data/lib/polyphony/net.rb +66 -7
  37. data/lib/polyphony/version.rb +1 -1
  38. data/lib/polyphony.rb +0 -2
  39. data/test/test_backend.rb +6 -2
  40. data/test/test_global_api.rb +0 -23
  41. data/test/test_io.rb +7 -7
  42. data/test/test_resource_pool.rb +1 -1
  43. data/test/test_signal.rb +15 -15
  44. data/test/test_thread.rb +1 -1
  45. data/test/test_throttler.rb +0 -6
  46. data/test/test_trace.rb +189 -24
  47. metadata +9 -8
  48. 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
- def __parser_read_method__
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 overrides (eventually rewritten in C)
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
- # def send(mesg, flags)
75
- # Polyphony.backend_send(self, mesg, flags)
76
- # end
77
-
78
- # def write(*args)
79
- # Polyphony.backend_sendv(self, args, 0)
80
- # end
81
-
82
- # def <<(mesg)
83
- # Polyphony.backend_send(self, mesg, 0)
84
- # end
85
-
86
- def readpartial(maxlen, str = +'', buffer_pos = 0, raise_on_eof = true)
87
- result = Polyphony.backend_recv(self, str, maxlen, buffer_pos)
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
- def self.open(*args)
124
- new(*args)
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(::Socket::SOL_SOCKET, ::Socket::SO_LINGER, ::Socket::ZERO_LINGER)
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(::Socket::IPPROTO_TCP, ::Socket::TCP_NODELAY, 1)
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(::Socket::SOL_SOCKET, ::Socket::SO_REUSEADDR, 1)
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
- # def send(mesg, flags)
203
- # Polyphony.backend_send(self, mesg, flags)
204
- # end
205
-
206
- # def write(*args)
207
- # Polyphony.backend_sendv(self, args, 0)
208
- # end
209
-
210
- # def <<(mesg)
211
- # Polyphony.backend_send(self, mesg, 0)
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
- def read_nonblock(len, str = nil, exception: true)
221
- @io.read_nonblock(len, str, exception: exception)
222
- end
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
- # Override stock TCPServer code by encapsulating a Socket instance.
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
- def accept
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