Skip to content

Commit ace05e4

Browse files
committed
[rb] remove bidi callbacks from sockets when unsubscribing
1 parent 13b63f6 commit ace05e4

File tree

16 files changed

+98
-75
lines changed

16 files changed

+98
-75
lines changed

rb/lib/selenium/webdriver/bidi.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@ def callbacks
4444
@ws.callbacks
4545
end
4646

47-
def add_callback(event, &block)
48-
@ws.add_callback(event, &block)
47+
def add_callback(event, id, &block)
48+
@ws.add_callback(event, id, &block)
4949
end
5050

5151
def remove_callback(event, id)

rb/lib/selenium/webdriver/bidi/log_handler.rb

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,19 +26,19 @@ class LogHandler
2626

2727
def initialize(bidi)
2828
@bidi = bidi
29-
@log_entry_subscribed = false
3029
end
3130

3231
# @return [int] id of the handler
3332
# steep:ignore:start
3433
def add_message_handler(type)
35-
subscribe_log_entry unless @log_entry_subscribed
36-
@bidi.add_callback('log.entryAdded') do |params|
34+
id = subscribe_log_entry
35+
@bidi.add_callback('log.entryAdded', id) do |params|
3736
if params['type'] == type
3837
log_entry_klass = type == 'console' ? ConsoleLogEntry : JavaScriptLogEntry
3938
yield(log_entry_klass.new(**params))
4039
end
4140
end
41+
id
4242
end
4343
# steep:ignore:end
4444

@@ -52,12 +52,10 @@ def remove_message_handler(id)
5252

5353
def subscribe_log_entry
5454
@bidi.session.subscribe('log.entryAdded')
55-
@log_entry_subscribed = true
5655
end
5756

5857
def unsubscribe_log_entry
59-
@bidi.session.unsubscribe('log.entryAdded')
60-
@log_entry_subscribed = false
58+
@bidi.session.unsubscribe(events: 'log.entryAdded')
6159
end
6260
end # LogHandler
6361
end # Bidi

rb/lib/selenium/webdriver/bidi/log_inspector.rb

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ def initialize(driver, browsing_context_ids = nil)
5151
end
5252

5353
@bidi = driver.bidi
54-
@bidi.session.subscribe('log.entryAdded', browsing_context_ids)
54+
@browsing_context_ids = browsing_context_ids
5555
end
5656

5757
def on_console_entry(filter_by = nil, &block)
@@ -96,7 +96,8 @@ def on_log(filter_by = nil, &block)
9696

9797
def on(event, &block)
9898
event = EVENTS[event] if event.is_a?(Symbol)
99-
@bidi.add_callback("log.#{event}", &block)
99+
id = @bidi.session.subscribe('log.entryAdded', @browsing_context_ids)
100+
@bidi.add_callback("log.#{event}", id, &block)
100101
end
101102

102103
def check_valid_filter(filter_by)

rb/lib/selenium/webdriver/bidi/network.rb

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,13 +45,19 @@ def add_intercept(phases: [], contexts: nil, url_patterns: nil, pattern_type: :s
4545
@bidi.send_cmd('network.addIntercept',
4646
phases: phases,
4747
contexts: contexts,
48-
urlPatterns: url_patterns)
48+
urlPatterns: url_patterns)['intercept']
4949
end
5050

5151
def remove_intercept(intercept)
5252
@bidi.send_cmd('network.removeIntercept', intercept: intercept)
5353
end
5454

