Refactor in prep for clip
This commit is contained in:
parent
3f7afc5b78
commit
3eba65f6e6
8 changed files with 101 additions and 94 deletions
|
|
@ -22,7 +22,7 @@ indoc = "1"
|
||||||
log = { version = "0.4", features = ["std"] }
|
log = { version = "0.4", features = ["std"] }
|
||||||
open = "3"
|
open = "3"
|
||||||
thiserror = "1.0"
|
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"
|
tokio-stream = "0.1"
|
||||||
toml = "0.5"
|
toml = "0.5"
|
||||||
tui = "0.19"
|
tui = "0.19"
|
||||||
|
|
|
||||||
|
|
@ -9,5 +9,10 @@ async fn main() {
|
||||||
std::process::exit(1);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
||||||
}
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
mod browse;
|
|
||||||
mod client;
|
mod client;
|
||||||
mod message;
|
mod message;
|
||||||
|
mod reverse;
|
||||||
mod server;
|
mod server;
|
||||||
|
|
||||||
pub use browse::browse_url;
|
|
||||||
pub use client::run_client;
|
pub use client::run_client;
|
||||||
|
pub use reverse::browse_url;
|
||||||
pub use server::run_server;
|
pub use server::run_server;
|
||||||
|
|
|
||||||
18
src/main.rs
18
src/main.rs
|
|
@ -5,7 +5,7 @@ const VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||||
|
|
||||||
fn usage() {
|
fn usage() {
|
||||||
println!(indoc! {"
|
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
|
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
|
`fwd <server>` on the client, where <server> is the name of the server to
|
||||||
|
|
@ -60,12 +60,16 @@ fn parse_args(args: Vec<String>) -> Args {
|
||||||
} else {
|
} else {
|
||||||
Args::Error
|
Args::Error
|
||||||
}
|
}
|
||||||
} else if rest.len() > 1 && rest[0] == "browse" {
|
} else if rest.len() > 1 {
|
||||||
|
if rest[0] == "browse" {
|
||||||
if rest.len() == 2 {
|
if rest.len() == 2 {
|
||||||
Args::Browse(rest[1].to_string())
|
Args::Browse(rest[1].to_string())
|
||||||
} else {
|
} else {
|
||||||
Args::Error
|
Args::Error
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
Args::Error
|
||||||
|
}
|
||||||
} else if rest.len() == 1 {
|
} else if rest.len() == 1 {
|
||||||
Args::Client(rest[0].to_string(), sudo.unwrap_or(false))
|
Args::Client(rest[0].to_string(), sudo.unwrap_or(false))
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -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]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
match parse_args(std::env::args().collect()) {
|
match parse_args(std::env::args().collect()) {
|
||||||
|
|
@ -86,7 +98,7 @@ async fn main() {
|
||||||
fwd::run_server().await;
|
fwd::run_server().await;
|
||||||
}
|
}
|
||||||
Args::Browse(url) => {
|
Args::Browse(url) => {
|
||||||
fwd::browse_url(&url).await;
|
browse_url(&url).await;
|
||||||
}
|
}
|
||||||
Args::Client(server, sudo) => {
|
Args::Client(server, sudo) => {
|
||||||
fwd::run_client(&server, sudo).await;
|
fwd::run_client(&server, sudo).await;
|
||||||
|
|
|
||||||
29
src/reverse.rs
Normal file
29
src/reverse.rs
Normal 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
|
||||||
|
}
|
||||||
|
|
@ -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 anyhow::{bail, Context, Result};
|
||||||
use log::warn;
|
use log::warn;
|
||||||
use std::os::unix::fs::DirBuilderExt;
|
use std::os::unix::fs::DirBuilderExt;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use tokio::net::{UnixListener, UnixStream};
|
use tokio::net::{UnixListener, UnixStream};
|
||||||
use tokio::sync::mpsc;
|
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 path = socket_path().context("Error getting socket path")?;
|
||||||
let stream = match UnixStream::connect(&path).await {
|
let stream = match UnixStream::connect(&path).await {
|
||||||
Ok(s) => s,
|
Ok(s) => s,
|
||||||
|
|
@ -18,38 +19,22 @@ pub async fn browse_url_impl(url: &String) -> Result<()> {
|
||||||
};
|
};
|
||||||
let mut writer = MessageWriter::new(stream);
|
let mut writer = MessageWriter::new(stream);
|
||||||
writer
|
writer
|
||||||
.write(Message::Browse(url.clone()))
|
.write(message)
|
||||||
.await
|
.await
|
||||||
.context("Error sending browse message")?;
|
.context("Error sending browse message")?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn handle_browser_open_impl(
|
fn socket_directory() -> Result<std::path::PathBuf> {
|
||||||
messages: mpsc::Sender<Message>,
|
let base_directories = xdg::BaseDirectories::new()
|
||||||
) -> Result<()> {
|
.context("Error creating BaseDirectories")?;
|
||||||
let path = socket_path().context("Error getting socket path")?;
|
match base_directories.place_runtime_file("fwd") {
|
||||||
handle_browser_open_with_path(messages, path).await
|
Ok(path) => Ok(path),
|
||||||
}
|
Err(_) => {
|
||||||
|
let mut path = std::env::temp_dir();
|
||||||
async fn handle_browser_open_with_path(
|
path.push(format!("fwd{}", users::get_current_uid()));
|
||||||
messages: mpsc::Sender<Message>,
|
Ok(path)
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -68,16 +53,32 @@ pub fn socket_path() -> Result<PathBuf> {
|
||||||
Ok(socket_path)
|
Ok(socket_path)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn socket_directory() -> Result<std::path::PathBuf> {
|
pub async fn handle_reverse_connections(
|
||||||
let base_directories = xdg::BaseDirectories::new()
|
messages: mpsc::Sender<Message>,
|
||||||
.context("Error creating BaseDirectories")?;
|
) -> Result<()> {
|
||||||
match base_directories.place_runtime_file("fwd") {
|
let path = socket_path().context("Error getting socket path")?;
|
||||||
Ok(path) => Ok(path),
|
handle_reverse_connections_with_path(messages, path).await
|
||||||
Err(_) => {
|
}
|
||||||
let mut path = std::env::temp_dir();
|
|
||||||
path.push(format!("fwd{}", users::get_current_uid()));
|
async fn handle_reverse_connections_with_path(
|
||||||
Ok(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();
|
let path_override = path.clone();
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
handle_browser_open_with_path(sender, path_override)
|
handle_reverse_connections_with_path(sender, path_override)
|
||||||
.await
|
.await
|
||||||
.expect("Error in server!");
|
.expect("Error in server!");
|
||||||
});
|
});
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::browse::handle_browser_open;
|
|
||||||
use crate::message::{Message, MessageReader, MessageWriter};
|
use crate::message::{Message, MessageReader, MessageWriter};
|
||||||
|
use crate::reverse::handle_reverse_connections;
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use log::{error, warn};
|
use log::{error, warn};
|
||||||
use tokio::io::{AsyncRead, AsyncWrite, AsyncWriteExt, BufReader, BufWriter};
|
use tokio::io::{AsyncRead, AsyncWrite, AsyncWriteExt, BufReader, BufWriter};
|
||||||
|
|
@ -13,7 +13,7 @@ mod refresh;
|
||||||
async fn write_driver<Writer: AsyncWrite + Unpin>(
|
async fn write_driver<Writer: AsyncWrite + Unpin>(
|
||||||
messages: &mut mpsc::Receiver<Message>,
|
messages: &mut mpsc::Receiver<Message>,
|
||||||
writer: &mut MessageWriter<Writer>,
|
writer: &mut MessageWriter<Writer>,
|
||||||
) -> () {
|
) {
|
||||||
while let Some(m) = messages.recv().await {
|
while let Some(m) = messages.recv().await {
|
||||||
writer.write(m).await.expect("Failed to write the message")
|
writer.write(m).await.expect("Failed to write the message")
|
||||||
}
|
}
|
||||||
|
|
@ -77,7 +77,7 @@ async fn server_main<
|
||||||
tokio::select! {
|
tokio::select! {
|
||||||
_ = write_driver(&mut receiver, &mut writer) => Ok(()),
|
_ = write_driver(&mut receiver, &mut writer) => Ok(()),
|
||||||
r = server_loop(&mut reader, &mut sender) => r,
|
r = server_loop(&mut reader, &mut sender) => r,
|
||||||
r = handle_browser_open(browse_sender) => r,
|
r = handle_reverse_connections(browse_sender) => r,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue