| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219 |
- # -*- coding: utf-8 -*-
- """
- LZ4-Kompressor.
- Implementiert schnelle Komprimierung mit dem LZ4-Algorithmus.
- Erfordert das optionale lz4-Paket.
- """
- from __future__ import annotations
- import time
- from typing import Any
- try:
- import lz4.frame
- import lz4.block
- LZ4_AVAILABLE = True
- except ImportError:
- LZ4_AVAILABLE = False
- from trixy_core.network.compression.compressor import (
- Compressor,
- CompressionLevel,
- CompressionError,
- DecompressionError,
- )
- if not LZ4_AVAILABLE:
- raise ImportError(
- "LZ4-Kompressor erfordert das lz4-Paket. "
- "Installieren mit: pip install lz4"
- )
- class LZ4Compressor(Compressor):
- """
- Kompressor basierend auf LZ4.
- LZ4 bietet extrem schnelle Komprimierung bei moderater
- Komprimierungsrate. Ideal für Echtzeit-Anwendungen.
- Beispiel:
- compressor = LZ4Compressor(level=CompressionLevel.FAST)
- compressed = compressor.compress(data)
- original = compressor.decompress(compressed)
- """
- # Mapping von CompressionLevel zu LZ4-Levels
- _LEVEL_MAP = {
- CompressionLevel.NONE: 0,
- CompressionLevel.FASTEST: 0,
- CompressionLevel.FAST: 3,
- CompressionLevel.DEFAULT: 6,
- CompressionLevel.BEST: 12,
- }
- def __init__(
- self,
- level: CompressionLevel = CompressionLevel.DEFAULT,
- use_frame: bool = True,
- ) -> None:
- """
- Initialisiert den LZ4-Kompressor.
- Args:
- level: Komprimierungsstufe
- use_frame: Frame-Format verwenden (empfohlen)
- False für Block-Format (schneller, aber ohne Streaming)
- """
- super().__init__(level)
- self._use_frame = use_frame
- self._lz4_level = self._LEVEL_MAP.get(level, 6)
- @property
- def name(self) -> str:
- return "lz4"
- @property
- def content_type(self) -> str:
- return "application/x-lz4"
- @property
- def min_size(self) -> int:
- """LZ4 hat minimalen Overhead."""
- return 16
- def compress(self, data: bytes) -> bytes:
- """
- Komprimiert Daten mit LZ4.
- Args:
- data: Unkomprimierte Daten
- Returns:
- Komprimierte Daten
- """
- if not data:
- return b""
- start = time.monotonic()
- try:
- if self._use_frame:
- compressed = lz4.frame.compress(
- data,
- compression_level=self._lz4_level,
- )
- else:
- compressed = lz4.block.compress(
- data,
- compression=self._lz4_level,
- store_size=True,
- )
- except Exception as e:
- self.stats.errors += 1
- raise CompressionError(f"LZ4-Komprimierung fehlgeschlagen: {e}") from e
- elapsed_ms = (time.monotonic() - start) * 1000
- self.stats.update_compression(len(data), len(compressed), elapsed_ms)
- return compressed
- def decompress(self, data: bytes) -> bytes:
- """
- Dekomprimiert LZ4-Daten.
- Args:
- data: Komprimierte Daten
- Returns:
- Ursprüngliche Daten
- """
- if not data:
- return b""
- start = time.monotonic()
- try:
- if self._use_frame:
- decompressed = lz4.frame.decompress(data)
- else:
- decompressed = lz4.block.decompress(data)
- except Exception as e:
- self.stats.errors += 1
- raise DecompressionError(
- f"LZ4-Dekomprimierung fehlgeschlagen: {e}"
- ) from e
- elapsed_ms = (time.monotonic() - start) * 1000
- self.stats.update_decompression(len(data), len(decompressed), elapsed_ms)
- return decompressed
- class LZ4HCCompressor(Compressor):
- """
- LZ4 High Compression Kompressor.
- Verwendet LZ4 HC-Modus für bessere Komprimierungsrate
- bei langsamerer Geschwindigkeit.
- """
- def __init__(
- self,
- level: CompressionLevel = CompressionLevel.BEST,
- ) -> None:
- super().__init__(level)
- # HC-Mode verwendet Levels 1-12
- self._hc_level = min(12, max(1, int(level) + 3))
- @property
- def name(self) -> str:
- return "lz4hc"
- @property
- def content_type(self) -> str:
- return "application/x-lz4hc"
- def compress(self, data: bytes) -> bytes:
- """Komprimiert mit LZ4 HC."""
- if not data:
- return b""
- start = time.monotonic()
- try:
- compressed = lz4.frame.compress(
- data,
- compression_level=lz4.frame.COMPRESSIONLEVEL_MAX,
- )
- except Exception as e:
- self.stats.errors += 1
- raise CompressionError(f"LZ4-HC-Komprimierung fehlgeschlagen: {e}") from e
- elapsed_ms = (time.monotonic() - start) * 1000
- self.stats.update_compression(len(data), len(compressed), elapsed_ms)
- return compressed
- def decompress(self, data: bytes) -> bytes:
- """Dekomprimiert LZ4-HC-Daten (identisch zu LZ4)."""
- if not data:
- return b""
- start = time.monotonic()
- try:
- decompressed = lz4.frame.decompress(data)
- except Exception as e:
- self.stats.errors += 1
- raise DecompressionError(
- f"LZ4-HC-Dekomprimierung fehlgeschlagen: {e}"
- ) from e
- elapsed_ms = (time.monotonic() - start) * 1000
- self.stats.update_decompression(len(data), len(decompressed), elapsed_ms)
- return decompressed
|