registry.py 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. # -*- coding: utf-8 -*-
  2. """
  3. Kompressor-Registry.
  4. Zentrale Verwaltung von Komprimierungsalgorithmen.
  5. """
  6. from __future__ import annotations
  7. from typing import Type
  8. from trixy_core.network.compression.compressor import (
  9. Compressor,
  10. CompressionLevel,
  11. )
  12. from trixy_core.network.compression.zlib import ZlibCompressor, GzipCompressor
  13. class CompressionRegistry:
  14. """
  15. Registry für Komprimierungsalgorithmen.
  16. Verwaltet verfügbare Kompressoren und ermöglicht
  17. die Auswahl basierend auf Namen oder Content-Type.
  18. Beispiel:
  19. registry = get_default_registry()
  20. # Nach Namen
  21. compressor = registry.get("zlib")
  22. # Nach Content-Type
  23. compressor = registry.get_by_content_type("application/gzip")
  24. """
  25. def __init__(self) -> None:
  26. """Initialisiert die Registry."""
  27. self._compressors: dict[str, Type[Compressor]] = {}
  28. self._content_types: dict[str, str] = {}
  29. def register(
  30. self,
  31. name: str,
  32. compressor_class: Type[Compressor],
  33. content_type: str | None = None,
  34. ) -> None:
  35. """
  36. Registriert einen Kompressor.
  37. Args:
  38. name: Name des Kompressors
  39. compressor_class: Kompressor-Klasse
  40. content_type: Optional: Content-Type Mapping
  41. """
  42. self._compressors[name.lower()] = compressor_class
  43. if content_type:
  44. self._content_types[content_type.lower()] = name.lower()
  45. def unregister(self, name: str) -> bool:
  46. """
  47. Entfernt einen Kompressor.
  48. Args:
  49. name: Name des Kompressors
  50. Returns:
  51. True wenn entfernt
  52. """
  53. name = name.lower()
  54. if name in self._compressors:
  55. del self._compressors[name]
  56. # Content-Type Mapping entfernen
  57. to_remove = [
  58. ct for ct, n in self._content_types.items()
  59. if n == name
  60. ]
  61. for ct in to_remove:
  62. del self._content_types[ct]
  63. return True
  64. return False
  65. def get(
  66. self,
  67. name: str,
  68. level: CompressionLevel = CompressionLevel.DEFAULT,
  69. ) -> Compressor | None:
  70. """
  71. Holt Kompressor nach Namen.
  72. Args:
  73. name: Name des Kompressors
  74. level: Komprimierungsstufe
  75. Returns:
  76. Kompressor-Instanz oder None
  77. """
  78. compressor_class = self._compressors.get(name.lower())
  79. if compressor_class:
  80. return compressor_class(level=level)
  81. return None
  82. def get_by_content_type(
  83. self,
  84. content_type: str,
  85. level: CompressionLevel = CompressionLevel.DEFAULT,
  86. ) -> Compressor | None:
  87. """
  88. Holt Kompressor nach Content-Type.
  89. Args:
  90. content_type: Content-Type (z.B. "application/gzip")
  91. level: Komprimierungsstufe
  92. Returns:
  93. Kompressor-Instanz oder None
  94. """
  95. name = self._content_types.get(content_type.lower())
  96. if name:
  97. return self.get(name, level)
  98. return None
  99. def list_available(self) -> list[str]:
  100. """Listet alle verfügbaren Kompressoren."""
  101. return list(self._compressors.keys())
  102. def is_available(self, name: str) -> bool:
  103. """Prüft ob Kompressor verfügbar ist."""
  104. return name.lower() in self._compressors
  105. def __contains__(self, name: str) -> bool:
  106. return self.is_available(name)
  107. def __len__(self) -> int:
  108. return len(self._compressors)
  109. # Globale Default-Registry
  110. _default_registry: CompressionRegistry | None = None
  111. def get_default_registry() -> CompressionRegistry:
  112. """
  113. Holt die globale Standard-Registry.
  114. Enthält vorregistrierte Standard-Kompressoren.
  115. Returns:
  116. CompressionRegistry-Instanz
  117. """
  118. global _default_registry
  119. if _default_registry is None:
  120. _default_registry = CompressionRegistry()
  121. # Zlib registrieren (immer verfügbar)
  122. _default_registry.register(
  123. "zlib",
  124. ZlibCompressor,
  125. "application/zlib"
  126. )
  127. # Gzip registrieren
  128. _default_registry.register(
  129. "gzip",
  130. GzipCompressor,
  131. "application/gzip"
  132. )
  133. # Content-Type Aliase
  134. _default_registry._content_types["application/x-gzip"] = "gzip"
  135. _default_registry._content_types["application/deflate"] = "zlib"
  136. # LZ4 wenn verfügbar
  137. try:
  138. from trixy_core.network.compression.lz4 import (
  139. LZ4Compressor,
  140. LZ4HCCompressor,
  141. )
  142. _default_registry.register(
  143. "lz4",
  144. LZ4Compressor,
  145. "application/x-lz4"
  146. )
  147. _default_registry.register(
  148. "lz4hc",
  149. LZ4HCCompressor,
  150. "application/x-lz4hc"
  151. )
  152. except ImportError:
  153. pass
  154. return _default_registry
  155. def get_compressor(
  156. name: str,
  157. level: CompressionLevel = CompressionLevel.DEFAULT,
  158. ) -> Compressor | None:
  159. """
  160. Convenience-Funktion zum Holen eines Kompressors.
  161. Args:
  162. name: Name des Kompressors
  163. level: Komprimierungsstufe
  164. Returns:
  165. Kompressor-Instanz oder None
  166. """
  167. return get_default_registry().get(name, level)