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

Fail gracefully for impossible hosts #3560

Open
dodexahedron opened this issue Jun 23, 2024 · 4 comments
Open

Fail gracefully for impossible hosts #3560

dodexahedron opened this issue Jun 23, 2024 · 4 comments
Labels
bug design Issues regarding Terminal.Gui design (bugs, guidelines, debates, etc...) priority-low Issues which are low-priority, but should be kept around. v2 For discussions, issues, etc... relavant for v2

Comments

@dodexahedron
Copy link
Collaborator

TL;DR: We should do better than V1 does for V2, when the host environment isn't a supportable terminal. V1 fails in unhelpful ways.

V2 failing with an informative result is really all that's needed. We can detect at least the situation the story below recounts. Read on to see how an unplanned use of a TG application over PS Remoting over SSH went.


So,

I was doing normal everyday administrative work on some systems (linux and windows) using PowerShell, as one does. (PS Remoting via SSH actually already works, today, across Windows, Linux, and macOS).

Here are the results of some experimentation I did, related to TG:

While on one of them, I tried to launch an application that uses v1 of Terminal.Gui, and it was unable to run, simply saying Error opening terminal: unknown.

Then I remembered that PS Remoting doesn't set the TERM environment variable (it's not really a terminal - it's a separate subsystem in ssh when used that way, like SFTP is). So, I set $Env:TERM (which is the TERM environment variable) to xterm-256color and tried again.

The TG application didn't immediately die, this time. Instead, it just did nothing and appeared to hang, after the application had logged that it was starting up the UI. So I ctrl-C killed the process.

However, inspecting the log output from that application, from that run, TG actually did initialize and thinks that things were all good and at least the code that creates and shows the main window for that app did run to completion without any exceptions (there's a global handler in that one that logs any received).

But then I thought I'd try hotkeys since supposedly it was running, right? So I launched it again to see if it would respond to hotkeys, even though I couldn't see it. At least the ctrl-q to quit, I thought. Nope. Wouldn't respond to any.

Then I set up all the other environment variables I would normally have in a regular login session and tried again. Same result. The application does work on that system via a normal login session.

It makes sense that it doesn't work, because PS Remoting is a whole different game and isn't a terminal. It's a non-interactive pwsh process running on the server, on-demand by sshd, and its stdin and stdout aren't System.Console (well...not what you'd typically think of it as, anyway).

You aren't even actually sending keystrokes to the remote machine as you type. Everything is serialized to XML (SOAP), and it's more like a transactional request/response paradigm, with the local host wrapping your commands in an invoke request and sending it off en-bloc. Hence no hotkey response. CTRL-C only worked because powrshell has that defined that way.

And stdout isn't connected to the client either. It's captured by the remote non-interactive pwsh process and buffered for later retrieval. It's written as either text or SOAP depending on configuration on the server side. And it's asynchronous - You can run the command while not attached to the remote and then retrieve the output whenever you want, ignore it and never retrieve output, or one of my favorites: give a list of systems and it will execute it on all of them simultaneously, with the output buffered in the same fashion on each for retrieval at your option and leisure.

So yeah... Anyway... Aside from the PS Remoting advert...
I think that v2, if it doesn't already, should at least provide a more meaningful output than what I got, in the first situation, and fail more gracefully in general when an attempt is made to use it somewhere it can't be used.

One of the differences that is likely one of the easiest to take advantage of is that the host isn't ConsoleHost in that scenario -- It is ServerRemoteHost.

Support for PS remoting would require its own completely different ConsoleDriver and tons of work around translating between the two worlds, so I'm not about to suggest we even begin to go down that road.

Anyway...

Have any of you guys happened to try it out, in any combination of OS on either end, using PS Remoting via the SSH transport? Or even Windows to Windows over the older WinRM HTTP-based transport (the SOAP is the same either way as far as I'm aware).

And note that this is not the same as using an interactive powershell session as either a login shell or on top of another shell, over SSH. That of course works as expected.

@dodexahedron dodexahedron added bug design Issues regarding Terminal.Gui design (bugs, guidelines, debates, etc...) priority-low Issues which are low-priority, but should be kept around. v2 For discussions, issues, etc... relavant for v2 labels Jun 23, 2024
@dodexahedron
Copy link
Collaborator Author

Here are some things that are true in a Remoting session:

  • Console.IsInputRedirected
  • Console.IsOutputRedirected
  • The PowerShell global session variable $PSSenderInfo is not null and is a dictionary
    • This one likely isn't accessible without referencing the PowerShell APIs because they're not environment variables - they're just ambient data in the PowerShell application itself, and aren't directly exposed to anything inside it as far as I know.

But...

The redirection alone is probably enough, at least with how Terminal.Gui currently works. Redirection of the in and out streams will break it, so a simple check against those first two boolean properties before doing anything else and throwing a meaningful exception or something is probably sufficient.

Any thoughts?

@dodexahedron
Copy link
Collaborator Author

And just for the record, I don't think TG breaking on redirection is a good thing to be a permanent limitation. But I suspect it's a bit too much for V2 to make it work with that, so that seems like an acceptable means of detecting an unsupported environment and terminating, right now.

@dodexahedron
Copy link
Collaborator Author

I played around with some code for a bit since I got annoyingly fixated on this (done now though)...

The environment variables that are set make it almost look like a normal interactive session, aside from missing $TERM, $COLUMNS, and $LINES. Those are simply not even defined, by default, at least in a PS Remoting session from my Windows 11 PC with PS 7.5 preview 3 remoting to an Ubuntu 24.04 system with the same version of PowerShell. It even shows as being on top of bash, in this particular environment, which was a semi-surprising thing since I figured the login shell for the user would have been bypassed. But it appears the user's default shell is being loaded. I changed the default shell for a user to sh and opened a new session to check that hypothesis, which was confirmed.

I don't know why the behavior when you've entered the session isn't to re-redirect the stdin and stdout streams to the active shell, but it isn't, so PS Remoting is currently just not compatible with a TG application.

There are a few other environment variables that are not there, so it's clearly not loading the shell with the logged in user's profile (I've got a .bashrc that sets a bunch of stuff up and it wasn't there in the bash case), but they're not helpful or in any significant way an actual indicator of what the environment is, anyway, as far as I can see without spending more time on it that I don't want to waste.

I suppose another option for validating the environment - which would need to be conditionally skipped if AoT compiled, because it isn't trim friendly - would be to attempt to load the System.Management.Automation library into the AppDomain to make the check, so that it could be used without having a hard compile-time dependency. Inability to load the assembly would mean you're not in PowerShell (probably), and if you can load it you can access the PS session variables through that API... But that's gross IMO, and the checks for redirection seem good enough for the time being.

Besides, it's likely to be a corner case anyway. Even if usage does explode after V2 release and people start running into the problem, it can simply be addressed by documenting it as an unsupported environment until or unless a driver that works with it is ever created by some ambitious individual. 🤷‍♂️

And if you have the ability to use PSRemoting over SSH, you already apparently have SSH, so you can just connect in a normal session and move on with life.

@dodexahedron
Copy link
Collaborator Author

Huh. Maybe it's lying actually...

Process list shows the pwsh-preview process directly owned by sshd, so... 🤷‍♂️

Back to work on important stuff now...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug design Issues regarding Terminal.Gui design (bugs, guidelines, debates, etc...) priority-low Issues which are low-priority, but should be kept around. v2 For discussions, issues, etc... relavant for v2
Projects
None yet
Development

No branches or pull requests

1 participant