Refactor in prep for clip

This commit is contained in:
John Doty 2024-06-22 07:32:11 -07:00
parent 3f7afc5b78
commit 3eba65f6e6
8 changed files with 101 additions and 94 deletions

View file

@ -22,7 +22,7 @@ indoc = "1"
log = { version = "0.4", features = ["std"] }
open = "3"
thiserror = "1.0"
tokio = { version = "1", features = ["io-std", "io-util", "macros", "net", "process", "rt", "rt-multi-thread"] }
tokio = { version = "1", features = ["io-std", "io-util", "macros", "net", "process", "rt", "rt-multi-thread", "fs"] }
tokio-stream = "0.1"
toml = "0.5"
tui = "0.19"

View file

@ -9,5 +9,10 @@ async fn main() {
std::process::exit(1);
}
fwd::browse_url(&args[1]).await;
let url = &args[1];
if let Err(e) = fwd::browse_url(url).await {
eprintln!("Unable to open {url}");
eprintln!("{}", e);
std::process::exit(1);
}
}

View file

@ -1,40 +0,0 @@
use crate::message::Message;
use anyhow::Result;
use tokio::sync::mpsc;
#[cfg(target_family = "unix")]
mod browse_unix;
#[cfg(target_family = "unix")]
use browse_unix::{browse_url_impl, handle_browser_open_impl};
#[inline]
pub async fn browse_url(url: &String) {
if let Err(e) = browse_url_impl(url).await {
eprintln!("Unable to open {url}");
eprintln!("{}", e);
std::process::exit(1);
}
}
#[cfg(not(target_family = "unix"))]
pub async fn browse_url_impl(_url: &String) -> Result<()> {
use anyhow::anyhow;
Err(anyhow!(
"Opening a browser is not supported on this platform"
))
}
#[inline]
pub async fn handle_browser_open(
messages: mpsc::Sender<Message>,
) -> Result<()> {
handle_browser_open_impl(messages).await
}
#[cfg(not(target_family = "unix"))]
async fn handle_browser_open_impl(
_messages: mpsc::Sender<Message>,
) -> Result<()> {
std::future::pending().await
}

View file

@ -1,8 +1,8 @@
mod browse;
mod client;
mod message;
mod reverse;
mod server;
pub use browse::browse_url;
pub use client::run_client;
pub use reverse::browse_url;
pub use server::run_server;

View file

