Update ws-proxy code (#19826)

This commit is contained in:
Steve Sanderson 2020-03-13 11:34:09 +00:00 committed by GitHub
parent 9343d2bca0
commit f1b812e21e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 76 additions and 33 deletions

View File

@ -1,4 +1,4 @@
using System; using System;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
@ -11,12 +11,45 @@ using System.Collections.Generic;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
namespace WebAssembly.Net.Debugging { namespace WebAssembly.Net.Debugging {
internal class SessionId { internal struct SessionId {
public string sessionId; public readonly string sessionId;
public SessionId (string sessionId)
{
this.sessionId = sessionId;
}
public override int GetHashCode ()
=> sessionId?.GetHashCode () ?? 0;
public override bool Equals (object obj)
=> (obj is SessionId) ? ((SessionId) obj).sessionId == sessionId : false;
public override string ToString ()
=> $"session-{sessionId}";
} }
internal class MessageId : SessionId { internal struct MessageId {
public int id; public readonly string sessionId;
public readonly int id;
public MessageId (string sessionId, int id)
{
this.sessionId = sessionId;
this.id = id;
}
public static implicit operator SessionId (MessageId id)
=> new SessionId (id.sessionId);
public override string ToString ()
=> $"msg-{sessionId}:::{id}";
public override int GetHashCode ()
=> (sessionId?.GetHashCode () ?? 0) ^ id.GetHashCode ();
public override bool Equals (object obj)
=> (obj is MessageId) ? ((MessageId) obj).sessionId == sessionId && ((MessageId) obj).id == id : false;
} }
internal struct Result { internal struct Result {
@ -28,17 +61,17 @@ namespace WebAssembly.Net.Debugging {
Result (JObject result, JObject error) Result (JObject result, JObject error)
{ {
if (result != null && error != null) if (result != null && error != null)
throw new ArgumentException ($"Both {nameof(result)} and {nameof(error)} arguments cannot be non-null."); throw new ArgumentException ($"Both {nameof(result)} and {nameof(error)} arguments cannot be non-null.");
bool resultHasError = String.Compare ((result? ["result"] as JObject)? ["subtype"]?. Value<string> (), "error") == 0; bool resultHasError = String.Compare ((result? ["result"] as JObject)? ["subtype"]?. Value<string> (), "error") == 0;
if (result != null && resultHasError) { if (result != null && resultHasError) {
this.Value = null; this.Value = null;
this.Error = result; this.Error = result;
} else { } else {
this.Value = result; this.Value = result;
this.Error = error; this.Error = error;
} }
} }
public static Result FromJson (JObject obj) public static Result FromJson (JObject obj)
@ -120,12 +153,13 @@ namespace WebAssembly.Net.Debugging {
internal class DevToolsProxy { internal class DevToolsProxy {
TaskCompletionSource<bool> side_exception = new TaskCompletionSource<bool> (); TaskCompletionSource<bool> side_exception = new TaskCompletionSource<bool> ();
TaskCompletionSource<bool> client_initiated_close = new TaskCompletionSource<bool> (); TaskCompletionSource<bool> client_initiated_close = new TaskCompletionSource<bool> ();
List<(MessageId, TaskCompletionSource<Result>)> pending_cmds = new List<(MessageId, TaskCompletionSource<Result>)> (); Dictionary<MessageId, TaskCompletionSource<Result>> pending_cmds = new Dictionary<MessageId, TaskCompletionSource<Result>> ();
ClientWebSocket browser; ClientWebSocket browser;
WebSocket ide; WebSocket ide;
int next_cmd_id; int next_cmd_id;
List<Task> pending_ops = new List<Task> (); List<Task> pending_ops = new List<Task> ();
List<DevToolsQueue> queues = new List<DevToolsQueue> (); List<DevToolsQueue> queues = new List<DevToolsQueue> ();
protected readonly ILogger logger; protected readonly ILogger logger;
public DevToolsProxy (ILoggerFactory loggerFactory) public DevToolsProxy (ILoggerFactory loggerFactory)
@ -219,11 +253,11 @@ namespace WebAssembly.Net.Debugging {
{ {
//logger.LogTrace ("got id {0} res {1}", id, result); //logger.LogTrace ("got id {0} res {1}", id, result);
// Fixme // Fixme
var idx = pending_cmds.FindIndex (e => e.Item1.id == id.id && e.Item1.sessionId == id.sessionId); if (pending_cmds.Remove (id, out var task)) {
var item = pending_cmds [idx]; task.SetResult (result);
pending_cmds.RemoveAt (idx); return;
}
item.Item2.SetResult (result); logger.LogError ("Cannot respond to command: {id} with result: {result} - command is not pending", id, result);
} }
void ProcessBrowserMessage (string msg, CancellationToken token) void ProcessBrowserMessage (string msg, CancellationToken token)
@ -232,9 +266,9 @@ namespace WebAssembly.Net.Debugging {
var res = JObject.Parse (msg); var res = JObject.Parse (msg);
if (res ["id"] == null) if (res ["id"] == null)
pending_ops.Add (OnEvent (new SessionId { sessionId = res ["sessionId"]?.Value<string> () }, res ["method"].Value<string> (), res ["params"] as JObject, token)); pending_ops.Add (OnEvent (new SessionId (res ["sessionId"]?.Value<string> ()), res ["method"].Value<string> (), res ["params"] as JObject, token));
else else
OnResponse (new MessageId { id = res ["id"].Value<int> (), sessionId = res ["sessionId"]?.Value<string> () }, Result.FromJson (res)); OnResponse (new MessageId (res ["sessionId"]?.Value<string> (), res ["id"].Value<int> ()), Result.FromJson (res));
} }
void ProcessIdeMessage (string msg, CancellationToken token) void ProcessIdeMessage (string msg, CancellationToken token)
@ -242,7 +276,10 @@ namespace WebAssembly.Net.Debugging {
Log ("protocol", $"ide: {msg}"); Log ("protocol", $"ide: {msg}");
if (!string.IsNullOrEmpty (msg)) { if (!string.IsNullOrEmpty (msg)) {
var res = JObject.Parse (msg); var res = JObject.Parse (msg);
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)); pending_ops.Add (OnCommand (
new MessageId (res ["sessionId"]?.Value<string> (), res ["id"].Value<int> ()),
res ["method"].Value<string> (),
res ["params"] as JObject, token));
} }
} }
@ -263,9 +300,9 @@ namespace WebAssembly.Net.Debugging {
}); });
var tcs = new TaskCompletionSource<Result> (); var tcs = new TaskCompletionSource<Result> ();
var msgId = new MessageId { id = id, sessionId = sessionId.sessionId }; var msgId = new MessageId (sessionId.sessionId, id);
//Log ("verbose", $"add cmd id {sessionId}-{id}"); //Log ("verbose", $"add cmd id {sessionId}-{id}");
pending_cmds.Add ((msgId , tcs)); pending_cmds[msgId] = tcs;
Send (this.browser, o, token); Send (this.browser, o, token);
return tcs.Task; return tcs.Task;

View File

@ -134,24 +134,22 @@ namespace WebAssembly.Net.Debugging {
} }
internal class MonoProxy : DevToolsProxy { internal class MonoProxy : DevToolsProxy {
Dictionary<string, ExecutionContext> contexts = new Dictionary<string, ExecutionContext> (); Dictionary<SessionId, ExecutionContext> contexts = new Dictionary<SessionId, ExecutionContext> ();
public MonoProxy (ILoggerFactory loggerFactory) : base(loggerFactory) { } public MonoProxy (ILoggerFactory loggerFactory) : base(loggerFactory) { }
ExecutionContext GetContext (SessionId sessionId) ExecutionContext GetContext (SessionId sessionId)
{ {
var id = sessionId?.sessionId ?? "default"; if (contexts.TryGetValue (sessionId, out var context))
if (contexts.TryGetValue (id, out var context))
return context; return context;
throw new ArgumentException ($"Invalid Session: \"{id}\"", nameof (sessionId)); throw new ArgumentException ($"Invalid Session: \"{sessionId}\"", nameof (sessionId));
} }
bool UpdateContext (SessionId sessionId, ExecutionContext executionContext, out ExecutionContext previousExecutionContext) bool UpdateContext (SessionId sessionId, ExecutionContext executionContext, out ExecutionContext previousExecutionContext)
{ {
var id = sessionId?.sessionId ?? "default"; var previous = contexts.TryGetValue (sessionId, out previousExecutionContext);
var previous = contexts.TryGetValue (id, out previousExecutionContext); contexts[sessionId] = executionContext;
contexts[id] = executionContext;
return previous; return previous;
} }
@ -494,6 +492,14 @@ namespace WebAssembly.Net.Debugging {
var res = await SendMonoCommand (msg_id, MonoCommands.StartSingleStepping (kind), token); var res = await SendMonoCommand (msg_id, MonoCommands.StartSingleStepping (kind), token);
var ret_code = res.Value? ["result"]? ["value"]?.Value<int> ();
if (ret_code.HasValue && ret_code.Value == 0) {
context.CallStack = null;
await SendCommand (msg_id, "Debugger.stepOut", new JObject (), token);
return false;
}
SendResponse (msg_id, Result.Ok (new JObject ()), token); SendResponse (msg_id, Result.Ok (new JObject ()), token);
context.CallStack = null; context.CallStack = null;