ferrum 0.13 → 0.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +1 -1
  3. data/README.md +288 -154
  4. data/lib/ferrum/browser/command.rb +8 -0
  5. data/lib/ferrum/browser/options/chrome.rb +17 -5
  6. data/lib/ferrum/browser/options.rb +38 -25
  7. data/lib/ferrum/browser/process.rb +44 -17
  8. data/lib/ferrum/browser.rb +34 -52
  9. data/lib/ferrum/client/subscriber.rb +76 -0
  10. data/lib/ferrum/{browser → client}/web_socket.rb +36 -22
  11. data/lib/ferrum/client.rb +169 -0
  12. data/lib/ferrum/context.rb +19 -15
  13. data/lib/ferrum/contexts.rb +46 -12
  14. data/lib/ferrum/cookies/cookie.rb +57 -0
  15. data/lib/ferrum/cookies.rb +40 -4
  16. data/lib/ferrum/downloads.rb +60 -0
  17. data/lib/ferrum/errors.rb +2 -1
  18. data/lib/ferrum/frame.rb +1 -0
  19. data/lib/ferrum/headers.rb +1 -1
  20. data/lib/ferrum/network/exchange.rb +29 -2
  21. data/lib/ferrum/network/intercepted_request.rb +8 -17
  22. data/lib/ferrum/network/request.rb +23 -39
  23. data/lib/ferrum/network/request_params.rb +57 -0
  24. data/lib/ferrum/network/response.rb +25 -5
  25. data/lib/ferrum/network.rb +43 -16
  26. data/lib/ferrum/node.rb +21 -1
  27. data/lib/ferrum/page/frames.rb +5 -5
  28. data/lib/ferrum/page/screenshot.rb +42 -24
  29. data/lib/ferrum/page.rb +183 -131
  30. data/lib/ferrum/proxy.rb +1 -1
  31. data/lib/ferrum/target.rb +25 -5
  32. data/lib/ferrum/utils/elapsed_time.rb +0 -2
  33. data/lib/ferrum/utils/event.rb +19 -0
  34. data/lib/ferrum/utils/platform.rb +4 -0
  35. data/lib/ferrum/utils/thread.rb +18 -0
  36. data/lib/ferrum/version.rb +1 -1
  37. data/lib/ferrum.rb +3 -0
  38. metadata +14 -114
  39. data/lib/ferrum/browser/client.rb +0 -102
  40. data/lib/ferrum/browser/subscriber.rb +0 -36
data/lib/ferrum.rb CHANGED
@@ -1,5 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "concurrent-ruby"
4
+ require "ferrum/utils/event"
5
+ require "ferrum/utils/thread"
3
6
  require "ferrum/utils/platform"
4
7
  require "ferrum/utils/elapsed_time"
5
8
  require "ferrum/utils/attempt"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ferrum
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.13'
4
+ version: '0.15'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dmitry Vorotilin
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-11-12 00:00:00.000000000 Z
11
+ date: 2024-02-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: addressable
@@ -55,121 +55,17 @@ dependencies:
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: websocket-driver
57
57
  requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - ">="
60
- - !ruby/object:Gem::Version
61
- version: '0.6'
62
- - - "<"
63
- - !ruby/object:Gem::Version
64
- version: '0.8'
65
- type: :runtime
66
- prerelease: false
67
- version_requirements: !ruby/object:Gem::Requirement
68
- requirements:
69
- - - ">="
70
- - !ruby/object:Gem::Version
71
- version: '0.6'
72
- - - "<"
73
- - !ruby/object:Gem::Version
74
- version: '0.8'
75
- - !ruby/object:Gem::Dependency
76
- name: chunky_png
77
- requirement: !ruby/object:Gem::Requirement
78
- requirements:
79
- - - "~>"
80
- - !ruby/object:Gem::Version
81
- version: '1.3'
82
- type: :development
83
- prerelease: false
84
- version_requirements: !ruby/object:Gem::Requirement
85
- requirements:
86
- - - "~>"
87
- - !ruby/object:Gem::Version
88
- version: '1.3'
89
- - !ruby/object:Gem::Dependency
90
- name: image_size
91
- requirement: !ruby/object:Gem::Requirement
92
- requirements:
93
- - - "~>"
94
- - !ruby/object:Gem::Version
95
- version: '2.0'
96
- type: :development
97
- prerelease: false
98
- version_requirements: !ruby/object:Gem::Requirement
99
- requirements:
100
- - - "~>"
101
- - !ruby/object:Gem::Version
102
- version: '2.0'
103
- - !ruby/object:Gem::Dependency
104
- name: pdf-reader
105
- requirement: !ruby/object:Gem::Requirement
106
- requirements:
107
- - - "~>"
108
- - !ruby/object:Gem::Version
109
- version: '2.2'
110
- type: :development
111
- prerelease: false
112
- version_requirements: !ruby/object:Gem::Requirement
113
58
  requirements:
