Skip to content

Commit 3de1d94

Browse files
authored
[dotnet] [bidi] Avoid polymorphic commands to be more statically easier (#15202)
1 parent 74feb5d commit 3de1d94

Some content is hidden

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

51 files changed

+173
-130
lines changed

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

+10-7
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public class Broker : IAsyncDisposable
4141
private readonly BiDi _bidi;
4242
private readonly ITransport _transport;
4343

44-
private readonly ConcurrentDictionary<int, TaskCompletionSource<object>> _pendingCommands = new();
44+
private readonly ConcurrentDictionary<int, TaskCompletionSource<JsonElement>> _pendingCommands = new();
4545
private readonly BlockingCollection<MessageEvent> _pendingEvents = [];
4646

4747
private readonly ConcurrentDictionary<string, List<EventHandler>> _eventHandlers = new();
@@ -176,23 +176,26 @@ private async Task ProcessEventsAwaiterAsync()
176176
}
177177
}
178178

179-
public async Task<TResult> ExecuteCommandAsync<TResult>(Command command, CommandOptions? options)
179+
public async Task<TResult> ExecuteCommandAsync<TCommand, TResult>(TCommand command, CommandOptions? options)
180+
where TCommand: Command
180181
{
181-
var result = await ExecuteCommandCoreAsync(command, options).ConfigureAwait(false);
182+
var jsonElement = await ExecuteCommandCoreAsync(command, options).ConfigureAwait(false);
182183

183-
return (TResult)((JsonElement)result).Deserialize(typeof(TResult), _jsonSerializerContext)!;
184+
return (TResult)jsonElement.Deserialize(typeof(TResult), _jsonSerializerContext)!;
184185
}
185186

186-
public async Task ExecuteCommandAsync(Command command, CommandOptions? options)
187+
public async Task ExecuteCommandAsync<TCommand>(TCommand command, CommandOptions? options)
188+
where TCommand: Command
187189
{
188190
await ExecuteCommandCoreAsync(command, options).ConfigureAwait(false);
189191
}
190192

191-
private async Task<object> ExecuteCommandCoreAsync(Command command, CommandOptions? options)
193+
private async Task<JsonElement> ExecuteCommandCoreAsync<TCommand>(TCommand command, CommandOptions? options)
194+
where TCommand: Command
192195
{
193196
command.Id = Interlocked.Increment(ref _currentCommandId);
194197

195-
var tcs = new TaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously);
198+
var tcs = new TaskCompletionSource<JsonElement>(TaskCreationOptions.RunContinuationsAsynchronously);
196199

197200
var timeout = options?.Timeout ?? TimeSpan.FromSeconds(30);
198201

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

+8-52
Original file line numberDiff line numberDiff line change
@@ -17,67 +17,23 @@
1717
// under the License.
1818
// </copyright>
1919

20-
using System.Text.Json.Serialization;
21-
2220
#nullable enable
2321

2422
namespace OpenQA.Selenium.BiDi.Communication;
2523

