Skip to content

Commit 9abca5e

Browse files
committed
Removing use of System.Threading.Channels
1 parent 98b5444 commit 9abca5e

File tree

6 files changed

+39
-64
lines changed

6 files changed

+39
-64
lines changed

dotnet/src/webdriver/BUILD.bazel

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,6 @@ csharp_library(
6565
"@identitymodel.tokens//:Microsoft.IdentityModel.Tokens",
6666
"@json.net//:Newtonsoft.Json",
6767
"@system.drawing.common//:System.Drawing.Common",
68-
"@system.threading.channels//:System.Threading.Channels",
69-
"@system.threading.tasks.extensions//:System.Threading.Tasks.Extensions",
7068
],
7169
)
7270

dotnet/src/webdriver/DevTools/DevToolsSession.cs

Lines changed: 35 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
using System.Globalization;
2222
using System.Net.Http;
2323
using System.Threading;
24-
using System.Threading.Channels;
2524
using System.Threading.Tasks;
2625
using Newtonsoft.Json;
2726
using Newtonsoft.Json.Linq;
@@ -46,14 +45,12 @@ public class DevToolsSession : IDevToolsSession
4645

4746
private WebSocketConnection connection;
4847
private ConcurrentDictionary<long, DevToolsCommandData> pendingCommands = new ConcurrentDictionary<long, DevToolsCommandData>();
49-
private readonly Channel<string> messageQueue;
48+
private readonly BlockingCollection<string> messageQueue = new BlockingCollection<string>();
5049
private readonly Task messageQueueMonitorTask;
5150
private long currentCommandId = 0;
5251

5352
private DevToolsDomains domains;
5453

