| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243 |
- # -*- coding: utf-8 -*-
- """
- Extension-Basisklasse.
- Definiert die Schnittstelle für alle Extensions.
- """
- from abc import ABC, abstractmethod
- from dataclasses import dataclass, field
- from datetime import datetime
- from enum import Enum
- from typing import Any, TypeVar, Generic
- class ExtensionState(Enum):
- """Zustand einer Extension."""
- REGISTERED = "registered" # Registriert, aber nicht aktiv
- INITIALIZING = "initializing" # Wird initialisiert
- ACTIVE = "active" # Aktiv und nutzbar
- ERROR = "error" # Fehler bei Initialisierung
- DISABLED = "disabled" # Deaktiviert
- @dataclass
- class ExtensionInfo:
- """Metadaten einer Extension."""
- # Identifikation
- id: str # Eindeutige ID (z.B. "spotify_source")
- name: str # Anzeigename
- description: str = ""
- version: str = "1.0.0"
- # Herkunft
- plugin_name: str = "" # Plugin das diese Extension bereitstellt
- author: str = ""
- # Extension Point
- extension_point: str = "" # z.B. "music.source"
- # Priorität (höher = wird bevorzugt)
- priority: int = 0
- # Abhängigkeiten
- dependencies: list[str] = field(default_factory=list)
- # Zustand
- state: ExtensionState = ExtensionState.REGISTERED
- error_message: str = ""
- # Zeitstempel
- registered_at: datetime = field(default_factory=datetime.now)
- activated_at: datetime | None = None
- # Zusätzliche Daten
- metadata: dict[str, Any] = field(default_factory=dict)
- def to_dict(self) -> dict[str, Any]:
- """Konvertiert zu Dictionary."""
- return {
- "id": self.id,
- "name": self.name,
- "description": self.description,
- "version": self.version,
- "plugin_name": self.plugin_name,
- "extension_point": self.extension_point,
- "priority": self.priority,
- "state": self.state.value,
- "error_message": self.error_message if self.state == ExtensionState.ERROR else None,
- }
- T = TypeVar("T")
- class Extension(ABC, Generic[T]):
- """
- Abstrakte Basisklasse für Extensions.
- Extensions erweitern Core-Komponenten um neue Funktionalität.
- Sie werden von Plugins registriert und von Core-Komponenten genutzt.
- Type Parameter T: Der Typ der Instanz die diese Extension bereitstellt.
- z.B. Extension[MusicSource] für Musikquellen.
- """
- def __init__(
- self,
- extension_id: str,
- name: str,
- plugin_name: str = "",
- ) -> None:
- """
- Initialisiert die Extension.
- Args:
- extension_id: Eindeutige ID
- name: Anzeigename
- plugin_name: Name des bereitstellenden Plugins
- """
- self._info = ExtensionInfo(
- id=extension_id,
- name=name,
- plugin_name=plugin_name,
- )
- self._instance: T | None = None
- @property
- def info(self) -> ExtensionInfo:
- """Extension-Informationen."""
- return self._info
- @property
- def id(self) -> str:
- """Extension-ID."""
- return self._info.id
- @property
- def name(self) -> str:
- """Anzeigename."""
- return self._info.name
- @property
- def state(self) -> ExtensionState:
- """Aktueller Zustand."""
- return self._info.state
- @property
- def is_active(self) -> bool:
- """Prüft ob Extension aktiv ist."""
- return self._info.state == ExtensionState.ACTIVE
- @property
- def instance(self) -> T | None:
- """Die bereitgestellte Instanz (wenn aktiv)."""
- return self._instance
- # ==========================================================================
- # Lifecycle
- # ==========================================================================
- @abstractmethod
- async def create_instance(self, config: dict[str, Any]) -> T:
- """
- Erstellt die Instanz die diese Extension bereitstellt.
- Args:
- config: Konfiguration für die Instanz
- Returns:
- Die erstellte Instanz
- Raises:
- Exception: Bei Fehlern
- """
- pass
- async def initialize(self, config: dict[str, Any]) -> bool:
- """
- Initialisiert die Extension.
- Args:
- config: Konfiguration
- Returns:
- True wenn erfolgreich
- """
- self._info.state = ExtensionState.INITIALIZING
- try:
- self._instance = await self.create_instance(config)
- self._info.state = ExtensionState.ACTIVE
- self._info.activated_at = datetime.now()
- return True
- except Exception as e:
- self._info.state = ExtensionState.ERROR
- self._info.error_message = str(e)
- return False
- async def shutdown(self) -> None:
- """Fährt die Extension herunter."""
- if self._instance is not None:
- await self.destroy_instance(self._instance)
- self._instance = None
- self._info.state = ExtensionState.DISABLED
- async def destroy_instance(self, instance: T) -> None:
- """
- Zerstört die Instanz (Cleanup).
- Override für spezifische Cleanup-Logik.
- Args:
- instance: Die zu zerstörende Instanz
- """
- # Standard: Nichts tun
- pass
- # ==========================================================================
- # Validierung
- # ==========================================================================
- def validate_config(self, config: dict[str, Any]) -> list[str]:
- """
- Validiert die Konfiguration.
- Args:
- config: Zu validierende Konfiguration
- Returns:
- Liste von Fehlermeldungen (leer = valide)
- """
- return []
- def get_default_config(self) -> dict[str, Any]:
- """
- Liefert Standard-Konfiguration.
- Returns:
- Standard-Konfiguration
- """
- return {}
- def get_config_schema(self) -> dict[str, Any]:
- """
- Liefert JSON-Schema für Konfiguration.
- Returns:
- JSON-Schema
- """
- return {}
- # ==========================================================================
- # Info
- # ==========================================================================
- def __repr__(self) -> str:
- return (
- f"{self.__class__.__name__}("
- f"id={self.id!r}, "
- f"state={self.state.value!r})"
- )
|