Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/mono.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLarry Ewing <lewing@microsoft.com>2020-01-30 02:05:43 +0300
committerGitHub <noreply@github.com>2020-01-30 02:05:43 +0300
commitb4cfcd5c5e3a8bcd5da5aee78f75bbc698d272cd (patch)
tree15491a3f2dd78aa160158f7ed333a00b714875a8
parent5e3e34220c0e2bb95096318e83bec2d1d9ebd330 (diff)
parentc75a1364c5d116049e0714817a93c0cde4fa5674 (diff)
Merge pull request #18602 from lewing/wasm-debug-inspect
[wasm][debugger] Initial support for proxying flat sessions
-rw-r--r--mono/mini/mini-wasm-debugger.c4
-rw-r--r--sdks/wasm/DebuggerTestSuite/Support.cs4
-rw-r--r--sdks/wasm/DebuggerTestSuite/Tests.cs2
-rw-r--r--sdks/wasm/Mono.WebAssembly.DebuggerProxy/DebugStore.cs108
-rw-r--r--sdks/wasm/Mono.WebAssembly.DebuggerProxy/DevToolsClient.cs (renamed from sdks/wasm/Mono.WebAssembly.DebuggerProxy/WsClient.cs)18
-rw-r--r--sdks/wasm/Mono.WebAssembly.DebuggerProxy/DevToolsProxy.cs (renamed from sdks/wasm/Mono.WebAssembly.DebuggerProxy/WsProxy.cs)153
-rw-r--r--sdks/wasm/Mono.WebAssembly.DebuggerProxy/InspectorClient.cs6
-rw-r--r--sdks/wasm/Mono.WebAssembly.DebuggerProxy/MonoProxy.cs218
-rw-r--r--sdks/wasm/ProxyDriver/Program.cs2
-rw-r--r--sdks/wasm/ProxyDriver/Startup.cs56
-rw-r--r--sdks/wasm/ProxyDriver/TestHarnessStartup.cs5
11 files changed, 317 insertions, 259 deletions
diff --git a/mono/mini/mini-wasm-debugger.c b/mono/mini/mini-wasm-debugger.c
index f1e4707c944..665bad11f39 100644
--- a/mono/mini/mini-wasm-debugger.c
+++ b/mono/mini/mini-wasm-debugger.c
@@ -371,14 +371,14 @@ mono_wasm_setup_single_step (int kind)
depth = STEP_DEPTH_OVER;
break;
default:
- g_error ("dunno step kind %d", kind);
+ g_error ("[dbg] unknown step kind %d", kind);
}
DbgEngineErrorCode err = mono_de_ss_create (THREAD_TO_INTERNAL (mono_thread_current ()), size, depth, filter, req);
if (err != DE_ERR_NONE) {
DEBUG_PRINTF (1, "[dbg] Failed to setup single step request");
}
- printf ("ss is in place, now ahat?\n");
+ DEBUG_PRINTF (1, "[dbg] single step is in place, now what?\n");
}
EMSCRIPTEN_KEEPALIVE void
diff --git a/sdks/wasm/DebuggerTestSuite/Support.cs b/sdks/wasm/DebuggerTestSuite/Support.cs
index 106fbe85d72..8c5a251eaa4 100644
--- a/sdks/wasm/DebuggerTestSuite/Support.cs
+++ b/sdks/wasm/DebuggerTestSuite/Support.cs
@@ -8,7 +8,7 @@ using System.IO;
using System.Text;
using System.Collections.Generic;
-using WsProxy;
+using WebAssembly.Net.Debugging;
using Newtonsoft.Json.Linq;
using Xunit;
@@ -133,7 +133,7 @@ namespace DebuggerTests
}
public DebuggerTestBase (string driver = "debugger-driver.html") {
- startTask = WsProxy.TestHarnessProxy.Start (FindChromePath (), FindTestPath (), driver);
+ startTask = TestHarnessProxy.Start (FindChromePath (), FindTestPath (), driver);
}
public Task Ready ()
diff --git a/sdks/wasm/DebuggerTestSuite/Tests.cs b/sdks/wasm/DebuggerTestSuite/Tests.cs
index d21ac9ee302..c432806ae11 100644
--- a/sdks/wasm/DebuggerTestSuite/Tests.cs
+++ b/sdks/wasm/DebuggerTestSuite/Tests.cs
@@ -10,7 +10,7 @@ using System.Collections.Generic;
using Newtonsoft.Json.Linq;
using Xunit;
-using WsProxy;
+using WebAssembly.Net.Debugging;
namespace DebuggerTests
{
diff --git a/sdks/wasm/Mono.WebAssembly.DebuggerProxy/DebugStore.cs b/sdks/wasm/Mono.WebAssembly.DebuggerProxy/DebugStore.cs
index f1b1bebc00b..520b61653ce 100644
--- a/sdks/wasm/Mono.WebAssembly.DebuggerProxy/DebugStore.cs
+++ b/sdks/wasm/Mono.WebAssembly.DebuggerProxy/DebugStore.cs
@@ -9,9 +9,10 @@ using System.Net.Http;
using Mono.Cecil.Pdb;
using Newtonsoft.Json;
using System.Text.RegularExpressions;
+using System.Threading.Tasks;
using System.Threading;
-namespace WsProxy {
+namespace WebAssembly.Net.Debugging {
internal class BreakPointRequest {
public string Assembly { get; private set; }
public string File { get; private set; }
@@ -32,7 +33,7 @@ namespace WsProxy {
var url = args? ["url"]?.Value<string> ();
if (url == null) {
var urlRegex = args?["urlRegex"].Value<string>();
- var sourceFile = store.GetFileByUrlRegex (urlRegex);
+ var sourceFile = store?.GetFileByUrlRegex (urlRegex);
url = sourceFile?.DotNetUrl;
}
@@ -75,7 +76,6 @@ namespace WsProxy {
}
}
-
internal class VarInfo {
public VarInfo (VariableDebugInformation v)
{
@@ -88,10 +88,10 @@ namespace WsProxy {
this.Name = p.Name;
this.Index = (p.Index + 1) * -1;
}
+
public string Name { get; private set; }
public int Index { get; private set; }
-
public override string ToString ()
{
return $"(var-info [{Index}] '{Name}')";
@@ -100,18 +100,14 @@ namespace WsProxy {
internal class CliLocation {
-
- private MethodInfo method;
- private int offset;
-
public CliLocation (MethodInfo method, int offset)
{
- this.method = method;
- this.offset = offset;
+ Method = method;
+ Offset = offset;
}
- public MethodInfo Method { get => method; }
- public int Offset { get => offset; }
+ public MethodInfo Method { get; private set; }
+ public int Offset { get; private set; }
}
@@ -285,7 +281,6 @@ namespace WsProxy {
.Where (v => !v.IsDebuggerHidden)
.Select (v => new VarInfo (v)));
-
return res.ToArray ();
}
}
@@ -297,20 +292,21 @@ namespace WsProxy {
Dictionary<int, MethodInfo> methods = new Dictionary<int, MethodInfo> ();
Dictionary<string, string> sourceLinkMappings = new Dictionary<string, string>();
readonly List<SourceFile> sources = new List<SourceFile>();
+ internal string Url { get; private set; }
- public AssemblyInfo (byte[] assembly, byte[] pdb)
+ public AssemblyInfo (string url, byte[] assembly, byte[] pdb)
{
lock (typeof (AssemblyInfo)) {
this.id = ++next_id;
}
try {
+ Url = url;
ReaderParameters rp = new ReaderParameters (/*ReadingMode.Immediate*/);
- if (pdb != null) {
- rp.ReadSymbols = true;
- rp.SymbolReaderProvider = new PortablePdbReaderProvider ();
+ rp.ReadSymbols = true;
+ rp.SymbolReaderProvider = new PdbReaderProvider ();
+ if (pdb != null)
rp.SymbolStream = new MemoryStream (pdb);
- }
rp.ReadingMode = ReadingMode.Immediate;
rp.InMemory = true;
@@ -318,13 +314,16 @@ namespace WsProxy {
this.image = ModuleDefinition.ReadModule (new MemoryStream (assembly), rp);
} catch (BadImageFormatException ex) {
Console.WriteLine ($"Failed to read assembly as portable PDB: {ex.Message}");
+ } catch (ArgumentNullException) {
+ if (pdb != null)
+ throw;
}
if (this.image == null) {
ReaderParameters rp = new ReaderParameters (/*ReadingMode.Immediate*/);
if (pdb != null) {
rp.ReadSymbols = true;
- rp.SymbolReaderProvider = new NativePdbReaderProvider ();
+ rp.SymbolReaderProvider = new PdbReaderProvider ();
rp.SymbolStream = new MemoryStream (pdb);
}
@@ -496,73 +495,70 @@ namespace WsProxy {
internal class DebugStore {
MonoProxy proxy;
List<AssemblyInfo> assemblies = new List<AssemblyInfo> ();
+ HttpClient client = new HttpClient ();
- public DebugStore (MonoProxy proxy)
- {
- this.proxy = proxy;
+ class DebugItem {
+ public string Url { get; set; }
+ public Task<byte[][]> Data { get; set; }
}
- internal void Initialize (string[] loaded_files, CancellationToken token)
+ public async Task Load (SessionId sessionId, string [] loaded_files, CancellationToken token)
{
- bool MatchPdb (string asm, string pdb)
- {
- return Path.ChangeExtension (asm, "pdb") == pdb;
- }
+ static bool MatchPdb (string asm, string pdb)
+ => Path.ChangeExtension (asm, "pdb") == pdb;
var asm_files = new List<string> ();
var pdb_files = new List<string> ();
- foreach (var f in loaded_files) {
- var file_name = f;
+ foreach (var file_name in loaded_files) {
if (file_name.EndsWith (".pdb", StringComparison.OrdinalIgnoreCase))
pdb_files.Add (file_name);
else
asm_files.Add (file_name);
}
- //FIXME make this parallel
- foreach (var p in asm_files) {
+ List<DebugItem> steps = new List<DebugItem> ();
+ foreach (var url in asm_files) {
try {
- var pdb = pdb_files.FirstOrDefault (n => MatchPdb (p, n));
- HttpClient h = new HttpClient ();
- var assembly_bytes = h.GetByteArrayAsync (p).Result;
- byte [] pdb_bytes = null;
- if (pdb != null)
- pdb_bytes = h.GetByteArrayAsync (pdb).Result;
-
- this.assemblies.Add (new AssemblyInfo (assembly_bytes, pdb_bytes));
+ var pdb = pdb_files.FirstOrDefault (n => MatchPdb (url, n));
+ steps.Add (
+ new DebugItem {
+ Url = url,
+ Data = Task.WhenAll (client.GetByteArrayAsync (url), pdb != null ? client.GetByteArrayAsync (pdb) : Task.FromResult<byte []> (null))
+ });
} catch (Exception e) {
- Console.WriteLine ($"Failed to read {p} ({e.Message})");
+ Console.WriteLine ($"Failed to read {url} ({e.Message})");
var o = JObject.FromObject (new {
entry = new {
source = "other",
level = "warning",
- text = $"Failed to read {p} ({e.Message})"
+ text = $"Failed to read {url} ({e.Message})"
}
});
- proxy.SendEvent ("Log.entryAdded", o, token);
+ proxy.SendEvent (sessionId, "Log.entryAdded", o, token);
+
}
}
- }
- public IEnumerable<SourceFile> AllSources ()
- {
- foreach (var a in assemblies) {
- foreach (var s in a.Sources)
- yield return s;
+ foreach (var step in steps) {
+ try {
+ var bytes = await step.Data;
+ assemblies.Add (new AssemblyInfo (step.Url, bytes[0], bytes[1]));
+ } catch (Exception e) {
+ Console.WriteLine ($"Failed to Load {step.Url} ({e.Message})");
+ }
}
}
+ public IEnumerable<SourceFile> AllSources ()
+ => assemblies.SelectMany (a => a.Sources);
+
public SourceFile GetFileById (SourceId id)
- {
- return AllSources ().FirstOrDefault (f => f.SourceId.Equals (id));
- }
+ => AllSources ().FirstOrDefault (f => f.SourceId.Equals (id));
public AssemblyInfo GetAssemblyByName (string name)
- {
- return assemblies.FirstOrDefault (a => a.Name.Equals (name, StringComparison.InvariantCultureIgnoreCase));
- }
+ => assemblies.FirstOrDefault (a => a.Name.Equals (name, StringComparison.InvariantCultureIgnoreCase));
- /*
+ /*
V8 uses zero based indexing for both line and column.
PPDBs uses one based indexing for both line and column.
*/
@@ -615,7 +611,7 @@ namespace WsProxy {
PPDBs uses one based indexing for both line and column.
*/
static bool Match (SequencePoint sp, int line, int column)
- {
+ {
var bp = (line: line + 1, column: column + 1);
if (sp.StartLine > bp.line || sp.EndLine < bp.line)
diff --git a/sdks/wasm/Mono.WebAssembly.DebuggerProxy/WsClient.cs b/sdks/wasm/Mono.WebAssembly.DebuggerProxy/DevToolsClient.cs
index 26f73068e4b..92272f9ae34 100644
--- a/sdks/wasm/Mono.WebAssembly.DebuggerProxy/WsClient.cs
+++ b/sdks/wasm/Mono.WebAssembly.DebuggerProxy/DevToolsClient.cs
@@ -1,7 +1,5 @@
using System;
-using System.Linq;
using System.Threading.Tasks;
-using Newtonsoft.Json.Linq;
using System.Net.WebSockets;
using System.Threading;
@@ -9,18 +7,18 @@ using System.IO;
using System.Text;
using System.Collections.Generic;
-namespace WsProxy {
- public class WsClient: IDisposable {
+namespace WebAssembly.Net.Debugging {
+ public class DevToolsClient: IDisposable {
ClientWebSocket socket;
List<Task> pending_ops = new List<Task> ();
TaskCompletionSource<bool> side_exit = new TaskCompletionSource<bool> ();
List<byte []> pending_writes = new List<byte []> ();
Task current_write;
- public WsClient () {
+ public DevToolsClient () {
}
- ~WsClient() {
+ ~DevToolsClient() {
Dispose(false);
}
@@ -28,7 +26,6 @@ namespace WsProxy {
Dispose(true);
}
-
public async Task Close (CancellationToken cancellationToken)
{
if (socket.State == WebSocketState.Open)
@@ -133,5 +130,10 @@ namespace WsProxy {
return false;
}
+
+ protected virtual void Log (string priority, string msg)
+ {
+ //
+ }
}
-}
+}
diff --git a/sdks/wasm/Mono.WebAssembly.DebuggerProxy/WsProxy.cs b/sdks/wasm/Mono.WebAssembly.DebuggerProxy/DevToolsProxy.cs
index 3d90be7b03b..750e037e4a7 100644
--- a/sdks/wasm/Mono.WebAssembly.DebuggerProxy/WsProxy.cs
+++ b/sdks/wasm/Mono.WebAssembly.DebuggerProxy/DevToolsProxy.cs
@@ -9,7 +9,14 @@ using System.IO;
using System.Text;
using System.Collections.Generic;
-namespace WsProxy {
+namespace WebAssembly.Net.Debugging {
+ public class SessionId {
+ public string sessionId;
+ }
+
+ public class MessageId : SessionId {
+ public int id;
+ }
public struct Result {
public JObject Value { get; private set; }
@@ -26,6 +33,7 @@ namespace WsProxy {
public static Result FromJson (JObject obj)
{
+ //Log ("protocol", $"from result: {obj}");
return new Result (obj ["result"] as JObject, obj ["error"] as JObject);
}
@@ -39,28 +47,30 @@ namespace WsProxy {
return new Result (null, err);
}
- public JObject ToJObject (int id) {
+ public JObject ToJObject (MessageId target) {
if (IsOk) {
return JObject.FromObject (new {
- id = id,
+ target.id,
+ target.sessionId,
result = Value
});
} else {
return JObject.FromObject (new {
- id = id,
+ target.id,
+ target.sessionId,
error = Error
});
}
}
}
- class WsQueue {
+ class DevToolsQueue {
Task current_send;
List<byte []> pending;
public WebSocket Ws { get; private set; }
public Task CurrentSend { get { return current_send; } }
- public WsQueue (WebSocket sock)
+ public DevToolsQueue (WebSocket sock)
{
this.Ws = sock;
pending = new List<byte []> ();
@@ -71,7 +81,7 @@ namespace WsProxy {
pending.Add (bytes);
if (pending.Count == 1) {
if (current_send != null)
- throw new Exception ("WTF, current_send MUST BE NULL IF THERE'S no pending send");
+ throw new Exception ("current_send MUST BE NULL IF THERE'S no pending send");
//Console.WriteLine ("sending {0} bytes", bytes.Length);
current_send = Ws.SendAsync (new ArraySegment<byte> (bytes), WebSocketMessageType.Text, true, token);
return current_send;
@@ -86,7 +96,7 @@ namespace WsProxy {
if (pending.Count > 0) {
if (current_send != null)
- throw new Exception ("WTF, current_send MUST BE NULL IF THERE'S no pending send");
+ throw new Exception ("current_send MUST BE NULL IF THERE'S no pending send");
//Console.WriteLine ("sending more {0} bytes", pending[0].Length);
current_send = Ws.SendAsync (new ArraySegment<byte> (pending [0]), WebSocketMessageType.Text, true, token);
return current_send;
@@ -95,22 +105,22 @@ namespace WsProxy {
}
}
- public class WsProxy {
+ public class DevToolsProxy {
TaskCompletionSource<bool> side_exception = new TaskCompletionSource<bool> ();
TaskCompletionSource<bool> client_initiated_close = new TaskCompletionSource<bool> ();
- List<(int, TaskCompletionSource<Result>)> pending_cmds = new List<(int, TaskCompletionSource<Result>)> ();
+ List<(MessageId, TaskCompletionSource<Result>)> pending_cmds = new List<(MessageId, TaskCompletionSource<Result>)> ();
ClientWebSocket browser;
WebSocket ide;
int next_cmd_id;
List<Task> pending_ops = new List<Task> ();
- List<WsQueue> queues = new List<WsQueue> ();
+ List<DevToolsQueue> queues = new List<DevToolsQueue> ();
- protected virtual Task<bool> AcceptEvent (string method, JObject args, CancellationToken token)
+ protected virtual Task<bool> AcceptEvent (SessionId sessionId, string method, JObject args, CancellationToken token)
{
return Task.FromResult (false);
}
- protected virtual Task<bool> AcceptCommand (int id, string method, JObject args, CancellationToken token)
+ protected virtual Task<bool> AcceptCommand (MessageId id, string method, JObject args, CancellationToken token)
{
return Task.FromResult (false);
}
@@ -122,7 +132,7 @@ namespace WsProxy {
while (true) {
if (socket.State != WebSocketState.Open) {
- Console.WriteLine ($"WSProxy: Socket is no longer open.");
+ Log ("error", $"DevToolsProxy: Socket is no longer open.");
client_initiated_close.TrySetResult (true);
return null;
}
@@ -133,51 +143,53 @@ namespace WsProxy {
return null;
}
- if (result.EndOfMessage) {
- mem.Write (buff, 0, result.Count);
+ mem.Write (buff, 0, result.Count);
+
+ if (result.EndOfMessage)
return Encoding.UTF8.GetString (mem.GetBuffer (), 0, (int)mem.Length);
- } else {
- mem.Write (buff, 0, result.Count);
- }
}
}
- WsQueue GetQueueForSocket (WebSocket ws)
+ DevToolsQueue GetQueueForSocket (WebSocket ws)
{
return queues.FirstOrDefault (q => q.Ws == ws);
}
- WsQueue GetQueueForTask (Task task) {
+ DevToolsQueue GetQueueForTask (Task task)
+ {
return queues.FirstOrDefault (q => q.CurrentSend == task);
}
void Send (WebSocket to, JObject o, CancellationToken token)
{
- var bytes = Encoding.UTF8.GetBytes (o.ToString ());
+ var sender = browser == to ? "Send-browser" : "Send-ide";
+ Log ("protocol", $"{sender}: {o}");
+ var bytes = Encoding.UTF8.GetBytes (o.ToString ());
var queue = GetQueueForSocket (to);
+
var task = queue.Send (bytes, token);
if (task != null)
pending_ops.Add (task);
}
- async Task OnEvent (string method, JObject args, CancellationToken token)
+ async Task OnEvent (SessionId sessionId, string method, JObject args, CancellationToken token)
{
try {
- if (!await AcceptEvent (method, args, token)) {
+ if (!await AcceptEvent (sessionId, method, args, token)) {
//Console.WriteLine ("proxy browser: {0}::{1}",method, args);
- SendEventInternal (method, args, token);
+ SendEventInternal (sessionId, method, args, token);
}
} catch (Exception e) {
side_exception.TrySetException (e);
}
}
- async Task OnCommand (int id, string method, JObject args, CancellationToken token)
+ async Task OnCommand (MessageId id, string method, JObject args, CancellationToken token)
{
try {
if (!await AcceptCommand (id, method, args, token)) {
- var res = await SendCommandInternal (method, args, token);
+ var res = await SendCommandInternal (id, method, args, token);
SendResponseInternal (id, res, token);
}
} catch (Exception e) {
@@ -185,10 +197,11 @@ namespace WsProxy {
}
}
- void OnResponse (int id, Result result)
+ void OnResponse (MessageId id, Result result)
{
//Console.WriteLine ("got id {0} res {1}", id, result);
- var idx = pending_cmds.FindIndex (e => e.Item1 == id);
+ // Fixme
+ var idx = pending_cmds.FindIndex (e => e.Item1.id == id.id && e.Item1.sessionId == id.sessionId);
var item = pending_cmds [idx];
pending_cmds.RemoveAt (idx);
@@ -197,68 +210,74 @@ namespace WsProxy {
void ProcessBrowserMessage (string msg, CancellationToken token)
{
- // Debug ($"browser: {msg}");
+ Log ("protocol", $"browser: {msg}");
var res = JObject.Parse (msg);
if (res ["id"] == null)
- pending_ops.Add (OnEvent (res ["method"].Value<string> (), res ["params"] as JObject, token));
+ pending_ops.Add (OnEvent (new SessionId { sessionId = res ["sessionId"]?.Value<string> () }, res ["method"].Value<string> (), res ["params"] as JObject, token));
else
- OnResponse (res ["id"].Value<int> (), Result.FromJson (res));
+ OnResponse (new MessageId { id = res ["id"].Value<int> (), sessionId = res ["sessionId"]?.Value<string> () }, Result.FromJson (res));
}
void ProcessIdeMessage (string msg, CancellationToken token)
{
+ Log ("protocol", $"ide: {msg}");
if (!string.IsNullOrEmpty (msg)) {
var res = JObject.Parse (msg);
- pending_ops.Add (OnCommand (res ["id"].Value<int> (), res ["method"].Value<string> (), res ["params"] as JObject, token));
+ pending_ops.Add (OnCommand (new MessageId { id = res ["id"].Value<int> (), sessionId = res ["sessionId"]?.Value<string> () }, res ["method"].Value<string> (), res ["params"] as JObject, token));
}
}
- internal async Task<Result> SendCommand (string method, JObject args, CancellationToken token) {
- // Debug ($"sending command {method}: {args}");
- return await SendCommandInternal (method, args, token);
+ internal async Task<Result> SendCommand (SessionId id, string method, JObject args, CancellationToken token) {
+ //Log ("verbose", $"sending command {method}: {args}");
+ return await SendCommandInternal (id, method, args, token);
}
- Task<Result> SendCommandInternal (string method, JObject args, CancellationToken token)
+ Task<Result> SendCommandInternal (SessionId sessionId, string method, JObject args, CancellationToken token)
{
int id = ++next_cmd_id;
var o = JObject.FromObject (new {
- id = id,
- method = method,
+ sessionId.sessionId,
+ id,
+ method,
@params = args
});
var tcs = new TaskCompletionSource<Result> ();
- //Console.WriteLine ("add cmd id {0}", id);
- pending_cmds.Add ((id, tcs));
+
+
+ var msgId = new MessageId { id = id, sessionId = sessionId.sessionId };
+ //Log ("verbose", $"add cmd id {sessionId}-{id}");
+ pending_cmds.Add ((msgId , tcs));
Send (this.browser, o, token);
return tcs.Task;
}
- public void SendEvent (string method, JObject args, CancellationToken token)
+ public void SendEvent (SessionId sessionId, string method, JObject args, CancellationToken token)
{
- //Debug ($"sending event {method}: {args}");
- SendEventInternal (method, args, token);
+ //Log ("verbose", $"sending event {method}: {args}");
+ SendEventInternal (sessionId, method, args, token);
}
- void SendEventInternal (string method, JObject args, CancellationToken token)
+ void SendEventInternal (SessionId sessionId, string method, JObject args, CancellationToken token)
{
var o = JObject.FromObject (new {
- method = method,
+ sessionId.sessionId,
+ method,
@params = args
});
Send (this.ide, o, token);
}
- internal void SendResponse (int id, Result result, CancellationToken token)
+ internal void SendResponse (MessageId id, Result result, CancellationToken token)
{
- //Debug ($"sending response: {id}: {result.ToJObject (id)}");
+ //Log ("verbose", $"sending response: {id}: {result.ToJObject (id)}");
SendResponseInternal (id, result, token);
}
- void SendResponseInternal (int id, Result result, CancellationToken token)
+ void SendResponseInternal (MessageId id, Result result, CancellationToken token)
{
JObject o = result.ToJObject (id);
@@ -268,16 +287,16 @@ namespace WsProxy {
// , HttpContext context)
public async Task Run (Uri browserUri, WebSocket ideSocket)
{
- Debug ($"WsProxy Starting on {browserUri}");
+ Log ("info", $"DevToolsProxy: Starting on {browserUri}");
using (this.ide = ideSocket) {
- Debug ($"WsProxy: IDE waiting for connection on {browserUri}");
- queues.Add (new WsQueue (this.ide));
+ Log ("verbose", $"DevToolsProxy: IDE waiting for connection on {browserUri}");
+ queues.Add (new DevToolsQueue (this.ide));
using (this.browser = new ClientWebSocket ()) {
this.browser.Options.KeepAliveInterval = Timeout.InfiniteTimeSpan;
await this.browser.ConnectAsync (browserUri, CancellationToken.None);
- queues.Add (new WsQueue (this.browser));
+ queues.Add (new DevToolsQueue (this.browser));
- Debug ($"WsProxy: Client connected on {browserUri}");
+ Log ("verbose", $"DevToolsProxy: Client connected on {browserUri}");
var x = new CancellationTokenSource ();
pending_ops.Add (ReadOne (browser, x.Token));
@@ -306,7 +325,7 @@ namespace WsProxy {
throw new Exception ("side task must always complete with an exception, what's going on???");
} else if (task == pending_ops [3]) {
var res = ((Task<bool>)task).Result;
- Debug ($"WsProxy: Client initiated close from {browserUri}");
+ Log ("verbose", $"DevToolsProxy: Client initiated close from {browserUri}");
x.Cancel ();
} else {
//must be a background task
@@ -320,7 +339,7 @@ namespace WsProxy {
}
}
} catch (Exception e) {
- Debug ($"WsProxy::Run: Exception {e}");
+ Log ("error", $"DevToolsProxy::Run: Exception {e}");
//throw;
} finally {
if (!x.IsCancellationRequested)
@@ -330,14 +349,22 @@ namespace WsProxy {
}
}
- protected void Debug (string msg)
- {
- Console.WriteLine (msg);
- }
-
- protected void Info (string msg)
+ protected void Log (string priority, string msg)
{
- Console.WriteLine (msg);
+ switch (priority) {
+ case "protocol":
+ Console.WriteLine (msg);
+ break;
+ case "verbose":
+ Console.WriteLine (msg);
+ break;
+ case "info":
+ case "warning":
+ case "error":
+ default:
+ Console.WriteLine (msg);
+ break;
+ }
}
}
}
diff --git a/sdks/wasm/Mono.WebAssembly.DebuggerProxy/InspectorClient.cs b/sdks/wasm/Mono.WebAssembly.DebuggerProxy/InspectorClient.cs
index 1eecc2c6945..7454aa6d871 100644
--- a/sdks/wasm/Mono.WebAssembly.DebuggerProxy/InspectorClient.cs
+++ b/sdks/wasm/Mono.WebAssembly.DebuggerProxy/InspectorClient.cs
@@ -9,8 +9,8 @@ using System.IO;
using System.Text;
using System.Collections.Generic;
-namespace WsProxy {
- public class InspectorClient : WsClient {
+namespace WebAssembly.Net.Debugging {
+ public class InspectorClient : DevToolsClient {
List<(int, TaskCompletionSource<Result>)> pending_cmds = new List<(int, TaskCompletionSource<Result>)> ();
Func<string, JObject, CancellationToken, Task> onEvent;
int next_cmd_id;
@@ -59,7 +59,7 @@ namespace WsProxy {
pending_cmds.Add ((id, tcs));
var str = o.ToString ();
- System.Console.WriteLine ($"Command: id: {id} method: {method} params: {args}");
+ //Log ("protocol", $"SendCommand: id: {id} method: {method} params: {args}");
var bytes = Encoding.UTF8.GetBytes (str);
Send (bytes, token);
diff --git a/sdks/wasm/Mono.WebAssembly.DebuggerProxy/MonoProxy.cs b/sdks/wasm/Mono.WebAssembly.DebuggerProxy/MonoProxy.cs
index 86f104f9c54..623cdeb0353 100644
--- a/sdks/wasm/Mono.WebAssembly.DebuggerProxy/MonoProxy.cs
+++ b/sdks/wasm/Mono.WebAssembly.DebuggerProxy/MonoProxy.cs
@@ -3,14 +3,12 @@ using System.Linq;
using System.Threading.Tasks;
using Newtonsoft.Json.Linq;
-using System.Net.WebSockets;
using System.Threading;
using System.IO;
-using System.Text;
using System.Collections.Generic;
using System.Net;
-namespace WsProxy {
+namespace WebAssembly.Net.Debugging {
internal class MonoCommands {
public const string GET_CALL_STACK = "MONO.mono_wasm_get_call_stack()";
@@ -29,10 +27,10 @@ namespace WsProxy {
BpNotFound = 100000,
}
-
internal class MonoConstants {
public const string RUNTIME_IS_READY = "mono_wasm_runtime_ready";
}
+
class Frame {
public Frame (MethodInfo method, SourceLocation location, int id)
{
@@ -73,7 +71,7 @@ namespace WsProxy {
Over
}
- public class MonoProxy : WsProxy {
+ public class MonoProxy : DevToolsProxy {
DebugStore store;
List<Breakpoint> breakpoints = new List<Breakpoint> ();
List<Frame> current_callstack;
@@ -84,7 +82,7 @@ namespace WsProxy {
public MonoProxy () { }
- protected override async Task<bool> AcceptEvent (string method, JObject args, CancellationToken token)
+ protected override async Task<bool> AcceptEvent (SessionId sessionId, string method, JObject args, CancellationToken token)
{
switch (method) {
case "Runtime.executionContextCreated": {
@@ -93,8 +91,8 @@ namespace WsProxy {
if (aux_data != null) {
var is_default = aux_data ["isDefault"]?.Value<bool> ();
if (is_default == true) {
- var ctx_id = ctx ["id"].Value<int> ();
- await OnDefaultContext (ctx_id, aux_data, token);
+ var id = new MessageId { id = ctx ["id"].Value<int> (), sessionId = sessionId.sessionId };
+ await OnDefaultContext (id, aux_data, token);
}
}
break;
@@ -103,11 +101,11 @@ namespace WsProxy {
//TODO figure out how to stich out more frames and, in particular what happens when real wasm is on the stack
var top_func = args? ["callFrames"]? [0]? ["functionName"]?.Value<string> ();
if (top_func == "mono_wasm_fire_bp" || top_func == "_mono_wasm_fire_bp") {
- await OnBreakPointHit (args, token);
+ await OnBreakPointHit (sessionId, args, token);
return true;
}
if (top_func == MonoConstants.RUNTIME_IS_READY) {
- await OnRuntimeReady (token);
+ await OnRuntimeReady (new SessionId { sessionId = sessionId.sessionId }, token);
return true;
}
break;
@@ -119,24 +117,33 @@ namespace WsProxy {
}
break;
}
+ case "Debugger.enabled": {
+ await LoadStore (new SessionId { sessionId = args? ["sessionId"]?.Value<string> () }, token);
+ break;
+ }
}
-
return false;
}
- protected override async Task<bool> AcceptCommand (int id, string method, JObject args, CancellationToken token)
+ protected override async Task<bool> AcceptCommand (MessageId id, string method, JObject args, CancellationToken token)
{
switch (method) {
+ case "Target.attachToTarget": {
+ break;
+ }
+ case "Target.attachToBrowserTarget": {
+ break;
+ }
case "Debugger.getScriptSource": {
var script_id = args? ["scriptId"]?.Value<string> ();
if (script_id.StartsWith ("dotnet://", StringComparison.InvariantCultureIgnoreCase)) {
await OnGetScriptSource (id, script_id, token);
return true;
}
-
break;
}
+
case "Runtime.compileScript": {
var exp = args? ["expression"]?.Value<string> ();
if (exp.StartsWith ("//dotnet:", StringComparison.InvariantCultureIgnoreCase)) {
@@ -156,7 +163,7 @@ namespace WsProxy {
}
case "Debugger.setBreakpointByUrl": {
- Info ($"BP req {args}");
+ Log ("info", $"BP req {args}");
var bp_req = BreakPointRequest.Parse (args, store);
if (bp_req != null) {
await SetBreakPoint (id, bp_req, token);
@@ -164,9 +171,10 @@ namespace WsProxy {
}
break;
}
+
case "Debugger.removeBreakpoint": {
- return await RemoveBreakpoint (id, args, token);
- }
+ return await RemoveBreakpoint (id, args, token);
+ }
case "Debugger.resume": {
await OnResume (token);
@@ -199,16 +207,24 @@ namespace WsProxy {
case "Runtime.getProperties": {
var objId = args? ["objectId"]?.Value<string> ();
- if (objId.StartsWith ("dotnet:scope:", StringComparison.InvariantCulture)) {
- await GetScopeProperties (id, int.Parse (objId.Substring ("dotnet:scope:".Length)), token);
- return true;
- }
- if (objId.StartsWith("dotnet:", StringComparison.InvariantCulture))
- {
- if (objId.StartsWith("dotnet:object:", StringComparison.InvariantCulture))
- await GetDetails(id, int.Parse(objId.Substring("dotnet:object:".Length)), token, MonoCommands.GET_OBJECT_PROPERTIES);
- if (objId.StartsWith("dotnet:array:", StringComparison.InvariantCulture))
- await GetDetails(id, int.Parse(objId.Substring("dotnet:array:".Length)), token, MonoCommands.GET_ARRAY_VALUES);
+ if (objId.StartsWith ("dotnet:")) {
+ var parts = objId.Split (new char [] { ':' });
+ if (parts.Length < 3)
+ return true;
+ switch (parts[1]) {
+ case "scope": {
+ await GetScopeProperties (id, int.Parse (parts[2]), token);
+ break;
+ }
+ case "object": {
+ await GetDetails (id, int.Parse (parts[2]), token, MonoCommands.GET_OBJECT_PROPERTIES);
+ break;
+ }
+ case "array": {
+ await GetDetails (id, int.Parse (parts[2]), token, MonoCommands.GET_ARRAY_VALUES);
+ break;
+ }
+ }
return true;
}
break;
@@ -218,15 +234,16 @@ namespace WsProxy {
return false;
}
- async Task OnRuntimeReady (CancellationToken token)
+ async Task OnRuntimeReady (SessionId sessionId, CancellationToken token)
{
- Info ("RUNTIME READY, PARTY TIME");
- await RuntimeReady (token);
- await SendCommand ("Debugger.resume", new JObject (), token);
- SendEvent ("Mono.runtimeReady", new JObject (), token);
+ Log ("info", "RUNTIME READY, PARTY TIME");
+ await RuntimeReady (sessionId, token);
+ await SendCommand (sessionId, "Debugger.resume", new JObject (), token);
+ SendEvent (sessionId, "Mono.runtimeReady", new JObject (), token);
}
- async Task OnBreakPointHit (JObject args, CancellationToken token)
+ //static int frame_id=0;
+ async Task OnBreakPointHit (SessionId sessionId, JObject args, CancellationToken token)
{
//FIXME we should send release objects every now and then? Or intercept those we inject and deal in the runtime
var o = JObject.FromObject (new {
@@ -238,11 +255,11 @@ namespace WsProxy {
});
var orig_callframes = args? ["callFrames"]?.Values<JObject> ();
- var res = await SendCommand ("Runtime.evaluate", o, token);
+ var res = await SendCommand (sessionId, "Runtime.evaluate", o, token);
if (res.IsErr) {
//Give up and send the original call stack
- SendEvent ("Debugger.paused", args, token);
+ SendEvent (sessionId, "Debugger.paused", args, token);
return;
}
@@ -250,16 +267,16 @@ namespace WsProxy {
var res_value = res.Value? ["result"]? ["value"];
if (res_value == null || res_value is JValue) {
//Give up and send the original call stack
- SendEvent ("Debugger.paused", args, token);
+ SendEvent (sessionId, "Debugger.paused", args, token);
return;
}
- Debug ($"call stack (err is {res.Error} value is:\n{res.Value}");
+ Log ("verbose", $"call stack (err is {res.Error} value is:\n{res.Value}");
var bp_id = res_value? ["breakpoint_id"]?.Value<int> ();
- Debug ($"We just hit bp {bp_id}");
+ Log ("verbose", $"We just hit bp {bp_id}");
if (!bp_id.HasValue) {
//Give up and send the original call stack
- SendEvent ("Debugger.paused", args, token);
+ SendEvent (sessionId, "Debugger.paused", args, token);
return;
}
var bp = this.breakpoints.FirstOrDefault (b => b.RemoteId == bp_id.Value);
@@ -282,14 +299,14 @@ namespace WsProxy {
var asm = store.GetAssemblyByName (assembly_name);
if (asm == null) {
- Info ($"Unable to find assembly: {assembly_name}");
+ Log ("info",$"Unable to find assembly: {assembly_name}");
continue;
}
var method = asm.GetMethodByToken (method_token);
if (method == null) {
- Info ($"Unable to find il offset: {il_pos} in method token: {method_token} assembly name: {assembly_name}");
+ Log ("info", $"Unable to find il offset: {il_pos} in method token: {method_token} assembly name: {assembly_name}");
continue;
}
@@ -303,8 +320,8 @@ namespace WsProxy {
continue;
}
- Info ($"frame il offset: {il_pos} method token: {method_token} assembly name: {assembly_name}");
- Info ($"\tmethod {method.Name} location: {location}");
+ Log ("info", $"frame il offset: {il_pos} method token: {method_token} assembly name: {assembly_name}");
+ Log ("info", $"\tmethod {method.Name} location: {location}");
frames.Add (new Frame (method, location, frame_id));
callFrames.Add (JObject.FromObject (new {
@@ -351,12 +368,12 @@ namespace WsProxy {
hitBreakpoints = bp_list,
});
- SendEvent ("Debugger.paused", o, token);
+ SendEvent (sessionId, "Debugger.paused", o, token);
}
- async Task OnDefaultContext (int ctx_id, JObject aux_data, CancellationToken token)
+ async Task OnDefaultContext (MessageId ctx_id, JObject aux_data, CancellationToken token)
{
- Debug ("Default context created, clearing state and sending events");
+ Log ("verbose", "Default context created, clearing state and sending events");
//reset all bps
foreach (var b in this.breakpoints){
@@ -371,16 +388,16 @@ namespace WsProxy {
silent = false,
returnByValue = true
});
- this.ctx_id = ctx_id;
+ this.ctx_id = ctx_id.id;
this.aux_ctx_data = aux_data;
- Debug ("checking if the runtime is ready");
- var res = await SendCommand ("Runtime.evaluate", o, token);
+ Log ("verbose", "checking if the runtime is ready");
+ var res = await SendCommand (ctx_id, "Runtime.evaluate", o, token);
var is_ready = res.Value? ["result"]? ["value"]?.Value<bool> ();
- //Debug ($"\t{is_ready}");
+ //Log ("verbose", $"\t{is_ready}");
if (is_ready.HasValue && is_ready.Value == true) {
- Debug ("RUNTIME LOOK READY. GO TIME!");
- await OnRuntimeReady (token);
+ Log ("verbose", "RUNTIME LOOK READY. GO TIME!");
+ await OnRuntimeReady (ctx_id, token);
}
}
@@ -392,7 +409,7 @@ namespace WsProxy {
await Task.CompletedTask;
}
- async Task Step (int msg_id, StepKind kind, CancellationToken token)
+ async Task Step (MessageId msg_id, StepKind kind, CancellationToken token)
{
var o = JObject.FromObject (new {
@@ -403,16 +420,16 @@ namespace WsProxy {
returnByValue = true,
});
- var res = await SendCommand ("Runtime.evaluate", o, token);
+ var res = await SendCommand (msg_id, "Runtime.evaluate", o, token);
SendResponse (msg_id, Result.Ok (new JObject ()), token);
this.current_callstack = null;
- await SendCommand ("Debugger.resume", new JObject (), token);
+ await SendCommand (msg_id, "Debugger.resume", new JObject (), token);
}
- async Task GetDetails(int msg_id, int object_id, CancellationToken token, string command)
+ async Task GetDetails(MessageId msg_id, int object_id, CancellationToken token, string command)
{
var o = JObject.FromObject(new
{
@@ -423,7 +440,7 @@ namespace WsProxy {
returnByValue = true,
});
- var res = await SendCommand("Runtime.evaluate", o, token);
+ var res = await SendCommand(msg_id, "Runtime.evaluate", o, token);
//if we fail we just buble that to the IDE (and let it panic over it)
if (res.IsErr)
@@ -461,14 +478,13 @@ namespace WsProxy {
{
result = var_list
});
- } catch {
- Debug ($"failed to parse {res.Value}");
+ } catch (Exception e) {
+ Log ("verbose", $"failed to parse {res.Value} - {e.Message}");
}
SendResponse(msg_id, Result.Ok(o), token);
}
-
- async Task GetScopeProperties (int msg_id, int scope_id, CancellationToken token)
+ async Task GetScopeProperties (MessageId msg_id, int scope_id, CancellationToken token)
{
var scope = this.current_callstack.FirstOrDefault (s => s.Id == scope_id);
var vars = scope.Method.GetLiveVarsAt (scope.Location.CliLocation.Offset);
@@ -484,7 +500,7 @@ namespace WsProxy {
returnByValue = true,
});
- var res = await SendCommand ("Runtime.evaluate", o, token);
+ var res = await SendCommand (msg_id, "Runtime.evaluate", o, token);
//if we fail we just buble that to the IDE (and let it panic over it)
if (res.IsErr) {
@@ -533,13 +549,13 @@ namespace WsProxy {
result = var_list
});
SendResponse (msg_id, Result.Ok (o), token);
- }
- catch {
+ } catch (Exception exception) {
+ Log ("verbose", $"Error resolving scope properties {exception.Message}");
SendResponse (msg_id, res, token);
}
}
- async Task<Result> EnableBreakPoint (Breakpoint bp, CancellationToken token)
+ async Task<Result> EnableBreakPoint (SessionId sessionId, Breakpoint bp, CancellationToken token)
{
var asm_name = bp.Location.CliLocation.Method.Assembly.Name;
var method_token = bp.Location.CliLocation.Method.Token;
@@ -553,21 +569,20 @@ namespace WsProxy {
returnByValue = true,
});
- var res = await SendCommand ("Runtime.evaluate", o, token);
+ var res = await SendCommand (sessionId, "Runtime.evaluate", o, token);
var ret_code = res.Value? ["result"]? ["value"]?.Value<int> ();
if (ret_code.HasValue) {
bp.RemoteId = ret_code.Value;
bp.State = BreakPointState.Active;
- //Debug ($"BP local id {bp.LocalId} enabled with remote id {bp.RemoteId}");
+ //Log ("verbose", $"BP local id {bp.LocalId} enabled with remote id {bp.RemoteId}");
}
return res;
}
- async Task RuntimeReady (CancellationToken token)
+ async Task LoadStore (SessionId sessionId, CancellationToken token)
{
-
var o = JObject.FromObject (new {
expression = MonoCommands.GET_LOADED_FILES,
objectGroup = "mono_debugger",
@@ -575,11 +590,19 @@ namespace WsProxy {
silent = false,
returnByValue = true,
});
- var loaded_pdbs = await SendCommand ("Runtime.evaluate", o, token);
+
+ var loaded_pdbs = await SendCommand (sessionId, "Runtime.evaluate", o, token);
var the_value = loaded_pdbs.Value? ["result"]? ["value"];
var the_pdbs = the_value?.ToObject<string[]> ();
- this.store = new DebugStore (this);
- this.store.Initialize (the_pdbs, token);
+
+ store = new DebugStore ();
+ await store.Load(sessionId, the_pdbs, token);
+ }
+
+ async Task RuntimeReady (SessionId sessionId, CancellationToken token)
+ {
+ if (store == null)
+ await LoadStore (sessionId, token);
foreach (var s in store.AllSources ()) {
var ok = JObject.FromObject (new {
@@ -588,13 +611,13 @@ namespace WsProxy {
executionContextId = this.ctx_id,
hash = s.DocHashCode,
executionContextAuxData = this.aux_ctx_data,
- dotNetUrl = s.DotNetUrl
+ dotNetUrl = s.DotNetUrl,
});
- //Debug ($"\tsending {s.Url}");
- SendEvent ("Debugger.scriptParsed", ok, token);
+ //Log ("verbose", $"\tsending {s.Url}");
+ SendEvent (sessionId, "Debugger.scriptParsed", ok, token);
}
- o = JObject.FromObject (new {
+ var o = JObject.FromObject (new {
expression = MonoCommands.CLEAR_ALL_BREAKPOINTS,
objectGroup = "mono_debugger",
includeCommandLineAPI = false,
@@ -602,9 +625,9 @@ namespace WsProxy {
returnByValue = true,
});
- var clear_result = await SendCommand ("Runtime.evaluate", o, token);
+ var clear_result = await SendCommand (sessionId, "Runtime.evaluate", o, token);
if (clear_result.IsErr) {
- Debug ($"Failed to clear breakpoints due to {clear_result}");
+ Log ("verbose", $"Failed to clear breakpoints due to {clear_result}");
}
@@ -613,19 +636,19 @@ namespace WsProxy {
foreach (var bp in breakpoints) {
if (bp.State != BreakPointState.Pending)
continue;
- var res = await EnableBreakPoint (bp, token);
+ var res = await EnableBreakPoint (sessionId, bp, token);
var ret_code = res.Value? ["result"]? ["value"]?.Value<int> ();
//if we fail we just buble that to the IDE (and let it panic over it)
if (!ret_code.HasValue) {
//FIXME figure out how to inform the IDE of that.
- Info ($"FAILED TO ENABLE BP {bp.LocalId}");
+ Log ("info", $"FAILED TO ENABLE BP {bp.LocalId}");
bp.State = BreakPointState.Disabled;
}
}
}
- async Task<bool> RemoveBreakpoint(int msg_id, JObject args, CancellationToken token) {
+ async Task<bool> RemoveBreakpoint(MessageId msg_id, JObject args, CancellationToken token) {
var bpid = args? ["breakpointId"]?.Value<string> ();
if (bpid?.StartsWith ("dotnet:") != true)
return false;
@@ -634,19 +657,19 @@ namespace WsProxy {
var bp = breakpoints.FirstOrDefault (b => b.LocalId == the_id);
if (bp == null) {
- Info ($"Could not find dotnet bp with id {the_id}");
+ Log ("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);
+ var res = await RemoveBreakPoint (msg_id, bp, token);
return true;
}
- async Task<Result> RemoveBreakPoint (Breakpoint bp, CancellationToken token)
+ async Task<Result> RemoveBreakPoint (SessionId sessionId, Breakpoint bp, CancellationToken token)
{
var o = JObject.FromObject (new {
expression = string.Format (MonoCommands.REMOVE_BREAK_POINT, bp.RemoteId),
@@ -656,7 +679,7 @@ namespace WsProxy {
returnByValue = true,
});
- var res = await SendCommand ("Runtime.evaluate", o, token);
+ var res = await SendCommand (sessionId, "Runtime.evaluate", o, token);
var ret_code = res.Value? ["result"]? ["value"]?.Value<int> ();
if (ret_code.HasValue) {
@@ -667,13 +690,13 @@ namespace WsProxy {
return res;
}
- async Task SetBreakPoint (int msg_id, BreakPointRequest req, CancellationToken token)
+ async Task SetBreakPoint (MessageId msg_id, BreakPointRequest req, CancellationToken token)
{
- var bp_loc = store.FindBestBreakpoint (req);
- Info ($"BP request for '{req}' runtime ready {runtime_ready} location '{bp_loc}'");
+ var bp_loc = store?.FindBestBreakpoint (req);
+ Log ("info", $"BP request for '{req}' runtime ready {runtime_ready} location '{bp_loc}'");
if (bp_loc == null) {
- Info ($"Could not resolve breakpoint request: {req}");
+ Log ("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."
@@ -687,7 +710,7 @@ namespace WsProxy {
} else {
bp = new Breakpoint (bp_loc, local_breakpoint_id++, BreakPointState.Disabled);
- var res = await EnableBreakPoint (bp, token);
+ var res = await EnableBreakPoint (msg_id, bp, token);
var ret_code = res.Value? ["result"]? ["value"]?.Value<int> ();
//if we fail we just buble that to the IDE (and let it panic over it)
@@ -715,7 +738,7 @@ namespace WsProxy {
SendResponse (msg_id, Result.Ok (ok), token);
}
- bool GetPossibleBreakpoints (int msg_id, SourceLocation start, SourceLocation end, CancellationToken token)
+ bool GetPossibleBreakpoints (MessageId msg_id, SourceLocation start, SourceLocation end, CancellationToken token)
{
var bps = store.FindPossibleBreakpoints (start, end);
if (bps == null)
@@ -735,15 +758,14 @@ namespace WsProxy {
return true;
}
- void OnCompileDotnetScript (int msg_id, CancellationToken token)
+ void OnCompileDotnetScript (MessageId msg_id, CancellationToken token)
{
var o = JObject.FromObject (new { });
SendResponse (msg_id, Result.Ok (o), token);
-
}
- async Task OnGetScriptSource (int msg_id, string script_id, CancellationToken token)
+ async Task OnGetScriptSource (MessageId msg_id, string script_id, CancellationToken token)
{
var id = new SourceId (script_id);
var src_file = store.GetFileById (id);
@@ -754,6 +776,16 @@ namespace WsProxy {
try {
var uri = new Uri (src_file.Url);
if (uri.IsFile && File.Exists(uri.LocalPath)) {
+ using (var f = new StreamReader (File.Open (uri.LocalPath, FileMode.Open))) {
+ await res.WriteAsync (await f.ReadToEndAsync ());
+ }
+
+ var o = JObject.FromObject (new {
+ scriptSource = res.ToString ()
+ });
+
+ SendResponse (msg_id, Result.Ok (o), token);
+ } else if (src_file.SourceUri.IsFile && File.Exists(src_file.SourceUri.LocalPath)) {
using (var f = new StreamReader (File.Open (src_file.SourceUri.LocalPath, FileMode.Open))) {
await res.WriteAsync (await f.ReadToEndAsync ());
}
diff --git a/sdks/wasm/ProxyDriver/Program.cs b/sdks/wasm/ProxyDriver/Program.cs
index 9224670ee5c..9a564382d79 100644
--- a/sdks/wasm/ProxyDriver/Program.cs
+++ b/sdks/wasm/ProxyDriver/Program.cs
@@ -7,7 +7,7 @@ using Microsoft.Extensions.Configuration;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
-namespace WsProxy
+namespace WebAssembly.Net.Debugging
{
public class ProxyOptions {
public Uri DevToolsUrl { get; set; } = new Uri ("http://localhost:9222");
diff --git a/sdks/wasm/ProxyDriver/Startup.cs b/sdks/wasm/ProxyDriver/Startup.cs
index 0468e2a9b95..61a18b561b3 100644
--- a/sdks/wasm/ProxyDriver/Startup.cs
+++ b/sdks/wasm/ProxyDriver/Startup.cs
@@ -8,13 +8,11 @@ using Microsoft.Extensions.Options;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.Configuration;
using System.Net.Http;
-using System.IO;
using System.Collections.Generic;
using Newtonsoft.Json;
using System.Linq;
-using System.Net;
-namespace WsProxy {
+namespace WebAssembly.Net.Debugging {
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
@@ -71,6 +69,15 @@ namespace WsProxy {
{
var devToolsHost = options.DevToolsUrl;
app.UseRouter (router => {
+ router.MapGet ("/", Copy);
+ router.MapGet ("/favicon.ico", Copy);
+ router.MapGet ("json", RewriteArray);
+ router.MapGet ("json/list", RewriteArray);
+ router.MapGet ("json/version", RewriteSingle);
+ router.MapGet ("json/new", RewriteSingle);
+ router.MapGet ("devtools/page/{pageId}", ConnectProxy);
+ router.MapGet ("devtools/browser/{pageId}", ConnectProxy);
+
string GetEndpoint (HttpContext context)
{
var request = context.Request;
@@ -106,33 +113,28 @@ namespace WsProxy {
await context.Response.WriteAsync (JsonConvert.SerializeObject (alteredTabs));
}
- router.MapGet ("/", Copy);
- router.MapGet ("/favicon.ico", Copy);
- router.MapGet ("json", RewriteArray);
- router.MapGet ("json/list", RewriteArray);
- router.MapGet ("json/version", RewriteSingle);
- router.MapGet ("json/new", RewriteSingle);
- router.MapGet ("devtools/page/{pageId}", async context => {
- if (!context.WebSockets.IsWebSocketRequest) {
- context.Response.StatusCode = 400;
- return;
- }
-
- var endpoint = new Uri ($"ws://{devToolsHost.Authority}{context.Request.Path.ToString()}");
- try {
- var proxy = new MonoProxy ();
- var ideSocket = await context.WebSockets.AcceptWebSocketAsync ();
-
- await proxy.Run (endpoint, ideSocket);
- } catch (Exception e) {
- Console.WriteLine ("got exception {0}", e);
- }
- });
- });
+ async Task ConnectProxy (HttpContext context)
+ {
+ if (!context.WebSockets.IsWebSocketRequest) {
+ context.Response.StatusCode = 400;
+ return;
+ }
+
+ var endpoint = new Uri ($"ws://{devToolsHost.Authority}{context.Request.Path.ToString ()}");
+ try {
+ var proxy = new MonoProxy ();
+ var ideSocket = await context.WebSockets.AcceptWebSocketAsync ();
+
+ await proxy.Run (endpoint, ideSocket);
+ } catch (Exception e) {
+ Console.WriteLine ("got exception {0}", e);
+ }
+ }
+ });
return app;
}
- private static async Task<T> ProxyGetJsonAsync<T> (string url)
+ static async Task<T> ProxyGetJsonAsync<T> (string url)
{
using (var httpClient = new HttpClient ()) {
var response = await httpClient.GetAsync (url);
diff --git a/sdks/wasm/ProxyDriver/TestHarnessStartup.cs b/sdks/wasm/ProxyDriver/TestHarnessStartup.cs
index 9b91dbc7bf6..8434f2308f3 100644
--- a/sdks/wasm/ProxyDriver/TestHarnessStartup.cs
+++ b/sdks/wasm/ProxyDriver/TestHarnessStartup.cs
@@ -14,10 +14,8 @@ using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Options;
using Microsoft.AspNetCore.StaticFiles;
using Newtonsoft.Json.Linq;
-using WsProxy;
-
-namespace WsProxy {
+namespace WebAssembly.Net.Debugging {
public class TestHarnessStartup {
public TestHarnessStartup (IConfiguration configuration)
{
@@ -119,6 +117,7 @@ namespace WsProxy {
proc.Close ();
}
}
+
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure (IApplicationBuilder app, IOptionsMonitor<TestHarnessOptions> optionsAccessor, IWebHostEnvironment env)
{