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/srpc/invoker.rs
CHANGED
|
@@ -10,59 +10,17 @@ use std::sync::Arc;
|
|
|
10
10
|
use crate::error::Result;
|
|
11
11
|
use crate::stream::Stream;
|
|
12
12
|
|
|
13
|
-
///
|
|
13
|
+
/// Dispatches incoming RPC calls to a handler implementation.
|
|
14
14
|
///
|
|
15
|
-
///
|
|
16
|
-
///
|
|
17
|
-
///
|
|
18
|
-
///
|
|
19
|
-
/// # Return Value
|
|
20
|
-
///
|
|
21
|
-
/// The `invoke_method` method returns a tuple of `(found, result)`:
|
|
22
|
-
/// - `found`: Whether the method was found and handled
|
|
23
|
-
/// - `result`: The result of the invocation, or an error
|
|
24
|
-
///
|
|
25
|
-
/// This design allows callers to distinguish between:
|
|
26
|
-
/// - Method not found: `(false, Err(Error::Unimplemented))`
|
|
27
|
-
/// - Method found but failed: `(true, Err(...))`
|
|
28
|
-
/// - Method found and succeeded: `(true, Ok(()))`
|
|
29
|
-
///
|
|
30
|
-
/// # Example
|
|
31
|
-
///
|
|
32
|
-
/// ```rust,ignore
|
|
33
|
-
/// #[async_trait]
|
|
34
|
-
/// impl Invoker for MyHandler {
|
|
35
|
-
/// async fn invoke_method(
|
|
36
|
-
/// &self,
|
|
37
|
-
/// service_id: &str,
|
|
38
|
-
/// method_id: &str,
|
|
39
|
-
/// stream: Box<dyn Stream>,
|
|
40
|
-
/// ) -> (bool, Result<()>) {
|
|
41
|
-
/// match method_id {
|
|
42
|
-
/// "MyMethod" => {
|
|
43
|
-
/// // Handle the method
|
|
44
|
-
/// (true, self.my_method(stream).await)
|
|
45
|
-
/// }
|
|
46
|
-
/// _ => (false, Err(Error::Unimplemented)),
|
|
47
|
-
/// }
|
|
48
|
-
/// }
|
|
49
|
-
/// }
|
|
50
|
-
/// ```
|
|
15
|
+
/// The Mux implements this trait to route calls by service and method ID.
|
|
16
|
+
/// `invoke_method` returns `(found, result)`, letting a caller distinguish a
|
|
17
|
+
/// method that was not found (`(false, Err(Error::Unimplemented))`) from one
|
|
18
|
+
/// that was found and failed (`(true, Err(...))`).
|
|
51
19
|
#[async_trait]
|
|
52
20
|
pub trait Invoker: Send + Sync {
|
|
53
|
-
/// Invokes
|
|
54
|
-
///
|
|
55
|
-
///
|
|
56
|
-
///
|
|
57
|
-
/// * `service_id` - The service identifier (e.g., "echo.Echoer")
|
|
58
|
-
/// * `method_id` - The method identifier (e.g., "Echo")
|
|
59
|
-
/// * `stream` - The bidirectional stream for this RPC
|
|
60
|
-
///
|
|
61
|
-
/// # Returns
|
|
62
|
-
///
|
|
63
|
-
/// A tuple of (found, result) where:
|
|
64
|
-
/// * `found` - Whether the method was found and handled
|
|
65
|
-
/// * `result` - The result of the invocation
|
|
21
|
+
/// Invokes the RPC method, consuming `stream` whether or not the method
|
|
22
|
+
/// is found. Returns whether the method was handled and the invocation's
|
|
23
|
+
/// result.
|
|
66
24
|
async fn invoke_method(
|
|
67
25
|
&self,
|
|
68
26
|
service_id: &str,
|
|
@@ -157,7 +115,9 @@ mod tests {
|
|
|
157
115
|
|
|
158
116
|
#[tokio::test]
|
|
159
117
|
async fn test_invoker_found() {
|
|
160
|
-
let invoker = TestInvoker {
|
|
118
|
+
let invoker = TestInvoker {
|
|
119
|
+
should_handle: true,
|
|
120
|
+
};
|
|
161
121
|
let (found, result) = invoker
|
|
162
122
|
.invoke_method("svc", "method", Box::new(MockStream))
|
|
163
123
|
.await;
|
|
@@ -181,7 +141,9 @@ mod tests {
|
|
|
181
141
|
|
|
182
142
|
#[tokio::test]
|
|
183
143
|
async fn test_arc_invoker() {
|
|
184
|
-
let invoker: Arc<dyn Invoker> = Arc::new(TestInvoker {
|
|
144
|
+
let invoker: Arc<dyn Invoker> = Arc::new(TestInvoker {
|
|
145
|
+
should_handle: true,
|
|
146
|
+
});
|
|
185
147
|
let (found, result) = invoker
|
|
186
148
|
.invoke_method("svc", "method", Box::new(MockStream))
|
|
187
149
|
.await;
|
package/srpc/lib.rs
CHANGED
|
@@ -57,6 +57,7 @@
|
|
|
57
57
|
//! This format is compatible with the Go and TypeScript implementations.
|
|
58
58
|
|
|
59
59
|
pub mod client;
|
|
60
|
+
pub mod client_invoker;
|
|
60
61
|
pub mod codec;
|
|
61
62
|
pub mod error;
|
|
62
63
|
pub mod handler;
|
|
@@ -82,6 +83,7 @@ pub mod yamux;
|
|
|
82
83
|
|
|
83
84
|
// Re-exports for convenience.
|
|
84
85
|
pub use client::{BoxClient, Client, OpenStream, SrpcClient};
|
|
86
|
+
pub use client_invoker::ClientInvoker;
|
|
85
87
|
pub use codec::{PacketCodec, MAX_MESSAGE_SIZE};
|
|
86
88
|
pub use error::{Error, Result};
|
|
87
89
|
pub use handler::{BoxHandler, Handler};
|
package/srpc/message.hpp
CHANGED
|
@@ -6,23 +6,28 @@
|
|
|
6
6
|
|
|
7
7
|
namespace starpc {
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
/*
|
|
10
|
+
* Message is the wire-message type handed across the RPC boundary. It aliases
|
|
11
|
+
* protobuf's MessageLite, matching the Go Message interface in message.go.
|
|
12
|
+
*/
|
|
12
13
|
using Message = google::protobuf::MessageLite;
|
|
13
14
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
/* MarshalVT serializes msg into out and reports parse success. */
|
|
16
|
+
inline bool MarshalVT(const Message &msg, std::string *out)
|
|
17
|
+
{
|
|
18
|
+
return msg.SerializeToString(out);
|
|
18
19
|
}
|
|
19
20
|
|
|
20
|
-
|
|
21
|
-
inline bool UnmarshalVT(Message *msg, const std::string &data)
|
|
22
|
-
|
|
21
|
+
/* UnmarshalVT parses data into msg and reports success. */
|
|
22
|
+
inline bool UnmarshalVT(Message *msg, const std::string &data)
|
|
23
|
+
{
|
|
24
|
+
return msg->ParseFromString(data);
|
|
23
25
|
}
|
|
24
26
|
|
|
25
|
-
|
|
26
|
-
inline size_t SizeVT(const Message &msg)
|
|
27
|
+
/* SizeVT returns the serialized size of msg in bytes. */
|
|
28
|
+
inline size_t SizeVT(const Message &msg)
|
|
29
|
+
{
|
|
30
|
+
return msg.ByteSizeLong();
|
|
31
|
+
}
|
|
27
32
|
|
|
28
33
|
} // namespace starpc
|
package/srpc/msg-stream.go
CHANGED
|
@@ -72,6 +72,7 @@ func (r *MsgStream) MsgRecv(msg Message) error {
|
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
// CloseSend signals to the remote that we will no longer send any messages.
|
|
75
|
+
// A write error leaves received messages and the call outcome to MsgRecv.
|
|
75
76
|
func (r *MsgStream) CloseSend() error {
|
|
76
77
|
return r.rw.WriteCallData(nil, false, true, nil)
|
|
77
78
|
}
|
package/srpc/msg-stream.hpp
CHANGED
|
@@ -1,86 +1,133 @@
|
|
|
1
1
|
#pragma once
|
|
2
2
|
|
|
3
|
-
#include <functional>
|
|
4
|
-
#include <string>
|
|
5
|
-
|
|
6
3
|
#include "errors.hpp"
|
|
7
4
|
#include "message.hpp"
|
|
8
5
|
#include "stream.hpp"
|
|
9
6
|
|
|
7
|
+
#include <atomic>
|
|
8
|
+
#include <functional>
|
|
9
|
+
#include <string>
|
|
10
|
+
|
|
10
11
|
namespace starpc {
|
|
11
12
|
|
|
12
|
-
|
|
13
|
-
|
|
13
|
+
/*
|
|
14
|
+
* MsgStreamRw is the call-state side of MsgStream: it reads and writes one
|
|
15
|
+
* call's messages. Matches the Go msgStreamRw interface.
|
|
16
|
+
*/
|
|
14
17
|
class MsgStreamRw {
|
|
15
18
|
public:
|
|
16
|
-
|
|
19
|
+
virtual ~MsgStreamRw() = default;
|
|
17
20
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
+
/* RemoteErrorMessage returns the peer's retained diagnostic, if any. */
|
|
22
|
+
virtual std::string RemoteErrorMessage() const
|
|
23
|
+
{
|
|
24
|
+
return {};
|
|
25
|
+
}
|
|
21
26
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
27
|
+
/*
|
|
28
|
+
* ReadOne returns the next message in out. Returns EOF_ after the
|
|
29
|
+
* call completes and Canceled after local cancellation.
|
|
30
|
+
*/
|
|
31
|
+
virtual Error ReadOne(std::string *out) = 0;
|
|
25
32
|
|
|
26
|
-
|
|
27
|
-
|
|
33
|
+
/*
|
|
34
|
+
* WriteCallData writes one data packet. data_is_zero marks an
|
|
35
|
+
* intentionally empty message; complete ends the sending side; err
|
|
36
|
+
* carries the terminal verdict.
|
|
37
|
+
*/
|
|
38
|
+
virtual Error WriteCallData(const std::string &data, bool data_is_zero,
|
|
39
|
+
bool complete, Error err) = 0;
|
|
40
|
+
|
|
41
|
+
/* WriteCallCancel cancels the call on the remote. */
|
|
42
|
+
virtual Error WriteCallCancel() = 0;
|
|
28
43
|
};
|
|
29
44
|
|
|
30
|
-
|
|
31
|
-
|
|
45
|
+
/*
|
|
46
|
+
* MsgStream is the Stream handed to handlers: it serializes messages over a
|
|
47
|
+
* MsgStreamRw and closes the call when the handler is done.
|
|
48
|
+
*/
|
|
32
49
|
class MsgStream : public Stream {
|
|
33
50
|
public:
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
51
|
+
/*
|
|
52
|
+
* MsgStream borrows rw; it must outlive the stream. close_cb, when
|
|
53
|
+
* set, replaces the cancel write on Close; stop carries the call's
|
|
54
|
+
* cancellation to the handler.
|
|
55
|
+
*/
|
|
56
|
+
MsgStream(MsgStreamRw *rw, std::function<void()> close_cb,
|
|
57
|
+
std::stop_token stop = {})
|
|
58
|
+
: rw(rw),
|
|
59
|
+
close_cb(std::move(close_cb)),
|
|
60
|
+
stop(stop)
|
|
61
|
+
{
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
std::stop_token StopToken() const override
|
|
65
|
+
{
|
|
66
|
+
return stop;
|
|
67
|
+
}
|
|
68
|
+
std::string RemoteErrorMessage() const override
|
|
69
|
+
{
|
|
70
|
+
return rw->RemoteErrorMessage();
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
Error MsgSend(const Message &msg) override
|
|
74
|
+
{
|
|
75
|
+
std::string msg_data;
|
|
76
|
+
if (!msg.SerializeToString(&msg_data))
|
|
77
|
+
return Error::InvalidMessage;
|
|
78
|
+
return rw->WriteCallData(msg_data, msg_data.empty(), false,
|
|
79
|
+
Error::OK);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
Error MsgRecv(Message *msg) override
|
|
83
|
+
{
|
|
84
|
+
std::string data;
|
|
85
|
+
Error err = rw->ReadOne(&data);
|
|
86
|
+
if (err != Error::OK)
|
|
87
|
+
return err;
|
|
88
|
+
if (!msg->ParseFromString(data))
|
|
89
|
+
return Error::InvalidMessage;
|
|
90
|
+
return Error::OK;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/*
|
|
94
|
+
* CloseSend half-closes the sending side. See Stream::CloseSend for
|
|
95
|
+
* why its failure leaves the outcome to MsgRecv.
|
|
96
|
+
*/
|
|
97
|
+
Error CloseSend() override
|
|
98
|
+
{
|
|
99
|
+
return rw->WriteCallData("", false, true, Error::OK);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/*
|
|
103
|
+
* Close ends the call once: through close_cb when the call is shared
|
|
104
|
+
* with a transport, otherwise by writing cancel to the remote.
|
|
105
|
+
*/
|
|
106
|
+
Error Close() override
|
|
107
|
+
{
|
|
108
|
+
if (closed.exchange(true))
|
|
109
|
+
return Error::OK;
|
|
110
|
+
if (close_cb) {
|
|
111
|
+
close_cb();
|
|
112
|
+
return Error::OK;
|
|
113
|
+
}
|
|
114
|
+
return rw->WriteCallCancel();
|
|
115
|
+
}
|
|
73
116
|
|
|
74
117
|
private:
|
|
75
|
-
|
|
76
|
-
|
|
118
|
+
/* rw is borrowed; the caller owns it. */
|
|
119
|
+
MsgStreamRw *rw;
|
|
120
|
+
std::function<void()> close_cb;
|
|
121
|
+
std::stop_token stop;
|
|
122
|
+
std::atomic<bool> closed{false};
|
|
77
123
|
};
|
|
78
124
|
|
|
79
|
-
|
|
80
|
-
// Matches Go NewMsgStream function in msg-stream.go
|
|
125
|
+
/* NewMsgStream constructs a Stream over rw. */
|
|
81
126
|
inline std::unique_ptr<MsgStream> NewMsgStream(MsgStreamRw *rw,
|
|
82
|
-
|
|
83
|
-
|
|
127
|
+
std::function<void()> close_cb,
|
|
128
|
+
std::stop_token stop = {})
|
|
129
|
+
{
|
|
130
|
+
return std::make_unique<MsgStream>(rw, std::move(close_cb), stop);
|
|
84
131
|
}
|
|
85
132
|
|
|
86
133
|
} // namespace starpc
|
package/srpc/mux.cpp
CHANGED
|
@@ -1,109 +1,109 @@
|
|
|
1
1
|
//go:build deps_only
|
|
2
2
|
|
|
3
3
|
#include "mux.hpp"
|
|
4
|
+
|
|
4
5
|
#include <mutex>
|
|
6
|
+
#include <shared_mutex>
|
|
5
7
|
|
|
6
8
|
namespace starpc {
|
|
7
9
|
|
|
8
10
|
Mux::Mux(std::vector<Invoker *> fallback_invokers)
|
|
9
|
-
|
|
11
|
+
: fallback(std::move(fallback_invokers))
|
|
12
|
+
{
|
|
13
|
+
}
|
|
10
14
|
|
|
11
|
-
Error Mux::Register(Handler *handler)
|
|
12
|
-
|
|
13
|
-
|
|
15
|
+
Error Mux::Register(Handler *handler)
|
|
16
|
+
{
|
|
17
|
+
const std::string &service_id = handler->GetServiceID();
|
|
18
|
+
auto method_ids = handler->GetMethodIDs();
|
|
14
19
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}
|
|
20
|
+
if (service_id.empty())
|
|
21
|
+
return Error::EmptyServiceID;
|
|
18
22
|
|
|
19
|
-
|
|
23
|
+
std::unique_lock<std::shared_mutex> lock(mu);
|
|
20
24
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
}
|
|
25
|
+
auto &service_methods = services[service_id];
|
|
26
|
+
for (const auto &method_id : method_ids) {
|
|
27
|
+
if (!method_id.empty())
|
|
28
|
+
service_methods[method_id] = handler;
|
|
29
|
+
}
|
|
27
30
|
|
|
28
|
-
|
|
31
|
+
return Error::OK;
|
|
29
32
|
}
|
|
30
33
|
|
|
31
|
-
bool Mux::HasService(const std::string &service_id) const
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
34
|
+
bool Mux::HasService(const std::string &service_id) const
|
|
35
|
+
{
|
|
36
|
+
if (service_id.empty())
|
|
37
|
+
return false;
|
|
35
38
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
+
std::shared_lock<std::shared_mutex> lock(mu);
|
|
40
|
+
auto it = services.find(service_id);
|
|
41
|
+
return it != services.end() && !it->second.empty();
|
|
39
42
|
}
|
|
40
43
|
|
|
41
44
|
bool Mux::HasServiceMethod(const std::string &service_id,
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
return false;
|
|
45
|
+
const std::string &method_id) const
|
|
46
|
+
{
|
|
47
|
+
if (service_id.empty() || method_id.empty())
|
|
48
|
+
return false;
|
|
49
|
+
|
|
50
|
+
std::shared_lock<std::shared_mutex> lock(mu);
|
|
51
|
+
auto svc_it = services.find(service_id);
|
|
52
|
+
if (svc_it == services.end())
|
|
53
|
+
return false;
|
|
54
|
+
|
|
55
|
+
for (const auto &[mid, handler] : svc_it->second) {
|
|
56
|
+
for (const auto &handler_method : handler->GetMethodIDs()) {
|
|
57
|
+
if (handler_method == method_id)
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return false;
|
|
62
63
|
}
|
|
63
64
|
|
|
64
65
|
std::pair<bool, Error> Mux::InvokeMethod(const std::string &service_id,
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
return {false, Error::OK};
|
|
66
|
+
const std::string &method_id,
|
|
67
|
+
Stream *strm)
|
|
68
|
+
{
|
|
69
|
+
Handler *handler = nullptr;
|
|
70
|
+
|
|
71
|
+
/* Find the registered handler outside any handler call. */
|
|
72
|
+
{
|
|
73
|
+
std::shared_lock<std::shared_mutex> lock(mu);
|
|
74
|
+
|
|
75
|
+
if (service_id.empty()) {
|
|
76
|
+
for (const auto &[svc_id, svc_methods] : services) {
|
|
77
|
+
auto it = svc_methods.find(method_id);
|
|
78
|
+
if (it != svc_methods.end()) {
|
|
79
|
+
handler = it->second;
|
|
80
|
+
break;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
} else {
|
|
84
|
+
auto svc_it = services.find(service_id);
|
|
85
|
+
if (svc_it != services.end()) {
|
|
86
|
+
auto method_it = svc_it->second.find(method_id);
|
|
87
|
+
if (method_it != svc_it->second.end())
|
|
88
|
+
handler = method_it->second;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (handler != nullptr)
|
|
94
|
+
return handler->InvokeMethod(service_id, method_id, strm);
|
|
95
|
+
|
|
96
|
+
/* Try each fallback invoker in order. */
|
|
97
|
+
for (auto *invoker : fallback) {
|
|
98
|
+
if (invoker == nullptr)
|
|
99
|
+
continue;
|
|
100
|
+
auto [handled, err] =
|
|
101
|
+
invoker->InvokeMethod(service_id, method_id, strm);
|
|
102
|
+
if (err != Error::OK || handled)
|
|
103
|
+
return {handled, err};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return {false, Error::OK};
|
|
107
107
|
}
|
|
108
108
|
|
|
109
109
|
} // namespace starpc
|
package/srpc/mux.hpp
CHANGED
|
@@ -1,64 +1,74 @@
|
|
|
1
1
|
#pragma once
|
|
2
2
|
|
|
3
|
+
#include "errors.hpp"
|
|
4
|
+
#include "handler.hpp"
|
|
5
|
+
#include "invoker.hpp"
|
|
6
|
+
|
|
3
7
|
#include <shared_mutex>
|
|
4
8
|
#include <string>
|
|
5
9
|
#include <unordered_map>
|
|
6
10
|
#include <vector>
|
|
7
11
|
|
|
8
|
-
#include "errors.hpp"
|
|
9
|
-
#include "handler.hpp"
|
|
10
|
-
#include "invoker.hpp"
|
|
11
|
-
|
|
12
12
|
namespace starpc {
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
/*
|
|
15
|
+
* Mux dispatches calls to registered handlers and falls back to a list of
|
|
16
|
+
* invokers when no handler matches. Matches the Go Mux in mux.go.
|
|
17
|
+
*/
|
|
16
18
|
class Mux : public Invoker, public QueryableInvoker {
|
|
17
19
|
public:
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
20
|
+
/*
|
|
21
|
+
* Mux consults fallback_invokers, in order, when no registered
|
|
22
|
+
* handler matches. The invokers are borrowed and must outlive the
|
|
23
|
+
* mux.
|
|
24
|
+
*/
|
|
25
|
+
explicit Mux(std::vector<Invoker *> fallback_invokers = {});
|
|
26
|
+
~Mux() override = default;
|
|
21
27
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
28
|
+
/*
|
|
29
|
+
* Register maps the handler's service and method IDs to it. An empty
|
|
30
|
+
* service ID fails; empty method IDs are skipped.
|
|
31
|
+
*/
|
|
32
|
+
Error Register(Handler *handler);
|
|
25
33
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
34
|
+
/*
|
|
35
|
+
* InvokeMethod runs the registered handler for the IDs and reports
|
|
36
|
+
* whether it found one. An empty service_id searches every service.
|
|
37
|
+
* Unhandled calls go to the fallback invokers.
|
|
38
|
+
*/
|
|
39
|
+
std::pair<bool, Error> InvokeMethod(const std::string &service_id,
|
|
40
|
+
const std::string &method_id,
|
|
41
|
+
Stream *strm) override;
|
|
33
42
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
bool HasService(const std::string &service_id) const override;
|
|
43
|
+
/* HasService reports whether any handler registered service_id. */
|
|
44
|
+
bool HasService(const std::string &service_id) const override;
|
|
37
45
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
46
|
+
/*
|
|
47
|
+
* HasServiceMethod reports whether a registered handler for
|
|
48
|
+
* service_id serves method_id.
|
|
49
|
+
*/
|
|
50
|
+
bool HasServiceMethod(const std::string &service_id,
|
|
51
|
+
const std::string &method_id) const override;
|
|
42
52
|
|
|
43
53
|
private:
|
|
44
|
-
|
|
45
|
-
|
|
54
|
+
/* methods maps one method ID to the handler that registered it. */
|
|
55
|
+
using methods = std::unordered_map<std::string, Handler *>;
|
|
46
56
|
|
|
47
|
-
|
|
48
|
-
|
|
57
|
+
/* fallback invokers are borrowed; the caller owns them. */
|
|
58
|
+
std::vector<Invoker *> fallback;
|
|
49
59
|
|
|
50
|
-
|
|
51
|
-
|
|
60
|
+
/* mu guards services. */
|
|
61
|
+
mutable std::shared_mutex mu;
|
|
52
62
|
|
|
53
|
-
|
|
54
|
-
|
|
63
|
+
/* services maps each service ID to its method table. */
|
|
64
|
+
std::unordered_map<std::string, methods> services;
|
|
55
65
|
};
|
|
56
66
|
|
|
57
|
-
|
|
58
|
-
// Matches Go NewMux function in mux.go
|
|
67
|
+
/* NewMux constructs a Mux with the given fallback invokers. */
|
|
59
68
|
inline std::unique_ptr<Mux>
|
|
60
|
-
NewMux(std::vector<Invoker *> fallback_invokers = {})
|
|
61
|
-
|
|
69
|
+
NewMux(std::vector<Invoker *> fallback_invokers = {})
|
|
70
|
+
{
|
|
71
|
+
return std::make_unique<Mux>(std::move(fallback_invokers));
|
|
62
72
|
}
|
|
63
73
|
|
|
64
74
|
} // namespace starpc
|