feat: multi-type server support — SQL, Redis, Grafana, Prometheus, Telnet, WinRM, RDP/VNC
Full implementation of multi-type server management across GUI and CLI: New clients: SQLClient (MariaDB/MSSQL/PostgreSQL), RedisClient, GrafanaClient, PrometheusClient, TelnetSession, WinRMClient, RemoteDesktopLauncher. New GUI tabs: QueryTab (SQL editor + Treeview), RedisTab (console + history), GrafanaTab (dashboards + alerts), PrometheusTab (PromQL + targets), PowershellTab (PS/CMD), LaunchTab (RDP/VNC external client). Infrastructure: TAB_REGISTRY for conditional tabs per server type, adaptive server_dialog fields, colored type badges in sidebar, status checker for all types (SSH/TCP/SQL/Redis/HTTP), 100+ i18n keys. CLI: ssh.py extended with --sql, --redis, --grafana-*, --prom-*, --ps, --cmd. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
124
core/remote_desktop.py
Normal file
124
core/remote_desktop.py
Normal file
@@ -0,0 +1,124 @@
|
||||
"""
|
||||
Remote desktop launchers — RDP and VNC via external clients.
|
||||
"""
|
||||
|
||||
import os
|
||||
import platform
|
||||
import subprocess
|
||||
import tempfile
|
||||
from core.logger import log
|
||||
|
||||
|
||||
class RemoteDesktopLauncher:
|
||||
"""Launch external RDP/VNC clients for remote desktop connections."""
|
||||
|
||||
@staticmethod
|
||||
def launch_rdp(server: dict) -> str:
|
||||
"""Generate a .rdp temp file and launch the system RDP client.
|
||||
|
||||
Returns:
|
||||
Status message string.
|
||||
"""
|
||||
hostname = server["ip"]
|
||||
port = server.get("port", 3389)
|
||||
user = server.get("user", "Administrator")
|
||||
|
||||
rdp_content = (
|
||||
f"full address:s:{hostname}:{port}\r\n"
|
||||
f"username:s:{user}\r\n"
|
||||
"prompt for credentials:i:1\r\n"
|
||||
"screen mode id:i:2\r\n"
|
||||
"desktopwidth:i:1920\r\n"
|
||||
"desktopheight:i:1080\r\n"
|
||||
"session bpp:i:32\r\n"
|
||||
"compression:i:1\r\n"
|
||||
"disable wallpaper:i:0\r\n"
|
||||
"allow font smoothing:i:1\r\n"
|
||||
"networkautodetect:i:1\r\n"
|
||||
"bandwidthautodetect:i:1\r\n"
|
||||
)
|
||||
|
||||
alias = server.get("alias", "remote")
|
||||
rdp_file = os.path.join(tempfile.gettempdir(), f"sm_{alias}.rdp")
|
||||
|
||||
with open(rdp_file, "w", encoding="utf-8") as f:
|
||||
f.write(rdp_content)
|
||||
|
||||
log.info(f"RDP file created: {rdp_file}")
|
||||
|
||||
system = platform.system()
|
||||
if system == "Windows":
|
||||
os.startfile(rdp_file)
|
||||
return f"RDP launched via mstsc for {alias}"
|
||||
elif system == "Linux":
|
||||
try:
|
||||
subprocess.Popen(
|
||||
["xfreerdp", f"/v:{hostname}:{port}", f"/u:{user}", "/dynamic-resolution"],
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL,
|
||||
)
|
||||
return f"RDP launched via xfreerdp for {alias}"
|
||||
except FileNotFoundError:
|
||||
log.warning("xfreerdp not found, trying rdesktop")
|
||||
subprocess.Popen(
|
||||
["rdesktop", f"{hostname}:{port}", "-u", user],
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL,
|
||||
)
|
||||
return f"RDP launched via rdesktop for {alias}"
|
||||
elif system == "Darwin":
|
||||
subprocess.Popen(["open", rdp_file])
|
||||
return f"RDP launched via macOS for {alias}"
|
||||
else:
|
||||
return f"Unsupported platform: {system}. RDP file saved to {rdp_file}"
|
||||
|
||||
@staticmethod
|
||||
def launch_vnc(server: dict) -> str:
|
||||
"""Launch a VNC viewer for the given server.
|
||||
|
||||
Returns:
|
||||
Status message string.
|
||||
"""
|
||||
hostname = server["ip"]
|
||||
port = server.get("port", 5900)
|
||||
alias = server.get("alias", "remote")
|
||||
target = f"{hostname}:{port}"
|
||||
|
||||
log.info(f"VNC launching for {alias} at {target}")
|
||||
|
||||
system = platform.system()
|
||||
if system == "Windows":
|
||||
# Try common VNC viewer paths
|
||||
viewers = [
|
||||
r"C:\Program Files\TightVNC\tvnviewer.exe",
|
||||
r"C:\Program Files (x86)\TightVNC\tvnviewer.exe",
|
||||
r"C:\Program Files\RealVNC\VNC Viewer\vncviewer.exe",
|
||||
r"C:\Program Files (x86)\RealVNC\VNC Viewer\vncviewer.exe",
|
||||
]
|
||||
for viewer in viewers:
|
||||
if os.path.exists(viewer):
|
||||
subprocess.Popen([viewer, target])
|
||||
return f"VNC launched via {os.path.basename(viewer)} for {alias}"
|
||||
# Fallback: try vncviewer in PATH
|
||||
try:
|
||||
subprocess.Popen(["vncviewer", target])
|
||||
return f"VNC launched via vncviewer for {alias}"
|
||||
except FileNotFoundError:
|
||||
return "No VNC viewer found. Install TightVNC or RealVNC Viewer."
|
||||
|
||||
elif system == "Linux":
|
||||
for cmd in ["vncviewer", "xtigervncviewer", "remmina"]:
|
||||
try:
|
||||
args = [cmd, target] if cmd != "remmina" else [cmd, f"vnc://{target}"]
|
||||
subprocess.Popen(args, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
||||
return f"VNC launched via {cmd} for {alias}"
|
||||
except FileNotFoundError:
|
||||
continue
|
||||
return "No VNC viewer found. Install tigervnc-viewer or remmina."
|
||||
|
||||
elif system == "Darwin":
|
||||
subprocess.Popen(["open", f"vnc://{target}"])
|
||||
return f"VNC launched via macOS Screen Sharing for {alias}"
|
||||
|
||||
else:
|
||||
return f"Unsupported platform: {system}"
|
||||
Reference in New Issue
Block a user