26-
[JsonPolymorphic(TypeDiscriminatorPropertyName = "method")]
27-
28-
[JsonDerivedType(typeof(Modules.Session.StatusCommand), "session.status")]
29-
[JsonDerivedType(typeof(Modules.Session.SubscribeCommand), "session.subscribe")]
30-
[JsonDerivedType(typeof(Modules.Session.UnsubscribeCommand), "session.unsubscribe")]
31-
[JsonDerivedType(typeof(Modules.Session.NewCommand), "session.new")]
32-
[JsonDerivedType(typeof(Modules.Session.EndCommand), "session.end")]
33-
34-
[JsonDerivedType(typeof(Modules.Browser.CreateUserContextCommand), "browser.createUserContext")]
35-
[JsonDerivedType(typeof(Modules.Browser.GetUserContextsCommand), "browser.getUserContexts")]
36-
[JsonDerivedType(typeof(Modules.Browser.RemoveUserContextCommand), "browser.removeUserContext")]
37-
[JsonDerivedType(typeof(Modules.Browser.CloseCommand), "browser.close")]
38-
39-
[JsonDerivedType(typeof(Modules.BrowsingContext.CreateCommand), "browsingContext.create")]
40-
[JsonDerivedType(typeof(Modules.BrowsingContext.NavigateCommand), "browsingContext.navigate")]
41-
[JsonDerivedType(typeof(Modules.BrowsingContext.ReloadCommand), "browsingContext.reload")]
42-
[JsonDerivedType(typeof(Modules.BrowsingContext.TraverseHistoryCommand), "browsingContext.traverseHistory")]
43-
[JsonDerivedType(typeof(Modules.BrowsingContext.LocateNodesCommand), "browsingContext.locateNodes")]
44-
[JsonDerivedType(typeof(Modules.BrowsingContext.ActivateCommand), "browsingContext.activate")]
45-
[JsonDerivedType(typeof(Modules.BrowsingContext.CaptureScreenshotCommand), "browsingContext.captureScreenshot")]
46-
[JsonDerivedType(typeof(Modules.BrowsingContext.SetViewportCommand), "browsingContext.setViewport")]
47-
[JsonDerivedType(typeof(Modules.BrowsingContext.GetTreeCommand), "browsingContext.getTree")]
48-
[JsonDerivedType(typeof(Modules.BrowsingContext.PrintCommand), "browsingContext.print")]
49-
[JsonDerivedType(typeof(Modules.BrowsingContext.HandleUserPromptCommand), "browsingContext.handleUserPrompt")]
50-
[JsonDerivedType(typeof(Modules.BrowsingContext.CloseCommand), "browsingContext.close")]
51-
52-
[JsonDerivedType(typeof(Modules.Network.AddInterceptCommand), "network.addIntercept")]
53-
[JsonDerivedType(typeof(Modules.Network.ContinueRequestCommand), "network.continueRequest")]
54-
[JsonDerivedType(typeof(Modules.Network.ContinueResponseCommand), "network.continueResponse")]
55-
[JsonDerivedType(typeof(Modules.Network.FailRequestCommand), "network.failRequest")]
56-
[JsonDerivedType(typeof(Modules.Network.ProvideResponseCommand), "network.provideResponse")]
57-
[JsonDerivedType(typeof(Modules.Network.ContinueWithAuthCommand), "network.continueWithAuth")]
58-
[JsonDerivedType(typeof(Modules.Network.RemoveInterceptCommand), "network.removeIntercept")]
59-
[JsonDerivedType(typeof(Modules.Network.SetCacheBehaviorCommand), "network.setCacheBehavior")]
60-
61-
[JsonDerivedType(typeof(Modules.Script.AddPreloadScriptCommand), "script.addPreloadScript")]
62-
[JsonDerivedType(typeof(Modules.Script.RemovePreloadScriptCommand), "script.removePreloadScript")]
63-
[JsonDerivedType(typeof(Modules.Script.EvaluateCommand), "script.evaluate")]
64-
[JsonDerivedType(typeof(Modules.Script.CallFunctionCommand), "script.callFunction")]
65-
[JsonDerivedType(typeof(Modules.Script.DisownCommand), "script.disown")]
66-
[JsonDerivedType(typeof(Modules.Script.GetRealmsCommand), "script.getRealms")]
67-
68-
[JsonDerivedType(typeof(Modules.Input.PerformActionsCommand), "input.performActions")]
69-
[JsonDerivedType(typeof(Modules.Input.ReleaseActionsCommand), "input.releaseActions")]
70-
71-
[JsonDerivedType(typeof(Modules.Storage.GetCookiesCommand), "storage.getCookies")]
72-
[JsonDerivedType(typeof(Modules.Storage.DeleteCookiesCommand), "storage.deleteCookies")]
73-
[JsonDerivedType(typeof(Modules.Storage.SetCookieCommand), "storage.setCookie")]
74-
7524
public abstract class Command
7625
{
26+
protected Command(string method)
27+
{
28+
Method = method;
29+
}
30+
31+
public string Method { get; }
32+
7733
public int Id { get; internal set; }
7834
}
7935

