plexus-python 0.7.0__py3-none-any.whl → 0.7.1__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.
- plexus/__init__.py +1 -1
- plexus/client.py +0 -14
- plexus/config.py +0 -48
- plexus/ws.py +1 -24
- {plexus_python-0.7.0.dist-info → plexus_python-0.7.1.dist-info}/METADATA +1 -1
- plexus_python-0.7.1.dist-info/RECORD +14 -0
- {plexus_python-0.7.0.dist-info → plexus_python-0.7.1.dist-info}/WHEEL +1 -1
- plexus_python-0.7.0.dist-info/RECORD +0 -14
- {plexus_python-0.7.0.dist-info → plexus_python-0.7.1.dist-info}/entry_points.txt +0 -0
- {plexus_python-0.7.0.dist-info → plexus_python-0.7.1.dist-info}/licenses/LICENSE +0 -0
plexus/__init__.py
CHANGED
|
@@ -10,5 +10,5 @@ Plexus — thin Python SDK for sending telemetry to the Plexus gateway.
|
|
|
10
10
|
from plexus.client import Plexus, PlexusError, AuthenticationError, read_mjpeg_frames
|
|
11
11
|
from plexus.config import RetryConfig
|
|
12
12
|
|
|
13
|
-
__version__ = "0.7.
|
|
13
|
+
__version__ = "0.7.1"
|
|
14
14
|
__all__ = ["Plexus", "PlexusError", "AuthenticationError", "RetryConfig", "read_mjpeg_frames"]
|
plexus/client.py
CHANGED
|
@@ -55,9 +55,7 @@ from plexus.config import (
|
|
|
55
55
|
get_endpoint,
|
|
56
56
|
get_gateway_url,
|
|
57
57
|
get_gateway_ws_url,
|
|
58
|
-
get_install_id,
|
|
59
58
|
get_source_id,
|
|
60
|
-
set_source_id,
|
|
61
59
|
)
|
|
62
60
|
|
|
63
61
|
logger = logging.getLogger(__name__)
|
|
@@ -414,9 +412,7 @@ class Plexus:
|
|
|
414
412
|
api_key=self.api_key,
|
|
415
413
|
source_id=self.source_id,
|
|
416
414
|
ws_url=self._ws_url,
|
|
417
|
-
install_id=get_install_id(),
|
|
418
415
|
agent_version=__version__,
|
|
419
|
-
on_source_id_assigned=self._on_source_id_assigned,
|
|
420
416
|
on_clock_synced=self._on_clock_synced,
|
|
421
417
|
)
|
|
422
418
|
self._ws.start()
|
|
@@ -428,16 +424,6 @@ class Plexus:
|
|
|
428
424
|
def _on_clock_synced(self, offset_ms: int) -> None:
|
|
429
425
|
self._clock_offset_ms = offset_ms
|
|
430
426
|
|
|
431
|
-
def _on_source_id_assigned(self, assigned: str) -> None:
|
|
432
|
-
"""Callback from WebSocketTransport when the gateway returns an
|
|
433
|
-
auto-suffixed source_id. Persists it so subsequent runs (and the HTTP
|
|
434
|
-
fallback path in this process) use the assigned name directly."""
|
|
435
|
-
self.source_id = assigned
|
|
436
|
-
try:
|
|
437
|
-
set_source_id(assigned)
|
|
438
|
-
except Exception as e: # pragma: no cover - persistence failure is non-fatal
|
|
439
|
-
logger.debug("failed to persist assigned source_id: %s", e)
|
|
440
|
-
|
|
441
427
|
def _encode_frame(self, frame, quality: int) -> Tuple[bytes, int, int]:
|
|
442
428
|
"""Normalize any supported frame type to (jpeg_bytes, width, height).
|
|
443
429
|
|
plexus/config.py
CHANGED
|
@@ -145,54 +145,6 @@ def get_source_id() -> Optional[str]:
|
|
|
145
145
|
return source_id
|
|
146
146
|
|
|
147
147
|
|
|
148
|
-
def get_install_id() -> str:
|
|
149
|
-
"""Get the device install ID, generating one if not set.
|
|
150
|
-
|
|
151
|
-
The install_id is a stable per-installation UUID. It is generated lazily
|
|
152
|
-
on first run (NOT at image-build time) so that cloned SD-card images
|
|
153
|
-
naturally get distinct install_ids on their first boot. The gateway uses
|
|
154
|
-
it to tell "same device reconnecting" from "different device claiming the
|
|
155
|
-
same name" when resolving source_id collisions.
|
|
156
|
-
|
|
157
|
-
Resolution order:
|
|
158
|
-
1. ``PLEXUS_INSTALL_ID`` env var — lets ephemeral containers (Fly
|
|
159
|
-
machines, CI runners, Kubernetes pods) pin a stable identity
|
|
160
|
-
across restarts when the config filesystem is ephemeral. Without
|
|
161
|
-
this, every redeploy generates a new install_id and the gateway
|
|
162
|
-
auto-suffixes the source_id to avoid a collision with the prior
|
|
163
|
-
install ("gw-001" → "gw-001_2" → "gw-001_3"…).
|
|
164
|
-
2. ``install_id`` in the on-disk config.
|
|
165
|
-
3. Newly-generated UUID, persisted to config.
|
|
166
|
-
"""
|
|
167
|
-
env_id = os.environ.get("PLEXUS_INSTALL_ID", "").strip()
|
|
168
|
-
if env_id:
|
|
169
|
-
return env_id
|
|
170
|
-
|
|
171
|
-
config = load_config()
|
|
172
|
-
install_id = config.get("install_id")
|
|
173
|
-
|
|
174
|
-
if not install_id:
|
|
175
|
-
import uuid
|
|
176
|
-
install_id = uuid.uuid4().hex
|
|
177
|
-
config["install_id"] = install_id
|
|
178
|
-
save_config(config)
|
|
179
|
-
|
|
180
|
-
return install_id
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
def set_source_id(source_id: str) -> None:
|
|
184
|
-
"""Persist an updated source_id to the config file.
|
|
185
|
-
|
|
186
|
-
Called by the SDK when the gateway returns an auto-suffixed name so the
|
|
187
|
-
assigned name is stable across reconnects.
|
|
188
|
-
"""
|
|
189
|
-
config = load_config()
|
|
190
|
-
if config.get("source_id") == source_id:
|
|
191
|
-
return
|
|
192
|
-
config["source_id"] = source_id
|
|
193
|
-
save_config(config)
|
|
194
|
-
|
|
195
|
-
|
|
196
148
|
def get_persistent_buffer() -> bool:
|
|
197
149
|
"""Get persistent buffer setting. Default True (store-and-forward enabled)."""
|
|
198
150
|
config = load_config()
|
plexus/ws.py
CHANGED
|
@@ -89,11 +89,9 @@ class WebSocketTransport:
|
|
|
89
89
|
source_id: str,
|
|
90
90
|
ws_url: str,
|
|
91
91
|
*,
|
|
92
|
-
install_id: str = "",
|
|
93
92
|
agent_version: str = "0.0.0",
|
|
94
93
|
platform: str = "python-sdk",
|
|
95
94
|
auto_reconnect: bool = True,
|
|
96
|
-
on_source_id_assigned: Optional[Callable[[str], None]] = None,
|
|
97
95
|
on_clock_synced: Optional[Callable[[int], None]] = None,
|
|
98
96
|
):
|
|
99
97
|
if not api_key:
|
|
@@ -103,12 +101,10 @@ class WebSocketTransport:
|
|
|
103
101
|
|
|
104
102
|
self.api_key = api_key
|
|
105
103
|
self.source_id = source_id
|
|
106
|
-
self.install_id = install_id
|
|
107
104
|
self.ws_url = _ensure_device_path(ws_url)
|
|
108
105
|
self.agent_version = agent_version
|
|
109
106
|
self.platform = platform
|
|
110
107
|
self.auto_reconnect = auto_reconnect
|
|
111
|
-
self._on_source_id_assigned = on_source_id_assigned
|
|
112
108
|
self._on_clock_synced = on_clock_synced
|
|
113
109
|
|
|
114
110
|
self._commands: Dict[str, _RegisteredCommand] = {}
|
|
@@ -278,16 +274,13 @@ class WebSocketTransport:
|
|
|
278
274
|
self._ws = ws
|
|
279
275
|
|
|
280
276
|
# 1. Send device_auth
|
|
281
|
-
desired_source_id = self.source_id
|
|
282
277
|
auth = {
|
|
283
278
|
"type": "device_auth",
|
|
284
279
|
"api_key": self.api_key,
|
|
285
|
-
"source_id":
|
|
280
|
+
"source_id": self.source_id,
|
|
286
281
|
"platform": self.platform,
|
|
287
282
|
"agent_version": self.agent_version,
|
|
288
283
|
}
|
|
289
|
-
if self.install_id:
|
|
290
|
-
auth["install_id"] = self.install_id
|
|
291
284
|
if self._commands:
|
|
292
285
|
auth["commands"] = [c.to_manifest() for c in self._commands.values()]
|
|
293
286
|
ws.send(json.dumps(auth))
|
|
@@ -312,22 +305,6 @@ class WebSocketTransport:
|
|
|
312
305
|
except Exception as e:
|
|
313
306
|
logger.debug("on_clock_synced callback raised: %s", e)
|
|
314
307
|
|
|
315
|
-
# The gateway may return a different source_id if the desired name
|
|
316
|
-
# was already claimed by another install — adopt the assigned value
|
|
317
|
-
# so all subsequent frames (heartbeats, future reconnects) use it.
|
|
318
|
-
assigned = msg.get("source_id")
|
|
319
|
-
if isinstance(assigned, str) and assigned and assigned != self.source_id:
|
|
320
|
-
logger.info(
|
|
321
|
-
"plexus ws source_id auto-suffixed: requested=%s assigned=%s",
|
|
322
|
-
desired_source_id, assigned,
|
|
323
|
-
)
|
|
324
|
-
self.source_id = assigned
|
|
325
|
-
if self._on_source_id_assigned is not None:
|
|
326
|
-
try:
|
|
327
|
-
self._on_source_id_assigned(assigned)
|
|
328
|
-
except Exception as e: # pragma: no cover - callback errors must not break auth
|
|
329
|
-
logger.debug("on_source_id_assigned callback raised: %s", e)
|
|
330
|
-
|
|
331
308
|
was_reconnect = self._backoff_attempt > 0
|
|
332
309
|
self._authenticated.set()
|
|
333
310
|
self._backoff_attempt = 0
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
plexus/__init__.py,sha256=ZzZDGRCztNWGUtN-YF1EwwYzngxsZkU9zb_rW1Tfalg,447
|
|
2
|
+
plexus/_log.py,sha256=3fjXrHFZghQ_17umMcvDUjjTH6aTQB3J4SpVDBiH03w,335
|
|
3
|
+
plexus/buffer.py,sha256=0i6PLgoj904jFNv9RCrlskvPQsPSu_KNdYWMasFOvsg,9596
|
|
4
|
+
plexus/cli.py,sha256=-2wvHXQzobx3_tDGTXpaE2PlHv884y93Mu29kZE8qZE,14214
|
|
5
|
+
plexus/client.py,sha256=SZ4V9FN-bt3QKqVgp9S5QKdRXw934WXZxKlYUb7bWHw,35810
|
|
6
|
+
plexus/config.py,sha256=RNym2Fon6JOCVi1rXPSRWjPFAdT8DSmokY5JPEljQOc,4450
|
|
7
|
+
plexus/ws.py,sha256=9DiQchqCQU7O8r8-FuqotJh8vYAQBO7npJn4BFNzLAE,16242
|
|
8
|
+
plexus/cameras/__init__.py,sha256=OvnU9KGKxkVtFLlk56H9x-ATa6UvpLI7PANa0HQO2cc,490
|
|
9
|
+
plexus/cameras/thermal.py,sha256=7o33QsF1RiZLManTxZ2E36nO8lRAHppCDkS3zXBHCxs,12047
|
|
10
|
+
plexus_python-0.7.1.dist-info/METADATA,sha256=OUDqqIIcHUaZms1QCwL7XdaFo6j11LeN0HZ3EipZEIM,11739
|
|
11
|
+
plexus_python-0.7.1.dist-info/WHEEL,sha256=mffPy8wBnZQn2VnJUU5jE99KsxaSfiyMHV9Yt0aLVxs,87
|
|
12
|
+
plexus_python-0.7.1.dist-info/entry_points.txt,sha256=YlkOtTn_7Q_IGuJaKdvpU-90dCeBSPx2p_UTGMAz5Zs,43
|
|
13
|
+
plexus_python-0.7.1.dist-info/licenses/LICENSE,sha256=nm3qP1F-JAGcfLpRVtIX24L20LMnRpxmZ2oKZzFpLVo,10755
|
|
14
|
+
plexus_python-0.7.1.dist-info/RECORD,,
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
plexus/__init__.py,sha256=HNRVhpDrkyyT-SQqfFzNf3E_uwbwQA-XcDKPoBytdEo,447
|
|
2
|
-
plexus/_log.py,sha256=3fjXrHFZghQ_17umMcvDUjjTH6aTQB3J4SpVDBiH03w,335
|
|
3
|
-
plexus/buffer.py,sha256=0i6PLgoj904jFNv9RCrlskvPQsPSu_KNdYWMasFOvsg,9596
|
|
4
|
-
plexus/cli.py,sha256=-2wvHXQzobx3_tDGTXpaE2PlHv884y93Mu29kZE8qZE,14214
|
|
5
|
-
plexus/client.py,sha256=DaCPURIhVswwjf4oGrp381Atiy02gk3viLy6NioBAtQ,36480
|
|
6
|
-
plexus/config.py,sha256=wsG6lhNLmKe3JRlVycyRUKQeywnPUPPfrWkXFxYwELE,6179
|
|
7
|
-
plexus/ws.py,sha256=_c--U-yySZbMXZsaj0fUaYKF_WesolHsrMDx4oWYfFQ,17428
|
|
8
|
-
plexus/cameras/__init__.py,sha256=OvnU9KGKxkVtFLlk56H9x-ATa6UvpLI7PANa0HQO2cc,490
|
|
9
|
-
plexus/cameras/thermal.py,sha256=7o33QsF1RiZLManTxZ2E36nO8lRAHppCDkS3zXBHCxs,12047
|
|
10
|
-
plexus_python-0.7.0.dist-info/METADATA,sha256=tlsktssdsOI7dyA7O2I6azPay2Xj998Z4zNxbFf4H6s,11739
|
|
11
|
-
plexus_python-0.7.0.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
|
|
12
|
-
plexus_python-0.7.0.dist-info/entry_points.txt,sha256=YlkOtTn_7Q_IGuJaKdvpU-90dCeBSPx2p_UTGMAz5Zs,43
|
|
13
|
-
plexus_python-0.7.0.dist-info/licenses/LICENSE,sha256=nm3qP1F-JAGcfLpRVtIX24L20LMnRpxmZ2oKZzFpLVo,10755
|
|
14
|
-
plexus_python-0.7.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|