Skip to content
Snippets Groups Projects
Commit c4bdc6d2 authored by Kevin Prudente's avatar Kevin Prudente Committed by GitHub
Browse files

Merge pull request #19 from svatal/master

Update tooling and protocols
parents 3207391a 700d4096
Branches
Tags
No related merge requests found
Showing
with 235 additions and 100 deletions
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
namespace MasterDevs.ChromeDevTools
{
public class ChromeProcess : IChromeProcess
{
public DirectoryInfo UserDirectory { get; set; }
public Process Process { get; set; }
public string RemoteDebuggingUri { get; set; }
public void Dispose()
{
Process.Kill();
try
{
UserDirectory.Delete(true);
}
catch
{
Thread.Sleep(500); // i'm being lazy because i'm tired
UserDirectory.Delete(true);
}
}
public async Task<string[]> GetSessions()
{
var remoteSessionUrls = new List<string>();
var webClient = new HttpClient();
var uriBuilder = new UriBuilder(RemoteDebuggingUri);
uriBuilder.Path = "/json";
var remoteSessions = await webClient.GetStringAsync(uriBuilder.Uri);
using (var stringReader = new StringReader(remoteSessions))
using (var jsonReader = new JsonTextReader(stringReader))
{
var sessionsObject = JToken.ReadFrom(jsonReader) as JArray;
foreach (var sessionObject in sessionsObject)
{
var sessionUrl = sessionObject["webSocketDebuggerUrl"].GetSafeString();
if (!String.IsNullOrEmpty(sessionUrl))
{
remoteSessionUrls.Add(sessionUrl);
}
}
}
return remoteSessionUrls.ToArray();
}
}
}
\ No newline at end of file
using System.Diagnostics;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
namespace MasterDevs.ChromeDevTools
{
public class ChromeProcessFactory : IChromeProcessFactory
{
public IChromeProcess Create(int port)
public IDirectoryCleaner DirectoryCleaner { get; set; }
public string ChromePath { get; }
public ChromeProcessFactory(IDirectoryCleaner directoryCleaner, string chromePath = @"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe")
{
DirectoryCleaner = directoryCleaner;
ChromePath = chromePath;
}
public IChromeProcess Create(int port, bool headless)
{
string path = Path.GetRandomFileName();
var directoryInfo = Directory.CreateDirectory(Path.Combine(Path.GetTempPath(), path));
var remoteDebuggingArg = "--remote-debugging-port=" + port;
var userDirectoryArg = "--user-data-dir=\"" + directoryInfo.FullName + "\"";
var chromeProcessArgs = remoteDebuggingArg + " " + userDirectoryArg + " --bwsi --no-first-run";
var processStartInfo = new ProcessStartInfo(@"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe", chromeProcessArgs);
var chromeProcess = Process.Start(processStartInfo);
return new ChromeProcess
var remoteDebuggingArg = $"--remote-debugging-port={port}";
var userDirectoryArg = $"--user-data-dir=\"{directoryInfo.FullName}\"";
const string headlessArg = "--headless --disable-gpu";
var chromeProcessArgs = new List<string>
{
Process = chromeProcess,
UserDirectory = directoryInfo,
RemoteDebuggingUri = "http://localhost:" + port
remoteDebuggingArg,
userDirectoryArg,
"--bwsi",
"--no-first-run"
};
if (headless)
chromeProcessArgs.Add(headlessArg);
var processStartInfo = new ProcessStartInfo(ChromePath, string.Join(" ", chromeProcessArgs));
var chromeProcess = Process.Start(processStartInfo);
string remoteDebuggingUrl = "http://localhost:" + port;
return new LocalChromeProcess(new Uri(remoteDebuggingUrl), () => DirectoryCleaner.Delete(directoryInfo), chromeProcess);
}
}
}
\ No newline at end of file
......@@ -81,10 +81,23 @@ namespace MasterDevs.ChromeDevTools
return SendCommand(command, cancellationToken);
}
public Task<ICommandResponse> SendAsync<T>(T parameter, CancellationToken cancellationToken)
public Task<CommandResponse<T>> SendAsync<T>(ICommand<T> parameter, CancellationToken cancellationToken)
{
var command = _commandFactory.Create(parameter);
return SendCommand(command, cancellationToken);
var task = SendCommand(command, cancellationToken);
return CastTaskResult<ICommandResponse, CommandResponse<T>>(task);
}
private Task<TDerived> CastTaskResult<TBase, TDerived>(Task<TBase> task) where TDerived: TBase
{
var tcs = new TaskCompletionSource<TDerived>();
task.ContinueWith(t => tcs.SetResult((TDerived)t.Result),
TaskContinuationOptions.OnlyOnRanToCompletion);
task.ContinueWith(t => tcs.SetException(t.Exception.InnerExceptions),
TaskContinuationOptions.OnlyOnFaulted);
task.ContinueWith(t => tcs.SetCanceled(),
TaskContinuationOptions.OnlyOnCanceled);
return tcs.Task;
}
public void Subscribe<T>(Action<T> handler) where T : class
......
......@@ -5,9 +5,9 @@ namespace MasterDevs.ChromeDevTools
{
public static class ChromeSessionExtensions
{
public static Task<ICommandResponse> SendAsync<T>(this IChromeSession session, T parameter)
public static Task<CommandResponse<T>> SendAsync<T>(this IChromeSession session, ICommand<T> parameter)
{
return session.SendAsync<T>(parameter, CancellationToken.None);
return session.SendAsync(parameter, CancellationToken.None);
}
public static Task<ICommandResponse> SendAsync<T>(this IChromeSession session)
......
......@@ -3,6 +3,11 @@ namespace MasterDevs.ChromeDevTools
{
public class ChromeSessionFactory : IChromeSessionFactory
{
public IChromeSession Create(ChromeSessionInfo sessionInfo)
{
return Create(sessionInfo.WebSocketDebuggerUrl);
}
public IChromeSession Create(string endpointUrl)
{
// Sometimes binding to localhost might resolve wrong AddressFamily, force IPv4
......
namespace MasterDevs.ChromeDevTools
{
public class ChromeSessionInfo
{
public string Description { get; set; }
public string DevtoolsFrontendUrl { get; set; }
public string Id { get; set; }
public string Title { get; set; }
public string Type { get; set; }
public string Url { get; set; }
public string WebSocketDebuggerUrl { get; set; }
}
}
\ No newline at end of file
using System;
using System.Diagnostics;
using System.IO;
using System.Threading.Tasks;
namespace MasterDevs.ChromeDevTools
{
public interface IChromeProcess : IDisposable
{
Task<string[]> GetSessions();
Task<ChromeSessionInfo[]> GetSessionInfo();
DirectoryInfo UserDirectory { get; }
Task<ChromeSessionInfo> StartNewSession();
Process Process { get; }
string RemoteDebuggingUri { get; }
Uri RemoteDebuggingUri { get; }
}
}
\ No newline at end of file
......@@ -2,6 +2,6 @@
{
public interface IChromeProcessFactory
{
IChromeProcess Create(int port);
IChromeProcess Create(int port, bool headless);
}
}
\ No newline at end of file
......@@ -4,9 +4,13 @@ using System.Threading.Tasks;
namespace MasterDevs.ChromeDevTools
{
public interface ICommand<T>
{
}
public interface IChromeSession
{
Task<ICommandResponse> SendAsync<T>(T parameter, CancellationToken cancellationToken);
Task<CommandResponse<TResponse>> SendAsync<TResponse>(ICommand<TResponse> parameter, CancellationToken cancellationToken);
Task<ICommandResponse> SendAsync<T>(CancellationToken cancellationToken);
......
using System.IO;
namespace MasterDevs.ChromeDevTools
{
public interface IDirectoryCleaner
{
void Delete(DirectoryInfo dir);
}
}
\ No newline at end of file
using System;
using System.Diagnostics;
namespace MasterDevs.ChromeDevTools
{
public class LocalChromeProcess : RemoteChromeProcess
{
public LocalChromeProcess(Uri remoteDebuggingUri, Action disposeUserDirectory, Process process)
: base(remoteDebuggingUri)
{
DisposeUserDirectory = disposeUserDirectory;
Process = process;
}
public Action DisposeUserDirectory { get; set; }
public Process Process { get; set; }
public override void Dispose()
{
base.Dispose();
Process.Kill();
Process.WaitForExit();
// Process.Close();
DisposeUserDirectory();
}
}
}
\ No newline at end of file
......@@ -60,10 +60,12 @@
</ItemGroup>
<ItemGroup>
<Compile Include="ChromeProcessFactory.cs" />
<Compile Include="ChromeProcess.cs" />
<Compile Include="IDirectoryCleaner.cs" />
<Compile Include="LocalChromeProcess.cs" />
<Compile Include="ChromeSession.cs" />
<Compile Include="ChromeSessionExtensions.cs" />
<Compile Include="ChromeSessionFactory.cs" />
<Compile Include="ChromeSessionInfo.cs" />
<Compile Include="Command.cs" />
<Compile Include="CommandAttribute.cs" />
<Compile Include="Extensions\JTokenExtensions.cs" />
......@@ -90,7 +92,9 @@
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ProtocolNameAttribute.cs" />
<Compile Include="Protocol\**\*.cs" />
<Compile Include="RemoteChromeProcess.cs" />
<Compile Include="Serialization\MessageContractResolver.cs" />
<Compile Include="StubbornDirectoryCleaner.cs" />
<Compile Include="SupportedByAttribute.cs" />
</ItemGroup>
<ItemGroup>
......
......@@ -15,5 +15,7 @@ namespace MasterDevs.ChromeDevTools.Protocol.Chrome.Accessibility{
Hidden,
HiddenRoot,
Invalid,
Keyshortcuts,
Roledescription,
}
}
......@@ -15,8 +15,18 @@ namespace MasterDevs.ChromeDevTools.Protocol.Chrome.Accessibility
/// </summary>
public string NodeId { get; set; }
/// <summary>
/// Gets or sets Whether this node is ignored for accessibility
/// </summary>
public bool Ignored { get; set; }
/// <summary>
/// Gets or sets Collection of reasons why this node is hidden.
/// </summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public AXProperty[] IgnoredReasons { get; set; }
/// <summary>
/// Gets or sets This <code>Node</code>'s role, whether explicit or implicit.
/// </summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public AXValue Role { get; set; }
/// <summary>
/// Gets or sets The accessible name for this <code>Node</code>.
......@@ -34,13 +44,19 @@ namespace MasterDevs.ChromeDevTools.Protocol.Chrome.Accessibility
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public AXValue Value { get; set; }
/// <summary>
/// Gets or sets Help.
/// Gets or sets All other properties
/// </summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public AXProperty[] Properties { get; set; }
/// <summary>
/// Gets or sets IDs for each of this node's child nodes.
/// </summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public AXValue Help { get; set; }
public string[] ChildIds { get; set; }
/// <summary>
/// Gets or sets All other properties
/// Gets or sets The backend ID for the associated DOM node, if any.
/// </summary>
public AXProperty[] Properties { get; set; }
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public long? BackendDOMNodeId { get; set; }
}
}
......@@ -10,14 +10,19 @@ namespace MasterDevs.ChromeDevTools.Protocol.Chrome.Accessibility
[SupportedBy("Chrome")]
public class AXRelatedNode
{
/// <summary>
/// Gets or sets The BackendNodeId of the related DOM node.
/// </summary>
public long BackendDOMNodeId { get; set; }
/// <summary>
/// Gets or sets The IDRef value provided, if any.
/// </summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public string Idref { get; set; }
/// <summary>
/// Gets or sets The BackendNodeId of the related node.
/// Gets or sets The text alternative of this node in the current context.
/// </summary>
public long BackendNodeId { get; set; }
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public string Text { get; set; }
}
}
......@@ -12,9 +12,11 @@ namespace MasterDevs.ChromeDevTools.Protocol.Chrome.Accessibility{
public enum AXRelationshipAttributes
{
Activedescendant,
Flowto,
Controls,
Describedby,
Details,
Errormessage,
Flowto,
Labelledby,
Owns,
}
......
......@@ -20,19 +20,14 @@ namespace MasterDevs.ChromeDevTools.Protocol.Chrome.Accessibility
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public object Value { get; set; }
/// <summary>
/// Gets or sets The related node value, if any.
/// Gets or sets One or more related nodes, if applicable.
/// </summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public AXRelatedNode RelatedNodeValue { get; set; }
/// <summary>
/// Gets or sets Multiple relted nodes, if applicable.
/// </summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public AXRelatedNode[] RelatedNodeArrayValue { get; set; }
public AXRelatedNode[] RelatedNodes { get; set; }
/// <summary>
/// Gets or sets The sources which contributed to the computation of this property.
/// </summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public AXPropertySource[] Sources { get; set; }
public AXValueSource[] Sources { get; set; }
}
}
using MasterDevs.ChromeDevTools;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using System.Runtime.Serialization;
namespace MasterDevs.ChromeDevTools.Protocol.Chrome.Accessibility{
/// <summary>
/// Enum of possible native property sources (as a subtype of a particular AXValueSourceType).
/// </summary>
[JsonConverter(typeof(StringEnumConverter))]
public enum AXValueNativeSourceType
{
Figcaption,
Label,
Labelfor,
Labelwrapped,
Legend,
Tablecaption,
Title,
Other,
}
}
......@@ -2,61 +2,57 @@ using MasterDevs.ChromeDevTools;
using Newtonsoft.Json;
using System.Collections.Generic;
namespace MasterDevs.ChromeDevTools.Protocol.Chrome.Debugger
namespace MasterDevs.ChromeDevTools.Protocol.Chrome.Accessibility
{
/// <summary>
/// Information about the promise.
/// A single source for a computed AX property.
/// </summary>
[SupportedBy("Chrome")]
public class PromiseDetails
public class AXValueSource
{
/// <summary>
/// Gets or sets Unique id of the promise.
/// Gets or sets What type of source this is.
/// </summary>
public long Id { get; set; }
public AXValueSourceType Type { get; set; }
/// <summary>
/// Gets or sets Status of the promise.
/// </summary>
public string Status { get; set; }
/// <summary>
/// Gets or sets Id of the parent promise.
/// Gets or sets The value of this property source.
/// </summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public long? ParentId { get; set; }
public AXValue Value { get; set; }
/// <summary>
/// Gets or sets Top call frame on promise creation.
/// Gets or sets The name of the relevant attribute, if any.
/// </summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public Console.CallFrame CallFrame { get; set; }
public string Attribute { get; set; }
/// <summary>
/// Gets or sets Creation time of the promise.
/// Gets or sets The value of the relevant attribute, if any.
/// </summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public double CreationTime { get; set; }
public AXValue AttributeValue { get; set; }
/// <summary>
/// Gets or sets Settlement time of the promise.
/// Gets or sets Whether this source is superseded by a higher priority source.
/// </summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public double SettlementTime { get; set; }
public bool? Superseded { get; set; }
/// <summary>
/// Gets or sets JavaScript stack trace on promise creation.
/// Gets or sets The native markup source for this value, e.g. a <label> element.
/// </summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public Console.CallFrame[] CreationStack { get; set; }
public AXValueNativeSourceType NativeSource { get; set; }
/// <summary>
/// Gets or sets JavaScript asynchronous stack trace on promise creation, if available.
/// Gets or sets The value, such as a node or node list, of the native source.
/// </summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public Console.AsyncStackTrace AsyncCreationStack { get; set; }
public AXValue NativeSourceValue { get; set; }
/// <summary>
/// Gets or sets JavaScript stack trace on promise settlement.
/// Gets or sets Whether the value for this property is invalid.
/// </summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public Console.CallFrame[] SettlementStack { get; set; }
public bool? Invalid { get; set; }
/// <summary>
/// Gets or sets JavaScript asynchronous stack trace on promise settlement, if available.
/// Gets or sets Reason for the value being invalid, if it is.
/// </summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public Console.AsyncStackTrace AsyncSettlementStack { get; set; }
public string InvalidReason { get; set; }
}
}
......@@ -9,10 +9,13 @@ namespace MasterDevs.ChromeDevTools.Protocol.Chrome.Accessibility{
/// Enum of possible property sources.
/// </summary>
[JsonConverter(typeof(StringEnumConverter))]
public enum AXPropertySourceType
public enum AXValueSourceType
{
Attribute,
Implicit,
Style,
Contents,
Placeholder,
RelatedElement,
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment