starpc 0.46.0 → 0.46.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/echo/echo_e2e_test.cpp +2 -2
- package/package.json +1 -1
- package/srpc/lib.rs +1 -0
- package/srpc/rpcstream/mod.rs +0 -38
- package/srpc/rpcstream/proto.rs +0 -286
- package/srpc/rpcstream/stream.rs +0 -517
- package/srpc/rpcstream/writer.rs +0 -150
package/echo/echo_e2e_test.cpp
CHANGED
|
@@ -182,9 +182,9 @@ public:
|
|
|
182
182
|
|
|
183
183
|
starpc::Error RpcStream(echo::SRPCEchoer_RpcStreamStream *strm) override {
|
|
184
184
|
// Wrap stream to implement rpcstream::RpcStream interface
|
|
185
|
-
|
|
185
|
+
auto adapter = std::make_shared<RpcStreamAdapter>(strm);
|
|
186
186
|
return rpcstream::HandleRpcStream(
|
|
187
|
-
|
|
187
|
+
adapter, [this](const std::string &component_id) {
|
|
188
188
|
if (!rpc_stream_mux_) {
|
|
189
189
|
return std::make_tuple(static_cast<starpc::Invoker *>(nullptr),
|
|
190
190
|
std::function<void()>(),
|
package/package.json
CHANGED
package/srpc/lib.rs
CHANGED
package/srpc/rpcstream/mod.rs
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
//! RpcStream module for nested RPC calls.
|
|
2
|
-
//!
|
|
3
|
-
//! This module enables nesting RPC calls within RPC calls, supporting
|
|
4
|
-
//! component-based architectures where different components expose different
|
|
5
|
-
//! services via sub-streams.
|
|
6
|
-
//!
|
|
7
|
-
//! # Overview
|
|
8
|
-
//!
|
|
9
|
-
//! The rpcstream protocol works as follows:
|
|
10
|
-
//! 1. Client opens a bidirectional stream to the server
|
|
11
|
-
//! 2. Client sends `RpcStreamInit` with the target component ID
|
|
12
|
-
//! 3. Server looks up the component and sends `RpcAck`
|
|
13
|
-
//! 4. Both sides exchange `RpcStreamPacket::Data` containing nested RPC packets
|
|
14
|
-
//!
|
|
15
|
-
//! # Example
|
|
16
|
-
//!
|
|
17
|
-
//! ```rust,ignore
|
|
18
|
-
//! use starpc::rpcstream::{open_rpc_stream, RpcStreamGetter};
|
|
19
|
-
//!
|
|
20
|
-
//! // Client side: open a stream to a component
|
|
21
|
-
//! let stream = my_service.rpc_stream().await?;
|
|
22
|
-
//! let rpc_stream = open_rpc_stream(stream, "my-component", true).await?;
|
|
23
|
-
//!
|
|
24
|
-
//! // Server side: handle incoming rpc stream
|
|
25
|
-
//! let getter: RpcStreamGetter = Arc::new(|ctx, component_id, released| {
|
|
26
|
-
//! // Look up the invoker for this component
|
|
27
|
-
//! Some((invoker, release_fn))
|
|
28
|
-
//! });
|
|
29
|
-
//! handle_rpc_stream(stream, getter).await?;
|
|
30
|
-
//! ```
|
|
31
|
-
|
|
32
|
-
mod proto;
|
|
33
|
-
mod stream;
|
|
34
|
-
mod writer;
|
|
35
|
-
|
|
36
|
-
pub use proto::*;
|
|
37
|
-
pub use stream::*;
|
|
38
|
-
pub use writer::*;
|
package/srpc/rpcstream/proto.rs
DELETED
|
@@ -1,286 +0,0 @@
|
|
|
1
|
-
//! Protocol buffer types for rpcstream.
|
|
2
|
-
//!
|
|
3
|
-
//! These types are defined manually to match the rpcstream.proto definitions.
|
|
4
|
-
//! They will be generated via protoc-gen-prost in a future update.
|
|
5
|
-
|
|
6
|
-
use bytes::{Buf, BufMut, Bytes};
|
|
7
|
-
use prost::{DecodeError, Message};
|
|
8
|
-
|
|
9
|
-
/// RpcStreamPacket is a packet encapsulating data for a RPC stream.
|
|
10
|
-
#[derive(Clone, PartialEq, Debug, Default)]
|
|
11
|
-
pub struct RpcStreamPacket {
|
|
12
|
-
/// Body of the packet.
|
|
13
|
-
pub body: Option<RpcStreamPacketBody>,
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/// Body variants for RpcStreamPacket.
|
|
17
|
-
#[derive(Clone, PartialEq, Debug)]
|
|
18
|
-
pub enum RpcStreamPacketBody {
|
|
19
|
-
/// Init is the first packet in the stream, sent by the initiator.
|
|
20
|
-
Init(RpcStreamInit),
|
|
21
|
-
/// Ack is sent in response to Init, by the server.
|
|
22
|
-
Ack(RpcAck),
|
|
23
|
-
/// Data is the encapsulated data packet.
|
|
24
|
-
Data(Bytes),
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/// RpcStreamInit is the first message in a RPC stream.
|
|
28
|
-
#[derive(Clone, PartialEq, Debug, Default)]
|
|
29
|
-
pub struct RpcStreamInit {
|
|
30
|
-
/// ComponentId is the identifier of the component making the request.
|
|
31
|
-
pub component_id: String,
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/// RpcAck is the acknowledgment message in a RPC stream.
|
|
35
|
-
#[derive(Clone, PartialEq, Debug, Default)]
|
|
36
|
-
pub struct RpcAck {
|
|
37
|
-
/// Error indicates there was some error setting up the stream.
|
|
38
|
-
pub error: String,
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// Manual Message implementation for RpcStreamInit
|
|
42
|
-
impl Message for RpcStreamInit {
|
|
43
|
-
fn encode_raw(&self, buf: &mut impl BufMut)
|
|
44
|
-
where
|
|
45
|
-
Self: Sized,
|
|
46
|
-
{
|
|
47
|
-
if !self.component_id.is_empty() {
|
|
48
|
-
prost::encoding::string::encode(1, &self.component_id, buf);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
fn merge_field(
|
|
53
|
-
&mut self,
|
|
54
|
-
tag: u32,
|
|
55
|
-
wire_type: prost::encoding::WireType,
|
|
56
|
-
buf: &mut impl Buf,
|
|
57
|
-
ctx: prost::encoding::DecodeContext,
|
|
58
|
-
) -> Result<(), DecodeError>
|
|
59
|
-
where
|
|
60
|
-
Self: Sized,
|
|
61
|
-
{
|
|
62
|
-
match tag {
|
|
63
|
-
1 => prost::encoding::string::merge(wire_type, &mut self.component_id, buf, ctx),
|
|
64
|
-
_ => prost::encoding::skip_field(wire_type, tag, buf, ctx),
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
fn encoded_len(&self) -> usize {
|
|
69
|
-
let mut len = 0;
|
|
70
|
-
if !self.component_id.is_empty() {
|
|
71
|
-
len += prost::encoding::string::encoded_len(1, &self.component_id);
|
|
72
|
-
}
|
|
73
|
-
len
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
fn clear(&mut self) {
|
|
77
|
-
self.component_id.clear();
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// Manual Message implementation for RpcAck
|
|
82
|
-
impl Message for RpcAck {
|
|
83
|
-
fn encode_raw(&self, buf: &mut impl BufMut)
|
|
84
|
-
where
|
|
85
|
-
Self: Sized,
|
|
86
|
-
{
|
|
87
|
-
if !self.error.is_empty() {
|
|
88
|
-
prost::encoding::string::encode(1, &self.error, buf);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
fn merge_field(
|
|
93
|
-
&mut self,
|
|
94
|
-
tag: u32,
|
|
95
|
-
wire_type: prost::encoding::WireType,
|
|
96
|
-
buf: &mut impl Buf,
|
|
97
|
-
ctx: prost::encoding::DecodeContext,
|
|
98
|
-
) -> Result<(), DecodeError>
|
|
99
|
-
where
|
|
100
|
-
Self: Sized,
|
|
101
|
-
{
|
|
102
|
-
match tag {
|
|
103
|
-
1 => prost::encoding::string::merge(wire_type, &mut self.error, buf, ctx),
|
|
104
|
-
_ => prost::encoding::skip_field(wire_type, tag, buf, ctx),
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
fn encoded_len(&self) -> usize {
|
|
109
|
-
let mut len = 0;
|
|
110
|
-
if !self.error.is_empty() {
|
|
111
|
-
len += prost::encoding::string::encoded_len(1, &self.error);
|
|
112
|
-
}
|
|
113
|
-
len
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
fn clear(&mut self) {
|
|
117
|
-
self.error.clear();
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
// Manual Message implementation for RpcStreamPacket
|
|
122
|
-
impl Message for RpcStreamPacket {
|
|
123
|
-
fn encode_raw(&self, buf: &mut impl BufMut)
|
|
124
|
-
where
|
|
125
|
-
Self: Sized,
|
|
126
|
-
{
|
|
127
|
-
match &self.body {
|
|
128
|
-
Some(RpcStreamPacketBody::Init(init)) => {
|
|
129
|
-
// Tag 1, wire type 2 (length-delimited)
|
|
130
|
-
prost::encoding::message::encode(1, init, buf);
|
|
131
|
-
}
|
|
132
|
-
Some(RpcStreamPacketBody::Ack(ack)) => {
|
|
133
|
-
// Tag 2, wire type 2 (length-delimited)
|
|
134
|
-
prost::encoding::message::encode(2, ack, buf);
|
|
135
|
-
}
|
|
136
|
-
Some(RpcStreamPacketBody::Data(data)) => {
|
|
137
|
-
// Tag 3, wire type 2 (length-delimited)
|
|
138
|
-
prost::encoding::bytes::encode(3, data, buf);
|
|
139
|
-
}
|
|
140
|
-
None => {}
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
fn merge_field(
|
|
145
|
-
&mut self,
|
|
146
|
-
tag: u32,
|
|
147
|
-
wire_type: prost::encoding::WireType,
|
|
148
|
-
buf: &mut impl Buf,
|
|
149
|
-
ctx: prost::encoding::DecodeContext,
|
|
150
|
-
) -> Result<(), DecodeError>
|
|
151
|
-
where
|
|
152
|
-
Self: Sized,
|
|
153
|
-
{
|
|
154
|
-
match tag {
|
|
155
|
-
1 => {
|
|
156
|
-
let mut init = RpcStreamInit::default();
|
|
157
|
-
prost::encoding::message::merge(wire_type, &mut init, buf, ctx)?;
|
|
158
|
-
self.body = Some(RpcStreamPacketBody::Init(init));
|
|
159
|
-
Ok(())
|
|
160
|
-
}
|
|
161
|
-
2 => {
|
|
162
|
-
let mut ack = RpcAck::default();
|
|
163
|
-
prost::encoding::message::merge(wire_type, &mut ack, buf, ctx)?;
|
|
164
|
-
self.body = Some(RpcStreamPacketBody::Ack(ack));
|
|
165
|
-
Ok(())
|
|
166
|
-
}
|
|
167
|
-
3 => {
|
|
168
|
-
let mut data = Bytes::default();
|
|
169
|
-
prost::encoding::bytes::merge(wire_type, &mut data, buf, ctx)?;
|
|
170
|
-
self.body = Some(RpcStreamPacketBody::Data(data));
|
|
171
|
-
Ok(())
|
|
172
|
-
}
|
|
173
|
-
_ => prost::encoding::skip_field(wire_type, tag, buf, ctx),
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
fn encoded_len(&self) -> usize {
|
|
178
|
-
match &self.body {
|
|
179
|
-
Some(RpcStreamPacketBody::Init(init)) => prost::encoding::message::encoded_len(1, init),
|
|
180
|
-
Some(RpcStreamPacketBody::Ack(ack)) => prost::encoding::message::encoded_len(2, ack),
|
|
181
|
-
Some(RpcStreamPacketBody::Data(data)) => prost::encoding::bytes::encoded_len(3, data),
|
|
182
|
-
None => 0,
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
fn clear(&mut self) {
|
|
187
|
-
self.body = None;
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
impl RpcStreamPacket {
|
|
192
|
-
/// Creates a new Init packet.
|
|
193
|
-
pub fn new_init(component_id: String) -> Self {
|
|
194
|
-
Self {
|
|
195
|
-
body: Some(RpcStreamPacketBody::Init(RpcStreamInit { component_id })),
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
/// Creates a new Ack packet.
|
|
200
|
-
pub fn new_ack(error: String) -> Self {
|
|
201
|
-
Self {
|
|
202
|
-
body: Some(RpcStreamPacketBody::Ack(RpcAck { error })),
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
/// Creates a new Data packet.
|
|
207
|
-
pub fn new_data(data: Bytes) -> Self {
|
|
208
|
-
Self {
|
|
209
|
-
body: Some(RpcStreamPacketBody::Data(data)),
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
#[cfg(test)]
|
|
215
|
-
mod tests {
|
|
216
|
-
use super::*;
|
|
217
|
-
|
|
218
|
-
#[test]
|
|
219
|
-
fn test_rpc_stream_init_encode_decode() {
|
|
220
|
-
let init = RpcStreamInit {
|
|
221
|
-
component_id: "test-component".to_string(),
|
|
222
|
-
};
|
|
223
|
-
|
|
224
|
-
let encoded = init.encode_to_vec();
|
|
225
|
-
let decoded = RpcStreamInit::decode(&encoded[..]).unwrap();
|
|
226
|
-
|
|
227
|
-
assert_eq!(init, decoded);
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
#[test]
|
|
231
|
-
fn test_rpc_ack_encode_decode() {
|
|
232
|
-
let ack = RpcAck {
|
|
233
|
-
error: "test error".to_string(),
|
|
234
|
-
};
|
|
235
|
-
|
|
236
|
-
let encoded = ack.encode_to_vec();
|
|
237
|
-
let decoded = RpcAck::decode(&encoded[..]).unwrap();
|
|
238
|
-
|
|
239
|
-
assert_eq!(ack, decoded);
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
#[test]
|
|
243
|
-
fn test_rpc_stream_packet_init() {
|
|
244
|
-
let packet = RpcStreamPacket::new_init("my-component".to_string());
|
|
245
|
-
|
|
246
|
-
let encoded = packet.encode_to_vec();
|
|
247
|
-
let decoded = RpcStreamPacket::decode(&encoded[..]).unwrap();
|
|
248
|
-
|
|
249
|
-
match decoded.body {
|
|
250
|
-
Some(RpcStreamPacketBody::Init(init)) => {
|
|
251
|
-
assert_eq!(init.component_id, "my-component");
|
|
252
|
-
}
|
|
253
|
-
_ => panic!("Expected Init body"),
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
#[test]
|
|
258
|
-
fn test_rpc_stream_packet_ack() {
|
|
259
|
-
let packet = RpcStreamPacket::new_ack("".to_string());
|
|
260
|
-
|
|
261
|
-
let encoded = packet.encode_to_vec();
|
|
262
|
-
let decoded = RpcStreamPacket::decode(&encoded[..]).unwrap();
|
|
263
|
-
|
|
264
|
-
match decoded.body {
|
|
265
|
-
Some(RpcStreamPacketBody::Ack(ack)) => {
|
|
266
|
-
assert!(ack.error.is_empty());
|
|
267
|
-
}
|
|
268
|
-
_ => panic!("Expected Ack body"),
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
#[test]
|
|
273
|
-
fn test_rpc_stream_packet_data() {
|
|
274
|
-
let packet = RpcStreamPacket::new_data(Bytes::from(vec![1, 2, 3, 4]));
|
|
275
|
-
|
|
276
|
-
let encoded = packet.encode_to_vec();
|
|
277
|
-
let decoded = RpcStreamPacket::decode(&encoded[..]).unwrap();
|
|
278
|
-
|
|
279
|
-
match decoded.body {
|
|
280
|
-
Some(RpcStreamPacketBody::Data(data)) => {
|
|
281
|
-
assert_eq!(&data[..], &[1, 2, 3, 4]);
|
|
282
|
-
}
|
|
283
|
-
_ => panic!("Expected Data body"),
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
}
|
package/srpc/rpcstream/stream.rs
DELETED
|
@@ -1,517 +0,0 @@
|
|
|
1
|
-
//! RpcStream trait and functions for opening/handling nested RPC streams.
|
|
2
|
-
|
|
3
|
-
use async_trait::async_trait;
|
|
4
|
-
use bytes::Bytes;
|
|
5
|
-
use prost::Message;
|
|
6
|
-
use std::sync::Arc;
|
|
7
|
-
|
|
8
|
-
use crate::client::{OpenStream, PacketReceiver};
|
|
9
|
-
use crate::error::{Error, Result};
|
|
10
|
-
use crate::invoker::Invoker;
|
|
11
|
-
use crate::proto::Packet;
|
|
12
|
-
use crate::rpc::{PacketWriter, ServerRpc};
|
|
13
|
-
use crate::stream::{Context, Stream};
|
|
14
|
-
|
|
15
|
-
use super::proto::{RpcStreamPacket, RpcStreamPacketBody};
|
|
16
|
-
use super::writer::RpcStreamWriter;
|
|
17
|
-
|
|
18
|
-
/// RpcStream is a bidirectional stream for RpcStreamPacket messages.
|
|
19
|
-
///
|
|
20
|
-
/// This trait extends the base Stream trait with typed send/recv operations
|
|
21
|
-
/// for RpcStreamPacket messages.
|
|
22
|
-
#[async_trait]
|
|
23
|
-
pub trait RpcStream: Stream {
|
|
24
|
-
/// Sends an RpcStreamPacket.
|
|
25
|
-
async fn send_packet(&self, packet: &RpcStreamPacket) -> Result<()>;
|
|
26
|
-
|
|
27
|
-
/// Receives an RpcStreamPacket.
|
|
28
|
-
async fn recv_packet(&self) -> Result<RpcStreamPacket>;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/// Generic RpcStream implementation wrapping any Stream.
|
|
32
|
-
pub struct RpcStreamImpl<S: Stream> {
|
|
33
|
-
inner: S,
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
impl<S: Stream> RpcStreamImpl<S> {
|
|
37
|
-
/// Creates a new RpcStreamImpl wrapping the given stream.
|
|
38
|
-
pub fn new(inner: S) -> Self {
|
|
39
|
-
Self { inner }
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
#[async_trait]
|
|
44
|
-
impl<S: Stream + Send + Sync> Stream for RpcStreamImpl<S> {
|
|
45
|
-
fn context(&self) -> &Context {
|
|
46
|
-
self.inner.context()
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
async fn send_bytes(&self, data: Bytes) -> Result<()> {
|
|
50
|
-
self.inner.send_bytes(data).await
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
async fn recv_bytes(&self) -> Result<Bytes> {
|
|
54
|
-
self.inner.recv_bytes().await
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
async fn close_send(&self) -> Result<()> {
|
|
58
|
-
self.inner.close_send().await
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
async fn close(&self) -> Result<()> {
|
|
62
|
-
self.inner.close().await
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
#[async_trait]
|
|
67
|
-
impl<S: Stream + Send + Sync> RpcStream for RpcStreamImpl<S> {
|
|
68
|
-
async fn send_packet(&self, packet: &RpcStreamPacket) -> Result<()> {
|
|
69
|
-
let data = packet.encode_to_vec();
|
|
70
|
-
self.inner.send_bytes(Bytes::from(data)).await
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
async fn recv_packet(&self) -> Result<RpcStreamPacket> {
|
|
74
|
-
let data = self.inner.recv_bytes().await?;
|
|
75
|
-
RpcStreamPacket::decode(&data[..]).map_err(Error::InvalidMessage)
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
// Implement RpcStream for Arc<S> where S: RpcStream
|
|
80
|
-
#[async_trait]
|
|
81
|
-
impl<S: RpcStream + ?Sized + Send + Sync> RpcStream for Arc<S> {
|
|
82
|
-
async fn send_packet(&self, packet: &RpcStreamPacket) -> Result<()> {
|
|
83
|
-
(**self).send_packet(packet).await
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
async fn recv_packet(&self) -> Result<RpcStreamPacket> {
|
|
87
|
-
(**self).recv_packet().await
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/// Getter function to resolve component ID to an invoker.
|
|
92
|
-
///
|
|
93
|
-
/// # Arguments
|
|
94
|
-
/// * `ctx` - Context for the RPC stream
|
|
95
|
-
/// * `component_id` - The component ID to look up
|
|
96
|
-
/// * `released` - Callback to invoke when the stream is released
|
|
97
|
-
///
|
|
98
|
-
/// # Returns
|
|
99
|
-
/// `Some((invoker, release_fn))` if found, `None` if not found.
|
|
100
|
-
pub type RpcStreamGetter = Arc<
|
|
101
|
-
dyn Fn(&Context, &str, Box<dyn FnOnce() + Send>) -> Option<(Arc<dyn Invoker>, Box<dyn FnOnce() + Send>)>
|
|
102
|
-
+ Send
|
|
103
|
-
+ Sync,
|
|
104
|
-
>;
|
|
105
|
-
|
|
106
|
-
/// Opens an RPC stream with a remote component.
|
|
107
|
-
///
|
|
108
|
-
/// This function performs the client-side init/ack handshake:
|
|
109
|
-
/// 1. Sends RpcStreamInit with the component ID
|
|
110
|
-
/// 2. Optionally waits for RpcAck from the server
|
|
111
|
-
///
|
|
112
|
-
/// # Arguments
|
|
113
|
-
/// * `stream` - The underlying RPC stream
|
|
114
|
-
/// * `component_id` - The target component ID
|
|
115
|
-
/// * `wait_ack` - Whether to wait for acknowledgment
|
|
116
|
-
///
|
|
117
|
-
/// # Returns
|
|
118
|
-
/// Ok(()) on success
|
|
119
|
-
pub async fn open_rpc_stream<S: RpcStream + Send + Sync>(
|
|
120
|
-
stream: &S,
|
|
121
|
-
component_id: &str,
|
|
122
|
-
wait_ack: bool,
|
|
123
|
-
) -> Result<()> {
|
|
124
|
-
// Send the init packet
|
|
125
|
-
let init_packet = RpcStreamPacket::new_init(component_id.to_string());
|
|
126
|
-
stream.send_packet(&init_packet).await?;
|
|
127
|
-
|
|
128
|
-
// Wait for ack if requested
|
|
129
|
-
if wait_ack {
|
|
130
|
-
let ack_packet = stream.recv_packet().await?;
|
|
131
|
-
match ack_packet.body {
|
|
132
|
-
Some(RpcStreamPacketBody::Ack(ack)) => {
|
|
133
|
-
if !ack.error.is_empty() {
|
|
134
|
-
return Err(Error::Remote(format!("remote: {}", ack.error)));
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
_ => {
|
|
138
|
-
return Err(Error::UnrecognizedPacket);
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
Ok(())
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
/// Handles an incoming RPC stream (server side).
|
|
147
|
-
///
|
|
148
|
-
/// This function handles the server-side of the rpcstream protocol:
|
|
149
|
-
/// 1. Receives RpcStreamInit with component ID
|
|
150
|
-
/// 2. Looks up the invoker for that component
|
|
151
|
-
/// 3. Sends RpcAck (with error if not found)
|
|
152
|
-
/// 4. Handles nested RPC calls over the stream
|
|
153
|
-
///
|
|
154
|
-
/// # Arguments
|
|
155
|
-
/// * `stream` - The incoming RPC stream
|
|
156
|
-
/// * `getter` - Function to look up invokers by component ID
|
|
157
|
-
pub async fn handle_rpc_stream<S: RpcStream + Send + Sync + 'static>(
|
|
158
|
-
stream: Arc<S>,
|
|
159
|
-
getter: RpcStreamGetter,
|
|
160
|
-
) -> Result<()> {
|
|
161
|
-
// Read the init packet
|
|
162
|
-
let init_packet = stream.recv_packet().await?;
|
|
163
|
-
let component_id = match init_packet.body {
|
|
164
|
-
Some(RpcStreamPacketBody::Init(init)) => init.component_id,
|
|
165
|
-
_ => {
|
|
166
|
-
return Err(Error::UnrecognizedPacket);
|
|
167
|
-
}
|
|
168
|
-
};
|
|
169
|
-
|
|
170
|
-
let ctx = stream.context().child();
|
|
171
|
-
|
|
172
|
-
// Look up the invoker
|
|
173
|
-
let ctx_cancel = ctx.clone();
|
|
174
|
-
let released = Box::new(move || {
|
|
175
|
-
ctx_cancel.cancel();
|
|
176
|
-
});
|
|
177
|
-
|
|
178
|
-
let lookup_result = getter(&ctx, &component_id, released);
|
|
179
|
-
|
|
180
|
-
// Send ack
|
|
181
|
-
let (invoker, release_fn) = match lookup_result {
|
|
182
|
-
Some((inv, rel)) => {
|
|
183
|
-
// Send success ack
|
|
184
|
-
stream
|
|
185
|
-
.send_packet(&RpcStreamPacket::new_ack(String::new()))
|
|
186
|
-
.await?;
|
|
187
|
-
(inv, Some(rel))
|
|
188
|
-
}
|
|
189
|
-
None => {
|
|
190
|
-
// Send error ack
|
|
191
|
-
let err_msg = format!("no server for component: {}", component_id);
|
|
192
|
-
stream
|
|
193
|
-
.send_packet(&RpcStreamPacket::new_ack(err_msg.clone()))
|
|
194
|
-
.await?;
|
|
195
|
-
return Err(Error::Remote(err_msg));
|
|
196
|
-
}
|
|
197
|
-
};
|
|
198
|
-
|
|
199
|
-
// Ensure release is called when we're done
|
|
200
|
-
let _release_guard = scopeguard::guard(release_fn, |rel| {
|
|
201
|
-
if let Some(f) = rel {
|
|
202
|
-
f();
|
|
203
|
-
}
|
|
204
|
-
});
|
|
205
|
-
|
|
206
|
-
// Create a writer for the RPC stream
|
|
207
|
-
let writer: Arc<dyn PacketWriter> = Arc::new(RpcStreamWriter::new(stream.clone()));
|
|
208
|
-
|
|
209
|
-
// Read and handle packets
|
|
210
|
-
loop {
|
|
211
|
-
let rpc_packet = match stream.recv_packet().await {
|
|
212
|
-
Ok(p) => p,
|
|
213
|
-
Err(Error::StreamClosed) => break,
|
|
214
|
-
Err(e) => return Err(e),
|
|
215
|
-
};
|
|
216
|
-
|
|
217
|
-
let packet = match rpc_packet.body {
|
|
218
|
-
Some(RpcStreamPacketBody::Data(data)) => {
|
|
219
|
-
match Packet::decode(&data[..]) {
|
|
220
|
-
Ok(p) => p,
|
|
221
|
-
Err(e) => return Err(Error::InvalidMessage(e)),
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
_ => continue, // Ignore non-data packets
|
|
225
|
-
};
|
|
226
|
-
|
|
227
|
-
// Handle the packet based on its type
|
|
228
|
-
use crate::proto::packet::Body;
|
|
229
|
-
match packet.body {
|
|
230
|
-
Some(Body::CallStart(call_start)) => {
|
|
231
|
-
let rpc_ctx = ctx.child();
|
|
232
|
-
let rpc = Arc::new(ServerRpc::from_call_start(
|
|
233
|
-
rpc_ctx,
|
|
234
|
-
call_start,
|
|
235
|
-
writer.clone(),
|
|
236
|
-
));
|
|
237
|
-
|
|
238
|
-
let service_id = rpc.service().to_string();
|
|
239
|
-
let method_id = rpc.method().to_string();
|
|
240
|
-
|
|
241
|
-
// Spawn a task to handle this RPC
|
|
242
|
-
let invoker_clone = invoker.clone();
|
|
243
|
-
tokio::spawn(async move {
|
|
244
|
-
let (_found, _result) = invoker_clone
|
|
245
|
-
.invoke_method(&service_id, &method_id, Box::new(ServerRpcStream { rpc }))
|
|
246
|
-
.await;
|
|
247
|
-
});
|
|
248
|
-
}
|
|
249
|
-
Some(Body::CallData(_)) | Some(Body::CallCancel(_)) => {
|
|
250
|
-
// These should be routed to an existing RPC
|
|
251
|
-
// In this simplified implementation, they're ignored
|
|
252
|
-
}
|
|
253
|
-
None => {}
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
Ok(())
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
/// Wrapper to make ServerRpc implement Stream for use with invoke_method.
|
|
261
|
-
struct ServerRpcStream {
|
|
262
|
-
rpc: Arc<ServerRpc>,
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
#[async_trait]
|
|
266
|
-
impl Stream for ServerRpcStream {
|
|
267
|
-
fn context(&self) -> &Context {
|
|
268
|
-
self.rpc.context()
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
async fn send_bytes(&self, data: Bytes) -> Result<()> {
|
|
272
|
-
crate::stream::Stream::send_bytes(self.rpc.as_ref(), data).await
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
async fn recv_bytes(&self) -> Result<Bytes> {
|
|
276
|
-
crate::stream::Stream::recv_bytes(self.rpc.as_ref()).await
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
async fn close_send(&self) -> Result<()> {
|
|
280
|
-
crate::stream::Stream::close_send(self.rpc.as_ref()).await
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
async fn close(&self) -> Result<()> {
|
|
284
|
-
crate::stream::Stream::close(self.rpc.as_ref()).await
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
/// Creates an OpenStream function using an RPC stream caller.
|
|
289
|
-
///
|
|
290
|
-
/// This allows creating a Client that operates over an RPC stream,
|
|
291
|
-
/// enabling nested RPC calls.
|
|
292
|
-
///
|
|
293
|
-
/// # Type Parameters
|
|
294
|
-
/// * `F` - Async function that creates a new stream
|
|
295
|
-
/// * `S` - Stream type
|
|
296
|
-
pub fn new_rpc_stream_open_stream<F, Fut, S>(
|
|
297
|
-
caller: F,
|
|
298
|
-
component_id: String,
|
|
299
|
-
wait_ack: bool,
|
|
300
|
-
) -> impl OpenStream
|
|
301
|
-
where
|
|
302
|
-
F: Fn() -> Fut + Send + Sync + 'static,
|
|
303
|
-
Fut: std::future::Future<Output = Result<S>> + Send + 'static,
|
|
304
|
-
S: Stream + Send + Sync + 'static,
|
|
305
|
-
{
|
|
306
|
-
RpcStreamOpener {
|
|
307
|
-
caller: Arc::new(caller),
|
|
308
|
-
component_id,
|
|
309
|
-
wait_ack,
|
|
310
|
-
_phantom: std::marker::PhantomData,
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
struct RpcStreamOpener<F, S> {
|
|
315
|
-
caller: Arc<F>,
|
|
316
|
-
component_id: String,
|
|
317
|
-
wait_ack: bool,
|
|
318
|
-
_phantom: std::marker::PhantomData<S>,
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
#[async_trait]
|
|
322
|
-
impl<F, Fut, S> OpenStream for RpcStreamOpener<F, S>
|
|
323
|
-
where
|
|
324
|
-
F: Fn() -> Fut + Send + Sync + 'static,
|
|
325
|
-
Fut: std::future::Future<Output = Result<S>> + Send + 'static,
|
|
326
|
-
S: Stream + Send + Sync + 'static,
|
|
327
|
-
{
|
|
328
|
-
async fn open_stream(&self) -> Result<(Arc<dyn PacketWriter>, PacketReceiver)> {
|
|
329
|
-
// Open the underlying stream
|
|
330
|
-
let stream = (self.caller)().await?;
|
|
331
|
-
let rpc_stream = Arc::new(RpcStreamImpl::new(stream));
|
|
332
|
-
|
|
333
|
-
// Perform the init/ack handshake
|
|
334
|
-
open_rpc_stream(rpc_stream.as_ref(), &self.component_id, self.wait_ack).await?;
|
|
335
|
-
|
|
336
|
-
// Create a writer
|
|
337
|
-
let writer: Arc<dyn PacketWriter> = Arc::new(RpcStreamWriter::new(rpc_stream.clone()));
|
|
338
|
-
|
|
339
|
-
// Create a channel for incoming packets
|
|
340
|
-
let (tx, rx) = tokio::sync::mpsc::channel(32);
|
|
341
|
-
|
|
342
|
-
// Spawn a read pump to convert RpcStreamPacket::Data into Packets
|
|
343
|
-
let stream_clone = rpc_stream.clone();
|
|
344
|
-
tokio::spawn(async move {
|
|
345
|
-
loop {
|
|
346
|
-
match stream_clone.recv_packet().await {
|
|
347
|
-
Ok(packet) => {
|
|
348
|
-
if let Some(RpcStreamPacketBody::Data(data)) = packet.body {
|
|
349
|
-
match Packet::decode(&data[..]) {
|
|
350
|
-
Ok(p) => {
|
|
351
|
-
if tx.send(p).await.is_err() {
|
|
352
|
-
break;
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
Err(_) => break,
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
Err(_) => break,
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
});
|
|
363
|
-
|
|
364
|
-
Ok((writer, rx))
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
/// Creates a Client that operates over an RPC stream.
|
|
369
|
-
///
|
|
370
|
-
/// # Arguments
|
|
371
|
-
/// * `caller` - Function that opens a new RPC stream
|
|
372
|
-
/// * `component_id` - Target component ID
|
|
373
|
-
/// * `wait_ack` - Whether to wait for acknowledgment
|
|
374
|
-
pub fn new_rpc_stream_client<F, Fut, S>(
|
|
375
|
-
caller: F,
|
|
376
|
-
component_id: String,
|
|
377
|
-
wait_ack: bool,
|
|
378
|
-
) -> crate::SrpcClient<impl OpenStream>
|
|
379
|
-
where
|
|
380
|
-
F: Fn() -> Fut + Send + Sync + 'static,
|
|
381
|
-
Fut: std::future::Future<Output = Result<S>> + Send + 'static,
|
|
382
|
-
S: Stream + Send + Sync + 'static,
|
|
383
|
-
{
|
|
384
|
-
let opener = new_rpc_stream_open_stream(caller, component_id, wait_ack);
|
|
385
|
-
crate::SrpcClient::new(opener)
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
#[cfg(test)]
|
|
389
|
-
mod tests {
|
|
390
|
-
use super::*;
|
|
391
|
-
use std::sync::atomic::{AtomicBool, Ordering};
|
|
392
|
-
use tokio::sync::Mutex;
|
|
393
|
-
use std::collections::VecDeque;
|
|
394
|
-
|
|
395
|
-
struct MockRpcStream {
|
|
396
|
-
ctx: Context,
|
|
397
|
-
send_queue: Mutex<VecDeque<RpcStreamPacket>>,
|
|
398
|
-
recv_queue: Mutex<VecDeque<RpcStreamPacket>>,
|
|
399
|
-
closed: AtomicBool,
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
impl MockRpcStream {
|
|
403
|
-
fn new() -> Self {
|
|
404
|
-
Self {
|
|
405
|
-
ctx: Context::new(),
|
|
406
|
-
send_queue: Mutex::new(VecDeque::new()),
|
|
407
|
-
recv_queue: Mutex::new(VecDeque::new()),
|
|
408
|
-
closed: AtomicBool::new(false),
|
|
409
|
-
}
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
async fn push_recv(&self, packet: RpcStreamPacket) {
|
|
413
|
-
self.recv_queue.lock().await.push_back(packet);
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
async fn pop_sent(&self) -> Option<RpcStreamPacket> {
|
|
417
|
-
self.send_queue.lock().await.pop_front()
|
|
418
|
-
}
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
#[async_trait]
|
|
422
|
-
impl Stream for MockRpcStream {
|
|
423
|
-
fn context(&self) -> &Context {
|
|
424
|
-
&self.ctx
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
async fn send_bytes(&self, data: Bytes) -> Result<()> {
|
|
428
|
-
let packet = RpcStreamPacket::decode(&data[..]).map_err(Error::InvalidMessage)?;
|
|
429
|
-
self.send_queue.lock().await.push_back(packet);
|
|
430
|
-
Ok(())
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
async fn recv_bytes(&self) -> Result<Bytes> {
|
|
434
|
-
loop {
|
|
435
|
-
if let Some(packet) = self.recv_queue.lock().await.pop_front() {
|
|
436
|
-
return Ok(Bytes::from(packet.encode_to_vec()));
|
|
437
|
-
}
|
|
438
|
-
if self.closed.load(Ordering::SeqCst) {
|
|
439
|
-
return Err(Error::StreamClosed);
|
|
440
|
-
}
|
|
441
|
-
tokio::time::sleep(tokio::time::Duration::from_millis(10)).await;
|
|
442
|
-
}
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
async fn close_send(&self) -> Result<()> {
|
|
446
|
-
Ok(())
|
|
447
|
-
}
|
|
448
|
-
|
|
449
|
-
async fn close(&self) -> Result<()> {
|
|
450
|
-
self.closed.store(true, Ordering::SeqCst);
|
|
451
|
-
Ok(())
|
|
452
|
-
}
|
|
453
|
-
}
|
|
454
|
-
|
|
455
|
-
#[async_trait]
|
|
456
|
-
impl RpcStream for MockRpcStream {
|
|
457
|
-
async fn send_packet(&self, packet: &RpcStreamPacket) -> Result<()> {
|
|
458
|
-
self.send_queue.lock().await.push_back(packet.clone());
|
|
459
|
-
Ok(())
|
|
460
|
-
}
|
|
461
|
-
|
|
462
|
-
async fn recv_packet(&self) -> Result<RpcStreamPacket> {
|
|
463
|
-
loop {
|
|
464
|
-
if let Some(packet) = self.recv_queue.lock().await.pop_front() {
|
|
465
|
-
return Ok(packet);
|
|
466
|
-
}
|
|
467
|
-
if self.closed.load(Ordering::SeqCst) {
|
|
468
|
-
return Err(Error::StreamClosed);
|
|
469
|
-
}
|
|
470
|
-
tokio::time::sleep(tokio::time::Duration::from_millis(10)).await;
|
|
471
|
-
}
|
|
472
|
-
}
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
#[tokio::test]
|
|
476
|
-
async fn test_open_rpc_stream_no_ack() {
|
|
477
|
-
let stream = MockRpcStream::new();
|
|
478
|
-
|
|
479
|
-
let result = open_rpc_stream(&stream, "test-component", false).await;
|
|
480
|
-
assert!(result.is_ok());
|
|
481
|
-
|
|
482
|
-
// Check that init was sent
|
|
483
|
-
let sent = stream.pop_sent().await.unwrap();
|
|
484
|
-
match sent.body {
|
|
485
|
-
Some(RpcStreamPacketBody::Init(init)) => {
|
|
486
|
-
assert_eq!(init.component_id, "test-component");
|
|
487
|
-
}
|
|
488
|
-
_ => panic!("Expected Init packet"),
|
|
489
|
-
}
|
|
490
|
-
}
|
|
491
|
-
|
|
492
|
-
#[tokio::test]
|
|
493
|
-
async fn test_open_rpc_stream_with_ack() {
|
|
494
|
-
let stream = MockRpcStream::new();
|
|
495
|
-
|
|
496
|
-
// Pre-queue an ack response
|
|
497
|
-
stream
|
|
498
|
-
.push_recv(RpcStreamPacket::new_ack(String::new()))
|
|
499
|
-
.await;
|
|
500
|
-
|
|
501
|
-
let result = open_rpc_stream(&stream, "test-component", true).await;
|
|
502
|
-
assert!(result.is_ok());
|
|
503
|
-
}
|
|
504
|
-
|
|
505
|
-
#[tokio::test]
|
|
506
|
-
async fn test_open_rpc_stream_with_error_ack() {
|
|
507
|
-
let stream = MockRpcStream::new();
|
|
508
|
-
|
|
509
|
-
// Pre-queue an error ack response
|
|
510
|
-
stream
|
|
511
|
-
.push_recv(RpcStreamPacket::new_ack("component not found".to_string()))
|
|
512
|
-
.await;
|
|
513
|
-
|
|
514
|
-
let result = open_rpc_stream(&stream, "test-component", true).await;
|
|
515
|
-
assert!(matches!(result, Err(Error::Remote(_))));
|
|
516
|
-
}
|
|
517
|
-
}
|
package/srpc/rpcstream/writer.rs
DELETED
|
@@ -1,150 +0,0 @@
|
|
|
1
|
-
//! RpcStreamWriter - PacketWriter implementation for RpcStream.
|
|
2
|
-
|
|
3
|
-
use async_trait::async_trait;
|
|
4
|
-
use bytes::Bytes;
|
|
5
|
-
use prost::Message;
|
|
6
|
-
|
|
7
|
-
use crate::error::Result;
|
|
8
|
-
use crate::proto::Packet;
|
|
9
|
-
use crate::rpc::PacketWriter;
|
|
10
|
-
|
|
11
|
-
use super::proto::RpcStreamPacket;
|
|
12
|
-
use super::stream::RpcStream;
|
|
13
|
-
|
|
14
|
-
/// RpcStreamWriter wraps an RpcStream and implements PacketWriter.
|
|
15
|
-
///
|
|
16
|
-
/// This allows using an RpcStream as the transport for nested RPC calls,
|
|
17
|
-
/// converting Packet messages to RpcStreamPacket::Data messages.
|
|
18
|
-
pub struct RpcStreamWriter<S> {
|
|
19
|
-
/// The underlying RpcStream.
|
|
20
|
-
pub(crate) inner: S,
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
impl<S> RpcStreamWriter<S> {
|
|
24
|
-
/// Creates a new RpcStreamWriter.
|
|
25
|
-
pub fn new(stream: S) -> Self {
|
|
26
|
-
Self { inner: stream }
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/// Returns a reference to the inner stream.
|
|
30
|
-
pub fn inner(&self) -> &S {
|
|
31
|
-
&self.inner
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
#[async_trait]
|
|
36
|
-
impl<S: RpcStream + Send + Sync> PacketWriter for RpcStreamWriter<S> {
|
|
37
|
-
async fn write_packet(&self, packet: Packet) -> Result<()> {
|
|
38
|
-
let data = packet.encode_to_vec();
|
|
39
|
-
let rpc_packet = RpcStreamPacket::new_data(Bytes::from(data));
|
|
40
|
-
self.inner.send_packet(&rpc_packet).await
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
async fn close(&self) -> Result<()> {
|
|
44
|
-
self.inner.close_send().await
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
#[cfg(test)]
|
|
50
|
-
mod tests {
|
|
51
|
-
use super::*;
|
|
52
|
-
use crate::stream::{Context, Stream};
|
|
53
|
-
use std::collections::VecDeque;
|
|
54
|
-
use std::sync::atomic::{AtomicBool, Ordering};
|
|
55
|
-
use tokio::sync::Mutex;
|
|
56
|
-
|
|
57
|
-
struct MockRpcStream {
|
|
58
|
-
ctx: Context,
|
|
59
|
-
packets: Mutex<VecDeque<RpcStreamPacket>>,
|
|
60
|
-
closed: AtomicBool,
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
impl MockRpcStream {
|
|
64
|
-
fn new() -> Self {
|
|
65
|
-
Self {
|
|
66
|
-
ctx: Context::new(),
|
|
67
|
-
packets: Mutex::new(VecDeque::new()),
|
|
68
|
-
closed: AtomicBool::new(false),
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
async fn get_packets(&self) -> Vec<RpcStreamPacket> {
|
|
73
|
-
self.packets.lock().await.iter().cloned().collect()
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
#[async_trait]
|
|
78
|
-
impl Stream for MockRpcStream {
|
|
79
|
-
fn context(&self) -> &Context {
|
|
80
|
-
&self.ctx
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
async fn send_bytes(&self, _data: Bytes) -> Result<()> {
|
|
84
|
-
Ok(())
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
async fn recv_bytes(&self) -> Result<Bytes> {
|
|
88
|
-
Err(crate::Error::StreamClosed)
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
async fn close_send(&self) -> Result<()> {
|
|
92
|
-
self.closed.store(true, Ordering::SeqCst);
|
|
93
|
-
Ok(())
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
async fn close(&self) -> Result<()> {
|
|
97
|
-
self.closed.store(true, Ordering::SeqCst);
|
|
98
|
-
Ok(())
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
#[async_trait]
|
|
103
|
-
impl RpcStream for MockRpcStream {
|
|
104
|
-
async fn send_packet(&self, packet: &RpcStreamPacket) -> Result<()> {
|
|
105
|
-
self.packets.lock().await.push_back(packet.clone());
|
|
106
|
-
Ok(())
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
async fn recv_packet(&self) -> Result<RpcStreamPacket> {
|
|
110
|
-
Err(crate::Error::StreamClosed)
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
#[tokio::test]
|
|
115
|
-
async fn test_rpc_stream_writer_write_packet() {
|
|
116
|
-
use std::sync::Arc;
|
|
117
|
-
let stream = Arc::new(MockRpcStream::new());
|
|
118
|
-
let writer = RpcStreamWriter::new(stream.clone());
|
|
119
|
-
|
|
120
|
-
let packet = crate::packet::new_call_start(
|
|
121
|
-
"test.Service".to_string(),
|
|
122
|
-
"TestMethod".to_string(),
|
|
123
|
-
Some(Bytes::from(vec![1, 2, 3])),
|
|
124
|
-
);
|
|
125
|
-
|
|
126
|
-
writer.write_packet(packet).await.unwrap();
|
|
127
|
-
|
|
128
|
-
let packets = stream.get_packets().await;
|
|
129
|
-
assert_eq!(packets.len(), 1);
|
|
130
|
-
|
|
131
|
-
match &packets[0].body {
|
|
132
|
-
Some(crate::rpcstream::RpcStreamPacketBody::Data(data)) => {
|
|
133
|
-
// Verify we can decode the inner packet
|
|
134
|
-
let inner = Packet::decode(&data[..]).unwrap();
|
|
135
|
-
assert!(inner.body.is_some());
|
|
136
|
-
}
|
|
137
|
-
_ => panic!("Expected Data packet"),
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
#[tokio::test]
|
|
142
|
-
async fn test_rpc_stream_writer_close() {
|
|
143
|
-
use std::sync::Arc;
|
|
144
|
-
let stream = Arc::new(MockRpcStream::new());
|
|
145
|
-
let writer = RpcStreamWriter::new(stream.clone());
|
|
146
|
-
|
|
147
|
-
writer.close().await.unwrap();
|
|
148
|
-
assert!(stream.closed.load(Ordering::SeqCst));
|
|
149
|
-
}
|
|
150
|
-
}
|