Class: Puppeteer::Browser

Inherits:
Object
  • Object
show all
Includes:
DebugPrint, EventCallbackable, IfPresent
Defined in:
lib/puppeteer/browser.rb

Defined Under Namespace

Classes: TargetAlreadyExistError, TargetNotExistError, Version

Class Method Summary collapse

Instance Method Summary collapse

Methods included from IfPresent

#if_present

Methods included from EventCallbackable

#add_event_listener, #emit_event, #observe_first, #on_event, #remove_event_listener

Methods included from DebugPrint

#debug_print, #debug_puts

Constructor Details

#initialize(connection:, context_ids:, ignore_https_errors:, default_viewport:, process:, close_callback:) ⇒ Browser



35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/puppeteer/browser.rb', line 35

def initialize(connection:, context_ids:, ignore_https_errors:, default_viewport:, process:, close_callback:)
  @ignore_https_errors = ignore_https_errors
  @default_viewport = default_viewport
  @process = process
  @connection = connection
  @close_callback = close_callback

  @default_context = Puppeteer::BrowserContext.new(@connection, self, nil)
  @contexts = {}
  context_ids.each do |context_id|
    @contexts[context_id] = Puppeteer::BrowserContext.new(@connection, self, context_id)
  end
  @targets = {}
  @wait_for_creating_targets = {}
  @connection.on_event(ConnectionEmittedEvents::Disconnected) do
    emit_event(BrowserEmittedEvents::Disconnected)
  end
  @connection.on_event('Target.targetCreated', &method(:handle_target_created))
  @connection.on_event('Target.targetDestroyed', &method(:handle_target_destroyed))
  @connection.on_event('Target.targetInfoChanged', &method(:handle_target_info_changed))
end

Class Method Details

.create(connection:, context_ids:, ignore_https_errors:, default_viewport:, process:, close_callback:) ⇒ Object



16
17
18
19
20
21
22
23
24
25
26
27
# File 'lib/puppeteer/browser.rb', line 16

def self.create(connection:, context_ids:, ignore_https_errors:, default_viewport:, process:, close_callback:)
  browser = Puppeteer::Browser.new(
    connection: connection,
    context_ids: context_ids,
    ignore_https_errors: ignore_https_errors,
    default_viewport: default_viewport,
    process: process,
    close_callback: close_callback,
  )
  connection.send_message('Target.setDiscoverTargets', discover: true)
  browser
end

Instance Method Details

#async_wait_for_target(predicate: , timeout: nil) ⇒ Object



255
# File 'lib/puppeteer/browser.rb', line 255

define_async_method :async_wait_for_target

#browser_contextsObject



87
88
89
# File 'lib/puppeteer/browser.rb', line 87

def browser_contexts
  [@default_context].concat(@contexts.values)
end

#closeObject



272
273
274
275
# File 'lib/puppeteer/browser.rb', line 272

def close
  @close_callback.call
  disconnect
end

#connected?Boolean



281
282
283
# File 'lib/puppeteer/browser.rb', line 281

def connected?
  !@connection.closed?
end

#create_incognito_browser_contextPuppeteer::BrowserContext



81
82
83
84
85
# File 'lib/puppeteer/browser.rb', line 81

def create_incognito_browser_context
  result = @connection.send_message('Target.createBrowserContext')
  browser_context_id = result['browserContextId']
  @contexts[browser_context_id] = Puppeteer::BrowserContext.new(@connection, self, browser_context_id)
end

#create_page_in_context(context_id) ⇒ !Promise<!Puppeteer.Page>



185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
# File 'lib/puppeteer/browser.rb', line 185

def create_page_in_context(context_id)
  create_target_params = { url: 'about:blank' }
  if context_id
    create_target_params[:browserContextId] = context_id
  end
  result = @connection.send_message('Target.createTarget', **create_target_params)
  target_id = result['targetId']
  target = @targets[target_id]
  unless target
    # Target.targetCreated is often notified before the response of Target.createdTarget.
    # https://github.com/YusukeIwaki/puppeteer-ruby/issues/91
    # D, [2021-04-07T03:00:10.125241 #187] DEBUG -- : SEND >> {"method":"Target.createTarget","params":{"url":"about:blank","browserContextId":"56A86FC3391B50180CF9A6450A0D8C21"},"id":3}
    # D, [2021-04-07T03:00:10.142396 #187] DEBUG -- : RECV << {"id"=>3, "result"=>{"targetId"=>"A518447C415A1A3E1A8979454A155632"}}
    # D, [2021-04-07T03:00:10.145360 #187] DEBUG -- : RECV << {"method"=>"Target.targetCreated", "params"=>{"targetInfo"=>{"targetId"=>"A518447C415A1A3E1A8979454A155632", "type"=>"page", "title"=>"", "url"=>"", "attached"=>false, "canAccessOpener"=>false, "browserContextId"=>"56A86FC3391B50180CF9A6450A0D8C21"}}}
    # This is just a workaround logic...
    @wait_for_creating_targets[target_id] = resolvable_future
    target = await @wait_for_creating_targets[target_id]
  end
  await target.initialized_promise
  await target.page
end

#default_browser_contextPuppeteer::BrowserContext



92
93
94
# File 'lib/puppeteer/browser.rb', line 92

def default_browser_context
  @default_context
end

#disconnectObject



277
278
279
# File 'lib/puppeteer/browser.rb', line 277

def disconnect
  @connection.dispose
end

#dispose_context(context_id) ⇒ Object



97
98
99
100
# File 'lib/puppeteer/browser.rb', line 97

def dispose_context(context_id)
  @connection.send_message('Target.disposeBrowserContext', browserContextId: context_id)
  @contexts.delete(context_id)