55-
private CancellationTokenSource receiveCancellationToken;
56-
5754
/// <summary>
5855
/// Initializes a new instance of the DevToolsSession class, using the specified WebSocket endpoint.
5956
/// </summary>
@@ -71,11 +68,6 @@ public DevToolsSession(string endpointAddress)
7168
{
7269
this.websocketAddress = endpointAddress;
7370
}
74-
this.messageQueue = Channel.CreateUnbounded<string>(new UnboundedChannelOptions()
75-
{
76-
SingleReader = true,
77-
SingleWriter = true,
78-
});
7971
this.messageQueueMonitorTask = Task.Run(() => this.MonitorMessageQueue());
8072
this.messageQueueMonitorTask.ConfigureAwait(false);
8173
}
@@ -166,7 +158,8 @@ public T GetVersionSpecificDomains<T>() where T : DevToolsSessionDomains
166158
/// </summary>
167159
/// <typeparam name="TCommandResponse"></typeparam>
168160
/// <typeparam name="TCommand">A command object implementing the <see cref="ICommand"/> interface.</typeparam>
169-
/// <param name="cancellationToken">A CancellationToken object to allow for cancellation of the command.</param>
161+
/// <param name="command">A CancellationToken object to allow for cancellation of the command.</param>
162+
/// <param name="cancellationToken">The command to be sent.</param>
170163
/// <param name="millisecondsTimeout">The execution timeout of the command in milliseconds.</param>
171164
/// <param name="throwExceptionIfResponseNotReceived"><see langword="true"/> to throw an exception if a response is not received; otherwise, <see langword="false"/>.</param>
172165
/// <returns>The command response object implementing the <see cref="ICommandResponse{T}"/> interface.</returns>
@@ -295,7 +288,7 @@ internal async Task StartSession(int requestedProtocolVersion)
295288
/// Asynchronously stops the session.
296289
/// </summary>
297290
/// <param name="manualDetach"><see langword="true"/> to manually detach the session
298-
/// from its attached target; otherswise <see langword="false""/>.</param>
291+
/// from its attached target; otherswise <see langword="false"/>.</param>
299292
/// <returns>A task that represents the asynchronous operation.</returns>
300293
internal async Task StopSession(bool manualDetach)
301294
{
@@ -413,38 +406,60 @@ private void OnTargetDetached(object sender, TargetDetachedEventArgs e)
413406
private async Task InitializeSocketConnection()
414407
{
415408
LogTrace("Creating WebSocket");
416-
this.connection = new WebSocketConnection();
409+
this.connection = new WebSocketConnection(this.openConnectionWaitTimeSpan, this.closeConnectionWaitTimeSpan);
417410
connection.DataReceived += OnConnectionDataReceived;
418411
await connection.Start(this.websocketAddress);
419-
LogTrace("WebSocket created; starting message listener");
412+
LogTrace("WebSocket created");
420413
}
421414

422415
private async Task TerminateSocketConnection()
423416
{
417+
LogTrace("Closing WebSocket");
424418
if (this.connection != null && this.connection.IsActive)
425419
{
426420
await this.connection.Stop();
427421
await this.ShutdownMessageQueue();
428422
}
423+
LogTrace("WebSocket closed");
429424
}
430425

431426
private async Task ShutdownMessageQueue()
432427
{
433-
// Attempt to wait for the channel to empty before marking the
434-
// writer as complete and waiting for the monitor task to end.
435428
// THe WebSockect connection is always closed before this method
436429
// is called, so there will eventually be no more data written
437-
// into the message queue, so this loop should be guaranteed to
438-
// complete.
439-
while (this.messageQueue.Reader.TryPeek(out _))
430+
// into the message queue, meaning this loop should be guaranteed
431+
// to complete.
432+
while (this.connection.IsActive)
440433
{
441434
await Task.Delay(TimeSpan.FromMilliseconds(10));
442435
}
443436

444-
this.messageQueue.Writer.Complete();
437+
this.messageQueue.CompleteAdding();
445438
await this.messageQueueMonitorTask;
446439
}
447440

441+
private void MonitorMessageQueue()
442+
{
443+
// Loop until the BlockingCollection is marked as completed for adding
444+
// (meaning no more information will be added into the collection, and
445+
// it is empty (meaning all items in the collection have been processed).
446+
while (!this.messageQueue.IsCompleted)
447+
{
448+
try
449+
{
450+
// The Take() method blocks until there is something to
451+
// remove from the BlockingCollection.
452+
this.ProcessMessage(this.messageQueue.Take());
453+
}
454+
catch (InvalidOperationException)
455+
{
456+
// InvalidOperationException is normal when the collection
457+
// is marked as completed while being blocked by the Take()
458+
// method.
459+
}
460+
}
461+
}
462+
448463
private void ProcessMessage(string message)
449464
{
450465
var messageObject = JObject.Parse(message);
@@ -498,25 +513,6 @@ private void ProcessMessage(string message)
498513
LogTrace("Recieved Other: {0}", message);
499514
}
500515

501-
/// <summary>
502-
/// Reads incoming messages in the message queue.
503-
/// </summary>
504-
private void ReadIncomingMessages()
505-
{
506-
while (this.messageQueue.Reader.TryRead(out string message))
507-
{
508-
this.ProcessMessage(message);
509-
}
510-
}
511-
512-
private async Task MonitorMessageQueue()
513-
{
514-
while (await this.messageQueue.Reader.WaitToReadAsync())
515-
{
516-
this.ReadIncomingMessages();
517-
}
518-
}
519-
520516
private void OnDevToolsEventReceived(DevToolsEventReceivedEventArgs e)
521517
{
522518
if (DevToolsEventReceived != null)
@@ -527,7 +523,7 @@ private void OnDevToolsEventReceived(DevToolsEventReceivedEventArgs e)
527523

528524
private void OnConnectionDataReceived(object sender, WebSocketConnectionDataReceivedEventArgs e)
529525
{
530-
_ = this.messageQueue.Writer.TryWrite(e.Data);
526+
this.messageQueue.Add(e.Data);
531527
}
532528

533529
private void LogTrace(string message, params object[] args)

dotnet/src/webdriver/DevTools/WebSocketConnection.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,10 @@ public virtual async Task Stop()
142142
// Whether we closed the socket or timed out, we cancel the token causing ReceiveAsync to abort the socket.
143143
// The finally block at the end of the processing loop will dispose of the ClientWebSocket object.
144144
this.clientTokenSource.Cancel();
145-
this.dataReceiveTask?.Wait();
145+
if (this.dataReceiveTask != null)
146+
{
147+
await this.dataReceiveTask;
148+
}
146149
}
147150

148151
/// <summary>

dotnet/src/webdriver/WebDriver.csproj

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -48,15 +48,6 @@
4848
<EmbeddedResource Remove="obj\**" />
4949
<None Remove="cdp\**" />
5050
<None Remove="obj\**" />
51-
<Compile Remove="Internal\IFindsByClassName.cs" />
52-
<Compile Remove="Internal\IFindsByCssSelector.cs" />
53-
<Compile Remove="Internal\IFindsById.cs" />
54-
<Compile Remove="Internal\IFindsByLinkText.cs" />
55-
<Compile Remove="Internal\IFindsByName.cs" />
56-
<Compile Remove="Internal\IFindsByPartialLinkText.cs" />
57-
<Compile Remove="Internal\IFindsByTagName.cs" />
58-
<Compile Remove="Internal\IFindsByXPath.cs" />
59-
<Compile Remove="Interactions\TouchActions.cs" />
6051
</ItemGroup>
6152

6253
<ItemGroup>
@@ -76,7 +67,6 @@
7667
<ItemGroup>
7768
<!--PackageReference Include="Microsoft.IdentityModel.Tokens" Version="6.19.0" PrivateAssets="All" /-->
7869
<PackageReference Include="System.Drawing.Common" Version="7.0.0" />
79-
<PackageReference Include="System.Threading.Channels" Version="7.0.0" />
8070
</ItemGroup>
8171

8272
<ItemGroup>

dotnet/workspace.bzl

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -41,18 +41,6 @@ def selenium_register_dotnet():
4141
sha256 = "b78141813321b8e039140db77e0d1640e1ae1f49e357b8495d24ff2e7fd99e4b",
4242
)
4343

44-
import_nuget_package(
45-
name = "system.threading.channels",
46-
file = "third_party/dotnet/nuget/packages/system.threading.channels.7.0.0.nupkg",
47-
sha256 = "0aed208d0b0b211f18be1d01e1c38f252615ab5d1afb717da55cff0b8dc235e3",
48-
)
49-
50-
import_nuget_package(
51-
name = "system.threading.tasks.extensions",
52-
file = "third_party/dotnet/nuget/packages/system.threading.tasks.extensions.4.5.4.nupkg",
53-
sha256 = "a304a963cc0796c5179f9c6b7d8022bbce3b2fa7c029eb6196f631f7b462d678",
54-
)
55-
5644
import_nuget_package(
5745
name = "moq",
5846
file = "third_party/dotnet/nuget/packages/moq.4.12.0.nupkg",
-191 KB
Binary file not shown.

0 commit comments

Comments
 (0)