Initial commit of SqlTools Service API

This commit is contained in:
Karl Burtram
2016-07-15 11:02:03 -07:00
parent 874ade9001
commit 790825cfab
112 changed files with 9782 additions and 1 deletions

View 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();
}
}

View File

@@ -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

View File

@@ -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

View 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();
}
}
}

View 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.
}
}
}