This commit is contained in:
Constantin
2025-09-12 23:04:52 +03:00
commit 2277b11563
127 changed files with 23640 additions and 0 deletions
+160
View File
@@ -0,0 +1,160 @@
#!/usr/bin/env python3
"""
Base Service Manager for Personal Internet Cell
Provides standardized interface for all service managers
"""
import logging
import json
from abc import ABC, abstractmethod
from typing import Dict, List, Optional, Any
from datetime import datetime
import traceback
logger = logging.getLogger(__name__)
class BaseServiceManager(ABC):
"""Base class for all service managers with standardized interface"""
def __init__(self, service_name: str, data_dir: str = '/app/data', config_dir: str = '/app/config'):
self.service_name = service_name
self.data_dir = data_dir
self.config_dir = config_dir
self.logger = logging.getLogger(f'picell.{service_name}')
# Ensure directories exist
self._ensure_directories()
def _ensure_directories(self):
"""Ensure required directories exist"""
import os
os.makedirs(self.data_dir, exist_ok=True)
os.makedirs(self.config_dir, exist_ok=True)
@abstractmethod
def get_status(self) -> Dict[str, Any]:
"""Get service status - must be implemented by subclasses"""
pass
@abstractmethod
def test_connectivity(self) -> Dict[str, Any]:
"""Test service connectivity - must be implemented by subclasses"""
pass
def get_logs(self, lines: int = 50) -> List[str]:
"""Get service logs - default implementation"""
try:
log_file = f"{self.data_dir}/{self.service_name}.log"
import os
if not os.path.exists(log_file):
return [f"No log file found for {self.service_name}"]
with open(log_file, 'r', encoding='utf-8', errors='ignore') as f:
all_lines = f.readlines()
return all_lines[-lines:] if lines > 0 else all_lines
except Exception as e:
self.logger.error(f"Error reading logs: {e}")
return [f"Error reading logs: {str(e)}"]
def restart_service(self) -> bool:
"""Restart service - default implementation"""
try:
self.logger.info(f"Restarting {self.service_name} service")
# Default implementation - subclasses can override
return True
except Exception as e:
self.logger.error(f"Error restarting {self.service_name}: {e}")
return False
def get_config(self) -> Dict[str, Any]:
"""Get service configuration - default implementation"""
try:
config_file = f"{self.config_dir}/{self.service_name}.json"
import os
if not os.path.exists(config_file):
return {"error": f"No configuration file found for {self.service_name}"}
with open(config_file, 'r') as f:
return json.load(f)
except Exception as e:
self.logger.error(f"Error reading config: {e}")
return {"error": str(e)}
def update_config(self, config: Dict[str, Any]) -> bool:
"""Update service configuration - default implementation"""
try:
config_file = f"{self.config_dir}/{self.service_name}.json"
import os
os.makedirs(os.path.dirname(config_file), exist_ok=True)
with open(config_file, 'w') as f:
json.dump(config, f, indent=2)
self.logger.info(f"Updated configuration for {self.service_name}")
return True
except Exception as e:
self.logger.error(f"Error updating config: {e}")
return False
def validate_config(self, config: Dict[str, Any]) -> Dict[str, Any]:
"""Validate configuration - default implementation"""
return {
"valid": True,
"errors": [],
"warnings": []
}
def get_metrics(self) -> Dict[str, Any]:
"""Get service metrics - default implementation"""
return {
"service": self.service_name,
"timestamp": datetime.utcnow().isoformat(),
"status": "unknown"
}
def handle_error(self, error: Exception, context: str = "") -> Dict[str, Any]:
"""Standardized error handling"""
error_info = {
"error": str(error),
"type": type(error).__name__,
"context": context,
"timestamp": datetime.utcnow().isoformat(),
"service": self.service_name,
"traceback": traceback.format_exc()
}
self.logger.error(f"Error in {context}: {error}")
return error_info
def log_operation(self, operation: str, details: Dict[str, Any] = None):
"""Log service operations"""
log_data = {
"operation": operation,
"service": self.service_name,
"timestamp": datetime.utcnow().isoformat(),
"details": details or {}
}
self.logger.info(f"Operation: {operation} - {json.dumps(details) if details else 'No details'}")
def health_check(self) -> Dict[str, Any]:
"""Comprehensive health check"""
try:
status = self.get_status()
connectivity = self.test_connectivity()
metrics = self.get_metrics()
return {
"service": self.service_name,
"timestamp": datetime.utcnow().isoformat(),
"status": status,
"connectivity": connectivity,
"metrics": metrics,
"healthy": self._is_healthy(status, connectivity)
}
except Exception as e:
return self.handle_error(e, "health_check")
def _is_healthy(self, status: Dict[str, Any], connectivity: Dict[str, Any]) -> bool:
"""Determine if service is healthy based on status and connectivity"""
# Default implementation - subclasses can override
return status.get("running", False) and connectivity.get("success", False)