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>
125 lines
4.5 KiB
Python
125 lines
4.5 KiB
Python
"""
|
|
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}"
|