Class: Ferrum::Context
- Inherits:
-
Object
- Object
- Ferrum::Context
- Defined in:
- lib/ferrum/context.rb
Overview
Represents a browser context, i.e. an isolated browsing profile (similar to an incognito window) with its own cookies, cache and storage. Keeps track of the Targets that belong to it and connects to them as Pages or Workers. Managed by Contexts, which owns the browser's collection of contexts and routes CDP target events to the right one.
Constant Summary collapse
- POSITION =
%i[first last].freeze
Instance Attribute Summary collapse
-
#id ⇒ Object
readonly
Returns the value of attribute id.
-
#targets ⇒ Object
readonly
Returns the value of attribute targets.
Instance Method Summary collapse
-
#add_target(params:, session_id: nil) ⇒ Target
Registers a target discovered via a CDP
Target.*event, or updates the session id on one already known. -
#attach_target(target_id) ⇒ Object
Manually attaches to a target, e.g.
-
#close_targets_connection ⇒ void
Closes the WebSocket connection of every connected target, without disposing the targets themselves.
-
#create_page(**options) ⇒ Page
Creates a new target in this context and eagerly connects to it as a Page, forwarding
optionsto Target#build_page. -
#create_target ⇒ Target
Creates a new target in this context via
Target.createTargetand blocks until it's been registered (see #add_target). -
#default_target ⇒ Target
The context's first known target, creating one via
Target.createTargetif none has attached yet. -
#delete_target(target_id) ⇒ Target?
Removes a target, e.g.
-
#dispose ⇒ Boolean
Disposes this browser context and all of its targets.
-
#find_target ⇒ Target?
Returns the first target for which the block returns truthy.
-
#initialize(client, contexts, id) ⇒ Context
constructor
A new instance of Context.
-
#inspect ⇒ String
Debug representation of the context, including its known targets.
-
#page ⇒ Page
Connects to and returns the #default_target's page.
-
#pages ⇒ Array<Page>
All page targets in this context, connected to as Pages.
-
#service_workers ⇒ Array<Target>
Service worker targets registered in this context.
-
#target?(target_id) ⇒ Boolean
Whether a target with the given id is known in this context.
-
#update_target(target_id, params) ⇒ void
Updates a known target's params, e.g.
-
#windows(pos = nil, size = 1) ⇒ Object
When we call
pagemethod on target it triggers ruby to connect to given page by WebSocket, if there are many opened windows, but we need only one it makes more sense to get and connect to the needed one only which usually is the last one. -
#workers ⇒ Array<Worker>
Dedicated and shared workers spawned by any page in this context.
Constructor Details
#initialize(client, contexts, id) ⇒ Context
Returns a new instance of Context.
18 19 20 21 22 23 24 |
# File 'lib/ferrum/context.rb', line 18 def initialize(client, contexts, id) @id = id @client = client @contexts = contexts @targets = Concurrent::Map.new @pendings = Concurrent::Map.new end |
Instance Attribute Details
#id ⇒ Object (readonly)
Returns the value of attribute id.
16 17 18 |
# File 'lib/ferrum/context.rb', line 16 def id @id end |
#targets ⇒ Object (readonly)
Returns the value of attribute targets.
16 17 18 |
# File 'lib/ferrum/context.rb', line 16 def targets @targets end |
Instance Method Details
#add_target(params:, session_id: nil) ⇒ Target
Registers a target discovered via a CDP Target.* event, or updates
the session id on one already known. Called by Ferrum::Contexts as targets
are created/attached.
116 117 118 119 120 121 122 123 124 125 126 127 128 |
# File 'lib/ferrum/context.rb', line 116 def add_target(params:, session_id: nil) new_target = Target.new(@client, session_id, params) # `put_if_absent` returns nil if added a new value or existing if there was one already target = @targets.put_if_absent(new_target.id, new_target) || new_target # on first iteration session_id may be nil, then if session is present here we must set it to the target target.session_id = session_id if session_id && target.session_id.nil? @default_target ||= target new_pending = Concurrent::IVar.new pending = @pendings.put_if_absent(target.id, new_pending) || new_pending pending.try_set(true) target end |
#attach_target(target_id) ⇒ Object
Manually attaches to a target, e.g. a service worker discovered via
#service_workers. Once attached, target.worker/target.page
returns a connected Worker/Page for it.
Note: attaching to a service worker's session prevents Chrome from ever terminating it while the connection is open.
156 157 158 159 160 161 162 163 164 |
# File 'lib/ferrum/context.rb', line 156 def attach_target(target_id) target = @targets[target_id] raise NoSuchTargetError unless target @contexts.manually_attached(target_id) session = @client.command("Target.attachToTarget", targetId: target_id, flatten: true) target.session_id = session["sessionId"] true end |
#close_targets_connection ⇒ void
This method returns an undefined value.
Closes the WebSocket connection of every connected target, without disposing the targets themselves.
179 180 181 182 183 184 185 |
# File 'lib/ferrum/context.rb', line 179 def close_targets_connection @targets.each_value do |target| next unless target.connected? target.close_connection end end |
#create_page(**options) ⇒ Page
Creates a new target in this context and eagerly connects to it as a
Page, forwarding options to Target#build_page.
83 84 85 86 |
# File 'lib/ferrum/context.rb', line 83 def create_page(**) target = create_target target.page = target.build_page(**) end |
#create_target ⇒ Target
Creates a new target in this context via Target.createTarget and
blocks until it's been registered (see #add_target).
94 95 96 97 98 99 100 101 102 103 104 |
# File 'lib/ferrum/context.rb', line 94 def create_target target_id = @client.command("Target.createTarget", browserContextId: @id, url: "about:blank")["targetId"] new_pending = Concurrent::IVar.new pending = @pendings.put_if_absent(target_id, new_pending) || new_pending resolved = pending.value(@client.protocol_timeout) raise NoSuchTargetError unless resolved @pendings.delete(target_id) @targets[target_id] end |
#default_target ⇒ Target
The context's first known target, creating one via
Target.createTarget if none has attached yet.
30 31 32 |
# File 'lib/ferrum/context.rb', line 30 def default_target @default_target ||= create_target end |
#delete_target(target_id) ⇒ Target?
Removes a target, e.g. on Target.targetDestroyed/targetCrashed.
146 147 148 |
# File 'lib/ferrum/context.rb', line 146 def delete_target(target_id) @targets.delete(target_id) end |
#dispose ⇒ Boolean
Disposes this browser context and all of its targets.
190 191 192 |
# File 'lib/ferrum/context.rb', line 190 def dispose @contexts.dispose(@id) end |
#find_target ⇒ Target?
Returns the first target for which the block returns truthy.
169 170 171 172 173 |
# File 'lib/ferrum/context.rb', line 169 def find_target @targets.each_value { |t| return t if yield(t) } nil end |
#inspect ⇒ String
Debug representation of the context, including its known targets.
206 207 208 |
# File 'lib/ferrum/context.rb', line 206 def inspect %(#<#{self.class} @id=#{@id.inspect} @targets=#{@targets.inspect} @default_target=#{@default_target.inspect}>) end |
#page ⇒ Page
Connects to and returns the #default_target's page.
37 38 39 |
# File 'lib/ferrum/context.rb', line 37 def page default_target.page end |
#pages ⇒ Array<Page>
All page targets in this context, connected to as Pages.
44 45 46 |
# File 'lib/ferrum/context.rb', line 44 def pages @targets.values.select(&:page?).map(&:page) end |
#service_workers ⇒ Array<Target>
61 62 63 |
# File 'lib/ferrum/context.rb', line 61 def service_workers @targets.values.select(&:service_worker?) end |
#target?(target_id) ⇒ Boolean
Whether a target with the given id is known in this context.
199 200 201 |
# File 'lib/ferrum/context.rb', line 199 def target?(target_id) !!@targets[target_id] end |
#update_target(target_id, params) ⇒ void
This method returns an undefined value.
Updates a known target's params, e.g. on Target.targetInfoChanged.
137 138 139 |
# File 'lib/ferrum/context.rb', line 137 def update_target(target_id, params) @targets[target_id]&.update(params) end |
#windows(pos = nil, size = 1) ⇒ Object
When we call page method on target it triggers ruby to connect to given
page by WebSocket, if there are many opened windows, but we need only one
it makes more sense to get and connect to the needed one only which
usually is the last one.
69 70 71 72 73 74 75 |
# File 'lib/ferrum/context.rb', line 69 def windows(pos = nil, size = 1) raise ArgumentError if pos && !POSITION.include?(pos) windows = @targets.values.select(&:window?) windows = windows.send(pos, size) if pos windows.map(&:page) end |
#workers ⇒ Array<Worker>
Dedicated and shared workers spawned by any page in this context.
51 52 53 |
# File 'lib/ferrum/context.rb', line 51 def workers @targets.values.select { |t| t.worker? || t.shared_worker? }.map(&:worker) end |