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

tower_lsp::ClientSocket is (potentially) missing some functionality from lspower::MessageStream #341

Open
rockstar opened this issue May 18, 2022 · 6 comments
Labels
bug Something isn't working

Comments

@rockstar
Copy link

In influxdata/flux-lsp#427, the flux-lsp moved from lspower to tower-lsp because the merge had occurred. The reason we had used lspower in the first place is because we needed to be able export the lsp server via wasm. We have a wasm interface that looks like this (expressed in TypeScript):

interface LspServer {
  run(): Promise<void>;
  send(message: String): Promise<String>;
  onMessage(handler: (message: String) => String): void;
}

The idea here was that you could request things from the server via send, and any time that the server needed to initiate diagnostics, logs, notifications, etc. via the onMessage handlers. The way we implemented this is something similar to this (you can read the full source in the PR/repo)

let (service, messages) = LspService::new(...);

while let Some(msg) = messages.next().await {
  ...some code for handling msg...
  for h in onMessageHandlers {
    h.call1(msg);
  }
}

Somewhere between the change from lspower::MessageStream to tower_lsp::ClientSocket, that message firing from the server is broken. While trying to dig into the issue, a lot of the introspection isn't possible because ClientSocket has a lot of private interfaces (which probably isn't related to the issue, but maybe something to consider for debugging going forward). What am I missing? How did the interface change so that messages.next().await doesn't ever loop, no matter how many messages the server sends to the client.

@ebkalderon ebkalderon added the bug Something isn't working label May 18, 2022
@ebkalderon
Copy link
Owner

Thanks for opening this ticket! If you check the Stream implementation of ClientSocket today (source), it delegates down into the underlying futures::channel::mpsc::Receiver<_> implementation of Stream. This is pretty much the same as how the old Client and MessageStream worked, albeit with a new abstraction around it.

How did the interface change so that messages.next().await doesn't ever loop, no matter how many messages the server sends to the client.

Do you think you could elaborate on what you mean by this? In the code snippet above, I cannot see how service is being driven. The LspService must be actively emitting server-to-client messages for messages.next().await to yield them, and since there isn't any service.call(...).await nor is service passed into Server::new, I can't understand how the loop would ever progress as described. I'd love if you could provide more details!

@rockstar
Copy link
Author

Thanks for the reply. I've been fighting trying to solve this bug for quite a bit; I don't see that much functional difference.

We have an exported run function that essentially fakes an event loop and runs forever. That calls server.processor.process().await (with some error handling). Our send function is where service.call is called, but I didn't think that'd have much to do with messages originating from the server; you asking about it makes me wonder if I need to be looking at this solution holistically, and potentially evaluating whether or solution is hacky or not.

@silvanshade
Copy link
Contributor

silvanshade commented May 28, 2022

@rockstar I'm not really sure why the approach you described worked before but doesn't work now, but I am wondering if the problem might go away if you could avoid using the custom LspServer interface and instead set things up through Server::new as usual.

In the case of a wasm target, I believe you should be able to use the web Streams API. There is a wasm-streams crate that provides adapters between the Streams API from web-sys and the usual futures Streams, along with impls for AsyncRead and AsyncWrite, which you will need for connecting everything up with Server::new.

I've created a quick minimal example that demonstrates this approach at tower-lsp-web-demo.

@silvanshade
Copy link
Contributor

The wasm-based project that I linked to above is now a fairly complete example which fully demonstrates how to use tower-lsp with the intended API in a wasm context. I'd be happy to answer any questions about how that was set up but otherwise I think it's safe to close this since the original motivation was to be able to use tower-lsp for a wasm target.

@rockstar
Copy link
Author

I'm not sure I agree that the bug is fixed. Sure, you've provided a workaround, but there's a disconnect where "what worked then doesn't work now" in an absolutely public api. The workaround is definitely something to explore, but this would require an re-architecture of a large portion of more than one application. As it stands, the migration from lspower to tower-lsp is a no-go for us.

@ebkalderon
Copy link
Owner

Reopening this ticket in order to ensure this gets addressed! I happened to notice this was closed a while ago, despite noticeable reservations that it was actually resolved.

@ebkalderon ebkalderon reopened this Aug 11, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants