136 lines
3.9 KiB
Python
136 lines
3.9 KiB
Python
# 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",
|
|
]
|