80-
internal abstract class Command<TCommandParameters>(TCommandParameters @params) : Command
36+
internal abstract class Command<TCommandParameters>(TCommandParameters @params, string method) : Command(method)
8137
where TCommandParameters : CommandParameters
8238
{
8339
public TCommandParameters Params { get; } = @params;

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

+50-7
Original file line numberDiff line numberDiff line change
@@ -73,31 +73,62 @@ namespace OpenQA.Selenium.BiDi.Communication.Json;
7373
[JsonSerializable(typeof(Command))]
7474
[JsonSerializable(typeof(Message))]
7575

76+
[JsonSerializable(typeof(Modules.Session.StatusCommand))]
7677
[JsonSerializable(typeof(Modules.Session.StatusResult))]
78+
[JsonSerializable(typeof(Modules.Session.NewCommand))]
7779
[JsonSerializable(typeof(Modules.Session.NewResult))]
80+
[JsonSerializable(typeof(Modules.Session.EndCommand))]
81+
[JsonSerializable(typeof(Modules.Session.SubscribeCommand))]
82+
[JsonSerializable(typeof(Modules.Session.UnsubscribeCommand))]
7883

7984
[JsonSerializable(typeof(Modules.Browser.CloseCommand), TypeInfoPropertyName = "Browser_CloseCommand")]
85+
[JsonSerializable(typeof(Modules.Browser.CreateUserContextCommand))]
86+
[JsonSerializable(typeof(Modules.Browser.GetUserContextsCommand))]
8087
[JsonSerializable(typeof(Modules.Browser.GetUserContextsResult))]
88+
[JsonSerializable(typeof(Modules.Browser.RemoveUserContextCommand))]
89+
[JsonSerializable(typeof(Modules.Browser.UserContextInfo))]
8190
[JsonSerializable(typeof(IReadOnlyList<Modules.Browser.UserContextInfo>))]
8291

92+
93+
[JsonSerializable(typeof(Modules.BrowsingContext.ActivateCommand))]
94+
[JsonSerializable(typeof(Modules.BrowsingContext.CaptureScreenshotCommand))]
95+
[JsonSerializable(typeof(Modules.BrowsingContext.CaptureScreenshotResult))]
8396
[JsonSerializable(typeof(Modules.BrowsingContext.CloseCommand), TypeInfoPropertyName = "BrowsingContext_CloseCommand")]
97+
[JsonSerializable(typeof(Modules.BrowsingContext.CreateCommand))]
8498
[JsonSerializable(typeof(Modules.BrowsingContext.CreateResult))]
85-
[JsonSerializable(typeof(Modules.BrowsingContext.BrowsingContextInfo))]
86-
[JsonSerializable(typeof(Modules.BrowsingContext.NavigateResult))]
87-
[JsonSerializable(typeof(Modules.BrowsingContext.NavigationInfo))]
88-
[JsonSerializable(typeof(Modules.BrowsingContext.TraverseHistoryResult))]
89-
[JsonSerializable(typeof(Modules.BrowsingContext.LocateNodesResult))]
90-
[JsonSerializable(typeof(Modules.BrowsingContext.CaptureScreenshotResult))]
99+
[JsonSerializable(typeof(Modules.BrowsingContext.GetTreeCommand))]
91100
[JsonSerializable(typeof(Modules.BrowsingContext.GetTreeResult))]
101+
[JsonSerializable(typeof(Modules.BrowsingContext.HandleUserPromptCommand))]
102+
[JsonSerializable(typeof(Modules.BrowsingContext.LocateNodesCommand))]
103+
[JsonSerializable(typeof(Modules.BrowsingContext.LocateNodesResult))]
104+
[JsonSerializable(typeof(Modules.BrowsingContext.NavigateCommand))]
105+
[JsonSerializable(typeof(Modules.BrowsingContext.NavigateResult))]
106+
[JsonSerializable(typeof(Modules.BrowsingContext.PrintCommand))]
92107
[JsonSerializable(typeof(Modules.BrowsingContext.PrintResult))]
108+
[JsonSerializable(typeof(Modules.BrowsingContext.ReloadCommand))]
109+
[JsonSerializable(typeof(Modules.BrowsingContext.SetViewportCommand))]
110+
[JsonSerializable(typeof(Modules.BrowsingContext.TraverseHistoryCommand))]
111+
[JsonSerializable(typeof(Modules.BrowsingContext.TraverseHistoryResult))]
112+
[JsonSerializable(typeof(Modules.BrowsingContext.BrowsingContextInfo))]
113+
[JsonSerializable(typeof(Modules.BrowsingContext.NavigationInfo))]
114+
93115
[JsonSerializable(typeof(Modules.BrowsingContext.UserPromptOpenedEventArgs))]
94116
[JsonSerializable(typeof(Modules.BrowsingContext.UserPromptClosedEventArgs))]
95117
[JsonSerializable(typeof(Modules.BrowsingContext.Origin), TypeInfoPropertyName = "BrowsingContext_Origin")]
96118

97119
[JsonSerializable(typeof(Modules.Network.BytesValue.String), TypeInfoPropertyName = "Network_BytesValue_String")]
98120
[JsonSerializable(typeof(Modules.Network.UrlPattern.String), TypeInfoPropertyName = "Network_UrlPattern_String")]
99121
[JsonSerializable(typeof(Modules.Network.ContinueWithAuthParameters.Default), TypeInfoPropertyName = "Network_ContinueWithAuthParameters_Default")]
122+
[JsonSerializable(typeof(Modules.Network.AddInterceptCommand))]
100123
[JsonSerializable(typeof(Modules.Network.AddInterceptResult))]
124+
[JsonSerializable(typeof(Modules.Network.ContinueRequestCommand))]
125+
[JsonSerializable(typeof(Modules.Network.ContinueResponseCommand))]
126+
[JsonSerializable(typeof(Modules.Network.ContinueWithAuthCommand))]
127+
[JsonSerializable(typeof(Modules.Network.FailRequestCommand))]
128+
[JsonSerializable(typeof(Modules.Network.ProvideResponseCommand))]
129+
[JsonSerializable(typeof(Modules.Network.RemoveInterceptCommand))]
130+
[JsonSerializable(typeof(Modules.Network.SetCacheBehaviorCommand))]
131+
101132
[JsonSerializable(typeof(Modules.Network.BeforeRequestSentEventArgs))]
102133
[JsonSerializable(typeof(Modules.Network.ResponseStartedEventArgs))]
103134
[JsonSerializable(typeof(Modules.Network.ResponseCompletedEventArgs))]
@@ -108,20 +139,32 @@ namespace OpenQA.Selenium.BiDi.Communication.Json;
108139
[JsonSerializable(typeof(Modules.Script.LocalValue.String), TypeInfoPropertyName = "Script_LocalValue_String")]
109140
[JsonSerializable(typeof(Modules.Script.Target.Realm), TypeInfoPropertyName = "Script_Target_Realm")]
110141
[JsonSerializable(typeof(Modules.Script.Target.Context), TypeInfoPropertyName = "Script_Target_Context")]
142+
143+
[JsonSerializable(typeof(Modules.Script.AddPreloadScriptCommand))]
111144
[JsonSerializable(typeof(Modules.Script.AddPreloadScriptResult))]
145+
[JsonSerializable(typeof(Modules.Script.DisownCommand))]
146+
[JsonSerializable(typeof(Modules.Script.CallFunctionCommand))]
147+
[JsonSerializable(typeof(Modules.Script.EvaluateCommand))]
112148
[JsonSerializable(typeof(Modules.Script.EvaluateResult))]
149+
[JsonSerializable(typeof(Modules.Script.GetRealmsCommand))]
113150
[JsonSerializable(typeof(Modules.Script.GetRealmsResult))]
151+
[JsonSerializable(typeof(Modules.Script.RemovePreloadScriptCommand))]
152+
114153
[JsonSerializable(typeof(Modules.Script.MessageEventArgs))]
115154
[JsonSerializable(typeof(Modules.Script.RealmDestroyedEventArgs))]
116155
[JsonSerializable(typeof(IReadOnlyList<Modules.Script.RealmInfo>))]
117156

118157
[JsonSerializable(typeof(Modules.Log.Entry))]
119158

159+
[JsonSerializable(typeof(Modules.Storage.GetCookiesCommand))]
120160
[JsonSerializable(typeof(Modules.Storage.GetCookiesResult))]
121-
[JsonSerializable(typeof(Modules.Storage.DeleteCookiesResult))]
161+
[JsonSerializable(typeof(Modules.Storage.SetCookieCommand))]
122162
[JsonSerializable(typeof(Modules.Storage.SetCookieResult))]
163+
[JsonSerializable(typeof(Modules.Storage.DeleteCookiesCommand))]
164+
[JsonSerializable(typeof(Modules.Storage.DeleteCookiesResult))]
123165

124166
[JsonSerializable(typeof(Modules.Input.PerformActionsCommand))]
167+
[JsonSerializable(typeof(Modules.Input.ReleaseActionsCommand))]
125168
[JsonSerializable(typeof(Modules.Input.Pointer.Down), TypeInfoPropertyName = "Input_Pointer_Down")]
126169
[JsonSerializable(typeof(Modules.Input.Pointer.Up), TypeInfoPropertyName = "Input_Pointer_Up")]
127170
[JsonSerializable(typeof(Modules.Input.Pointer.Move), TypeInfoPropertyName = "Input_Pointer_Move")]

dotnet/src/webdriver/BiDi/Communication/Transport/ITransport.cs

+2-1
Original file line numberDiff line numberDiff line change
@@ -32,5 +32,6 @@ interface ITransport : IDisposable
3232

3333
Task<T> ReceiveAsJsonAsync<T>(JsonSerializerContext jsonSerializerContext, CancellationToken cancellationToken);
3434

35-
Task SendAsJsonAsync(Command command, JsonSerializerContext jsonSerializerContext, CancellationToken cancellationToken);
35+
Task SendAsJsonAsync<TCommand>(TCommand command, JsonSerializerContext jsonSerializerContext, CancellationToken cancellationToken)
36+
where TCommand : Command;
3637
}

