v1.8.3: session pool + sidebar indicators
- SessionPool: LRU cache for SSH/SFTP sessions across server switches - Sidebar: green dot indicators for servers with active sessions - Sidebar: active sessions count label - Terminal: buffer preservation on server switch via get_current_buffer() - FilesTab/TerminalTab: pool integration for session reuse Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -11,9 +11,10 @@ from core.i18n import t
|
||||
|
||||
|
||||
class TerminalTab(ctk.CTkFrame):
|
||||
def __init__(self, master, store):
|
||||
def __init__(self, master, store, session_pool=None):
|
||||
super().__init__(master, fg_color="transparent")
|
||||
self.store = store
|
||||
self.session_pool = session_pool
|
||||
self._current_alias: str | None = None
|
||||
self._session: ShellSession | None = None
|
||||
self._reconnect_count = 0
|
||||
@@ -39,7 +40,16 @@ class TerminalTab(ctk.CTkFrame):
|
||||
def set_server(self, alias: str | None):
|
||||
if alias == self._current_alias:
|
||||
return
|
||||
|
||||
# Store state of current session before switching
|
||||
if self._current_alias and self._session and self.session_pool:
|
||||
# Store terminal buffer from widget
|
||||
buf = self._terminal.get_current_buffer()
|
||||
self.session_pool.store_shell_state(self._current_alias, buf)
|
||||
|
||||
# Disconnect current session
|
||||
self._disconnect()
|
||||
|
||||
self._current_alias = alias
|
||||
if alias:
|
||||
self._connect()
|
||||
@@ -65,15 +75,32 @@ class TerminalTab(ctk.CTkFrame):
|
||||
def _do_connect():
|
||||
try:
|
||||
key_path = self.store.get_ssh_key_path()
|
||||
cols, rows = self._terminal.get_size()
|
||||
session = ShellSession(server, key_path, cols=cols, rows=rows)
|
||||
session.on_data = self._on_data_received
|
||||
session.on_disconnect = self._on_disconnected
|
||||
session.connect()
|
||||
|
||||
# Use session pool if available
|
||||
if self.session_pool:
|
||||
cols, rows = self._terminal.get_size()
|
||||
session, is_new = self.session_pool.get_or_create_shell_session(alias, server, key_path)
|
||||
if is_new:
|
||||
# Configure the session with proper terminal dimensions
|
||||
session.cols = cols
|
||||
session.rows = rows
|
||||
session.connect()
|
||||
|
||||
# Set up callbacks even if session already existed
|
||||
session.on_data = self._on_data_received
|
||||
session.on_disconnect = self._on_disconnected
|
||||
self._session = session
|
||||
else:
|
||||
# Legacy behavior without session pool
|
||||
cols, rows = self._terminal.get_size()
|
||||
session = ShellSession(server, key_path, cols=cols, rows=rows)
|
||||
session.on_data = self._on_data_received
|
||||
session.on_disconnect = self._on_disconnected
|
||||
session.connect()
|
||||
self._session = session
|
||||
|
||||
# Set session on main thread to avoid races
|
||||
def _set_session():
|
||||
self._session = session
|
||||
self._reconnect_count = 0
|
||||
self._terminal.set_status(
|
||||
t("term_connected").format(alias=alias), "#44cc44"
|
||||
@@ -89,10 +116,16 @@ class TerminalTab(ctk.CTkFrame):
|
||||
|
||||
def _disconnect(self):
|
||||
self._intentional_disconnect = True
|
||||
session = self._session
|
||||
self._session = None
|
||||
if session:
|
||||
session.disconnect()
|
||||
# Only disconnect if we don't have a session pool (otherwise session stays alive)
|
||||
if not self.session_pool and self._session:
|
||||
self._session.disconnect()
|
||||
self._session = None
|
||||
# If using session pool, session remains active in the pool
|
||||
elif self.session_pool and self._session:
|
||||
# Remove callbacks to prevent processing data after switch
|
||||
self._session.on_data = None
|
||||
self._session.on_disconnect = None
|
||||
self._session = None
|
||||
|
||||
def _on_data_received(self, data: bytes):
|
||||
"""Called from SSH thread — put data in thread-safe queue."""
|
||||
@@ -117,6 +150,10 @@ class TerminalTab(ctk.CTkFrame):
|
||||
self._terminal.set_status(t("term_disconnected"), "#888888")
|
||||
return
|
||||
|
||||
# Remove dead session from pool so it gets recreated on next connect
|
||||
if self.session_pool and self._current_alias:
|
||||
self.session_pool.disconnect_session(self._current_alias)
|
||||
|
||||
self._session = None
|
||||
|
||||
if self._reconnect_count < self._max_reconnect:
|
||||
|
||||
Reference in New Issue
Block a user