mirror of
https://github.com/Astatin3/unshell.git
synced 2026-06-09 06:47:59 -06:00
Add compile-time leaf declarations
Introduce a function-like leaf declaration macro, bind endpoint and TUI hosts to shared generated metadata, and move remote shell endpoint construction out of the leaf module into the examples and runtime assembly code.
This commit is contained in:
@@ -6,13 +6,10 @@ mod transport;
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use unshell::Leaf;
|
||||
use unshell::protocol::tree::{
|
||||
Call, HookKey, Procedure, ProcedureEffect, ProcedureRuntime, ProcedureStore, ProtocolEndpoint,
|
||||
};
|
||||
use unshell::protocol::tree::{Call, HookKey, Procedure, ProcedureEffect, ProcedureStore};
|
||||
|
||||
pub use errors::ShellLeafError;
|
||||
pub use session::ProcedureOpen;
|
||||
pub use session::Open;
|
||||
pub use transport::{LISTEN_ADDR, send_forward, spawn_frame_reader, write_frames};
|
||||
|
||||
use super::OpenRequest;
|
||||
@@ -22,25 +19,24 @@ use super::OpenRequest;
|
||||
/// The endpoint keeps each live shell session in an explicit map keyed by the
|
||||
/// caller-owned hook identity. That makes ownership and cleanup of hook-backed
|
||||
/// shell processes easy to inspect during debugging.
|
||||
#[derive(Default, Leaf)]
|
||||
#[leaf(leaf_name = "remote_shell")]
|
||||
#[derive(Default)]
|
||||
pub struct RemoteShellEndpoint {
|
||||
sessions: BTreeMap<HookKey, ProcedureOpen>,
|
||||
sessions: BTreeMap<HookKey, Open>,
|
||||
}
|
||||
|
||||
impl ProcedureStore<ProcedureOpen> for RemoteShellEndpoint {
|
||||
fn procedure_sessions(&mut self) -> &mut BTreeMap<HookKey, ProcedureOpen> {
|
||||
impl ProcedureStore<Open> for RemoteShellEndpoint {
|
||||
fn procedure_sessions(&mut self) -> &mut BTreeMap<HookKey, Open> {
|
||||
&mut self.sessions
|
||||
}
|
||||
}
|
||||
|
||||
impl Procedure<RemoteShellEndpoint> for ProcedureOpen {
|
||||
impl Procedure<RemoteShellEndpoint> for Open {
|
||||
type Error = ShellLeafError;
|
||||
type Input = OpenRequest;
|
||||
|
||||
fn open(_leaf: &mut RemoteShellEndpoint, call: Call<Self::Input>) -> Result<Self, Self::Error> {
|
||||
let hook_key = call.response_hook.ok_or(ShellLeafError::MissingHook)?;
|
||||
ProcedureOpen::spawn(hook_key.return_path, hook_key.hook_id, call.procedure_id)
|
||||
Open::spawn(hook_key.return_path, hook_key.hook_id, call.procedure_id)
|
||||
}
|
||||
|
||||
fn on_data(
|
||||
@@ -70,31 +66,3 @@ impl Procedure<RemoteShellEndpoint> for ProcedureOpen {
|
||||
session.terminate()
|
||||
}
|
||||
}
|
||||
|
||||
/// Builds the controller endpoint used by the receiver example.
|
||||
pub fn build_controller_endpoint() -> ProtocolEndpoint {
|
||||
ProtocolEndpoint::new(
|
||||
Vec::new(),
|
||||
None,
|
||||
vec![unshell::protocol::tree::ChildRoute::registered(agent_path())],
|
||||
Vec::new(),
|
||||
)
|
||||
}
|
||||
|
||||
/// Builds the stateful shell runtime used by the endpoint example.
|
||||
pub fn build_agent_runtime() -> ProcedureRuntime<RemoteShellEndpoint, ProcedureOpen> {
|
||||
let endpoint = ProtocolEndpoint::new(
|
||||
agent_path(),
|
||||
Some(Vec::new()),
|
||||
Vec::new(),
|
||||
vec![unshell::protocol::tree::LeafSpec {
|
||||
name: RemoteShellEndpoint::protocol_leaf_name(),
|
||||
procedures: vec![ProcedureOpen::protocol_procedure_id()],
|
||||
}],
|
||||
);
|
||||
ProcedureRuntime::new(endpoint, RemoteShellEndpoint::default())
|
||||
}
|
||||
|
||||
fn agent_path() -> Vec<String> {
|
||||
vec![String::from("agent")]
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ use super::errors::ShellLeafError;
|
||||
/// one opening procedure and one live hook remains direct and visible.
|
||||
#[derive(Procedure)]
|
||||
#[procedure(leaf = RemoteShellEndpoint, name = "open")]
|
||||
pub struct ProcedureOpen {
|
||||
pub struct Open {
|
||||
/// Spawned PTY child process.
|
||||
pub(super) child: Box<dyn portable_pty::Child + Send>,
|
||||
/// Process-group leader used for Unix hangup and kill signaling.
|
||||
@@ -52,7 +52,7 @@ enum OutputEvent {
|
||||
ReaderClosed,
|
||||
}
|
||||
|
||||
impl ProcedureOpen {
|
||||
impl Open {
|
||||
pub(super) fn spawn(
|
||||
return_path: Vec<String>,
|
||||
hook_id: u64,
|
||||
@@ -213,7 +213,7 @@ impl ProcedureOpen {
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for ProcedureOpen {
|
||||
impl Drop for Open {
|
||||
fn drop(&mut self) {
|
||||
let _ = self.terminate();
|
||||
}
|
||||
|
||||
@@ -24,6 +24,29 @@ pub use tui::RemoteShellTui;
|
||||
#[derive(Archive, Serialize, Deserialize, Debug, Clone, Default, PartialEq, Eq)]
|
||||
pub struct OpenRequest;
|
||||
|
||||
#[cfg(any(feature = "leaf_endpoint", feature = "leaf_tui"))]
|
||||
macro_rules! declare_remote_shell_leaf {
|
||||
($($role_args:tt)*) => {
|
||||
crate::leaf! {
|
||||
name = "remote_shell",
|
||||
procedures = [Open],
|
||||
$($role_args)*
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "leaf_endpoint", not(feature = "leaf_tui")))]
|
||||
declare_remote_shell_leaf!(endpoint_struct = RemoteShellEndpoint,);
|
||||
|
||||
#[cfg(all(not(feature = "leaf_endpoint"), feature = "leaf_tui"))]
|
||||
declare_remote_shell_leaf!(tui_struct = RemoteShellTui,);
|
||||
|
||||
#[cfg(all(feature = "leaf_endpoint", feature = "leaf_tui"))]
|
||||
declare_remote_shell_leaf!(
|
||||
endpoint_struct = RemoteShellEndpoint,
|
||||
tui_struct = RemoteShellTui,
|
||||
);
|
||||
|
||||
crate::role_leaf! {
|
||||
/// Feature-selected remote shell surface.
|
||||
pub type RemoteShell {
|
||||
|
||||
@@ -7,14 +7,12 @@
|
||||
use std::string::String;
|
||||
use std::vec::Vec;
|
||||
|
||||
use unshell::Leaf;
|
||||
use unshell::protocol::DataMessage;
|
||||
|
||||
use crate::{LeafTui, TuiError};
|
||||
|
||||
/// Stub TUI surface for the remote shell leaf.
|
||||
#[derive(Default, Leaf)]
|
||||
#[leaf(leaf_name = "remote_shell")]
|
||||
#[derive(Default)]
|
||||
pub struct RemoteShellTui {
|
||||
transcript: Vec<u8>,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user