starpc 0.52.0 → 0.52.2
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/README.md +37 -8
- 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-rpc.d.ts +1 -0
- package/dist/srpc/client-rpc.js +9 -0
- package/dist/srpc/client-rpc.test.d.ts +1 -0
- package/dist/srpc/client-rpc.test.js +50 -0
- package/dist/srpc/client.js +18 -4
- package/dist/srpc/common-rpc.d.ts +5 -0
- package/dist/srpc/common-rpc.js +37 -8
- package/dist/srpc/common-rpc.test.js +2 -0
- package/dist/srpc/errors.d.ts +2 -0
- package/dist/srpc/errors.js +14 -0
- package/dist/srpc/index.d.ts +1 -1
- package/dist/srpc/index.js +1 -1
- 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/Cargo.toml +8 -0
- package/echo/client-test.ts +124 -2
- package/echo/echo_e2e_test.cpp +542 -985
- package/echo/echo_pb2.py +40 -0
- package/echo/echo_pb2.pyi +13 -0
- package/echo/echo_srpc.pb.cpp +3 -5
- package/echo/echo_srpc.pb.go +6 -9
- package/echo/echo_srpc.pb.hpp +23 -3
- package/echo/echo_srpc.pb.rs +61 -26
- package/echo/echo_srpc.py +309 -0
- package/echo/echo_srpc.pyi +85 -0
- package/echo/half_close_test.rs +178 -0
- package/echo/integration_server.rs +14 -21
- package/echo/main.rs +28 -48
- package/go.mod +3 -3
- package/go.sum +6 -8
- package/integration/cross-language/cpp-client.cpp +446 -402
- package/integration/cross-language/cpp-pipe-server.cpp +139 -0
- package/integration/cross-language/cpp-pipe_test.go +114 -0
- package/integration/cross-language/cpp-server.cpp +222 -186
- 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.pb.cpp +1 -1
- package/mock/mock_srpc.pb.hpp +1 -1
- package/mock/mock_srpc.pb.rs +10 -9
- package/mock/mock_srpc.py +71 -0
- package/mock/mock_srpc.pyi +27 -0
- package/package.json +19 -5
- package/srpc/CMakeLists.txt +3 -58
- package/srpc/README-cpp.md +69 -0
- package/srpc/__init__.py +0 -0
- package/srpc/accept.go +10 -4
- package/srpc/accept_test.go +25 -0
- package/srpc/build.rs +129 -34
- package/srpc/client-half-close_test.go +152 -0
- package/srpc/client-invoker.go +32 -42
- package/srpc/client-invoker_test.go +53 -0
- package/srpc/client-rpc.cpp +65 -80
- package/srpc/client-rpc.go +32 -33
- package/srpc/client-rpc.hpp +52 -38
- package/srpc/client-rpc.test.ts +67 -0
- package/srpc/client-rpc.ts +10 -0
- package/srpc/client-rpc_test.go +76 -0
- package/srpc/client.cpp +99 -87
- package/srpc/client.hpp +46 -35
- package/srpc/client.rs +78 -38
- package/srpc/client.ts +20 -4
- package/srpc/client_half_close_test.cc +331 -0
- package/srpc/client_invoker.rs +75 -0
- package/srpc/codec.rs +6 -0
- package/srpc/common-rpc.cpp +186 -146
- package/srpc/common-rpc.go +5 -4
- package/srpc/common-rpc.hpp +119 -89
- package/srpc/common-rpc.test.ts +2 -0
- package/srpc/common-rpc.ts +43 -8
- package/srpc/common-rpc_test.go +23 -0
- package/srpc/error.rs +19 -2
- package/srpc/errors.hpp +80 -50
- package/srpc/errors.ts +16 -0
- package/srpc/handler.hpp +9 -7
- package/srpc/handler.rs +7 -45
- package/srpc/index.ts +2 -0
- package/srpc/invoker.hpp +82 -55
- package/srpc/invoker.rs +14 -52
- package/srpc/lib.rs +2 -0
- package/srpc/message.hpp +17 -12
- package/srpc/msg-stream.go +1 -0
- package/srpc/msg-stream.hpp +108 -61
- package/srpc/mux.cpp +84 -84
- package/srpc/mux.hpp +48 -38
- package/srpc/mux.rs +4 -4
- package/srpc/net.go +12 -3
- 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.cpp +60 -58
- package/srpc/packet.hpp +35 -20
- package/srpc/packet.rs +8 -27
- package/srpc/packet.ts +15 -2
- package/srpc/py.typed +0 -0
- package/srpc/rpc.rs +332 -115
- package/srpc/rpc_lifecycle_test.cc +333 -0
- package/srpc/rpcproto_pb2.py +40 -0
- package/srpc/rpcproto_pb2.pyi +40 -0
- package/srpc/server-cancel_test.go +39 -0
- package/srpc/server-rpc.cpp +83 -73
- package/srpc/server-rpc.go +21 -19
- package/srpc/server-rpc.hpp +56 -37
- package/srpc/server.rs +76 -131
- package/srpc/server.test.ts +50 -0
- package/srpc/server.ts +22 -6
- package/srpc/starpc.hpp +4 -2
- package/srpc/stream.go +4 -0
- package/srpc/stream.hpp +95 -34
- package/srpc/stream.rs +7 -2
- 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
- package/srpc/testing.rs +11 -66
- package/srpc/transport.rs +21 -71
- package/srpc/websocket.rs +106 -57
- package/srpc/writer.hpp +46 -32
- package/srpc/yamux.rs +82 -26
- package/srpc/tests/integration_test.rs +0 -495
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "starpc",
|
|
3
|
-
"version": "0.52.
|
|
3
|
+
"version": "0.52.2",
|
|
4
4
|
"description": "Streaming protobuf RPC service protocol over any two-way channel.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": {
|
|
@@ -68,12 +68,12 @@
|
|
|
68
68
|
"deps": "depcheck --ignores 'bufferutil,utf-8-validate,rimraf,starpc,@aptre/protobuf-es-lite,tsx'",
|
|
69
69
|
"codegen": "bun run gen",
|
|
70
70
|
"ci": "bun run build && bun run lint:js && bun run lint:go",
|
|
71
|
-
"format": "bun run format:js && bun run format:go && bun run format:config",
|
|
71
|
+
"format": "bun run format:js && bun run format:go && bun run format:python && bun run format:config",
|
|
72
72
|
"format:config": "oxfmt '*.json' '.github/**/*.json' '.github/**/*.yml' '.oxfmtrc.json' 'tsconfig.json'",
|
|
73
73
|
"format:go": "bun run go:aptre -- format",
|
|
74
74
|
"format:js": "oxfmt './{srpc,echo,e2e,integration,rpcstream,cmd,mock,scripts}/**/*.{ts,tsx,js,mjs,html,css,scss}' '*.{ts,tsx,js,mjs}'",
|
|
75
|
-
"gen": "bun run go:aptre -- generate && bun run format",
|
|
76
|
-
"gen:force": "bun run go:aptre -- generate --force && bun run format",
|
|
75
|
+
"gen": "bun run build && bun run go:aptre -- generate && bun run format",
|
|
76
|
+
"gen:force": "bun run build && bun run go:aptre -- generate --force && bun run format",
|
|
77
77
|
"test": "bun run test:js && bun run test:go",
|
|
78
78
|
"test:go": "bun run go:aptre -- test",
|
|
79
79
|
"test:cpp": "mkdir -p build && cd build && cmake -G Ninja .. -DCMAKE_BUILD_TYPE=Release && cmake --build . --parallel && ctest --output-on-failure",
|
|
@@ -100,7 +100,8 @@
|
|
|
100
100
|
"release:version": "bun scripts/release-version.ts patch",
|
|
101
101
|
"release:version:minor": "bun scripts/release-version.ts minor",
|
|
102
102
|
"release:commit": "version=$(bun -e 'console.log(require(\"./package.json\").version)') && git reset && git add package.json Cargo.toml && git commit -s -m \"release: v$version\" && git tag \"v$version\"",
|
|
103
|
-
"release:publish": "git push && git push --tags"
|
|
103
|
+
"release:publish": "git push && git push --tags",
|
|
104
|
+
"format:python": "files=$(find echo mock -type f \\( -name '*_srpc.py' -o -name '*_srpc.pyi' \\)); if [ -n \"$files\" ]; then uv run ruff check --fix --ignore UP026 $files && uv run ruff format $files; fi"
|
|
104
105
|
},
|
|
105
106
|
"preferUnplugged": true,
|
|
106
107
|
"lint-staged": {
|
|
@@ -138,5 +139,18 @@
|
|
|
138
139
|
},
|
|
139
140
|
"overrides": {
|
|
140
141
|
"@aptre/protobuf-es-lite": "1.1.1"
|
|
142
|
+
},
|
|
143
|
+
"aptre": {
|
|
144
|
+
"languages": [
|
|
145
|
+
"go",
|
|
146
|
+
"ts",
|
|
147
|
+
"cpp",
|
|
148
|
+
"rust",
|
|
149
|
+
"python"
|
|
150
|
+
],
|
|
151
|
+
"rpc": [
|
|
152
|
+
"starpc",
|
|
153
|
+
"starpc-python"
|
|
154
|
+
]
|
|
141
155
|
}
|
|
142
156
|
}
|
package/srpc/CMakeLists.txt
CHANGED
|
@@ -1,59 +1,4 @@
|
|
|
1
|
-
cmake_minimum_required(VERSION 3.
|
|
1
|
+
cmake_minimum_required(VERSION 3.24)
|
|
2
2
|
|
|
3
|
-
#
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
set(STARPC_SOURCES
|
|
7
|
-
packet.cpp
|
|
8
|
-
common-rpc.cpp
|
|
9
|
-
client-rpc.cpp
|
|
10
|
-
server-rpc.cpp
|
|
11
|
-
mux.cpp
|
|
12
|
-
client.cpp
|
|
13
|
-
rpcproto.pb.cc
|
|
14
|
-
)
|
|
15
|
-
|
|
16
|
-
set(STARPC_HEADERS
|
|
17
|
-
starpc.hpp
|
|
18
|
-
errors.hpp
|
|
19
|
-
message.hpp
|
|
20
|
-
writer.hpp
|
|
21
|
-
packet.hpp
|
|
22
|
-
stream.hpp
|
|
23
|
-
msg-stream.hpp
|
|
24
|
-
common-rpc.hpp
|
|
25
|
-
client-rpc.hpp
|
|
26
|
-
server-rpc.hpp
|
|
27
|
-
invoker.hpp
|
|
28
|
-
handler.hpp
|
|
29
|
-
mux.hpp
|
|
30
|
-
client.hpp
|
|
31
|
-
rpcproto.pb.h
|
|
32
|
-
)
|
|
33
|
-
|
|
34
|
-
add_library(starpc ${STARPC_SOURCES})
|
|
35
|
-
|
|
36
|
-
target_include_directories(starpc PUBLIC
|
|
37
|
-
${CMAKE_CURRENT_SOURCE_DIR}/..
|
|
38
|
-
${CMAKE_CURRENT_SOURCE_DIR}
|
|
39
|
-
)
|
|
40
|
-
|
|
41
|
-
target_compile_features(starpc PUBLIC cxx_std_17)
|
|
42
|
-
|
|
43
|
-
# Link protobuf
|
|
44
|
-
find_package(Protobuf REQUIRED)
|
|
45
|
-
target_link_libraries(starpc PUBLIC protobuf::libprotobuf)
|
|
46
|
-
|
|
47
|
-
# Link threads
|
|
48
|
-
find_package(Threads REQUIRED)
|
|
49
|
-
target_link_libraries(starpc PUBLIC Threads::Threads)
|
|
50
|
-
|
|
51
|
-
# Install targets
|
|
52
|
-
install(TARGETS starpc
|
|
53
|
-
ARCHIVE DESTINATION lib
|
|
54
|
-
LIBRARY DESTINATION lib
|
|
55
|
-
)
|
|
56
|
-
|
|
57
|
-
install(FILES ${STARPC_HEADERS}
|
|
58
|
-
DESTINATION include/srpc
|
|
59
|
-
)
|
|
3
|
+
# Keep the historical subdirectory entry point on the same complete target.
|
|
4
|
+
add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/.. ${CMAKE_CURRENT_BINARY_DIR}/starpc)
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# Starpc C++
|
|
2
|
+
|
|
3
|
+
Starpc provides generated C++ clients and handlers for unary and streaming
|
|
4
|
+
protobuf RPCs. It uses the same packets as the Go, TypeScript, Rust, and Python
|
|
5
|
+
implementations. C++20 and the protobuf runtime matching the generated headers
|
|
6
|
+
are required.
|
|
7
|
+
|
|
8
|
+
## Build
|
|
9
|
+
|
|
10
|
+
```sh
|
|
11
|
+
go mod vendor
|
|
12
|
+
cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release
|
|
13
|
+
cmake --build build --parallel
|
|
14
|
+
ctest --test-dir build --output-on-failure --timeout 60
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
A parent project can use `add_subdirectory(path/to/starpc)` and link
|
|
18
|
+
`starpc::starpc`. An existing `protobuf::libprotobuf` target is reused, including
|
|
19
|
+
its include paths and compile definitions. Otherwise, set
|
|
20
|
+
`STARPC_USE_SYSTEM_PROTOBUF=ON` to find an installed protobuf package, or vendor
|
|
21
|
+
Go dependencies before configuring. Tests and examples default to off when
|
|
22
|
+
Starpc is a subdirectory. The library includes the nested RPC messages even
|
|
23
|
+
when examples are disabled.
|
|
24
|
+
|
|
25
|
+
Generate service bindings with `protoc-gen-starpc-cpp`. The generated streaming
|
|
26
|
+
wrappers expose `Send`, `Recv`, `Close`, `CloseSend`, and `StopToken` as applicable.
|
|
27
|
+
See `echo/echo.proto` and its generated bindings for each RPC shape.
|
|
28
|
+
|
|
29
|
+
## Connect a transport
|
|
30
|
+
|
|
31
|
+
One Starpc call uses one ordered, bidirectional packet stream. A streaming RPC
|
|
32
|
+
can carry successive commands and events over a single process connection.
|
|
33
|
+
Independent concurrent calls require separate streams from the transport.
|
|
34
|
+
|
|
35
|
+
A C++ server lends an `Invoker` and `PacketWriter` to `ServerRPC`, then feeds
|
|
36
|
+
received packets to `HandlePacketData`. Call `HandleStreamClose` when input ends,
|
|
37
|
+
including errors. Serialize those input callbacks. Destruction cancels the call
|
|
38
|
+
and joins its handler before the borrowed objects can be released.
|
|
39
|
+
|
|
40
|
+
For a client, supply an `OpenStreamFunc` to `NewClient`. Its returned writer must
|
|
41
|
+
keep receive callbacks alive until destruction. `Close` must interrupt blocked
|
|
42
|
+
transport reads and writes without waiting for those callbacks; destruction must
|
|
43
|
+
join any receive thread. This permits a callback to close its own transport.
|
|
44
|
+
|
|
45
|
+
Packet writers serialize their writes and allow `Close` concurrently with a
|
|
46
|
+
write. Close is idempotent. A byte-stream transport uses a four-byte unsigned
|
|
47
|
+
little-endian length followed by the serialized `srpc.Packet`, matching Go's
|
|
48
|
+
`PacketReadWriter`. Reject empty frames and frames larger than 10,000,000 bytes
|
|
49
|
+
before allocating their bodies. The process-pipe integration test demonstrates
|
|
50
|
+
this framing with a Go client and a C++ child process.
|
|
51
|
+
|
|
52
|
+
## Cancellation and completion
|
|
53
|
+
|
|
54
|
+
`CloseSend` ends outgoing messages while allowing incoming replies. Once the
|
|
55
|
+
request is written, the half-close is only a notice: it fails when the call
|
|
56
|
+
already ended, so generated callers ignore its error and read the outcome with
|
|
57
|
+
`MsgRecv`. Explicit remote completion becomes EOF after queued messages are
|
|
58
|
+
read. A disconnected
|
|
59
|
+
transport without completion returns `ClosedBeforeCompletion`. Remote errors
|
|
60
|
+
return `RemoteError`; `CommonRPC::RemoteErrorMessage` retains the peer's text.
|
|
61
|
+
|
|
62
|
+
Handlers performing work outside `Recv` must observe their stream's `StopToken`.
|
|
63
|
+
Destroying a server waits for its handler to return; it cannot forcibly terminate
|
|
64
|
+
application code that ignores cancellation. Dropping a client stream closes its
|
|
65
|
+
transport and releases its receive thread. Nested RPCs release their service
|
|
66
|
+
only after the nested handler returns.
|
|
67
|
+
|
|
68
|
+
An unread C++ call is limited to 4 MiB or 1,024 queued messages, including empty
|
|
69
|
+
messages. Exceeding either bound ends the call with `ResourceExhausted`.
|
package/srpc/__init__.py
ADDED
|
File without changes
|
package/srpc/accept.go
CHANGED
|
@@ -7,14 +7,20 @@ import (
|
|
|
7
7
|
"github.com/libp2p/go-yamux/v5"
|
|
8
8
|
)
|
|
9
9
|
|
|
10
|
-
// AcceptMuxedListener accepts
|
|
11
|
-
//
|
|
12
|
-
// Uses the default yamux muxer.
|
|
13
|
-
// If yamux conf is nil, uses the defaults.
|
|
10
|
+
// AcceptMuxedListener accepts connections until ctx is canceled or the listener
|
|
11
|
+
// fails. Cancellation closes lis to interrupt Accept. A nil yamuxConf uses defaults.
|
|
14
12
|
func AcceptMuxedListener(ctx context.Context, lis net.Listener, srv *Server, yamuxConf *yamux.Config) error {
|
|
13
|
+
// Interrupt a blocked Accept when its serving context ends.
|
|
14
|
+
stop := context.AfterFunc(ctx, func() { _ = lis.Close() })
|
|
15
|
+
defer stop()
|
|
16
|
+
|
|
17
|
+
// Transfer accepted connections to the server and release rejected ones.
|
|
15
18
|
for {
|
|
16
19
|
nc, err := lis.Accept()
|
|
17
20
|
if err != nil {
|
|
21
|
+
if ctx.Err() != nil {
|
|
22
|
+
return ctx.Err()
|
|
23
|
+
}
|
|
18
24
|
return err
|
|
19
25
|
}
|
|
20
26
|
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
package srpc
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"context"
|
|
5
|
+
"errors"
|
|
6
|
+
"net"
|
|
7
|
+
"testing"
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
func TestAcceptMuxedListenerCancellation(t *testing.T) {
|
|
11
|
+
// An idle listener must not retain a blocked Accept after cancellation.
|
|
12
|
+
listener, err := net.Listen("tcp", "127.0.0.1:0")
|
|
13
|
+
if err != nil {
|
|
14
|
+
t.Fatal(err)
|
|
15
|
+
}
|
|
16
|
+
t.Cleanup(func() { _ = listener.Close() })
|
|
17
|
+
ctx, cancel := context.WithCancel(t.Context())
|
|
18
|
+
t.Cleanup(cancel)
|
|
19
|
+
done := make(chan error, 1)
|
|
20
|
+
go func() { done <- AcceptMuxedListener(ctx, listener, nil, nil) }()
|
|
21
|
+
cancel()
|
|
22
|
+
if err := <-done; !errors.Is(err, context.Canceled) {
|
|
23
|
+
t.Fatalf("listener cancellation returned %v", err)
|
|
24
|
+
}
|
|
25
|
+
}
|