1use crate::error::{Result, RpcError};
2use crate::io::{AsyncStream, read_message};
3use crate::rpc_capnp;
4
5pub struct RpcClient<S> {
17 stream: S,
18 next_question: u32,
19 has_bootstrap: bool,
20}
21
22enum BootstrapOutcome {
23 Capability,
24 Exception(String),
25 NoCapability,
26 UnexpectedKind,
27}
28
29enum CallOutcome<T> {
30 Value(T),
31 Exception(String),
32 UnexpectedKind,
33}
34
35impl<S: AsyncStream + Unpin> RpcClient<S> {
36 pub fn new(stream: S) -> Self {
38 Self {
39 stream,
40 next_question: 0,
41 has_bootstrap: false,
42 }
43 }
44
45 pub fn into_inner(self) -> S {
47 self.stream
48 }
49
50 pub async fn bootstrap(&mut self) -> Result<u32> {
53 if self.has_bootstrap {
54 return Err(RpcError::Protocol("bootstrap called twice".into()));
55 }
56 let question = self.next_question;
57 self.next_question += 1;
58
59 tracing::trace!(question, "sending bootstrap");
60 let bytes = build_bootstrap(question)?;
61 crate::io::write_raw(&mut self.stream, &bytes).await?;
62 let reader = read_message(&mut self.stream).await?;
63 let outcome = decode_bootstrap(&reader, question)?;
64 drop(reader);
65 match outcome {
66 BootstrapOutcome::Capability => {
67 self.has_bootstrap = true;
68 self.send_finish(question, false).await?;
69 Ok(0)
70 }
71 BootstrapOutcome::Exception(reason) => {
72 self.send_finish(question, true).await?;
73 Err(RpcError::RemoteCall(reason))
74 }
75 BootstrapOutcome::NoCapability => {
76 self.send_finish(question, true).await?;
77 Err(RpcError::Protocol(
78 "bootstrap return carried no capability".into(),
79 ))
80 }
81 BootstrapOutcome::UnexpectedKind => {
82 self.send_finish(question, true).await?;
83 Err(RpcError::Protocol(
84 "bootstrap got unexpected return kind".into(),
85 ))
86 }
87 }
88 }
89
90 pub async fn call<T>(
93 &mut self,
94 import_identifier: u32,
95 interface_identifier: u64,
96 method_identifier: u16,
97 fill_parameters: impl FnOnce(&mut rpc_capnp::payload::Builder<'_>) -> Result<()>,
98 decode: impl FnOnce(rpc_capnp::payload::Reader<'_>) -> Result<T>,
99 ) -> Result<T> {
100 if !self.has_bootstrap {
101 return Err(RpcError::Protocol("call before bootstrap".into()));
102 }
103 let question = self.next_question;
104 self.next_question += 1;
105
106 tracing::trace!(
107 question,
108 interface_identifier,
109 method_identifier,
110 "sending call"
111 );
112 let bytes = build_call(
113 question,
114 import_identifier,
115 interface_identifier,
116 method_identifier,
117 fill_parameters,
118 )?;
119 crate::io::write_raw(&mut self.stream, &bytes).await?;
120 let reader = read_message(&mut self.stream).await?;
121 let outcome = decode_call(&reader, question, decode)?;
122 drop(reader);
123 match outcome {
124 CallOutcome::Value(value) => {
125 self.send_finish(question, false).await?;
126 Ok(value)
127 }
128 CallOutcome::Exception(reason) => {
129 self.send_finish(question, true).await?;
130 Err(RpcError::RemoteCall(reason))
131 }
132 CallOutcome::UnexpectedKind => {
133 self.send_finish(question, true).await?;
134 Err(RpcError::Protocol("call got unexpected return kind".into()))
135 }
136 }
137 }
138
139 async fn send_finish(&mut self, question: u32, release_result_caps: bool) -> Result<()> {
142 let bytes = build_finish(question, release_result_caps)?;
143 crate::io::write_raw(&mut self.stream, &bytes).await
144 }
145
146 pub async fn close(mut self) -> Result<S> {
150 if self.has_bootstrap {
151 let bytes = build_release(0, 1)?;
152 crate::io::write_raw(&mut self.stream, &bytes).await?;
153 self.has_bootstrap = false;
154 }
155 Ok(self.stream)
156 }
157}
158
159fn decode_bootstrap(
160 reader: &capnp::message::Reader<capnp::serialize::OwnedSegments>,
161 question: u32,
162) -> Result<BootstrapOutcome> {
163 let root = reader.get_root::<rpc_capnp::message::Reader>()?;
164 let answer = expect_return(&root, question)?;
165 let payload = match answer.reborrow().which()? {
166 rpc_capnp::return_::Results(r) => r?,
167 rpc_capnp::return_::Exception(e) => {
168 return Ok(BootstrapOutcome::Exception(
169 e?.get_reason()?.to_str()?.to_string(),
170 ));
171 }
172 _ => return Ok(BootstrapOutcome::UnexpectedKind),
173 };
174 let ctab = payload.get_cap_table()?;
175 if ctab.is_empty() {
176 return Ok(BootstrapOutcome::NoCapability);
177 }
178 let desc = ctab.get(0);
179 match desc.reborrow().which()? {
180 rpc_capnp::cap_descriptor::SenderHosted(_)
181 | rpc_capnp::cap_descriptor::SenderPromise(_) => Ok(BootstrapOutcome::Capability),
182 _ => Ok(BootstrapOutcome::UnexpectedKind),
183 }
184}
185
186fn decode_call<T>(
187 reader: &capnp::message::Reader<capnp::serialize::OwnedSegments>,
188 question: u32,
189 decode: impl FnOnce(rpc_capnp::payload::Reader<'_>) -> Result<T>,
190) -> Result<CallOutcome<T>> {
191 let root = reader.get_root::<rpc_capnp::message::Reader>()?;
192 let answer = expect_return(&root, question)?;
193 match answer.reborrow().which()? {
194 rpc_capnp::return_::Results(r) => Ok(CallOutcome::Value(decode(r?)?)),
195 rpc_capnp::return_::Exception(e) => Ok(CallOutcome::Exception(
196 e?.get_reason()?.to_str()?.to_string(),
197 )),
198 _ => Ok(CallOutcome::UnexpectedKind),
199 }
200}
201
202fn expect_return<'a>(
203 root: &'a rpc_capnp::message::Reader<'a>,
204 question: u32,
205) -> Result<rpc_capnp::return_::Reader<'a>> {
206 match root.reborrow().which()? {
207 rpc_capnp::message::Return(ret) => {
208 let ret = ret?;
209 if ret.reborrow().get_answer_id() != question {
210 return Err(RpcError::Protocol(format!(
211 "answer id {} does not match question {}",
212 ret.reborrow().get_answer_id(),
213 question
214 )));
215 }
216 Ok(ret)
217 }
218 rpc_capnp::message::Abort(exc) => {
219 let exc = exc?;
220 let reason = exc.get_reason()?.to_str()?.to_string();
221 let error_type = exc.get_type()? as u16;
222 Err(RpcError::Abort { reason, error_type })
223 }
224 _ => Err(RpcError::Protocol("expected return message".into())),
225 }
226}
227
228fn build_bootstrap(question: u32) -> Result<Vec<u8>> {
229 let mut message = capnp::message::Builder::new_default();
230 let root = message.init_root::<rpc_capnp::message::Builder>();
231 let mut bs = root.init_bootstrap();
232 bs.set_question_id(question);
233 Ok(crate::io::serialize_message(&message))
234}
235
236fn build_call<F>(
237 question: u32,
238 import_identifier: u32,
239 interface_identifier: u64,
240 method_identifier: u16,
241 fill_parameters: F,
242) -> Result<Vec<u8>>
243where
244 F: FnOnce(&mut rpc_capnp::payload::Builder<'_>) -> Result<()>,
245{
246 let mut message = capnp::message::Builder::new_default();
247 let root = message.init_root::<rpc_capnp::message::Builder>();
248 let mut call = root.init_call();
249 call.set_question_id(question);
250 let mut target = call.reborrow().init_target();
251 target.set_imported_cap(import_identifier);
252 call.reborrow().set_interface_id(interface_identifier);
253 call.reborrow().set_method_id(method_identifier);
254 call.reborrow().init_send_results_to().set_caller(());
255 let mut payload = call.reborrow().init_params();
256 fill_parameters(&mut payload)?;
257 Ok(crate::io::serialize_message(&message))
258}
259
260fn build_finish(question: u32, release_result_caps: bool) -> Result<Vec<u8>> {
261 let mut finish = capnp::message::Builder::new_default();
262 let froot = finish.init_root::<rpc_capnp::message::Builder>();
263 let mut f = froot.init_finish();
264 f.set_question_id(question);
265 f.set_release_result_caps(release_result_caps);
266 Ok(crate::io::serialize_message(&finish))
267}
268
269fn build_release(identifier: u32, reference_count: u32) -> Result<Vec<u8>> {
270 let mut message = capnp::message::Builder::new_default();
271 let root = message.init_root::<rpc_capnp::message::Builder>();
272 let mut rel = root.init_release();
273 rel.set_id(identifier);
274 rel.set_reference_count(reference_count);
275 Ok(crate::io::serialize_message(&message))
276}
277
278pub async fn send_exception<S: AsyncStream + Unpin>(
281 stream: &mut S,
282 question_identifier: u32,
283 reason: &str,
284) -> Result<()> {
285 let bytes = build_exception(question_identifier, reason)?;
286 crate::io::write_raw(stream, &bytes).await
287}
288
289pub(crate) fn build_exception(question_identifier: u32, reason: &str) -> Result<Vec<u8>> {
292 let mut message = capnp::message::Builder::new_default();
293 let root = message.init_root::<rpc_capnp::message::Builder>();
294 let mut ret = root.init_return();
295 ret.set_answer_id(question_identifier);
296 let mut exc = ret.init_exception();
297 exc.set_reason(reason);
298 exc.set_type(rpc_capnp::exception::Type::Unimplemented);
299 Ok(crate::io::serialize_message(&message))
300}
301
302#[derive(Debug, Clone, PartialEq)]
304pub enum Incoming {
305 Bootstrap {
307 question_identifier: u32,
309 },
310 Call {
312 question_identifier: u32,
314 interface_identifier: u64,
316 method_identifier: u16,
318 },
319 Finish {
321 question_identifier: u32,
323 },
324 Release,
326 Other,
328}
329
330pub async fn read_incoming<S: AsyncStream + Unpin>(stream: &mut S) -> Result<Option<Incoming>> {
333 let reader = match read_message(stream).await {
334 Ok(r) => r,
335 Err(RpcError::Eof) => return Ok(None),
336 Err(e) => return Err(e),
337 };
338 let root = reader.get_root::<rpc_capnp::message::Reader>()?;
339 match root.reborrow().which()? {
340 rpc_capnp::message::Bootstrap(b) => Ok(Some(Incoming::Bootstrap {
341 question_identifier: b?.get_question_id(),
342 })),
343 rpc_capnp::message::Call(c) => {
344 let c = c?;
345 Ok(Some(Incoming::Call {
346 question_identifier: c.reborrow().get_question_id(),
347 interface_identifier: c.reborrow().get_interface_id(),
348 method_identifier: c.reborrow().get_method_id(),
349 }))
350 }
351 rpc_capnp::message::Finish(f) => Ok(Some(Incoming::Finish {
352 question_identifier: f?.get_question_id(),
353 })),
354 rpc_capnp::message::Release(_) => Ok(Some(Incoming::Release)),
355 _ => Ok(Some(Incoming::Other)),
356 }
357}