114
59
  - - "~>"
115
60
  - !ruby/object:Gem::Version
116
- version: '2.2'
117
- - !ruby/object:Gem::Dependency
118
- name: puma
119
- requirement: !ruby/object:Gem::Requirement
120
- requirements:
121
- - - "~>"
122
- - !ruby/object:Gem::Version
123
- version: '4.1'
124
- type: :development
125
- prerelease: false
126
- version_requirements: !ruby/object:Gem::Requirement
127
- requirements:
128
- - - "~>"
129
- - !ruby/object:Gem::Version
130
- version: '4.1'
131
- - !ruby/object:Gem::Dependency
132
- name: rake
133
- requirement: !ruby/object:Gem::Requirement
134
- requirements:
135
- - - "~>"
136
- - !ruby/object:Gem::Version
137
- version: '13.0'
138
- type: :development
139
- prerelease: false
140
- version_requirements: !ruby/object:Gem::Requirement
141
- requirements:
142
- - - "~>"
143
- - !ruby/object:Gem::Version
144
- version: '13.0'
145
- - !ruby/object:Gem::Dependency
146
- name: rspec
147
- requirement: !ruby/object:Gem::Requirement
148
- requirements:
149
- - - "~>"
150
- - !ruby/object:Gem::Version
151
- version: '3.8'
152
- type: :development
153
- prerelease: false
154
- version_requirements: !ruby/object:Gem::Requirement
155
- requirements:
156
- - - "~>"
157
- - !ruby/object:Gem::Version
158
- version: '3.8'
159
- - !ruby/object:Gem::Dependency
160
- name: sinatra
161
- requirement: !ruby/object:Gem::Requirement
162
- requirements:
163
- - - "~>"
164
- - !ruby/object:Gem::Version
165
- version: '2.0'
166
- type: :development
61
+ version: '0.7'
62
+ type: :runtime
167
63
  prerelease: false
168
64
  version_requirements: !ruby/object:Gem::Requirement
169
65
  requirements:
170
66
  - - "~>"
171
67
  - !ruby/object:Gem::Version
172
- version: '2.0'
68
+ version: '0.7'
173
69
  description: Ferrum allows you to control headless Chrome browser
174
70
  email:
175
71
  - d.vorotilin@gmail.com
@@ -182,22 +78,23 @@ files:
182
78
  - lib/ferrum.rb
183
79
  - lib/ferrum/browser.rb
184
80
  - lib/ferrum/browser/binary.rb
185
- - lib/ferrum/browser/client.rb
186
81
  - lib/ferrum/browser/command.rb
187
82
  - lib/ferrum/browser/options.rb
188
83
  - lib/ferrum/browser/options/base.rb
189
84
  - lib/ferrum/browser/options/chrome.rb
190
85
  - lib/ferrum/browser/options/firefox.rb
191
86
  - lib/ferrum/browser/process.rb
192
- - lib/ferrum/browser/subscriber.rb
193
87
  - lib/ferrum/browser/version_info.rb
194
- - lib/ferrum/browser/web_socket.rb
195
88
  - lib/ferrum/browser/xvfb.rb
89
+ - lib/ferrum/client.rb
90
+ - lib/ferrum/client/subscriber.rb
91
+ - lib/ferrum/client/web_socket.rb
196
92
  - lib/ferrum/context.rb
197
93
  - lib/ferrum/contexts.rb
198
94
  - lib/ferrum/cookies.rb
199
95
  - lib/ferrum/cookies/cookie.rb
200
96
  - lib/ferrum/dialog.rb
97
+ - lib/ferrum/downloads.rb
201
98
  - lib/ferrum/errors.rb
202
99
  - lib/ferrum/frame.rb
203
100
  - lib/ferrum/frame/dom.rb
@@ -212,6 +109,7 @@ files:
212
109
  - lib/ferrum/network/exchange.rb
213
110
  - lib/ferrum/network/intercepted_request.rb
214
111
  - lib/ferrum/network/request.rb
112
+ - lib/ferrum/network/request_params.rb
215
113
  - lib/ferrum/network/response.rb
216
114
  - lib/ferrum/node.rb
217
115
  - lib/ferrum/page.rb
@@ -225,7 +123,9 @@ files:
225
123
  - lib/ferrum/target.rb
226
124
  - lib/ferrum/utils/attempt.rb
227
125
  - lib/ferrum/utils/elapsed_time.rb
126
+ - lib/ferrum/utils/event.rb
228
127
  - lib/ferrum/utils/platform.rb
128
+ - lib/ferrum/utils/thread.rb
229
129
  - lib/ferrum/version.rb
