starpc 0.52.0 → 0.52.1
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.
- package/dist/echo/client-test.d.ts +1 -1
- package/dist/echo/client-test.js +110 -2
- package/dist/integration/cross-language/tcp-packet-stream.d.ts +3 -0
- package/dist/integration/cross-language/tcp-packet-stream.js +112 -0
- package/dist/integration/cross-language/tcp-packet-stream.test.d.ts +1 -0
- package/dist/integration/cross-language/tcp-packet-stream.test.js +121 -0
- package/dist/integration/cross-language/ts-client.js +50 -37
- package/dist/integration/cross-language/ts-server.js +1 -36
- package/dist/rpcstream/rpcstream.d.ts +5 -1
- package/dist/rpcstream/rpcstream.js +75 -28
- package/dist/rpcstream/rpcstream.test.d.ts +1 -0
- package/dist/rpcstream/rpcstream.test.js +92 -0
- package/dist/srpc/client.js +18 -4
- package/dist/srpc/common-rpc.test.js +2 -0
- package/dist/srpc/packet-codec.test.d.ts +1 -0
- package/dist/srpc/packet-codec.test.js +75 -0
- package/dist/srpc/packet.d.ts +1 -1
- package/dist/srpc/packet.js +11 -1
- package/dist/srpc/server.js +19 -6
- package/dist/srpc/server.test.js +43 -0
- package/dist/srpc/stream.d.ts +4 -1
- package/dist/srpc/stream.js +62 -3
- package/dist/srpc/stream.test.js +110 -1
- package/dist/srpc/termination.d.ts +27 -0
- package/dist/srpc/termination.js +56 -0
- package/dist/srpc/termination.test.d.ts +1 -0
- package/dist/srpc/termination.test.js +24 -0
- package/dist/testdata/packet-codec-vectors.json +64 -0
- package/echo/client-test.ts +124 -2
- package/echo/echo_pb2.py +40 -0
- package/echo/echo_pb2.pyi +13 -0
- package/echo/echo_srpc.py +306 -0
- package/echo/echo_srpc.pyi +85 -0
- package/go.mod +2 -2
- package/go.sum +14 -0
- package/integration/cross-language/go-client/main.go +79 -3
- package/integration/cross-language/python-client.py +146 -0
- package/integration/cross-language/python-server.py +140 -0
- package/integration/cross-language/run.bash +190 -65
- package/integration/cross-language/tcp-packet-stream.test.ts +154 -0
- package/integration/cross-language/tcp-packet-stream.ts +121 -0
- package/integration/cross-language/ts-client.ts +62 -40
- package/integration/cross-language/ts-server.ts +1 -45
- package/mock/mock_pb2.py +38 -0
- package/mock/mock_pb2.pyi +11 -0
- package/mock/mock_srpc.py +71 -0
- package/mock/mock_srpc.pyi +27 -0
- package/package.json +19 -5
- package/srpc/__init__.py +0 -0
- package/srpc/client.ts +20 -4
- package/srpc/codec.rs +6 -0
- package/srpc/common-rpc.test.ts +2 -0
- package/srpc/packet-codec-vectors_test.go +195 -0
- package/srpc/packet-codec.test.ts +139 -0
- package/srpc/packet-rw.go +9 -2
- package/srpc/packet.ts +15 -2
- package/srpc/py.typed +0 -0
- package/srpc/rpcproto_pb2.py +40 -0
- package/srpc/rpcproto_pb2.pyi +40 -0
- package/srpc/server.test.ts +50 -0
- package/srpc/server.ts +22 -6
- package/srpc/stream.test.ts +132 -1
- package/srpc/stream.ts +65 -9
- package/srpc/termination.test.ts +30 -0
- package/srpc/termination.ts +70 -0
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections.abc import AsyncIterable, AsyncIterator
|
|
4
|
+
from typing import Protocol
|
|
5
|
+
|
|
6
|
+
from google.protobuf import empty_pb2 as _google_protobuf_empty_pb2
|
|
7
|
+
|
|
8
|
+
from echo import (
|
|
9
|
+
echo_pb2 as _github_com_aperturerobotics_starpc_echo_echo_pb2,
|
|
10
|
+
)
|
|
11
|
+
from rpcstream import (
|
|
12
|
+
rpcstream_pb2 as _github_com_aperturerobotics_starpc_rpcstream_rpcstream_pb2,
|
|
13
|
+
)
|
|
14
|
+
from starpc.call import Call, CallProtocolError
|
|
15
|
+
from starpc.client import Client
|
|
16
|
+
from starpc.server import ServiceRegistry
|
|
17
|
+
from starpc.service import MethodDescriptor, ServiceDescriptor, bidirectional_bytes
|
|
18
|
+
|
|
19
|
+
ECHOER_SERVICE = ServiceDescriptor(
|
|
20
|
+
"echo.Echoer",
|
|
21
|
+
(
|
|
22
|
+
MethodDescriptor(
|
|
23
|
+
"Echo",
|
|
24
|
+
_github_com_aperturerobotics_starpc_echo_echo_pb2.EchoMsg,
|
|
25
|
+
_github_com_aperturerobotics_starpc_echo_echo_pb2.EchoMsg,
|
|
26
|
+
False,
|
|
27
|
+
False,
|
|
28
|
+
),
|
|
29
|
+
MethodDescriptor(
|
|
30
|
+
"EchoServerStream",
|
|
31
|
+
_github_com_aperturerobotics_starpc_echo_echo_pb2.EchoMsg,
|
|
32
|
+
_github_com_aperturerobotics_starpc_echo_echo_pb2.EchoMsg,
|
|
33
|
+
False,
|
|
34
|
+
True,
|
|
35
|
+
),
|
|
36
|
+
MethodDescriptor(
|
|
37
|
+
"EchoClientStream",
|
|
38
|
+
_github_com_aperturerobotics_starpc_echo_echo_pb2.EchoMsg,
|
|
39
|
+
_github_com_aperturerobotics_starpc_echo_echo_pb2.EchoMsg,
|
|
40
|
+
True,
|
|
41
|
+
False,
|
|
42
|
+
),
|
|
43
|
+
MethodDescriptor(
|
|
44
|
+
"EchoBidiStream",
|
|
45
|
+
_github_com_aperturerobotics_starpc_echo_echo_pb2.EchoMsg,
|
|
46
|
+
_github_com_aperturerobotics_starpc_echo_echo_pb2.EchoMsg,
|
|
47
|
+
True,
|
|
48
|
+
True,
|
|
49
|
+
),
|
|
50
|
+
MethodDescriptor(
|
|
51
|
+
"RpcStream",
|
|
52
|
+
_github_com_aperturerobotics_starpc_rpcstream_rpcstream_pb2.RpcStreamPacket,
|
|
53
|
+
_github_com_aperturerobotics_starpc_rpcstream_rpcstream_pb2.RpcStreamPacket,
|
|
54
|
+
True,
|
|
55
|
+
True,
|
|
56
|
+
),
|
|
57
|
+
MethodDescriptor(
|
|
58
|
+
"DoNothing",
|
|
59
|
+
_google_protobuf_empty_pb2.Empty,
|
|
60
|
+
_google_protobuf_empty_pb2.Empty,
|
|
61
|
+
False,
|
|
62
|
+
False,
|
|
63
|
+
),
|
|
64
|
+
),
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class EchoerClient:
|
|
69
|
+
def __init__(self, client: Client, service: str | None = None) -> None:
|
|
70
|
+
self._client = client
|
|
71
|
+
self._service = service or "echo.Echoer"
|
|
72
|
+
|
|
73
|
+
async def echo(
|
|
74
|
+
self, request: _github_com_aperturerobotics_starpc_echo_echo_pb2.EchoMsg
|
|
75
|
+
) -> _github_com_aperturerobotics_starpc_echo_echo_pb2.EchoMsg:
|
|
76
|
+
call = await self._client.open_call(
|
|
77
|
+
self._service, "Echo", request.SerializeToString(deterministic=True)
|
|
78
|
+
)
|
|
79
|
+
try:
|
|
80
|
+
data = await call.receive()
|
|
81
|
+
if data is None:
|
|
82
|
+
raise CallProtocolError("missing unary response")
|
|
83
|
+
response = _github_com_aperturerobotics_starpc_echo_echo_pb2.EchoMsg()
|
|
84
|
+
response.ParseFromString(data)
|
|
85
|
+
if await call.receive() is not None:
|
|
86
|
+
raise CallProtocolError("extra unary response")
|
|
87
|
+
return response
|
|
88
|
+
finally:
|
|
89
|
+
await call.aclose()
|
|
90
|
+
|
|
91
|
+
async def echo_server_stream(
|
|
92
|
+
self, request: _github_com_aperturerobotics_starpc_echo_echo_pb2.EchoMsg
|
|
93
|
+
) -> AsyncIterator[_github_com_aperturerobotics_starpc_echo_echo_pb2.EchoMsg]:
|
|
94
|
+
call = await self._client.open_call(
|
|
95
|
+
self._service,
|
|
96
|
+
"EchoServerStream",
|
|
97
|
+
request.SerializeToString(deterministic=True),
|
|
98
|
+
)
|
|
99
|
+
try:
|
|
100
|
+
while True:
|
|
101
|
+
data = await call.receive()
|
|
102
|
+
if data is None:
|
|
103
|
+
return
|
|
104
|
+
response = _github_com_aperturerobotics_starpc_echo_echo_pb2.EchoMsg()
|
|
105
|
+
response.ParseFromString(data)
|
|
106
|
+
yield response
|
|
107
|
+
finally:
|
|
108
|
+
await call.aclose()
|
|
109
|
+
|
|
110
|
+
async def echo_client_stream(
|
|
111
|
+
self,
|
|
112
|
+
requests: AsyncIterable[
|
|
113
|
+
_github_com_aperturerobotics_starpc_echo_echo_pb2.EchoMsg
|
|
114
|
+
],
|
|
115
|
+
) -> _github_com_aperturerobotics_starpc_echo_echo_pb2.EchoMsg:
|
|
116
|
+
call = await self._client.open_call(self._service, "EchoClientStream")
|
|
117
|
+
try:
|
|
118
|
+
async for request in requests:
|
|
119
|
+
await call.send(request.SerializeToString(deterministic=True))
|
|
120
|
+
await call.finish()
|
|
121
|
+
data = await call.receive()
|
|
122
|
+
if data is None:
|
|
123
|
+
raise CallProtocolError("missing client-stream response")
|
|
124
|
+
response = _github_com_aperturerobotics_starpc_echo_echo_pb2.EchoMsg()
|
|
125
|
+
response.ParseFromString(data)
|
|
126
|
+
if await call.receive() is not None:
|
|
127
|
+
raise CallProtocolError("extra client-stream response")
|
|
128
|
+
return response
|
|
129
|
+
finally:
|
|
130
|
+
await call.aclose()
|
|
131
|
+
|
|
132
|
+
async def echo_bidi_stream(
|
|
133
|
+
self,
|
|
134
|
+
requests: AsyncIterable[
|
|
135
|
+
_github_com_aperturerobotics_starpc_echo_echo_pb2.EchoMsg
|
|
136
|
+
],
|
|
137
|
+
) -> AsyncIterator[_github_com_aperturerobotics_starpc_echo_echo_pb2.EchoMsg]:
|
|
138
|
+
call = await self._client.open_call(self._service, "EchoBidiStream")
|
|
139
|
+
|
|
140
|
+
async def encoded() -> AsyncIterator[bytes]:
|
|
141
|
+
async for request in requests:
|
|
142
|
+
yield request.SerializeToString(deterministic=True)
|
|
143
|
+
|
|
144
|
+
async for data in bidirectional_bytes(call, encoded()):
|
|
145
|
+
response = _github_com_aperturerobotics_starpc_echo_echo_pb2.EchoMsg()
|
|
146
|
+
response.ParseFromString(data)
|
|
147
|
+
yield response
|
|
148
|
+
|
|
149
|
+
async def rpc_stream(
|
|
150
|
+
self,
|
|
151
|
+
requests: AsyncIterable[
|
|
152
|
+
_github_com_aperturerobotics_starpc_rpcstream_rpcstream_pb2.RpcStreamPacket
|
|
153
|
+
],
|
|
154
|
+
) -> AsyncIterator[
|
|
155
|
+
_github_com_aperturerobotics_starpc_rpcstream_rpcstream_pb2.RpcStreamPacket
|
|
156
|
+
]:
|
|
157
|
+
call = await self._client.open_call(self._service, "RpcStream")
|
|
158
|
+
|
|
159
|
+
async def encoded() -> AsyncIterator[bytes]:
|
|
160
|
+
async for request in requests:
|
|
161
|
+
yield request.SerializeToString(deterministic=True)
|
|
162
|
+
|
|
163
|
+
async for data in bidirectional_bytes(call, encoded()):
|
|
164
|
+
response = _github_com_aperturerobotics_starpc_rpcstream_rpcstream_pb2.RpcStreamPacket()
|
|
165
|
+
response.ParseFromString(data)
|
|
166
|
+
yield response
|
|
167
|
+
|
|
168
|
+
async def do_nothing(
|
|
169
|
+
self, request: _google_protobuf_empty_pb2.Empty
|
|
170
|
+
) -> _google_protobuf_empty_pb2.Empty:
|
|
171
|
+
call = await self._client.open_call(
|
|
172
|
+
self._service, "DoNothing", request.SerializeToString(deterministic=True)
|
|
173
|
+
)
|
|
174
|
+
try:
|
|
175
|
+
data = await call.receive()
|
|
176
|
+
if data is None:
|
|
177
|
+
raise CallProtocolError("missing unary response")
|
|
178
|
+
response = _google_protobuf_empty_pb2.Empty()
|
|
179
|
+
response.ParseFromString(data)
|
|
180
|
+
if await call.receive() is not None:
|
|
181
|
+
raise CallProtocolError("extra unary response")
|
|
182
|
+
return response
|
|
183
|
+
finally:
|
|
184
|
+
await call.aclose()
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
class EchoerServer(Protocol):
|
|
188
|
+
async def echo(
|
|
189
|
+
self, request: _github_com_aperturerobotics_starpc_echo_echo_pb2.EchoMsg
|
|
190
|
+
) -> _github_com_aperturerobotics_starpc_echo_echo_pb2.EchoMsg: ...
|
|
191
|
+
def echo_server_stream(
|
|
192
|
+
self, request: _github_com_aperturerobotics_starpc_echo_echo_pb2.EchoMsg
|
|
193
|
+
) -> AsyncIterator[_github_com_aperturerobotics_starpc_echo_echo_pb2.EchoMsg]: ...
|
|
194
|
+
async def echo_client_stream(
|
|
195
|
+
self,
|
|
196
|
+
requests: AsyncIterator[
|
|
197
|
+
_github_com_aperturerobotics_starpc_echo_echo_pb2.EchoMsg
|
|
198
|
+
],
|
|
199
|
+
) -> _github_com_aperturerobotics_starpc_echo_echo_pb2.EchoMsg: ...
|
|
200
|
+
def echo_bidi_stream(
|
|
201
|
+
self,
|
|
202
|
+
requests: AsyncIterator[
|
|
203
|
+
_github_com_aperturerobotics_starpc_echo_echo_pb2.EchoMsg
|
|
204
|
+
],
|
|
205
|
+
) -> AsyncIterator[_github_com_aperturerobotics_starpc_echo_echo_pb2.EchoMsg]: ...
|
|
206
|
+
def rpc_stream(
|
|
207
|
+
self,
|
|
208
|
+
requests: AsyncIterator[
|
|
209
|
+
_github_com_aperturerobotics_starpc_rpcstream_rpcstream_pb2.RpcStreamPacket
|
|
210
|
+
],
|
|
211
|
+
) -> AsyncIterator[
|
|
212
|
+
_github_com_aperturerobotics_starpc_rpcstream_rpcstream_pb2.RpcStreamPacket
|
|
213
|
+
]: ...
|
|
214
|
+
async def do_nothing(
|
|
215
|
+
self, request: _google_protobuf_empty_pb2.Empty
|
|
216
|
+
) -> _google_protobuf_empty_pb2.Empty: ...
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
def register_echoer(
|
|
220
|
+
registry: ServiceRegistry,
|
|
221
|
+
implementation: EchoerServer,
|
|
222
|
+
service: str = "echo.Echoer",
|
|
223
|
+
) -> None:
|
|
224
|
+
async def echo_handler(call: Call) -> None:
|
|
225
|
+
first = await call.receive()
|
|
226
|
+
if first is None:
|
|
227
|
+
raise CallProtocolError("missing initial request")
|
|
228
|
+
request = _github_com_aperturerobotics_starpc_echo_echo_pb2.EchoMsg()
|
|
229
|
+
request.ParseFromString(first)
|
|
230
|
+
response = await implementation.echo(request)
|
|
231
|
+
await call.send(response.SerializeToString(deterministic=True))
|
|
232
|
+
|
|
233
|
+
registry.register(service, "Echo", echo_handler)
|
|
234
|
+
|
|
235
|
+
async def echo_server_stream_handler(call: Call) -> None:
|
|
236
|
+
first = await call.receive()
|
|
237
|
+
if first is None:
|
|
238
|
+
raise CallProtocolError("missing initial request")
|
|
239
|
+
request = _github_com_aperturerobotics_starpc_echo_echo_pb2.EchoMsg()
|
|
240
|
+
request.ParseFromString(first)
|
|
241
|
+
async for response in implementation.echo_server_stream(request):
|
|
242
|
+
await call.send(response.SerializeToString(deterministic=True))
|
|
243
|
+
|
|
244
|
+
registry.register(service, "EchoServerStream", echo_server_stream_handler)
|
|
245
|
+
|
|
246
|
+
async def echo_client_stream_handler(call: Call) -> None:
|
|
247
|
+
async def requests() -> AsyncIterator[
|
|
248
|
+
_github_com_aperturerobotics_starpc_echo_echo_pb2.EchoMsg
|
|
249
|
+
]:
|
|
250
|
+
while True:
|
|
251
|
+
data = await call.receive()
|
|
252
|
+
if data is None:
|
|
253
|
+
return
|
|
254
|
+
request = _github_com_aperturerobotics_starpc_echo_echo_pb2.EchoMsg()
|
|
255
|
+
request.ParseFromString(data)
|
|
256
|
+
yield request
|
|
257
|
+
|
|
258
|
+
response = await implementation.echo_client_stream(requests())
|
|
259
|
+
await call.send(response.SerializeToString(deterministic=True))
|
|
260
|
+
|
|
261
|
+
registry.register(service, "EchoClientStream", echo_client_stream_handler)
|
|
262
|
+
|
|
263
|
+
async def echo_bidi_stream_handler(call: Call) -> None:
|
|
264
|
+
async def requests() -> AsyncIterator[
|
|
265
|
+
_github_com_aperturerobotics_starpc_echo_echo_pb2.EchoMsg
|
|
266
|
+
]:
|
|
267
|
+
while True:
|
|
268
|
+
data = await call.receive()
|
|
269
|
+
if data is None:
|
|
270
|
+
return
|
|
271
|
+
request = _github_com_aperturerobotics_starpc_echo_echo_pb2.EchoMsg()
|
|
272
|
+
request.ParseFromString(data)
|
|
273
|
+
yield request
|
|
274
|
+
|
|
275
|
+
async for response in implementation.echo_bidi_stream(requests()):
|
|
276
|
+
await call.send(response.SerializeToString(deterministic=True))
|
|
277
|
+
|
|
278
|
+
registry.register(service, "EchoBidiStream", echo_bidi_stream_handler)
|
|
279
|
+
|
|
280
|
+
async def rpc_stream_handler(call: Call) -> None:
|
|
281
|
+
async def requests() -> AsyncIterator[
|
|
282
|
+
_github_com_aperturerobotics_starpc_rpcstream_rpcstream_pb2.RpcStreamPacket
|
|
283
|
+
]:
|
|
284
|
+
while True:
|
|
285
|
+
data = await call.receive()
|
|
286
|
+
if data is None:
|
|
287
|
+
return
|
|
288
|
+
request = _github_com_aperturerobotics_starpc_rpcstream_rpcstream_pb2.RpcStreamPacket()
|
|
289
|
+
request.ParseFromString(data)
|
|
290
|
+
yield request
|
|
291
|
+
|
|
292
|
+
async for response in implementation.rpc_stream(requests()):
|
|
293
|
+
await call.send(response.SerializeToString(deterministic=True))
|
|
294
|
+
|
|
295
|
+
registry.register(service, "RpcStream", rpc_stream_handler)
|
|
296
|
+
|
|
297
|
+
async def do_nothing_handler(call: Call) -> None:
|
|
298
|
+
first = await call.receive()
|
|
299
|
+
if first is None:
|
|
300
|
+
raise CallProtocolError("missing initial request")
|
|
301
|
+
request = _google_protobuf_empty_pb2.Empty()
|
|
302
|
+
request.ParseFromString(first)
|
|
303
|
+
response = await implementation.do_nothing(request)
|
|
304
|
+
await call.send(response.SerializeToString(deterministic=True))
|
|
305
|
+
|
|
306
|
+
registry.register(service, "DoNothing", do_nothing_handler)
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
from collections.abc import AsyncIterable, AsyncIterator
|
|
2
|
+
from typing import Protocol
|
|
3
|
+
|
|
4
|
+
from google.protobuf import empty_pb2 as _google_protobuf_empty_pb2
|
|
5
|
+
|
|
6
|
+
from echo import (
|
|
7
|
+
echo_pb2 as _github_com_aperturerobotics_starpc_echo_echo_pb2,
|
|
8
|
+
)
|
|
9
|
+
from rpcstream import (
|
|
10
|
+
rpcstream_pb2 as _github_com_aperturerobotics_starpc_rpcstream_rpcstream_pb2,
|
|
11
|
+
)
|
|
12
|
+
from starpc.client import Client
|
|
13
|
+
from starpc.server import ServiceRegistry
|
|
14
|
+
from starpc.service import ServiceDescriptor
|
|
15
|
+
|
|
16
|
+
ECHOER_SERVICE: ServiceDescriptor
|
|
17
|
+
|
|
18
|
+
class EchoerClient:
|
|
19
|
+
def __init__(self, client: Client, service: str | None = None) -> None: ...
|
|
20
|
+
async def echo(
|
|
21
|
+
self, request: _github_com_aperturerobotics_starpc_echo_echo_pb2.EchoMsg
|
|
22
|
+
) -> _github_com_aperturerobotics_starpc_echo_echo_pb2.EchoMsg: ...
|
|
23
|
+
def echo_server_stream(
|
|
24
|
+
self, request: _github_com_aperturerobotics_starpc_echo_echo_pb2.EchoMsg
|
|
25
|
+
) -> AsyncIterator[_github_com_aperturerobotics_starpc_echo_echo_pb2.EchoMsg]: ...
|
|
26
|
+
async def echo_client_stream(
|
|
27
|
+
self,
|
|
28
|
+
requests: AsyncIterable[
|
|
29
|
+
_github_com_aperturerobotics_starpc_echo_echo_pb2.EchoMsg
|
|
30
|
+
],
|
|
31
|
+
) -> _github_com_aperturerobotics_starpc_echo_echo_pb2.EchoMsg: ...
|
|
32
|
+
def echo_bidi_stream(
|
|
33
|
+
self,
|
|
34
|
+
requests: AsyncIterable[
|
|
35
|
+
_github_com_aperturerobotics_starpc_echo_echo_pb2.EchoMsg
|
|
36
|
+
],
|
|
37
|
+
) -> AsyncIterator[_github_com_aperturerobotics_starpc_echo_echo_pb2.EchoMsg]: ...
|
|
38
|
+
def rpc_stream(
|
|
39
|
+
self,
|
|
40
|
+
requests: AsyncIterable[
|
|
41
|
+
_github_com_aperturerobotics_starpc_rpcstream_rpcstream_pb2.RpcStreamPacket
|
|
42
|
+
],
|
|
43
|
+
) -> AsyncIterator[
|
|
44
|
+
_github_com_aperturerobotics_starpc_rpcstream_rpcstream_pb2.RpcStreamPacket
|
|
45
|
+
]: ...
|
|
46
|
+
async def do_nothing(
|
|
47
|
+
self, request: _google_protobuf_empty_pb2.Empty
|
|
48
|
+
) -> _google_protobuf_empty_pb2.Empty: ...
|
|
49
|
+
|
|
50
|
+
class EchoerServer(Protocol):
|
|
51
|
+
async def echo(
|
|
52
|
+
self, request: _github_com_aperturerobotics_starpc_echo_echo_pb2.EchoMsg
|
|
53
|
+
) -> _github_com_aperturerobotics_starpc_echo_echo_pb2.EchoMsg: ...
|
|
54
|
+
def echo_server_stream(
|
|
55
|
+
self, request: _github_com_aperturerobotics_starpc_echo_echo_pb2.EchoMsg
|
|
56
|
+
) -> AsyncIterator[_github_com_aperturerobotics_starpc_echo_echo_pb2.EchoMsg]: ...
|
|
57
|
+
async def echo_client_stream(
|
|
58
|
+
self,
|
|
59
|
+
requests: AsyncIterator[
|
|
60
|
+
_github_com_aperturerobotics_starpc_echo_echo_pb2.EchoMsg
|
|
61
|
+
],
|
|
62
|
+
) -> _github_com_aperturerobotics_starpc_echo_echo_pb2.EchoMsg: ...
|
|
63
|
+
def echo_bidi_stream(
|
|
64
|
+
self,
|
|
65
|
+
requests: AsyncIterator[
|
|
66
|
+
_github_com_aperturerobotics_starpc_echo_echo_pb2.EchoMsg
|
|
67
|
+
],
|
|
68
|
+
) -> AsyncIterator[_github_com_aperturerobotics_starpc_echo_echo_pb2.EchoMsg]: ...
|
|
69
|
+
def rpc_stream(
|
|
70
|
+
self,
|
|
71
|
+
requests: AsyncIterator[
|
|
72
|
+
_github_com_aperturerobotics_starpc_rpcstream_rpcstream_pb2.RpcStreamPacket
|
|
73
|
+
],
|
|
74
|
+
) -> AsyncIterator[
|
|
75
|
+
_github_com_aperturerobotics_starpc_rpcstream_rpcstream_pb2.RpcStreamPacket
|
|
76
|
+
]: ...
|
|
77
|
+
async def do_nothing(
|
|
78
|
+
self, request: _google_protobuf_empty_pb2.Empty
|
|
79
|
+
) -> _google_protobuf_empty_pb2.Empty: ...
|
|
80
|
+
|
|
81
|
+
def register_echoer(
|
|
82
|
+
registry: ServiceRegistry,
|
|
83
|
+
implementation: EchoerServer,
|
|
84
|
+
service: str = "echo.Echoer",
|
|
85
|
+
) -> None: ...
|
package/go.mod
CHANGED
|
@@ -3,7 +3,7 @@ module github.com/aperturerobotics/starpc
|
|
|
3
3
|
go 1.25.0
|
|
4
4
|
|
|
5
5
|
require (
|
|
6
|
-
github.com/aperturerobotics/common v0.35.0 // latest
|
|
6
|
+
github.com/aperturerobotics/common v0.35.1-0.20260808123156-c77af26f63bd // latest
|
|
7
7
|
github.com/aperturerobotics/protobuf-go-lite v0.16.0 // latest
|
|
8
8
|
github.com/aperturerobotics/util v1.34.9 // latest
|
|
9
9
|
)
|
|
@@ -12,7 +12,7 @@ require (
|
|
|
12
12
|
github.com/aperturerobotics/abseil-cpp v0.0.0-20260131110040-4bb56e2f9017 // aperture-2
|
|
13
13
|
github.com/aperturerobotics/cli v1.1.0 // indirect
|
|
14
14
|
github.com/aperturerobotics/go-protoc-gen-prost v0.0.0-20260705010911-9f53feac967b // indirect
|
|
15
|
-
github.com/aperturerobotics/go-protoc-wasi v0.0.0-
|
|
15
|
+
github.com/aperturerobotics/go-protoc-wasi v0.0.0-20260808023521-7b1595380c3f // indirect
|
|
16
16
|
github.com/aperturerobotics/go-websocket v1.8.15-0.20260619192713-a096778f08c1 // master
|
|
17
17
|
github.com/aperturerobotics/json-iterator-lite v1.1.0 // indirect
|
|
18
18
|
github.com/aperturerobotics/protobuf v0.0.0-20260203024654-8201686529c4 // wasi
|
package/go.sum
CHANGED
|
@@ -6,10 +6,24 @@ github.com/aperturerobotics/common v0.34.4 h1:RQTOm6LxEnucXkED/kruhKKAOL6tbaPzMg
|
|
|
6
6
|
github.com/aperturerobotics/common v0.34.4/go.mod h1:xnb1VBRs3x2o1PaKg0OlP7SqDaC9Hmrmt9xH85rOS+A=
|
|
7
7
|
github.com/aperturerobotics/common v0.35.0 h1:VU4OPMXJyqT37lTOtNEMa3QLW5tR8YIBAKbjgxSzuZs=
|
|
8
8
|
github.com/aperturerobotics/common v0.35.0/go.mod h1:xnb1VBRs3x2o1PaKg0OlP7SqDaC9Hmrmt9xH85rOS+A=
|
|
9
|
+
github.com/aperturerobotics/common v0.35.1-0.20260808094909-49d3232b4f83 h1:QkFoyeJ0QBw21a+1YR0kB+JaBSY2mHFiIGiFwWUJ/wQ=
|
|
10
|
+
github.com/aperturerobotics/common v0.35.1-0.20260808094909-49d3232b4f83/go.mod h1:sPjrQZeS/yr9kBro4rN2BrYvG9TCn1eIGk7dMH/E2NQ=
|
|
11
|
+
github.com/aperturerobotics/common v0.35.1-0.20260808095531-8f6fd4367389 h1:J/vc+AKFh8hIVJJ2LrAJVwEgIYvFeQ5XANg3dK3OnYk=
|
|
12
|
+
github.com/aperturerobotics/common v0.35.1-0.20260808095531-8f6fd4367389/go.mod h1:sPjrQZeS/yr9kBro4rN2BrYvG9TCn1eIGk7dMH/E2NQ=
|
|
13
|
+
github.com/aperturerobotics/common v0.35.1-0.20260808100945-fe2b561bec93 h1:Bc7ThfLt5ekHZmOH9vGW0PiiuVUl1R+vneFH/G0j5D4=
|
|
14
|
+
github.com/aperturerobotics/common v0.35.1-0.20260808100945-fe2b561bec93/go.mod h1:sPjrQZeS/yr9kBro4rN2BrYvG9TCn1eIGk7dMH/E2NQ=
|
|
15
|
+
github.com/aperturerobotics/common v0.35.1-0.20260808101203-caeb6303ba93 h1:JoERBAX9HuOzopNLZQCT851YnYz9h9nYSpEe6XjcP0o=
|
|
16
|
+
github.com/aperturerobotics/common v0.35.1-0.20260808101203-caeb6303ba93/go.mod h1:sPjrQZeS/yr9kBro4rN2BrYvG9TCn1eIGk7dMH/E2NQ=
|
|
17
|
+
github.com/aperturerobotics/common v0.35.1-0.20260808102028-33a08259dd38 h1:c3IXUqJHt1EAlCyD0d0IrI7YYf4txwICtoh+ylQV6tU=
|
|
18
|
+
github.com/aperturerobotics/common v0.35.1-0.20260808102028-33a08259dd38/go.mod h1:sPjrQZeS/yr9kBro4rN2BrYvG9TCn1eIGk7dMH/E2NQ=
|
|
19
|
+
github.com/aperturerobotics/common v0.35.1-0.20260808123156-c77af26f63bd h1:BTfB1V2X+u3/56negSjrx+AWg+Uk84rFFryvpGTj7f4=
|
|
20
|
+
github.com/aperturerobotics/common v0.35.1-0.20260808123156-c77af26f63bd/go.mod h1:sPjrQZeS/yr9kBro4rN2BrYvG9TCn1eIGk7dMH/E2NQ=
|
|
9
21
|
github.com/aperturerobotics/go-protoc-gen-prost v0.0.0-20260705010911-9f53feac967b h1:MMk+AbWPCMfqc2Lm2bJl8lCCsuvlM2+C0CP10fpE3bc=
|
|
10
22
|
github.com/aperturerobotics/go-protoc-gen-prost v0.0.0-20260705010911-9f53feac967b/go.mod h1:OBb/beWmr/pDIZAUfi86j/4tBh2v5ctTxKMqSnh9c/4=
|
|
11
23
|
github.com/aperturerobotics/go-protoc-wasi v0.0.0-20260712054757-d8078c296c17 h1:WT1YmZjJf8fUF1zKbeNNKXFA+t8Wtbr8AVMAmdKcrUU=
|
|
12
24
|
github.com/aperturerobotics/go-protoc-wasi v0.0.0-20260712054757-d8078c296c17/go.mod h1:vEq8i7EKb32+KXGtIEZjjhNns+BdsL2dUMw4uhy3578=
|
|
25
|
+
github.com/aperturerobotics/go-protoc-wasi v0.0.0-20260808023521-7b1595380c3f h1:UszdpmKBfQd0LdOZjypeRGrHz2tcPpmKpw6SV3DYyN0=
|
|
26
|
+
github.com/aperturerobotics/go-protoc-wasi v0.0.0-20260808023521-7b1595380c3f/go.mod h1:vEq8i7EKb32+KXGtIEZjjhNns+BdsL2dUMw4uhy3578=
|
|
13
27
|
github.com/aperturerobotics/go-websocket v1.8.15-0.20260619192713-a096778f08c1 h1:q2qkdNOrnhAFf6B7TBeUoAYstYWxPvozN+3vJi2jgp0=
|
|
14
28
|
github.com/aperturerobotics/go-websocket v1.8.15-0.20260619192713-a096778f08c1/go.mod h1:9KnSGuqxSXbdB/Oi0I6vvfPLkclfJwMGAQaDDGVgGow=
|
|
15
29
|
github.com/aperturerobotics/json-iterator-lite v1.1.0 h1:ZLLqHhHTKYlmCAP873ras2e/yVU/THtwC+ji3tXLMMg=
|
|
@@ -6,19 +6,23 @@ import (
|
|
|
6
6
|
"io"
|
|
7
7
|
"net"
|
|
8
8
|
"os"
|
|
9
|
+
"strings"
|
|
9
10
|
|
|
10
11
|
"github.com/aperturerobotics/starpc/echo"
|
|
12
|
+
"github.com/aperturerobotics/starpc/rpcstream"
|
|
11
13
|
"github.com/aperturerobotics/starpc/srpc"
|
|
12
14
|
)
|
|
13
15
|
|
|
14
16
|
const bodyTxt = "hello world via starpc cross-language e2e test"
|
|
15
17
|
|
|
16
18
|
func main() {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
+
nested := len(os.Args) >= 3 && os.Args[1] == "--nested"
|
|
20
|
+
nestedRelease := len(os.Args) >= 3 && os.Args[1] == "--nested-release"
|
|
21
|
+
if len(os.Args) != 2 && !nested && !nestedRelease {
|
|
22
|
+
fmt.Fprintf(os.Stderr, "usage: go-client [--nested] <addr>\n")
|
|
19
23
|
os.Exit(1)
|
|
20
24
|
}
|
|
21
|
-
addr := os.Args[1]
|
|
25
|
+
addr := os.Args[len(os.Args)-1]
|
|
22
26
|
openStream := func(ctx context.Context, msgHandler srpc.PacketDataHandler, closeHandler srpc.CloseHandler) (srpc.PacketWriter, error) {
|
|
23
27
|
conn, err := net.Dial("tcp", addr) //nolint:gosec
|
|
24
28
|
if err != nil {
|
|
@@ -48,6 +52,12 @@ func main() {
|
|
|
48
52
|
fmt.Fprintf(os.Stderr, "bidi stream test failed: %v\n", err)
|
|
49
53
|
os.Exit(1)
|
|
50
54
|
}
|
|
55
|
+
if nested || nestedRelease {
|
|
56
|
+
if err := testNested(ctx, echoClient, nestedRelease); err != nil {
|
|
57
|
+
fmt.Fprintf(os.Stderr, "nested lifecycle test failed: %v\n", err)
|
|
58
|
+
os.Exit(1)
|
|
59
|
+
}
|
|
60
|
+
}
|
|
51
61
|
fmt.Println("All tests passed.")
|
|
52
62
|
}
|
|
53
63
|
|
|
@@ -143,3 +153,69 @@ func testBidiStream(ctx context.Context, client echo.SRPCEchoerClient) error {
|
|
|
143
153
|
fmt.Println(" PASSED")
|
|
144
154
|
return nil
|
|
145
155
|
}
|
|
156
|
+
|
|
157
|
+
func testNested(ctx context.Context, parent echo.SRPCEchoerClient, release bool) error {
|
|
158
|
+
proxy := rpcstream.NewRpcStreamClient(parent.RpcStream, "test", true)
|
|
159
|
+
if err := testUnary(ctx, echo.NewSRPCEchoerClient(proxy)); err != nil {
|
|
160
|
+
return fmt.Errorf("nested unary: %w", err)
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if release {
|
|
164
|
+
missing := rpcstream.NewRpcStreamClient(parent.RpcStream, "missing", true)
|
|
165
|
+
var missingOut echo.EchoMsg
|
|
166
|
+
if err := missing.ExecCall(ctx, "echo.Echoer", "Echo", &echo.EchoMsg{}, &missingOut); err == nil || !strings.Contains(err.Error(), "unknown component: missing") {
|
|
167
|
+
return fmt.Errorf("unknown component returned wrong result: %v", err)
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
stream, err := proxy.NewStream(ctx, "echo.Echoer", "EchoBidiStream", nil)
|
|
172
|
+
if err != nil {
|
|
173
|
+
return fmt.Errorf("nested bidi: %w", err)
|
|
174
|
+
}
|
|
175
|
+
if err := stream.MsgSend(&echo.EchoMsg{Body: "nested later data"}); err != nil {
|
|
176
|
+
return fmt.Errorf("nested later data: %w", err)
|
|
177
|
+
}
|
|
178
|
+
if err := stream.Close(); err != nil {
|
|
179
|
+
return fmt.Errorf("nested cancel: %w", err)
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
var terminal echo.EchoMsg
|
|
183
|
+
if err := proxy.ExecCall(ctx, "missing.Service", "Missing", &echo.EchoMsg{}, &terminal); err == nil || !strings.Contains(err.Error(), "missing.Service") {
|
|
184
|
+
return fmt.Errorf("unknown nested method returned wrong result: %v", err)
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
if release {
|
|
188
|
+
var terminalError echo.EchoMsg
|
|
189
|
+
if err := proxy.ExecCall(ctx, "echo.Echoer", "Echo", &echo.EchoMsg{Body: "__nested_error__"}, &terminalError); err == nil || !strings.Contains(err.Error(), "nested terminal error") {
|
|
190
|
+
return fmt.Errorf("terminal nested error returned wrong result: %v", err)
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
if release {
|
|
195
|
+
releaseClient := rpcstream.NewRpcStreamClient(parent.RpcStream, "release", true)
|
|
196
|
+
var released echo.EchoMsg
|
|
197
|
+
err := releaseClient.ExecCall(ctx, "echo.Echoer", "Echo", &echo.EchoMsg{Body: "__nested_release__"}, &released)
|
|
198
|
+
if err == nil || (!strings.Contains(err.Error(), "stream closed before the remote reported completion") && !strings.Contains(err.Error(), "EOF") && !strings.Contains(err.Error(), "canceled")) {
|
|
199
|
+
return fmt.Errorf("release during active call returned wrong result: %v", err)
|
|
200
|
+
}
|
|
201
|
+
status, err := parent.Echo(ctx, &echo.EchoMsg{Body: "__nested_release_status__"})
|
|
202
|
+
if err != nil {
|
|
203
|
+
return fmt.Errorf("release completion status failed: %w", err)
|
|
204
|
+
}
|
|
205
|
+
if status.GetBody() != "released" {
|
|
206
|
+
return fmt.Errorf("release completion returned %q", status.GetBody())
|
|
207
|
+
}
|
|
208
|
+
if err := releaseClient.ExecCall(ctx, "echo.Echoer", "Echo", &echo.EchoMsg{}, &released); err == nil || !strings.Contains(err.Error(), "unknown component: release") {
|
|
209
|
+
return fmt.Errorf("released component returned wrong result: %v", err)
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
direct, err := rpcstream.OpenRpcStream(ctx, parent.RpcStream, "test", true)
|
|
214
|
+
if err != nil {
|
|
215
|
+
return fmt.Errorf("nested direct open: %w", err)
|
|
216
|
+
}
|
|
217
|
+
if err := direct.Close(); err != nil {
|
|
218
|
+
return fmt.Errorf("nested abrupt close: %w", err)
|
|
219
|
+
}
|
|
220
|
+
return nil
|
|
221
|
+
}
|