rocket-welder-sdk 1.1.42__py3-none-any.whl → 1.1.44__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.
- rocket_welder_sdk/__init__.py +18 -22
- rocket_welder_sdk/binary_frame_reader.py +222 -0
- rocket_welder_sdk/binary_frame_writer.py +213 -0
- rocket_welder_sdk/confidence.py +206 -0
- rocket_welder_sdk/delta_frame.py +150 -0
- rocket_welder_sdk/high_level/__init__.py +8 -1
- rocket_welder_sdk/high_level/client.py +114 -3
- rocket_welder_sdk/high_level/connection_strings.py +3 -15
- rocket_welder_sdk/high_level/frame_sink_factory.py +2 -15
- rocket_welder_sdk/high_level/transport_protocol.py +4 -130
- rocket_welder_sdk/keypoints_protocol.py +520 -55
- rocket_welder_sdk/rocket_welder_client.py +0 -77
- rocket_welder_sdk/segmentation_result.py +387 -2
- rocket_welder_sdk/session_id.py +6 -182
- rocket_welder_sdk/transport/__init__.py +10 -3
- rocket_welder_sdk/transport/frame_sink.py +3 -3
- rocket_welder_sdk/transport/frame_source.py +2 -2
- rocket_welder_sdk/transport/websocket_transport.py +316 -0
- rocket_welder_sdk/varint.py +213 -0
- {rocket_welder_sdk-1.1.42.dist-info → rocket_welder_sdk-1.1.44.dist-info}/METADATA +1 -4
- {rocket_welder_sdk-1.1.42.dist-info → rocket_welder_sdk-1.1.44.dist-info}/RECORD +23 -18
- rocket_welder_sdk/transport/nng_transport.py +0 -197
- {rocket_welder_sdk-1.1.42.dist-info → rocket_welder_sdk-1.1.44.dist-info}/WHEEL +0 -0
- {rocket_welder_sdk-1.1.42.dist-info → rocket_welder_sdk-1.1.44.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Core varint and ZigZag encoding/decoding algorithms.
|
|
3
|
+
Matches C# Varint static class from RocketWelder.SDK.Protocols.
|
|
4
|
+
|
|
5
|
+
Single source of truth for all varint operations in the SDK.
|
|
6
|
+
Compatible with Protocol Buffers varint encoding.
|
|
7
|
+
|
|
8
|
+
Varint encoding uses 7 bits per byte with MSB as continuation flag.
|
|
9
|
+
ZigZag encoding maps signed integers to unsigned for efficient varint encoding
|
|
10
|
+
of values near zero (both positive and negative).
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
from typing import Tuple
|
|
16
|
+
|
|
17
|
+
# Maximum bytes needed for a uint32 varint
|
|
18
|
+
MAX_BYTES_UINT32 = 5
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def zigzag_encode(value: int) -> int:
|
|
22
|
+
"""
|
|
23
|
+
ZigZag encode a signed integer to unsigned.
|
|
24
|
+
|
|
25
|
+
Maps negative numbers to odd positives: 0->0, -1->1, 1->2, -2->3, 2->4, etc.
|
|
26
|
+
This allows efficient varint encoding of signed values near zero.
|
|
27
|
+
|
|
28
|
+
Args:
|
|
29
|
+
value: Signed integer to encode
|
|
30
|
+
|
|
31
|
+
Returns:
|
|
32
|
+
Unsigned integer (ZigZag encoded)
|
|
33
|
+
"""
|
|
34
|
+
return (value << 1) ^ (value >> 31)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def zigzag_decode(value: int) -> int:
|
|
38
|
+
"""
|
|
39
|
+
ZigZag decode an unsigned integer to signed.
|
|
40
|
+
|
|
41
|
+
Reverses the ZigZag encoding: 0->0, 1->-1, 2->1, 3->-2, 4->2, etc.
|
|
42
|
+
|
|
43
|
+
Args:
|
|
44
|
+
value: Unsigned integer (ZigZag encoded)
|
|
45
|
+
|
|
46
|
+
Returns:
|
|
47
|
+
Signed integer (decoded)
|
|
48
|
+
"""
|
|
49
|
+
return (value >> 1) ^ -(value & 1)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def get_byte_count(value: int) -> int:
|
|
53
|
+
"""
|
|
54
|
+
Calculate the number of bytes needed to encode a value as varint.
|
|
55
|
+
|
|
56
|
+
Args:
|
|
57
|
+
value: Unsigned integer value
|
|
58
|
+
|
|
59
|
+
Returns:
|
|
60
|
+
Number of bytes needed (1-5)
|
|
61
|
+
"""
|
|
62
|
+
if value < 0x80:
|
|
63
|
+
return 1
|
|
64
|
+
if value < 0x4000:
|
|
65
|
+
return 2
|
|
66
|
+
if value < 0x200000:
|
|
67
|
+
return 3
|
|
68
|
+
if value < 0x10000000:
|
|
69
|
+
return 4
|
|
70
|
+
return 5
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def write_varint(buffer: bytearray, offset: int, value: int) -> int:
|
|
74
|
+
"""
|
|
75
|
+
Write a varint to a buffer at the given offset.
|
|
76
|
+
|
|
77
|
+
Args:
|
|
78
|
+
buffer: Destination buffer (must have at least 5 bytes from offset)
|
|
79
|
+
offset: Starting offset in buffer
|
|
80
|
+
value: Unsigned value to encode
|
|
81
|
+
|
|
82
|
+
Returns:
|
|
83
|
+
Number of bytes written (1-5)
|
|
84
|
+
"""
|
|
85
|
+
i = 0
|
|
86
|
+
while value >= 0x80:
|
|
87
|
+
buffer[offset + i] = (value & 0x7F) | 0x80
|
|
88
|
+
value >>= 7
|
|
89
|
+
i += 1
|
|
90
|
+
buffer[offset + i] = value
|
|
91
|
+
return i + 1
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def write_zigzag(buffer: bytearray, offset: int, value: int) -> int:
|
|
95
|
+
"""
|
|
96
|
+
Write a ZigZag-encoded signed integer as varint.
|
|
97
|
+
|
|
98
|
+
Args:
|
|
99
|
+
buffer: Destination buffer (must have at least 5 bytes from offset)
|
|
100
|
+
offset: Starting offset in buffer
|
|
101
|
+
value: Signed value to encode
|
|
102
|
+
|
|
103
|
+
Returns:
|
|
104
|
+
Number of bytes written (1-5)
|
|
105
|
+
"""
|
|
106
|
+
return write_varint(buffer, offset, zigzag_encode(value))
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def read_varint(data: bytes, offset: int) -> Tuple[int, int]:
|
|
110
|
+
"""
|
|
111
|
+
Read a varint from bytes at the given offset.
|
|
112
|
+
|
|
113
|
+
Args:
|
|
114
|
+
data: Source buffer
|
|
115
|
+
offset: Starting offset in buffer
|
|
116
|
+
|
|
117
|
+
Returns:
|
|
118
|
+
Tuple of (decoded_value, bytes_read)
|
|
119
|
+
|
|
120
|
+
Raises:
|
|
121
|
+
EOFError: If buffer ends before varint completes
|
|
122
|
+
ValueError: If varint is malformed (too long)
|
|
123
|
+
"""
|
|
124
|
+
result = 0
|
|
125
|
+
shift = 0
|
|
126
|
+
i = 0
|
|
127
|
+
|
|
128
|
+
while True:
|
|
129
|
+
if offset + i >= len(data):
|
|
130
|
+
raise EOFError("Unexpected end of varint")
|
|
131
|
+
|
|
132
|
+
b = data[offset + i]
|
|
133
|
+
result |= (b & 0x7F) << shift
|
|
134
|
+
i += 1
|
|
135
|
+
|
|
136
|
+
if (b & 0x80) == 0:
|
|
137
|
+
break
|
|
138
|
+
|
|
139
|
+
shift += 7
|
|
140
|
+
if shift >= 35:
|
|
141
|
+
raise ValueError("Varint too long (corrupted data)")
|
|
142
|
+
|
|
143
|
+
return result, i
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def read_zigzag(data: bytes, offset: int) -> Tuple[int, int]:
|
|
147
|
+
"""
|
|
148
|
+
Read a ZigZag-encoded signed integer.
|
|
149
|
+
|
|
150
|
+
Args:
|
|
151
|
+
data: Source buffer
|
|
152
|
+
offset: Starting offset in buffer
|
|
153
|
+
|
|
154
|
+
Returns:
|
|
155
|
+
Tuple of (decoded_signed_value, bytes_read)
|
|
156
|
+
"""
|
|
157
|
+
encoded, bytes_read = read_varint(data, offset)
|
|
158
|
+
return zigzag_decode(encoded), bytes_read
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def try_read_varint(data: bytes, offset: int) -> Tuple[bool, int, int]:
|
|
162
|
+
"""
|
|
163
|
+
Try to read a varint, returning False if not enough data.
|
|
164
|
+
|
|
165
|
+
Args:
|
|
166
|
+
data: Source buffer
|
|
167
|
+
offset: Starting offset in buffer
|
|
168
|
+
|
|
169
|
+
Returns:
|
|
170
|
+
Tuple of (success, value, bytes_read)
|
|
171
|
+
If success is False, value and bytes_read are 0
|
|
172
|
+
"""
|
|
173
|
+
result = 0
|
|
174
|
+
shift = 0
|
|
175
|
+
|
|
176
|
+
for i in range(min(5, len(data) - offset)):
|
|
177
|
+
b = data[offset + i]
|
|
178
|
+
result |= (b & 0x7F) << shift
|
|
179
|
+
|
|
180
|
+
if (b & 0x80) == 0:
|
|
181
|
+
return True, result, i + 1
|
|
182
|
+
|
|
183
|
+
shift += 7
|
|
184
|
+
|
|
185
|
+
return False, 0, 0
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
def encode_varint(value: int) -> bytes:
|
|
189
|
+
"""
|
|
190
|
+
Convenience function to encode a value to varint bytes.
|
|
191
|
+
|
|
192
|
+
Args:
|
|
193
|
+
value: Unsigned value to encode
|
|
194
|
+
|
|
195
|
+
Returns:
|
|
196
|
+
Bytes containing the varint encoding
|
|
197
|
+
"""
|
|
198
|
+
buffer = bytearray(MAX_BYTES_UINT32)
|
|
199
|
+
length = write_varint(buffer, 0, value)
|
|
200
|
+
return bytes(buffer[:length])
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
def encode_zigzag(value: int) -> bytes:
|
|
204
|
+
"""
|
|
205
|
+
Convenience function to encode a signed value to ZigZag varint bytes.
|
|
206
|
+
|
|
207
|
+
Args:
|
|
208
|
+
value: Signed value to encode
|
|
209
|
+
|
|
210
|
+
Returns:
|
|
211
|
+
Bytes containing the ZigZag varint encoding
|
|
212
|
+
"""
|
|
213
|
+
return encode_varint(zigzag_encode(value))
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: rocket-welder-sdk
|
|
3
|
-
Version: 1.1.
|
|
3
|
+
Version: 1.1.44
|
|
4
4
|
Summary: High-performance video streaming SDK for RocketWelder services using ZeroBuffer IPC
|
|
5
5
|
Home-page: https://github.com/modelingevolution/rocket-welder-sdk
|
|
6
6
|
Author: ModelingEvolution
|
|
@@ -32,8 +32,6 @@ Requires-Dist: zerobuffer-ipc>=1.1.17
|
|
|
32
32
|
Requires-Dist: pydantic>=2.5.0
|
|
33
33
|
Requires-Dist: py-micro-plumberd>=0.1.8
|
|
34
34
|
Requires-Dist: typing-extensions>=4.0.0
|
|
35
|
-
Provides-Extra: nng
|
|
36
|
-
Requires-Dist: pynng>=0.7.2; extra == "nng"
|
|
37
35
|
Provides-Extra: dev
|
|
38
36
|
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
39
37
|
Requires-Dist: pytest-cov>=4.0; extra == "dev"
|
|
@@ -42,7 +40,6 @@ Requires-Dist: black>=22.0; extra == "dev"
|
|
|
42
40
|
Requires-Dist: mypy>=1.0; extra == "dev"
|
|
43
41
|
Requires-Dist: ruff>=0.1.0; extra == "dev"
|
|
44
42
|
Requires-Dist: types-setuptools; extra == "dev"
|
|
45
|
-
Requires-Dist: pynng>=0.7.2; extra == "dev"
|
|
46
43
|
Dynamic: author
|
|
47
44
|
Dynamic: home-page
|
|
48
45
|
Dynamic: requires-python
|
|
@@ -1,40 +1,45 @@
|
|
|
1
|
-
rocket_welder_sdk/__init__.py,sha256=
|
|
1
|
+
rocket_welder_sdk/__init__.py,sha256=r2zUZzUMZuAPUy5Sat5EWaxeocIjRbdqBDoC1i0C89w,3413
|
|
2
|
+
rocket_welder_sdk/binary_frame_reader.py,sha256=5IyYO7yv07gLpQ9Toyw1zLkTrnqHLjxIeMVRn8B40-E,6270
|
|
3
|
+
rocket_welder_sdk/binary_frame_writer.py,sha256=2-VEJNHw0fL30TXsCBHyhHltvgx7KUahmbamwdSU8sw,6658
|
|
2
4
|
rocket_welder_sdk/bytes_size.py,sha256=Myl29-wyWCIYdbMmgaxXebT8Dz8_Fwcr3fnfaNW81P0,7463
|
|
5
|
+
rocket_welder_sdk/confidence.py,sha256=AlgVM7gNDff3UxcQHhA5sJlTb4VeOMFAraF3W59AeSI,6498
|
|
3
6
|
rocket_welder_sdk/connection_string.py,sha256=NIC6OiOXF-DeBFCWzgMFOWsenrSS45hY81j_HLMSpgo,9974
|
|
4
7
|
rocket_welder_sdk/controllers.py,sha256=uuVyKsNHtpaIzQt8pXCAu7SywoFa7cfww8VSa4LNi_E,33130
|
|
8
|
+
rocket_welder_sdk/delta_frame.py,sha256=51RFWI2odKVak-d3qhv7S8DiXbk4M5f-bbuTT1unXfk,4518
|
|
5
9
|
rocket_welder_sdk/frame_metadata.py,sha256=TMLIY47cIdIlxqk9xj7I3M8FZFmZ3GcVoLZht7prjQM,3929
|
|
6
10
|
rocket_welder_sdk/gst_metadata.py,sha256=6Ov-DekGsKNuAo3UIc-g9fh4_SAPdHYQTnnPqCK3Ks0,16180
|
|
7
|
-
rocket_welder_sdk/keypoints_protocol.py,sha256=
|
|
11
|
+
rocket_welder_sdk/keypoints_protocol.py,sha256=kN8ok6Ptpgl4txoQE9DpKhMoI7zr73vTw9CTvCICtgE,36921
|
|
8
12
|
rocket_welder_sdk/opencv_controller.py,sha256=MDM6_yFBB9BaMa5jnZRqw7xZZB-WuLr7EPrrfHQ2DK4,9905
|
|
9
13
|
rocket_welder_sdk/periodic_timer.py,sha256=hnObybmrnf3J47QrNKJhYAytLKwria016123NvPRfQ0,9369
|
|
10
14
|
rocket_welder_sdk/py.typed,sha256=0cXFZXmes4Y-vnl4lO3HtyyyWaFNw85B7tJdFeCtHDc,67
|
|
11
|
-
rocket_welder_sdk/rocket_welder_client.py,sha256=
|
|
12
|
-
rocket_welder_sdk/segmentation_result.py,sha256=
|
|
13
|
-
rocket_welder_sdk/session_id.py,sha256=
|
|
15
|
+
rocket_welder_sdk/rocket_welder_client.py,sha256=VqxP-GkJKCZCjGZq2tVJ7v5yrh-ztXxlF3CT__818vg,23384
|
|
16
|
+
rocket_welder_sdk/segmentation_result.py,sha256=b3xpv6AZyWzm924cd1RfXwCuEwdkPL5TUA0gzT3HpBA,29153
|
|
17
|
+
rocket_welder_sdk/session_id.py,sha256=9GM4T6xmcNxR9gxZnDUlQGviNd3x3hT71q8y85XtH6g,1884
|
|
18
|
+
rocket_welder_sdk/varint.py,sha256=SmffemQCXToRzs3lb7hWQWDY7NmKv4XG_Wb0oeMrb_I,5058
|
|
14
19
|
rocket_welder_sdk/external_controls/__init__.py,sha256=ldOLGhLLS5BQL8m4VKFYV0SvsNNlV2tghlc7rkqadU8,699
|
|
15
20
|
rocket_welder_sdk/external_controls/contracts.py,sha256=3DU6pdpteN50gF2fsS7C2279dGjDa0tZLrLntkBa2LM,2607
|
|
16
21
|
rocket_welder_sdk/external_controls/contracts_old.py,sha256=XWriuXJZu5caTSS0bcTIOZcKnj-IRCm96voA4gqLBfU,2980
|
|
17
|
-
rocket_welder_sdk/high_level/__init__.py,sha256=
|
|
18
|
-
rocket_welder_sdk/high_level/client.py,sha256=
|
|
19
|
-
rocket_welder_sdk/high_level/connection_strings.py,sha256=
|
|
22
|
+
rocket_welder_sdk/high_level/__init__.py,sha256=OKbI3l0PFo1Cb_v0kbv16Wr05urz8heVGps0dJcTcG4,1507
|
|
23
|
+
rocket_welder_sdk/high_level/client.py,sha256=rVnnrn68PEvc68p5acuOBZfEjobWWed8XcssTRzxNr8,11502
|
|
24
|
+
rocket_welder_sdk/high_level/connection_strings.py,sha256=3EpFafyrmX_QNhs2nPscC63EMg5ikscvthu-0C6xC1c,9861
|
|
20
25
|
rocket_welder_sdk/high_level/data_context.py,sha256=SXJvDpDBFi8Lm4XqSRSHK7YUUHuugXGo4ZRCb6_z5l0,4833
|
|
21
|
-
rocket_welder_sdk/high_level/frame_sink_factory.py,sha256=
|
|
26
|
+
rocket_welder_sdk/high_level/frame_sink_factory.py,sha256=tLhMV_qnY-ZUtffIzhycM9znNjYguRumba4vphpNx7E,3493
|
|
22
27
|
rocket_welder_sdk/high_level/schema.py,sha256=2Vv0rDwahtGswWB_ceaCdc7JDtmbkx4wE2jQePzeTpU,5367
|
|
23
|
-
rocket_welder_sdk/high_level/transport_protocol.py,sha256=
|
|
24
|
-
rocket_welder_sdk/transport/__init__.py,sha256=
|
|
25
|
-
rocket_welder_sdk/transport/frame_sink.py,sha256
|
|
26
|
-
rocket_welder_sdk/transport/frame_source.py,sha256=
|
|
27
|
-
rocket_welder_sdk/transport/nng_transport.py,sha256=o-qgcmHCGnwtdPe-mwwrC-a9H0rgS-VdH2QvU-6kFlI,5838
|
|
28
|
+
rocket_welder_sdk/high_level/transport_protocol.py,sha256=pdl7l1Tu9b7IYb95q6kzDY7-g1fbhSnhdV_gGhLeYzk,2943
|
|
29
|
+
rocket_welder_sdk/transport/__init__.py,sha256=J1iMvmIwC89PO8VZwd-qxKoAoB6BOxEY82aB9wLdB5c,950
|
|
30
|
+
rocket_welder_sdk/transport/frame_sink.py,sha256=--uL0kqxoz10Qya3eKpH6vjbMuSZHP0C9q6uwmbEo38,3332
|
|
31
|
+
rocket_welder_sdk/transport/frame_source.py,sha256=pgWFmqSLoIjGx8vW6Uv5uYCpcC49_iBSVU0oJZHDuPw,2171
|
|
28
32
|
rocket_welder_sdk/transport/stream_transport.py,sha256=FhxFlZT-CTo6aPq6VclM1A_ecqfeHcwR4Ty1vmlt3W0,5886
|
|
29
33
|
rocket_welder_sdk/transport/tcp_transport.py,sha256=Tui6nKgu50C1KV_UDANQKgVK3M52XN7zrkZTcWIpGmY,4745
|
|
30
34
|
rocket_welder_sdk/transport/unix_socket_transport.py,sha256=t44Q2Fj6fMv53Ll561hN35-ZbHPdAQt0t9tUAXoL0rY,12245
|
|
35
|
+
rocket_welder_sdk/transport/websocket_transport.py,sha256=ti-Vr2I90JvgJgRfjqo2PfTYk5B86SYZhNofuxpwdBo,9591
|
|
31
36
|
rocket_welder_sdk/ui/__init__.py,sha256=5-fCkv3vG0VVVZkselrifkMmx8d51EJp3nNT9mt4JK4,886
|
|
32
37
|
rocket_welder_sdk/ui/controls.py,sha256=cRBxdUDWMOYlCxtw1PV11fTlte6qLxSfCGpr9bQiLcE,11162
|
|
33
38
|
rocket_welder_sdk/ui/icons.py,sha256=DcDklZkPmiEzlOD4IR7VTJOtGPCuuh_OM_WN7ScghWE,8934592
|
|
34
39
|
rocket_welder_sdk/ui/ui_events_projection.py,sha256=siiNhjLEBOPfTKw1ZhOPGkwIN5rLDH7V9VCZTNrhEtQ,7836
|
|
35
40
|
rocket_welder_sdk/ui/ui_service.py,sha256=uRdpyJGoCQmtOli_HKSrxLwhZYG-XRuHIYdkmFz1zNk,12026
|
|
36
41
|
rocket_welder_sdk/ui/value_types.py,sha256=f7OA_9zgXEDPoITc8v8SfAR23I4XeFhE3E2_GcAbR6k,1616
|
|
37
|
-
rocket_welder_sdk-1.1.
|
|
38
|
-
rocket_welder_sdk-1.1.
|
|
39
|
-
rocket_welder_sdk-1.1.
|
|
40
|
-
rocket_welder_sdk-1.1.
|
|
42
|
+
rocket_welder_sdk-1.1.44.dist-info/METADATA,sha256=XszsJzlnvEQCiPGYl-QxGK6TCTEYmWvi0AzvlHOqYKA,24739
|
|
43
|
+
rocket_welder_sdk-1.1.44.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
44
|
+
rocket_welder_sdk-1.1.44.dist-info/top_level.txt,sha256=2iZvBjnwVCUW-uDE23-eJld5PZ9-mlPI69QiXM5IrTA,18
|
|
45
|
+
rocket_welder_sdk-1.1.44.dist-info/RECORD,,
|
|
@@ -1,197 +0,0 @@
|
|
|
1
|
-
"""NNG transport using pynng library.
|
|
2
|
-
|
|
3
|
-
NNG (nanomsg next generation) provides high-performance, scalable messaging patterns.
|
|
4
|
-
Supported patterns:
|
|
5
|
-
- Pub/Sub: One publisher to many subscribers
|
|
6
|
-
- Push/Pull: Load-balanced distribution to workers
|
|
7
|
-
"""
|
|
8
|
-
|
|
9
|
-
from typing import Any, Optional, cast
|
|
10
|
-
|
|
11
|
-
import pynng
|
|
12
|
-
|
|
13
|
-
from .frame_sink import IFrameSink
|
|
14
|
-
from .frame_source import IFrameSource
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
class NngFrameSink(IFrameSink):
|
|
18
|
-
"""
|
|
19
|
-
Frame sink that publishes to NNG Pub/Sub or Push/Pull pattern.
|
|
20
|
-
|
|
21
|
-
Each frame is sent as a single NNG message (no framing needed - NNG handles message boundaries).
|
|
22
|
-
"""
|
|
23
|
-
|
|
24
|
-
def __init__(self, socket: Any, leave_open: bool = False):
|
|
25
|
-
"""
|
|
26
|
-
Create an NNG frame sink from a socket.
|
|
27
|
-
|
|
28
|
-
Args:
|
|
29
|
-
socket: pynng socket (Publisher or Pusher)
|
|
30
|
-
leave_open: If True, doesn't close socket on close
|
|
31
|
-
"""
|
|
32
|
-
self._socket: Any = socket
|
|
33
|
-
self._leave_open = leave_open
|
|
34
|
-
self._closed = False
|
|
35
|
-
|
|
36
|
-
@classmethod
|
|
37
|
-
def create_publisher(cls, url: str) -> "NngFrameSink":
|
|
38
|
-
"""
|
|
39
|
-
Create an NNG Publisher frame sink bound to the specified URL.
|
|
40
|
-
|
|
41
|
-
Args:
|
|
42
|
-
url: NNG URL (e.g., "tcp://127.0.0.1:5555", "ipc:///tmp/mysocket")
|
|
43
|
-
|
|
44
|
-
Returns:
|
|
45
|
-
Frame sink ready to publish messages
|
|
46
|
-
"""
|
|
47
|
-
socket = pynng.Pub0()
|
|
48
|
-
socket.listen(url)
|
|
49
|
-
return cls(socket, leave_open=False)
|
|
50
|
-
|
|
51
|
-
@classmethod
|
|
52
|
-
def create_pusher(cls, url: str, bind_mode: bool = True) -> "NngFrameSink":
|
|
53
|
-
"""
|
|
54
|
-
Create an NNG Pusher frame sink.
|
|
55
|
-
|
|
56
|
-
Args:
|
|
57
|
-
url: NNG URL (e.g., "tcp://127.0.0.1:5555", "ipc:///tmp/mysocket")
|
|
58
|
-
bind_mode: If True, listens (bind); if False, dials (connect)
|
|
59
|
-
|
|
60
|
-
Returns:
|
|
61
|
-
Frame sink ready to push messages
|
|
62
|
-
"""
|
|
63
|
-
socket = pynng.Push0()
|
|
64
|
-
if bind_mode:
|
|
65
|
-
socket.listen(url)
|
|
66
|
-
else:
|
|
67
|
-
socket.dial(url)
|
|
68
|
-
return cls(socket, leave_open=False)
|
|
69
|
-
|
|
70
|
-
def write_frame(self, frame_data: bytes) -> None:
|
|
71
|
-
"""Write frame to NNG socket (no length prefix - NNG handles message boundaries)."""
|
|
72
|
-
if self._closed:
|
|
73
|
-
raise ValueError("Cannot write to closed sink")
|
|
74
|
-
|
|
75
|
-
self._socket.send(frame_data)
|
|
76
|
-
|
|
77
|
-
async def write_frame_async(self, frame_data: bytes) -> None:
|
|
78
|
-
"""Write frame asynchronously."""
|
|
79
|
-
if self._closed:
|
|
80
|
-
raise ValueError("Cannot write to closed sink")
|
|
81
|
-
|
|
82
|
-
await self._socket.asend(frame_data)
|
|
83
|
-
|
|
84
|
-
def flush(self) -> None:
|
|
85
|
-
"""Flush is a no-op for NNG (data sent immediately)."""
|
|
86
|
-
pass
|
|
87
|
-
|
|
88
|
-
async def flush_async(self) -> None:
|
|
89
|
-
"""Flush asynchronously is a no-op for NNG."""
|
|
90
|
-
pass
|
|
91
|
-
|
|
92
|
-
def close(self) -> None:
|
|
93
|
-
"""Close the NNG sink."""
|
|
94
|
-
if self._closed:
|
|
95
|
-
return
|
|
96
|
-
self._closed = True
|
|
97
|
-
if not self._leave_open:
|
|
98
|
-
self._socket.close()
|
|
99
|
-
|
|
100
|
-
async def close_async(self) -> None:
|
|
101
|
-
"""Close the NNG sink asynchronously."""
|
|
102
|
-
self.close()
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
class NngFrameSource(IFrameSource):
|
|
106
|
-
"""
|
|
107
|
-
Frame source that subscribes to NNG Pub/Sub or Pull pattern.
|
|
108
|
-
|
|
109
|
-
Each NNG message is treated as a complete frame (no framing needed - NNG handles message boundaries).
|
|
110
|
-
"""
|
|
111
|
-
|
|
112
|
-
def __init__(self, socket: Any, leave_open: bool = False):
|
|
113
|
-
"""
|
|
114
|
-
Create an NNG frame source from a socket.
|
|
115
|
-
|
|
116
|
-
Args:
|
|
117
|
-
socket: pynng socket (Subscriber or Puller)
|
|
118
|
-
leave_open: If True, doesn't close socket on close
|
|
119
|
-
"""
|
|
120
|
-
self._socket: Any = socket
|
|
121
|
-
self._leave_open = leave_open
|
|
122
|
-
self._closed = False
|
|
123
|
-
|
|
124
|
-
@classmethod
|
|
125
|
-
def create_subscriber(cls, url: str, topic: bytes = b"") -> "NngFrameSource":
|
|
126
|
-
"""
|
|
127
|
-
Create an NNG Subscriber frame source connected to the specified URL.
|
|
128
|
-
|
|
129
|
-
Args:
|
|
130
|
-
url: NNG URL (e.g., "tcp://127.0.0.1:5555", "ipc:///tmp/mysocket")
|
|
131
|
-
topic: Optional topic filter (empty for all messages)
|
|
132
|
-
|
|
133
|
-
Returns:
|
|
134
|
-
Frame source ready to receive messages
|
|
135
|
-
"""
|
|
136
|
-
socket = pynng.Sub0()
|
|
137
|
-
socket.subscribe(topic)
|
|
138
|
-
socket.dial(url)
|
|
139
|
-
return cls(socket, leave_open=False)
|
|
140
|
-
|
|
141
|
-
@classmethod
|
|
142
|
-
def create_puller(cls, url: str, bind_mode: bool = True) -> "NngFrameSource":
|
|
143
|
-
"""
|
|
144
|
-
Create an NNG Puller frame source.
|
|
145
|
-
|
|
146
|
-
Args:
|
|
147
|
-
url: NNG URL (e.g., "tcp://127.0.0.1:5555", "ipc:///tmp/mysocket")
|
|
148
|
-
bind_mode: If True, listens (bind); if False, dials (connect)
|
|
149
|
-
|
|
150
|
-
Returns:
|
|
151
|
-
Frame source ready to pull messages
|
|
152
|
-
"""
|
|
153
|
-
socket = pynng.Pull0()
|
|
154
|
-
if bind_mode:
|
|
155
|
-
socket.listen(url)
|
|
156
|
-
else:
|
|
157
|
-
socket.dial(url)
|
|
158
|
-
return cls(socket, leave_open=False)
|
|
159
|
-
|
|
160
|
-
@property
|
|
161
|
-
def has_more_frames(self) -> bool:
|
|
162
|
-
"""Check if more frames available (NNG blocks waiting for messages)."""
|
|
163
|
-
return not self._closed
|
|
164
|
-
|
|
165
|
-
def read_frame(self) -> Optional[bytes]:
|
|
166
|
-
"""Read frame from NNG socket (blocking)."""
|
|
167
|
-
if self._closed:
|
|
168
|
-
return None
|
|
169
|
-
|
|
170
|
-
try:
|
|
171
|
-
return cast("bytes", self._socket.recv())
|
|
172
|
-
except pynng.Closed:
|
|
173
|
-
self._closed = True
|
|
174
|
-
return None
|
|
175
|
-
|
|
176
|
-
async def read_frame_async(self) -> Optional[bytes]:
|
|
177
|
-
"""Read frame asynchronously."""
|
|
178
|
-
if self._closed:
|
|
179
|
-
return None
|
|
180
|
-
|
|
181
|
-
try:
|
|
182
|
-
return cast("bytes", await self._socket.arecv())
|
|
183
|
-
except pynng.Closed:
|
|
184
|
-
self._closed = True
|
|
185
|
-
return None
|
|
186
|
-
|
|
187
|
-
def close(self) -> None:
|
|
188
|
-
"""Close the NNG source."""
|
|
189
|
-
if self._closed:
|
|
190
|
-
return
|
|
191
|
-
self._closed = True
|
|
192
|
-
if not self._leave_open:
|
|
193
|
-
self._socket.close()
|
|
194
|
-
|
|
195
|
-
async def close_async(self) -> None:
|
|
196
|
-
"""Close the NNG source asynchronously."""
|
|
197
|
-
self.close()
|
|
File without changes
|
|
File without changes
|