puppeteer-ruby 0.50.0.alpha9 → 0.50.0.alpha10

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 904e4fe437eb2088c1c1f6650e840818b9d8b0be5d420cdf4aa33142dd7468a4
4
- data.tar.gz: 27ca94c22baf6edcf0ebf6173df06142a071803995a3c29462ccd00286adf723
3
+ metadata.gz: 6ad92e4a471db943a70ea1f6e928ba29e611cba0fc4b62b001bafb0cf444c797
4
+ data.tar.gz: 226103f1934651f038099e58a7b94414e248db9290f928c4fc2d4b262df59807
5
5
  SHA512:
6
- metadata.gz: a874a9d182af6525021f91a2cf3eeaeffe6fd5380eef345b8fd9e6bb896b3468543d67900af2b827a263a6c2adc0a8a85f06bf6d05241e4477033863dd6a4601
7
- data.tar.gz: 3d99750cef4daa4438786a581f8246d1f03c2920c0ff6bc3ebc7f2fbe5f97cbb47ea577faae87f45bf37933adfa7a40d3df6b3ae1347a2c37eeb3488e1142029
6
+ metadata.gz: 1ba290b15ba557824715b8aa82ad8695cdc9d08200381c7e004cb3c3fe63e041bc732e5e27f904e6bf75ff4eef51e6fdb905972d4225cfa495bbde9637a5f2ac
7
+ data.tar.gz: c7a208b38765265b77cef6f81dc1945daa6b4f4c09957c0b9b8e20484630a20a0359bbd3bbde26d5d88c1b55ea5c17cb02d522e358e294aa3db814685559a736
data/docs/api_coverage.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # API coverages
2
2
  - Puppeteer version: v24.35.0
3
- - puppeteer-ruby version: 0.50.0.alpha9
3
+ - puppeteer-ruby version: 0.50.0.alpha10
4
4
 
5
5
  ## Puppeteer
6
6
 
@@ -1,4 +1,5 @@
1
1
  require 'json'
2
+ require 'async/queue'
2
3
 
3
4
  class Puppeteer::Connection
4
5
  include Puppeteer::DebugPrint
@@ -44,11 +45,16 @@ class Puppeteer::Connection
44
45
  @delay = delay
45
46
  @protocol_timeout = protocol_timeout
46
47
 
48
+ @network_message_queue = Async::Queue.new
49
+ @network_message_task = nil
50
+
47
51
  @transport = transport
48
52
  @transport.on_message do |data|
49
53
  message = JSON.parse(data)
50
54
  sleep_before_handling_message(message)
51
- if should_handle_synchronously?(message)
55
+ if network_event_message?(message)
56
+ enqueue_network_message(message)
57
+ elsif should_handle_synchronously?(message)
52
58
  handle_message(message)
53
59
  else
54
60
  async_handle_message(message)
@@ -87,7 +93,8 @@ class Puppeteer::Connection
87
93
  when nil
88
94
  false
89
95
  when /^Network\./
90
- true
96
+ # Network events are queued for ordered async processing.
97
+ false
91
98
  when /^Page\.frame/
92
99
  # Page.frameAttached
93
100
  # Page.frameNavigated
@@ -112,6 +119,34 @@ class Puppeteer::Connection
112
119
  end
113
120
  end
114
121
 
122
+ private def network_event_message?(message)
123
+ message['method']&.start_with?('Network.')
124
+ end
125
+
126
+ private def ensure_network_message_task
127
+ return if @network_message_task&.alive?
128
+ return unless Async::Task.current?
129
+
130
+ @network_message_task = Async do
131
+ while (queued = @network_message_queue.dequeue)
132
+ handle_message(queued)
133
+ end
134
+ end
135
+ end
136
+
137
+ private def enqueue_network_message(message)
138
+ if Async::Task.current?
139
+ ensure_network_message_task
140
+ begin
141
+ @network_message_queue.enqueue(message)
142
+ rescue Async::Queue::ClosedError
143
+ # Connection is closing; ignore late network events.
144
+ end
145
+ else
146
+ handle_message(message)
147
+ end
148
+ end
149
+
115
150
  def self.from_session(session)
116
151
  session.connection
117
152
  end
@@ -310,6 +345,12 @@ class Puppeteer::Connection
310
345
  @closed = true
311
346
  @transport.on_message
312
347
  @transport.on_close
348
+ @network_message_queue.close
349
+ begin
350
+ @network_message_task&.stop
351
+ rescue Async::Stop
352
+ # Task already stopping; ignore.
353
+ end
313
354
  callbacks = @callbacks_mutex.synchronize do
314
355
  @callbacks.values.tap { @callbacks.clear }
315
356
  end
@@ -35,33 +35,48 @@ class Puppeteer::FrameManager
35
35
  # Keeps track of frames that are in the process of being attached in #onFrameAttached.
36
36
  @frames_pending_attachment = {}
37
37
  @frame_tree_handled_promise = nil
