Support new config options to launch the Node process with a debug listener. This is compatible with node-inspector.

This commit is contained in:
SteveSandersonMS
2016-07-26 18:33:27 +01:00
parent 79872c1bde
commit f2f67fe880
5 changed files with 60 additions and 13 deletions

View File

@@ -68,10 +68,12 @@ namespace Microsoft.AspNetCore.NodeServices
switch (options.HostingModel)
{
case NodeHostingModel.Http:
return new HttpNodeInstance(options.ProjectPath, options.WatchFileExtensions, logger, /* port */ 0);
return new HttpNodeInstance(options.ProjectPath, options.WatchFileExtensions, logger,
options.LaunchWithDebugging, options.DebuggingPort, /* port */ 0);
case NodeHostingModel.Socket:
var pipeName = "pni-" + Guid.NewGuid().ToString("D"); // Arbitrary non-clashing string
return new SocketNodeInstance(options.ProjectPath, options.WatchFileExtensions, pipeName, logger);
return new SocketNodeInstance(options.ProjectPath, options.WatchFileExtensions, pipeName, logger,
options.LaunchWithDebugging, options.DebuggingPort);
default:
throw new ArgumentException("Unknown hosting model: " + options.HostingModel);
}

View File

@@ -21,5 +21,7 @@ namespace Microsoft.AspNetCore.NodeServices
public string ProjectPath { get; set; }
public string[] WatchFileExtensions { get; set; }
public ILogger NodeInstanceOutputLogger { get; set; }
public bool LaunchWithDebugging { get; set; }
public int? DebuggingPort { get; set; }
}
}

View File

@@ -33,7 +33,8 @@ namespace Microsoft.AspNetCore.NodeServices.HostingModels
private bool _disposed;
private int _portNumber;
public HttpNodeInstance(string projectPath, string[] watchFileExtensions, ILogger nodeInstanceOutputLogger, int port = 0)
public HttpNodeInstance(string projectPath, string[] watchFileExtensions, ILogger nodeInstanceOutputLogger,
bool launchWithDebugging, int? debuggingPort, int port = 0)
: base(
EmbeddedResourceReader.Read(
typeof(HttpNodeInstance),
@@ -41,7 +42,9 @@ namespace Microsoft.AspNetCore.NodeServices.HostingModels
projectPath,
watchFileExtensions,
MakeCommandLineOptions(port),
nodeInstanceOutputLogger)
nodeInstanceOutputLogger,
launchWithDebugging,
debuggingPort)
{
_client = new HttpClient();
}

View File

@@ -21,11 +21,22 @@ namespace Microsoft.AspNetCore.NodeServices.HostingModels
{
protected readonly ILogger OutputLogger;
private const string ConnectionEstablishedMessage = "[Microsoft.AspNetCore.NodeServices:Listening]";
private const string DebuggingStartedMessageFormat = @"-----
*** Node.js debugging is enabled ***
{0}
To debug, run:
node-inspector{1}
If you haven't yet installed node-inspector, you can do so as follows:
npm install -g node-inspector
-----";
private readonly TaskCompletionSource<object> _connectionIsReadySource = new TaskCompletionSource<object>();
private bool _disposed;
private readonly StringAsTempFile _entryPointScript;
private FileSystemWatcher _fileSystemWatcher;
private readonly Process _nodeProcess;
private int? _nodeDebuggingPort;
private bool _nodeProcessNeedsRestart;
private readonly string[] _watchFileExtensions;
@@ -34,7 +45,9 @@ namespace Microsoft.AspNetCore.NodeServices.HostingModels
string projectPath,
string[] watchFileExtensions,
string commandLineArguments,
ILogger nodeOutputLogger)
ILogger nodeOutputLogger,
bool launchWithDebugging,
int? debuggingPort)
{
if (nodeOutputLogger == null)
{
@@ -44,7 +57,8 @@ namespace Microsoft.AspNetCore.NodeServices.HostingModels
OutputLogger = nodeOutputLogger;
_entryPointScript = new StringAsTempFile(entryPointScript);
var startInfo = PrepareNodeProcessStartInfo(_entryPointScript.FileName, projectPath, commandLineArguments);
var startInfo = PrepareNodeProcessStartInfo(_entryPointScript.FileName, projectPath, commandLineArguments,
launchWithDebugging, debuggingPort);
_nodeProcess = LaunchNodeProcess(startInfo);
_watchFileExtensions = watchFileExtensions;
_fileSystemWatcher = BeginFileWatcher(projectPath);
@@ -84,11 +98,23 @@ namespace Microsoft.AspNetCore.NodeServices.HostingModels
// This method is virtual, as it provides a way to override the NODE_PATH or the path to node.exe
protected virtual ProcessStartInfo PrepareNodeProcessStartInfo(
string entryPointFilename, string projectPath, string commandLineArguments)
string entryPointFilename, string projectPath, string commandLineArguments,
bool launchWithDebugging, int? debuggingPort)
{
string debuggingArgs;
if (launchWithDebugging)
{
debuggingArgs = debuggingPort.HasValue ? $"--debug={debuggingPort.Value} " : "--debug ";
_nodeDebuggingPort = debuggingPort;
}
else
{
debuggingArgs = string.Empty;
}
var startInfo = new ProcessStartInfo("node")
{
Arguments = "\"" + entryPointFilename + "\" " + (commandLineArguments ?? string.Empty),
Arguments = debuggingArgs + "\"" + entryPointFilename + "\" " + (commandLineArguments ?? string.Empty),
UseShellExecute = false,
RedirectStandardInput = true,
RedirectStandardOutput = true,
@@ -201,7 +227,12 @@ namespace Microsoft.AspNetCore.NodeServices.HostingModels
{
if (evt.Data != null)
{
if (!initializationIsCompleted)
if (IsDebuggerListeningMessage(evt.Data))
{
var debugPortArg = _nodeDebuggingPort.HasValue ? $" --debug-port={_nodeDebuggingPort.Value}" : string.Empty;
OutputLogger.LogWarning(string.Format(DebuggingStartedMessageFormat, evt.Data, debugPortArg));
}
else if (!initializationIsCompleted)
{
_connectionIsReadySource.SetException(
new InvalidOperationException("The Node.js process failed to initialize: " + evt.Data));
@@ -218,6 +249,11 @@ namespace Microsoft.AspNetCore.NodeServices.HostingModels
_nodeProcess.BeginErrorReadLine();
}
private static bool IsDebuggerListeningMessage(string message)
{
return message.StartsWith("Debugger listening on port ", StringComparison.OrdinalIgnoreCase);
}
private FileSystemWatcher BeginFileWatcher(string rootDir)
{
if (_watchFileExtensions == null || _watchFileExtensions.Length == 0)

View File

@@ -37,14 +37,18 @@ namespace Microsoft.AspNetCore.NodeServices.HostingModels
private string _socketAddress;
private VirtualConnectionClient _virtualConnectionClient;
public SocketNodeInstance(string projectPath, string[] watchFileExtensions, string socketAddress, ILogger nodeInstanceOutputLogger) : base(
public SocketNodeInstance(string projectPath, string[] watchFileExtensions, string socketAddress,
ILogger nodeInstanceOutputLogger, bool launchWithDebugging, int? debuggingPort)
: base(
EmbeddedResourceReader.Read(
typeof(SocketNodeInstance),
"/Content/Node/entrypoint-socket.js"),
projectPath,
watchFileExtensions,
MakeNewCommandLineOptions(socketAddress),
nodeInstanceOutputLogger)
nodeInstanceOutputLogger,
launchWithDebugging,
debuggingPort)
{
_socketAddress = socketAddress;
}