Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion dotnet/src/webdriver/BiDi/BiDi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ public static async Task<IBiDi> ConnectAsync(string url, Action<BiDiOptionsBuild

BiDi bidi = new();

bidi.Broker = new Broker(transport, bidi, () => bidi.Session);
bidi.Broker = new Broker(transport, bidi);

return bidi;
}
Expand Down
63 changes: 54 additions & 9 deletions dotnet/src/webdriver/BiDi/Broker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
using System.Text.Json;
using System.Text.Json.Serialization.Metadata;
using System.Threading.Channels;
using OpenQA.Selenium.BiDi.Session;
using OpenQA.Selenium.Internal.Logging;

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

private readonly ITransport _transport;
private readonly EventDispatcher _eventDispatcher;
private readonly IBiDi _bidi;
private readonly BiDi _bidi;

private readonly ConcurrentDictionary<string, EventMetadata> _eventMetadata = new();

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

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

public Broker(ITransport transport, IBiDi bidi, Func<ISessionModule> sessionProvider)
public Broker(ITransport transport, BiDi bidi)
{
_transport = transport;
_bidi = bidi;
_eventDispatcher = new EventDispatcher(sessionProvider);
_eventDispatcher = new EventDispatcher();

_receiveMessagesCancellationTokenSource = new CancellationTokenSource();
_receivingTask = Task.Run(() => ReceiveMessagesAsync(_receiveMessagesCancellationTokenSource.Token));
_processingTask = Task.Run(ProcessMessagesAsync);
}

public Task<Subscription> SubscribeAsync<TEventArgs>(string eventName, EventHandler eventHandler, SubscriptionOptions? options, JsonTypeInfo<TEventArgs> jsonTypeInfo, CancellationToken cancellationToken)
public async Task<Subscription> SubscribeAsync<TEventArgs, TEventParams>(string eventName, Action<TEventArgs> action, Func<IBiDi, TEventParams, TEventArgs> factory, SubscriptionOptions? options, JsonTypeInfo<TEventParams> jsonTypeInfo, CancellationToken cancellationToken)
where TEventArgs : EventArgs
{
return _eventDispatcher.SubscribeAsync(eventName, eventHandler, options, jsonTypeInfo, cancellationToken);
ValueTask InvokeAction(EventArgs args) { action((TEventArgs)args); return default; }
return await SubscribeAsync(eventName, InvokeAction, (bidi, ep) => factory(bidi, (TEventParams)ep), jsonTypeInfo, options, cancellationToken).ConfigureAwait(false);
}

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)
where TEventArgs : EventArgs
{
ValueTask InvokeFunc(EventArgs args) => new(func((TEventArgs)args));
return await SubscribeAsync(eventName, InvokeFunc, (bidi, ep) => factory(bidi, (TEventParams)ep), jsonTypeInfo, options, cancellationToken).ConfigureAwait(false);
}
Comment thread
nvborisenko marked this conversation as resolved.

private async Task<Subscription> SubscribeAsync(string eventName, Func<EventArgs, ValueTask> handler, Func<IBiDi, object, EventArgs> argsFactory, JsonTypeInfo jsonTypeInfo, SubscriptionOptions? options, CancellationToken cancellationToken)
{
var metadata = _eventMetadata.GetOrAdd(eventName, new EventMetadata(jsonTypeInfo, argsFactory));

if (metadata.JsonTypeInfo != jsonTypeInfo)
{
throw new ArgumentException($"Event '{eventName}' is already registered with different metadata.", nameof(eventName));
}

_eventDispatcher.AddHandler(eventName, handler);

try
{
var subscribeResult = await _bidi.Session.SubscribeAsync([eventName], new() { Contexts = options?.Contexts, UserContexts = options?.UserContexts }, cancellationToken)
.ConfigureAwait(false);
Comment thread
nvborisenko marked this conversation as resolved.

return new Subscription(subscribeResult.Subscription, this, eventName) { Handler = handler };
}
catch
{
_eventDispatcher.RemoveHandler(eventName, handler);
throw;
}
Comment thread
nvborisenko marked this conversation as resolved.
}

public async ValueTask UnsubscribeAsync(Subscription subscription, CancellationToken cancellationToken)
{
await _bidi.Session.UnsubscribeAsync([subscription.SubscriptionId], null, cancellationToken).ConfigureAwait(false);
_eventDispatcher.RemoveHandler(subscription.EventName, subscription.Handler);
}

public async Task<TResult> ExecuteCommandAsync<TCommand, TResult>(TCommand command, CommandOptions? options, JsonTypeInfo<TCommand> jsonCommandTypeInfo, JsonTypeInfo<TResult> jsonResultTypeInfo, CancellationToken cancellationToken)
Expand Down Expand Up @@ -274,7 +314,7 @@ private void ProcessReceivedMessage(ReadOnlySpan<byte> data)
case TypeEvent:
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())}");

