# Copyright (c) 2025 Patrick Motsch # All rights reserved. """ Service Center. Central registry for core and importable services with per-feature resolution. """ import logging from typing import Any, List, Optional from modules.serviceCenter.context import ServiceCenterContext from modules.serviceCenter.registry import ( CORE_SERVICES, IMPORTABLE_SERVICES, SERVICE_RBAC_OBJECTS, ) from modules.serviceCenter.resolver import ( resolve, get_resolution_cache, clear_cache, ) logger = logging.getLogger(__name__) def getService( key: str, context: ServiceCenterContext, legacy_hub: Optional[Any] = None, ) -> Any: """ Get a service instance by key for the given context. Args: key: Service key (e.g., "web", "extraction", "utils") context: ServiceCenterContext with user, mandate_id, feature_instance_id, workflow legacy_hub: Optional legacy Services instance for fallback when service not yet migrated Returns: Service instance """ cache = get_resolution_cache() resolving = set() return resolve(key, context, cache, resolving, legacy_hub=legacy_hub) def preWarm(service_keys: Optional[List[str]] = None) -> None: """ Pre-load service modules at startup to avoid first-request latency. Args: service_keys: Optional list of keys to preload. If None, preloads all registered services. """ import importlib keys = service_keys or list(CORE_SERVICES.keys()) + list(IMPORTABLE_SERVICES.keys()) for key in keys: spec = CORE_SERVICES.get(key) or IMPORTABLE_SERVICES.get(key) if not spec: continue try: importlib.import_module(spec["module"]) logger.debug(f"Pre-warmed service module: {key}") except (ImportError, ModuleNotFoundError) as e: logger.debug(f"Could not pre-warm {key}: {e}") def registerServiceObjects(catalogService) -> bool: """Register service RBAC objects in the catalog. Call at startup.""" try: for obj in SERVICE_RBAC_OBJECTS: catalogService.registerResourceObject( featureCode="system", objectKey=obj["objectKey"], label=obj["label"], meta=obj.get("meta"), ) logger.info(f"Registered {len(SERVICE_RBAC_OBJECTS)} service RBAC objects") return True except Exception as e: logger.error(f"Failed to register service RBAC objects: {e}") return False def can_access_service( user, rbac, service_key: str, mandate_id: Optional[str] = None, feature_instance_id: Optional[str] = None, allow_when_no_rbac: bool = True, ) -> bool: """ Check if user has permission to access the given service. Args: user: User object rbac: RbacClass instance (e.g. from interfaceDbApp.rbac) service_key: Service key (e.g., "web", "extraction") mandate_id: Optional mandate context feature_instance_id: Optional feature instance context allow_when_no_rbac: If True, allow when rbac is None (migration/default) Returns: True if user has view permission on the service """ if not rbac: return allow_when_no_rbac if service_key not in IMPORTABLE_SERVICES: return False obj = IMPORTABLE_SERVICES[service_key] object_key = obj.get("objectKey") if not object_key: return False from modules.datamodels.datamodelRbac import AccessRuleContext permissions = rbac.getUserPermissions( user, AccessRuleContext.RESOURCE, object_key, mandateId=mandate_id, featureInstanceId=feature_instance_id, ) return permissions.view if permissions else False __all__ = [ "ServiceCenterContext", "getService", "preWarm", "clear_cache", "registerServiceObjects", "can_access_service", "SERVICE_RBAC_OBJECTS", "CORE_SERVICES", "IMPORTABLE_SERVICES", ]