99 lines
2.1 KiB
Python
99 lines
2.1 KiB
Python
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
|
|
|