8000 feat(share): add --copy option to copy ticket to clipboard by AK-Lmn · Pull Request #7 · osmanahmadxai/beemr · GitHub
[go: up one dir, main page]

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ beemr get <ticket> -o ~/Downloads # download into a specific folder
| `-p`, `--port <port>` | Listen on a specific port instead of a random one. |
| `--no-port-mapping` | Don't ask your router to open a port (UPnP, PCP, NAT-PMP). |
| `--no-relay` | Don't relay for other beemr users while sharing (see [How it connects](#how-it-connects)). |
| `--copy` | Copy the `beemr get …` command to the clipboard. |

### Your device and contacts

Expand Down
6 changes: 6 additions & 0 deletions docs/beemr.1
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ beemr \- peer\-to\-peer file sharing
.IR port ]
.RB [ \-\-no\-port\-mapping ]
.RB [ \-\-no\-relay ]
.RB [ \-\-copy ]
.br
.B beemr get
.I ticket
Expand Down Expand Up @@ -93,6 +94,11 @@ Don't relay end\-to\-end encrypted traffic for other beemr users while
sharing.
By default, a sharer that is reachable from the internet relays for devices
that can't connect directly, until the share ends.
.TP
.B \-\-copy
Copy the
.B beemr get
command to the system clipboard.
.SH ENVIRONMENT
.TP
.B BEEMR_HOME
Expand Down
3 changes: 3 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ Share options:
-p, --port <port> Listen on this port (default: random)
--no-port-mapping Don't ask the router to open a port (UPnP, PCP, NAT-PMP)
--no-relay Don't relay for other beemr users while sharing
--copy Copy the beemr get command to the clipboard
";

#[tokio::main]
Expand Down Expand Up @@ -128,6 +129,7 @@ async fn share(args: &[String]) -> Result<()> {
port: 0,
upnp: true,
relay_for_others: true,
copy: false,
};
let mut path = None;
let mut args = args.iter();
Expand All @@ -153,6 +155,7 @@ async fn share(args: &[String]) -> Result<()> {
"-p" | "--port" => options.port = parse_port(value(&mut args, arg)?)?,
"--no-port-mapping" | "--no-upnp" => options.upnp = false,
"--no-relay" => options.relay_for_others = false,
"--copy" => options.copy = true,
flag if flag.starts_with('-') && flag.len() > 1 => {
return Err(Error::new(format!("unknown option {flag}")))
}
Expand Down
72 changes: 71 additions & 1 deletion src/share.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ pub struct ShareOptions {
pub upnp: bool,
/// Relay for other beemr devices while sharing, when reachable.
pub relay_for_others: bool,
/// Copy the `beemr get <ticket>` command to the system clipboard.
pub copy: bool,
}

/// Why sharing stopped.
Expand Down Expand Up @@ -99,10 +101,15 @@ pub async fn run(options: ShareOptions, profile: Profile) -> Result<Outcome> {
changed: Notify::new(),
});
print_policy(&share, options.expires_in);
let command = format!("beemr get {}", ticket.encode());
eprintln!("\nOn the other device, run:\n");
println!(" beemr get {}", ticket.encode());
println!(" {command}");
eprintln!();

if options.copy {
copy_to_clipboard(&command);
}

let (onion_tx, onion_rx) = watch::channel(None);
if let Some(dht) = &dht {
let name = share.profile.name.clone();
Expand Down Expand Up @@ -883,3 +890,66 @@ async fn with_timeout<T>(future: impl std::future::Future<Output = Result<T>>) -
.await
.map_err(|_| Error::new("the other device stopped responding"))?
}

fn copy_to_clipboard(text: &str) {
match try_copy_to_clipboard(text) {
Ok(()) => eprintln!(" ✓ Copied the command to the clipboard"),
Err(e) => eprintln!(" ✗ {e}"),
}
}

fn try_copy_to_clipboard(text: &str) -> std::result::Result<(), String> {
#[cfg(target_os = "windows")]
{
run_clipboard_cmd("clip.exe", &[], text)
.map_err(|_| "Couldn't copy to the clipboard".to_string())
}

#[cfg(target_os = "macos")]
{
run_clipboard_cmd("pbcopy", &[], text)
.map_err(|_| "Couldn't copy to the clipboard".to_string())
}

#[cfg(not(any(target_os = "windows", target_os = "macos")))]
{
let tools: &[(&str, &[&str])] = &[
("wl-copy", &[]),
("xclip", &["-selection", "clipboard"]),
("xsel", &["--clipboard", "--input"]),
];

for (cmd, args) in tools {
if run_clipboard_cmd(cmd, args, text).is_ok() {
return Ok(());
}
}
Err("Couldn't copy to the clipboard (install wl-clipboard, xclip or xsel)".to_string())
}
}

fn run_clipboard_cmd(cmd: &str, args: &[&str], text: &str) -> std::result::Result<(), String> {
use std::io::Write;
use std::process::{Command, Stdio};

let mut child = Command::new(cmd)
.args(args)
.stdin(Stdio::piped())
.stdout(Stdio::null())
.stderr(Stdio::null())
.spawn()
.map_err(|e| e.to_string())?;

if let Some(mut stdin) = child.stdin.take() {
stdin
.write_all(text.as_bytes())
.map_err(|e| e.to_string())?;
} // stdin is dropped here, so the tool sees end-of-file

let status = child.wait().map_err(|e| e.to_string())?;
if status.success() {
Ok(())
} else {
Err(format!("exited with {status}"))
}
}
Loading
0