-
Notifications
You must be signed in to change notification settings - Fork 223
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Adds ability to use separate pipes for reading and writing #785
Changes from 5 commits
9db4d7e
ea65162
8d20b53
c47e80b
4e747a1
0189966
569c223
93a391f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -15,7 +15,7 @@ | |||||
# Services GitHub repository: | ||||||
# | ||||||
# https://github.com/PowerShell/PowerShellEditorServices/blob/master/module/PowerShellEditorServices/Start-EditorServices.ps1 | ||||||
|
||||||
[Cmdletbinding(DefaultParameterSetName="NamedPipe")] | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
param( | ||||||
[Parameter(Mandatory=$true)] | ||||||
[ValidateNotNullOrEmpty()] | ||||||
|
@@ -65,14 +65,39 @@ param( | |||||
[switch] | ||||||
$ConfirmInstall, | ||||||
|
||||||
[Parameter(ParameterSetName="Stdio",Mandatory=$true)] | ||||||
[switch] | ||||||
$Stdio, | ||||||
|
||||||
[Parameter(ParameterSetName="NamedPipe")] | ||||||
[string] | ||||||
$LanguageServicePipeName = $null, | ||||||
|
||||||
[Parameter(ParameterSetName="NamedPipe")] | ||||||
[string] | ||||||
$DebugServicePipeName = $null, | ||||||
|
||||||
[Parameter(ParameterSetName="NamedPipeHalfDuplex",Mandatory=$true)] | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Setting |
||||||
[switch] | ||||||
$SplitInOutPipes, | ||||||
|
||||||
[Parameter(ParameterSetName="NamedPipeHalfDuplexParam",Mandatory=$true)] | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What's the reason for the I feel like we probably don't need so many different parameter sets -- what is the envisioned usage of each current set? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Right. I wanted to enforce the contract that one could either specify |
||||||
[ValidateNotNullOrEmpty()] | ||||||
[string] | ||||||
$DebugServicePipeName = $null | ||||||
$LanguageServiceInPipeName, | ||||||
|
||||||
[Parameter(ParameterSetName="NamedPipeHalfDuplexParam",Mandatory=$true)] | ||||||
[ValidateNotNullOrEmpty()] | ||||||
[string] | ||||||
$LanguageServiceOutPipeName, | ||||||
|
||||||
[Parameter(ParameterSetName="NamedPipeHalfDuplexParam")] | ||||||
[string] | ||||||
$DebugServiceInPipeName = $null, | ||||||
|
||||||
[Parameter(ParameterSetName="NamedPipeHalfDuplexParam")] | ||||||
[string] | ||||||
$DebugServiceOutPipeName = $null | ||||||
) | ||||||
|
||||||
$DEFAULT_USER_MODE = "600" | ||||||
|
@@ -173,8 +198,7 @@ function New-NamedPipeName { | |||||
|
||||||
# We try 10 times to find a valid pipe name | ||||||
for ($i = 0; $i -lt 10; $i++) { | ||||||
# add a guid to make the pipe unique | ||||||
$PipeName = "PSES_$([guid]::NewGuid())" | ||||||
$PipeName = "PSES_$([System.IO.Path]::GetRandomFileName())" | ||||||
TylerLeonhardt marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
|
||||||
if ((Test-NamedPipeName -PipeName $PipeName)) { | ||||||
return $PipeName | ||||||
|
@@ -243,6 +267,29 @@ function Set-NamedPipeMode { | |||||
} | ||||||
} | ||||||
|
||||||
function Test-NamedPipeName-OrCreate-IfNull { | ||||||
param( | ||||||
[string] | ||||||
$PipeName | ||||||
) | ||||||
if (-not $PipeName) { | ||||||
$PipeName = New-NamedPipeName | ||||||
} | ||||||
else { | ||||||
if (-not (Test-NamedPipeName -PipeName $PipeName)) { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So what happens when Test-NamedPipeName equals I feel as if the Test & Create part should be two separate functions. Separation of concerns There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The function will fail and abort with the error if the supplied by the user pipe name is not a valid name. If a valid name was supplied it just returns this pipe name. If no pipe name was provided it creates it. |
||||||
ExitWithError "Pipe name supplied is already taken: $PipeName" | ||||||
} | ||||||
} | ||||||
return $PipeName | ||||||
} | ||||||
|
||||||
function SetPipeFileResult($ResultTable, [string]$PipeNameKey, [string]$PipeNameValue) { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This function should separate the verb There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If result table is expected to be a hashtable, it might be worth adding that to the param signature as well. |
||||||
$ResultTable[$PipeNameKey] = Get-NamedPipePath -PipeName $PipeNameValue | ||||||
if ($IsLinux -or $IsMacOS) { | ||||||
Set-NamedPipeMode -PipeFile $ResultTable[$PipeNameKey] | ||||||
} | ||||||
} | ||||||
|
||||||
# Add BundledModulesPath to $env:PSModulePath | ||||||
if ($BundledModulesPath) { | ||||||
$env:PSModulePath = $env:PSModulePath.TrimEnd([System.IO.Path]::PathSeparator) + [System.IO.Path]::PathSeparator + $BundledModulesPath | ||||||
|
@@ -263,81 +310,90 @@ try { | |||||
|
||||||
Microsoft.PowerShell.Core\Import-Module PowerShellEditorServices -ErrorAction Stop | ||||||
|
||||||
# Locate available port numbers for services | ||||||
# There could be only one service on Stdio channel | ||||||
|
||||||
$languageServiceTransport = $null | ||||||
$debugServiceTransport = $null | ||||||
|
||||||
if ($Stdio.IsPresent) { | ||||||
$languageServiceTransport = "Stdio" | ||||||
$debugServiceTransport = "Stdio" | ||||||
} | ||||||
else { | ||||||
$languageServiceTransport = "NamedPipe" | ||||||
$debugServiceTransport = "NamedPipe" | ||||||
if (-not $LanguageServicePipeName) { | ||||||
$LanguageServicePipeName = New-NamedPipeName | ||||||
} | ||||||
else { | ||||||
if (-not (Test-NamedPipeName -PipeName $LanguageServicePipeName)) { | ||||||
ExitWithError "Pipe name supplied is already taken: $LanguageServicePipeName" | ||||||
} | ||||||
} | ||||||
if (-not $DebugServicePipeName) { | ||||||
$DebugServicePipeName = New-NamedPipeName | ||||||
} | ||||||
else { | ||||||
if (-not (Test-NamedPipeName -PipeName $DebugServicePipeName)) { | ||||||
ExitWithError "Pipe name supplied is already taken: $DebugServicePipeName" | ||||||
} | ||||||
} | ||||||
} | ||||||
|
||||||
if ($EnableConsoleRepl) { | ||||||
Write-Host "PowerShell Integrated Console`n" | ||||||
} | ||||||
|
||||||
# Create the Editor Services host | ||||||
Log "Invoking Start-EditorServicesHost" | ||||||
$editorServicesHost = | ||||||
Start-EditorServicesHost ` | ||||||
-HostName $HostName ` | ||||||
-HostProfileId $HostProfileId ` | ||||||
-HostVersion $HostVersion ` | ||||||
-LogPath $LogPath ` | ||||||
-LogLevel $LogLevel ` | ||||||
-AdditionalModules $AdditionalModules ` | ||||||
-LanguageServiceNamedPipe $LanguageServicePipeName ` | ||||||
-DebugServiceNamedPipe $DebugServicePipeName ` | ||||||
-Stdio:$Stdio.IsPresent` | ||||||
-BundledModulesPath $BundledModulesPath ` | ||||||
-EnableConsoleRepl:$EnableConsoleRepl.IsPresent ` | ||||||
-DebugServiceOnly:$DebugServiceOnly.IsPresent ` | ||||||
-WaitForDebugger:$WaitForDebugger.IsPresent | ||||||
|
||||||
# TODO: Verify that the service is started | ||||||
Log "Start-EditorServicesHost returned $editorServicesHost" | ||||||
|
||||||
$resultDetails = @{ | ||||||
"status" = "started"; | ||||||
"languageServiceTransport" = $languageServiceTransport; | ||||||
"debugServiceTransport" = $debugServiceTransport; | ||||||
"status" = "not started"; | ||||||
"languageServiceTransport" = $PSCmdlet.ParameterSetName.Replace("Param",""); | ||||||
"debugServiceTransport" = $PSCmdlet.ParameterSetName.Replace("Param",""); | ||||||
}; | ||||||
|
||||||
if ($LanguageServicePipeName) { | ||||||
$resultDetails["languageServicePipeName"] = Get-NamedPipePath -PipeName $LanguageServicePipeName | ||||||
if ($IsLinux -or $IsMacOS) { | ||||||
Set-NamedPipeMode -PipeFile $resultDetails["languageServicePipeName"] | ||||||
# Create the Editor Services host | ||||||
Log "Invoking Start-EditorServicesHost" | ||||||
# There could be only one service on Stdio channel | ||||||
# Locate available port numbers for services | ||||||
switch -Wildcard ($PSCmdlet.ParameterSetName) { | ||||||
"Stdio" { | ||||||
$editorServicesHost = Start-EditorServicesHost ` | ||||||
-HostName $HostName ` | ||||||
-HostProfileId $HostProfileId ` | ||||||
-HostVersion $HostVersion ` | ||||||
-LogPath $LogPath ` | ||||||
-LogLevel $LogLevel ` | ||||||
-AdditionalModules $AdditionalModules ` | ||||||
-Stdio ` | ||||||
-BundledModulesPath $BundledModulesPath ` | ||||||
-EnableConsoleRepl:$EnableConsoleRepl.IsPresent ` | ||||||
-DebugServiceOnly:$DebugServiceOnly.IsPresent ` | ||||||
-WaitForDebugger:$WaitForDebugger.IsPresent | ||||||
} | ||||||
} | ||||||
if ($DebugServicePipeName) { | ||||||
$resultDetails["debugServicePipeName"] = Get-NamedPipePath -PipeName $DebugServicePipeName | ||||||
if ($IsLinux -or $IsMacOS) { | ||||||
Set-NamedPipeMode -PipeFile $resultDetails["debugServicePipeName"] | ||||||
"NamedPipeHalfDuplex*" { | ||||||
$LanguageServiceInPipeName = Test-NamedPipeName-OrCreate-IfNull $LanguageServiceInPipeName | ||||||
$LanguageServiceOutPipeName = Test-NamedPipeName-OrCreate-IfNull $LanguageServiceOutPipeName | ||||||
$DebugServiceInPipeName = Test-NamedPipeName-OrCreate-IfNull $DebugServiceInPipeName | ||||||
$DebugServiceOutPipeName = Test-NamedPipeName-OrCreate-IfNull $DebugServiceOutPipeName | ||||||
|
||||||
$editorServicesHost = Start-EditorServicesHost ` | ||||||
-HostName $HostName ` | ||||||
-HostProfileId $HostProfileId ` | ||||||
-HostVersion $HostVersion ` | ||||||
-LogPath $LogPath ` | ||||||
-LogLevel $LogLevel ` | ||||||
-AdditionalModules $AdditionalModules ` | ||||||
-LanguageServiceInNamedPipe $LanguageServiceInPipeName ` | ||||||
-LanguageServiceOutNamedPipe $LanguageServiceOutPipeName ` | ||||||
-DebugServiceInNamedPipe $DebugServiceInPipeName ` | ||||||
-DebugServiceOutNamedPipe $DebugServiceOutPipeName ` | ||||||
-BundledModulesPath $BundledModulesPath ` | ||||||
-EnableConsoleRepl:$EnableConsoleRepl.IsPresent ` | ||||||
-DebugServiceOnly:$DebugServiceOnly.IsPresent ` | ||||||
-WaitForDebugger:$WaitForDebugger.IsPresent | ||||||
|
||||||
SetPipeFileResult $resultDetails "languageServiceReadPipeName" $LanguageServiceInPipeName | ||||||
SetPipeFileResult $resultDetails "languageServiceWritePipeName" $LanguageServiceOutPipeName | ||||||
SetPipeFileResult $resultDetails "debugServiceReadPipeName" $DebugServiceInPipeName | ||||||
SetPipeFileResult $resultDetails "debugServiceWritePipeName" $DebugServiceOutPipeName | ||||||
} | ||||||
Default { | ||||||
$LanguageServicePipeName = Test-NamedPipeName-OrCreate-IfNull $LanguageServicePipeName | ||||||
$DebugServicePipeName = Test-NamedPipeName-OrCreate-IfNull $DebugServicePipeName | ||||||
|
||||||
$editorServicesHost = Start-EditorServicesHost ` | ||||||
-HostName $HostName ` | ||||||
-HostProfileId $HostProfileId ` | ||||||
-HostVersion $HostVersion ` | ||||||
-LogPath $LogPath ` | ||||||
-LogLevel $LogLevel ` | ||||||
-AdditionalModules $AdditionalModules ` | ||||||
-LanguageServiceNamedPipe $LanguageServicePipeName ` | ||||||
-DebugServiceNamedPipe $DebugServicePipeName ` | ||||||
-BundledModulesPath $BundledModulesPath ` | ||||||
-EnableConsoleRepl:$EnableConsoleRepl.IsPresent ` | ||||||
-DebugServiceOnly:$DebugServiceOnly.IsPresent ` | ||||||
-WaitForDebugger:$WaitForDebugger.IsPresent | ||||||
|
||||||
SetPipeFileResult $resultDetails "languageServicePipeName" $LanguageServicePipeName | ||||||
SetPipeFileResult $resultDetails "debugServicePipeName" $DebugServicePipeName | ||||||
} | ||||||
} | ||||||
|
||||||
# TODO: Verify that the service is started | ||||||
Log "Start-EditorServicesHost returned $editorServicesHost" | ||||||
|
||||||
$resultDetails["status"] = "started" | ||||||
|
||||||
# Notify the client that the services have started | ||||||
WriteSessionFile $resultDetails | ||||||
|
||||||
|
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -43,7 +43,10 @@ public class EditorServiceTransportConfig | |||||
/// For Stdio it's ignored. | ||||||
/// For NamedPipe it's the pipe name. | ||||||
/// </summary> | ||||||
public string Endpoint { get; set; } | ||||||
public string InOutPipeName { get; set; } | ||||||
public string OutPipeName { get; set; } | ||||||
public string InPipeName { get; set; } | ||||||
internal string Endpoint => OutPipeName != null && InPipeName!=null ? $"In pipe: {InPipeName} Out pipe: {OutPipeName}" : $" InOut pipe: {InOutPipeName}"; | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
} | ||||||
|
||||||
/// <summary> | ||||||
|
@@ -463,7 +466,15 @@ private IServerListener CreateServiceListener(MessageProtocolType protocol, Edit | |||||
|
||||||
case EditorServiceTransportType.NamedPipe: | ||||||
{ | ||||||
return new NamedPipeServerListener(protocol, config.Endpoint, this.logger); | ||||||
if (config.OutPipeName !=null && config.InPipeName !=null) | ||||||
{ | ||||||
this.logger.Write(LogLevel.Verbose, $"Creating NamedPipeServerListener for ${protocol} protocol with two pipes: In: '" + config.InPipeName + "'. Out: '" + config.OutPipeName + "'"); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There could be $DebugAdapter or $LanguageServer protocols. Example log:
|
||||||
return new NamedPipeServerListener(protocol, config.InPipeName, config.OutPipeName, this.logger); | ||||||
} | ||||||
else | ||||||
{ | ||||||
return new NamedPipeServerListener(protocol, config.InOutPipeName, this.logger); | ||||||
} | ||||||
} | ||||||
|
||||||
default: | ||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Technically, I think this may be "simplex" rather than "half duplex" since each pipe can only ever be used in one direction (rather than both directions, one at a time), but it's not a major concern