sockudo-http-python 2.0.0__tar.gz → 2.1.0__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.
- {sockudo_http_python-2.0.0/src/sockudo_http_python.egg-info → sockudo_http_python-2.1.0}/PKG-INFO +2 -9
- {sockudo_http_python-2.0.0 → sockudo_http_python-2.1.0}/README.md +1 -8
- {sockudo_http_python-2.0.0 → sockudo_http_python-2.1.0}/pyproject.toml +1 -1
- {sockudo_http_python-2.0.0 → sockudo_http_python-2.1.0}/src/sockudo_http_python/client.py +26 -2
- {sockudo_http_python-2.0.0 → sockudo_http_python-2.1.0/src/sockudo_http_python.egg-info}/PKG-INFO +2 -9
- {sockudo_http_python-2.0.0 → sockudo_http_python-2.1.0}/tests/test_client.py +71 -0
- {sockudo_http_python-2.0.0 → sockudo_http_python-2.1.0}/LICENSE +0 -0
- {sockudo_http_python-2.0.0 → sockudo_http_python-2.1.0}/setup.cfg +0 -0
- {sockudo_http_python-2.0.0 → sockudo_http_python-2.1.0}/src/sockudo_http/__init__.py +0 -0
- {sockudo_http_python-2.0.0 → sockudo_http_python-2.1.0}/src/sockudo_http_python/__init__.py +0 -0
- {sockudo_http_python-2.0.0 → sockudo_http_python-2.1.0}/src/sockudo_http_python.egg-info/SOURCES.txt +0 -0
- {sockudo_http_python-2.0.0 → sockudo_http_python-2.1.0}/src/sockudo_http_python.egg-info/dependency_links.txt +0 -0
- {sockudo_http_python-2.0.0 → sockudo_http_python-2.1.0}/src/sockudo_http_python.egg-info/requires.txt +0 -0
- {sockudo_http_python-2.0.0 → sockudo_http_python-2.1.0}/src/sockudo_http_python.egg-info/top_level.txt +0 -0
{sockudo_http_python-2.0.0/src/sockudo_http_python.egg-info → sockudo_http_python-2.1.0}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sockudo-http-python
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.1.0
|
|
4
4
|
Summary: High-performance Python HTTP server SDK for Sockudo
|
|
5
5
|
Author: Sockudo
|
|
6
6
|
License-Expression: MIT
|
|
@@ -46,14 +46,7 @@ For apps, install the published package:
|
|
|
46
46
|
pip install sockudo-http-python
|
|
47
47
|
```
|
|
48
48
|
|
|
49
|
-
For
|
|
50
|
-
|
|
51
|
-
```bash
|
|
52
|
-
git clone https://github.com/sockudo/sockudo.git
|
|
53
|
-
pip install -e sockudo/server-sdks/sockudo-http-python
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
For local development from this monorepo:
|
|
49
|
+
For contributors working inside this repository:
|
|
57
50
|
|
|
58
51
|
```bash
|
|
59
52
|
pip install -e server-sdks/sockudo-http-python[dev]
|
|
@@ -24,14 +24,7 @@ For apps, install the published package:
|
|
|
24
24
|
pip install sockudo-http-python
|
|
25
25
|
```
|
|
26
26
|
|
|
27
|
-
For
|
|
28
|
-
|
|
29
|
-
```bash
|
|
30
|
-
git clone https://github.com/sockudo/sockudo.git
|
|
31
|
-
pip install -e sockudo/server-sdks/sockudo-http-python
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
For local development from this monorepo:
|
|
27
|
+
For contributors working inside this repository:
|
|
35
28
|
|
|
36
29
|
```bash
|
|
37
30
|
pip install -e server-sdks/sockudo-http-python[dev]
|
|
@@ -387,6 +387,19 @@ class WebhookEvent:
|
|
|
387
387
|
data: Optional[Any] = None
|
|
388
388
|
socket_id: Optional[str] = None
|
|
389
389
|
user_id: Optional[str] = None
|
|
390
|
+
raw: Mapping[str, Any] = field(default_factory=dict)
|
|
391
|
+
|
|
392
|
+
@staticmethod
|
|
393
|
+
def from_payload(payload: Mapping[str, Any]) -> "WebhookEvent":
|
|
394
|
+
return WebhookEvent(
|
|
395
|
+
name=_optional_string(payload.get("name")) or "",
|
|
396
|
+
channel=_optional_string(payload.get("channel")),
|
|
397
|
+
event=_optional_string(payload.get("event")),
|
|
398
|
+
data=payload.get("data"),
|
|
399
|
+
socket_id=_optional_string(payload.get("socket_id")),
|
|
400
|
+
user_id=_optional_string(payload.get("user_id")),
|
|
401
|
+
raw=dict(payload),
|
|
402
|
+
)
|
|
390
403
|
|
|
391
404
|
|
|
392
405
|
@dataclass(frozen=True)
|
|
@@ -398,7 +411,11 @@ class Webhook:
|
|
|
398
411
|
def parse(body: Union[str, bytes]) -> "Webhook":
|
|
399
412
|
text = body.decode("utf-8") if isinstance(body, bytes) else body
|
|
400
413
|
raw = json.loads(text)
|
|
401
|
-
events = tuple(
|
|
414
|
+
events = tuple(
|
|
415
|
+
WebhookEvent.from_payload(event)
|
|
416
|
+
for event in raw.get("events", [])
|
|
417
|
+
if isinstance(event, Mapping)
|
|
418
|
+
)
|
|
402
419
|
return Webhook(time_ms=raw.get("time_ms"), events=events)
|
|
403
420
|
|
|
404
421
|
|
|
@@ -702,13 +719,16 @@ class _BaseSockudo:
|
|
|
702
719
|
nacl_exceptions.CryptoError,
|
|
703
720
|
) as exc:
|
|
704
721
|
raise SockudoError("Failed to decrypt encrypted webhook event") from exc
|
|
722
|
+
raw = dict(event.raw)
|
|
723
|
+
raw["data"] = plaintext.decode("utf-8")
|
|
705
724
|
return WebhookEvent(
|
|
706
725
|
name=event.name,
|
|
707
726
|
channel=event.channel,
|
|
708
727
|
event=event.event,
|
|
709
|
-
data=
|
|
728
|
+
data=raw["data"],
|
|
710
729
|
socket_id=event.socket_id,
|
|
711
730
|
user_id=event.user_id,
|
|
731
|
+
raw=raw,
|
|
712
732
|
)
|
|
713
733
|
|
|
714
734
|
def _serialize(self, payload: Mapping[str, Any]) -> str:
|
|
@@ -1744,6 +1764,10 @@ def _clean_raw(values: Mapping[str, Any]) -> JsonDict:
|
|
|
1744
1764
|
return {key: value for key, value in values.items() if value is not None}
|
|
1745
1765
|
|
|
1746
1766
|
|
|
1767
|
+
def _optional_string(value: Any) -> Optional[str]:
|
|
1768
|
+
return value if isinstance(value, str) else None
|
|
1769
|
+
|
|
1770
|
+
|
|
1747
1771
|
def _clean_query(values: Mapping[str, Any]) -> Dict[str, str]:
|
|
1748
1772
|
return {key: str(value) for key, value in values.items() if value is not None}
|
|
1749
1773
|
|
{sockudo_http_python-2.0.0 → sockudo_http_python-2.1.0/src/sockudo_http_python.egg-info}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sockudo-http-python
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.1.0
|
|
4
4
|
Summary: High-performance Python HTTP server SDK for Sockudo
|
|
5
5
|
Author: Sockudo
|
|
6
6
|
License-Expression: MIT
|
|
@@ -46,14 +46,7 @@ For apps, install the published package:
|
|
|
46
46
|
pip install sockudo-http-python
|
|
47
47
|
```
|
|
48
48
|
|
|
49
|
-
For
|
|
50
|
-
|
|
51
|
-
```bash
|
|
52
|
-
git clone https://github.com/sockudo/sockudo.git
|
|
53
|
-
pip install -e sockudo/server-sdks/sockudo-http-python
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
For local development from this monorepo:
|
|
49
|
+
For contributors working inside this repository:
|
|
57
50
|
|
|
58
51
|
```bash
|
|
59
52
|
pip install -e server-sdks/sockudo-http-python[dev]
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import json
|
|
2
2
|
import base64
|
|
3
3
|
import hashlib
|
|
4
|
+
from pathlib import Path
|
|
4
5
|
from urllib.parse import parse_qs, urlparse
|
|
5
6
|
|
|
6
7
|
import httpx
|
|
@@ -23,6 +24,7 @@ from sockudo_http_python import (
|
|
|
23
24
|
Status,
|
|
24
25
|
TriggerOptions,
|
|
25
26
|
Validity,
|
|
27
|
+
Webhook,
|
|
26
28
|
sign,
|
|
27
29
|
)
|
|
28
30
|
|
|
@@ -42,6 +44,16 @@ def make_client(handler):
|
|
|
42
44
|
)
|
|
43
45
|
|
|
44
46
|
|
|
47
|
+
def load_forward_fixture(name):
|
|
48
|
+
for parent in Path(__file__).resolve().parents:
|
|
49
|
+
candidate = (
|
|
50
|
+
parent / "tests" / "ai-conformance" / "fixtures" / "forward-compat" / name
|
|
51
|
+
)
|
|
52
|
+
if candidate.exists():
|
|
53
|
+
return candidate.read_text(encoding="utf-8")
|
|
54
|
+
raise AssertionError(f"forward-compat fixture not found: {name}")
|
|
55
|
+
|
|
56
|
+
|
|
45
57
|
def test_signed_uri_contains_expected_signature_params():
|
|
46
58
|
sockudo = Sockudo(
|
|
47
59
|
"app-id", "key", "secret", options=SockudoOptions(host="localhost", port=6001)
|
|
@@ -60,6 +72,65 @@ def test_signed_uri_contains_expected_signature_params():
|
|
|
60
72
|
sockudo.close()
|
|
61
73
|
|
|
62
74
|
|
|
75
|
+
def test_webhook_accepts_future_event_fixture_and_preserves_unknown_fields():
|
|
76
|
+
body = load_forward_fixture("future-webhook-events.json")
|
|
77
|
+
sockudo = Sockudo(
|
|
78
|
+
"app-id", "app-key", "app-secret", options=SockudoOptions(max_retries=1)
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
webhook = sockudo.parse_webhook("app-key", sign(body, "app-secret"), body)
|
|
82
|
+
|
|
83
|
+
assert webhook.time_ms == 1710000000000
|
|
84
|
+
assert [event.name for event in webhook.events] == [
|
|
85
|
+
"member_updated",
|
|
86
|
+
"ai_turn_started",
|
|
87
|
+
"message_version_created",
|
|
88
|
+
]
|
|
89
|
+
assert webhook.events[0].channel == "presence-ai-forward"
|
|
90
|
+
assert webhook.events[0].user_id == "user-1"
|
|
91
|
+
assert webhook.events[0].raw["future_field"] == "must-pass-through"
|
|
92
|
+
assert webhook.events[1].raw["turn_id"] == "turn-1"
|
|
93
|
+
assert Webhook.parse(body).events[2].raw["version_serial"] == "ver-1"
|
|
94
|
+
sockudo.close()
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def test_webhook_preserves_nested_future_event_values():
|
|
98
|
+
body = json.dumps(
|
|
99
|
+
{
|
|
100
|
+
"time_ms": 1710000000000,
|
|
101
|
+
"events": [
|
|
102
|
+
{
|
|
103
|
+
"name": "ai_turn_started",
|
|
104
|
+
"channel": "private-ai-forward",
|
|
105
|
+
"data": {
|
|
106
|
+
"turn_id": "turn-1",
|
|
107
|
+
"tokens": ["hello", "world"],
|
|
108
|
+
"done": False,
|
|
109
|
+
"nullable": None,
|
|
110
|
+
},
|
|
111
|
+
"future_field": {"nested": True},
|
|
112
|
+
}
|
|
113
|
+
],
|
|
114
|
+
},
|
|
115
|
+
separators=(",", ":"),
|
|
116
|
+
)
|
|
117
|
+
sockudo = Sockudo(
|
|
118
|
+
"app-id", "app-key", "app-secret", options=SockudoOptions(max_retries=1)
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
webhook = sockudo.parse_webhook("app-key", sign(body, "app-secret"), body)
|
|
122
|
+
|
|
123
|
+
assert webhook.events[0].name == "ai_turn_started"
|
|
124
|
+
assert webhook.events[0].data == {
|
|
125
|
+
"turn_id": "turn-1",
|
|
126
|
+
"tokens": ["hello", "world"],
|
|
127
|
+
"done": False,
|
|
128
|
+
"nullable": None,
|
|
129
|
+
}
|
|
130
|
+
assert webhook.events[0].raw["future_field"] == {"nested": True}
|
|
131
|
+
sockudo.close()
|
|
132
|
+
|
|
133
|
+
|
|
63
134
|
def test_signed_uri_signs_lowercase_query_keys_but_keeps_original_request_keys():
|
|
64
135
|
sockudo = Sockudo(
|
|
65
136
|
"app-id", "key", "secret", options=SockudoOptions(host="localhost", port=6001)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sockudo_http_python-2.0.0 → sockudo_http_python-2.1.0}/src/sockudo_http_python.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|