Loading src/open_exposure_gateway/adapters/database/mappers.py +4 −0 Original line number Diff line number Diff line Loading @@ -121,6 +121,8 @@ class QodSessionMapper: duration_seconds=row.duration_seconds, state=row.state, external_ref=row.external_ref, device_ports=row.device_ports, application_server_ports=row.application_server_ports, created_at=row.created_at, updated_at=row.updated_at, ) Loading @@ -135,6 +137,8 @@ class QodSessionMapper: duration_seconds=domain.duration_seconds, state=domain.state, external_ref=domain.external_ref, device_ports=domain.device_ports, application_server_ports=domain.application_server_ports, ) Loading src/open_exposure_gateway/adapters/database/sql.py +2 −0 Original line number Diff line number Diff line Loading @@ -200,3 +200,5 @@ class QodSessionRow(AuditedMixin, Base): duration_seconds: Mapped[int] = mapped_column(Integer, nullable=False) state: Mapped[QodSessionState] = mapped_column(_enum_type(QodSessionState), nullable=False) external_ref: Mapped[str | None] = mapped_column(String(255)) device_ports: Mapped[dict[str, object] | None] = mapped_column(JSONB) application_server_ports: Mapped[dict[str, object] | None] = mapped_column(JSONB) src/open_exposure_gateway/application/mappers/quality_on_demand_mapper.py +31 −0 Original line number Diff line number Diff line Loading @@ -7,6 +7,7 @@ from open_exposure_gateway.api.camara.quality_on_demand.v0_10_1.schemas import ( CreateSession, Device, DeviceIpv4Addr, PortsSpec, QosStatus, SessionInfo, ) Loading @@ -16,6 +17,8 @@ from open_exposure_gateway.domain.quality_on_demand import ( NetworkCapabilityDeactivateTarget, NetworkCapabilityParameters, NetworkCapabilityPayload, NetworkCapabilityPortRange, NetworkCapabilityPorts, NetworkCapabilityTarget, NetworkCapabilityTargetApplicationServer, NetworkCapabilityTargetDevice, Loading @@ -26,6 +29,20 @@ from open_exposure_gateway.domain.quality_on_demand import ( ) def _to_capability_ports(spec: PortsSpec | None) -> NetworkCapabilityPorts | None: """CAMARA `PortsSpec` -> canonical `target.*.ports`.""" if spec is None: return None return NetworkCapabilityPorts( ranges=( [NetworkCapabilityPortRange(**{"from": r.from_, "to": r.to}) for r in spec.ranges] if spec.ranges is not None else None ), ports=spec.ports, ) def build_activate_command( request: CreateSession, operation_id: UUID, Loading @@ -44,10 +61,12 @@ def build_activate_command( ipv4=device.ipv4Address.publicAddress if device.ipv4Address else None, ipv6=device.ipv6Address, network_access_id=device.networkAccessIdentifier, ports=_to_capability_ports(request.devicePorts), ), application_server=NetworkCapabilityTargetApplicationServer( ipv4=application_server.ipv4Address, ipv6=application_server.ipv6Address, ports=_to_capability_ports(request.applicationServerPorts), ), ) Loading Loading @@ -98,12 +117,24 @@ def build_session_info(qod_session: QodSession, capability: SRMNetworkCapability ipv4Address=server_target.ipv4, ipv6Address=server_target.ipv6, ) device_ports = ( PortsSpec.model_validate(qod_session.device_ports) if qod_session.device_ports is not None else None ) application_server_ports = ( PortsSpec.model_validate(qod_session.application_server_ports) if qod_session.application_server_ports is not None else None ) started_at = int((qod_session.created_at or datetime.now(timezone.utc)).timestamp()) return SessionInfo( sessionId=qod_session.session_id, device=device, applicationServer=application_server, devicePorts=device_ports, applicationServerPorts=application_server_ports, qosProfile=qod_session.qos_profile, duration=qod_session.duration_seconds, startedAt=started_at, Loading src/open_exposure_gateway/application/services/quality_on_demand_service.py +11 −1 Original line number Diff line number Diff line Loading @@ -86,7 +86,7 @@ class QualityOnDemandService: if self._publisher is None: raise RuntimeError("DataBus publisher is not available") try: await self._publisher.publish(subject, command.model_dump(mode="json")) await self._publisher.publish(subject, command.model_dump(mode="json", by_alias=True)) except Exception as exc: raise DownstreamServiceException(error_msg) from exc Loading Loading @@ -140,6 +140,16 @@ class QualityOnDemandService: qos_profile=request.qosProfile, duration_seconds=request.duration, state=QodSessionState.REQUESTED, device_ports=( request.devicePorts.model_dump(mode="json") if request.devicePorts is not None else None ), application_server_ports=( request.applicationServerPorts.model_dump(mode="json") if request.applicationServerPorts is not None else None ), ) ) Loading src/open_exposure_gateway/domain/models/qod_sessions/models.py +3 −0 Original line number Diff line number Diff line from datetime import datetime from typing import Any from uuid import UUID from pydantic import BaseModel Loading @@ -14,5 +15,7 @@ class QodSession(BaseModel): duration_seconds: int state: QodSessionState external_ref: str | None = None device_ports: dict[str, Any] | None = None application_server_ports: dict[str, Any] | None = None created_at: datetime | None = None updated_at: datetime | None = None Loading
src/open_exposure_gateway/adapters/database/mappers.py +4 −0 Original line number Diff line number Diff line Loading @@ -121,6 +121,8 @@ class QodSessionMapper: duration_seconds=row.duration_seconds, state=row.state, external_ref=row.external_ref, device_ports=row.device_ports, application_server_ports=row.application_server_ports, created_at=row.created_at, updated_at=row.updated_at, ) Loading @@ -135,6 +137,8 @@ class QodSessionMapper: duration_seconds=domain.duration_seconds, state=domain.state, external_ref=domain.external_ref, device_ports=domain.device_ports, application_server_ports=domain.application_server_ports, ) Loading
src/open_exposure_gateway/adapters/database/sql.py +2 −0 Original line number Diff line number Diff line Loading @@ -200,3 +200,5 @@ class QodSessionRow(AuditedMixin, Base): duration_seconds: Mapped[int] = mapped_column(Integer, nullable=False) state: Mapped[QodSessionState] = mapped_column(_enum_type(QodSessionState), nullable=False) external_ref: Mapped[str | None] = mapped_column(String(255)) device_ports: Mapped[dict[str, object] | None] = mapped_column(JSONB) application_server_ports: Mapped[dict[str, object] | None] = mapped_column(JSONB)
src/open_exposure_gateway/application/mappers/quality_on_demand_mapper.py +31 −0 Original line number Diff line number Diff line Loading @@ -7,6 +7,7 @@ from open_exposure_gateway.api.camara.quality_on_demand.v0_10_1.schemas import ( CreateSession, Device, DeviceIpv4Addr, PortsSpec, QosStatus, SessionInfo, ) Loading @@ -16,6 +17,8 @@ from open_exposure_gateway.domain.quality_on_demand import ( NetworkCapabilityDeactivateTarget, NetworkCapabilityParameters, NetworkCapabilityPayload, NetworkCapabilityPortRange, NetworkCapabilityPorts, NetworkCapabilityTarget, NetworkCapabilityTargetApplicationServer, NetworkCapabilityTargetDevice, Loading @@ -26,6 +29,20 @@ from open_exposure_gateway.domain.quality_on_demand import ( ) def _to_capability_ports(spec: PortsSpec | None) -> NetworkCapabilityPorts | None: """CAMARA `PortsSpec` -> canonical `target.*.ports`.""" if spec is None: return None return NetworkCapabilityPorts( ranges=( [NetworkCapabilityPortRange(**{"from": r.from_, "to": r.to}) for r in spec.ranges] if spec.ranges is not None else None ), ports=spec.ports, ) def build_activate_command( request: CreateSession, operation_id: UUID, Loading @@ -44,10 +61,12 @@ def build_activate_command( ipv4=device.ipv4Address.publicAddress if device.ipv4Address else None, ipv6=device.ipv6Address, network_access_id=device.networkAccessIdentifier, ports=_to_capability_ports(request.devicePorts), ), application_server=NetworkCapabilityTargetApplicationServer( ipv4=application_server.ipv4Address, ipv6=application_server.ipv6Address, ports=_to_capability_ports(request.applicationServerPorts), ), ) Loading Loading @@ -98,12 +117,24 @@ def build_session_info(qod_session: QodSession, capability: SRMNetworkCapability ipv4Address=server_target.ipv4, ipv6Address=server_target.ipv6, ) device_ports = ( PortsSpec.model_validate(qod_session.device_ports) if qod_session.device_ports is not None else None ) application_server_ports = ( PortsSpec.model_validate(qod_session.application_server_ports) if qod_session.application_server_ports is not None else None ) started_at = int((qod_session.created_at or datetime.now(timezone.utc)).timestamp()) return SessionInfo( sessionId=qod_session.session_id, device=device, applicationServer=application_server, devicePorts=device_ports, applicationServerPorts=application_server_ports, qosProfile=qod_session.qos_profile, duration=qod_session.duration_seconds, startedAt=started_at, Loading
src/open_exposure_gateway/application/services/quality_on_demand_service.py +11 −1 Original line number Diff line number Diff line Loading @@ -86,7 +86,7 @@ class QualityOnDemandService: if self._publisher is None: raise RuntimeError("DataBus publisher is not available") try: await self._publisher.publish(subject, command.model_dump(mode="json")) await self._publisher.publish(subject, command.model_dump(mode="json", by_alias=True)) except Exception as exc: raise DownstreamServiceException(error_msg) from exc Loading Loading @@ -140,6 +140,16 @@ class QualityOnDemandService: qos_profile=request.qosProfile, duration_seconds=request.duration, state=QodSessionState.REQUESTED, device_ports=( request.devicePorts.model_dump(mode="json") if request.devicePorts is not None else None ), application_server_ports=( request.applicationServerPorts.model_dump(mode="json") if request.applicationServerPorts is not None else None ), ) ) Loading
src/open_exposure_gateway/domain/models/qod_sessions/models.py +3 −0 Original line number Diff line number Diff line from datetime import datetime from typing import Any from uuid import UUID from pydantic import BaseModel Loading @@ -14,5 +15,7 @@ class QodSession(BaseModel): duration_seconds: int state: QodSessionState external_ref: str | None = None device_ports: dict[str, Any] | None = None application_server_ports: dict[str, Any] | None = None created_at: datetime | None = None updated_at: datetime | None = None