Skip to content
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

Decouple ProtocolEndpoint from client and server implementations #489

Merged
merged 1 commit into from
Jun 4, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Decouple ProtocolEndpoint from client and server implementations
This change decouples the ProtocolEndpoint class from the existing
client and server implementations for the language and debug services.
The goal here is to eventually decentralize all editor feature
implementations into individual classes, so separating out the
ProtocolEndpoint is the first step in achieving this.  This class will
now be exposed in the framework as the IMessageSender interface.

This change also simplifies the LanguageServer/DebugAdapter client and
server implementations, removing some unnecessary abstraction and base
classes.
  • Loading branch information
daviwil committed Jun 4, 2017
commit 1104e7b0c50030338b06c7dce124308f9c1a448e
39 changes: 30 additions & 9 deletions src/PowerShellEditorServices.Host/EditorServicesHost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,14 @@ private async void OnLanguageServiceClientConnect(
object sender,
TcpSocketServerChannel serverChannel)
{
MessageDispatcher messageDispatcher = new MessageDispatcher(this.logger);

ProtocolEndpoint protocolEndpoint =
new ProtocolEndpoint(
serverChannel,
messageDispatcher,
this.logger);

this.editorSession =
CreateSession(
this.hostDetails,
Expand All @@ -192,15 +200,17 @@ private async void OnLanguageServiceClientConnect(
this.languageServer =
new LanguageServer(
this.editorSession,
serverChannel,
messageDispatcher,
protocolEndpoint,
this.logger);

await this.editorSession.PowerShellContext.ImportCommandsModule(
Path.Combine(
Path.GetDirectoryName(this.GetType().GetTypeInfo().Assembly.Location),
@"..\..\Commands"));

await this.languageServer.Start();
this.languageServer.Start();
protocolEndpoint.Start();
}

/// <summary>
Expand All @@ -214,7 +224,7 @@ public void StartDebugService(
{
this.debugServiceListener =
new TcpSocketServerListener(
MessageProtocolType.LanguageServer,
MessageProtocolType.DebugAdapter,
debugServicePort,
this.logger);

Expand All @@ -228,15 +238,24 @@ public void StartDebugService(
debugServicePort));
}

private async void OnDebugServiceClientConnect(object sender, TcpSocketServerChannel serverChannel)
private void OnDebugServiceClientConnect(object sender, TcpSocketServerChannel serverChannel)
{
MessageDispatcher messageDispatcher = new MessageDispatcher(this.logger);

ProtocolEndpoint protocolEndpoint =
new ProtocolEndpoint(
serverChannel,
messageDispatcher,
this.logger);

if (this.enableConsoleRepl)
{
this.debugAdapter =
new DebugAdapter(
this.editorSession,
serverChannel,
false,
messageDispatcher,
protocolEndpoint,
this.logger);
}
else
Expand All @@ -250,8 +269,9 @@ private async void OnDebugServiceClientConnect(object sender, TcpSocketServerCha
this.debugAdapter =
new DebugAdapter(
debugSession,
serverChannel,
true,
messageDispatcher,
protocolEndpoint,
this.logger);
}

Expand All @@ -265,18 +285,19 @@ private async void OnDebugServiceClientConnect(object sender, TcpSocketServerCha
this.debugServiceListener.Start();
};

await this.debugAdapter.Start();
this.debugAdapter.Start();
protocolEndpoint.Start();
}

/// <summary>
/// Stops the language or debug services if either were started.
/// </summary>
public void StopServices()
{
this.languageServer?.Stop().Wait();
// TODO: Need a new way to shut down the services

this.languageServer = null;

this.debugAdapter?.Stop().Wait();
this.debugAdapter = null;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,46 @@
using Microsoft.PowerShell.EditorServices.Protocol.DebugAdapter;
using Microsoft.PowerShell.EditorServices.Protocol.MessageProtocol;
using Microsoft.PowerShell.EditorServices.Protocol.MessageProtocol.Channel;
using System.Threading.Tasks;
using Microsoft.PowerShell.EditorServices.Utility;
using System.Threading.Tasks;
using System;

namespace Microsoft.PowerShell.EditorServices.Protocol.Client
{
public class DebugAdapterClient : ProtocolEndpoint
public class DebugAdapterClient : IMessageSender, IMessageHandlers
{
private ILogger logger;
private ProtocolEndpoint protocolEndpoint;
private MessageDispatcher messageDispatcher;

public DebugAdapterClient(ChannelBase clientChannel, ILogger logger)
: base(
{
this.logger = logger;
this.messageDispatcher = new MessageDispatcher(logger);
this.protocolEndpoint = new ProtocolEndpoint(
clientChannel,
new MessageDispatcher(logger),
MessageProtocolType.DebugAdapter,
logger)
messageDispatcher,
logger);
}

public async Task Start()
{
this.protocolEndpoint.Start();

// Initialize the debug adapter
await this.SendRequest(
InitializeRequest.Type,
new InitializeRequestArguments
{
LinesStartAt1 = true,
ColumnsStartAt1 = true
},
true);
}

public void Stop()
{
this.protocolEndpoint.Stop();
}

public async Task LaunchScript(string scriptFilePath)
Expand All @@ -28,21 +54,43 @@ await this.SendRequest(
LaunchRequest.Type,
new LaunchRequestArguments {
Script = scriptFilePath
});
},
true);

await this.SendRequest(ConfigurationDoneRequest.Type, null);
await this.SendRequest(
ConfigurationDoneRequest.Type,
null,
true);
}

protected override Task OnStart()
public Task SendEvent<TParams, TRegistrationOptions>(NotificationType<TParams, TRegistrationOptions> eventType, TParams eventParams)
{
// Initialize the debug adapter
return this.SendRequest(
InitializeRequest.Type,
new InitializeRequestArguments
{
LinesStartAt1 = true,
ColumnsStartAt1 = true
});
return ((IMessageSender)protocolEndpoint).SendEvent(eventType, eventParams);
}

public Task<TResult> SendRequest<TParams, TResult, TError, TRegistrationOptions>(RequestType<TParams, TResult, TError, TRegistrationOptions> requestType, TParams requestParams, bool waitForResponse)
{
return ((IMessageSender)protocolEndpoint).SendRequest(requestType, requestParams, waitForResponse);
}

public Task<TResult> SendRequest<TResult, TError, TRegistrationOptions>(RequestType0<TResult, TError, TRegistrationOptions> requestType0)
{
return ((IMessageSender)protocolEndpoint).SendRequest(requestType0);
}

public void SetRequestHandler<TParams, TResult, TError, TRegistrationOptions>(RequestType<TParams, TResult, TError, TRegistrationOptions> requestType, Func<TParams, RequestContext<TResult>, Task> requestHandler)
{
((IMessageHandlers)messageDispatcher).SetRequestHandler(requestType, requestHandler);
}

public void SetRequestHandler<TResult, TError, TRegistrationOptions>(RequestType0<TResult, TError, TRegistrationOptions> requestType0, Func<RequestContext<TResult>, Task> requestHandler)
{
((IMessageHandlers)messageDispatcher).SetRequestHandler(requestType0, requestHandler);
}

public void SetEventHandler<TParams, TRegistrationOptions>(NotificationType<TParams, TRegistrationOptions> eventType, Func<TParams, EventContext, Task> eventHandler)
{
((IMessageHandlers)messageDispatcher).SetEventHandler(eventType, eventHandler);
}
}
}
Expand Down
75 changes: 64 additions & 11 deletions src/PowerShellEditorServices.Protocol/Client/LanguageClientBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,44 +6,97 @@
using Microsoft.PowerShell.EditorServices.Protocol.LanguageServer;
using Microsoft.PowerShell.EditorServices.Protocol.MessageProtocol;
using Microsoft.PowerShell.EditorServices.Protocol.MessageProtocol.Channel;
using System.Threading.Tasks;
using Microsoft.PowerShell.EditorServices.Utility;
using System;
using System.Threading.Tasks;

