Update to ws-proxy code matching Mono repo 5e318afd
This commit is contained in:
parent
edff13f25a
commit
5a836ef0a6
|
|
@ -52,7 +52,8 @@ namespace Microsoft.AspNetCore.Builder
|
|||
}
|
||||
|
||||
var browserUri = new Uri(context.Request.Query["browser"]);
|
||||
await new MonoProxy().Run(context, browserUri);
|
||||
var ideSocket = await context.WebSockets.AcceptWebSocketAsync();
|
||||
await new MonoProxy().Run(browserUri, ideSocket);
|
||||
}
|
||||
|
||||
private static async Task DebugHome(HttpContext context)
|
||||
|
|
|
|||
|
|
@ -14,6 +14,10 @@ namespace WsProxy {
|
|||
public int Line { get; private set; }
|
||||
public int Column { get; private set; }
|
||||
|
||||
public override string ToString () {
|
||||
return $"BreakPointRequest Assembly: {Assembly} File: {File} Line: {Line} Column: {Column}";
|
||||
}
|
||||
|
||||
public static BreakPointRequest Parse (JObject args)
|
||||
{
|
||||
if (args == null)
|
||||
|
|
@ -457,13 +461,18 @@ namespace WsProxy {
|
|||
var doc = GetFileById (src_id);
|
||||
|
||||
var res = new List<SourceLocation> ();
|
||||
if (doc == null) {
|
||||
//FIXME we need to write up logging here
|
||||
Console.WriteLine ($"Could not find document {src_id}");
|
||||
return res;
|
||||
}
|
||||
|
||||
foreach (var m in doc.Methods) {
|
||||
foreach (var sp in m.methodDef.DebugInformation.SequencePoints) {
|
||||
if (Match (sp, start, end))
|
||||
res.Add (new SourceLocation (m, sp));
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
using System.Net.WebSockets;
|
||||
|
|
@ -18,10 +17,16 @@ namespace WsProxy {
|
|||
public const string START_SINGLE_STEPPING = "MONO.mono_wasm_start_single_stepping({0})";
|
||||
public const string GET_SCOPE_VARIABLES = "MONO.mono_wasm_get_variables({0}, [ {1} ])";
|
||||
public const string SET_BREAK_POINT = "MONO.mono_wasm_set_breakpoint(\"{0}\", {1}, {2})";
|
||||
public const string REMOVE_BREAK_POINT = "MONO.mono_wasm_remove_breakpoint({0})";
|
||||
public const string GET_LOADED_FILES = "MONO.mono_wasm_get_loaded_files()";
|
||||
public const string CLEAR_ALL_BREAKPOINTS = "MONO.mono_wasm_clear_all_breakpoints()";
|
||||
}
|
||||
|
||||
internal enum MonoErrorCodes {
|
||||
BpNotFound = 100000,
|
||||
}
|
||||
|
||||
|
||||
internal class MonoConstants {
|
||||
public const string RUNTIME_IS_READY = "mono_wasm_runtime_ready";
|
||||
}
|
||||
|
|
@ -156,6 +161,9 @@ namespace WsProxy {
|
|||
}
|
||||
break;
|
||||
}
|
||||
case "Debugger.removeBreakpoint": {
|
||||
return await RemoveBreakpoint (id, args, token);
|
||||
}
|
||||
|
||||
case "Debugger.resume": {
|
||||
await OnResume (token);
|
||||
|
|
@ -265,14 +273,14 @@ namespace WsProxy {
|
|||
var method = asm.GetMethodByToken (method_token);
|
||||
var location = method.GetLocationByIl (il_pos);
|
||||
|
||||
// When hitting a breakpoint on the "IncrementCount" method in the standard
|
||||
// Blazor project template, one of the stack frames is inside mscorlib.dll
|
||||
// and we get location==null for it. It will trigger a NullReferenceException
|
||||
// if we don't skip over that stack frame.
|
||||
if (location == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
// When hitting a breakpoint on the "IncrementCount" method in the standard
|
||||
// Blazor project template, one of the stack frames is inside mscorlib.dll
|
||||
// and we get location==null for it. It will trigger a NullReferenceException
|
||||
// if we don't skip over that stack frame.
|
||||
if (location == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Info ($"frame il offset: {il_pos} method token: {method_token} assembly name: {assembly_name}");
|
||||
Info ($"\tmethod {method.Name} location: {location}");
|
||||
|
|
@ -413,9 +421,9 @@ namespace WsProxy {
|
|||
|
||||
var var_list = new List<JObject> ();
|
||||
|
||||
// Trying to inspect the stack frame for DotNetDispatcher::InvokeSynchronously
|
||||
// results in a "Memory access out of bounds", causing 'values' to be null,
|
||||
// so skip returning variable values in that case.
|
||||
// Trying to inspect the stack frame for DotNetDispatcher::InvokeSynchronously
|
||||
// results in a "Memory access out of bounds", causing 'values' to be null,
|
||||
// so skip returning variable values in that case.
|
||||
for (int i = 0; values != null && i < vars.Length; ++i) {
|
||||
var_list.Add (JObject.FromObject (new {
|
||||
name = vars [i].Name,
|
||||
|
|
@ -432,7 +440,7 @@ namespace WsProxy {
|
|||
|
||||
async Task<Result> EnableBreakPoint (Breakpoint bp, CancellationToken token)
|
||||
{
|
||||
var asm_name = bp.Location.CliLocation.Method.Assembly.Name.ToLower ();
|
||||
var asm_name = bp.Location.CliLocation.Method.Assembly.Name;
|
||||
var method_token = bp.Location.CliLocation.Method.Token;
|
||||
var il_offset = bp.Location.CliLocation.Offset;
|
||||
|
||||
|
|
@ -514,10 +522,61 @@ namespace WsProxy {
|
|||
}
|
||||
}
|
||||
|
||||
async Task<bool> RemoveBreakpoint(int msg_id, JObject args, CancellationToken token) {
|
||||
var bpid = args? ["breakpointId"]?.Value<string> ();
|
||||
if (bpid?.StartsWith ("dotnet:") != true)
|
||||
return false;
|
||||
|
||||
var the_id = int.Parse (bpid.Substring ("dotnet:".Length));
|
||||
|
||||
var bp = breakpoints.FirstOrDefault (b => b.LocalId == the_id);
|
||||
if (bp == null) {
|
||||
Info ($"Could not find dotnet bp with id {the_id}");
|
||||
return false;
|
||||
}
|
||||
|
||||
breakpoints.Remove (bp);
|
||||
//FIXME verify result (and log?)
|
||||
var res = await RemoveBreakPoint (bp, token);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
async Task<Result> RemoveBreakPoint (Breakpoint bp, CancellationToken token)
|
||||
{
|
||||
var o = JObject.FromObject (new {
|
||||
expression = string.Format (MonoCommands.REMOVE_BREAK_POINT, bp.RemoteId),
|
||||
objectGroup = "mono_debugger",
|
||||
includeCommandLineAPI = false,
|
||||
silent = false,
|
||||
returnByValue = true,
|
||||
});
|
||||
|
||||
var res = await SendCommand ("Runtime.evaluate", o, token);
|
||||
var ret_code = res.Value? ["result"]? ["value"]?.Value<int> ();
|
||||
|
||||
if (ret_code.HasValue) {
|
||||
bp.RemoteId = -1;
|
||||
bp.State = BreakPointState.Disabled;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
async Task SetBreakPoint (int msg_id, BreakPointRequest req, CancellationToken token)
|
||||
{
|
||||
var bp_loc = store.FindBestBreakpoint (req);
|
||||
Info ($"BP request for '{req}' runtime ready {runtime_ready}");
|
||||
Info ($"BP request for '{req}' runtime ready {runtime_ready} location '{bp_loc}'");
|
||||
if (bp_loc == null) {
|
||||
|
||||
Info ($"Could not resolve breakpoint request: {req}");
|
||||
SendResponse (msg_id, Result.Err(JObject.FromObject (new {
|
||||
code = (int)MonoErrorCodes.BpNotFound,
|
||||
message = $"C# Breakpoint at {req} not found."
|
||||
})), token);
|
||||
return;
|
||||
}
|
||||
|
||||
Breakpoint bp = null;
|
||||
if (!runtime_ready) {
|
||||
|
|
@ -589,17 +648,8 @@ namespace WsProxy {
|
|||
var res = new StringWriter ();
|
||||
res.WriteLine ($"//dotnet:{id}");
|
||||
|
||||
try
|
||||
{
|
||||
using (var f = new StreamReader(File.Open(src_file.LocalPath, FileMode.Open)))
|
||||
{
|
||||
res.Write(f.ReadToEnd());
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
res.WriteLine($"Unable to open file {src_file.LocalPath}");
|
||||
res.WriteLine($"\nException:\n{ex}");
|
||||
using (var f = new StreamReader (File.Open (src_file.LocalPath, FileMode.Open))) {
|
||||
res.Write (f.ReadToEnd ());
|
||||
}
|
||||
|
||||
var o = JObject.FromObject (new {
|
||||
|
|
|
|||
|
|
@ -1,13 +0,0 @@
|
|||
# Running the proxy
|
||||
|
||||
Hack your way around, good luck
|
||||
|
||||
# TODO
|
||||
|
||||
Reconnects - reconsile with all existing breakpoints in the runtime
|
||||
F5 - recognize it and reset debuger state
|
||||
release object groups - we don't send for the groups we create nor do we intercept the fake ones we generate for the runtime
|
||||
Deal with the browser caching stuff across execution - cache invalidation and proper bundling of resources
|
||||
Figure out how to enable/disable debugging
|
||||
Do some target validation - right now we simply assume the debugee has a mono runtime in debug mode
|
||||
|
||||
|
|
@ -1,72 +0,0 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using System.Net.WebSockets;
|
||||
using System.Threading;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace WsProxy
|
||||
{
|
||||
|
||||
internal class Startup {
|
||||
// This method gets called by the runtime. Use this method to add services to the container.
|
||||
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
|
||||
public void ConfigureServices (IServiceCollection services)
|
||||
{
|
||||
services.AddRouting ();
|
||||
}
|
||||
|
||||
public static async Task ProxyMsg (string desc, WebSocket from, WebSocket to)
|
||||
{
|
||||
byte [] buff = new byte [4000];
|
||||
var mem = new MemoryStream ();
|
||||
while (true) {
|
||||
var result = await from.ReceiveAsync (new ArraySegment<byte> (buff), CancellationToken.None);
|
||||
if (result.MessageType == WebSocketMessageType.Close) {
|
||||
await to.SendAsync (new ArraySegment<byte> (mem.GetBuffer (), 0, (int)mem.Length), WebSocketMessageType.Close, true, CancellationToken.None);
|
||||
return;
|
||||
}
|
||||
|
||||
if (result.EndOfMessage) {
|
||||
mem.Write (buff, 0, result.Count);
|
||||
|
||||
var str = Encoding.UTF8.GetString (mem.GetBuffer (), 0, (int)mem.Length);
|
||||
|
||||
await to.SendAsync (new ArraySegment<byte> (mem.GetBuffer (), 0, (int)mem.Length), WebSocketMessageType.Text, true, CancellationToken.None);
|
||||
mem.SetLength (0);
|
||||
} else {
|
||||
mem.Write (buff, 0, result.Count);
|
||||
}
|
||||
}
|
||||
}
|
||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||
/*
|
||||
public void Configure (IApplicationBuilder app, IHostingEnvironment env)
|
||||
{
|
||||
//loggerFactory.AddConsole();
|
||||
//loggerFactory.AddDebug();
|
||||
app.UseDeveloperExceptionPage ();
|
||||
|
||||
app.UseWebSockets (); app.UseRouter (router => {
|
||||
router.MapGet ("devtools/page/{pageId}", async context => {
|
||||
if (!context.WebSockets.IsWebSocketRequest) {
|
||||
context.Response.StatusCode = 400;
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
var proxy = new MonoProxy ();
|
||||
await proxy.Run (context);
|
||||
} catch (Exception e) {
|
||||
Console.WriteLine ("got exception {0}", e);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
using System.Net.WebSockets;
|
||||
|
|
@ -115,11 +114,6 @@ namespace WsProxy {
|
|||
return Task.FromResult (false);
|
||||
}
|
||||
|
||||
Uri GetBrowserUri (string path)
|
||||
{
|
||||
return new Uri ("ws://localhost:9222" + path);
|
||||
}
|
||||
|
||||
async Task<string> ReadOne (WebSocket socket, CancellationToken token)
|
||||
{
|
||||
byte [] buff = new byte [4000];
|
||||
|
|
@ -139,8 +133,6 @@ namespace WsProxy {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
WsQueue GetQueueForSocket (WebSocket ws)
|
||||
{
|
||||
return queues.FirstOrDefault (q => q.Ws == ws);
|
||||
|
|
@ -212,8 +204,8 @@ namespace WsProxy {
|
|||
pending_ops.Add (OnCommand (res ["id"].Value<int> (), res ["method"].Value<string> (), res ["params"] as JObject, token));
|
||||
}
|
||||
|
||||
public async Task<Result> SendCommand (string method, JObject args, CancellationToken token) {
|
||||
Debug ($"sending command {method}: {args}");
|
||||
internal async Task<Result> SendCommand (string method, JObject args, CancellationToken token) {
|
||||
// Debug ($"sending command {method}: {args}");
|
||||
return await SendCommandInternal (method, args, token);
|
||||
}
|
||||
|
||||
|
|
@ -250,7 +242,7 @@ namespace WsProxy {
|
|||
Send (this.ide, o, token);
|
||||
}
|
||||
|
||||
public void SendResponse (int id, Result result, CancellationToken token)
|
||||
internal void SendResponse (int id, Result result, CancellationToken token)
|
||||
{
|
||||
//Debug ($"sending response: {id}: {result.ToJObject (id)}");
|
||||
SendResponseInternal (id, result, token);
|
||||
|
|
@ -263,11 +255,11 @@ namespace WsProxy {
|
|||
Send (this.ide, o, token);
|
||||
}
|
||||
|
||||
public async Task Run (HttpContext context, Uri browserUri)
|
||||
// , HttpContext context)
|
||||
public async Task Run (Uri browserUri, WebSocket ideSocket)
|
||||
{
|
||||
//var browserUri = GetBrowserUri (context.Request.Path.ToString ());
|
||||
Debug ("wsproxy start");
|
||||
using (this.ide = await context.WebSockets.AcceptWebSocketAsync ()) {
|
||||
using (this.ide = ideSocket) {
|
||||
Debug ("ide connected");
|
||||
queues.Add (new WsQueue (this.ide));
|
||||
using (this.browser = new ClientWebSocket ()) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue