Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
40 changes: 24 additions & 16 deletions dotnet/src/webdriver/BiDi/Communication/Broker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ internal Broker(BiDi bidi, ITransport transport)
new DateTimeOffsetConverter(),
new PrintPageRangeConverter(),
new InputOriginConverter(),
new SubscriptionConverter(),
new JsonStringEnumConverter(JsonNamingPolicy.CamelCase),

// https://github.com/dotnet/runtime/issues/72604
Expand Down Expand Up @@ -223,23 +224,23 @@ public async Task<Subscription> SubscribeAsync<TEventArgs>(string eventName, Act

if (options is BrowsingContextsSubscriptionOptions browsingContextsOptions)
{
await _bidi.SessionModule.SubscribeAsync([eventName], new() { Contexts = browsingContextsOptions.Contexts }).ConfigureAwait(false);
var subscribeResult = await _bidi.SessionModule.SubscribeAsync([eventName], new() { Contexts = browsingContextsOptions.Contexts }).ConfigureAwait(false);

var eventHandler = new SyncEventHandler<TEventArgs>(eventName, action, browsingContextsOptions?.Contexts);

handlers.Add(eventHandler);

return new Subscription(this, eventHandler);
return new Subscription(subscribeResult.Subscription, this, eventHandler);
}
else
{
await _bidi.SessionModule.SubscribeAsync([eventName]).ConfigureAwait(false);
var subscribeResult = await _bidi.SessionModule.SubscribeAsync([eventName]).ConfigureAwait(false);

var eventHandler = new SyncEventHandler<TEventArgs>(eventName, action);

handlers.Add(eventHandler);

return new Subscription(this, eventHandler);
return new Subscription(subscribeResult.Subscription, this, eventHandler);
}
}

Expand All @@ -250,44 +251,51 @@ public async Task<Subscription> SubscribeAsync<TEventArgs>(string eventName, Fun

if (options is BrowsingContextsSubscriptionOptions browsingContextsOptions)
{
await _bidi.SessionModule.SubscribeAsync([eventName], new() { Contexts = browsingContextsOptions.Contexts }).ConfigureAwait(false);
var subscribeResult = await _bidi.SessionModule.SubscribeAsync([eventName], new() { Contexts = browsingContextsOptions.Contexts }).ConfigureAwait(false);

var eventHandler = new AsyncEventHandler<TEventArgs>(eventName, func, browsingContextsOptions.Contexts);

handlers.Add(eventHandler);

return new Subscription(this, eventHandler);
return new Subscription(subscribeResult.Subscription, this, eventHandler);
}
else
{
await _bidi.SessionModule.SubscribeAsync([eventName]).ConfigureAwait(false);
var subscribeResult = await _bidi.SessionModule.SubscribeAsync([eventName]).ConfigureAwait(false);

var eventHandler = new AsyncEventHandler<TEventArgs>(eventName, func);

handlers.Add(eventHandler);

return new Subscription(this, eventHandler);
return new Subscription(subscribeResult.Subscription, this, eventHandler);
}
}

