Update Mono WebAssembly for Blazor (https://github.com/aspnet/Blazor/pull/1807)
This commit is contained in:
parent
dbe9ab7dd5
commit
6c5e1690ad
|
|
@ -27,6 +27,11 @@
|
||||||
$(RestoreSources);
|
$(RestoreSources);
|
||||||
https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json;
|
https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json;
|
||||||
</RestoreSources>
|
</RestoreSources>
|
||||||
|
<!-- TODO remove this once we move Microsoft.AspNetCore.Blazor.Mono to a non-myget feed -->
|
||||||
|
<RestoreSources>
|
||||||
|
$(RestoreSources);
|
||||||
|
https://dotnet.myget.org/F/blazor-dev/api/v3/index.json;
|
||||||
|
</RestoreSources>
|
||||||
|
|
||||||
<!-- In an orchestrated build, this may be overriden to other Azure feeds. -->
|
<!-- In an orchestrated build, this may be overriden to other Azure feeds. -->
|
||||||
<DotNetAssetRootUrl Condition="'$(DotNetAssetRootUrl)'==''">https://dotnetcli.blob.core.windows.net/dotnet/</DotNetAssetRootUrl>
|
<DotNetAssetRootUrl Condition="'$(DotNetAssetRootUrl)'==''">https://dotnetcli.blob.core.windows.net/dotnet/</DotNetAssetRootUrl>
|
||||||
|
|
|
||||||
|
|
@ -165,7 +165,7 @@
|
||||||
<MicrosoftWebXdtPackageVersion>1.4.0</MicrosoftWebXdtPackageVersion>
|
<MicrosoftWebXdtPackageVersion>1.4.0</MicrosoftWebXdtPackageVersion>
|
||||||
<SystemIdentityModelTokensJwtPackageVersion>5.3.0</SystemIdentityModelTokensJwtPackageVersion>
|
<SystemIdentityModelTokensJwtPackageVersion>5.3.0</SystemIdentityModelTokensJwtPackageVersion>
|
||||||
<!-- Dependencies for Blazor. -->
|
<!-- Dependencies for Blazor. -->
|
||||||
<MicrosoftAspNetCoreBlazorMonoPackageVersion>0.10.0-preview-20190325.1</MicrosoftAspNetCoreBlazorMonoPackageVersion>
|
<MicrosoftAspNetCoreBlazorMonoPackageVersion>0.10.0-preview-20190523.1</MicrosoftAspNetCoreBlazorMonoPackageVersion>
|
||||||
<!-- Packages from 2.1/2.2 branches used for site extension build -->
|
<!-- Packages from 2.1/2.2 branches used for site extension build -->
|
||||||
<MicrosoftAspNetCoreAzureAppServicesSiteExtension21PackageVersion>2.1.1</MicrosoftAspNetCoreAzureAppServicesSiteExtension21PackageVersion>
|
<MicrosoftAspNetCoreAzureAppServicesSiteExtension21PackageVersion>2.1.1</MicrosoftAspNetCoreAzureAppServicesSiteExtension21PackageVersion>
|
||||||
<MicrosoftAspNetCoreAzureAppServicesSiteExtension22PackageVersion>2.2.0</MicrosoftAspNetCoreAzureAppServicesSiteExtension22PackageVersion>
|
<MicrosoftAspNetCoreAzureAppServicesSiteExtension22PackageVersion>2.2.0</MicrosoftAspNetCoreAzureAppServicesSiteExtension22PackageVersion>
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
<PropertyGroup Label="Blazor build outputs">
|
<PropertyGroup Label="Blazor build outputs">
|
||||||
<MonoLinkerI18NAssemblies>none</MonoLinkerI18NAssemblies> <!-- See Mono linker docs - allows comma-separated values from: none,all,cjk,mideast,other,rare,west -->
|
<MonoLinkerI18NAssemblies>none</MonoLinkerI18NAssemblies> <!-- See Mono linker docs - allows comma-separated values from: none,all,cjk,mideast,other,rare,west -->
|
||||||
<AdditionalMonoLinkerOptions>--verbose --strip-security true --exclude-feature com --exclude-feature sre -v false -c link -u link -b true</AdditionalMonoLinkerOptions>
|
<AdditionalMonoLinkerOptions>--disable-opt unreachablebodies --verbose --strip-security true --exclude-feature com --exclude-feature sre -v false -c link -u link -b true</AdditionalMonoLinkerOptions>
|
||||||
<BaseBlazorDistPath>dist/</BaseBlazorDistPath>
|
<BaseBlazorDistPath>dist/</BaseBlazorDistPath>
|
||||||
<BaseBlazorPackageContentOutputPath>$(BaseBlazorDistPath)_content/</BaseBlazorPackageContentOutputPath>
|
<BaseBlazorPackageContentOutputPath>$(BaseBlazorDistPath)_content/</BaseBlazorPackageContentOutputPath>
|
||||||
<BaseBlazorRuntimeOutputPath>$(BaseBlazorDistPath)_framework/</BaseBlazorRuntimeOutputPath>
|
<BaseBlazorRuntimeOutputPath>$(BaseBlazorDistPath)_framework/</BaseBlazorRuntimeOutputPath>
|
||||||
|
|
|
||||||
|
|
@ -1,20 +0,0 @@
|
||||||
@echo off
|
|
||||||
echo |----
|
|
||||||
echo | Copying the ws-proxy sources here is a temporary step until ws-proxy is
|
|
||||||
echo | distributed as a NuGet package.
|
|
||||||
echo | ...
|
|
||||||
echo | Instead of dealing with Git submodules, this script simply fetches the
|
|
||||||
echo | latest sources so they can be built directly inside this project (hence
|
|
||||||
echo | we don't have to publish our own separate package for this).
|
|
||||||
echo | ...
|
|
||||||
echo | When updating, you'll need to re-apply any patches we've made manually.
|
|
||||||
echo |----
|
|
||||||
@echo on
|
|
||||||
|
|
||||||
cd /D "%~dp0"
|
|
||||||
rmdir /s /q ws-proxy
|
|
||||||
git clone https://github.com/kumpera/ws-proxy.git
|
|
||||||
rmdir /s /q ws-proxy\.git
|
|
||||||
del ws-proxy\*.csproj
|
|
||||||
del ws-proxy\*.sln
|
|
||||||
del ws-proxy\Program.cs
|
|
||||||
|
|
@ -6,6 +6,9 @@ using Mono.Cecil.Cil;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
|
using Mono.Cecil.Pdb;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
namespace WsProxy {
|
namespace WsProxy {
|
||||||
internal class BreakPointRequest {
|
internal class BreakPointRequest {
|
||||||
|
|
@ -18,17 +21,29 @@ namespace WsProxy {
|
||||||
return $"BreakPointRequest Assembly: {Assembly} File: {File} Line: {Line} Column: {Column}";
|
return $"BreakPointRequest Assembly: {Assembly} File: {File} Line: {Line} Column: {Column}";
|
||||||
}
|
}
|
||||||
|
|
||||||
public static BreakPointRequest Parse (JObject args)
|
public static BreakPointRequest Parse (JObject args, DebugStore store)
|
||||||
{
|
{
|
||||||
if (args == null)
|
if (args == null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
var url = args? ["url"]?.Value<string> ();
|
var url = args? ["url"]?.Value<string> ();
|
||||||
if (!url.StartsWith ("dotnet://", StringComparison.InvariantCulture))
|
if (url == null) {
|
||||||
|
var urlRegex = args?["urlRegex"].Value<string>();
|
||||||
|
var sourceFile = store.GetFileByUrlRegex (urlRegex);
|
||||||
|
|
||||||
|
url = sourceFile?.DotNetUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (url != null && !url.StartsWith ("dotnet://", StringComparison.InvariantCulture)) {
|
||||||
|
var sourceFile = store.GetFileByUrl (url);
|
||||||
|
url = sourceFile?.DotNetUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (url == null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
var parts = url.Substring ("dotnet://".Length).Split ('/');
|
var parts = ParseDocumentUrl (url);
|
||||||
if (parts.Length != 2)
|
if (parts.Assembly == null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
var line = args? ["lineNumber"]?.Value<int> ();
|
var line = args? ["lineNumber"]?.Value<int> ();
|
||||||
|
|
@ -37,12 +52,24 @@ namespace WsProxy {
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
return new BreakPointRequest () {
|
return new BreakPointRequest () {
|
||||||
Assembly = parts [0],
|
Assembly = parts.Assembly,
|
||||||
File = parts [1],
|
File = parts.DocumentPath,
|
||||||
Line = line.Value,
|
Line = line.Value,
|
||||||
Column = column.Value
|
Column = column.Value
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static (string Assembly, string DocumentPath) ParseDocumentUrl (string url)
|
||||||
|
{
|
||||||
|
if (Uri.TryCreate (url, UriKind.Absolute, out var docUri) && docUri.Scheme == "dotnet") {
|
||||||
|
return (
|
||||||
|
docUri.Host,
|
||||||
|
docUri.PathAndQuery.Substring (1)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return (null, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -101,7 +128,7 @@ namespace WsProxy {
|
||||||
public SourceLocation (MethodInfo mi, SequencePoint sp)
|
public SourceLocation (MethodInfo mi, SequencePoint sp)
|
||||||
{
|
{
|
||||||
this.id = mi.SourceId;
|
this.id = mi.SourceId;
|
||||||
this.line = sp.StartLine;
|
this.line = sp.StartLine - 1;
|
||||||
this.column = sp.StartColumn - 1;
|
this.column = sp.StartColumn - 1;
|
||||||
this.cliLoc = new CliLocation (mi, sp.Offset);
|
this.cliLoc = new CliLocation (mi, sp.Offset);
|
||||||
}
|
}
|
||||||
|
|
@ -260,13 +287,13 @@ namespace WsProxy {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
internal class AssemblyInfo {
|
internal class AssemblyInfo {
|
||||||
static int next_id;
|
static int next_id;
|
||||||
ModuleDefinition image;
|
ModuleDefinition image;
|
||||||
readonly int id;
|
readonly int id;
|
||||||
Dictionary<int, MethodInfo> methods = new Dictionary<int, MethodInfo> ();
|
Dictionary<int, MethodInfo> methods = new Dictionary<int, MethodInfo> ();
|
||||||
readonly List<SourceFile> sources = new List<SourceFile> ();
|
Dictionary<string, string> sourceLinkMappings = new Dictionary<string, string>();
|
||||||
|
readonly List<SourceFile> sources = new List<SourceFile>();
|
||||||
|
|
||||||
public AssemblyInfo (byte[] assembly, byte[] pdb)
|
public AssemblyInfo (byte[] assembly, byte[] pdb)
|
||||||
{
|
{
|
||||||
|
|
@ -274,16 +301,35 @@ namespace WsProxy {
|
||||||
this.id = ++next_id;
|
this.id = ++next_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReaderParameters rp = new ReaderParameters (/*ReadingMode.Immediate*/);
|
try {
|
||||||
if (pdb != null) {
|
ReaderParameters rp = new ReaderParameters (/*ReadingMode.Immediate*/);
|
||||||
rp.ReadSymbols = true;
|
if (pdb != null) {
|
||||||
rp.SymbolReaderProvider = new PortablePdbReaderProvider ();
|
rp.ReadSymbols = true;
|
||||||
rp.SymbolStream = new MemoryStream (pdb);
|
rp.SymbolReaderProvider = new PortablePdbReaderProvider ();
|
||||||
|
rp.SymbolStream = new MemoryStream (pdb);
|
||||||
|
}
|
||||||
|
|
||||||
|
rp.ReadingMode = ReadingMode.Immediate;
|
||||||
|
rp.InMemory = true;
|
||||||
|
|
||||||
|
this.image = ModuleDefinition.ReadModule (new MemoryStream (assembly), rp);
|
||||||
|
} catch (BadImageFormatException ex) {
|
||||||
|
Console.WriteLine ($"Failed to read assembly as portable PDB: {ex.Message}");
|
||||||
}
|
}
|
||||||
|
|
||||||
rp.InMemory = true;
|
if (this.image == null) {
|
||||||
|
ReaderParameters rp = new ReaderParameters (/*ReadingMode.Immediate*/);
|
||||||
|
if (pdb != null) {
|
||||||
|
rp.ReadSymbols = true;
|
||||||
|
rp.SymbolReaderProvider = new NativePdbReaderProvider ();
|
||||||
|
rp.SymbolStream = new MemoryStream (pdb);
|
||||||
|
}
|
||||||
|
|
||||||
this.image = ModuleDefinition.ReadModule (new MemoryStream (assembly), rp);
|
rp.ReadingMode = ReadingMode.Immediate;
|
||||||
|
rp.InMemory = true;
|
||||||
|
|
||||||
|
this.image = ModuleDefinition.ReadModule (new MemoryStream (assembly), rp);
|
||||||
|
}
|
||||||
|
|
||||||
Populate ();
|
Populate ();
|
||||||
}
|
}
|
||||||
|
|
@ -294,6 +340,8 @@ namespace WsProxy {
|
||||||
|
|
||||||
void Populate ()
|
void Populate ()
|
||||||
{
|
{
|
||||||
|
ProcessSourceLink();
|
||||||
|
|
||||||
var d2s = new Dictionary<Document, SourceFile> ();
|
var d2s = new Dictionary<Document, SourceFile> ();
|
||||||
|
|
||||||
Func<Document, SourceFile> get_src = (doc) => {
|
Func<Document, SourceFile> get_src = (doc) => {
|
||||||
|
|
@ -301,33 +349,88 @@ namespace WsProxy {
|
||||||
return null;
|
return null;
|
||||||
if (d2s.ContainsKey (doc))
|
if (d2s.ContainsKey (doc))
|
||||||
return d2s [doc];
|
return d2s [doc];
|
||||||
var src = new SourceFile (this, sources.Count, doc);
|
var src = new SourceFile (this, sources.Count, doc, GetSourceLinkUrl (doc.Url));
|
||||||
sources.Add (src);
|
sources.Add (src);
|
||||||
d2s [doc] = src;
|
d2s [doc] = src;
|
||||||
return src;
|
return src;
|
||||||
};
|
};
|
||||||
|
|
||||||
foreach (var m in image.GetTypes ().SelectMany (t => t.Methods)) {
|
foreach (var m in image.GetTypes().SelectMany(t => t.Methods)) {
|
||||||
Document first_doc = null;
|
Document first_doc = null;
|
||||||
foreach (var sp in m.DebugInformation.SequencePoints) {
|
foreach (var sp in m.DebugInformation.SequencePoints) {
|
||||||
if (first_doc == null) {
|
if (first_doc == null && !sp.Document.Url.EndsWith (".g.cs")) {
|
||||||
first_doc = sp.Document;
|
first_doc = sp.Document;
|
||||||
} else if (first_doc != sp.Document) {
|
|
||||||
//FIXME this is needed for (c)ctors in corlib
|
|
||||||
throw new Exception ($"Cant handle multi-doc methods in {m}");
|
|
||||||
}
|
}
|
||||||
|
// else if (first_doc != sp.Document) {
|
||||||
|
// //FIXME this is needed for (c)ctors in corlib
|
||||||
|
// throw new Exception ($"Cant handle multi-doc methods in {m}");
|
||||||
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
var src = get_src (first_doc);
|
if (first_doc == null) {
|
||||||
var mi = new MethodInfo (this, m, src);
|
// all generated files
|
||||||
int mt = (int)m.MetadataToken.RID;
|
first_doc = m.DebugInformation.SequencePoints.FirstOrDefault ()?.Document;
|
||||||
this.methods [mt] = mi;
|
}
|
||||||
if (src != null)
|
|
||||||
src.AddMethod (mi);
|
|
||||||
|
|
||||||
|
if (first_doc != null) {
|
||||||
|
var src = get_src (first_doc);
|
||||||
|
var mi = new MethodInfo (this, m, src);
|
||||||
|
int mt = (int)m.MetadataToken.RID;
|
||||||
|
this.methods [mt] = mi;
|
||||||
|
if (src != null)
|
||||||
|
src.AddMethod (mi);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void ProcessSourceLink ()
|
||||||
|
{
|
||||||
|
var sourceLinkDebugInfo = image.CustomDebugInformations.FirstOrDefault (i => i.Kind == CustomDebugInformationKind.SourceLink);
|
||||||
|
|
||||||
|
if (sourceLinkDebugInfo != null) {
|
||||||
|
var sourceLinkContent = ((SourceLinkDebugInformation)sourceLinkDebugInfo).Content;
|
||||||
|
|
||||||
|
if (sourceLinkContent != null) {
|
||||||
|
var jObject = JObject.Parse (sourceLinkContent) ["documents"];
|
||||||
|
sourceLinkMappings = JsonConvert.DeserializeObject<Dictionary<string, string>> (jObject.ToString ());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Uri GetSourceLinkUrl (string document)
|
||||||
|
{
|
||||||
|
if (sourceLinkMappings.TryGetValue (document, out string url)) {
|
||||||
|
return new Uri (url);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var sourceLinkDocument in sourceLinkMappings) {
|
||||||
|
string key = sourceLinkDocument.Key;
|
||||||
|
|
||||||
|
if (Path.GetFileName (key) != "*") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var keyTrim = key.TrimEnd ('*');
|
||||||
|
|
||||||
|
if (document.StartsWith(keyTrim, StringComparison.OrdinalIgnoreCase)) {
|
||||||
|
var docUrlPart = document.Replace (keyTrim, "");
|
||||||
|
return new Uri (sourceLinkDocument.Value.TrimEnd ('*') + docUrlPart);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetRelativePath (string relativeTo, string path)
|
||||||
|
{
|
||||||
|
var uri = new Uri (relativeTo, UriKind.RelativeOrAbsolute);
|
||||||
|
var rel = Uri.UnescapeDataString (uri.MakeRelativeUri (new Uri (path, UriKind.RelativeOrAbsolute)).ToString ()).Replace (Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
|
||||||
|
if (rel.Contains (Path.DirectorySeparatorChar.ToString ()) == false) {
|
||||||
|
rel = $".{ Path.DirectorySeparatorChar }{ rel }";
|
||||||
|
}
|
||||||
|
return rel;
|
||||||
|
}
|
||||||
|
|
||||||
public IEnumerable<SourceFile> Sources {
|
public IEnumerable<SourceFile> Sources {
|
||||||
get { return this.sources; }
|
get { return this.sources; }
|
||||||
}
|
}
|
||||||
|
|
@ -342,9 +445,9 @@ namespace WsProxy {
|
||||||
|
|
||||||
public MethodInfo GetMethodByToken (int token)
|
public MethodInfo GetMethodByToken (int token)
|
||||||
{
|
{
|
||||||
return methods [token];
|
methods.TryGetValue (token, out var value);
|
||||||
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class SourceFile {
|
internal class SourceFile {
|
||||||
|
|
@ -353,23 +456,36 @@ namespace WsProxy {
|
||||||
int id;
|
int id;
|
||||||
Document doc;
|
Document doc;
|
||||||
|
|
||||||
internal SourceFile (AssemblyInfo assembly, int id, Document doc)
|
internal SourceFile (AssemblyInfo assembly, int id, Document doc, Uri sourceLinkUri)
|
||||||
{
|
{
|
||||||
this.methods = new HashSet<MethodInfo> ();
|
this.methods = new HashSet<MethodInfo> ();
|
||||||
|
this.SourceLinkUri = sourceLinkUri;
|
||||||
this.assembly = assembly;
|
this.assembly = assembly;
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.doc = doc;
|
this.doc = doc;
|
||||||
|
this.DebuggerFileName = doc.Url.Replace ("\\", "/").Replace (":", "");
|
||||||
|
|
||||||
|
this.SourceUri = new Uri ((Path.IsPathRooted (doc.Url) ? "file://" : "") + doc.Url, UriKind.RelativeOrAbsolute);
|
||||||
|
if (SourceUri.IsFile && File.Exists (SourceUri.LocalPath)) {
|
||||||
|
this.Url = this.SourceUri.ToString ();
|
||||||
|
} else {
|
||||||
|
this.Url = DotNetUrl;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void AddMethod (MethodInfo mi)
|
internal void AddMethod (MethodInfo mi)
|
||||||
{
|
{
|
||||||
this.methods.Add (mi);
|
this.methods.Add (mi);
|
||||||
}
|
}
|
||||||
public string FileName => Path.GetFileName (doc.Url);
|
public string DebuggerFileName { get; }
|
||||||
public string Url => $"dotnet://{assembly.Name}/{FileName}";
|
public string Url { get; }
|
||||||
|
public string AssemblyName => assembly.Name;
|
||||||
|
public string DotNetUrl => $"dotnet://{assembly.Name}/{DebuggerFileName}";
|
||||||
public string DocHashCode => "abcdee" + id;
|
public string DocHashCode => "abcdee" + id;
|
||||||
public SourceId SourceId => new SourceId (assembly.Id, this.id);
|
public SourceId SourceId => new SourceId (assembly.Id, this.id);
|
||||||
public string LocalPath => doc.Url;
|
public Uri SourceLinkUri { get; }
|
||||||
|
public Uri SourceUri { get; }
|
||||||
|
|
||||||
public IEnumerable<MethodInfo> Methods => this.methods;
|
public IEnumerable<MethodInfo> Methods => this.methods;
|
||||||
}
|
}
|
||||||
|
|
@ -377,17 +493,18 @@ namespace WsProxy {
|
||||||
internal class DebugStore {
|
internal class DebugStore {
|
||||||
List<AssemblyInfo> assemblies = new List<AssemblyInfo> ();
|
List<AssemblyInfo> assemblies = new List<AssemblyInfo> ();
|
||||||
|
|
||||||
public DebugStore (string[] loaded_files)
|
public DebugStore (string [] loaded_files)
|
||||||
{
|
{
|
||||||
bool MatchPdb (string asm, string pdb) {
|
bool MatchPdb (string asm, string pdb)
|
||||||
|
{
|
||||||
return Path.ChangeExtension (asm, "pdb") == pdb;
|
return Path.ChangeExtension (asm, "pdb") == pdb;
|
||||||
}
|
}
|
||||||
|
|
||||||
var asm_files = new List<string> ();
|
var asm_files = new List<string> ();
|
||||||
var pdb_files = new List<string> ();
|
var pdb_files = new List<string> ();
|
||||||
foreach (var f in loaded_files) {
|
foreach (var f in loaded_files) {
|
||||||
var file_name = f.ToLower ();
|
var file_name = f;
|
||||||
if (file_name.EndsWith (".pdb", StringComparison.Ordinal))
|
if (file_name.EndsWith (".pdb", StringComparison.OrdinalIgnoreCase))
|
||||||
pdb_files.Add (file_name);
|
pdb_files.Add (file_name);
|
||||||
else
|
else
|
||||||
asm_files.Add (file_name);
|
asm_files.Add (file_name);
|
||||||
|
|
@ -395,14 +512,18 @@ namespace WsProxy {
|
||||||
|
|
||||||
//FIXME make this parallel
|
//FIXME make this parallel
|
||||||
foreach (var p in asm_files) {
|
foreach (var p in asm_files) {
|
||||||
var pdb = pdb_files.FirstOrDefault (n => MatchPdb (p, n));
|
try {
|
||||||
HttpClient h = new HttpClient ();
|
var pdb = pdb_files.FirstOrDefault (n => MatchPdb (p, n));
|
||||||
var assembly_bytes = h.GetByteArrayAsync (p).Result;
|
HttpClient h = new HttpClient ();
|
||||||
byte[] pdb_bytes = null;
|
var assembly_bytes = h.GetByteArrayAsync (p).Result;
|
||||||
if (pdb != null)
|
byte [] pdb_bytes = null;
|
||||||
pdb_bytes = h.GetByteArrayAsync (pdb).Result;
|
if (pdb != null)
|
||||||
|
pdb_bytes = h.GetByteArrayAsync (pdb).Result;
|
||||||
|
|
||||||
this.assemblies.Add (new AssemblyInfo (assembly_bytes, pdb_bytes));
|
this.assemblies.Add (new AssemblyInfo (assembly_bytes, pdb_bytes));
|
||||||
|
} catch (Exception e) {
|
||||||
|
Console.WriteLine ($"Failed to read {p} ({e.Message})");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -412,7 +533,6 @@ namespace WsProxy {
|
||||||
foreach (var s in a.Sources)
|
foreach (var s in a.Sources)
|
||||||
yield return s;
|
yield return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public SourceFile GetFileById (SourceId id)
|
public SourceFile GetFileById (SourceId id)
|
||||||
|
|
@ -426,26 +546,23 @@ namespace WsProxy {
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Matching logic here is hilarious and it goes like this:
|
|
||||||
We inject one line at the top of all sources to make it easy to identify them [1].
|
|
||||||
V8 uses zero based indexing for both line and column.
|
V8 uses zero based indexing for both line and column.
|
||||||
PPDBs uses one based indexing for both line and column.
|
PPDBs uses one based indexing for both line and column.
|
||||||
Which means that:
|
|
||||||
- for lines, values are already adjusted (v8 numbers come +1 due to the injected line)
|
|
||||||
- for columns, we need to +1 the v8 numbers
|
|
||||||
[1] It's so we can deal with the Runtime.compileScript ide cmd
|
|
||||||
*/
|
*/
|
||||||
static bool Match (SequencePoint sp, SourceLocation start, SourceLocation end)
|
static bool Match (SequencePoint sp, SourceLocation start, SourceLocation end)
|
||||||
{
|
{
|
||||||
if (start.Line > sp.StartLine)
|
var spStart = (Line: sp.StartLine - 1, Column: sp.StartColumn - 1);
|
||||||
|
var spEnd = (Line: sp.EndLine - 1, Column: sp.EndColumn - 1);
|
||||||
|
|
||||||
|
if (start.Line > spStart.Line)
|
||||||
return false;
|
return false;
|
||||||
if ((start.Column + 1) > sp.StartColumn && start.Line == sp.StartLine)
|
if (start.Column > spStart.Column && start.Line == sp.StartLine)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (end.Line < sp.EndLine)
|
if (end.Line < spEnd.Line)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if ((end.Column + 1) < sp.EndColumn && end.Line == sp.EndLine)
|
if (end.Column < spEnd.Column && end.Line == spEnd.Line)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -477,28 +594,24 @@ namespace WsProxy {
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Matching logic here is hilarious and it goes like this:
|
|
||||||
We inject one line at the top of all sources to make it easy to identify them [1].
|
|
||||||
V8 uses zero based indexing for both line and column.
|
V8 uses zero based indexing for both line and column.
|
||||||
PPDBs uses one based indexing for both line and column.
|
PPDBs uses one based indexing for both line and column.
|
||||||
Which means that:
|
|
||||||
- for lines, values are already adjusted (v8 numbers come + 1 due to the injected line)
|
|
||||||
- for columns, we need to +1 the v8 numbers
|
|
||||||
[1] It's so we can deal with the Runtime.compileScript ide cmd
|
|
||||||
*/
|
*/
|
||||||
static bool Match (SequencePoint sp, int line, int column)
|
static bool Match (SequencePoint sp, int line, int column)
|
||||||
{
|
{
|
||||||
if (sp.StartLine > line || sp.EndLine < line)
|
var bp = (line: line + 1, column: column + 1);
|
||||||
|
|
||||||
|
if (sp.StartLine > bp.line || sp.EndLine < bp.line)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
//Chrome sends a zero column even if getPossibleBreakpoints say something else
|
//Chrome sends a zero column even if getPossibleBreakpoints say something else
|
||||||
if (column == 0)
|
if (column == 0)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (sp.StartColumn > (column + 1) && sp.StartLine == line)
|
if (sp.StartColumn > bp.column && sp.StartLine == bp.line)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (sp.EndColumn < (column + 1) && sp.EndLine == line)
|
if (sp.EndColumn < bp.column && sp.EndLine == bp.line)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -506,8 +619,11 @@ namespace WsProxy {
|
||||||
|
|
||||||
public SourceLocation FindBestBreakpoint (BreakPointRequest req)
|
public SourceLocation FindBestBreakpoint (BreakPointRequest req)
|
||||||
{
|
{
|
||||||
var asm = this.assemblies.FirstOrDefault (a => a.Name == req.Assembly);
|
var asm = assemblies.FirstOrDefault (a => a.Name.Equals (req.Assembly, StringComparison.OrdinalIgnoreCase));
|
||||||
var src = asm.Sources.FirstOrDefault (s => s.FileName == req.File);
|
var src = asm?.Sources?.FirstOrDefault (s => s.DebuggerFileName.Equals (req.File, StringComparison.OrdinalIgnoreCase));
|
||||||
|
|
||||||
|
if (src == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
foreach (var m in src.Methods) {
|
foreach (var m in src.Methods) {
|
||||||
foreach (var sp in m.methodDef.DebugInformation.SequencePoints) {
|
foreach (var sp in m.methodDef.DebugInformation.SequencePoints) {
|
||||||
|
|
@ -521,8 +637,15 @@ namespace WsProxy {
|
||||||
}
|
}
|
||||||
|
|
||||||
public string ToUrl (SourceLocation location)
|
public string ToUrl (SourceLocation location)
|
||||||
|
=> location != null ? GetFileById (location.Id).Url : "";
|
||||||
|
|
||||||
|
public SourceFile GetFileByUrlRegex (string urlRegex)
|
||||||
{
|
{
|
||||||
return GetFileById (location.Id).Url;
|
var regex = new Regex (urlRegex);
|
||||||
|
return AllSources ().FirstOrDefault (file => regex.IsMatch (file.Url.ToString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public SourceFile GetFileByUrl (string url)
|
||||||
|
=> AllSources ().FirstOrDefault (file => file.Url.ToString() == url);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ using System.Threading;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Net;
|
||||||
|
|
||||||
namespace WsProxy {
|
namespace WsProxy {
|
||||||
|
|
||||||
|
|
@ -20,6 +21,8 @@ namespace WsProxy {
|
||||||
public const string REMOVE_BREAK_POINT = "MONO.mono_wasm_remove_breakpoint({0})";
|
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 GET_LOADED_FILES = "MONO.mono_wasm_get_loaded_files()";
|
||||||
public const string CLEAR_ALL_BREAKPOINTS = "MONO.mono_wasm_clear_all_breakpoints()";
|
public const string CLEAR_ALL_BREAKPOINTS = "MONO.mono_wasm_clear_all_breakpoints()";
|
||||||
|
public const string GET_OBJECT_PROPERTIES = "MONO.mono_wasm_get_object_properties({0})";
|
||||||
|
public const string GET_ARRAY_VALUES = "MONO.mono_wasm_get_array_values({0})";
|
||||||
}
|
}
|
||||||
|
|
||||||
internal enum MonoErrorCodes {
|
internal enum MonoErrorCodes {
|
||||||
|
|
@ -128,7 +131,7 @@ namespace WsProxy {
|
||||||
case "Debugger.getScriptSource": {
|
case "Debugger.getScriptSource": {
|
||||||
var script_id = args? ["scriptId"]?.Value<string> ();
|
var script_id = args? ["scriptId"]?.Value<string> ();
|
||||||
if (script_id.StartsWith ("dotnet://", StringComparison.InvariantCultureIgnoreCase)) {
|
if (script_id.StartsWith ("dotnet://", StringComparison.InvariantCultureIgnoreCase)) {
|
||||||
OnGetScriptSource (id, script_id, token);
|
await OnGetScriptSource (id, script_id, token);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -154,7 +157,7 @@ namespace WsProxy {
|
||||||
|
|
||||||
case "Debugger.setBreakpointByUrl": {
|
case "Debugger.setBreakpointByUrl": {
|
||||||
Info ($"BP req {args}");
|
Info ($"BP req {args}");
|
||||||
var bp_req = BreakPointRequest.Parse (args);
|
var bp_req = BreakPointRequest.Parse (args, store);
|
||||||
if (bp_req != null) {
|
if (bp_req != null) {
|
||||||
await SetBreakPoint (id, bp_req, token);
|
await SetBreakPoint (id, bp_req, token);
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -200,7 +203,14 @@ namespace WsProxy {
|
||||||
await GetScopeProperties (id, int.Parse (objId.Substring ("dotnet:scope:".Length)), token);
|
await GetScopeProperties (id, int.Parse (objId.Substring ("dotnet:scope:".Length)), token);
|
||||||
return true;
|
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);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -213,6 +223,7 @@ namespace WsProxy {
|
||||||
Info ("RUNTIME READY, PARTY TIME");
|
Info ("RUNTIME READY, PARTY TIME");
|
||||||
await RuntimeReady (token);
|
await RuntimeReady (token);
|
||||||
await SendCommand ("Debugger.resume", new JObject (), token);
|
await SendCommand ("Debugger.resume", new JObject (), token);
|
||||||
|
SendEvent ("Mono.runtimeReady", new JObject (), token);
|
||||||
}
|
}
|
||||||
|
|
||||||
async Task OnBreakPointHit (JObject args, CancellationToken token)
|
async Task OnBreakPointHit (JObject args, CancellationToken token)
|
||||||
|
|
@ -257,9 +268,9 @@ namespace WsProxy {
|
||||||
var src = bp == null ? null : store.GetFileById (bp.Location.Id);
|
var src = bp == null ? null : store.GetFileById (bp.Location.Id);
|
||||||
|
|
||||||
var callFrames = new List<JObject> ();
|
var callFrames = new List<JObject> ();
|
||||||
foreach (var f in orig_callframes) {
|
foreach (var frame in orig_callframes) {
|
||||||
var function_name = f ["functionName"]?.Value<string> ();
|
var function_name = frame ["functionName"]?.Value<string> ();
|
||||||
var url = f ["url"]?.Value<string> ();
|
var url = frame ["url"]?.Value<string> ();
|
||||||
if ("mono_wasm_fire_bp" == function_name || "_mono_wasm_fire_bp" == function_name) {
|
if ("mono_wasm_fire_bp" == function_name || "_mono_wasm_fire_bp" == function_name) {
|
||||||
var frames = new List<Frame> ();
|
var frames = new List<Frame> ();
|
||||||
int frame_id = 0;
|
int frame_id = 0;
|
||||||
|
|
@ -271,14 +282,19 @@ namespace WsProxy {
|
||||||
|
|
||||||
var asm = store.GetAssemblyByName (assembly_name);
|
var asm = store.GetAssemblyByName (assembly_name);
|
||||||
var method = asm.GetMethodByToken (method_token);
|
var method = asm.GetMethodByToken (method_token);
|
||||||
var location = method.GetLocationByIl (il_pos);
|
|
||||||
|
if (method == null) {
|
||||||
|
Info ($"Unable to find il offset: {il_pos} in method token: {method_token} assembly name: {assembly_name}");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var location = method?.GetLocationByIl (il_pos);
|
||||||
|
|
||||||
// When hitting a breakpoint on the "IncrementCount" method in the standard
|
// When hitting a breakpoint on the "IncrementCount" method in the standard
|
||||||
// Blazor project template, one of the stack frames is inside mscorlib.dll
|
// Blazor project template, one of the stack frames is inside mscorlib.dll
|
||||||
// and we get location==null for it. It will trigger a NullReferenceException
|
// and we get location==null for it. It will trigger a NullReferenceException
|
||||||
// if we don't skip over that stack frame.
|
// if we don't skip over that stack frame.
|
||||||
if (location == null)
|
if (location == null) {
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -288,7 +304,7 @@ namespace WsProxy {
|
||||||
|
|
||||||
callFrames.Add (JObject.FromObject (new {
|
callFrames.Add (JObject.FromObject (new {
|
||||||
functionName = method.Name,
|
functionName = method.Name,
|
||||||
|
callFrameId = $"dotnet:scope:{frame_id}",
|
||||||
functionLocation = method.StartLocation.ToJObject (),
|
functionLocation = method.StartLocation.ToJObject (),
|
||||||
|
|
||||||
location = location.ToJObject (),
|
location = location.ToJObject (),
|
||||||
|
|
@ -300,25 +316,24 @@ namespace WsProxy {
|
||||||
type = "local",
|
type = "local",
|
||||||
@object = new {
|
@object = new {
|
||||||
@type = "object",
|
@type = "object",
|
||||||
className = "Object",
|
className = "Object",
|
||||||
description = "Object",
|
description = "Object",
|
||||||
objectId = $"dotnet:scope:{frame_id}"
|
objectId = $"dotnet:scope:{frame_id}",
|
||||||
},
|
},
|
||||||
name = method.Name,
|
name = method.Name,
|
||||||
startLocation = method.StartLocation.ToJObject (),
|
startLocation = method.StartLocation.ToJObject (),
|
||||||
endLocation = method.EndLocation.ToJObject (),
|
endLocation = method.EndLocation.ToJObject (),
|
||||||
}
|
}},
|
||||||
},
|
@this = new { }
|
||||||
|
|
||||||
@this = new {
|
|
||||||
}
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
++frame_id;
|
++frame_id;
|
||||||
this.current_callstack = frames;
|
this.current_callstack = frames;
|
||||||
|
|
||||||
}
|
}
|
||||||
} else if (!url.StartsWith ("wasm://wasm/", StringComparison.InvariantCulture)) {
|
} else if (!(function_name.StartsWith ("wasm-function", StringComparison.InvariantCulture)
|
||||||
callFrames.Add (f);
|
|| url.StartsWith ("wasm://wasm/", StringComparison.InvariantCulture))) {
|
||||||
|
callFrames.Add (frame);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -393,6 +408,57 @@ namespace WsProxy {
|
||||||
await SendCommand ("Debugger.resume", new JObject (), token);
|
await SendCommand ("Debugger.resume", new JObject (), token);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async Task GetDetails(int msg_id, int object_id, CancellationToken token, string command)
|
||||||
|
{
|
||||||
|
var o = JObject.FromObject(new
|
||||||
|
{
|
||||||
|
expression = string.Format(command, object_id),
|
||||||
|
objectGroup = "mono_debugger",
|
||||||
|
includeCommandLineAPI = false,
|
||||||
|
silent = false,
|
||||||
|
returnByValue = true,
|
||||||
|
});
|
||||||
|
|
||||||
|
var res = await SendCommand("Runtime.evaluate", o, token);
|
||||||
|
|
||||||
|
//if we fail we just buble that to the IDE (and let it panic over it)
|
||||||
|
if (res.IsErr)
|
||||||
|
{
|
||||||
|
SendResponse(msg_id, res, token);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var values = res.Value?["result"]?["value"]?.Values<JObject>().ToArray();
|
||||||
|
|
||||||
|
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.
|
||||||
|
for (int i = 0; i < values.Length; i+=2)
|
||||||
|
{
|
||||||
|
string fieldName = (string)values[i]["name"];
|
||||||
|
if (fieldName.Contains("k__BackingField")){
|
||||||
|
fieldName = fieldName.Replace("k__BackingField", "");
|
||||||
|
fieldName = fieldName.Replace("<", "");
|
||||||
|
fieldName = fieldName.Replace(">", "");
|
||||||
|
}
|
||||||
|
var_list.Add(JObject.FromObject(new
|
||||||
|
{
|
||||||
|
name = fieldName,
|
||||||
|
value = values[i+1]["value"]
|
||||||
|
}));
|
||||||
|
|
||||||
|
}
|
||||||
|
o = JObject.FromObject(new
|
||||||
|
{
|
||||||
|
result = var_list
|
||||||
|
});
|
||||||
|
|
||||||
|
SendResponse(msg_id, Result.Ok(o), token);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
async Task GetScopeProperties (int msg_id, int scope_id, CancellationToken token)
|
async Task GetScopeProperties (int msg_id, int scope_id, CancellationToken token)
|
||||||
{
|
{
|
||||||
var scope = this.current_callstack.FirstOrDefault (s => s.Id == scope_id);
|
var scope = this.current_callstack.FirstOrDefault (s => s.Id == scope_id);
|
||||||
|
|
@ -425,6 +491,10 @@ namespace WsProxy {
|
||||||
// results in a "Memory access out of bounds", causing 'values' to be null,
|
// results in a "Memory access out of bounds", causing 'values' to be null,
|
||||||
// so skip returning variable values in that case.
|
// so skip returning variable values in that case.
|
||||||
for (int i = 0; values != null && i < vars.Length; ++i) {
|
for (int i = 0; values != null && i < vars.Length; ++i) {
|
||||||
|
var value = values [i] ["value"];
|
||||||
|
if (((string)value ["description"]) == null)
|
||||||
|
value ["description"] = value ["value"]?.ToString();
|
||||||
|
|
||||||
var_list.Add (JObject.FromObject (new {
|
var_list.Add (JObject.FromObject (new {
|
||||||
name = vars [i].Name,
|
name = vars [i].Name,
|
||||||
value = values [i] ["value"]
|
value = values [i] ["value"]
|
||||||
|
|
@ -485,7 +555,8 @@ namespace WsProxy {
|
||||||
url = s.Url,
|
url = s.Url,
|
||||||
executionContextId = this.ctx_id,
|
executionContextId = this.ctx_id,
|
||||||
hash = s.DocHashCode,
|
hash = s.DocHashCode,
|
||||||
executionContextAuxData = this.aux_ctx_data
|
executionContextAuxData = this.aux_ctx_data,
|
||||||
|
dotNetUrl = s.DotNetUrl
|
||||||
});
|
});
|
||||||
//Debug ($"\tsending {s.Url}");
|
//Debug ($"\tsending {s.Url}");
|
||||||
SendEvent ("Debugger.scriptParsed", ok, token);
|
SendEvent ("Debugger.scriptParsed", ok, token);
|
||||||
|
|
@ -640,23 +711,51 @@ namespace WsProxy {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnGetScriptSource (int msg_id, string script_id, CancellationToken token)
|
async Task OnGetScriptSource (int msg_id, string script_id, CancellationToken token)
|
||||||
{
|
{
|
||||||
var id = new SourceId (script_id);
|
var id = new SourceId (script_id);
|
||||||
var src_file = store.GetFileById (id);
|
var src_file = store.GetFileById (id);
|
||||||
|
|
||||||
var res = new StringWriter ();
|
var res = new StringWriter ();
|
||||||
res.WriteLine ($"//dotnet:{id}");
|
//res.WriteLine ($"//{id}");
|
||||||
|
|
||||||
using (var f = new StreamReader (File.Open (src_file.LocalPath, FileMode.Open))) {
|
try {
|
||||||
res.Write (f.ReadToEnd ());
|
var uri = new Uri (src_file.Url);
|
||||||
|
if (uri.IsFile && File.Exists(uri.LocalPath)) {
|
||||||
|
using (var f = new StreamReader (File.Open (src_file.SourceUri.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.SourceLinkUri != null) {
|
||||||
|
var doc = await new WebClient ().DownloadStringTaskAsync (src_file.SourceLinkUri);
|
||||||
|
await res.WriteAsync (doc);
|
||||||
|
|
||||||
|
var o = JObject.FromObject (new {
|
||||||
|
scriptSource = res.ToString ()
|
||||||
|
});
|
||||||
|
|
||||||
|
SendResponse (msg_id, Result.Ok (o), token);
|
||||||
|
} else {
|
||||||
|
var o = JObject.FromObject (new {
|
||||||
|
scriptSource = $"// Unable to find document {src_file.SourceUri}"
|
||||||
|
});
|
||||||
|
|
||||||
|
SendResponse (msg_id, Result.Ok (o), token);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
var o = JObject.FromObject (new {
|
||||||
|
scriptSource = $"// Unable to read document ({e.Message})\n" +
|
||||||
|
$"Local path: {src_file?.SourceUri}\n" +
|
||||||
|
$"SourceLink path: {src_file?.SourceLinkUri}\n"
|
||||||
|
});
|
||||||
|
|
||||||
|
SendResponse (msg_id, Result.Ok (o), token);
|
||||||
}
|
}
|
||||||
|
|
||||||
var o = JObject.FromObject (new {
|
|
||||||
scriptSource = res.ToString ()
|
|
||||||
});
|
|
||||||
|
|
||||||
SendResponse (msg_id, Result.Ok (o), token);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -144,7 +144,7 @@ namespace WsProxy {
|
||||||
|
|
||||||
void Send (WebSocket to, JObject o, CancellationToken token)
|
void Send (WebSocket to, JObject o, CancellationToken token)
|
||||||
{
|
{
|
||||||
var bytes = Encoding.UTF8.GetBytes (o.ToString ());
|
var bytes = Encoding.UTF8.GetBytes (o.ToString ());
|
||||||
|
|
||||||
var queue = GetQueueForSocket (to);
|
var queue = GetQueueForSocket (to);
|
||||||
var task = queue.Send (bytes, token);
|
var task = queue.Send (bytes, token);
|
||||||
|
|
@ -256,7 +256,7 @@ namespace WsProxy {
|
||||||
}
|
}
|
||||||
|
|
||||||
// , HttpContext context)
|
// , HttpContext context)
|
||||||
public async Task Run (Uri browserUri, WebSocket ideSocket)
|
public async Task Run (Uri browserUri, WebSocket ideSocket)
|
||||||
{
|
{
|
||||||
Debug ("wsproxy start");
|
Debug ("wsproxy start");
|
||||||
using (this.ide = ideSocket) {
|
using (this.ide = ideSocket) {
|
||||||
|
|
@ -276,7 +276,7 @@ namespace WsProxy {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
while (!x.IsCancellationRequested) {
|
while (!x.IsCancellationRequested) {
|
||||||
var task = await Task.WhenAny (pending_ops);
|
var task = await Task.WhenAny (pending_ops.ToArray ());
|
||||||
//Console.WriteLine ("pump {0} {1}", task, pending_ops.IndexOf (task));
|
//Console.WriteLine ("pump {0} {1}", task, pending_ops.IndexOf (task));
|
||||||
if (task == pending_ops [0]) {
|
if (task == pending_ops [0]) {
|
||||||
var msg = ((Task<string>)task).Result;
|
var msg = ((Task<string>)task).Result;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue