Files
scientific-surfing/scientific_surfing/storage.py

114 lines
4.3 KiB
Python

"""
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())
}