switch from IO#sendfile_nonblock to IO#trysendfile
[rainbows.git] / lib / rainbows / revactor / client / methods.rb
blobb2e1847ae56d53c8b03f46e122ffd29ee64f7583
1 # -*- encoding: binary -*-
2 # :enddoc:
3 module Rainbows::Revactor::Client::Methods
4   if IO.method_defined?(:trysendfile)
5     def write_body_file(body, range)
6       body, client = body_to_io(body), @client
7       sock = @client.instance_variable_get(:@_io)
8       pfx = Revactor::TCP::Socket === client ? :tcp : :unix
9       write_complete = T[:"#{pfx}_write_complete", client]
10       closed = T[:"#{pfx}_closed", client]
11       offset, count = range ? range : [ 0, body.stat.size ]
12       case n = sock.trysendfile(body, offset, count)
13       when Integer
14         offset += n
15         return if 0 == (count -= n)
16       when :wait_writable
17         # The @_write_buffer is empty at this point, trigger the
18         # on_readable method which in turn triggers on_write_complete
19         # even though nothing was written
20         client.controller = Actor.current
21         client.__send__(:enable_write_watcher)
22         Actor.receive do |filter|
23           filter.when(write_complete) {}
24           filter.when(closed) { raise Errno::EPIPE }
25         end
26       else # nil
27         return
28       end while true
29       ensure
30         close_if_private(body)
31     end
32   end
34   def handle_error(e)
35     Revactor::TCP::ReadError === e or super
36   end
38   def write_response(status, headers, body, alive)
39     super(status, headers, body, alive)
40     alive && @ts and @hp.buf << @ts.leftover
41   end
43   def self.included(klass)
44     klass.__send__ :alias_method, :write_body_stream, :write_body_each
45   end
46 end