# This software code is made available "AS IS" without warranties of any # kind. You may copy, display, modify and redistribute the software # code either by itself or as incorporated into your code; provided that # you do not remove any proprietary notices. Your use of this software # code is at your own risk and you waive any claim against the author # with respect to your use of this software code. # (c) 2007 s3sync.net # # The purpose of this file is to overlay the net/http library # to add some functionality # (without changing the file itself or requiring a specific version) # It still isn't perfectly robust, i.e. if radical changes are made # to the underlying lib this stuff will need updating. require 'net/http' require 'delegate' module Net $HTTPStreamingDebug = false # Allow request body to be an IO stream # Allow an IO stream argument to stream the response body out class HTTP alias _HTTPStreaming_request request def request(req, body = nil, streamResponseBodyTo = nil, &block) if not block_given? and streamResponseBodyTo and streamResponseBodyTo.respond_to?(:write) $stderr.puts "Response using streaming" if $HTTPStreamingDebug # this might be a retry, we should make sure the stream is at its beginning streamResponseBodyTo.rewind if streamResponseBodyTo.respond_to?(:rewind) and streamResponseBodyTo != $stdout block = proc do |res| res.read_body do |chunk| streamResponseBodyTo.write(chunk) end end end if body != nil && body.respond_to?(:read) $stderr.puts "Request using streaming" if $HTTPStreamingDebug # this might be a retry, we should make sure the stream is at its beginning body.rewind if body.respond_to?(:rewind) req.body_stream = body return _HTTPStreaming_request(req, nil, &block) else return _HTTPStreaming_request(req, body, &block) end end end end #module module S3sync class ProgressStream < SimpleDelegator def initialize(s, size=0) @start = @last = Time.new @total = size @transferred = 0 @closed = false @printed = false @innerStream = s super(@innerStream) __setobj__(@innerStream) end # need to catch reads and writes so we can count what's being transferred def read(i) res = @innerStream.read(i) @transferred += res.respond_to?(:length) ? res.length : 0 now = Time.new if(now - @last > 1) # don't do this oftener than once per second @printed = true begin $stdout.printf("\rProgress: %db %db/s %s ", @transferred, (@transferred/(now - @start)).floor, @total > 0? (100 * @transferred/@total).floor.to_s + "%" : "" ) rescue FloatDomainError #wtf? end $stdout.flush @last = now end res end def write(s) @transferred += s.length res = @innerStream.write(s) now = Time.new if(now -@last > 1) # don't do this oftener than once per second @printed = true $stdout.printf("\rProgress: %db %db/s %s ", @transferred, (@transferred/(now - @start)).floor, @total > 0? (100 * @transferred/@total).floor.to_s + "%" : "" ) $stdout.flush @last = now end res end def rewind() @transferred = 0 @innerStream.rewind if @innerStream.respond_to?(:rewind) end def close() $stdout.printf("\n") if @printed and not @closed @closed = true @innerStream.close end end end #module