Skip to content

Commit 853933e

Browse files
nvborisenkogryznar
authored andcommitted
[dotnet][bidi] Use subscription id for events to unsubscribe (SeleniumHQ#15251)
1 parent d50a6b5 commit 853933e

File tree

8 files changed

+141
-31
lines changed

8 files changed

+141
-31
lines changed

dotnet/src/webdriver/BiDi/Communication/Broker.cs

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ internal Broker(BiDi bidi, ITransport transport)
8383
new DateTimeOffsetConverter(),
8484
new PrintPageRangeConverter(),
8585
new InputOriginConverter(),
86+
new SubscriptionConverter(),
8687
new JsonStringEnumConverter(JsonNamingPolicy.CamelCase),
8788

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

224225
if (options is BrowsingContextsSubscriptionOptions browsingContextsOptions)
225226
{
226-
await _bidi.SessionModule.SubscribeAsync([eventName], new() { Contexts = browsingContextsOptions.Contexts }).ConfigureAwait(false);
227+
var subscribeResult = await _bidi.SessionModule.SubscribeAsync([eventName], new() { Contexts = browsingContextsOptions.Contexts }).ConfigureAwait(false);
227228

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

230231
handlers.Add(eventHandler);
231232

232-
return new Subscription(this, eventHandler);
233+
return new Subscription(subscribeResult.Subscription, this, eventHandler);
233234
}
234235
else
235236
{
236-
await _bidi.SessionModule.SubscribeAsync([eventName]).ConfigureAwait(false);
237+
var subscribeResult = await _bidi.SessionModule.SubscribeAsync([eventName]).ConfigureAwait(false);
237238

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

240241
handlers.Add(eventHandler);
241242

242-
return new Subscription(this, eventHandler);
243+
return new Subscription(subscribeResult.Subscription, this, eventHandler);
243244
}
244245
}
245246

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

251252
if (options is BrowsingContextsSubscriptionOptions browsingContextsOptions)
252253
{
253-
await _bidi.SessionModule.SubscribeAsync([eventName], new() { Contexts = browsingContextsOptions.Contexts }).ConfigureAwait(false);
254+
var subscribeResult = await _bidi.SessionModule.SubscribeAsync([eventName], new() { Contexts = browsingContextsOptions.Contexts }).ConfigureAwait(false);
254255

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

257258
handlers.Add(eventHandler);
258259

259-
return new Subscription(this, eventHandler);
260+
return new Subscription(subscribeResult.Subscription, this, eventHandler);
260261
}
261262
else
262263
{
263-
await _bidi.SessionModule.SubscribeAsync([eventName]).ConfigureAwait(false);
264+
var subscribeResult = await _bidi.SessionModule.SubscribeAsync([eventName]).ConfigureAwait(false);
264265

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

267268
handlers.Add(eventHandler);
268269

269-
return new Subscription(this, eventHandler);
270+
return new Subscription(subscribeResult.Subscription, this, eventHandler);
270271
}
271272
}
272273

273-
public async Task UnsubscribeAsync(EventHandler eventHandler)
274+
public async Task UnsubscribeAsync(Modules.Session.Subscription subscription, EventHandler eventHandler)
274275
{
275276
var eventHandlers = _eventHandlers[eventHandler.EventName];
276277

277278
eventHandlers.Remove(eventHandler);
278279

279-
if (eventHandler.Contexts is not null)
280+
if (subscription is not null)
280281
{
281-
if (!eventHandlers.Any(h => eventHandler.Contexts.Equals(h.Contexts)) && !eventHandlers.Any(h => h.Contexts is null))
282-
{
283-
await _bidi.SessionModule.UnsubscribeAsync([eventHandler.EventName], new() { Contexts = eventHandler.Contexts }).ConfigureAwait(false);
284-
}
282+
await _bidi.SessionModule.UnsubscribeAsync([subscription]).ConfigureAwait(false);
285283
}
286284
else
287285
{
288-
if (!eventHandlers.Any(h => h.Contexts is not null) && !eventHandlers.Any(h => h.Contexts is null))
286+
if (eventHandler.Contexts is not null)
287+
{
288+
if (!eventHandlers.Any(h => eventHandler.Contexts.Equals(h.Contexts)) && !eventHandlers.Any(h => h.Contexts is null))
289+
{
290+
await _bidi.SessionModule.UnsubscribeAsync([eventHandler.EventName], new() { Contexts = eventHandler.Contexts }).ConfigureAwait(false);
291+
}
292+
}
293+
else
289294
{
290-
await _bidi.SessionModule.UnsubscribeAsync([eventHandler.EventName]).ConfigureAwait(false);
295+
if (!eventHandlers.Any(h => h.Contexts is not null) && !eventHandlers.Any(h => h.Contexts is null))
296+
{
297+
await _bidi.SessionModule.UnsubscribeAsync([eventHandler.EventName]).ConfigureAwait(false);
298+
}
291299
}
292300
}
293301
}

