Skip to content

Commit 2e21ecd

Browse files
authored
Make the available targets an async dictionary (#2281)
* Make the available targets an async dictionary * Ignore one test
1 parent 6ab2419 commit 2e21ecd

File tree

8 files changed

+43
-43
lines changed

8 files changed

+43
-43
lines changed

lib/PuppeteerSharp.Tests/HeadfulTests/HeadfulTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public async Task BackgroundPageTargetTypeShouldBeAvailable()
4040
}
4141

4242
[PuppeteerTest("headful.spec.ts", "HEADFUL", "target.page() should return a background_page")]
43-
[Skip(SkipAttribute.Targets.Firefox)]
43+
[Ignore("Marked as Fail/Pass upstream")]
4444
public async Task TargetPageShouldReturnABackgroundPage()
4545
{
4646
await using (var browserWithExtension = await Puppeteer.LaunchAsync(

lib/PuppeteerSharp/Browser.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,8 @@ public bool IsClosed
147147
public Task<IPage> NewPageAsync() => _defaultContext.NewPageAsync();
148148

149149
/// <inheritdoc/>
150-
public ITarget[] Targets() => TargetManager.GetAvailableTargets().Values.ToArray();
150+
public ITarget[] Targets()
151+
=> TargetManager.GetAvailableTargets().InnerDictionary.Values.ToArray();
151152

152153
/// <inheritdoc/>
153154
public async Task<IBrowserContext> CreateIncognitoBrowserContextAsync()
@@ -317,7 +318,7 @@ internal async Task<IPage> CreatePageInContextAsync(string contextId)
317318

318319
var targetId = (await Connection.SendAsync<TargetCreateTargetResponse>("Target.createTarget", createTargetRequest)
319320
.ConfigureAwait(false)).TargetId;
320-
var target = TargetManager.GetAvailableTargets()[targetId];
321+
var target = await TargetManager.GetAvailableTargets().GetItemAsync(targetId).ConfigureAwait(false);
321322
await target.InitializedTask.ConfigureAwait(false);
322323
return await target.PageAsync().ConfigureAwait(false);
323324
}

lib/PuppeteerSharp/ChromeTargetManager.cs

Lines changed: 20 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ internal class ChromeTargetManager : ITargetManager
1919
private readonly Func<TargetInfo, CDPSession, Target> _targetFactoryFunc;
2020
private readonly Func<TargetInfo, bool> _targetFilterFunc;
2121
private readonly ILogger<ChromeTargetManager> _logger;
22-
private readonly ConcurrentDictionary<string, Target> _attachedTargetsByTargetId = new();
22+
private readonly ConcurrentDictionary<string, Target> _availableTargetsByTargetIdDictionary = new();
23+
private readonly AsyncDictionaryHelper<string, Target> _attachedTargetsByTargetId;
2324
private readonly ConcurrentDictionary<string, Target> _attachedTargetsBySessionId = new();
2425
private readonly ConcurrentDictionary<string, TargetInfo> _discoveredTargetsByTargetId = new();
2526
private readonly ConcurrentDictionary<ICDPConnection, List<TargetInterceptor>> _targetInterceptors = new();
@@ -36,6 +37,7 @@ public ChromeTargetManager(
3637
Func<TargetInfo, bool> targetFilterFunc,
3738
int targetDiscoveryTimeout = 0)
3839
{
40+
_attachedTargetsByTargetId = new AsyncDictionaryHelper<string, Target>(_availableTargetsByTargetIdDictionary, "Target {0} not found");
3941
_connection = connection;
4042
_targetFilterFunc = targetFilterFunc;
4143
_targetFactoryFunc = targetFactoryFunc;
@@ -86,7 +88,7 @@ public ChromeTargetManager(
8688

8789
public event EventHandler<TargetChangedArgs> TargetDiscovered;
8890

89-
public ConcurrentDictionary<string, Target> GetAvailableTargets() => _attachedTargetsByTargetId;
91+
public AsyncDictionaryHelper<string, Target> GetAvailableTargets() => _attachedTargetsByTargetId;
9092

9193
public async Task InitializeAsync()
9294
{
@@ -112,11 +114,7 @@ public void AddTargetInterceptor(CDPSession session, TargetInterceptor intercept
112114
public void RemoveTargetInterceptor(CDPSession session, TargetInterceptor interceptor)
113115
{
114116
_targetInterceptors.TryGetValue(session, out var interceptors);
115-
116-
if (interceptors != null)
117-
{
118-
interceptors.Remove(interceptor);
119-
}
117+
interceptors?.Remove(interceptor);
120118
}
121119

122120
private void StoreExistingTargetsForInit()
@@ -190,13 +188,13 @@ private void OnTargetCreated(TargetCreatedResponse e)
190188

191189
if (e.TargetInfo.Type == TargetType.Browser && e.TargetInfo.Attached)
192190
{
193-
if (_attachedTargetsByTargetId.ContainsKey(e.TargetInfo.TargetId))
191+
if (_availableTargetsByTargetIdDictionary.ContainsKey(e.TargetInfo.TargetId))
194192
{
195193
return;
196194
}
197195

198196
var target = _targetFactoryFunc(e.TargetInfo, null);
199-
_attachedTargetsByTargetId[e.TargetInfo.TargetId] = target;
197+
_attachedTargetsByTargetId.AddItem(e.TargetInfo.TargetId, target);
200198
}
201199
}
202200

@@ -206,7 +204,7 @@ private async void OnTargetDestroyed(TargetDestroyedResponse e)
206204
await EnsureTargetsIdsForInit().ConfigureAwait(false);
207205
FinishInitializationIfReady(e.TargetId);
208206

209-
if (targetInfo?.Type == TargetType.ServiceWorker && _attachedTargetsByTargetId.TryRemove(e.TargetId, out var target))
207+
if (targetInfo?.Type == TargetType.ServiceWorker && _availableTargetsByTargetIdDictionary.TryRemove(e.TargetId, out var target))
210208
{
211209
TargetGone?.Invoke(this, new TargetChangedArgs { Target = target, TargetInfo = targetInfo });
212210
}
@@ -217,7 +215,7 @@ private void OnTargetInfoChanged(TargetCreatedResponse e)
217215
_discoveredTargetsByTargetId[e.TargetInfo.TargetId] = e.TargetInfo;
218216

219217
if (_ignoredTargets.Contains(e.TargetInfo.TargetId) ||
220-
!_attachedTargetsByTargetId.TryGetValue(e.TargetInfo.TargetId, out var target) ||
218+
!_availableTargetsByTargetIdDictionary.TryGetValue(e.TargetInfo.TargetId, out var target) ||
221219
!e.TargetInfo.Attached)
222220
{
223221
return;
@@ -229,16 +227,10 @@ private void OnTargetInfoChanged(TargetCreatedResponse e)
229227
private async Task OnAttachedToTarget(object sender, TargetAttachedToTargetResponse e)
230228
{
231229
var parent = sender as ICDPConnection;
232-
var parentSession = parent as CDPSession;
233230
var targetInfo = e.TargetInfo;
234-
var session = _connection.GetSession(e.SessionId);
231+
var session = _connection.GetSession(e.SessionId) ?? throw new PuppeteerException($"Session {e.SessionId} was not created.");
235232

236-
if (session == null)
237-
{
238-
throw new PuppeteerException($"Session {e.SessionId} was not created.");
239-
}
240-
241-
Func<Task> silentDetach = async () =>
233+
async Task SilentDetach()
242234
{
243235
try
244236
{
@@ -254,7 +246,7 @@ await parent.SendAsync(
254246
{
255247
_logger.LogError(ex, "silentDetach failed.");
256248
}
257-
};
249+
}
258250

259251
if (!_connection.IsAutoAttached(targetInfo.TargetId))
260252
{
@@ -266,14 +258,14 @@ await parent.SendAsync(
266258
{
267259
await EnsureTargetsIdsForInit().ConfigureAwait(false);
268260
FinishInitializationIfReady(targetInfo.TargetId);
269-
await silentDetach().ConfigureAwait(false);
270-
if (_attachedTargetsByTargetId.ContainsKey(targetInfo.TargetId))
261+
await SilentDetach().ConfigureAwait(false);
262+
if (_availableTargetsByTargetIdDictionary.ContainsKey(targetInfo.TargetId))
271263
{
272264
return;
273265
}
274266

275267
var workerTarget = _targetFactoryFunc(targetInfo, null);
276-
_attachedTargetsByTargetId.TryAdd(targetInfo.TargetId, workerTarget);
268+
_attachedTargetsByTargetId.AddItem(targetInfo.TargetId, workerTarget);
277269
TargetAvailable?.Invoke(this, new TargetChangedArgs { Target = workerTarget });
278270
return;
279271
}
@@ -283,11 +275,11 @@ await parent.SendAsync(
283275
_ignoredTargets.Add(targetInfo.TargetId);
284276
await EnsureTargetsIdsForInit().ConfigureAwait(false);
285277
FinishInitializationIfReady(targetInfo.TargetId);
286-
await silentDetach().ConfigureAwait(false);
278+
await SilentDetach().ConfigureAwait(false);
287279
return;
288280
}
289281

290-
var existingTarget = _attachedTargetsByTargetId.TryGetValue(targetInfo.TargetId, out var target);
282+
var existingTarget = _availableTargetsByTargetIdDictionary.TryGetValue(targetInfo.TargetId, out var target);
291283
if (!existingTarget)
292284
{
293285
target = _targetFactoryFunc(targetInfo, session);
@@ -301,7 +293,7 @@ await parent.SendAsync(
301293
}
302294
else
303295
{
304-
_attachedTargetsByTargetId.TryAdd(targetInfo.TargetId, target);
296+
_attachedTargetsByTargetId.AddItem(targetInfo.TargetId, target);
305297
_attachedTargetsBySessionId.TryAdd(session.Id, target);
306298
}
307299

@@ -310,7 +302,7 @@ await parent.SendAsync(
310302
foreach (var interceptor in interceptors)
311303
{
312304
Target parentTarget = null;
313-
if (parentSession != null && !_attachedTargetsBySessionId.TryGetValue(parentSession.Id, out parentTarget))
305+
if (parent is CDPSession parentSession && !_attachedTargetsBySessionId.TryGetValue(parentSession.Id, out parentTarget))
314306
{
315307
throw new PuppeteerException("Parent session not found in attached targets");
316308
}
@@ -385,7 +377,7 @@ private void OnDetachedFromTarget(object sender, TargetDetachedFromTargetRespons
385377
return;
386378
}
387379

388-
_attachedTargetsByTargetId.TryRemove(target.TargetId, out _);
380+
_availableTargetsByTargetIdDictionary.TryRemove(target.TargetId, out _);
389381
TargetGone?.Invoke(this, new TargetChangedArgs { Target = target });
390382
}
391383
}

lib/PuppeteerSharp/FirefoxTargetManager.cs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System.Collections.Generic;
55
using System.Threading.Tasks;
66
using Microsoft.Extensions.Logging;
7+
using PuppeteerSharp.Helpers;
78
using PuppeteerSharp.Helpers.Json;
89
using PuppeteerSharp.Messaging;
910

@@ -16,7 +17,9 @@ internal class FirefoxTargetManager : ITargetManager
1617
private readonly Func<TargetInfo, bool> _targetFilterFunc;
1718
private readonly ILogger<FirefoxTargetManager> _logger;
1819
private readonly ConcurrentDictionary<ICDPConnection, List<TargetInterceptor>> _targetInterceptors = new();
19-
private readonly ConcurrentDictionary<string, Target> _availableTargetsByTargetId = new();
20+
21+
private readonly ConcurrentDictionary<string, Target> _availableTargetsByTargetIdDictionary = new();
22+
private readonly AsyncDictionaryHelper<string, Target> _availableTargetsByTargetId;
2023
private readonly ConcurrentDictionary<string, Target> _availableTargetsBySessionId = new();
2124
private readonly ConcurrentDictionary<string, TargetInfo> _discoveredTargetsByTargetId = new();
2225
private readonly TaskCompletionSource<bool> _initializeCompletionSource = new();
@@ -28,6 +31,7 @@ public FirefoxTargetManager(
2831
Func<TargetInfo, CDPSession, Target> targetFactoryFunc,
2932
Func<TargetInfo, bool> targetFilterFunc)
3033
{
34+
_availableTargetsByTargetId = new AsyncDictionaryHelper<string, Target>(_availableTargetsByTargetIdDictionary, "Target {0} not found");
3135
_connection = connection;
3236
_targetFilterFunc = targetFilterFunc;
3337
_targetFactoryFunc = targetFactoryFunc;
@@ -72,7 +76,7 @@ public async Task InitializeAsync()
7276
await _initializeCompletionSource.Task.ConfigureAwait(false);
7377
}
7478

75-
public ConcurrentDictionary<string, Target> GetAvailableTargets() => _availableTargetsByTargetId;
79+
public AsyncDictionaryHelper<string, Target> GetAvailableTargets() => _availableTargetsByTargetId;
7680

7781
private void OnMessageReceived(object sender, MessageEventArgs e)
7882
{
@@ -116,7 +120,7 @@ private void OnTargetCreated(TargetCreatedResponse e)
116120
if (e.TargetInfo.Type == TargetType.Browser && e.TargetInfo.Attached)
117121
{
118122
var browserTarget = _targetFactoryFunc(e.TargetInfo, null);
119-
_availableTargetsByTargetId[e.TargetInfo.TargetId] = browserTarget;
123+
_availableTargetsByTargetId.AddItem(e.TargetInfo.TargetId, browserTarget);
120124
FinishInitializationIfReady(e.TargetInfo.TargetId);
121125
}
122126

@@ -128,7 +132,7 @@ private void OnTargetCreated(TargetCreatedResponse e)
128132
}
129133

130134
var target = _targetFactoryFunc(e.TargetInfo, null);
131-
_availableTargetsByTargetId[e.TargetInfo.TargetId] = target;
135+
_availableTargetsByTargetId.AddItem(e.TargetInfo.TargetId, target);
132136
TargetAvailable?.Invoke(
133137
this,
134138
new TargetChangedArgs
@@ -144,7 +148,7 @@ private void OnTargetDestroyed(TargetDestroyedResponse e)
144148
_discoveredTargetsByTargetId.TryRemove(e.TargetId, out var targetInfo);
145149
FinishInitializationIfReady(e.TargetId);
146150

147-
if (_availableTargetsByTargetId.TryRemove(e.TargetId, out var target))
151+
if (_availableTargetsByTargetIdDictionary.TryGetValue(e.TargetId, out var target))
148152
{
149153
TargetGone?.Invoke(this, new TargetChangedArgs { Target = target, TargetInfo = targetInfo });
150154
}
@@ -155,7 +159,7 @@ private void OnAttachedToTarget(object sender, TargetAttachedToTargetResponse e)
155159
var parent = sender as ICDPConnection;
156160
var targetInfo = e.TargetInfo;
157161
var session = _connection.GetSession(e.SessionId) ?? throw new PuppeteerException($"Session {e.SessionId} was not created.");
158-
var existingTarget = _availableTargetsByTargetId.TryGetValue(targetInfo.TargetId, out var target);
162+
var existingTarget = _availableTargetsByTargetIdDictionary.TryGetValue(targetInfo.TargetId, out var target);
159163
session.MessageReceived += OnMessageReceived;
160164

161165
_availableTargetsBySessionId.TryAdd(session.Id, target);

lib/PuppeteerSharp/Helpers/AsyncDictionaryHelper.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ public AsyncDictionaryHelper(ConcurrentDictionary<TKey, TValue> dictionary, stri
1717
_timeoutMessage = timeoutMessage;
1818
}
1919

20+
internal ConcurrentDictionary<TKey, TValue> InnerDictionary => _dictionary;
21+
2022
internal async Task<TValue> GetItemAsync(TKey key)
2123
{
2224
var tcs = new TaskCompletionSource<TValue>(TaskCreationOptions.RunContinuationsAsynchronously);

lib/PuppeteerSharp/ITargetManager.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System.Collections.Generic;
44
using System.Threading;
55
using System.Threading.Tasks;
6+
using PuppeteerSharp.Helpers;
67
using PuppeteerSharp.Messaging;
78
using PuppeteerSharp.Transport;
89

@@ -39,7 +40,7 @@ internal interface ITargetManager
3940
/// All the available targets.
4041
/// </summary>
4142
/// <returns>A dictionary with the available targets.</returns>
42-
ConcurrentDictionary<string, Target> GetAvailableTargets();
43+
AsyncDictionaryHelper<string, Target> GetAvailableTargets();
4344

4445
/// <summary>
4546
/// Async tasks to be performed after calling the target manager constructor.

lib/PuppeteerSharp/PuppeteerSharp.csproj

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@
1212
<Description>Headless Browser .NET API</Description>
1313
<PackageId>PuppeteerSharp</PackageId>
1414
<PackageReleaseNotes></PackageReleaseNotes>
15-
<PackageVersion>10.1.3</PackageVersion>
16-
<ReleaseVersion>10.1.3</ReleaseVersion>
17-
<AssemblyVersion>10.1.3.0</AssemblyVersion>
18-
<FileVersion>10.1.3.0</FileVersion>
15+
<PackageVersion>10.1.4</PackageVersion>
16+
<ReleaseVersion>10.1.4</ReleaseVersion>
17+
<AssemblyVersion>10.1.4.0</AssemblyVersion>
18+
<FileVersion>10.1.4.0</FileVersion>
1919
<SynchReleaseVersion>false</SynchReleaseVersion>
2020
<StyleCopTreatErrorsAsWarnings>false</StyleCopTreatErrorsAsWarnings>
2121
<DebugType>embedded</DebugType>

lib/PuppeteerSharp/Target.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ internal Target(
8888

8989
/// <inheritdoc/>
9090
public ITarget Opener => TargetInfo.OpenerId != null ?
91-
((Browser)Browser).TargetManager.GetAvailableTargets().GetValueOrDefault(TargetInfo.OpenerId) : null;
91+
((Browser)Browser).TargetManager.GetAvailableTargets().InnerDictionary.GetValueOrDefault(TargetInfo.OpenerId) : null;
9292

9393
/// <inheritdoc/>
9494
public IBrowser Browser => BrowserContext.Browser;

0 commit comments

Comments
 (0)