feat: add self-contained link composer
Build and Push Docker Container / build-and-push (push) Successful in 1m36s
Build and Push Docker Container / build-and-push (push) Successful in 1m36s
- Add structured URL codec with compact alphabets and dictionary support. - Add public decode, redirect, and QR endpoints for composed links. - Add authenticated encode API and link composer UI. - Generate PNG QR codes via qrcode with Pillow support. - Register the new blueprint and navigation entry. - Cover public decode, auth gating, redirect URL parsing, and QR output. - Bump NanoShare to 1.27.0 and lock new dependencies.
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
class BitWriter:
|
||||
def __init__(self) -> None:
|
||||
self._bits: list[int] = []
|
||||
|
||||
@property
|
||||
def bit_length(self) -> int:
|
||||
return len(self._bits)
|
||||
|
||||
def write(self, value: int, width: int) -> None:
|
||||
if width < 0:
|
||||
raise ValueError("width must be positive")
|
||||
if value < 0 or value >= (1 << width):
|
||||
raise ValueError(f"value {value} does not fit in {width} bits")
|
||||
for shift in range(width - 1, -1, -1):
|
||||
self._bits.append((value >> shift) & 1)
|
||||
|
||||
def to_bytes(self) -> bytes:
|
||||
padding = (-len(self._bits)) % 8
|
||||
bits = self._bits + [0] * padding
|
||||
out = bytearray()
|
||||
for i in range(0, len(bits), 8):
|
||||
byte = 0
|
||||
for bit in bits[i : i + 8]:
|
||||
byte = (byte << 1) | bit
|
||||
out.append(byte)
|
||||
return bytes(out)
|
||||
|
||||
class BitReader:
|
||||
def __init__(self, data: bytes, bit_length: int) -> None:
|
||||
self._bits: list[int] = []
|
||||
for byte in data:
|
||||
for shift in range(7, -1, -1):
|
||||
self._bits.append((byte >> shift) & 1)
|
||||
self._bits = self._bits[:bit_length]
|
||||
self._pos = 0
|
||||
|
||||
def read(self, width: int) -> int:
|
||||
if self._pos + width > len(self._bits):
|
||||
raise ValueError("payload ended unexpectedly")
|
||||
value = 0
|
||||
for bit in self._bits[self._pos : self._pos + width]:
|
||||
value = (value << 1) | bit
|
||||
self._pos += width
|
||||
return value
|
||||
|
||||
@property
|
||||
def remaining(self) -> int:
|
||||
return len(self._bits) - self._pos
|
||||
Reference in New Issue
Block a user