230
130
  homepage: https://github.com/rubycdp/ferrum
231
131
  licenses:
@@ -245,14 +145,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
245
145
  requirements:
246
146
  - - ">="
247
147
  - !ruby/object:Gem::Version
248
- version: 2.6.0
148
+ version: 2.7.0
249
149
  required_rubygems_version: !ruby/object:Gem::Requirement
250
150
  requirements:
251
151
  - - ">="
252
152
  - !ruby/object:Gem::Version
253
153
  version: '0'
254
154
  requirements: []
255
- rubygems_version: 3.3.7
155
+ rubygems_version: 3.5.6
256
156
  signing_key:
257
157
  specification_version: 4
258
158
  summary: Ruby headless Chrome driver
@@ -1,102 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "ferrum/browser/subscriber"
4
- require "ferrum/browser/web_socket"
5
-
6
- module Ferrum
7
- class Browser
8
- class Client
9
- INTERRUPTIONS = %w[Fetch.requestPaused Fetch.authRequired].freeze
10
-
11
- def initialize(ws_url, connectable, logger: nil, ws_max_receive_size: nil, id_starts_with: 0)
12
- @connectable = connectable
13
- @command_id = id_starts_with
14
- @pendings = Concurrent::Hash.new
15
- @ws = WebSocket.new(ws_url, ws_max_receive_size, logger)
16
- @subscriber, @interrupter = Subscriber.build(2)
17
-
18
- @thread = Thread.new do
19
- Thread.current.abort_on_exception = true
20
- Thread.current.report_on_exception = true if Thread.current.respond_to?(:report_on_exception=)
21
-
22
- loop do
23
- message = @ws.messages.pop
24
- break unless message
25
-
26
- if INTERRUPTIONS.include?(message["method"])
27
- @interrupter.async.call(message)
28
- elsif message.key?("method")
29
- @subscriber.async.call(message)
30
- else
31
- @pendings[message["id"]]&.set(message)
32
- end
33
- end
34
- end
35
- end
36
-
37
- def command(method, params = {})
38
- pending = Concurrent::IVar.new
39
- message = build_message(method, params)
40
- @pendings[message[:id]] = pending
41
- @ws.send_message(message)
42
- data = pending.value!(@connectable.timeout)
43
- @pendings.delete(message[:id])
44
-
45
- raise DeadBrowserError if data.nil? && @ws.messages.closed?
46
- raise TimeoutError unless data
47
-
48
- error, response = data.values_at("error", "result")
49
- raise_browser_error(error) if error
50
- response
51
- end
52
-
53
- def on(event, &block)
54
- case event
55
- when *INTERRUPTIONS
56
- @interrupter.on(event, &block)
57
- else
58
- @subscriber.on(event, &block)
59
- end
60
- end
61
-
62
- def subscribed?(event)
63
- [@interrupter, @subscriber].any? { |s| s.subscribed?(event) }
64
- end
65
-
66
- def close
67
- @ws.close
68
- # Give a thread some time to handle a tail of messages
69
- @pendings.clear
70
- @thread.kill unless @thread.join(1)
71
- end
72
-
73
- private
74
-
75
- def build_message(method, params)
76
- { method: method, params: params }.merge(id: next_command_id)
77
- end
78
-
79
- def next_command_id
80
- @command_id += 1
81
- end
82
-
83
- def raise_browser_error(error)
84
- case error["message"]
85
- # Node has disappeared while we were trying to get it
86
- when "No node with given id found",
87
- "Could not find node with given id"
88
- raise NodeNotFoundError, error
89
- # Context is lost, page is reloading
90
- when "Cannot find context with specified id"
91
- raise NoExecutionContextError, error
92
- when "No target with given id found"
93
- raise NoSuchPageError
94
- when /Could not compute content quads/
95
- raise CoordinatesNotFoundError
96
- else
97
- raise BrowserError, error
98
- end
99
- end
100
- end
101
- end
102
- end
@@ -1,36 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Ferrum
4
- class Browser
5
- class Subscriber
6
- include Concurrent::Async
7
-
8
- def self.build(size)
9
- (0..size).map { new }
10
- end
11
-
12
- def initialize
13
- super
14
- @on = Concurrent::Hash.new { |h, k| h[k] = Concurrent::Array.new }
15
- end
16
-
17
- def on(event, &block)
18
- @on[event] << block
19
- true
20
- end
21
-
22
- def subscribed?(event)
23
- @on.key?(event)
24
- end
25
-
26
- def call(message)
27
- method, params = message.values_at("method", "params")
28
- total = @on[method].size
29
- @on[method].each_with_index do |block, index|
30
- # In case of multiple callbacks we provide current index and total
31
- block.call(params, index, total)
32
- end
33
- end
34
- end
35
- end
36
- end