Something went wrong. Try again.
Replicate the clipboard across your machines
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119//! `yank peer`: the machines the clipboard is shared with.//!//! Pairing runs in the daemon, which holds the identity key; hosting only//! asks it for a ticket and returns. The daemon finishes the pairing on//! its own once the other machine redeems it.
use clap::{Args, Subcommand};
use super::{ client::{request, unexpected}, hostname, ui,};use crate::{ config::Dirs, daemon::control::{PAIR_TICKET_TTL, Request, Response},};
/// Manage the machines you share the clipboard with#[derive(Debug, Args)]pub struct PeerArgs { #[command(subcommand)] command: PeerCommand,}
#[derive(Debug, Subcommand)]enum PeerCommand { /// Pair with another machine /// /// Run this on one machine to print a ticket, then run it again on the /// other with the ticket. A ticket works once and expires after a few /// minutes. /// /// A paired machine sees everything you copy, and can pair further /// machines itself. Pair only machines you own. Add { /// Ticket printed by `yank peer add` on the other machine ticket: Option<String>,
/// Name to announce; the hostname by default #[arg(long)] name: Option<String>, }, /// Stop sharing with a machine /// /// It stops being told what you copy, and stops being able to reach /// this one. Whatever it already has, it keeps. #[command(visible_alias = "remove")] Rm { /// Machine to remove, by name or by the start of its id peer: String, },}
pub fn run(args: PeerArgs, dirs: &Dirs) -> eyre::Result<()> { match args.command { PeerCommand::Add { ticket, name } => { let name = name.unwrap_or_else(hostname); match ticket { Some(ticket) => join(dirs, ticket, name), None => host(dirs, name), } } PeerCommand::Rm { peer } => rm(dirs, peer), }}
/// Asks the daemon for a ticket and prints it. The pairing itself finishes/// in the daemon, so there is nothing to wait for here.fn host(dirs: &Dirs, name: String) -> eyre::Result<()> { let response = request(dirs, &Request::PairHost { name })?; let Response::PairTicket(ticket) = response else { return Err(unexpected(&response)); };
anstream::println!("Run this on the other machine:\n"); anstream::println!( " {}\n", ui::heading(format_args!("yank peer add {ticket}")) ); anstream::println!( "{}", ui::dim(format_args!( "It will see everything you copy. The ticket works once, \ and expires in {} minutes.", PAIR_TICKET_TTL.as_secs() / 60, )), );
Ok(())}
/// Redeems a ticket printed by another machine.fn join(dirs: &Dirs, ticket: String, name: String) -> eyre::Result<()> { anstream::println!("Reaching the other machine..."); let response = request(dirs, &Request::PairJoin { ticket, name })?; let Response::Paired(name) = response else { return Err(unexpected(&response)); };
anstream::println!("{}", ui::good(format_args!("Paired with `{name}`")));
Ok(())}
fn rm(dirs: &Dirs, peer: String) -> eyre::Result<()> { let response = request(dirs, &Request::RemovePeer { peer })?; let Response::PeerRemoved(endpoint) = response else { return Err(unexpected(&response)); };
anstream::println!("{}", ui::good(format_args!("Removed {endpoint}"))); anstream::println!( "{}", ui::dim("It will be removed on the other machines as they hear about it."), );
Ok(())}