Skip to content

✨Middleware#6

Merged
cowboyd merged 3 commits intomainfrom
middleware
Apr 2, 2025
Merged

✨Middleware#6
cowboyd merged 3 commits intomainfrom
middleware

Conversation

@cowboyd
Copy link
Copy Markdown
Member

@cowboyd cowboyd commented Mar 31, 2025

Motivation

In order to have an extensible architecture that will allow us to do things like provide client capabilities that the upstream client does not provide, we need a way to insert lspx into the conversation between client and servers. An example of this is fixing the gap in the conversation between eglot and vscode-eslint-language-server. (see #3)

Approach

This applies the middleware pattern to all communication between client and server so that a single middleware can intercept whichever messages it needs to carry out its job. Because connections are stateful and support both notification and request, there are four components to each middleware:

client to N servers:

  • notify
  • request

1 of N servers to client:

  • notify
  • request

Because the middleware contains not only the request/notification params, but also the lsp agents that are sending and receiving, it can make decisions about filtering agents before forwarding on, or it can ever respond directly without consulting the other end of the connection.

As part of this, the lifecycle that captures capabilities has been re-written as the very first middleware at the top of the stack, and it actually makes it quite a bit cleaner. The lifecycle of the LSPX server is a middleware that delegates to a "State" middleware.

Possible Drawbacks or Risks

A hypothetical risk is that it could lead to performance problems if there is too much delegation bouncing around in the system. Another concern that could be raised is that the delegation itself makes the codebase more difficult to understand, however while that might be nominally true at the level of baseline request routing. However, the clarity it brings to actually defining the behavior of the system far outweighs that.

TODOs and Open Questions

  • This change limits itself to the minimum required to insert the middleware into each piece of communication, but in the future we should look to extracting out the special case "completion" handler in the defaultRequest and implement it as middleware.

cowboyd added 2 commits March 31, 2025 11:19
In order to have an extensible architecture that will allow us to do
things like provide client capabilities that the upstream client does
not provide, we need a way to insert lspx into the conversation
between client and servers. An example of this is fixing the gap in
the conversation between `eglot` and `vscode-eslint-language-server`.

This applies the middleware pattern to all communication between
client and server so that a single middleware can intercept whichever
messages it needs to carry out its job. Because connections are
stateful and support both notification and request, there are four
components to each middleware:

client to N servers:

- notify
- request

1 of N servers to client:
- notify
- request

Because the middleware contains not only the request/notification
params, but also the lsp agents that are sending and receiving, it can
make decisions about filtering agents before forwarding on, or it can
ever respond directly without consulting the other end of the
connection.

As part of this, the lifecycle that captures capabilities has been
re-written as the very first middleware at the top of the stack, and
it actually makes it quite a bit cleaner. The lifecycle of the LSPX
server is a middleware that delegates to a "State" middleware.

This change limits itself to the minimum required to insert the
middleware into each piece of communication, but in the future we
should look to extracting out the special case "completion" handler in
the `defaultRequest` and implement it as middleware
@cowboyd cowboyd linked an issue Apr 2, 2025 that may be closed by this pull request
@cowboyd cowboyd merged commit 369dff2 into main Apr 2, 2025
3 checks passed
@cowboyd cowboyd deleted the middleware branch April 2, 2025 14:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

stderr from servers are missing

1 participant