ReticulumTelemetryHub 0.1.0__py3-none-any.whl → 0.143.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- reticulum_telemetry_hub/api/__init__.py +23 -0
- reticulum_telemetry_hub/api/models.py +323 -0
- reticulum_telemetry_hub/api/service.py +836 -0
- reticulum_telemetry_hub/api/storage.py +528 -0
- reticulum_telemetry_hub/api/storage_base.py +156 -0
- reticulum_telemetry_hub/api/storage_models.py +118 -0
- reticulum_telemetry_hub/atak_cot/__init__.py +49 -0
- reticulum_telemetry_hub/atak_cot/base.py +277 -0
- reticulum_telemetry_hub/atak_cot/chat.py +506 -0
- reticulum_telemetry_hub/atak_cot/detail.py +235 -0
- reticulum_telemetry_hub/atak_cot/event.py +181 -0
- reticulum_telemetry_hub/atak_cot/pytak_client.py +569 -0
- reticulum_telemetry_hub/atak_cot/tak_connector.py +848 -0
- reticulum_telemetry_hub/config/__init__.py +25 -0
- reticulum_telemetry_hub/config/constants.py +7 -0
- reticulum_telemetry_hub/config/manager.py +515 -0
- reticulum_telemetry_hub/config/models.py +215 -0
- reticulum_telemetry_hub/embedded_lxmd/__init__.py +5 -0
- reticulum_telemetry_hub/embedded_lxmd/embedded.py +418 -0
- reticulum_telemetry_hub/internal_api/__init__.py +21 -0
- reticulum_telemetry_hub/internal_api/bus.py +344 -0
- reticulum_telemetry_hub/internal_api/core.py +690 -0
- reticulum_telemetry_hub/internal_api/v1/__init__.py +74 -0
- reticulum_telemetry_hub/internal_api/v1/enums.py +109 -0
- reticulum_telemetry_hub/internal_api/v1/manifest.json +8 -0
- reticulum_telemetry_hub/internal_api/v1/schemas.py +478 -0
- reticulum_telemetry_hub/internal_api/versioning.py +63 -0
- reticulum_telemetry_hub/lxmf_daemon/Handlers.py +122 -0
- reticulum_telemetry_hub/lxmf_daemon/LXMF.py +252 -0
- reticulum_telemetry_hub/lxmf_daemon/LXMPeer.py +898 -0
- reticulum_telemetry_hub/lxmf_daemon/LXMRouter.py +4227 -0
- reticulum_telemetry_hub/lxmf_daemon/LXMessage.py +1006 -0
- reticulum_telemetry_hub/lxmf_daemon/LXStamper.py +490 -0
- reticulum_telemetry_hub/lxmf_daemon/__init__.py +10 -0
- reticulum_telemetry_hub/lxmf_daemon/_version.py +1 -0
- reticulum_telemetry_hub/lxmf_daemon/lxmd.py +1655 -0
- reticulum_telemetry_hub/lxmf_telemetry/model/fields/field_telemetry_stream.py +6 -0
- reticulum_telemetry_hub/lxmf_telemetry/model/persistance/__init__.py +3 -0
- {lxmf_telemetry → reticulum_telemetry_hub/lxmf_telemetry}/model/persistance/appearance.py +19 -19
- {lxmf_telemetry → reticulum_telemetry_hub/lxmf_telemetry}/model/persistance/peer.py +17 -13
- reticulum_telemetry_hub/lxmf_telemetry/model/persistance/sensors/__init__.py +65 -0
- reticulum_telemetry_hub/lxmf_telemetry/model/persistance/sensors/acceleration.py +68 -0
- reticulum_telemetry_hub/lxmf_telemetry/model/persistance/sensors/ambient_light.py +37 -0
- reticulum_telemetry_hub/lxmf_telemetry/model/persistance/sensors/angular_velocity.py +68 -0
- reticulum_telemetry_hub/lxmf_telemetry/model/persistance/sensors/battery.py +68 -0
- reticulum_telemetry_hub/lxmf_telemetry/model/persistance/sensors/connection_map.py +258 -0
- reticulum_telemetry_hub/lxmf_telemetry/model/persistance/sensors/generic.py +841 -0
- reticulum_telemetry_hub/lxmf_telemetry/model/persistance/sensors/gravity.py +68 -0
- reticulum_telemetry_hub/lxmf_telemetry/model/persistance/sensors/humidity.py +37 -0
- reticulum_telemetry_hub/lxmf_telemetry/model/persistance/sensors/information.py +42 -0
- reticulum_telemetry_hub/lxmf_telemetry/model/persistance/sensors/location.py +110 -0
- reticulum_telemetry_hub/lxmf_telemetry/model/persistance/sensors/lxmf_propagation.py +429 -0
- reticulum_telemetry_hub/lxmf_telemetry/model/persistance/sensors/magnetic_field.py +68 -0
- reticulum_telemetry_hub/lxmf_telemetry/model/persistance/sensors/physical_link.py +53 -0
- reticulum_telemetry_hub/lxmf_telemetry/model/persistance/sensors/pressure.py +37 -0
- reticulum_telemetry_hub/lxmf_telemetry/model/persistance/sensors/proximity.py +37 -0
- reticulum_telemetry_hub/lxmf_telemetry/model/persistance/sensors/received.py +75 -0
- reticulum_telemetry_hub/lxmf_telemetry/model/persistance/sensors/rns_transport.py +209 -0
- reticulum_telemetry_hub/lxmf_telemetry/model/persistance/sensors/sensor.py +65 -0
- reticulum_telemetry_hub/lxmf_telemetry/model/persistance/sensors/sensor_enum.py +27 -0
- reticulum_telemetry_hub/lxmf_telemetry/model/persistance/sensors/sensor_mapping.py +58 -0
- reticulum_telemetry_hub/lxmf_telemetry/model/persistance/sensors/temperature.py +37 -0
- {lxmf_telemetry → reticulum_telemetry_hub/lxmf_telemetry}/model/persistance/sensors/time.py +36 -32
- {lxmf_telemetry → reticulum_telemetry_hub/lxmf_telemetry}/model/persistance/telemeter.py +26 -23
- reticulum_telemetry_hub/lxmf_telemetry/sampler.py +229 -0
- reticulum_telemetry_hub/lxmf_telemetry/telemeter_manager.py +409 -0
- reticulum_telemetry_hub/lxmf_telemetry/telemetry_controller.py +804 -0
- reticulum_telemetry_hub/northbound/__init__.py +5 -0
- reticulum_telemetry_hub/northbound/app.py +195 -0
- reticulum_telemetry_hub/northbound/auth.py +119 -0
- reticulum_telemetry_hub/northbound/gateway.py +310 -0
- reticulum_telemetry_hub/northbound/internal_adapter.py +302 -0
- reticulum_telemetry_hub/northbound/models.py +213 -0
- reticulum_telemetry_hub/northbound/routes_chat.py +123 -0
- reticulum_telemetry_hub/northbound/routes_files.py +119 -0
- reticulum_telemetry_hub/northbound/routes_rest.py +345 -0
- reticulum_telemetry_hub/northbound/routes_subscribers.py +150 -0
- reticulum_telemetry_hub/northbound/routes_topics.py +178 -0
- reticulum_telemetry_hub/northbound/routes_ws.py +107 -0
- reticulum_telemetry_hub/northbound/serializers.py +72 -0
- reticulum_telemetry_hub/northbound/services.py +373 -0
- reticulum_telemetry_hub/northbound/websocket.py +855 -0
- reticulum_telemetry_hub/reticulum_server/__main__.py +2237 -0
- reticulum_telemetry_hub/reticulum_server/command_manager.py +1268 -0
- reticulum_telemetry_hub/reticulum_server/command_text.py +399 -0
- reticulum_telemetry_hub/reticulum_server/constants.py +1 -0
- reticulum_telemetry_hub/reticulum_server/event_log.py +357 -0
- reticulum_telemetry_hub/reticulum_server/internal_adapter.py +358 -0
- reticulum_telemetry_hub/reticulum_server/outbound_queue.py +312 -0
- reticulum_telemetry_hub/reticulum_server/services.py +422 -0
- reticulumtelemetryhub-0.143.0.dist-info/METADATA +181 -0
- reticulumtelemetryhub-0.143.0.dist-info/RECORD +97 -0
- {reticulumtelemetryhub-0.1.0.dist-info → reticulumtelemetryhub-0.143.0.dist-info}/WHEEL +1 -1
- reticulumtelemetryhub-0.143.0.dist-info/licenses/LICENSE +277 -0
- lxmf_telemetry/model/fields/field_telemetry_stream.py +0 -7
- lxmf_telemetry/model/persistance/__init__.py +0 -3
- lxmf_telemetry/model/persistance/sensors/location.py +0 -69
- lxmf_telemetry/model/persistance/sensors/magnetic_field.py +0 -36
- lxmf_telemetry/model/persistance/sensors/sensor.py +0 -44
- lxmf_telemetry/model/persistance/sensors/sensor_enum.py +0 -24
- lxmf_telemetry/model/persistance/sensors/sensor_mapping.py +0 -9
- lxmf_telemetry/telemetry_controller.py +0 -124
- reticulum_server/main.py +0 -182
- reticulumtelemetryhub-0.1.0.dist-info/METADATA +0 -15
- reticulumtelemetryhub-0.1.0.dist-info/RECORD +0 -19
- {lxmf_telemetry → reticulum_telemetry_hub}/__init__.py +0 -0
- {lxmf_telemetry/model/persistance/sensors → reticulum_telemetry_hub/lxmf_telemetry}/__init__.py +0 -0
- {reticulum_server → reticulum_telemetry_hub/reticulum_server}/__init__.py +0 -0
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
"""Topic routes for the northbound API."""
|
|
2
|
+
# pylint: disable=import-error
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
from typing import Callable
|
|
7
|
+
|
|
8
|
+
from fastapi import Depends
|
|
9
|
+
from fastapi import FastAPI
|
|
10
|
+
from fastapi import HTTPException
|
|
11
|
+
from fastapi import Query
|
|
12
|
+
from fastapi import status
|
|
13
|
+
|
|
14
|
+
from reticulum_telemetry_hub.api.service import ReticulumTelemetryHubAPI
|
|
15
|
+
|
|
16
|
+
from .models import SubscribeTopicRequest
|
|
17
|
+
from .models import TopicPayload
|
|
18
|
+
from .serializers import build_topic
|
|
19
|
+
from .serializers import serialize_subscriber
|
|
20
|
+
from .serializers import serialize_topic
|
|
21
|
+
from .services import NorthboundServices
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def register_topic_routes(
|
|
25
|
+
app: FastAPI,
|
|
26
|
+
*,
|
|
27
|
+
services: NorthboundServices,
|
|
28
|
+
api: ReticulumTelemetryHubAPI,
|
|
29
|
+
require_protected: Callable[[], None],
|
|
30
|
+
) -> None:
|
|
31
|
+
"""Register topic routes on the FastAPI app.
|
|
32
|
+
|
|
33
|
+
Args:
|
|
34
|
+
app (FastAPI): FastAPI application instance.
|
|
35
|
+
services (NorthboundServices): Aggregated services.
|
|
36
|
+
api (ReticulumTelemetryHubAPI): API service instance.
|
|
37
|
+
require_protected (Callable[[], None]): Dependency for protected routes.
|
|
38
|
+
|
|
39
|
+
Returns:
|
|
40
|
+
None: Routes are registered on the application.
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
@app.get("/Topic/{topic_id}")
|
|
44
|
+
def retrieve_topic(topic_id: str) -> dict:
|
|
45
|
+
"""Retrieve a topic by ID.
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
topic_id (str): Topic identifier.
|
|
49
|
+
|
|
50
|
+
Returns:
|
|
51
|
+
dict: Topic payload.
|
|
52
|
+
"""
|
|
53
|
+
|
|
54
|
+
try:
|
|
55
|
+
topic = api.retrieve_topic(topic_id)
|
|
56
|
+
except KeyError as exc:
|
|
57
|
+
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(exc)) from exc
|
|
58
|
+
return serialize_topic(topic)
|
|
59
|
+
|
|
60
|
+
@app.post("/Topic", dependencies=[Depends(require_protected)])
|
|
61
|
+
def create_topic(payload: TopicPayload) -> dict:
|
|
62
|
+
"""Create a new topic.
|
|
63
|
+
|
|
64
|
+
Args:
|
|
65
|
+
payload (TopicPayload): Topic request payload.
|
|
66
|
+
|
|
67
|
+
Returns:
|
|
68
|
+
dict: Created topic payload.
|
|
69
|
+
"""
|
|
70
|
+
|
|
71
|
+
topic = build_topic(payload)
|
|
72
|
+
try:
|
|
73
|
+
created = api.create_topic(topic)
|
|
74
|
+
except ValueError as exc:
|
|
75
|
+
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(exc)) from exc
|
|
76
|
+
services.record_event("topic_created", f"Topic created: {created.topic_id}")
|
|
77
|
+
return serialize_topic(created)
|
|
78
|
+
|
|
79
|
+
@app.delete("/Topic", dependencies=[Depends(require_protected)])
|
|
80
|
+
def delete_topic(topic_id: str = Query(alias="id")) -> dict:
|
|
81
|
+
"""Delete a topic.
|
|
82
|
+
|
|
83
|
+
Args:
|
|
84
|
+
topic_id (str): Topic identifier.
|
|
85
|
+
|
|
86
|
+
Returns:
|
|
87
|
+
dict: Deleted topic payload.
|
|
88
|
+
"""
|
|
89
|
+
|
|
90
|
+
try:
|
|
91
|
+
topic = api.delete_topic(topic_id)
|
|
92
|
+
except KeyError as exc:
|
|
93
|
+
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(exc)) from exc
|
|
94
|
+
services.record_event("topic_deleted", f"Topic deleted: {topic.topic_id}")
|
|
95
|
+
return serialize_topic(topic)
|
|
96
|
+
|
|
97
|
+
@app.get("/Topic")
|
|
98
|
+
def list_topics() -> list[dict]:
|
|
99
|
+
"""List topics.
|
|
100
|
+
|
|
101
|
+
Returns:
|
|
102
|
+
list[dict]: Topic entries.
|
|
103
|
+
"""
|
|
104
|
+
|
|
105
|
+
return [serialize_topic(topic) for topic in services.list_topics()]
|
|
106
|
+
|
|
107
|
+
@app.patch("/Topic", dependencies=[Depends(require_protected)])
|
|
108
|
+
def patch_topic(payload: TopicPayload) -> dict:
|
|
109
|
+
"""Update a topic.
|
|
110
|
+
|
|
111
|
+
Args:
|
|
112
|
+
payload (TopicPayload): Topic update payload.
|
|
113
|
+
|
|
114
|
+
Returns:
|
|
115
|
+
dict: Updated topic payload.
|
|
116
|
+
"""
|
|
117
|
+
|
|
118
|
+
if not payload.topic_id:
|
|
119
|
+
raise HTTPException(
|
|
120
|
+
status_code=status.HTTP_400_BAD_REQUEST,
|
|
121
|
+
detail="TopicID is required",
|
|
122
|
+
)
|
|
123
|
+
try:
|
|
124
|
+
topic = api.patch_topic(payload.topic_id, **payload.model_dump(by_alias=True, exclude_unset=True))
|
|
125
|
+
except KeyError as exc:
|
|
126
|
+
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(exc)) from exc
|
|
127
|
+
services.record_event("topic_updated", f"Topic updated: {topic.topic_id}")
|
|
128
|
+
return serialize_topic(topic)
|
|
129
|
+
|
|
130
|
+
@app.post("/Topic/Subscribe")
|
|
131
|
+
def subscribe_topic(payload: SubscribeTopicRequest) -> dict:
|
|
132
|
+
"""Subscribe a destination to a topic.
|
|
133
|
+
|
|
134
|
+
Args:
|
|
135
|
+
payload (SubscribeTopicRequest): Subscription payload.
|
|
136
|
+
|
|
137
|
+
Returns:
|
|
138
|
+
dict: Subscriber payload.
|
|
139
|
+
"""
|
|
140
|
+
|
|
141
|
+
if not payload.destination:
|
|
142
|
+
raise HTTPException(
|
|
143
|
+
status_code=status.HTTP_400_BAD_REQUEST,
|
|
144
|
+
detail="Destination is required when authentication identity is unavailable",
|
|
145
|
+
)
|
|
146
|
+
try:
|
|
147
|
+
subscriber = api.subscribe_topic(
|
|
148
|
+
payload.topic_id,
|
|
149
|
+
payload.destination,
|
|
150
|
+
reject_tests=payload.reject_tests,
|
|
151
|
+
metadata=payload.metadata,
|
|
152
|
+
)
|
|
153
|
+
except KeyError as exc:
|
|
154
|
+
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(exc)) from exc
|
|
155
|
+
services.record_event(
|
|
156
|
+
"topic_subscribed",
|
|
157
|
+
f"Subscriber added: {subscriber.subscriber_id}",
|
|
158
|
+
metadata={"topic_id": subscriber.topic_id},
|
|
159
|
+
)
|
|
160
|
+
return serialize_subscriber(subscriber)
|
|
161
|
+
|
|
162
|
+
@app.post("/Topic/Associate", dependencies=[Depends(require_protected)])
|
|
163
|
+
def associate_topic(payload: TopicPayload) -> dict:
|
|
164
|
+
"""Return the topic association payload.
|
|
165
|
+
|
|
166
|
+
Args:
|
|
167
|
+
payload (TopicPayload): Topic association payload.
|
|
168
|
+
|
|
169
|
+
Returns:
|
|
170
|
+
dict: Topic association payload.
|
|
171
|
+
"""
|
|
172
|
+
|
|
173
|
+
if not payload.topic_id:
|
|
174
|
+
raise HTTPException(
|
|
175
|
+
status_code=status.HTTP_400_BAD_REQUEST,
|
|
176
|
+
detail="TopicID is required",
|
|
177
|
+
)
|
|
178
|
+
return {"TopicID": payload.topic_id}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"""WebSocket route registrations for the northbound API."""
|
|
2
|
+
# pylint: disable=import-error
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
from fastapi import FastAPI
|
|
7
|
+
from fastapi import WebSocket
|
|
8
|
+
|
|
9
|
+
from .auth import ApiAuth
|
|
10
|
+
from .services import NorthboundServices
|
|
11
|
+
from .websocket import EventBroadcaster
|
|
12
|
+
from .websocket import MessageBroadcaster
|
|
13
|
+
from .websocket import TelemetryBroadcaster
|
|
14
|
+
from .websocket import handle_message_socket
|
|
15
|
+
from .websocket import handle_system_socket
|
|
16
|
+
from .websocket import handle_telemetry_socket
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def register_ws_routes(
|
|
20
|
+
app: FastAPI,
|
|
21
|
+
*,
|
|
22
|
+
services: NorthboundServices,
|
|
23
|
+
auth: ApiAuth,
|
|
24
|
+
event_broadcaster: EventBroadcaster,
|
|
25
|
+
telemetry_broadcaster: TelemetryBroadcaster,
|
|
26
|
+
message_broadcaster: MessageBroadcaster,
|
|
27
|
+
) -> None:
|
|
28
|
+
"""Register WebSocket routes on the FastAPI app.
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
app (FastAPI): FastAPI application instance.
|
|
32
|
+
services (NorthboundServices): Aggregated services.
|
|
33
|
+
auth (ApiAuth): Auth validator.
|
|
34
|
+
event_broadcaster (EventBroadcaster): Event broadcaster.
|
|
35
|
+
telemetry_broadcaster (TelemetryBroadcaster): Telemetry broadcaster.
|
|
36
|
+
message_broadcaster (MessageBroadcaster): Message broadcaster.
|
|
37
|
+
|
|
38
|
+
Returns:
|
|
39
|
+
None: Routes are registered on the application.
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
@app.websocket("/events/system")
|
|
43
|
+
async def system_websocket(websocket: WebSocket) -> None:
|
|
44
|
+
"""WebSocket stream for system status and events.
|
|
45
|
+
|
|
46
|
+
Args:
|
|
47
|
+
websocket (WebSocket): WebSocket connection.
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
def _event_list_provider(limit: int) -> list[dict]:
|
|
51
|
+
"""Return recent events with the provided limit.
|
|
52
|
+
|
|
53
|
+
Args:
|
|
54
|
+
limit (int): Maximum number of events to return.
|
|
55
|
+
|
|
56
|
+
Returns:
|
|
57
|
+
list[dict]: Event entries.
|
|
58
|
+
"""
|
|
59
|
+
|
|
60
|
+
return services.list_events(limit=limit)
|
|
61
|
+
|
|
62
|
+
await handle_system_socket(
|
|
63
|
+
websocket,
|
|
64
|
+
auth=auth,
|
|
65
|
+
event_broadcaster=event_broadcaster,
|
|
66
|
+
status_provider=services.status_snapshot,
|
|
67
|
+
event_list_provider=_event_list_provider,
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
@app.websocket("/telemetry/stream")
|
|
71
|
+
async def telemetry_websocket(websocket: WebSocket) -> None:
|
|
72
|
+
"""WebSocket stream for telemetry updates.
|
|
73
|
+
|
|
74
|
+
Args:
|
|
75
|
+
websocket (WebSocket): WebSocket connection.
|
|
76
|
+
"""
|
|
77
|
+
|
|
78
|
+
def _telemetry_snapshot(since: int, topic_id: str | None) -> list[dict]:
|
|
79
|
+
"""Return telemetry snapshots for WebSocket clients.
|
|
80
|
+
|
|
81
|
+
Args:
|
|
82
|
+
since (int): Unix timestamp (seconds) for the earliest entries.
|
|
83
|
+
topic_id (str | None): Optional topic filter.
|
|
84
|
+
|
|
85
|
+
Returns:
|
|
86
|
+
list[dict]: Telemetry entries.
|
|
87
|
+
"""
|
|
88
|
+
|
|
89
|
+
return services.telemetry_entries(since=since, topic_id=topic_id)
|
|
90
|
+
|
|
91
|
+
await handle_telemetry_socket(
|
|
92
|
+
websocket,
|
|
93
|
+
auth=auth,
|
|
94
|
+
telemetry_broadcaster=telemetry_broadcaster,
|
|
95
|
+
telemetry_snapshot=_telemetry_snapshot,
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
@app.websocket("/messages/stream")
|
|
99
|
+
async def message_websocket(websocket: WebSocket) -> None:
|
|
100
|
+
"""WebSocket stream for inbound/outbound messages."""
|
|
101
|
+
|
|
102
|
+
await handle_message_socket(
|
|
103
|
+
websocket,
|
|
104
|
+
auth=auth,
|
|
105
|
+
message_broadcaster=message_broadcaster,
|
|
106
|
+
message_sender=services.send_message,
|
|
107
|
+
)
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"""Serialization helpers for the northbound API."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from reticulum_telemetry_hub.api.models import Subscriber
|
|
6
|
+
from reticulum_telemetry_hub.api.models import Topic
|
|
7
|
+
|
|
8
|
+
from .models import SubscriberPayload
|
|
9
|
+
from .models import TopicPayload
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def serialize_topic(topic: Topic) -> dict:
|
|
13
|
+
"""Serialize a topic for JSON output.
|
|
14
|
+
|
|
15
|
+
Args:
|
|
16
|
+
topic (Topic): Topic instance.
|
|
17
|
+
|
|
18
|
+
Returns:
|
|
19
|
+
dict: Serialized topic payload.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
return topic.to_dict()
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def serialize_subscriber(subscriber: Subscriber) -> dict:
|
|
26
|
+
"""Serialize a subscriber for JSON output.
|
|
27
|
+
|
|
28
|
+
Args:
|
|
29
|
+
subscriber (Subscriber): Subscriber instance.
|
|
30
|
+
|
|
31
|
+
Returns:
|
|
32
|
+
dict: Serialized subscriber payload.
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
return subscriber.to_dict()
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def build_topic(payload: TopicPayload) -> Topic:
|
|
39
|
+
"""Build a topic model from a payload.
|
|
40
|
+
|
|
41
|
+
Args:
|
|
42
|
+
payload (TopicPayload): Topic payload.
|
|
43
|
+
|
|
44
|
+
Returns:
|
|
45
|
+
Topic: Topic instance.
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
return Topic(
|
|
49
|
+
topic_id=payload.topic_id,
|
|
50
|
+
topic_name=payload.topic_name or "",
|
|
51
|
+
topic_path=payload.topic_path or "",
|
|
52
|
+
topic_description=payload.topic_description or "",
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def build_subscriber(payload: SubscriberPayload) -> Subscriber:
|
|
57
|
+
"""Build a subscriber model from a payload.
|
|
58
|
+
|
|
59
|
+
Args:
|
|
60
|
+
payload (SubscriberPayload): Subscriber payload.
|
|
61
|
+
|
|
62
|
+
Returns:
|
|
63
|
+
Subscriber: Subscriber instance.
|
|
64
|
+
"""
|
|
65
|
+
|
|
66
|
+
return Subscriber(
|
|
67
|
+
subscriber_id=payload.subscriber_id,
|
|
68
|
+
destination=payload.destination or "",
|
|
69
|
+
topic_id=payload.topic_id,
|
|
70
|
+
reject_tests=payload.reject_tests,
|
|
71
|
+
metadata=payload.metadata or {},
|
|
72
|
+
)
|