38
- @queued_lifecycle_events = []
38
+ @queued_frame_events = []
39
+ @frame_tree_mutex = Mutex.new
39
40
 
40
41
  setup_listeners(@client)
41
42
  end
42
43
 
43
44
  private def setup_listeners(client)
44
45
  client.on_event('Page.frameAttached') do |event|
45
- handle_frame_attached(client, event['frameId'], event['parentFrameId'])
46
+ with_frame_tree_handled do
47
+ handle_frame_attached(client, event['frameId'], event['parentFrameId'])
48
+ end
46
49
  end
47
50
  client.on_event('Page.frameNavigated') do |event|
48
- @frame_naviigated_received << event['frame']['id']
49
- handle_frame_navigated(event['frame'])
51
+ with_frame_tree_handled do
52
+ @frame_naviigated_received << event['frame']['id']
53
+ handle_frame_navigated(event['frame'])
54
+ end
50
55
  end
51
56
  client.on_event('Page.navigatedWithinDocument') do |event|
52
- handle_frame_navigated_within_document(event['frameId'], event['url'])
57
+ with_frame_tree_handled do
58
+ handle_frame_navigated_within_document(event['frameId'], event['url'])
59
+ end
53
60
  end
54
61
  client.on_event('Page.frameDetached') do |event|
55
- handle_frame_detached(event['frameId'], event['reason'])
62
+ with_frame_tree_handled do
63
+ handle_frame_detached(event['frameId'], event['reason'])
64
+ end
56
65
  end
57
66
  client.on_event('Page.frameStartedLoading') do |event|
58
- handle_frame_started_loading(event['frameId'])
67
+ with_frame_tree_handled do
68
+ handle_frame_started_loading(event['frameId'])
69
+ end
59
70
  end
60
71
  client.on_event('Page.frameStoppedLoading') do |event|
61
- handle_frame_stopped_loading(event['frameId'])
72
+ with_frame_tree_handled do
73
+ handle_frame_stopped_loading(event['frameId'])
74
+ end
62
75
  end
63
76
  client.on_event('Runtime.executionContextCreated') do |event|
64
- handle_execution_context_created(event['context'], client)
77
+ with_frame_tree_handled do
78
+ handle_execution_context_created(event['context'], client)
79
+ end
65
80
  end
66
81
  client.on_event('Runtime.executionContextDestroyed') do |event|
67
82
  handle_execution_context_destroyed(event['executionContextId'], client)
@@ -70,7 +85,9 @@ class Puppeteer::FrameManager
70
85
  handle_execution_contexts_cleared(client)
71
86
  end
72
87
  client.on_event('Page.lifecycleEvent') do |event|
73
- handle_lifecycle_event(event)
88
+ with_frame_tree_handled do
89
+ handle_lifecycle_event(event)
90
+ end
74
91
  end
75
92
  end
76
93
 
@@ -98,15 +115,13 @@ class Puppeteer::FrameManager
98
115
  rescue => err
99
116
  # The target might have been closed before the initialization finished.
100
117
  if err.message.include?('Target closed') || err.message.include?('Session closed')
101
- finish_frame_tree_handling(process_queue: false)
118
+ finish_frame_tree_handling
102
119
  return
103
120
  end
104
121
 
105
122
  raise
106
123
  ensure
107
- if @frame_tree_handled_promise && !@frame_tree_handled_promise.resolved?
108
- finish_frame_tree_handling(process_queue: false)
109
- end
124
+ finish_frame_tree_handling if @frame_tree_handled_promise && !@frame_tree_handled_promise.resolved?
110
125
  @frames_pending_target_init.delete(target_id)&.resolve(nil)
111
126
  end
112
127
 
@@ -224,21 +239,52 @@ class Puppeteer::FrameManager
224
239
 
225
240
  # @param event [Hash]
226
241
  def handle_lifecycle_event(event)
227
- if @frame_tree_handled_promise && !@frame_tree_handled_promise.resolved?
228
- @queued_lifecycle_events << event
229
- return
230
- end
231
-
232
- handle_lifecycle_event_impl(event)
233
- end
234
-
235
- private def handle_lifecycle_event_impl(event)
236
242
  frame = @frames[event['frameId']]
237
243
  return if !frame
238
244
  frame.handle_lifecycle_event(event['loaderId'], event['name'])
239
245
  emit_event(FrameManagerEmittedEvents::LifecycleEvent, frame)
240
246
  end
241
247
 
