Skip to content

Commit e78c390

Browse files
authored
[dotnet] [bidi] Revise event args (#17304)
1 parent e2d3e8f commit e78c390

File tree

67 files changed

+1184
-768
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

67 files changed

+1184
-768
lines changed

dotnet/src/webdriver/BiDi/BiDi.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ public static async Task<IBiDi> ConnectAsync(string url, Action<BiDiOptionsBuild
6262

6363
BiDi bidi = new();
6464

65-
bidi.Broker = new Broker(transport, bidi, () => bidi.Session);
65+
bidi.Broker = new Broker(transport, bidi);
6666

6767
return bidi;
6868
}

dotnet/src/webdriver/BiDi/Broker.cs

Lines changed: 54 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
using System.Text.Json;
2323
using System.Text.Json.Serialization.Metadata;
2424
using System.Threading.Channels;
25-
using OpenQA.Selenium.BiDi.Session;
2625
using OpenQA.Selenium.Internal.Logging;
2726

2827
namespace OpenQA.Selenium.BiDi;
@@ -39,7 +38,9 @@ internal sealed class Broker : IAsyncDisposable
3938

4039
private readonly ITransport _transport;
4140
private readonly EventDispatcher _eventDispatcher;
42-
private readonly IBiDi _bidi;
41+
private readonly BiDi _bidi;
42+
43+
private readonly ConcurrentDictionary<string, EventMetadata> _eventMetadata = new();
4344

4445
private readonly ConcurrentDictionary<long, CommandInfo> _pendingCommands = new();
4546

@@ -57,21 +58,60 @@ internal sealed class Broker : IAsyncDisposable
5758
private readonly Task _processingTask;
5859
private readonly CancellationTokenSource _receiveMessagesCancellationTokenSource;
5960

60-
public Broker(ITransport transport, IBiDi bidi, Func<ISessionModule> sessionProvider)
61+
public Broker(ITransport transport, BiDi bidi)
6162
{
6263
_transport = transport;
6364
_bidi = bidi;
64-
_eventDispatcher = new EventDispatcher(sessionProvider);
65+
_eventDispatcher = new EventDispatcher();
6566

6667
_receiveMessagesCancellationTokenSource = new CancellationTokenSource();
6768
_receivingTask = Task.Run(() => ReceiveMessagesAsync(_receiveMessagesCancellationTokenSource.Token));
6869
_processingTask = Task.Run(ProcessMessagesAsync);
6970
}
7071

71-
public Task<Subscription> SubscribeAsync<TEventArgs>(string eventName, EventHandler eventHandler, SubscriptionOptions? options, JsonTypeInfo<TEventArgs> jsonTypeInfo, CancellationToken cancellationToken)
72+
public async Task<Subscription> SubscribeAsync<TEventArgs, TEventParams>(string eventName, Action<TEventArgs> action, Func<IBiDi, TEventParams, TEventArgs> factory, SubscriptionOptions? options, JsonTypeInfo<TEventParams> jsonTypeInfo, CancellationToken cancellationToken)
7273
where TEventArgs : EventArgs
7374
{
74-
return _eventDispatcher.SubscribeAsync(eventName, eventHandler, options, jsonTypeInfo, cancellationToken);
75+
ValueTask InvokeAction(EventArgs args) { action((TEventArgs)args); return default; }
76+
return await SubscribeAsync(eventName, InvokeAction, (bidi, ep) => factory(bidi, (TEventParams)ep), jsonTypeInfo, options, cancellationToken).ConfigureAwait(false);
77+
}
78+
79+
public async Task<Subscription> SubscribeAsync<TEventArgs, TEventParams>(string eventName, Func<TEventArgs, Task> func, Func<IBiDi, TEventParams, TEventArgs> factory, SubscriptionOptions? options, JsonTypeInfo<TEventParams> jsonTypeInfo, CancellationToken cancellationToken)
80+
where TEventArgs : EventArgs
81+
{
82+
ValueTask InvokeFunc(EventArgs args) => new(func((TEventArgs)args));
83+
return await SubscribeAsync(eventName, InvokeFunc, (bidi, ep) => factory(bidi, (TEventParams)ep), jsonTypeInfo, options, cancellationToken).ConfigureAwait(false);
84+
}
85+
86+
private async Task<Subscription> SubscribeAsync(string eventName, Func<EventArgs, ValueTask> handler, Func<IBiDi, object, EventArgs> argsFactory, JsonTypeInfo jsonTypeInfo, SubscriptionOptions? options, CancellationToken cancellationToken)
87+
{
88+
var metadata = _eventMetadata.GetOrAdd(eventName, new EventMetadata(jsonTypeInfo, argsFactory));
89+
90+
if (metadata.JsonTypeInfo != jsonTypeInfo)
91+
{
92+
throw new ArgumentException($"Event '{eventName}' is already registered with different metadata.", nameof(eventName));
93+
}
94+
95+
_eventDispatcher.AddHandler(eventName, handler);
96+
97+
try
98+
{
99+
var subscribeResult = await _bidi.Session.SubscribeAsync([eventName], new() { Contexts = options?.Contexts, UserContexts = options?.UserContexts }, cancellationToken)
100+
.ConfigureAwait(false);
101+
102+
return new Subscription(subscribeResult.Subscription, this, eventName) { Handler = handler };
103+
}
104+
catch
105+
{
106+
_eventDispatcher.RemoveHandler(eventName, handler);
107+
throw;
108+
}
109+
}
110+
111+
public async ValueTask UnsubscribeAsync(Subscription subscription, CancellationToken cancellationToken)
112+
{
113+
await _bidi.Session.UnsubscribeAsync([subscription.SubscriptionId], null, cancellationToken).ConfigureAwait(false);
114+
_eventDispatcher.RemoveHandler(subscription.EventName, subscription.Handler);
75115
}
76116

77117
public async Task<TResult> ExecuteCommandAsync<TCommand, TResult>(TCommand command, CommandOptions? options, JsonTypeInfo<TCommand> jsonCommandTypeInfo, JsonTypeInfo<TResult> jsonResultTypeInfo, CancellationToken cancellationToken)
@@ -274,7 +314,7 @@ private void ProcessReceivedMessage(ReadOnlySpan<byte> data)
274314
case TypeEvent:
275315
if (method is null) throw new BiDiException($"The remote end responded with 'event' message type, but missed required 'method' property. Message content: {System.Text.Encoding.UTF8.GetString(data.ToArray())}");
276316

277-
if (!_eventDispatcher.TryGetJsonTypeInfo(method, out var jsonTypeInfo))
317+
if (!_eventMetadata.TryGetValue(method, out var metadata))
278318
{
279319
if (_logger.IsEnabled(LogEventLevel.Warn))
280320
{
@@ -284,10 +324,10 @@ private void ProcessReceivedMessage(ReadOnlySpan<byte> data)
284324
break;
285325
}
286326

287-
var eventArgs = JsonSerializer.Deserialize(ref paramsReader, jsonTypeInfo) as EventArgs
327+
var eventParams = JsonSerializer.Deserialize(ref paramsReader, metadata.JsonTypeInfo)
288328
?? throw new BiDiException("Remote end returned null event args in the 'params' property.");
289329

290-
eventArgs.BiDi = _bidi;
330+
var eventArgs = metadata.CreateEventArgs(_bidi, eventParams);
291331

292332
_eventDispatcher.EnqueueEvent(method, eventArgs);
293333
break;
@@ -427,6 +467,11 @@ private void ReturnBuffer(PooledBufferWriter buffer)
427467

428468
private readonly record struct CommandInfo(TaskCompletionSource<EmptyResult> TaskCompletionSource, JsonTypeInfo JsonResultTypeInfo);
429469

470+
private readonly record struct EventMetadata(JsonTypeInfo JsonTypeInfo, Func<IBiDi, object, EventArgs> ArgsFactory)
471+
{
472+
public EventArgs CreateEventArgs(IBiDi bidi, object eventParams) => ArgsFactory(bidi, eventParams);
473+
}
474+
430475
private sealed class PooledBufferWriter : IBufferWriter<byte>, IDisposable
431476
{
432477
private const int DefaultBufferSize = 1024 * 8;

dotnet/src/webdriver/BiDi/BrowsingContext/BrowsingContext.cs

Lines changed: 28 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ public Task<GetTreeResult> GetTreeAsync(ContextGetTreeOptions? options = null, C
123123
return BiDi.BrowsingContext.GetTreeAsync(ContextGetTreeOptions.WithContext(options, this), cancellationToken);
124124
}
125125

126-
public Task<Subscription> OnNavigationStartedAsync(Func<NavigationEventArgs, Task> handler, ContextSubscriptionOptions? options = null)
126+
public Task<Subscription> OnNavigationStartedAsync(Func<NavigationStartedEventArgs, Task> handler, ContextSubscriptionOptions? options = null)
127127
{
128128
if (handler is null) throw new ArgumentNullException(nameof(handler));
129129

@@ -132,7 +132,7 @@ public Task<Subscription> OnNavigationStartedAsync(Func<NavigationEventArgs, Tas
132132
ContextSubscriptionOptions.WithContext(options, this));
133133
}
134134

135-
public Task<Subscription> OnNavigationStartedAsync(Action<NavigationEventArgs> handler, ContextSubscriptionOptions? options = null)
135+
public Task<Subscription> OnNavigationStartedAsync(Action<NavigationStartedEventArgs> handler, ContextSubscriptionOptions? options = null)
136136
{
137137
if (handler is null) throw new ArgumentNullException(nameof(handler));
138138

@@ -141,7 +141,7 @@ public Task<Subscription> OnNavigationStartedAsync(Action<NavigationEventArgs> h
141141
ContextSubscriptionOptions.WithContext(options, this));
142142
}
143143

144-
public Task<Subscription> OnFragmentNavigatedAsync(Func<NavigationEventArgs, Task> handler, ContextSubscriptionOptions? options = null)
144+
public Task<Subscription> OnFragmentNavigatedAsync(Func<FragmentNavigatedEventArgs, Task> handler, ContextSubscriptionOptions? options = null)
145145
{
146146
if (handler is null) throw new ArgumentNullException(nameof(handler));
147147

@@ -150,7 +150,7 @@ public Task<Subscription> OnFragmentNavigatedAsync(Func<NavigationEventArgs, Tas
150150
ContextSubscriptionOptions.WithContext(options, this));
151151
}
152152

153-
public Task<Subscription> OnFragmentNavigatedAsync(Action<NavigationEventArgs> handler, ContextSubscriptionOptions? options = null)
153+
public Task<Subscription> OnFragmentNavigatedAsync(Action<FragmentNavigatedEventArgs> handler, ContextSubscriptionOptions? options = null)
154154
{
155155
if (handler is null) throw new ArgumentNullException(nameof(handler));
156156

@@ -177,7 +177,7 @@ public Task<Subscription> OnHistoryUpdatedAsync(Action<HistoryUpdatedEventArgs>
177177
ContextSubscriptionOptions.WithContext(options, this));
178178
}
179179

180-
public Task<Subscription> OnDomContentLoadedAsync(Func<NavigationEventArgs, Task> handler, ContextSubscriptionOptions? options = null)
180+
public Task<Subscription> OnDomContentLoadedAsync(Func<DomContentLoadedEventArgs, Task> handler, ContextSubscriptionOptions? options = null)
181181
{
182182
if (handler is null) throw new ArgumentNullException(nameof(handler));
183183

@@ -186,7 +186,7 @@ public Task<Subscription> OnDomContentLoadedAsync(Func<NavigationEventArgs, Task
186186
ContextSubscriptionOptions.WithContext(options, this));
187187
}
188188

189-
public Task<Subscription> OnDomContentLoadedAsync(Action<NavigationEventArgs> handler, ContextSubscriptionOptions? options = null)
189+
public Task<Subscription> OnDomContentLoadedAsync(Action<DomContentLoadedEventArgs> handler, ContextSubscriptionOptions? options = null)
190190
{
191191
if (handler is null) throw new ArgumentNullException(nameof(handler));
192192

@@ -195,7 +195,7 @@ public Task<Subscription> OnDomContentLoadedAsync(Action<NavigationEventArgs> ha
195195
ContextSubscriptionOptions.WithContext(options, this));
196196
}
197197

198-
public Task<Subscription> OnLoadAsync(Action<NavigationEventArgs> handler, ContextSubscriptionOptions? options = null)
198+
public Task<Subscription> OnLoadAsync(Action<LoadEventArgs> handler, ContextSubscriptionOptions? options = null)
199199
{
200200
if (handler is null) throw new ArgumentNullException(nameof(handler));
201201

@@ -204,7 +204,7 @@ public Task<Subscription> OnLoadAsync(Action<NavigationEventArgs> handler, Conte
204204
ContextSubscriptionOptions.WithContext(options, this));
205205
}
206206

207-
public Task<Subscription> OnLoadAsync(Func<NavigationEventArgs, Task> handler, ContextSubscriptionOptions? options = null)
207+
public Task<Subscription> OnLoadAsync(Func<LoadEventArgs, Task> handler, ContextSubscriptionOptions? options = null)
208208
{
209209
if (handler is null) throw new ArgumentNullException(nameof(handler));
210210

@@ -249,7 +249,7 @@ public Task<Subscription> OnDownloadEndAsync(Func<DownloadEndEventArgs, Task> ha
249249
ContextSubscriptionOptions.WithContext(options, this));
250250
}
251251

252-
public Task<Subscription> OnNavigationAbortedAsync(Action<NavigationEventArgs> handler, ContextSubscriptionOptions? options = null)
252+
public Task<Subscription> OnNavigationAbortedAsync(Action<NavigationAbortedEventArgs> handler, ContextSubscriptionOptions? options = null)
253253
{
254254
if (handler is null) throw new ArgumentNullException(nameof(handler));
255255

@@ -258,7 +258,7 @@ public Task<Subscription> OnNavigationAbortedAsync(Action<NavigationEventArgs> h
258258
ContextSubscriptionOptions.WithContext(options, this));
259259
}
260260

261-
public Task<Subscription> OnNavigationAbortedAsync(Func<NavigationEventArgs, Task> handler, ContextSubscriptionOptions? options = null)
261+
public Task<Subscription> OnNavigationAbortedAsync(Func<NavigationAbortedEventArgs, Task> handler, ContextSubscriptionOptions? options = null)
262262
{
263263
if (handler is null) throw new ArgumentNullException(nameof(handler));
264264

@@ -267,7 +267,7 @@ public Task<Subscription> OnNavigationAbortedAsync(Func<NavigationEventArgs, Tas
267267
ContextSubscriptionOptions.WithContext(options, this));
268268
}
269269

270-
public Task<Subscription> OnNavigationFailedAsync(Action<NavigationEventArgs> handler, ContextSubscriptionOptions? options = null)
270+
public Task<Subscription> OnNavigationFailedAsync(Action<NavigationFailedEventArgs> handler, ContextSubscriptionOptions? options = null)
271271
{
272272
if (handler is null) throw new ArgumentNullException(nameof(handler));
273273

@@ -276,7 +276,7 @@ public Task<Subscription> OnNavigationFailedAsync(Action<NavigationEventArgs> ha
276276
ContextSubscriptionOptions.WithContext(options, this));
277277
}
278278

279-
public Task<Subscription> OnNavigationFailedAsync(Func<NavigationEventArgs, Task> handler, ContextSubscriptionOptions? options = null)
279+
public Task<Subscription> OnNavigationFailedAsync(Func<NavigationFailedEventArgs, Task> handler, ContextSubscriptionOptions? options = null)
280280
{
281281
if (handler is null) throw new ArgumentNullException(nameof(handler));
282282

@@ -285,7 +285,7 @@ public Task<Subscription> OnNavigationFailedAsync(Func<NavigationEventArgs, Task
285285
ContextSubscriptionOptions.WithContext(options, this));
286286
}
287287

288-
public Task<Subscription> OnNavigationCommittedAsync(Action<NavigationEventArgs> handler, ContextSubscriptionOptions? options = null)
288+
public Task<Subscription> OnNavigationCommittedAsync(Action<NavigationCommittedEventArgs> handler, ContextSubscriptionOptions? options = null)
289289
{
290290
if (handler is null) throw new ArgumentNullException(nameof(handler));
291291

@@ -294,7 +294,7 @@ public Task<Subscription> OnNavigationCommittedAsync(Action<NavigationEventArgs>
294294
ContextSubscriptionOptions.WithContext(options, this));
295295
}
296296

297-
public Task<Subscription> OnNavigationCommittedAsync(Func<NavigationEventArgs, Task> handler, ContextSubscriptionOptions? options = null)
297+
public Task<Subscription> OnNavigationCommittedAsync(Func<NavigationCommittedEventArgs, Task> handler, ContextSubscriptionOptions? options = null)
298298
{
299299
if (handler is null) throw new ArgumentNullException(nameof(handler));
300300

@@ -303,31 +303,31 @@ public Task<Subscription> OnNavigationCommittedAsync(Func<NavigationEventArgs, T
303303
ContextSubscriptionOptions.WithContext(options, this));
304304
}
305305

306-
private async Task HandleNavigationStartedAsync(NavigationEventArgs e, Func<NavigationEventArgs, Task> handler)
306+
private async Task HandleNavigationStartedAsync(NavigationStartedEventArgs e, Func<NavigationStartedEventArgs, Task> handler)
307307
{
308308
if (Equals(e.Context))
309309
{
310310
await handler(e).ConfigureAwait(false);
311311
}
312312
}
313313

314-
private void HandleNavigationStarted(NavigationEventArgs e, Action<NavigationEventArgs> handler)
314+
private void HandleNavigationStarted(NavigationStartedEventArgs e, Action<NavigationStartedEventArgs> handler)
315315
{
316316
if (Equals(e.Context))
317317
{
318318
handler(e);
319319
}
320320
}
321321

322-
private async Task HandleFragmentNavigatedAsync(NavigationEventArgs e, Func<NavigationEventArgs, Task> handler)
322+
private async Task HandleFragmentNavigatedAsync(FragmentNavigatedEventArgs e, Func<FragmentNavigatedEventArgs, Task> handler)
323323
{
324324
if (Equals(e.Context))
325325
{
326326
await handler(e).ConfigureAwait(false);
327327
}
328328
}
329329

330-
private void HandleFragmentNavigated(NavigationEventArgs e, Action<NavigationEventArgs> handler)
330+
private void HandleFragmentNavigated(FragmentNavigatedEventArgs e, Action<FragmentNavigatedEventArgs> handler)
331331
{
332332
if (Equals(e.Context))
333333
{
@@ -351,31 +351,31 @@ private void HandleHistoryUpdated(HistoryUpdatedEventArgs e, Action<HistoryUpdat
351351
}
352352
}
353353

354-
private async Task HandleDomContentLoadedAsync(NavigationEventArgs e, Func<NavigationEventArgs, Task> handler)
354+
private async Task HandleDomContentLoadedAsync(DomContentLoadedEventArgs e, Func<DomContentLoadedEventArgs, Task> handler)
355355
{
356356
if (Equals(e.Context))
357357
{
358358
await handler(e).ConfigureAwait(false);
359359
}
360360
}
361361

362-
private void HandleDomContentLoaded(NavigationEventArgs e, Action<NavigationEventArgs> handler)
362+
private void HandleDomContentLoaded(DomContentLoadedEventArgs e, Action<DomContentLoadedEventArgs> handler)
363363
{
364364
if (Equals(e.Context))
365365
{
366366
handler(e);
367367
}
368368
}
369369

370-
private void HandleLoad(NavigationEventArgs e, Action<NavigationEventArgs> handler)
370+
private void HandleLoad(LoadEventArgs e, Action<LoadEventArgs> handler)
371371
{
372372
if (Equals(e.Context))
373373
{
374374
handler(e);
375375
}
376376
}
377377

378-
private async Task HandleLoadAsync(NavigationEventArgs e, Func<NavigationEventArgs, Task> handler)
378+
private async Task HandleLoadAsync(LoadEventArgs e, Func<LoadEventArgs, Task> handler)
379379
{
380380
if (Equals(e.Context))
381381
{
@@ -415,47 +415,47 @@ private async Task HandleDownloadEndAsync(DownloadEndEventArgs e, Func<DownloadE
415415
}
416416
}
417417

418-
private void HandleNavigationAborted(NavigationEventArgs e, Action<NavigationEventArgs> handler)
418+
private void HandleNavigationAborted(NavigationAbortedEventArgs e, Action<NavigationAbortedEventArgs> handler)
419419
{
420420
if (Equals(e.Context))
421421
{
422422
handler(e);
423423
}
424424
}
425425

426-
private async Task HandleNavigationAbortedAsync(NavigationEventArgs e, Func<NavigationEventArgs, Task> handler)
426+
private async Task HandleNavigationAbortedAsync(NavigationAbortedEventArgs e, Func<NavigationAbortedEventArgs, Task> handler)
427427
{
428428
if (Equals(e.Context))
429429
{
430430
await handler(e).ConfigureAwait(false);
431431
}
432432
}
433433

434-
private void HandleNavigationFailed(NavigationEventArgs e, Action<NavigationEventArgs> handler)
434+
private void HandleNavigationFailed(NavigationFailedEventArgs e, Action<NavigationFailedEventArgs> handler)
435435
{
436436
if (Equals(e.Context))
437437
{
438438
handler(e);
439439
}
440440
}
441441

442-
private async Task HandleNavigationFailedAsync(NavigationEventArgs e, Func<NavigationEventArgs, Task> handler)
442+
private async Task HandleNavigationFailedAsync(NavigationFailedEventArgs e, Func<NavigationFailedEventArgs, Task> handler)
443443
{
444444
if (Equals(e.Context))
445445
{
446446
await handler(e).ConfigureAwait(false);
447447
}
448448
}
449449

450-
private void HandleNavigationCommitted(NavigationEventArgs e, Action<NavigationEventArgs> handler)
450+
private void HandleNavigationCommitted(NavigationCommittedEventArgs e, Action<NavigationCommittedEventArgs> handler)
451451
{
452452
if (Equals(e.Context))
453453
{
454454
handler(e);
455455
}
456456
}
457457

458-
private async Task HandleNavigationCommittedAsync(NavigationEventArgs e, Func<NavigationEventArgs, Task> handler)
458+
private async Task HandleNavigationCommittedAsync(NavigationCommittedEventArgs e, Func<NavigationCommittedEventArgs, Task> handler)
459459
{
460460
if (Equals(e.Context))
461461
{

0 commit comments

Comments
 (0)