From 5aba7dc779cbb7c9636d5b1a4cfb3eadeb958656 Mon Sep 17 00:00:00 2001 From: Bjoern Esswein <4-Bjoern@users.noreply.git.esswe.in> Date: Sun, 24 Mar 2024 11:26:29 +0100 Subject: [PATCH] added SendCommandAsync<C,R>(C command) wich returns a Task that resolves to the response --- .../ChromeDevtools/DevtoolsProtocolHandler.cs | 30 +++++++ Runtime/ChromeDevtools/DevtoolsWebsocket.cs | 1 - Runtime/ChromeDevtools/DomNodeWrapper.cs | 81 ++++++++++++++++++- .../Protocol/DevtoolsResponse.cs | 1 - Runtime/WebViewComponent.cs | 33 +------- 5 files changed, 113 insertions(+), 33 deletions(-) diff --git a/Runtime/ChromeDevtools/DevtoolsProtocolHandler.cs b/Runtime/ChromeDevtools/DevtoolsProtocolHandler.cs index fe7e710..737ffe3 100644 --- a/Runtime/ChromeDevtools/DevtoolsProtocolHandler.cs +++ b/Runtime/ChromeDevtools/DevtoolsProtocolHandler.cs @@ -196,6 +196,36 @@ namespace bessw.Unity.WebView.ChromeDevTools yield return new WaitUntil(() => sendTask.IsCompleted); } + /// <summary> + /// json serializes and sends a command over the devtools websocket + /// </summary> + /// <typeparam name="C">IDevtoolsCommandWithResponse</typeparam> + /// <typeparam name="R">IDevtoolsResponse</typeparam> + /// <param name="command"></param> + /// <returns>Task that resoves with the response</returns> + public Task<R> SendCommandAsync<C, R>(C command) where C : IDevtoolsCommandWithResponse where R : class, IDevtoolsResponse + { + // apply the message wrapper + var wrappedCommand = new DevtoolsCommandWrapper<C>(command) + { + Id = ++LAST_COMMAND_ID + }; + + TaskCompletionSource<R> tcs = new TaskCompletionSource<R>(); + + // register the response callback for this command id + if (!commandResponseDict.TryAdd(wrappedCommand.Id, new ResponseTypeAndCallback(typeof(R), (res) => tcs.SetResult(res as R)))) + { + throw new InvalidOperationException($"could not add response callback for command '{wrappedCommand.Id}' to commandResponseDict"); + } + + // json serialize the command and send it + var json = JsonConvert.SerializeObject(wrappedCommand, Browser.devtoolsSerializerSettings); + Debug.Log($"ws send: '{json}'"); + devtools.SendCommandAsync(json); + return tcs.Task; + } + /// <summary> /// json serializes and sends a command over the devtools websocket /// </summary> diff --git a/Runtime/ChromeDevtools/DevtoolsWebsocket.cs b/Runtime/ChromeDevtools/DevtoolsWebsocket.cs index c4e0526..b6565d6 100644 --- a/Runtime/ChromeDevtools/DevtoolsWebsocket.cs +++ b/Runtime/ChromeDevtools/DevtoolsWebsocket.cs @@ -1,4 +1,3 @@ -using bessw.Unity.WebView.ChromeDevTools; using System; using System.IO; using System.Net.WebSockets; diff --git a/Runtime/ChromeDevtools/DomNodeWrapper.cs b/Runtime/ChromeDevtools/DomNodeWrapper.cs index 5f97af3..c59666e 100644 --- a/Runtime/ChromeDevtools/DomNodeWrapper.cs +++ b/Runtime/ChromeDevtools/DomNodeWrapper.cs @@ -2,7 +2,6 @@ using bessw.Unity.WebView.ChromeDevTools.Protocol.DOM; using System; using System.Collections; using System.Collections.Generic; -using System.Linq; using System.Threading.Tasks; #nullable enable @@ -169,6 +168,86 @@ namespace bessw.Unity.WebView.ChromeDevTools #endregion Event Handlers + #region Async Commands + + /// <summary> + /// get the root node of the document + /// </summary> + /// <param name="tab"></param> + public static async Task<DomNodeWrapper> getDocumentAsync(BrowserTab tab) + { + var commandResponse = await tab.devtools.SendCommandAsync<getDocument, getDocumentCommandResponse>(new getDocument()); + var documentRoot = commandResponse.root; + + var domNode = createOrUpdateNode(tab, + documentRoot.nodeId, + documentRoot.parentId, + documentRoot.backendNodeId, + documentRoot + ); + return domNode; + } + + /// <summary> + /// get a node by its js object id + /// </summary> + /// <param name="tab"></param> + /// <param name="objectId">Javascript html object id</param> + public static async Task<DomNodeWrapper> describeNodeAsync(BrowserTab tab, string objectId, int? depth = null, bool? pierce = null) + { + var commandResponse = await tab.devtools.SendCommandAsync<describeNode, describeNodeCommandResponse>(new describeNode + { + objectId = objectId, + depth = depth, + pierce = pierce + }); + return createOrUpdateNode(tab, commandResponse.node.nodeId, null, null, commandResponse.node); + } + + /// <summary> + /// get the nodeId by its js object id + /// </summary> + /// <param name="tab"></param> + /// <param name="objectId">Javascript html object id</param> + public static async Task<DomNodeWrapper> requestNodeAsync(BrowserTab tab, string objectId) + { + var commandResponse = await tab.devtools.SendCommandAsync<requestNode, requestNodeCommandResponse>(new requestNode + { + objectId = objectId + }); + return createOrUpdateNode(tab, commandResponse.nodeId); + } + + + public async Task<DomNodeWrapper[]> querySelectorAllAsync(string selector) + { + var commandResponse = await tab.devtools.SendCommandAsync<querySelectorAll, querySelectorAllCommandResponse>(new querySelectorAll + { + nodeId = NodeId, + selector = selector + }); + var nodeIds = commandResponse.nodeIds; + var domNodes = new DomNodeWrapper[nodeIds.Length]; + for (int i = 0; i < nodeIds.Length; i++) + { + domNodes[i] = createOrUpdateNode(tab, nodeIds[i]); + } + return domNodes; + } + + + public async Task<Dictionary<string, string>> getAttributesAsync() + { + var commandResponse = await tab.devtools.SendCommandAsync<getAttributes, getAttributesCommandResponse>(new getAttributes + { + nodeId = NodeId + }); + Node.attributes = commandResponse.attributes; + return commandResponse.attributes; + } + + #endregion Async Commands + #region Commands /// <summary> diff --git a/Runtime/ChromeDevtools/Protocol/DevtoolsResponse.cs b/Runtime/ChromeDevtools/Protocol/DevtoolsResponse.cs index ac790ad..def8bdb 100644 --- a/Runtime/ChromeDevtools/Protocol/DevtoolsResponse.cs +++ b/Runtime/ChromeDevtools/Protocol/DevtoolsResponse.cs @@ -1,5 +1,4 @@ using Newtonsoft.Json.Linq; -using System; namespace bessw.Unity.WebView.ChromeDevTools.Protocol { diff --git a/Runtime/WebViewComponent.cs b/Runtime/WebViewComponent.cs index 76dad43..7865670 100644 --- a/Runtime/WebViewComponent.cs +++ b/Runtime/WebViewComponent.cs @@ -1,9 +1,11 @@ using bessw.Unity.WebView.ChromeDevTools; using bessw.Unity.WebView.ChromeDevTools.Protocol.Input; +using MoreLinq; using Newtonsoft.Json; using Newtonsoft.Json.Serialization; using System.Collections; using System.Collections.Generic; +using System.Linq; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.UI; @@ -39,7 +41,7 @@ namespace bessw.Unity.WebView #endregion json serializer private Browser browser; - protected BrowserTab tab; + public BrowserTab tab; private RawImage rawImage; private RectTransform rectTransform; @@ -87,32 +89,6 @@ namespace bessw.Unity.WebView }); } - private IEnumerator getDropzoneState () - { - Debug.LogWarning($"dropzone pre"); - - DomNodeWrapper doc = null; - yield return DomNodeWrapper.getDocument(tab, (document) => { - Debug.LogWarning($"dropzone 1: '{document}'"); - doc = document; - - StartCoroutine(document.querySelectorAll("[dropzone='copy']", (dropzones) => { - foreach (var dropzone in dropzones) - { - Debug.LogWarning($"dropzone 2: Node is Null?: '{dropzone.Node == null}'"); - StartCoroutine(dropzone.getAttributes((attributes) => - { - Debug.LogWarning($"dropzone 3 getAttributes: '{string.Join(", ", attributes.Values)}'"); - })); - } - })); - }); - Debug.LogWarning($"dropzone post: '{doc}'"); - - // alternative way to get the dropzone state - - } - // Update is called once per frame private void Update() { @@ -162,9 +138,6 @@ namespace bessw.Unity.WebView { Debug.LogWarning($"OnDrop: {eventData.position}"); createDragEvent(DragEventType.drop, eventData); - - // TODO: remove debug code - StartCoroutine(getDropzoneState()); } public void OnPointerExit(PointerEventData eventData) -- GitLab