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,399 @@
|
|
|
1
|
+
"""Text-building helpers for command responses."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
from typing import Any, List
|
|
7
|
+
|
|
8
|
+
from reticulum_telemetry_hub.api.models import FileAttachment, Subscriber, Topic
|
|
9
|
+
from reticulum_telemetry_hub.lxmf_telemetry.telemetry_controller import (
|
|
10
|
+
TelemetryController,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def build_help_text(command_manager: Any) -> str:
|
|
15
|
+
"""Assemble a Markdown list of supported commands for LXMF clients.
|
|
16
|
+
|
|
17
|
+
Args:
|
|
18
|
+
command_manager (Any): An object exposing the command name constants.
|
|
19
|
+
|
|
20
|
+
Returns:
|
|
21
|
+
str: Markdown-formatted list of supported commands.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
command_names = command_manager._all_command_names() # noqa: SLF001
|
|
25
|
+
lines = [
|
|
26
|
+
"# Command list",
|
|
27
|
+
"",
|
|
28
|
+
"Use the `Command` field (`0`) to choose an action when building payloads.",
|
|
29
|
+
"Tip: tag file/image attachments with a `TopicID` (or send `AssociateTopicID`) "
|
|
30
|
+
"to link them to a topic.",
|
|
31
|
+
"",
|
|
32
|
+
"## Supported commands",
|
|
33
|
+
]
|
|
34
|
+
for command_name in command_names:
|
|
35
|
+
lines.append(f"- `{command_name}`")
|
|
36
|
+
lines.append("- `TelemetryRequest` (`1`)")
|
|
37
|
+
return "\n".join(lines)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def build_examples_text(command_manager: Any) -> str:
|
|
41
|
+
"""Assemble Markdown examples for LXMF clients.
|
|
42
|
+
|
|
43
|
+
Args:
|
|
44
|
+
command_manager (Any): An object exposing the command name constants.
|
|
45
|
+
|
|
46
|
+
Returns:
|
|
47
|
+
str: Markdown-formatted description and payload examples for commands.
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
lines = [
|
|
51
|
+
"# Command examples",
|
|
52
|
+
"",
|
|
53
|
+
"Use the `Command` field (`0`) to choose an action when building payloads.",
|
|
54
|
+
"",
|
|
55
|
+
"## Examples",
|
|
56
|
+
]
|
|
57
|
+
for entry in command_reference(command_manager):
|
|
58
|
+
lines.append(f"- **{entry['title']}**")
|
|
59
|
+
lines.append(f" - Description: {entry['description']}")
|
|
60
|
+
lines.append(f" - Example: `{entry['example']}`")
|
|
61
|
+
telemetry_example = _telemetry_request_example()
|
|
62
|
+
lines.append("- **TelemetryRequest (numeric key `1`)**")
|
|
63
|
+
lines.append(
|
|
64
|
+
" - Description: Request telemetry snapshots using the `TelemetryRequest` numeric key."
|
|
65
|
+
)
|
|
66
|
+
lines.append(
|
|
67
|
+
" - Example: `"
|
|
68
|
+
f"{telemetry_example}"
|
|
69
|
+
"` (timestamp = earliest UNIX time to include)"
|
|
70
|
+
)
|
|
71
|
+
return "\n".join(lines)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def _telemetry_request_example() -> str:
|
|
75
|
+
"""Return an example telemetry request payload."""
|
|
76
|
+
|
|
77
|
+
return json.dumps(
|
|
78
|
+
{
|
|
79
|
+
str(TelemetryController.TELEMETRY_REQUEST): "<unix timestamp>",
|
|
80
|
+
"TopicID": "<TopicID>",
|
|
81
|
+
},
|
|
82
|
+
sort_keys=True,
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def command_reference(command_manager: Any) -> List[dict]:
|
|
87
|
+
"""Return the command reference entries used by help text generation.
|
|
88
|
+
|
|
89
|
+
Args:
|
|
90
|
+
command_manager (Any): An object exposing the command name constants.
|
|
91
|
+
|
|
92
|
+
Returns:
|
|
93
|
+
List[dict]: Descriptions and examples for supported commands.
|
|
94
|
+
"""
|
|
95
|
+
|
|
96
|
+
def example(command: str, **fields: Any) -> str:
|
|
97
|
+
payload = {"Command": command}
|
|
98
|
+
payload.update(fields)
|
|
99
|
+
return json.dumps(payload, sort_keys=True)
|
|
100
|
+
|
|
101
|
+
return [
|
|
102
|
+
{
|
|
103
|
+
"title": command_manager.CMD_JOIN,
|
|
104
|
+
"description": "Register your LXMF destination with the hub to receive replies.",
|
|
105
|
+
"example": example(command_manager.CMD_JOIN),
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
"title": command_manager.CMD_LEAVE,
|
|
109
|
+
"description": "Remove your destination from the hub's connection list.",
|
|
110
|
+
"example": example(command_manager.CMD_LEAVE),
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
"title": command_manager.CMD_LIST_CLIENTS,
|
|
114
|
+
"description": "List LXMF destinations currently joined to the hub.",
|
|
115
|
+
"example": example(command_manager.CMD_LIST_CLIENTS),
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
"title": command_manager.CMD_GET_APP_INFO,
|
|
119
|
+
"description": (
|
|
120
|
+
"Return the app name, version, and description from config.ini."
|
|
121
|
+
),
|
|
122
|
+
"example": example(command_manager.CMD_GET_APP_INFO),
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
"title": command_manager.CMD_LIST_FILES,
|
|
126
|
+
"description": (
|
|
127
|
+
"List stored file attachments saved on the hub. Tagged attachments include "
|
|
128
|
+
"a TopicID in the listing (set it via `TopicID`, `topic_id`, `topic`, or "
|
|
129
|
+
"`Topic`, or send `AssociateTopicID`)."
|
|
130
|
+
),
|
|
131
|
+
"example": example(command_manager.CMD_LIST_FILES),
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
"title": command_manager.CMD_LIST_IMAGES,
|
|
135
|
+
"description": (
|
|
136
|
+
"List stored image attachments saved on the hub. Tagged attachments include "
|
|
137
|
+
"a TopicID in the listing (set it via `TopicID`, `topic_id`, `topic`, or "
|
|
138
|
+
"`Topic`, or send `AssociateTopicID`)."
|
|
139
|
+
),
|
|
140
|
+
"example": example(command_manager.CMD_LIST_IMAGES),
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
"title": command_manager.CMD_LIST_TOPIC,
|
|
144
|
+
"description": "Display every registered topic and its ID.",
|
|
145
|
+
"example": example(command_manager.CMD_LIST_TOPIC),
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
"title": command_manager.CMD_CREATE_TOPIC,
|
|
149
|
+
"description": "Create a topic by providing a name and path.",
|
|
150
|
+
"example": example(
|
|
151
|
+
command_manager.CMD_CREATE_TOPIC,
|
|
152
|
+
TopicName="Weather",
|
|
153
|
+
TopicPath="environment/weather",
|
|
154
|
+
),
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
"title": command_manager.CMD_RETRIEVE_FILE,
|
|
158
|
+
"description": (
|
|
159
|
+
"Retrieve a stored file by FileID. The hub responds with metadata and "
|
|
160
|
+
"includes the file bytes in FIELD_FILE_ATTACHMENTS."
|
|
161
|
+
),
|
|
162
|
+
"example": example(command_manager.CMD_RETRIEVE_FILE, FileID="<FileID>"),
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
"title": command_manager.CMD_RETRIEVE_IMAGE,
|
|
166
|
+
"description": (
|
|
167
|
+
"Retrieve a stored image by FileID. The hub responds with metadata and "
|
|
168
|
+
"includes the image bytes in FIELD_IMAGE."
|
|
169
|
+
),
|
|
170
|
+
"example": example(command_manager.CMD_RETRIEVE_IMAGE, FileID="<FileID>"),
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
"title": command_manager.CMD_ASSOCIATE_TOPIC_ID,
|
|
174
|
+
"description": (
|
|
175
|
+
"Associate uploaded attachments with a TopicID. Accepted keys: `TopicID`, "
|
|
176
|
+
"`topic_id`, `topic`, or `Topic`."
|
|
177
|
+
),
|
|
178
|
+
"example": example(
|
|
179
|
+
command_manager.CMD_ASSOCIATE_TOPIC_ID, TopicID="weather"
|
|
180
|
+
),
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
"title": command_manager.CMD_RETRIEVE_TOPIC,
|
|
184
|
+
"description": "Fetch a specific topic by TopicID.",
|
|
185
|
+
"example": example(command_manager.CMD_RETRIEVE_TOPIC, TopicID="<TopicID>"),
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
"title": command_manager.CMD_DELETE_TOPIC,
|
|
189
|
+
"description": "Delete a topic (and unsubscribe listeners).",
|
|
190
|
+
"example": example(command_manager.CMD_DELETE_TOPIC, TopicID="<TopicID>"),
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
"title": command_manager.CMD_PATCH_TOPIC,
|
|
194
|
+
"description": "Update fields on a topic by TopicID.",
|
|
195
|
+
"example": example(
|
|
196
|
+
command_manager.CMD_PATCH_TOPIC,
|
|
197
|
+
TopicID="<TopicID>",
|
|
198
|
+
TopicDescription="New description",
|
|
199
|
+
),
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
"title": command_manager.CMD_SUBSCRIBE_TOPIC,
|
|
203
|
+
"description": "Subscribe the sending destination to a topic.",
|
|
204
|
+
"example": example(
|
|
205
|
+
command_manager.CMD_SUBSCRIBE_TOPIC,
|
|
206
|
+
TopicID="<TopicID>",
|
|
207
|
+
Metadata={"tag": "field-station"},
|
|
208
|
+
),
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
"title": command_manager.CMD_LIST_SUBSCRIBER,
|
|
212
|
+
"description": "List every subscriber registered with the hub.",
|
|
213
|
+
"example": example(command_manager.CMD_LIST_SUBSCRIBER),
|
|
214
|
+
},
|
|
215
|
+
{
|
|
216
|
+
"title": f"{command_manager.CMD_CREATE_SUBSCRIBER} / {command_manager.CMD_ADD_SUBSCRIBER}",
|
|
217
|
+
"description": "Create a subscriber entry for any destination.",
|
|
218
|
+
"example": example(
|
|
219
|
+
command_manager.CMD_CREATE_SUBSCRIBER,
|
|
220
|
+
Destination="<hex destination>",
|
|
221
|
+
TopicID="<TopicID>",
|
|
222
|
+
),
|
|
223
|
+
},
|
|
224
|
+
{
|
|
225
|
+
"title": command_manager.CMD_RETRIEVE_SUBSCRIBER,
|
|
226
|
+
"description": "Fetch subscriber metadata by SubscriberID.",
|
|
227
|
+
"example": example(
|
|
228
|
+
command_manager.CMD_RETRIEVE_SUBSCRIBER,
|
|
229
|
+
SubscriberID="<SubscriberID>",
|
|
230
|
+
),
|
|
231
|
+
},
|
|
232
|
+
{
|
|
233
|
+
"title": f"{command_manager.CMD_DELETE_SUBSCRIBER} / {command_manager.CMD_REMOVE_SUBSCRIBER}",
|
|
234
|
+
"description": "Remove a subscriber mapping.",
|
|
235
|
+
"example": example(
|
|
236
|
+
command_manager.CMD_DELETE_SUBSCRIBER,
|
|
237
|
+
SubscriberID="<SubscriberID>",
|
|
238
|
+
),
|
|
239
|
+
},
|
|
240
|
+
{
|
|
241
|
+
"title": command_manager.CMD_PATCH_SUBSCRIBER,
|
|
242
|
+
"description": "Update subscriber metadata by SubscriberID.",
|
|
243
|
+
"example": example(
|
|
244
|
+
command_manager.CMD_PATCH_SUBSCRIBER,
|
|
245
|
+
SubscriberID="<SubscriberID>",
|
|
246
|
+
Metadata={"tag": "updated"},
|
|
247
|
+
),
|
|
248
|
+
},
|
|
249
|
+
{
|
|
250
|
+
"title": command_manager.CMD_STATUS,
|
|
251
|
+
"description": "Return dashboard metrics and telemetry counts.",
|
|
252
|
+
"example": example(command_manager.CMD_STATUS),
|
|
253
|
+
},
|
|
254
|
+
{
|
|
255
|
+
"title": command_manager.CMD_LIST_EVENTS,
|
|
256
|
+
"description": "Return recent hub events for dashboards.",
|
|
257
|
+
"example": example(command_manager.CMD_LIST_EVENTS),
|
|
258
|
+
},
|
|
259
|
+
{
|
|
260
|
+
"title": command_manager.CMD_BAN_IDENTITY,
|
|
261
|
+
"description": "Ban an identity from the hub.",
|
|
262
|
+
"example": example(command_manager.CMD_BAN_IDENTITY, Identity="<IdentityHash>"),
|
|
263
|
+
},
|
|
264
|
+
{
|
|
265
|
+
"title": command_manager.CMD_UNBAN_IDENTITY,
|
|
266
|
+
"description": "Remove bans/blackholes for an identity.",
|
|
267
|
+
"example": example(command_manager.CMD_UNBAN_IDENTITY, Identity="<IdentityHash>"),
|
|
268
|
+
},
|
|
269
|
+
{
|
|
270
|
+
"title": command_manager.CMD_BLACKHOLE_IDENTITY,
|
|
271
|
+
"description": "Blackhole an identity for routing suppression.",
|
|
272
|
+
"example": example(
|
|
273
|
+
command_manager.CMD_BLACKHOLE_IDENTITY, Identity="<IdentityHash>"
|
|
274
|
+
),
|
|
275
|
+
},
|
|
276
|
+
{
|
|
277
|
+
"title": command_manager.CMD_LIST_IDENTITIES,
|
|
278
|
+
"description": "List identity moderation status entries.",
|
|
279
|
+
"example": example(command_manager.CMD_LIST_IDENTITIES),
|
|
280
|
+
},
|
|
281
|
+
{
|
|
282
|
+
"title": command_manager.CMD_GET_CONFIG,
|
|
283
|
+
"description": "Fetch the raw config.ini content.",
|
|
284
|
+
"example": example(command_manager.CMD_GET_CONFIG),
|
|
285
|
+
},
|
|
286
|
+
{
|
|
287
|
+
"title": command_manager.CMD_VALIDATE_CONFIG,
|
|
288
|
+
"description": "Validate config.ini payloads without applying.",
|
|
289
|
+
"example": example(
|
|
290
|
+
command_manager.CMD_VALIDATE_CONFIG, ConfigText="<ini content>"
|
|
291
|
+
),
|
|
292
|
+
},
|
|
293
|
+
{
|
|
294
|
+
"title": command_manager.CMD_APPLY_CONFIG,
|
|
295
|
+
"description": "Apply a new config.ini payload.",
|
|
296
|
+
"example": example(command_manager.CMD_APPLY_CONFIG, ConfigText="<ini content>"),
|
|
297
|
+
},
|
|
298
|
+
{
|
|
299
|
+
"title": command_manager.CMD_ROLLBACK_CONFIG,
|
|
300
|
+
"description": "Rollback configuration to the latest backup.",
|
|
301
|
+
"example": example(command_manager.CMD_ROLLBACK_CONFIG),
|
|
302
|
+
},
|
|
303
|
+
{
|
|
304
|
+
"title": command_manager.CMD_FLUSH_TELEMETRY,
|
|
305
|
+
"description": "Delete all stored telemetry snapshots.",
|
|
306
|
+
"example": example(command_manager.CMD_FLUSH_TELEMETRY),
|
|
307
|
+
},
|
|
308
|
+
{
|
|
309
|
+
"title": command_manager.CMD_RELOAD_CONFIG,
|
|
310
|
+
"description": "Reload config.ini from disk.",
|
|
311
|
+
"example": example(command_manager.CMD_RELOAD_CONFIG),
|
|
312
|
+
},
|
|
313
|
+
{
|
|
314
|
+
"title": command_manager.CMD_DUMP_ROUTING,
|
|
315
|
+
"description": "Return connected destinations.",
|
|
316
|
+
"example": example(command_manager.CMD_DUMP_ROUTING),
|
|
317
|
+
},
|
|
318
|
+
]
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
def format_topic_entry(index: int, topic: Topic) -> str:
|
|
322
|
+
"""Create a single line describing a topic entry."""
|
|
323
|
+
|
|
324
|
+
description = f" - {topic.topic_description}" if topic.topic_description else ""
|
|
325
|
+
topic_id = topic.topic_id or "<unassigned>"
|
|
326
|
+
return f"{index}. {topic.topic_name} [{topic.topic_path}] (ID: {topic_id}){description}"
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
def format_topic_list(topics: List[Topic]) -> List[str]:
|
|
330
|
+
"""Create a formatted list of topics suitable for LXMF reply bodies."""
|
|
331
|
+
|
|
332
|
+
if not topics:
|
|
333
|
+
return ["No topics registered yet."]
|
|
334
|
+
return [format_topic_entry(idx, topic) for idx, topic in enumerate(topics, start=1)]
|
|
335
|
+
|
|
336
|
+
|
|
337
|
+
def topic_subscribe_hint(subscribe_command: str) -> str:
|
|
338
|
+
"""Provide a subscription hint for help replies."""
|
|
339
|
+
|
|
340
|
+
example = json.dumps(
|
|
341
|
+
{"Command": subscribe_command, "TopicID": "<TopicID>"},
|
|
342
|
+
sort_keys=True,
|
|
343
|
+
)
|
|
344
|
+
return f"Send the command payload {example} to subscribe to a topic from the list above."
|
|
345
|
+
|
|
346
|
+
|
|
347
|
+
def format_subscriber_entry(index: int, subscriber: Subscriber) -> str:
|
|
348
|
+
"""Create a single line describing a subscriber entry."""
|
|
349
|
+
|
|
350
|
+
metadata = subscriber.metadata or {}
|
|
351
|
+
metadata_str = json.dumps(metadata, sort_keys=True)
|
|
352
|
+
topic_id = subscriber.topic_id or "<any>"
|
|
353
|
+
subscriber_id = subscriber.subscriber_id or "<pending>"
|
|
354
|
+
return (
|
|
355
|
+
f"{index}. {subscriber.destination} subscribed to {topic_id} "
|
|
356
|
+
f"(SubscriberID: {subscriber_id}) metadata={metadata_str}"
|
|
357
|
+
)
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
def format_subscriber_list(subscribers: List[Subscriber]) -> List[str]:
|
|
361
|
+
"""Create a formatted list of subscribers for LXMF replies."""
|
|
362
|
+
|
|
363
|
+
if not subscribers:
|
|
364
|
+
return ["No subscribers registered yet."]
|
|
365
|
+
return [
|
|
366
|
+
format_subscriber_entry(idx, subscriber)
|
|
367
|
+
for idx, subscriber in enumerate(subscribers, start=1)
|
|
368
|
+
]
|
|
369
|
+
|
|
370
|
+
|
|
371
|
+
def format_attachment_entry(index: int, attachment: FileAttachment) -> str:
|
|
372
|
+
"""Create a single line describing a stored file or image."""
|
|
373
|
+
|
|
374
|
+
category = attachment.category or "file"
|
|
375
|
+
attachment_id = attachment.file_id if attachment.file_id is not None else "<pending>"
|
|
376
|
+
media_suffix = f" ({attachment.media_type})" if attachment.media_type else ""
|
|
377
|
+
size_text = f", size={attachment.size} bytes" if attachment.size is not None else ""
|
|
378
|
+
topic_text = (
|
|
379
|
+
f", TopicID={attachment.topic_id}"
|
|
380
|
+
if attachment.topic_id is not None and attachment.topic_id != ""
|
|
381
|
+
else ""
|
|
382
|
+
)
|
|
383
|
+
return (
|
|
384
|
+
f"{index}. {attachment.name}{media_suffix} "
|
|
385
|
+
f"(ID: {attachment_id}, category={category}{size_text}{topic_text})"
|
|
386
|
+
)
|
|
387
|
+
|
|
388
|
+
|
|
389
|
+
def format_attachment_list(
|
|
390
|
+
attachments: List[FileAttachment], *, empty_text: str
|
|
391
|
+
) -> List[str]:
|
|
392
|
+
"""Create a formatted list of attachments for LXMF replies."""
|
|
393
|
+
|
|
394
|
+
if not attachments:
|
|
395
|
+
return [empty_text]
|
|
396
|
+
return [
|
|
397
|
+
format_attachment_entry(index, attachment)
|
|
398
|
+
for index, attachment in enumerate(attachments, start=1)
|
|
399
|
+
]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
PLUGIN_COMMAND = 0
|