55+
def unsubscribe(event, id)
56+
event = EVENTS[event] if event.is_a?(Symbol)
57+
@bidi.session.unsubscribe(ids: id)
58+
@bidi.remove_callback(event.to_s, id)
59+
end
60+
5561
def continue_with_auth(request_id, username, password)
5662
@bidi.send_cmd(
5763
'network.continueWithAuth',
@@ -133,8 +139,9 @@ def set_cache_behavior(behavior, *contexts)
133139

134140
def on(event, &block)
135141
event = EVENTS[event] if event.is_a?(Symbol)
136-
@bidi.add_callback(event, &block)
137-
@bidi.session.subscribe(event)
142+
id = @bidi.session.subscribe(event)
143+
@bidi.add_callback(event, id, &block)
144+
id
138145
end
139146
end # Network
140147
end # BiDi

rb/lib/selenium/webdriver/bidi/session.rb

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,13 @@ def subscribe(events, browsing_contexts = nil)
3636
opts = {events: Array(events)}
3737
opts[:browsing_contexts] = Array(browsing_contexts) if browsing_contexts
3838

39-
@bidi.send_cmd('session.subscribe', **opts)
39+
@bidi.send_cmd('session.subscribe', **opts)['subscription']
4040
end
4141

42-
def unsubscribe(events, browsing_contexts = nil)
43-
opts = {events: Array(events)}
44-
opts[:browsing_contexts] = Array(browsing_contexts) if browsing_contexts
42+
def unsubscribe(events: nil, ids: nil)
43+
raise ArgumentError('unsubscribe by event or by id, not both') if events && ids
4544

45+
opts = events ? {events: Array(events)} : {subscriptions: Array(ids)}
4646
@bidi.send_cmd('session.unsubscribe', **opts)
4747
end
4848
end # Session

rb/lib/selenium/webdriver/common/network.rb

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,24 +24,26 @@ module WebDriver
2424
class Network
2525
extend Forwardable
2626

27-
attr_reader :callbacks, :network
27+
Registration = Struct.new(:subscription, :interception, :event)
28+
29+
attr_reader :registrations, :network
2830
alias bidi network
2931

3032
def_delegators :network, :continue_with_auth, :continue_with_request, :continue_with_response
3133

3234
def initialize(bridge)
3335
@network = BiDi::Network.new(bridge.bidi)
34-
@callbacks = {}
36+
@registrations = []
3537
end
3638

37-
def remove_handler(id)
38-
intercept = callbacks[id]
39-
network.remove_intercept(intercept['intercept'])
40-
callbacks.delete(id)
39+
def remove_handler(registration)
40+
network.remove_intercept(registration.interception)
41+
network.unsubscribe(registration.event, registration.subscription)
42+
registrations.delete(registration)
4143
end
4244

4345
def clear_handlers
44-
callbacks.each_key { |id| remove_handler(id) }
46+
registrations.dup.each { |registration| remove_handler(registration) }
4547
end
4648

4749
def add_authentication_handler(username = nil, password = nil, *filter, pattern_type: nil, &block)
@@ -87,15 +89,17 @@ def add_response_handler(*filter, pattern_type: nil, &block)
8789
private
8890

8991
def add_handler(event_type, phase, intercept_type, filter, pattern_type: nil)
90-
intercept = network.add_intercept(phases: [phase], url_patterns: [filter].flatten, pattern_type: pattern_type)
91-
callback_id = network.on(event_type) do |event|
92+
interception = network.add_intercept(phases: [phase], url_patterns: [filter].flatten,
93+
pattern_type: pattern_type)
94+
subscription = network.on(event_type) do |event|
9295
request = event['request']
9396
intercepted_item = intercept_type.new(network, request)
9497
yield(intercepted_item)
9598
end
9699

97-
callbacks[callback_id] = intercept
98-
callback_id
100+
registration = Registration.new(event: event_type, subscription: subscription, interception: interception)
101+
@registrations << registration
102+
registration
99103
end
100104
end # Network
101105
end # WebDriver

rb/lib/selenium/webdriver/common/websocket_connection.rb

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -49,19 +49,23 @@ def close
4949
end
5050

5151
def callbacks
52-
@callbacks ||= Hash.new { |callbacks, event| callbacks[event] = [] }
52+
@callbacks ||= Hash.new { |callbacks, event| callbacks[event] = {} }
5353
end
5454

55-
def add_callback(event, &block)
56-
callbacks[event] << block
57-
block.object_id
55+
def add_callback(event, id, &block)
56+
callbacks[event][id] = block
5857
end
5958

6059
def remove_callback(event, id)
61-
return if callbacks[event].reject! { |callback| callback.object_id == id }
60+
if callbacks.dig(event, id).nil?
61+
raise Error::WebDriverError, "Callback with ID #{id} does not exist for event #{event}"
62+
end
63+
64+
callbacks[event].delete(id)
65+
end
6266

63-
ids = callbacks[event]&.map(&:object_id)
64-
raise Error::WebDriverError, "Callback with ID #{id} does not exist for event #{event}: #{ids}"
67+
def clear_callbacks
68+
@callbacks = Hash.new { |callbacks, event| callbacks[event] = {} }
6569
end
6670

6771
def send_cmd(**payload)
@@ -78,7 +82,7 @@ def send_cmd(**payload)
7882
private
7983

8084
# We should be thread-safe to use the hash without synchronization
81-
# because its keys are WebSocket message identifiers and they should be
85+
# because its keys are WebSocket message identifiers, and they should be
8286
# unique within a devtools session.
8387
def messages
8488
@messages ||= {}
@@ -102,7 +106,7 @@ def attach_socket_listener
102106
next unless message['method']
103107

104108
params = message['params']
105-
callbacks[message['method']].each do |callback|
109+
callbacks[message['method']].each_value do |callback|
106110
@callback_threads.add(callback_thread(params, &callback))
107111
end
108112
end

rb/sig/lib/selenium/webdriver/bidi.rbs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@ module Selenium
77

88
def initialize: (url: String) -> void
99

10-
def add_callback: (String | Symbol event) { () -> void } -> Integer
10+
def add_callback: (String event, String id) { () -> void } -> Integer
1111

1212
def close: () -> nil
1313

1414
def callbacks: () -> Hash[untyped, untyped]
1515

16-
def remove_callback: (String event, Integer id) -> Error::WebDriverError?
16+
def remove_callback: (String event, String id) -> Error::WebDriverError?
1717

1818
def session: () -> Session
1919

rb/sig/lib/selenium/webdriver/bidi/log_handler.rbs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ module Selenium
1818

1919
private
2020

21-
def subscribe_log_entry: () -> bool
21+
def subscribe_log_entry: () -> string
2222

2323
def unsubscribe_log_entry: () -> bool
2424
end

rb/sig/lib/selenium/webdriver/bidi/log_inspector.rbs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ module Selenium
88

99
LOG_LEVEL: Hash[Symbol, String]
1010

11+
@browsing_context_ids: Array[String]?
12+
1113
def initialize: (untyped driver, ?untyped? browsing_context_ids) -> void
1214

1315
def on_console_entry: (?untyped? filter_by) { () -> untyped } -> untyped

0 commit comments

Comments
 (0)