Skip to content

Commit c51fab4

Browse files
kblokMeir017
authored andcommitted
Don't wait for Runtime.Evaluate (#690)
* Don't wait for Runtime.Evaluate * Configure await * Ops * codefactor * Default true on interface
1 parent 1219913 commit c51fab4

File tree

5 files changed

+59
-26
lines changed

5 files changed

+59
-26
lines changed

lib/PuppeteerSharp.Tests/PageTests/ExposeFunctionTests.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,5 +81,13 @@ await Page.ExposeFunctionAsync("changeFlag", () =>
8181
await Page.EvaluateExpressionAsync("changeFlag()");
8282
Assert.True(called);
8383
}
84+
85+
[Fact]
86+
public async Task ShouldKeepTheCallbackClean()
87+
{
88+
await Page.ExposeFunctionAsync("compute", (int a, int b) => a * b);
89+
var result = await Page.EvaluateExpressionAsync<int>("compute(9, 4)");
90+
Assert.False(Page.Client.HasPendingCallbacks());
91+
}
8492
}
8593
}

lib/PuppeteerSharp/CDPSession.cs

Lines changed: 31 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ namespace PuppeteerSharp
1212
{
1313
/// <summary>
1414
/// The CDPSession instances are used to talk raw Chrome Devtools Protocol:
15-
/// * Protocol methods can be called with <see cref="CDPSession.SendAsync(string, dynamic)"/> method.
15+
/// * Protocol methods can be called with <see cref="CDPSession.SendAsync(string, dynamic, bool)"/> method.
1616
/// * Protocol events, using the <see cref="CDPSession.MessageReceived"/> event.
1717
///
1818
/// Documentation on DevTools Protocol can be found here: <see href="https://chromedevtools.github.io/devtools-protocol/"/>.
@@ -95,6 +95,10 @@ internal CDPSession(IConnection connection, TargetType targetType, string sessio
9595
#endregion
9696

9797
#region Public Methods
98+
99+
internal void Send(string method, dynamic args = null)
100+
=> _ = SendAsync(method, args, false);
101+
98102
/// <summary>
99103
/// Protocol methods can be called with this method.
100104
/// </summary>
@@ -113,9 +117,13 @@ public async Task<T> SendAsync<T>(string method, dynamic args = null)
113117
/// </summary>
114118
/// <param name="method">The method name</param>
115119
/// <param name="args">The method args</param>
120+
/// <param name="waitForCallback">
121+
/// If <c>true</c> the method will return a task to be completed when the message is confirmed by Chromium.
122+
/// If <c>false</c> the task will be considered complete after sending the message to Chromium.
123+
/// </param>
116124
/// <returns>The task.</returns>
117-
/// <exception cref="T:PuppeteerSharp.PuppeteerException"></exception>
118-
public async Task<JObject> SendAsync(string method, dynamic args = null)
125+
/// <exception cref="PuppeteerSharp.PuppeteerException"></exception>
126+
public async Task<JObject> SendAsync(string method, dynamic args = null, bool waitForCallback = true)
119127
{
120128
if (Connection == null)
121129
{
@@ -130,31 +138,37 @@ public async Task<JObject> SendAsync(string method, dynamic args = null)
130138
});
131139
_logger.LogTrace("Send ► {Id} Method {Method} Params {@Params}", id, method, (object)args);
132140

133-
var callback = new MessageTask
141+
MessageTask callback = null;
142+
if (waitForCallback)
134143
{
135-
TaskWrapper = new TaskCompletionSource<JObject>(),
136-
Method = method
137-
};
138-
_callbacks[id] = callback;
144+
callback = new MessageTask
145+
{
146+
TaskWrapper = new TaskCompletionSource<JObject>(),
147+
Method = method
148+
};
149+
_callbacks[id] = callback;
150+
}
139151

140152
try
141153
{
142-
await Connection.SendAsync("Target.sendMessageToTarget", new Dictionary<string, object>
143-
{
144-
{ MessageKeys.SessionId, SessionId },
145-
{ MessageKeys.Message, message }
146-
}).ConfigureAwait(false);
154+
await Connection.SendAsync(
155+
"Target.sendMessageToTarget", new Dictionary<string, object>
156+
{
157+
{"sessionId", SessionId},
158+
{"message", message}
159+
},
160+
waitForCallback).ConfigureAwait(false);
147161
}
148162
catch (Exception ex)
149163
{
150-
if (_callbacks.ContainsKey(id))
164+
if (waitForCallback && _callbacks.ContainsKey(id))
151165
{
152166
_callbacks.Remove(id);
153167
callback.TaskWrapper.SetException(new MessageException(ex.Message, ex));
154168
}
155169
}
156170

157-
return await callback.TaskWrapper.Task.ConfigureAwait(false);
171+
return waitForCallback ? await callback.TaskWrapper.Task.ConfigureAwait(false) : null;
158172
}
159173

