""" Cross-platform data storage for scientific-surfing. Handles configuration and subscription data storage using YAML format. """ import os import platform import yaml from pathlib import Path from typing import Optional, Dict from scientific_surfing.models import SubscriptionsData class StorageManager: """Manages cross-platform data storage for subscriptions and configuration.""" def __init__(self): self.config_dir = self._get_config_dir() self.config_file = self.config_dir / "config.yaml" self.subscriptions_file = self.config_dir / "subscriptions.yaml" self._ensure_config_dir() def _get_config_dir(self) -> Path: """Get the appropriate configuration directory for the current platform.""" system = platform.system().lower() if system == "windows": # Windows: %APPDATA%/scientific_surfing app_data = os.environ.get("APPDATA") if app_data: return Path(app_data) / "scientific_surfing" else: return Path.home() / "AppData" / "Roaming" / "scientific_surfing" elif system == "darwin": # macOS: ~/Library/Application Support/scientific_surfing return Path.home() / "Library" / "Application Support" / "scientific_surfing" else: # Linux and other Unix-like systems: ~/.config/scientific_surfing xdg_config_home = os.environ.get("XDG_CONFIG_HOME") if xdg_config_home: return Path(xdg_config_home) / "scientific_surfing" else: return Path.home() / ".config" / "scientific_surfing" def _ensure_config_dir(self) -> None: """Ensure the configuration directory exists.""" self.config_dir.mkdir(parents=True, exist_ok=True) def load_subscriptions(self) -> SubscriptionsData: """Load subscriptions from YAML file.""" if not self.subscriptions_file.exists(): return SubscriptionsData() try: with open(self.subscriptions_file, 'r', encoding='utf-8') as f: data = yaml.safe_load(f) if isinstance(data, dict): return SubscriptionsData(**data) return SubscriptionsData() except (yaml.YAMLError, IOError) as e: print(f"Warning: Failed to load subscriptions: {e}") return SubscriptionsData() def save_subscriptions(self, subscriptions: SubscriptionsData) -> bool: """Save subscriptions to YAML file.""" try: with open(self.subscriptions_file, 'w', encoding='utf-8') as f: # Convert Pydantic model to dict for YAML serialization data = subscriptions.dict() yaml.dump(data, f, default_flow_style=False, allow_unicode=True) return True except (yaml.YAMLError, IOError, ValueError) as e: print(f"Error: Failed to save subscriptions: {e}") return False def load_config(self) -> dict: """Load configuration from YAML file.""" if not self.config_file.exists(): return {} try: with open(self.config_file, 'r', encoding='utf-8') as f: data = yaml.safe_load(f) if isinstance(data, dict): return data return {} except (yaml.YAMLError, IOError) as e: print(f"Warning: Failed to load config: {e}") return {} def save_config(self, config: dict) -> bool: """Save configuration to YAML file.""" try: with open(self.config_file, 'w', encoding='utf-8') as f: # Convert Pydantic model to dict for YAML serialization data = config yaml.dump(data, f, default_flow_style=False, allow_unicode=True) return True except (yaml.YAMLError, IOError, ValueError) as e: print(f"Error: Failed to save config: {e}") return False def get_storage_info(self) -> Dict[str, str]: """Get information about the storage location.""" return { 'config_dir': str(self.config_dir), 'config_file': str(self.config_file), 'subscriptions_file': str(self.subscriptions_file), 'platform': platform.system(), 'exists': str(self.config_dir.exists()) }