Accept file payloads for pipe send
This commit is contained in:
parent
78dbbf240b
commit
55cb455de3
5 changed files with 34 additions and 11 deletions
|
|
@ -177,8 +177,8 @@ Roadmap items should be actionable and checkable:
|
||||||
ALPN and requires `pipe.connect` on `resource:pipe:<name>`. Remote
|
ALPN and requires `pipe.connect` on `resource:pipe:<name>`. Remote
|
||||||
`geth pipe listen <name> --node <node-id>` requires `pipe.listen` on the same
|
`geth pipe listen <name> --node <node-id>` requires `pipe.listen` on the same
|
||||||
resource before creating a daemon-lifetime listener on the peer. `geth pipe
|
resource before creating a daemon-lifetime listener on the peer. `geth pipe
|
||||||
send <name> <message> --node <node-id>` carries a byte message over the
|
send <name> [message|--in <path>|--in -] --node <node-id>` carries a byte
|
||||||
dedicated `/geth/pipe/1` ALPN when `pipe.connect` is authorized, and
|
message over the dedicated `/geth/pipe/1` ALPN when `pipe.connect` is authorized, and
|
||||||
`geth pipe recv <name>` drains local daemon-lifetime messages. Long-lived
|
`geth pipe recv <name>` drains local daemon-lifetime messages. Long-lived
|
||||||
bidirectional streams and TCP/Unix forwarding are still roadmap work.
|
bidirectional streams and TCP/Unix forwarding are still roadmap work.
|
||||||
- `geth ssh proxy <node-id>` performs an authorized control-plane handshake over
|
- `geth ssh proxy <node-id>` performs an authorized control-plane handshake over
|
||||||
|
|
|
||||||
|
|
@ -145,7 +145,7 @@ The bootstrap implementation provides:
|
||||||
- pipe registry/message commands:
|
- pipe registry/message commands:
|
||||||
`geth pipe listen <name> [--node <node-id>] [--bearer-secret <secret>]`,
|
`geth pipe listen <name> [--node <node-id>] [--bearer-secret <secret>]`,
|
||||||
`geth pipe connect <name> [--node <node-id>] [--bearer-secret <secret>]`,
|
`geth pipe connect <name> [--node <node-id>] [--bearer-secret <secret>]`,
|
||||||
`geth pipe send <name> <message> [--node <node-id>] [--bearer-secret <secret>]`,
|
`geth pipe send <name> [message|--in <path>|--in -] [--node <node-id>] [--bearer-secret <secret>]`,
|
||||||
and `geth pipe recv <name> [--peek]`
|
and `geth pipe recv <name> [--peek]`
|
||||||
|
|
||||||
`geth peer export/import/list` is for untrusted peer-card exchange. Peer cards
|
`geth peer export/import/list` is for untrusted peer-card exchange. Peer cards
|
||||||
|
|
@ -201,9 +201,9 @@ peer's current daemon-lifetime snapshot for that topic.
|
||||||
Remote pipe connect uses the same protected Iroh control path and requires
|
Remote pipe connect uses the same protected Iroh control path and requires
|
||||||
`pipe.connect` on `resource:pipe:<name>`. The current prototype records a remote
|
`pipe.connect` on `resource:pipe:<name>`. The current prototype records a remote
|
||||||
connection attempt and whether a listener exists. `geth pipe send <name>
|
connection attempt and whether a listener exists. `geth pipe send <name>
|
||||||
<message> --node <node-id>` uses the dedicated `/geth/pipe/1` Iroh ALPN to
|
[message|--in <path>|--in -] --node <node-id>` uses the dedicated `/geth/pipe/1`
|
||||||
write a byte message to an authorized peer listener, and `geth pipe recv <name>`
|
Iroh ALPN to write a byte message to an authorized peer listener, and `geth pipe
|
||||||
drains local daemon-lifetime messages.
|
recv <name>` drains local daemon-lifetime messages.
|
||||||
Remote pipe listen uses the same protected path:
|
Remote pipe listen uses the same protected path:
|
||||||
`geth pipe listen <name> --node <node-id>` requires `pipe.listen` on
|
`geth pipe listen <name> --node <node-id>` requires `pipe.listen` on
|
||||||
`resource:pipe:<name>` before registering a daemon-lifetime listener on the
|
`resource:pipe:<name>` before registering a daemon-lifetime listener on the
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ use clap::{Args, Parser, Subcommand};
|
||||||
use geth_config::GethPaths;
|
use geth_config::GethPaths;
|
||||||
use geth_control::{ControlRequest, ControlResponse};
|
use geth_control::{ControlRequest, ControlResponse};
|
||||||
use geth_node::service::{ServiceInstallOptions, ServiceManager, ServiceReport};
|
use geth_node::service::{ServiceInstallOptions, ServiceManager, ServiceReport};
|
||||||
|
use std::io::Read;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
#[derive(Debug, Parser)]
|
#[derive(Debug, Parser)]
|
||||||
|
|
@ -398,7 +399,9 @@ pub enum PipeCommand {
|
||||||
},
|
},
|
||||||
Send {
|
Send {
|
||||||
target: String,
|
target: String,
|
||||||
message: String,
|
message: Option<String>,
|
||||||
|
#[arg(long = "in", value_name = "PATH")]
|
||||||
|
input: Option<PathBuf>,
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
node: Option<String>,
|
node: Option<String>,
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
|
|
@ -880,11 +883,12 @@ fn request_for_command(command: Command) -> Result<ControlRequest> {
|
||||||
PipeCommand::Send {
|
PipeCommand::Send {
|
||||||
target,
|
target,
|
||||||
message,
|
message,
|
||||||
|
input,
|
||||||
node,
|
node,
|
||||||
bearer_secret,
|
bearer_secret,
|
||||||
} => ControlRequest::PipeSend {
|
} => ControlRequest::PipeSend {
|
||||||
target,
|
target,
|
||||||
data_base64: base64::engine::general_purpose::STANDARD.encode(message.as_bytes()),
|
data_base64: pipe_send_payload_base64(message, input)?,
|
||||||
node,
|
node,
|
||||||
bearer_secret,
|
bearer_secret,
|
||||||
},
|
},
|
||||||
|
|
@ -2140,6 +2144,25 @@ fn print_pipe_message_data(message: &geth_pipe::PipeMessage) -> Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn pipe_send_payload_base64(message: Option<String>, input: Option<PathBuf>) -> Result<String> {
|
||||||
|
match (message, input) {
|
||||||
|
(Some(message), None) => Ok(base64::engine::general_purpose::STANDARD.encode(message)),
|
||||||
|
(None, Some(path)) if path.as_os_str() == "-" => {
|
||||||
|
let mut bytes = Vec::new();
|
||||||
|
std::io::stdin()
|
||||||
|
.read_to_end(&mut bytes)
|
||||||
|
.context("read pipe payload from stdin")?;
|
||||||
|
Ok(base64::engine::general_purpose::STANDARD.encode(bytes))
|
||||||
|
}
|
||||||
|
(None, Some(path)) => {
|
||||||
|
let bytes = std::fs::read(&path).with_context(|| format!("read {}", path.display()))?;
|
||||||
|
Ok(base64::engine::general_purpose::STANDARD.encode(bytes))
|
||||||
|
}
|
||||||
|
(Some(_), Some(_)) => bail!("pipe send accepts either MESSAGE or --in, not both"),
|
||||||
|
(None, None) => bail!("pipe send requires MESSAGE or --in <path>; use --in - for stdin"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn shell_quote_command(command: &[String]) -> String {
|
fn shell_quote_command(command: &[String]) -> String {
|
||||||
command
|
command
|
||||||
.iter()
|
.iter()
|
||||||
|
|
|
||||||
|
|
@ -208,7 +208,7 @@ daemon-lifetime runtime. `geth pipe connect <name> --node <node-id>` sends an
|
||||||
authorized remote connect request over the protected Iroh control ALPN. The
|
authorized remote connect request over the protected Iroh control ALPN. The
|
||||||
remote daemon validates endpoint/card binding and requires `pipe.connect` on
|
remote daemon validates endpoint/card binding and requires `pipe.connect` on
|
||||||
`resource:pipe:<name>` before recording the connection attempt and reporting
|
`resource:pipe:<name>` before recording the connection attempt and reporting
|
||||||
whether a listener exists. `geth pipe send <name> <message> --node <node-id>`
|
whether a listener exists. `geth pipe send <name> [message|--in <path>|--in -] --node <node-id>`
|
||||||
uses the dedicated `/geth/pipe/1` ALPN to write a byte message to a peer
|
uses the dedicated `/geth/pipe/1` ALPN to write a byte message to a peer
|
||||||
listener after the same endpoint/card and capability checks. `geth pipe recv
|
listener after the same endpoint/card and capability checks. `geth pipe recv
|
||||||
<name>` drains local daemon-lifetime messages. `geth pipe listen <name> --node
|
<name>` drains local daemon-lifetime messages. `geth pipe listen <name> --node
|
||||||
|
|
|
||||||
|
|
@ -364,8 +364,8 @@ Goal: add authorized stream-oriented management workflows over Iroh.
|
||||||
- `[x]` Remote pipe listen requires `pipe.listen` on
|
- `[x]` Remote pipe listen requires `pipe.listen` on
|
||||||
`resource:pipe:<name>`.
|
`resource:pipe:<name>`.
|
||||||
- `[x]` Tests cover denied and allowed remote listener registration.
|
- `[x]` Tests cover denied and allowed remote listener registration.
|
||||||
- `[x]` `geth pipe send <name> <message> --node <node-id>` carries a byte
|
- `[x]` `geth pipe send <name> [message|--in <path>|--in -] --node <node-id>`
|
||||||
message over the dedicated `/geth/pipe/1` Iroh ALPN.
|
carries a byte message over the dedicated `/geth/pipe/1` Iroh ALPN.
|
||||||
- `[x]` `geth pipe recv <name>` drains daemon-lifetime pipe messages.
|
- `[x]` `geth pipe recv <name>` drains daemon-lifetime pipe messages.
|
||||||
- `[x]` Remote pipe send requires `pipe.connect` on
|
- `[x]` Remote pipe send requires `pipe.connect` on
|
||||||
`resource:pipe:<name>`.
|
`resource:pipe:<name>`.
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue