about summary refs log tree commit homepage
path: root/lib/rainbows/fiber/io.rb
blob: 111132f086eaf5757fef9a0b0a62758e836abbbd (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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# -*- encoding: binary -*-
# :enddoc:
# A \Fiber-aware IO class, gives users the illusion of a synchronous
# interface that yields away from the current \Fiber whenever
# the underlying descriptor is blocked on reads or write
#
# It's not recommended to use any of this in your applications
# unless you're willing to accept breakage.  Most of this is very
# difficult-to-use, fragile and we don't have much time to devote to
# supporting these in the future.
#
# This is a stable, legacy interface and should be preserved for all
# future versions of Rainbows!  However, new apps should use
# Rainbows::Fiber::IO::Socket or Rainbows::Fiber::IO::Pipe instead
# (or better yet, avoid any of the Rainbows::Fiber* stuff).
class Rainbows::Fiber::IO
  attr_accessor :to_io

  # :stopdoc:
  # see Rainbows::Fiber::IO::Compat for initialize implementation
  class << self
    alias :[] :new
  end
  # :startdoc:

  # no longer used internally within Rainbows!, only for compatibility
  def write_nonblock(buf)
    @to_io.write_nonblock(buf)
  end

  def kgio_addr
    @to_io.kgio_addr
  end

  # for wrapping output response bodies
  def each
    buf = readpartial(16384)
    yield buf
    yield buf while readpartial(16384, buf)
    rescue EOFError
      self
  end

  def closed?
    @to_io.closed?
  end

  def fileno
    @to_io.fileno
  end

  def write(buf)
    case rv = Kgio.trywrite(@to_io, buf)
    when String
      buf = rv
    when :wait_writable
      kgio_wait_writable
    end until nil == rv
  end

  # used for reading headers (respecting keepalive_timeout)
  def timed_read(buf)
    expire = nil
    case rv = Kgio.tryread(@to_io, 16384, buf)
    when :wait_readable
      return if expire && expire < Rainbows.now
      expire ||= read_expire
      kgio_wait_readable
    else
      return rv
    end while true
  end

  def readpartial(length, buf = "")
    case rv = Kgio.tryread(@to_io, length, buf)
    when nil
      raise EOFError, "end of file reached", []
    when :wait_readable
      kgio_wait_readable
    else
      return rv
    end while true
  end

  def kgio_read(*args)
    @to_io.kgio_read(*args)
  end

  def kgio_read!(*args)
    @to_io.kgio_read!(*args)
  end

  def kgio_trywrite(*args)
    @to_io.kgio_trywrite(*args)
  end

  autoload :Socket, 'rainbows/fiber/io/socket'
  autoload :Pipe, 'rainbows/fiber/io/pipe'
end

# :stopdoc:
require 'rainbows/fiber/io/methods'
require 'rainbows/fiber/io/compat'
class Rainbows::Fiber::IO
  include Rainbows::Fiber::IO::Compat
  include Rainbows::Fiber::IO::Methods
  alias_method :wait_readable, :kgio_wait_readable
  alias_method :wait_writable, :kgio_wait_writable
end