Class: Typhoeus::Multi

Inherits:
Object
  • Object
show all
Defined in:
lib/typhoeus/multi.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeMulti

Returns a new instance of Multi.



5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# File 'lib/typhoeus/multi.rb', line 5

def initialize
  Curl.init

  @handle = Curl.multi_init
  @active = 0
  @running = 0
  @easy_handles = []

  @timeout = ::FFI::MemoryPointer.new(:long)
  @timeval = Curl::Timeval.new
  @fd_read = Curl::FDSet.new
  @fd_write = Curl::FDSet.new
  @fd_excep = Curl::FDSet.new
  @max_fd = ::FFI::MemoryPointer.new(:int)

  ObjectSpace.define_finalizer(self, self.class.finalizer(self))
end

Instance Attribute Details

#easy_handlesObject (readonly)

Returns the value of attribute easy_handles.



3
4
5
# File 'lib/typhoeus/multi.rb', line 3

def easy_handles
  @easy_handles
end

Class Method Details

.finalizer(multi) ⇒ Object



23
24
25
# File 'lib/typhoeus/multi.rb', line 23

def self.finalizer(multi)
  proc { Curl.multi_cleanup(multi.handle) }
end

Instance Method Details

#add(easy) ⇒ Object

Raises:

  • (RuntimeError)


27
28
29
30
31
32
33
34
35
36
37
38
39
# File 'lib/typhoeus/multi.rb', line 27

def add(easy)
  raise "trying to add easy handle twice" if @easy_handles.include?(easy)
  easy.set_headers() if easy.headers.empty?

  code = Curl.multi_add_handle(@handle, easy.handle)
  raise RuntimeError.new("An error occured adding the handle: #{code}: #{Curl.multi_strerror(code)}") if code != :call_multi_perform and code != :ok

  do_perform if code == :call_multi_perform

  @active += 1
  @easy_handles << easy
  easy
end

#cleanupObject



116
117
118
119
120
121
# File 'lib/typhoeus/multi.rb', line 116

def cleanup
  Curl.multi_cleanup(@handle)
  @active = 0
  @running = 0
  @easy_handles = []
end

#fire_and_forgetObject



89
90
91
# File 'lib/typhoeus/multi.rb', line 89

def fire_and_forget
  run
end

#performObject



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
# File 'lib/typhoeus/multi.rb', line 49

def perform
  while @active > 0
    run
    while @running > 0
      # get the curl-suggested timeout
      code = Curl.multi_timeout(@handle, @timeout)
      raise RuntimeError.new("an error occured getting the timeout: #{code}: #{Curl.multi_strerror(code)}") if code != :ok
      timeout = @timeout.read_long
      if timeout == 0 # no delay
        run
        next
      elsif timeout < 0
        timeout = 1
      end

      # load the fd sets from the multi handle
      @fd_read.clear
      @fd_write.clear
      @fd_excep.clear
      code = Curl.multi_fdset(@handle, @fd_read, @fd_write, @fd_excep, @max_fd)
      raise RuntimeError.new("an error occured getting the fdset: #{code}: #{Curl.multi_strerror(code)}") if code != :ok

      max_fd = @max_fd.read_int
      if max_fd == -1
        # curl is doing something special so let it run for a moment
        sleep(0.001)
      else
        @timeval[:sec] = timeout / 1000
        @timeval[:usec] = (timeout * 1000) % 1000000

        code = Curl.select(max_fd + 1, @fd_read, @fd_write, @fd_excep, @timeval)
        raise RuntimeError.new("error on thread select: #{::FFI.errno}") if code < 0
      end

      run
    end
  end
  reset_easy_handles
end

#read_infoObject

check for finished easy handles and remove from the multi handle



94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/typhoeus/multi.rb', line 94

def read_info
  msgs_left = ::FFI::MemoryPointer.new(:int)
  while not (msg = Curl.multi_info_read(@handle, msgs_left)).null?
    next if msg[:code] != :done

    easy = @easy_handles.find {|easy| easy.handle == msg[:easy_handle] }
    next if not easy

    response_code = ::FFI::MemoryPointer.new(:long)
    response_code.write_long(-1)
    Curl.easy_getinfo(easy.handle, :response_code, response_code)
    response_code = response_code.read_long
    remove(easy)

    easy.curl_return_code = msg[:data][:code]
    if easy.curl_return_code != 0 then easy.failure
    elsif (200..299).member?(response_code) or response_code == 0 then easy.success
    else easy.failure
    end
  end
end

#remove(easy) ⇒ Object



41
42
43
44
45
46
47
# File 'lib/typhoeus/multi.rb', line 41

def remove(easy)
  if @easy_handles.include?(easy)
    @active -= 1
    Curl.multi_remove_handle(@handle, easy.handle)
    @easy_handles.delete(easy)
  end
end

#reset_easy_handlesObject



123
124
125
126
127
128
# File 'lib/typhoeus/multi.rb', line 123

def reset_easy_handles
  @easy_handles.dup.each do |easy|
    remove(easy)
    yield easy if block_given?
  end
end