dotnet/src/webdriver/BiDi/Communication/Transport/WebSocketTransport.cs

+3-2
Original file line numberDiff line numberDiff line change
@@ -71,9 +71,10 @@ public async Task<T> ReceiveAsJsonAsync<T>(JsonSerializerContext jsonSerializerC
7171
return (T)res!;
7272
}
7373

74-
public async Task SendAsJsonAsync(Command command, JsonSerializerContext jsonSerializerContext, CancellationToken cancellationToken)
74+
public async Task SendAsJsonAsync<TCommand>(TCommand command, JsonSerializerContext jsonSerializerContext, CancellationToken cancellationToken)
75+
where TCommand : Command
7576
{
76-
var buffer = JsonSerializer.SerializeToUtf8Bytes(command, typeof(Command), jsonSerializerContext);
77+
var buffer = JsonSerializer.SerializeToUtf8Bytes(command, typeof(TCommand), jsonSerializerContext);
7778

7879
await _socketSendSemaphoreSlim.WaitAsync(cancellationToken);
7980

dotnet/src/webdriver/BiDi/Modules/Browser/BrowserModule.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,12 @@ public async Task CloseAsync(CloseOptions? options = null)
3434

3535
public async Task<UserContextInfo> CreateUserContextAsync(CreateUserContextOptions? options = null)
3636
{
37-
return await Broker.ExecuteCommandAsync<UserContextInfo>(new CreateUserContextCommand(), options).ConfigureAwait(false);
37+
return await Broker.ExecuteCommandAsync<CreateUserContextCommand, UserContextInfo>(new CreateUserContextCommand(), options).ConfigureAwait(false);
3838
}
3939

4040
public async Task<GetUserContextsResult> GetUserContextsAsync(GetUserContextsOptions? options = null)
4141
{
42-
return await Broker.ExecuteCommandAsync<GetUserContextsResult>(new GetUserContextsCommand(), options).ConfigureAwait(false);
42+
return await Broker.ExecuteCommandAsync<GetUserContextsCommand, GetUserContextsResult>(new GetUserContextsCommand(), options).ConfigureAwait(false);
4343
}
4444

4545
public async Task RemoveUserContextAsync(UserContext userContext, RemoveUserContextOptions? options = null)

dotnet/src/webdriver/BiDi/Modules/Browser/CloseCommand.cs

+2-1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323

2424
namespace OpenQA.Selenium.BiDi.Modules.Browser;
2525

26-
internal class CloseCommand() : Command<CommandParameters>(CommandParameters.Empty);
26+
internal class CloseCommand()
27+
: Command<CommandParameters>(CommandParameters.Empty, "browser.close");
2728

2829
public record CloseOptions : CommandOptions;

dotnet/src/webdriver/BiDi/Modules/Browser/CreateUserContextCommand.cs

+2-1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323

2424
namespace OpenQA.Selenium.BiDi.Modules.Browser;
2525

26-
internal class CreateUserContextCommand() : Command<CommandParameters>(CommandParameters.Empty);
26+
internal class CreateUserContextCommand()
27+
: Command<CommandParameters>(CommandParameters.Empty, "browser.createUserContext");
2728

2829
public record CreateUserContextOptions : CommandOptions;

dotnet/src/webdriver/BiDi/Modules/Browser/GetUserContextsCommand.cs

+2-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@
2525

2626
namespace OpenQA.Selenium.BiDi.Modules.Browser;
2727

28-
internal class GetUserContextsCommand() : Command<CommandParameters>(CommandParameters.Empty);
28+
internal class GetUserContextsCommand()
29+
: Command<CommandParameters>(CommandParameters.Empty, "browser.getUserContexts");
2930

3031
public record GetUserContextsOptions : CommandOptions;
3132

dotnet/src/webdriver/BiDi/Modules/Browser/RemoveUserContextCommand.cs

+2-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@
2323

2424
namespace OpenQA.Selenium.BiDi.Modules.Browser;
2525

26-
internal class RemoveUserContextCommand(RemoveUserContextCommandParameters @params) : Command<RemoveUserContextCommandParameters>(@params);
26+
internal class RemoveUserContextCommand(RemoveUserContextCommandParameters @params)
27+
: Command<RemoveUserContextCommandParameters>(@params, "browser.removeUserContext");
2728

2829
internal record RemoveUserContextCommandParameters(UserContext UserContext) : CommandParameters;
2930

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

+2-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@
2323

2424
namespace OpenQA.Selenium.BiDi.Modules.BrowsingContext;
2525

26-
internal class ActivateCommand(ActivateCommandParameters @params) : Command<ActivateCommandParameters>(@params);
26+
internal class ActivateCommand(ActivateCommandParameters @params)
27+
: Command<ActivateCommandParameters>(@params, "browsingContext.activate");
2728

2829
internal record ActivateCommandParameters(BrowsingContext Context) : CommandParameters;
2930

0 commit comments

Comments
 (0)