ThePirateRay/spikes/rayforge-jcz-no-device-addon/pirate_ray_jcz/rayforge_compat.py

127 lines
4.4 KiB
Python

"""Fail-closed compatibility boundary for Rayforge's driver registry.
Rayforge API 23 does not expose addon-aware driver registration and cleanup.
Keep the unavoidable internal registry access here so it can be removed when
the host provides a supported symmetric API.
"""
from typing import Any
SUPPORTED_PLUGIN_API_VERSION = 23
class RayforgeCompatibilityError(RuntimeError):
"""The pinned Rayforge registry contract is unavailable or has drifted."""
def _resolve_host() -> tuple[Any, int]:
from rayforge.core.hooks import PLUGIN_API_VERSION
from rayforge.machine import driver as registry
return registry, PLUGIN_API_VERSION
def _validate_host(registry: Any, plugin_api_version: int) -> None:
if plugin_api_version != SUPPORTED_PLUGIN_API_VERSION:
raise RayforgeCompatibilityError(
"unsupported Rayforge addon API: "
f"expected {SUPPORTED_PLUGIN_API_VERSION}, got {plugin_api_version}"
)
if not isinstance(getattr(registry, "driver_by_classname", None), dict):
raise RayforgeCompatibilityError(
"Rayforge driver_by_classname registry is unavailable"
)
if not isinstance(getattr(registry, "drivers", None), list):
raise RayforgeCompatibilityError("Rayforge drivers registry is unavailable")
if not callable(getattr(registry, "register_driver", None)):
raise RayforgeCompatibilityError("Rayforge register_driver is unavailable")
def _host(
registry: Any | None, plugin_api_version: int | None
) -> tuple[Any, int]:
if registry is None or plugin_api_version is None:
resolved_registry, resolved_version = _resolve_host()
registry = resolved_registry if registry is None else registry
plugin_api_version = (
resolved_version
if plugin_api_version is None
else plugin_api_version
)
_validate_host(registry, plugin_api_version)
return registry, plugin_api_version
def register_driver(
driver_cls: type,
*,
registry: Any | None = None,
plugin_api_version: int | None = None,
) -> bool:
"""Register exactly one driver class, or fail before replacing anything."""
registry, _version = _host(registry, plugin_api_version)
name = driver_cls.__name__
registered = registry.driver_by_classname.get(name)
named_entries = [item for item in registry.drivers if item.__name__ == name]
if registered is driver_cls:
if named_entries == [driver_cls]:
return False
raise RayforgeCompatibilityError(
f"inconsistent Rayforge driver registry for {name}"
)
if registered is not None or named_entries:
raise RayforgeCompatibilityError(
f"Rayforge driver name collision for {name}"
)
registry.register_driver(driver_cls)
if registry.driver_by_classname.get(name) is not driver_cls:
raise RayforgeCompatibilityError(
f"Rayforge did not index registered driver {name}"
)
if sum(item is driver_cls for item in registry.drivers) != 1:
raise RayforgeCompatibilityError(
f"Rayforge did not register exactly one {name} driver"
)
return True
def unregister_driver(
driver_cls: type,
*,
registry: Any | None = None,
plugin_api_version: int | None = None,
) -> bool:
"""Remove only the exact class previously registered by this addon."""
registry, _version = _host(registry, plugin_api_version)
name = driver_cls.__name__
registered = registry.driver_by_classname.get(name)
identity_entries = [item for item in registry.drivers if item is driver_cls]
named_foreign = [
item
for item in registry.drivers
if item.__name__ == name and item is not driver_cls
]
if registered is None and not identity_entries and not named_foreign:
return False
if registered is not driver_cls or named_foreign:
raise RayforgeCompatibilityError(
f"refusing to unregister foreign Rayforge driver {name}"
)
del registry.driver_by_classname[name]
registry.drivers[:] = [
item for item in registry.drivers if item is not driver_cls
]
if name in registry.driver_by_classname or any(
item is driver_cls for item in registry.drivers
):
raise RayforgeCompatibilityError(
f"Rayforge did not fully unregister driver {name}"
)
return True