about summary refs log tree commit homepage
path: root/lib/rainbows/revactor/client/tee_socket.rb
blob: 2f9f52e29f90006ea75553f431ac66828b782872 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# -*- encoding: binary -*-
# :enddoc:
#
# Revactor Sockets do not implement readpartial, so we emulate just
# enough to avoid mucking with TeeInput internals.  Fortunately
# this code is not heavily used so we can usually avoid the overhead
# of adding a userspace buffer.
class Rainbows::Revactor::Client::TeeSocket
  def initialize(socket)
    # IO::Buffer is used internally by Rev which Revactor is based on
    # so we'll always have it available
    @socket, @rbuf = socket, IO::Buffer.new
  end

  def leftover
    @rbuf.read
  end

  # Revactor socket reads always return an unspecified amount,
  # sometimes too much
  def kgio_read(length, dst = "")
    return dst.replace("") if length == 0

    # always check and return from the userspace buffer first
    @rbuf.size > 0 and return dst.replace(@rbuf.read(length))

    # read off the socket since there was nothing in rbuf
    tmp = @socket.read

    # we didn't read too much, good, just return it straight back
    # to avoid needlessly wasting memory bandwidth
    tmp.size <= length and return dst.replace(tmp)

    # ugh, read returned too much
    @rbuf << tmp[length, tmp.size]
    dst.replace(tmp[0, length])
    rescue EOFError
  end

  # just proxy any remaining methods TeeInput may use
  def close
    @socket.close
  end
end