Files
connpy/connpy/services/config_service.py
T
fluzzi32 12543c683e 1. Persistence Setup: Optimized the dockerfile to manually create the /root/.config/conn/.folder file
pointing to /config. This avoids running the conn command during the build process and ensures a
      cleaner setup.
   2. Copilot UI Fix: Resolved a double-escaping bug in the terminal bottom bar. Device prompts (like
      6WIND-PE1>) will now render correctly instead of showing HTML entities like >.
   3. AI Model Update: Updated the default engineer model in connpy/ai.py to
      gemini/gemini-3.1-flash-lite, removing the deprecated -preview suffix.
   4. Standardized Timeouts: Unified all default timeouts to 20 seconds across the board. This includes
      direct execution (run/test), modern playbooks (v2), and classic task-based playbooks (v1).
   5. Documentation Update: Regenerated the full documentation site in the docs/ directory using pdoc to
      reflect the latest changes.
   6. Cleanup: Removed all debug prints from connpy/core.py and restored the docker/logs/.gitignore
      file.
2026-05-13 14:16:14 -03:00

87 lines
3.3 KiB
Python

import os
import shutil
import base64
from typing import Any, Dict
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP
from .base import BaseService
from .exceptions import ConnpyError, InvalidConfigurationError, NodeNotFoundError
class ConfigService(BaseService):
"""Business logic for general application settings and state configuration."""
def get_settings(self) -> Dict[str, Any]:
"""Get the global configuration settings block."""
settings = self.config.config.copy()
settings["configfolder"] = self.config.defaultdir
return settings
def get_default_dir(self) -> str:
"""Get the default configuration directory."""
return self.config.defaultdir
def set_config_folder(self, folder_path: str):
"""Set the default location for config file by writing to ~/.config/conn/.folder"""
if not os.path.isdir(folder_path):
raise ConnpyError(f"readable_dir:{folder_path} is not a valid path")
pathfile = os.path.join(self.config.anchor_path, ".folder")
folder = os.path.abspath(folder_path).rstrip('/')
try:
with open(pathfile, "w") as f:
f.write(str(folder))
except Exception as e:
raise ConnpyError(f"Failed to save config folder: {e}")
def update_setting(self, key, value):
"""Update a setting in the configuration file."""
self.config.config[key] = value
self.config._saveconfig(self.config.file)
def encrypt_password(self, password):
"""Encrypt a password using the application's configuration encryption key."""
return self.config.encrypt(password)
def apply_theme_from_file(self, theme_input):
"""Apply 'dark', 'light' theme or load a YAML theme file and save it to the configuration."""
import yaml
from ..printer import STYLES, LIGHT_THEME
if theme_input == "dark":
valid_styles = {}
self.update_setting("theme", valid_styles)
return valid_styles
elif theme_input == "light":
valid_styles = LIGHT_THEME.copy()
self.update_setting("theme", valid_styles)
return valid_styles
if not os.path.exists(theme_input):
raise InvalidConfigurationError(f"Theme file '{theme_input}' not found.")
try:
with open(theme_input, 'r') as f:
user_styles = yaml.safe_load(f)
except Exception as e:
raise InvalidConfigurationError(f"Failed to parse theme file: {e}")
if not isinstance(user_styles, dict):
raise InvalidConfigurationError("Theme file must be a YAML dictionary.")
# Support both direct styles and nested under 'theme' key
if "theme" in user_styles and isinstance(user_styles["theme"], dict):
user_styles = user_styles["theme"]
# Filter for valid styles only (prevent junk in config)
valid_styles = {k: v for k, v in user_styles.items() if k in STYLES}
if not valid_styles:
raise InvalidConfigurationError("No valid style keys found in theme file.")
# Persist and return merged styles
self.update_setting("theme", valid_styles)
return valid_styles