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.
Files changed (152) hide show
  1. package/README.md +37 -8
  2. package/dist/echo/client-test.d.ts +1 -1
  3. package/dist/echo/client-test.js +110 -2
  4. package/dist/integration/cross-language/tcp-packet-stream.d.ts +3 -0
  5. package/dist/integration/cross-language/tcp-packet-stream.js +112 -0
  6. package/dist/integration/cross-language/tcp-packet-stream.test.d.ts +1 -0
  7. package/dist/integration/cross-language/tcp-packet-stream.test.js +121 -0
  8. package/dist/integration/cross-language/ts-client.js +50 -37
  9. package/dist/integration/cross-language/ts-server.js +1 -36
  10. package/dist/rpcstream/rpcstream.d.ts +5 -1
  11. package/dist/rpcstream/rpcstream.js +75 -28
  12. package/dist/rpcstream/rpcstream.test.d.ts +1 -0
  13. package/dist/rpcstream/rpcstream.test.js +92 -0
  14. package/dist/srpc/client-rpc.d.ts +1 -0
  15. package/dist/srpc/client-rpc.js +9 -0
  16. package/dist/srpc/client-rpc.test.d.ts +1 -0
  17. package/dist/srpc/client-rpc.test.js +50 -0
  18. package/dist/srpc/client.js +18 -4
  19. package/dist/srpc/common-rpc.d.ts +5 -0
  20. package/dist/srpc/common-rpc.js +37 -8
  21. package/dist/srpc/common-rpc.test.js +2 -0
  22. package/dist/srpc/errors.d.ts +2 -0
  23. package/dist/srpc/errors.js +14 -0
  24. package/dist/srpc/index.d.ts +1 -1
  25. package/dist/srpc/index.js +1 -1
  26. package/dist/srpc/packet-codec.test.d.ts +1 -0
  27. package/dist/srpc/packet-codec.test.js +75 -0
  28. package/dist/srpc/packet.d.ts +1 -1
  29. package/dist/srpc/packet.js +11 -1
  30. package/dist/srpc/server.js +19 -6
  31. package/dist/srpc/server.test.js +43 -0
  32. package/dist/srpc/stream.d.ts +4 -1
  33. package/dist/srpc/stream.js +62 -3
  34. package/dist/srpc/stream.test.js +110 -1
  35. package/dist/srpc/termination.d.ts +27 -0
  36. package/dist/srpc/termination.js +56 -0
  37. package/dist/srpc/termination.test.d.ts +1 -0
  38. package/dist/srpc/termination.test.js +24 -0
  39. package/dist/testdata/packet-codec-vectors.json +64 -0
  40. package/echo/Cargo.toml +8 -0
  41. package/echo/client-test.ts +124 -2
  42. package/echo/echo_e2e_test.cpp +542 -985
  43. package/echo/echo_pb2.py +40 -0
  44. package/echo/echo_pb2.pyi +13 -0
  45. package/echo/echo_srpc.pb.cpp +3 -5
  46. package/echo/echo_srpc.pb.go +6 -9
  47. package/echo/echo_srpc.pb.hpp +23 -3
  48. package/echo/echo_srpc.pb.rs +61 -26
  49. package/echo/echo_srpc.py +309 -0
  50. package/echo/echo_srpc.pyi +85 -0
  51. package/echo/half_close_test.rs +178 -0
  52. package/echo/integration_server.rs +14 -21
  53. package/echo/main.rs +28 -48
  54. package/go.mod +3 -3
  55. package/go.sum +6 -8
  56. package/integration/cross-language/cpp-client.cpp +446 -402
  57. package/integration/cross-language/cpp-pipe-server.cpp +139 -0
  58. package/integration/cross-language/cpp-pipe_test.go +114 -0
  59. package/integration/cross-language/cpp-server.cpp +222 -186
  60. package/integration/cross-language/go-client/main.go +79 -3
  61. package/integration/cross-language/python-client.py +146 -0
  62. package/integration/cross-language/python-server.py +140 -0
  63. package/integration/cross-language/run.bash +190 -65
  64. package/integration/cross-language/tcp-packet-stream.test.ts +154 -0
  65. package/integration/cross-language/tcp-packet-stream.ts +121 -0
  66. package/integration/cross-language/ts-client.ts +62 -40
  67. package/integration/cross-language/ts-server.ts +1 -45
  68. package/mock/mock_pb2.py +38 -0
  69. package/mock/mock_pb2.pyi +11 -0
  70. package/mock/mock_srpc.pb.cpp +1 -1
  71. package/mock/mock_srpc.pb.hpp +1 -1
  72. package/mock/mock_srpc.pb.rs +10 -9
  73. package/mock/mock_srpc.py +71 -0
  74. package/mock/mock_srpc.pyi +27 -0
  75. package/package.json +19 -5
  76. package/srpc/CMakeLists.txt +3 -58
  77. package/srpc/README-cpp.md +69 -0
  78. package/srpc/__init__.py +0 -0
  79. package/srpc/accept.go +10 -4
  80. package/srpc/accept_test.go +25 -0
  81. package/srpc/build.rs +129 -34
  82. package/srpc/client-half-close_test.go +152 -0
  83. package/srpc/client-invoker.go +32 -42
  84. package/srpc/client-invoker_test.go +53 -0
  85. package/srpc/client-rpc.cpp +65 -80
  86. package/srpc/client-rpc.go +32 -33
  87. package/srpc/client-rpc.hpp +52 -38
  88. package/srpc/client-rpc.test.ts +67 -0
  89. package/srpc/client-rpc.ts +10 -0
  90. package/srpc/client-rpc_test.go +76 -0
  91. package/srpc/client.cpp +99 -87
  92. package/srpc/client.hpp +46 -35
  93. package/srpc/client.rs +78 -38
  94. package/srpc/client.ts +20 -4
  95. package/srpc/client_half_close_test.cc +331 -0
  96. package/srpc/client_invoker.rs +75 -0
  97. package/srpc/codec.rs +6 -0
  98. package/srpc/common-rpc.cpp +186 -146
  99. package/srpc/common-rpc.go +5 -4
  100. package/srpc/common-rpc.hpp +119 -89
  101. package/srpc/common-rpc.test.ts +2 -0
  102. package/srpc/common-rpc.ts +43 -8
  103. package/srpc/common-rpc_test.go +23 -0
  104. package/srpc/error.rs +19 -2
  105. package/srpc/errors.hpp +80 -50
  106. package/srpc/errors.ts +16 -0
  107. package/srpc/handler.hpp +9 -7
  108. package/srpc/handler.rs +7 -45
  109. package/srpc/index.ts +2 -0
  110. package/srpc/invoker.hpp +82 -55
  111. package/srpc/invoker.rs +14 -52
  112. package/srpc/lib.rs +2 -0
  113. package/srpc/message.hpp +17 -12
  114. package/srpc/msg-stream.go +1 -0
  115. package/srpc/msg-stream.hpp +108 -61
  116. package/srpc/mux.cpp +84 -84
  117. package/srpc/mux.hpp +48 -38
  118. package/srpc/mux.rs +4 -4
  119. package/srpc/net.go +12 -3
  120. package/srpc/packet-codec-vectors_test.go +195 -0
  121. package/srpc/packet-codec.test.ts +139 -0
  122. package/srpc/packet-rw.go +9 -2
  123. package/srpc/packet.cpp +60 -58
  124. package/srpc/packet.hpp +35 -20
  125. package/srpc/packet.rs +8 -27
  126. package/srpc/packet.ts +15 -2
  127. package/srpc/py.typed +0 -0
  128. package/srpc/rpc.rs +332 -115
  129. package/srpc/rpc_lifecycle_test.cc +333 -0
  130. package/srpc/rpcproto_pb2.py +40 -0
  131. package/srpc/rpcproto_pb2.pyi +40 -0
  132. package/srpc/server-cancel_test.go +39 -0
  133. package/srpc/server-rpc.cpp +83 -73
  134. package/srpc/server-rpc.go +21 -19
  135. package/srpc/server-rpc.hpp +56 -37
  136. package/srpc/server.rs +76 -131
  137. package/srpc/server.test.ts +50 -0
  138. package/srpc/server.ts +22 -6
  139. package/srpc/starpc.hpp +4 -2
  140. package/srpc/stream.go +4 -0
  141. package/srpc/stream.hpp +95 -34
  142. package/srpc/stream.rs +7 -2
  143. package/srpc/stream.test.ts +132 -1
  144. package/srpc/stream.ts +65 -9
  145. package/srpc/termination.test.ts +30 -0
  146. package/srpc/termination.ts +70 -0
  147. package/srpc/testing.rs +11 -66
  148. package/srpc/transport.rs +21 -71
  149. package/srpc/websocket.rs +106 -57
  150. package/srpc/writer.hpp +46 -32
  151. package/srpc/yamux.rs +82 -26
  152. 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.0",
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
  }
@@ -1,59 +1,4 @@
1
- cmake_minimum_required(VERSION 3.14)
1
+ cmake_minimum_required(VERSION 3.24)
2
2
 
3
- # C++ starpc library
4
- # This builds the core srpc library
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`.
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 incoming connections from a net.Listener.
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
+ }