dotnet/src/webdriver/BiDi/Communication/Json/BiDiJsonSerializerContext.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,9 @@ namespace OpenQA.Selenium.BiDi.Communication.Json;
7979
[JsonSerializable(typeof(Modules.Session.NewResult))]
8080
[JsonSerializable(typeof(Modules.Session.EndCommand))]
8181
[JsonSerializable(typeof(Modules.Session.SubscribeCommand))]
82-
[JsonSerializable(typeof(Modules.Session.UnsubscribeCommand))]
82+
[JsonSerializable(typeof(Modules.Session.SubscribeResult))]
83+
[JsonSerializable(typeof(Modules.Session.UnsubscribeByIdCommand))]
84+
[JsonSerializable(typeof(Modules.Session.UnsubscribeByAttributesCommand))]
8385

8486
[JsonSerializable(typeof(Modules.Browser.CloseCommand), TypeInfoPropertyName = "Browser_CloseCommand")]
8587
[JsonSerializable(typeof(Modules.Browser.CreateUserContextCommand))]
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// <copyright file="SubscriptionConverter.cs" company="Selenium Committers">
2+
// Licensed to the Software Freedom Conservancy (SFC) under one
3+
// or more contributor license agreements. See the NOTICE file
4+
// distributed with this work for additional information
5+
// regarding copyright ownership. The SFC licenses this file
6+
// to you under the Apache License, Version 2.0 (the
7+
// "License"); you may not use this file except in compliance
8+
// with the License. You may obtain a copy of the License at
9+
//
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
//
12+
// Unless required by applicable law or agreed to in writing,
13+
// software distributed under the License is distributed on an
14+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
// KIND, either express or implied. See the License for the
16+
// specific language governing permissions and limitations
17+
// under the License.
18+
// </copyright>
19+
20+
using System;
21+
using System.Text.Json;
22+
using System.Text.Json.Serialization;
23+
24+
#nullable enable
25+
26+
namespace OpenQA.Selenium.BiDi.Communication.Json.Converters;
27+
28+
internal class SubscriptionConverter : JsonConverter<Modules.Session.Subscription>
29+
{
30+
public override Modules.Session.Subscription? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
31+
{
32+
var id = reader.GetString();
33+
34+
return new Modules.Session.Subscription(id!);
35+
}
36+
37+
public override void Write(Utf8JsonWriter writer, Modules.Session.Subscription value, JsonSerializerOptions options)
38+
{
39+
writer.WriteStringValue(value.Id);
40+
}
41+
}

dotnet/src/webdriver/BiDi/Modules/Session/SessionModule.cs

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public async Task<StatusResult> StatusAsync(StatusOptions? options = null)
3232
return await Broker.ExecuteCommandAsync<StatusCommand, StatusResult>(new StatusCommand(), options).ConfigureAwait(false);
3333
}
3434

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

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

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

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

51-
if (options is not null)
52-
{
53-
@params.Contexts = options.Contexts;
54-
}
51+
await Broker.ExecuteCommandAsync(new UnsubscribeByIdCommand(@params), options).ConfigureAwait(false);
52+
}
53+
54+
public async Task UnsubscribeAsync(IEnumerable<string> eventNames = null, UnsubscribeByAttributesOptions? options = null)
55+
{
56+
var @params = new UnsubscribeByAttributesCommandParameters(eventNames);
57+
58+
@params.Contexts = options?.Contexts;
5559

56-
await Broker.ExecuteCommandAsync(new UnsubscribeCommand(@params), options).ConfigureAwait(false);
60+
await Broker.ExecuteCommandAsync(new UnsubscribeByAttributesCommand(@params), options).ConfigureAwait(false);
5761
}
5862

5963
public async Task<NewResult> NewAsync(CapabilitiesRequest capabilitiesRequest, NewOptions? options = null)

