from __future__ import annotations import json from dataclasses import asdict, dataclass from typing import Any, Callable from .device_id import is_android_device_id, is_valid_egid from .device_profile import DeviceProfile from .dfp_forms import DfpRequestSpec @dataclass(frozen=True) class BootstrapIdentity: did: str = "" cdid_tag: int = 0 egid: str = "" def to_dict(self) -> dict[str, Any]: return asdict(self) @dataclass(frozen=True) class DfpHttpResponse: status_code: int ok: bool data: Any text: str def to_dict(self) -> dict[str, Any]: return asdict(self) def _as_mapping(value: Any) -> dict[str, Any]: return value if isinstance(value, dict) else {} def _int_tag(value: Any) -> int: try: return int(value) except (TypeError, ValueError): return 0 def extract_bootstrap_identity( fetch_response: dict[str, Any] | None, report_response: dict[str, Any] | None, ) -> BootstrapIdentity: fetch = _as_mapping(fetch_response) report = _as_mapping(report_response) did = str(fetch.get("cloud_did") or fetch.get("did") or "") if not is_android_device_id(did): did = "" cdid_tag = _int_tag(fetch.get("did_tag") or fetch.get("didTag") or fetch.get("cdid_tag")) egid = str(report.get("egid") or fetch.get("egid") or "") if egid and not is_valid_egid(egid): egid = "" return BootstrapIdentity(did=did, cdid_tag=cdid_tag, egid=egid) def apply_bootstrap_identity(profile: DeviceProfile, identity: BootstrapIdentity) -> None: if identity.did: profile.apply_cloud_identity(identity.did, identity.cdid_tag, identity.egid) return if identity.egid: profile.egid = identity.egid profile.sync_egid_cache() profile.validate() def post_request( request: DfpRequestSpec, *, timeout: int = 20, post_func: Callable[..., Any] | None = None, ) -> DfpHttpResponse: if post_func is None: import requests post_func = requests.post try: response = post_func( request.url, data=request.body.encode("utf-8"), headers=request.headers, timeout=timeout, ) except Exception as exc: text = str(exc) return DfpHttpResponse( status_code=0, ok=False, data={"error_type": exc.__class__.__name__, "error": text}, text=text, ) text = getattr(response, "text", "") try: data = response.json() except Exception: try: data = json.loads(text) except Exception: data = text return DfpHttpResponse( status_code=int(getattr(response, "status_code", 0)), ok=bool(getattr(response, "ok", False)), data=data, text=text, ) __all__ = [ "BootstrapIdentity", "DfpHttpResponse", "apply_bootstrap_identity", "extract_bootstrap_identity", "post_request", ]