From f07f043dcba87b71c22a4dd8b2f5278d9948c89a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dar=C3=ADo=20Kondratiuk?= Date: Tue, 3 Dec 2024 10:50:56 -0300 Subject: [PATCH] First bidi function evaluation implementation (#2831) * Some progress * First passing tests * MVP * undo temp code * Ignore more tests * ignore another test --- .../TestExpectations.local.json | 197 +++++++++++- .../EvaluationTests/PageEvaluateTests.cs | 7 +- .../PageWaitForNavigationTests.cs | 11 +- lib/PuppeteerSharp/Bidi/BidiFrame.cs | 18 ++ lib/PuppeteerSharp/Bidi/BidiFrameRealm.cs | 64 ++++ lib/PuppeteerSharp/Bidi/BidiJSHandle.cs | 37 +++ lib/PuppeteerSharp/Bidi/BidiPage.cs | 3 - lib/PuppeteerSharp/Bidi/BidiRealm.cs | 291 ++++++++++++++++++ .../Bidi/Core/BrowsingContext.cs | 20 ++ .../Bidi/Core/CallFunctionParameters.cs | 37 +++ .../Bidi/Core/DedicatedWorkerRealm.cs | 51 +++ .../Bidi/Core/IDedicatedWorkerOwnerRealm.cs | 35 +++ lib/PuppeteerSharp/Bidi/Core/Realm.cs | 99 ++++++ .../Bidi/Core/WorkerRealmEventArgs.cs | 30 ++ lib/PuppeteerSharp/Bidi/WindowRealm.cs | 105 +++++++ lib/PuppeteerSharp/ExecutionContext.cs | 5 +- lib/PuppeteerSharp/ExecutionUtils.cs | 30 ++ lib/PuppeteerSharp/Frame.cs | 4 +- lib/PuppeteerSharp/IPuppeteerUtilWrapper.cs | 37 +++ lib/PuppeteerSharp/IsolatedWorld.cs | 2 +- lib/PuppeteerSharp/PuppeteerSharp.csproj | 2 +- 21 files changed, 1061 insertions(+), 24 deletions(-) create mode 100644 lib/PuppeteerSharp/Bidi/BidiFrameRealm.cs create mode 100644 lib/PuppeteerSharp/Bidi/BidiJSHandle.cs create mode 100644 lib/PuppeteerSharp/Bidi/BidiRealm.cs create mode 100644 lib/PuppeteerSharp/Bidi/Core/CallFunctionParameters.cs create mode 100644 lib/PuppeteerSharp/Bidi/Core/DedicatedWorkerRealm.cs create mode 100644 lib/PuppeteerSharp/Bidi/Core/IDedicatedWorkerOwnerRealm.cs create mode 100644 lib/PuppeteerSharp/Bidi/Core/Realm.cs create mode 100644 lib/PuppeteerSharp/Bidi/Core/WorkerRealmEventArgs.cs create mode 100644 lib/PuppeteerSharp/Bidi/WindowRealm.cs create mode 100644 lib/PuppeteerSharp/ExecutionUtils.cs create mode 100644 lib/PuppeteerSharp/IPuppeteerUtilWrapper.cs diff --git a/lib/PuppeteerSharp.Nunit/TestExpectations/TestExpectations.local.json b/lib/PuppeteerSharp.Nunit/TestExpectations/TestExpectations.local.json index ed7e4a428..8ec5f46dc 100644 --- a/lib/PuppeteerSharp.Nunit/TestExpectations/TestExpectations.local.json +++ b/lib/PuppeteerSharp.Nunit/TestExpectations/TestExpectations.local.json @@ -527,7 +527,202 @@ }, { "comment": "This is part of organizing the webdriver bidi implementation, We will remove it one by one", - "testIdPattern": "[evaluation.spec] *", + "testIdPattern": "[evaluation.spec] *should accept element handle as an argument*", + "platforms": [ + "darwin", + "linux", + "win32" + ], + "parameters": [ + "webDriverBiDi" + ], + "expectations": [ + "FAIL" + ] + }, + { + "comment": "This is part of organizing the webdriver bidi implementation, We will remove it one by one", + "testIdPattern": "[evaluation.spec] *tricky*", + "platforms": [ + "darwin", + "linux", + "win32" + ], + "parameters": [ + "webDriverBiDi" + ], + "expectations": [ + "FAIL" + ] + }, + { + "comment": "This is part of organizing the webdriver bidi implementation, We will remove it one by one", + "testIdPattern": "[evaluation.spec] *circular*", + "platforms": [ + "darwin", + "linux", + "win32" + ], + "parameters": [ + "webDriverBiDi" + ], + "expectations": [ + "FAIL" + ] + }, + { + "comment": "This is part of organizing the webdriver bidi implementation, We will remove it one by one", + "testIdPattern": "[evaluation.spec] *should throw*", + "platforms": [ + "darwin", + "linux", + "win32" + ], + "parameters": [ + "webDriverBiDi" + ], + "expectations": [ + "FAIL" + ] + }, + { + "comment": "This is part of organizing the webdriver bidi implementation, We will remove it one by one", + "testIdPattern": "[evaluation.spec] *objects*", + "platforms": [ + "darwin", + "linux", + "win32" + ], + "parameters": [ + "webDriverBiDi" + ], + "expectations": [ + "FAIL" + ] + }, + { + "comment": "This is part of organizing the webdriver bidi implementation, We will remove it one by one", + "testIdPattern": "[evaluation.spec] *exposed*", + "platforms": [ + "darwin", + "linux", + "win32" + ], + "parameters": [ + "webDriverBiDi" + ], + "expectations": [ + "FAIL" + ] + }, + { + "comment": "This is part of organizing the webdriver bidi implementation, We will remove it one by one", + "testIdPattern": "[evaluation.spec] *should properly serialize null fields*", + "platforms": [ + "darwin", + "linux", + "win32" + ], + "parameters": [ + "webDriverBiDi" + ], + "expectations": [ + "FAIL" + ] + }, + { + "comment": "This is part of organizing the webdriver bidi implementation, We will remove it one by one", + "testIdPattern": "[evaluation.spec] *promise*", + "platforms": [ + "darwin", + "linux", + "win32" + ], + "parameters": [ + "webDriverBiDi" + ], + "expectations": [ + "FAIL" + ] + }, + { + "comment": "This is part of organizing the webdriver bidi implementation, We will remove it one by one", + "testIdPattern": "[evaluation.spec] *error messages*", + "platforms": [ + "darwin", + "linux", + "win32" + ], + "parameters": [ + "webDriverBiDi" + ], + "expectations": [ + "FAIL" + ] + }, + { + "comment": "This is part of organizing the webdriver bidi implementation, We will remove it one by one", + "testIdPattern": "[evaluation.spec] *should work right after framenavigated*", + "platforms": [ + "darwin", + "linux", + "win32" + ], + "parameters": [ + "webDriverBiDi" + ], + "expectations": [ + "FAIL" + ] + }, + { + "comment": "This is part of organizing the webdriver bidi implementation, We will remove it one by one", + "testIdPattern": "[evaluation.spec] *should work with unicode chars*", + "platforms": [ + "darwin", + "linux", + "win32" + ], + "parameters": [ + "webDriverBiDi" + ], + "expectations": [ + "FAIL" + ] + }, + { + "comment": "This is part of organizing the webdriver bidi implementation, We will remove it one by one", + "testIdPattern": "[evaluation.spec] *execution context*", + "platforms": [ + "darwin", + "linux", + "win32" + ], + "parameters": [ + "webDriverBiDi" + ], + "expectations": [ + "FAIL" + ] + }, + { + "comment": "This is part of organizing the webdriver bidi implementation, We will remove it one by one", + "testIdPattern": "[evaluation.spec] *Evaluation specs Page.evaluateOnNewDocument*", + "platforms": [ + "darwin", + "linux", + "win32" + ], + "parameters": [ + "webDriverBiDi" + ], + "expectations": [ + "FAIL" + ] + }, + { + "comment": "This is part of organizing the webdriver bidi implementation, We will remove it one by one", + "testIdPattern": "[evaluation.spec] *Page.removeScriptToEvaluateOnNewDocument*", "platforms": [ "darwin", "linux", diff --git a/lib/PuppeteerSharp.Tests/EvaluationTests/PageEvaluateTests.cs b/lib/PuppeteerSharp.Tests/EvaluationTests/PageEvaluateTests.cs index cde74e8d7..c6af34371 100644 --- a/lib/PuppeteerSharp.Tests/EvaluationTests/PageEvaluateTests.cs +++ b/lib/PuppeteerSharp.Tests/EvaluationTests/PageEvaluateTests.cs @@ -10,10 +10,6 @@ namespace PuppeteerSharp.Tests.EvaluationTests { public class EvaluateTests : PuppeteerPageBaseTest { - public EvaluateTests() : base() - { - } - [Test] [Retry(2)] [PuppeteerTest("evaluation.spec", "Evaluation specs Page.evaluate", "should work")] @@ -191,6 +187,7 @@ public async Task BasicEvaluationTest(string script, object expected) public async Task ShouldAcceptNullAsOneOfMultipleParameters() { var result = await Page.EvaluateFunctionAsync( + "(a, b) => Object.is(a, null) && Object.is(b, 'foo')", null, "foo"); @@ -236,7 +233,7 @@ public async Task ShouldBeAbleToThrowATrickyError() [TestCase("1 + 2;", 3)] [TestCase("1 + 5;", 6)] [TestCase("2 + 5\n// do some math!'", 7)] - public async Task BasicIntExressionEvaluationTest(string script, object expected) + public async Task BasicIntExpressionEvaluationTest(string script, object expected) { var result = await Page.EvaluateExpressionAsync(script); Assert.That(result, Is.EqualTo(expected)); diff --git a/lib/PuppeteerSharp.Tests/NavigationTests/PageWaitForNavigationTests.cs b/lib/PuppeteerSharp.Tests/NavigationTests/PageWaitForNavigationTests.cs index a8c90d616..e2b9e0d15 100644 --- a/lib/PuppeteerSharp.Tests/NavigationTests/PageWaitForNavigationTests.cs +++ b/lib/PuppeteerSharp.Tests/NavigationTests/PageWaitForNavigationTests.cs @@ -4,14 +4,10 @@ using PuppeteerSharp.Helpers; using PuppeteerSharp.Nunit; -namespace PuppeteerSharp.Tests.PageTests +namespace PuppeteerSharp.Tests.NavigationTests { public class PageWaitForNavigationTests : PuppeteerPageBaseTest { - public PageWaitForNavigationTests() : base() - { - } - [Test, Retry(2), PuppeteerTest("navigation.spec", "navigation Page.waitForNavigation", "should work")] public async Task ShouldWork() { @@ -30,10 +26,7 @@ await Task.WhenAll( public async Task ShouldWorkWithBothDomcontentloadedAndLoad() { var responseCompleted = new TaskCompletionSource(); - Server.SetRoute("/one-style.css", _ => - { - return responseCompleted.Task; - }); + Server.SetRoute("/one-style.css", _ => responseCompleted.Task); var waitForRequestTask = Server.WaitForRequest("/one-style.css"); var navigationTask = Page.GoToAsync(TestConstants.ServerUrl + "/one-style.html"); diff --git a/lib/PuppeteerSharp/Bidi/BidiFrame.cs b/lib/PuppeteerSharp/Bidi/BidiFrame.cs index a1dad6937..f7164c402 100644 --- a/lib/PuppeteerSharp/Bidi/BidiFrame.cs +++ b/lib/PuppeteerSharp/Bidi/BidiFrame.cs @@ -34,12 +34,18 @@ namespace PuppeteerSharp.Bidi; public class BidiFrame : Frame { private readonly ConcurrentDictionary _frames = new(); + private readonly Realms _realms; internal BidiFrame(BidiPage parentPage, BidiFrame parentFrame, BrowsingContext browsingContext) { ParentPage = parentPage; ParentFrame = parentFrame; BrowsingContext = browsingContext; + _realms = new Realms( +#pragma warning disable CA2000 + BidiFrameRealm.From(browsingContext.DefaultRealm, this), + BidiFrameRealm.From(browsingContext.CreateWindowRealm($"__puppeteer_internal_{new Random().Next(0, 10000)}"), this)); +#pragma warning restore CA2000 } /// @@ -54,6 +60,11 @@ internal BidiFrame(BidiPage parentPage, BidiFrame parentFrame, BrowsingContext b /// public override CDPSession Client { get; protected set; } + /// + internal override Realm MainRealm => _realms.Default; + + internal override Realm IsolatedRealm => _realms.Internal; + internal BidiPage BidiPage { get @@ -286,5 +297,12 @@ private void CreateFrameTarget(BrowsingContext browsingContext) _frames.TryRemove(browsingContext, out var _); }; } + + private class Realms(BidiFrameRealm defaultRealm, BidiFrameRealm internalRealm) + { + public BidiFrameRealm Default { get; } = defaultRealm; + + public BidiFrameRealm Internal { get; } = internalRealm; + } } diff --git a/lib/PuppeteerSharp/Bidi/BidiFrameRealm.cs b/lib/PuppeteerSharp/Bidi/BidiFrameRealm.cs new file mode 100644 index 000000000..82d7cee96 --- /dev/null +++ b/lib/PuppeteerSharp/Bidi/BidiFrameRealm.cs @@ -0,0 +1,64 @@ +// * MIT License +// * +// * Copyright (c) Darío Kondratiuk +// * +// * Permission is hereby granted, free of charge, to any person obtaining a copy +// * of this software and associated documentation files (the "Software"), to deal +// * in the Software without restriction, including without limitation the rights +// * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// * copies of the Software, and to permit persons to whom the Software is +// * furnished to do so, subject to the following conditions: +// * +// * The above copyright notice and this permission notice shall be included in all +// * copies or substantial portions of the Software. +// * +// * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// * SOFTWARE. + +using System.Threading.Tasks; + +namespace PuppeteerSharp.Bidi; + +internal class BidiFrameRealm(WindowRealm realm, BidiFrame frame) : BidiRealm(realm, frame.TimeoutSettings) +{ + private readonly WindowRealm _realm = realm; + private bool _bindingsInstalled; + + public static BidiFrameRealm From(WindowRealm realm, BidiFrame frame) + { + var frameRealm = new BidiFrameRealm(realm, frame); + frameRealm.Initialize(); + return frameRealm; + } + + public override async Task GetPuppeteerUtilAsync() + { + var installTcs = new TaskCompletionSource(); + + if (!_bindingsInstalled) + { + // TODO: Implement + installTcs.TrySetResult(true); + _bindingsInstalled = true; + } + + await installTcs.Task.ConfigureAwait(false); + return await base.GetPuppeteerUtilAsync().ConfigureAwait(false); + } + + protected override void Initialize() + { + base.Initialize(); + + _realm.Updated += (_, __) => + { + (Environment as Frame)?.ClearDocumentHandle(); + _bindingsInstalled = false; + }; + } +} diff --git a/lib/PuppeteerSharp/Bidi/BidiJSHandle.cs b/lib/PuppeteerSharp/Bidi/BidiJSHandle.cs new file mode 100644 index 000000000..e98fb072e --- /dev/null +++ b/lib/PuppeteerSharp/Bidi/BidiJSHandle.cs @@ -0,0 +1,37 @@ +// * MIT License +// * +// * Copyright (c) Darío Kondratiuk +// * +// * Permission is hereby granted, free of charge, to any person obtaining a copy +// * of this software and associated documentation files (the "Software"), to deal +// * in the Software without restriction, including without limitation the rights +// * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// * copies of the Software, and to permit persons to whom the Software is +// * furnished to do so, subject to the following conditions: +// * +// * The above copyright notice and this permission notice shall be included in all +// * copies or substantial portions of the Software. +// * +// * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// * SOFTWARE. + +using System.Threading.Tasks; +using PuppeteerSharp.Cdp.Messaging; + +namespace PuppeteerSharp.Bidi; + +internal class BidiJSHandle : JSHandle +{ + public BidiJSHandle(IsolatedWorld world, RemoteObject remoteObject) : base(world, remoteObject) + { + } + + public override Task JsonValueAsync() => throw new System.NotImplementedException(); + + public override ValueTask DisposeAsync() => throw new System.NotImplementedException(); +} diff --git a/lib/PuppeteerSharp/Bidi/BidiPage.cs b/lib/PuppeteerSharp/Bidi/BidiPage.cs index 448409227..ca113c89d 100644 --- a/lib/PuppeteerSharp/Bidi/BidiPage.cs +++ b/lib/PuppeteerSharp/Bidi/BidiPage.cs @@ -95,9 +95,6 @@ internal BidiPage(BidiBrowserContext browserContext, BrowsingContext browsingCon /// public override Task ReloadAsync(NavigationOptions options) => throw new NotImplementedException(); - /// - public override Task WaitForNetworkIdleAsync(WaitForNetworkIdleOptions options = null) => throw new NotImplementedException(); - /// public override Task WaitForRequestAsync(Func predicate, WaitForOptions options = null) => throw new NotImplementedException(); diff --git a/lib/PuppeteerSharp/Bidi/BidiRealm.cs b/lib/PuppeteerSharp/Bidi/BidiRealm.cs new file mode 100644 index 000000000..febd84b1a --- /dev/null +++ b/lib/PuppeteerSharp/Bidi/BidiRealm.cs @@ -0,0 +1,291 @@ +// * MIT License +// * +// * Copyright (c) Darío Kondratiuk +// * +// * Permission is hereby granted, free of charge, to any person obtaining a copy +// * of this software and associated documentation files (the "Software"), to deal +// * in the Software without restriction, including without limitation the rights +// * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// * copies of the Software, and to permit persons to whom the Software is +// * furnished to do so, subject to the following conditions: +// * +// * The above copyright notice and this permission notice shall be included in all +// * copies or substantial portions of the Software. +// * +// * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// * SOFTWARE. + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Data; +using System.Globalization; +using System.Linq; +using System.Numerics; +using System.Reflection; +using System.Text.Json; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using PuppeteerSharp.Bidi.Core; +using WebDriverBiDi.Script; + +namespace PuppeteerSharp.Bidi; + +/// +/// A BidiLazyArg is an evaluation argument that will be resolved when the CDP call is built. +/// +/// Execution context. +/// Resolved argument. +public delegate Task BidiLazyArg(IPuppeteerUtilWrapper context); + +internal class BidiRealm(Core.Realm realm, TimeoutSettings timeoutSettings) : Realm(timeoutSettings), IDisposable, IPuppeteerUtilWrapper +{ + private static readonly Regex _sourceUrlRegex = new(@"^[\x20\t]*//([@#])\s*sourceURL=\s{0,10}(\S*?)\s{0,10}$", RegexOptions.Multiline); + + public bool Disposed { get; private set; } + + public JSHandle InternalPuppeteerUtilHandle { get; set; } + + internal override IEnvironment Environment { get; } + + public void Dispose() + { + Disposed = true; + TaskManager.TerminateAll(new PuppeteerException("waitForFunction failed: frame got detached.")); + } + + public virtual Task GetPuppeteerUtilAsync() => throw new NotImplementedException(); + + internal override Task AdoptHandleAsync(IJSHandle handle) => throw new System.NotImplementedException(); + + internal override Task AdoptBackendNodeAsync(object backendNodeId) => throw new System.NotImplementedException(); + + internal override Task TransferHandleAsync(IJSHandle handle) => throw new System.NotImplementedException(); + + internal override Task EvaluateExpressionHandleAsync(string script) => throw new System.NotImplementedException(); + + internal override Task EvaluateFunctionHandleAsync(string script, params object[] args) => throw new System.NotImplementedException(); + + internal override async Task EvaluateExpressionAsync(string script) + => DeserializeResult((await EvaluateAsync(true, true, script).ConfigureAwait(false)).Result.Value); + + internal override Task EvaluateExpressionAsync(string script) => throw new System.NotImplementedException(); + + internal override async Task EvaluateFunctionAsync(string script, params object[] args) + => DeserializeResult((await EvaluateAsync(true, false, script, args).ConfigureAwait(false)).Result.Value); + + internal override Task EvaluateFunctionAsync(string script, params object[] args) => throw new System.NotImplementedException(); + + protected virtual void Initialize() + { + realm.Destroyed += (_, e) => + { + TaskManager.TerminateAll(new PuppeteerException(e.Reason)); + Dispose(); + }; + + realm.Updated += (_, __) => + { + InternalPuppeteerUtilHandle = null; + TaskManager.RerunAll(); + }; + } + + private async Task EvaluateAsync(bool returnByValue, bool isExpression, string script, params object[] args) + { + var sourceUrlComment = ExecutionUtils.GetSourceUrlComment(); + var resultOwnership = returnByValue + ? ResultOwnership.None + : ResultOwnership.Root; + + var serializationOptions = new SerializationOptions(); + + if (!returnByValue) + { + serializationOptions.MaxObjectDepth = 0; + serializationOptions.MaxDomDepth = 0; + } + + var functionDeclaration = _sourceUrlRegex.IsMatch(script) + ? script + : $"{script}\n{sourceUrlComment}\n"; + + var options = new CallFunctionParameters(); + + options.Arguments.AddRange( + await Task.WhenAll(args.Select(FormatArgumentAsync).ToArray()).ConfigureAwait(false)); + options.ResultOwnership = resultOwnership; + options.UserActivation = true; + options.SerializationOptions = serializationOptions; + + EvaluateResult result; + + if (isExpression) + { + result = await realm.EvaluateAsync( + functionDeclaration, + true, + options).ConfigureAwait(false); + } + else + { + result = await realm.CallFunctionAsync( + functionDeclaration, + true, + options).ConfigureAwait(false); + } + + if (result.ResultType == EvaluateResultType.Exception) + { + // TODO: Improve text details + throw new EvaluateException(((EvaluateResultException)result).ExceptionDetails.Text); + } + + return result as EvaluateResultSuccess; + } + + private T DeserializeResult(object result) + { + if (result is null) + { + return default; + } + + if (typeof(T) == typeof(JsonElement?)) + { + return (T)(object)JsonSerializer.SerializeToElement(result); + } + + // Convert known types first + if (typeof(T) == typeof(int)) + { + return (T)(object)Convert.ToInt32(result, CultureInfo.InvariantCulture); + } + + if (typeof(T) == typeof(double)) + { + return (T)(object)Convert.ToDouble(result, CultureInfo.InvariantCulture); + } + + if (typeof(T) == typeof(string)) + { + return (T)result; + } + + if (typeof(T) == typeof(bool)) + { + return (T)(object)Convert.ToBoolean(result, CultureInfo.InvariantCulture); + } + + if (typeof(T).IsArray) + { + // Get the element type of the array + var elementType = typeof(T).GetElementType(); + + if (elementType != null && result is IEnumerable enumerable) + { + // Create a list of the element type + var list = (IList)Activator.CreateInstance(typeof(List<>).MakeGenericType(elementType)); + + // Iterate over the input and add converted items to the list + foreach (var item in enumerable) + { + var itemToSerialize = item; + + if (item is RemoteValue remoteValue) + { + itemToSerialize = remoteValue.Value; + } + + // Maybe there is a better way to do this. + var deserializedItem = typeof(BidiRealm) + .GetMethod(nameof(DeserializeResult), BindingFlags.Instance | BindingFlags.NonPublic) + ?.MakeGenericMethod(elementType) + .Invoke(this, [itemToSerialize]); + + list.Add(deserializedItem); + } + + // Convert the list to an array + return (T)list.GetType().GetMethod("ToArray")!.Invoke(list, null)!; + } + } + + return (T)result; + } + + private async Task FormatArgumentAsync(object arg) + { + if (arg is TaskCompletionSource tcs) + { + arg = await tcs.Task.ConfigureAwait(false); + } + + if (arg is BidiLazyArg lazyArg) + { + arg = await lazyArg(this).ConfigureAwait(false); + } + + if (arg is null) + { + return LocalValue.Null; + } + + switch (arg) + { + case BigInteger big: + return LocalValue.BigInt(big); + + case int integer when integer == -0: + return LocalValue.NegativeZero; + + case double d: + if (double.IsPositiveInfinity(d)) + { + return LocalValue.Infinity; + } + + if (double.IsNegativeInfinity(d)) + { + return LocalValue.NegativeInfinity; + } + + if (double.IsNaN(d)) + { + return LocalValue.NaN; + } + + break; + case string stringValue: + return LocalValue.String(stringValue); + case int intValue: + return LocalValue.Number(intValue); + case bool boolValue: + return LocalValue.Boolean(boolValue); + case long longValue: + return LocalValue.Number(longValue); + case float floatValue: + return LocalValue.Number(floatValue); + case IEnumerable enumerable: + var list = new List(); + foreach (var item in enumerable) + { + list.Add(await FormatArgumentAsync(item).ConfigureAwait(false)); + } + + return LocalValue.Array(list); + case IJSHandle objectHandle: + // TODO: Implement this + return null; + + // TODO: Cover the rest of the cases + } + + return null; + } +} diff --git a/lib/PuppeteerSharp/Bidi/Core/BrowsingContext.cs b/lib/PuppeteerSharp/Bidi/Core/BrowsingContext.cs index 902a29645..b6b0ae65d 100644 --- a/lib/PuppeteerSharp/Bidi/Core/BrowsingContext.cs +++ b/lib/PuppeteerSharp/Bidi/Core/BrowsingContext.cs @@ -42,10 +42,14 @@ private BrowsingContext(UserContext userContext, BrowsingContext parent, string Id = id; Url = url; OriginalOpener = originalOpener; + + DefaultRealm = CreateWindowRealm(); } public event EventHandler Closed; + public event EventHandler Worker; + public event EventHandler DomContentLoaded; public event EventHandler Load; @@ -66,6 +70,8 @@ private BrowsingContext(UserContext userContext, BrowsingContext parent, string public IEnumerable Children => _children.Values; + public WindowRealm DefaultRealm { get; } + internal string OriginalOpener { get; } internal BrowsingContext Top @@ -123,6 +129,18 @@ await Session.Driver.BrowsingContext.NavigateAsync(new NavigateCommandParameters }).ConfigureAwait(false); } + internal WindowRealm CreateWindowRealm(string sandbox = null) + { + var realm = WindowRealm.From(this, sandbox); + + realm.Worker += (sender, args) => + { + OnWorker(args.Realm); + }; + + return realm; + } + protected virtual void OnBrowsingContextCreated(BidiBrowsingContextEventArgs e) => BrowsingContextCreated?.Invoke(this, e); private void Initialize() @@ -245,4 +263,6 @@ private void Dispose(string reason) } private void OnClosed(string reason) => Closed?.Invoke(this, new ClosedEventArgs(reason)); + + private void OnWorker(DedicatedWorkerRealm args) => Worker?.Invoke(this, new WorkerRealmEventArgs(args)); } diff --git a/lib/PuppeteerSharp/Bidi/Core/CallFunctionParameters.cs b/lib/PuppeteerSharp/Bidi/Core/CallFunctionParameters.cs new file mode 100644 index 000000000..8cdfa5a1e --- /dev/null +++ b/lib/PuppeteerSharp/Bidi/Core/CallFunctionParameters.cs @@ -0,0 +1,37 @@ +// * MIT License +// * +// * Copyright (c) Darío Kondratiuk +// * +// * Permission is hereby granted, free of charge, to any person obtaining a copy +// * of this software and associated documentation files (the "Software"), to deal +// * in the Software without restriction, including without limitation the rights +// * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// * copies of the Software, and to permit persons to whom the Software is +// * furnished to do so, subject to the following conditions: +// * +// * The above copyright notice and this permission notice shall be included in all +// * copies or substantial portions of the Software. +// * +// * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// * SOFTWARE. + +using System.Collections.Generic; +using WebDriverBiDi.Script; + +namespace PuppeteerSharp.Bidi.Core; + +internal class CallFunctionParameters +{ + public List Arguments { get; set; } = new(); + + public ResultOwnership? ResultOwnership { get; set; } + + public bool? UserActivation { get; set; } + + public SerializationOptions SerializationOptions { get; set; } +} diff --git a/lib/PuppeteerSharp/Bidi/Core/DedicatedWorkerRealm.cs b/lib/PuppeteerSharp/Bidi/Core/DedicatedWorkerRealm.cs new file mode 100644 index 000000000..ec12b6194 --- /dev/null +++ b/lib/PuppeteerSharp/Bidi/Core/DedicatedWorkerRealm.cs @@ -0,0 +1,51 @@ +// * MIT License +// * +// * Copyright (c) Darío Kondratiuk +// * +// * Permission is hereby granted, free of charge, to any person obtaining a copy +// * of this software and associated documentation files (the "Software"), to deal +// * in the Software without restriction, including without limitation the rights +// * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// * copies of the Software, and to permit persons to whom the Software is +// * furnished to do so, subject to the following conditions: +// * +// * The above copyright notice and this permission notice shall be included in all +// * copies or substantial portions of the Software. +// * +// * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// * SOFTWARE. + +using System.Linq; +using PuppeteerSharp.Helpers; + +namespace PuppeteerSharp.Bidi.Core; + +internal class DedicatedWorkerRealm : Realm +{ + private readonly ConcurrentSet _owners = []; + + private DedicatedWorkerRealm(IDedicatedWorkerOwnerRealm owner, string id, string origin) + : base(id, origin) + { + _owners.Add(owner); + } + + public override Session Session => _owners.FirstOrDefault()?.Session; + + public static DedicatedWorkerRealm From(IDedicatedWorkerOwnerRealm owner, string id, string origin) + { + var realm = new DedicatedWorkerRealm(owner, id, origin); + realm.Initialize(); + return realm; + } + + private void Initialize() + { + throw new System.NotImplementedException(); + } +} diff --git a/lib/PuppeteerSharp/Bidi/Core/IDedicatedWorkerOwnerRealm.cs b/lib/PuppeteerSharp/Bidi/Core/IDedicatedWorkerOwnerRealm.cs new file mode 100644 index 000000000..2348b81c4 --- /dev/null +++ b/lib/PuppeteerSharp/Bidi/Core/IDedicatedWorkerOwnerRealm.cs @@ -0,0 +1,35 @@ +// * MIT License +// * +// * Copyright (c) Darío Kondratiuk +// * +// * Permission is hereby granted, free of charge, to any person obtaining a copy +// * of this software and associated documentation files (the "Software"), to deal +// * in the Software without restriction, including without limitation the rights +// * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// * copies of the Software, and to permit persons to whom the Software is +// * furnished to do so, subject to the following conditions: +// * +// * The above copyright notice and this permission notice shall be included in all +// * copies or substantial portions of the Software. +// * +// * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// * SOFTWARE. + +namespace PuppeteerSharp.Bidi.Core; + +/// +/// Different types of realms. +/// Upstream it's DedicatedWorkerRealm | SharedWorkerRealm | WindowRealm. +/// +internal interface IDedicatedWorkerOwnerRealm +{ + /// + /// Session. + /// + Session Session { get; } +} diff --git a/lib/PuppeteerSharp/Bidi/Core/Realm.cs b/lib/PuppeteerSharp/Bidi/Core/Realm.cs new file mode 100644 index 000000000..1eaa094f3 --- /dev/null +++ b/lib/PuppeteerSharp/Bidi/Core/Realm.cs @@ -0,0 +1,99 @@ +// * MIT License +// * +// * Copyright (c) Darío Kondratiuk +// * +// * Permission is hereby granted, free of charge, to any person obtaining a copy +// * of this software and associated documentation files (the "Software"), to deal +// * in the Software without restriction, including without limitation the rights +// * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// * copies of the Software, and to permit persons to whom the Software is +// * furnished to do so, subject to the following conditions: +// * +// * The above copyright notice and this permission notice shall be included in all +// * copies or substantial portions of the Software. +// * +// * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// * SOFTWARE. + +using System; +using System.Threading.Tasks; +using WebDriverBiDi.Script; + +namespace PuppeteerSharp.Bidi.Core; + +internal abstract class Realm(string id, string origin) : IDisposable +{ + private string _reason; + + public event EventHandler Destroyed; + + public event EventHandler Updated; + + public string Id { get; protected set; } = id; + + public string Origin { get; protected set; } = origin; + + public bool Disposed { get; private set; } + + public WebDriverBiDi.Script.Target Target => new RealmTarget(Id); + + public abstract Session Session { get; } + + public void Dispose(string reason) + { + _reason = reason; + Dispose(); + } + + public virtual void Dispose() + { + _reason ??= + "Realm already destroyed, probably because all associated browsing contexts closed."; + OnDestroyed(); + Disposed = true; + } + + public Task EvaluateAsync( + string functionDeclaration, + bool awaitPromise, + CallFunctionParameters options = null) + { + var parameters = new EvaluateCommandParameters(functionDeclaration, Target, awaitPromise); + + if (options != null) + { + parameters.ResultOwnership = options.ResultOwnership; + parameters.UserActivation = options.UserActivation; + parameters.SerializationOptions = options.SerializationOptions; + } + + return Session.Driver.Script.EvaluateAsync(parameters); + } + + public Task CallFunctionAsync( + string functionDeclaration, + bool awaitPromise, + CallFunctionParameters options = null) + { + var parameters = new CallFunctionCommandParameters(functionDeclaration, Target, awaitPromise); + + if (options != null) + { + parameters.Arguments.AddRange(options.Arguments); + parameters.ResultOwnership = options.ResultOwnership; + parameters.UserActivation = options.UserActivation; + parameters.SerializationOptions = options.SerializationOptions; + } + + return Session.Driver.Script.CallFunctionAsync(parameters); + } + + protected virtual void OnUpdated() => Updated?.Invoke(this, EventArgs.Empty); + + private void OnDestroyed() => Destroyed?.Invoke(this, new ClosedEventArgs(_reason)); +} diff --git a/lib/PuppeteerSharp/Bidi/Core/WorkerRealmEventArgs.cs b/lib/PuppeteerSharp/Bidi/Core/WorkerRealmEventArgs.cs new file mode 100644 index 000000000..cc8f07220 --- /dev/null +++ b/lib/PuppeteerSharp/Bidi/Core/WorkerRealmEventArgs.cs @@ -0,0 +1,30 @@ +// * MIT License +// * +// * Copyright (c) Darío Kondratiuk +// * +// * Permission is hereby granted, free of charge, to any person obtaining a copy +// * of this software and associated documentation files (the "Software"), to deal +// * in the Software without restriction, including without limitation the rights +// * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// * copies of the Software, and to permit persons to whom the Software is +// * furnished to do so, subject to the following conditions: +// * +// * The above copyright notice and this permission notice shall be included in all +// * copies or substantial portions of the Software. +// * +// * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// * SOFTWARE. + +using System; + +namespace PuppeteerSharp.Bidi.Core; + +internal class WorkerRealmEventArgs(DedicatedWorkerRealm realm) : EventArgs +{ + public DedicatedWorkerRealm Realm { get; } = realm; +} diff --git a/lib/PuppeteerSharp/Bidi/WindowRealm.cs b/lib/PuppeteerSharp/Bidi/WindowRealm.cs new file mode 100644 index 000000000..13a2012bc --- /dev/null +++ b/lib/PuppeteerSharp/Bidi/WindowRealm.cs @@ -0,0 +1,105 @@ +// * MIT License +// * +// * Copyright (c) Darío Kondratiuk +// * +// * Permission is hereby granted, free of charge, to any person obtaining a copy +// * of this software and associated documentation files (the "Software"), to deal +// * in the Software without restriction, including without limitation the rights +// * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// * copies of the Software, and to permit persons to whom the Software is +// * furnished to do so, subject to the following conditions: +// * +// * The above copyright notice and this permission notice shall be included in all +// * copies or substantial portions of the Software. +// * +// * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// * SOFTWARE. + +using System; +using System.Collections.Concurrent; +using PuppeteerSharp.Bidi.Core; +using PuppeteerSharp.Helpers; +using WebDriverBiDi.Script; + +namespace PuppeteerSharp.Bidi; + +internal class WindowRealm(BrowsingContext browsingContext, string sandbox = null) : Core.Realm(string.Empty, string.Empty), IDedicatedWorkerOwnerRealm +{ + private readonly string _sandbox = sandbox; + private readonly ConcurrentDictionary _workers = []; + + public event EventHandler Worker; + + public override Session Session => browsingContext.UserContext.Browser.Session; + + public string ExecutionContextId { get; set; } + + public static WindowRealm From(BrowsingContext context, string sandbox = null) + { + var realm = new WindowRealm(context, sandbox); + realm.Initialize(); + return realm; + } + + public override void Dispose() + { + browsingContext.Dispose(); + Session.Dispose(); + + foreach (var worker in _workers.Values) + { + worker.Dispose(); + } + + base.Dispose(); + } + + private void Initialize() + { + browsingContext.Closed += (sender, args) => Dispose(args.Reason); + Session.Driver.Script.OnRealmCreated.AddObserver(OnWindowRealmCreated); + Session.Driver.Script.OnRealmCreated.AddObserver(OnDedicatedRealmCreated); + } + + private void OnWindowRealmCreated(RealmCreatedEventArgs args) + { + if (args.Type != RealmType.DedicatedWorker) + { + return; + } + + var dedicatedWorkerInfo = args.As(); + + if (!dedicatedWorkerInfo.Owners.Contains(Id)) + { + return; + } + + var realm = DedicatedWorkerRealm.From(this, dedicatedWorkerInfo.RealmId, dedicatedWorkerInfo.Origin); + _workers.TryAdd(realm.Id, realm); + realm.Destroyed += (sender, args) => _workers.TryRemove(realm.Id, out _); + OnWorker(realm); + } + + private void OnWorker(DedicatedWorkerRealm realm) => Worker?.Invoke(this, new WorkerRealmEventArgs(realm)); + + private void OnDedicatedRealmCreated(RealmCreatedEventArgs args) + { + if (args.Type != RealmType.Window || + args.As().BrowsingContext != browsingContext.Id || + args.As().Sandbox != _sandbox) + { + return; + } + + Id = args.RealmId; + Origin = args.Origin; + ExecutionContextId = null; + OnUpdated(); + } +} diff --git a/lib/PuppeteerSharp/ExecutionContext.cs b/lib/PuppeteerSharp/ExecutionContext.cs index 8d5d9cbbe..64cc7d2d9 100644 --- a/lib/PuppeteerSharp/ExecutionContext.cs +++ b/lib/PuppeteerSharp/ExecutionContext.cs @@ -12,7 +12,7 @@ namespace PuppeteerSharp { /// - public sealed class ExecutionContext : IExecutionContext, IDisposable, IAsyncDisposable + public sealed class ExecutionContext : IExecutionContext, IDisposable, IAsyncDisposable, IPuppeteerUtilWrapper { internal const string EvaluationScriptUrl = "__puppeteer_evaluation_script__"; private const string EvaluationScriptSuffix = $"//# sourceURL={EvaluationScriptUrl}"; @@ -97,7 +97,8 @@ public void Dispose() GC.SuppressFinalize(this); } - internal async Task GetPuppeteerUtilAsync() + /// + public async Task GetPuppeteerUtilAsync() { await _puppeteerUtilQueue.Enqueue(async () => { diff --git a/lib/PuppeteerSharp/ExecutionUtils.cs b/lib/PuppeteerSharp/ExecutionUtils.cs new file mode 100644 index 000000000..6b0089d1f --- /dev/null +++ b/lib/PuppeteerSharp/ExecutionUtils.cs @@ -0,0 +1,30 @@ +// * MIT License +// * +// * Copyright (c) Darío Kondratiuk +// * +// * Permission is hereby granted, free of charge, to any person obtaining a copy +// * of this software and associated documentation files (the "Software"), to deal +// * in the Software without restriction, including without limitation the rights +// * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// * copies of the Software, and to permit persons to whom the Software is +// * furnished to do so, subject to the following conditions: +// * +// * The above copyright notice and this permission notice shall be included in all +// * copies or substantial portions of the Software. +// * +// * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// * SOFTWARE. + +namespace PuppeteerSharp; + +internal class ExecutionUtils +{ + public const string InternalUrl = "pptr:internal"; + + public static string GetSourceUrlComment(string url = null) => $"//# sourceURL={url ?? InternalUrl}"; +} diff --git a/lib/PuppeteerSharp/Frame.cs b/lib/PuppeteerSharp/Frame.cs index a8bc3c237..a1364b37d 100644 --- a/lib/PuppeteerSharp/Frame.cs +++ b/lib/PuppeteerSharp/Frame.cs @@ -58,9 +58,9 @@ public abstract class Frame : IFrame, IEnvironment internal List LifecycleEvents { get; } = new(); - internal Realm MainRealm { get; set; } + internal virtual Realm MainRealm { get; set; } - internal Realm IsolatedRealm { get; set; } + internal virtual Realm IsolatedRealm { get; set; } internal IsolatedWorld MainWorld => MainRealm as IsolatedWorld; diff --git a/lib/PuppeteerSharp/IPuppeteerUtilWrapper.cs b/lib/PuppeteerSharp/IPuppeteerUtilWrapper.cs new file mode 100644 index 000000000..8d02593e3 --- /dev/null +++ b/lib/PuppeteerSharp/IPuppeteerUtilWrapper.cs @@ -0,0 +1,37 @@ +// * MIT License +// * +// * Copyright (c) Darío Kondratiuk +// * +// * Permission is hereby granted, free of charge, to any person obtaining a copy +// * of this software and associated documentation files (the "Software"), to deal +// * in the Software without restriction, including without limitation the rights +// * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// * copies of the Software, and to permit persons to whom the Software is +// * furnished to do so, subject to the following conditions: +// * +// * The above copyright notice and this permission notice shall be included in all +// * copies or substantial portions of the Software. +// * +// * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// * SOFTWARE. + +using System.Threading.Tasks; + +namespace PuppeteerSharp; + +/// +/// A class that contains a method to get the PuppeteerUtil handle. +/// +public interface IPuppeteerUtilWrapper +{ + /// + /// Gets the PuppeteerUtil handle. + /// + /// The PuppeteerUtil handle. + Task GetPuppeteerUtilAsync(); +} diff --git a/lib/PuppeteerSharp/IsolatedWorld.cs b/lib/PuppeteerSharp/IsolatedWorld.cs index b5490c350..fe06dedab 100644 --- a/lib/PuppeteerSharp/IsolatedWorld.cs +++ b/lib/PuppeteerSharp/IsolatedWorld.cs @@ -16,7 +16,7 @@ namespace PuppeteerSharp /// /// Execution context. /// Resolved argument. - public delegate Task LazyArg(ExecutionContext context); + public delegate Task LazyArg(IPuppeteerUtilWrapper context); internal class IsolatedWorld : Realm, IDisposable, IAsyncDisposable { diff --git a/lib/PuppeteerSharp/PuppeteerSharp.csproj b/lib/PuppeteerSharp/PuppeteerSharp.csproj index 65bf5050c..c185d7612 100644 --- a/lib/PuppeteerSharp/PuppeteerSharp.csproj +++ b/lib/PuppeteerSharp/PuppeteerSharp.csproj @@ -43,7 +43,7 @@ all - +