phystack-hub-client 0.2.3__tar.gz → 0.2.5__tar.gz

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.
Files changed (24) hide show
  1. {phystack_hub_client-0.2.3 → phystack_hub_client-0.2.5}/PKG-INFO +1 -1
  2. {phystack_hub_client-0.2.3 → phystack_hub_client-0.2.5}/pyproject.toml +1 -1
  3. {phystack_hub_client-0.2.3 → phystack_hub_client-0.2.5}/src/phystack/hub_client/__init__.py +8 -1
  4. {phystack_hub_client-0.2.3 → phystack_hub_client-0.2.5}/src/phystack/hub_client/client.py +17 -4
  5. {phystack_hub_client-0.2.3 → phystack_hub_client-0.2.5}/src/phystack/hub_client/twin_messaging.py +12 -4
  6. {phystack_hub_client-0.2.3 → phystack_hub_client-0.2.5}/.gitignore +0 -0
  7. {phystack_hub_client-0.2.3 → phystack_hub_client-0.2.5}/README.md +0 -0
  8. {phystack_hub_client-0.2.3 → phystack_hub_client-0.2.5}/examples/browser_test_backend.py +0 -0
  9. {phystack_hub_client-0.2.3 → phystack_hub_client-0.2.5}/scripts/python-node-test.sh +0 -0
  10. {phystack_hub_client-0.2.3 → phystack_hub_client-0.2.5}/scripts/webrtc-test.sh +0 -0
  11. {phystack_hub_client-0.2.3 → phystack_hub_client-0.2.5}/src/phystack/hub_client/instances/__init__.py +0 -0
  12. {phystack_hub_client-0.2.3 → phystack_hub_client-0.2.5}/src/phystack/hub_client/instances/base_instance.py +0 -0
  13. {phystack_hub_client-0.2.3 → phystack_hub_client-0.2.5}/src/phystack/hub_client/instances/edge_instance.py +0 -0
  14. {phystack_hub_client-0.2.3 → phystack_hub_client-0.2.5}/src/phystack/hub_client/instances/peripheral_instance.py +0 -0
  15. {phystack_hub_client-0.2.3 → phystack_hub_client-0.2.5}/src/phystack/hub_client/services/__init__.py +0 -0
  16. {phystack_hub_client-0.2.3 → phystack_hub_client-0.2.5}/src/phystack/hub_client/services/phyhub_connection.py +0 -0
  17. {phystack_hub_client-0.2.3 → phystack_hub_client-0.2.5}/src/phystack/hub_client/services/signals.py +0 -0
  18. {phystack_hub_client-0.2.3 → phystack_hub_client-0.2.5}/src/phystack/hub_client/services/webrtc/__init__.py +0 -0
  19. {phystack_hub_client-0.2.3 → phystack_hub_client-0.2.5}/src/phystack/hub_client/services/webrtc/data_channel.py +0 -0
  20. {phystack_hub_client-0.2.3 → phystack_hub_client-0.2.5}/src/phystack/hub_client/services/webrtc/media_stream.py +0 -0
  21. {phystack_hub_client-0.2.3 → phystack_hub_client-0.2.5}/src/phystack/hub_client/twin_registry.py +0 -0
  22. {phystack_hub_client-0.2.3 → phystack_hub_client-0.2.5}/src/phystack/hub_client/types/__init__.py +0 -0
  23. {phystack_hub_client-0.2.3 → phystack_hub_client-0.2.5}/src/phystack/hub_client/types/twin_types.py +0 -0
  24. {phystack_hub_client-0.2.3 → phystack_hub_client-0.2.5}/tests/test_communication.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: phystack-hub-client
3
- Version: 0.2.3
3
+ Version: 0.2.5
4
4
  Summary: Python client for PhyHub - events, actions, DataChannel, and MediaStream
5
5
  Project-URL: Homepage, https://github.com/phystack/phystack-pypi
6
6
  Project-URL: Documentation, https://docs.phystack.com
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "phystack-hub-client"
7
- version = "0.2.3"
7
+ version = "0.2.5"
8
8
  description = "Python client for PhyHub - events, actions, DataChannel, and MediaStream"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -10,6 +10,12 @@ A Python client for PhyHub that provides:
10
10
  - Settings API
11
11
 
12
12
  Usage:
13
+ from phystack.hub_client import connect_phy_client
14
+
15
+ client = await connect_phy_client()
16
+ instance = await client.get_instance()
17
+
18
+ Or with context manager:
13
19
  from phystack.hub_client import PhyHubClient