if (!_eventDispatcher.TryGetJsonTypeInfo(method, out var jsonTypeInfo))
if (!_eventMetadata.TryGetValue(method, out var metadata))
{
if (_logger.IsEnabled(LogEventLevel.Warn))
{
Expand All @@ -284,10 +324,10 @@ private void ProcessReceivedMessage(ReadOnlySpan<byte> data)
break;
}

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

eventArgs.BiDi = _bidi;
var eventArgs = metadata.CreateEventArgs(_bidi, eventParams);

_eventDispatcher.EnqueueEvent(method, eventArgs);
break;
Expand Down Expand Up @@ -427,6 +467,11 @@ private void ReturnBuffer(PooledBufferWriter buffer)

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

private readonly record struct EventMetadata(JsonTypeInfo JsonTypeInfo, Func<IBiDi, object, EventArgs> ArgsFactory)
{
public EventArgs CreateEventArgs(IBiDi bidi, object eventParams) => ArgsFactory(bidi, eventParams);
}

private sealed class PooledBufferWriter : IBufferWriter<byte>, IDisposable
{
private const int DefaultBufferSize = 1024 * 8;
Expand Down
56 changes: 28 additions & 28 deletions dotnet/src/webdriver/BiDi/BrowsingContext/BrowsingContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ public Task<GetTreeResult> GetTreeAsync(ContextGetTreeOptions? options = null, C
return BiDi.BrowsingContext.GetTreeAsync(ContextGetTreeOptions.WithContext(options, this), cancellationToken);
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

private async Task HandleNavigationStartedAsync(NavigationEventArgs e, Func<NavigationEventArgs, Task> handler)
private async Task HandleNavigationStartedAsync(NavigationStartedEventArgs e, Func<NavigationStartedEventArgs, Task> handler)
{
if (Equals(e.Context))
{
await handler(e).ConfigureAwait(false);
}
}

private void HandleNavigationStarted(NavigationEventArgs e, Action<NavigationEventArgs> handler)
private void HandleNavigationStarted(NavigationStartedEventArgs e, Action<NavigationStartedEventArgs> handler)
{
if (Equals(e.Context))
{
handler(e);
}
}

private async Task HandleFragmentNavigatedAsync(NavigationEventArgs e, Func<NavigationEventArgs, Task> handler)
private async Task HandleFragmentNavigatedAsync(FragmentNavigatedEventArgs e, Func<FragmentNavigatedEventArgs, Task> handler)
{
if (Equals(e.Context))
{
await handler(e).ConfigureAwait(false);
}
}

private void HandleFragmentNavigated(NavigationEventArgs e, Action<NavigationEventArgs> handler)
private void HandleFragmentNavigated(FragmentNavigatedEventArgs e, Action<FragmentNavigatedEventArgs> handler)
{
if (Equals(e.Context))
{
Expand All @@ -351,31 +351,31 @@ private void HandleHistoryUpdated(HistoryUpdatedEventArgs e, Action<HistoryUpdat
}
}

private async Task HandleDomContentLoadedAsync(NavigationEventArgs e, Func<NavigationEventArgs, Task> handler)
private async Task HandleDomContentLoadedAsync(DomContentLoadedEventArgs e, Func<DomContentLoadedEventArgs, Task> handler)
{
if (Equals(e.Context))
{
await handler(e).ConfigureAwait(false);
}
}

private void HandleDomContentLoaded(NavigationEventArgs e, Action<NavigationEventArgs> handler)
private void HandleDomContentLoaded(DomContentLoadedEventArgs e, Action<DomContentLoadedEventArgs> handler)
{
if (Equals(e.Context))
{
handler(e);
}
}

private void HandleLoad(NavigationEventArgs e, Action<NavigationEventArgs> handler)
private void HandleLoad(LoadEventArgs e, Action<LoadEventArgs> handler)
{
if (Equals(e.Context))
{
handler(e);
}
}

private async Task HandleLoadAsync(NavigationEventArgs e, Func<NavigationEventArgs, Task> handler)
private async Task HandleLoadAsync(LoadEventArgs e, Func<LoadEventArgs, Task> handler)
{
if (Equals(e.Context))
{
Expand Down Expand Up @@ -415,47 +415,47 @@ private async Task HandleDownloadEndAsync(DownloadEndEventArgs e, Func<DownloadE
}
}

private void HandleNavigationAborted(NavigationEventArgs e, Action<NavigationEventArgs> handler)
private void HandleNavigationAborted(NavigationAbortedEventArgs e, Action<NavigationAbortedEventArgs> handler)
{
if (Equals(e.Context))
{
handler(e);
}
}

private async Task HandleNavigationAbortedAsync(NavigationEventArgs e, Func<NavigationEventArgs, Task> handler)
private async Task HandleNavigationAbortedAsync(NavigationAbortedEventArgs e, Func<NavigationAbortedEventArgs, Task> handler)
{
if (Equals(e.Context))
{
await handler(e).ConfigureAwait(false);
}
}

private void HandleNavigationFailed(NavigationEventArgs e, Action<NavigationEventArgs> handler)
private void HandleNavigationFailed(NavigationFailedEventArgs e, Action<NavigationFailedEventArgs> handler)
{
if (Equals(e.Context))
{
handler(e);
}
}

private async Task HandleNavigationFailedAsync(NavigationEventArgs e, Func<NavigationEventArgs, Task> handler)
private async Task HandleNavigationFailedAsync(NavigationFailedEventArgs e, Func<NavigationFailedEventArgs, Task> handler)
{
if (Equals(e.Context))
{
await handler(e).ConfigureAwait(false);
}
}

private void HandleNavigationCommitted(NavigationEventArgs e, Action<NavigationEventArgs> handler)
private void HandleNavigationCommitted(NavigationCommittedEventArgs e, Action<NavigationCommittedEventArgs> handler)
{
if (Equals(e.Context))
{
handler(e);
}
}

private async Task HandleNavigationCommittedAsync(NavigationEventArgs e, Func<NavigationEventArgs, Task> handler)
private async Task HandleNavigationCommittedAsync(NavigationCommittedEventArgs e, Func<NavigationCommittedEventArgs, Task> handler)
{
if (Equals(e.Context))
{
Expand Down
Loading
Loading