ferrum 0.14 → 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.
data/lib/ferrum/target.rb CHANGED
@@ -8,17 +8,21 @@ module Ferrum
8
8
  # where we enhance page class and build page ourselves.
9
9
  attr_writer :page
10
10
 
11
- def initialize(browser, params = nil)
11
+ attr_reader :session_id, :options
12
+
13
+ def initialize(browser_client, session_id = nil, params = nil)
12
14
  @page = nil
13
- @browser = browser
15
+ @session_id = session_id
14
16
  @params = params
17
+ @browser_client = browser_client
18
+ @options = browser_client.options
15
19
  end
16
20
 
17
21
  def update(params)
18
- @params = params
22
+ @params.merge!(params)
19
23
  end
20
24
 
21
- def attached?
25
+ def connected?
22
26
  !!@page
23
27
  end
24
28
 
@@ -26,9 +30,13 @@ module Ferrum
26
30
  @page ||= build_page
27
31
  end
28
32
 
33
+ def client
34
+ @client ||= build_client
35
+ end
36
+
29
37
  def build_page(**options)
30
38
  maybe_sleep_if_new_window
31
- Page.new(id, @browser, **options)
39
+ Page.new(client, context_id: context_id, target_id: id, **options)
32
40
  end
33
41
 
34
42
  def id
@@ -63,5 +71,17 @@ module Ferrum
63
71
  # Dirty hack because new window doesn't have events at all
64
72
  sleep(NEW_WINDOW_WAIT) if window?
65
73
  end
74
+
75
+ private
76
+
77
+ def build_client
78
+ return @browser_client.session(session_id) if options.flatten
79
+
80
+ Client.new(ws_url, options)
81
+ end
82
+
83
+ def ws_url
84
+ @browser_client.ws_url.merge(path: "/devtools/page/#{id}")
85
+ end
66
86
  end
67
87
  end
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "concurrent-ruby"
4
-
5
3
  module Ferrum
6
4
  module Utils
7
5
  module ElapsedTime
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ferrum
4
+ module Utils
5
+ class Event < Concurrent::Event
6
+ def iteration
7
+ synchronize { @iteration }
8
+ end
9
+
10
+ def reset
11
+ synchronize do
12
+ @iteration += 1
13
+ @set = false if @set
14
+ @iteration
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -20,6 +20,10 @@ module Ferrum
20
20
  RbConfig::CONFIG["host_os"] =~ /darwin/
21
21
  end
22
22
 
23
+ def mac_arm?
24
+ mac? && RbConfig::CONFIG["host_cpu"] =~ /arm/
25
+ end
26
+
23
27
  def mri?
24
28
  defined?(RUBY_ENGINE) && RUBY_ENGINE == "ruby"
25
29
  end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ferrum
4
+ module Utils
5
+ module Thread
6
+ module_function
7
+
8
+ def spawn(abort_on_exception: true)
9
+ ::Thread.new(abort_on_exception) do |whether_abort_on_exception|
10
+ ::Thread.current.abort_on_exception = whether_abort_on_exception
11
+ ::Thread.current.report_on_exception = true if ::Thread.current.respond_to?(:report_on_exception=)
12
+
13
+ yield
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Ferrum
4
- VERSION = "0.14"
4
+ VERSION = "0.15"
5
5
  end
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.14'
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: 2023-09-14 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
@@ -56,22 +56,16 @@ dependencies:
56
56
  name: websocket-driver
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - ">="
60
- - !ruby/object:Gem::Version
61
- version: '0.6'
62
- - - "<"
59
+ - - "~>"
63
60
  - !ruby/object:Gem::Version
64
- version: '0.8'
61
+ version: '0.7'
65
62
  type: :runtime
66
63
  prerelease: false
67
64
  version_requirements: !ruby/object:Gem::Requirement
68
65
  requirements:
69
- - - ">="
70
- - !ruby/object:Gem::Version
71
- version: '0.6'
72
- - - "<"
66
+ - - "~>"
73
67
  - !ruby/object:Gem::Version
74
- version: '0.8'
68
+ version: '0.7'
75
69
  description: Ferrum allows you to control headless Chrome browser
76
70
  email:
77
71
  - d.vorotilin@gmail.com
@@ -84,22 +78,23 @@ files:
84
78
  - lib/ferrum.rb
85
79
  - lib/ferrum/browser.rb
86
80
  - lib/ferrum/browser/binary.rb
87
- - lib/ferrum/browser/client.rb
88
81
  - lib/ferrum/browser/command.rb
89
82
  - lib/ferrum/browser/options.rb
90
83
  - lib/ferrum/browser/options/base.rb
91
84
  - lib/ferrum/browser/options/chrome.rb
92
85
  - lib/ferrum/browser/options/firefox.rb
93
86
  - lib/ferrum/browser/process.rb
94
- - lib/ferrum/browser/subscriber.rb
95
87
  - lib/ferrum/browser/version_info.rb
96
- - lib/ferrum/browser/web_socket.rb
97
88
  - lib/ferrum/browser/xvfb.rb
89
+ - lib/ferrum/client.rb
90
+ - lib/ferrum/client/subscriber.rb
91
+ - lib/ferrum/client/web_socket.rb
98
92
  - lib/ferrum/context.rb
99
93
  - lib/ferrum/contexts.rb
100
94
  - lib/ferrum/cookies.rb
101
95
  - lib/ferrum/cookies/cookie.rb
102
96
  - lib/ferrum/dialog.rb
97
+ - lib/ferrum/downloads.rb
103
98
  - lib/ferrum/errors.rb
104
99
  - lib/ferrum/frame.rb
105
100
  - lib/ferrum/frame/dom.rb
@@ -128,7 +123,9 @@ files:
128
123
  - lib/ferrum/target.rb
129
124
  - lib/ferrum/utils/attempt.rb
130
125
  - lib/ferrum/utils/elapsed_time.rb
126
+ - lib/ferrum/utils/event.rb
131
127
  - lib/ferrum/utils/platform.rb
128
+ - lib/ferrum/utils/thread.rb
132
129
  - lib/ferrum/version.rb
133
130
  homepage: https://github.com/rubycdp/ferrum
134
131
  licenses:
@@ -148,14 +145,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
148
145
  requirements:
149
146
  - - ">="
150
147
  - !ruby/object:Gem::Version
151
- version: 2.6.0
148
+ version: 2.7.0
152
149
  required_rubygems_version: !ruby/object:Gem::Requirement
153
150
  requirements:
154
151
  - - ">="
155
152
  - !ruby/object:Gem::Version
156
153
  version: '0'
157
154
  requirements: []
158
- rubygems_version: 3.4.13
155
+ rubygems_version: 3.5.6
159
156
  signing_key:
160
157
  specification_version: 4
161
158
  summary: Ruby headless Chrome driver
@@ -1,103 +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
- "Inspected target navigated or closed"
89
- raise NodeNotFoundError, error
90
- # Context is lost, page is reloading
91
- when "Cannot find context with specified id"
92
- raise NoExecutionContextError, error
93
- when "No target with given id found"
94
- raise NoSuchPageError
95
- when /Could not compute content quads/
96
- raise CoordinatesNotFoundError
97
- else
98
- raise BrowserError, error
99
- end
100
- end
101
- end
102
- end
103
- 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