starpc 0.52.1 → 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 (91) hide show
  1. package/README.md +37 -8
  2. package/dist/srpc/client-rpc.d.ts +1 -0
  3. package/dist/srpc/client-rpc.js +9 -0
  4. package/dist/srpc/client-rpc.test.d.ts +1 -0
  5. package/dist/srpc/client-rpc.test.js +50 -0
  6. package/dist/srpc/common-rpc.d.ts +5 -0
  7. package/dist/srpc/common-rpc.js +37 -8
  8. package/dist/srpc/errors.d.ts +2 -0
  9. package/dist/srpc/errors.js +14 -0
  10. package/dist/srpc/index.d.ts +1 -1
  11. package/dist/srpc/index.js +1 -1
  12. package/echo/Cargo.toml +8 -0
  13. package/echo/echo_e2e_test.cpp +542 -985
  14. package/echo/echo_srpc.pb.cpp +3 -5
  15. package/echo/echo_srpc.pb.go +6 -9
  16. package/echo/echo_srpc.pb.hpp +23 -3
  17. package/echo/echo_srpc.pb.rs +61 -26
  18. package/echo/echo_srpc.py +4 -1
  19. package/echo/half_close_test.rs +178 -0
  20. package/echo/integration_server.rs +14 -21
  21. package/echo/main.rs +28 -48
  22. package/go.mod +1 -1
  23. package/go.sum +2 -18
  24. package/integration/cross-language/cpp-client.cpp +446 -402
  25. package/integration/cross-language/cpp-pipe-server.cpp +139 -0
  26. package/integration/cross-language/cpp-pipe_test.go +114 -0
  27. package/integration/cross-language/cpp-server.cpp +222 -186
  28. package/mock/mock_srpc.pb.cpp +1 -1
  29. package/mock/mock_srpc.pb.hpp +1 -1
  30. package/mock/mock_srpc.pb.rs +10 -9
  31. package/package.json +1 -1
  32. package/srpc/CMakeLists.txt +3 -58
  33. package/srpc/README-cpp.md +69 -0
  34. package/srpc/accept.go +10 -4
  35. package/srpc/accept_test.go +25 -0
  36. package/srpc/build.rs +129 -34
  37. package/srpc/client-half-close_test.go +152 -0
  38. package/srpc/client-invoker.go +32 -42
  39. package/srpc/client-invoker_test.go +53 -0
  40. package/srpc/client-rpc.cpp +65 -80
  41. package/srpc/client-rpc.go +32 -33
  42. package/srpc/client-rpc.hpp +52 -38
  43. package/srpc/client-rpc.test.ts +67 -0
  44. package/srpc/client-rpc.ts +10 -0
  45. package/srpc/client-rpc_test.go +76 -0
  46. package/srpc/client.cpp +99 -87
  47. package/srpc/client.hpp +46 -35
  48. package/srpc/client.rs +78 -38
  49. package/srpc/client_half_close_test.cc +331 -0
  50. package/srpc/client_invoker.rs +75 -0
  51. package/srpc/common-rpc.cpp +186 -146
  52. package/srpc/common-rpc.go +5 -4
  53. package/srpc/common-rpc.hpp +119 -89
  54. package/srpc/common-rpc.ts +43 -8
  55. package/srpc/common-rpc_test.go +23 -0
  56. package/srpc/error.rs +19 -2
  57. package/srpc/errors.hpp +80 -50
  58. package/srpc/errors.ts +16 -0
  59. package/srpc/handler.hpp +9 -7
  60. package/srpc/handler.rs +7 -45
  61. package/srpc/index.ts +2 -0
  62. package/srpc/invoker.hpp +82 -55
  63. package/srpc/invoker.rs +14 -52
  64. package/srpc/lib.rs +2 -0
  65. package/srpc/message.hpp +17 -12
  66. package/srpc/msg-stream.go +1 -0
  67. package/srpc/msg-stream.hpp +108 -61
  68. package/srpc/mux.cpp +84 -84
  69. package/srpc/mux.hpp +48 -38
  70. package/srpc/mux.rs +4 -4
  71. package/srpc/net.go +12 -3
  72. package/srpc/packet.cpp +60 -58
  73. package/srpc/packet.hpp +35 -20
  74. package/srpc/packet.rs +8 -27
  75. package/srpc/rpc.rs +332 -115
  76. package/srpc/rpc_lifecycle_test.cc +333 -0
  77. package/srpc/server-cancel_test.go +39 -0
  78. package/srpc/server-rpc.cpp +83 -73
  79. package/srpc/server-rpc.go +21 -19
  80. package/srpc/server-rpc.hpp +56 -37
  81. package/srpc/server.rs +76 -131
  82. package/srpc/starpc.hpp +4 -2
  83. package/srpc/stream.go +4 -0
  84. package/srpc/stream.hpp +95 -34
  85. package/srpc/stream.rs +7 -2
  86. package/srpc/testing.rs +11 -66
  87. package/srpc/transport.rs +21 -71
  88. package/srpc/websocket.rs +106 -57
  89. package/srpc/writer.hpp +46 -32
  90. package/srpc/yamux.rs +82 -26
  91. package/srpc/tests/integration_test.rs +0 -495
package/srpc/mux.rs CHANGED
@@ -90,9 +90,7 @@ impl Mux {
90
90
  let method_ids = handler.method_ids();
91
91
 
92
92
  let mut services = self.services.write().unwrap();
93
- let service_methods = services
94
- .entry(service_id.to_string())
95
- .or_insert_with(HashMap::new);
93
+ let service_methods = services.entry(service_id.to_string()).or_default();
96
94
 
97
95
  for method_id in method_ids {
98
96
  if !method_id.is_empty() {
@@ -346,7 +344,9 @@ mod tests {
346
344
  }
347
345
 
348
346
  // Should find the method even with empty service ID
349
- let (handled, result) = mux.invoke_method("", "TestMethod", Box::new(MockStream)).await;
347
+ let (handled, result) = mux
348
+ .invoke_method("", "TestMethod", Box::new(MockStream))
349
+ .await;
350
350
  assert!(handled);
351
351
  assert!(result.is_ok());
352
352
  }
package/srpc/net.go CHANGED
@@ -7,12 +7,14 @@ import (
7
7
 
8
8
  // Dial dials a remote server using TCP with the default muxed conn type.
9
9
  func Dial(addr string) (Client, error) {
10
+ // Connect the byte stream before attaching its stream multiplexer.
10
11
  nconn, err := net.Dial("tcp", addr)
11
12
  if err != nil {
12
13
  return nil, err
13
14
  }
14
15
  muxedConn, err := NewMuxedConn(nconn, false, nil)
15
16
  if err != nil {
17
+ _ = nconn.Close()
16
18
  return nil, err
17
19
  }
18
20
  return NewClientWithMuxedConn(muxedConn), nil
@@ -22,11 +24,14 @@ func Dial(addr string) (Client, error) {
22
24
  // Returns on any fatal error or if ctx was canceled.
23
25
  // errCh is an optional error channel (can be nil)
24
26
  func Listen(ctx context.Context, addr string, srv *Server, errCh <-chan error) error {
27
+ // The listener and its accept routine live until this function returns.
25
28
  lis, err := net.Listen("tcp", addr)
26
29
  if err != nil {
27
30
  return err
28
31
  }
32
+ defer lis.Close()
29
33
 
34
+ // Observe serving failure alongside the caller's stop conditions.
30
35
  listenErrCh := make(chan error, 1)
31
36
  go func() {
32
37
  listenErrCh <- AcceptMuxedListener(ctx, lis, srv, nil)
@@ -35,10 +40,14 @@ func Listen(ctx context.Context, addr string, srv *Server, errCh <-chan error) e
35
40
 
36
41
  select {
37
42
  case <-ctx.Done():
38
- return context.Canceled
39
- case err := <-errCh:
40
- return err
43
+ err = ctx.Err()
44
+ case err = <-errCh:
41
45
  case err := <-listenErrCh:
42
46
  return err
43
47
  }
48
+
49
+ // Closing the listener wakes Accept; wait for its cleanup before returning.
50
+ _ = lis.Close()
51
+ <-listenErrCh
52
+ return err
44
53
  }
package/srpc/packet.cpp CHANGED
@@ -6,78 +6,80 @@
6
6
 
7
7
  namespace starpc {
8
8
 
9
- PacketDataHandler NewPacketDataHandler(PacketHandler handler) {
10
- return [handler](const std::string &data) -> Error {
11
- srpc::Packet pkt;
12
- if (!pkt.ParseFromString(data)) {
13
- return Error::InvalidMessage;
14
- }
15
- return handler(pkt);
16
- };
9
+ PacketDataHandler NewPacketDataHandler(PacketHandler handler)
10
+ {
11
+ return [handler](const std::string &data) -> Error {
12
+ srpc::Packet pkt;
13
+ if (!pkt.ParseFromString(data))
14
+ return Error::InvalidMessage;
15
+ return handler(pkt);
16
+ };
17
17
  }
18
18
 
19
- Error ValidatePacket(const srpc::Packet &pkt) {
20
- switch (pkt.body_case()) {
21
- case srpc::Packet::kCallStart:
22
- return ValidateCallStart(pkt.call_start());
23
- case srpc::Packet::kCallData:
24
- return ValidateCallData(pkt.call_data());
25
- case srpc::Packet::kCallCancel:
26
- return Error::OK;
27
- default:
28
- return Error::UnrecognizedPacket;
29
- }
19
+ Error ValidatePacket(const srpc::Packet &pkt)
20
+ {
21
+ switch (pkt.body_case()) {
22
+ case srpc::Packet::kCallStart:
23
+ return ValidateCallStart(pkt.call_start());
24
+ case srpc::Packet::kCallData:
25
+ return ValidateCallData(pkt.call_data());
26
+ case srpc::Packet::kCallCancel:
27
+ return Error::OK;
28
+ default:
29
+ return Error::UnrecognizedPacket;
30
+ }
30
31
  }
31
32
 
32
- Error ValidateCallStart(const srpc::CallStart &pkt) {
33
- if (pkt.rpc_method().empty()) {
34
- return Error::EmptyMethodID;
35
- }
36
- if (pkt.rpc_service().empty()) {
37
- return Error::EmptyServiceID;
38
- }
39
- return Error::OK;
33
+ Error ValidateCallStart(const srpc::CallStart &pkt)
34
+ {
35
+ if (pkt.rpc_method().empty())
36
+ return Error::EmptyMethodID;
37
+ if (pkt.rpc_service().empty())
38
+ return Error::EmptyServiceID;
39
+ return Error::OK;
40
40
  }
41
41
 
42
- Error ValidateCallData(const srpc::CallData &pkt) {
43
- if (pkt.data().empty() && !pkt.complete() && pkt.error().empty() &&
44
- !pkt.data_is_zero()) {
45
- return Error::EmptyPacket;
46
- }
47
- return Error::OK;
42
+ Error ValidateCallData(const srpc::CallData &pkt)
43
+ {
44
+ if (pkt.data().empty() && !pkt.complete() && pkt.error().empty() &&
45
+ !pkt.data_is_zero())
46
+ return Error::EmptyPacket;
47
+ return Error::OK;
48
48
  }
49
49
 
50
50
  std::unique_ptr<srpc::Packet> NewCallStartPacket(const std::string &service,
51
- const std::string &method,
52
- const std::string &data,
53
- bool data_is_zero) {
54
- auto pkt = std::make_unique<srpc::Packet>();
55
- auto *call_start = pkt->mutable_call_start();
56
- call_start->set_rpc_service(service);
57
- call_start->set_rpc_method(method);
58
- call_start->set_data(data);
59
- call_start->set_data_is_zero(data_is_zero);
60
- return pkt;
51
+ const std::string &method,
52
+ const std::string &data,
53
+ bool data_is_zero)
54
+ {
55
+ auto pkt = std::make_unique<srpc::Packet>();
56
+ auto *call_start = pkt->mutable_call_start();
57
+ call_start->set_rpc_service(service);
58
+ call_start->set_rpc_method(method);
59
+ call_start->set_data(data);
60
+ call_start->set_data_is_zero(data_is_zero);
61
+ return pkt;
61
62
  }
62
63
 
63
64
  std::unique_ptr<srpc::Packet> NewCallDataPacket(const std::string &data,
64
- bool data_is_zero,
65
- bool complete, Error err) {
66
- auto pkt = std::make_unique<srpc::Packet>();
67
- auto *call_data = pkt->mutable_call_data();
68
- call_data->set_data(data);
69
- call_data->set_data_is_zero(data_is_zero);
70
- call_data->set_complete(err != Error::OK || complete);
71
- if (err != Error::OK) {
72
- call_data->set_error(ErrorString(err));
73
- }
74
- return pkt;
65
+ bool data_is_zero,
66
+ bool complete, Error err)
67
+ {
68
+ auto pkt = std::make_unique<srpc::Packet>();
69
+ auto *call_data = pkt->mutable_call_data();
70
+ call_data->set_data(data);
71
+ call_data->set_data_is_zero(data_is_zero);
72
+ call_data->set_complete(err != Error::OK || complete);
73
+ if (err != Error::OK)
74
+ call_data->set_error(ErrorString(err));
75
+ return pkt;
75
76
  }
76
77
 
77
- std::unique_ptr<srpc::Packet> NewCallCancelPacket() {
78
- auto pkt = std::make_unique<srpc::Packet>();
79
- pkt->set_call_cancel(true);
80
- return pkt;
78
+ std::unique_ptr<srpc::Packet> NewCallCancelPacket()
79
+ {
80
+ auto pkt = std::make_unique<srpc::Packet>();
81
+ pkt->set_call_cancel(true);
82
+ return pkt;
81
83
  }
82
84
 
83
85
  } // namespace starpc
package/srpc/packet.hpp CHANGED
@@ -1,12 +1,12 @@
1
1
  #pragma once
2
2
 
3
+ #include "errors.hpp"
4
+
3
5
  #include <cstdint>
4
6
  #include <functional>
5
7
  #include <memory>
6
8
  #include <string>
7
9
 
8
- #include "errors.hpp"
9
-
10
10
  namespace srpc {
11
11
  class Packet;
12
12
  class CallStart;
@@ -15,42 +15,57 @@ class CallData;
15
15
 
16
16
  namespace starpc {
17
17
 
18
- // CloseHandler handles the stream closing with an optional error.
19
- // Matches Go CloseHandler in packet.go
18
+ /*
19
+ * CloseHandler receives the transport close outcome for a stream.
20
+ * Matches Go CloseHandler in packet.go.
21
+ */
20
22
  using CloseHandler = std::function<void(Error close_err)>;
21
23
 
22
- // PacketHandler handles a packet.
23
- // Matches Go PacketHandler in packet.go
24
+ /* PacketHandler receives one parsed packet. Matches Go PacketHandler. */
24
25
  using PacketHandler = std::function<Error(const srpc::Packet &pkt)>;
25
26
 
26
- // PacketDataHandler handles a packet before it is parsed.
27
- // Matches Go PacketDataHandler in packet.go
27
+ /*
28
+ * PacketDataHandler receives one packet before parsing, as its serialized
29
+ * bytes. Matches Go PacketDataHandler in packet.go.
30
+ */
28
31
  using PacketDataHandler = std::function<Error(const std::string &data)>;
29
32
 
30
- // NewPacketDataHandler wraps a PacketHandler with a decoding step.
33
+ /* NewPacketDataHandler parses each payload and forwards it to handler. */
31
34
  PacketDataHandler NewPacketDataHandler(PacketHandler handler);
32
35
 
33
- // Validate performs cursory validation of a Packet.
36
+ /*
37
+ * ValidatePacket checks a packet's shape: its body is one of the known types
38
+ * and the body's required fields are present.
39
+ */
34
40
  Error ValidatePacket(const srpc::Packet &pkt);
35
41
 
36
- // Validate performs cursory validation of a CallStart.
42
+ /* ValidateCallStart requires the service and method IDs to be present. */
37
43
  Error ValidateCallStart(const srpc::CallStart &pkt);
38
44
 
39
- // Validate performs cursory validation of a CallData.
45
+ /*
46
+ * ValidateCallData rejects a packet that carries no data, no completion, no
47
+ * error, and no zero-length marker.
48
+ */
40
49
  Error ValidateCallData(const srpc::CallData &pkt);
41
50
 
42
- // NewCallStartPacket constructs a new CallStart packet.
51
+ /*
52
+ * NewCallStartPacket builds the CallStart packet that opens a call.
53
+ * data_is_zero marks an intentionally empty first message.
54
+ */
43
55
  std::unique_ptr<srpc::Packet> NewCallStartPacket(const std::string &service,
44
- const std::string &method,
45
- const std::string &data,
46
- bool data_is_zero);
56
+ const std::string &method,
57
+ const std::string &data,
58
+ bool data_is_zero);
47
59
 
48
- // NewCallDataPacket constructs a new CallData packet.
60
+ /*
61
+ * NewCallDataPacket builds one CallData packet. err carries the call's
62
+ * terminal verdict; complete ends the sending side.
63
+ */
49
64
  std::unique_ptr<srpc::Packet> NewCallDataPacket(const std::string &data,
50
- bool data_is_zero,
51
- bool complete, Error err);
65
+ bool data_is_zero,
66
+ bool complete, Error err);
52
67
 
53
- // NewCallCancelPacket constructs a new CallCancel packet with cancel.
68
+ /* NewCallCancelPacket builds the packet that cancels the call. */
54
69
  std::unique_ptr<srpc::Packet> NewCallCancelPacket();
55
70
 
56
71
  } // namespace starpc
package/srpc/packet.rs CHANGED
@@ -10,10 +10,8 @@ use bytes::Bytes;
10
10
 
11
11
  /// Creates a new CallStart packet.
12
12
  ///
13
- /// # Arguments
14
- /// * `service` - The service ID
15
- /// * `method` - The method ID
16
- /// * `data` - Optional initial data (None = no data, Some(empty) = empty data)
13
+ /// `None` data sends no payload; `Some(empty)` sends empty data with the
14
+ /// `data_is_zero` flag set.
17
15
  pub fn new_call_start(
18
16
  service: impl Into<String>,
19
17
  method: impl Into<String>,
@@ -31,10 +29,7 @@ pub fn new_call_start(
31
29
  }
32
30
  }
33
31
 
34
- /// Creates a new CallData packet with data.
35
- ///
36
- /// # Arguments
37
- /// * `data` - The data to send (can be empty)
32
+ /// Creates a new CallData packet carrying `data`, which may be empty.
38
33
  pub fn new_call_data(data: Vec<u8>) -> Packet {
39
34
  let data_is_zero = data.is_empty();
40
35
  Packet {
@@ -49,16 +44,9 @@ pub fn new_call_data(data: Vec<u8>) -> Packet {
49
44
 
50
45
  /// Creates a new CallData packet with optional data and flags.
51
46
  ///
52
- /// # Arguments
53
- /// * `data` - Optional data bytes
54
- /// * `data_is_zero` - True if empty data should be sent
55
- /// * `complete` - True if this completes the stream
56
- /// * `error` - Optional error message
57
- pub fn new_call_data_full(
58
- data: Option<Bytes>,
59
- complete: bool,
60
- error: Option<String>,
61
- ) -> Packet {
47
+ /// Sets `complete` when either `complete` or `error` is set, so an error
48
+ /// always ends the call.
49
+ pub fn new_call_data_full(data: Option<Bytes>, complete: bool, error: Option<String>) -> Packet {
62
50
  let (data_bytes, data_is_zero) = encode_optional_data(data);
63
51
 
64
52
  Packet {
@@ -83,10 +71,7 @@ pub fn new_call_complete() -> Packet {
83
71
  }
84
72
  }
85
73
 
86
- /// Creates a new CallData packet with an error.
87
- ///
88
- /// # Arguments
89
- /// * `error` - The error message
74
+ /// Creates a new CallData packet carrying an error message.
90
75
  pub fn new_call_error(error: impl Into<String>) -> Packet {
91
76
  Packet {
92
77
  body: Some(Body::CallData(CallData {
@@ -154,11 +139,7 @@ impl Validate for CallData {
154
139
  // - data_is_zero flag set (indicating intentionally empty data)
155
140
  // - complete flag set
156
141
  // - error message
157
- if self.data.is_empty()
158
- && !self.data_is_zero
159
- && !self.complete
160
- && self.error.is_empty()
161
- {
142
+ if self.data.is_empty() && !self.data_is_zero && !self.complete && self.error.is_empty() {
162
143
  return Err(Error::EmptyPacket);
163
144
  }
164
145
  Ok(())