mirror of
https://github.com/Astatin3/unshell.git
synced 2026-06-08 22:38:01 -06:00
Work on implementing interface.
This commit is contained in:
@@ -7,6 +7,11 @@ description = "Hook-backed PTY leaf implementation for UnShell"
|
||||
[dependencies]
|
||||
unshell = { workspace = true }
|
||||
|
||||
[features]
|
||||
default = []
|
||||
interface = ["unshell/interface"]
|
||||
interface_ratatui = ["interface", "unshell/interface_ratatui"]
|
||||
|
||||
[lints.rust]
|
||||
elided_lifetimes_in_paths = "warn"
|
||||
future_incompatible = { level = "warn", priority = -1 }
|
||||
|
||||
@@ -4,10 +4,9 @@ use crate::{constants::LEAF_FAKE_PTY, session::PtySession};
|
||||
|
||||
/// User-owned state for the generated fake PTY leaf.
|
||||
///
|
||||
/// The macro-generated `FakePtyLeaf` wrapper stores sessions and retry queues around
|
||||
/// this struct. Keeping counters here makes tests and future procedures observe leaf
|
||||
/// behavior without reaching into generated session storage.
|
||||
#[unshell_leaf(leaf = FakePtyLeaf, id = LEAF_FAKE_PTY, sessions(PtySession))]
|
||||
/// The `unshell_leaf!` template stores sessions and retry queues around this struct.
|
||||
/// Keeping counters here makes tests and future procedures observe leaf behavior
|
||||
/// without reaching into generated session storage.
|
||||
pub struct FakePtyState {
|
||||
/// Number of sessions that application logic considers active.
|
||||
pub active_count: usize,
|
||||
@@ -35,3 +34,19 @@ impl Default for FakePtyState {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
unshell_leaf! {
|
||||
pub leaf FakePtyLeaf for FakePtyState {
|
||||
id: LEAF_FAKE_PTY,
|
||||
meta: unshell::protocol::LeafMeta {
|
||||
name: "Fake PTY Leaf",
|
||||
identifier: "dev.unshell.v1.pty",
|
||||
version: "v0",
|
||||
authors: unshell::alloc::vec!["ASTATIN3"],
|
||||
},
|
||||
sessions {
|
||||
pty: PtySession,
|
||||
}
|
||||
procedures {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,9 @@ use alloc::{vec, vec::Vec};
|
||||
|
||||
use unshell::protocol::{Endpoint, Leaf, Packet};
|
||||
|
||||
#[cfg(feature = "interface")]
|
||||
use unshell::interface::{InterfaceEventKind, InterfaceStore};
|
||||
|
||||
use super::{
|
||||
FakePtyLeaf, FakePtyState, OP_ABORT, OP_ERROR, OP_EXIT, OP_INPUT, OP_OPENED, OP_OUTPUT,
|
||||
OP_STDIN_EOF, OP_TERMINATE, PROC_PTY, frame_opcode, frame_payload, pty_open_packet, pty_packet,
|
||||
@@ -391,3 +394,39 @@ fn pty_leaf_does_not_consume_other_leaf_packets() {
|
||||
assert_eq!(other_packets[0].procedure_id, PROC_OTHER);
|
||||
assert_eq!(other_packets[0].data, b"leave-me".to_vec());
|
||||
}
|
||||
|
||||
#[cfg(feature = "interface")]
|
||||
#[test]
|
||||
fn interface_update_records_session_flow() {
|
||||
let (mut endpoint_a, mut endpoint_b) = pty_endpoints();
|
||||
let mut leaf = FakePtyLeaf::new(FakePtyState::new());
|
||||
let mut interface = InterfaceStore::new();
|
||||
let hook_id = endpoint_a.get_hook_id();
|
||||
|
||||
endpoint_a
|
||||
.add_outbound(pty_open_packet(
|
||||
vec![ENDPOINT_A, ENDPOINT_B],
|
||||
hook_id,
|
||||
&[ENDPOINT_A],
|
||||
))
|
||||
.unwrap();
|
||||
transfer_packets(&mut endpoint_a, &mut endpoint_b, ENDPOINT_B, ENDPOINT_A);
|
||||
|
||||
leaf.update_interface(&mut endpoint_b, &mut interface);
|
||||
|
||||
assert_eq!(leaf.active_session_count(), 1);
|
||||
assert!(interface.events().iter().any(|event| {
|
||||
matches!(
|
||||
&event.kind,
|
||||
InterfaceEventKind::SessionCreated { hook_id: recorded_hook, .. }
|
||||
if *recorded_hook == hook_id
|
||||
)
|
||||
}));
|
||||
assert!(interface.events().iter().any(|event| {
|
||||
matches!(
|
||||
&event.kind,
|
||||
InterfaceEventKind::RouteSuccess { packet }
|
||||
if packet.hook_id == hook_id && frame_opcode(packet) == Some(OP_OPENED)
|
||||
)
|
||||
}));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user