from __future__ import annotations
from typing import Any, Iterable
from .metadata import UDB_PROTOCOL_VERSION
ENCODING_RECORD_SET_V1 = "record_set_v1"
ENCODING_RECORD_BATCH_V2 = "record_batch_v2"
CLIENT_SUPPORTED_ENCODINGS: tuple[str, ...] = (ENCODING_RECORD_SET_V1,)
def _extract_protocol_support(source: Any) -> Any:
if source is None:
return None
if _get(source, "encodings", None) is not None or _get(
source, "min_protocol_version", None
) not in (None, ""):
nested = _get(source, "protocol_support", None)
return nested if nested is not None else source
return _get(source, "protocol_support", None)
def _get(obj: Any, name: str, default: Any) -> Any:
if obj is None:
return default
if isinstance(obj, dict):
return obj.get(name, default)
return getattr(obj, name, default)
class Negotiator:
def __init__(self, source: Any = None) -> None:
self._support = _extract_protocol_support(source)
def _encodings(self) -> list[str]:
raw = _get(self._support, "encodings", None)
if not raw:
return []
return [str(item) for item in raw]
def supports_encoding(self, name: str) -> bool:
encodings = self._encodings()
if not encodings:
return name == ENCODING_RECORD_SET_V1
return name in encodings
def negotiated_encoding(self) -> str:
if (
ENCODING_RECORD_BATCH_V2 in CLIENT_SUPPORTED_ENCODINGS
and self.supports_encoding(ENCODING_RECORD_BATCH_V2)
):
return ENCODING_RECORD_BATCH_V2
return ENCODING_RECORD_SET_V1
def protocol_range(self) -> tuple[str, str]:
minimum = _get(self._support, "min_protocol_version", "") or UDB_PROTOCOL_VERSION
maximum = _get(self._support, "max_protocol_version", "") or UDB_PROTOCOL_VERSION
return (str(minimum), str(maximum))
def server_supports_streaming_reads(self) -> bool:
return bool(_get(self._support, "supports_streaming_reads", False))
def client_supported_encodings() -> Iterable[str]:
return CLIENT_SUPPORTED_ENCODINGS