@ -5,7 +5,7 @@ const VERSION: &str = env!("CARGO_PKG_VERSION");
fn usage() {
println!(indoc! {"
usage: fwd [options] (<server> | browse <url>)
usage: fwd [options] (<server> | browse <url> | clip [<file>])
To connect a client to a server that has an `fwd` installed in its path, run
`fwd <server>` on the client, where <server> is the name of the server to
@ -60,9 +60,13 @@ fn parse_args(args: Vec<String>) -> Args {
} else {
Args::Error
}
} else if rest.len() > 1 && rest[0] == "browse" {
if rest.len() == 2 {
Args::Browse(rest[1].to_string())
} else if rest.len() > 1 {
if rest[0] == "browse" {
if rest.len() == 2 {
Args::Browse(rest[1].to_string())
} else {
Args::Error
}
} else {
Args::Error
}
@ -73,6 +77,14 @@ fn parse_args(args: Vec<String>) -> Args {
}
}
async fn browse_url(url: &str) {
if let Err(e) = fwd::browse_url(&url).await {
eprintln!("Unable to open {url}");
eprintln!("{}", e);
std::process::exit(1);
}
}
#[tokio::main]
async fn main() {
match parse_args(std::env::args().collect()) {
@ -86,7 +98,7 @@ async fn main() {
fwd::run_server().await;
}
Args::Browse(url) => {
fwd::browse_url(&url).await;
browse_url(&url).await;
}
Args::Client(server, sudo) => {
fwd::run_client(&server, sudo).await;

29
src/reverse.rs Normal file
View file

@ -0,0 +1,29 @@
use anyhow::Result;
#[cfg(target_family = "unix")]
mod unix;
#[cfg(target_family = "unix")]
pub use unix::{handle_reverse_connections, send_reverse_message};
use crate::message::Message;
#[cfg(not(target_family = "unix"))]
pub async fn send_reverse_message(_message: Message) -> Result<()> {
use anyhow::anyhow;
Err(anyhow!(
"Server-side operations are not supported on this platform"
))
}
#[cfg(not(target_family = "unix"))]
pub async fn handle_reverse_connections(
_messages: mpsc::Sender<Message>,
) -> Result<()> {
std::future::pending().await
}
#[inline]
pub async fn browse_url(url: &str) -> Result<()> {
send_reverse_message(Message::Browse(url.to_string())).await
}

View file

@ -1,14 +1,15 @@
use crate::message::{Message, MessageReader, MessageWriter};
// The reverse client connects to the server via a local connection to send
// commands back to the client.
use anyhow::{bail, Context, Result};
use log::warn;
use std::os::unix::fs::DirBuilderExt;
use std::path::PathBuf;
use tokio::net::{UnixListener, UnixStream};
use tokio::sync::mpsc;
use users;
use xdg;
pub async fn browse_url_impl(url: &String) -> Result<()> {
use crate::message::{Message, MessageReader, MessageWriter};
pub async fn send_reverse_message(message: Message) -> Result<()> {
let path = socket_path().context("Error getting socket path")?;
let stream = match UnixStream::connect(&path).await {
Ok(s) => s,
@ -18,38 +19,22 @@ pub async fn browse_url_impl(url: &String) -> Result<()> {
};
let mut writer = MessageWriter::new(stream);
writer
.write(Message::Browse(url.clone()))
.write(message)
.await
.context("Error sending browse message")?;
Ok(())
}
pub async fn handle_browser_open_impl(
messages: mpsc::Sender<Message>,
) -> Result<()> {
let path = socket_path().context("Error getting socket path")?;
handle_browser_open_with_path(messages, path).await
}
async fn handle_browser_open_with_path(
messages: mpsc::Sender<Message>,
path: PathBuf,
) -> Result<()> {
let _ = std::fs::remove_file(&path);
let listener = UnixListener::bind(&path)
.with_context(|| format!("Failed to bind to {}", path.display()))?;
loop {
let (socket, _addr) = listener
.accept()
.await
.context("Error accepting connection")?;
let sender = messages.clone();
tokio::spawn(async move {
if let Err(e) = handle_connection(socket, sender).await {
warn!("Error handling socket connection: {:?}", e);
}
});
fn socket_directory() -> Result<std::path::PathBuf> {
let base_directories = xdg::BaseDirectories::new()
.context("Error creating BaseDirectories")?;
match base_directories.place_runtime_file("fwd") {
Ok(path) => Ok(path),
Err(_) => {
let mut path = std::env::temp_dir();
path.push(format!("fwd{}", users::get_current_uid()));
Ok(path)
}
}
}
@ -68,16 +53,32 @@ pub fn socket_path() -> Result<PathBuf> {
Ok(socket_path)
}
fn socket_directory() -> Result<std::path::PathBuf> {
let base_directories = xdg::BaseDirectories::new()
.context("Error creating BaseDirectories")?;
match base_directories.place_runtime_file("fwd") {
Ok(path) => Ok(path),
Err(_) => {
let mut path = std::env::temp_dir();
path.push(format!("fwd{}", users::get_current_uid()));
Ok(path)
}
pub async fn handle_reverse_connections(
messages: mpsc::Sender<Message>,
) -> Result<()> {
let path = socket_path().context("Error getting socket path")?;
handle_reverse_connections_with_path(messages, path).await
}
async fn handle_reverse_connections_with_path(
messages: mpsc::Sender<Message>,
path: PathBuf,
) -> Result<()> {
let _ = std::fs::remove_file(&path);
let listener = UnixListener::bind(&path)
.with_context(|| format!("Failed to bind to {}", path.display()))?;
loop {
let (socket, _addr) = listener
.accept()
.await
.context("Error accepting connection")?;
let sender = messages.clone();
tokio::spawn(async move {
if let Err(e) = handle_connection(socket, sender).await {
warn!("Error handling socket connection: {:?}", e);
}
});
}
}
@ -119,7 +120,7 @@ mod tests {
let path_override = path.clone();
tokio::spawn(async move {
handle_browser_open_with_path(sender, path_override)
handle_reverse_connections_with_path(sender, path_override)
.await
.expect("Error in server!");
});

View file

@ -1,5 +1,5 @@
use crate::browse::handle_browser_open;
use crate::message::{Message, MessageReader, MessageWriter};
use crate::reverse::handle_reverse_connections;
use anyhow::Result;
use log::{error, warn};
use tokio::io::{AsyncRead, AsyncWrite, AsyncWriteExt, BufReader, BufWriter};
@ -13,7 +13,7 @@ mod refresh;
async fn write_driver<Writer: AsyncWrite + Unpin>(
messages: &mut mpsc::Receiver<Message>,
writer: &mut MessageWriter<Writer>,
) -> () {
) {
while let Some(m) = messages.recv().await {
writer.write(m).await.expect("Failed to write the message")
}
@ -77,7 +77,7 @@ async fn server_main<
tokio::select! {
_ = write_driver(&mut receiver, &mut writer) => Ok(()),
r = server_loop(&mut reader, &mut sender) => r,
r = handle_browser_open(browse_sender) => r,
r = handle_reverse_connections(browse_sender) => r,
}
}