Skip to content

Commit 9cff529

Browse files
authored
Move to flatten protocol (#920)
* Move to flatten protocol * Some progress * cr * Let's get this green
1 parent 9b1a597 commit 9cff529

15 files changed

+137
-259
lines changed

lib/PuppeteerSharp/BrowserContext.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@ namespace PuppeteerSharp
1212
/// </summary>
1313
public class BrowserContext
1414
{
15-
private readonly IConnection _connection;
15+
private readonly Connection _connection;
1616
private readonly string _id;
1717

18-
internal BrowserContext(IConnection connection, Browser browser, string contextId)
18+
internal BrowserContext(Connection connection, Browser browser, string contextId)
1919
{
2020
_connection = connection;
2121
Browser = browser;

lib/PuppeteerSharp/CDPSession.cs

Lines changed: 6 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,9 @@ namespace PuppeteerSharp
3737
/// });
3838
/// ]]></code>
3939
/// </summary>
40-
public class CDPSession : IConnection
40+
public class CDPSession
4141
{
42-
internal CDPSession(IConnection connection, TargetType targetType, string sessionId, ILoggerFactory loggerFactory = null)
42+
internal CDPSession(Connection connection, TargetType targetType, string sessionId, ILoggerFactory loggerFactory = null)
4343
{
4444
LoggerFactory = loggerFactory ?? new LoggerFactory();
4545
Connection = connection;
@@ -48,14 +48,11 @@ internal CDPSession(IConnection connection, TargetType targetType, string sessio
4848

4949
_callbacks = new ConcurrentDictionary<int, MessageTask>();
5050
_logger = Connection.LoggerFactory.CreateLogger<CDPSession>();
51-
_sessions = new ConcurrentDictionary<string, CDPSession>();
5251
}
5352

5453
#region Private Members
55-
private int _lastId;
5654
private readonly ConcurrentDictionary<int, MessageTask> _callbacks;
5755
private readonly ILogger _logger;
58-
private readonly ConcurrentDictionary<string, CDPSession> _sessions;
5956
#endregion
6057

6158
#region Properties
@@ -73,16 +70,12 @@ internal CDPSession(IConnection connection, TargetType targetType, string sessio
7370
/// Gets the connection.
7471
/// </summary>
7572
/// <value>The connection.</value>
76-
internal IConnection Connection { get; private set; }
73+
internal Connection Connection { get; private set; }
7774
/// <summary>
7875
/// Occurs when message received from Chromium.
7976
/// </summary>
8077
public event EventHandler<MessageEventArgs> MessageReceived;
8178
/// <summary>
82-
/// Occurs when tracing is completed.
83-
/// </summary>
84-
public event EventHandler<TracingCompleteEventArgs> TracingComplete;
85-
/// <summary>
8679
/// Occurs when the connection is closed.
8780
/// </summary>
8881
public event EventHandler Disconnected;
@@ -116,7 +109,6 @@ internal void Send(string method, object args = null)
116109
public async Task<T> SendAsync<T>(string method, object args = null)
117110
{
118111
var content = await SendAsync(method, args).ConfigureAwait(false);
119-
120112
return content.ToObject<T>(true);
121113
}
122114

@@ -140,16 +132,7 @@ public async Task<JObject> SendAsync(string method, object args = null, bool wai
140132
$"Most likely the {TargetType} has been closed." +
141133
$"Close reason: {CloseReason}");
142134
}
143-
var id = Interlocked.Increment(ref _lastId);
144-
var message = JsonConvert.SerializeObject(new ConnectionRequest
145-
{
146-
Id = id,
147-
Method = method,
148-
Params = args
149-
}, JsonHelper.DefaultJsonSerializerSettings);
150-
151-
_logger.LogTrace("Send ► {Id} Method {Method} Params {@Params}", id, method, args);
152-
135+
var id = Connection.GetMessageID();
153136
MessageTask callback = null;
154137
if (waitForCallback)
155138
{
@@ -163,14 +146,7 @@ public async Task<JObject> SendAsync(string method, object args = null, bool wai
163146

164147
try
165148
{
166-
await Connection.SendAsync(
167-
"Target.sendMessageToTarget",
168-
new TargetSendMessageToTargetRequest
169-
{
170-
SessionId = SessionId,
171-
Message = message
172-
},
173-
waitForCallback).ConfigureAwait(false);
149+
await Connection.RawSendASync(id, method, args, SessionId).ConfigureAwait(false);
174150
}
175151
catch (Exception ex)
176152
{
@@ -206,22 +182,8 @@ public Task DetachAsync()
206182

207183
#region Private Methods
208184

209-
internal void OnMessage(string message)
185+
internal void OnMessage(ConnectionResponse obj)
210186
{
211-
_logger.LogTrace("◀ Receive {Message}", message);
212-
213-
ConnectionResponse obj = null;
214-
215-
try
216-
{
217-
obj = JsonConvert.DeserializeObject<ConnectionResponse>(message, JsonHelper.DefaultJsonSerializerSettings);
218-
}
219-
catch (JsonException exc)
220-
{
221-
_logger.LogError(exc, "Failed to deserialize message", message);
222-
return;
223-
}
224-
225187
var id = obj.Id;
226188

227189
if (id.HasValue && _callbacks.TryRemove(id.Value, out var callback))
@@ -240,32 +202,6 @@ internal void OnMessage(string message)
240202
var method = obj.Method;
241203
var param = obj.Params?.ToObject<ConnectionResponseParams>();
242204

243-
if (method == "Tracing.tracingComplete")
244-
{
245-
TracingComplete?.Invoke(this, new TracingCompleteEventArgs
246-
{
247-
Stream = param.Stream
248-
});
249-
}
250-
else if (method == "Target.receivedMessageFromTarget")
251-
{
252-
var sessionId = param.SessionId;
253-
254-
if (_sessions.TryGetValue(sessionId, out var session))
255-
{
256-
session.OnMessage(param.Message);
257-
}
258-
}
259-
else if (method == "Target.detachedFromTarget")
260-
{
261-
var sessionId = param.SessionId;
262-
263-
if (_sessions.TryRemove(sessionId, out var session))
264-
{
265-
session.Close("Target.detachedFromTarget");
266-
}
267-
}
268-
269205
MessageReceived?.Invoke(this, new MessageEventArgs
270206
{
271207
MessageID = method,
@@ -283,12 +219,6 @@ internal void Close(string closeReason)
283219
CloseReason = closeReason;
284220
IsClosed = true;
285221

286-
foreach (var session in _sessions.Values.ToArray())
287-
{
288-
session.Close(closeReason);
289-
}
290-
_sessions.Clear();
291-
292222
foreach (var callback in _callbacks.Values.ToArray())
293223
{
294224
callback.TaskWrapper.TrySetException(new TargetClosedException(
@@ -301,21 +231,6 @@ internal void Close(string closeReason)
301231
Connection = null;
302232
}
303233

304-
internal CDPSession CreateSession(TargetType targetType, string sessionId)
305-
{
306-
var session = new CDPSession(this, targetType, sessionId);
307-
_sessions[sessionId] = session;
308-
return session;
309-
}
310-
#endregion
311-
312-
#region IConnection
313-
ILoggerFactory IConnection.LoggerFactory => LoggerFactory;
314-
bool IConnection.IsClosed => IsClosed;
315-
Task<JObject> IConnection.SendAsync(string method, object args, bool waitForCallback)
316-
=> SendAsync(method, args, waitForCallback);
317-
IConnection IConnection.Connection => Connection;
318-
void IConnection.Close(string closeReason) => Close(closeReason);
319234
#endregion
320235
}
321236
}

lib/PuppeteerSharp/Connection.cs

Lines changed: 50 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using Microsoft.Extensions.Logging;
88
using Newtonsoft.Json;
99
using Newtonsoft.Json.Linq;
10+
using PuppeteerSharp.Helpers;
1011
using PuppeteerSharp.Helpers.Json;
1112
using PuppeteerSharp.Messaging;
1213
using PuppeteerSharp.Transport;
@@ -16,7 +17,7 @@ namespace PuppeteerSharp
1617
/// <summary>
1718
/// A connection handles the communication with a Chromium browser
1819
/// </summary>
19-
public class Connection : IDisposable, IConnection
20+
public class Connection : IDisposable
2021
{
2122
private readonly ILogger _logger;
2223

@@ -33,12 +34,14 @@ internal Connection(string url, int delay, IConnectionTransport transport, ILogg
3334
Transport.Closed += Transport_Closed;
3435
_callbacks = new ConcurrentDictionary<int, MessageTask>();
3536
_sessions = new ConcurrentDictionary<string, CDPSession>();
37+
_asyncSessions = new AsyncDictionaryHelper<string, CDPSession>(_sessions, "Session {0} not found");
3638
}
3739

3840
#region Private Members
3941
private int _lastId;
4042
private readonly ConcurrentDictionary<int, MessageTask> _callbacks;
4143
private readonly ConcurrentDictionary<string, CDPSession> _sessions;
44+
private readonly AsyncDictionaryHelper<string, CDPSession> _asyncSessions;
4245
#endregion
4346

4447
#region Properties
@@ -86,21 +89,24 @@ internal Connection(string url, int delay, IConnectionTransport transport, ILogg
8689

8790
#region Public Methods
8891

92+
internal int GetMessageID() => Interlocked.Increment(ref _lastId);
93+
internal Task RawSendASync(int id, string method, object args, string sessionId = null)
94+
=> Transport.SendAsync(JsonConvert.SerializeObject(new ConnectionRequest
95+
{
96+
Id = id,
97+
Method = method,
98+
Params = args,
99+
SessionId = sessionId
100+
}, JsonHelper.DefaultJsonSerializerSettings));
101+
89102
internal async Task<JObject> SendAsync(string method, object args = null, bool waitForCallback = true)
90103
{
91104
if (IsClosed)
92105
{
93106
throw new TargetClosedException($"Protocol error({method}): Target closed.", CloseReason);
94107
}
95108

96-
var id = Interlocked.Increment(ref _lastId);
97-
var message = JsonConvert.SerializeObject(new ConnectionRequest
98-
{
99-
Id = id,
100-
Method = method,
101-
Params = args
102-
}, JsonHelper.DefaultJsonSerializerSettings);
103-
109+
var id = GetMessageID();
104110
_logger.LogTrace("Send ► {Id} Method {Method} Params {@Params}", id, method, (object)args);
105111

106112
MessageTask callback = null;
@@ -114,7 +120,7 @@ internal async Task<JObject> SendAsync(string method, object args = null, bool w
114120
_callbacks[id] = callback;
115121
}
116122

117-
await Transport.SendAsync(message).ConfigureAwait(false);
123+
await RawSendASync(id, method, args).ConfigureAwait(false);
118124
return waitForCallback ? await callback.TaskWrapper.Task.ConfigureAwait(false) : null;
119125
}
120126

@@ -128,11 +134,10 @@ internal async Task<CDPSession> CreateSessionAsync(TargetInfo targetInfo)
128134
{
129135
var sessionId = (await SendAsync<TargetAttachToTargetResponse>("Target.attachToTarget", new TargetAttachToTargetRequest
130136
{
131-
TargetId = targetInfo.TargetId
137+
TargetId = targetInfo.TargetId,
138+
Flatten = true
132139
}).ConfigureAwait(false)).SessionId;
133-
var session = new CDPSession(this, targetInfo.Type, sessionId);
134-
_sessions.TryAdd(sessionId, session);
135-
return session;
140+
return await GetSessionAsync(sessionId).ConfigureAwait(false);
136141
}
137142

138143
internal bool HasPendingCallbacks() => _callbacks.Count != 0;
@@ -166,15 +171,10 @@ internal void Close(string closeReason)
166171
_callbacks.Clear();
167172
}
168173

169-
internal static IConnection FromSession(CDPSession session)
170-
{
171-
var connection = session.Connection;
172-
while (connection is CDPSession)
173-
{
174-
connection = connection.Connection;
175-
}
176-
return connection;
177-
}
174+
internal static Connection FromSession(CDPSession session) => session.Connection;
175+
internal CDPSession GetSession(string sessionId) => _sessions.GetValueOrDefault(sessionId);
176+
internal Task<CDPSession> GetSessionAsync(string sessionId) => _asyncSessions.GetItemAsync(sessionId);
177+
178178
#region Private Methods
179179

180180
private async void Transport_MessageReceived(object sender, MessageReceivedEventArgs e)
@@ -200,29 +200,7 @@ private async void Transport_MessageReceived(object sender, MessageReceivedEvent
200200
}
201201

202202
_logger.LogTrace("◀ Receive {Message}", response);
203-
204-
var id = obj.Id;
205-
206-
if (id.HasValue)
207-
{
208-
//If we get the object we are waiting for we return if
209-
//if not we add this to the list, sooner or later some one will come for it
210-
if (_callbacks.TryRemove(id.Value, out var callback))
211-
{
212-
if (obj.Error != null)
213-
{
214-
callback.TaskWrapper.TrySetException(new MessageException(callback, obj.Error));
215-
}
216-
else
217-
{
218-
callback.TaskWrapper.TrySetResult(obj.Result);
219-
}
220-
}
221-
}
222-
else
223-
{
224-
ProcessIncomingMessage(obj);
225-
}
203+
ProcessIncomingMessage(obj);
226204
}
227205
catch (Exception ex)
228206
{
@@ -235,15 +213,13 @@ private async void Transport_MessageReceived(object sender, MessageReceivedEvent
235213
private void ProcessIncomingMessage(ConnectionResponse obj)
236214
{
237215
var method = obj.Method;
238-
var param = obj.Params.ToObject<ConnectionResponseParams>();
216+
var param = obj.Params?.ToObject<ConnectionResponseParams>();
239217

240-
if (method == "Target.receivedMessageFromTarget")
218+
if (method == "Target.attachedToTarget")
241219
{
242220
var sessionId = param.SessionId;
243-
if (_sessions.TryGetValue(sessionId, out var session))
244-
{
245-
session.OnMessage(param.Message);
246-
}
221+
var session = new CDPSession(this, param.TargetInfo.Type, sessionId);
222+
_asyncSessions.AddItem(sessionId, session);
247223
}
248224
else if (method == "Target.detachedFromTarget")
249225
{
@@ -253,6 +229,28 @@ private void ProcessIncomingMessage(ConnectionResponse obj)
253229
session.Close("Target.detachedFromTarget");
254230
}
255231
}
232+
233+
if (!string.IsNullOrEmpty(obj.SessionId))
234+
{
235+
var session = GetSession(obj.SessionId);
236+
session.OnMessage(obj);
237+
}
238+
else if (obj.Id.HasValue)
239+
{
240+
//If we get the object we are waiting for we return if
241+
//if not we add this to the list, sooner or later some one will come for it
242+
if (_callbacks.TryRemove(obj.Id.Value, out var callback))
243+
{
244+
if (obj.Error != null)
245+
{
246+
callback.TaskWrapper.TrySetException(new MessageException(callback, obj.Error));
247+
}
248+
else
249+
{
250+
callback.TaskWrapper.TrySetResult(obj.Result);
251+
}
252+
}
253+
}
256254
else
257255
{
258256
MessageReceived?.Invoke(this, new MessageEventArgs
@@ -305,14 +303,5 @@ public void Dispose()
305303
Transport.Dispose();
306304
}
307305
#endregion
308-
309-
#region IConnection
310-
ILoggerFactory IConnection.LoggerFactory => LoggerFactory;
311-
bool IConnection.IsClosed => IsClosed;
312-
Task<JObject> IConnection.SendAsync(string method, object args, bool waitForCallback)
313-
=> SendAsync(method, args, waitForCallback);
314-
IConnection IConnection.Connection => null;
315-
void IConnection.Close(string closeReason) => Close(closeReason);
316-
#endregion
317306
}
318307
}

0 commit comments

Comments
 (0)