feat: add optional libtw2 huffman backend

Prefer libtw2 over TeeAI huffman but do not install it by default.
Thanks to @heinrich5991 for porting his rust code to python.
This commit is contained in:
ChillerDragon 2023-06-18 12:51:07 +02:00
parent ec507c0dcc
commit d9c5f0d066
5 changed files with 52 additions and 3 deletions

View file

@ -125,6 +125,29 @@ packet.messages.append(msg)
packet.pack() # => b'\x02~\x06H\x1f\x93\xd7\x00\x00\x80\x01option\x00test\x00\x00\x00'
```
## Zero dependencies by default
Running ``pip install twnet_parser`` will not install any additional packages.
But there is an optional dependency for huffman compression.
By default twnet_parser is using the huffman compression code from the [TeeAI](https://github.com/edg-l/TeeAI)
project which is written in pure python.
If you have [libtw2-huffman](https://pypi.org/project/libtw2-huffman/) installed it will use that one instead.
Because it is faster since it is written in rust and has better error handling.
But since it is so much overhead it is not installed by default to keep twnet_parser light weight.
You can install it by running ``pip install libtw2-huffman``
or by running ``pip install -r requirements/optional.txt``
You can also check which huffman backend is currently active with these lines of code
```python
import twnet_parser.huffman
print(twnet_parser.huffman.backend_name()) # => rust-libtw2 or python-TeeAI
```
## development setup
```bash

View file

@ -1,4 +1,5 @@
-r prod.txt
-r optional.txt
astroid==2.15.0
attrs==22.2.0
bleach==6.0.0

View file

@ -0,0 +1 @@
libtw2-huffman==0.2.0

24
twnet_parser/huffman.py Normal file
View file

@ -0,0 +1,24 @@
from twnet_parser.external.huffman import huffman
HAS_LIBTW2 = False
try:
import libtw2_huffman # type: ignore
HAS_LIBTW2 = True
except ImportError:
HAS_LIBTW2 = False
def backend_name() -> str:
if HAS_LIBTW2:
return 'rust-libtw2'
return 'python-TeeAI'
def compress(data: bytes) -> bytes:
if HAS_LIBTW2:
return libtw2_huffman.compress(data)
return huffman.decompress(bytearray(data))
def decompress(data: bytes) -> bytes:
if HAS_LIBTW2:
return libtw2_huffman.decompress(data)
return huffman.decompress(bytearray(data))

View file

@ -15,7 +15,7 @@ from twnet_parser.msg_matcher.control6 import match_control6
from twnet_parser.msg_matcher.connless6 import match_connless6
from twnet_parser.constants import NET_MAX_SEQUENCE, NET_PACKETVERSION
from twnet_parser.external.huffman import huffman
import twnet_parser.huffman
# TODO: what is a nice pythonic way of storing those?
# also does some version:: namespace thing make sense?
@ -419,7 +419,7 @@ class PacketParser():
return pck
if pck.header.flags.compression:
payload = bytearray(pck.payload_raw)
pck.payload_decompressed = huffman.decompress(payload)
pck.payload_decompressed = twnet_parser.huffman.decompress(payload)
pck.messages = cast(
list[Union[CtrlMessage, NetMessage, ConnlessMessage]],
self.get_messages(pck.payload_decompressed))
@ -448,7 +448,7 @@ class PacketParser():
return pck
if pck.header.flags.compression:
payload = bytearray(pck.payload_raw)
pck.payload_decompressed = huffman.decompress(payload)
pck.payload_decompressed = twnet_parser.huffman.decompress(payload)
pck.messages = cast(
list[Union[CtrlMessage, NetMessage, ConnlessMessage]],
self.get_messages(pck.payload_decompressed))