polyphony 0.79 → 0.80

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +10 -0
  3. data/Gemfile.lock +2 -1
  4. data/examples/core/zlib_stream.rb +15 -0
  5. data/ext/polyphony/backend_common.c +2 -1
  6. data/ext/polyphony/backend_common.h +7 -2
  7. data/lib/polyphony/adapters/fs.rb +4 -0
  8. data/lib/polyphony/adapters/process.rb +14 -1
  9. data/lib/polyphony/adapters/redis.rb +28 -0
  10. data/lib/polyphony/adapters/sequel.rb +19 -1
  11. data/lib/polyphony/core/debug.rb +129 -72
  12. data/lib/polyphony/core/exceptions.rb +21 -6
  13. data/lib/polyphony/core/global_api.rb +228 -73
  14. data/lib/polyphony/core/resource_pool.rb +65 -20
  15. data/lib/polyphony/core/sync.rb +57 -12
  16. data/lib/polyphony/core/thread_pool.rb +42 -5
  17. data/lib/polyphony/core/throttler.rb +21 -5
  18. data/lib/polyphony/core/timer.rb +125 -1
  19. data/lib/polyphony/extensions/exception.rb +36 -6
  20. data/lib/polyphony/extensions/fiber.rb +238 -57
  21. data/lib/polyphony/extensions/io.rb +4 -2
  22. data/lib/polyphony/extensions/kernel.rb +9 -4
  23. data/lib/polyphony/extensions/object.rb +8 -0
  24. data/lib/polyphony/extensions/openssl.rb +3 -1
  25. data/lib/polyphony/extensions/socket.rb +458 -39
  26. data/lib/polyphony/extensions/thread.rb +108 -43
  27. data/lib/polyphony/extensions/timeout.rb +12 -1
  28. data/lib/polyphony/extensions.rb +1 -0
  29. data/lib/polyphony/net.rb +59 -0
  30. data/lib/polyphony/version.rb +1 -1
  31. data/lib/polyphony.rb +0 -2
  32. data/test/test_backend.rb +6 -2
  33. data/test/test_global_api.rb +0 -23
  34. data/test/test_resource_pool.rb +1 -1
  35. data/test/test_throttler.rb +0 -6
  36. data/test/test_trace.rb +87 -0
  37. metadata +9 -8
  38. 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