from __future__ import annotations
import json
from typing import Any, Optional
from .exceptions import ProtocolError, ServerError
def encode_request(op: str, **fields: Any) -> bytes:
payload: dict[str, Any] = {"op": op}
payload.update(fields)
return (json.dumps(payload, separators=(",", ":")) + "\n").encode()
def decode_response(line: str) -> dict[str, Any]:
line = line.strip()
if not line:
raise ProtocolError("received empty response from daemon")
try:
data: dict[str, Any] = json.loads(line)
except json.JSONDecodeError as exc:
raise ProtocolError(f"invalid JSON from daemon: {exc}") from exc
if not isinstance(data, dict):
raise ProtocolError(f"expected JSON object, got {type(data).__name__}")
ok = data.get("ok")
if ok is None:
raise ProtocolError("response missing 'ok' field")
if ok is False:
error_msg = data.get("error", "unknown error")
raise ServerError(str(error_msg))
return data
def build_get_request(key: str, path: Optional[str] = None) -> bytes:
kwargs: dict[str, Any] = {"key": key}
if path is not None:
kwargs["path"] = path
return encode_request("get", **kwargs)
def build_poke_request(key: str, path: Optional[str] = None) -> bytes:
kwargs: dict[str, Any] = {"key": key}
if path is not None:
kwargs["path"] = path
return encode_request("poke", **kwargs)
def build_context_request(path: str) -> bytes:
return encode_request("context", path=path)
def build_list_request() -> bytes:
return encode_request("list")
def build_status_request() -> bytes:
return encode_request("status")