Files
MicrosoftIris/UIX/Microsoft/Iris/Debug/SystemNet/NetDebuggerServer.cs
T

140 lines
4.1 KiB
C#

using Microsoft.Iris.Debug.Data;
using System;
using System.Collections.Concurrent;
using System.Net.Sockets;
using System.Runtime.Serialization;
namespace Microsoft.Iris.Debug.SystemNet;
internal class NetDebuggerServer : IDebuggerServer, IDisposable
{
public static IDebuggerServer Current { get; private set; }
private readonly ConcurrentQueue<byte[]> _outQueue = new();
private readonly TcpListener _listener;
private readonly IFormatter _formatter;
private Socket _socket;
private bool _disposed = false;
private InterpreterCommand _uibCommand = InterpreterCommand.Continue;
public Uri ConnectionUri { get; }
public InterpreterCommand DebuggerCommand
{
get => _uibCommand;
set
{
var data = new[] { (byte)value };
QueueDebuggerMessage(new(0, DebuggerMessageType.InterpreterCommand, data));
_uibCommand = value;
}
}
public NetDebuggerServer(string connectionUri) : this(new Uri(connectionUri))
{
}
public NetDebuggerServer(Uri connectionUri)
{
ConnectionUri = connectionUri ?? DebugRemoting.DEFAULT_TCP_URI;
_listener = TcpListener.Create(connectionUri.Port);
_listener.Start();
_formatter = DebugRemoting.CreateBsonFormatter();
System.Threading.Thread connectThread = new(ConnectLoop) { IsBackground = true };
connectThread.Start();
Current = this;
}
public void LogInterpreterDecode(object context, InterpreterInstruction instruction)
{
QueueDebuggerMessage(new(0, DebuggerMessageType.InterpreterDecode, instruction.Serialize(_formatter)));
}
public void LogInterpreterExecute(object context, InterpreterEntry entry)
{
QueueDebuggerMessage(new(0, DebuggerMessageType.InterpreterExecute, entry.Serialize(_formatter)));
}
public void LogDispatcher(string message)
{
QueueDebuggerMessage(new(0, DebuggerMessageType.DispatcherStep, message));
}
public void Dispose()
{
if (_disposed)
return;
_disposed = true;
_listener.Stop();
_socket?.Dispose();
}
private void QueueDebuggerMessage(DebuggerMessageFrame frame)
{
_outQueue.Enqueue(frame.ToBytes());
}
private void MessageReceiveLoop()
{
while (_socket.Connected)
{
DebuggerMessageFrame frame;
while ((frame = DebugRemoting.ReceiveDebuggerMessage(_socket)) == null)
if (!_socket.Connected) return;
switch (frame.Type)
{
case DebuggerMessageType.UpdateBreakpoint:
var breakpoint = frame.DeserializeData<Breakpoint>(_formatter);
if (breakpoint.Enabled)
Application.DebugSettings.Breakpoints.Add(breakpoint);
else
Application.DebugSettings.Breakpoints.Remove(breakpoint);
break;
case DebuggerMessageType.InterpreterCommand:
_uibCommand = (InterpreterCommand)frame.Data[0];
break;
default:
Trace.WriteLine(TraceCategory.MarkupDebug, "Recieved unknown debugger message of type '{0}'.", frame.Type);
break;
}
}
}
private void MessageSendLoop()
{
while (_socket.Connected)
{
byte[] frameBytes;
while (!_outQueue.TryDequeue(out frameBytes)) ;
try
{
_socket.Send(BitConverter.GetBytes(frameBytes.Length));
_socket.Send(frameBytes);
}
catch (SocketException) { }
}
}
private void ConnectLoop()
{
while (!_listener.Pending())
if (_disposed) return;
_socket = _listener.AcceptSocket();
System.Threading.Thread receiveThread = new(MessageReceiveLoop) { IsBackground = true };
System.Threading.Thread sendThread = new(MessageSendLoop) { IsBackground = true };
receiveThread.Start();
sendThread.Start();
}
}