end

#handle_target_created(event) ⇒ Object



109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# File 'lib/puppeteer/browser.rb', line 109

def handle_target_created(event)
  target_info = Puppeteer::Target::TargetInfo.new(event['targetInfo'])
  browser_context_id = target_info.browser_context_id
  context =
    if browser_context_id && @contexts.has_key?(browser_context_id)
      @contexts[browser_context_id]
    else
      @default_context
    end

  if @targets[target_info.target_id]
    raise TargetAlreadyExistError.new
  end
  target = Puppeteer::Target.new(
    target_info: target_info,
    browser_context: context,
    session_factory: -> { @connection.create_session(target_info) },
    ignore_https_errors: @ignore_https_errors,
    default_viewport: @default_viewport,
  )
  @targets[target_info.target_id] = target
  if_present(@wait_for_creating_targets.delete(target_info.target_id)) do |promise|
    promise.fulfill(target)
  end
  if await target.initialized_promise
    emit_event(BrowserEmittedEvents::TargetCreated, target)
    context.emit_event(BrowserContextEmittedEvents::TargetCreated, target)
  end
end

#handle_target_destroyed(event) ⇒ Object



140
141
142
143
144
145
146
147
148
149
150
151
152
153
# File 'lib/puppeteer/browser.rb', line 140

def handle_target_destroyed(event)
  target_id = event['targetId']
  target = @targets[target_id]
  target.ignore_initialize_callback_promise
  @targets.delete(target_id)
  if_present(@wait_for_creating_targets.delete(target_id)) do |promise|
    promise.reject('target destroyed')
  end
  target.closed_callback
  if await target.initialized_promise
    emit_event(BrowserEmittedEvents::TargetDestroyed, target)
    target.browser_context.emit_event(BrowserContextEmittedEvents::TargetDestroyed, target)
  end
end

#handle_target_info_changed(event) ⇒ Object



162
163
164
165
166
167
168
169
170
171
172
# File 'lib/puppeteer/browser.rb', line 162

def handle_target_info_changed(event)
  target_info = Puppeteer::Target::TargetInfo.new(event['targetInfo'])
  target = @targets[target_info.target_id] or raise TargetNotExistError.new
  previous_url = target.url
  was_initialized = target.initialized?
  target.handle_target_info_changed(target_info)
  if was_initialized && previous_url != target.url
    emit_event(BrowserEmittedEvents::TargetChanged, target)
    target.browser_context.emit_event(BrowserContextEmittedEvents::TargetChanged, target)
  end
end

#new_pageObject



179
180
181
# File 'lib/puppeteer/browser.rb', line 179

def new_page
  @default_context.new_page
end

#on(event_name, &block) ⇒ Object



58
59
60
61
62
63
64
# File 'lib/puppeteer/browser.rb', line 58

def on(event_name, &block)
  unless BrowserEmittedEvents.values.include?(event_name.to_s)
    raise ArgumentError.new("Unknown event name: #{event_name}. Known events are #{BrowserEmittedEvents.values.to_a.join(", ")}")
  end

  super(event_name.to_s, &block)
end

#once(event_name, &block) ⇒ Object



67
68
69
70
71
72
73
# File 'lib/puppeteer/browser.rb', line 67

def once(event_name, &block)
  unless BrowserEmittedEvents.values.include?(event_name.to_s)
    raise ArgumentError.new("Unknown event name: #{event_name}. Known events are #{BrowserEmittedEvents.values.to_a.join(", ")}")
  end

  super(event_name.to_s, &block)
end

#pages!Promise<!Array<!Puppeteer.Page>>



258
259
260
# File 'lib/puppeteer/browser.rb', line 258

def pages
  browser_contexts.flat_map(&:pages)
end

#processPuppeteer::BrowserRunner::BrowserProcess



76
77
78
# File 'lib/puppeteer/browser.rb', line 76

def process
  @process
end

#target!Target



214
215
216
# File 'lib/puppeteer/browser.rb', line 214

def target
  targets.find { |target| target.type == 'browser' }
end

#targets!Array<!Target>



208
209
210
# File 'lib/puppeteer/browser.rb', line 208

def targets
  @targets.values.select { |target| target.initialized? }
end

#user_agentString



268
269
270
# File 'lib/puppeteer/browser.rb', line 268

def user_agent
  get_version.user_agent
end

#versionString



263
264
265
# File 'lib/puppeteer/browser.rb', line 263

def version
  get_version.product
end

#wait_for_target(predicate:, timeout: nil) ⇒ Puppeteer::Target



225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
# File 'lib/puppeteer/browser.rb', line 225

def wait_for_target(predicate:, timeout: nil)
  timeout_helper = Puppeteer::TimeoutHelper.new('target', timeout_ms: timeout, default_timeout_ms: 30000)
  existing_target = targets.find { |target| predicate.call(target) }
  return existing_target if existing_target

  event_listening_ids = []
  target_promise = resolvable_future
  event_listening_ids << add_event_listener(BrowserEmittedEvents::TargetCreated) do |target|
    if predicate.call(target)
      target_promise.fulfill(target)
    end
  end
  event_listening_ids << add_event_listener(BrowserEmittedEvents::TargetChanged) do |target|
    if predicate.call(target)
      target_promise.fulfill(target)
    end
  end

  begin
    timeout_helper.with_timeout do
      target_promise.value!
    end
  ensure
    remove_event_listener(*event_listening_ids)
  end
end

#ws_endpointString



175
176
177
# File 'lib/puppeteer/browser.rb', line 175

def ws_endpoint
  @connection.url
end