about summary refs log tree commit homepage
path: root/lib/rainbows/revactor/client/tee_socket.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/rainbows/revactor/client/tee_socket.rb')
-rw-r--r--lib/rainbows/revactor/client/tee_socket.rb44
1 files changed, 44 insertions, 0 deletions
diff --git a/lib/rainbows/revactor/client/tee_socket.rb b/lib/rainbows/revactor/client/tee_socket.rb
new file mode 100644
index 0000000..2f9f52e
--- /dev/null
+++ b/lib/rainbows/revactor/client/tee_socket.rb
@@ -0,0 +1,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