Prune commentary and stale Rust port notes
This commit is contained in:
1 parent
5428cd75c9
commit
25370731d0
193 files changed
+693
-16219
No files matched your search
@@ -1,24 +1,3 @@
|
||||
//! Where a session's process runs, and the only place that knows how.
|
||||
//!
|
||||
//! A driver says *what* to run -- a [`Launch`] -- and hands it here. Whether
|
||||
//! that becomes a child of this process or an `ssh host …` invocation is
|
||||
//! settled in this module, so a driver carries no transport knowledge and a
|
||||
//! second one cannot forget to handle the remote case. It also means the
|
||||
//! wrapping is honest about drivers that run nothing at all: `EchoDriver`
|
||||
//! builds no [`Launch`], so there is no host for it to appear to honour.
|
||||
//!
|
||||
//! The quoting, the forced ssh options and the remote script are
|
||||
//! `crate::ssh`'s: this module decides *which* transport, that one knows what a
|
||||
//! correct ssh invocation is.
|
||||
//!
|
||||
//! A transport is therefore two operations rather than one: **run this** and
|
||||
//! **reach this port**. The second is what a managed `llama-server` needs -- it
|
||||
//! is spawned as a process and then spoken to over HTTP -- and it is a no-op
|
||||
//! locally, where the port a program binds is already one this machine can
|
||||
//! dial. Over ssh it is an `-L` tunnel on the same connection that runs the
|
||||
//! command, so the model server binds loopback on the far machine and is never
|
||||
//! exposed to its network. See [`Transport::reserve_port`].
|
||||
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::Stdio;
|
||||
|
||||
@@ -36,10 +15,6 @@ pub struct Launch {
|
||||
pub program: String,
|
||||
pub args: Vec<String>,
|
||||
pub cwd: Option<PathBuf>,
|
||||
/// A port this program will listen on, and the port that reaches it
|
||||
/// from here -- see [`Transport::reserve_port`], which is the only
|
||||
/// thing that should produce one.
|
||||
///
|
||||
/// On the launch rather than in [`Transport::spawn`]'s signature
|
||||
/// because it is part of what is being run: a caller that needs to
|
||||
/// reach the process it is starting says so once, where it says
|
||||
@@ -66,23 +41,9 @@ impl Launch {
|
||||
}
|
||||
}
|
||||
|
||||
/// How a launched process's standard streams are connected.
|
||||
///
|
||||
/// The choice is not the transport's and not the driver's dialect: it is
|
||||
/// whether the process is expected to outlive this server. A probe answers
|
||||
/// within one call, so pipes this server drains are right. A session is a
|
||||
/// conversation somebody is having, so its streams live in the session
|
||||
/// directory where a later run of this server can pick them up.
|
||||
pub enum Streams {
|
||||
/// Pipes owned by this server; the child is killed when they drop.
|
||||
Piped,
|
||||
/// The same, except that stdin is already open on something this server
|
||||
/// holds -- the file being copied to another machine. Bytes this process has
|
||||
/// in memory do not need this: [`Streams::Piped`] gives a pipe to write them
|
||||
/// into as the child reads.
|
||||
PipedFrom(Stdio),
|
||||
/// Files -- and, for stdin, a fifo the child itself holds open so it never
|
||||
/// reads EOF -- that outlast this process.
|
||||
Detached {
|
||||
stdin: Stdio,
|
||||
stdout: Stdio,
|
||||
@@ -90,18 +51,12 @@ pub enum Streams {
|
||||
},
|
||||
}
|
||||
|
||||
/// The machine a session's process runs on.
|
||||
pub enum Transport {
|
||||
/// The machine this server is running on.
|
||||
Here,
|
||||
/// Reached with the system `ssh` client. Owns its entry rather than
|
||||
/// borrowing it, so a session keeps working against the config it was
|
||||
/// spawned with even if the setup is edited afterwards.
|
||||
Ssh { name: String, ssh: SshConfig },
|
||||
}
|
||||
|
||||
impl Transport {
|
||||
/// The transport a setup describes; a setup with no `ssh` is here.
|
||||
pub fn for_setup(setup: &crate::config::SetupConfig) -> Self {
|
||||
match &setup.ssh {
|
||||
Some(ssh) => Self::Ssh {
|
||||
@@ -112,10 +67,6 @@ impl Transport {
|
||||
}
|
||||
}
|
||||
|
||||
/// Starts `launch` with its streams connected as `streams` says. The failure
|
||||
/// names what to check, and the two transports fail for genuinely different
|
||||
/// reasons -- a missing ssh client here versus a program not on the remote
|
||||
/// PATH -- so each says its own thing.
|
||||
pub fn spawn(&self, launch: &Launch, streams: Streams) -> Result<Child> {
|
||||
let host = match self {
|
||||
Self::Here => None,
|
||||
@@ -149,9 +100,6 @@ impl Transport {
|
||||
stderr,
|
||||
} => {
|
||||
command.stdin(stdin).stdout(stdout).stderr(stderr);
|
||||
// No `kill_on_drop`: outliving this server is the point. Its own
|
||||
// process group as well, so a signal sent to the server's group
|
||||
// does not travel to a session meant to survive being stopped.
|
||||
command.process_group(0);
|
||||
}
|
||||
}
|
||||
@@ -198,9 +146,6 @@ impl Transport {
|
||||
Ok(String::from_utf8_lossy(&output.stdout).into_owned())
|
||||
}
|
||||
|
||||
/// Runs `launch` with `input` on its stdin and reports everything it
|
||||
/// produced -- stdout as bytes, stderr as text, and the exit status.
|
||||
///
|
||||
/// The one description of "run this there, with this on stdin", so that
|
||||
/// shipping an attachment and writing a file through the explorer are the
|
||||
/// same operation rather than two. It is also the only capture that hands
|
||||
@@ -211,9 +156,6 @@ impl Transport {
|
||||
/// Bytes rather than a `String`, because a file's contents are not text
|
||||
/// until something has checked, and lossy decoding would replace the
|
||||
/// evidence that they are not.
|
||||
///
|
||||
/// `Err` means the process could not be started at all; a process that ran
|
||||
/// and failed is a [`Captured`] with a status saying so.
|
||||
pub async fn capture_with_input(&self, launch: &Launch, input: Input) -> Result<Captured> {
|
||||
let (streams, to_write) = match input {
|
||||
Input::None => (Streams::Piped, None),
|
||||
@@ -245,13 +187,6 @@ impl Transport {
|
||||
})
|
||||
}
|
||||
|
||||
/// Picks a port for a launched program to serve on, and the port that
|
||||
/// reaches it from here.
|
||||
///
|
||||
/// The "reach this port" half of what a transport is. Locally there is
|
||||
/// one port and the OS chooses it, by binding and letting go -- racy
|
||||
/// in principle, and nothing on this machine is hunting for ports.
|
||||
///
|
||||
/// Over ssh the near end is chosen the same way and the far end is a
|
||||
/// guess, because there is no portable way to ask a machine for a free
|
||||
/// port that does not race with binding it anyway. It is taken from
|
||||
@@ -273,7 +208,6 @@ impl Transport {
|
||||
})
|
||||
}
|
||||
|
||||
/// How to say where this runs, for a log line a person reads.
|
||||
pub fn describe(&self) -> String {
|
||||
match self {
|
||||
Self::Here => "on this machine".to_string(),
|
||||
@@ -282,13 +216,8 @@ impl Transport {
|
||||
}
|
||||
}
|
||||
|
||||
/// Where a port on another machine is guessed from: high enough to be out
|
||||
/// of the way of services, and below the 32768-60999 Linux hands out to
|
||||
/// outgoing connections, which is where a guess would most often collide.
|
||||
const FAR_PORTS: std::ops::Range<u16> = 20000..30000;
|
||||
|
||||
/// What a command is given on its standard input.
|
||||
///
|
||||
/// Three cases rather than an `Option<Stdio>` because they are three genuinely
|
||||
/// different arrangements and only this knows which: nothing to say, bytes this
|
||||
/// process is holding, or a file it has open. The last is how a
|
||||
@@ -300,18 +229,13 @@ pub enum Input {
|
||||
File(std::fs::File),
|
||||
}
|
||||
|
||||
/// Everything a finished command produced, including the status.
|
||||
pub struct Captured {
|
||||
pub status: std::process::ExitStatus,
|
||||
pub stdout: Vec<u8>,
|
||||
/// Trimmed, and what a failure is reported as: ssh's own refusals and a
|
||||
/// tool's own message about the file it could not open are both the useful
|
||||
/// half of why something did not work.
|
||||
pub stderr: String,
|
||||
}
|
||||
|
||||
impl Captured {
|
||||
/// The stdout of a command that succeeded, or the machine's own words.
|
||||
pub fn ok(self) -> Result<Vec<u8>> {
|
||||
if self.status.success() {
|
||||
return Ok(self.stdout);
|
||||
|
||||
Reference in new issue
Block a user