dotnet/src/webdriver/BiDi/Modules/Session/SubscribeCommand.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,5 @@ public record SubscribeOptions : CommandOptions
3636
{
3737
public IEnumerable<BrowsingContext.BrowsingContext>? Contexts { get; set; }
3838
}
39+
40+
internal record SubscribeResult(Subscription Subscription);
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// <copyright file="Subscription.cs" company="Selenium Committers">
2+
// Licensed to the Software Freedom Conservancy (SFC) under one
3+
// or more contributor license agreements. See the NOTICE file
4+
// distributed with this work for additional information
5+
// regarding copyright ownership. The SFC licenses this file
6+
// to you under the Apache License, Version 2.0 (the
7+
// "License"); you may not use this file except in compliance
8+
// with the License. You may obtain a copy of the License at
9+
//
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
//
12+
// Unless required by applicable law or agreed to in writing,
13+
// software distributed under the License is distributed on an
14+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
// KIND, either express or implied. See the License for the
16+
// specific language governing permissions and limitations
17+
// under the License.
18+
// </copyright>
19+
20+
#nullable enable
21+
22+
namespace OpenQA.Selenium.BiDi.Modules.Session;
23+
24+
public sealed class Subscription
25+
{
26+
internal Subscription(string id)
27+
{
28+
Id = id;
29+
}
30+
31+
internal string Id { get; }
32+
}

dotnet/src/webdriver/BiDi/Modules/Session/UnsubscribeCommand.cs

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,31 @@
1818
// </copyright>
1919

2020
using OpenQA.Selenium.BiDi.Communication;
21+
using System;
22+
using System.Collections.Generic;
2123

2224
#nullable enable
2325

2426
namespace OpenQA.Selenium.BiDi.Modules.Session;
2527

26-
internal class UnsubscribeCommand(SubscribeCommandParameters @params)
27-
: Command<SubscribeCommandParameters>(@params, "session.unsubscribe");
28+
internal class UnsubscribeByIdCommand(UnsubscribeByIdCommandParameters @params)
29+
: Command<UnsubscribeByIdCommandParameters>(@params, "session.unsubscribe");
2830

29-
public record UnsubscribeOptions : SubscribeOptions;
31+
internal class UnsubscribeByAttributesCommand(UnsubscribeByAttributesCommandParameters @params)
32+
: Command<UnsubscribeByAttributesCommandParameters>(@params, "session.unsubscribe");
33+
34+
internal record UnsubscribeByIdCommandParameters(IEnumerable<Subscription> Subscriptions) : CommandParameters;
35+
36+
public record UnsubscribeByIdOptions : CommandOptions;
37+
38+
internal record UnsubscribeByAttributesCommandParameters(IEnumerable<string> Events) : CommandParameters
39+
{
40+
[Obsolete("Contexts param is deprecated and will be removed in the future versions")]
41+
// https://w3c.github.io/webdriver-bidi/#type-session-UnsubscribeByAttributesRequest
42+
public IEnumerable<BrowsingContext.BrowsingContext>? Contexts { get; set; }
43+
}
44+
45+
public record UnsubscribeByAttributesOptions : CommandOptions
46+
{
47+
public IEnumerable<BrowsingContext.BrowsingContext>? Contexts { get; set; }
48+
}

dotnet/src/webdriver/BiDi/Subscription.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,18 +28,20 @@ namespace OpenQA.Selenium.BiDi;
2828

2929
public class Subscription : IAsyncDisposable
3030
{
31+
private readonly Modules.Session.Subscription _subscription;
3132
private readonly Broker _broker;
3233
private readonly Communication.EventHandler _eventHandler;
3334

34-
internal Subscription(Broker broker, Communication.EventHandler eventHandler)
35+
internal Subscription(Modules.Session.Subscription subscription, Broker broker, Communication.EventHandler eventHandler)
3536
{
37+
_subscription = subscription;
3638
_broker = broker;
3739
_eventHandler = eventHandler;
3840
}
3941

4042
public async Task UnsubscribeAsync()
4143
{
42-
await _broker.UnsubscribeAsync(_eventHandler).ConfigureAwait(false);
44+
await _broker.UnsubscribeAsync(_subscription, _eventHandler).ConfigureAwait(false);
4345
}
4446

4547
public async ValueTask DisposeAsync()

0 commit comments

Comments
 (0)