about summary refs log tree commit homepage
path: root/lib/rainbows/fiber/io.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/rainbows/fiber/io.rb')
-rw-r--r--lib/rainbows/fiber/io.rb65
1 files changed, 65 insertions, 0 deletions
diff --git a/lib/rainbows/fiber/io.rb b/lib/rainbows/fiber/io.rb
new file mode 100644
index 0000000..bc6c0fe
--- /dev/null
+++ b/lib/rainbows/fiber/io.rb
@@ -0,0 +1,65 @@
+# -*- encoding: binary -*-
+module Rainbows
+  module Fiber
+
+    # A partially complete IO wrapper, this exports an IO.select()-able
+    # #to_io method and gives users the illusion of a synchronous
+    # interface that yields away from the current Fiber whenever
+    # the underlying IO object cannot read or write
+    class IO < Struct.new(:to_io, :f)
+
+      # for wrapping output response bodies
+      def each(&block)
+        begin
+          yield readpartial(16384)
+        rescue EOFError
+          break
+        end while true
+        self
+      end
+
+      def close
+        to_io.close
+      end
+
+      def write(buf)
+        begin
+          (w = to_io.write_nonblock(buf)) == buf.size and return
+          buf = buf[w..-1]
+        rescue Errno::EAGAIN
+          WR[self] = false
+          ::Fiber.yield
+          WR.delete(self)
+          retry
+        end while true
+      end
+
+      # used for reading headers (respecting keepalive_timeout)
+      def read_timeout
+        expire = false
+        begin
+          to_io.read_nonblock(16384)
+        rescue Errno::EAGAIN
+          return if expire && expire < Time.now
+          RD[self] = false
+          expire = Time.now + G.kato
+          ::Fiber.yield
+          RD.delete(self)
+          retry
+        end
+      end
+
+      def readpartial(length, buf = "")
+        begin
+          to_io.read_nonblock(length, buf)
+        rescue Errno::EAGAIN
+          RD[self] = false
+          ::Fiber.yield
+          RD.delete(self)
+          retry
+        end
+      end
+
+    end
+  end
+end