mirror of
https://github.com/ckaczor/sqltoolsservice.git
synced 2026-01-25 01:25:40 -05:00
Initial commit of SqlTools Service API
This commit is contained in:
81
ServiceHost/MessageProtocol/Channel/ChannelBase.cs
Normal file
81
ServiceHost/MessageProtocol/Channel/ChannelBase.cs
Normal file
@@ -0,0 +1,81 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
using Microsoft.PowerShell.EditorServices.Protocol.MessageProtocol.Serializers;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.PowerShell.EditorServices.Protocol.MessageProtocol.Channel
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines a base implementation for servers and their clients over a
|
||||
/// single kind of communication channel.
|
||||
/// </summary>
|
||||
public abstract class ChannelBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets a boolean that is true if the channel is connected or false if not.
|
||||
/// </summary>
|
||||
public bool IsConnected { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the MessageReader for reading messages from the channel.
|
||||
/// </summary>
|
||||
public MessageReader MessageReader { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the MessageWriter for writing messages to the channel.
|
||||
/// </summary>
|
||||
public MessageWriter MessageWriter { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// Starts the channel and initializes the MessageDispatcher.
|
||||
/// </summary>
|
||||
/// <param name="messageProtocolType">The type of message protocol used by the channel.</param>
|
||||
public void Start(MessageProtocolType messageProtocolType)
|
||||
{
|
||||
IMessageSerializer messageSerializer = null;
|
||||
if (messageProtocolType == MessageProtocolType.LanguageServer)
|
||||
{
|
||||
messageSerializer = new JsonRpcMessageSerializer();
|
||||
}
|
||||
else
|
||||
{
|
||||
messageSerializer = new V8MessageSerializer();
|
||||
}
|
||||
|
||||
this.Initialize(messageSerializer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a Task that allows the consumer of the ChannelBase
|
||||
/// implementation to wait until a connection has been made to
|
||||
/// the opposite endpoint whether it's a client or server.
|
||||
/// </summary>
|
||||
/// <returns>A Task to be awaited until a connection is made.</returns>
|
||||
public abstract Task WaitForConnection();
|
||||
|
||||
/// <summary>
|
||||
/// Stops the channel.
|
||||
/// </summary>
|
||||
public void Stop()
|
||||
{
|
||||
this.Shutdown();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A method to be implemented by subclasses to handle the
|
||||
/// actual initialization of the channel and the creation and
|
||||
/// assignment of the MessageReader and MessageWriter properties.
|
||||
/// </summary>
|
||||
/// <param name="messageSerializer">The IMessageSerializer to use for message serialization.</param>
|
||||
protected abstract void Initialize(IMessageSerializer messageSerializer);
|
||||
|
||||
/// <summary>
|
||||
/// A method to be implemented by subclasses to handle shutdown
|
||||
/// of the channel once Stop is called.
|
||||
/// </summary>
|
||||
protected abstract void Shutdown();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
#if false
|
||||
|
||||
using System;
|
||||
using System.IO.Pipes;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.PowerShell.EditorServices.Protocol.MessageProtocol.Channel
|
||||
{
|
||||
public class NamedPipeClientChannel : ChannelBase
|
||||
{
|
||||
private string pipeName;
|
||||
private bool isClientConnected;
|
||||
private NamedPipeClientStream pipeClient;
|
||||
|
||||
public NamedPipeClientChannel(string pipeName)
|
||||
{
|
||||
this.pipeName = pipeName;
|
||||
}
|
||||
|
||||
public override async Task WaitForConnection()
|
||||
{
|
||||
#if NanoServer
|
||||
await this.pipeClient.ConnectAsync();
|
||||
#else
|
||||
this.IsConnected = false;
|
||||
|
||||
while (!this.IsConnected)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Wait for 500 milliseconds so that we don't tie up the thread
|
||||
this.pipeClient.Connect(500);
|
||||
this.IsConnected = this.pipeClient.IsConnected;
|
||||
}
|
||||
catch (TimeoutException)
|
||||
{
|
||||
// Connect timed out, wait and try again
|
||||
await Task.Delay(1000);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// If we've reached this point, we're connected
|
||||
this.IsConnected = true;
|
||||
}
|
||||
|
||||
protected override void Initialize(IMessageSerializer messageSerializer)
|
||||
{
|
||||
this.pipeClient =
|
||||
new NamedPipeClientStream(
|
||||
".",
|
||||
this.pipeName,
|
||||
PipeDirection.InOut,
|
||||
PipeOptions.Asynchronous);
|
||||
|
||||
this.MessageReader =
|
||||
new MessageReader(
|
||||
this.pipeClient,
|
||||
messageSerializer);
|
||||
|
||||
this.MessageWriter =
|
||||
new MessageWriter(
|
||||
this.pipeClient,
|
||||
messageSerializer);
|
||||
}
|
||||
|
||||
protected override void Shutdown()
|
||||
{
|
||||
if (this.pipeClient != null)
|
||||
{
|
||||
this.pipeClient.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,65 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
#if false
|
||||
using System;
|
||||
using System.IO.Pipes;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.PowerShell.EditorServices.Protocol.MessageProtocol.Channel
|
||||
{
|
||||
public class NamedPipeServerChannel : ChannelBase
|
||||
{
|
||||
private string pipeName;
|
||||
private NamedPipeServerStream pipeServer;
|
||||
|
||||
public NamedPipeServerChannel(string pipeName)
|
||||
{
|
||||
this.pipeName = pipeName;
|
||||
}
|
||||
|
||||
public override async Task WaitForConnection()
|
||||
{
|
||||
#if NanoServer
|
||||
await this.pipeServer.WaitForConnectionAsync();
|
||||
#else
|
||||
await Task.Factory.FromAsync(this.pipeServer.BeginWaitForConnection, this.pipeServer.EndWaitForConnection, null);
|
||||
#endif
|
||||
|
||||
this.IsConnected = true;
|
||||
}
|
||||
|
||||
protected override void Initialize(IMessageSerializer messageSerializer)
|
||||
{
|
||||
this.pipeServer =
|
||||
new NamedPipeServerStream(
|
||||
pipeName,
|
||||
PipeDirection.InOut,
|
||||
1,
|
||||
PipeTransmissionMode.Byte,
|
||||
PipeOptions.Asynchronous);
|
||||
|
||||
this.MessageReader =
|
||||
new MessageReader(
|
||||
this.pipeServer,
|
||||
messageSerializer);
|
||||
|
||||
this.MessageWriter =
|
||||
new MessageWriter(
|
||||
this.pipeServer,
|
||||
messageSerializer);
|
||||
}
|
||||
|
||||
protected override void Shutdown()
|
||||
{
|
||||
if (this.pipeServer != null)
|
||||
{
|
||||
this.pipeServer.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
127
ServiceHost/MessageProtocol/Channel/StdioClientChannel.cs
Normal file
127
ServiceHost/MessageProtocol/Channel/StdioClientChannel.cs
Normal file
@@ -0,0 +1,127 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
using Microsoft.PowerShell.EditorServices.Protocol.MessageProtocol.Serializers;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.PowerShell.EditorServices.Protocol.MessageProtocol.Channel
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides a client implementation for the standard I/O channel.
|
||||
/// Launches the server process and then attaches to its console
|
||||
/// streams.
|
||||
/// </summary>
|
||||
public class StdioClientChannel : ChannelBase
|
||||
{
|
||||
private string serviceProcessPath;
|
||||
private string serviceProcessArguments;
|
||||
|
||||
private Stream inputStream;
|
||||
private Stream outputStream;
|
||||
private Process serviceProcess;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the process ID of the server process.
|
||||
/// </summary>
|
||||
public int ProcessId { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes an instance of the StdioClient.
|
||||
/// </summary>
|
||||
/// <param name="serverProcessPath">The full path to the server process executable.</param>
|
||||
/// <param name="serverProcessArguments">Optional arguments to pass to the service process executable.</param>
|
||||
public StdioClientChannel(
|
||||
string serverProcessPath,
|
||||
params string[] serverProcessArguments)
|
||||
{
|
||||
this.serviceProcessPath = serverProcessPath;
|
||||
|
||||
if (serverProcessArguments != null)
|
||||
{
|
||||
this.serviceProcessArguments =
|
||||
string.Join(
|
||||
" ",
|
||||
serverProcessArguments);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Initialize(IMessageSerializer messageSerializer)
|
||||
{
|
||||
this.serviceProcess = new Process
|
||||
{
|
||||
StartInfo = new ProcessStartInfo
|
||||
{
|
||||
FileName = this.serviceProcessPath,
|
||||
Arguments = this.serviceProcessArguments,
|
||||
CreateNoWindow = true,
|
||||
UseShellExecute = false,
|
||||
RedirectStandardInput = true,
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true,
|
||||
StandardOutputEncoding = Encoding.UTF8,
|
||||
},
|
||||
EnableRaisingEvents = true,
|
||||
};
|
||||
|
||||
// Start the process
|
||||
this.serviceProcess.Start();
|
||||
this.ProcessId = this.serviceProcess.Id;
|
||||
|
||||
// Open the standard input/output streams
|
||||
this.inputStream = this.serviceProcess.StandardOutput.BaseStream;
|
||||
this.outputStream = this.serviceProcess.StandardInput.BaseStream;
|
||||
|
||||
// Set up the message reader and writer
|
||||
this.MessageReader =
|
||||
new MessageReader(
|
||||
this.inputStream,
|
||||
messageSerializer);
|
||||
|
||||
this.MessageWriter =
|
||||
new MessageWriter(
|
||||
this.outputStream,
|
||||
messageSerializer);
|
||||
|
||||
this.IsConnected = true;
|
||||
}
|
||||
|
||||
public override Task WaitForConnection()
|
||||
{
|
||||
// We're always connected immediately in the stdio channel
|
||||
return Task.FromResult(true);
|
||||
}
|
||||
|
||||
protected override void Shutdown()
|
||||
{
|
||||
if (this.inputStream != null)
|
||||
{
|
||||
this.inputStream.Dispose();
|
||||
this.inputStream = null;
|
||||
}
|
||||
|
||||
if (this.outputStream != null)
|
||||
{
|
||||
this.outputStream.Dispose();
|
||||
this.outputStream = null;
|
||||
}
|
||||
|
||||
if (this.MessageReader != null)
|
||||
{
|
||||
this.MessageReader = null;
|
||||
}
|
||||
|
||||
if (this.MessageWriter != null)
|
||||
{
|
||||
this.MessageWriter = null;
|
||||
}
|
||||
|
||||
this.serviceProcess.Kill();
|
||||
}
|
||||
}
|
||||
}
|
||||
62
ServiceHost/MessageProtocol/Channel/StdioServerChannel.cs
Normal file
62
ServiceHost/MessageProtocol/Channel/StdioServerChannel.cs
Normal file
@@ -0,0 +1,62 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
using Microsoft.PowerShell.EditorServices.Protocol.MessageProtocol.Serializers;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.PowerShell.EditorServices.Protocol.MessageProtocol.Channel
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides a server implementation for the standard I/O channel.
|
||||
/// When started in a process, attaches to the console I/O streams
|
||||
/// to communicate with the client that launched the process.
|
||||
/// </summary>
|
||||
public class StdioServerChannel : ChannelBase
|
||||
{
|
||||
private Stream inputStream;
|
||||
private Stream outputStream;
|
||||
|
||||
protected override void Initialize(IMessageSerializer messageSerializer)
|
||||
{
|
||||
#if !NanoServer
|
||||
// Ensure that the console is using UTF-8 encoding
|
||||
System.Console.InputEncoding = Encoding.UTF8;
|
||||
System.Console.OutputEncoding = Encoding.UTF8;
|
||||
#endif
|
||||
|
||||
// Open the standard input/output streams
|
||||
this.inputStream = System.Console.OpenStandardInput();
|
||||
this.outputStream = System.Console.OpenStandardOutput();
|
||||
|
||||
// Set up the reader and writer
|
||||
this.MessageReader =
|
||||
new MessageReader(
|
||||
this.inputStream,
|
||||
messageSerializer);
|
||||
|
||||
this.MessageWriter =
|
||||
new MessageWriter(
|
||||
this.outputStream,
|
||||
messageSerializer);
|
||||
|
||||
this.IsConnected = true;
|
||||
}
|
||||
|
||||
public override Task WaitForConnection()
|
||||
{
|
||||
// We're always connected immediately in the stdio channel
|
||||
return Task.FromResult(true);
|
||||
}
|
||||
|
||||
protected override void Shutdown()
|
||||
{
|
||||
// No default implementation needed, streams will be
|
||||
// disposed on process shutdown.
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user