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:
chrome-storm-c442
2026-02-24 03:05:05 -05:00
parent 1a7b075cca
commit 8f55b210b3
9 changed files with 426 additions and 31 deletions

View File

@@ -9,6 +9,7 @@ from core.server_store import ServerStore
from core.status_checker import StatusChecker
from core import i18n
from core.i18n import t, LANGUAGES
from core.session_pool import SessionPool
from gui.sidebar import Sidebar
from gui.server_dialog import ServerDialog
from gui.about_dialog import AboutDialog
@@ -35,6 +36,7 @@ class App(ctk.CTk):
# Core
self.store = ServerStore()
self.checker = StatusChecker(self.store)
self.session_pool = SessionPool(max_sessions=5) # Create session pool
# Layout
self._build_layout()
@@ -49,7 +51,7 @@ class App(ctk.CTk):
def _build_layout(self):
# Sidebar
self.sidebar = Sidebar(self, self.store, on_select=self._on_server_select)
self.sidebar = Sidebar(self, self.store, on_select=self._on_server_select, session_pool=self.session_pool)
self.sidebar.pack(side="left", fill="y")
self.sidebar.add_callback = self._add_server
self.sidebar.edit_callback = self._edit_server
@@ -91,10 +93,10 @@ class App(ctk.CTk):
for key in self._tab_keys:
self.tabview.add(t(key))
self.terminal_tab = TerminalTab(self.tabview.tab(t("terminal")), self.store)
self.terminal_tab = TerminalTab(self.tabview.tab(t("terminal")), self.store, self.session_pool)
self.terminal_tab.pack(fill="both", expand=True)
self.files_tab = FilesTab(self.tabview.tab(t("files")), self.store)
self.files_tab = FilesTab(self.tabview.tab(t("files")), self.store, self.session_pool)
self.files_tab.pack(fill="both", expand=True)
self.info_tab = InfoTab(self.tabview.tab(t("info")), self.store, edit_callback=self._edit_server)
@@ -115,6 +117,8 @@ class App(ctk.CTk):
self.info_tab.set_server(alias)
self.keys_tab.set_server(alias)
self.totp_tab.set_server(alias)
# Update session indicators after a short delay (connection is async)
self.after(1500, self.sidebar.update_session_indicators)
def _add_server(self):
dialog = ServerDialog(self, self.store)
@@ -129,11 +133,14 @@ class App(ctk.CTk):
def _delete_server(self, alias: str):
if messagebox.askyesno(t("delete_server"), t("delete_confirm").format(alias=alias)):
# Clean up sessions when deleting server
self.session_pool.cleanup_deleted_server(alias)
self.store.remove_server(alias)
self._on_server_select(None)
def _on_status_update(self):
self.sidebar.update_statuses()
self.sidebar.update_session_indicators()
self.info_tab.refresh()
def _show_about(self):
@@ -176,9 +183,8 @@ class App(ctk.CTk):
saved_local_path = self.files_tab._local_path
had_sftp = self.files_tab._sftp is not None and self.files_tab._sftp.connected
# Disconnect terminal and SFTP before destroying tabs
self.terminal_tab._disconnect()
self.files_tab._disconnect_sftp()
# Disconnect all sessions in the pool
self.session_pool.disconnect_all()
# Detach tab contents
self.terminal_tab.pack_forget()
@@ -200,10 +206,10 @@ class App(ctk.CTk):
self.tabview.add(t(key))
# Re-parent tab contents
self.terminal_tab = TerminalTab(self.tabview.tab(t("terminal")), self.store)
self.terminal_tab = TerminalTab(self.tabview.tab(t("terminal")), self.store, self.session_pool)
self.terminal_tab.pack(fill="both", expand=True)
self.files_tab = FilesTab(self.tabview.tab(t("files")), self.store)
self.files_tab = FilesTab(self.tabview.tab(t("files")), self.store, self.session_pool)
self.files_tab.pack(fill="both", expand=True)
self.info_tab = InfoTab(self.tabview.tab(t("info")), self.store, edit_callback=self._edit_server)
@@ -245,7 +251,7 @@ class App(ctk.CTk):
self.sidebar.update_language()
def _on_close(self):
self.terminal_tab._disconnect()
self.files_tab._disconnect_sftp()
# Disconnect all sessions before closing
self.session_pool.disconnect_all()
self.checker.stop()
self.destroy()