Skip to content

Commit 1104e7b

Browse files
committed
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.
1 parent 9b0f2a0 commit 1104e7b

File tree

17 files changed

+409
-378
lines changed

17 files changed

+409
-378
lines changed

src/PowerShellEditorServices.Host/EditorServicesHost.cs

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,14 @@ private async void OnLanguageServiceClientConnect(
183183
object sender,
184184
TcpSocketServerChannel serverChannel)
185185
{
186+
MessageDispatcher messageDispatcher = new MessageDispatcher(this.logger);
187+
188+
ProtocolEndpoint protocolEndpoint =
189+
new ProtocolEndpoint(
190+
serverChannel,
191+
messageDispatcher,
192+
this.logger);
193+
186194
this.editorSession =
187195
CreateSession(
188196
this.hostDetails,
@@ -192,15 +200,17 @@ private async void OnLanguageServiceClientConnect(
192200
this.languageServer =
193201
new LanguageServer(
194202
this.editorSession,
195-
serverChannel,
203+
messageDispatcher,
204+
protocolEndpoint,
196205
this.logger);
197206

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

203-
await this.languageServer.Start();
212+
this.languageServer.Start();
213+
protocolEndpoint.Start();
204214
}
205215

206216
/// <summary>
@@ -214,7 +224,7 @@ public void StartDebugService(
214224
{
215225
this.debugServiceListener =
216226
new TcpSocketServerListener(
217-
MessageProtocolType.LanguageServer,
227+
MessageProtocolType.DebugAdapter,
218228
debugServicePort,
219229
this.logger);
220230

@@ -228,15 +238,24 @@ public void StartDebugService(
228238
debugServicePort));
229239
}
230240

231-
private async void OnDebugServiceClientConnect(object sender, TcpSocketServerChannel serverChannel)
241+
private void OnDebugServiceClientConnect(object sender, TcpSocketServerChannel serverChannel)
232242
{
243+
MessageDispatcher messageDispatcher = new MessageDispatcher(this.logger);
244+
245+
ProtocolEndpoint protocolEndpoint =
246+
new ProtocolEndpoint(
247+
serverChannel,
248+
messageDispatcher,
249+
this.logger);
250+
233251
if (this.enableConsoleRepl)
234252
{
235253
this.debugAdapter =
236254
new DebugAdapter(
237255
this.editorSession,
238-
serverChannel,
239256
false,
257+
messageDispatcher,
258+
protocolEndpoint,
240259
this.logger);
241260
}
242261
else
@@ -250,8 +269,9 @@ private async void OnDebugServiceClientConnect(object sender, TcpSocketServerCha
250269
this.debugAdapter =
251270
new DebugAdapter(
252271
debugSession,
253-
serverChannel,
254272
true,
273+
messageDispatcher,
274+
protocolEndpoint,
255275
this.logger);
256276
}
257277

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

268-
await this.debugAdapter.Start();
288+
this.debugAdapter.Start();
289+
protocolEndpoint.Start();
269290
}
270291

271292
/// <summary>
272293
/// Stops the language or debug services if either were started.
273294
/// </summary>
274295
public void StopServices()
275296
{
276-
this.languageServer?.Stop().Wait();
297+
// TODO: Need a new way to shut down the services
298+
277299
this.languageServer = null;
278300

279-
this.debugAdapter?.Stop().Wait();
280301
this.debugAdapter = null;
281302
}
282303

src/PowerShellEditorServices.Protocol/Client/DebugAdapterClientBase.cs

Lines changed: 65 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,46 @@
66
using Microsoft.PowerShell.EditorServices.Protocol.DebugAdapter;
77
using Microsoft.PowerShell.EditorServices.Protocol.MessageProtocol;
88
using Microsoft.PowerShell.EditorServices.Protocol.MessageProtocol.Channel;
9-
using System.Threading.Tasks;
109
using Microsoft.PowerShell.EditorServices.Utility;
10+
using System.Threading.Tasks;
11+
using System;
1112

1213
namespace Microsoft.PowerShell.EditorServices.Protocol.Client
1314
{
14-
public class DebugAdapterClient : ProtocolEndpoint
15+
public class DebugAdapterClient : IMessageSender, IMessageHandlers
1516
{
17+
private ILogger logger;
18+
private ProtocolEndpoint protocolEndpoint;
19+
private MessageDispatcher messageDispatcher;
20+
1621
public DebugAdapterClient(ChannelBase clientChannel, ILogger logger)
17-
: base(
22+
{
23+
this.logger = logger;
24+
this.messageDispatcher = new MessageDispatcher(logger);
25+
this.protocolEndpoint = new ProtocolEndpoint(
1826
clientChannel,
19-
new MessageDispatcher(logger),
20-
MessageProtocolType.DebugAdapter,
21-
logger)
27+
messageDispatcher,
28+
logger);
29+
}
30+
31+
public async Task Start()
32+
{
33+
this.protocolEndpoint.Start();
34+
35+
// Initialize the debug adapter
36+
await this.SendRequest(
37+
InitializeRequest.Type,
38+
new InitializeRequestArguments
39+
{
40+
LinesStartAt1 = true,
41+
ColumnsStartAt1 = true
42+
},
43+
true);
44+
}
45+
46+
public void Stop()
2247
{
48+
this.protocolEndpoint.Stop();
2349
}
2450

2551
public async Task LaunchScript(string scriptFilePath)
@@ -28,21 +54,43 @@ await this.SendRequest(
2854
LaunchRequest.Type,
2955
new LaunchRequestArguments {
3056
Script = scriptFilePath
31-
});
57+
},
58+
true);
3259

33-
await this.SendRequest(ConfigurationDoneRequest.Type, null);
60+
await this.SendRequest(
61+
ConfigurationDoneRequest.Type,
62+
null,
63+
true);
3464
}
3565

36-
protected override Task OnStart()
66+
public Task SendEvent<TParams, TRegistrationOptions>(NotificationType<TParams, TRegistrationOptions> eventType, TParams eventParams)
3767
{
38-
// Initialize the debug adapter
39-
return this.SendRequest(
40-
InitializeRequest.Type,
41-
new InitializeRequestArguments
42-
{
43-
LinesStartAt1 = true,
44-
ColumnsStartAt1 = true
45-
});
68+
return ((IMessageSender)protocolEndpoint).SendEvent(eventType, eventParams);
69+
}
70+
71+
public Task<TResult> SendRequest<TParams, TResult, TError, TRegistrationOptions>(RequestType<TParams, TResult, TError, TRegistrationOptions> requestType, TParams requestParams, bool waitForResponse)
72+
{
73+
return ((IMessageSender)protocolEndpoint).SendRequest(requestType, requestParams, waitForResponse);
74+
}
75+
76+
public Task<TResult> SendRequest<TResult, TError, TRegistrationOptions>(RequestType0<TResult, TError, TRegistrationOptions> requestType0)
77+
{
78+
return ((IMessageSender)protocolEndpoint).SendRequest(requestType0);
79+
}
80+
81+
public void SetRequestHandler<TParams, TResult, TError, TRegistrationOptions>(RequestType<TParams, TResult, TError, TRegistrationOptions> requestType, Func<TParams, RequestContext<TResult>, Task> requestHandler)
82+
{
83+
((IMessageHandlers)messageDispatcher).SetRequestHandler(requestType, requestHandler);
84+
}
85+
86+
public void SetRequestHandler<TResult, TError, TRegistrationOptions>(RequestType0<TResult, TError, TRegistrationOptions> requestType0, Func<RequestContext<TResult>, Task> requestHandler)
87+
{
88+
((IMessageHandlers)messageDispatcher).SetRequestHandler(requestType0, requestHandler);
89+
}
90+
91+
public void SetEventHandler<TParams, TRegistrationOptions>(NotificationType<TParams, TRegistrationOptions> eventType, Func<TParams, EventContext, Task> eventHandler)
92+
{
93+
((IMessageHandlers)messageDispatcher).SetEventHandler(eventType, eventHandler);
4694
}
4795
}
4896
}

src/PowerShellEditorServices.Protocol/Client/LanguageClientBase.cs

Lines changed: 64 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,44 +6,97 @@
66
using Microsoft.PowerShell.EditorServices.Protocol.LanguageServer;
77
using Microsoft.PowerShell.EditorServices.Protocol.MessageProtocol;
88
using Microsoft.PowerShell.EditorServices.Protocol.MessageProtocol.Channel;
9-
using System.Threading.Tasks;
109
using Microsoft.PowerShell.EditorServices.Utility;
10+
using System;
11+
using System.Threading.Tasks;
1112

1213
namespace Microsoft.PowerShell.EditorServices.Protocol.Client
1314
{
1415
/// <summary>
1516
/// Provides a base implementation for language server clients.
1617
/// </summary>
17-
public abstract class LanguageClientBase : ProtocolEndpoint
18+
public abstract class LanguageClientBase : IMessageHandlers, IMessageSender
1819
{
20+
ILogger logger;
21+
private ProtocolEndpoint protocolEndpoint;
22+
private MessageDispatcher messageDispatcher;
23+
1924
/// <summary>
2025
/// Initializes an instance of the language client using the
2126
/// specified channel for communication.
2227
/// </summary>
2328
/// <param name="clientChannel">The channel to use for communication with the server.</param>
2429
public LanguageClientBase(ChannelBase clientChannel, ILogger logger)
25-
: base(
26-
clientChannel,
27-
new MessageDispatcher(logger),
28-
MessageProtocolType.LanguageServer,
29-
logger)
3030
{
31+
this.logger = logger;
32+
this.messageDispatcher = new MessageDispatcher(logger);
33+
this.protocolEndpoint = new ProtocolEndpoint(
34+
clientChannel,
35+
messageDispatcher,
36+
logger);
3137
}
3238

33-
protected override Task OnStart()
39+
public Task Start()
3440
{
41+
this.protocolEndpoint.Start();
42+
3543
// Initialize the implementation class
3644
return this.Initialize();
3745
}
3846

39-
protected override async Task OnStop()
47+
public async Task Stop()
4048
{
49+
await this.OnStop();
50+
4151
// First, notify the language server that we're stopping
42-
var response = await this.SendRequest<object, object, object>(ShutdownRequest.Type);
52+
var response =
53+
await this.SendRequest<object, object, object>(
54+
ShutdownRequest.Type);
55+
4356
await this.SendEvent(ExitNotification.Type, new object());
57+
58+
this.protocolEndpoint.Stop();
59+
}
60+
61+
protected virtual Task OnStop()
62+
{
63+
return Task.FromResult(true);
64+
}
65+
66+
protected virtual Task Initialize()
67+
{
68+
return Task.FromResult(true);
69+
}
70+
71+
public Task SendEvent<TParams, TRegistrationOptions>(NotificationType<TParams, TRegistrationOptions> eventType, TParams eventParams)
72+
{
73+
return ((IMessageSender)protocolEndpoint).SendEvent(eventType, eventParams);
74+
}
75+
76+
public Task<TResult> SendRequest<TParams, TResult, TError, TRegistrationOptions>(RequestType<TParams, TResult, TError, TRegistrationOptions> requestType, TParams requestParams, bool waitForResponse)
77+
{
78+
return ((IMessageSender)protocolEndpoint).SendRequest(requestType, requestParams, waitForResponse);
79+
}
80+
81+
public Task<TResult> SendRequest<TResult, TError, TRegistrationOptions>(RequestType0<TResult, TError, TRegistrationOptions> requestType0)
82+
{
83+
return ((IMessageSender)protocolEndpoint).SendRequest(requestType0);
4484
}
4585

46-
protected abstract Task Initialize();
86+
public void SetRequestHandler<TParams, TResult, TError, TRegistrationOptions>(RequestType<TParams, TResult, TError, TRegistrationOptions> requestType, Func<TParams, RequestContext<TResult>, Task> requestHandler)
87+
{
88+
((IMessageHandlers)messageDispatcher).SetRequestHandler(requestType, requestHandler);
89+
}
90+
91+
public void SetRequestHandler<TResult, TError, TRegistrationOptions>(RequestType0<TResult, TError, TRegistrationOptions> requestType0, Func<RequestContext<TResult>, Task> requestHandler)
92+
{
93+
((IMessageHandlers)messageDispatcher).SetRequestHandler(requestType0, requestHandler);
94+
}
95+
96+
public void SetEventHandler<TParams, TRegistrationOptions>(NotificationType<TParams, TRegistrationOptions> eventType, Func<TParams, EventContext, Task> eventHandler)
97+
{
98+
((IMessageHandlers)messageDispatcher).SetEventHandler(eventType, eventHandler);
99+
}
47100
}
48101
}
49102

src/PowerShellEditorServices.Protocol/Client/LanguageServiceClient.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ protected override Task Initialize()
3838

3939
return this.SendRequest(
4040
InitializeRequest.Type,
41-
initializeParams);
41+
initializeParams,
42+
true);
4243
}
4344

4445
#region Events
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
//
2+
// Copyright (c) Microsoft. All rights reserved.
3+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
4+
//
5+
6+
using System;
7+
using System.Threading.Tasks;
8+
9+
namespace Microsoft.PowerShell.EditorServices.Protocol.MessageProtocol
10+
{
11+
public interface IMessageHandlers
12+
{
13+
void SetRequestHandler<TParams, TResult, TError, TRegistrationOptions>(
14+
RequestType<TParams, TResult, TError, TRegistrationOptions> requestType,
15+
Func<TParams, RequestContext<TResult>, Task> requestHandler);
16+
17+
void SetRequestHandler<TResult, TError, TRegistrationOptions>(
18+
RequestType0<TResult, TError, TRegistrationOptions> requestType0,
19+
Func<RequestContext<TResult>, Task> requestHandler);
20+
21+
void SetEventHandler<TParams, TRegistrationOptions>(
22+
NotificationType<TParams, TRegistrationOptions> eventType,
23+
Func<TParams, EventContext, Task> eventHandler);
24+
}
25+
}

src/PowerShellEditorServices.Protocol/MessageProtocol/IMessageSender.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
namespace Microsoft.PowerShell.EditorServices.Protocol.MessageProtocol
99
{
10-
internal interface IMessageSender
10+
public interface IMessageSender
1111
{
1212
Task SendEvent<TParams, TRegistrationOptions>(
1313
NotificationType<TParams, TRegistrationOptions> eventType,
@@ -17,6 +17,9 @@ Task<TResult> SendRequest<TParams, TResult, TError, TRegistrationOptions>(
1717
RequestType<TParams, TResult, TError, TRegistrationOptions> requestType,
1818
TParams requestParams,
1919
bool waitForResponse);
20+
21+
Task<TResult> SendRequest<TResult, TError, TRegistrationOptions>(
22+
RequestType0<TResult, TError, TRegistrationOptions> requestType0);
2023
}
2124
}
2225

0 commit comments

Comments
 (0)