160174
/// <summary>
@@ -281,7 +295,8 @@ internal CDPSession CreateSession(TargetType targetType, string sessionId)
281295
#region IConnection
282296
ILoggerFactory IConnection.LoggerFactory => LoggerFactory;
283297
bool IConnection.IsClosed => IsClosed;
284-
Task<JObject> IConnection.SendAsync(string method, dynamic args) => SendAsync(method, args);
298+
Task<JObject> IConnection.SendAsync(string method, dynamic args, bool waitForCallback)
299+
=> SendAsync(method, args, waitForCallback);
285300
#endregion
286301
}
287302
}

lib/PuppeteerSharp/Connection.cs

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ internal Connection(string url, int delay, WebSocket ws, ILoggerFactory loggerFa
8484

8585
#region Public Methods
8686

87-
internal async Task<JObject> SendAsync(string method, dynamic args = null)
87+
internal async Task<JObject> SendAsync(string method, dynamic args = null, bool waitForCallback = true)
8888
{
8989
if (IsClosed)
9090
{
@@ -101,18 +101,23 @@ internal async Task<JObject> SendAsync(string method, dynamic args = null)
101101

102102
_logger.LogTrace("Send ► {Id} Method {Method} Params {@Params}", id, method, (object)args);
103103

104-
var callback = new MessageTask
104+
MessageTask callback = null;
105+
if (waitForCallback)
105106
{
106-
TaskWrapper = new TaskCompletionSource<JObject>(),
107-
Method = method
108-
};
109-
_callbacks[id] = callback;
107+
108+
callback = new MessageTask
109+
{
110+
TaskWrapper = new TaskCompletionSource<JObject>(),
111+
Method = method
112+
};
113+
_callbacks[id] = callback;
114+
}
110115

111116
var encoded = Encoding.UTF8.GetBytes(message);
112117
var buffer = new ArraySegment<byte>(encoded, 0, encoded.Length);
113118
await _socketQueue.Enqueue(() => WebSocket.SendAsync(buffer, WebSocketMessageType.Text, true, default)).ConfigureAwait(false);
114119

115-
return await callback.TaskWrapper.Task.ConfigureAwait(false);
120+
return waitForCallback ? await callback.TaskWrapper.Task.ConfigureAwait(false) : null;
116121
}
117122

118123
internal async Task<T> SendAsync<T>(string method, dynamic args = null)
@@ -335,7 +340,8 @@ public void Dispose()
335340
#region IConnection
336341
ILoggerFactory IConnection.LoggerFactory => LoggerFactory;
337342
bool IConnection.IsClosed => IsClosed;
338-
Task<JObject> IConnection.SendAsync(string method, dynamic args) => SendAsync(method, args);
343+
Task<JObject> IConnection.SendAsync(string method, dynamic args, bool waitForCallback)
344+
=> SendAsync(method, args, waitForCallback);
339345
#endregion
340346
}
341347
}

lib/PuppeteerSharp/IConnection.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ internal interface IConnection
2525
/// <returns>The async.</returns>
2626
/// <param name="method">Method to call.</param>
2727
/// <param name="args">Method arguments.</param>
28-
Task<JObject> SendAsync(string method, dynamic args = null);
28+
/// <param name="waitForCallback">
29+
/// If <c>true</c> the method will return a task to be completed when the message is confirmed by Chromium.
30+
/// If <c>false</c> the task will be considered complete after sending the message to Chromium.
31+
/// </param>
32+
Task<JObject> SendAsync(string method, dynamic args = null, bool waitForCallback = true);
2933
}
3034
}

lib/PuppeteerSharp/Page.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1833,7 +1833,7 @@ private async Task OnBindingCalled(BindingCalledResponse e)
18331833
window[name]['callbacks'].delete(seq);
18341834
}", e.Payload.Name, e.Payload.Seq, result);
18351835

1836-
await Client.SendAsync("Runtime.evaluate", new
1836+
Client.Send("Runtime.evaluate", new
18371837
{
18381838
expression,
18391839
contextId = e.ExecutionContextId

0 commit comments

Comments
 (0)