namespace Microsoft.PowerShell.EditorServices.Protocol.Client
{
/// <summary>
/// Provides a base implementation for language server clients.
/// </summary>
public abstract class LanguageClientBase : ProtocolEndpoint
public abstract class LanguageClientBase : IMessageHandlers, IMessageSender
{
ILogger logger;
private ProtocolEndpoint protocolEndpoint;
private MessageDispatcher messageDispatcher;

/// <summary>
/// Initializes an instance of the language client using the
/// specified channel for communication.
/// </summary>
/// <param name="clientChannel">The channel to use for communication with the server.</param>
public LanguageClientBase(ChannelBase clientChannel, ILogger logger)
: base(
clientChannel,
new MessageDispatcher(logger),
MessageProtocolType.LanguageServer,
logger)
{
this.logger = logger;
this.messageDispatcher = new MessageDispatcher(logger);
this.protocolEndpoint = new ProtocolEndpoint(
clientChannel,
messageDispatcher,
logger);
}

protected override Task OnStart()
public Task Start()
{
this.protocolEndpoint.Start();

// Initialize the implementation class
return this.Initialize();
}

protected override async Task OnStop()
public async Task Stop()
{
await this.OnStop();

// First, notify the language server that we're stopping
var response = await this.SendRequest<object, object, object>(ShutdownRequest.Type);
var response =
await this.SendRequest<object, object, object>(
ShutdownRequest.Type);

await this.SendEvent(ExitNotification.Type, new object());

this.protocolEndpoint.Stop();
}

protected virtual Task OnStop()
{
return Task.FromResult(true);
}

protected virtual Task Initialize()
{
return Task.FromResult(true);
}

public Task SendEvent<TParams, TRegistrationOptions>(NotificationType<TParams, TRegistrationOptions> eventType, TParams eventParams)
{
return ((IMessageSender)protocolEndpoint).SendEvent(eventType, eventParams);
}

public Task<TResult> SendRequest<TParams, TResult, TError, TRegistrationOptions>(RequestType<TParams, TResult, TError, TRegistrationOptions> requestType, TParams requestParams, bool waitForResponse)
{
return ((IMessageSender)protocolEndpoint).SendRequest(requestType, requestParams, waitForResponse);
}

public Task<TResult> SendRequest<TResult, TError, TRegistrationOptions>(RequestType0<TResult, TError, TRegistrationOptions> requestType0)
{
return ((IMessageSender)protocolEndpoint).SendRequest(requestType0);
}

protected abstract Task Initialize();
public void SetRequestHandler<TParams, TResult, TError, TRegistrationOptions>(RequestType<TParams, TResult, TError, TRegistrationOptions> requestType, Func<TParams, RequestContext<TResult>, Task> requestHandler)
{
((IMessageHandlers)messageDispatcher).SetRequestHandler(requestType, requestHandler);
}

public void SetRequestHandler<TResult, TError, TRegistrationOptions>(RequestType0<TResult, TError, TRegistrationOptions> requestType0, Func<RequestContext<TResult>, Task> requestHandler)
{
((IMessageHandlers)messageDispatcher).SetRequestHandler(requestType0, requestHandler);
}

public void SetEventHandler<TParams, TRegistrationOptions>(NotificationType<TParams, TRegistrationOptions> eventType, Func<TParams, EventContext, Task> eventHandler)
{
((IMessageHandlers)messageDispatcher).SetEventHandler(eventType, eventHandler);
}
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ protected override Task Initialize()

return this.SendRequest(
InitializeRequest.Type,
initializeParams);
initializeParams,
true);
}

#region Events
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//

using System;
using System.Threading.Tasks;

namespace Microsoft.PowerShell.EditorServices.Protocol.MessageProtocol
{
public interface IMessageHandlers
{
void SetRequestHandler<TParams, TResult, TError, TRegistrationOptions>(
RequestType<TParams, TResult, TError, TRegistrationOptions> requestType,
Func<TParams, RequestContext<TResult>, Task> requestHandler);

void SetRequestHandler<TResult, TError, TRegistrationOptions>(
RequestType0<TResult, TError, TRegistrationOptions> requestType0,
Func<RequestContext<TResult>, Task> requestHandler);

void SetEventHandler<TParams, TRegistrationOptions>(
NotificationType<TParams, TRegistrationOptions> eventType,
Func<TParams, EventContext, Task> eventHandler);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

namespace Microsoft.PowerShell.EditorServices.Protocol.MessageProtocol
{
internal interface IMessageSender
public interface IMessageSender
{
Task SendEvent<TParams, TRegistrationOptions>(
NotificationType<TParams, TRegistrationOptions> eventType,
Expand All @@ -17,6 +17,9 @@ Task<TResult> SendRequest<TParams, TResult, TError, TRegistrationOptions>(
RequestType<TParams, TResult, TError, TRegistrationOptions> requestType,
TParams requestParams,
bool waitForResponse);

Task<TResult> SendRequest<TResult, TError, TRegistrationOptions>(
RequestType0<TResult, TError, TRegistrationOptions> requestType0);
}
}

Loading