Initial browse support, server side
This commit is contained in:
parent
6f906d80a7
commit
d63ceb730f
6 changed files with 297 additions and 5 deletions
126
Cargo.lock
generated
126
Cargo.lock
generated
|
|
@ -133,6 +133,26 @@ dependencies = [
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dirs"
|
||||||
|
version = "4.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059"
|
||||||
|
dependencies = [
|
||||||
|
"dirs-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dirs-sys"
|
||||||
|
version = "0.3.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"redox_users",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "errno"
|
name = "errno"
|
||||||
version = "0.2.8"
|
version = "0.2.8"
|
||||||
|
|
@ -164,6 +184,12 @@ dependencies = [
|
||||||
"miniz_oxide",
|
"miniz_oxide",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fuchsia-cprng"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-core"
|
name = "futures-core"
|
||||||
version = "0.3.24"
|
version = "0.3.24"
|
||||||
|
|
@ -182,11 +208,25 @@ dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"open",
|
"open",
|
||||||
"procfs",
|
"procfs",
|
||||||
|
"tempdir",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-stream",
|
"tokio-stream",
|
||||||
"toml",
|
"toml",
|
||||||
"tui",
|
"tui",
|
||||||
|
"users",
|
||||||
|
"xdg",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "getrandom"
|
||||||
|
version = "0.2.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -418,6 +458,43 @@ dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand"
|
||||||
|
version = "0.4.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293"
|
||||||
|
dependencies = [
|
||||||
|
"fuchsia-cprng",
|
||||||
|
"libc",
|
||||||
|
"rand_core 0.3.1",
|
||||||
|
"rdrand",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_core"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
|
||||||
|
dependencies = [
|
||||||
|
"rand_core 0.4.2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_core"
|
||||||
|
version = "0.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rdrand"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
|
||||||
|
dependencies = [
|
||||||
|
"rand_core 0.3.1",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "redox_syscall"
|
name = "redox_syscall"
|
||||||
version = "0.2.16"
|
version = "0.2.16"
|
||||||
|
|
@ -427,6 +504,26 @@ dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "redox_users"
|
||||||
|
version = "0.4.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b"
|
||||||
|
dependencies = [
|
||||||
|
"getrandom",
|
||||||
|
"redox_syscall",
|
||||||
|
"thiserror",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "remove_dir_all"
|
||||||
|
version = "0.5.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
|
||||||
|
dependencies = [
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustix"
|
name = "rustix"
|
||||||
version = "0.35.11"
|
version = "0.35.11"
|
||||||
|
|
@ -510,6 +607,16 @@ dependencies = [
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tempdir"
|
||||||
|
version = "0.3.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8"
|
||||||
|
dependencies = [
|
||||||
|
"rand",
|
||||||
|
"remove_dir_all",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror"
|
name = "thiserror"
|
||||||
version = "1.0.37"
|
version = "1.0.37"
|
||||||
|
|
@ -623,6 +730,16 @@ version = "0.1.10"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
|
checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "users"
|
||||||
|
version = "0.11.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "24cc0f6d6f267b73e5a2cadf007ba8f9bc39c6a6f9666f8cf25ea809a153b032"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"log",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasi"
|
name = "wasi"
|
||||||
version = "0.10.0+wasi-snapshot-preview1"
|
version = "0.10.0+wasi-snapshot-preview1"
|
||||||
|
|
@ -753,3 +870,12 @@ name = "windows_x86_64_msvc"
|
||||||
version = "0.36.1"
|
version = "0.36.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680"
|
checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "xdg"
|
||||||
|
version = "2.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0c4583db5cbd4c4c0303df2d15af80f0539db703fa1c68802d4cbbd2dd0f88f6"
|
||||||
|
dependencies = [
|
||||||
|
"dirs",
|
||||||
|
]
|
||||||
|
|
|
||||||
|
|
@ -20,9 +20,12 @@ tokio = { version = "1", features = ["full"] }
|
||||||
tokio-stream = "0.1"
|
tokio-stream = "0.1"
|
||||||
toml = "0.5"
|
toml = "0.5"
|
||||||
tui = "0.19"
|
tui = "0.19"
|
||||||
|
users = "0.11"
|
||||||
|
xdg = "2"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
assert_matches = "1"
|
assert_matches = "1"
|
||||||
|
tempdir = "0.3"
|
||||||
|
|
||||||
[target.'cfg(target_os="linux")'.dependencies]
|
[target.'cfg(target_os="linux")'.dependencies]
|
||||||
procfs = "0.14.1"
|
procfs = "0.14.1"
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,9 @@ pub enum Message {
|
||||||
|
|
||||||
// List of available ports from server to client.
|
// List of available ports from server to client.
|
||||||
Ports(Vec<PortDesc>),
|
Ports(Vec<PortDesc>),
|
||||||
|
|
||||||
|
// Browse a thing
|
||||||
|
Browse(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Message {
|
impl Message {
|
||||||
|
|
@ -96,6 +99,10 @@ impl Message {
|
||||||
put_string(result, sliced);
|
put_string(result, sliced);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Browse(url) => {
|
||||||
|
result.put_u8(0x07);
|
||||||
|
put_string(result, url);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -124,6 +131,7 @@ impl Message {
|
||||||
}
|
}
|
||||||
Ok(Ports(ports))
|
Ok(Ports(ports))
|
||||||
}
|
}
|
||||||
|
0x07 => Ok(Browse(get_string(cursor)?)),
|
||||||
b => Err(Error::Unknown(b).into()),
|
b => Err(Error::Unknown(b).into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -274,6 +282,7 @@ mod message_tests {
|
||||||
desc: "metadata-library".to_string(),
|
desc: "metadata-library".to_string(),
|
||||||
},
|
},
|
||||||
]));
|
]));
|
||||||
|
assert_round_trip(Browse("https://google.com/".to_string()));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
||||||
15
src/server/browser.rs
Normal file
15
src/server/browser.rs
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
use crate::message::Message;
|
||||||
|
use anyhow::Result;
|
||||||
|
use tokio::sync::mpsc;
|
||||||
|
|
||||||
|
#[cfg(target_family = "unix")]
|
||||||
|
use browser_unix::handle_browser_open_impl;
|
||||||
|
|
||||||
|
mod browser_unix;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub async fn handle_browser_open(
|
||||||
|
messages: mpsc::Sender<Message>,
|
||||||
|
) -> Result<()> {
|
||||||
|
handle_browser_open_impl(messages).await
|
||||||
|
}
|
||||||
136
src/server/browser/browser_unix.rs
Normal file
136
src/server/browser/browser_unix.rs
Normal file
|
|
@ -0,0 +1,136 @@
|
||||||
|
use crate::message::{Message, MessageReader};
|
||||||
|
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 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);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn socket_path() -> Result<PathBuf> {
|
||||||
|
let mut socket_path = socket_directory()?;
|
||||||
|
|
||||||
|
std::fs::DirBuilder::new()
|
||||||
|
.recursive(true)
|
||||||
|
.mode(0o700)
|
||||||
|
.create(&socket_path)
|
||||||
|
.context("Error creating socket directory")?;
|
||||||
|
|
||||||
|
// TODO: check mode of directory
|
||||||
|
|
||||||
|
socket_path.push("browser");
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn handle_connection(
|
||||||
|
socket: UnixStream,
|
||||||
|
sender: mpsc::Sender<Message>,
|
||||||
|
) -> Result<()> {
|
||||||
|
let mut reader = MessageReader::new(socket);
|
||||||
|
let message = reader.read().await.context("Error reading message")?;
|
||||||
|
match message {
|
||||||
|
Message::Browse(url) => sender.send(Message::Browse(url)).await?,
|
||||||
|
_ => bail!("Unsupported message: {:?}", message),
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use crate::message::MessageWriter;
|
||||||
|
use tempdir::TempDir;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn socket_path_repeats() {
|
||||||
|
assert_eq!(
|
||||||
|
socket_path().expect("Could not get socket path a"),
|
||||||
|
socket_path().expect("Could not get socket path b")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn url_to_message() {
|
||||||
|
let (sender, mut receiver) = mpsc::channel(64);
|
||||||
|
|
||||||
|
let tmp_dir =
|
||||||
|
TempDir::new("url_to_message").expect("Error getting tmpdir");
|
||||||
|
let path = tmp_dir.path().join("socket");
|
||||||
|
|
||||||
|
let path_override = path.clone();
|
||||||
|
tokio::spawn(async move {
|
||||||
|
handle_browser_open_with_path(sender, path_override)
|
||||||
|
.await
|
||||||
|
.expect("Error in server!");
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut attempt = 0;
|
||||||
|
let stream = loop {
|
||||||
|
match UnixStream::connect(&path).await {
|
||||||
|
Ok(stream) => break Ok(stream),
|
||||||
|
Err(e) => {
|
||||||
|
if attempt == 5 {
|
||||||
|
break Err(e)
|
||||||
|
.context("Maximum retries exceeded, last error");
|
||||||
|
}
|
||||||
|
attempt += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tokio::time::sleep(tokio::time::Duration::from_millis(10)).await;
|
||||||
|
}
|
||||||
|
.expect("Error connecting to socket");
|
||||||
|
let mut writer = MessageWriter::new(stream);
|
||||||
|
let sent = Message::Browse("https://google.com/".to_string());
|
||||||
|
writer
|
||||||
|
.write(sent.clone())
|
||||||
|
.await
|
||||||
|
.expect("Error writing browse message");
|
||||||
|
|
||||||
|
let received = receiver.recv().await.expect("Error receiving message");
|
||||||
|
assert_eq!(sent, received);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -4,6 +4,7 @@ use log::{error, warn};
|
||||||
use tokio::io::{AsyncRead, AsyncWrite, AsyncWriteExt, BufReader, BufWriter};
|
use tokio::io::{AsyncRead, AsyncWrite, AsyncWriteExt, BufReader, BufWriter};
|
||||||
use tokio::sync::mpsc;
|
use tokio::sync::mpsc;
|
||||||
|
|
||||||
|
mod browser;
|
||||||
mod refresh;
|
mod refresh;
|
||||||
|
|
||||||
// We drive writes through an mpsc queue, because we not only handle requests
|
// We drive writes through an mpsc queue, because we not only handle requests
|
||||||
|
|
@ -76,11 +77,13 @@ async fn server_main<
|
||||||
let mut writer = MessageWriter::new(writer);
|
let mut writer = MessageWriter::new(writer);
|
||||||
let mut reader = MessageReader::new(reader);
|
let mut reader = MessageReader::new(reader);
|
||||||
|
|
||||||
let (_, result) = tokio::join!(
|
let browse_sender = sender.clone();
|
||||||
write_driver(&mut receiver, &mut writer),
|
|
||||||
server_loop(&mut reader, &mut sender)
|
tokio::select! {
|
||||||
);
|
_ = write_driver(&mut receiver, &mut writer) => Ok(()),
|
||||||
result
|
r = server_loop(&mut reader, &mut sender) => r,
|
||||||
|
r = browser::handle_browser_open(browse_sender) => r,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn run_server() {
|
pub async fn run_server() {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue