mirror of
https://github.com/Astatin3/unshell.git
synced 2026-06-08 22:38:01 -06:00
Add stateful call leaf runtime
This commit is contained in:
@@ -1,46 +1,101 @@
|
||||
use std::error::Error;
|
||||
use std::{convert::Infallible, string::String};
|
||||
|
||||
use unshell::Leaf;
|
||||
use unshell::protocol::tree::{Endpoint, Ingress, LocalEvent, ProtocolEndpoint};
|
||||
use rkyv::{Archive, Deserialize, Serialize};
|
||||
use unshell::protocol::tree::{Call, CallLeaf, Ingress, LeafRuntime, ProtocolEndpoint};
|
||||
use unshell::protocol::tree::{ChildRoute, ConnectionState};
|
||||
use unshell::protocol::{PacketType, decode_frame};
|
||||
use unshell::{Leaf, procedures};
|
||||
|
||||
#[derive(Leaf)]
|
||||
#[leaf(org = "org", product = "example", version = "v1", leaf_name = "echo")]
|
||||
#[leaf(procedures(call, stream))]
|
||||
struct EchoLeaf;
|
||||
struct EchoLeaf {
|
||||
prefix: String,
|
||||
}
|
||||
|
||||
#[derive(Archive, Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
|
||||
struct EchoRequest {
|
||||
text: String,
|
||||
}
|
||||
|
||||
#[derive(Archive, Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
|
||||
struct EchoResponse {
|
||||
text: String,
|
||||
}
|
||||
|
||||
#[procedures(error = Infallible)]
|
||||
impl EchoLeaf {
|
||||
#[call]
|
||||
fn echo(&mut self, request: Call<EchoRequest>) -> EchoResponse {
|
||||
EchoResponse {
|
||||
text: format!("{}{}", self.prefix, request.input.text),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CallLeaf for EchoLeaf {
|
||||
type Error = Infallible;
|
||||
}
|
||||
|
||||
fn path(parts: &[&str]) -> Vec<String> {
|
||||
parts.iter().map(|part| (*part).to_owned()).collect()
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
let mut endpoint = ProtocolEndpoint::new(
|
||||
let endpoint = ProtocolEndpoint::new(
|
||||
path(&["agent"]),
|
||||
Some(Vec::new()),
|
||||
Vec::new(),
|
||||
vec![EchoLeaf::protocol_leaf_spec()],
|
||||
);
|
||||
let mut runtime = LeafRuntime::new(
|
||||
endpoint,
|
||||
EchoLeaf {
|
||||
prefix: String::from("echo: "),
|
||||
},
|
||||
);
|
||||
|
||||
let hook_id = endpoint.allocate_hook_id();
|
||||
let frame = endpoint.make_call(
|
||||
let mut controller = ProtocolEndpoint::new(
|
||||
Vec::new(),
|
||||
None,
|
||||
vec![ChildRoute {
|
||||
path: path(&["agent"]),
|
||||
state: ConnectionState::Registered,
|
||||
}],
|
||||
Vec::new(),
|
||||
);
|
||||
let hook_id = controller.allocate_hook_id();
|
||||
let controller_outcome = controller.send_call(
|
||||
path(&["agent"]),
|
||||
Some(EchoLeaf::protocol_leaf_name()),
|
||||
EchoLeaf::protocol_procedure_id("call").expect("known procedure suffix"),
|
||||
EchoLeaf::protocol_procedure_id("echo").expect("known procedure suffix"),
|
||||
Some(hook_id),
|
||||
b"hello leaf".to_vec(),
|
||||
unshell::protocol::tree::encode_call_reply(&EchoRequest {
|
||||
text: String::from("hello leaf"),
|
||||
})?,
|
||||
)?;
|
||||
|
||||
let outcome = endpoint.receive(&Ingress::Parent, frame)?;
|
||||
let Some(LocalEvent::Call { header, message }) = outcome.event else {
|
||||
return Err("expected local leaf call".into());
|
||||
let Some((_, frame)) = controller_outcome.forward else {
|
||||
return Err("expected controller to forward call".into());
|
||||
};
|
||||
|
||||
assert_eq!(header.dst_leaf.as_deref(), Some("org.example.v1.echo"));
|
||||
assert_eq!(message.procedure_id, "org.example.v1.echo.call");
|
||||
let outcome = runtime.receive(&Ingress::Parent, frame)?;
|
||||
let [response_frame] = outcome.frames.as_slice() else {
|
||||
return Err("expected one response frame".into());
|
||||
};
|
||||
let parsed = decode_frame(response_frame.as_slice())?;
|
||||
assert_eq!(parsed.packet_type(), PacketType::Data);
|
||||
let response = unshell::protocol::tree::decode_call_input::<EchoResponse>(
|
||||
parsed.deserialize_data()?.data.as_slice(),
|
||||
)?;
|
||||
|
||||
assert_eq!(EchoLeaf::protocol_leaf_name(), "org.example.v1.echo");
|
||||
assert_eq!(response.text, "echo: hello leaf");
|
||||
|
||||
println!(
|
||||
"leaf={} procedure={}",
|
||||
"leaf={} procedure={} response={}",
|
||||
EchoLeaf::protocol_leaf_name(),
|
||||
message.procedure_id
|
||||
EchoLeaf::protocol_procedure_id("echo").expect("known procedure suffix"),
|
||||
response.text,
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user