0

I'm trying to write a cross-platform, wrapper around console apps that will allow me to connect to their stdio from network/remote clients. It is a VERY pared down concept of what Terminado does. In Windows, I'm trying pywinpty so that functions like up-arrow and down-arrow work properly (i.e. move through recent command history).

Each new connection gets a "reader" task that writes directly to the subprocess stdin and there is a "writer" class that monitors the a global queue of pty output and forwards the bytes on to all connected clients. The connected clients are a list of writers in a global variable as is the PTY_PROC object.

There is also the pty_reader, that takes text from the PTY and puts it on the global byte queue.

I am testing using Telnet. I get some good data to the client, but some of it is garbled up. Mainly:

  1. when I type in characters, they are doubled up on the client being typed in but not on others
D:\sandbox\epics\pyProcServ\area_51>didrir

Local echo is off and the terminal type is ANSI.

  1. Some times it seems parts of escape codes are being printed.

When the client connects, this is what it gets:

0;C:\Windows\System32\cmd.exeMicrosoft Windows [Version 10.0.18363.1556][9C
(c) 2019 Microsoft Corporation. All rights reserved.  
52C
D:\sandbox\epics\pyProcServ\area_51>[16C

So far, I've tried matching columns (80) and rows (24) and have been looking in to different terminal settings (i.e VT100, etc), but to no avail.

I'm hoping it's something simple and "obvious".

The core essentials (I believe) are here:

async def client_reader(reader, addr = ''):
# Monitor incoming data and put the bytes in to the subproc stdin
    cmd = ''

    while True:
        try:
            s = await reader.read(1024)
        except asyncio.CancelledError as e:
            break

        PTY_PROC.write(s.decode())

        print(f"client_reader ({addr}): Cancelled and tidying up...")

        return(f"client_reader ({addr})")

async def write_clients():
# Watches the global CLIENTS_QUEUE and writes bytes out to
# all the clients in "WRITERS"

    data = None

    while True:
        try:
            data = await CLIENTS_QUEUE.get()

            if not data:
                break

            for writer in WRITERS:
                if data != None:
                    writer.write(data.encode())
                    await writer.drain()

        except asyncio.CancelledError:

            break

    for writer in WRITERS:
    # flush existing data to clients
        if data != None:
            writer.write(data.encode())
        writer.write(b"\r\n\r\n### Server shutting down or restarting...")
        await writer.drain()

        writer.close()
        await writer.wait_closed()

    print(f"write_clients exiting.")

    return("write_clients")

async def pty_output():
# Read chars/strings from pty and place on byte queue.
    global CACHED_OUTPUT
    timeout = 0.1

    s = ''
    while True:
        try:
            r, _, _ = select.select([PTY_PROC.fd], [], [], timeout)

            if not r:
                await asyncio.sleep(0.1)
                continue

            s = PTY_PROC.read(1024)
            await CLIENTS_QUEUE.put(s.encode())

        except asyncio.CancelledError:
            print(f"pty_output: Cancelled and tidying up...")
            break

    if len(s) > 0: # flush any remaining data to the queue
        await CLIENTS_QUEUE.put(s.encode())

    return("pty_output")
Robatron
  • 83
  • 9
  • You need to focus on one problem at a time. Some of your issues appear to be cosmetic (having to do with what you see on screen), and others appear to be possibly related to functionality, like characters appearing twice. And when you say that sometimes it works and sometimes it doesn't, it appears like you might have some issues with how the user is interacting with the application. I suggest you pick one problem and try restating the question. – Paul Cornelius Aug 17 '22 at 22:49
  • @PaulCornelius, thanks for the guidance!! :) I was kinda' hoping (assuming) they were all related. I have narrowed it down to two issues. Number 2 is the most critical (I think). – Robatron Aug 18 '22 at 00:22

0 Answers0