diff --git a/Cargo.lock b/Cargo.lock index 79068bf..c0630d2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -147,6 +147,20 @@ dependencies = [ "tracing", ] +[[package]] +name = "alknet-tty-local" +version = "0.1.0" +dependencies = [ + "alknet-tty", + "bytes", + "futures-core", + "libc", + "portable-pty", + "thiserror 2.0.18", + "tokio", + "tracing", +] + [[package]] name = "alknet-vault" version = "0.1.0" @@ -1077,6 +1091,12 @@ dependencies = [ "litrs", ] +[[package]] +name = "downcast-rs" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" + [[package]] name = "dunce" version = "1.0.5" @@ -1246,6 +1266,17 @@ version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" +[[package]] +name = "filedescriptor" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e40758ed24c9b2eeb76c35fb0aebc66c626084edd827e07e1552279814c6682d" +dependencies = [ + "libc", + "thiserror 1.0.69", + "winapi", +] + [[package]] name = "find-msvc-tools" version = "0.1.9" @@ -1932,6 +1963,15 @@ dependencies = [ "web-sys", ] +[[package]] +name = "ioctl-rs" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7970510895cee30b3e9128319f2cefd4bde883a39f38baa279567ba3a7eb97d" +dependencies = [ + "libc", +] + [[package]] name = "ipconfig" version = "0.3.4" @@ -2377,6 +2417,15 @@ version = "2.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "88904434abc2901f197fe8cc55f0445e7ded921dba5911dad2e2b39b48e663c4" +[[package]] +name = "memoffset" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" +dependencies = [ + "autocfg", +] + [[package]] name = "mime" version = "0.3.17" @@ -2621,6 +2670,20 @@ dependencies = [ "wmi", ] +[[package]] +name = "nix" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f346ff70e7dbfd675fe90590b92d59ef2de15a8779ae305ebcbfd3f0caf59be4" +dependencies = [ + "autocfg", + "bitflags 1.3.2", + "cfg-if", + "libc", + "memoffset", + "pin-utils", +] + [[package]] name = "no-std-net" version = "0.6.0" @@ -3118,6 +3181,27 @@ version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" +[[package]] +name = "portable-pty" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "806ee80c2a03dbe1a9fb9534f8d19e4c0546b790cde8fd1fea9d6390644cb0be" +dependencies = [ + "anyhow", + "bitflags 1.3.2", + "downcast-rs", + "filedescriptor", + "lazy_static", + "libc", + "log", + "nix", + "serial", + "shared_library", + "shell-words", + "winapi", + "winreg", +] + [[package]] name = "portmapper" version = "0.5.0" @@ -4082,6 +4166,48 @@ dependencies = [ "serde", ] +[[package]] +name = "serial" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1237a96570fc377c13baa1b88c7589ab66edced652e43ffb17088f003db3e86" +dependencies = [ + "serial-core", + "serial-unix", + "serial-windows", +] + +[[package]] +name = "serial-core" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f46209b345401737ae2125fe5b19a77acce90cd53e1658cda928e4fe9a64581" +dependencies = [ + "libc", +] + +[[package]] +name = "serial-unix" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f03fbca4c9d866e24a459cbca71283f545a37f8e3e002ad8c70593871453cab7" +dependencies = [ + "ioctl-rs", + "libc", + "serial-core", + "termios", +] + +[[package]] +name = "serial-windows" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15c6d3b776267a75d31bbdfd5d36c0ca051251caafc285827052bc53bcdc8162" +dependencies = [ + "libc", + "serial-core", +] + [[package]] name = "sha1" version = "0.10.6" @@ -4119,6 +4245,22 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "shared_library" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a9e7e0f2bfae24d8a5b5a66c5b257a83c7412304311512a0c054cd5e619da11" +dependencies = [ + "lazy_static", + "libc", +] + +[[package]] +name = "shell-words" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc6fe69c597f9c37bfeeeeeb33da3530379845f10be461a66d16d03eca2ded77" + [[package]] name = "shlex" version = "2.0.1" @@ -4409,6 +4551,15 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "termios" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5d9cf598a6d7ce700a4e6a9199da127e6819a61e64b68609683cc9a01b5683a" +dependencies = [ + "libc", +] + [[package]] name = "thiserror" version = "1.0.69" @@ -5509,6 +5660,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "winreg" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" +dependencies = [ + "winapi", +] + [[package]] name = "wit-bindgen" version = "0.57.1" diff --git a/Cargo.toml b/Cargo.toml index af9b3c2..82c877b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,6 +5,7 @@ members = [ "crates/alknet-call", "crates/alknet-http", "crates/alknet-tty", + "crates/alknet-tty-local", ] resolver = "2" diff --git a/crates/alknet-tty-local/Cargo.toml b/crates/alknet-tty-local/Cargo.toml new file mode 100644 index 0000000..8e4ffb4 --- /dev/null +++ b/crates/alknet-tty-local/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "alknet-tty-local" +version.workspace = true +edition.workspace = true +license.workspace = true +description = "Local TTY backend for alknet-tty: LocalTtyBackend via portable_pty (PTY mode) and std::process::Command (pipe/runner mode)" +repository.workspace = true + +[lib] +name = "alknet_tty_local" + +[dependencies] +alknet-tty = { path = "../alknet-tty" } +portable-pty = "0.8" +tokio = { version = "1", features = ["full"] } +bytes = "1" +futures-core = "0.3" +tracing = "0.1" +thiserror = "2" + +[target.'cfg(unix)'.dependencies] +libc = "0.2" \ No newline at end of file diff --git a/crates/alknet-tty-local/src/backend.rs b/crates/alknet-tty-local/src/backend.rs new file mode 100644 index 0000000..dd88ea0 --- /dev/null +++ b/crates/alknet-tty-local/src/backend.rs @@ -0,0 +1,16 @@ +//! `LocalTtyBackend`: the `TtyBackend` implementation for local processes. +//! +//! `allocate()` branches on `TtyParams::terminal`: `Some(TerminalParams)` +//! selects PTY mode (this crate's `pty` module); `None` selects pipe mode +//! (the runner case, this crate's `pipe` module). One backend serves both +//! (ADR-054). + +// TODO: implement + +/// Local TTY backend: implements `alknet_tty::TtyBackend` for local processes. +/// +/// `allocate()` branches on `TtyParams::terminal`: `Some(TerminalParams)` +/// selects PTY mode (this crate's `pty` module); `None` selects pipe mode +/// (the runner case, this crate's `pipe` module). One backend serves both +/// (ADR-054). +pub struct LocalTtyBackend; diff --git a/crates/alknet-tty-local/src/lib.rs b/crates/alknet-tty-local/src/lib.rs new file mode 100644 index 0000000..2c6cf05 --- /dev/null +++ b/crates/alknet-tty-local/src/lib.rs @@ -0,0 +1,13 @@ +//! alknet-tty-local: Local TTY backend for alknet-tty. +//! +//! `LocalTtyBackend` implements `alknet_tty::TtyBackend` via `portable_pty` +//! (PTY mode, terminal semantics) and `std::process::Command` (pipe mode, +//! the runner case). The blocking→async bridge for PTY mode uses three +//! dedicated std threads feeding tokio mpsc/oneshot channels (REQ-TTY-01). +//! Signal forwarding targets the foreground process group (REQ-TTY-02). + +pub mod backend; +pub mod pipe; +pub mod pty; + +pub use backend::LocalTtyBackend; diff --git a/crates/alknet-tty-local/src/pipe.rs b/crates/alknet-tty-local/src/pipe.rs new file mode 100644 index 0000000..36c82e7 --- /dev/null +++ b/crates/alknet-tty-local/src/pipe.rs @@ -0,0 +1,8 @@ +//! Pipe mode for `LocalTtyBackend`: `tokio::process`-backed runner sessions. +//! +//! Spawns the command with `Stdio::piped()` for stdin/stdout/stderr, exposes +//! tokio-native `AsyncRead`/`AsyncWrite` (no std-thread bridge needed), +//! `PipeControl` (no-op resize, `libc::kill(pid, sig)` signal), and the +//! ADR-056 kill guard on the `exit_code` future. + +// TODO: implement diff --git a/crates/alknet-tty-local/src/pty.rs b/crates/alknet-tty-local/src/pty.rs new file mode 100644 index 0000000..867f2ea --- /dev/null +++ b/crates/alknet-tty-local/src/pty.rs @@ -0,0 +1,9 @@ +//! PTY mode for `LocalTtyBackend`: `portable_pty`-backed terminal sessions. +//! +//! Implements the blocking→async bridge (REQ-TTY-01) via three dedicated +//! std threads (reader, writer, waiter) feeding tokio mpsc/oneshot channels, +//! `PtyControl` for resize/signal, REQ-TTY-02 process-group signal +//! forwarding (`libc::kill(-pgid, sig)`), and the ADR-056 kill guard on the +//! `exit_code` future. + +// TODO: implement