14
20
 
15
21
  async with PhyHubClient.from_env() as client:
@@ -38,7 +44,7 @@ Usage:
38
44
  stream = await instance.get_media_stream(peer_twin_id)
39
45
  """
40
46
 
41
- from phystack.hub_client.client import PhyHubClient
47
+ from phystack.hub_client.client import PhyHubClient, connect_phy_client
42
48
  from phystack.hub_client.types.twin_types import (
43
49
  TwinMessageResult,
44
50
  TwinMessageResultStatus,
@@ -78,6 +84,7 @@ __version__ = "0.1.0"
78
84
  __all__ = [
79
85
  # Client
80
86
  "PhyHubClient",
87
+ "connect_phy_client",
81
88
  # Instances
82
89
  "BaseInstance",
83
90
  "EdgeInstance",
@@ -414,10 +414,10 @@ class PhyHubClient:
414
414
  "sourceDeviceId": self._connection.device_id,
415
415
  }
416
416
 
417
- # Fire-and-forget subscription using unified emit
418
- asyncio.create_task(self._emit_to_socket(self.EVENTS.TWIN_SUBSCRIBE, payload))
419
-
420
- return {"status": "success", "message": "Subscribed"}
417
+ # Send subscription request with ack (matches Node.js behavior)
418
+ return await self._emit_to_socket(
419
+ self.EVENTS.TWIN_SUBSCRIBE, payload, callback=True
420
+ )
421
421
 
422
422
  async def get_twin_by_id(self, twin_id: str) -> Optional[dict[str, Any]]:
423
423
  """Get twin data by ID.
@@ -797,3 +797,16 @@ class PhyHubClient:
797
797
  async def __aexit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
798
798
  """Async context manager exit."""
799
799
  await self.disconnect()
800
+
801
+
802
+ async def connect_phy_client() -> PhyHubClient:
803
+ """Connect to PhyHub in one call (matches Node.js connectPhyClient).
804
+
805
+ Reads connection config from environment variables and connects.
806
+
807
+ Returns:
808
+ Connected PhyHubClient instance.
809
+ """
810
+ client = PhyHubClient.from_env()
811
+ await client.connect()
812
+ return client
@@ -12,6 +12,7 @@ API Design:
12
12
  """
13
13
 
14
14
  import asyncio
15
+ import re
15
16
  import time
16
17
  import random
17
18
  import string
@@ -23,6 +24,15 @@ from phystack.hub_client.types.twin_types import TwinMessageResult, TwinMessageR
23
24
 
24
25
  REQUEST_TIMEOUT = 10.0 # seconds
25
26
 
27
+ # Backward compatibility: strip known type prefixes to extract bare event type.
28
+ # Matches Node.js hub-client behavior for cross-approach communication.
29
+ _KNOWN_PREFIX_PATTERN = re.compile(r"^(edgeInstance|peripheralInstance:[^:]+):")
30
+
31
+
32
+ def _strip_type_prefix(message_type: str) -> str:
33
+ """Strip known type prefix to get bare event type (matches Node.js)."""
34
+ return _KNOWN_PREFIX_PATTERN.sub("", message_type)
35
+
26
36
 
27
37
  @dataclass
28
38
  class PendingRequest:
@@ -177,7 +187,7 @@ class TwinMessaging:
177
187
 
178
188
  def handle_response(payload: dict[str, Any]) -> None:
179
189
  message_type = (payload.get("data") or {}).get("type") or payload.get("type")
180
- if message_type == f"{self._context.type_prefix}:response":
190
+ if _strip_type_prefix(message_type) == "response":
181
191
  response_data = (payload.get("data") or {}).get("data") or payload.get("data")
182
192
  request_id = (response_data or {}).get("requestId")
183
193
 
@@ -220,12 +230,10 @@ class TwinMessaging:
220
230
  event_type: Type of event to listen for.
221
231
  callback: Handler function (data, respond?) => None
222
232
  """
223
- expected_type = f"{self._context.type_prefix}:{event_type}"
224
-
225
233
  def handler(payload: dict[str, Any]) -> None:
226
234
  message_type = (payload.get("data") or {}).get("type") or payload.get("type")
227
235
 
228
- if message_type == expected_type:
236
+ if _strip_type_prefix(message_type) == event_type:
229
237
  message_data = (payload.get("data") or {}).get("data") or payload.get("data")
230
238
  request_id = (message_data or {}).get("requestId") if message_data else None
231
239
  source_twin_id = payload.get("sourceTwinId")