public async Task UnsubscribeAsync(EventHandler eventHandler)
public async Task UnsubscribeAsync(Modules.Session.Subscription subscription, EventHandler eventHandler)
{
var eventHandlers = _eventHandlers[eventHandler.EventName];

eventHandlers.Remove(eventHandler);

if (eventHandler.Contexts is not null)
if (subscription is not null)
{
if (!eventHandlers.Any(h => eventHandler.Contexts.Equals(h.Contexts)) && !eventHandlers.Any(h => h.Contexts is null))
{
await _bidi.SessionModule.UnsubscribeAsync([eventHandler.EventName], new() { Contexts = eventHandler.Contexts }).ConfigureAwait(false);
}
await _bidi.SessionModule.UnsubscribeAsync([subscription]).ConfigureAwait(false);
}
else
{
if (!eventHandlers.Any(h => h.Contexts is not null) && !eventHandlers.Any(h => h.Contexts is null))
if (eventHandler.Contexts is not null)
{
if (!eventHandlers.Any(h => eventHandler.Contexts.Equals(h.Contexts)) && !eventHandlers.Any(h => h.Contexts is null))
{
await _bidi.SessionModule.UnsubscribeAsync([eventHandler.EventName], new() { Contexts = eventHandler.Contexts }).ConfigureAwait(false);
}
}
else
{
await _bidi.SessionModule.UnsubscribeAsync([eventHandler.EventName]).ConfigureAwait(false);
if (!eventHandlers.Any(h => h.Contexts is not null) && !eventHandlers.Any(h => h.Contexts is null))
{
await _bidi.SessionModule.UnsubscribeAsync([eventHandler.EventName]).ConfigureAwait(false);
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,9 @@ namespace OpenQA.Selenium.BiDi.Communication.Json;
[JsonSerializable(typeof(Modules.Session.NewResult))]
[JsonSerializable(typeof(Modules.Session.EndCommand))]
[JsonSerializable(typeof(Modules.Session.SubscribeCommand))]
[JsonSerializable(typeof(Modules.Session.UnsubscribeCommand))]
[JsonSerializable(typeof(Modules.Session.SubscribeResult))]
[JsonSerializable(typeof(Modules.Session.UnsubscribeByIdCommand))]
[JsonSerializable(typeof(Modules.Session.UnsubscribeByAttributesCommand))]

[JsonSerializable(typeof(Modules.Browser.CloseCommand), TypeInfoPropertyName = "Browser_CloseCommand")]
[JsonSerializable(typeof(Modules.Browser.CreateUserContextCommand))]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// <copyright file="SubscriptionConverter.cs" company="Selenium Committers">
// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The SFC licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
// </copyright>

using System;
using System.Text.Json;
using System.Text.Json.Serialization;

#nullable enable

namespace OpenQA.Selenium.BiDi.Communication.Json.Converters;

internal class SubscriptionConverter : JsonConverter<Modules.Session.Subscription>
{
public override Modules.Session.Subscription? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
var id = reader.GetString();

return new Modules.Session.Subscription(id!);
}

public override void Write(Utf8JsonWriter writer, Modules.Session.Subscription value, JsonSerializerOptions options)
{
writer.WriteStringValue(value.Id);
}
}
22 changes: 13 additions & 9 deletions dotnet/src/webdriver/BiDi/Modules/Session/SessionModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public async Task<StatusResult> StatusAsync(StatusOptions? options = null)
return await Broker.ExecuteCommandAsync<StatusCommand, StatusResult>(new StatusCommand(), options).ConfigureAwait(false);
}

public async Task SubscribeAsync(IEnumerable<string> events, SubscribeOptions? options = null)
public async Task<SubscribeResult> SubscribeAsync(IEnumerable<string> events, SubscribeOptions? options = null)
{
var @params = new SubscribeCommandParameters(events);

Expand All @@ -41,19 +41,23 @@ public async Task SubscribeAsync(IEnumerable<string> events, SubscribeOptions? o
@params.Contexts = options.Contexts;
}

await Broker.ExecuteCommandAsync(new SubscribeCommand(@params), options).ConfigureAwait(false);
return await Broker.ExecuteCommandAsync<SubscribeCommand, SubscribeResult>(new(@params), options).ConfigureAwait(false);
}

public async Task UnsubscribeAsync(IEnumerable<string> events, UnsubscribeOptions? options = null)
public async Task UnsubscribeAsync(IEnumerable<Subscription> subscriptions, UnsubscribeByIdOptions? options = null)
{
var @params = new SubscribeCommandParameters(events);
var @params = new UnsubscribeByIdCommandParameters(subscriptions);

if (options is not null)
{
@params.Contexts = options.Contexts;
}
await Broker.ExecuteCommandAsync(new UnsubscribeByIdCommand(@params), options).ConfigureAwait(false);
}

public async Task UnsubscribeAsync(IEnumerable<string> eventNames = null, UnsubscribeByAttributesOptions? options = null)
{
var @params = new UnsubscribeByAttributesCommandParameters(eventNames);

@params.Contexts = options?.Contexts;

await Broker.ExecuteCommandAsync(new UnsubscribeCommand(@params), options).ConfigureAwait(false);
await Broker.ExecuteCommandAsync(new UnsubscribeByAttributesCommand(@params), options).ConfigureAwait(false);
}

public async Task<NewResult> NewAsync(CapabilitiesRequest capabilitiesRequest, NewOptions? options = null)
Expand Down
2 changes: 2 additions & 0 deletions dotnet/src/webdriver/BiDi/Modules/Session/SubscribeCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,5 @@ public record SubscribeOptions : CommandOptions
{
public IEnumerable<BrowsingContext.BrowsingContext>? Contexts { get; set; }
}

internal record SubscribeResult(Subscription Subscription);
32 changes: 32 additions & 0 deletions dotnet/src/webdriver/BiDi/Modules/Session/Subscription.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// <copyright file="Subscription.cs" company="Selenium Committers">
// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The SFC licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
// </copyright>

#nullable enable

namespace OpenQA.Selenium.BiDi.Modules.Session;

public sealed class Subscription
{
internal Subscription(string id)
{
Id = id;
}

internal string Id { get; }
}
25 changes: 22 additions & 3 deletions dotnet/src/webdriver/BiDi/Modules/Session/UnsubscribeCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,31 @@
// </copyright>

using OpenQA.Selenium.BiDi.Communication;
using System;
using System.Collections.Generic;

#nullable enable

namespace OpenQA.Selenium.BiDi.Modules.Session;

internal class UnsubscribeCommand(SubscribeCommandParameters @params)
: Command<SubscribeCommandParameters>(@params, "session.unsubscribe");
internal class UnsubscribeByIdCommand(UnsubscribeByIdCommandParameters @params)
: Command<UnsubscribeByIdCommandParameters>(@params, "session.unsubscribe");

public record UnsubscribeOptions : SubscribeOptions;
internal class UnsubscribeByAttributesCommand(UnsubscribeByAttributesCommandParameters @params)
: Command<UnsubscribeByAttributesCommandParameters>(@params, "session.unsubscribe");

internal record UnsubscribeByIdCommandParameters(IEnumerable<Subscription> Subscriptions) : CommandParameters;

public record UnsubscribeByIdOptions : CommandOptions;

internal record UnsubscribeByAttributesCommandParameters(IEnumerable<string> Events) : CommandParameters
{
[Obsolete("Contexts param is deprecated and will be removed in the future versions")]
// https://w3c.github.io/webdriver-bidi/#type-session-UnsubscribeByAttributesRequest
public IEnumerable<BrowsingContext.BrowsingContext>? Contexts { get; set; }
}

public record UnsubscribeByAttributesOptions : CommandOptions
{
public IEnumerable<BrowsingContext.BrowsingContext>? Contexts { get; set; }
}
6 changes: 4 additions & 2 deletions dotnet/src/webdriver/BiDi/Subscription.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,18 +28,20 @@ namespace OpenQA.Selenium.BiDi;

public class Subscription : IAsyncDisposable
{
private readonly Modules.Session.Subscription _subscription;
private readonly Broker _broker;
private readonly Communication.EventHandler _eventHandler;

internal Subscription(Broker broker, Communication.EventHandler eventHandler)
internal Subscription(Modules.Session.Subscription subscription, Broker broker, Communication.EventHandler eventHandler)
{
_subscription = subscription;
_broker = broker;
_eventHandler = eventHandler;
}

public async Task UnsubscribeAsync()
{
await _broker.UnsubscribeAsync(_eventHandler).ConfigureAwait(false);
await _broker.UnsubscribeAsync(_subscription, _eventHandler).ConfigureAwait(false);
}

public async ValueTask DisposeAsync()
Expand Down
Loading