mirror of
https://github.com/Astatin3/unshell.git
synced 2026-06-08 22:38:01 -06:00
Fix examples for renamed leaf endpoint surface
Update the remote shell examples to use unshell::leaves and the leaf_endpoint feature-gated endpoint module, and restore the local macro aliasing needed after removing the direct unshell dependency from unshell-leaves.
This commit is contained in:
Generated
+2
-1
@@ -1454,7 +1454,8 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"portable-pty",
|
||||
"rkyv",
|
||||
"unshell",
|
||||
"unshell-macros",
|
||||
"unshell-protocol",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
+9
-3
@@ -44,6 +44,11 @@ description = "Pure no_std implementation of the UnShell Protocol"
|
||||
default = []
|
||||
log = []
|
||||
log_debug = ["log", "dep:chrono"]
|
||||
|
||||
# Leaf features
|
||||
leaf_endpoint = ["unshell-leaves/leaf_endpoint"]
|
||||
leaf_tui = ["unshell-leaves/leaf_tui"]
|
||||
|
||||
# obfuscate_aes = ["ush-obfuscate/obfuscate_aes"]
|
||||
# obfuscate_ref = ["ush-obfuscate/obfuscate_ref"]
|
||||
|
||||
@@ -55,9 +60,7 @@ chrono = { workspace = true, optional = true }
|
||||
static_init = { workspace = true }
|
||||
unshell-macros = { path = "./unshell-macros" }
|
||||
unshell-protocol = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
unshell-leaves = { workspace = true, features = ["endpoint"] }
|
||||
unshell-leaves = { workspace = true }
|
||||
|
||||
[[example]]
|
||||
name = "leaf_derive"
|
||||
@@ -66,14 +69,17 @@ path = "examples/protocol/leaf_derive.rs"
|
||||
[[example]]
|
||||
name = "remote_shell_endpoint"
|
||||
path = "examples/protocol/remote_shell_endpoint.rs"
|
||||
required-features = ["leaf_endpoint"]
|
||||
|
||||
[[example]]
|
||||
name = "remote_shell_receive"
|
||||
path = "examples/protocol/remote_shell_receive.rs"
|
||||
required-features = ["leaf_endpoint"]
|
||||
|
||||
[[example]]
|
||||
name = "remote_shell_single_endpoint"
|
||||
path = "examples/protocol/remote_shell_single_endpoint.rs"
|
||||
required-features = ["leaf_endpoint"]
|
||||
|
||||
[[example]]
|
||||
name = "bench"
|
||||
|
||||
@@ -9,29 +9,32 @@ use std::net::TcpStream;
|
||||
use std::sync::mpsc::RecvTimeoutError;
|
||||
use std::time::Duration;
|
||||
|
||||
use unshell::leaves::remote_shell;
|
||||
use unshell::protocol::tree::Ingress;
|
||||
use unshell_leaves::remote_shell;
|
||||
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
let mut stream = TcpStream::connect(remote_shell::LISTEN_ADDR)?;
|
||||
let frame_rx = remote_shell::spawn_frame_reader(stream.try_clone()?);
|
||||
let mut runtime = remote_shell::build_agent_runtime();
|
||||
let mut stream = TcpStream::connect(remote_shell::endpoint::LISTEN_ADDR)?;
|
||||
let frame_rx = remote_shell::endpoint::spawn_frame_reader(stream.try_clone()?);
|
||||
let mut runtime = remote_shell::endpoint::build_agent_runtime();
|
||||
|
||||
println!("connected to controller at {}", remote_shell::LISTEN_ADDR);
|
||||
println!(
|
||||
"connected to controller at {}",
|
||||
remote_shell::endpoint::LISTEN_ADDR
|
||||
);
|
||||
|
||||
loop {
|
||||
match frame_rx.recv_timeout(Duration::from_millis(25)) {
|
||||
Ok(result) => {
|
||||
let frame = result?;
|
||||
let outcome = runtime.receive(&Ingress::Parent, frame)?;
|
||||
remote_shell::write_frames(&mut stream, &outcome.frames)?;
|
||||
remote_shell::endpoint::write_frames(&mut stream, &outcome.frames)?;
|
||||
}
|
||||
Err(RecvTimeoutError::Timeout) => {}
|
||||
Err(RecvTimeoutError::Disconnected) => break,
|
||||
}
|
||||
|
||||
let outcome = runtime.poll()?;
|
||||
remote_shell::write_frames(&mut stream, &outcome.frames)?;
|
||||
remote_shell::endpoint::write_frames(&mut stream, &outcome.frames)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -6,38 +6,40 @@
|
||||
use std::error::Error;
|
||||
use std::net::TcpListener;
|
||||
|
||||
use unshell::leaves::remote_shell;
|
||||
use unshell::leaves::remote_shell::OpenRequest;
|
||||
use unshell::protocol::tree::encode_call_reply;
|
||||
use unshell::protocol::tree::{Endpoint, EndpointOutcome, Ingress, LocalEvent};
|
||||
use unshell_leaves::remote_shell;
|
||||
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
let listener = TcpListener::bind(remote_shell::LISTEN_ADDR)?;
|
||||
println!("listening on {}", remote_shell::LISTEN_ADDR);
|
||||
let listener = TcpListener::bind(remote_shell::endpoint::LISTEN_ADDR)?;
|
||||
println!("listening on {}", remote_shell::endpoint::LISTEN_ADDR);
|
||||
|
||||
let (mut stream, peer_addr) = listener.accept()?;
|
||||
println!("accepted endpoint connection from {peer_addr}");
|
||||
|
||||
let frame_rx = remote_shell::spawn_frame_reader(stream.try_clone()?);
|
||||
let mut endpoint = remote_shell::build_controller_endpoint();
|
||||
let frame_rx = remote_shell::endpoint::spawn_frame_reader(stream.try_clone()?);
|
||||
let mut endpoint = remote_shell::endpoint::build_controller_endpoint();
|
||||
let hook_id = endpoint.allocate_hook_id();
|
||||
let shell_leaf_name = remote_shell::shell_leaf_name();
|
||||
let open_procedure = remote_shell::shell_open_procedure();
|
||||
let shell_leaf_name = remote_shell::endpoint::RemoteShellEndpoint::protocol_leaf_name();
|
||||
let open_procedure = remote_shell::endpoint::ProcedureOpen::protocol_procedure_id();
|
||||
|
||||
remote_shell::send_forward(
|
||||
remote_shell::endpoint::send_forward(
|
||||
&mut stream,
|
||||
endpoint.send_call(
|
||||
remote_shell::agent_path(),
|
||||
agent_path(),
|
||||
Some(shell_leaf_name),
|
||||
open_procedure.clone(),
|
||||
Some(hook_id),
|
||||
remote_shell::shell_open_payload(),
|
||||
encode_call_reply(&OpenRequest).expect("remote shell open payload should encode"),
|
||||
)?,
|
||||
)?;
|
||||
|
||||
for (index, command) in ["pwd\n", "whoami\n", "exit\n"].iter().enumerate() {
|
||||
remote_shell::send_forward(
|
||||
remote_shell::endpoint::send_forward(
|
||||
&mut stream,
|
||||
endpoint.send_data(
|
||||
remote_shell::agent_path(),
|
||||
agent_path(),
|
||||
hook_id,
|
||||
open_procedure.clone(),
|
||||
command.as_bytes().to_vec(),
|
||||
@@ -48,7 +50,7 @@ fn main() -> Result<(), Box<dyn Error>> {
|
||||
|
||||
for result in frame_rx {
|
||||
let frame = result?;
|
||||
let outcome = endpoint.receive(&Ingress::Child(remote_shell::agent_path()), frame)?;
|
||||
let outcome = endpoint.receive(&Ingress::Child(agent_path()), frame)?;
|
||||
let EndpointOutcome::Local(event) = outcome else {
|
||||
continue;
|
||||
};
|
||||
@@ -71,3 +73,7 @@ fn main() -> Result<(), Box<dyn Error>> {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn agent_path() -> Vec<String> {
|
||||
vec![String::from("agent")]
|
||||
}
|
||||
|
||||
@@ -7,25 +7,25 @@
|
||||
|
||||
use std::error::Error;
|
||||
|
||||
use unshell::leaves::remote_shell;
|
||||
use unshell::protocol::tree::{EndpointOutcome, LocalEvent, ProtocolEndpoint};
|
||||
use unshell::protocol::{INTROSPECTION_PROCEDURE_ID, LeafIntrospection};
|
||||
use unshell_leaves::remote_shell;
|
||||
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
let mut endpoint = ProtocolEndpoint::new(
|
||||
remote_shell::agent_path(),
|
||||
agent_path(),
|
||||
Some(Vec::new()),
|
||||
Vec::new(),
|
||||
vec![unshell::protocol::tree::LeafSpec {
|
||||
name: remote_shell::shell_leaf_name(),
|
||||
procedures: vec![remote_shell::shell_open_procedure()],
|
||||
name: remote_shell::endpoint::RemoteShellEndpoint::protocol_leaf_name(),
|
||||
procedures: vec![remote_shell::endpoint::ProcedureOpen::protocol_procedure_id()],
|
||||
}],
|
||||
);
|
||||
|
||||
let hook_id = endpoint.allocate_hook_id();
|
||||
let outcome = endpoint.send_call(
|
||||
remote_shell::agent_path(),
|
||||
Some(remote_shell::shell_leaf_name()),
|
||||
agent_path(),
|
||||
Some(remote_shell::endpoint::RemoteShellEndpoint::protocol_leaf_name()),
|
||||
INTROSPECTION_PROCEDURE_ID,
|
||||
Some(hook_id),
|
||||
Vec::new(),
|
||||
@@ -38,10 +38,14 @@ fn main() -> Result<(), Box<dyn Error>> {
|
||||
let payload = unshell::protocol::tree::decode_call_input::<LeafIntrospection>(&message.data)?;
|
||||
println!(
|
||||
"remote-shell examples normally listen on {}",
|
||||
remote_shell::LISTEN_ADDR
|
||||
remote_shell::endpoint::LISTEN_ADDR
|
||||
);
|
||||
println!("endpoint path: {:?}", remote_shell::agent_path());
|
||||
println!("endpoint path: {:?}", agent_path());
|
||||
println!("leaf: {}", payload.leaf_name);
|
||||
println!("procedures: {:?}", payload.procedures);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn agent_path() -> Vec<String> {
|
||||
vec![String::from("agent")]
|
||||
}
|
||||
|
||||
@@ -23,6 +23,9 @@ pub mod logger;
|
||||
/// proc-macro output and downstream code do not need a second migration.
|
||||
pub use unshell_protocol as protocol;
|
||||
|
||||
/// Re-export the leaf library crate behind the historical `unshell::leaves` path
|
||||
pub use unshell_leaves as leaves;
|
||||
|
||||
pub use unshell_macros::{Leaf, Procedure, procedures};
|
||||
|
||||
// pub use ush_obfuscate as obfuscate;
|
||||
|
||||
@@ -6,13 +6,14 @@ description = "Application-layer UnShell leaves and client surfaces"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
endpoint = ["dep:portable-pty"]
|
||||
tui = []
|
||||
leaf_endpoint = ["dep:portable-pty"]
|
||||
leaf_tui = []
|
||||
|
||||
[dependencies]
|
||||
rkyv = { workspace = true }
|
||||
portable-pty = { workspace = true, optional = true }
|
||||
unshell = { workspace = true }
|
||||
unshell-macros = { path = "../unshell-macros" }
|
||||
unshell-protocol = { workspace = true }
|
||||
|
||||
[lints.rust]
|
||||
elided_lifetimes_in_paths = "warn"
|
||||
|
||||
@@ -2,10 +2,18 @@
|
||||
//! protocol runtime.
|
||||
//!
|
||||
//! Each leaf module always exports its shared protocol-facing types. Role-specific
|
||||
//! implementations are selected with the crate-wide `endpoint` and `tui`
|
||||
//! implementations are selected with the crate-wide `leaf_endpoint` and `leaf_tui`
|
||||
//! features, and can optionally be re-exported behind one stable alias.
|
||||
|
||||
use unshell::protocol::DataMessage;
|
||||
#[allow(unused_extern_crates)]
|
||||
extern crate self as unshell;
|
||||
|
||||
pub extern crate alloc;
|
||||
|
||||
use unshell_protocol::DataMessage;
|
||||
|
||||
pub use unshell_macros::{Leaf, Procedure, procedures};
|
||||
pub use unshell_protocol as protocol;
|
||||
|
||||
/// Re-exports one role-specific type behind a stable public alias.
|
||||
///
|
||||
@@ -20,18 +28,18 @@ macro_rules! role_leaf {
|
||||
tui => $tui:path $(,)?
|
||||
}
|
||||
) => {
|
||||
#[cfg(all(feature = "endpoint", feature = "tui"))]
|
||||
#[cfg(all(feature = "leaf_endpoint", feature = "leaf_tui"))]
|
||||
compile_error!(concat!(
|
||||
"`",
|
||||
stringify!($alias),
|
||||
"` can only alias one concrete role at a time; enable either `endpoint` or `tui`, not both"
|
||||
"` can only alias one concrete role at a time; enable either `leaf_endpoint` or `leaf_tui`, not both"
|
||||
));
|
||||
|
||||
#[cfg(feature = "endpoint")]
|
||||
#[cfg(feature = "leaf_endpoint")]
|
||||
$(#[$meta])*
|
||||
$vis type $alias = $endpoint;
|
||||
|
||||
#[cfg(all(not(feature = "endpoint"), feature = "tui"))]
|
||||
#[cfg(all(not(feature = "leaf_endpoint"), feature = "leaf_tui"))]
|
||||
$(#[$meta])*
|
||||
$vis type $alias = $tui;
|
||||
};
|
||||
|
||||
@@ -15,7 +15,7 @@ pub use errors::ShellLeafError;
|
||||
pub use session::ProcedureOpen;
|
||||
pub use transport::{LISTEN_ADDR, send_forward, spawn_frame_reader, write_frames};
|
||||
|
||||
use super::{OpenRequest, agent_path};
|
||||
use super::OpenRequest;
|
||||
|
||||
/// Leaf state for the remote shell endpoint runtime.
|
||||
///
|
||||
@@ -94,3 +94,7 @@ pub fn build_agent_runtime() -> ProcedureRuntime<RemoteShellEndpoint, ProcedureO
|
||||
);
|
||||
ProcedureRuntime::new(endpoint, RemoteShellEndpoint::default())
|
||||
}
|
||||
|
||||
fn agent_path() -> Vec<String> {
|
||||
vec![String::from("agent")]
|
||||
}
|
||||
|
||||
@@ -2,26 +2,21 @@
|
||||
//!
|
||||
//! The module always exports the protocol contract for the leaf. Role-specific
|
||||
//! implementations live behind crate-wide features:
|
||||
//! - `endpoint` builds the PTY-backed runtime leaf
|
||||
//! - `tui` builds a placeholder client-side TUI surface
|
||||
//! - `leaf_endpoint` builds the PTY-backed runtime leaf
|
||||
//! - `leaf_tui` builds a placeholder client-side TUI surface
|
||||
|
||||
use rkyv::{Archive, Deserialize, Serialize};
|
||||
|
||||
#[cfg(feature = "endpoint")]
|
||||
mod endpoint;
|
||||
#[cfg(feature = "tui")]
|
||||
mod tui;
|
||||
#[cfg(feature = "leaf_endpoint")]
|
||||
pub mod endpoint;
|
||||
#[cfg(feature = "leaf_tui")]
|
||||
pub mod tui;
|
||||
|
||||
#[cfg(feature = "endpoint")]
|
||||
pub use endpoint::{
|
||||
LISTEN_ADDR, RemoteShellEndpoint, ShellLeafError, build_agent_runtime,
|
||||
build_controller_endpoint, send_forward, spawn_frame_reader, write_frames,
|
||||
};
|
||||
#[cfg(feature = "tui")]
|
||||
#[cfg(feature = "leaf_endpoint")]
|
||||
pub use endpoint::RemoteShellEndpoint;
|
||||
#[cfg(feature = "leaf_tui")]
|
||||
pub use tui::RemoteShellTui;
|
||||
|
||||
use unshell::protocol::tree::encode_call_reply;
|
||||
|
||||
/// Open-request payload for the remote shell leaf.
|
||||
///
|
||||
/// The shell currently needs no structured arguments, but a named payload type is
|
||||
@@ -36,57 +31,3 @@ crate::role_leaf! {
|
||||
tui => tui::RemoteShellTui,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the example endpoint path used by the remote shell samples.
|
||||
pub fn agent_path() -> Vec<String> {
|
||||
path(&["agent"])
|
||||
}
|
||||
|
||||
/// Returns the canonical leaf id used by endpoint and TUI code.
|
||||
#[cfg(feature = "endpoint")]
|
||||
pub fn shell_leaf_name() -> String {
|
||||
RemoteShellEndpoint::protocol_leaf_name()
|
||||
}
|
||||
|
||||
/// Returns the canonical opening `procedure_id` for the shell leaf.
|
||||
#[cfg(feature = "endpoint")]
|
||||
pub fn shell_open_procedure() -> String {
|
||||
endpoint::ProcedureOpen::protocol_procedure_id()
|
||||
}
|
||||
|
||||
/// Encodes the empty open-request payload used by the shell example.
|
||||
#[cfg(all(not(feature = "endpoint"), feature = "tui"))]
|
||||
pub fn shell_leaf_name() -> String {
|
||||
RemoteShellTui::protocol_leaf_name()
|
||||
}
|
||||
|
||||
/// Returns the canonical opening `procedure_id` for the shell leaf.
|
||||
#[cfg(all(not(feature = "endpoint"), feature = "tui"))]
|
||||
pub fn shell_open_procedure() -> String {
|
||||
let mut procedure_id = shell_leaf_name();
|
||||
procedure_id.push_str(".open");
|
||||
procedure_id
|
||||
}
|
||||
|
||||
/// Encodes the empty open-request payload used by the shell example.
|
||||
#[cfg(not(any(feature = "endpoint", feature = "tui")))]
|
||||
pub fn shell_leaf_name() -> String {
|
||||
String::from("remote_shell")
|
||||
}
|
||||
|
||||
/// Returns the canonical opening `procedure_id` for the shell leaf.
|
||||
#[cfg(not(any(feature = "endpoint", feature = "tui")))]
|
||||
pub fn shell_open_procedure() -> String {
|
||||
let mut procedure_id = shell_leaf_name();
|
||||
procedure_id.push_str(".open");
|
||||
procedure_id
|
||||
}
|
||||
|
||||
/// Encodes the empty open-request payload used by the shell example.
|
||||
pub fn shell_open_payload() -> Vec<u8> {
|
||||
encode_call_reply(&OpenRequest).expect("remote shell open payload should encode")
|
||||
}
|
||||
|
||||
fn path(parts: &[&str]) -> Vec<String> {
|
||||
parts.iter().map(|part| (*part).to_owned()).collect()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user