创建了 create_terminal 方法;没有子进程时,自动调用 create_terminal 重新创建

This commit is contained in:
CakeCN
2026-01-08 00:28:39 +08:00
parent 6fba03ea4a
commit eba1e8052c

View File

@@ -123,25 +123,24 @@ def read_and_forward_pty_output(fd=None, pid=None, room_id=None, namespace=None)
pass pass
class VSCLikeNameSpace(Namespace): class VSCLikeNameSpace(Namespace):
def on_connect(self): def create_terminal(self):
"""new client connected""" """创建新的终端并更新session配置"""
# 为每个客户端生成唯一的会话ID和房间ID terminal_config = session.get('terminal_config', {})
session_id = str(uuid.uuid4())
room_id = f"terminal_{session_id}"
# 加入房间 # 如果没有房间ID创建一个新的
join_room(room_id) if not terminal_config.get('room_id'):
session_id = str(uuid.uuid4())
room_id = f"terminal_{session_id}"
join_room(room_id)
terminal_config.update({
**TERM_INIT_CONFIG.copy(),
'session_id': session_id,
'room_id': room_id
})
else:
room_id = terminal_config['room_id']
# 确保terminal_config存在于session中每个客户端有独立配置 current_app.logger.debug(f"Creating new terminal for room: {room_id}")
terminal_config = {
**TERM_INIT_CONFIG.copy(),
'session_id': session_id,
'room_id': room_id
}
session['terminal_config'] = terminal_config
session.modified = True
current_app.logger.debug(f"Client connected, session_id: {session_id}, room_id: {room_id}")
# create child process attached to a pty we can read from and write to # create child process attached to a pty we can read from and write to
(child_pid, fd) = pty.fork() (child_pid, fd) = pty.fork()
@@ -200,11 +199,36 @@ class VSCLikeNameSpace(Namespace):
# 记录日志 # 记录日志
current_app.logger.debug(f"Child process created: {child_pid} for room: {room_id}") current_app.logger.debug(f"Child process created: {child_pid} for room: {room_id}")
current_app.logger.debug(f"Client joined room: {room_id}")
# 启动后台任务读取pty输出传入正确的room_id # 启动后台任务读取pty输出传入正确的room_id
socketio.start_background_task(read_and_forward_pty_output, fd, child_pid, room_id, self) socketio.start_background_task(read_and_forward_pty_output, fd, child_pid, room_id, self)
current_app.logger.debug("background task running") current_app.logger.debug("Background task running")
return terminal_config
def on_connect(self):
"""new client connected"""
# 为每个客户端生成唯一的会话ID和房间ID
session_id = str(uuid.uuid4())
room_id = f"terminal_{session_id}"
# 加入房间
join_room(room_id)
# 确保terminal_config存在于session中每个客户端有独立配置
terminal_config = {
**TERM_INIT_CONFIG.copy(),
'session_id': session_id,
'room_id': room_id
}
session['terminal_config'] = terminal_config
session.modified = True
current_app.logger.debug(f"Client connected, session_id: {session_id}, room_id: {room_id}")
# 创建终端
self.create_terminal()
current_app.logger.debug("background task running")
def on_pty_input(self, data): def on_pty_input(self, data):
"""write to the child pty, which now is the ssh process from this machine to the 'domain' configured """write to the child pty, which now is the ssh process from this machine to the 'domain' configured
@@ -227,36 +251,50 @@ class VSCLikeNameSpace(Namespace):
try: try:
terminal_config = session.get('terminal_config', {}) terminal_config = session.get('terminal_config', {})
child_pid = terminal_config.get('child_pid') child_pid = terminal_config.get('child_pid')
# 如果没有子进程,重新创建终端
if not child_pid: if not child_pid:
current_app.logger.error("No child process found") current_app.logger.debug("No child process found, creating new terminal")
return terminal_config = self.create_terminal()
child_pid = terminal_config.get('child_pid')
if not child_pid:
current_app.logger.error("Failed to create new terminal")
return
child_process = psutil.Process(child_pid) # 检查子进程是否存在且运行中
if child_process.status() not in ('running', 'sleeping'): try:
current_app.logger.debug("Child process not running, cleaning up") child_process = psutil.Process(child_pid)
terminal_config.pop('child_pid', None) if child_process.status() not in ('running', 'sleeping'):
terminal_config.pop('fd', None) current_app.logger.debug("Child process not running, creating new terminal")
session.modified = True terminal_config = self.create_terminal()
return child_pid = terminal_config.get('child_pid')
if not child_pid:
current_app.logger.error("Failed to create new terminal")
return
except psutil.NoSuchProcess:
current_app.logger.debug("Child process not found, creating new terminal")
terminal_config = self.create_terminal()
child_pid = terminal_config.get('child_pid')
if not child_pid:
current_app.logger.error("Failed to create new terminal")
return
# 获取文件描述符并写入数据
fd = terminal_config.get('fd') fd = terminal_config.get('fd')
if fd: if fd:
try: try:
os.write(fd, input_data.encode()) os.write(fd, input_data.encode())
except (OSError, IOError) as e: except (OSError, IOError) as e:
# File descriptor closed or invalid, clean up # File descriptor closed or invalid, create new terminal
current_app.logger.debug(f"Error writing to file descriptor: {e}") current_app.logger.debug(f"Error writing to file descriptor: {e}, creating new terminal")
terminal_config.pop('child_pid', None) terminal_config = self.create_terminal()
terminal_config.pop('fd', None)
session.modified = True
except psutil.NoSuchProcess:
# Process no longer exists, clean up
terminal_config = session.get('terminal_config', {})
terminal_config.pop('child_pid', None)
terminal_config.pop('fd', None)
session.modified = True
except Exception as e: except Exception as e:
current_app.logger.error(f"Error in pty_input handling: {e}") current_app.logger.error(f"Error in pty_input handling: {e}")
# 发生异常时尝试重新创建终端
try:
self.create_terminal()
except Exception as create_err:
current_app.logger.error(f"Failed to recreate terminal: {create_err}")
def on_resize(self, data): def on_resize(self, data):
@@ -281,39 +319,51 @@ class VSCLikeNameSpace(Namespace):
try: try:
terminal_config = session.get('terminal_config', {}) terminal_config = session.get('terminal_config', {})
child_pid = terminal_config.get('child_pid') child_pid = terminal_config.get('child_pid')
# 如果没有子进程,重新创建终端
if not child_pid: if not child_pid:
current_app.logger.error("No child process found for resize") current_app.logger.debug("No child process found for resize, creating new terminal")
return terminal_config = self.create_terminal()
child_pid = terminal_config.get('child_pid')
if not child_pid:
current_app.logger.error("Failed to create new terminal for resize")
return
# 检查子进程是否存在且运行中 # 检查子进程是否存在且运行中
child_process = psutil.Process(child_pid) try:
if child_process.status() not in ('running', 'sleeping'): child_process = psutil.Process(child_pid)
current_app.logger.debug("Child process not running, cleaning up resize") if child_process.status() not in ('running', 'sleeping'):
terminal_config.pop('child_pid', None) current_app.logger.debug("Child process not running for resize, creating new terminal")
terminal_config.pop('fd', None) terminal_config = self.create_terminal()
session.modified = True child_pid = terminal_config.get('child_pid')
return if not child_pid:
current_app.logger.error("Failed to create new terminal for resize")
return
except psutil.NoSuchProcess:
current_app.logger.debug("Child process not found for resize, creating new terminal")
terminal_config = self.create_terminal()
child_pid = terminal_config.get('child_pid')
if not child_pid:
current_app.logger.error("Failed to create new terminal for resize")
return
# 获取文件描述符并调整窗口大小
fd = terminal_config.get('fd') fd = terminal_config.get('fd')
if fd: if fd:
# 检查文件描述符是否有效
try: try:
os.fstat(fd) os.fstat(fd)
set_winsize(fd, rows, cols) set_winsize(fd, rows, cols)
except (OSError, IOError) as e: except (OSError, IOError) as e:
# 文件描述符无效,清理资源 # 文件描述符无效,创建新终端
current_app.logger.debug(f"Error resizing terminal: {e}") current_app.logger.debug(f"Error resizing terminal: {e}, creating new terminal")
terminal_config.pop('child_pid', None) terminal_config = self.create_terminal()
terminal_config.pop('fd', None)
session.modified = True
except psutil.NoSuchProcess:
# 进程不存在,清理资源
terminal_config = session.get('terminal_config', {})
terminal_config.pop('child_pid', None)
terminal_config.pop('fd', None)
session.modified = True
except Exception as e: except Exception as e:
current_app.logger.error(f"Error in resize handling: {e}") current_app.logger.error(f"Error in resize handling: {e}")
# 发生异常时尝试重新创建终端
try:
self.create_terminal()
except Exception as create_err:
current_app.logger.error(f"Failed to recreate terminal for resize: {create_err}")
def on_disconnect(self): def on_disconnect(self):
terminal_config = session.get('terminal_config', {}) terminal_config = session.get('terminal_config', {})