From 563f7218ec3790ac684a227bc8808c6ec2fbc6a6 Mon Sep 17 00:00:00 2001 From: yumoqing Date: Tue, 15 Jul 2025 16:55:33 +0800 Subject: [PATCH] bugfix --- appPublic/sshx.py | 6 ++- test/sshnode.py | 98 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 103 insertions(+), 1 deletion(-) create mode 100644 test/sshnode.py diff --git a/appPublic/sshx.py b/appPublic/sshx.py index a323faf..3604c08 100644 --- a/appPublic/sshx.py +++ b/appPublic/sshx.py @@ -12,7 +12,11 @@ import asyncio, asyncssh, sys class SSHServer: def __init__(self, server, jumpservers=[]): self.server = server - self.jumpservers = jumpservers + if not jumpservers: + if server['jumpservers']: + self.jumpservers = server['jumpservers'] + else: + self.jumpservers = jumpservers async def _connect_server(self, server, refconn=None): f = asyncssh.connect diff --git a/test/sshnode.py b/test/sshnode.py new file mode 100644 index 0000000..4210965 --- /dev/null +++ b/test/sshnode.py @@ -0,0 +1,98 @@ +import asyncio +import asyncssh +import sys +import termios +import tty +import signal +from appPublic.sshx import SSHServer + +class InteractiveSSHClient(asyncssh.SSHClientSession): + def __init__(self): + self._chan = None + self._stdin_task = None + + def connection_made(self, chan): + self._chan = chan + self._stdin_task = asyncio.create_task(self._forward_stdin()) + + async def _forward_stdin(self): + old_attrs = termios.tcgetattr(sys.stdin) + try: + tty.setraw(sys.stdin.fileno()) + while True: + data = await asyncio.get_event_loop().run_in_executor(None, sys.stdin.read, 1) + if not data: + break + self._chan.write(data) + except asyncio.CancelledError: + pass + finally: + termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_attrs) + + def data_received(self, data, datatype): + print(data, end='', flush=True) + + def connection_lost(self, exc): + if self._stdin_task: + self._stdin_task.cancel() + +def get_terminal_size(): + try: + import fcntl, struct + h, w, hp, wp = struct.unpack('HHHH', + fcntl.ioctl(sys.stdin, termios.TIOCGWINSZ, + struct.pack('HHHH', 0, 0, 0, 0))) + return (h, w) + except: + return (24, 80) # fallback + + +async def run_interactive_bash(): + term_size = get_terminal_size() + + node = { + "host":"192.168.16.8", + "username":"root", + "password":"Kyy@123456", + "jumpservers" : [ + { + "host":"git.opencomputing.cn", + "username":"ymq", + "password":"Ymq@651018" + } + ] + } + jumpservers = [ + { + "host":"git.opencomputing.cn", + "username":"ymq", + "password":"Ymq@651018" + } + ] + node = SSHServer(node) + async with node.get_connector() as conn: + A, B = await conn.create_session( + InteractiveSSHClient, + term_type='xterm', + term_size=term_size + ) + print(f'{A=}, {B=}') + # 监听窗口 resize 信号,更新远端窗口大小 + def resize_handler(signum, frame): + nonlocal A + if A: + rows, cols = get_terminal_size() + chan.change_pty('xterm', term_size=(rows, cols)) + + signal.signal(signal.SIGWINCH, resize_handler) + + await A.wait_closed() + +if __name__ == '__main__': + try: + asyncio.run(run_interactive_bash()) + except (OSError, asyncssh.Error) as e: + print(f'SSH session failed: {e}') + except KeyboardInterrupt: + pass +