77using Microsoft . Extensions . Logging ;
88using Newtonsoft . Json ;
99using Newtonsoft . Json . Linq ;
10+ using PuppeteerSharp . Helpers ;
1011using PuppeteerSharp . Helpers . Json ;
1112using PuppeteerSharp . Messaging ;
1213using 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