hSaria / ChromaTerm

Color your Terminal with RegEx!

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

BlockingIOError Still Seen in v0.10.7

jetblackrx89 opened this issue · comments

ChromaTerm version

ct 0.10.7

Terminal

iTerm 2

What's happening?

Seem like the commit for issue #93 either got backed out or wasn't properly committed. I am seeing the same BlockingIOError on pretty much any telnet session to any Cisco router on a corporate network due to the fact that the output obviously isn't immediate but rather delayed by a couple hundred milliseconds.

I manually imported the patched "__main__.py" from the commit listed at the end of that bug and it seems to work fine. If telnet is slow, it adds an extremely minor delay in output so outputs can be color formatted properly. When running commands locally on my own computer, the output is immediate. I think the fix is working properly, so can it be committed to the main branch?

The fix (e330cb0) is already applied; It was never removed, although it was refactored a bit.

# #93: Avoid BlockingIOError when output to non-blocking stdout is too fast
try:
getattr(os, 'set_blocking', lambda *_: None)(sys.stdout.fileno(), True)
except io.UnsupportedOperation:
pass

Can you run pip3 install --force-reinstall chromaterm then paste the traceback when the error is shown? And how do you invoke ChromaTerm (e.g. ct ssh host, ssh host | ct, or terminal-wide highlighting)?

Thanks for the response. As soon as I run pip3 install --force-reinstall chromaterm the issue returns. Traceback seen:

                                    File "/usr/local/bin/ct", line 8, in <module>
                                                                                     sys.exit(main())
                                                                                                       File "/usr/local/lib/python3.10/site-packages/chromaterm/__main__.py", line 499, in main
                                                        process_input(config, data_fd, forward_fd, max_wait)
                                                                                                              File "/usr/local/lib/python3.10/site-packages/chromaterm/__main__.py", line 332, in process_input
                                                                        sys.stdout.flush()
                                                                                          BlockingIOError: [Errno 35] write could not complete without blocking

I am running CT via adding a new "profile" to iTerm 2 to intercept all telnet:// URL's with the command /usr/local/bin/telnet_chromaterm $$HOST$$ $$PORT$$. I think I did it this way because iTerm 2 doesn't like piped outputs in the "profiles" > "command" setting. "telnet_chromaterm" is a very basic bash script I wrote that in turn does:

#!/bin/tcsh

/usr/local/bin/telnet $1 $2 | /usr/local/bin/ct

I was able to recreate this issue using a pubic route server.

ChromaTerm is settings stdout to blocking mode (as intended), but the telnet client is setting the stdout back to non-blocking after logging in, which is causing this issue.

For the time being, you can change your script to use /usr/local/bin/ct /usr/local/bin/telnet $1 $2 which will provide telnet with a pseudo TTY, so it wouldn't change the blocking mode of the real stdout.

Thank you so much. I followed your suggestion and modified the wrapper bash script I made per your suggestion, and it's working fine now.

Unfortunately, fixing this is not feasible due to how some programs behave, so you should let ChromaTerm spawn your program (i.e. as per the suggestion above).

Using pipes will make it so a program can escape the redirection and gain direct access to stdout (see #80 for an example). As such, some programs will modify the properties of stdout, like telnet. The workaround would be to periodically override them, which might cause unintended effects to the program. And even then, the program can simply reapply their changes at any point.

I could wrap various parts of the code with error handling, but because of the nature of writing to a non-blocking file descriptor, I wouldn't know how much of the data was written out before the error was encountered, so we'd either have to print it twice or just move on. Either way, the output would be invalid. There's also the possibility of using select.select to ensure the stdout is ready to be written to, but that would incur a performance penalty because I'd have to runs this check before every single write call, of which there are many.

I'd rather that people avoid pipes when dealing with intricate programs that attempt to escape piping or modify the properties of stdout. Let ct spawn your program.