mirror of
https://github.com/ZuneDev/ZuneUIXTools.git
synced 2026-07-27 13:11:59 -07:00
IT WORKS
This commit is contained in:
@@ -45,12 +45,6 @@ public class IrisDebugAdapterClient : IDebuggerClient, IRemoteDebuggerState, IDi
|
||||
public event Action<string> DispatcherStep;
|
||||
public event Action<IDebuggerState, object> Connected;
|
||||
|
||||
public IrisDebugAdapterClient(Stream inputStream, Stream outputStream)
|
||||
{
|
||||
_inputStream = inputStream;
|
||||
_outputStream = outputStream;
|
||||
}
|
||||
|
||||
public IrisDebugAdapterClient(string connectionString)
|
||||
{
|
||||
ConnectionString = connectionString;
|
||||
@@ -58,20 +52,14 @@ public class IrisDebugAdapterClient : IDebuggerClient, IRemoteDebuggerState, IDi
|
||||
|
||||
public async Task StartAsync()
|
||||
{
|
||||
if (ConnectionString is not null)
|
||||
{
|
||||
ConnectionStringHelper.ConnectToString(ConnectionString, out _inputStream, out _outputStream);
|
||||
}
|
||||
|
||||
_debugAdapter = await DebugAdapterClient.From(options =>
|
||||
{
|
||||
options
|
||||
.WithInput(_inputStream)
|
||||
.WithOutput(_outputStream)
|
||||
.OnInitialize((server, _, cancellationToken) =>
|
||||
.OnInitialize(async (server, _, cancellationToken) =>
|
||||
{
|
||||
var __ = server.RequestDebugAdapterInitialize(new());
|
||||
return Task.CompletedTask;
|
||||
//await server.RequestDebugAdapterInitialize(new(), default);
|
||||
})
|
||||
.OnInitialized((_, _, response, _) =>
|
||||
{
|
||||
@@ -90,6 +78,9 @@ public class IrisDebugAdapterClient : IDebuggerClient, IRemoteDebuggerState, IDi
|
||||
})
|
||||
;
|
||||
}).ConfigureAwait(false);
|
||||
|
||||
var tcs = new TaskCompletionSource<object>();
|
||||
await tcs.Task;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
@@ -143,6 +134,11 @@ public class IrisDebugAdapterClient : IDebuggerClient, IRemoteDebuggerState, IDi
|
||||
|
||||
public void Start()
|
||||
{
|
||||
if (ConnectionString is not null)
|
||||
{
|
||||
ConnectionStringHelper.ConnectToString(ConnectionString, out _inputStream, out _outputStream);
|
||||
}
|
||||
|
||||
System.Threading.Thread clientThread = new(() =>
|
||||
{
|
||||
_ = StartAsync();
|
||||
|
||||
@@ -65,8 +65,6 @@ public class IrisDebugAdapterServer : IDebuggerServer, IRemoteDebuggerState, IDi
|
||||
/// <returns>A task that completes when the server is ready.</returns>
|
||||
public async Task StartAsync()
|
||||
{
|
||||
ConnectionStringHelper.CreateFromString(ConnectionString, out _inputStream, out _outputStream);
|
||||
|
||||
Server = DebugAdapterServer.Create(options =>
|
||||
{
|
||||
// We need to let the PowerShell Context Service know that we are in a debug session
|
||||
@@ -103,29 +101,13 @@ public class IrisDebugAdapterServer : IDebuggerServer, IRemoteDebuggerState, IDi
|
||||
// https://microsoft.github.io/debug-adapter-protocol/specification#Requests_Initialize
|
||||
.OnInitialize(async (server, _, cancellationToken) =>
|
||||
{
|
||||
// Start the host if not already started, and enable debug mode (required
|
||||
// for remote debugging).
|
||||
//
|
||||
// TODO: We might need to fill in HostStartOptions here.
|
||||
//_startedPses = !await _psesHost.TryStartAsync(new HostStartOptions(), cancellationToken).ConfigureAwait(false);
|
||||
//_psesHost.DebugContext.EnableDebugMode();
|
||||
|
||||
// Clear any existing breakpoints before proceeding.
|
||||
//BreakpointService breakpointService = server.GetService<BreakpointService>();
|
||||
//await breakpointService.RemoveAllBreakpointsAsync().ConfigureAwait(false);
|
||||
System.Diagnostics.Debug.WriteLine("SERVER: OnInitialize called");
|
||||
Console.WriteLine("SERVER: OnInitialize called");
|
||||
})
|
||||
// The OnInitialized delegate gets run right before the server responds to the _Initialize_ request:
|
||||
// https://microsoft.github.io/debug-adapter-protocol/specification#Requests_Initialize
|
||||
.OnInitialized((_, _, response, _) =>
|
||||
{
|
||||
//response.SupportsConditionalBreakpoints = true;
|
||||
//response.SupportsConfigurationDoneRequest = true;
|
||||
//response.SupportsFunctionBreakpoints = true;
|
||||
//response.SupportsHitConditionalBreakpoints = true;
|
||||
//response.SupportsLogPoints = true;
|
||||
//response.SupportsSetVariable = true;
|
||||
//response.SupportsDelayedStackTraceLoading = true;
|
||||
|
||||
System.Diagnostics.Debug.WriteLine("SERVER: OnInitialized called");
|
||||
Console.WriteLine("SERVER: OnInitialized called");
|
||||
return Task.CompletedTask;
|
||||
})
|
||||
;
|
||||
@@ -134,6 +116,8 @@ public class IrisDebugAdapterServer : IDebuggerServer, IRemoteDebuggerState, IDi
|
||||
await Server.Initialize(default).ConfigureAwait(false);
|
||||
|
||||
Connected?.Invoke(this, EventArgs.Empty);
|
||||
|
||||
await WaitForShutdownAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
@@ -179,6 +163,8 @@ public class IrisDebugAdapterServer : IDebuggerServer, IRemoteDebuggerState, IDi
|
||||
|
||||
public void Start()
|
||||
{
|
||||
ConnectionStringHelper.CreateFromString(ConnectionString, out _inputStream, out _outputStream);
|
||||
|
||||
Thread serverThread = new(() =>
|
||||
{
|
||||
_ = StartAsync();
|
||||
|
||||
@@ -1,33 +1,81 @@
|
||||
using System.IO;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.IO.Pipes;
|
||||
using System.Text;
|
||||
|
||||
namespace Microsoft.Iris.DebugAdapter;
|
||||
|
||||
public static class ConnectionStringHelper
|
||||
{
|
||||
private const string PIPE_PREFIX = @"\\.\pipe\";
|
||||
|
||||
public static void CreateFromString(string connectionString, out Stream input, out Stream output)
|
||||
{
|
||||
// TODO: Support other transports
|
||||
var pipeName = connectionString.StartsWith(PIPE_PREFIX)
|
||||
? connectionString
|
||||
: NamedPipeUtils.GenerateValidNamedPipeName();
|
||||
if (NamedPipeUtils.TryGetPipeName(connectionString, out var pipeName))
|
||||
{
|
||||
var pipeToClient = NamedPipeUtils.CreateNamedPipe(pipeName + "_ToClient", PipeDirection.Out);
|
||||
var pipeFromClient = NamedPipeUtils.CreateNamedPipe(pipeName + "_FromClient", PipeDirection.In);
|
||||
|
||||
var pipe = NamedPipeUtils.CreateNamedPipe(pipeName, PipeDirection.InOut);
|
||||
pipe.WaitForConnection();
|
||||
pipeToClient.WaitForConnection();
|
||||
pipeFromClient.WaitForConnection();
|
||||
|
||||
output = input = pipe;
|
||||
var loggingInputStream = new LoggingStream(pipeFromClient, LoggingStream_OnRead, LoggingStream_OnWrite);
|
||||
var loggingOutputStream = new LoggingStream(pipeToClient, LoggingStream_OnRead, LoggingStream_OnWrite);
|
||||
|
||||
input = loggingInputStream;
|
||||
output = loggingOutputStream;
|
||||
return;
|
||||
}
|
||||
else if (Uri.TryCreate(connectionString, UriKind.Absolute, out var connectionUri))
|
||||
{
|
||||
if (connectionUri.Scheme == "tcp")
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
throw new ArgumentException("Invalid connection string", nameof(connectionString));
|
||||
}
|
||||
|
||||
private static void LoggingStream_OnWrite(object? sender, ArraySegment<byte> obj)
|
||||
{
|
||||
try
|
||||
{
|
||||
var str = Encoding.UTF8.GetString(obj.Array!, obj.Offset, obj.Count);
|
||||
System.Diagnostics.Debug.WriteLine($"Sent `{str}`");
|
||||
}
|
||||
catch
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine($"Sent {obj.Count} bytes");
|
||||
}
|
||||
}
|
||||
|
||||
private static void LoggingStream_OnRead(object? sender, ArraySegment<byte> obj)
|
||||
{
|
||||
try
|
||||
{
|
||||
var str = Encoding.UTF8.GetString(obj.Array!, obj.Offset, obj.Count);
|
||||
System.Diagnostics.Debug.WriteLine($"Received `{str}`");
|
||||
}
|
||||
catch
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine($"Received {obj.Count} bytes");
|
||||
}
|
||||
}
|
||||
|
||||
public static void ConnectToString(string connectionString, out Stream input, out Stream output)
|
||||
{
|
||||
if (!connectionString.StartsWith(PIPE_PREFIX))
|
||||
throw new System.NotSupportedException();
|
||||
var pipeName = NamedPipeUtils.GetPipeName(connectionString);
|
||||
|
||||
var pipe = new NamedPipeClientStream(connectionString);
|
||||
pipe.Connect();
|
||||
var pipeToServer = new NamedPipeClientStream(".", pipeName + "_FromClient", PipeDirection.Out, PipeOptions.Asynchronous);
|
||||
var pipeFromServer = new NamedPipeClientStream(".", pipeName + "_ToClient", PipeDirection.In, PipeOptions.Asynchronous);
|
||||
|
||||
output = input = pipe;
|
||||
pipeToServer.Connect();
|
||||
pipeFromServer.Connect();
|
||||
|
||||
var loggingInputStream = new LoggingStream(pipeFromServer, LoggingStream_OnRead, LoggingStream_OnWrite);
|
||||
var loggingOutputStream = new LoggingStream(pipeToServer, LoggingStream_OnRead, LoggingStream_OnWrite);
|
||||
|
||||
input = loggingInputStream;
|
||||
output = loggingOutputStream;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.Iris.DebugAdapter;
|
||||
|
||||
public class LoggingStream(Stream stream) : Stream
|
||||
{
|
||||
public LoggingStream(Stream stream, EventHandler<ArraySegment<byte>>? onRead, EventHandler<ArraySegment<byte>>? onWrite)
|
||||
: this(stream)
|
||||
{
|
||||
OnRead += onRead;
|
||||
OnWrite += onWrite;
|
||||
}
|
||||
|
||||
public Stream InnerStream { get; } = stream;
|
||||
|
||||
public event EventHandler<ArraySegment<byte>>? OnRead;
|
||||
public event EventHandler<ArraySegment<byte>>? OnWrite;
|
||||
|
||||
public override bool CanRead => InnerStream.CanRead;
|
||||
|
||||
public override bool CanSeek => InnerStream.CanSeek;
|
||||
|
||||
public override bool CanWrite => InnerStream.CanWrite;
|
||||
|
||||
public override long Length => InnerStream.Length;
|
||||
|
||||
public override long Position { get => InnerStream.Position; set => InnerStream.Position = value; }
|
||||
|
||||
public override void Flush()
|
||||
{
|
||||
InnerStream.Flush();
|
||||
}
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
var length = InnerStream.Read(buffer, offset, count);
|
||||
OnRead?.Invoke(this, new(buffer, offset, length));
|
||||
return length;
|
||||
}
|
||||
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
return InnerStream.Seek(offset, origin);
|
||||
}
|
||||
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
InnerStream.SetLength(value);
|
||||
}
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
OnWrite?.Invoke(this, new(buffer, offset, count));
|
||||
InnerStream.Write(buffer, offset, count);
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
InnerStream.Dispose();
|
||||
}
|
||||
|
||||
#if NET6_0_OR_GREATER
|
||||
public override ValueTask DisposeAsync() => InnerStream.DisposeAsync();
|
||||
#endif
|
||||
}
|
||||
@@ -4,6 +4,8 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO.Pipes;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
|
||||
|
||||
#if !NET
|
||||
@@ -20,6 +22,8 @@ namespace Microsoft.Iris.DebugAdapter;
|
||||
/// </summary>
|
||||
public static class NamedPipeUtils
|
||||
{
|
||||
private const string PIPE_PREFIX = @"\\.\pipe\";
|
||||
|
||||
#if !NET
|
||||
// .NET Framework requires the buffer size to be specified
|
||||
private const int PipeBufferSize = 1024;
|
||||
@@ -35,7 +39,7 @@ public static class NamedPipeUtils
|
||||
direction: pipeDirection,
|
||||
maxNumberOfServerInstances: 1,
|
||||
transmissionMode: PipeTransmissionMode.Byte,
|
||||
options: PipeOptions.CurrentUserOnly | PipeOptions.Asynchronous);
|
||||
options: PipeOptions.Asynchronous);
|
||||
#else
|
||||
|
||||
// In .NET Framework, we must manually ACL the named pipes we create
|
||||
@@ -116,6 +120,25 @@ public static class NamedPipeUtils
|
||||
throw new IOException("Unable to create named pipe; no available names");
|
||||
}
|
||||
|
||||
public static bool TryGetPipeName(string pipePath, [NotNullWhen(true)] out string? pipeName)
|
||||
{
|
||||
if (!IsPipeNameValid(pipePath))
|
||||
{
|
||||
pipeName = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
pipeName = pipePath[PIPE_PREFIX.Length..];
|
||||
return true;
|
||||
}
|
||||
|
||||
public static string GetPipeName(string pipePath)
|
||||
{
|
||||
if (!TryGetPipeName(pipePath, out var pipeName))
|
||||
throw new System.ArgumentException(nameof(pipePath));
|
||||
return pipeName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validate that a named pipe file name is a legitimate named pipe file name and is not already in use.
|
||||
/// </summary>
|
||||
|
||||
Reference in New Issue
Block a user