248
+ private def with_frame_tree_handled(&block)
249
+ promise = @frame_tree_handled_promise
250
+ if promise && !promise.resolved?
251
+ queued = false
252
+ @frame_tree_mutex.synchronize do
253
+ promise = @frame_tree_handled_promise
254
+ if promise && !promise.resolved?
255
+ @queued_frame_events << block
256
+ queued = true
257
+ end
258
+ end
259
+ return if queued
260
+ end
261
+ block.call
262
+ end
263
+
264
+ private def prepare_frame_tree_handling
265
+ queued = nil
266
+ @frame_tree_mutex.synchronize do
267
+ if @frame_tree_handled_promise && !@frame_tree_handled_promise.resolved?
268
+ @frame_tree_handled_promise.resolve(nil)
269
+ queued = @queued_frame_events
270
+ end
271
+ @queued_frame_events = []
272
+ @frame_tree_handled_promise = Async::Promise.new
273
+ end
274
+ queued&.each(&:call)
275
+ end
276
+
277
+ private def finish_frame_tree_handling
278
+ queued = nil
279
+ @frame_tree_mutex.synchronize do
280
+ return unless @frame_tree_handled_promise
281
+ @frame_tree_handled_promise.resolve(nil) unless @frame_tree_handled_promise.resolved?
282
+ queued = @queued_frame_events
283
+ @queued_frame_events = []
284
+ end
285
+ queued&.each(&:call)
286
+ end
287
+
242
288
  # @param frame_id [String]
243
289
  def handle_frame_started_loading(frame_id)
244
290
  frame = @frames[frame_id]
@@ -270,29 +316,6 @@ class Puppeteer::FrameManager
270
316
  end
271
317
  end
272
318
 
273
- private def prepare_frame_tree_handling
274
- if @frame_tree_handled_promise && !@frame_tree_handled_promise.resolved?
275
- @frame_tree_handled_promise.resolve(nil)
276
- end
277
- @frame_tree_handled_promise = Async::Promise.new
278
- @queued_lifecycle_events = []
279
- end
280
-
281
- private def finish_frame_tree_handling(process_queue: true)
282
- return unless @frame_tree_handled_promise
283
-
284
- @frame_tree_handled_promise.resolve(nil) unless @frame_tree_handled_promise.resolved?
285
- flush_queued_lifecycle_events if process_queue
286
- end
287
-
288
- private def flush_queued_lifecycle_events
289
- return if @queued_lifecycle_events.empty?
290
-
291
- queued = @queued_lifecycle_events
292
- @queued_lifecycle_events = []
293
- queued.each { |event| handle_lifecycle_event_impl(event) }
294
- end
295
-
296
319
  # @return {!Puppeteer.Page}
297
320
  def page
298
321
  @page
@@ -394,8 +417,11 @@ class Puppeteer::FrameManager
394
417
  if is_main_frame
395
418
  if frame
396
419
  # Update frame id to retain frame identity on cross-process navigation.
397
- @frames.delete(frame.id)
398
- frame.id = frame_id
420
+ if frame.id != frame_id
421
+ old_frame_id = frame.id
422
+ @frames.delete(old_frame_id)
423
+ frame.id = frame_id
424
+ end
399
425
  else
400
426
  # Initial main frame navigation.
401
427
  frame = Puppeteer::Frame.new(self, nil, frame_id, @client)
@@ -1,3 +1,3 @@
1
1
  module Puppeteer
2
- VERSION = '0.50.0.alpha9'
2
+ VERSION = '0.50.0.alpha10'
3
3
  end
@@ -178,10 +178,9 @@ class Puppeteer::FrameManager
178
178
 
179
179
  def setup_listeners: (Puppeteer::CDPSession client) -> void
180
180
  def init: (String target_id, ?Puppeteer::CDPSession cdp_session) -> void
181
- def handle_lifecycle_event_impl: (Hash[String, untyped] event) -> void
181
+ def with_frame_tree_handled: () { () -> void } -> void
182
182
  def prepare_frame_tree_handling: () -> void
183
- def finish_frame_tree_handling: (?process_queue: bool) -> void
184
- def flush_queued_lifecycle_events: () -> void
183
+ def finish_frame_tree_handling: () -> void
185
184
  def attach_child_frame: (Puppeteer::Frame parent_frame, String parent_frame_id, String frame_id, Puppeteer::CDPSession? session) -> void
186
185
  def reattach_frame: (Puppeteer::Frame frame, String frame_id, bool is_main_frame, Hash[String, untyped] frame_payload) -> void
187
186
  def ensure_isolated_world: (Puppeteer::CDPSession session, String name) -> void
@@ -290,6 +289,9 @@ class Puppeteer::Connection
290
289
 
291
290
  def sleep_before_handling_message: (Hash[String, untyped] message) -> void
292
291
  def should_handle_synchronously?: (Hash[String, untyped] message) -> bool
292
+ def network_event_message?: (Hash[String, untyped] message) -> bool
293
+ def ensure_network_message_task: () -> void
294
+ def enqueue_network_message: (Hash[String, untyped] message) -> void
293
295
  def request_debug_printer: () -> untyped
294
296
  def response_debug_printer: () -> untyped
295
297
  def handle_message: (Hash[String, untyped] message) -> void
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: puppeteer-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.50.0.alpha9
4
+ version: 0.50.0.alpha10
5
5
  platform: ruby
6
6
  authors:
7
7
  - YusukeIwaki
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-01-24 00:00:00.000000000 Z
11
+ date: 2026-01-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: async